@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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/adapters/detect.ts"],"sourcesContent":["/**\n * adapters/detect — two complementary detection answers.\n *\n * 1. detectInstalledPlatforms(projectDir): which hosts are INSTALLED on this\n * machine (probe each adapter's config dirs / marker files). Drives the\n * install planner (\"auto\" target expansion, `doctor`).\n *\n * 2. detectRuntimeHost(env): which host is EXECUTING right now (read env\n * markers the host runtime injects into its child processes). Drives the\n * universal hook entrypoint — it must know which adapter's wire format the\n * stdin payload is in before it can parse it.\n *\n * Both derive their platform set from `ADAPTER_REGISTRY` (the single source of\n * truth in registry.ts), generalizing context-mode's detection cascade\n * (env-var tier → config-dir tier → low-confidence fallback) to our\n * Adapter/AdapterFactory contract. The config-dir tier is delegated to each\n * adapter's `detectInstalled()` rather than duplicated here, so adding a\n * platform never requires editing this file.\n */\n\nimport type { DetectedPlatform, DetectionSignal, PlatformId } from \"../core/types.js\";\nimport { ADAPTER_REGISTRY, loadAdapter } from \"./registry.js\";\n\n/**\n * Detect every platform installed on this machine.\n *\n * Loads each registered adapter and calls its `detectInstalled(projectDir)`\n * (which probes the platform's native config dirs + marker files), returning\n * only those reported `installed === true`, in registry order. Adapters never\n * throw from detection, but we guard each call so one misbehaving adapter\n * cannot abort the whole probe.\n *\n * @param projectDir Resolved project root — lets project-scoped adapters look\n * for `<projectDir>/.mcp.json`, `<projectDir>/.cursor`, etc.\n */\nexport async function detectInstalledPlatforms(\n projectDir: string,\n): Promise<DetectedPlatform[]> {\n const adapters = await Promise.all(\n ADAPTER_REGISTRY.map(async (factory) => {\n try {\n return await factory.load();\n } catch {\n return undefined;\n }\n }),\n );\n\n const detected: DetectedPlatform[] = [];\n for (const adapter of adapters) {\n if (!adapter) continue;\n try {\n const result = adapter.detectInstalled(projectDir);\n if (result.installed) detected.push(result);\n } catch {\n // A single adapter's detection failure must not sink the whole probe.\n }\n }\n return detected;\n}\n\n/**\n * One env-marker rule for runtime-host detection. `vars` is checked in order;\n * the FIRST rule with any non-empty matching env var wins, so the table order\n * is the detection precedence (forks before parents). Each var is documented at\n * the rule so the source of the marker is auditable.\n */\ninterface RuntimeSignalRule {\n readonly platform: PlatformId;\n /** Env var names that prove \"this host is executing me\". */\n readonly vars: readonly string[];\n /** Human-readable note (printed in the DetectionSignal.reason). */\n readonly note: string;\n}\n\n/**\n * Ordered env-marker table. Forks BEFORE parents (cursor — a VS Code fork —\n * precedes any future vscode-copilot entry so a Cursor session inside a\n * VS Code-derived shell is not misclassified). Markers are verified against\n * each host's source:\n *\n * - claude-code: CLAUDE_CODE_ENTRYPOINT is set on every Claude Code session;\n * CLAUDE_PLUGIN_ROOT is set when a plugin is loaded. Both are CC-exclusive\n * and serve as the disambiguators when CC runs inside another IDE's shell.\n * - codex: CODEX_THREAD_ID is set per exec (codex-rs/core exec_env);\n * CODEX_CI is set in CI mode (unified_exec process_manager).\n * - cursor: CURSOR_TRACE_ID is the widely-observed Cursor marker (Cursor\n * CLI / agent); CURSOR_CLI marks the Cursor terminal; CURSOR_CWD is the\n * documented workspace var.\n */\nconst RUNTIME_SIGNALS: readonly RuntimeSignalRule[] = [\n {\n platform: \"claude-code\",\n vars: [\"CLAUDE_CODE_ENTRYPOINT\", \"CLAUDE_PLUGIN_ROOT\", \"CLAUDE_PROJECT_DIR\", \"CLAUDE_SESSION_ID\"],\n note: \"Claude Code env marker set\",\n },\n {\n platform: \"cursor\",\n vars: [\"CURSOR_TRACE_ID\", \"CURSOR_CLI\", \"CURSOR_CWD\"],\n note: \"Cursor env marker set\",\n },\n {\n platform: \"codex\",\n vars: [\"CODEX_THREAD_ID\", \"CODEX_CI\"],\n note: \"Codex env marker set\",\n },\n];\n\n/**\n * Identify which host runtime is executing the current process from environment\n * markers. High confidence on an env-marker hit; otherwise an explicit\n * `AGENT_CONNECTOR_PLATFORM` override (high confidence, validated against the\n * registry) is honored; failing both, returns `unknown` at low confidence so\n * the caller can decide on a safe default.\n *\n * Pure with respect to its `env` argument (defaults to `process.env`) so it is\n * trivially testable — pass a synthetic env to assert each rule.\n */\nexport function detectRuntimeHost(env: NodeJS.ProcessEnv = process.env): DetectionSignal {\n // ── Explicit override (highest priority, validated against the registry) ──\n const override = env.AGENT_CONNECTOR_PLATFORM;\n if (override && override.trim() !== \"\") {\n if (REGISTERED_RUNTIME_IDS.has(override as PlatformId)) {\n return {\n platform: override as PlatformId,\n confidence: \"high\",\n reason: `AGENT_CONNECTOR_PLATFORM=${override} override`,\n };\n }\n }\n\n // ── Env-marker tier (forks before parents; first hit wins) ──────────────\n for (const rule of RUNTIME_SIGNALS) {\n const hit = rule.vars.find((name) => {\n const value = env[name];\n return typeof value === \"string\" && value !== \"\";\n });\n if (hit) {\n return {\n platform: rule.platform,\n confidence: \"high\",\n reason: `${rule.note} (${hit})`,\n };\n }\n }\n\n // ── Fallback: no host marker present ────────────────────────────────────\n return {\n platform: \"unknown\",\n confidence: \"low\",\n reason: \"no host runtime env marker detected\",\n };\n}\n\n/** Platform ids the runtime-signal table knows how to detect. */\nconst REGISTERED_RUNTIME_IDS: ReadonlySet<PlatformId> = new Set(\n RUNTIME_SIGNALS.map((rule) => rule.platform),\n);\n\n// Re-export for callers that resolve an adapter straight from a detection\n// result without reaching into registry.ts.\nexport { loadAdapter };\n"],"mappings":";;;;;;AAmCA,eAAsB,yBACpB,YAC6B;AAC7B,QAAM,WAAW,MAAM,QAAQ;AAAA,IAC7B,iBAAiB,IAAI,OAAO,YAAY;AACtC,UAAI;AACF,eAAO,MAAM,QAAQ,KAAK;AAAA,MAC5B,QAAQ;AACN,eAAO;AAAA,MACT;AAAA,IACF,CAAC;AAAA,EACH;AAEA,QAAM,WAA+B,CAAC;AACtC,aAAW,WAAW,UAAU;AAC9B,QAAI,CAAC,QAAS;AACd,QAAI;AACF,YAAM,SAAS,QAAQ,gBAAgB,UAAU;AACjD,UAAI,OAAO,UAAW,UAAS,KAAK,MAAM;AAAA,IAC5C,QAAQ;AAAA,IAER;AAAA,EACF;AACA,SAAO;AACT;AA+BA,IAAM,kBAAgD;AAAA,EACpD;AAAA,IACE,UAAU;AAAA,IACV,MAAM,CAAC,0BAA0B,sBAAsB,sBAAsB,mBAAmB;AAAA,IAChG,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,UAAU;AAAA,IACV,MAAM,CAAC,mBAAmB,cAAc,YAAY;AAAA,IACpD,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,UAAU;AAAA,IACV,MAAM,CAAC,mBAAmB,UAAU;AAAA,IACpC,MAAM;AAAA,EACR;AACF;AAYO,SAAS,kBAAkB,MAAyB,QAAQ,KAAsB;AAEvF,QAAM,WAAW,IAAI;AACrB,MAAI,YAAY,SAAS,KAAK,MAAM,IAAI;AACtC,QAAI,uBAAuB,IAAI,QAAsB,GAAG;AACtD,aAAO;AAAA,QACL,UAAU;AAAA,QACV,YAAY;AAAA,QACZ,QAAQ,4BAA4B,QAAQ;AAAA,MAC9C;AAAA,IACF;AAAA,EACF;AAGA,aAAW,QAAQ,iBAAiB;AAClC,UAAM,MAAM,KAAK,KAAK,KAAK,CAAC,SAAS;AACnC,YAAM,QAAQ,IAAI,IAAI;AACtB,aAAO,OAAO,UAAU,YAAY,UAAU;AAAA,IAChD,CAAC;AACD,QAAI,KAAK;AACP,aAAO;AAAA,QACL,UAAU,KAAK;AAAA,QACf,YAAY;AAAA,QACZ,QAAQ,GAAG,KAAK,IAAI,KAAK,GAAG;AAAA,MAC9B;AAAA,IACF;AAAA,EACF;AAGA,SAAO;AAAA,IACL,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,QAAQ;AAAA,EACV;AACF;AAGA,IAAM,yBAAkD,IAAI;AAAA,EAC1D,gBAAgB,IAAI,CAAC,SAAS,KAAK,QAAQ;AAC7C;","names":[]}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
resolveSpawnCommand
|
|
4
|
+
} from "./chunk-I5MLE6S7.js";
|
|
5
|
+
|
|
6
|
+
// src/core/spawn-child.ts
|
|
7
|
+
import { spawn } from "child_process";
|
|
8
|
+
function winQuoteArg(s) {
|
|
9
|
+
return `"${s.replace(/"/g, '""')}"`;
|
|
10
|
+
}
|
|
11
|
+
function spawnChild(command, args, options) {
|
|
12
|
+
const resolved = resolveSpawnCommand(command);
|
|
13
|
+
if (!resolved.needsShell) return spawn(resolved.file, args, options);
|
|
14
|
+
const line = [resolved.file, ...args].map(winQuoteArg).join(" ");
|
|
15
|
+
return spawn(line, { ...options, shell: true });
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export {
|
|
19
|
+
spawnChild
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=chunk-F5RX62T7.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/spawn-child.ts"],"sourcesContent":["/**\n * core/spawn-child — the cross-platform child_process.spawn wrapper.\n *\n * Kept SEPARATE from core/spawn.ts (pure string/path helpers, imported widely\n * and early) so that pulling in `node:child_process` here does not perturb the\n * module-eval order of test suites that vi.mock(\"node:child_process\").\n */\n\nimport { type ChildProcess, type SpawnOptions, spawn } from \"node:child_process\";\n\nimport { resolveSpawnCommand } from \"./spawn.js\";\n\n/**\n * Quote one token for a cmd.exe command line: wrap in double quotes, doubling any\n * embedded double quote. Sufficient for the paths / package names / flags we\n * spawn (connector config, not untrusted end-user input) — we intentionally do\n * not escape cmd metacharacters (& | ^ %), which never appear in those tokens.\n */\nfunction winQuoteArg(s: string): string {\n return `\"${s.replace(/\"/g, '\"\"')}\"`;\n}\n\n/**\n * Cross-platform child spawn that fixes native-Windows package-runner launches.\n * Direct spawn on macOS/Linux. On win32 it routes through\n * {@link resolveSpawnCommand}; an `.exe` runs directly, while a `.cmd`/`.bat`\n * (npx.cmd, the agent-connector.cmd launcher) is launched via a SINGLE quoted\n * command line with `shell: true` — a string rather than an args array, which\n * Node requires for a batch file AND which avoids the DEP0190 deprecation that\n * `shell: true` + an args array triggers on Node ≥ 24.\n */\nexport function spawnChild(\n command: string,\n args: string[],\n options: SpawnOptions,\n): ChildProcess {\n const resolved = resolveSpawnCommand(command);\n if (!resolved.needsShell) return spawn(resolved.file, args, options);\n const line = [resolved.file, ...args].map(winQuoteArg).join(\" \");\n return spawn(line, { ...options, shell: true });\n}\n"],"mappings":";;;;;;AAQA,SAA+C,aAAa;AAU5D,SAAS,YAAY,GAAmB;AACtC,SAAO,IAAI,EAAE,QAAQ,MAAM,IAAI,CAAC;AAClC;AAWO,SAAS,WACd,SACA,MACA,SACc;AACd,QAAM,WAAW,oBAAoB,OAAO;AAC5C,MAAI,CAAC,SAAS,WAAY,QAAO,MAAM,SAAS,MAAM,MAAM,OAAO;AACnE,QAAM,OAAO,CAAC,SAAS,MAAM,GAAG,IAAI,EAAE,IAAI,WAAW,EAAE,KAAK,GAAG;AAC/D,SAAO,MAAM,MAAM,EAAE,GAAG,SAAS,OAAO,KAAK,CAAC;AAChD;","names":[]}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
ensureDir
|
|
4
|
+
} from "./chunk-TRQKHP7D.js";
|
|
5
|
+
|
|
6
|
+
// src/core/config-patch-ledger.ts
|
|
7
|
+
import { createHash, randomBytes } from "crypto";
|
|
8
|
+
import {
|
|
9
|
+
existsSync,
|
|
10
|
+
readFileSync,
|
|
11
|
+
renameSync,
|
|
12
|
+
rmSync,
|
|
13
|
+
writeFileSync
|
|
14
|
+
} from "fs";
|
|
15
|
+
import { dirname, join } from "path";
|
|
16
|
+
var CONFIG_PATCH_SEGMENT_RE = /^[A-Za-z0-9_-]+$/;
|
|
17
|
+
function isValidConfigPatchKey(key) {
|
|
18
|
+
if (typeof key !== "string" || key.length === 0) return false;
|
|
19
|
+
return key.split(".").every((seg) => CONFIG_PATCH_SEGMENT_RE.test(seg));
|
|
20
|
+
}
|
|
21
|
+
function isJsonValue(value) {
|
|
22
|
+
if (value === null) return true;
|
|
23
|
+
switch (typeof value) {
|
|
24
|
+
case "string":
|
|
25
|
+
case "boolean":
|
|
26
|
+
return true;
|
|
27
|
+
case "number":
|
|
28
|
+
return Number.isFinite(value);
|
|
29
|
+
case "object":
|
|
30
|
+
break;
|
|
31
|
+
default:
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
if (Array.isArray(value)) return value.every((v) => isJsonValue(v));
|
|
35
|
+
const proto = Object.getPrototypeOf(value);
|
|
36
|
+
if (proto !== Object.prototype && proto !== null) return false;
|
|
37
|
+
return Object.values(value).every((v) => isJsonValue(v));
|
|
38
|
+
}
|
|
39
|
+
function configPatchNamespaceViolation(key) {
|
|
40
|
+
const head = key.split(".")[0] ?? "";
|
|
41
|
+
if (head === "hooks") {
|
|
42
|
+
return `"${key}" targets the hooks config agent-connector already models; declare it via \`hooks\` (normalized) or \`platforms.<id>.nativeHooks\` instead`;
|
|
43
|
+
}
|
|
44
|
+
if (head === "mcpServers" || head === "enableAllProjectMcpServers" || head === "enabledMcpjsonServers" || head === "disabledMcpjsonServers") {
|
|
45
|
+
return `"${key}" targets MCP server registration agent-connector already models; declare it via \`server\` / \`platforms.<id>.server\` / \`extra\` instead`;
|
|
46
|
+
}
|
|
47
|
+
if (head === "statusLine") {
|
|
48
|
+
return `"${key}" is modeled by the statusline surface; declare it via \`statusline: { render }\` instead`;
|
|
49
|
+
}
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
function configPatchManualEdit(patch) {
|
|
53
|
+
const docs = patch.docsUrl ? ` \u2014 see ${patch.docsUrl}` : "";
|
|
54
|
+
return `manual edit if wanted: set ${patch.key} = ${describeJsonValue(patch.value)} (${patch.reason})${docs}`;
|
|
55
|
+
}
|
|
56
|
+
function describeJsonValue(value) {
|
|
57
|
+
if (value === void 0) return "<absent>";
|
|
58
|
+
try {
|
|
59
|
+
return JSON.stringify(value);
|
|
60
|
+
} catch {
|
|
61
|
+
return String(value);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function canonicalJson(value) {
|
|
65
|
+
if (value === void 0) return "undefined";
|
|
66
|
+
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
67
|
+
if (Array.isArray(value)) {
|
|
68
|
+
return `[${value.map((v) => canonicalJson(v)).join(",")}]`;
|
|
69
|
+
}
|
|
70
|
+
const keys = Object.keys(value).sort();
|
|
71
|
+
const parts = keys.map((k) => `${JSON.stringify(k)}:${canonicalJson(value[k])}`);
|
|
72
|
+
return `{${parts.join(",")}}`;
|
|
73
|
+
}
|
|
74
|
+
function hashJsonValue(value) {
|
|
75
|
+
return createHash("sha256").update(canonicalJson(value)).digest("hex");
|
|
76
|
+
}
|
|
77
|
+
function jsonDeepEquals(a, b) {
|
|
78
|
+
return canonicalJson(a) === canonicalJson(b);
|
|
79
|
+
}
|
|
80
|
+
function configPatchLedgerPath(dataRoot) {
|
|
81
|
+
return join(dataRoot, "state", "config-patches.json");
|
|
82
|
+
}
|
|
83
|
+
function loadConfigPatchLedger(dataRoot) {
|
|
84
|
+
const path = configPatchLedgerPath(dataRoot);
|
|
85
|
+
if (!existsSync(path)) return { version: 1, entries: [] };
|
|
86
|
+
try {
|
|
87
|
+
const parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
88
|
+
if (!parsed || !Array.isArray(parsed.entries)) return { version: 1, entries: [] };
|
|
89
|
+
return { version: 1, entries: parsed.entries.filter(isPlausibleEntry) };
|
|
90
|
+
} catch {
|
|
91
|
+
return { version: 1, entries: [] };
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function isPlausibleEntry(e) {
|
|
95
|
+
if (e == null || typeof e !== "object") return false;
|
|
96
|
+
const entry = e;
|
|
97
|
+
return typeof entry.platform === "string" && typeof entry.file === "string" && typeof entry.key === "string" && Array.isArray(entry.owners);
|
|
98
|
+
}
|
|
99
|
+
function saveConfigPatchLedger(dataRoot, ledger) {
|
|
100
|
+
const path = configPatchLedgerPath(dataRoot);
|
|
101
|
+
ensureDir(dirname(path));
|
|
102
|
+
const tmpFile = `${path}.${process.pid}-${randomBytes(4).toString("hex")}.tmp`;
|
|
103
|
+
try {
|
|
104
|
+
writeFileSync(tmpFile, `${JSON.stringify(ledger, null, 2)}
|
|
105
|
+
`, "utf8");
|
|
106
|
+
renameSync(tmpFile, path);
|
|
107
|
+
} catch (err) {
|
|
108
|
+
rmSync(tmpFile, { force: true });
|
|
109
|
+
throw err;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function findLedgerEntry(ledger, platform, file, key) {
|
|
113
|
+
return ledger.entries.find(
|
|
114
|
+
(e) => e.platform === platform && e.file === file && e.key === key
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
function ledgerEntriesOwnedBy(ledger, platform, connectorId) {
|
|
118
|
+
return ledger.entries.filter(
|
|
119
|
+
(e) => e.platform === platform && e.owners.some((o) => o.connectorId === connectorId)
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
function createLedgerEntry(ledger, init) {
|
|
123
|
+
const entry = {
|
|
124
|
+
platform: init.platform,
|
|
125
|
+
file: init.file,
|
|
126
|
+
key: init.key,
|
|
127
|
+
writtenValue: init.value,
|
|
128
|
+
writtenValueHash: hashJsonValue(init.value),
|
|
129
|
+
prior: { present: false },
|
|
130
|
+
owners: [
|
|
131
|
+
{
|
|
132
|
+
connectorId: init.connectorId,
|
|
133
|
+
connectorVersion: init.connectorVersion,
|
|
134
|
+
installedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
135
|
+
}
|
|
136
|
+
]
|
|
137
|
+
};
|
|
138
|
+
ledger.entries.push(entry);
|
|
139
|
+
return entry;
|
|
140
|
+
}
|
|
141
|
+
function addLedgerOwner(entry, connectorId, connectorVersion) {
|
|
142
|
+
if (entry.owners.some((o) => o.connectorId === connectorId)) return false;
|
|
143
|
+
entry.owners.push({
|
|
144
|
+
connectorId,
|
|
145
|
+
connectorVersion,
|
|
146
|
+
installedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
147
|
+
});
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
function removeLedgerOwner(entry, connectorId) {
|
|
151
|
+
const before = entry.owners.length;
|
|
152
|
+
entry.owners = entry.owners.filter((o) => o.connectorId !== connectorId);
|
|
153
|
+
return { removed: entry.owners.length < before, lastOwner: entry.owners.length === 0 };
|
|
154
|
+
}
|
|
155
|
+
function dropLedgerEntry(ledger, entry) {
|
|
156
|
+
ledger.entries = ledger.entries.filter((e) => e !== entry);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export {
|
|
160
|
+
CONFIG_PATCH_SEGMENT_RE,
|
|
161
|
+
isValidConfigPatchKey,
|
|
162
|
+
isJsonValue,
|
|
163
|
+
configPatchNamespaceViolation,
|
|
164
|
+
configPatchManualEdit,
|
|
165
|
+
describeJsonValue,
|
|
166
|
+
hashJsonValue,
|
|
167
|
+
jsonDeepEquals,
|
|
168
|
+
loadConfigPatchLedger,
|
|
169
|
+
saveConfigPatchLedger,
|
|
170
|
+
findLedgerEntry,
|
|
171
|
+
ledgerEntriesOwnedBy,
|
|
172
|
+
createLedgerEntry,
|
|
173
|
+
addLedgerOwner,
|
|
174
|
+
removeLedgerOwner,
|
|
175
|
+
dropLedgerEntry
|
|
176
|
+
};
|
|
177
|
+
//# sourceMappingURL=chunk-FAHIMJRU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/config-patch-ledger.ts"],"sourcesContent":["/**\n * core/config-patch-ledger — the persisted, refcounted ownership ledger behind\n * the declarative `configPatch` surface, plus the shared configPatch helpers\n * (leaf-path grammar, JSON-value checks, the agent-connector namespace guard,\n * canonical hashing, and the manual-edit hint every skip-warn prints).\n *\n * WHY A LEDGER (and not the hooks-style recompute ownership): hook entries\n * embed the connector id in their command string, so uninstall can identify\n * \"mine\" by inspection. configPatch writes bare host keys (`true` is `true`) —\n * not attributable by inspection — and the same key may be needed by SEVERAL\n * connectors (a shared host feature flag). Without a persisted refcount,\n * connector A uninstalling would delete a key connector B still relies on.\n *\n * Contract (docs/ARCHITECTURE.md §4 \"configPatch\"):\n * • One global file at `<dataRoot>/state/config-patches.json`, written\n * ATOMICALLY (temp + rename) — shared across connectors because\n * refcounting requires a global view; survives a connector's record purge.\n * • Primary key per entry: (platform, file, key). `prior` is ALWAYS\n * `{ present: false }` — ownership only ever attaches to keys\n * agent-connector itself created (set-if-absent), so the blind\n * \"restore prior value\" footgun is structurally impossible.\n * • Uninstall removes a key ONLY when the releasing connector is the LAST\n * owner AND the current value still deep-equals `writtenValue` AND prior\n * was absent; any mismatch → skip-warn and leave the key in place.\n * • The ledger is advisory FOR DELETION ONLY: the worst desync outcome is a\n * skip-warn and a leftover key, never data loss.\n */\n\nimport { createHash, randomBytes } from \"node:crypto\";\nimport {\n existsSync,\n readFileSync,\n renameSync,\n rmSync,\n writeFileSync,\n} from \"node:fs\";\nimport { dirname, join } from \"node:path\";\n\nimport type { ConfigPatchDef, JsonValue, PlatformId } from \"./types.js\";\nimport { ensureDir } from \"./paths.js\";\n\n// ─────────────────────────────────────────────────────────────────────────\n// Shared configPatch helpers (grammar / values / namespace guard / hints)\n// ─────────────────────────────────────────────────────────────────────────\n\n/** Grammar for ONE dotted-path segment: no dots-in-key, no array indices. */\nexport const CONFIG_PATCH_SEGMENT_RE = /^[A-Za-z0-9_-]+$/;\n\n/**\n * True when `key` is a valid dotted LEAF path: 1+ segments joined by \".\",\n * every segment matching {@link CONFIG_PATCH_SEGMENT_RE}.\n */\nexport function isValidConfigPatchKey(key: unknown): key is string {\n if (typeof key !== \"string\" || key.length === 0) return false;\n return key.split(\".\").every((seg) => CONFIG_PATCH_SEGMENT_RE.test(seg));\n}\n\n/**\n * True when `value` is JSON-serializable data (string / finite number /\n * boolean / null / arrays / plain objects thereof). Rejects undefined,\n * functions, symbols, bigints, NaN/Infinity (JSON.stringify silently corrupts\n * those), and class instances other than plain objects/arrays.\n */\nexport function isJsonValue(value: unknown): value is JsonValue {\n if (value === null) return true;\n switch (typeof value) {\n case \"string\":\n case \"boolean\":\n return true;\n case \"number\":\n return Number.isFinite(value);\n case \"object\":\n break;\n default:\n return false;\n }\n if (Array.isArray(value)) return value.every((v) => isJsonValue(v));\n const proto = Object.getPrototypeOf(value);\n if (proto !== Object.prototype && proto !== null) return false;\n return Object.values(value as Record<string, unknown>).every((v) => isJsonValue(v));\n}\n\n/**\n * GUARDED NAMESPACE: keys agent-connector already models are NOT patchable —\n * the proper surface must be used instead (otherwise a connector could smuggle\n * hooks past the nativeHooks modeling/reporting, or fight the server install).\n * Returns a human-readable violation pointing at the proper surface, or null.\n * Checked at defineConnector (statically knowable) AND re-enforced in the\n * adapter (meta-loaded connectors must not bypass it).\n */\nexport function configPatchNamespaceViolation(key: string): string | null {\n const head = key.split(\".\")[0] ?? \"\";\n if (head === \"hooks\") {\n return `\"${key}\" targets the hooks config agent-connector already models; declare it via \\`hooks\\` (normalized) or \\`platforms.<id>.nativeHooks\\` instead`;\n }\n if (\n head === \"mcpServers\" ||\n head === \"enableAllProjectMcpServers\" ||\n head === \"enabledMcpjsonServers\" ||\n head === \"disabledMcpjsonServers\"\n ) {\n return `\"${key}\" targets MCP server registration agent-connector already models; declare it via \\`server\\` / \\`platforms.<id>.server\\` / \\`extra\\` instead`;\n }\n if (head === \"statusLine\") {\n return `\"${key}\" is modeled by the statusline surface; declare it via \\`statusline: { render }\\` instead`;\n }\n return null;\n}\n\n/**\n * The exact manual edit a user can perform when a patch is skipped (conflict,\n * drift, unsupported host, denylist…). Printed in every skip-warn so a single\n * declaration doubles as its own documented manual step.\n */\nexport function configPatchManualEdit(patch: ConfigPatchDef): string {\n const docs = patch.docsUrl ? ` — see ${patch.docsUrl}` : \"\";\n return (\n `manual edit if wanted: set ${patch.key} = ${describeJsonValue(patch.value)} ` +\n `(${patch.reason})${docs}`\n );\n}\n\n/** Compact single-line JSON rendering for diffs/warnings (\"<absent>\" for undefined). */\nexport function describeJsonValue(value: JsonValue | undefined): string {\n if (value === undefined) return \"<absent>\";\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Canonical JSON / deep equality\n// ─────────────────────────────────────────────────────────────────────────\n\n/** Canonical (sorted-keys) JSON of a value — the hash/equality basis. */\nexport function canonicalJson(value: JsonValue | undefined): string {\n if (value === undefined) return \"undefined\";\n if (value === null || typeof value !== \"object\") return JSON.stringify(value);\n if (Array.isArray(value)) {\n return `[${value.map((v) => canonicalJson(v)).join(\",\")}]`;\n }\n const keys = Object.keys(value).sort();\n const parts = keys.map((k) => `${JSON.stringify(k)}:${canonicalJson(value[k])}`);\n return `{${parts.join(\",\")}}`;\n}\n\n/** sha256 of the canonical JSON — the fast path; deep-equal is the authority. */\nexport function hashJsonValue(value: JsonValue): string {\n return createHash(\"sha256\").update(canonicalJson(value)).digest(\"hex\");\n}\n\n/** Order-insensitive (object keys) deep equality over JSON data. */\nexport function jsonDeepEquals(\n a: JsonValue | undefined,\n b: JsonValue | undefined,\n): boolean {\n return canonicalJson(a) === canonicalJson(b);\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Ledger shape + persistence\n// ─────────────────────────────────────────────────────────────────────────\n\n/** One connector's registration on a ledger entry. */\nexport interface ConfigPatchOwner {\n connectorId: string;\n connectorVersion: string;\n installedAt: string;\n}\n\n/** Refcounted ownership record for one (platform, file, key). */\nexport interface ConfigPatchLedgerEntry {\n platform: PlatformId;\n /** Absolute path of the file actually written (scope-resolved at install time). */\n file: string;\n /** Dotted leaf path — (platform, file, key) is the primary key. */\n key: string;\n writtenValue: JsonValue;\n /** sha256 of canonical (sorted-keys) JSON of writtenValue (fast path only). */\n writtenValueHash: string;\n /** Always { present: false } — ownership ONLY attaches to keys we created. */\n prior: { present: false };\n owners: ConfigPatchOwner[];\n}\n\nexport interface ConfigPatchLedger {\n version: 1;\n entries: ConfigPatchLedgerEntry[];\n}\n\n/** Ledger file path under the framework data-root. */\nexport function configPatchLedgerPath(dataRoot: string): string {\n return join(dataRoot, \"state\", \"config-patches.json\");\n}\n\n/**\n * Load the ledger; a missing or corrupt file degrades to an empty ledger\n * (advisory-for-deletion-only: a lost ledger can never cause data loss, only\n * retained keys + skip-warns).\n */\nexport function loadConfigPatchLedger(dataRoot: string): ConfigPatchLedger {\n const path = configPatchLedgerPath(dataRoot);\n if (!existsSync(path)) return { version: 1, entries: [] };\n try {\n const parsed = JSON.parse(readFileSync(path, \"utf8\")) as ConfigPatchLedger;\n if (!parsed || !Array.isArray(parsed.entries)) return { version: 1, entries: [] };\n return { version: 1, entries: parsed.entries.filter(isPlausibleEntry) };\n } catch {\n return { version: 1, entries: [] };\n }\n}\n\n/** Minimal shape sanity for a persisted entry (corrupt rows are dropped). */\nfunction isPlausibleEntry(e: unknown): e is ConfigPatchLedgerEntry {\n if (e == null || typeof e !== \"object\") return false;\n const entry = e as Partial<ConfigPatchLedgerEntry>;\n return (\n typeof entry.platform === \"string\" &&\n typeof entry.file === \"string\" &&\n typeof entry.key === \"string\" &&\n Array.isArray(entry.owners)\n );\n}\n\n/**\n * Persist the ledger ATOMICALLY: write to a temp file in the same directory,\n * then rename over the target (rename is atomic on the same filesystem).\n */\nexport function saveConfigPatchLedger(dataRoot: string, ledger: ConfigPatchLedger): void {\n const path = configPatchLedgerPath(dataRoot);\n ensureDir(dirname(path));\n const tmpFile = `${path}.${process.pid}-${randomBytes(4).toString(\"hex\")}.tmp`;\n try {\n writeFileSync(tmpFile, `${JSON.stringify(ledger, null, 2)}\\n`, \"utf8\");\n renameSync(tmpFile, path);\n } catch (err) {\n rmSync(tmpFile, { force: true });\n throw err;\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Ledger operations (pure in-memory; callers load → mutate → save)\n// ─────────────────────────────────────────────────────────────────────────\n\n/** Find the entry for (platform, file, key), or undefined. */\nexport function findLedgerEntry(\n ledger: ConfigPatchLedger,\n platform: PlatformId,\n file: string,\n key: string,\n): ConfigPatchLedgerEntry | undefined {\n return ledger.entries.find(\n (e) => e.platform === platform && e.file === file && e.key === key,\n );\n}\n\n/** Every entry on `platform` owned (at least in part) by `connectorId`. */\nexport function ledgerEntriesOwnedBy(\n ledger: ConfigPatchLedger,\n platform: PlatformId,\n connectorId: string,\n): ConfigPatchLedgerEntry[] {\n return ledger.entries.filter(\n (e) => e.platform === platform && e.owners.some((o) => o.connectorId === connectorId),\n );\n}\n\n/** Create a fresh entry (prior is absent BY CONSTRUCTION) and append it. */\nexport function createLedgerEntry(\n ledger: ConfigPatchLedger,\n init: {\n platform: PlatformId;\n file: string;\n key: string;\n value: JsonValue;\n connectorId: string;\n connectorVersion: string;\n },\n): ConfigPatchLedgerEntry {\n const entry: ConfigPatchLedgerEntry = {\n platform: init.platform,\n file: init.file,\n key: init.key,\n writtenValue: init.value,\n writtenValueHash: hashJsonValue(init.value),\n prior: { present: false },\n owners: [\n {\n connectorId: init.connectorId,\n connectorVersion: init.connectorVersion,\n installedAt: new Date().toISOString(),\n },\n ],\n };\n ledger.entries.push(entry);\n return entry;\n}\n\n/**\n * Register `connectorId` as a (co-)owner. Returns true when added, false when\n * it was already an owner (idempotent re-install → no ledger mutation).\n */\nexport function addLedgerOwner(\n entry: ConfigPatchLedgerEntry,\n connectorId: string,\n connectorVersion: string,\n): boolean {\n if (entry.owners.some((o) => o.connectorId === connectorId)) return false;\n entry.owners.push({\n connectorId,\n connectorVersion,\n installedAt: new Date().toISOString(),\n });\n return true;\n}\n\n/**\n * Remove `connectorId` from the owners. Returns whether an owner was removed\n * and whether the entry is now ownerless (last owner out).\n */\nexport function removeLedgerOwner(\n entry: ConfigPatchLedgerEntry,\n connectorId: string,\n): { removed: boolean; lastOwner: boolean } {\n const before = entry.owners.length;\n entry.owners = entry.owners.filter((o) => o.connectorId !== connectorId);\n return { removed: entry.owners.length < before, lastOwner: entry.owners.length === 0 };\n}\n\n/** Drop an entry from the ledger (identity match). */\nexport function dropLedgerEntry(\n ledger: ConfigPatchLedger,\n entry: ConfigPatchLedgerEntry,\n): void {\n ledger.entries = ledger.entries.filter((e) => e !== entry);\n}\n"],"mappings":"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","names":[]}
|
|
@@ -9,6 +9,9 @@ function narrowInstallScope(scope) {
|
|
|
9
9
|
function quoteArg(arg) {
|
|
10
10
|
return `"${arg.replace(/\\/g, "/")}"`;
|
|
11
11
|
}
|
|
12
|
+
function hasVerbSlot(hay, homeBinNorm, verb) {
|
|
13
|
+
return hay.includes(`"${homeBinNorm}" ${verb} `);
|
|
14
|
+
}
|
|
12
15
|
function buildHomeBinHookCommand(homeBinPath, platformId, event, connectorId) {
|
|
13
16
|
return `${quoteArg(homeBinPath)} hook ${platformId} ${event} --connector ${connectorId}`;
|
|
14
17
|
}
|
|
@@ -32,8 +35,31 @@ function buildUsageEventCommand(homeBinPath, platformId, connectorId) {
|
|
|
32
35
|
function isUsageEventCommand(command, homeBinPath, connectorId) {
|
|
33
36
|
if (!command) return false;
|
|
34
37
|
const hay = command.replace(/\\/g, "/");
|
|
35
|
-
|
|
36
|
-
if (!hay.includes(
|
|
38
|
+
const homeBinNorm = homeBinPath.replace(/\\/g, "/");
|
|
39
|
+
if (!hay.includes(homeBinNorm)) return false;
|
|
40
|
+
if (!hasVerbSlot(hay, homeBinNorm, "usage-event")) return false;
|
|
41
|
+
return isHomeBinHookCommand(command, homeBinPath, connectorId);
|
|
42
|
+
}
|
|
43
|
+
function buildHomeBinStatuslineCommand(homeBinPath, platformId, connectorId) {
|
|
44
|
+
return `${quoteArg(homeBinPath)} statusline ${platformId} --connector ${connectorId}`;
|
|
45
|
+
}
|
|
46
|
+
function isHomeBinStatuslineCommand(command, homeBinPath, connectorId) {
|
|
47
|
+
if (!command) return false;
|
|
48
|
+
const hay = command.replace(/\\/g, "/");
|
|
49
|
+
const homeBinNorm = homeBinPath.replace(/\\/g, "/");
|
|
50
|
+
if (!hay.includes(homeBinNorm)) return false;
|
|
51
|
+
if (!hasVerbSlot(hay, homeBinNorm, "statusline")) return false;
|
|
52
|
+
return isHomeBinHookCommand(command, homeBinPath, connectorId);
|
|
53
|
+
}
|
|
54
|
+
function buildHomeBinActionCommand(homeBinPath, platformId, actionId, connectorId) {
|
|
55
|
+
return `${quoteArg(homeBinPath)} action ${platformId} ${actionId} --connector ${connectorId}`;
|
|
56
|
+
}
|
|
57
|
+
function isHomeBinActionCommand(command, homeBinPath, connectorId) {
|
|
58
|
+
if (!command) return false;
|
|
59
|
+
const hay = command.replace(/\\/g, "/");
|
|
60
|
+
const homeBinNorm = homeBinPath.replace(/\\/g, "/");
|
|
61
|
+
if (!hay.includes(homeBinNorm)) return false;
|
|
62
|
+
if (!hasVerbSlot(hay, homeBinNorm, "action")) return false;
|
|
37
63
|
return isHomeBinHookCommand(command, homeBinPath, connectorId);
|
|
38
64
|
}
|
|
39
65
|
function isHostNativeUsageEnabled(telemetry, env = process.env) {
|
|
@@ -102,10 +128,14 @@ export {
|
|
|
102
128
|
isHomeBinHookCommand,
|
|
103
129
|
buildUsageEventCommand,
|
|
104
130
|
isUsageEventCommand,
|
|
131
|
+
buildHomeBinStatuslineCommand,
|
|
132
|
+
isHomeBinStatuslineCommand,
|
|
133
|
+
buildHomeBinActionCommand,
|
|
134
|
+
isHomeBinActionCommand,
|
|
105
135
|
isHostNativeUsageEnabled,
|
|
106
136
|
shouldWrapForTelemetry,
|
|
107
137
|
buildServeWrapperCommand,
|
|
108
138
|
resolveSpawnCommand,
|
|
109
139
|
detectLaunchMethod
|
|
110
140
|
};
|
|
111
|
-
//# sourceMappingURL=chunk-
|
|
141
|
+
//# sourceMappingURL=chunk-I5MLE6S7.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/spawn.ts"],"sourcesContent":["/**\n * core/spawn — cross-platform command construction.\n *\n * Borrowed from context-mode (issues #369/#372/#548/#738): bare `node` is\n * unreliable on Windows Git Bash (MSYS) and MSYS rewrites absolute paths on\n * non-C: drives. Always use the resolved runtime path, forward slashes, and\n * double-quoting. No-ops on macOS/Linux.\n */\n\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nimport type { InstallScope, PlatformId, ServerDef } from \"./types.js\";\nimport type {\n LaunchMethod,\n TelemetryInstallScope,\n} from \"../telemetry/types.js\";\n\n/**\n * Narrow the framework's 5-value {@link InstallScope} down to the two telemetry\n * slicing buckets: only a `project`-local install is `project`; everything else\n * (system/user/profile/managed) is global and reads as `user`.\n */\nexport function narrowInstallScope(scope: InstallScope): TelemetryInstallScope {\n return scope === \"project\" ? \"project\" : \"user\";\n}\n\n/** Build `\"<nodePath>\" \"<scriptPath>\"`. */\nexport function buildNodeCommand(\n scriptPath: string,\n opts?: { nodePath?: string },\n): string {\n const nodePath = (opts?.nodePath ?? process.execPath).replace(/\\\\/g, \"/\");\n const safe = scriptPath.replace(/\\\\/g, \"/\");\n return `\"${nodePath}\" \"${safe}\"`;\n}\n\n/**\n * Strict inverse of buildNodeCommand. Returns the two quoted tokens, or null if\n * `cmd` was not produced by buildNodeCommand (no fragile last-whitespace tail\n * grabbing — that was the #548 doubled-path bug when paths contained spaces).\n */\nexport function parseNodeCommand(\n cmd: string,\n): { nodePath: string; scriptPath: string } | null {\n if (typeof cmd !== \"string\" || cmd.length === 0) return null;\n const m = cmd.match(/^\"([^\"]+)\"\\s+\"([^\"]+)\"\\s*$/);\n if (!m || !m[1] || !m[2]) return null;\n return { nodePath: m[1], scriptPath: m[2] };\n}\n\n/** Quote a single argument for inclusion in a host hook command string. */\nexport function quoteArg(arg: string): string {\n return `\"${arg.replace(/\\\\/g, \"/\")}\"`;\n}\n\n/**\n * True when `hay` (slash-normalized) has the quoted home-bin path IMMEDIATELY\n * followed by `verb` — i.e. the verb sits in its command SLOT (right after the\n * home binary), not merely somewhere in the argument list. This distinguishes\n * `\"<bin>\" statusline …` from `\"<bin>\" action … statusline …`: the action verb\n * takes a free-form `actionId` positional that can legitimately equal another\n * verb's name (`statusline` / `usage-event` / `hook`), and only the SLOT\n * position identifies the real verb. `homeBinNorm` is the slash-normalized\n * home-bin path the caller already derived.\n */\nfunction hasVerbSlot(hay: string, homeBinNorm: string, verb: string): boolean {\n return hay.includes(`\"${homeBinNorm}\" ${verb} `);\n}\n\n/**\n * Build the universal hook command a host config points at:\n * \"<homeBin>\" hook <platformId> <event> --connector <id>\n * Pointing every host at the one stable home binary is how a single update\n * propagates everywhere (docs/ARCHITECTURE.md §3 R1).\n */\nexport function buildHomeBinHookCommand(\n homeBinPath: string,\n platformId: string,\n event: string,\n connectorId: string,\n): string {\n return `${quoteArg(homeBinPath)} hook ${platformId} ${event} --connector ${connectorId}`;\n}\n\n/**\n * True when `command` is a home-bin hook command for exactly `connectorId`.\n *\n * Critical: the connector id is the LAST token of the hook command\n * (`... --connector <id>`), so a naive `command.includes(\"--connector \" + id)`\n * collides on shared-prefix ids — `--connector acme-db` contains\n * `--connector acme`, which would let uninstalling `acme` strip `acme-db`'s\n * hooks. We anchor the id token: the character after it must be end-of-string,\n * whitespace, or a closing double-quote (the JSON-embedded case). Connector ids\n * are kebab-case (ID_RE) so they never contain whitespace or quotes themselves.\n */\nexport function isHomeBinHookCommand(\n command: string | undefined,\n homeBinPath: string,\n connectorId: string,\n): boolean {\n if (!command) return false;\n // The stored command was forward-slashed by quoteArg(); homeBinPath() yields\n // NATIVE (back)slashes on Windows (node:path join). Normalize BOTH sides so the\n // ownership substring test holds on win32 (without this, detection always\n // returns false there → duplicate hooks on re-install + orphans on uninstall).\n // No-op on POSIX.\n const hay = command.replace(/\\\\/g, \"/\");\n if (!hay.includes(homeBinPath.replace(/\\\\/g, \"/\"))) return false;\n const token = `--connector ${connectorId}`;\n let from = 0;\n for (;;) {\n const idx = hay.indexOf(token, from);\n if (idx < 0) return false;\n const after = hay.charAt(idx + token.length);\n if (after === \"\" || after === '\"' || /\\s/.test(after)) return true;\n from = idx + token.length;\n }\n}\n\n/**\n * Build the OPT-IN host-native usage-event command an AfterModel / PostInvocation\n * hook points at:\n * \"<homeBin>\" usage-event <platformId> --connector <id>\n * Mirrors {@link buildHomeBinHookCommand} (same anchoring rules apply) but routes\n * to the hidden `usage-event` entrypoint, which records a DISTINCT `model_turn`\n * row instead of dispatching a connector handler.\n */\nexport function buildUsageEventCommand(\n homeBinPath: string,\n platformId: string,\n connectorId: string,\n): string {\n return `${quoteArg(homeBinPath)} usage-event ${platformId} --connector ${connectorId}`;\n}\n\n/**\n * True when `command` is OUR host-native usage-event command for exactly\n * `connectorId`. Same end-of-token anchoring as {@link isHomeBinHookCommand} so a\n * shared-prefix id can't collide; additionally requires the ` usage-event ` verb\n * so it is never confused with a plain `hook` command during uninstall.\n */\nexport function isUsageEventCommand(\n command: string | undefined,\n homeBinPath: string,\n connectorId: string,\n): boolean {\n if (!command) return false;\n // Normalize separators like isHomeBinHookCommand (win32 ownership detection).\n const hay = command.replace(/\\\\/g, \"/\");\n const homeBinNorm = homeBinPath.replace(/\\\\/g, \"/\");\n if (!hay.includes(homeBinNorm)) return false;\n if (!hasVerbSlot(hay, homeBinNorm, \"usage-event\")) return false;\n return isHomeBinHookCommand(command, homeBinPath, connectorId);\n}\n\n/**\n * Build the home-bin statusline command a host's status line config points at:\n * \"<homeBin>\" statusline <platformId> --connector <id>\n * Mirrors {@link buildHomeBinHookCommand} / {@link buildUsageEventCommand} (the\n * same single-home-binary indirection) but routes to the `statusline`\n * entrypoint, which renders the connector's HUD line for the host.\n */\nexport function buildHomeBinStatuslineCommand(\n homeBinPath: string,\n platformId: string,\n connectorId: string,\n): string {\n return `${quoteArg(homeBinPath)} statusline ${platformId} --connector ${connectorId}`;\n}\n\n/**\n * True when `command` is OUR home-bin statusline command for exactly\n * `connectorId`. Same end-of-token anchoring as {@link isHomeBinHookCommand} so a\n * shared-prefix id can't collide; additionally requires the ` statusline ` verb\n * so it is never confused with a plain `hook` / `usage-event` command.\n */\nexport function isHomeBinStatuslineCommand(\n command: string | undefined,\n homeBinPath: string,\n connectorId: string,\n): boolean {\n if (!command) return false;\n // Normalize separators like isHomeBinHookCommand (win32 ownership detection).\n const hay = command.replace(/\\\\/g, \"/\");\n const homeBinNorm = homeBinPath.replace(/\\\\/g, \"/\");\n if (!hay.includes(homeBinNorm)) return false;\n if (!hasVerbSlot(hay, homeBinNorm, \"statusline\")) return false;\n return isHomeBinHookCommand(command, homeBinPath, connectorId);\n}\n\n/**\n * Build the home-bin action command a future host affordance (slash command /\n * keybinding) points at:\n * \"<homeBin>\" action <platformId> <actionId> --connector <id>\n * Mirrors {@link buildHomeBinStatuslineCommand} (the same single-home-binary\n * indirection) but routes to the `action` entrypoint, which re-imports the\n * connector and runs the named action's run(ctx). v1 ships only this command\n * builder + the runtime verb; no adapter EMITS the affordance yet.\n */\nexport function buildHomeBinActionCommand(\n homeBinPath: string,\n platformId: string,\n actionId: string,\n connectorId: string,\n): string {\n return `${quoteArg(homeBinPath)} action ${platformId} ${actionId} --connector ${connectorId}`;\n}\n\n/**\n * True when `command` is OUR home-bin action command for exactly `connectorId`.\n * Same end-of-token anchoring as {@link isHomeBinHookCommand} so a shared-prefix\n * id can't collide; additionally requires the ` action ` verb so it is never\n * confused with a plain `hook` / `usage-event` / `statusline` command.\n */\nexport function isHomeBinActionCommand(\n command: string | undefined,\n homeBinPath: string,\n connectorId: string,\n): boolean {\n if (!command) return false;\n // Normalize separators like isHomeBinHookCommand (win32 ownership detection).\n const hay = command.replace(/\\\\/g, \"/\");\n const homeBinNorm = homeBinPath.replace(/\\\\/g, \"/\");\n if (!hay.includes(homeBinNorm)) return false;\n if (!hasVerbSlot(hay, homeBinNorm, \"action\")) return false;\n return isHomeBinHookCommand(command, homeBinPath, connectorId);\n}\n\n/**\n * Single source of truth for \"is OPT-IN host-native turn-usage capture enabled\n * for this connector?\" — read by the Gemini / Antigravity adapters at install\n * time to decide whether to ALSO write the AfterModel / PostInvocation usage hook.\n * Enabled when the connector opts in via telemetry.hostNativeUsage OR when the\n * install-time env switch AGENT_CONNECTOR_HOST_NATIVE=1 forces it on. Off by\n * default (privacy: host-native capture is never installed silently).\n */\nexport function isHostNativeUsageEnabled(\n telemetry: { enabled: boolean; hostNativeUsage?: boolean },\n env: NodeJS.ProcessEnv = process.env,\n): boolean {\n if (telemetry.enabled !== true) return false;\n if (env.AGENT_CONNECTOR_HOST_NATIVE === \"1\") return true;\n return telemetry.hostNativeUsage === true;\n}\n\n/**\n * Single source of truth for \"should this server be wrapped by `serve` for\n * telemetry?\" — so every adapter behaves identically even for a server that\n * skipped normalizeServer (e.g. a per-platform override). On by default for an\n * stdio server with a command, unless explicitly disabled or telemetry is off.\n */\nexport function shouldWrapForTelemetry(\n server: ServerDef,\n telemetry: { enabled: boolean },\n): boolean {\n return (\n server.wrapForTelemetry !== false &&\n telemetry.enabled === true &&\n server.transport === \"stdio\" &&\n typeof server.command === \"string\" &&\n server.command !== \"\"\n );\n}\n\n/**\n * Build the telemetry-wrapping server command:\n * \"<homeBin>\" serve --connector <id> --scope <scope> --host <platformId> -- <realCommand> <realArgs...>\n * Used when a stdio server opts into transparent telemetry capture.\n *\n * `scope` records the install dimension (global user vs project-local) on every\n * telemetry row so usage can be sliced by it later. It is OPTIONAL for backward\n * compatibility: when omitted, the `--scope` flag is not emitted and the runtime\n * treats the scope as \"unknown\".\n *\n * `platformId` bakes the install TARGET platform into the wrapper so the proxy\n * stamps `hostPlatform` correctly even under a headless spawn where runtime env\n * markers are absent (detectRuntimeHost only knows claude-code/cursor/codex and\n * otherwise mis-attributes). Emitted as `--host <platformId>` in the FLAG\n * section (before `--`). It is OPTIONAL + backward-compatible: when omitted the\n * `--host` flag is not emitted and the runtime falls back to env detection.\n */\nexport function buildServeWrapperCommand(\n homeBinPath: string,\n connectorId: string,\n realCommand: string,\n realArgs: string[],\n scope?: InstallScope,\n platformId?: PlatformId,\n): { command: string; args: string[] } {\n const flags = [\"serve\", \"--connector\", connectorId];\n if (scope !== undefined) flags.push(\"--scope\", narrowInstallScope(scope));\n if (platformId !== undefined) flags.push(\"--host\", platformId);\n return {\n command: homeBinPath,\n args: [...flags, \"--\", realCommand, ...realArgs],\n };\n}\n\n/** Injectable deps for {@link resolveSpawnCommand} (so the win32 branch is unit-testable on POSIX). */\nexport interface SpawnResolveDeps {\n platform?: NodeJS.Platform;\n /** PATH value (`;`-separated on Windows). */\n pathEnv?: string;\n /** PATHEXT value (`;`-separated). */\n pathExt?: string;\n /** File-existence probe (defaults to fs.existsSync). */\n exists?: (p: string) => boolean;\n}\n\n/** How a child command should be handed to spawn() on this platform. */\nexport interface SpawnResolution {\n /** The command to pass to spawn() (an absolute path on win32 when resolved). */\n file: string;\n /**\n * Whether spawn() MUST use `shell: true`. On native Windows a `.cmd`/`.bat`\n * shim (npx.cmd, pnpm.cmd, the agent-connector.cmd launcher) cannot be run by\n * raw CreateProcess — Node throws EINVAL since the 2024 security fix unless a\n * shell is used. `.exe` resolves directly with no shell.\n */\n needsShell: boolean;\n}\n\n/**\n * Resolve a child command for spawn() across platforms. NO-OP on macOS/Linux\n * (returns the command unchanged, no shell). On native Windows it fixes the two\n * spawn failure modes for bare package runners:\n * 1. raw CreateProcess ignores PATHEXT, so spawn(\"npx\") → ENOENT even though\n * `npx.cmd` is on PATH. We search PATH × PATHEXT and return the resolved\n * absolute path.\n * 2. a resolved `.cmd`/`.bat` still cannot be launched without a shell, so we\n * flag `needsShell` for those (and `.exe`/`.com` run directly).\n * A bare name that PATH search misses falls back to `{ file: command,\n * needsShell: true }` so cmd.exe's own PATHEXT lookup still finds it.\n */\nexport function resolveSpawnCommand(\n command: string,\n deps: SpawnResolveDeps = {},\n): SpawnResolution {\n const platform = deps.platform ?? process.platform;\n if (platform !== \"win32\") return { file: command, needsShell: false };\n\n const isBatch = (s: string): boolean => /\\.(cmd|bat)$/i.test(s);\n\n // Already a path or already has an extension → don't search; only decide shell.\n if (/[\\\\/]/.test(command) || /\\.[a-z0-9]+$/i.test(command)) {\n return { file: command, needsShell: isBatch(command) };\n }\n\n const exists = deps.exists ?? existsSync;\n const pathEnv = deps.pathEnv ?? process.env.PATH ?? process.env.Path ?? \"\";\n const pathExt = deps.pathExt ?? process.env.PATHEXT ?? \".COM;.EXE;.BAT;.CMD\";\n const dirs = pathEnv.split(\";\").filter((d) => d !== \"\");\n const exts = pathExt.split(\";\").filter((e) => e !== \"\");\n for (const dir of dirs) {\n for (const ext of exts) {\n const candidate = join(dir, command + ext);\n if (exists(candidate)) return { file: candidate, needsShell: isBatch(ext) };\n }\n }\n // Not found on PATH — let cmd.exe resolve it (handles shim dirs we may miss).\n return { file: command, needsShell: true };\n}\n\n/** Basenames (case-insensitive, sans common extensions) of the ephemeral package runners. */\nconst PACKAGE_RUNNERS: Record<string, Extract<LaunchMethod, \"npx\" | \"bunx\" | \"uvx\">> = {\n npx: \"npx\",\n bunx: \"bunx\",\n uvx: \"uvx\",\n};\n\n/** Basenames of language interpreters that launch a local script. */\nconst INTERPRETERS: ReadonlySet<string> = new Set([\"node\", \"bun\", \"deno\"]);\n\n/**\n * Strip a directory prefix and a trailing executable extension to get the bare\n * program name. Tolerates both POSIX and Windows separators (the wrapped command\n * may be an absolute Windows path) and lowercases for case-insensitive matching.\n */\nfunction commandBasename(realCommand: string): string {\n const noDir = realCommand.replace(/\\\\/g, \"/\").split(\"/\").pop() ?? realCommand;\n return noDir.replace(/\\.(exe|cmd|bat|com)$/i, \"\").toLowerCase();\n}\n\n/**\n * Classify how the real MCP server is launched, for the \"launch-method\" slicing\n * dimension. Package runners (npx/bunx/uvx) and interpreters (node/bun/deno) are\n * detected by the command basename. A remote (http) server is not launched\n * locally, so the caller — which alone knows the transport — passes\n * `isRemote: true` to force \"http\". Anything else resolves to \"binary\".\n */\nexport function detectLaunchMethod(\n realCommand: string,\n realArgs: string[],\n opts?: { isRemote?: boolean },\n): LaunchMethod {\n void realArgs; // reserved: args may later refine node-vs-script heuristics\n if (opts?.isRemote === true) return \"http\";\n if (typeof realCommand !== \"string\" || realCommand.trim() === \"\") {\n return \"unknown\";\n }\n const base = commandBasename(realCommand);\n if (base === \"\") return \"unknown\";\n const runner = PACKAGE_RUNNERS[base];\n if (runner !== undefined) return runner;\n if (INTERPRETERS.has(base)) return \"node\";\n return \"binary\";\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
resolveSpawnCommand
|
|
4
|
-
} from "./chunk-MEH7GC7R.js";
|
|
5
2
|
|
|
6
3
|
// src/core/logger.ts
|
|
7
4
|
var ORDER = {
|
|
@@ -27,20 +24,7 @@ var log = {
|
|
|
27
24
|
debug: (...args) => emit("debug", args)
|
|
28
25
|
};
|
|
29
26
|
|
|
30
|
-
// src/core/spawn-child.ts
|
|
31
|
-
import { spawn } from "child_process";
|
|
32
|
-
function winQuoteArg(s) {
|
|
33
|
-
return `"${s.replace(/"/g, '""')}"`;
|
|
34
|
-
}
|
|
35
|
-
function spawnChild(command, args, options) {
|
|
36
|
-
const resolved = resolveSpawnCommand(command);
|
|
37
|
-
if (!resolved.needsShell) return spawn(resolved.file, args, options);
|
|
38
|
-
const line = [resolved.file, ...args].map(winQuoteArg).join(" ");
|
|
39
|
-
return spawn(line, { ...options, shell: true });
|
|
40
|
-
}
|
|
41
|
-
|
|
42
27
|
export {
|
|
43
|
-
log
|
|
44
|
-
spawnChild
|
|
28
|
+
log
|
|
45
29
|
};
|
|
46
|
-
//# sourceMappingURL=chunk-
|
|
30
|
+
//# sourceMappingURL=chunk-KHO5WNTP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/logger.ts"],"sourcesContent":["/**\n * core/logger — minimal leveled logger. Writes human output to stderr so stdout\n * stays clean for machine-readable payloads (hook replies, --json output).\n */\n\nexport type LogLevel = \"silent\" | \"error\" | \"warn\" | \"info\" | \"debug\";\n\nconst ORDER: Record<LogLevel, number> = {\n silent: 0,\n error: 1,\n warn: 2,\n info: 3,\n debug: 4,\n};\n\nfunction currentLevel(): LogLevel {\n const env = (process.env.AGENT_CONNECTOR_LOG ?? \"info\").toLowerCase();\n return (env in ORDER ? env : \"info\") as LogLevel;\n}\n\nfunction emit(level: Exclude<LogLevel, \"silent\">, args: unknown[]): void {\n if (ORDER[currentLevel()] < ORDER[level]) return;\n const prefix = { error: \"✗\", warn: \"!\", info: \"›\", debug: \"·\" }[level];\n // eslint-disable-next-line no-console\n console.error(prefix, ...args);\n}\n\nexport const log = {\n error: (...args: unknown[]) => emit(\"error\", args),\n warn: (...args: unknown[]) => emit(\"warn\", args),\n info: (...args: unknown[]) => emit(\"info\", args),\n debug: (...args: unknown[]) => emit(\"debug\", args),\n};\n"],"mappings":";;;AAOA,IAAM,QAAkC;AAAA,EACtC,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AACT;AAEA,SAAS,eAAyB;AAChC,QAAM,OAAO,QAAQ,IAAI,uBAAuB,QAAQ,YAAY;AACpE,SAAQ,OAAO,QAAQ,MAAM;AAC/B;AAEA,SAAS,KAAK,OAAoC,MAAuB;AACvE,MAAI,MAAM,aAAa,CAAC,IAAI,MAAM,KAAK,EAAG;AAC1C,QAAM,SAAS,EAAE,OAAO,UAAK,MAAM,KAAK,MAAM,UAAK,OAAO,OAAI,EAAE,KAAK;AAErE,UAAQ,MAAM,QAAQ,GAAG,IAAI;AAC/B;AAEO,IAAM,MAAM;AAAA,EACjB,OAAO,IAAI,SAAoB,KAAK,SAAS,IAAI;AAAA,EACjD,MAAM,IAAI,SAAoB,KAAK,QAAQ,IAAI;AAAA,EAC/C,MAAM,IAAI,SAAoB,KAAK,QAAQ,IAAI;AAAA,EAC/C,OAAO,IAAI,SAAoB,KAAK,SAAS,IAAI;AACnD;","names":[]}
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from "./chunk-DBQMX75U.js";
|
|
5
5
|
import {
|
|
6
6
|
BaseAdapter
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-CPLK7GTE.js";
|
|
8
8
|
import {
|
|
9
9
|
buildHomeBinHookCommand,
|
|
10
10
|
buildServeWrapperCommand,
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
isHostNativeUsageEnabled,
|
|
14
14
|
isUsageEventCommand,
|
|
15
15
|
shouldWrapForTelemetry
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-I5MLE6S7.js";
|
|
17
17
|
|
|
18
18
|
// src/adapters/antigravity/index.ts
|
|
19
19
|
import { existsSync } from "fs";
|
|
@@ -710,4 +710,4 @@ export {
|
|
|
710
710
|
adapter,
|
|
711
711
|
antigravity_default
|
|
712
712
|
};
|
|
713
|
-
//# sourceMappingURL=chunk-
|
|
713
|
+
//# sourceMappingURL=chunk-LQRAPXS4.js.map
|
|
@@ -73,28 +73,36 @@ function renderInstallResult(result, verb) {
|
|
|
73
73
|
return lines.join("\n");
|
|
74
74
|
}
|
|
75
75
|
var COMMANDS = {
|
|
76
|
-
detect: () => import("./detect-
|
|
77
|
-
install: () => import("./install-
|
|
78
|
-
uninstall: () => import("./uninstall-
|
|
76
|
+
detect: () => import("./detect-KG5FG3EV.js"),
|
|
77
|
+
install: () => import("./install-BSR62UHJ.js"),
|
|
78
|
+
uninstall: () => import("./uninstall-ZYTW7YMZ.js"),
|
|
79
79
|
// `upgrade` is the single "bring everything current" verb (re-render host
|
|
80
80
|
// config + refresh the home pointer + managed channel guidance). `sync` and
|
|
81
81
|
// `update` are kept as back-compat aliases that route to the same module so
|
|
82
82
|
// existing scripts/docs keep working without a second concept to learn.
|
|
83
|
-
upgrade: () => import("./upgrade-
|
|
84
|
-
sync: () => import("./upgrade-
|
|
85
|
-
update: () => import("./upgrade-
|
|
86
|
-
package: () => import("./package-
|
|
87
|
-
doctor: () => import("./doctor-
|
|
88
|
-
status: () => import("./status-
|
|
89
|
-
telemetry: () => import("./telemetry-
|
|
90
|
-
usage: () => import("./usage-
|
|
91
|
-
leaderboard: () => import("./leaderboard-
|
|
92
|
-
hook: () => import("./hook-
|
|
93
|
-
|
|
83
|
+
upgrade: () => import("./upgrade-4LUEEOZW.js"),
|
|
84
|
+
sync: () => import("./upgrade-4LUEEOZW.js"),
|
|
85
|
+
update: () => import("./upgrade-4LUEEOZW.js"),
|
|
86
|
+
package: () => import("./package-ACZXJHWB.js"),
|
|
87
|
+
doctor: () => import("./doctor-FLZF34Y3.js"),
|
|
88
|
+
status: () => import("./status-LAJE3BM5.js"),
|
|
89
|
+
telemetry: () => import("./telemetry-B3DX3PWU.js"),
|
|
90
|
+
usage: () => import("./usage-ZFBVQF3H.js"),
|
|
91
|
+
leaderboard: () => import("./leaderboard-MJG24O35.js"),
|
|
92
|
+
hook: () => import("./hook-XR3Z45FB.js"),
|
|
93
|
+
// Internal (omitted from USAGE): the statusline (HUD) entrypoint a host's
|
|
94
|
+
// status line config points at. Fail-safe: always exits 0 with at most a
|
|
95
|
+
// rendered line. See cli/commands/statusline.ts.
|
|
96
|
+
statusline: () => import("./statusline-L376ZPZU.js"),
|
|
97
|
+
// Internal (omitted from USAGE): the user-invokable action entrypoint a future
|
|
98
|
+
// host affordance points at. USER-TRIGGERED: surfaces errors (exit 1 + stderr),
|
|
99
|
+
// unlike the fail-open hook / fail-safe statusline. See cli/commands/action.ts.
|
|
100
|
+
action: () => import("./action-WT7GVRCC.js"),
|
|
101
|
+
serve: () => import("./serve-GER7URPR.js"),
|
|
94
102
|
// Hidden (omitted from USAGE): the opt-in host-native turn-usage entrypoint an
|
|
95
103
|
// AfterModel / PostInvocation hook points at. Always exits 0; records a
|
|
96
104
|
// distinct `model_turn` row. See cli/commands/usage-event.ts.
|
|
97
|
-
"usage-event": () => import("./usage-event-
|
|
105
|
+
"usage-event": () => import("./usage-event-GZ32AGEB.js")
|
|
98
106
|
};
|
|
99
107
|
var DEFAULT_PROGRAM_NAME = "agent-connector";
|
|
100
108
|
var COMMAND_USAGE = {
|
|
@@ -105,12 +113,14 @@ var COMMAND_USAGE = {
|
|
|
105
113
|
sync: "sync \u2014 alias of upgrade (see `upgrade --help`)",
|
|
106
114
|
update: "update \u2014 alias of upgrade (see `upgrade --help`)",
|
|
107
115
|
package: "package [--connector <path>] [--format <fmt>|all] [--out <dir>] [--project <dir>] [--dry-run]",
|
|
108
|
-
doctor: "doctor [--targets a,b] [--connector <path>] [--scope user|project] [--project <dir>] [--probe] [--json]",
|
|
116
|
+
doctor: "doctor [--targets a,b] [--connector <path>] [--scope user|project] [--project <dir>] [--probe] [--json] [--heal] [--dry-run]",
|
|
109
117
|
status: "status [--connector <path>] [--scope user|project] [--project <dir>] [--json]",
|
|
110
118
|
telemetry: "telemetry report|export|leaderboard [--by <dim>] [--since <dur>] [--connector <id>] [--scope <slice>] [--format csv|json] [--out <file>] [--json]",
|
|
111
119
|
usage: "usage report|export|leaderboard [--by <dim>] [--since <dur>] [--platform <id>] [--format csv|json] [--out <file>] [--json]",
|
|
112
120
|
leaderboard: "leaderboard [--since <dur>] [--connector <id>] [--scope <slice>] [--json]",
|
|
113
121
|
hook: "hook <platform> <event> --connector <id> (internal \u2014 host hook configs point here)",
|
|
122
|
+
statusline: "statusline <platform> --connector <id> (internal \u2014 host status line configs point here)",
|
|
123
|
+
action: "action <platform> <actionId> --connector <id> (internal \u2014 host action affordances point here)",
|
|
114
124
|
serve: "serve --connector <id> [--scope user|project] [--host <platformId>] -- <command> [args...] (internal \u2014 host MCP entries point here)"
|
|
115
125
|
};
|
|
116
126
|
function buildUsage(programName) {
|
|
@@ -188,4 +198,4 @@ export {
|
|
|
188
198
|
renderInstallResult,
|
|
189
199
|
main
|
|
190
200
|
};
|
|
191
|
-
//# sourceMappingURL=chunk-
|
|
201
|
+
//# sourceMappingURL=chunk-O5TWCIJN.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/app.ts"],"sourcesContent":["/**\n * cli/app — shared CLI helpers + command dispatch (NO side effects).\n *\n * Command modules import the shared helpers (print, fail, parse-flags,\n * renderInstallResult) from here, and main() dispatches the first positional to a\n * command module.\n * This module never auto-runs — `cli/index.ts` is the thin bin entry that calls\n * `main()`. Keeping the auto-run out of here is what prevents a dispatch recursion\n * (a command module importing a helper must not re-trigger the program) and makes\n * it robust to bundler entry-splitting (the old import.meta.url entry-guard broke\n * once tsup hoisted this code into a shared chunk).\n */\n\nimport { createRequire } from \"node:module\";\n\nimport type {\n ChangeRecord,\n InstallResult,\n InstallScope,\n PlatformId,\n} from \"../core/types.js\";\n\n// ─────────────────────────────────────────────────────────────────────────\n// Shared helpers (imported by the command modules)\n// ─────────────────────────────────────────────────────────────────────────\n\n/** Print a line to stdout (machine-readable payloads must stay on stdout). */\nexport function print(line: string): void {\n process.stdout.write(`${line}\\n`);\n}\n\n/**\n * The brand active for THIS invocation. main() sets it from\n * {@link MainOptions.programName} before dispatch, so error messages printed by\n * command modules via {@link fail} read as the embedding tool (e.g. `acme-db:`)\n * instead of always `agent-connector:`.\n */\nlet activeProgramName = \"agent-connector\";\n\n/** Print an error to stderr (branded) and return a non-zero exit code (default 2). */\nexport function fail(message: string, code = 2): number {\n process.stderr.write(`${activeProgramName}: ${message}\\n`);\n return code;\n}\n\n/**\n * Resolve agent-connector's own package version at runtime. Works from both the\n * bundled dist layout (dist/*.js → ../package.json) and the src layout under\n * tsx/vitest (src/cli/ → ../../package.json); the name check guards against\n * accidentally reading some other package.json on the walk.\n */\nexport function resolveOwnVersion(): string {\n const req = createRequire(import.meta.url);\n for (const rel of [\"../package.json\", \"../../package.json\", \"../../../package.json\"]) {\n try {\n const pkg = req(rel) as { name?: string; version?: string };\n if (pkg.name === \"@ken-jo/agent-connector\" && typeof pkg.version === \"string\") {\n return pkg.version;\n }\n } catch {\n /* keep walking */\n }\n }\n return \"0.0.0\";\n}\n\n/** Parse a --scope value the CLI accepts (user|project) into an InstallScope. */\nexport function parseScope(value: string | undefined): InstallScope | null {\n if (value === \"user\" || value === \"project\") return value;\n return null;\n}\n\n/**\n * Parse a comma-separated --targets value into PlatformId[]. Returns undefined\n * when the flag is absent/empty so callers can fall back to connector/detection.\n */\nexport function parseTargets(value: string | undefined): PlatformId[] | undefined {\n if (value == null || value.trim() === \"\") return undefined;\n const ids = value\n .split(\",\")\n .map((s) => s.trim())\n .filter((s) => s !== \"\") as PlatformId[];\n return ids.length > 0 ? ids : undefined;\n}\n\nconst ACTION_GLYPH: Record<ChangeRecord[\"action\"], string> = {\n create: \"+\",\n update: \"~\",\n remove: \"-\",\n skip: \"=\",\n warn: \"!\",\n};\n\n/**\n * Render an InstallResult as a readable diff: one line per ChangeRecord (glyph,\n * platform, detail, path) followed by any warnings and a summary tally. Used by\n * install / upgrade / uninstall.\n */\nexport function renderInstallResult(\n result: InstallResult,\n verb: \"install\" | \"upgrade\" | \"uninstall\",\n): string {\n const lines: string[] = [];\n const mode = result.dryRun ? \" (dry-run — nothing written)\" : \"\";\n lines.push(`${verb} \"${result.connectorId}\"${mode}`);\n\n if (result.changes.length === 0) {\n lines.push(\" (no changes)\");\n } else {\n for (const c of result.changes) {\n const glyph = ACTION_GLYPH[c.action];\n const where = c.path ? ` ${c.path}` : \"\";\n lines.push(` ${glyph} [${c.platform}] ${c.action}: ${c.detail}${where}`);\n }\n }\n\n if (result.warnings.length > 0) {\n lines.push(\"\");\n lines.push(\"warnings:\");\n for (const w of result.warnings) lines.push(` ! ${w}`);\n }\n\n const tally = result.changes.reduce<Record<ChangeRecord[\"action\"], number>>(\n (acc, c) => {\n acc[c.action] += 1;\n return acc;\n },\n { create: 0, update: 0, remove: 0, skip: 0, warn: 0 },\n );\n lines.push(\"\");\n lines.push(\n `summary: ${tally.create} created, ${tally.update} updated, ` +\n `${tally.remove} removed, ${tally.skip} skipped, ${tally.warn} warning(s)`,\n );\n\n return lines.join(\"\\n\");\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Command dispatch\n// ─────────────────────────────────────────────────────────────────────────\n\n/** A command module: takes the post-command argv slice, returns an exit code. */\ntype CommandModule = { run: (argv: string[]) => Promise<number> | number };\n\n/** Lazy command loaders — keyed by the first positional. Imported on demand. */\nconst COMMANDS: Record<string, () => Promise<CommandModule>> = {\n detect: () => import(\"./commands/detect.js\"),\n install: () => import(\"./commands/install.js\"),\n uninstall: () => import(\"./commands/uninstall.js\"),\n // `upgrade` is the single \"bring everything current\" verb (re-render host\n // config + refresh the home pointer + managed channel guidance). `sync` and\n // `update` are kept as back-compat aliases that route to the same module so\n // existing scripts/docs keep working without a second concept to learn.\n upgrade: () => import(\"./commands/upgrade.js\"),\n sync: () => import(\"./commands/upgrade.js\"),\n update: () => import(\"./commands/upgrade.js\"),\n package: () => import(\"./commands/package.js\"),\n doctor: () => import(\"./commands/doctor.js\"),\n status: () => import(\"./commands/status.js\"),\n telemetry: () => import(\"./commands/telemetry.js\"),\n usage: () => import(\"./commands/usage.js\"),\n leaderboard: () => import(\"./commands/leaderboard.js\"),\n hook: () => import(\"./commands/hook.js\"),\n // Internal (omitted from USAGE): the statusline (HUD) entrypoint a host's\n // status line config points at. Fail-safe: always exits 0 with at most a\n // rendered line. See cli/commands/statusline.ts.\n statusline: () => import(\"./commands/statusline.js\"),\n // Internal (omitted from USAGE): the user-invokable action entrypoint a future\n // host affordance points at. USER-TRIGGERED: surfaces errors (exit 1 + stderr),\n // unlike the fail-open hook / fail-safe statusline. See cli/commands/action.ts.\n action: () => import(\"./commands/action.js\"),\n serve: () => import(\"./commands/serve.js\"),\n // Hidden (omitted from USAGE): the opt-in host-native turn-usage entrypoint an\n // AfterModel / PostInvocation hook points at. Always exits 0; records a\n // distinct `model_turn` row. See cli/commands/usage-event.ts.\n \"usage-event\": () => import(\"./commands/usage-event.js\"),\n};\n\n/** Default program name; an embedding SDK CLI overrides it via {@link MainOptions}. */\nexport const DEFAULT_PROGRAM_NAME = \"agent-connector\";\n\n/**\n * One-line usage signature per command — the single central copy behind\n * `<command> --help` and the friendly bad-flag error. Command modules use\n * node:util parseArgs (strict), which THROWS on an unknown flag; without the\n * dispatcher-level handling in {@link main}, `agent-connector install --help`\n * would die with a raw ERR_PARSE_ARGS stack trace — the very invocation the\n * root help tells users to run.\n */\nconst COMMAND_USAGE: Record<string, string> = {\n detect: \"detect [--json] [--project <dir>]\",\n install:\n \"install [--method direct|marketplace] [--connector <path>] [--scope user|project] [--targets a,b] [--project <dir>] [--dry-run] [--force]\",\n uninstall:\n \"uninstall [--method auto|direct|marketplace] [--connector <path>] [--connector-id <id>] [--scope user|project] [--targets a,b] [--project <dir>] [--dry-run] [--purge]\",\n upgrade:\n \"upgrade [--method direct|marketplace] [--channel stable|latest] [--connector <path>] [--scope user|project] [--targets a,b] [--project <dir>] [--dry-run]\",\n sync: \"sync — alias of upgrade (see `upgrade --help`)\",\n update: \"update — alias of upgrade (see `upgrade --help`)\",\n package:\n \"package [--connector <path>] [--format <fmt>|all] [--out <dir>] [--project <dir>] [--dry-run]\",\n doctor:\n \"doctor [--targets a,b] [--connector <path>] [--scope user|project] [--project <dir>] [--probe] [--json] [--heal] [--dry-run]\",\n status: \"status [--connector <path>] [--scope user|project] [--project <dir>] [--json]\",\n telemetry:\n \"telemetry report|export|leaderboard [--by <dim>] [--since <dur>] [--connector <id>] [--scope <slice>] [--format csv|json] [--out <file>] [--json]\",\n usage:\n \"usage report|export|leaderboard [--by <dim>] [--since <dur>] [--platform <id>] [--format csv|json] [--out <file>] [--json]\",\n leaderboard: \"leaderboard [--since <dur>] [--connector <id>] [--scope <slice>] [--json]\",\n hook: \"hook <platform> <event> --connector <id> (internal — host hook configs point here)\",\n statusline:\n \"statusline <platform> --connector <id> (internal — host status line configs point here)\",\n action:\n \"action <platform> <actionId> --connector <id> (internal — host action affordances point here)\",\n serve:\n \"serve --connector <id> [--scope user|project] [--host <platformId>] -- <command> [args...] (internal — host MCP entries point here)\",\n};\n\n/**\n * Build the top-level usage string for a given program name. The brand replaces\n * \"agent-connector\" in the title, the `usage:` line, and the per-command help\n * footer so an embedded CLI (e.g. `acme-db`) reads as its own tool.\n */\nfunction buildUsage(programName: string): string {\n return `${programName} — write your MCP server + hooks once, install everywhere.\n\nusage: ${programName} <command> [flags]\n\ncommands:\n detect List the AI-agent platforms installed on this machine.\n install Deploy a connector across its target platforms (--method direct writes host config; --method marketplace drives the host's plugin install).\n uninstall Remove a connector's registrations (--method auto reverses whichever method is actually installed).\n upgrade Bring everything current: re-render host config + heal the home pointer + managed update guidance (alias: update, sync).\n package Emit a marketplace/extension bundle (9 host formats, or the standard artifacts mcp-server-json | mcpb).\n doctor Health-check every detected platform; non-zero exit on any failure.\n status Light install-state summary: which connectors are present on which hosts (always exits 0).\n telemetry Inspect local per-tool token telemetry (report | export | leaderboard).\n usage Inspect host-native token usage from agent CLI logs (report | export | leaderboard).\n leaderboard Three leaderboards: 🔌 MCP/plugin (mcp-self) + 🖥️ host/user (host-scan-logs) + 🛰️ host-native turns (host-native-live) — never summed.\n hook Universal json-stdio hook entrypoint (hosts call this).\n serve Telemetry-wrapping MCP stdio proxy (wraps a real server command).\n\nRun \\`${programName} <command> --help\\` for command-specific flags.`;\n}\n\n/** Options accepted by {@link main}. */\nexport interface MainOptions {\n /**\n * The brand shown in usage/help text. Defaults to {@link DEFAULT_PROGRAM_NAME}.\n * An embedding SDK CLI (see cli/sdk.ts) passes its own bin name so every\n * subcommand's help reads as the developer's tool.\n */\n programName?: string;\n}\n\nexport async function main(argv: string[], opts: MainOptions = {}): Promise<number> {\n const programName = opts.programName ?? DEFAULT_PROGRAM_NAME;\n activeProgramName = programName; // brand every fail() in this invocation\n const usage = buildUsage(programName);\n const command = argv[0];\n\n if (command == null || command === \"--help\" || command === \"-h\" || command === \"help\") {\n print(usage);\n return command == null ? 1 : 0;\n }\n if (command === \"--version\" || command === \"-v\") {\n print(`${programName} ${resolveOwnVersion()}`);\n return 0;\n }\n\n const loader = COMMANDS[command];\n if (!loader) {\n process.stderr.write(`${programName}: unknown command \"${command}\"\\n\\n`);\n process.stderr.write(`${usage}\\n`);\n return 2;\n }\n\n // Per-command help: no command module defines a --help flag (strict parseArgs\n // would throw on it), so answer it centrally from COMMAND_USAGE.\n const rest = argv.slice(1);\n if (rest.includes(\"--help\") || rest.includes(\"-h\")) {\n const sig = COMMAND_USAGE[command];\n if (sig) {\n print(`usage: ${programName} ${sig}`);\n return 0;\n }\n }\n\n const mod = await loader();\n try {\n return await mod.run(rest);\n } catch (err) {\n // Friendly bad-flag errors: strict parseArgs throws ERR_PARSE_ARGS_* for an\n // unknown/malformed option — print the message + the usage line instead of\n // letting a raw stack trace reach the user. Everything else still rethrows\n // (the bin entry reports those as fatal).\n const code = (err as { code?: string }).code;\n if (typeof code === \"string\" && code.startsWith(\"ERR_PARSE_ARGS\")) {\n const message = err instanceof Error ? err.message : String(err);\n const sig = COMMAND_USAGE[command];\n if (sig) process.stderr.write(`usage: ${programName} ${sig}\\n`);\n return fail(message);\n }\n throw err;\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
isConcreteSemver,
|
|
8
8
|
isPlaceholderVersion,
|
|
9
9
|
registryTransportType
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-4ENJK5S2.js";
|
|
11
11
|
import {
|
|
12
12
|
writeTomlString
|
|
13
13
|
} from "./chunk-OPXAP3AC.js";
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
buildHomeBinHookCommand,
|
|
21
21
|
buildServeWrapperCommand,
|
|
22
22
|
shouldWrapForTelemetry
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-I5MLE6S7.js";
|
|
24
24
|
import {
|
|
25
25
|
ensureDir,
|
|
26
26
|
homeBinPath
|
|
@@ -80,7 +80,8 @@ var CLAUDE_MAPPED_EVENTS = /* @__PURE__ */ new Set([
|
|
|
80
80
|
"PermissionRequest",
|
|
81
81
|
"PostToolUseFailure",
|
|
82
82
|
"SubagentStart",
|
|
83
|
-
"SubagentStop"
|
|
83
|
+
"SubagentStop",
|
|
84
|
+
"PostCompact"
|
|
84
85
|
]);
|
|
85
86
|
function buildClaudeHooksJson(connector, homeBin, platformId) {
|
|
86
87
|
const events = connector.hookEvents.filter((e) => CLAUDE_MAPPED_EVENTS.has(e));
|
|
@@ -1040,4 +1041,4 @@ export {
|
|
|
1040
1041
|
packageConnectorAll,
|
|
1041
1042
|
installInstructions
|
|
1042
1043
|
};
|
|
1043
|
-
//# sourceMappingURL=chunk-
|
|
1044
|
+
//# sourceMappingURL=chunk-QREL7LZJ.js.map
|