Repository navigation
release: 0.22.0 (beta → main) - #357
Open
eFAILution wants to merge 53 commits into
Open
eFAILution wants to merge 53 commits into
eFAILution wants to merge 53 commits into
Conversation
Co-authored-by: Simon Heather <simon.heather@yulife.com>
The barrel re-exported handler.ts, which imports vscode at module load, so anything importing ../errors could not run under plain Node. That blocks the standalone MCP server and forced pure modules to import errors/types directly. Drop the handler re-export and build the HTTP timeout error as a plain NetworkError with status 408 (same as handler.createHttpError did). Co-authored-by: eFAILution <eFAILution@users.noreply.github.com>
The outdated-version check and the cache lookups behind validation live in ValidationProvider, mixed with vscode diagnostics and the cache manager instance. Add src/core/validation/versionFindings.ts. It computes outdated refs from text plus a reference resolver and a version fetcher, reads versionCheck.enabled and severity through the config port, and turns each ref into a finding. Each finding also carries a suggested edit that bumps the pinned ref, which is the edit the extension's quick fix makes today. Add src/core/validation/componentLookup.ts with the pure parts of findComponentInCache, parseComponentIdentity, and the version lookup entry, taking the cache contents as input.
ValidationProvider now runs the core include validator and version check and turns each finding into a vscode.Diagnostic through the new findingToDiagnostic mapper. What stays in the provider is the VS Code part: document events, diagnostic collections, code actions, the input quick pick, and the cache-backed component lookup it hands to the core. The gitlab.example.com mock component stays in the provider's lookup, so the core never sees it. The metadata types move to src/core/validation/metadata.ts. validationMetadata.ts keeps the attach and read helpers and re-exports the types. The provider drops from 1504 to 940 lines. Diagnostic messages, codes, ranges, severities, and metadata are unchanged; the unit tests added with the core validator pin them.
createReferenceResolver lived in componentDetector and read the VS Code Git extension, the workspace folders, and the git CLI directly, so the MCP server couldn't expand $CI_SERVER_FQDN and friends. Add src/core/referenceResolver.ts, which expands GitLab variables over a RepoContextPort (the file's GitLab remote, and a non-GitLab remote check) and the runtime config port for the component source fallback. The remote URL parsers move to src/core/gitRemote.ts. The raw git spawn fallback moves to src/adapters/node/repoContext.ts. That file also provides a git CLI RepoContextPort for the MCP server. componentDetector keeps createReferenceResolver(uri) as a thin wrapper over a VS Code port with the same lookup order as before, so callers are unchanged.
Local include resolution picked the root and read files through VS Code APIs inside localComponentResolver, so the MCP server couldn't validate local: includes. src/core/localInclude.ts now resolves a local: path over a WorkspacePort (roots, the resolution root for a file, and a text reader) and parses the target. The VS Code side moves to src/adapters/vscode/workspace.ts. That covers the Git extension repo root, the workspace folder fallbacks, and the open-buffer fast path. localComponentResolver keeps its exports as thin wrappers, so callers are unchanged. Add a done-check unit test. It loads every src/core module under plain Node, then runs the core validator over the local-include and enum-options fixtures through a filesystem workspace port and a fake component lookup.
…gh them (#358) The MCP server needs to reuse the fetch, cache, and validation code from plain Node, but those modules read settings, log, and store state straight through the vscode API. Add small ports for config, secrets, storage, and logging, a runtime that holds them, and an Emitter that can stand in for vscode.EventEmitter later. The default runtime uses the package.json setting defaults, no secrets, in-memory storage, and stderr, so unit tests need no setup. The extension installs VS Code adapters first thing in activate. Logger and HttpClient now read settings through the config port, and Logger writes through the log sink. The logLevel watcher and the dev mode check move to the VS Code logger adapter. Logger.time/timeEnd used console.time on stdout, which the MCP server needs for protocol messages, so they now log at DEBUG through the sink. Co-authored-by: eFAILution <eFAILution@users.noreply.github.com>
Contributor
🛡️ Security Hardening Pipeline ResultsBranch: Workflow Run: 626 Scan Status
Summaries Collected: 4 Scanner Results🔬 CodeQL SAST (Javascript)Status: Completed Findings Summary
No security findings detected for Javascript. Artifacts: CodeQL Reports (Javascript) 🔗 Dependency ReviewStatus: ✅ No issues found No vulnerable or license-violating dependencies detected in this PR. 🔑 Gitleaks (Secrets)No 🔑 Gitleaks (Secrets) findings summary was produced. 📦 OSV (Dependencies)No 📦 OSV (Dependencies) findings summary was produced. Generated by Argus Generated by Argus |
…ort (#359) * refactor(core): add host ports and route logger and HTTP config through them The MCP server needs to reuse the fetch, cache, and validation code from plain Node, but those modules read settings, log, and store state straight through the vscode API. Add small ports for config, secrets, storage, and logging, a runtime that holds them, and an Emitter that can stand in for vscode.EventEmitter later. The default runtime uses the package.json setting defaults, no secrets, in-memory storage, and stderr, so unit tests need no setup. The extension installs VS Code adapters first thing in activate. Logger and HttpClient now read settings through the config port, and Logger writes through the log sink. The logLevel watcher and the dev mode check move to the VS Code logger adapter. Logger.time/timeEnd used console.time on stdout, which the MCP server needs for protocol messages, so they now log at DEBUG through the sink. * refactor(core): read the remaining core settings through the config port The cache manager, component fetcher, discovery config, CI file matcher, and reference resolver still read settings straight from vscode.workspace. Route those reads through the runtime config port so the MCP server can supply its own settings. Same keys, same defaults. Move the componentSources watcher out of ComponentCacheManager into activate. It calls the same forceRefresh and logs the same lines, but the cache manager no longer has to subscribe to VS Code config events. discoveryConfig no longer needs its lazy vscode require, and gitlabCiFileMatcher only uses vscode for types now, so both load under plain Node. --------- Co-authored-by: eFAILution <eFAILution@users.noreply.github.com>
Fixes from the security review of the validation core: - Validation no longer JSON-stringifies each include for a debug log. The argument was built even with debug off, and a 500-byte YAML alias bomb blocked for seconds before throwing. Documents (and local include targets) with more than 100 aliases are skipped. - isUnsupportedLocalPath treats \ as a separator and rejects drive letters, UNC paths, and NUL bytes. The core resolver also checks that the joined path stays inside its root. - Local include targets read from disk must be regular files of at most 1 MB, in the Node reader and the VS Code adapter. - git runs with fixed args, no shell, stdin and stderr ignored, a 5s timeout, a 64 KB output cap, and GIT_DIR, GIT_WORK_TREE, and GIT_CONFIG* stripped with GIT_TERMINAL_PROMPT=0. It resolves on close so stdout isn't truncated. - The local: line regex no longer backtracks quadratically on long whitespace lines. - parseGitLabRemoteUrl ignores remotes whose host isn't a plain hostname, like git@gitlab.com@evil.example:g/p.git.
… into an adapter (#360) TokenManager, ComponentFetcher, and ComponentService imported vscode for SecretStorage, EventEmitter, and the token input box, so the MCP server could not load them. TokenManager now reads and stores tokens through the runtime secrets port and fires changes through the core Emitter. When the port can't store, setTokenForProject throws the same "SecretStorage not available" error as before. It also keeps a gitlab-token-instances list in storage, because secret stores can't be listed and the MCP launcher will need to know which instances have tokens. The token prompt moves to the VS Code auth prompt adapter behind a new AuthPromptPort. Hosts without a UI return undefined, which means public access. The unused ExtensionContext params and setSecretStorage are gone. Co-authored-by: eFAILution <eFAILution@users.noreply.github.com>
Hover markdown embeds component and input descriptions from remote specs and was marked isTrusted = true, so a command: link in a description could run any VS Code command when clicked. Enable only gitlab-component-helper.detachHover. Co-authored-by: eFAILution <eFAILution@users.noreply.github.com>
…361) * refactor(core): persist the component cache through the storage port ComponentCacheManager and UnifiedCache read and wrote VS Code globalState through an ExtensionContext and used vscode.EventEmitter, so the cache could not load outside the extension. Both now go through the runtime storage port, and the cache manager fires through the core Emitter. The ExtensionContext params and setContext are gone. A new persistent flag on the storage port drives the cache status location text, which used to key off whether a context was set. Add an eagerRefresh option (default true, as today). A host that passes false still loads the stored cache but skips the startup fetch of every source, so the MCP server makes no network calls until a tool needs components. Drop the commands re-export from the component services barrel so the cache modules that import the barrel stay free of vscode. Everything under src/services except commands.ts now loads under plain Node. * fix(core): harden events, token index, and cache logs found in review - Emitter logs and skips a throwing listener, like vscode.EventEmitter, so one bad listener can't fail a token save or a cache update. - The token instance list is best effort. A failed write is logged and the token still counts as saved. A malformed list is logged, and an instance string that embeds credentials is never recorded. - Request dedup keys hash the auth token so the raw token never sits in getDeduplicationStats(). - Cache logs report the real storage location and warn when storage isn't persistent. - A failed refresh after a componentSources change logs at warn. --------- Co-authored-by: eFAILution <eFAILution@users.noreply.github.com>
ValidationProvider builds vscode.Diagnostic objects inline while it walks the include list, so the MCP server can't reuse the checks. Add src/core/validation with validateIncludes, which returns plain findings (code, severity, message, file, 0-based range, metadata) for component and local includes. Callers supply the reference resolver, the component lookup, and the local include reader, so nothing in core touches vscode. Messages, codes, ranges, and metadata are the ones the provider publishes today. The provider switches over in the next change. The local include text parser moves to src/core/localInclude.ts, and the reference result types move to src/core/references.ts. The provider modules re-export both, so callers are unchanged. New unit tests pin the findings for the extension-host fixtures (local-include, duplicate-include, flow-inputs, merge-key, revalidate-on-edit, enum-options) and for component includes with a fake lookup.
Add a standalone MCP server so agents (Copilot Chat, Claude Code, and others) can query the same component data the extension uses. The protocol is hand-rolled: newline-delimited JSON-RPC 2.0 over stdio, with initialize, ping, tools/list, and tools/call. It negotiates protocol versions 2025-11-25, 2025-06-18, 2025-03-26, and 2024-11-05, and only sends outputSchema and structuredContent when the negotiated version has them. Tool arguments are validated against each tool's schema. Results are capped in size, and unexpected errors don't leak details. The transport is the only writer to stdout. A stray console.log is redirected to stderr so it can't corrupt the stream. The first tool, get_component_spec, returns a component version's inputs, versions, and latest stable version. Spec text is cleaned of control and bidi characters and length-capped. GitLab error bodies are never passed through. esbuild builds the server to out/mcp/server.js, and a plugin fails the build on any vscode import. The bundle ships in the VSIX. Test output and local agent state are now excluded from the package.
…network Give the MCP server its own host ports and install them once at startup. After that the runtime is locked against replacement. - Config: --config > GCH_CONFIG_JSON > GCH_LOG_LEVEL > the root's .gitlab-component-helper.json > its .vscode/settings.json (JSONC, via jsonc-parser) > defaults. Unknown or wrongly-typed keys are dropped, and gitlabToken is refused. - Tokens: GCH_TOKEN_<HOST> and GITLAB_TOKEN (for GITLAB_HOST) are read once and deleted from the environment. The variable name is lossy, so a token is only bound to a host named by the launcher's settings, GCH_TOKEN_HOSTS, or GITLAB_HOST, never by a workspace file. Two trusted hosts that share a variable name get neither token. - Storage: one JSON file per key in a 0700 cache dir, written atomically as 0600. - Files: only regular files of at most 1 MB under the realpath'd roots. Traversal, symlinks out, and missing files all get the same answer. - Network: HTTPS only, to gitlab.com, componentSources instances, and hosts with a token. Private, loopback, and link-local addresses are refused, including after DNS resolution. A refused host gets a message saying how to allow it. - git: an absolute path found on PATH, only for files under the roots, and GIT_CEILING_DIRECTORIES stops discovery above them. Child processes no longer inherit GCH_* or GITLAB_TOKEN.
Add the tools an agent needs to find and fix CI component problems: - validate_ci_file runs the core validator and version check over one file, a directory, or every CI file in the workspace (same globs as the extension, 500 files max, node_modules and .git skipped). - check_component_versions returns only outdated-version findings. - list_component_usages lists every component and local include with its line, version, and input names. - list_component_versions returns tags, branches, and the latest stable version. The server never writes files. Findings carry suggestedEdits for mechanical fixes (version bumps, and renaming an unknown input that is one typo away from a declared one). The initialize instructions tell agents to validate first, read the spec for the exact version before changing inputs, and apply the edits themselves. Output is built for untrusted content. Messages are fixed text. Names, descriptions, and defaults from YAML or specs go in cleaned, length-capped data fields. Provided input values never appear, since they can be alias-bomb trees. Findings are capped. Hosts the allowlist refused come back as blockedHosts with a hint on how to allow them.
Contribute an MCP server definition provider, so Copilot Chat in agent mode (and other in-editor MCP clients) can start the server with no setup. The definition runs out/mcp/server.js with the editor's own Node (process.execPath with ELECTRON_RUN_AS_NODE=1) and passes: - a --root per workspace folder - the effective settings minus gitlabToken as GCH_CONFIG_JSON - a cache dir under global storage Tokens are only added in resolveMcpServerDefinition, when VS Code actually starts the server. That covers every instance in the token index, plus every componentSources instance with a stored secret, so tokens saved before the index existed still work. GCH_TOKEN_HOSTS names those hosts so the server can bind each token to exactly one. Tokens are never logged. The definition refreshes on token, settings, and workspace folder changes. Registration is skipped on editors without the API and can't fail activation.
Add docs/mcp.md: the tools, using the server from Copilot Chat agent mode, prompts to try, running it from other MCP clients, and its options, setting precedence, token variables, host allowlist, file limits, and protocol versions. Link it from the README. Record the MCP design in AICaC: the core, adapters, and mcp components, and the MCP_STDIO_HANDROLLED, MCP_SERVER_NEVER_WRITES_FILES, MCP_DISTRIBUTED_AS_RELEASE_ASSET, and MCP_TOKENS_VIA_ENV_FROM_EXTENSION decisions. Fix the stale VS Code engine version (1.120) in AGENTS.md and .ai/context.yaml, and drop the removed outputChannel.ts from the architecture file.
The network policy refused every private and loopback address, which blocks self-managed GitLab on internal networks even when the user listed it in componentSources. The host allowlist already limits who we talk to, so only link-local (cloud metadata), unspecified, and multicast addresses stay blocked.
takeEnvTokens deleted GCH_TOKEN_HOSTS before bootstrap read it, so token binding fell back to GCH_CONFIG_JSON. That includes workspace settings, and GCH_TOKEN_<HOST> names are lossy, so a repository that set componentSources to gitlab-example.com got the gitlab.example.com token. - The extension now passes tokens as one GCH_TOKENS_JSON map of exact host to token. The server reads it and deletes it first, and binds each token only to its key. - GCH_TOKEN_<HOST> (for terminal use) binds only to a host named in GCH_TOKEN_HOSTS, which is now read before it's deleted, or in --config. - The extension picks token hosts from the token index plus the user's global componentSources, never workspace or folder values. - Only launcher-trusted hosts widen the network allowlist: --config, GCH_TRUSTED_HOSTS (the user's global sources), token hosts, and gitlab.com. A host named only by a repo file or workspace settings is blocked. The hint tells the agent to use user settings, never repo files. - Workspace config files may only set catalog and checking behavior, not network, cache, or logging settings. - Settings are parsed into null-prototype objects and looked up with own-property checks, so __proto__ can't smuggle values. - The allowlist matches url.host, with the default port normalized.
…e lock - Workspace paths must sit inside a root as written, before any realpath or fs call. UNC and \\?\ paths are refused up front. - readBoundedTextFile stats first and opens with O_NONBLOCK, so a FIFO or device is never read. Repo config files are read through the workspace guard, so a symlink out of the root is ignored. - Output text also drops Unicode tag characters, zero-width and direction marks, word joiners, BOM, the Arabic letter mark, and line and paragraph separators. File paths are cleaned and capped everywhere. documentationUrl is kept only when it's https. - Addresses are parsed to bytes, so IPv4 carried in IPv6 (mapped, compatible, NAT64, 6to4) gets the same checks. 100.100.100.200 and fd00:ec2::254 (cloud metadata) are blocked. - lockRuntime freezes the ports and the network policy. HttpClient refuses to send when the runtime is locked and no policy is installed.
HttpClient is shared by the extension and the MCP server: - It aborts a response body over 10 MB. - Each request has an overall deadline (three socket timeouts, at most 3 minutes), so a server that trickles bytes can't hold it open. - httpTimeout is clamped to 1-60s and retryAttempts to 0-5 wherever they're read. - A request the network policy refuses (RequestRefusedError, which HostNotAllowedError now extends) fails at once, with no retries. - GitLabComponentError keeps its cause, so wrapped refusals are still recognized. The MCP server stops a tool call after 60s with an isError result. It also turns away calls beyond 4 in flight, instead of queuing them without bound.
…nabled docs/mcp.md now matches the hardened server: - GCH_TOKENS_JSON with exact hosts. GCH_TOKEN_<HOST> binds only to gitlab.com, GCH_TOKEN_HOSTS, or --config. - Only launcher-trusted hosts are contacted. Repository files may only set catalog and checking settings. - The response, deadline, tool-call, and walk limits. - Path rules and the suggestedEdits coordinates. - What the server gets when an in-editor AI client starts it, and the application-scoped gitlabComponentHelper.mcp.enabled setting. The README settings table lists mcp.enabled, and the MCP_TOKENS_VIA_ENV_FROM_EXTENSION decision records the new hand-off and mitigations.
A request that throws while being built (e.g. a token with a trailing newline in a header) left its deadline timer running, and the timer later threw a ReferenceError on the uninitialized request. Clear it in the catch and guard the destroy. Also give the whole-request deadline 6 socket timeouts (60s at the default) so slow, steady downloads finish, map httpTimeout 0 to the longest allowed timeout, clamp pagination and parallel fetches the same way, and treat retryAttempts 0 as zero retries.
…mlinks - Tokens are trimmed (a pasted token often ends in a newline) and refused if they're empty or contain control characters. That applies both when the extension stores one and when the MCP server reads GCH_TOKENS_JSON, GCH_TOKEN_<HOST>, or GITLAB_TOKEN. The error and warnings never include the token. - GCH_CONFIG_JSON from the extension now uses the user (global) value for every key a workspace may not set, so the repo's .vscode/settings.json can't reach the server's trusted layer that way. The workspace-settable keys move to core as WORKSPACE_SETTABLE_KEYS, shared by both sides. - lockRuntime deep-freezes every port, not just the top-level object. - Before realpath, the workspace follows symlinks one component at a time. A link with an absolute target (which could be /net autofs or a UNC share) or one that lands outside the roots is refused, so realpath never touches the network.
…ules Recommend GCH_TOKENS_JSON for terminal setups, since it binds each token to exactly one host. Note that tokens are trimmed and ones with control characters are ignored. Note that network, cache, and logging settings come from user scope only, and that symlinks must be relative and stay inside the roots.
AI clients only get the user's GitLab tokens after they opt in with gitlabComponentHelper.mcp.enabled.
A process's starting environment stays readable to the same OS user (ps eww) even after the server deletes the variable, so an agent with terminal access could read tokens passed in env. The extension now writes them to a random 0600 file in its private storage and passes only the path. The server refuses a symlinked, oversized, shared, or foreign-owned file, reads it once, and deletes it. The extension deletes its own unread files after 30s and on dispose, and purges stale ones at activation.
The server now reads and deletes a hand-off file only if its name matches what the extension writes and it sits in a private mcp-handoff folder we own, so a launcher typo can't make it delete an unrelated private file. A failed delete after a good read is a warning, not lost tokens.
eFAILution
had a problem deploying
to
publish-beta
October 22, 2026 21:41 — with
GitHub Actions
Error
The Marketplace page is the README, so it now covers the opt-in setting, the Copilot setup steps, example prompts, the tools, how tokens are protected, and troubleshooting when Copilot doesn't see the server. Co-authored-by: eFAILution <eFAILution@users.noreply.github.com>
scripts/ci/decisionRecords.ts checks, lists and scaffolds decision records. New decisions go in .ai/decisions/ADR-<issue>.yaml, one AICaC v2 document per file with a single key that matches the file name. .ai/decisions.yaml keeps its twenty entries and is closed to new keys. check fails on duplicate keys, new legacy keys, badly named or shaped record files and dangling supersedes. With --branch and --base it also fails on a record whose number is not the branch's issue. list builds the index from both stores at read time. new writes a skeleton record. ADR-366 records the decision. Refs #366
The Decision Records workflow runs on every PR and push to main and beta, with no paths filter so it can be a required check. Release commits are skipped by a job-level if. On PRs it passes the head branch through an environment variable and diffs against HEAD^1; on pushes it runs a plain check. Actions are SHA-pinned and the token is read-only. Refs #366
AGENTS.md gets a quick reference and an "Issues, branches, and records" section. It says to start from an issue, name the branch <type>/<issue>-<desc>, check nobody has the issue, open a draft PR against beta, and record decisions as .ai/decisions/ADR-<issue>.yaml. It also covers what each check failure means and how to move to a correctly named branch without closing the PR. The PR template opens with "Closes #" and adds checklist items for the branch name and the record file. README, workflows.yaml, context.yaml and architecture.yaml point at the new rules and files. Refs #366
This was referenced Oct 23, 2026
* feat(mcp): report why a component fetch failed Classify fetch failures (TLS, DNS, connection, timeout, 404, rate limit, server) from Node error codes and HTTP statuses and return a fixed-text hint. validate_ci_file adds reason, errorCode and hint to component-fetch-failed findings and groups failures per host in summary.fetchFailures. A path outside the workspace now names the roots. Refs #370 * fix(mcp): look past our own error codes when classifying a fetch failure NetworkError carries its own code (NETWORK_ERROR), and the classifier stopped at it, so a TLS, DNS or connection cause was never reached and every network failure came back as unknown. Skip our wrapper codes when walking the cause chain. Also drops a non-null assertion that failed lint. Refs #370 * fix(mcp): give expired and mismatched certificates their own hint The trust-store advice (NODE_EXTRA_CA_CERTS) only helps when Node does not know the issuer. An expired certificate needs a renewal or a clock fix, and a hostname mismatch usually means the wrong instance address. Refs #370 --------- Co-authored-by: eFAILution <eFAILution@users.noreply.github.com>
The beta -> main release PR adds every record that landed on beta, and its head branch has no issue number, so the check always failed it. Each of those records already passed the rule on its own PR. Fork branches named beta still get the rule. Closes #368 Co-authored-by: eFAILution <eFAILution@users.noreply.github.com>
…#373) * feat(mcp): cache component specs and start from the extension's cache The server fetched a spec from GitLab on every tool call. It now keeps its own spec cache in its cache directory and checks it before GitLab. A spec pinned to a tag is reused while cached, as in the extension; any other ref only for cacheTime. Failed fetches are never stored. When VS Code starts the server, the extension writes the spec fields of its component cache to a private file in its storage folder and passes the path in GCH_CACHE_SEED. The server reads it bounded and shape-checked, and uses it when its own cache has nothing fresh. Refs #372 * docs(mcp): describe spec caching and the cache seed Refs #372 * feat(mcp): keep a running server in step with the extension's cache The seed was only written when VS Code started the server, so specs the extension cached later, and cache resets, never reached a running one. Now the extension rewrites the seed shortly after its cache changes, and the server re-reads it when the file's mtime changes, checking at most once a second. A reset is carried as clearedAt, and the server drops what it fetched before then. Refs #372 * docs(ai): fix the indentation of an ADR-372 consequence Refs #372 --------- Co-authored-by: eFAILution <eFAILution@users.noreply.github.com>
Co-authored-by: Simon Heather <simon.heather@yulife.com>
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Release PR for the next stable version. Merging to
maincuts a stable GitHub Release straight away. The Marketplace publish is a separate manualworkflow_dispatch.What is on
betafix(completion): use the referenced version's inputsfix(hover): only trust the detach command in hover markdownfeat(mcp): MCP server for AI agents to check component inputs and versionsrefactor(validation): move validation into a host-neutral core, and harden local includes, git and YAML handlingrefactor(core): host ports for config, secrets, storage, logging and the token prompt, so the core runs without VS Codedocs(readme): how to turn on and use the MCP server (the Marketplace page)chore(workflow): issue-keyed branches, PRs and decision records, with a CI check (#366)User-facing changes
New: MCP server for AI agents (#364). Copilot Chat agent mode, and other MCP clients, can call
validate_ci_file,check_component_versions,get_component_spec,list_component_versionsandlist_component_usages. They find unknown or missing inputs and outdated versions, look up the exact inputs a component version takes, and get suggested edits to apply. The server is read-only and never writes files. It ships inside the VSIX and is off by default. Turn ongitlabComponentHelper.mcp.enabled(application scope, so a workspace can't flip it). Guide:docs/mcp.md.Fixes:
@refthe include points at.command:link inside a remote component description run arbitrary VS Code commands. Only our "Open in Detailed View" link is enabled.local:includes reject..\, drive letters and UNC paths, must stay inside the repo, and must be regular files of at most 1 MB. Git calls are bounded and use a cleaned env. Git remotes with spoofed hosts are ignored.Behavior changes in the shared HTTP client:
httpTimeoutis clamped to 1–60s, and 0 means 60s.retryAttemptsis clamped to 0–5, and 0 now really means no retries.Tokens: they're trimmed when saved, and tokens with control characters are refused. Diagnostics, quick fixes, hovers and the token prompt are otherwise unchanged. The validation refactor was checked line by line, and unit tests pin every message.
Contributor workflow (#367)
No change for users. Work now starts from an issue. Branches are named
<type>/<issue>-<desc>, PRs sayCloses #<issue>, and new decisions go in.ai/decisions/ADR-<issue>.yaml. The new Decision Records workflow checks this on every PR and push tobetaandmain.AGENTS.mdholds the rules, andCLAUDE.mdjust points at it.Security
Two review rounds on the MCP server. The first found a critical issue, fixed before merge: a repo's settings could get a token sent to a lookalike host through the lossy
GCH_TOKEN_<HOST>mapping.npm audit --omit=devreports 0 vulnerabilities. The full audit reports 23 (21 high, 1 critical, 1 moderate), all in dev tooling. The one new devDependency,jsonc-parser3.3.1 (pinned), is bundled into the MCP server and has no dependencies.Soak
Not yet seen working in VS Code: the Copilot trust prompt and tools picker, protocol negotiation with VS Code's MCP client, and the server restarting after a token change.
Versioning
betais at 0.21.7. On merge,.release-it.json'srequireEvenMinorrolls this to 0.22.0 for the stable channel.Verification on
betatipbetaBefore merging
docs/mcp.mdhas prompts to try)betawith a ruleset. The last release merge deletedbetaand auto-closed open PRs targeting it.betaandmain.feat/,fix/,chore/, ...), withdependabot/,copilot/,claude/andbetaallowed.