mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-06 15:39:41 +02:00
Maintainer merge-time fixes for the MCP server sync (opt-in mcpSyncEnabled, synced, default OFF).
M1, parse errors echoed config text (secrets included) into the HTTP response and Settings:
smol-toml's TomlError carries a code frame of the offending lines and V8's JSON "Unexpected
token" errors quote source. Both catch sites now go through describeMcpSyncError(): a parse
failure is reported by line/column only ("not valid TOML (line 3, column 21)", "not valid
JSON"), an errno failure by Node's own message (code, syscall, path), the module's own
messages via a McpConfigError class, anything else as "unexpected error". Tests put a secret
on the broken line (TOML, both JSON message shapes, and a write refused at the re-parse that
would have quoted a copied server's env) and assert it is absent from the result and from the
route's response body; they fail against the old code.
M2, CODEX_HOME / CLAUDE_CONFIG_DIR / XDG_CONFIG_HOME were ignored, so a sync could create a
file the CLI never reads and report success: new optional registry field
capabilities.mcpConfig.relocation { envVar, path } (registry data, no id branch; schema
reuses the env-name and no-traversal path rules). Declared for claude (CLAUDE_CONFIG_DIR,
checked in the 2.1.289 binary), codex (CODEX_HOME), opencode (XDG_CONFIG_HOME) and gemini
(GEMINI_CLI_HOME, gemini-cli paths.ts); antigravity follows $HOME only (agy 1.1.12 has no
relocation var). Resolved from the server process env at call time: absolute moves the file,
empty means unset, anything else reports the target with the new status "skipped" plus the
reason and writes nothing. Dedupe is now by resolved file. When a caller overrides `home`
without passing `env`, process.env is not consulted, and the route tests clear those vars so
a CI runner's XDG_CONFIG_HOME can never aim a write outside the temp HOME.
M3, feature undocumented: CLAUDE.md Key Patterns paragraph (opt-in, admin-only, additive
only, backups, re-parse validation, 0600 for copied secrets, names-only responses with
position-only parse errors, capabilities.mcpConfig and relocation), a Settings-Reference row
in the wiki, and docs/cli-registry.md + docs/api-reference.md updated for relocation, the
"skipped" status and the error policy.
Nits:
- N1 Preview/Sync before Save: the UI remembers the saved value on open and says "Save
settings to turn MCP sync on first" instead of calling the routes; the 403 message also
says to turn it on and save.
- N2 non-admins in multi-user mode: _applyMcpSyncAdminGate() hides the whole MCP group, called
from applyMcpSyncVisibility() and the codeman:me event like the CLI-management gate.
- N3 scope chip says "synced".
- N4 "(1 servers)" pluralised; the unsupported list only names installed CLIs (route test
pins it with a per-test installed set).
- N5 McpSyncResult / McpSyncTargetResult moved to src/types/mcp-sync.ts (barrel export); only
the route imported them, so no churn.
Verified with an isolated instance (throwaway HOME, own instance and tmux socket) and
Playwright: chip, save-first message, preview rendering and the admin gate.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
42 lines
1.7 KiB
TypeScript
42 lines
1.7 KiB
TypeScript
/**
|
|
* @fileoverview Response types for MCP server sync (`GET`/`POST /api/mcp-sync`, src/mcp-sync.ts).
|
|
*
|
|
* These are returned over HTTP, so they carry server NAMES only: never env values or headers,
|
|
* and never file content (a parse failure is reported by position, see `describeMcpSyncError`).
|
|
*/
|
|
|
|
/** One participating CLI in a sync result. */
|
|
export interface McpSyncTargetResult {
|
|
id: string;
|
|
label: string;
|
|
/** The config file read (and written). For a `skipped` target, the unresolved location. */
|
|
file: string;
|
|
/**
|
|
* `absent`: not installed and no config file, so neither read nor created.
|
|
* `skipped`: the CLI's config location could not be resolved safely (e.g. its relocation env
|
|
* var is a relative path), so it is neither read nor written; `error` says why.
|
|
* `unreadable`: the file exists but cannot be parsed safely, so it is not written.
|
|
* `failed`: a read or write error (the file may be unchanged).
|
|
*/
|
|
status: 'ok' | 'absent' | 'skipped' | 'unreadable' | 'failed';
|
|
/** Why the target is not `ok`. Position or category only, never file content. */
|
|
error?: string;
|
|
servers: string[];
|
|
/** Servers added (apply) or that would be added (plan). */
|
|
added: string[];
|
|
/** Missing servers this dialect cannot express. */
|
|
skipped: string[];
|
|
}
|
|
|
|
/** The `data` of `GET`/`POST /api/mcp-sync`. */
|
|
export interface McpSyncResult {
|
|
applied: boolean;
|
|
targets: McpSyncTargetResult[];
|
|
/** Names defined differently by different CLIs; existing definitions are left untouched. */
|
|
conflicts: string[];
|
|
/** Names left out because the only definitions are switched off in their own CLI. */
|
|
disabled: string[];
|
|
/** Installed, enabled agent CLIs with no known MCP config file, so sync cannot touch them. */
|
|
unsupported: string[];
|
|
}
|