@ken-jo/agent-connector 0.3.1 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +180 -16
- package/dist/action-WT7GVRCC.js +55 -0
- package/dist/action-WT7GVRCC.js.map +1 -0
- package/dist/amazon-q-COAL3764.js +276 -0
- package/dist/amazon-q-COAL3764.js.map +1 -0
- package/dist/{amp-YGV66GJT.js → amp-4U33CU7E.js} +81 -5
- package/dist/amp-4U33CU7E.js.map +1 -0
- package/dist/{antigravity-7IBYFO6P.js → antigravity-AMKKKHS4.js} +4 -4
- package/dist/{antigravity-cli-JEOUP2VN.js → antigravity-cli-XERXEH5W.js} +4 -4
- package/dist/{chunk-3JCRUROU.js → chunk-24IDL5RW.js} +13 -4
- package/dist/chunk-24IDL5RW.js.map +1 -0
- package/dist/chunk-2AVLX7GH.js +351 -0
- package/dist/chunk-2AVLX7GH.js.map +1 -0
- package/dist/{chunk-GSGDG2BV.js → chunk-4ENJK5S2.js} +106 -176
- package/dist/chunk-4ENJK5S2.js.map +1 -0
- package/dist/{chunk-ZAM4M7LI.js → chunk-5OWS5CMA.js} +136 -296
- package/dist/chunk-5OWS5CMA.js.map +1 -0
- package/dist/{chunk-PD4VFEBY.js → chunk-CPLK7GTE.js} +79 -5
- package/dist/chunk-CPLK7GTE.js.map +1 -0
- package/dist/chunk-DCKFYWGM.js +237 -0
- package/dist/chunk-DCKFYWGM.js.map +1 -0
- package/dist/chunk-EGCBZ2DC.js +83 -0
- package/dist/chunk-EGCBZ2DC.js.map +1 -0
- package/dist/chunk-F5RX62T7.js +21 -0
- package/dist/chunk-F5RX62T7.js.map +1 -0
- package/dist/chunk-FAHIMJRU.js +177 -0
- package/dist/chunk-FAHIMJRU.js.map +1 -0
- package/dist/{chunk-MEH7GC7R.js → chunk-I5MLE6S7.js} +33 -3
- package/dist/chunk-I5MLE6S7.js.map +1 -0
- package/dist/{chunk-KVAAFYRR.js → chunk-KHO5WNTP.js} +2 -18
- package/dist/chunk-KHO5WNTP.js.map +1 -0
- package/dist/{chunk-KQSNDFBN.js → chunk-LQRAPXS4.js} +3 -3
- package/dist/{chunk-3RBLIHPZ.js → chunk-O5TWCIJN.js} +27 -17
- package/dist/chunk-O5TWCIJN.js.map +1 -0
- package/dist/{chunk-WNREHWKL.js → chunk-QREL7LZJ.js} +5 -4
- package/dist/chunk-QREL7LZJ.js.map +1 -0
- package/dist/{chunk-KMAKDD3Z.js → chunk-RIMVWCZY.js} +37 -12
- package/dist/chunk-RIMVWCZY.js.map +1 -0
- package/dist/{openclaw-UZ5BMCGQ.js → chunk-URHQMFB3.js} +210 -41
- package/dist/chunk-URHQMFB3.js.map +1 -0
- package/dist/chunk-WZA4CSGJ.js +28 -0
- package/dist/chunk-WZA4CSGJ.js.map +1 -0
- package/dist/chunk-XJ4S47CT.js +44 -0
- package/dist/chunk-XJ4S47CT.js.map +1 -0
- package/dist/{claude-code-4275HQU4.js → claude-code-W4PUFZL5.js} +194 -52
- package/dist/claude-code-W4PUFZL5.js.map +1 -0
- package/dist/cli/sdk.js +5 -3
- package/dist/cli/sdk.js.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/cline-WRYMNS7Z.js +442 -0
- package/dist/cline-WRYMNS7Z.js.map +1 -0
- package/dist/{codebuff-LE3KBZGM.js → codebuff-DH5Y7GAT.js} +106 -5
- package/dist/codebuff-DH5Y7GAT.js.map +1 -0
- package/dist/{codex-4BY2ZJIW.js → codex-DDHIV767.js} +43 -11
- package/dist/codex-DDHIV767.js.map +1 -0
- package/dist/continue-K43SUHLQ.js +790 -0
- package/dist/continue-K43SUHLQ.js.map +1 -0
- package/dist/{copilot-cli-IPISKO3V.js → copilot-cli-Q3SSPT4V.js} +70 -12
- package/dist/copilot-cli-Q3SSPT4V.js.map +1 -0
- package/dist/{crush-X3E25EQG.js → crush-MBEH2R3I.js} +130 -6
- package/dist/crush-MBEH2R3I.js.map +1 -0
- package/dist/{cursor-UH3W622V.js → cursor-TMBXDYR4.js} +119 -16
- package/dist/cursor-TMBXDYR4.js.map +1 -0
- package/dist/{detect-U3E7NVNW.js → detect-KG5FG3EV.js} +5 -3
- package/dist/{detect-U3E7NVNW.js.map → detect-KG5FG3EV.js.map} +1 -1
- package/dist/{doctor-DZTWED4O.js → doctor-FLZF34Y3.js} +226 -96
- package/dist/doctor-FLZF34Y3.js.map +1 -0
- package/dist/{droid-T5VBRXZF.js → droid-JC2NT6S4.js} +298 -10
- package/dist/droid-JC2NT6S4.js.map +1 -0
- package/dist/{gemini-cli-ZSUK55UA.js → gemini-cli-ILR7M5X3.js} +62 -10
- package/dist/gemini-cli-ILR7M5X3.js.map +1 -0
- package/dist/{goose-M3RR3CZG.js → goose-SFO5BBGW.js} +112 -10
- package/dist/goose-SFO5BBGW.js.map +1 -0
- package/dist/{hermes-CUNKIAR5.js → hermes-3N7WN4WS.js} +329 -15
- package/dist/hermes-3N7WN4WS.js.map +1 -0
- package/dist/{hook-EVY7LOUQ.js → hook-XR3Z45FB.js} +16 -10
- package/dist/hook-XR3Z45FB.js.map +1 -0
- package/dist/index.d.ts +71 -3
- package/dist/index.js +23 -3
- package/dist/{install-OWAS5UIE.js → install-BSR62UHJ.js} +12 -9
- package/dist/{install-OWAS5UIE.js.map → install-BSR62UHJ.js.map} +1 -1
- package/dist/introspect-Nw8hTReX.d.ts +53 -0
- package/dist/{jetbrains-copilot-C3HDGGML.js → jetbrains-copilot-NRZHI5PC.js} +85 -18
- package/dist/jetbrains-copilot-NRZHI5PC.js.map +1 -0
- package/dist/{kilo-PKAJCWPX.js → kilo-5NWOXVSD.js} +16 -16
- package/dist/kilo-5NWOXVSD.js.map +1 -0
- package/dist/{kilo-cli-QWUVXG2O.js → kilo-cli-UZ7R5UOP.js} +3 -3
- package/dist/{kimi-EVD7YKXS.js → kimi-2YFK2GBA.js} +87 -25
- package/dist/kimi-2YFK2GBA.js.map +1 -0
- package/dist/{kiro-UQRY6EIO.js → kiro-YL6AWUYG.js} +3 -3
- package/dist/{leaderboard-CSWHI4UY.js → leaderboard-MJG24O35.js} +2 -2
- package/dist/mimo-code-FTMGSKMQ.js +790 -0
- package/dist/mimo-code-FTMGSKMQ.js.map +1 -0
- package/dist/{mux-5CI5FP2W.js → mux-5XZFB44C.js} +156 -6
- package/dist/mux-5XZFB44C.js.map +1 -0
- package/dist/nemoclaw-W5KEJ3WX.js +58 -0
- package/dist/nemoclaw-W5KEJ3WX.js.map +1 -0
- package/dist/{omp-AXA7XY22.js → omp-2QMEY6HD.js} +138 -18
- package/dist/omp-2QMEY6HD.js.map +1 -0
- package/dist/openclaw-EXJEFNZI.js +18 -0
- package/dist/openclaw-EXJEFNZI.js.map +1 -0
- package/dist/{opencode-NZBRLJN3.js → opencode-WNXYJR4X.js} +84 -27
- package/dist/opencode-WNXYJR4X.js.map +1 -0
- package/dist/{package-WFOS4QVU.js → package-ACZXJHWB.js} +8 -6
- package/dist/{package-WFOS4QVU.js.map → package-ACZXJHWB.js.map} +1 -1
- package/dist/{pi-WMTUX6ES.js → pi-PVVPVWKG.js} +3 -2
- package/dist/{pi-WMTUX6ES.js.map → pi-PVVPVWKG.js.map} +1 -1
- package/dist/{qwen-code-MRRIUQ3P.js → qwen-code-G4CXKUHR.js} +426 -10
- package/dist/qwen-code-G4CXKUHR.js.map +1 -0
- package/dist/{roo-code-NI5UU6JB.js → roo-code-67TYJIQR.js} +137 -4
- package/dist/roo-code-67TYJIQR.js.map +1 -0
- package/dist/runtime/index.d.ts +96 -2
- package/dist/runtime/index.js +19 -10
- package/dist/sdk/index.d.ts +52 -0
- package/dist/sdk/index.js +82 -0
- package/dist/sdk/index.js.map +1 -0
- package/dist/sdk/test.d.ts +74 -0
- package/dist/sdk/test.js +292 -0
- package/dist/sdk/test.js.map +1 -0
- package/dist/{serve-3C2VFPAY.js → serve-GER7URPR.js} +13 -9
- package/dist/{serve-3C2VFPAY.js.map → serve-GER7URPR.js.map} +1 -1
- package/dist/{status-MKQYX5MW.js → status-LAJE3BM5.js} +10 -7
- package/dist/{status-MKQYX5MW.js.map → status-LAJE3BM5.js.map} +1 -1
- package/dist/statusline-L376ZPZU.js +60 -0
- package/dist/statusline-L376ZPZU.js.map +1 -0
- package/dist/{telemetry-3DN6XGYB.js → telemetry-B3DX3PWU.js} +6 -4
- package/dist/{telemetry-3DN6XGYB.js.map → telemetry-B3DX3PWU.js.map} +1 -1
- package/dist/{trae-CQC72RHH.js → trae-7CZZGOGI.js} +99 -5
- package/dist/trae-7CZZGOGI.js.map +1 -0
- package/dist/{types-CNigfEuR.d.ts → types-CRVrFWeU.d.ts} +322 -18
- package/dist/{uninstall-WG6PFWF3.js → uninstall-ZYTW7YMZ.js} +12 -9
- package/dist/{uninstall-WG6PFWF3.js.map → uninstall-ZYTW7YMZ.js.map} +1 -1
- package/dist/{upgrade-32NC2RKI.js → upgrade-4LUEEOZW.js} +12 -9
- package/dist/{upgrade-32NC2RKI.js.map → upgrade-4LUEEOZW.js.map} +1 -1
- package/dist/{usage-CJOM2WQM.js → usage-ZFBVQF3H.js} +2 -2
- package/dist/{usage-event-472X3DOY.js → usage-event-GZ32AGEB.js} +12 -8
- package/dist/{usage-event-472X3DOY.js.map → usage-event-GZ32AGEB.js.map} +1 -1
- package/dist/{vscode-copilot-4RVRTCKV.js → vscode-copilot-MF2CDNMT.js} +23 -10
- package/dist/vscode-copilot-MF2CDNMT.js.map +1 -0
- package/dist/{warp-X6MB67NT.js → warp-VKG55TAT.js} +55 -4
- package/dist/warp-VKG55TAT.js.map +1 -0
- package/dist/windsurf-FU5G4SHF.js +443 -0
- package/dist/windsurf-FU5G4SHF.js.map +1 -0
- package/dist/{zed-NTCYW4V2.js → zed-SFUHL3GS.js} +3 -3
- package/package.json +10 -2
- package/dist/amp-YGV66GJT.js.map +0 -1
- package/dist/chunk-3JCRUROU.js.map +0 -1
- package/dist/chunk-3RBLIHPZ.js.map +0 -1
- package/dist/chunk-GSGDG2BV.js.map +0 -1
- package/dist/chunk-KMAKDD3Z.js.map +0 -1
- package/dist/chunk-KVAAFYRR.js.map +0 -1
- package/dist/chunk-MEH7GC7R.js.map +0 -1
- package/dist/chunk-NJU275US.js +0 -238
- package/dist/chunk-NJU275US.js.map +0 -1
- package/dist/chunk-PD4VFEBY.js.map +0 -1
- package/dist/chunk-WNREHWKL.js.map +0 -1
- package/dist/chunk-ZAM4M7LI.js.map +0 -1
- package/dist/claude-code-4275HQU4.js.map +0 -1
- package/dist/codebuff-LE3KBZGM.js.map +0 -1
- package/dist/codex-4BY2ZJIW.js.map +0 -1
- package/dist/copilot-cli-IPISKO3V.js.map +0 -1
- package/dist/crush-X3E25EQG.js.map +0 -1
- package/dist/cursor-UH3W622V.js.map +0 -1
- package/dist/doctor-DZTWED4O.js.map +0 -1
- package/dist/droid-T5VBRXZF.js.map +0 -1
- package/dist/gemini-cli-ZSUK55UA.js.map +0 -1
- package/dist/goose-M3RR3CZG.js.map +0 -1
- package/dist/hermes-CUNKIAR5.js.map +0 -1
- package/dist/hook-EVY7LOUQ.js.map +0 -1
- package/dist/jetbrains-copilot-C3HDGGML.js.map +0 -1
- package/dist/kilo-PKAJCWPX.js.map +0 -1
- package/dist/kimi-EVD7YKXS.js.map +0 -1
- package/dist/mux-5CI5FP2W.js.map +0 -1
- package/dist/omp-AXA7XY22.js.map +0 -1
- package/dist/openclaw-UZ5BMCGQ.js.map +0 -1
- package/dist/opencode-NZBRLJN3.js.map +0 -1
- package/dist/qwen-code-MRRIUQ3P.js.map +0 -1
- package/dist/roo-code-NI5UU6JB.js.map +0 -1
- package/dist/trae-CQC72RHH.js.map +0 -1
- package/dist/vscode-copilot-4RVRTCKV.js.map +0 -1
- package/dist/warp-X6MB67NT.js.map +0 -1
- /package/dist/{antigravity-7IBYFO6P.js.map → antigravity-AMKKKHS4.js.map} +0 -0
- /package/dist/{antigravity-cli-JEOUP2VN.js.map → antigravity-cli-XERXEH5W.js.map} +0 -0
- /package/dist/{chunk-KQSNDFBN.js.map → chunk-LQRAPXS4.js.map} +0 -0
- /package/dist/{kilo-cli-QWUVXG2O.js.map → kilo-cli-UZ7R5UOP.js.map} +0 -0
- /package/dist/{kiro-UQRY6EIO.js.map → kiro-YL6AWUYG.js.map} +0 -0
- /package/dist/{leaderboard-CSWHI4UY.js.map → leaderboard-MJG24O35.js.map} +0 -0
- /package/dist/{usage-CJOM2WQM.js.map → usage-ZFBVQF3H.js.map} +0 -0
- /package/dist/{zed-NTCYW4V2.js.map → zed-SFUHL3GS.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/package.ts","../src/core/package-formats/claude-family.ts","../src/core/package-formats/shared.ts","../src/core/package-formats/cursor.ts","../src/core/package-formats/gemini.ts","../src/core/package-formats/agy.ts","../src/core/package-formats/kimi.ts","../src/core/package-formats/npm.ts","../src/core/package-formats/mcp-server.ts","../src/core/package-formats/mcpb.ts"],"sourcesContent":["/**\n * core/package — emit a marketplace/extension-installable connector bundle.\n *\n * Turns a {@link ResolvedConnector} into a self-contained plugin/extension bundle\n * for ANY of the emit-feasible plugin/marketplace formats the agent ecosystem\n * supports. The format-specific emitters live under `package-formats/<family>.ts`,\n * each conforming to the shared {@link FormatEmitter} signature; this module is\n * the single, consistent dispatch over them.\n *\n * Supported formats (PackageFormat):\n * • claude-plugin — Claude Code / codex / vscode-copilot / openclaw / omp\n * • codex-plugin — Codex `.codex-plugin/` manifest variant of claude-plugin\n * • factory-plugin — droid `.factory-plugin/` (droids/, mcp.json) variant\n * • gemini-extension — Gemini CLI extension (gemini-extension.json + TOML commands)\n * • qwen-extension — Qwen Code extension (qwen-extension.json + Markdown commands)\n * • agy-plugin — Antigravity CLI/IDE (root plugin.json + mcp_config.json)\n * • cursor-plugin — Cursor (.cursor-plugin/ + pointer fields + marketplace.json)\n * • kimi-plugin — Kimi (skills + MCP only; hooks/commands/subagents dropped)\n * • npm-plugin — opencode / kilo-cli / pi (publishable npm package + bridge)\n *\n * The command / skill / subagent markdown is rendered through the SAME shared\n * claude-code renderers the live adapters write with (where the target uses\n * markdown), hooks via buildHomeBinHookCommand, and MCP via buildServeWrapperCommand\n * with `--host <platform>` — so telemetry-wrap + the universal home-bin pointer\n * carry through every bundle exactly as an `agent-connector install` would.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\n\nimport type { ResolvedConnector } from \"./types.js\";\nimport { homeBinPath as defaultHomeBinPath } from \"./paths.js\";\nimport type { EmitContext, FormatEmitter, PackageResult } from \"./package-formats/shared.js\";\nimport {\n emitClaudePlugin,\n emitCodexPlugin,\n emitFactoryPlugin,\n} from \"./package-formats/claude-family.js\";\nimport { emitCursorPlugin } from \"./package-formats/cursor.js\";\nimport {\n emitGeminiExtension,\n emitQwenExtension,\n} from \"./package-formats/gemini.js\";\nimport { emitAgyPlugin } from \"./package-formats/agy.js\";\nimport { emitKimiPlugin } from \"./package-formats/kimi.js\";\nimport { emitNpmPlugin } from \"./package-formats/npm.js\";\nimport { emitMcpServerJson } from \"./package-formats/mcp-server.js\";\nimport { emitMcpbBundle } from \"./package-formats/mcpb.js\";\n\nexport type { PackageResult } from \"./package-formats/shared.js\";\n\n/** Every packaging format `package` can emit. */\nexport type PackageFormat =\n | \"claude-plugin\"\n | \"codex-plugin\"\n | \"factory-plugin\"\n | \"gemini-extension\"\n | \"qwen-extension\"\n | \"agy-plugin\"\n | \"cursor-plugin\"\n | \"kimi-plugin\"\n | \"npm-plugin\"\n // Official MCP standard artifacts (describe the dev's REAL upstream server,\n // not our serve wrapper; require `publish` metadata, so they are opt-in and\n // excluded from `--format all`).\n | \"mcp-server-json\"\n | \"mcpb\";\n\n/** The single consistent dispatch map: format → emitter. */\nconst EMITTERS: Record<PackageFormat, FormatEmitter> = {\n \"claude-plugin\": emitClaudePlugin,\n \"codex-plugin\": emitCodexPlugin,\n \"factory-plugin\": emitFactoryPlugin,\n \"gemini-extension\": emitGeminiExtension,\n \"qwen-extension\": emitQwenExtension,\n \"agy-plugin\": emitAgyPlugin,\n \"cursor-plugin\": emitCursorPlugin,\n \"kimi-plugin\": emitKimiPlugin,\n \"npm-plugin\": emitNpmPlugin,\n \"mcp-server-json\": emitMcpServerJson,\n mcpb: emitMcpbBundle,\n};\n\n/** All formats, in a stable, documented order. */\nexport const ALL_FORMATS: readonly PackageFormat[] = [\n \"claude-plugin\",\n \"codex-plugin\",\n \"factory-plugin\",\n \"gemini-extension\",\n \"qwen-extension\",\n \"agy-plugin\",\n \"cursor-plugin\",\n \"kimi-plugin\",\n \"npm-plugin\",\n \"mcp-server-json\",\n \"mcpb\",\n] as const;\n\n/**\n * The formats `--format all` emits — the host plugin/marketplace bundles that\n * work for ANY connector. The official MCP standard artifacts (mcp-server-json,\n * and the MCPB bundle) are deliberately EXCLUDED: they require `publish`\n * metadata (a namespace the dev owns, their published package) and would error\n * for a connector that has not opted into publishing, so they are emitted only\n * when requested explicitly by name.\n */\nexport const FEASIBLE_FORMATS: readonly PackageFormat[] = [\n \"claude-plugin\",\n \"codex-plugin\",\n \"factory-plugin\",\n \"gemini-extension\",\n \"qwen-extension\",\n \"agy-plugin\",\n \"cursor-plugin\",\n \"kimi-plugin\",\n \"npm-plugin\",\n] as const;\n\n/** Type guard: is `s` a supported {@link PackageFormat}? */\nexport function isPackageFormat(s: string): s is PackageFormat {\n return Object.prototype.hasOwnProperty.call(EMITTERS, s);\n}\n\nexport interface PackageOptions {\n /** Directory the bundle is written under (the format root). */\n outDir: string;\n /** Output format. Defaults to \"claude-plugin\". */\n format?: PackageFormat;\n /**\n * Absolute path to agent-connector's stable home-bin that hooks + the MCP\n * serve-wrapper point at. Defaults to {@link defaultHomeBinPath}.\n */\n homeBinPath?: string;\n /** Compute the file list without writing anything. */\n dryRun?: boolean;\n}\n\n/**\n * Emit a bundle for `connector` in a single `format` (default claude-plugin).\n *\n * Writes (or, for dryRun, only enumerates) the bundle under `opts.outDir`.\n * Returns the absolute file list, the plugin root dir, an optional marketplace\n * path, and optional drop notes (for lossy formats like kimi-plugin).\n */\n/**\n * Host-bundle formats whose hooks/MCP entries embed the ABSOLUTE home-bin path\n * of the machine that ran `package`. They install fine locally, but on another\n * machine/user the baked path points at nothing — so every emit carries a note.\n * (npm-plugin resolves the CLI by name on PATH; mcp-server-json/mcpb describe\n * the dev's real upstream server — none of those embed a local path.)\n */\nconst HOME_BIN_EMBED_FORMATS: ReadonlySet<PackageFormat> = new Set([\n \"claude-plugin\",\n \"codex-plugin\",\n \"factory-plugin\",\n \"gemini-extension\",\n \"qwen-extension\",\n \"agy-plugin\",\n \"cursor-plugin\",\n \"kimi-plugin\",\n]);\n\nexport function packageConnector(\n connector: ResolvedConnector,\n opts: PackageOptions,\n): PackageResult {\n const format = opts.format ?? \"claude-plugin\";\n const emitter = EMITTERS[format];\n if (!emitter) {\n throw new Error(`unsupported package format: ${format}`);\n }\n\n const ctx: EmitContext = {\n outDir: resolve(opts.outDir),\n homeBinPath: opts.homeBinPath ?? defaultHomeBinPath(),\n dryRun: opts.dryRun ?? false,\n };\n const result = emitter(connector, ctx);\n if (HOME_BIN_EMBED_FORMATS.has(format)) {\n const note =\n `bundle embeds this machine's agent-connector launcher path (${ctx.homeBinPath}) — ` +\n \"valid for LOCAL install; for a shared marketplace, consumers need agent-connector \" +\n \"at the same home path (run `agent-connector upgrade` there) or re-run `package` per machine\";\n result.notes = [...(result.notes ?? []), note];\n }\n return result;\n}\n\n/** One entry in a multi-format ({@link packageConnectorAll}) emit. */\nexport interface MultiPackageResult {\n format: PackageFormat;\n result: PackageResult;\n}\n\n/**\n * Emit EVERY feasible format, each into its own `<outDir>/<format>/` subdir, so a\n * single `package --format all` produces the whole matrix without collisions.\n */\nexport function packageConnectorAll(\n connector: ResolvedConnector,\n opts: { outDir: string; homeBinPath?: string; dryRun?: boolean },\n): MultiPackageResult[] {\n const base = resolve(opts.outDir);\n const homeBin = opts.homeBinPath ?? defaultHomeBinPath();\n const dryRun = opts.dryRun ?? false;\n return FEASIBLE_FORMATS.map((format) => ({\n format,\n result: packageConnector(connector, {\n outDir: resolve(base, format),\n format,\n homeBinPath: homeBin,\n dryRun,\n }),\n }));\n}\n\n/**\n * Per-format MANUAL install commands (the accurate two-step add+install where\n * applicable). Lives in core (not the CLI) so both `package`'s printed\n * instructions and the marketplace method's skip-warn records for non-drivable\n * hosts quote the SAME commands — one copy, no drift.\n */\nexport function installInstructions(\n format: PackageFormat,\n id: string,\n outDir: string,\n): string[] {\n switch (format) {\n case \"claude-plugin\":\n return [\n `/plugin marketplace add ${outDir}`,\n `/plugin install ${id}@agent-connector`,\n `(CLI: claude plugin marketplace add ${outDir} && claude plugin install ${id}@agent-connector)`,\n ];\n case \"codex-plugin\":\n return [\n `codex plugin marketplace add ${outDir}`,\n `codex plugin add ${id}@agent-connector`,\n ];\n case \"factory-plugin\":\n return [\n `droid plugin marketplace add ${outDir}`,\n `droid plugin install ${id}@agent-connector`,\n ];\n case \"gemini-extension\":\n return [`gemini extensions install ${join(outDir, id)}`];\n case \"qwen-extension\":\n return [`qwen extensions install ${join(outDir, id)}`];\n case \"agy-plugin\":\n return [\n `agy plugin install ${join(outDir, id)}`,\n `(validate: agy plugin validate ${join(outDir, id)})`,\n ];\n case \"cursor-plugin\":\n return [\n `link ${join(outDir, id)} into ~/.cursor/plugins/local/${id}/ then Developer: Reload Window`,\n `(or publish ${outDir} as a Cursor marketplace repo)`,\n ];\n case \"kimi-plugin\":\n return [`kimi plugin install ${join(outDir, id)}`];\n case \"npm-plugin\":\n return [\n `npm publish ${join(outDir, id)} (then: opencode plugin install <pkg> | kilo plugin <pkg> | pi install npm:<pkg>)`,\n ];\n case \"mcp-server-json\":\n return [\n `mcp-publisher login <github|dns|http> (prove ownership of your namespace once)`,\n `cd ${outDir} && mcp-publisher publish (uploads server.json to the official MCP Registry)`,\n ];\n case \"mcpb\":\n return [\n `vendor your built server under ${join(outDir, \"server\")}/ (see the emitted README)`,\n `npx @anthropic-ai/mcpb pack ${outDir} (then optionally: mcpb sign)`,\n ];\n default:\n return [];\n }\n}\n\n/** Read + parse a JSON file (used by callers/tests). Returns null on absence/parse error. */\nexport function readPackagedJson<T = unknown>(path: string): T | null {\n if (!existsSync(path)) return null;\n try {\n return JSON.parse(readFileSync(path, \"utf8\")) as T;\n } catch {\n return null;\n }\n}\n","/**\n * core/package-formats/claude-family — the claude-plugin emitter + its two\n * manifest-rename siblings (codex-plugin, factory-plugin).\n *\n * All three share ONE component tree (commands/ agents-or-droids/ skills/<n>/\n * SKILL.md + hooks/hooks.json + an MCP json) and differ only in:\n * • the manifest DIR + filename (.claude-plugin/ | .codex-plugin/ | .factory-plugin/)\n * • the subagent dir name (agents/ vs droids/ for factory)\n * • the MCP filename (.mcp.json vs mcp.json for factory)\n * • the manifest extra fields (claude adds $schema; factory pins version+author)\n * • the marketplace catalog shape (claude/codex object-owner; factory git-repo catalog)\n *\n * The command / skill / subagent markdown is rendered through the SAME shared\n * claude-code renderers the live adapter writes with, so an installed plugin and\n * an `agent-connector install` produce byte-identical content files. Hooks use\n * the universal home-bin command (telemetry-routed) and the MCP entry is\n * serve-wrapped with `--host <platform>` so telemetry carries through.\n */\n\nimport { join } from \"node:path\";\n\nimport type { PlatformId, ResolvedConnector } from \"../types.js\";\nimport {\n renderCommandMd,\n renderSkillMd,\n renderSubagentMd,\n} from \"../../adapters/claude-code/render.js\";\nimport {\n buildClaudeHooksJson,\n buildMcpEntry,\n createEmitter,\n json,\n resolveWithin,\n type EmitContext,\n type FormatEmitter,\n type PackageResult,\n} from \"./shared.js\";\n\n/** Per-variant layout + manifest knobs for a Claude-family bundle. */\ninterface ClaudeFamilySpec {\n /** Host platform stamped into the serve-wrapper + hook command (--host). */\n platformId: PlatformId;\n /** Manifest directory under the plugin root (e.g. \".claude-plugin\"). */\n manifestDir: string;\n /** Subagent directory name (claude/codex: \"agents\"; factory: \"droids\"). */\n subagentDir: string;\n /** MCP filename at the plugin root (claude/codex: \".mcp.json\"; factory: \"mcp.json\"). */\n mcpFile: string;\n /** Add `$schema` to plugin.json (claude only). */\n schemaUrl?: string;\n /** Always carry a version in plugin.json, defaulting placeholder to \"0.0.1\" (factory requires it). */\n requireVersion?: boolean;\n /** Always carry an `author` object in plugin.json (factory pins it). */\n alwaysAuthor?: boolean;\n /**\n * Where to write the marketplace catalog, relative to outDir, and which shape.\n * \"claude\": <outDir>/.claude-plugin/marketplace.json (object owner).\n * \"codex\": <outDir>/.agents/plugins/marketplace.json (same object-owner\n * catalog; codex's documented location — `codex plugin marketplace\n * add` REJECTS a `.codex-plugin/` catalog with \"marketplace root\n * does not contain a supported manifest\"; live-verified 0.139.0).\n * \"factory\":<outDir>/marketplace.json (git-repo catalog at the repo root).\n */\n marketplace: { dir: string | null; file: string; shape: \"claude\" | \"factory\" };\n}\n\nconst SPECS: Record<string, ClaudeFamilySpec> = {\n \"claude-plugin\": {\n platformId: \"claude-code\",\n manifestDir: \".claude-plugin\",\n subagentDir: \"agents\",\n mcpFile: \".mcp.json\",\n schemaUrl: \"https://json.schemastore.org/claude-code-plugin-manifest.json\",\n marketplace: { dir: \".claude-plugin\", file: \"marketplace.json\", shape: \"claude\" },\n },\n \"codex-plugin\": {\n platformId: \"codex\",\n manifestDir: \".codex-plugin\",\n subagentDir: \"agents\",\n mcpFile: \".mcp.json\",\n marketplace: {\n dir: join(\".agents\", \"plugins\"),\n file: \"marketplace.json\",\n shape: \"claude\",\n },\n },\n \"factory-plugin\": {\n platformId: \"droid\",\n manifestDir: \".factory-plugin\",\n subagentDir: \"droids\",\n mcpFile: \"mcp.json\",\n requireVersion: true,\n alwaysAuthor: true,\n // droid marketplaces are Git-repo catalogs; the catalog sits at the repo root.\n marketplace: { dir: null, file: \"marketplace.json\", shape: \"factory\" },\n },\n};\n\n/** Build the plugin manifest for a Claude-family variant. */\nfunction buildManifest(\n connector: ResolvedConnector,\n spec: ClaudeFamilySpec,\n): Record<string, unknown> {\n const manifest: Record<string, unknown> = {};\n if (spec.schemaUrl) manifest.$schema = spec.schemaUrl;\n manifest.name = connector.id;\n manifest.description = `${connector.displayName} — connector emitted by agent-connector`;\n\n const hasRealVersion = connector.version && connector.version !== \"0.0.0\";\n if (hasRealVersion) {\n manifest.version = connector.version;\n } else if (spec.requireVersion) {\n // factory requires a semver version; supply a sane default when unpinned.\n manifest.version = \"0.0.1\";\n }\n // Attribute the bundle to the connector developer when they declared an\n // author (publish.author); the framework name is only the fallback.\n if (spec.alwaysAuthor) {\n manifest.author = { name: connector.publish?.author?.name ?? \"agent-connector\" };\n }\n return manifest;\n}\n\n/** Build the marketplace catalog for a Claude-family variant. */\nfunction buildMarketplace(connector: ResolvedConnector): Record<string, unknown> {\n // Both the claude/codex object-owner catalog and the droid git-repo catalog\n // use the same minimal { name, owner, plugins:[{name,source,description}] }\n // shape — droid reads source as a path relative to the marketplace repo root.\n // The catalog NAME stays \"agent-connector\" (the printed install instructions\n // `<id>@agent-connector` key on it); the OWNER is the developer when known.\n return {\n name: \"agent-connector\",\n owner: { name: connector.publish?.author?.name ?? \"agent-connector\" },\n plugins: [\n {\n name: connector.id,\n source: `./${connector.id}`,\n description: `${connector.displayName} — connector emitted by agent-connector`,\n },\n ],\n };\n}\n\n/** Emit a Claude-family bundle (claude-plugin | codex-plugin | factory-plugin). */\nfunction emitClaudeFamily(\n connector: ResolvedConnector,\n ctx: EmitContext,\n format: keyof typeof SPECS,\n): PackageResult {\n const spec = SPECS[format];\n if (!spec) throw new Error(`unknown claude-family format: ${format}`);\n\n const { emit, files } = createEmitter(ctx.dryRun);\n const pluginDir = join(ctx.outDir, connector.id);\n\n // ── plugin.json (the ONLY file inside the manifest dir) ───────────────────\n emit(\n join(pluginDir, spec.manifestDir, \"plugin.json\"),\n json(buildManifest(connector, spec)),\n );\n\n // ── commands/<name>.md ────────────────────────────────────────────────────\n for (const cmd of connector.commands) {\n emit(join(pluginDir, \"commands\", `${cmd.name}.md`), renderCommandMd(cmd));\n }\n\n // ── agents|droids/<name>.md ───────────────────────────────────────────────\n for (const agent of connector.subagents) {\n emit(\n join(pluginDir, spec.subagentDir, `${agent.name}.md`),\n renderSubagentMd(agent),\n );\n }\n\n // ── skills/<name>/SKILL.md (+ resources) ──────────────────────────────────\n for (const skill of connector.skills) {\n const skillDir = join(pluginDir, \"skills\", skill.name);\n emit(join(skillDir, \"SKILL.md\"), renderSkillMd(skill));\n for (const [rel, contents] of Object.entries(skill.resources ?? {})) {\n const target = resolveWithin(skillDir, rel);\n if (target === null) continue; // never write outside the skill dir\n emit(target, contents);\n }\n }\n\n // ── hooks/hooks.json (mapped events only) ─────────────────────────────────\n const hooksJson = buildClaudeHooksJson(connector, ctx.homeBinPath, spec.platformId);\n if (hooksJson) emit(join(pluginDir, \"hooks\", \"hooks.json\"), json(hooksJson));\n\n // ── MCP json (serve-wrapped stdio server) ─────────────────────────────────\n const mcp = buildMcpEntry(connector, ctx.homeBinPath, spec.platformId);\n if (mcp) {\n emit(\n join(pluginDir, spec.mcpFile),\n json({ mcpServers: { [mcp.serverName]: mcp.entry } }),\n );\n }\n\n // ── marketplace catalog ───────────────────────────────────────────────────\n const marketplacePath = spec.marketplace.dir\n ? join(ctx.outDir, spec.marketplace.dir, spec.marketplace.file)\n : join(ctx.outDir, spec.marketplace.file);\n emit(marketplacePath, json(buildMarketplace(connector)));\n\n return { files, pluginDir, marketplacePath };\n}\n\nexport const emitClaudePlugin: FormatEmitter = (connector, ctx) =>\n emitClaudeFamily(connector, ctx, \"claude-plugin\");\n\nexport const emitCodexPlugin: FormatEmitter = (connector, ctx) =>\n emitClaudeFamily(connector, ctx, \"codex-plugin\");\n\nexport const emitFactoryPlugin: FormatEmitter = (connector, ctx) =>\n emitClaudeFamily(connector, ctx, \"factory-plugin\");\n","/**\n * core/package-formats/shared — the common emitter contract + helpers every\n * format family is built on.\n *\n * A format emitter is a pure function conforming to {@link FormatEmitter}: it\n * takes a {@link ResolvedConnector} plus an {@link EmitContext} ({outDir,\n * homeBinPath, dryRun}) and either writes the bundle (dryRun=false) or only\n * enumerates the files it WOULD write (dryRun=true), returning a\n * {@link PackageResult} ({pluginDir, files[], marketplacePath?, notes?}).\n *\n * Everything below is shared across families so each emitter file is just the\n * format-specific manifest + layout, never a re-implementation of file writing,\n * JSON serialization, traversal-safe resource placement, the home-bin hooks\n * block, or the serve-wrapper MCP entry. Reusing these keeps telemetry-wrap +\n * the universal home-bin hook command byte-identical to the live adapters.\n */\n\nimport { dirname, relative, resolve, sep } from \"node:path\";\nimport { writeFileSync } from \"node:fs\";\n\nimport type {\n HookEventName,\n PlatformId,\n ResolvedConnector,\n} from \"../types.js\";\nimport { ensureDir } from \"../paths.js\";\nimport {\n buildHomeBinHookCommand,\n buildServeWrapperCommand,\n shouldWrapForTelemetry,\n} from \"../spawn.js\";\n\n/** Inputs every format emitter receives. */\nexport interface EmitContext {\n /** Directory the bundle is written under (the format root). */\n outDir: string;\n /** Absolute path to agent-connector's stable home-bin (hooks + serve wrapper point here). */\n homeBinPath: string;\n /** Enumerate the file list without writing anything. */\n dryRun: boolean;\n}\n\n/** What every format emitter returns. */\nexport interface PackageResult {\n /** Absolute paths of every file the bundle comprises (written, or planned for dryRun). */\n files: string[];\n /** Absolute path to the plugin/extension root directory. */\n pluginDir: string;\n /** Absolute path to the emitted marketplace catalog, when the format has one. */\n marketplacePath?: string;\n /**\n * Human-readable notes about surfaces the format intentionally DROPS (e.g.\n * Kimi ignores hooks/commands/subagents). The CLI surfaces these so a lossy\n * bundle is never silent. Empty when nothing was dropped.\n */\n notes?: string[];\n}\n\n/** The shared signature every `package-formats/<family>.ts` exports. */\nexport type FormatEmitter = (\n connector: ResolvedConnector,\n ctx: EmitContext,\n) => PackageResult;\n\n/** A small file-collecting writer bound to one emit run (honors dryRun). */\nexport interface Emitter {\n /** Write `contents` to `path` (skipped under dryRun) and record it. */\n emit(path: string, contents: string): void;\n /** The accumulated absolute file list (in emit order). */\n readonly files: string[];\n}\n\n/** Build a dryRun-aware {@link Emitter} that records every (would-be) write. */\nexport function createEmitter(dryRun: boolean): Emitter {\n const files: string[] = [];\n return {\n files,\n emit(path: string, contents: string): void {\n if (!dryRun) {\n ensureDir(dirname(path));\n writeFileSync(path, contents, \"utf8\");\n }\n files.push(path);\n },\n };\n}\n\n/** Pretty-print a value as 2-space JSON with a trailing newline. */\nexport function json(value: unknown): string {\n return `${JSON.stringify(value, null, 2)}\\n`;\n}\n\n/**\n * Resolve a skill-resource relative key against `baseDir`, returning the\n * absolute target ONLY when it stays inside the dir (defense-in-depth — config\n * validation already rejects traversal, but never trust input). Null otherwise.\n */\nexport function resolveWithin(baseDir: string, rel: string): string | null {\n const base = resolve(baseDir);\n const target = resolve(base, rel);\n if (target === base) return null;\n const rind = relative(base, target);\n if (rind === \"\" || rind.startsWith(\"..\") || resolve(base, rind) !== target) {\n return null;\n }\n if (rind === \"..\" || rind.startsWith(`..${sep}`)) return null;\n return target;\n}\n\n/** Pass env through unchanged when present, else undefined (drops empty objects). */\nexport function renderEnv(\n env: Record<string, string> | undefined,\n): Record<string, string> | undefined {\n if (!env || Object.keys(env).length === 0) return undefined;\n return { ...env };\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Hooks — the Claude-shaped hooks.json block, shared by every format whose\n// hooks file mirrors Claude Code's `{ type:\"command\", command:\"<string>\" }`.\n// ─────────────────────────────────────────────────────────────────────────\n\n/** Claude event names a Claude-style plugin's hooks.json may key on. */\nexport const CLAUDE_MAPPED_EVENTS: ReadonlySet<HookEventName> =\n new Set<HookEventName>([\n \"PreToolUse\",\n \"PostToolUse\",\n \"PreCompact\",\n \"SessionStart\",\n \"SessionEnd\",\n \"UserPromptSubmit\",\n \"Stop\",\n \"Notification\",\n \"PermissionRequest\",\n \"PostToolUseFailure\",\n \"SubagentStart\",\n \"SubagentStop\",\n ]);\n\n/** A single hooks.json entry (identical in shape to a settings.json hooks block). */\nexport interface PluginHookEntry {\n matcher?: string;\n hooks: Array<{ type: \"command\"; command: string }>;\n}\n\n/**\n * Build the Claude-shaped hooks.json body for the MAPPED events the connector\n * declares. Each command is the SAME single-string home-bin form the live\n * adapters write (via buildHomeBinHookCommand). `platformId` lets a format point\n * the hook at the right host (e.g. \"cursor\", \"claude-code\"). Returns null when\n * the connector declares no mapped events.\n */\nexport function buildClaudeHooksJson(\n connector: ResolvedConnector,\n homeBin: string,\n platformId: PlatformId,\n): { hooks: Record<string, PluginHookEntry[]> } | null {\n const events = connector.hookEvents.filter((e) => CLAUDE_MAPPED_EVENTS.has(e));\n if (events.length === 0) return null;\n\n const hooks: Record<string, PluginHookEntry[]> = {};\n for (const event of events) {\n const matcher = connector.hooks[event]?.matcher ?? \"\";\n const command = {\n type: \"command\" as const,\n command: buildHomeBinHookCommand(homeBin, platformId, event, connector.id),\n };\n hooks[event] = [matcher ? { matcher, hooks: [command] } : { hooks: [command] }];\n }\n return { hooks };\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// MCP — the serve-wrapped stdio server entry, shared by every format whose MCP\n// file carries a launchable { command, args, env?, cwd? } (the Claude .mcp.json\n// dialect). Remote/non-stdio servers are out of scope for a launchable bundle.\n// ─────────────────────────────────────────────────────────────────────────\n\n/** Native MCP server entry shape a Claude-dialect mcpServers map accepts. */\nexport interface PluginMcpEntry {\n command: string;\n args: string[];\n env?: Record<string, string>;\n cwd?: string;\n}\n\n/**\n * Render the connector's ServerDef into a serve-wrapped MCP entry for\n * `platformId`, so per-tool telemetry carries through the bundle exactly as the\n * live adapter's install does. Returns null when there is no stdio command to\n * launch (remote / server-less connectors). The returned `serverName` is the\n * connector id (the conventional single-server key).\n */\nexport function buildMcpEntry(\n connector: ResolvedConnector,\n homeBin: string,\n platformId: PlatformId,\n): { serverName: string; entry: PluginMcpEntry } | null {\n const server = connector.server;\n if (!server) return null;\n // A launchable bundle entry can only carry stdio servers; remote (http/sse/ws)\n // servers register a URL elsewhere, out of scope for the bundled plugin.\n if (server.transport !== \"stdio\") return null;\n\n const realCommand = server.command ?? \"\";\n if (realCommand === \"\") return null;\n const realArgs = [...(server.args ?? [])];\n\n let entry: PluginMcpEntry;\n if (shouldWrapForTelemetry(server, connector.telemetry)) {\n const wrapped = buildServeWrapperCommand(\n homeBin,\n connector.id,\n realCommand,\n realArgs,\n undefined,\n platformId,\n );\n entry = { command: wrapped.command, args: wrapped.args };\n } else {\n entry = { command: realCommand, args: realArgs };\n }\n\n const env = renderEnv(server.env);\n if (env) entry.env = env;\n if (server.cwd) entry.cwd = server.cwd;\n\n return { serverName: connector.id, entry };\n}\n","/**\n * core/package-formats/cursor — the `cursor-plugin` emitter.\n *\n * Cursor's bundle is near-isomorphic to claude-plugin: manifest at\n * `.cursor-plugin/plugin.json` (only `name` required) with the surface fields\n * declared as POINTERS (\"skills\":\"./skills/\", \"hooks\":\"./hooks/hooks.json\",\n * \"mcpServers\":\"./mcp.json\") so a validator/IDE finds each dir; components live\n * at the plugin root: commands/<n>.md, agents/<n>.md, skills/<n>/SKILL.md,\n * mcp.json, hooks/hooks.json. A multi-plugin repo adds .cursor-plugin/\n * marketplace.json { name, owner:{name,email?}, plugins:[{name,source,description}] }.\n *\n * Markdown reuses the shared claude-code renderers (Cursor reads the same md +\n * frontmatter command/agent/skill documents). Hooks + MCP use the shared\n * builders with --host cursor so the home-bin hook + serve-wrapper telemetry\n * carry through.\n *\n * (Cursor also supports `rules/*.mdc`, but a connector declares no rules surface,\n * so no rules/ dir is emitted and the manifest omits the `rules` pointer.)\n */\n\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nimport type { PlatformId, ResolvedConnector } from \"../types.js\";\nimport {\n renderCommandMd,\n renderSkillMd,\n renderSubagentMd,\n} from \"../../adapters/claude-code/render.js\";\nimport {\n buildClaudeHooksJson,\n buildMcpEntry,\n createEmitter,\n json,\n resolveWithin,\n type EmitContext,\n type FormatEmitter,\n type PackageResult,\n} from \"./shared.js\";\n\nconst PLATFORM: PlatformId = \"cursor\";\n\n/** Build .cursor-plugin/plugin.json with pointer surface fields for what exists. */\nfunction buildManifest(\n connector: ResolvedConnector,\n has: { commands: boolean; agents: boolean; skills: boolean; hooks: boolean; mcp: boolean },\n): Record<string, unknown> {\n const manifest: Record<string, unknown> = {\n name: connector.id,\n description: `${connector.displayName} — connector emitted by agent-connector`,\n };\n if (connector.version && connector.version !== \"0.0.0\") {\n manifest.version = connector.version;\n }\n // Pointer fields: only declare a surface that actually ships in the bundle.\n if (has.commands) manifest.commands = \"./commands/\";\n if (has.agents) manifest.agents = \"./agents/\";\n if (has.skills) manifest.skills = \"./skills/\";\n if (has.hooks) manifest.hooks = \"./hooks/hooks.json\";\n if (has.mcp) manifest.mcpServers = \"./mcp.json\";\n return manifest;\n}\n\n/** Build .cursor-plugin/marketplace.json (owner object carries name; email optional). */\nfunction buildMarketplace(connector: ResolvedConnector): Record<string, unknown> {\n // Catalog NAME stays \"agent-connector\" (install instructions key on it); the\n // OWNER is the connector developer when publish.author is declared.\n return {\n name: \"agent-connector\",\n owner: { name: connector.publish?.author?.name ?? \"agent-connector\" },\n plugins: [\n {\n name: connector.id,\n source: `./${connector.id}`,\n description: `${connector.displayName} — connector emitted by agent-connector`,\n },\n ],\n };\n}\n\nexport const emitCursorPlugin: FormatEmitter = (\n connector: ResolvedConnector,\n ctx: EmitContext,\n): PackageResult => {\n const { emit, files } = createEmitter(ctx.dryRun);\n const pluginDir = join(ctx.outDir, connector.id);\n\n const hooksJson = buildClaudeHooksJson(connector, ctx.homeBinPath, PLATFORM);\n const mcp = buildMcpEntry(connector, ctx.homeBinPath, PLATFORM);\n\n const has = {\n commands: connector.commands.length > 0,\n agents: connector.subagents.length > 0,\n skills: connector.skills.length > 0,\n hooks: hooksJson !== null,\n mcp: mcp !== null,\n };\n\n // ── .cursor-plugin/plugin.json (ONLY file under .cursor-plugin/) ───────────\n emit(\n join(pluginDir, \".cursor-plugin\", \"plugin.json\"),\n json(buildManifest(connector, has)),\n );\n\n // ── commands/<name>.md ────────────────────────────────────────────────────\n for (const cmd of connector.commands) {\n emit(join(pluginDir, \"commands\", `${cmd.name}.md`), renderCommandMd(cmd));\n }\n\n // ── agents/<name>.md ──────────────────────────────────────────────────────\n for (const agent of connector.subagents) {\n emit(join(pluginDir, \"agents\", `${agent.name}.md`), renderSubagentMd(agent));\n }\n\n // ── skills/<name>/SKILL.md (+ resources) ──────────────────────────────────\n for (const skill of connector.skills) {\n const skillDir = join(pluginDir, \"skills\", skill.name);\n emit(join(skillDir, \"SKILL.md\"), renderSkillMd(skill));\n for (const [rel, contents] of Object.entries(skill.resources ?? {})) {\n const target = resolveWithin(skillDir, rel);\n if (target === null) continue;\n emit(target, contents);\n }\n }\n\n // ── hooks/hooks.json ──────────────────────────────────────────────────────\n if (hooksJson) emit(join(pluginDir, \"hooks\", \"hooks.json\"), json(hooksJson));\n\n // ── mcp.json (Cursor's MCP filename, no leading dot) ──────────────────────\n if (mcp) {\n emit(\n join(pluginDir, \"mcp.json\"),\n json({ mcpServers: { [mcp.serverName]: mcp.entry } }),\n );\n }\n\n // ── .cursor-plugin/marketplace.json ───────────────────────────────────────\n const marketplacePath = join(ctx.outDir, \".cursor-plugin\", \"marketplace.json\");\n emit(marketplacePath, json(buildMarketplace(connector)));\n\n return { files, pluginDir, marketplacePath };\n};\n\n/** True when a local install of this plugin already exists (used by the CLI hint). */\nexport function cursorLocalInstallExists(name: string, home: string): boolean {\n return existsSync(join(home, \".cursor\", \"plugins\", \"local\", name));\n}\n","/**\n * core/package-formats/gemini — the `gemini-extension` emitter + its `qwen-extension`\n * variant.\n *\n * A Gemini CLI extension is a directory with `gemini-extension.json` at its root\n * carrying `{ name, version, description, mcpServers, contextFileName }` plus the\n * component dirs: commands/<n>.toml (slash commands), skills/<n>/SKILL.md,\n * agents/<n>.md, hooks/hooks.json, and a GEMINI.md context file. UNLIKE the\n * Claude family, MCP is declared INLINE in the manifest's `mcpServers` map (not a\n * separate .mcp.json) — we still serve-wrap it so telemetry carries through.\n *\n * Qwen Code is a Gemini-CLI fork with its own `qwen-extension.json` (same shape)\n * but two differences captured here: commands are MARKDOWN (commands/<n>.md) not\n * TOML, and the context file is QWEN.md.\n *\n * Commands render to Gemini's native TOML `{ description, prompt }` (the same\n * shape the live gemini-cli adapter writes); skills/subagents reuse the shared\n * claude-code renderers (Gemini/Qwen read the same SKILL.md + md+frontmatter).\n * Hooks use the universal home-bin command; the MCP entry is serve-wrapped with\n * --host gemini-cli | qwen-code.\n */\n\nimport { join } from \"node:path\";\n\nimport type { CommandDef, PlatformId, ResolvedConnector } from \"../types.js\";\nimport { writeTomlString } from \"../toml.js\";\nimport {\n renderCommandMd,\n renderSkillMd,\n renderSubagentMd,\n} from \"../../adapters/claude-code/render.js\";\nimport {\n buildClaudeHooksJson,\n buildMcpEntry,\n createEmitter,\n json,\n resolveWithin,\n type EmitContext,\n type FormatEmitter,\n type PackageResult,\n} from \"./shared.js\";\n\n/** Per-variant knobs for a Gemini-family extension. */\ninterface GeminiFamilySpec {\n platformId: PlatformId;\n /** Manifest filename at the extension root. */\n manifestFile: string;\n /** Context file name (GEMINI.md | QWEN.md). */\n contextFile: string;\n /** Command file format: TOML (gemini) or Markdown (qwen). */\n commandFormat: \"toml\" | \"md\";\n}\n\nconst SPECS: Record<string, GeminiFamilySpec> = {\n \"gemini-extension\": {\n platformId: \"gemini-cli\",\n manifestFile: \"gemini-extension.json\",\n contextFile: \"GEMINI.md\",\n commandFormat: \"toml\",\n },\n \"qwen-extension\": {\n platformId: \"qwen-code\",\n manifestFile: \"qwen-extension.json\",\n contextFile: \"QWEN.md\",\n commandFormat: \"md\",\n },\n};\n\n/** Render a command to Gemini's native TOML `{ description, prompt }`. */\nfunction renderCommandToml(cmd: CommandDef): string {\n const obj: Record<string, unknown> = {};\n if (cmd.description !== undefined) obj.description = cmd.description;\n obj.prompt = cmd.prompt;\n return writeTomlString(obj);\n}\n\n/** Build gemini-extension.json | qwen-extension.json (with optional inline mcpServers). */\nfunction buildManifest(\n connector: ResolvedConnector,\n spec: GeminiFamilySpec,\n homeBin: string,\n): Record<string, unknown> {\n const manifest: Record<string, unknown> = {\n name: connector.id,\n // gemini requires a version; default a placeholder to a real semver.\n version:\n connector.version && connector.version !== \"0.0.0\"\n ? connector.version\n : \"0.0.1\",\n description: `${connector.displayName} — connector emitted by agent-connector`,\n };\n\n const mcp = buildMcpEntry(connector, homeBin, spec.platformId);\n if (mcp) {\n manifest.mcpServers = { [mcp.serverName]: mcp.entry };\n }\n manifest.contextFileName = spec.contextFile;\n return manifest;\n}\n\nfunction emitGeminiFamily(\n connector: ResolvedConnector,\n ctx: EmitContext,\n format: keyof typeof SPECS,\n): PackageResult {\n const spec = SPECS[format];\n if (!spec) throw new Error(`unknown gemini-family format: ${format}`);\n\n const { emit, files } = createEmitter(ctx.dryRun);\n const pluginDir = join(ctx.outDir, connector.id);\n\n // ── gemini-extension.json | qwen-extension.json (MCP is inline here) ──────\n emit(\n join(pluginDir, spec.manifestFile),\n json(buildManifest(connector, spec, ctx.homeBinPath)),\n );\n\n // ── context file (GEMINI.md | QWEN.md) ────────────────────────────────────\n emit(\n join(pluginDir, spec.contextFile),\n `# ${connector.displayName}\\n\\nConnector context emitted by agent-connector.\\n`,\n );\n\n // ── commands/<name>.{toml|md} ─────────────────────────────────────────────\n for (const cmd of connector.commands) {\n if (spec.commandFormat === \"toml\") {\n emit(join(pluginDir, \"commands\", `${cmd.name}.toml`), renderCommandToml(cmd));\n } else {\n emit(join(pluginDir, \"commands\", `${cmd.name}.md`), renderCommandMd(cmd));\n }\n }\n\n // ── agents/<name>.md ──────────────────────────────────────────────────────\n for (const agent of connector.subagents) {\n emit(join(pluginDir, \"agents\", `${agent.name}.md`), renderSubagentMd(agent));\n }\n\n // ── skills/<name>/SKILL.md (+ resources) ──────────────────────────────────\n for (const skill of connector.skills) {\n const skillDir = join(pluginDir, \"skills\", skill.name);\n emit(join(skillDir, \"SKILL.md\"), renderSkillMd(skill));\n for (const [rel, contents] of Object.entries(skill.resources ?? {})) {\n const target = resolveWithin(skillDir, rel);\n if (target === null) continue;\n emit(target, contents);\n }\n }\n\n // ── hooks/hooks.json ──────────────────────────────────────────────────────\n const hooksJson = buildClaudeHooksJson(connector, ctx.homeBinPath, spec.platformId);\n if (hooksJson) emit(join(pluginDir, \"hooks\", \"hooks.json\"), json(hooksJson));\n\n // A Gemini/Qwen extension has no separate marketplace catalog (it installs by\n // URL/path); marketplacePath is left undefined.\n return { files, pluginDir };\n}\n\nexport const emitGeminiExtension: FormatEmitter = (connector, ctx) =>\n emitGeminiFamily(connector, ctx, \"gemini-extension\");\n\nexport const emitQwenExtension: FormatEmitter = (connector, ctx) =>\n emitGeminiFamily(connector, ctx, \"qwen-extension\");\n","/**\n * core/package-formats/agy — the `agy plugin` bundle emitter (Antigravity CLI +\n * Antigravity IDE, which share the bundle).\n *\n * Live-confirmed layout (`agy plugin validate`):\n * • REQUIRED root `plugin.json` marker { name, version, description } — its\n * absence is the one hard error the validator reports.\n * • MCP MUST be a SEPARATE `mcp_config.json` { mcpServers:{...} } — an inline\n * `mcpServers` in plugin.json is NOT picked up. (This is the one structural\n * difference from the Claude family.)\n * • hooks.json at the BUNDLE ROOT keyed { hooks:{ <Event>:[{matcher,hooks:[{type,command}]}] } }\n * — agy 1.0.7 NEVER reads hooks/hooks.json: validate+install report\n * \"hooks: skipped (not found)\" and copy the file unprocessed. The root\n * location was fix-proven live (\"hooks: 1 processed\", components +hooks).\n * • skills/<n>/SKILL.md, agents/<n>.md, commands/<n>.md (commands are converted\n * to skills on validate — still emitted as Markdown command files).\n *\n * Markdown reuses the shared claude-code renderers; hooks use the universal\n * home-bin command; the MCP entry is serve-wrapped with --host antigravity-cli so\n * telemetry carries through. No marketplace catalog ships in the bundle (agy\n * installs by target / plugin@marketplace).\n */\n\nimport { join } from \"node:path\";\n\nimport type { PlatformId, ResolvedConnector } from \"../types.js\";\nimport {\n renderCommandMd,\n renderSkillMd,\n renderSubagentMd,\n} from \"../../adapters/claude-code/render.js\";\nimport {\n buildClaudeHooksJson,\n buildMcpEntry,\n createEmitter,\n json,\n resolveWithin,\n type EmitContext,\n type FormatEmitter,\n type PackageResult,\n} from \"./shared.js\";\n\nconst PLATFORM: PlatformId = \"antigravity-cli\";\n\n/** Build the required root plugin.json marker. */\nfunction buildManifest(connector: ResolvedConnector): Record<string, unknown> {\n return {\n name: connector.id,\n // agy expects a version on the marker; default a placeholder to a real semver.\n version:\n connector.version && connector.version !== \"0.0.0\"\n ? connector.version\n : \"0.0.1\",\n description: `${connector.displayName} — connector emitted by agent-connector`,\n };\n}\n\nexport const emitAgyPlugin: FormatEmitter = (\n connector: ResolvedConnector,\n ctx: EmitContext,\n): PackageResult => {\n const { emit, files } = createEmitter(ctx.dryRun);\n const pluginDir = join(ctx.outDir, connector.id);\n\n // ── plugin.json (REQUIRED root marker) ────────────────────────────────────\n emit(join(pluginDir, \"plugin.json\"), json(buildManifest(connector)));\n\n // ── commands/<name>.md (validator converts these to skills) ───────────────\n for (const cmd of connector.commands) {\n emit(join(pluginDir, \"commands\", `${cmd.name}.md`), renderCommandMd(cmd));\n }\n\n // ── agents/<name>.md ──────────────────────────────────────────────────────\n for (const agent of connector.subagents) {\n emit(join(pluginDir, \"agents\", `${agent.name}.md`), renderSubagentMd(agent));\n }\n\n // ── skills/<name>/SKILL.md (+ resources) ──────────────────────────────────\n for (const skill of connector.skills) {\n const skillDir = join(pluginDir, \"skills\", skill.name);\n emit(join(skillDir, \"SKILL.md\"), renderSkillMd(skill));\n for (const [rel, contents] of Object.entries(skill.resources ?? {})) {\n const target = resolveWithin(skillDir, rel);\n if (target === null) continue;\n emit(target, contents);\n }\n }\n\n // ── hooks.json (bundle ROOT — agy silently ignores hooks/hooks.json) ──────\n const hooksJson = buildClaudeHooksJson(connector, ctx.homeBinPath, PLATFORM);\n if (hooksJson) emit(join(pluginDir, \"hooks.json\"), json(hooksJson));\n\n // ── mcp_config.json (SEPARATE file — inline mcpServers is NOT read by agy) ─\n const mcp = buildMcpEntry(connector, ctx.homeBinPath, PLATFORM);\n if (mcp) {\n emit(\n join(pluginDir, \"mcp_config.json\"),\n json({ mcpServers: { [mcp.serverName]: mcp.entry } }),\n );\n }\n\n return { files, pluginDir };\n};\n","/**\n * core/package-formats/kimi — the `kimi-plugin` emitter (skills + MCP ONLY).\n *\n * A Kimi plugin is a directory whose manifest is `kimi.plugin.json` at the root\n * carrying { name, version, description, skills, mcpServers }. Kimi plugins carry\n * exactly TWO functional surfaces:\n * • skills/<n>/SKILL.md (declared via the `skills` pointer)\n * • mcpServers (a standard MCP map, stdio + http)\n *\n * Kimi EXPLICITLY ignores `tools`, `commands`, `hooks`, `apps`, `inject`,\n * `configFile` (they surface as diagnostics). So when the connector declares\n * commands, subagents, or hooks, those surfaces are DROPPED — and a note is\n * returned so the lossy bundle is never silent. The MCP entry is still\n * serve-wrapped with --host kimi so telemetry carries through; hooks are NOT\n * emitted because Kimi has no hooks surface.\n */\n\nimport { join } from \"node:path\";\n\nimport type { PlatformId, ResolvedConnector } from \"../types.js\";\nimport { renderSkillMd } from \"../../adapters/claude-code/render.js\";\nimport {\n buildMcpEntry,\n createEmitter,\n json,\n resolveWithin,\n type EmitContext,\n type FormatEmitter,\n type PackageResult,\n} from \"./shared.js\";\n\nconst PLATFORM: PlatformId = \"kimi\";\n\n/** Build kimi.plugin.json (skills pointer + inline mcpServers when present). */\nfunction buildManifest(\n connector: ResolvedConnector,\n hasSkills: boolean,\n homeBin: string,\n): Record<string, unknown> {\n const manifest: Record<string, unknown> = {\n name: connector.id,\n version:\n connector.version && connector.version !== \"0.0.0\"\n ? connector.version\n : \"0.0.1\",\n description: `${connector.displayName} — connector emitted by agent-connector`,\n };\n if (hasSkills) manifest.skills = \"./skills/\";\n const mcp = buildMcpEntry(connector, homeBin, PLATFORM);\n if (mcp) manifest.mcpServers = { [mcp.serverName]: mcp.entry };\n return manifest;\n}\n\nexport const emitKimiPlugin: FormatEmitter = (\n connector: ResolvedConnector,\n ctx: EmitContext,\n): PackageResult => {\n const { emit, files } = createEmitter(ctx.dryRun);\n const pluginDir = join(ctx.outDir, connector.id);\n const notes: string[] = [];\n\n const hasSkills = connector.skills.length > 0;\n\n // ── kimi.plugin.json (root manifest; MCP inline; hooks/commands ignored) ──\n emit(join(pluginDir, \"kimi.plugin.json\"), json(buildManifest(connector, hasSkills, ctx.homeBinPath)));\n\n // ── skills/<name>/SKILL.md (+ resources) ──────────────────────────────────\n for (const skill of connector.skills) {\n const skillDir = join(pluginDir, \"skills\", skill.name);\n emit(join(skillDir, \"SKILL.md\"), renderSkillMd(skill));\n for (const [rel, contents] of Object.entries(skill.resources ?? {})) {\n const target = resolveWithin(skillDir, rel);\n if (target === null) continue;\n emit(target, contents);\n }\n }\n\n // ── Surfaces Kimi cannot carry → DROPPED, with an explicit note ───────────\n if (connector.commands.length > 0) {\n notes.push(\n `kimi-plugin: dropped ${connector.commands.length} command(s) — Kimi plugins ignore commands`,\n );\n }\n if (connector.subagents.length > 0) {\n notes.push(\n `kimi-plugin: dropped ${connector.subagents.length} subagent(s) — Kimi plugins ignore subagents`,\n );\n }\n if (connector.hookEvents.length > 0) {\n notes.push(\n `kimi-plugin: dropped ${connector.hookEvents.length} hook event(s) — Kimi plugins ignore hooks`,\n );\n }\n\n return { files, pluginDir, ...(notes.length > 0 ? { notes } : {}) };\n};\n","/**\n * core/package-formats/npm — the `npm-plugin` emitter (opencode + kilo-cli + pi).\n *\n * This is the one genuinely NET-NEW artifact: a publishable npm package whose\n * default export is a plugin module. It is emitted ONLY in its clean form — a\n * real package.json + a self-contained ESM `index.js` bridge — never a\n * half-baked stub. The surface limit (documented, and returned as notes) is\n * inherent to the opencode/kilo plugin contract: ONLY hook code rides inside the\n * npm package; commands/skills/subagents are native host dirs and MCP is a\n * config key, so they do NOT ride inside the published module.\n *\n * Layout:\n * <outDir>/<id>/\n * ├── package.json (type:module, exports \".\", keywords incl. \"opencode-plugin\"\n * │ + \"pi-package\", engines.node)\n * ├── index.js (default-export plugin fn; bridges each declared hook event\n * │ to `<homeBin> hook opencode <event> --connector <id>`)\n * ├── skills/<n>/SKILL.md (pi packages DO bundle skills; opencode ignores them)\n * └── README.md\n *\n * The bridge shells out to the ONE stable home binary over child_process, so the\n * SAME universal json-stdio dispatcher every other host uses serves the npm host\n * too — and telemetry continues to flow through the home-bin. (MCP wrapping is\n * NOT inlined here: opencode's MCP is the opencode.json \"mcp\" key, out of band\n * for the npm package; a note records this.)\n */\n\nimport { join } from \"node:path\";\n\nimport type { HookEventName, ResolvedConnector } from \"../types.js\";\nimport { renderSkillMd } from \"../../adapters/claude-code/render.js\";\nimport {\n createEmitter,\n json,\n resolveWithin,\n type EmitContext,\n type FormatEmitter,\n type PackageResult,\n} from \"./shared.js\";\n\n/** OpenCode event keys this connector can bridge (PreToolUse/PostToolUse/SessionStart). */\nconst EVENT_TO_OPENCODE: Partial<Record<HookEventName, string>> = {\n PreToolUse: \"tool.execute.before\",\n PostToolUse: \"tool.execute.after\",\n SessionStart: \"experimental.chat.system.transform\",\n};\n\n/** Build the publishable package.json for an opencode/kilo/pi plugin package. */\nfunction buildPackageJson(connector: ResolvedConnector): Record<string, unknown> {\n // Use an opencode- name prefix (the discovery-confirmed convention) so the\n // package is discoverable; keywords cover opencode + pi-package.\n const pkgName = connector.id.startsWith(\"opencode-\")\n ? connector.id\n : `opencode-${connector.id}`;\n const version =\n connector.version && connector.version !== \"0.0.0\" ? connector.version : \"0.0.1\";\n const pkg: Record<string, unknown> = {\n name: pkgName,\n version,\n description: `${connector.displayName} — connector emitted by agent-connector`,\n type: \"module\",\n main: \"index.js\",\n exports: { \".\": \"./index.js\" },\n keywords: [\"opencode\", \"opencode-plugin\", \"pi-package\", \"agent-connector\"],\n // pi reads skills/prompts/themes/extensions from the package.json \"pi\" key.\n pi: { extensions: [\"./index.js\"], skills: [\"./skills\"] },\n engines: { node: \">=18.17\", opencode: \">=1.0.0\" },\n // NOTE: no hardcoded license — this is the DEVELOPER'S publishable package\n // and agent-connector has no authority to license it. The emitter returns a\n // note telling the dev to set license (and author) before `npm publish`.\n };\n if (connector.publish?.author?.name) {\n pkg.author = connector.publish.author.name;\n }\n return pkg;\n}\n\n/** Compose the self-contained ESM plugin bridge (default-export plugin fn). */\nfunction buildIndexJs(connector: ResolvedConnector): string {\n const homeBin = JSON.stringify(\"agent-connector\");\n const connectorId = JSON.stringify(connector.id);\n\n const events = connector.hookEvents.filter(\n (e): e is HookEventName => EVENT_TO_OPENCODE[e] !== undefined,\n );\n const has = (e: HookEventName): boolean => events.includes(e);\n\n const header = `/**\n * AUTO-GENERATED by agent-connector — DO NOT EDIT.\n *\n * Publishable OpenCode/Kilo/Pi plugin for connector ${connector.id}. It imports\n * nothing from agent-connector: every hook invocation shells out to the stable\n * home binary's universal entrypoint and JSON-parses the normalized response.\n * Fail-open: any bridge error degrades to \"allow\".\n */\nimport { execFileSync, execSync } from \"node:child_process\";\n\nconst HOME_BIN = ${homeBin};\nconst CONNECTOR_ID = ${connectorId};\n\nfunction bridge(event, payload) {\n try {\n // The published bridge resolves HOME_BIN by bare name via the consumer's\n // PATH, where on Windows it is agent-connector.cmd. Node cannot execFile a\n // .cmd, and shell+args is deprecated (DEP0190), so on Windows run one quoted\n // command line via a shell (cmd.exe applies PATHEXT). POSIX keeps execFile.\n const args = [\"hook\", \"opencode\", event, \"--connector\", CONNECTOR_ID];\n const opts = { input: JSON.stringify(payload), encoding: \"utf8\" };\n const stdout =\n process.platform === \"win32\"\n ? execSync([HOME_BIN, ...args].map((a) => '\"' + a + '\"').join(\" \"), opts)\n : execFileSync(HOME_BIN, args, opts);\n const text = (stdout || \"\").trim();\n if (text === \"\") return { decision: \"allow\" };\n return JSON.parse(text);\n } catch {\n return null;\n }\n}\n`;\n\n const handlers: string[] = [];\n if (has(\"PreToolUse\")) {\n handlers.push(` \"tool.execute.before\": async (input, output) => {\n const res = bridge(\"PreToolUse\", {\n toolName: input.tool ?? \"\",\n toolInput: (output && output.args) ?? {},\n sessionId: input.sessionID ?? \"\",\n projectDir: PROJECT_DIR,\n });\n if (!res) return;\n if (res.decision === \"deny\" || res.decision === \"ask\") {\n throw new Error(res.reason || \"Blocked by ${connector.id}\");\n }\n if (res.updatedInput && output && output.args) Object.assign(output.args, res.updatedInput);\n },`);\n }\n if (has(\"PostToolUse\")) {\n handlers.push(` \"tool.execute.after\": async (input, output) => {\n const res = bridge(\"PostToolUse\", {\n toolName: input.tool ?? \"\",\n toolInput: input.args ?? {},\n toolOutput: output ? output.output : undefined,\n sessionId: input.sessionID ?? \"\",\n projectDir: PROJECT_DIR,\n });\n if (!res) return;\n if (typeof res.updatedOutput === \"string\" && output) output.output = res.updatedOutput;\n },`);\n }\n if (has(\"SessionStart\")) {\n handlers.push(` \"experimental.chat.system.transform\": async (input, output) => {\n const res = bridge(\"SessionStart\", {\n sessionId: (input && input.sessionID) ?? \"\",\n projectDir: PROJECT_DIR,\n });\n if (!res) return;\n if (res.additionalContext && output && Array.isArray(output.system)) {\n output.system.splice(1, 0, res.additionalContext);\n }\n },`);\n }\n\n const factory = `\nexport default async function (ctx) {\n const PROJECT_DIR =\n (ctx && (ctx.directory || (ctx.worktree && ctx.worktree.path))) || process.cwd();\n return {\n${handlers.join(\"\\n\")}\n };\n}\n`;\n return header + factory;\n}\n\nexport const emitNpmPlugin: FormatEmitter = (\n connector: ResolvedConnector,\n ctx: EmitContext,\n): PackageResult => {\n const { emit, files } = createEmitter(ctx.dryRun);\n const pluginDir = join(ctx.outDir, connector.id);\n const notes: string[] = [];\n\n // ── package.json (publishable) ────────────────────────────────────────────\n emit(join(pluginDir, \"package.json\"), json(buildPackageJson(connector)));\n\n // ── index.js (the default-export plugin bridge) ───────────────────────────\n emit(join(pluginDir, \"index.js\"), buildIndexJs(connector));\n\n // ── skills/<name>/SKILL.md (+ resources) — pi bundles skills ──────────────\n for (const skill of connector.skills) {\n const skillDir = join(pluginDir, \"skills\", skill.name);\n emit(join(skillDir, \"SKILL.md\"), renderSkillMd(skill));\n for (const [rel, contents] of Object.entries(skill.resources ?? {})) {\n const target = resolveWithin(skillDir, rel);\n if (target === null) continue;\n emit(target, contents);\n }\n }\n\n // ── README.md ─────────────────────────────────────────────────────────────\n emit(\n join(pluginDir, \"README.md\"),\n `# ${connector.displayName}\\n\\nOpenCode / Kilo / Pi plugin package emitted by agent-connector.\\n\\n` +\n \"Install with `opencode plugin install <pkg>` / `kilo plugin <pkg>` / `pi install <pkg>`.\\n\\n\" +\n \"Local install (no npm publish needed — live-verified on opencode 1.17.0 / kilo 7.3.16):\\n\" +\n \"`opencode plugin --global file:///<abs-dir>` or `kilo plugin --global file:///<abs-dir>`\\n\" +\n \"(bare absolute paths work too; the entry lands in the config `plugin` array —\\n\" +\n \"there is no uninstall verb, remove it by editing that array).\\n\\n\" +\n \"## Prerequisite\\n\\n\" +\n \"Hooks shell out to the `agent-connector` CLI resolved from the consumer's PATH —\\n\" +\n \"the consumer machine needs `npm i -g @ken-jo/agent-connector` (hooks silently no-op,\\n\" +\n \"fail-open, without it).\\n\\n\" +\n \"## Before you publish\\n\\n\" +\n \"The emitted package.json carries **no `license` and no `author`** unless your\\n\" +\n \"connector declared `publish.author` — set them to YOUR terms before `npm publish`.\\n\",\n );\n\n // The published bridge resolves the CLI by bare name on the consumer's PATH.\n notes.push(\n \"npm-plugin: hooks require `npm i -g @ken-jo/agent-connector` on the consumer machine (bridge resolves the CLI by name on PATH; silently fail-open without it)\",\n );\n notes.push(\n \"npm-plugin: set license/author in the emitted package.json before `npm publish` — agent-connector does not license your plugin for you\",\n );\n\n // Surface the inherent limits of the npm-plugin contract.\n if (connector.commands.length > 0) {\n notes.push(\n `npm-plugin: ${connector.commands.length} command(s) NOT bundled — opencode/kilo commands are native host dirs`,\n );\n }\n if (connector.subagents.length > 0) {\n notes.push(\n `npm-plugin: ${connector.subagents.length} subagent(s) NOT bundled — opencode/kilo subagents are native host dirs`,\n );\n }\n if (connector.server) {\n notes.push(\n `npm-plugin: MCP server NOT bundled inside the package — register it via the opencode.json \"mcp\" key`,\n );\n }\n\n return { files, pluginDir, ...(notes.length > 0 ? { notes } : {}) };\n};\n","/**\n * core/package-formats/mcp-server — emit an official MCP Registry `server.json`.\n *\n * Unlike the host plugin/marketplace bundles, server.json is a DISCOVERY +\n * PUBLISH artifact: it describes the developer's REAL upstream MCP server (what\n * a registry installer runs DIRECTLY), so it must NOT carry agent-connector's\n * `serve` telemetry wrapper. It is emitted from the connector's `publish`\n * metadata (the namespace the dev proved ownership of + their published package)\n * and conforms to the pinned 2025-12-11 schema:\n * • name = `${publish.registryNamespace}/${connector.id}` (one '/', regex-checked)\n * • version = concrete SemVer (ranges are rejected by the registry)\n * • stdio → packages[] { registryType:\"npm\", identifier:<dev pkg>, transport:{type:\"stdio\"} }\n * • remote → remotes[] { type:\"streamable-http\"|\"sse\", url, headers }\n * • token env vars are marked isSecret.\n *\n * agent-connector EMITS a conformant server.json; the dev runs the publish-time\n * ownership proof + upload themselves with the official `mcp-publisher` CLI.\n */\n\nimport { resolve } from \"node:path\";\n\nimport type { ResolvedConnector, ServerDef } from \"../types.js\";\nimport {\n MCP_SERVER_SCHEMA_URL,\n NPM_REGISTRY_BASE_URL,\n REGISTRY_NAME_RE,\n isConcreteSemver,\n isPlaceholderVersion,\n registryTransportType,\n} from \"../mcp-standard.js\";\nimport type { EmitContext, FormatEmitter, PackageResult } from \"./shared.js\";\nimport { createEmitter, json } from \"./shared.js\";\n\n/** A server.json KeyValueInput (environmentVariables[] / headers[] entry). */\ninterface KeyValueInput {\n name: string;\n isSecret?: boolean;\n isRequired?: boolean;\n}\n\n/** Build environmentVariables[] from a stdio ServerDef, marking the bearer token secret. */\nfunction buildEnvVars(server: ServerDef): KeyValueInput[] {\n const vars: KeyValueInput[] = [];\n const byName = new Map<string, KeyValueInput>();\n for (const key of Object.keys(server.env ?? {})) {\n const v: KeyValueInput = { name: key };\n vars.push(v);\n byName.set(key, v);\n }\n if (server.auth?.type === \"bearerEnv\" && server.auth.bearerEnvVar) {\n const name = server.auth.bearerEnvVar;\n const existing = byName.get(name);\n if (existing) {\n existing.isSecret = true;\n existing.isRequired = true;\n } else {\n vars.push({ name, isSecret: true, isRequired: true });\n }\n }\n return vars;\n}\n\n/** Build the conformant server.json object (throws a clear error on missing inputs). */\nfunction buildServerJson(\n connector: ResolvedConnector,\n notes: string[],\n): Record<string, unknown> {\n const publish = connector.publish ?? {};\n\n if (!publish.registryNamespace) {\n throw new Error(\n 'package --format mcp-server-json needs publish.registryNamespace — a reverse-DNS ' +\n 'namespace you OWN (e.g. \"io.github.<your-handle>\" or \"com.<your-domain>\"). ' +\n \"agent-connector never publishes under a namespace it owns; set it in your connector config.\",\n );\n }\n const name = `${publish.registryNamespace}/${connector.id}`;\n if (!REGISTRY_NAME_RE.test(name)) {\n throw new Error(\n `server.json name \"${name}\" must match ${REGISTRY_NAME_RE} (exactly one \"/\").`,\n );\n }\n if (!isConcreteSemver(connector.version)) {\n throw new Error(\n `server.json version must be a concrete SemVer (the registry rejects ranges); got \"${connector.version}\".`,\n );\n }\n if (isPlaceholderVersion(connector.version)) {\n notes.push(\n 'version is the unset placeholder \"0.0.0\" — set a real version before publishing to the registry.',\n );\n }\n\n const out: Record<string, unknown> = {\n $schema: MCP_SERVER_SCHEMA_URL,\n name,\n description: connector.displayName,\n version: connector.version,\n };\n\n const server = connector.server;\n if (!server) {\n notes.push(\n \"connector declares no server — emitted server.json carries neither packages nor remotes \" +\n \"(a hooks/commands-only connector is not a registry server).\",\n );\n return out;\n }\n\n const tt = registryTransportType(server.transport);\n if (tt === null) {\n notes.push(\n `transport \"${server.transport}\" is not an MCP spec transport and cannot be represented in ` +\n \"server.json; emitted server metadata without a package/remote entry.\",\n );\n return out;\n }\n\n if (server.transport === \"stdio\") {\n if (!publish.packageName) {\n throw new Error(\n \"package --format mcp-server-json needs publish.packageName — your REAL published npm \" +\n 'package that runs the MCP server (e.g. \"@acme/acme-db-mcp\"). The registry runs that ' +\n \"package directly, not agent-connector's serve wrapper.\",\n );\n }\n const pkg: Record<string, unknown> = {\n registryType: \"npm\",\n registryBaseUrl: publish.registryBaseUrl ?? NPM_REGISTRY_BASE_URL,\n identifier: publish.packageName,\n version: connector.version,\n transport: { type: \"stdio\" },\n };\n const envVars = buildEnvVars(server);\n if (envVars.length > 0) pkg.environmentVariables = envVars;\n out.packages = [pkg];\n } else {\n // streamable-http | sse → remotes[]\n const remote: Record<string, unknown> = { type: tt, url: server.url };\n const headers = Object.keys(server.headers ?? {}).map((k): KeyValueInput => ({ name: k }));\n if (headers.length > 0) remote.headers = headers;\n if (server.auth && server.auth.type !== \"none\") {\n notes.push(\n `remote server uses auth \"${server.auth.type}\" — add the credential header (isSecret) to ` +\n \"the emitted remotes[].headers before publishing.\",\n );\n }\n out.remotes = [remote];\n }\n\n return out;\n}\n\n/** Emit a registry-conformant server.json for `connector` into ctx.outDir. */\nexport const emitMcpServerJson: FormatEmitter = (\n connector: ResolvedConnector,\n ctx: EmitContext,\n): PackageResult => {\n const emitter = createEmitter(ctx.dryRun);\n const notes: string[] = [];\n const serverJson = buildServerJson(connector, notes);\n const path = resolve(ctx.outDir, \"server.json\");\n emitter.emit(path, json(serverJson));\n return {\n files: emitter.files,\n pluginDir: ctx.outDir,\n ...(notes.length > 0 ? { notes } : {}),\n };\n};\n","/**\n * core/package-formats/mcpb — emit an MCPB (.mcpb, formerly DXT) bundle manifest.\n *\n * MCPB is the official cross-client one-click LOCAL-install bundle (Claude\n * Desktop + any MCPB host). A real .mcpb is a SELF-CONTAINED zip (manifest.json\n * + the server + vendored node_modules), which agent-connector cannot assemble\n * at emit time — we do not have the developer's built server tree. So, per the\n * conformance analysis, we emit a CONFORMANT manifest.json describing a\n * self-contained node bundle (NOT an out-of-spec `npx` command-reference, which\n * would assume network + node on PATH at launch and break offline/signing) plus\n * a packaging RECIPE, and leave the `mcpb pack`/`mcpb sign` to the developer —\n * mirroring how server.json defers the publish-time ownership proof.\n *\n * Secrets (the bearer token / sensitive env) are routed through `user_config`\n * (sensitive:true) and referenced as `${user_config.<key>}` in mcp_config.env,\n * so credentials are collected by the host keychain, never inlined.\n */\n\nimport { resolve } from \"node:path\";\n\nimport type { ResolvedConnector, ServerDef } from \"../types.js\";\nimport {\n MCPB_MANIFEST_VERSION,\n isConcreteSemver,\n isPlaceholderVersion,\n} from \"../mcp-standard.js\";\nimport type { EmitContext, FormatEmitter, PackageResult } from \"./shared.js\";\nimport { createEmitter, json } from \"./shared.js\";\n\n/** \"ACME_DB_TOKEN\" → \"Acme Db Token\" for a user_config field title. */\nfunction titleize(s: string): string {\n return s\n .toLowerCase()\n .split(/[_-]+/)\n .filter(Boolean)\n .map((w) => w[0]!.toUpperCase() + w.slice(1))\n .join(\" \");\n}\n\n/** The names of env vars that hold secrets (the bearer token). */\nfunction secretEnvNames(server: ServerDef): Set<string> {\n const names = new Set<string>();\n if (server.auth?.type === \"bearerEnv\" && server.auth.bearerEnvVar) {\n names.add(server.auth.bearerEnvVar);\n }\n return names;\n}\n\nfunction recipeReadme(connector: ResolvedConnector): string {\n return `# ${connector.displayName} — MCPB bundle\n\n\\`agent-connector package --format mcpb\\` emitted the conformant **manifest.json**\n(manifest_version ${MCPB_MANIFEST_VERSION}) for this connector. It does NOT build\nthe \\`.mcpb\\` zip — that step vendors your server and is yours to run, so the\nbundle stays self-contained and signable.\n\n## Finish the bundle\n\n1. Put your built, self-contained MCP server at \\`server/index.js\\`\n (the manifest's \\`entry_point\\` / \\`mcp_config\\`).\n2. Vendor production dependencies into the bundle:\n\n \\`\\`\\`bash\n cd server && npm install --omit=dev && cd ..\n \\`\\`\\`\n\n3. Pack (and optionally sign) with the official MCPB CLI:\n\n \\`\\`\\`bash\n npx @anthropic-ai/mcpb pack . # → ${connector.id}.mcpb\n npx @anthropic-ai/mcpb sign ${connector.id}.mcpb\n \\`\\`\\`\n\nThe resulting \\`.mcpb\\` installs one-click into Claude Desktop and any MCPB host.\nSecrets are declared under \\`user_config\\` and collected by the host keychain at\ninstall time — never inline them in the manifest.\n`;\n}\n\n/** Emit a conformant MCPB manifest.json + packaging recipe for `connector`. */\nexport const emitMcpbBundle: FormatEmitter = (\n connector: ResolvedConnector,\n ctx: EmitContext,\n): PackageResult => {\n const publish = connector.publish ?? {};\n if (!publish.author?.name) {\n throw new Error(\n \"package --format mcpb needs publish.author.name — the MCPB manifest requires an author.\",\n );\n }\n if (!isConcreteSemver(connector.version)) {\n throw new Error(\n `mcpb manifest version must be a concrete SemVer; got \"${connector.version}\".`,\n );\n }\n\n const server = connector.server;\n if (!server) {\n throw new Error(\"package --format mcpb needs a server (an MCPB bundle packages an MCP server).\");\n }\n if (server.transport !== \"stdio\") {\n throw new Error(\n `package --format mcpb supports stdio servers; \"${server.transport}\" is a remote server — ` +\n \"publish it via the registry (--format mcp-server-json) instead.\",\n );\n }\n\n const notes: string[] = [];\n if (isPlaceholderVersion(connector.version)) {\n notes.push('version is the unset placeholder \"0.0.0\" — set a real version before packing.');\n }\n\n // Route secret env vars through user_config; pass the rest through verbatim.\n const secrets = secretEnvNames(server);\n const env: Record<string, string> = {};\n const userConfig: Record<string, Record<string, unknown>> = {};\n for (const [k, v] of Object.entries(server.env ?? {})) {\n if (secrets.has(k)) {\n const key = k.toLowerCase();\n userConfig[key] = {\n type: \"string\",\n title: titleize(k),\n description: `Value for ${k}`,\n sensitive: true,\n required: true,\n };\n env[k] = `\\${user_config.${key}}`;\n } else {\n env[k] = v;\n }\n }\n // A bearer-token env not already present in server.env still needs a field.\n for (const name of secrets) {\n if (!(name in env)) {\n const key = name.toLowerCase();\n userConfig[key] = {\n type: \"string\",\n title: titleize(name),\n description: `Value for ${name}`,\n sensitive: true,\n required: true,\n };\n env[name] = `\\${user_config.${key}}`;\n }\n }\n\n const author: Record<string, string> = { name: publish.author.name };\n if (publish.author.email) author.email = publish.author.email;\n if (publish.author.url) author.url = publish.author.url;\n\n const mcpConfig: Record<string, unknown> = {\n command: \"node\",\n args: [\"${__dirname}/server/index.js\"],\n };\n if (Object.keys(env).length > 0) mcpConfig.env = env;\n\n const manifest: Record<string, unknown> = {\n manifest_version: MCPB_MANIFEST_VERSION,\n name: connector.id,\n version: connector.version,\n description: connector.displayName,\n author,\n server: {\n type: \"node\",\n entry_point: \"server/index.js\",\n mcp_config: mcpConfig,\n },\n };\n if (Object.keys(userConfig).length > 0) manifest.user_config = userConfig;\n\n // If the dev's real command is not node-ish, the node template needs adjusting.\n if (server.command && !/\\b(node|npx)\\b/.test(server.command)) {\n notes.push(\n `your server command is \"${server.command}\" — the emitted manifest assumes a node ` +\n \"server (server.type:node); adjust server.type/entry_point for your runtime (python|binary).\",\n );\n }\n notes.push(\n \"emitted manifest.json + README recipe; this format does NOT build the .mcpb zip. \" +\n \"Place your self-contained server at server/index.js, vendor deps, then run `mcpb pack` (see README).\",\n );\n\n const emitter = createEmitter(ctx.dryRun);\n emitter.emit(resolve(ctx.outDir, \"manifest.json\"), json(manifest));\n emitter.emit(resolve(ctx.outDir, \"README.md\"), recipeReadme(connector));\n return { files: emitter.files, pluginDir: ctx.outDir, notes };\n};\n"],"mappings":"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","names":["existsSync","join","resolve","join","buildManifest","buildMarketplace","join","join","SPECS","buildManifest","join","join","PLATFORM","buildManifest","join","join","PLATFORM","buildManifest","join","join","join","resolve","resolve","resolve","resolve","resolve","join"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/telemetry/measure.ts","../src/runtime/hook-entrypoint.ts","../src/runtime/serve.ts","../src/telemetry/calibration.ts","../src/telemetry/proxy.ts","../src/runtime/usage-event.ts"],"sourcesContent":["/**\n * telemetry/measure — pure measurement helpers over a single MCP tool call.\n *\n * The framework tokenizes its OWN bytes: the tool-call arguments going in, the\n * tool result coming out, and the fixed tool-definition schemas. These helpers\n * turn those into {@link TokenCount}s using the default {@link Tokenizer}.\n *\n * Honesty rules:\n * • Binary modalities (image/audio/resource blobs) are NOT tokenized — base64\n * would massively over-count. Each gets a flat per-modality estimate, and\n * because that estimate is itself an approximation the combined confidence\n * is pulled down to at least \"tokenizer-approx\".\n * • When combining several counts, the reported confidence is the WORST\n * (least-confident) of the inputs — never report \"exact\" for a mixed bag.\n *\n * Everything here is pure: no IO, no mutation of inputs.\n */\n\nimport { getTokenizer } from \"./tokenizer.js\";\nimport { worstConfidence } from \"./types.js\";\nimport type {\n ConfidenceSource,\n ModelFamily,\n TokenCount,\n Tokenizer,\n} from \"./types.js\";\n\n/** Per-call measurement: tokens in, tokens out, and combined confidence. */\nexport interface ToolCallMeasurement {\n inputTokens: number;\n outputTokens: number;\n source: ConfidenceSource;\n}\n\n/**\n * Flat token estimates for non-text content blocks. These mirror common host\n * accounting (an image tile is roughly ~85 tokens at low detail); they are\n * deliberately coarse — we never tokenize the underlying base64 payload.\n */\nconst MODALITY_ESTIMATE: Record<string, number> = {\n image: 85,\n audio: 85,\n resource: 85,\n};\n/** Fallback estimate for an unknown non-text block type. */\nconst UNKNOWN_BLOCK_ESTIMATE = 85;\n\n// Confidence ordering + the worst-of comparison live in ./types (the single\n// source of truth, imported as `worstConfidence` above). Re-exported here so\n// callers that already import `worstConfidence` from this module keep working\n// as a new ConfidenceSource value (e.g. tokenizer-calibrated) slots into the\n// shared ordering.\nexport { worstConfidence };\n\n/** Reduce a list of sources to the single worst (least-confident) one. */\nfunction combineSources(sources: readonly ConfidenceSource[]): ConfidenceSource {\n // Default to the most-confident floor so an empty list combines to the only\n // other source it is paired with; in practice callers always pass ≥1 source.\n let worst: ConfidenceSource = \"host-native\";\n for (const s of sources) worst = worstConfidence(worst, s);\n return worst;\n}\n\n// ── Structural shapes we read from a tool result (kept local + narrow) ───────\n\n/** A text content block: `{ type: \"text\", text: \"...\" }`. */\ninterface TextBlock {\n type: \"text\";\n text?: unknown;\n}\n/** Any content block; only text blocks expose a `text` field we tokenize. */\ninterface ContentBlock {\n type?: unknown;\n text?: unknown;\n}\n/** The portion of an MCP tool result we measure. */\ninterface ToolResultLike {\n content?: unknown;\n structuredContent?: unknown;\n}\n\nfunction isObject(v: unknown): v is Record<string, unknown> {\n return typeof v === \"object\" && v !== null;\n}\n\nfunction isTextBlock(block: ContentBlock): block is TextBlock {\n return block.type === \"text\";\n}\n\n/**\n * Measure one tool call.\n *\n * Input = canonical JSON of `args`.\n * Output = tokens over the TEXTUAL parts of `result`:\n * • If `result.content` is an array of blocks, text blocks are tokenized via\n * their `text` field and non-text blocks add a flat per-modality estimate\n * (no base64 tokenization).\n * • `result.structuredContent`, when present, is tokenized as canonical JSON.\n * • Anything else (string / arbitrary object) is tokenized as canonical JSON.\n *\n * The reported `source` is the worst of the input and output sources.\n */\nexport function measureToolCall(\n args: unknown,\n result: unknown,\n family: ModelFamily,\n tok: Tokenizer = getTokenizer(),\n): ToolCallMeasurement {\n const input = tok.countValue(args, family);\n const output = measureResult(result, family, tok);\n return {\n inputTokens: input.tokens,\n outputTokens: output.tokens,\n source: worstConfidence(input.source, output.source),\n };\n}\n\n/** Tokenize the textual + structured parts of a tool result. */\nfunction measureResult(\n result: unknown,\n family: ModelFamily,\n tok: Tokenizer,\n): TokenCount {\n if (!isObject(result)) {\n // Plain string or scalar result — count its canonical form directly.\n return tok.countValue(result, family);\n }\n\n const res = result as ToolResultLike;\n const sources: ConfidenceSource[] = [];\n let tokens = 0;\n\n if (Array.isArray(res.content)) {\n for (const raw of res.content) {\n if (!isObject(raw)) continue;\n const block = raw as ContentBlock;\n if (isTextBlock(block)) {\n const text = typeof block.text === \"string\" ? block.text : \"\";\n const c = tok.count(text, family);\n tokens += c.tokens;\n sources.push(c.source);\n } else {\n // image / audio / resource / unknown → flat estimate, no base64 BPE.\n const key = typeof block.type === \"string\" ? block.type : \"\";\n tokens += MODALITY_ESTIMATE[key] ?? UNKNOWN_BLOCK_ESTIMATE;\n // A flat estimate is an approximation, never \"exact\".\n sources.push(\"tokenizer-approx\");\n }\n }\n } else if (res.content !== undefined) {\n // content present but not an array (e.g. a bare string) → count it whole.\n const c = tok.countValue(res.content, family);\n tokens += c.tokens;\n sources.push(c.source);\n }\n\n if (res.structuredContent !== undefined) {\n const c = tok.countValue(res.structuredContent, family);\n tokens += c.tokens;\n sources.push(c.source);\n }\n\n // Nothing measurable found → count the whole object as a fallback so we never\n // silently report zero for a non-empty result.\n if (sources.length === 0) {\n return tok.countValue(result, family);\n }\n\n return { tokens, source: combineSources(sources) };\n}\n\n/**\n * Measure the fixed tool-definition overhead: tokenize the JSON of the entire\n * `tools/list` array once. `tools` is the raw array of tool descriptors as the\n * server advertises them (shape is host/SDK-specific, so it is treated as\n * opaque JSON here).\n */\nexport function measureToolDefs(\n tools: readonly unknown[],\n family: ModelFamily,\n tok: Tokenizer = getTokenizer(),\n): TokenCount {\n return tok.countValue(tools, family);\n}\n\n/**\n * Measure one RUNTIME hook dispatch (the new `hook` developer-axis surface).\n *\n * Input = canonical JSON of the inbound normalized event payload the handler\n * reads (the host-provided fields: toolInput / prompt / raw / etc.).\n * Output = canonical JSON of what the handler RETURNS that becomes context or a\n * decision the host consumes (additionalContext / updatedInput / reason\n * and the rest of the normalized {@link HookResponse}).\n *\n * Uses the SAME tokenizer + worst-of confidence combination as the proxy. Pure:\n * no IO, no mutation. The two values are tokenized whole (a hook payload has no\n * binary content blocks to special-case, unlike a tool result).\n */\nexport function measureHook(\n eventPayload: unknown,\n handlerReturn: unknown,\n family: ModelFamily,\n tok: Tokenizer = getTokenizer(),\n): ToolCallMeasurement {\n const input = tok.countValue(eventPayload, family);\n const output = tok.countValue(handlerReturn, family);\n return {\n inputTokens: input.tokens,\n outputTokens: output.tokens,\n source: worstConfidence(input.source, output.source),\n };\n}\n","/**\n * runtime/hook-entrypoint — the universal json-stdio hook dispatcher.\n *\n * Every json-stdio host points its hook config at the single stable home binary\n * (`<homeBin> hook <platformId> <event> --connector <id>`, built by\n * core/spawn.buildHomeBinHookCommand). The CLI reads stdin and calls\n * {@link runHook} with the parsed flags + the raw stdin string. This module:\n *\n * 1. Loads the registered connector (live handlers) and the host adapter.\n * 2. Parses the host's stdin payload into a normalized event via the adapter.\n * 3. Finds the connector's handler for the event, honoring the tool matcher.\n * 4. Runs the handler, normalizes its return, and formats the adapter's native\n * reply.\n *\n * Fail-open is the safety contract: ANY error degrades to exit 0 (\"allow\") so a\n * framework or handler bug can never wedge a host's tool call — EXCEPT when the\n * event is PreToolUse or PermissionRequest and the handler explicitly denied,\n * in which case the deny (a deliberate security decision) is preserved rather\n * than swallowed.\n */\n\nimport type {\n HookEventName,\n HookResponse,\n NativeHookDef,\n NativeHookEvent,\n PlatformId,\n ResolvedConnector,\n} from \"../core/types.js\";\nimport { log } from \"../core/logger.js\";\nimport { loadRegisteredConnector } from \"../core/load-connector.js\";\nimport { loadAdapter, REGISTERED_PLATFORM_IDS } from \"../adapters/registry.js\";\nimport type { NormalizedEvent } from \"../adapters/spi.js\";\nimport { projectIdentity } from \"../core/paths.js\";\nimport { measureHook } from \"../telemetry/measure.js\";\nimport { openStore, newRecordId } from \"../telemetry/store.js\";\nimport { getTokenizer, inferModelFamily } from \"../telemetry/tokenizer.js\";\n\n/** Flags + stdin the CLI hands to {@link runHook}. */\nexport interface RunHookOptions {\n /** Host platform id from the hook command (`hook <platformId> ...`). */\n platformId: string;\n /** Canonical lifecycle event name from the hook command. */\n event: HookEventName;\n /** Connector id from `--connector <id>`. */\n connectorId: string;\n /** Raw stdin payload (host-native JSON). Empty string is tolerated → `{}`. */\n stdin: string;\n}\n\n/** Process-level result the CLI translates into exit code + stdout/stderr. */\nexport interface RunHookResult {\n exitCode: number;\n stdout?: string;\n stderr?: string;\n}\n\n/** A pass-through \"allow\" reply with exit 0 and no payload. */\nconst ALLOW: RunHookResult = { exitCode: 0 };\n\n/**\n * The string a connector matcher filters on, when the event carries one:\n * tool events (PreToolUse / PostToolUse / PermissionRequest /\n * PostToolUseFailure) expose `toolName`; subagent events expose `agentType`.\n * Returns undefined when the event has neither (no filtering) — including a\n * SubagentStop arriving WITHOUT agent_type, which some hosts fail to populate;\n * filtering out such an event would silently drop a real stop, so we run the\n * handler instead (fail-open).\n */\nfunction eventMatcherSubject(evt: NormalizedEvent): string | undefined {\n const name = (evt as { toolName?: unknown }).toolName;\n if (typeof name === \"string\") return name;\n const agentType = (evt as { agentType?: unknown }).agentType;\n if (typeof agentType === \"string\") return agentType;\n return undefined;\n}\n\n/**\n * Tolerantly parse the host's stdin payload. Empty / whitespace-only input is a\n * legitimate \"no payload\" signal from some hosts and resolves to `{}`. Malformed\n * JSON also degrades to `{}` rather than throwing — fail-open is the contract.\n */\nfunction parseStdin(stdin: string): unknown {\n const trimmed = stdin.trim();\n if (trimmed === \"\") return {};\n try {\n return JSON.parse(trimmed);\n } catch {\n return {};\n }\n}\n\n/**\n * Compile the connector's matcher (a regex string) for a tool event. A missing\n * or empty matcher matches everything (returns null → no filtering). An invalid\n * regex degrades to \"match everything\" so a typo never blocks tool calls.\n */\nfunction compileMatcher(matcher: string | undefined): RegExp | null {\n if (!matcher || matcher === \"\") return null;\n try {\n return new RegExp(matcher);\n } catch {\n return null;\n }\n}\n\n/**\n * Normalize a handler return into a concrete HookResponse. A void/non-object\n * return becomes `{}` — NO decision — which every adapter formats as\n * pass-through allow (`response.decision ?? \"allow\"`). Deliberately NOT\n * `{decision:\"allow\"}`: on PermissionRequest an explicit \"allow\" is an ACTIVE\n * grant that suppresses the host's permission dialog, and a handler that\n * returns nothing must fall through to the dialog, never silently grant.\n */\nfunction normalizeResponse(value: HookResponse | void): HookResponse {\n if (value == null || typeof value !== \"object\") return {};\n return value;\n}\n\n/**\n * Resolve the host platform to stamp on a hook telemetry row. Mirrors the serve\n * `--host` plumbing: the install-target platform id is baked into the hook\n * command (`hook <platformId> <event> …`) so `opts.platformId` is authoritative,\n * but an explicit env override (AGENT_CONNECTOR_HOST) wins when it names a known\n * platform. Falls back to the event's adapter-stamped hostPlatform, then\n * \"unknown\" — never throws.\n */\nfunction resolveHookHostPlatform(\n platformId: string,\n evt: NormalizedEvent | NativeHookEvent,\n): PlatformId {\n const override = process.env.AGENT_CONNECTOR_HOST;\n if (\n override !== undefined &&\n REGISTERED_PLATFORM_IDS.has(override as PlatformId)\n ) {\n return override as PlatformId;\n }\n if (REGISTERED_PLATFORM_IDS.has(platformId as PlatformId)) {\n return platformId as PlatformId;\n }\n const fromEvent = (evt as { hostPlatform?: unknown }).hostPlatform;\n if (\n typeof fromEvent === \"string\" &&\n REGISTERED_PLATFORM_IDS.has(fromEvent as PlatformId)\n ) {\n return fromEvent as PlatformId;\n }\n return \"unknown\";\n}\n\n/**\n * Record one RUNTIME hook dispatch as a `hook` developer-axis telemetry row.\n *\n * input = the inbound event payload the handler reads (normalized event, or\n * the {@link NativeHookEvent} envelope for native passthrough hooks);\n * output = what the handler returned (a normalized {@link HookResponse}, or the\n * verbatim native reply object). Tokenized with the SAME tokenizer the\n * proxy uses. For a native hook `opts.event` is the host-native name.\n *\n * MUST be fail-open (the hook runtime is fail-open by contract): any error here\n * is swallowed so a measurement bug can NEVER break a host's hook. Honors the\n * AGENT_CONNECTOR_TELEMETRY=0 kill switch (skips entirely; the store's append is\n * already a no-op under it, but we also skip the tokenize work).\n */\nfunction recordHookTelemetry(\n opts: { platformId: string; event: string; connectorId: string },\n connector: ResolvedConnector,\n evt: NormalizedEvent | NativeHookEvent,\n response: unknown,\n): void {\n if (process.env.AGENT_CONNECTOR_TELEMETRY === \"0\") return;\n try {\n const family = inferModelFamily(\"\", connector.telemetry.modelFamilyHint);\n const measurement = measureHook(evt, response, family, getTokenizer());\n\n const sessionId =\n typeof (evt as { sessionId?: unknown }).sessionId === \"string\"\n ? ((evt as { sessionId: string }).sessionId)\n : \"\";\n const evtProjectDir = (evt as { projectDir?: unknown }).projectDir;\n const projectDir =\n typeof evtProjectDir === \"string\" && evtProjectDir !== \"\"\n ? evtProjectDir\n : process.cwd();\n const id = projectIdentity(projectDir);\n\n const store = openStore({});\n try {\n store.append({\n id: newRecordId(0),\n ts: Date.now(),\n connectorId: opts.connectorId,\n toolName: opts.event, // for a hook row the per-item name IS the event\n scope: \"hook\",\n surfaceKind: \"hook\",\n hostPlatform: resolveHookHostPlatform(opts.platformId, evt),\n sessionId,\n projectKey: id.key,\n projectDir: id.dir,\n inputTokens: measurement.inputTokens,\n outputTokens: measurement.outputTokens,\n confidenceSource: measurement.source,\n isError: false,\n });\n } finally {\n store.close();\n }\n } catch {\n // Fail-open: a telemetry error must NEVER break the hook runtime.\n }\n}\n\n/**\n * Dispatch one host hook invocation. Always resolves (never rejects): every\n * failure path returns a concrete {@link RunHookResult} so the CLI can exit\n * cleanly. See the module header for the fail-open contract.\n */\nexport async function runHook(opts: RunHookOptions): Promise<RunHookResult> {\n const { platformId, event, connectorId, stdin } = opts;\n\n try {\n const connector = await loadRegisteredConnector(connectorId);\n const adapter = await loadAdapter(platformId);\n\n // mcp-only hosts (and any adapter without runtime dispatch) cannot parse a\n // hook payload — nothing to do, allow.\n if (!adapter || !adapter.parseEvent || !adapter.formatReply) {\n return ALLOW;\n }\n\n const raw = parseStdin(stdin);\n const evt = adapter.parseEvent(event, raw);\n // The hook command carries the authoritative connector id; stamp it on the\n // event so handlers see the connector they were dispatched for.\n evt.connectorId = connectorId;\n\n const definition = connector.hooks[event];\n if (!definition || typeof definition.handler !== \"function\") {\n // The connector declares no handler for this event — allow.\n return ALLOW;\n }\n\n // Matcher: if set and the event's subject (tool name, or agent type for\n // Subagent* events) does not match, allow (the hook is simply not\n // interested in this tool/agent).\n const subject = eventMatcherSubject(evt);\n if (subject !== undefined) {\n const re = compileMatcher(definition.matcher);\n if (re && !re.test(subject)) return ALLOW;\n }\n\n // Run the handler. Its return is normalized (void → allow) and handed to the\n // adapter to render the host-native reply.\n const handlerResult = await definition.handler(\n // The adapter parsed `evt` as exactly this event's payload type; the\n // HooksConfig handler for the same event expects that payload.\n evt as never,\n );\n const response = normalizeResponse(handlerResult);\n\n // Developer-axis telemetry for the RUNTIME `hook` surface. Fail-open: never\n // lets a measurement error break the hook (handled inside the helper).\n recordHookTelemetry(opts, connector, evt, response);\n\n const reply = adapter.formatReply(event, response);\n return {\n exitCode: reply.exitCode,\n ...(reply.stdout !== undefined ? { stdout: reply.stdout } : {}),\n ...(reply.stderr !== undefined ? { stderr: reply.stderr } : {}),\n };\n } catch (err) {\n // Fail-open: a framework/handler error must not wedge the host's tool call.\n // The ONE exception is a PreToolUse / PermissionRequest deny — a deliberate\n // block we honor even if a later step threw. We re-derive that decision\n // defensively from the adapter so a throw AFTER the deny still surfaces it.\n const message = err instanceof Error ? err.message : String(err);\n log.error(`hook ${platformId}/${event} (${connectorId}) failed:`, message);\n return failOpenOrPreserveDeny(opts, message);\n }\n}\n\n/**\n * Events whose explicit deny survives the fail-open error path. Both are\n * permission gates — a deny there is a deliberate security decision that must\n * never be silently downgraded to allow. (Stop-class denies are persistence\n * conveniences, not security boundaries, so they stay fail-open.)\n */\nconst DENY_PRESERVE_EVENTS: ReadonlySet<HookEventName> = new Set([\n \"PreToolUse\",\n \"PermissionRequest\",\n]);\n\n/**\n * Error path. Returns fail-open allow, UNLESS this is a deny-preserving event\n * (PreToolUse / PermissionRequest) whose handler explicitly denied — in which\n * case the deny is reconstructed and preserved (a security decision is never\n * silently downgraded to allow).\n *\n * Best-effort: if anything in the deny reconstruction itself throws, we fall\n * back to allow (we never escalate an error into a spurious block).\n */\nasync function failOpenOrPreserveDeny(\n opts: RunHookOptions,\n errorMessage: string,\n): Promise<RunHookResult> {\n if (!DENY_PRESERVE_EVENTS.has(opts.event)) return ALLOW;\n try {\n const connector = await loadRegisteredConnector(opts.connectorId);\n const adapter = await loadAdapter(opts.platformId);\n if (!adapter?.parseEvent || !adapter.formatReply) return ALLOW;\n\n const definition = connector.hooks[opts.event];\n if (!definition || typeof definition.handler !== \"function\") return ALLOW;\n\n const raw = parseStdin(opts.stdin);\n const evt = adapter.parseEvent(opts.event, raw);\n evt.connectorId = opts.connectorId;\n\n const subject = eventMatcherSubject(evt);\n if (subject !== undefined) {\n const re = compileMatcher(definition.matcher);\n if (re && !re.test(subject)) return ALLOW;\n }\n\n const response = normalizeResponse(await definition.handler(evt as never));\n if (response.decision !== \"deny\") return ALLOW;\n\n const reply = adapter.formatReply(opts.event, response);\n return {\n exitCode: reply.exitCode,\n ...(reply.stdout !== undefined ? { stdout: reply.stdout } : {}),\n ...(reply.stderr !== undefined\n ? { stderr: reply.stderr }\n : { stderr: errorMessage }),\n };\n } catch {\n // Reconstruction failed — never escalate an internal error into a block.\n return ALLOW;\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Native (passthrough) hooks — host events OUTSIDE the normalized union\n// ─────────────────────────────────────────────────────────────────────────\n\n/** Flags + stdin for {@link runNativeHook}. `event` is HOST-NATIVE (non-union). */\nexport interface RunNativeHookOptions {\n /** Host platform id from the hook command (`hook <platformId> ...`). */\n platformId: string;\n /** Host-native event name, verbatim (e.g. \"TaskCreated\"). */\n event: string;\n /** Connector id from `--connector <id>`. */\n connectorId: string;\n /** Raw stdin payload (host-native JSON). Empty string is tolerated → `{}`. */\n stdin: string;\n}\n\n/** The connector's native hook definition for `platformId`/`event`, if any. */\nfunction nativeHookDef(\n connector: ResolvedConnector,\n platformId: string,\n event: string,\n): NativeHookDef | undefined {\n return connector.platforms[platformId as PlatformId]?.nativeHooks?.[event];\n}\n\n/**\n * True when the registered connector declares `event` under\n * `platforms[platformId].nativeHooks` with a live handler. Used by the hook CLI\n * to decide whether a non-union event name is accepted (declared → dispatch via\n * {@link runNativeHook}) or rejected with the strict unknown-event error.\n * Fail-safe: any load error reads as \"not declared\".\n */\nexport async function isNativeHookDeclared(\n platformId: string,\n event: string,\n connectorId: string,\n): Promise<boolean> {\n try {\n const connector = await loadRegisteredConnector(connectorId);\n return typeof nativeHookDef(connector, platformId, event)?.handler === \"function\";\n } catch {\n return false;\n }\n}\n\n/**\n * Dispatch one NATIVE (passthrough) hook invocation. No normalized parse, no\n * HookResponse mapping, no runtime matcher evaluation (the host's own matcher\n * already filtered — the def's matcher string was written verbatim into the\n * host config at install):\n *\n * stdin JSON → NativeHookEvent{raw} → handler → VERBATIM JSON stdout (exit 0).\n *\n * void/undefined return → exit 0 with no output. Fail-open: ANY throw degrades\n * to exit 0 with no output — exit-2 blocking semantics are not modeled in v1.\n * Telemetry: records the same scope:\"hook\" developer-axis row as normalized\n * hooks, with the NATIVE event name as the per-item name.\n */\nexport async function runNativeHook(\n opts: RunNativeHookOptions,\n): Promise<RunHookResult> {\n const { platformId, event, connectorId, stdin } = opts;\n try {\n const connector = await loadRegisteredConnector(connectorId);\n const def = nativeHookDef(connector, platformId, event);\n if (!def || typeof def.handler !== \"function\") {\n // Not declared for this platform — nothing to do, allow.\n return ALLOW;\n }\n\n const raw = parseStdin(stdin);\n // Best-effort session/project extraction from the json-stdio common shape\n // (Claude Code: session_id / cwd). Everything else stays in `raw` untouched.\n const sessionId =\n typeof (raw as { session_id?: unknown })?.session_id === \"string\"\n ? (raw as { session_id: string }).session_id\n : \"\";\n const cwd = (raw as { cwd?: unknown })?.cwd;\n const evt: NativeHookEvent = {\n event,\n hostPlatform: REGISTERED_PLATFORM_IDS.has(platformId as PlatformId)\n ? (platformId as PlatformId)\n : \"unknown\",\n sessionId,\n ...(typeof cwd === \"string\" && cwd !== \"\" ? { projectDir: cwd } : {}),\n raw,\n };\n\n const result = await def.handler(evt);\n\n // Same scope:\"hook\" telemetry row as normalized hooks (fail-open inside).\n recordHookTelemetry(opts, connector, evt, result === undefined ? {} : result);\n\n if (result === undefined) return ALLOW; // void → exit 0, no output\n const json = JSON.stringify(result);\n // Non-JSON-serializable returns (functions/symbols) degrade to silence.\n if (json === undefined) return ALLOW;\n return { exitCode: 0, stdout: json };\n } catch (err) {\n // Fail-open, unconditionally: native hooks have no deny-preserve carve-out\n // (there is no normalized decision to reconstruct).\n const message = err instanceof Error ? err.message : String(err);\n log.error(\n `native hook ${platformId}/${event} (${connectorId}) failed:`,\n message,\n );\n return ALLOW;\n }\n}\n","/**\n * runtime/serve — the `agent-connector serve` telemetry-wrapping entrypoint.\n *\n * When a stdio MCP server opts into transparent telemetry, its host config is\n * rewritten (by the adapter, via core/spawn.buildServeWrapperCommand) to launch\n * <homeBin> serve --connector <id> -- <realCommand> <realArgs...>\n * instead of the server directly. The CLI parses those flags and calls\n * {@link runServe}, which stands up the per-session telemetry context (store,\n * tokenizer, project identity, host detection) and hands off to the proxy.\n *\n * The proxy (telemetry/proxy.runServeProxy) forwards bytes VERBATIM in both\n * directions and measures aggregate per-tool token counts out of band, so this\n * wrapper is transparent to both the host and the real server. It resolves with\n * the child server's exit code, which the CLI uses as its own.\n */\n\nimport { randomUUID } from \"node:crypto\";\n\nimport { detectRuntimeHost } from \"../adapters/detect.js\";\nimport { REGISTERED_PLATFORM_IDS } from \"../adapters/registry.js\";\nimport { loadRegisteredConnector } from \"../core/load-connector.js\";\nimport { projectIdentity } from \"../core/paths.js\";\nimport { detectLaunchMethod } from \"../core/spawn.js\";\nimport type { PlatformId } from \"../core/types.js\";\nimport { runServeProxy } from \"../telemetry/proxy.js\";\nimport { openStore } from \"../telemetry/store.js\";\nimport { getTokenizer } from \"../telemetry/tokenizer.js\";\nimport type { TelemetryInstallScope } from \"../telemetry/types.js\";\n\n/** Flags the CLI hands to {@link runServe}. */\nexport interface RunServeOptions {\n /** Connector id from `--connector <id>`; selects telemetry config + stamps records. */\n connectorId: string;\n /** The real MCP server executable to spawn (everything after `--`). */\n serverCommand: string;\n /** Arguments passed to that executable. */\n serverArgs: string[];\n /**\n * Install scope from `--scope <user|project>`. OPTIONAL: absent for configs\n * written before scope plumbing existed — left unstamped so older rows read\n * as \"unknown\". Stamped verbatim onto every telemetry record when present.\n */\n installScope?: TelemetryInstallScope;\n /**\n * Install TARGET platform id from `--host <platformId>` (baked into the\n * wrapper at install time). OPTIONAL: when a recognized platform id, it\n * OVERRIDES runtime env detection so headless spawns stamp hostPlatform\n * correctly (detectRuntimeHost only knows env markers for a few hosts and\n * otherwise mis-attributes). Absent/unrecognized → fall back to detection.\n */\n hostPlatformOverride?: PlatformId;\n}\n\n/**\n * Launch the developer's real MCP server under the telemetry-wrapping proxy.\n *\n * Resolves with the child server's exit code (propagated as this process's exit\n * code by the CLI). The session id comes from AGENT_CONNECTOR_SESSION when the\n * host sets it (empty otherwise); the host platform is detected from runtime env\n * markers; the project identity partitions telemetry by the stable project key.\n */\n/**\n * Resolve a session id for telemetry attribution. Prefers a host-provided\n * session/thread marker (so records from the same host session group together);\n * falls back to a per-process UUID — each `serve` invocation is one server\n * session, a sensible default granularity — so `--by session` rollups are never\n * collapsed into a single empty-keyed group.\n */\nfunction resolveSessionId(env: NodeJS.ProcessEnv = process.env): string {\n return (\n env.AGENT_CONNECTOR_SESSION ||\n env.CLAUDE_SESSION_ID ||\n env.CODEX_THREAD_ID ||\n env.CURSOR_TRACE_ID ||\n env.MCP_SESSION_ID ||\n `proc-${randomUUID()}`\n );\n}\n\nexport async function runServe(opts: RunServeOptions): Promise<number> {\n const { connectorId, serverCommand, serverArgs, installScope, hostPlatformOverride } =\n opts;\n\n const connector = await loadRegisteredConnector(connectorId);\n\n const id = projectIdentity(process.cwd());\n // Prefer the install TARGET platform baked into the wrapper (--host), but only\n // when it is a KNOWN registered platform id — a bad/unknown value falls back to\n // runtime env detection so a config typo can never poison hostPlatform.\n const hostPlatform: PlatformId =\n hostPlatformOverride !== undefined &&\n REGISTERED_PLATFORM_IDS.has(hostPlatformOverride)\n ? hostPlatformOverride\n : detectRuntimeHost().platform;\n const sessionId = resolveSessionId();\n\n // `serve` only ever wraps a locally-spawned stdio server (a remote/http server\n // is never launched through the proxy), so isRemote is always false here.\n const launchMethod = detectLaunchMethod(serverCommand, serverArgs);\n\n const store = openStore({});\n const tok = getTokenizer();\n\n return runServeProxy({\n connectorId,\n command: serverCommand,\n args: serverArgs,\n store,\n tokenizer: tok,\n modelFamilyHint: connector.telemetry.modelFamilyHint,\n hostPlatform,\n sessionId,\n projectKey: id.key,\n projectDir: id.dir,\n measureToolDefs: connector.telemetry.measureToolDefs,\n installScope,\n launchMethod,\n });\n}\n","/**\n * telemetry/calibration — OPT-IN Anthropic count_tokens calibration.\n *\n * The default tokenizer counts every family with the OpenAI o200k_base BPE, so\n * an Anthropic session's counts are an honest-but-approximate stand-in\n * (\"tokenizer-approx\"). This module lets a developer OPT IN to calibrating that\n * approximation against Anthropic's real `count_tokens` endpoint: we sample a\n * tiny fraction of tool calls off-box, learn a per-family correction factor\n * (rolling mean of exact/approx), and apply it to the locally-tokenized counts\n * so they land much closer to the host's real numbers — labeled honestly as\n * \"tokenizer-calibrated\".\n *\n * PRIVACY + SAFETY — load-bearing invariants:\n * • OPT-IN only. Nothing here runs unless BOTH AGENT_CONNECTOR_CALIBRATE\n * contains \"anthropic\" AND ANTHROPIC_API_KEY is set (see isCalibrationEnabled).\n * • Sampling only — shouldSample() rate-limits hard so we never hammer the API.\n * • Content leaves the box ONLY on a sampled call, ONLY when opted in. We store\n * a single scalar factor + sample count — NEVER the sampled text itself.\n * • Fail-open everywhere: a network/parse/IO error returns null / passes the\n * approximation through unchanged and NEVER throws into a tool call or hook.\n *\n * No new dependencies: uses Node's global fetch (Node >= 18) and node:fs.\n */\n\nimport { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nimport { dataRoot, ensureDir } from \"../core/paths.js\";\nimport type { ConfidenceSource, ModelFamily } from \"./types.js\";\n\n// ── Env switches ──────────────────────────────────────────────────────────\n\n/**\n * Is opt-in Anthropic calibration enabled for this process?\n *\n * Requires BOTH:\n * • AGENT_CONNECTOR_CALIBRATE — a comma-separated allowlist that INCLUDES\n * `anthropic` (so a future `AGENT_CONNECTOR_CALIBRATE=openai,anthropic` can\n * opt other families in without touching this gate), and\n * • ANTHROPIC_API_KEY — a non-empty key to authenticate the off-box call.\n *\n * Either missing → disabled (the privacy-safe default).\n */\nexport function isCalibrationEnabled(): boolean {\n const families = (process.env.AGENT_CONNECTOR_CALIBRATE || \"\")\n .split(\",\")\n .map((s) => s.trim())\n .filter((s) => s !== \"\");\n const key = (process.env.ANTHROPIC_API_KEY || \"\").trim();\n return families.includes(\"anthropic\") && key !== \"\";\n}\n\n// ── Factor store (dataRoot/calibration.json) ────────────────────────────────\n\n/** One learned correction factor for a model family: factor + sample count. */\nexport interface CalibrationFactor {\n /** Multiply an approx count by this to estimate the real count. */\n factor: number;\n /** How many samples have folded into the rolling mean. */\n samples: number;\n}\n\n/** The on-disk factor map, keyed by model family. */\nexport type CalibrationFactors = Partial<Record<ModelFamily, CalibrationFactor>>;\n\n/** Path to the learned-factor store: dataRoot()/calibration.json. */\nexport function calibrationPath(): string {\n return join(dataRoot(), \"calibration.json\");\n}\n\n/**\n * Clamp a measured exact/approx ratio into a sane range. A pathological sample\n * (e.g. an empty-string approx of 0 → Infinity, or a parse glitch) must never\n * poison the rolling mean, so ratios are pinned to [0.2, 5].\n */\nconst RATIO_MIN = 0.2;\nconst RATIO_MAX = 5;\n\nfunction clampRatio(ratio: number): number | null {\n if (!Number.isFinite(ratio) || ratio <= 0) return null;\n if (ratio < RATIO_MIN) return RATIO_MIN;\n if (ratio > RATIO_MAX) return RATIO_MAX;\n return ratio;\n}\n\n/**\n * Load the learned factors from disk. Fail-open: a missing/unreadable/malformed\n * file returns an empty map rather than throwing.\n */\nexport function loadFactors(): CalibrationFactors {\n const path = calibrationPath();\n if (!existsSync(path)) return {};\n try {\n const parsed = JSON.parse(readFileSync(path, \"utf8\")) as unknown;\n if (parsed === null || typeof parsed !== \"object\") return {};\n const out: CalibrationFactors = {};\n for (const [family, value] of Object.entries(parsed as Record<string, unknown>)) {\n if (value === null || typeof value !== \"object\") continue;\n const rec = value as Record<string, unknown>;\n const factor = rec[\"factor\"];\n const samples = rec[\"samples\"];\n if (\n typeof factor === \"number\" &&\n Number.isFinite(factor) &&\n factor > 0 &&\n typeof samples === \"number\" &&\n Number.isFinite(samples) &&\n samples >= 0\n ) {\n (out as Record<string, CalibrationFactor>)[family] = {\n factor,\n samples,\n };\n }\n }\n return out;\n } catch {\n return {};\n }\n}\n\n/**\n * Fold one observed exact/approx `ratio` into the rolling mean for `family` and\n * persist it. A running average converges to the true mean while staying cheap\n * and stateless across processes (each writer reads the prior count, blends in\n * the new sample, writes back). Fail-open: any read/write/clamp problem leaves\n * the store untouched and never throws.\n */\nexport function recordSample(family: ModelFamily, ratio: number): void {\n const clamped = clampRatio(ratio);\n if (clamped === null) return;\n try {\n const factors = loadFactors();\n const prior = factors[family];\n let next: CalibrationFactor;\n if (prior === undefined || prior.samples <= 0) {\n next = { factor: clamped, samples: 1 };\n } else {\n const samples = prior.samples + 1;\n // Running average: new mean = old mean + (sample - old mean) / n.\n const factor = prior.factor + (clamped - prior.factor) / samples;\n next = { factor, samples };\n }\n const updated: CalibrationFactors = { ...factors, [family]: next };\n const path = calibrationPath();\n ensureDir(dataRoot());\n writeFileSync(path, `${JSON.stringify(updated, null, 2)}\\n`, \"utf8\");\n } catch {\n /* fail-open: a calibration write must never break a tool call */\n }\n}\n\n// ── Anthropic count_tokens (off-box, sampled, fail-open) ─────────────────────\n\n/** Default model used for count_tokens when no family→model map applies. */\nconst DEFAULT_ANTHROPIC_MODEL = \"claude-3-5-sonnet-latest\";\n\n/** Anthropic count_tokens endpoint. */\nconst COUNT_TOKENS_URL = \"https://api.anthropic.com/v1/messages/count_tokens\";\n\n/** The single field we read out of a successful response. */\ninterface CountTokensResponse {\n input_tokens?: unknown;\n}\n\n/**\n * Ask Anthropic's `count_tokens` endpoint for the exact token count of `text`\n * under `model`. Returns the integer count, or `null` on ANY failure (no key,\n * non-200, network error, unparseable body) — fail-open by contract.\n *\n * Only ever called on a SAMPLED tool call when calibration is opted in, so the\n * sampled text leaves the box only under explicit operator consent.\n */\nexport async function countTokensAnthropic(\n text: string,\n model: string = DEFAULT_ANTHROPIC_MODEL,\n): Promise<number | null> {\n const apiKey = (process.env.ANTHROPIC_API_KEY || \"\").trim();\n if (apiKey === \"\") return null;\n try {\n const res = await fetch(COUNT_TOKENS_URL, {\n method: \"POST\",\n headers: {\n \"x-api-key\": apiKey,\n \"anthropic-version\": \"2023-06-01\",\n \"content-type\": \"application/json\",\n },\n body: JSON.stringify({\n model,\n messages: [{ role: \"user\", content: text }],\n }),\n });\n if (!res.ok) return null;\n const body = (await res.json()) as CountTokensResponse;\n const n = body.input_tokens;\n if (typeof n === \"number\" && Number.isFinite(n) && n >= 0) {\n return n;\n }\n return null;\n } catch {\n return null;\n }\n}\n\n// ── Sampling (rate-limit so we never hammer the API) ─────────────────────────\n\n/**\n * Sample roughly 1 in {@link SAMPLE_EVERY} calls, with a hard per-minute cap so\n * a burst of tool calls can never fan out into a burst of API calls. Both\n * counters are in-memory (per process) — calibration is a best-effort,\n * low-volume background signal, not a per-call requirement.\n */\nconst SAMPLE_EVERY = 20;\nconst MAX_SAMPLES_PER_MINUTE = 10;\n\nlet callCounter = 0;\nlet windowStartMs = 0;\nlet samplesThisWindow = 0;\n\n/**\n * Should THIS call fire an off-box count_tokens sample? Combines a 1-in-N\n * counter with a rolling per-minute cap. Pure in-memory bookkeeping; never\n * throws, never blocks.\n */\nexport function shouldSample(now: number = Date.now()): boolean {\n // Roll the per-minute window.\n if (now - windowStartMs >= 60_000) {\n windowStartMs = now;\n samplesThisWindow = 0;\n }\n callCounter += 1;\n if (callCounter % SAMPLE_EVERY !== 0) return false;\n if (samplesThisWindow >= MAX_SAMPLES_PER_MINUTE) return false;\n samplesThisWindow += 1;\n return true;\n}\n\n/** Reset the in-memory sampling counters. Test-only seam; cheap + side-effect-free. */\nexport function _resetSamplingForTest(): void {\n callCounter = 0;\n windowStartMs = 0;\n samplesThisWindow = 0;\n}\n\n// ── Apply a learned factor to a local approximation ──────────────────────────\n\n/** Result of {@link applyCalibration}: the adjusted count + its honest source. */\nexport interface CalibratedCount {\n tokens: number;\n source: Extract<ConfidenceSource, \"tokenizer-approx\" | \"tokenizer-calibrated\">;\n}\n\n/**\n * Adjust a locally-tokenized `approxTokens` count by the learned factor for\n * `family`. When a stored factor exists for the anthropic family, return the\n * scaled count labeled \"tokenizer-calibrated\"; otherwise pass the approximation\n * through unchanged as \"tokenizer-approx\". Pure: reads the factor store but\n * mutates nothing.\n */\nexport function applyCalibration(\n approxTokens: number,\n family: ModelFamily,\n factors: CalibrationFactors = loadFactors(),\n): CalibratedCount {\n if (family === \"anthropic\") {\n const f = factors[family];\n if (f !== undefined && f.samples > 0 && Number.isFinite(f.factor) && f.factor > 0) {\n return {\n tokens: Math.max(0, Math.round(approxTokens * f.factor)),\n source: \"tokenizer-calibrated\",\n };\n }\n }\n return { tokens: approxTokens, source: \"tokenizer-approx\" };\n}\n\n/** The model used for a family's count_tokens sample (anthropic → default model). */\nexport function modelForFamily(_family: ModelFamily): string {\n return DEFAULT_ANTHROPIC_MODEL;\n}\n","/**\n * telemetry/proxy — the telemetry-wrapping MCP stdio proxy.\n *\n * `agent-connector serve <command> <args…>` spawns the developer's REAL MCP\n * server as a child and sits transparently between the host and that server,\n * speaking the MCP stdio wire format: NEWLINE-DELIMITED JSON-RPC (one single-line\n * JSON object per message, terminated by `\\n`; stdio has NO Content-Length\n * framing). Bytes are forwarded VERBATIM in both directions so the proxy can\n * never corrupt the stream; a side line-buffer tees a COPY of each direction,\n * parses complete messages, and measures per-tool token usage out of band.\n *\n * Honesty / safety rules baked in here:\n * • Forwarding always happens FIRST. Measurement runs after the bytes are out\n * the door and is wrapped so a measurement bug can never break a tool call.\n * • Telemetry stores AGGREGATE COUNTS ONLY — the parsed `tools/call` arguments\n * and results are tokenized and discarded; raw content is never persisted.\n * • AGENT_CONNECTOR_TELEMETRY=0 → still proxy transparently, skip all measure.\n *\n * The proxy resolves with the child's exit code and propagates SIGINT/SIGTERM.\n */\n\nimport type { PlatformId } from \"../core/types.js\";\nimport { spawnChild } from \"../core/spawn-child.js\";\nimport { type JsonRpcMessage, LineBuffer, idKey, isObject } from \"./jsonrpc.js\";\nimport {\n applyCalibration,\n countTokensAnthropic,\n isCalibrationEnabled,\n modelForFamily,\n recordSample,\n shouldSample,\n} from \"./calibration.js\";\nimport { measureToolCall, measureToolDefs } from \"./measure.js\";\nimport { newRecordId } from \"./store.js\";\nimport { inferModelFamily } from \"./tokenizer.js\";\nimport type {\n ConfidenceSource,\n LaunchMethod,\n ModelFamily,\n TelemetryInstallScope,\n TelemetryStore,\n Tokenizer,\n ToolEventRecord,\n} from \"./types.js\";\n\n/** Options for {@link runServeProxy}. */\nexport interface RunServeProxyOptions {\n /** Connector id this server belongs to (stamped on every record). */\n connectorId: string;\n /** The real MCP server executable to spawn. */\n command: string;\n /** Arguments passed to that executable. */\n args: string[];\n /** Where measured records are appended. */\n store: TelemetryStore;\n /** Tokenizer used for measurement (defaults baked into measure helpers). */\n tokenizer: Tokenizer;\n /**\n * Telemetry model-family hint. \"auto\" infers the family from the MCP client's\n * `initialize` clientInfo.name; any explicit family wins outright.\n */\n modelFamilyHint: \"auto\" | ModelFamily;\n /** Host platform executing this proxy (stamped on every record). */\n hostPlatform: PlatformId;\n /** Host session id (stamped on every record). */\n sessionId: string;\n /** Hashed stable project identity (stamped on every record). */\n projectKey: string;\n /** Human-readable project directory (stamped on every record). */\n projectDir: string;\n /** When true, tokenize the `tools/list` schema once → tool-defs overhead. */\n measureToolDefs: boolean;\n /**\n * Install scope (global user vs project-local) stamped on every record.\n * OPTIONAL: omitted for configs written before scope plumbing existed, leaving\n * the field off the row so it reads as \"unknown\".\n */\n installScope?: TelemetryInstallScope;\n /**\n * How the wrapped server was launched (npx/bunx/uvx/node/binary/http), stamped\n * on every record. OPTIONAL for the same backward-compat reason as above.\n */\n launchMethod?: LaunchMethod;\n}\n\n// ── JSON-RPC shapes we read (kept local + narrow; everything else opaque) ─────\n\n/** A client→server `tools/call` we remember until its result comes back. */\ninterface PendingCall {\n toolName: string;\n args: unknown;\n}\n\n/**\n * Canonical string form of a tool call's arguments for an off-box count_tokens\n * sample — mirrors the tokenizer's own serialization so the sampled text equals\n * the bytes we approximated locally. A string passes through; anything else is\n * JSON-stringified; a value that stringifies to undefined becomes \"\".\n */\nfunction canonicalArgs(value: unknown): string {\n if (typeof value === \"string\") return value;\n try {\n return JSON.stringify(value) ?? \"\";\n } catch {\n return \"\";\n }\n}\n\n/**\n * Run the telemetry-wrapping MCP stdio proxy.\n *\n * Spawns `command args` with piped stdin/stdout (stderr inherited), forwards\n * both directions byte-for-byte, and measures `tools/call` round-trips and the\n * one-time `tools/list` tool-defs overhead into `store`. Resolves with the\n * child's exit code (or a signal-derived code) once the child closes.\n */\nexport async function runServeProxy(\n opts: RunServeProxyOptions,\n): Promise<number> {\n const {\n connectorId,\n command,\n args,\n store,\n tokenizer,\n modelFamilyHint,\n hostPlatform,\n sessionId,\n projectKey,\n projectDir,\n measureToolDefs: shouldMeasureToolDefs,\n installScope,\n launchMethod,\n } = opts;\n\n // Global kill switch: still proxy transparently, but skip ALL measurement.\n const measuringEnabled = process.env.AGENT_CONNECTOR_TELEMETRY !== \"0\";\n // OPT-IN Anthropic count_tokens calibration. Resolved once per session — the\n // gate (AGENT_CONNECTOR_CALIBRATE + ANTHROPIC_API_KEY) is process-level and\n // does not change mid-session. Off by default; privacy-safe.\n const calibrationEnabled = isCalibrationEnabled();\n\n // spawnChild fixes native-Windows package-runner launches: a bare npx/uvx\n // resolves to a .cmd shim that raw CreateProcess can't find/launch, so it is\n // run via a quoted single command line with a shell. No-op on macOS/Linux.\n const child = spawnChild(command, args, {\n stdio: [\"pipe\", \"pipe\", \"inherit\"],\n env: process.env,\n });\n\n // ── Per-session measurement state ───────────────────────────────────────\n // Family resolved from the client's `initialize` (or the hint) and cached.\n let family: ModelFamily = inferModelFamily(\"\", modelFamilyHint);\n // Outstanding tools/call requests, keyed by JSON-RPC id.\n const pending = new Map<string, PendingCall>();\n // Monotonic sequence so two records in the same ms still get distinct ids.\n let seq = 0;\n // tools/list overhead is measured exactly once per session.\n let toolDefsMeasured = false;\n\n /**\n * Build a base record stamped with the per-session identity fields plus the\n * scope dimensions. `installScope` / `launchMethod` are spread in ONLY when\n * defined, so a session without them leaves those fields off the row entirely\n * (read as \"unknown\") rather than writing an explicit `undefined`.\n */\n function baseRecord(): Omit<\n ToolEventRecord,\n \"toolName\" | \"scope\" | \"inputTokens\" | \"outputTokens\" | \"confidenceSource\" | \"isError\"\n > {\n return {\n id: newRecordId(seq++),\n ts: Date.now(),\n connectorId,\n hostPlatform,\n sessionId,\n projectKey,\n projectDir,\n ...(installScope !== undefined ? { installScope } : {}),\n ...(launchMethod !== undefined ? { launchMethod } : {}),\n };\n }\n\n /**\n * Inspect one parsed CLIENT→SERVER message. Caches the model family on\n * `initialize` and remembers `tools/call` requests so their results can be\n * measured when they come back. Never throws into the data path.\n */\n function onClientMessage(msg: JsonRpcMessage): void {\n const method = msg.method;\n if (method === \"initialize\") {\n const params = isObject(msg.params) ? msg.params : undefined;\n const clientInfo =\n params && isObject(params[\"clientInfo\"])\n ? (params[\"clientInfo\"] as Record<string, unknown>)\n : undefined;\n const clientName =\n clientInfo && typeof clientInfo[\"name\"] === \"string\"\n ? (clientInfo[\"name\"] as string)\n : \"\";\n family = inferModelFamily(clientName, modelFamilyHint);\n return;\n }\n\n if (method === \"tools/call\") {\n const key = idKey(msg.id);\n if (key === null) return; // a call with no id has no result to match\n const params = isObject(msg.params) ? msg.params : undefined;\n const toolName =\n params && typeof params[\"name\"] === \"string\"\n ? (params[\"name\"] as string)\n : \"unknown\";\n const callArgs = params ? params[\"arguments\"] : undefined;\n pending.set(key, { toolName, args: callArgs });\n }\n }\n\n /**\n * Inspect one parsed SERVER→CLIENT message. Matches `tools/call` results to\n * remembered requests and measures them; measures `tools/list` results once.\n * Never throws into the data path.\n */\n function onServerMessage(msg: JsonRpcMessage): void {\n const key = idKey(msg.id);\n if (key === null) return; // notifications carry no id we can correlate\n\n const pendingCall = pending.get(key);\n if (pendingCall !== undefined) {\n pending.delete(key);\n recordToolCall(pendingCall, msg);\n return;\n }\n\n // Not a tracked tools/call — it may be the tools/list result we measure\n // once for the fixed tool-definition overhead.\n if (shouldMeasureToolDefs && !toolDefsMeasured) {\n const result = isObject(msg.result) ? msg.result : undefined;\n const tools = result ? result[\"tools\"] : undefined;\n if (Array.isArray(tools)) {\n recordToolDefs(tools);\n }\n }\n }\n\n /** Measure a matched tools/call round-trip and append the record. */\n function recordToolCall(call: PendingCall, response: JsonRpcMessage): void {\n const hasError = response.error !== undefined;\n const result = response.result;\n // A JSON-RPC error has no `result`; measure against an empty object so the\n // input (args) tokens are still recorded honestly.\n const resultForMeasure = hasError ? {} : result;\n const measurement = measureToolCall(\n call.args,\n resultForMeasure,\n family,\n tokenizer,\n );\n\n // OPT-IN calibration: for an anthropic session, nudge the locally-tokenized\n // approx counts toward Anthropic's real numbers via the learned factor, and\n // fire a sampled off-box count_tokens to keep that factor fresh. Both steps\n // are best-effort and wrapped so they can never break the record path.\n let inputTokens = measurement.inputTokens;\n let outputTokens = measurement.outputTokens;\n let confidenceSource: ConfidenceSource = measurement.source;\n if (calibrationEnabled && family === \"anthropic\") {\n try {\n ({ inputTokens, outputTokens, confidenceSource } = calibrateCounts(\n measurement.inputTokens,\n measurement.outputTokens,\n measurement.source,\n ));\n maybeSampleCalibration(call.args, measurement.inputTokens);\n } catch {\n // Calibration is a non-essential enrichment — fall back to the raw\n // measurement values already captured above.\n }\n }\n\n // MCP signals a tool-level failure via result.isError===true; a JSON-RPC\n // protocol error (response.error) is also a failure.\n const resultIsError =\n isObject(result) && result[\"isError\"] === true;\n store.append({\n ...baseRecord(),\n toolName: call.toolName,\n scope: \"call\",\n inputTokens,\n outputTokens,\n confidenceSource,\n isError: hasError || resultIsError,\n });\n }\n\n /**\n * Apply the learned anthropic factor to the approx input/output counts. Only\n * a `tokenizer-approx` measurement is calibratable (a heuristic fallback or\n * host-native count is left exactly as-is); the combined source becomes\n * `tokenizer-calibrated` only when at least one side was actually scaled.\n */\n function calibrateCounts(\n rawIn: number,\n rawOut: number,\n rawSource: ConfidenceSource,\n ): { inputTokens: number; outputTokens: number; confidenceSource: ConfidenceSource } {\n if (rawSource !== \"tokenizer-approx\") {\n return { inputTokens: rawIn, outputTokens: rawOut, confidenceSource: rawSource };\n }\n const cin = applyCalibration(rawIn, family);\n const cout = applyCalibration(rawOut, family);\n const calibrated =\n cin.source === \"tokenizer-calibrated\" || cout.source === \"tokenizer-calibrated\";\n return {\n inputTokens: cin.tokens,\n outputTokens: cout.tokens,\n confidenceSource: calibrated ? \"tokenizer-calibrated\" : \"tokenizer-approx\",\n };\n }\n\n /**\n * On a SAMPLED call, fire-and-forget an off-box count_tokens for the call's\n * input args and fold the resulting exact/approx ratio into the learned\n * factor. Returns immediately — the network round-trip never blocks\n * forwarding or measurement. Fail-open: any error is swallowed.\n */\n function maybeSampleCalibration(args: unknown, approxInputTokens: number): void {\n if (approxInputTokens <= 0) return; // nothing to ratio against\n if (!shouldSample()) return;\n const text = canonicalArgs(args);\n if (text === \"\") return;\n // Detached promise — intentionally NOT awaited so the proxy never blocks on\n // the network. Errors are handled inside countTokensAnthropic (returns null)\n // and the .catch is a belt-and-braces guard against an unhandled rejection.\n void countTokensAnthropic(text, modelForFamily(family))\n .then((exact) => {\n if (exact !== null && exact > 0) {\n recordSample(family, exact / approxInputTokens);\n }\n })\n .catch(() => {\n /* fail-open: a calibration sample must never surface an error */\n });\n }\n\n /** Measure the one-time tools/list overhead and append the record. */\n function recordToolDefs(tools: readonly unknown[]): void {\n toolDefsMeasured = true;\n const count = measureToolDefs(tools, family, tokenizer);\n store.append({\n ...baseRecord(),\n toolName: \"*\",\n scope: \"tool_defs\",\n inputTokens: count.tokens,\n outputTokens: 0,\n confidenceSource: count.source,\n isError: false,\n });\n }\n\n /** Parse one NDJSON line and route it, swallowing any measurement error. */\n function handleLine(line: string, direction: \"client\" | \"server\"): void {\n if (!measuringEnabled) return;\n let msg: JsonRpcMessage;\n try {\n const parsed = JSON.parse(line) as unknown;\n if (!isObject(parsed)) return;\n msg = parsed as JsonRpcMessage;\n } catch {\n return; // not a complete/valid JSON message — ignore for telemetry\n }\n try {\n if (direction === \"client\") onClientMessage(msg);\n else onServerMessage(msg);\n } catch {\n // Measurement must NEVER break the proxy. Drop the record silently.\n }\n }\n\n const clientLines = new LineBuffer((line) => handleLine(line, \"client\"));\n const serverLines = new LineBuffer((line) => handleLine(line, \"server\"));\n\n // ── Transparent byte forwarding (host stdin → child stdin) ───────────────\n // Forward VERBATIM first, then tee a copy into the line buffer to measure.\n // Honor backpressure: if the child's stdin buffer is full, pause the host\n // stdin and resume on drain so a slow server can't make us buffer unboundedly.\n process.stdin.on(\"data\", (chunk: Buffer) => {\n if (child.stdin && child.stdin.writable) {\n const ok = child.stdin.write(chunk);\n if (!ok) {\n process.stdin.pause();\n child.stdin.once(\"drain\", () => process.stdin.resume());\n }\n }\n if (measuringEnabled) {\n try {\n clientLines.push(chunk);\n } catch {\n /* tee side-channel must never affect forwarding */\n }\n }\n });\n process.stdin.on(\"end\", () => {\n if (child.stdin && !child.stdin.destroyed) child.stdin.end();\n });\n\n // ── Transparent byte forwarding (child stdout → host stdout) ─────────────\n if (child.stdout) {\n const childStdout = child.stdout;\n childStdout.on(\"data\", (chunk: Buffer) => {\n const ok = process.stdout.write(chunk);\n if (!ok) {\n childStdout.pause();\n process.stdout.once(\"drain\", () => childStdout.resume());\n }\n if (measuringEnabled) {\n try {\n serverLines.push(chunk);\n } catch {\n /* tee side-channel must never affect forwarding */\n }\n }\n });\n }\n\n // ── Signal propagation: forward SIGINT/SIGTERM to the child ──────────────\n const forwardSignal = (signal: NodeJS.Signals): void => {\n try {\n if (!child.killed) child.kill(signal);\n } catch {\n /* child may already be gone */\n }\n };\n const onSigint = (): void => forwardSignal(\"SIGINT\");\n const onSigterm = (): void => forwardSignal(\"SIGTERM\");\n process.on(\"SIGINT\", onSigint);\n process.on(\"SIGTERM\", onSigterm);\n\n // ── Resolve with the child's exit code (or signal-derived code) ──────────\n return await new Promise<number>((resolve) => {\n const finish = (code: number): void => {\n process.removeListener(\"SIGINT\", onSigint);\n process.removeListener(\"SIGTERM\", onSigterm);\n try {\n store.close();\n } catch {\n /* best-effort flush */\n }\n resolve(code);\n };\n\n child.on(\"error\", () => {\n // The server could not be spawned/launched. Surface a conventional\n // \"command not executable\" style failure code.\n finish(126);\n });\n\n child.on(\"close\", (code, signal) => {\n if (typeof code === \"number\") {\n finish(code);\n return;\n }\n // Killed by a signal → conventional 128 + signal number where known.\n if (signal) {\n const num = signalToNumber(signal);\n finish(num === undefined ? 1 : 128 + num);\n return;\n }\n finish(1);\n });\n });\n}\n\n/** Map the common termination signals to their numbers for exit-code math. */\nfunction signalToNumber(signal: NodeJS.Signals): number | undefined {\n const table: Partial<Record<NodeJS.Signals, number>> = {\n SIGINT: 2,\n SIGQUIT: 3,\n SIGKILL: 9,\n SIGTERM: 15,\n };\n return table[signal];\n}\n\nexport default runServeProxy;\n","/**\n * runtime/usage-event — the OPT-IN host-native turn-usage enricher (enricher 4a).\n *\n * Gemini CLI / Antigravity fire an `AfterModel` (Antigravity CLI: `PostInvocation`)\n * hook AFTER each model turn, whose stdin payload carries a `usageMetadata` block\n * with the host's OWN exact token accounting for that whole conversation turn:\n * { promptTokenCount, candidatesTokenCount, cachedContentTokenCount,\n * thoughtsTokenCount, totalTokenCount }\n * This is the single point in the whole matrix where a host reports REAL per-turn\n * usage to a command we control — so we record it as `confidenceSource:\"host-native\"`\n * (the top of CONFIDENCE_RANK), upgrading those rows from the serve-proxy estimate.\n *\n * DISTINCT, NEVER-SUMMED ORIGIN. Host-native turn usage is WHOLE-CONVERSATION, not\n * per-MCP. To avoid double-counting against (a) the per-MCP serve-proxy `call`\n * rows and (b) the usage-reader host-scan numbers, every record written here uses\n * the DISTINCT scope `\"model_turn\"`. The MCP leaderboard excludes that scope (just\n * as it special-cases `tool_defs`); the unified leaderboard surfaces it as its own\n * clearly-labeled section that is explicitly never added to the other two origins.\n *\n * PRIVACY + FAIL-OPEN. This enricher is OPT-IN at install time (see the adapters);\n * it stores AGGREGATE COUNTS ONLY (no raw content — the payload's prompt/response\n * text is never read). ANY parse / store / IO error degrades to exit 0 and records\n * NOTHING: a host-native usage hook must never break a model turn. This function\n * never throws.\n */\n\nimport { projectIdentity } from \"../core/paths.js\";\nimport { newRecordId, openStore } from \"../telemetry/store.js\";\nimport type { PlatformId } from \"../core/types.js\";\nimport type { ToolEventRecord } from \"../telemetry/types.js\";\n\n/** Flags + stdin the CLI hands to {@link runUsageEvent}. */\nexport interface RunUsageEventOptions {\n /** Host platform id from the command (`usage-event <platformId> …`). */\n platformId: string;\n /** Connector id from `--connector <id>` (stamped on the record). */\n connectorId: string;\n /** Raw stdin payload (host-native JSON). Empty string is tolerated → no record. */\n stdin: string;\n}\n\n/** Process-level result the CLI translates into an exit code. */\nexport interface RunUsageEventResult {\n /** Always 0 — a host-native usage hook must never block a model turn. */\n exitCode: number;\n /** True when a `model_turn` record was appended (false on any fail-open path). */\n recorded: boolean;\n}\n\n/** The never-records, never-throws result. */\nconst NOOP: RunUsageEventResult = { exitCode: 0, recorded: false };\n\nfunction isObject(v: unknown): v is Record<string, unknown> {\n return typeof v === \"object\" && v !== null && !Array.isArray(v);\n}\n\n/** Coerce a value to a non-negative safe integer (NaN/negatives/floats → 0). */\nfunction toNonNegInt(v: unknown): number {\n const n = typeof v === \"number\" ? v : typeof v === \"string\" ? Number(v) : NaN;\n if (!Number.isFinite(n) || n < 0) return 0;\n return Math.floor(n);\n}\n\n/** First non-empty string among the given keys of an object. */\nfunction firstStr(obj: Record<string, unknown>, keys: readonly string[]): string | undefined {\n for (const k of keys) {\n const v = obj[k];\n if (typeof v === \"string\" && v.trim() !== \"\") return v;\n }\n return undefined;\n}\n\n/** Read a token field tolerant of both camelCase and snake_case spellings. */\nfunction tokenField(\n meta: Record<string, unknown>,\n keys: readonly string[],\n): number {\n for (const k of keys) {\n if (k in meta) return toNonNegInt(meta[k]);\n }\n return 0;\n}\n\n/** Locate the `usageMetadata` block under either spelling, top-level or nested. */\nfunction findUsageMetadata(root: Record<string, unknown>): Record<string, unknown> | undefined {\n for (const k of [\"usageMetadata\", \"usage_metadata\"]) {\n if (isObject(root[k])) return root[k] as Record<string, unknown>;\n }\n // Some hosts nest the model response (with its usage) under a `response` /\n // `modelResponse` envelope — probe one level down, best-effort.\n for (const k of [\"response\", \"modelResponse\", \"model_response\"]) {\n const nested = root[k];\n if (isObject(nested)) {\n for (const mk of [\"usageMetadata\", \"usage_metadata\"]) {\n if (isObject(nested[mk])) return nested[mk] as Record<string, unknown>;\n }\n }\n }\n return undefined;\n}\n\n/** A registered PlatformId, or \"unknown\" when the id is not one we know. */\nconst KNOWN_PLATFORMS: ReadonlySet<string> = new Set<PlatformId>([\n \"claude-code\", \"codex\", \"cursor\", \"vscode-copilot\", \"jetbrains-copilot\",\n \"copilot-cli\", \"gemini-cli\", \"opencode\", \"kilo\", \"kilo-cli\", \"warp\", \"hermes\",\n \"openclaw\", \"zed\", \"antigravity\", \"antigravity-cli\", \"kiro\", \"qwen-code\",\n \"kimi\", \"pi\", \"omp\", \"droid\", \"roo-code\", \"trae\", \"amp\", \"codebuff\", \"mux\",\n \"crush\", \"goose\", \"synthetic\", \"unknown\",\n]);\n\nfunction asPlatformId(id: string): PlatformId {\n return (KNOWN_PLATFORMS.has(id) ? id : \"unknown\") as PlatformId;\n}\n\n/**\n * Record one host-native model turn. Parses the host's `usageMetadata`, maps it to\n * a DISTINCT `model_turn` `ToolEventRecord` (confidence `host-native`, toolName\n * `\"*\"`), and appends it to the shared telemetry store. NEVER throws and never\n * blocks the turn: every failure path resolves to {@link NOOP} (exit 0, nothing\n * recorded).\n */\nexport async function runUsageEvent(\n opts: RunUsageEventOptions,\n): Promise<RunUsageEventResult> {\n try {\n // Global telemetry kill switch is honored by the store's append (no-op when\n // AGENT_CONNECTOR_TELEMETRY=0); we still parse cheaply and let append drop it.\n const trimmed = opts.stdin.trim();\n if (trimmed === \"\") return NOOP;\n\n let raw: unknown;\n try {\n raw = JSON.parse(trimmed);\n } catch {\n return NOOP; // malformed payload → fail-open, record nothing\n }\n if (!isObject(raw)) return NOOP;\n\n const meta = findUsageMetadata(raw);\n if (meta === undefined) return NOOP;\n\n const promptTokens = tokenField(meta, [\"promptTokenCount\", \"prompt_token_count\"]);\n const candidates = tokenField(meta, [\"candidatesTokenCount\", \"candidates_token_count\"]);\n const cached = tokenField(meta, [\"cachedContentTokenCount\", \"cached_content_token_count\"]);\n const thoughts = tokenField(meta, [\"thoughtsTokenCount\", \"thoughts_token_count\"]);\n\n // promptTokenCount is cache-INCLUSIVE (Gemini-family semantics, mirrored by\n // the antigravity-shared usage reader): net fresh input = prompt - cached.\n const inputTokens = Math.max(0, promptTokens - Math.min(cached, promptTokens));\n // Output = generated candidates + reasoning (\"thoughts\") tokens.\n const outputTokens = candidates + thoughts;\n\n // A turn with no measurable tokens is not worth a row.\n if (inputTokens === 0 && outputTokens === 0) return NOOP;\n\n // Identity: prefer payload session/cwd; fall back to process.cwd() for the\n // project key so a turn always lands in a stable project partition.\n const sessionId =\n firstStr(raw, [\"session_id\", \"sessionId\", \"conversationId\", \"conversation_id\"]) ?? \"\";\n const cwd = firstStr(raw, [\"cwd\", \"workspace\", \"projectDir\", \"project_dir\"]) ?? process.cwd();\n const id = projectIdentity(cwd);\n\n const record: ToolEventRecord = {\n id: newRecordId(0),\n ts: Date.now(),\n connectorId: opts.connectorId,\n toolName: \"*\",\n scope: \"model_turn\",\n hostPlatform: asPlatformId(opts.platformId),\n sessionId,\n projectKey: id.key,\n projectDir: id.dir,\n inputTokens,\n outputTokens,\n confidenceSource: \"host-native\",\n isError: false,\n };\n\n const store = openStore({});\n try {\n store.append(record);\n } finally {\n try {\n store.close();\n } catch {\n /* best-effort flush */\n }\n }\n return { exitCode: 0, recorded: true };\n } catch {\n // Fail-open: a host-native usage enricher must never surface an error.\n return NOOP;\n }\n}\n\nexport default runUsageEvent;\n"],"mappings":"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","names":["isObject","args","isObject"]}
|