Files
mcpctl/scripts/generate-prime-agent-extension.ts

42 lines
1.9 KiB
TypeScript
Raw Permalink Normal View History

refactor(prime-agent): extract the /mcpctl switcher to typechecked source; pi --dry-run; docs The prime-agent switcher existed only as a 275-line string literal inside prime-agent-extension.ts, so nothing typechecked or linted it — the exact gap that let a wrong ctx.ui.select() option shape ship in the pi extension. It now lives at src/prime-agent-ext/mcpctl-switch.ts with a generator, a tsconfig checking it against the real @earendil-works/pi-coding-agent types, eslint coverage and an embed-freshness test, matching pi and opencode. The extraction was verified byte-identical before any edit, so the behaviour shipped today is exactly what was captured. Linting it then found six problems in code nothing had ever checked: object-truthiness null guards, a nullable string conditional and a missing return type. All behaviour-preserving to fix, but exactly the class of thing that ships silently when nothing is looking. Also: - `config pi` gains --dry-run, the last agent without it. - The SessionStart hook installer now drops untagged duplicates of its own exact command — rows left behind before the marker existed, or by a suite that used to write into a real ~/.claude. Invisible in the UI; they just run the sync twice per session. A hook the user wrote is never touched, even one calling `mcpctl skills sync` with different flags. - docs/claude-integration.md and docs/prime-agent-extension.md, the two integrations that had no page. prime-agent deliberately keeps its per-project MCP entry name rather than the constant `mcpctl` claude and opencode now use: its switcher already unmounts the previous project, so it never accumulates entries, and re-keying auth.json from mcp:<project> to mcp:mcpctl would give up per-project token caching and needs a migration. Documented as its own change rather than folded in here. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BVwuCjuMoA13gmzYEfcrNP
2026-08-09 19:20:36 +01:00
#!/usr/bin/env node
/**
* Generates `src/cli/src/config/prime-agent-extension.ts`, which embeds the
* prime-agent `/mcpctl` switcher as a string constant the same arrangement
* the pi and opencode extensions use.
*
* The switcher used to live *only* as that string literal, with no source file
* behind it, so nothing typechecked or linted it. Now `src/prime-agent-ext/`
* holds the real source and this script produces the embed, so the file the CLI
* writes into ~/.prime/agent/extensions/ is always exactly what was checked.
*
* Regenerate after editing the extension source:
* npx tsx scripts/generate-prime-agent-extension.ts
*/
import { readFileSync, writeFileSync, mkdirSync } from 'node:fs';
import { dirname, join } from 'node:path';
const scriptsDir = import.meta.dirname;
const root = join(scriptsDir, '..');
const extDir = join(root, 'src', 'prime-agent-ext');
const SOURCE = readFileSync(join(extDir, 'mcpctl-switch.ts'), 'utf-8');
const out = `/**
* The source of the \`/mcpctl\` project-switcher extension, exported as a string
* so \`mcpctl config prime-agent\` can install it into prime-agent's auto-
* discovered extensions directory (\`~/.prime/agent/extensions/\`).
*
* DO NOT EDIT BY HAND. Generated by
* \`npx tsx scripts/generate-prime-agent-extension.ts\` from
* \`src/prime-agent-ext/mcpctl-switch.ts\` — edit that instead, so the change is
* typechecked before it ships. The installed file is this exact source
* (verbatim), so the extension the CLI writes is always the one that ran.
*/
export const MCPCTL_SWITCH_EXTENSION_FILENAME = 'mcpctl-switch.ts';
export const MCPCTL_SWITCH_EXTENSION = ${JSON.stringify(SOURCE)};
`;
mkdirSync(dirname(join(root, 'src', 'cli', 'src', 'config')), { recursive: true });
writeFileSync(join(root, 'src', 'cli', 'src', 'config', 'prime-agent-extension.ts'), out);
console.log('wrote src/cli/src/config/prime-agent-extension.ts');