Replaces hardcoded 38 roles with complete list extracted from
bicep/lookup/rbaclookup:2.x module.
Changes:
- Add scripts/extract_roles_from_rbaclookup.py to parse rbacLookup.bicep
- Generate ilsp/bicep_lsp/azure_roles.json with 682 role names
- Load roles dynamically in modules.py from JSON file
- Now supports ALL Azure built-in roles for autocomplete
Benefits:
- Complete Azure RBAC coverage (682 vs 38 roles)
- Easy to update when new roles are added to rbaclookup module
- Cleaner code (no giant hardcoded list in modules.py)
Usage to update roles:
python3 scripts/extract_roles_from_rbaclookup.py /path/to/rbacLookup.bicep
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Adds support for autocomplete in multi-line array syntax like:
roles: [
'KEY_VAULT_ ← cursor triggers completion here
]
Previously only worked on same line as opening bracket:
roles: ['KEY_VAULT_ ← only this worked
Changes:
- Walk backwards up to 10 lines to find array opening (e.g. "roles: [")
- Detect if cursor is inside array based on indentation and quotes
- Stop lookback if closing bracket found (not in array anymore)
- Add test case for nested multi-line array completion
- Improve lsp_bridge.py error handling with traceback logging
- Add lsp_bridge_debug.sh wrapper for easier IntelliJ debugging
- Update EDITOR_SETUP.md with correct IntelliJ LSP4IJ config
Fixes autocomplete for deeply nested structures like:
assignments: [{ roles: ['APP_CONFIGURATION_...'] }]
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Catalog stores lowercase paths (e.g. modules/keyvault) but .bicep files
may use camelCase (e.g. modules/keyVault). Make get_module_by_ref
case-insensitive so completions work regardless of casing.
Previously the 'if lru_items:' guard meant that when our catalog returned
an empty list (e.g. a param with no allowed enum values), the Bicep LS
completions (Bicep keywords, schema types) would leak through unchanged.
Now the replace is unconditional for version/param/param_value contexts.
The Bicep LS has no knowledge of our private ACR registry so its output
in these positions is always noise — suppress it even when we have nothing
better to show.
The lookback regex used ([^']+) requiring one or more version chars,
so 'br/modules:modules/keyvault:' (no version yet) silently fell through
to the unknown context and injected all module names instead of params.
Change + to * to allow empty version string. The param_completion_items
fallback already handles empty version by picking the closest schema.
For specific LRU contexts (version, param, param_value), the Bicep LS was
appending its own random/irrelevant completions alongside the LRU catalog
items. The LS has no knowledge of the private ACR registry, so its suggestions
in these positions are noise.
Now the LS items are discarded entirely for these three contexts. LS items
are still kept (below LRU items) for module_path and unknown contexts.
Clean HTML page describing iLSP, what LSP is, the WebSocket endpoints,
and setup instructions for Neovim, IntelliJ and VS Code. Live stats
(Bicep modules, pipeline templates, PyPI packages) are rendered from
the in-memory catalog at request time.
No emojis. Minimal CSS, no external dependencies.
- Inject AzDO schema into yaml-language-server via initializationOptions
at startup (primary mechanism, works without workspace.configuration)
- Respond to workspace/configuration pull requests from yaml-language-server
so schema is applied even when editors declare configuration capability
- Keep post-init workspace/didChangeConfiguration as belt-and-suspenders
- Bake azdo-pipeline-schema.json (~1.6MB, 119 defs) into Docker image
- Add smoke test [8]: AzDO task@version completions (254 items)
- Update smoke test YAML initialize to declare workspace.configuration
- yaml-language-server: rewrite to stdio per WebSocket (fixes crash loop)
vscode-jsonrpc v9 createServerSocketTransport is a TCP client, not server
now spawns yaml-language-server --stdio per connection via asyncio subprocess
- bicep/modules.py: add /iac_source_catalog.json as first path in _IAC_SOURCE_PATHS
Dockerfile copies to /iac_source_catalog.json but path wasn't listed
- server.py: remove YAML_LSP_PORT daemon (no longer needed with stdio mode)
- Makefile: add -e HTTP_PORT=$(HEALTH_PORT) to all docker run commands
server defaulted to :8000 but Makefile exposed :2089 with no override
Two bugs fixed in BicepModuleCatalog:
1. as_completion_items() generated 'br/modules:bicep/modules/appservice:...'
but bicepconfig modulePath='bicep' means Bicep prepends 'bicep/' automatically.
Fix: store ref_path = path.removeprefix('bicep/') and use it in insertText.
Correct output: 'br/modules:modules/appservice:2.3.x'
2. version/param lookups used get_module_by_name() which only matches the last
path segment ('appservice'). New-style refs capture 'modules/appservice' from
the regex, so lookup returned empty. Fix: add get_module_by_ref() that matches
both ref_path and bare name.
Also fixes _iac_param_map to strip path prefix so IAC source descriptions
still enrich completions for 'modules/appservice' refs.
All 63 tests pass.
asyncio.open_connection hangs indefinitely when backend port is silently
dropped. Add wait_for(timeout=3.0) so the WS close frame is always sent
within the test's 5s window.
- Remove static ports 2087/2088/2089 from Nomad; use one dynamic port
- pylsp and Bicep LS stay on localhost inside container (not exposed)
- aiohttp adds /python and /bicep WebSocket routes bridging to localhost LSPs
- Nomad env: HTTP_PORT=$NOMAD_PORT_http, internal ports fixed at 2087/2088
- Editors connect via ws://ilsp.i80.dk/python and ws://ilsp.i80.dk/bicep
- Traefik routes ilsp.i80.dk → single dynamic HTTP port
- Remove all DevOpsMCP/aiohttp runtime deps from BicepModuleCatalog
- BicepModuleCatalog.load() reads bicep_modules_catalog.json from disk at startup (sync)
- Fix _load_catalog: catalog uses dict {path: {versions, schema}} not a list
- server.py: call BicepModuleCatalog.load() synchronously, not via asyncio.gather
- Dockerfile: COPY bicep_modules_catalog.json into both builder + runtime stages
- Health endpoint now reports bicep_modules: 27
Verified locally: make run-quick → health returns pypi_packages:40 bicep_modules:27
catalog.py: Fix HTML parsing regex — pypi-server.i80.dk uses relative hrefs
like href="pkg-name/" not /simple/pkg-name/. Use simpler <a> text extractor.
modules.py: Replace /call-tool POST (wrong) with GET /api/bicep-modules (new REST
endpoint added to DevOpsMCP). Simpler, no MCP protocol overhead.