feat: add GitHub Copilot and VS Code integrations - #71
AntonioLujanoLuna wants to merge 2 commits into
Conversation
Add `copilot` as a `zg install` / `zg uninstall` target so GitHub Copilot
joins Codex, Claude Code, Qwen Code, Qoder, OpenCode, and Cursor as a
supported agent.
The installer manages the user-level Copilot configuration under
`${COPILOT_HOME:-~/.copilot}`:
- `mcp-config.json` receives a managed `zvec_grep` entry under `mcpServers`,
using `type: "local"` (`zg server --stdio`) for stdio transport and
`type: "http"` with an optional `Authorization` header for HTTP transport.
- `copilot-instructions.md` receives the existing zvec-grep search-routing
guidance inside the standard `ZVEC_GREP_START`/`ZVEC_GREP_END` markers,
so Copilot learns when to prefer semantic search over native grep.
The managed entry sets `tools` to `["*"]` so the server-side `--mcp-toolset`
selection stays the single place that decides which tools are exposed;
pinning a tool list here would silently truncate `--mcp-toolset full`.
Both files reuse the existing JSON MCP and marked-block machinery, so
unrelated MCP servers, unrelated instructions, and unmanaged `zvec_grep`
entries are preserved, `--force` is still required to replace an unmanaged
entry, and uninstall removes only zvec-grep-owned state.
Copilot CLI and the VS Code agent host both read this user-level
`mcp-config.json`, so one install covers both. The Copilot cloud coding
agent and code review use separate repository-level configuration and are
out of scope here.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YPkQZNkK72inHZobHhrCrd
Add `vscode` as a `zg install` / `zg uninstall` target. The `copilot` target
covers Copilot CLI and Agent Host, which read `~/.copilot/mcp-config.json`
natively, but not VS Code's own agent mode: VS Code keeps its servers in
`mcp.json` and forwards them to Agent Host.
The installer manages the `mcp.json` of the default VS Code user profile, so
the server is available across every workspace. The profile directory is
resolved the way VS Code resolves it: `VSCODE_PORTABLE`, then `VSCODE_APPDATA`,
then the per-platform application data directory, with `VSCODE_USER_DIR`
available to point at another profile, Insiders, or a derivative.
VS Code validates `servers` entries with `additionalProperties: false`, so the
managed entry carries only fields from its stdio and HTTP schemas — no timeout
or tool allowlist, unlike the Copilot CLI entry. An HTTP token is referenced as
`${env:NAME}` rather than `${input:NAME}` so the entry stays forwardable to
Agent Host, which drops servers that need interactive input.
Search guidance goes to
`${COPILOT_HOME:-~/.copilot}/instructions/zvec-grep.instructions.md`, the
harness-agnostic user instructions folder VS Code and Agent Host both read,
with the `applyTo: '**'` frontmatter that makes VS Code apply it automatically.
Uninstall removes the managed block and deletes the file when nothing else
remains in it.
The JSONC MCP helpers now take a container key so VS Code's `servers` object
reuses the comment-preserving machinery that Qoder uses for `mcpServers`.
Auto-target tests pin `VSCODE_USER_DIR` at a missing path so a VS Code profile
on the developer's own machine cannot be detected by them.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YPkQZNkK72inHZobHhrCrd
There was a problem hiding this comment.
Superseded by the English inline review. The original inline comments were deleted.
egolearner
left a comment
There was a problem hiding this comment.
Inline findings from a static review. No local build or tests were run.
| id: "vscode", | ||
| aliases: ["vs-code", "code"], | ||
| label: "VS Code", | ||
| executables: ["code", "code-insiders"], |
There was a problem hiding this comment.
[P1] Auto-detection treats code-insiders as the vscode target, but the default path resolver always writes Code/User/mcp.json. On a machine with only Insiders installed, zg install --yes reports success while creating a Stable-profile configuration that Insiders never reads. Please carry the detected product/channel into path resolution (or stop auto-detecting Insiders as the default Stable target) and add an auto-install test with only code-insiders available.
| const configPath = resolveVsCodeMcpConfigPath(); | ||
| const guidancePath = resolveVsCodeGuidancePath(); | ||
|
|
||
| await updateJsoncMcpSettings({ |
There was a problem hiding this comment.
[P1] The reused parseJsoncSettings() still parses with allowTrailingComma: false, whereas VS Code's mcp.json schema explicitly allows trailing commas. An existing, valid mcp.json with a trailing comma therefore makes both install and uninstall fail with Invalid VS Code configuration, instead of preserving the user's JSONC. Please allow trailing commas for the VS Code path without changing other hosts' parsing semantics, and cover install/uninstall with comments and trailing commas. See the VS Code schema.
| options: InstallAgentOptions, | ||
| ): Promise<InstallAgentResult> { | ||
| const configPath = resolveVsCodeMcpConfigPath(); | ||
| const guidancePath = resolveVsCodeGuidancePath(); |
There was a problem hiding this comment.
[P1] This ~/.copilot/instructions file is also read by standalone Copilot CLI, while the vscode target configures only VS Code's mcp.json. Installing vscode alone, or uninstalling copilot while keeping vscode, leaves the CLI with instructions to call zvec_grep_search but no corresponding CLI MCP entry. Please handle this cross-target lifecycle so the guidance only directs a host to use a tool it actually exposes, and add tests for those install/uninstall sequences.
| // VS Code reads user instructions from the harness-agnostic | ||
| // `~/.copilot/instructions` folder, so the guidance needs the frontmatter | ||
| // header before the managed block rather than a bare markdown file. | ||
| if (!(await readTextFileIfExists(guidancePath)).trim()) { |
There was a problem hiding this comment.
[P1] The required applyTo: '**' frontmatter is written only when the guidance file is empty. If zvec-grep.instructions.md already contains user text, no frontmatter, or a narrower applyTo, the managed block is appended but VS Code does not automatically apply the search guidance to all files. Please ensure the required frontmatter while preserving user content (or fail explicitly if that cannot be done safely), and test installation over a non-empty existing file.
| type: "local", | ||
| command: "zg", | ||
| args: stdioArgs(options.mcpToolset), | ||
| tools: COPILOT_MCP_TOOLS, |
There was a problem hiding this comment.
[P2] Copilot CLI supports a per-server timeout for local MCP entries and defaults to 30,000 ms, but this entry ignores the advertised --mcp-tool-timeout option (which defaults to 600 seconds in the installer). Slow tool discovery or calls can still time out after 30 seconds even when the user requests a longer limit. Please emit timeout: options.mcpToolTimeoutSeconds * 1000 and test that the option reaches the generated configuration. See the CLI MCP field reference.
|
|
||
| async function removeVsCodeGuidanceFileIfEmpty(path: string): Promise<void> { | ||
| const remaining = await readTextFileIfExists(path); | ||
| if (!remaining.trim()) return; |
There was a problem hiding this comment.
[P2] After uninstall removes the managed block, an otherwise blank guidance file returns here before unlink, leaving an empty zvec-grep.instructions.md behind. The current test only covers the case where the exact generated frontmatter remains. Please also delete a file that becomes blank (while keeping a missing file as a no-op) and cover an existing or edited guidance file on uninstall.
| ); | ||
|
|
||
| test("GitHub Copilot installer manages a user-level stdio MCP server", async (t) => { | ||
| const temporaryDirectory = await mkdtemp( |
There was a problem hiding this comment.
[P3] Duplicated Code: these new cases repeatedly copy mkdtemp, t.after(...rm...), COPILOT_HOME / VSCODE_USER_DIR setup, and target invocation across the Copilot and VS Code tests. A shared temporary-directory fixture plus small target-specific install helpers would leave each case focused on inputs and behavior assertions, and avoid synchronized edits in more than a dozen tests when setup changes.
Adds
copilotandvscodeaszg install/zg uninstalltargets, so GitHub Copilot CLI, Agent Host, and VS Code join Codex, Claude Code, Qwen Code, Qoder, OpenCode, and Cursor as supported agents.Both reuse the existing installer machinery — the JSON/JSONC MCP helpers and the
ZVEC_GREP_START/ZVEC_GREP_ENDmarked-block writer — so unrelated servers, unrelated instructions, JSONC comments, and unmanagedzvec_grepentries are preserved,--forceis still required to replace an unmanaged entry, and uninstall removes only zvec-grep-owned state.copilotManages the user-level Copilot configuration under
${COPILOT_HOME:-~/.copilot}:mcp-config.json— a managedzvec_grepentry undermcpServers,type: "local"(zg server --stdio) for stdio transport,type: "http"with an optionalAuthorizationheader for HTTP.copilot-instructions.md— the existing zvec-grep search-routing guidance, so Copilot learns when to prefer semantic search over native grep.The entry sets
toolsto["*"]so the server-side--mcp-toolsetselection stays the single place that decides which tools are exposed. Pinning a tool list here would silently truncate--mcp-toolset fulland hidezvec_grep_rg, which the installed guidance itself references.vscodeAgent Host reads
~/.copilot/mcp-config.jsonnatively, so thecopilottarget already covers it — but not VS Code's own agent mode, which keeps its servers inmcp.jsonand forwards them to Agent Host. Hence a separate target.It manages the
mcp.jsonof the default user profile, resolved the way VS Code resolves it:VSCODE_PORTABLE, thenVSCODE_APPDATA, then the per-platform application data directory.VSCODE_USER_DIRpoints at another profile, Insiders, or a derivative.Two constraints shaped the entry, and they are why it is not simply a copy of the Copilot one:
serversentries withadditionalProperties: false, so the entry carries only fields from its stdio and HTTP schemas. There is no per-server timeout or tool allowlist to manage, and--mcp-tool-timeoutdoes not apply.${env:NAME}rather than${input:NAME}, which keeps the entry forwardable to Agent Host — VS Code does not forward servers that require interactive input.Guidance goes to
${COPILOT_HOME:-~/.copilot}/instructions/zvec-grep.instructions.md, the harness-agnostic user instructions folder that VS Code, Agent Host, and Copilot CLI all read, with theapplyTo: '**'frontmatter that makes VS Code apply it automatically. Uninstall removes the managed block and deletes the file when nothing else remains in it.The two targets deliberately keep separate guidance files rather than sharing one: Copilot CLI applies
copilot-instructions.mdon every turn, while a modular.instructions.mdfile is path-scoped. Collapsing them would have weakened the CLI case. The overlap is documented indocs/01-agents.md.Supporting change
The JSONC MCP helpers now take a container key, so VS Code's
serversobject reuses the comment-preserving machinery that Qoder uses formcpServers. The default is unchanged, so existing call sites are untouched.Tests
14 new tests in
test/install.test.mjscovering, for each target: the stdio entry and guidance with unrelated configuration preserved, idempotent re-install, the HTTP entry,--mcp-toolsetpropagation,--forceagainst an unmanaged entry, uninstall leaving an unmanaged entry alone, auto-detection, and help output. VS Code additionally covers JSONC comment preservation,VSCODE_PORTABLEresolution, frontmatter ordering, user-authored guidance surviving uninstall, and a field-set assertion pinning each entry to the schema VS Code accepts.Auto-target tests now pin
VSCODE_USER_DIRat a missing path, so a VS Code profile on a contributor's own machine cannot be detected by them.Verification
npm run checkpasses end to end — lint, format, typecheck, coverage thresholds, and package tests, exit 0 with no failures.The generated
mcp.jsonwas validated against the JSON schema VS Code itself uses for MCP configuration, in both stdio and HTTP form, with a negative control confirming the schema was actually being enforced. That is schema conformance rather than a live editor session; loading the server in a real VS Code window is worth confirming by hand before release.Out of scope: the Copilot cloud coding agent and Copilot code review, which use separate repository-level MCP configuration. zvec-grep indexes a local workspace, so those hosted surfaces cannot reach it.