@ken-jo/agent-connector 0.4.44 → 0.4.67
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 +17 -4
- package/dist/{action-72J2TCKQ.js → action-RUM6GP23.js} +12 -12
- package/dist/{amazon-q-UFLBUSHG.js → amazon-q-KXVJFT7Q.js} +7 -11
- package/dist/amazon-q-KXVJFT7Q.js.map +1 -0
- package/dist/{amp-5DJK7VAL.js → amp-WAPHJYTK.js} +38 -63
- package/dist/amp-WAPHJYTK.js.map +1 -0
- package/dist/{antigravity-NWP2TUG6.js → antigravity-GF3RU42A.js} +5 -5
- package/dist/{antigravity-cli-KPNLE7X4.js → antigravity-cli-OH27IFH5.js} +5 -5
- package/dist/{chunk-QY42WGBX.js → chunk-2HCJV6UO.js} +33 -3
- package/dist/chunk-2HCJV6UO.js.map +1 -0
- package/dist/{chunk-ERV4TKRV.js → chunk-3Y23ZYYF.js} +10 -10
- package/dist/chunk-3Y23ZYYF.js.map +1 -0
- package/dist/{chunk-L7ESV37V.js → chunk-7CZKXXBD.js} +4 -2
- package/dist/chunk-7CZKXXBD.js.map +1 -0
- package/dist/{chunk-ZY25RG4Y.js → chunk-ALVXORZM.js} +4 -2
- package/dist/chunk-ALVXORZM.js.map +1 -0
- package/dist/{chunk-M3H7PQWT.js → chunk-AXAHW2KU.js} +4 -2
- package/dist/chunk-AXAHW2KU.js.map +1 -0
- package/dist/{chunk-CFM3JKIR.js → chunk-CSRBMJLU.js} +7 -7
- package/dist/{chunk-F4DSMVZ7.js → chunk-D6ZJS4ND.js} +2 -2
- package/dist/{chunk-B47MDOV3.js → chunk-E45SUUD7.js} +5 -5
- package/dist/{chunk-3Q6YEDCG.js → chunk-F5COBB5F.js} +17 -45
- package/dist/chunk-F5COBB5F.js.map +1 -0
- package/dist/{chunk-5M2SMDA4.js → chunk-GCRRX4MO.js} +2 -2
- package/dist/{chunk-2RPHDVHW.js → chunk-IU42THN7.js} +2 -2
- package/dist/{chunk-VPSHGDDQ.js → chunk-IZ4XQ23W.js} +26 -10
- package/dist/chunk-IZ4XQ23W.js.map +1 -0
- package/dist/{chunk-SBV2QJ5C.js → chunk-LS65GL2P.js} +36 -36
- package/dist/{chunk-IKEXNI2W.js → chunk-NXR4HM5N.js} +18 -18
- package/dist/{chunk-ASHAMORS.js → chunk-P5KA5NVR.js} +2 -2
- package/dist/{chunk-A767JFHW.js → chunk-RHML2NOB.js} +65 -35
- package/dist/chunk-RHML2NOB.js.map +1 -0
- package/dist/{chunk-UXG64P6R.js → chunk-RQCBBLTA.js} +7 -4
- package/dist/chunk-RQCBBLTA.js.map +1 -0
- package/dist/{chunk-LETB5HCK.js → chunk-TZ5KGCE2.js} +2 -2
- package/dist/{chunk-WZWK4ICE.js → chunk-UVBAH263.js} +10 -7
- package/dist/chunk-UVBAH263.js.map +1 -0
- package/dist/{chunk-E3GWKJU5.js → chunk-ZEFUDBTY.js} +5 -5
- package/dist/{chunk-XW46WVR2.js → chunk-ZSMGHEB5.js} +10 -5
- package/dist/chunk-ZSMGHEB5.js.map +1 -0
- package/dist/{claude-code-HXIVRZCY.js → claude-code-WLN43K7I.js} +15 -8
- package/dist/claude-code-WLN43K7I.js.map +1 -0
- package/dist/cli/sdk.js +7 -7
- package/dist/cli.js +1 -1
- package/dist/{cline-AGFJF4AC.js → cline-PEGTGVQD.js} +4 -4
- package/dist/{codebuff-YUQ4PN7G.js → codebuff-UG6LVSOM.js} +4 -4
- package/dist/{codex-FLU37DV3.js → codex-4LVDQXCD.js} +32 -6
- package/dist/codex-4LVDQXCD.js.map +1 -0
- package/dist/{continue-ZMI4YN75.js → continue-DYV5V55Y.js} +9 -5
- package/dist/continue-DYV5V55Y.js.map +1 -0
- package/dist/{copilot-cli-XPRJ5MQB.js → copilot-cli-NVFXFLUF.js} +66 -51
- package/dist/copilot-cli-NVFXFLUF.js.map +1 -0
- package/dist/{crush-3OB5ZTCC.js → crush-PP4HYZLT.js} +4 -4
- package/dist/{cursor-F4HYO2FP.js → cursor-XMXOZKAP.js} +5 -5
- package/dist/{detect-L3NJTBO5.js → detect-IZOWP5AA.js} +4 -4
- package/dist/{doctor-PUE4HO3N.js → doctor-5IVUQ2YH.js} +14 -14
- package/dist/{droid-NZCKYKOV.js → droid-ETNOUIPJ.js} +6 -12
- package/dist/droid-ETNOUIPJ.js.map +1 -0
- package/dist/{gemini-cli-3ZGCXUDD.js → gemini-cli-P7XJXWVH.js} +19 -6
- package/dist/gemini-cli-P7XJXWVH.js.map +1 -0
- package/dist/{goose-MGGNVXJP.js → goose-UZVA6MQC.js} +16 -22
- package/dist/goose-UZVA6MQC.js.map +1 -0
- package/dist/{hermes-L3CBJ37L.js → hermes-IC6R4CII.js} +44 -22
- package/dist/hermes-IC6R4CII.js.map +1 -0
- package/dist/{hook-S3DNNGZX.js → hook-7IUPIHCZ.js} +12 -12
- package/dist/index.d.ts +2 -2
- package/dist/index.js +5 -5
- package/dist/{install-7SUJFRYO.js → install-EP6GPQ65.js} +14 -14
- package/dist/{introspect-B164-hj3.d.ts → introspect-BFcXpfUp.d.ts} +1 -1
- package/dist/{jetbrains-copilot-M2LHJBAW.js → jetbrains-copilot-MZO2RQGJ.js} +19 -15
- package/dist/jetbrains-copilot-MZO2RQGJ.js.map +1 -0
- package/dist/{kilo-RMRP2EL7.js → kilo-CCB34CQQ.js} +18 -55
- package/dist/kilo-CCB34CQQ.js.map +1 -0
- package/dist/{kilo-cli-6ITBNHTH.js → kilo-cli-EOMN3WC7.js} +18 -55
- package/dist/kilo-cli-EOMN3WC7.js.map +1 -0
- package/dist/{kimi-QYHWAY54.js → kimi-GUSJME55.js} +8 -4
- package/dist/kimi-GUSJME55.js.map +1 -0
- package/dist/{kiro-2K5UJVGC.js → kiro-6OHZ5RGV.js} +5 -5
- package/dist/kiro-6OHZ5RGV.js.map +1 -0
- package/dist/{leaderboard-2VAAOK3D.js → leaderboard-6I2E5XZK.js} +5 -5
- package/dist/{mimo-code-K7AMX2QW.js → mimo-code-ZPJJ6IIW.js} +21 -56
- package/dist/mimo-code-ZPJJ6IIW.js.map +1 -0
- package/dist/{mux-GT7FWVLH.js → mux-AFTVMGGM.js} +4 -4
- package/dist/{nemoclaw-GQMS6CUM.js → nemoclaw-D5EN4G2Q.js} +5 -5
- package/dist/{omp-2RPYIZUF.js → omp-GKI2PZ7G.js} +17 -46
- package/dist/omp-GKI2PZ7G.js.map +1 -0
- package/dist/{openclaw-P5GMEEGC.js → openclaw-A76PCNBV.js} +5 -5
- package/dist/{opencode-5D2SK3EX.js → opencode-M34E6PI7.js} +21 -56
- package/dist/opencode-M34E6PI7.js.map +1 -0
- package/dist/{package-VUX663ET.js → package-BWLV24OO.js} +11 -11
- package/dist/{pi-ZMM4KJTO.js → pi-HVG6ZWFE.js} +4 -4
- package/dist/{qwen-code-4ZLVGN2C.js → qwen-code-OWLM3I5P.js} +12 -5
- package/dist/qwen-code-OWLM3I5P.js.map +1 -0
- package/dist/{roo-code-67QGLQRM.js → roo-code-RFKKTNNI.js} +4 -4
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/index.js +10 -10
- package/dist/sdk/index.d.ts +3 -3
- package/dist/sdk/index.js +6 -6
- package/dist/sdk/test.d.ts +2 -2
- package/dist/sdk/test.js +9 -9
- package/dist/{serve-MOIIYFER.js → serve-CM4HZPMP.js} +12 -12
- package/dist/{status-SCBCWS7H.js → status-BPB4VLQX.js} +10 -10
- package/dist/{statusline-NRPDOPGA.js → statusline-HIKR2I4Q.js} +11 -11
- package/dist/{telemetry-Q55B5NSZ.js → telemetry-SBVUJYNE.js} +10 -10
- package/dist/{trae-TMJPHWZ5.js → trae-FVHQALK3.js} +4 -4
- package/dist/{types-COSBYpKs.d.ts → types-ChUrvw0j.d.ts} +8 -8
- package/dist/{uninstall-SNI7GPQD.js → uninstall-MO3RGGVE.js} +21 -14
- package/dist/uninstall-MO3RGGVE.js.map +1 -0
- package/dist/{upgrade-ZUNBJWJ7.js → upgrade-6XIGSPGY.js} +14 -14
- package/dist/{usage-UQDBIU42.js → usage-IBN36ZVW.js} +2 -2
- package/dist/{usage-event-HPG2BIAY.js → usage-event-4RJP37K6.js} +11 -11
- package/dist/{vscode-copilot-H7JKUKLZ.js → vscode-copilot-6FLDRTKV.js} +26 -19
- package/dist/vscode-copilot-6FLDRTKV.js.map +1 -0
- package/dist/{warp-SVDVKQQI.js → warp-7CC52UJV.js} +4 -4
- package/dist/{windsurf-H36YKOMR.js → windsurf-6ZLQMBQW.js} +4 -4
- package/dist/{zed-LHWJALLZ.js → zed-FULJMNBV.js} +4 -4
- package/package.json +2 -1
- package/dist/amazon-q-UFLBUSHG.js.map +0 -1
- package/dist/amp-5DJK7VAL.js.map +0 -1
- package/dist/chunk-3Q6YEDCG.js.map +0 -1
- package/dist/chunk-A767JFHW.js.map +0 -1
- package/dist/chunk-ERV4TKRV.js.map +0 -1
- package/dist/chunk-L7ESV37V.js.map +0 -1
- package/dist/chunk-M3H7PQWT.js.map +0 -1
- package/dist/chunk-QY42WGBX.js.map +0 -1
- package/dist/chunk-UXG64P6R.js.map +0 -1
- package/dist/chunk-VPSHGDDQ.js.map +0 -1
- package/dist/chunk-WZWK4ICE.js.map +0 -1
- package/dist/chunk-XW46WVR2.js.map +0 -1
- package/dist/chunk-ZY25RG4Y.js.map +0 -1
- package/dist/claude-code-HXIVRZCY.js.map +0 -1
- package/dist/codex-FLU37DV3.js.map +0 -1
- package/dist/continue-ZMI4YN75.js.map +0 -1
- package/dist/copilot-cli-XPRJ5MQB.js.map +0 -1
- package/dist/droid-NZCKYKOV.js.map +0 -1
- package/dist/gemini-cli-3ZGCXUDD.js.map +0 -1
- package/dist/goose-MGGNVXJP.js.map +0 -1
- package/dist/hermes-L3CBJ37L.js.map +0 -1
- package/dist/jetbrains-copilot-M2LHJBAW.js.map +0 -1
- package/dist/kilo-RMRP2EL7.js.map +0 -1
- package/dist/kilo-cli-6ITBNHTH.js.map +0 -1
- package/dist/kimi-QYHWAY54.js.map +0 -1
- package/dist/kiro-2K5UJVGC.js.map +0 -1
- package/dist/mimo-code-K7AMX2QW.js.map +0 -1
- package/dist/omp-2RPYIZUF.js.map +0 -1
- package/dist/opencode-5D2SK3EX.js.map +0 -1
- package/dist/qwen-code-4ZLVGN2C.js.map +0 -1
- package/dist/uninstall-SNI7GPQD.js.map +0 -1
- package/dist/vscode-copilot-H7JKUKLZ.js.map +0 -1
- /package/dist/{action-72J2TCKQ.js.map → action-RUM6GP23.js.map} +0 -0
- /package/dist/{antigravity-NWP2TUG6.js.map → antigravity-GF3RU42A.js.map} +0 -0
- /package/dist/{antigravity-cli-KPNLE7X4.js.map → antigravity-cli-OH27IFH5.js.map} +0 -0
- /package/dist/{chunk-CFM3JKIR.js.map → chunk-CSRBMJLU.js.map} +0 -0
- /package/dist/{chunk-F4DSMVZ7.js.map → chunk-D6ZJS4ND.js.map} +0 -0
- /package/dist/{chunk-B47MDOV3.js.map → chunk-E45SUUD7.js.map} +0 -0
- /package/dist/{chunk-5M2SMDA4.js.map → chunk-GCRRX4MO.js.map} +0 -0
- /package/dist/{chunk-2RPHDVHW.js.map → chunk-IU42THN7.js.map} +0 -0
- /package/dist/{chunk-SBV2QJ5C.js.map → chunk-LS65GL2P.js.map} +0 -0
- /package/dist/{chunk-IKEXNI2W.js.map → chunk-NXR4HM5N.js.map} +0 -0
- /package/dist/{chunk-ASHAMORS.js.map → chunk-P5KA5NVR.js.map} +0 -0
- /package/dist/{chunk-LETB5HCK.js.map → chunk-TZ5KGCE2.js.map} +0 -0
- /package/dist/{chunk-E3GWKJU5.js.map → chunk-ZEFUDBTY.js.map} +0 -0
- /package/dist/{cline-AGFJF4AC.js.map → cline-PEGTGVQD.js.map} +0 -0
- /package/dist/{codebuff-YUQ4PN7G.js.map → codebuff-UG6LVSOM.js.map} +0 -0
- /package/dist/{crush-3OB5ZTCC.js.map → crush-PP4HYZLT.js.map} +0 -0
- /package/dist/{cursor-F4HYO2FP.js.map → cursor-XMXOZKAP.js.map} +0 -0
- /package/dist/{detect-L3NJTBO5.js.map → detect-IZOWP5AA.js.map} +0 -0
- /package/dist/{doctor-PUE4HO3N.js.map → doctor-5IVUQ2YH.js.map} +0 -0
- /package/dist/{hook-S3DNNGZX.js.map → hook-7IUPIHCZ.js.map} +0 -0
- /package/dist/{install-7SUJFRYO.js.map → install-EP6GPQ65.js.map} +0 -0
- /package/dist/{leaderboard-2VAAOK3D.js.map → leaderboard-6I2E5XZK.js.map} +0 -0
- /package/dist/{mux-GT7FWVLH.js.map → mux-AFTVMGGM.js.map} +0 -0
- /package/dist/{nemoclaw-GQMS6CUM.js.map → nemoclaw-D5EN4G2Q.js.map} +0 -0
- /package/dist/{openclaw-P5GMEEGC.js.map → openclaw-A76PCNBV.js.map} +0 -0
- /package/dist/{package-VUX663ET.js.map → package-BWLV24OO.js.map} +0 -0
- /package/dist/{pi-ZMM4KJTO.js.map → pi-HVG6ZWFE.js.map} +0 -0
- /package/dist/{roo-code-67QGLQRM.js.map → roo-code-RFKKTNNI.js.map} +0 -0
- /package/dist/{serve-MOIIYFER.js.map → serve-CM4HZPMP.js.map} +0 -0
- /package/dist/{status-SCBCWS7H.js.map → status-BPB4VLQX.js.map} +0 -0
- /package/dist/{statusline-NRPDOPGA.js.map → statusline-HIKR2I4Q.js.map} +0 -0
- /package/dist/{telemetry-Q55B5NSZ.js.map → telemetry-SBVUJYNE.js.map} +0 -0
- /package/dist/{trae-TMJPHWZ5.js.map → trae-FVHQALK3.js.map} +0 -0
- /package/dist/{upgrade-ZUNBJWJ7.js.map → upgrade-6XIGSPGY.js.map} +0 -0
- /package/dist/{usage-UQDBIU42.js.map → usage-IBN36ZVW.js.map} +0 -0
- /package/dist/{usage-event-HPG2BIAY.js.map → usage-event-4RJP37K6.js.map} +0 -0
- /package/dist/{warp-SVDVKQQI.js.map → warp-7CC52UJV.js.map} +0 -0
- /package/dist/{windsurf-H36YKOMR.js.map → windsurf-6ZLQMBQW.js.map} +0 -0
- /package/dist/{zed-LHWJALLZ.js.map → zed-FULJMNBV.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/jsonc.ts","../src/core/object-map.ts","../src/adapters/claude-code/render.ts","../src/adapters/base.ts","../src/core/hook-array.ts"],"sourcesContent":["/**\n * core/jsonc — tolerant JSONC / JSON5-lite parsing.\n *\n * Many hosts document their config file as JSONC (or JSON5): // line comments,\n * /* *\\/ block comments, and trailing commas are all legal. A strict JSON.parse\n * false-fails such a perfectly valid file → null → and a careless `?? {}` then\n * OVERWRITES the user's entire config with just our entry (data loss). To avoid\n * that, every JSON/JSONC adapter parses through `parseJsonc`, which strips\n * comments + trailing commas in ONE string-aware pass before JSON.parse.\n *\n * The single pass is deliberately string-literal aware: a // or /* inside a\n * quoted value (e.g. \"http://x//y\") is NOT a comment, and a comma inside a\n * string (e.g. \"a,]\") is NOT a trailing comma — both must survive verbatim.\n */\n\n/**\n * Strip // line comments, /* *\\/ block comments, and trailing commas from JSONC\n * text in a SINGLE string-aware pass.\n *\n * Rules:\n * - While inside a string literal, every character (including //, /*, and ,)\n * is copied verbatim; backslash escapes the next character.\n * - Outside a string, // … runs to end-of-line and /* … *\\/ to its close.\n * - A comma is dropped ONLY when the next non-whitespace, non-comment token is\n * a closing `}` or `]` (a trailing comma). A comma followed by another value\n * or by end-of-input is preserved (the latter lets JSON.parse report the\n * real syntax error instead of us masking it).\n */\nexport function stripJsonc(text: string): string {\n const n = text.length;\n let out = \"\";\n let i = 0;\n let inString = false;\n let quote = \"\";\n\n while (i < n) {\n const ch = text[i] as string;\n\n if (inString) {\n out += ch;\n if (ch === \"\\\\\") {\n // Copy the escaped character verbatim (covers \\\" \\\\ \\/ etc.).\n if (i + 1 < n) {\n out += text[i + 1] as string;\n i += 2;\n continue;\n }\n } else if (ch === quote) {\n inString = false;\n }\n i += 1;\n continue;\n }\n\n const next = i + 1 < n ? (text[i + 1] as string) : \"\";\n\n // Enter a string literal.\n if (ch === '\"' || ch === \"'\") {\n inString = true;\n quote = ch;\n out += ch;\n i += 1;\n continue;\n }\n\n // Line comment — skip to end of line (keep the newline for line tracking).\n if (ch === \"/\" && next === \"/\") {\n i += 2;\n while (i < n && text[i] !== \"\\n\") i += 1;\n continue;\n }\n\n // Block comment — skip to the closing */.\n if (ch === \"/\" && next === \"*\") {\n i += 2;\n while (i < n && !(text[i] === \"*\" && text[i + 1] === \"/\")) i += 1;\n i += 2; // consume the closing */\n continue;\n }\n\n // Trailing comma — drop it only when the next significant token (skipping\n // whitespace AND comments) is a closing } or ]. This stays string-aware\n // because we only reach here outside a string.\n if (ch === \",\") {\n const closer = nextSignificant(text, i + 1);\n if (closer === \"}\" || closer === \"]\") {\n i += 1; // drop the trailing comma\n continue;\n }\n }\n\n out += ch;\n i += 1;\n }\n\n return out;\n}\n\n/**\n * Peek the next significant (non-whitespace, non-comment) character at/after\n * `from`, returning \"\" at end-of-input. Used only outside string literals.\n */\nfunction nextSignificant(text: string, from: number): string {\n const n = text.length;\n let i = from;\n while (i < n) {\n const ch = text[i] as string;\n if (ch === \" \" || ch === \"\\t\" || ch === \"\\r\" || ch === \"\\n\") {\n i += 1;\n continue;\n }\n const next = i + 1 < n ? (text[i + 1] as string) : \"\";\n if (ch === \"/\" && next === \"/\") {\n i += 2;\n while (i < n && text[i] !== \"\\n\") i += 1;\n continue;\n }\n if (ch === \"/\" && next === \"*\") {\n i += 2;\n while (i < n && !(text[i] === \"*\" && text[i + 1] === \"/\")) i += 1;\n i += 2;\n continue;\n }\n return ch;\n }\n return \"\";\n}\n\n/**\n * Parse JSONC text tolerantly: strip comments + trailing commas, then JSON.parse.\n * Throws (like JSON.parse) on genuinely malformed input — callers that want a\n * fail-soft null should wrap in try/catch (BaseAdapter.readJson does).\n */\nexport function parseJsonc<T = unknown>(text: string): T {\n return JSON.parse(stripJsonc(text)) as T;\n}\n","import type { ChangeRecord } from \"./types.js\";\n\n/**\n * Format-agnostic upsert/remove for a config that stores entries in an object\n * map at config[rootKey][entryId]. Extracted from BaseAdapter.upsertServerInJson\n * / removeServerFromJson so JSON today (and other formats via a Codec later)\n * share ONE create/skip/update + overwrite/malformed-guard orchestration. The\n * JSON binding in BaseAdapter is a byte-identical wrapper over this.\n */\n\n/** The only format-specific surface: parse a config file to a record and\n * serialize it back. parse() fail-softs to null (absent or unparseable). */\nexport interface ObjectMapCodec {\n parse(path: string): Record<string, unknown> | null;\n serialize(path: string, data: Record<string, unknown>, dryRun: boolean): void;\n /** Detection half of the overwrite guard: present, non-empty, still unparseable. */\n isPresentButUnparseable(path: string): boolean;\n}\n\n/** What to do when config[rootKey] is present but the wrong type (hand-edited to\n * an array / primitive). \"warn-skip\" leaves the user's value untouched (the JSON\n * server/hook policy); \"coerce\" replaces it with a fresh {} and proceeds (the\n * TOML/YAML host policy, used by a later follow-up). */\nexport type MalformedRootPolicy = \"warn-skip\" | \"coerce\";\n\n/** True when a PRESENT value is not a plain object map (array / primitive).\n * null/undefined is NOT malformed — that is the well-formed \"absent\" case the\n * engine creates fresh. */\nexport function isMalformedRootValue(value: unknown): boolean {\n return value != null && (typeof value !== \"object\" || Array.isArray(value));\n}\n\nexport interface ObjectMapUpsertOptions {\n codec: ObjectMapCodec;\n rootKey: string;\n platform: string;\n configPath: string;\n entryId: string;\n entry: unknown;\n dryRun?: boolean;\n policy?: MalformedRootPolicy;\n}\n\nexport interface ObjectMapRemoveOptions {\n codec: ObjectMapCodec;\n rootKey: string;\n platform: string;\n configPath: string;\n entryId: string;\n dryRun?: boolean;\n policy?: MalformedRootPolicy;\n}\n\nfunction unparseableWarn(platform: string, configPath: string): ChangeRecord {\n return {\n platform: platform as ChangeRecord[\"platform\"],\n action: \"warn\",\n path: configPath,\n detail: `existing ${configPath} is not parseable; left untouched (back it up / fix it, then re-run)`,\n };\n}\n\nfunction malformedWarn(platform: string, rootKey: string, configPath: string): ChangeRecord {\n return {\n platform: platform as ChangeRecord[\"platform\"],\n action: \"warn\",\n path: configPath,\n detail: `existing \"${rootKey}\" in ${configPath} is not an object map; left untouched (fix it, then re-run)`,\n };\n}\n\nexport function upsertInObjectMap(o: ObjectMapUpsertOptions): ChangeRecord {\n const policy = o.policy ?? \"warn-skip\";\n if (o.codec.isPresentButUnparseable(o.configPath)) {\n return unparseableWarn(o.platform, o.configPath);\n }\n const cfg = o.codec.parse(o.configPath) ?? {};\n if (isMalformedRootValue(cfg[o.rootKey])) {\n if (policy === \"warn-skip\") return malformedWarn(o.platform, o.rootKey, o.configPath);\n cfg[o.rootKey] = {}; // coerce\n }\n const bucket = (cfg[o.rootKey] ?? (cfg[o.rootKey] = {})) as Record<string, unknown>;\n const before = JSON.stringify(bucket[o.entryId]);\n const after = JSON.stringify(o.entry);\n let action: ChangeRecord[\"action\"];\n if (before === undefined) action = \"create\";\n else if (before === after) action = \"skip\";\n else action = \"update\";\n if (action !== \"skip\") {\n bucket[o.entryId] = o.entry;\n o.codec.serialize(o.configPath, cfg, o.dryRun ?? false);\n }\n return {\n platform: o.platform as ChangeRecord[\"platform\"],\n action,\n path: o.configPath,\n detail: `${o.rootKey}.${o.entryId}`,\n };\n}\n\nexport function removeFromObjectMap(o: ObjectMapRemoveOptions): ChangeRecord {\n const policy = o.policy ?? \"warn-skip\";\n if (o.codec.isPresentButUnparseable(o.configPath)) {\n return unparseableWarn(o.platform, o.configPath);\n }\n const cfg = o.codec.parse(o.configPath);\n if (cfg && isMalformedRootValue(cfg[o.rootKey])) {\n if (policy === \"warn-skip\") return malformedWarn(o.platform, o.rootKey, o.configPath);\n // coerce: a malformed root holds nothing of ours to remove → absent skip\n return {\n platform: o.platform as ChangeRecord[\"platform\"],\n action: \"skip\",\n path: o.configPath,\n detail: `${o.rootKey}.${o.entryId} absent`,\n };\n }\n const bucket = cfg?.[o.rootKey] as Record<string, unknown> | undefined;\n if (!cfg || !bucket || !(o.entryId in bucket)) {\n return {\n platform: o.platform as ChangeRecord[\"platform\"],\n action: \"skip\",\n path: o.configPath,\n detail: `${o.rootKey}.${o.entryId} absent`,\n };\n }\n delete bucket[o.entryId];\n o.codec.serialize(o.configPath, cfg, o.dryRun ?? false);\n return {\n platform: o.platform as ChangeRecord[\"platform\"],\n action: \"remove\",\n path: o.configPath,\n detail: `${o.rootKey}.${o.entryId}`,\n };\n}\n","/**\n * adapters/claude-code/render — shared content-surface renderers.\n *\n * The single source of truth for how a connector's commands / skills / subagents\n * are serialized into Claude Code's native `md + YAML-frontmatter` documents.\n * BOTH the live claude-code adapter (which writes into ~/.claude or .claude when\n * installing) AND `core/package` (which emits a marketplace-installable plugin\n * bundle) import these so the two paths produce BYTE-IDENTICAL output — there is\n * no second, subtly-different copy to drift.\n *\n * The frontmatter serializer reuses the `yaml` package (the same serializer\n * core/yaml and BaseAdapter.renderFrontmatterMd use): a `---` fence, the YAML\n * block, a closing `---`, a blank line, then the markdown body and a trailing\n * newline.\n */\n\nimport { stringify as stringifyYaml } from \"yaml\";\n\nimport type { CommandDef, SkillDef, SubagentDef } from \"../../core/types.js\";\n\n/**\n * Render a YAML-frontmatter + markdown body document:\n * \"---\\n\" + <yaml> + \"---\\n\\n\" + <body> + \"\\n\".\n * Identical to BaseAdapter.renderFrontmatterMd (which now delegates here).\n */\nexport function renderFrontmatterMd(\n frontmatter: Record<string, unknown>,\n body: string,\n): string {\n return `---\\n${stringifyYaml(frontmatter)}---\\n\\n${body}\\n`;\n}\n\n/**\n * Render a command to md+frontmatter\n * (description, argument-hint, allowed-tools, model + verbatim extra).\n *\n * `opts.includeToolsAndModel` (default `true`) controls the allowed-tools and\n * model insertions. Hosts whose command frontmatter is only\n * (description, argument-hint + verbatim extra) — i.e. they have no native\n * allowed-tools/model keys — pass `{ includeToolsAndModel: false }` to suppress\n * both; the default reproduces the full shape byte-for-byte.\n */\nexport function renderCommandMd(\n cmd: CommandDef,\n opts: { includeToolsAndModel?: boolean } = {},\n): string {\n const { includeToolsAndModel = true } = opts;\n const frontmatter: Record<string, unknown> = {};\n if (cmd.description !== undefined) frontmatter.description = cmd.description;\n if (cmd.argumentHint !== undefined) frontmatter[\"argument-hint\"] = cmd.argumentHint;\n if (includeToolsAndModel) {\n const allow = cmd.tools?.allow;\n if (allow && allow.length > 0) frontmatter[\"allowed-tools\"] = allow.join(\", \");\n if (cmd.model !== undefined) frontmatter.model = cmd.model;\n }\n if (cmd.extra) Object.assign(frontmatter, cmd.extra);\n return renderFrontmatterMd(frontmatter, cmd.prompt);\n}\n\n/**\n * Render a skill's SKILL.md: frontmatter (name, description + optional model,\n * allowed-tools, disable-model-invocation, verbatim extra) + body.\n */\nexport function renderSkillMd(skill: SkillDef): string {\n const frontmatter: Record<string, unknown> = {\n name: skill.name,\n description: skill.description,\n };\n if (skill.model !== undefined) frontmatter.model = skill.model;\n const allow = skill.tools?.allow;\n if (allow && allow.length > 0) frontmatter[\"allowed-tools\"] = allow.join(\", \");\n if (skill.disableModelInvocation !== undefined) {\n frontmatter[\"disable-model-invocation\"] = skill.disableModelInvocation;\n }\n if (skill.extra) Object.assign(frontmatter, skill.extra);\n return renderFrontmatterMd(frontmatter, skill.body);\n}\n\n/** Render a subagent to md+frontmatter (name, description, tools, model) + prompt body. */\nexport function renderSubagentMd(agent: SubagentDef): string {\n const frontmatter: Record<string, unknown> = {\n name: agent.name,\n description: agent.description,\n };\n const allow = agent.tools?.allow;\n if (allow && allow.length > 0) frontmatter.tools = allow.join(\", \");\n if (agent.model !== undefined) frontmatter.model = agent.model;\n if (agent.extra) Object.assign(frontmatter, agent.extra);\n return renderFrontmatterMd(frontmatter, agent.prompt);\n}\n\n/**\n * Render a subagent in OpenCode's shape (shared by opencode/kilo/mimo-code):\n * frontmatter (description, mode:\"subagent\", model?, permission? + verbatim\n * extra) with the system prompt as the body. `name` is NOT a frontmatter\n * field — it comes from the filename. `permission` is derived from the coarse\n * `readonly` knob: a readonly agent gets a per-tool deny map (edit/bash) so it\n * cannot mutate the workspace.\n */\nexport function renderOpenCodeSubagentMd(agent: SubagentDef): string {\n const frontmatter: Record<string, unknown> = {\n description: agent.description,\n mode: \"subagent\",\n };\n if (agent.model !== undefined) frontmatter.model = agent.model;\n if (agent.readonly === true) {\n // Per-tool permission map: deny mutating tools for a readonly subagent.\n frontmatter.permission = { edit: \"deny\", bash: \"deny\" };\n }\n if (agent.extra) Object.assign(frontmatter, agent.extra);\n return renderFrontmatterMd(frontmatter, agent.prompt);\n}\n","/**\n * adapters/base — shared adapter foundation.\n *\n * Provides JSON config IO, settings backup, and a default doctor. Per-platform\n * specifics (paths, capabilities, native render format, runtime parse/format)\n * are abstract and implemented by each adapter. TOML/YAML adapters override the\n * JSON helpers entirely.\n */\n\nimport {\n chmodSync,\n copyFileSync,\n existsSync,\n readdirSync,\n readFileSync,\n rmSync,\n statSync,\n writeFileSync,\n} from \"node:fs\";\nimport type { Dirent } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { basename, dirname, isAbsolute, join, relative, resolve, sep } from \"node:path\";\n\nimport type {\n ChangeRecord,\n DetectedPlatform,\n DiagnosticResult,\n HealthCheck,\n HookParadigm,\n PlatformCapabilities,\n PlatformId,\n PlatformMemoryOverride,\n} from \"../core/types.js\";\nimport { backupsDir, ensureDir, firstSymlinkInPath } from \"../core/paths.js\";\nimport { parseJsonc } from \"../core/jsonc.js\";\nimport {\n isMalformedRootValue as isMalformedRootValueFn,\n removeFromObjectMap,\n upsertInObjectMap,\n type ObjectMapCodec,\n} from \"../core/object-map.js\";\nimport { removeFromArray, upsertInArray } from \"../core/hook-array.js\";\nimport { buildHomeBinActionCommand, buildHomeBinHookCommand } from \"../core/spawn.js\";\nimport {\n MEMORY_CONTENT_SOFT_BUDGET_BYTES,\n listManagedBlocks,\n loadMemoryLedger,\n recordMemoryTarget,\n removeManagedBlocksFile,\n saveMemoryLedger,\n upsertManagedBlockFile,\n} from \"../core/managed-block.js\";\nimport { renderFrontmatterMd } from \"./claude-code/render.js\";\nimport type { Adapter, InstallContext, MemoryTarget } from \"./spi.js\";\n\n/** Content-surface kinds with BaseAdapter default install/uninstall handling. */\ntype ContentSurface =\n | \"commands\"\n | \"skills\"\n | \"subagents\"\n | \"memory\"\n | \"statusline\"\n | \"actions\";\n\n/**\n * Per-host policy + observables for the shared object-map hook-array merge\n * engine ({@link BaseAdapter.upsertHookEntries} / {@link BaseAdapter.removeHookEntries}).\n * `E` is the host's per-event array element type (e.g. claude-code's\n * `{ matcher, hooks: [...] }`). EVERY observable string + ownership predicate\n * is carried here so the engine body hardcodes none of them and per-host\n * wording never drifts; a future host needing divergent details overrides only\n * its descriptor, not the engine.\n */\nexport interface HookMergeDescriptor<E> {\n /**\n * How to handle a present-but-malformed `hooks` root (an array / primitive\n * instead of an object map) on install:\n * - \"warn-skip\" (DEFAULT): route through {@link BaseAdapter.malformedHookRootSkip}\n * — surface a `warn`, write nothing, leave the user's value untouched. This\n * is byte-identical to the pre-axis engine, so existing hosts that omit the\n * field are unchanged.\n * - \"coerce\": replace a malformed root (and any non-array event bucket) with a\n * fresh object map / array, then proceed — matching the container hosts\n * (codex, goose) whose server path already coerces a malformed root.\n */\n malformedPolicy?: \"warn-skip\" | \"coerce\";\n /**\n * Canonical → host event name. `undefined` = the host has no equivalent for\n * this event → the engine emits a warn (via unmappedWarnDetail) and skips it.\n * Omit the field entirely for identity hosts (claude-code) — no warn path.\n */\n mapEvent?(event: string): string | undefined;\n /** Warn detail for an event mapEvent returns undefined for. Required iff mapEvent can return undefined. */\n unmappedWarnDetail?(event: string): string;\n /** Render one host entry from the event name, declared matcher, and home-bin command. */\n renderEntry(event: string, matcher: string, command: string): E;\n /** Upsert find: does `entry` already carry THIS specific command (idempotency check)? */\n entryOwnsCommand(entry: E, command: string): boolean;\n /**\n * Uninstall whole-entry predicate (FLAT hosts): does `entry` belong to us?\n * NESTED hosts supplying {@link stripInner} may return a never-true predicate —\n * the engine then only ever invokes `stripInner`. Bound to `ctx` because\n * ownership is connector-generic (ANY of our commands), wider than the\n * install-time specific-command check. The `event` param lets EVENT-SPECIFIC\n * hosts (codex, whose ownership is per-event by construction) match the\n * canonical event being stripped; hosts whose ownership is event-independent\n * (claude-code/droid/cursor/qwen) ignore it — a `(ctx) => …` arrow is assignable\n * to this 2-param type (fewer params is fine in TS), so they need no change.\n */\n ownsEntryForRemove(ctx: InstallContext, event: string): (entry: E) => boolean;\n /**\n * Uninstall inner-strip (NESTED hosts): strip our owned inner commands from\n * `entry`, returning the rebuilt entry (`null` when fully emptied) and the\n * count of inner commands removed. Omit for FLAT hosts.\n */\n stripInner?(ctx: InstallContext): (entry: E) => { next: E | null; removed: number };\n /** Idempotent-reinstall skip detail, e.g. `hooks.<event> already registered`. */\n skipDetail(event: string): string;\n /** Uninstall remove detail, e.g. `hooks.<event> (<n>)`. */\n removeDetail(event: string, removed: number): string;\n /** Uninstall skip detail when no hooks section is present at all. */\n absentDetail: string;\n /** Uninstall skip detail when a hooks section exists but nothing matched. */\n noMatchDetail: string;\n /**\n * Uninstall: the exact event keys to scan, in order. Omit (default) to scan\n * every key actually present (`Object.keys(hooks)`). EVENT-SPECIFIC hosts whose\n * ownership predicate rebuilds a per-event command (codex) MUST pin their fixed\n * event set here so a home-bin command hand-placed under a foreign event key is\n * left untouched — byte-identical to a fixed-event-list uninstall loop.\n */\n removeEventKeys?: readonly string[];\n /** Optional post-mutation hook on the whole parsed file, before the single write. */\n onMutate?(file: Record<string, unknown>): void;\n /**\n * Native-pass ownership find (EXACT command match, vs the normalized\n * entryOwnsCommand). Set only when a `native` list is passed.\n */\n nativeOwnsCommand?(entry: E, command: string): boolean;\n /** Native-pass skip detail, e.g. `hooks.<event> (native) already registered`. */\n nativeSkipDetail?(event: string): string;\n /** Native-pass create/update detail, e.g. `hooks.<event> (native)`. */\n nativeMutateDetail?(event: string): string;\n}\n\n/**\n * One resolved action trigger for an EMITTER adapter: the host-native trigger\n * the adapter writes runs `command`, which re-enters the home binary at the\n * `action` verb. `label`/`description` fall back to the action id when the\n * connector declared none. Produced by {@link BaseAdapter.actionTriggers}.\n */\nexport interface ActionTrigger {\n /** The action id — also the per-action file/key name on most hosts. */\n id: string;\n /** Display label (action.description ?? action.id). */\n label: string;\n /** One-line description (action.description ?? action.id). */\n description: string;\n /** `<homeBin> action <host> <id> --connector <connectorId>` (the verb the host runs). */\n command: string;\n}\n\n/**\n * Documented USER-scope AGENTS.md locations, per host (the AGENTS.md-first\n * research matrix). Only hosts with a REAL user/global AGENTS.md file are\n * listed. Hosts whose documented user-scope memory lives in a DIFFERENT file\n * (qwen-code ~/.qwen/QWEN.md, goose .goosehints, kilo/roo/kiro rules dirs,\n * copilot-cli copilot-instructions.md) override memoryTargets in-adapter;\n * hosts whose user rules are app/UI/cloud-managed (warp Drive, trae,\n * jetbrains/cursor settings UI) deliberately have no row — user-scope memory\n * there reports the standard skip-warn (the JetBrains-MCP precedent), never a\n * write into a file the host ignores.\n */\nconst AGENTS_MD_USER_PATHS: Partial<Record<PlatformId, () => MemoryTarget>> = {\n // codex resolves its own user path in-adapter ($CODEX_HOME with ~ expansion\n // + the AGENTS.override.md shadow probe) — deliberately no row here.\n zed: () => ({\n path:\n process.platform === \"win32\" && process.env.APPDATA\n ? join(process.env.APPDATA, \"Zed\", \"AGENTS.md\")\n : join(homedir(), \".config\", \"zed\", \"AGENTS.md\"),\n reason: \"zed personal instructions file\",\n }),\n amp: () => ({\n path: join(homedir(), \".config\", \"amp\", \"AGENTS.md\"),\n reason: \"amp user-scope AGENTS.md\",\n }),\n mux: () => ({\n path: join(homedir(), \".mux\", \"AGENTS.md\"),\n reason: \"mux global AGENTS.md\",\n }),\n pi: () => ({\n path: join(homedir(), \".pi\", \"agent\", \"AGENTS.md\"),\n reason: \"pi global AGENTS.md\",\n }),\n droid: () => ({\n path: join(homedir(), \".factory\", \"AGENTS.md\"),\n reason: \"droid (Factory) personal AGENTS.md\",\n }),\n opencode: () => ({\n path: join(homedir(), \".config\", \"opencode\", \"AGENTS.md\"),\n reason: \"opencode global AGENTS.md\",\n }),\n antigravity: () => ({\n path: join(homedir(), \".gemini\", \"AGENTS.md\"),\n reason: \"antigravity global rules (~/.gemini/AGENTS.md, shared tree)\",\n }),\n \"antigravity-cli\": () => ({\n path: join(homedir(), \".gemini\", \"AGENTS.md\"),\n reason: \"agy shares the IDE's ~/.gemini tree (idempotent upsert dedupes)\",\n }),\n omp: () => ({\n path: join(homedir(), \".omp\", \"agent\", \"AGENTS.md\"),\n reason: \"omp global AGENTS.md (pi-parity; verify for your version)\",\n }),\n};\n\nexport abstract class BaseAdapter implements Adapter {\n abstract readonly id: PlatformId;\n abstract readonly name: string;\n abstract readonly paradigm: HookParadigm;\n abstract readonly capabilities: PlatformCapabilities;\n\n abstract detectInstalled(projectDir: string): DetectedPlatform;\n abstract getConfigDir(ctx: InstallContext): string;\n abstract getServerConfigPath(ctx: InstallContext): string;\n abstract getHookConfigPath(ctx: InstallContext): string;\n abstract installServer(ctx: InstallContext): ChangeRecord[];\n abstract uninstallServer(ctx: InstallContext): ChangeRecord[];\n abstract installHooks(ctx: InstallContext): ChangeRecord[];\n abstract uninstallHooks(ctx: InstallContext): ChangeRecord[];\n\n // ── Content surfaces (commands / skills / subagents) ─────────────────────\n // CONCRETE (overridable) defaults so every adapter inherits all six methods\n // and the installer can call them without optional-chaining. Each returns a\n // single skip when the connector declares no entries of that surface, else a\n // single \"warn\" — mirroring the mcp-only hook handling. Supporting adapters\n // override only the surfaces they honor.\n\n installCommands(ctx: InstallContext): ChangeRecord[] {\n return this.unsupportedSurface(ctx, \"commands\", ctx.connector.commands.length);\n }\n uninstallCommands(ctx: InstallContext): ChangeRecord[] {\n return this.unsupportedSurface(ctx, \"commands\", ctx.connector.commands.length);\n }\n installSkills(ctx: InstallContext): ChangeRecord[] {\n return this.unsupportedSurface(ctx, \"skills\", ctx.connector.skills.length);\n }\n uninstallSkills(ctx: InstallContext): ChangeRecord[] {\n return this.unsupportedSurface(ctx, \"skills\", ctx.connector.skills.length);\n }\n installSubagents(ctx: InstallContext): ChangeRecord[] {\n return this.unsupportedSurface(ctx, \"subagents\", ctx.connector.subagents.length);\n }\n uninstallSubagents(ctx: InstallContext): ChangeRecord[] {\n return this.unsupportedSurface(ctx, \"subagents\", ctx.connector.subagents.length);\n }\n\n // ── Memory surface (managed marker blocks; AGENTS.md-first) ───────────────\n // ONE generic implementation for every supporting host: the per-adapter\n // `memoryTargets()` hook resolves WHERE to write (AGENTS.md defaults below;\n // claude-code → CLAUDE.md and gemini-cli → GEMINI.md override it), and the\n // core/managed-block engine performs the surgical, hash-stamped block edit.\n // Unlike commands/skills/subagents these files are SHARED and user-authored —\n // bytes outside this connector's own marker pair are never touched.\n\n /**\n * Resolve the memory/rules file(s) this host actually reads at ctx.scope.\n * Base default (AGENTS.md-first, owner mandate):\n * - an explicit `platforms[<id>].memory.path` override wins;\n * - project scope → `<projectDir>/AGENTS.md` (the agents.md standard);\n * - user scope → the host's documented user-scope AGENTS.md, when one\n * exists ({@link AGENTS_MD_USER_PATHS}); otherwise [] → skip-warn.\n * Exception hosts (claude-code, gemini-cli) override this hook.\n */\n protected memoryTargets(ctx: InstallContext): MemoryTarget[] {\n const override = this.memoryOverride(ctx);\n if (override?.path) {\n const base = ctx.scope === \"project\" ? ctx.projectDir : homedir();\n return [\n {\n path: isAbsolute(override.path) ? override.path : join(base, override.path),\n reason: `platforms.${this.id}.memory.path override`,\n },\n ];\n }\n if (ctx.scope === \"project\") {\n return [\n { path: join(ctx.projectDir, \"AGENTS.md\"), reason: \"AGENTS.md standard (project root)\" },\n ];\n }\n if (ctx.scope === \"user\") {\n const user = AGENTS_MD_USER_PATHS[this.id]?.();\n return user ? [user] : [];\n }\n return [];\n }\n\n /** The per-platform memory override object, when one is declared. */\n protected memoryOverride(ctx: InstallContext): PlatformMemoryOverride | undefined {\n const o = ctx.connector.platforms[this.id]?.memory;\n return o && typeof o === \"object\" ? o : undefined;\n }\n\n installMemory(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n // `?? []` tolerates pre-resolved connectors from versions before the\n // memory surface existed (the installer applies the same guard).\n const entries = connector.memory ?? [];\n if (connector.platforms[this.id]?.memory === false) {\n return [{ platform: this.id, action: \"skip\", detail: `memory disabled for ${this.id}` }];\n }\n if (entries.length === 0) {\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no memory\" }];\n }\n if (!(this.capabilities.supportsMemory ?? false)) {\n return this.unsupportedSurface(ctx, \"memory\", entries.length);\n }\n\n const changes: ChangeRecord[] = [];\n const override = this.memoryOverride(ctx);\n if (override?.mode && this.id !== \"claude-code\") {\n changes.push({\n platform: this.id,\n action: \"warn\",\n detail: `memory.mode is claude-code-only; ignored on ${this.id}`,\n });\n }\n if (ctx.scope !== \"project\" && ctx.scope !== \"user\") {\n // system/profile/managed memory files are admin-owned — out of scope (v1).\n changes.push({\n platform: this.id,\n action: \"warn\",\n detail:\n `memory not supported at ${ctx.scope} scope on ${this.id} ` +\n `(managed/admin memory files are out of scope); ${entries.length} skipped`,\n });\n return changes;\n }\n const targets = this.memoryTargets(ctx);\n if (targets.length === 0) {\n changes.push({\n platform: this.id,\n action: \"warn\",\n detail:\n `no ${ctx.scope}-scope memory file on ${this.id} ` +\n `(user rules are app/UI-managed or undocumented); ${entries.length} skipped`,\n });\n return changes;\n }\n changes.push(...this.writeMemoryBlocks(ctx, targets));\n return changes;\n }\n\n /**\n * Upsert every declared memory entry's block into every resolved target and\n * record the ownership ledger rows (`connectorDir(id)/memory-state.json`).\n * Shared by the base implementation and the exception-host overrides.\n */\n protected writeMemoryBlocks(ctx: InstallContext, targets: MemoryTarget[]): ChangeRecord[] {\n const changes: ChangeRecord[] = [];\n const ledger = loadMemoryLedger(ctx.connector.id);\n let ledgerMutated = false;\n\n for (const target of targets) {\n const symlink = this.symlinkPathWarning(target.path);\n if (symlink) {\n changes.push(symlink);\n continue;\n }\n\n for (const entry of ctx.connector.memory ?? []) {\n const blockId = `${ctx.connector.id}/${entry.name ?? \"memory\"}`;\n const res = upsertManagedBlockFile(target.path, {\n blockId,\n connectorId: ctx.connector.id,\n content: entry.content,\n ...(target.commentStyle ? { commentStyle: target.commentStyle } : {}),\n force: ctx.force ?? false,\n dryRun: ctx.dryRun,\n });\n changes.push({\n platform: this.id,\n action: res.action,\n path: target.path,\n detail: `memory: ${res.detail} — ${target.reason}`,\n });\n if (res.backupPath) {\n changes.push({\n platform: this.id,\n action: \"create\",\n path: res.backupPath,\n detail: \"backed up memory file before destructive change\",\n });\n }\n const bytes = Buffer.byteLength(entry.content, \"utf8\");\n if (bytes > MEMORY_CONTENT_SOFT_BUDGET_BYTES) {\n changes.push({\n platform: this.id,\n action: \"warn\",\n path: target.path,\n detail:\n `memory entry \"${entry.name ?? \"memory\"}\" is ${bytes} bytes ` +\n `(soft budget ${MEMORY_CONTENT_SOFT_BUDGET_BYTES}); this file is injected into ` +\n `every prompt — keep guidance terse`,\n });\n }\n if (res.action !== \"warn\") {\n recordMemoryTarget(ledger, {\n platform: this.id,\n scope: ctx.scope,\n path: target.path,\n blockId,\n createdFile: res.createdFile,\n hash: res.hash,\n });\n ledgerMutated = true;\n }\n }\n // Per-FILE budget (e.g. codex caps combined project docs at 32 KiB —\n // budgetBytes ≈ 28 KiB leaves headroom): warn when the whole target file\n // (user content + every block) outgrows what the host will actually load.\n if (target.budgetBytes !== undefined && !ctx.dryRun && existsSync(target.path)) {\n const fileBytes = statSync(target.path).size;\n if (fileBytes > target.budgetBytes) {\n changes.push({\n platform: this.id,\n action: \"warn\",\n path: target.path,\n detail:\n `memory file is ${fileBytes} bytes — over this host's ~${target.budgetBytes}-byte ` +\n `budget; the host may truncate or drop it`,\n });\n }\n }\n }\n\n if (ledgerMutated && !ctx.dryRun) saveMemoryLedger(ctx.connector.id, ledger);\n return changes;\n }\n\n uninstallMemory(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n if (!(this.capabilities.supportsMemory ?? false)) {\n // Nothing could ever have been written by a non-supporting adapter.\n return this.unsupportedSurface(ctx, \"memory\", (connector.memory ?? []).length);\n }\n\n // Candidate files = union of (a) memoryTargets recomputed NOW (probe re-run\n // — catches teammate machines with no ledger; the markers in the committed\n // file are the source of truth) and (b) ledger rows for this platform from\n // EVERY scope (catches a scope flag that differs from install time).\n const ledger = loadMemoryLedger(connector.id);\n const mine = ledger.targets.filter((t) => t.platform === this.id);\n const candidates = new Map<string, { createdFile: boolean }>();\n if (ctx.scope === \"project\" || ctx.scope === \"user\") {\n for (const t of this.memoryTargets(ctx)) {\n candidates.set(t.path, { createdFile: false });\n }\n }\n for (const row of mine) {\n const existing = candidates.get(row.path);\n candidates.set(row.path, { createdFile: (existing?.createdFile ?? false) || row.createdFile });\n }\n if (candidates.size === 0) {\n return [\n { platform: this.id, action: \"skip\", detail: `no memory targets to clean on ${this.id}` },\n ];\n }\n\n // Prefix scan (`<connectorId>/`), NOT the declared entry list: renamed or\n // removed entries and stale blocks from older versions are reclaimed too.\n const changes: ChangeRecord[] = [];\n let sawSymlink = false;\n for (const [path, { createdFile }] of candidates) {\n const symlink = this.symlinkPathWarning(path);\n if (symlink) {\n changes.push(symlink);\n sawSymlink = true;\n continue;\n }\n\n const results = removeManagedBlocksFile(\n path,\n { blockIdPrefix: `${connector.id}/` },\n { dryRun: ctx.dryRun, deleteFileIfCreated: createdFile },\n );\n for (const r of results) {\n changes.push({\n platform: this.id,\n action: r.action,\n path: r.path,\n detail: `memory: ${r.detail}`,\n });\n if (r.backupPath) {\n changes.push({\n platform: this.id,\n action: \"create\",\n path: r.backupPath,\n detail: \"backed up memory file before block removal\",\n });\n }\n }\n }\n\n // Prune this connector's ledger rows for this platform (the file itself is\n // deleted when no rows remain). Markers stay the uninstall source of truth.\n if (!ctx.dryRun && mine.length > 0 && !sawSymlink) {\n ledger.targets = ledger.targets.filter((t) => t.platform !== this.id);\n saveMemoryLedger(connector.id, ledger);\n }\n return changes;\n }\n\n /**\n * Doctor: per-ledger-row memory state for this platform — file present,\n * block present, and recorded-vs-actual inner hash (drift → warn, the\n * user edited inside our block; sync reports the same drift and never\n * clobbers it without --force).\n */\n protected memoryDiagnostics(ctx: InstallContext): DiagnosticResult[] {\n const results: DiagnosticResult[] = [];\n const rows = loadMemoryLedger(ctx.connector.id).targets.filter(\n (t) => t.platform === this.id,\n );\n for (const row of rows) {\n const check = `${this.name}: memory block ${row.blockId}`;\n if (!existsSync(row.path)) {\n results.push({\n check,\n status: \"warn\",\n message: `memory file missing: ${row.path}`,\n fix: \"agent-connector install (sync) will re-create the block\",\n fixable: true,\n });\n continue;\n }\n let raw: string;\n try {\n raw = readFileSync(row.path, \"utf8\");\n } catch {\n results.push({ check, status: \"warn\", message: `cannot read ${row.path}` });\n continue;\n }\n const block = listManagedBlocks(raw).find((b) => b.blockId === row.blockId);\n if (!block) {\n results.push({\n check,\n status: \"warn\",\n message: `managed block not found in ${row.path}`,\n fix: \"agent-connector install (sync) will re-append it\",\n fixable: true,\n });\n } else if (block.drifted) {\n results.push({\n check,\n status: \"warn\",\n message:\n `user-edited: inner content hash ${block.actualHash} differs from recorded ` +\n `${block.recordedHash} in ${row.path}; sync leaves it intact (use --force to overwrite)`,\n });\n } else {\n results.push({ check, status: \"pass\", message: `intact in ${row.path}` });\n }\n // Shadow-flip probe: re-run memoryTargets NOW for the row's scope — if\n // the host's resolution moved (a WARP.md / AGENTS.override.md / .rules /\n // .hermes.md appeared, gemini context.fileName changed), the written\n // block sits in a file the host no longer reads. The #1 wrong-file\n // risk; doctor is the detection layer.\n // (`_shared/` bridge rows deliberately live OUTSIDE memoryTargets —\n // e.g. claude-code's @AGENTS.md import in CLAUDE.md — skip those.)\n if (\n !row.blockId.startsWith(\"_shared/\") &&\n row.scope === ctx.scope &&\n (ctx.scope === \"project\" || ctx.scope === \"user\")\n ) {\n const current = this.memoryTargets(ctx);\n if (current.length > 0 && !current.some((t) => t.path === row.path)) {\n results.push({\n check,\n status: \"warn\",\n message:\n `${this.id} now resolves its ${row.scope}-scope memory file to ` +\n `${current[0]!.path} (${current[0]!.reason}) — the block in ${row.path} ` +\n `may no longer be read`,\n fix: \"agent-connector install (sync) re-probes and writes the file the host reads now\",\n fixable: true,\n });\n }\n }\n }\n return results;\n }\n\n // ── Declarative host-config key patches (configPatch) ─────────────────────\n // CONCRETE (overridable) defaults, mirroring the content surfaces above: the\n // installer additionally guards these behind capabilities.supportsConfigPatch\n // (the nativeHooks precedent), so these defaults only fire if a capability-\n // flagged adapter forgot to override them — still skip-warn, never silent.\n\n installConfigPatches(ctx: InstallContext): ChangeRecord[] {\n const count = (ctx.connector.platforms[this.id]?.configPatch ?? []).length;\n if (count === 0) {\n return [\n { platform: this.id, action: \"skip\", detail: \"connector declares no configPatch entries\" },\n ];\n }\n return [\n {\n platform: this.id,\n action: \"warn\",\n detail: `configPatch not supported on ${this.id}; ${count} skipped`,\n },\n ];\n }\n\n uninstallConfigPatches(_ctx: InstallContext): ChangeRecord[] {\n // Nothing was ever applied by a non-supporting adapter → nothing to release.\n return [];\n }\n\n // ── Statusline surface (a HUD/status line) ────────────────────────────────\n // CONCRETE (overridable) defaults, mirroring the content surfaces: the\n // installer calls these unconditionally (BaseAdapter defines them), and they\n // self-skip when the connector declares no statusline, else skip-warn on a\n // non-supporting host. Only claude-code overrides them today.\n\n installStatusline(ctx: InstallContext): ChangeRecord[] {\n if (ctx.connector.statusline == null) {\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no statusline\" }];\n }\n if (ctx.connector.platforms[this.id]?.statusline === false) {\n return [{ platform: this.id, action: \"skip\", detail: `statusline disabled for ${this.id}` }];\n }\n if (!(this.capabilities.supportsStatusline ?? false)) {\n return this.unsupportedSurface(ctx, \"statusline\", 1);\n }\n // A supporting adapter must override this; the default is the same skip-warn\n // safety net the configPatch defaults provide (never silent).\n return this.unsupportedSurface(ctx, \"statusline\", 1);\n }\n\n uninstallStatusline(ctx: InstallContext): ChangeRecord[] {\n if (ctx.connector.statusline == null) {\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no statusline\" }];\n }\n if (!(this.capabilities.supportsStatusline ?? false)) {\n // Nothing could ever have been written by a non-supporting adapter.\n return this.unsupportedSurface(ctx, \"statusline\", 1);\n }\n return this.unsupportedSurface(ctx, \"statusline\", 1);\n }\n\n // ── Action surface (a user-invokable action) ──────────────────────────────\n // CONCRETE (overridable) defaults, mirroring the statusline pair. v1 ships\n // ONLY the dispatch backbone: there is no verifiable host affordance to emit,\n // so EVERY host honestly skip-warns and NO adapter overrides these. (`?? []`\n // tolerates pre-resolved connectors from versions before the action surface\n // existed, exactly like installMemory.)\n\n installActions(ctx: InstallContext): ChangeRecord[] {\n return this.unsupportedSurface(ctx, \"actions\", (ctx.connector.actions ?? []).length);\n }\n uninstallActions(ctx: InstallContext): ChangeRecord[] {\n return this.unsupportedSurface(ctx, \"actions\", (ctx.connector.actions ?? []).length);\n }\n\n /**\n * Shared, surface-agnostic helper for the action EMITTERS: yield one\n * {@link ActionTrigger} per declared action, each carrying the home-bin verb\n * command the host trigger must run\n * (`<homeBin> action <host> <actionId> --connector <id>`, via\n * {@link buildHomeBinActionCommand}) plus a `label`/`description` that fall\n * back to the action id. Each supporting adapter iterates this and writes its\n * host-native trigger (hermes quick_commands / warp workflow / droid exec\n * file) — the per-host file shape is NOT this helper's concern, only the\n * common (id, label, description, command) tuple. Callers own the standard\n * guards (platforms[id].actions === false / empty actions).\n */\n protected actionTriggers(ctx: InstallContext): ActionTrigger[] {\n return (ctx.connector.actions ?? []).map((action) => ({\n id: action.id,\n label: action.description ?? action.id,\n description: action.description ?? action.id,\n command: buildHomeBinActionCommand(\n ctx.homeBinPath,\n this.id,\n action.id,\n ctx.connector.id,\n ),\n }));\n }\n\n /**\n * Default response for a content surface this platform cannot honor: a single\n * skip when the connector declares none of that surface, else a single \"warn\"\n * ChangeRecord noting how many were skipped. Mirrors mcp-only hook handling.\n */\n protected unsupportedSurface(\n _ctx: InstallContext,\n surface: ContentSurface,\n count: number,\n ): ChangeRecord[] {\n if (count === 0) {\n return [{ platform: this.id, action: \"skip\", detail: `connector declares no ${surface}` }];\n }\n return [\n {\n platform: this.id,\n action: \"warn\",\n detail: `${surface} not supported on ${this.id}; ${count} skipped`,\n },\n ];\n }\n\n // ── Content-file helpers (used by surface-supporting adapters) ────────────\n\n protected symlinkPathWarning(path: string): ChangeRecord | null {\n const symlink = firstSymlinkInPath(path);\n if (symlink === null) return null;\n return {\n platform: this.id,\n action: \"warn\",\n path,\n detail: `${basename(path)} skipped: symbolic link in path (${symlink})`,\n };\n }\n\n protected writeManagedFile(\n path: string,\n contents: string,\n dryRun: boolean,\n detail = basename(path),\n executable?: boolean,\n ): ChangeRecord {\n const symlink = this.symlinkPathWarning(path);\n if (symlink) return symlink;\n\n let action: ChangeRecord[\"action\"];\n if (!existsSync(path)) {\n action = \"create\";\n } else {\n let current: string | null = null;\n try {\n current = readFileSync(path, \"utf8\");\n } catch {\n current = null;\n }\n action = current === contents ? \"skip\" : \"update\";\n }\n if (action !== \"skip\" && !dryRun) {\n ensureDir(dirname(path));\n writeFileSync(path, contents, \"utf8\");\n if (executable !== undefined) chmodSync(path, executable ? 0o755 : 0o644);\n }\n return { platform: this.id, action, path, detail };\n }\n\n protected removeManagedFile(\n path: string,\n dryRun: boolean,\n detail = basename(path),\n absentDetail = `${detail} absent`,\n ): ChangeRecord {\n const symlink = this.symlinkPathWarning(path);\n if (symlink) return symlink;\n\n if (!existsSync(path)) {\n return { platform: this.id, action: \"skip\", path, detail: absentDetail };\n }\n if (!dryRun) {\n rmSync(path, { recursive: true, force: true });\n }\n return { platform: this.id, action: \"remove\", path, detail };\n }\n\n /**\n * Write a content file idempotently: \"skip\" when the existing bytes are\n * already identical, else \"create\"/\"update\". Creates parent dirs (mkdir -p).\n * Honors dryRun (computes the action but writes nothing).\n */\n protected writeContentFile(path: string, contents: string, dryRun: boolean): ChangeRecord {\n return this.writeManagedFile(path, contents, dryRun);\n }\n\n /**\n * Remove a content file we wrote; \"skip\" when already absent. Honors dryRun.\n * Uses rmSync with `force` to also tolerate a path that is a directory tree\n * (e.g. a skill folder removed by the supporting adapter).\n */\n protected removeContentFile(path: string, dryRun: boolean): ChangeRecord {\n return this.removeManagedFile(path, dryRun);\n }\n\n /**\n * Defense-in-depth path containment: resolve `rel` against `baseDir` and\n * return the absolute path ONLY when it stays inside `baseDir`. Returns null\n * when `rel` escapes (absolute path, `..` traversal, etc.) so a caller can\n * skip-and-warn rather than write/delete outside the surface dir. This is the\n * runtime backstop behind the config-time validation in normalizeSkills.\n */\n protected resolveWithin(baseDir: string, rel: string): string | null {\n const base = resolve(baseDir);\n const target = resolve(base, rel);\n if (target === base) return null; // rel resolved to the dir itself (e.g. \"\" / \".\")\n const rind = relative(base, target);\n // Outside when the relative path climbs out (`..`) or is itself absolute.\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 /**\n * Recursively report whether a directory tree contains any regular FILE (vs\n * only empty/nested-empty subdirectories). Symlinks count as files (we never\n * recurse through them). Used by removeDirIfEmpty to decide if a tree is safe\n * to drop. An unreadable entry is treated as \"a file is present\" (conservative).\n */\n private dirTreeHasFile(dir: string): boolean {\n let entries: Dirent[];\n try {\n entries = readdirSync(dir, { withFileTypes: true });\n } catch {\n return true; // unreadable → assume it holds data; do not remove\n }\n for (const e of entries) {\n if (e.isDirectory()) {\n if (this.dirTreeHasFile(join(dir, e.name))) return true;\n } else {\n return true; // a file / symlink / special → the tree is not \"empty\"\n }\n }\n return false;\n }\n\n /**\n * Remove a directory ONLY when its tree holds NO regular files — i.e. it is\n * empty or contains only (nested) empty directories, such as the intermediate\n * dirs our own nested skill resources created. Replaces the unconditional\n * `rm -rf <dir>` that uninstallSkills used to call, which destroyed user-added\n * files / sibling-tool files / shared skill dirs the connector never wrote.\n * When ANY file remains (at any depth) the whole tree is left in place and the\n * skip is noted. Honors dryRun (computes the action but removes nothing). A\n * missing dir is a no-op \"skip\".\n */\n protected removeDirIfEmpty(dir: string, dryRun: boolean): ChangeRecord {\n const symlink = this.symlinkPathWarning(dir);\n if (symlink) return symlink;\n\n if (!existsSync(dir)) {\n return { platform: this.id, action: \"skip\", path: dir, detail: `${basename(dir)} absent` };\n }\n let stat: ReturnType<typeof statSync>;\n try {\n stat = statSync(dir);\n } catch {\n return {\n platform: this.id,\n action: \"skip\",\n path: dir,\n detail: `${basename(dir)} unreadable; left in place`,\n };\n }\n if (!stat.isDirectory()) {\n return {\n platform: this.id,\n action: \"skip\",\n path: dir,\n detail: `${basename(dir)} not a directory; left in place`,\n };\n }\n if (this.dirTreeHasFile(dir)) {\n return {\n platform: this.id,\n action: \"skip\",\n path: dir,\n detail: `${basename(dir)} still holds files we did not write; left in place`,\n };\n }\n if (!dryRun) {\n try {\n // The tree is files-free: only (possibly nested) empty dirs remain, which\n // are ours / inert. A recursive remove drops them without touching data.\n rmSync(dir, { recursive: true, force: true });\n } catch {\n // Lost a race or perms — non-fatal; report as a skip.\n return {\n platform: this.id,\n action: \"skip\",\n path: dir,\n detail: `${basename(dir)} could not be removed; left in place`,\n };\n }\n }\n return { platform: this.id, action: \"remove\", path: dir, detail: basename(dir) };\n }\n\n /**\n * Render a YAML-frontmatter + markdown body document:\n * \"---\\n\" + <yaml> + \"---\\n\\n\" + <body> + \"\\n\".\n * Delegates to the shared renderer (adapters/claude-code/render) so every\n * content-file path — adapters AND the plugin packager — emits identical bytes.\n */\n protected renderFrontmatterMd(\n frontmatter: Record<string, unknown>,\n body: string,\n ): string {\n return renderFrontmatterMd(frontmatter, body);\n }\n\n // ── JSON config helpers (used by JSON-format adapters) ───────────────────\n\n /**\n * Read + parse a JSON/JSONC config file, returning null when it is absent OR\n * unparseable. Parses TOLERANTLY via parseJsonc (strips // and /* *\\/ comments\n * and trailing commas) so a perfectly valid JSONC file never false-fails to\n * null — that null is what `?? {}` would otherwise turn into a clobbering\n * overwrite of the user's whole config.\n */\n protected readJson<T = Record<string, unknown>>(path: string): T | null {\n if (!existsSync(path)) return null;\n try {\n return parseJsonc<T>(readFileSync(path, \"utf8\"));\n } catch {\n return null;\n }\n }\n\n /**\n * True when `path` exists and holds non-whitespace content but readJson cannot\n * parse it (even after JSONC stripping). The overwrite guard: writing a\n * `{}`-based config over a present-but-broken settings file would silently\n * destroy the user's data, so callers warn-and-skip instead.\n */\n protected isPresentButUnparseable(path: string): boolean {\n if (!existsSync(path)) return false;\n let raw: string;\n try {\n if (statSync(path).size === 0) return false;\n raw = readFileSync(path, \"utf8\");\n } catch {\n return false;\n }\n if (raw.trim() === \"\") return false;\n return this.readJson(path) === null;\n }\n\n protected writeJson(path: string, data: unknown, dryRun = false): void {\n if (dryRun) return;\n const symlink = firstSymlinkInPath(path);\n if (symlink !== null) {\n throw new Error(`${basename(path)} skipped: symbolic link in path (${symlink})`);\n }\n ensureDir(dirname(path));\n writeFileSync(path, `${JSON.stringify(data, null, 2)}\\n`, \"utf8\");\n }\n\n /**\n * True when a PRESENT rootKey value is not a plain object map (the user\n * hand-edited it to an array / string / number / boolean). Assigning a server\n * entry into such a value would corrupt the file silently (a named property on\n * an Array is dropped by JSON.stringify) or throw under strict mode (a property\n * write / `in` operator against a primitive), so callers warn-and-skip. A\n * `null`/`undefined` value is NOT malformed — it is the well-formed \"absent\"\n * case the helpers create fresh.\n */\n protected isMalformedRootValue(value: unknown): boolean {\n return isMalformedRootValueFn(value);\n }\n\n /**\n * Warn-skip ChangeRecord when an existing JSON `hooks` config is present-but-\n * malformed (root hand-edited to an array/primitive, or an existing event\n * bucket is a non-array) — installing a hook into it would silently drop the\n * entry (a named property on an Array is dropped by JSON.stringify) or throw\n * under strict mode (a `.push`/property write against a primitive or non-array\n * bucket). Returns null when the hooks config is well-formed, including the\n * absent case the installers create fresh (proceed normally). Mirrors the\n * server-root guard (isMalformedRootValue). All targeted hosts use the Claude-\n * style `{ Event: Matcher[] }` shape, so every present event bucket must be an\n * array; a non-array bucket is the same malformed class as a wrong-typed root.\n */\n protected malformedHookRootSkip(configPath: string, hooksRoot: unknown): ChangeRecord | null {\n if (hooksRoot == null) return null; // absent → installer creates fresh\n if (this.isMalformedRootValue(hooksRoot)) {\n // array / primitive root\n return {\n platform: this.id,\n action: \"warn\",\n path: configPath,\n detail: `existing \"hooks\" in ${configPath} is not an object map; left untouched (fix it, then re-run)`,\n };\n }\n for (const v of Object.values(hooksRoot as Record<string, unknown>)) {\n if (v !== undefined && !Array.isArray(v)) {\n // an existing event bucket is a non-array\n return {\n platform: this.id,\n action: \"warn\",\n path: configPath,\n detail: `existing \"hooks\" in ${configPath} has a non-array event bucket; left untouched (fix it, then re-run)`,\n };\n }\n }\n return null;\n }\n\n // ── Shared object-map hook-array merge engine ────────────────────────────\n // installHooks/uninstallHooks for every json-stdio host that stores hooks as\n // `{ <event>: HookEntry[] }` share ONE create/update/skip + strip/remove\n // orchestration. The host supplies a {@link HookMergeDescriptor} carrying\n // EVERY observable string and ownership predicate — the engine body hardcodes\n // none of them, so per-host wording (skip/remove/absent/no-match details) and\n // FLAT-vs-NESTED removal stay host-controlled and never drift to a lowest-\n // common-denominator phrasing the suites (which assert by action) would miss.\n // The write-gate is the `mutated` bool, matching the migrated host exactly.\n\n /**\n * Install: upsert each `{ event, matcher }` in `pending` into the object-map\n * `hooks` root at `configPath`. Reproduces the canonical host's loop: read\n * `?? {}`, warn-skip on a malformed `hooks` root, then per pending item render\n * the entry, find the owned slot, and create/update/skip. Writes once at the\n * end iff anything mutated.\n *\n * Hosts that fold their `nativeHooks` surface into `pending` (claude-code) pass\n * no `native` arg. Hosts that keep the native surface SEPARATE — verbatim\n * event keys, EXACT-command ownership, a distinct `(native)` detail — pass it\n * as the optional `native` list (cursor); that pass runs after the normalized\n * loop and before the single write. Omitting it is byte-identical to before.\n */\n /**\n * Resolve the per-event hook bucket. With \"coerce\" policy a present-but-non-\n * array bucket (hand-edited) is replaced by a fresh array; otherwise `??=` is\n * used (the warn-skip path already rejected any non-array bucket via\n * malformedHookRootSkip, so `??=` only ever fills the absent case).\n */\n private coerceHookBucket<E>(\n hooks: Record<string, E[]>,\n event: string,\n coerce: boolean,\n ): E[] {\n if (coerce) {\n return Array.isArray(hooks[event]) ? hooks[event] : (hooks[event] = []);\n }\n return (hooks[event] ??= []);\n }\n\n protected upsertHookEntries<E>(\n ctx: InstallContext,\n configPath: string,\n pending: ReadonlyArray<{ event: string; matcher: string }>,\n descriptor: HookMergeDescriptor<E>,\n native?: ReadonlyArray<{ event: string; matcher: string }>,\n ): ChangeRecord[] {\n const symlink = this.symlinkPathWarning(configPath);\n if (symlink) return [symlink];\n\n const file = this.readJson<Record<string, unknown>>(configPath) ?? {};\n const coerce = descriptor.malformedPolicy === \"coerce\";\n let hooks: Record<string, E[]>;\n if (coerce) {\n // COERCE policy: a present-but-malformed `hooks` root (array / primitive,\n // hand-edited) is replaced by a fresh object map; a well-formed object map\n // is kept as-is. Never warn, never throw — matches the container hosts'\n // server-path policy.\n const existing = file.hooks;\n hooks =\n existing && typeof existing === \"object\" && !Array.isArray(existing)\n ? (existing as Record<string, E[]>)\n : ((file.hooks = {}) as Record<string, E[]>);\n } else {\n const skip = this.malformedHookRootSkip(configPath, file.hooks);\n if (skip) return [skip];\n hooks = (file.hooks ??= {}) as Record<string, E[]>;\n }\n\n const changes: ChangeRecord[] = [];\n let mutated = false;\n\n for (const { event, matcher } of pending) {\n const hostEvent = descriptor.mapEvent ? descriptor.mapEvent(event) : event;\n if (hostEvent === undefined) {\n changes.push({\n platform: this.id,\n action: \"warn\",\n path: configPath,\n detail: descriptor.unmappedWarnDetail!(event),\n });\n continue;\n }\n // Command is built from the CANONICAL `event` (NOT hostEvent) — the home\n // binary dispatches on the canonical name; only the host's bucket key,\n // detail, and skipDetail use the mapped `hostEvent`.\n const command = buildHomeBinHookCommand(\n ctx.homeBinPath,\n this.id,\n event,\n ctx.connector.id,\n );\n const entry = descriptor.renderEntry(hostEvent, matcher, command);\n const bucket = this.coerceHookBucket(hooks, hostEvent, coerce);\n const r = upsertInArray(bucket, entry, (e) =>\n descriptor.entryOwnsCommand(e, command),\n );\n\n if (r.action !== \"skip\") {\n hooks[hostEvent] = r.array;\n mutated = true;\n }\n changes.push({\n platform: this.id,\n action: r.action,\n path: configPath,\n detail:\n r.action === \"skip\"\n ? descriptor.skipDetail(hostEvent)\n : `hooks.${hostEvent}`,\n });\n }\n\n // Native pass (json-stdio hosts with a verbatim `nativeHooks` surface):\n // native event-name keys are NOT mapEvent-mapped, are found by EXACT command\n // (so a native key coinciding with a normalized event's mapped key adds a\n // SECOND distinct command rather than clobbering it), and carry the `(native)`\n // detail. Hosts passing no `native` list skip this loop entirely → the\n // normalized-only behavior is byte-identical.\n for (const { event, matcher } of native ?? []) {\n const command = buildHomeBinHookCommand(\n ctx.homeBinPath,\n this.id,\n event,\n ctx.connector.id,\n );\n const entry = descriptor.renderEntry(event, matcher, command);\n const bucket = this.coerceHookBucket(hooks, event, coerce);\n const r = upsertInArray(bucket, entry, (e) =>\n descriptor.nativeOwnsCommand!(e, command),\n );\n if (r.action !== \"skip\") {\n hooks[event] = r.array;\n mutated = true;\n }\n changes.push({\n platform: this.id,\n action: r.action,\n path: configPath,\n detail:\n r.action === \"skip\"\n ? descriptor.nativeSkipDetail!(event)\n : descriptor.nativeMutateDetail!(event),\n });\n }\n\n if (mutated) {\n descriptor.onMutate?.(file);\n this.writeJson(configPath, file, ctx.dryRun);\n }\n return changes;\n }\n\n /**\n * Uninstall: strip owned content from every event bucket in the object-map\n * `hooks` root at `configPath`. NESTED hosts pass `descriptor.stripInner`\n * (strip owned inner commands, drop emptied entries; `removed` = inner\n * commands); FLAT hosts omit it (drop whole owned entries). Reproduces the\n * canonical host: read (NO `?? {}`), `[skip]` (absentDetail) when no hooks\n * section, per-event remove → delete-or-replace bucket, write once iff\n * mutated, and a single `[skip]` (noMatchDetail) when nothing matched.\n */\n protected removeHookEntries<E>(\n ctx: InstallContext,\n configPath: string,\n descriptor: HookMergeDescriptor<E>,\n ): ChangeRecord[] {\n const symlink = this.symlinkPathWarning(configPath);\n if (symlink) return [symlink];\n\n const file = this.readJson<Record<string, unknown>>(configPath);\n const hooks = file?.hooks as Record<string, E[]> | undefined;\n if (!file || !hooks) {\n return [\n {\n platform: this.id,\n action: \"skip\",\n path: configPath,\n detail: descriptor.absentDetail,\n },\n ];\n }\n\n const changes: ChangeRecord[] = [];\n let mutated = false;\n // stripInner is event-independent for current hosts → computed once. The\n // whole-entry ownership predicate is rebuilt PER EVENT so EVENT-SPECIFIC\n // hosts (codex) can match the canonical event being stripped; event-agnostic\n // hosts simply ignore the param.\n const stripInner = descriptor.stripInner?.(ctx);\n\n // Default: scan every present key. EVENT-SPECIFIC hosts pin a fixed event set\n // (descriptor.removeEventKeys) so a foreign-key bucket is never inspected —\n // matching their original fixed-event-list uninstall loop byte-for-byte.\n for (const event of descriptor.removeEventKeys ?? Object.keys(hooks)) {\n const bucket = hooks[event];\n if (!Array.isArray(bucket)) continue;\n\n const ownsEntry = descriptor.ownsEntryForRemove(ctx, event);\n const r = removeFromArray(bucket, ownsEntry, stripInner);\n if (r.removed > 0) {\n if (r.array.length > 0) hooks[event] = r.array;\n else delete hooks[event];\n changes.push({\n platform: this.id,\n action: \"remove\",\n path: configPath,\n detail: descriptor.removeDetail(event, r.removed),\n });\n mutated = true;\n }\n }\n\n if (mutated) this.writeJson(configPath, file, ctx.dryRun);\n if (changes.length === 0) {\n changes.push({\n platform: this.id,\n action: \"skip\",\n path: configPath,\n detail: descriptor.noMatchDetail,\n });\n }\n return changes;\n }\n\n /** Bind BaseAdapter's JSON leaf IO (readJson/writeJson + the unparseable\n * overwrite guard) as a Codec for the object-map engine. */\n private jsonObjectMapCodec(): ObjectMapCodec {\n return {\n parse: (path) => this.readJson<Record<string, unknown>>(path),\n serialize: (path, data, dryRun) => this.writeJson(path, data, dryRun),\n isPresentButUnparseable: (path) => this.isPresentButUnparseable(path),\n };\n }\n\n /**\n * Upsert `entry` at `config[rootKey][serverId]` in a JSON file, creating the\n * file/object as needed. Returns a ChangeRecord describing create/update/skip.\n * Idempotent: an identical entry yields \"skip\".\n */\n protected upsertServerInJson(\n configPath: string,\n rootKey: string,\n serverId: string,\n entry: unknown,\n dryRun = false,\n ): ChangeRecord {\n const symlink = this.symlinkPathWarning(configPath);\n if (symlink) return symlink;\n\n return upsertInObjectMap({\n codec: this.jsonObjectMapCodec(),\n rootKey,\n platform: this.id,\n configPath,\n entryId: serverId,\n entry,\n dryRun,\n });\n }\n\n /** Remove `config[rootKey][serverId]` from a JSON file. */\n protected removeServerFromJson(\n configPath: string,\n rootKey: string,\n serverId: string,\n dryRun = false,\n ): ChangeRecord {\n const symlink = this.symlinkPathWarning(configPath);\n if (symlink) return symlink;\n\n return removeFromObjectMap({\n codec: this.jsonObjectMapCodec(),\n rootKey,\n platform: this.id,\n configPath,\n entryId: serverId,\n dryRun,\n });\n }\n\n // ── Backup ───────────────────────────────────────────────────────────────\n\n backupSettings(ctx: InstallContext): string | null {\n const files = [...new Set([this.getServerConfigPath(ctx), this.getHookConfigPath(ctx)])].filter(\n (f) => existsSync(f),\n );\n if (files.length === 0) return null;\n if (ctx.dryRun) return null;\n ensureDir(backupsDir());\n const stamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n let last: string | null = null;\n for (const f of files) {\n const dest = join(backupsDir(), `${this.id}-${stamp}-${basename(f)}`);\n copyFileSync(f, dest);\n last = dest;\n }\n return last;\n }\n\n // ── Diagnostics ─────────────────────────────────────────────────────────\n\n getHealthChecks?(ctx: InstallContext): readonly HealthCheck[];\n\n doctor(ctx: InstallContext): DiagnosticResult[] {\n const results: DiagnosticResult[] = [];\n const cfg = this.getServerConfigPath(ctx);\n results.push(\n existsSync(cfg)\n ? { check: `${this.name}: config present`, status: \"pass\", message: cfg }\n : {\n check: `${this.name}: config present`,\n status: \"warn\",\n message: `not found: ${cfg}`,\n fix: `agent-connector install --targets ${this.id}`,\n // Only sync-recoverable when the connector actually declares a\n // server — a re-sync writes the config file only then. For a\n // serverless (memory/configPatch-only) connector the file is never\n // created, so marking it fixable would loop it into \"still failing\".\n fixable: !!ctx.connector.server,\n },\n );\n for (const hc of this.getHealthChecks?.(ctx) ?? []) {\n const r = hc.check();\n results.push({\n check: hc.name,\n status: r.status === \"OK\" ? \"pass\" : \"fail\",\n message: r.detail ?? r.status,\n });\n }\n // Memory-surface checks are ledger-driven: no installed memory → no rows →\n // no noise. Shared by every adapter (the overrides call super.doctor()).\n results.push(...this.memoryDiagnostics(ctx));\n return results;\n }\n}\n","/** Decision for one inner-array upsert. */\nexport type ArrayUpsertAction = \"create\" | \"update\" | \"skip\";\n\nexport interface ArrayUpsertResult<E> {\n array: E[];\n action: ArrayUpsertAction;\n}\n\n/**\n * Upsert one rendered `candidate` into a per-event hook array.\n * - find the FIRST entry the caller OWNS via `ownsEntry`;\n * - hit + JSON-equal → skip (array returned unchanged);\n * - hit + differs → update (replace that slot);\n * - miss → create (push).\n */\nexport function upsertInArray<E>(\n array: E[],\n candidate: E,\n ownsEntry: (entry: E) => boolean,\n): ArrayUpsertResult<E> {\n const idx = array.findIndex(ownsEntry);\n if (idx >= 0) {\n if (JSON.stringify(array[idx]) === JSON.stringify(candidate)) {\n return { array, action: \"skip\" };\n }\n const next = array.slice();\n next[idx] = candidate;\n return { array: next, action: \"update\" };\n }\n return { array: [...array, candidate], action: \"create\" };\n}\n\nexport interface ArrayRemoveResult<E> {\n array: E[];\n removed: number;\n}\n\n/**\n * Remove owned content from a per-event hook array.\n * - FLAT hosts: omit `stripInner` → drop whole entries matching `ownsEntry`;\n * `removed` = whole entries dropped.\n * - NESTED hosts: pass `stripInner` → strip owned inner commands and rebuild,\n * dropping entries left empty; `removed` = inner commands removed.\n */\nexport function removeFromArray<E>(\n array: E[],\n ownsEntry: (entry: E) => boolean,\n stripInner?: (entry: E) => { next: E | null; removed: number },\n): ArrayRemoveResult<E> {\n if (!stripInner) {\n const kept = array.filter((e) => !ownsEntry(e));\n return { array: kept, removed: array.length - kept.length };\n }\n const kept: E[] = [];\n let removed = 0;\n for (const e of array) {\n const r = stripInner(e);\n removed += r.removed;\n if (r.next !== null) kept.push(r.next);\n }\n return { array: kept, removed };\n}\n"],"mappings":"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","names":["kept"]}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
defineConnector
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-UVBAH263.js";
|
|
5
5
|
import {
|
|
6
|
+
assertNoSymlinkInPath,
|
|
6
7
|
connectorDir,
|
|
7
8
|
connectorsDir,
|
|
8
9
|
ensureDir
|
|
9
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-2HCJV6UO.js";
|
|
10
11
|
|
|
11
12
|
// src/core/load-connector.ts
|
|
12
13
|
import { existsSync, readdirSync, readFileSync, realpathSync, rmSync, writeFileSync } from "fs";
|
|
@@ -99,14 +100,16 @@ function registerConnector(connector, modulePath, scope) {
|
|
|
99
100
|
...scope !== void 0 ? { scope } : {}
|
|
100
101
|
};
|
|
101
102
|
const dir = connectorDir(connector.id);
|
|
102
|
-
ensureDir(dir);
|
|
103
103
|
const outPath = join(dir, "connector.json");
|
|
104
|
+
assertNoSymlinkInPath(outPath);
|
|
105
|
+
ensureDir(dir);
|
|
104
106
|
writeFileSync(outPath, `${JSON.stringify(meta, null, 2)}
|
|
105
107
|
`, "utf8");
|
|
106
108
|
return outPath;
|
|
107
109
|
}
|
|
108
110
|
function deregisterConnector(id) {
|
|
109
111
|
const dir = connectorDir(id);
|
|
112
|
+
assertNoSymlinkInPath(dir);
|
|
110
113
|
const existed = existsSync(dir);
|
|
111
114
|
if (existed) rmSync(dir, { recursive: true, force: true });
|
|
112
115
|
return { removed: existed, path: dir };
|
|
@@ -178,4 +181,4 @@ export {
|
|
|
178
181
|
connectorFromMeta,
|
|
179
182
|
listRegisteredConnectors
|
|
180
183
|
};
|
|
181
|
-
//# sourceMappingURL=chunk-
|
|
184
|
+
//# sourceMappingURL=chunk-RQCBBLTA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/load-connector.ts"],"sourcesContent":["/**\n * core/load-connector — discover, load, and register connector definitions.\n *\n * Responsibilities:\n * 1. Locate the developer's `agent-connector.config.{mjs,js,json}` by walking\n * upward from a start directory (the project root convention).\n * 2. Load a config from a path into a LIVE ResolvedConnector (with handlers).\n * 3. Register a connector by persisting SERIALIZABLE metadata (no functions)\n * to `connectorDir(id)/connector.json`, pointing at the source module so\n * live handlers can be re-imported at runtime from a stable record.\n *\n * Why split live vs. serialized? Hook handlers are functions and cannot survive\n * JSON. The registry stores only what JSON can hold plus an absolute\n * `modulePath`; the runtime re-imports that module to recover the live handlers.\n */\n\nimport { existsSync, readdirSync, readFileSync, realpathSync, rmSync, writeFileSync } from \"node:fs\";\nimport { dirname, isAbsolute, join, resolve } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\n\nimport type {\n CommandDef,\n HookEventName,\n InstallScope,\n MemoryDef,\n PlatformId,\n PlatformOverride,\n ResolvedConnector,\n ServerDef,\n SkillDef,\n SubagentDef,\n} from \"./types.js\";\nimport { defineConnector } from \"./define-connector.js\";\nimport { assertNoSymlinkInPath, connectorDir, connectorsDir, ensureDir } from \"./paths.js\";\n\n/** Candidate config filenames, in resolution-precedence order. */\nconst CONFIG_FILENAMES = [\n \"agent-connector.config.mjs\",\n \"agent-connector.config.js\",\n \"agent-connector.config.json\",\n] as const;\n\n/**\n * The serializable subset of a connector persisted to `connector.json`.\n * Hook handler functions are intentionally absent — only the absolute\n * `modulePath` is stored so the live ResolvedConnector can be re-imported.\n */\nexport interface RegisteredMeta {\n id: string;\n displayName: string;\n version: string;\n /** Absolute path to the source module that produced this connector. */\n modulePath: string;\n telemetry: ResolvedConnector[\"telemetry\"];\n /** Canonical event names the connector handles (handlers themselves stripped). */\n hookEvents: HookEventName[];\n hasServer: boolean;\n server: ServerDef | null;\n /**\n * Content surfaces (commands/skills/subagents). These are JSON-serializable\n * (no functions) so they persist cleanly and let uninstall locate the files\n * to remove even when the source module is gone.\n */\n commands: CommandDef[];\n skills: SkillDef[];\n subagents: SubagentDef[];\n /**\n * Memory entries (managed-block content surface). Plain content, persisted\n * whole so uninstall normally has the full entry list even when the source\n * module is gone (the marker prefix-scan is the fallback beyond that).\n */\n memory: MemoryDef[];\n targets: ResolvedConnector[\"targets\"];\n /** Per-platform overrides with any hook handler functions stripped. */\n platforms: Partial<Record<PlatformId, PlatformOverride>>;\n /**\n * The install scope this connector was registered under, persisted so the\n * runtime entrypoints (hook/statusline/action) can recover it cheaply (sync)\n * and stamp it onto the HostCtx/event — scope is an install-time property the\n * runtime otherwise has no access to. OPTIONAL: absent for an ad-hoc register\n * that passed no scope, or a record written before this field existed.\n * This is the install's RUN-WIDE DEFAULT scope; it can differ from the\n * effective per-host scope when a `platforms[host].scope` override is set (the\n * record is keyed by connector id only and holds no per-host scope map).\n */\n scope?: InstallScope;\n}\n\n/**\n * Search `startDir` and each ancestor for a connector config file. Returns the\n * absolute path to the first match (filesystem-root-stopping), or null.\n */\nexport function findConnectorConfig(startDir: string): string | null {\n let dir = resolve(startDir);\n // Walk upward until `dirname(dir) === dir` (filesystem root).\n for (;;) {\n for (const name of CONFIG_FILENAMES) {\n const candidate = join(dir, name);\n if (existsSync(candidate)) return candidate;\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return null;\n}\n\n/** True if a value already looks like a ResolvedConnector (vs. a raw config). */\nfunction isResolvedConnector(value: unknown): value is ResolvedConnector {\n return (\n typeof value === \"object\" &&\n value !== null &&\n Array.isArray((value as { hookEvents?: unknown }).hookEvents)\n );\n}\n\n/**\n * Load a connector from an absolute or relative path.\n * - `.json` → JSON.parse, then defineConnector().\n * - `.mjs` / `.js` → dynamic import (via pathToFileURL, Windows-safe),\n * take the default export. If it already looks like a\n * ResolvedConnector use it as-is; otherwise treat it as\n * a ConnectorConfig and run it through defineConnector().\n * Returns the live connector plus the absolute module path it came from.\n */\nexport async function loadConnectorFromPath(\n path: string,\n): Promise<{ connector: ResolvedConnector; modulePath: string }> {\n let modulePath = isAbsolute(path) ? path : resolve(path);\n // Canonicalize before building the file:// URL for dynamic import. On Windows a\n // short (8.3) temp path like C:\\Users\\RUNNER~1\\...\\x.mjs round-trips the \"~\" as\n // %7E and fails to load; realpathSync.native expands it to the real long path.\n // It also resolves symlinked temp roots (e.g. macOS /var -> /private/var).\n // If the file does not exist yet, fall through with the resolve()'d path so the\n // subsequent read/import throws the real not-found error.\n try {\n modulePath = realpathSync.native(modulePath);\n } catch {\n /* keep the resolve()'d path */\n }\n\n if (modulePath.endsWith(\".json\")) {\n const text = readFileSync(modulePath, \"utf8\");\n const config = JSON.parse(text) as unknown;\n const connector = defineConnector(config as Parameters<typeof defineConnector>[0]);\n return { connector, modulePath };\n }\n\n // .mjs / .js — dynamic ESM import. pathToFileURL keeps Windows paths valid.\n const moduleUrl = pathToFileURL(modulePath).href;\n const mod = (await import(/* @vite-ignore */ moduleUrl)) as {\n default?: unknown;\n };\n const exported = mod.default;\n if (exported == null) {\n throw new Error(\n `Connector module has no default export: ${modulePath}`,\n );\n }\n const connector = isResolvedConnector(exported)\n ? exported\n : defineConnector(exported as Parameters<typeof defineConnector>[0]);\n return { connector, modulePath };\n}\n\n/**\n * Strip any function-valued `hooks` from per-platform overrides so the result\n * is JSON-serializable. A boolean `hooks` override is preserved; an object\n * override is dropped (it can only carry handler functions, which are not\n * serializable). `nativeHooks` declarations are persisted HANDLER-LESS (event\n * name + matcher only) so meta-based inspection (doctor / health checks / the\n * hook CLI) can still see WHICH native events were declared — the live handlers\n * are re-imported from `modulePath` at runtime, exactly like normalized hooks.\n * Everything else on the override is kept verbatim — notably `configPatch`\n * declarations, which are pure JSON (key/value/reason/docsUrl, no functions)\n * and persist WHOLE so uninstall/doctor can reason about them even when the\n * source module is gone.\n */\nfunction serializablePlatforms(\n platforms: Partial<Record<PlatformId, PlatformOverride>>,\n): Partial<Record<PlatformId, PlatformOverride>> {\n const out: Partial<Record<PlatformId, PlatformOverride>> = {};\n for (const [id, override] of Object.entries(platforms) as [\n PlatformId,\n PlatformOverride | undefined,\n ][]) {\n if (!override) continue;\n const { hooks, nativeHooks, ...rest } = override;\n const clean: PlatformOverride = { ...rest };\n // Keep only a boolean hooks flag; object hooks carry handler functions.\n if (typeof hooks === \"boolean\") clean.hooks = hooks;\n if (nativeHooks && typeof nativeHooks === \"object\") {\n const stripped: Record<string, { matcher?: string }> = {};\n for (const [event, def] of Object.entries(nativeHooks)) {\n stripped[event] =\n typeof def?.matcher === \"string\" ? { matcher: def.matcher } : {};\n }\n // Cast: the persisted record deliberately omits the (non-serializable)\n // handler; consumers of meta-derived connectors never dispatch handlers.\n clean.nativeHooks = stripped as PlatformOverride[\"nativeHooks\"];\n }\n out[id] = clean;\n }\n return out;\n}\n\n/**\n * Persist a connector's serializable metadata to `connectorDir(id)/connector.json`.\n * Handlers are NOT serialized — they are re-imported from `modulePath` at runtime.\n * The optional `scope` (the install scope the caller deployed under) is persisted\n * so the runtime entrypoints can recover it and stamp it onto the HostCtx/event.\n * Returns the absolute path of the written record.\n */\nexport function registerConnector(\n connector: ResolvedConnector,\n modulePath: string,\n scope?: InstallScope,\n): string {\n const meta: RegisteredMeta = {\n id: connector.id,\n displayName: connector.displayName,\n version: connector.version,\n modulePath: resolve(modulePath),\n telemetry: connector.telemetry,\n hookEvents: connector.hookEvents,\n hasServer: !!connector.server,\n server: connector.server ?? null,\n commands: connector.commands,\n skills: connector.skills,\n subagents: connector.subagents,\n memory: connector.memory,\n targets: connector.targets,\n platforms: serializablePlatforms(connector.platforms),\n // Persist the install scope when the caller supplied one (the installer\n // passes its install scope). Omitted from the record when undefined so an\n // ad-hoc register stays minimal and round-trips as \"no scope known\".\n ...(scope !== undefined ? { scope } : {}),\n };\n\n const dir = connectorDir(connector.id);\n const outPath = join(dir, \"connector.json\");\n assertNoSymlinkInPath(outPath);\n ensureDir(dir);\n writeFileSync(outPath, `${JSON.stringify(meta, null, 2)}\\n`, \"utf8\");\n return outPath;\n}\n\n/**\n * Deregister a connector by removing its DATA-dir record directory\n * (`connectorDir(id)`) recursively. This is the inverse of {@link registerConnector}:\n * registerConnector writes `connectorDir(id)/connector.json`, but per-target\n * uninstall only strips host-native registrations — it never removes this record,\n * leaving an orphan behind. Best-effort + guarded: returns the directory path and\n * whether it existed before removal.\n */\nexport function deregisterConnector(id: string): {\n removed: boolean;\n path: string;\n} {\n const dir = connectorDir(id);\n assertNoSymlinkInPath(dir);\n const existed = existsSync(dir);\n if (existed) rmSync(dir, { recursive: true, force: true });\n return { removed: existed, path: dir };\n}\n\n/**\n * Read the registered metadata record for `id`, or null if not registered or\n * the record is unreadable/corrupt.\n */\nexport function readRegisteredMeta(id: string): RegisteredMeta | null {\n const recordPath = join(connectorDir(id), \"connector.json\");\n if (!existsSync(recordPath)) return null;\n try {\n return JSON.parse(readFileSync(recordPath, \"utf8\")) as RegisteredMeta;\n } catch {\n return null;\n }\n}\n\n/**\n * Load the LIVE ResolvedConnector (with hook handlers) for a registered id by\n * re-importing its source module. Throws a clear error when the connector is\n * not registered or its source module no longer resolves to it.\n */\nexport async function loadRegisteredConnector(\n id: string,\n): Promise<ResolvedConnector> {\n const meta = readRegisteredMeta(id);\n if (!meta) {\n throw new Error(\n `Connector \"${id}\" is not registered (no record at ${join(connectorDir(id), \"connector.json\")}). ` +\n `Run an install/register step first.`,\n );\n }\n if (!meta.modulePath || !existsSync(meta.modulePath)) {\n throw new Error(\n `Connector \"${id}\" record points at a missing module: ${meta.modulePath}`,\n );\n }\n const { connector } = await loadConnectorFromPath(meta.modulePath);\n return connector;\n}\n\n/**\n * Build a handler-less ResolvedConnector from stored metadata. Suitable for\n * inspection/doctor where live hook handlers are not needed (and where the\n * source module may even be gone). `hooks` is empty; `hookEvents` is preserved.\n */\nexport function connectorFromMeta(meta: RegisteredMeta): ResolvedConnector {\n return {\n id: meta.id,\n displayName: meta.displayName,\n version: meta.version,\n ...(meta.server ? { server: meta.server } : {}),\n hooks: {},\n hookEvents: meta.hookEvents ?? [],\n telemetry: meta.telemetry,\n commands: meta.commands ?? [],\n skills: meta.skills ?? [],\n subagents: meta.subagents ?? [],\n memory: meta.memory ?? [],\n // Actions carry live `run` handlers, so they are NOT serialized into the\n // record (like the statusline render). A handler-less meta-derived connector\n // gets [] — inspection/uninstall never dispatch action handlers, and the\n // BaseAdapter action default already tolerates an empty list.\n actions: [],\n platforms: meta.platforms ?? {},\n targets: meta.targets,\n };\n}\n\n/**\n * List every registered connector as a handler-less ResolvedConnector (read\n * from `connectorsDir()`). Used by doctor to health-check what is actually\n * installed, rather than guessing from the local working directory.\n */\nexport function listRegisteredConnectors(): ResolvedConnector[] {\n const dir = connectorsDir();\n if (!existsSync(dir)) return [];\n const out: ResolvedConnector[] = [];\n for (const entry of readdirSync(dir)) {\n const meta = readRegisteredMeta(entry);\n if (meta) out.push(connectorFromMeta(meta));\n }\n return out;\n}\n"],"mappings":"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","names":["connector"]}
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
inferModelFamily,
|
|
5
5
|
openStore,
|
|
6
6
|
worstConfidence
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-D6ZJS4ND.js";
|
|
8
8
|
|
|
9
9
|
// src/telemetry/surface-footprint.ts
|
|
10
10
|
function countParts(parts, family, tok) {
|
|
@@ -590,4 +590,4 @@ export {
|
|
|
590
590
|
formatHostNativeTurns,
|
|
591
591
|
formatSurfaceLeaderboard
|
|
592
592
|
};
|
|
593
|
-
//# sourceMappingURL=chunk-
|
|
593
|
+
//# sourceMappingURL=chunk-TZ5KGCE2.js.map
|
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
REGISTERED_PLATFORM_IDS
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-LS65GL2P.js";
|
|
5
5
|
import {
|
|
6
6
|
CONFIG_PATCH_SEGMENT_RE,
|
|
7
7
|
configPatchNamespaceViolation,
|
|
8
8
|
isJsonValue,
|
|
9
9
|
isValidConfigPatchKey
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-7CZKXXBD.js";
|
|
11
11
|
import {
|
|
12
12
|
MANAGED_BLOCK_BEGIN_TOKEN,
|
|
13
13
|
MANAGED_BLOCK_END_TOKEN,
|
|
14
14
|
MEMORY_CONTENT_HARD_CAP_BYTES
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-ALVXORZM.js";
|
|
16
|
+
import {
|
|
17
|
+
CONNECTOR_ID_RE,
|
|
18
|
+
isValidConnectorId
|
|
19
|
+
} from "./chunk-2HCJV6UO.js";
|
|
16
20
|
|
|
17
21
|
// src/core/define-connector.ts
|
|
18
22
|
import { isAbsolute, normalize } from "path";
|
|
@@ -44,7 +48,6 @@ var REGISTRY_NAMESPACE_RE = /^[a-zA-Z0-9.-]+$/;
|
|
|
44
48
|
var REGISTRY_NAME_RE = /^[a-zA-Z0-9.-]+\/[a-zA-Z0-9._-]+$/;
|
|
45
49
|
|
|
46
50
|
// src/core/define-connector.ts
|
|
47
|
-
var ID_RE = /^[a-z0-9][a-z0-9-]*$/;
|
|
48
51
|
var SURFACE_NAME_RE = /^[a-z0-9][a-z0-9-]*$/;
|
|
49
52
|
var SKILL_DESCRIPTION_MAX = 1024;
|
|
50
53
|
var ALL_EVENTS = [
|
|
@@ -76,9 +79,9 @@ function defineConnector(config) {
|
|
|
76
79
|
if (!config || typeof config !== "object") {
|
|
77
80
|
throw new ConnectorConfigError("config must be an object");
|
|
78
81
|
}
|
|
79
|
-
if (
|
|
82
|
+
if (!isValidConnectorId(config.id)) {
|
|
80
83
|
throw new ConnectorConfigError(
|
|
81
|
-
`id must be kebab-case matching ${
|
|
84
|
+
`id must be kebab-case matching ${CONNECTOR_ID_RE} (got ${JSON.stringify(config.id)})`
|
|
82
85
|
);
|
|
83
86
|
}
|
|
84
87
|
const hasCommands = Array.isArray(config.commands) && config.commands.length > 0;
|
|
@@ -495,4 +498,4 @@ export {
|
|
|
495
498
|
defineConfigPatch,
|
|
496
499
|
defineNativeHook
|
|
497
500
|
};
|
|
498
|
-
//# sourceMappingURL=chunk-
|
|
501
|
+
//# sourceMappingURL=chunk-UVBAH263.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/define-connector.ts","../src/core/mcp-standard.ts"],"sourcesContent":["/**\n * core/define-connector — the public write-once entry point.\n *\n * Validates a ConnectorConfig and normalizes it into a ResolvedConnector with\n * every optional field resolved to a default. Validation is intentionally\n * dependency-free (no zod) to keep the single-binary install lean.\n */\n\nimport { isAbsolute, normalize } from \"node:path\";\n\nimport type {\n ActionDef,\n CommandDef,\n ConfigPatchDef,\n ConnectorConfig,\n HookDefinition,\n HookEventName,\n HooksConfig,\n MemoryDef,\n NativeHookDef,\n PlatformId,\n PublishConfig,\n ResolvedConnector,\n SkillDef,\n StatuslineDef,\n SubagentDef,\n} from \"./types.js\";\nimport { REGISTERED_PLATFORM_IDS } from \"../adapters/registry.js\";\nimport { REGISTRY_NAMESPACE_RE } from \"./mcp-standard.js\";\nimport { CONNECTOR_ID_RE, isValidConnectorId } from \"./ids.js\";\nimport {\n MANAGED_BLOCK_BEGIN_TOKEN,\n MANAGED_BLOCK_END_TOKEN,\n MEMORY_CONTENT_HARD_CAP_BYTES,\n} from \"./managed-block.js\";\nimport {\n CONFIG_PATCH_SEGMENT_RE,\n configPatchNamespaceViolation,\n isJsonValue,\n isValidConfigPatchKey,\n} from \"./config-patch-ledger.js\";\n\n/** kebab-case name regex shared by command/skill/subagent names. */\nconst SURFACE_NAME_RE = /^[a-z0-9][a-z0-9-]*$/;\n\n/** Max length of a skill description (Agent Skills open standard). */\nconst SKILL_DESCRIPTION_MAX = 1024;\n\n// NOTE: canonical ordering — append new events at the END (hookEvents ordering\n// is pinned by tests and feeds install-file ordering). Exported so the\n// hook-dispatch gate + Claude-bundle event sets can be drift-tested against it.\nexport const ALL_EVENTS: HookEventName[] = [\n \"SessionStart\",\n \"SessionEnd\",\n \"UserPromptSubmit\",\n \"PreToolUse\",\n \"PostToolUse\",\n \"PreCompact\",\n \"Stop\",\n \"Notification\",\n \"PermissionRequest\",\n \"PostToolUseFailure\",\n \"SubagentStart\",\n \"SubagentStop\",\n \"PostCompact\",\n];\n\n/** Thrown on an invalid connector configuration. */\nexport class ConnectorConfigError extends Error {\n constructor(message: string) {\n super(`Invalid connector config: ${message}`);\n this.name = \"ConnectorConfigError\";\n }\n}\n\nfunction declaredEvents(hooks: HooksConfig | undefined): HookEventName[] {\n if (!hooks) return [];\n return ALL_EVENTS.filter((e) => typeof hooks[e]?.handler === \"function\");\n}\n\n/**\n * Validate + normalize a connector definition.\n * Returns a ResolvedConnector that adapters and the CLI consume directly.\n */\nexport function defineConnector(config: ConnectorConfig): ResolvedConnector {\n if (!config || typeof config !== \"object\") {\n throw new ConnectorConfigError(\"config must be an object\");\n }\n if (!isValidConnectorId(config.id)) {\n throw new ConnectorConfigError(\n `id must be kebab-case matching ${CONNECTOR_ID_RE} (got ${JSON.stringify(config.id)})`,\n );\n }\n const hasCommands = Array.isArray(config.commands) && config.commands.length > 0;\n const hasSkills = Array.isArray(config.skills) && config.skills.length > 0;\n const hasSubagents = Array.isArray(config.subagents) && config.subagents.length > 0;\n const hasMemory = Array.isArray(config.memory) && config.memory.length > 0;\n // A statusline (a HUD) is a legitimate sole payload — a connector whose whole\n // job is rendering a status line. SINGULAR (one per connector), so a plain\n // presence check (object with a render handler — validated in normalizeStatusline).\n const hasStatusline = config.statusline != null;\n // Actions (each a user-invokable run handler) are a legitimate sole payload —\n // a connector whose whole job is shipping dispatchable actions.\n const hasActions = Array.isArray(config.actions) && config.actions.length > 0;\n // A platform-scoped nativeHooks declaration is a legitimate sole payload\n // (a hooks-only connector wired entirely through native passthrough events).\n const hasNativeHooks = Object.values(config.platforms ?? {}).some(\n (override) =>\n override?.nativeHooks != null && Object.keys(override.nativeHooks).length > 0,\n );\n // Likewise a platform-scoped configPatch declaration (a connector whose whole\n // job is asserting a host config key, e.g. an experimental feature flag).\n const hasConfigPatch = Object.values(config.platforms ?? {}).some(\n (override) => Array.isArray(override?.configPatch) && override.configPatch.length > 0,\n );\n if (\n !config.server &&\n !config.hooks &&\n !hasCommands &&\n !hasSkills &&\n !hasSubagents &&\n !hasMemory &&\n !hasStatusline &&\n !hasActions &&\n !hasNativeHooks &&\n !hasConfigPatch\n ) {\n throw new ConnectorConfigError(\n \"a connector must declare at least one of `server`, `hooks`, `commands`, `skills`, `subagents`, `memory`, `statusline`, `actions`, \" +\n \"or a per-platform `nativeHooks` / `configPatch` declaration\",\n );\n }\n\n if (config.server) {\n const s = config.server;\n if (s.transport === \"stdio\") {\n if (!s.command || typeof s.command !== \"string\") {\n throw new ConnectorConfigError(\n \"server.command is required for stdio transport\",\n );\n }\n } else {\n if (!s.url || typeof s.url !== \"string\") {\n throw new ConnectorConfigError(\n `server.url is required for ${s.transport} transport`,\n );\n }\n }\n }\n\n // Validate hook handlers are functions, plus any per-host override map.\n if (config.hooks) {\n for (const ev of ALL_EVENTS) {\n const def = config.hooks[ev];\n if (def != null && typeof def.handler !== \"function\") {\n throw new ConnectorConfigError(`hooks.${ev}.handler must be a function`);\n }\n // Per-host override map: every key must be a registered platform id and\n // every entry's handler a function (author-time hard error, not skip-warn).\n validateHostsMap(def?.hosts, `hooks.${ev}.hosts`, \"handler\");\n }\n }\n\n // Validate per-platform native passthrough hooks (handlers live in this same\n // config module, exactly like normalized hooks — the resolved connector keeps\n // `platforms` verbatim, so live handlers survive resolution and are recovered\n // at runtime by re-importing the module via the registry's modulePath).\n validateNativeHooks(config.platforms);\n\n // Validate per-platform declarative config patches (pure JSON — persisted\n // whole; semantics are FIXED set-if-absent/skip-warn, so only the shape is\n // validated here; the host adapter enforces its sensitive-key denylist).\n validateConfigPatches(config.platforms);\n\n const commands = normalizeCommands(config.commands);\n const skills = normalizeSkills(config.skills);\n const subagents = normalizeSubagents(config.subagents);\n const memory = normalizeMemory(config.memory);\n const statusline = normalizeStatusline(config.statusline);\n const actions = normalizeActions(config.actions);\n\n const t = config.telemetry ?? {};\n\n const resolved: ResolvedConnector = {\n id: config.id,\n displayName: config.displayName ?? config.id,\n version: config.version ?? \"0.0.0\",\n ...(config.server ? { server: normalizeServer(config.server) } : {}),\n hooks: config.hooks ?? {},\n hookEvents: declaredEvents(config.hooks),\n telemetry: {\n enabled: t.enabled ?? true,\n modelFamilyHint: t.modelFamilyHint ?? \"auto\",\n measureToolDefs: t.measureToolDefs ?? true,\n // OPT-IN: host-native turn-usage capture is OFF unless explicitly enabled\n // in config (or forced on at install via AGENT_CONNECTOR_HOST_NATIVE=1).\n hostNativeUsage: t.hostNativeUsage ?? false,\n store: t.store ?? \"ndjson\",\n calibration: {\n anthropicCountTokens: t.calibration?.anthropicCountTokens ?? false,\n },\n },\n commands,\n skills,\n subagents,\n memory,\n ...(statusline ? { statusline } : {}),\n actions,\n platforms: config.platforms ?? {},\n targets: config.targets ?? \"auto\",\n ...(config.publish ? { publish: normalizePublish(config.publish) } : {}),\n };\n\n return resolved;\n}\n\n/** The 13 normalized event names, for the nativeHooks collision check. */\nconst NORMALIZED_EVENT_SET: ReadonlySet<string> = new Set(ALL_EVENTS);\n\n/**\n * Validate a per-host override map (`hosts?:`) declared on a hook definition or\n * on the statusline. Shared by the hook-validation loop and normalizeStatusline:\n * - the value must be a plain object keyed by platform id;\n * - every key MUST be a REGISTERED platform id (REGISTERED_PLATFORM_IDS) —\n * an unknown id is an author-time ConnectorConfigError (NOT a skip-warn:\n * a typo'd host would otherwise silently never fire);\n * - every entry's implementation field (`handler` for hooks, `render` for\n * statusline, `run` for actions) MUST be a function (it is re-imported from\n * the connector module at runtime, like the top-level handler/render/run).\n * `undefined` (no map) is valid and skipped.\n */\nfunction validateHostsMap(\n map: unknown,\n surfaceLabel: string,\n implField: \"handler\" | \"render\" | \"run\",\n): void {\n if (map == null) return;\n if (typeof map !== \"object\" || Array.isArray(map)) {\n throw new ConnectorConfigError(\n `${surfaceLabel} must be an object keyed by platform id`,\n );\n }\n for (const [platformId, entry] of Object.entries(map as Record<string, unknown>)) {\n if (!REGISTERED_PLATFORM_IDS.has(platformId as PlatformId)) {\n const valid = [...REGISTERED_PLATFORM_IDS].sort().join(\", \");\n throw new ConnectorConfigError(\n `unknown platform id \"${platformId}\" in hosts map for ${surfaceLabel}; valid ids: ${valid}`,\n );\n }\n if (\n entry == null ||\n typeof entry !== \"object\" ||\n typeof (entry as Record<string, unknown>)[implField] !== \"function\"\n ) {\n throw new ConnectorConfigError(\n `${surfaceLabel}.${platformId}.${implField} must be a function`,\n );\n }\n }\n}\n\n/**\n * Validate every `platforms[<id>].nativeHooks` declaration:\n * - the value must be an object keyed by HOST-NATIVE event name;\n * - an event name must NOT collide with the normalized {@link HookEventName}\n * union (those belong in the cross-platform `hooks` API, which gets\n * normalization, matcher evaluation, and HookResponse mapping);\n * - each handler must be a function (it is re-imported from the config module\n * at runtime, like normalized hook handlers);\n * - `matcher`, when present, must be a string (written verbatim into the\n * host's hook config — the host evaluates it).\n */\nfunction validateNativeHooks(platforms: ConnectorConfig[\"platforms\"]): void {\n if (platforms == null) return;\n for (const [platformId, override] of Object.entries(platforms)) {\n const native = override?.nativeHooks;\n if (native == null) continue;\n const where = `platforms.${platformId}.nativeHooks`;\n if (typeof native !== \"object\" || Array.isArray(native)) {\n throw new ConnectorConfigError(\n `${where} must be an object keyed by host-native event name`,\n );\n }\n for (const [event, def] of Object.entries(native)) {\n if (NORMALIZED_EVENT_SET.has(event)) {\n throw new ConnectorConfigError(\n `${where}.${event} collides with the normalized hook event \"${event}\"; ` +\n `declare it under \\`hooks.${event}\\` (the normalized, cross-platform hooks API) instead`,\n );\n }\n if (def == null || typeof def !== \"object\" || typeof def.handler !== \"function\") {\n throw new ConnectorConfigError(`${where}.${event}.handler must be a function`);\n }\n if (def.matcher !== undefined && typeof def.matcher !== \"string\") {\n throw new ConnectorConfigError(`${where}.${event}.matcher must be a string`);\n }\n }\n }\n}\n\n/**\n * Validate every `platforms[<id>].configPatch` declaration:\n * - the value must be an array of patch objects;\n * - `key` must be a dotted LEAF path whose segments match\n * {@link CONFIG_PATCH_SEGMENT_RE} — no dots-in-key, no array indices;\n * - `key` must not collide with the agent-connector-modeled namespace\n * (`hooks*` → hooks/nativeHooks; `mcpServers*` & friends → server/extra);\n * - duplicate keys within one platform's list are rejected (a duplicate\n * would double-apply / fight itself on refcounts);\n * - `value` must be JSON-serializable data (it is persisted whole in the\n * connector record and in the ownership ledger);\n * - `reason` is REQUIRED (printed in the install diff and every skip-warn);\n * - `docsUrl`, when present, must be a string.\n * The HOST-side sensitive-key denylist is deliberately NOT validated here —\n * it lives in (and is documented by) each supporting adapter.\n */\nfunction validateConfigPatches(platforms: ConnectorConfig[\"platforms\"]): void {\n if (platforms == null) return;\n for (const [platformId, override] of Object.entries(platforms)) {\n const patches = override?.configPatch;\n if (patches == null) continue;\n const where = `platforms.${platformId}.configPatch`;\n if (!Array.isArray(patches)) {\n throw new ConnectorConfigError(`${where} must be an array of patch objects`);\n }\n const seen = new Set<string>();\n patches.forEach((patch, i) => {\n if (patch == null || typeof patch !== \"object\" || Array.isArray(patch)) {\n throw new ConnectorConfigError(`${where}[${i}] must be an object`);\n }\n if (!isValidConfigPatchKey(patch.key)) {\n throw new ConnectorConfigError(\n `${where}[${i}].key must be a dotted LEAF path whose segments match ` +\n `${CONFIG_PATCH_SEGMENT_RE} (no dots-in-key, no array indices); ` +\n `got ${JSON.stringify(patch.key)}`,\n );\n }\n const violation = configPatchNamespaceViolation(patch.key);\n if (violation) {\n throw new ConnectorConfigError(`${where}[${i}].key ${violation}`);\n }\n if (seen.has(patch.key)) {\n throw new ConnectorConfigError(\n `${where}[${i}] duplicate key \"${patch.key}\"`,\n );\n }\n seen.add(patch.key);\n if (!isJsonValue(patch.value)) {\n throw new ConnectorConfigError(\n `${where}[${i}].value must be JSON-serializable data ` +\n `(string/finite number/boolean/null/array/plain object)`,\n );\n }\n if (typeof patch.reason !== \"string\" || patch.reason.trim() === \"\") {\n throw new ConnectorConfigError(\n `${where}[${i}].reason is required (a human-readable why, printed in ` +\n `the install diff and every skip-warn)`,\n );\n }\n if (patch.docsUrl !== undefined && typeof patch.docsUrl !== \"string\") {\n throw new ConnectorConfigError(`${where}[${i}].docsUrl must be a string`);\n }\n });\n }\n}\n\n/**\n * Validate the optional `publish` block (registry server.json + MCPB bundle\n * distribution metadata). Light, dependency-free: we only reject shapes that\n * would emit a clearly INVALID standard artifact. The per-format required-field\n * checks (e.g. server.json needs registryNamespace, mcpb needs author.name)\n * live in the emitters so a connector that never publishes pays nothing.\n */\nfunction normalizePublish(publish: PublishConfig): PublishConfig {\n if (typeof publish !== \"object\" || Array.isArray(publish)) {\n throw new ConnectorConfigError(\"publish must be an object\");\n }\n if (publish.registryNamespace !== undefined) {\n const ns = publish.registryNamespace;\n if (typeof ns !== \"string\" || !REGISTRY_NAMESPACE_RE.test(ns)) {\n throw new ConnectorConfigError(\n `publish.registryNamespace must be a reverse-DNS namespace matching ${REGISTRY_NAMESPACE_RE} ` +\n `(e.g. \"io.github.acme\" or \"com.acme\"); got ${JSON.stringify(ns)}`,\n );\n }\n }\n if (publish.packageName !== undefined && typeof publish.packageName !== \"string\") {\n throw new ConnectorConfigError(\"publish.packageName must be a string\");\n }\n if (publish.author !== undefined) {\n const a = publish.author;\n if (typeof a !== \"object\" || a == null || typeof a.name !== \"string\" || a.name === \"\") {\n throw new ConnectorConfigError(\"publish.author.name must be a non-empty string\");\n }\n }\n return { ...publish };\n}\n\n/** Validate a surface name (kebab-case) or throw a ConnectorConfigError. */\nfunction assertSurfaceName(\n surface: string,\n name: unknown,\n index: number,\n field = \"name\",\n): string {\n if (typeof name !== \"string\" || !SURFACE_NAME_RE.test(name)) {\n throw new ConnectorConfigError(\n `${surface}[${index}].${field} must be kebab-case matching ${SURFACE_NAME_RE} (got ${JSON.stringify(name)})`,\n );\n }\n return name;\n}\n\n/** Require a non-empty string field on a surface entry. */\nfunction assertNonEmptyString(\n surface: string,\n index: number,\n field: string,\n value: unknown,\n): string {\n if (typeof value !== \"string\" || value.length === 0) {\n throw new ConnectorConfigError(`${surface}[${index}].${field} must be a non-empty string`);\n }\n return value;\n}\n\n/** Detect a duplicate surface name within one array, throwing on collision. */\nfunction assertNoDuplicate(\n surface: string,\n seen: Set<string>,\n name: string,\n index: number,\n field = \"name\",\n): void {\n if (seen.has(name)) {\n throw new ConnectorConfigError(`${surface}[${index}] duplicate ${field} \"${name}\"`);\n }\n seen.add(name);\n}\n\nfunction normalizeCommands(input: CommandDef[] | undefined): CommandDef[] {\n if (input == null) return [];\n if (!Array.isArray(input)) {\n throw new ConnectorConfigError(\"commands must be an array\");\n }\n const seen = new Set<string>();\n return input.map((cmd, i) => {\n if (!cmd || typeof cmd !== \"object\") {\n throw new ConnectorConfigError(`commands[${i}] must be an object`);\n }\n const name = assertSurfaceName(\"commands\", cmd.name, i);\n assertNoDuplicate(\"commands\", seen, name, i);\n assertNonEmptyString(\"commands\", i, \"prompt\", cmd.prompt);\n // Pass through verbatim (content); arrays are content, not handlers.\n return { ...cmd, name };\n });\n}\n\nfunction normalizeSkills(input: SkillDef[] | undefined): SkillDef[] {\n if (input == null) return [];\n if (!Array.isArray(input)) {\n throw new ConnectorConfigError(\"skills must be an array\");\n }\n const seen = new Set<string>();\n return input.map((skill, i) => {\n if (!skill || typeof skill !== \"object\") {\n throw new ConnectorConfigError(`skills[${i}] must be an object`);\n }\n const name = assertSurfaceName(\"skills\", skill.name, i);\n assertNoDuplicate(\"skills\", seen, name, i);\n const description = assertNonEmptyString(\"skills\", i, \"description\", skill.description);\n if (description.length > SKILL_DESCRIPTION_MAX) {\n throw new ConnectorConfigError(\n `skills[${i}].description exceeds ${SKILL_DESCRIPTION_MAX} chars (got ${description.length})`,\n );\n }\n assertNonEmptyString(\"skills\", i, \"body\", skill.body);\n assertSafeResourceKeys(\"skills\", i, skill.resources);\n return { ...skill, name };\n });\n}\n\n/**\n * Validate every `skill.resources` key as a SAFE relative path that stays inside\n * the skill dir. Each resource is later written/removed via join(skillDir, rel)\n * by every adapter, so an unvalidated key like \"../../settings.json\" would\n * escape the skill dir → arbitrary file write/delete. Reject (throw) when a key\n * is empty/\".\", absolute, or normalizes to a path that begins with \"..\" or\n * contains a \"/..\" (or platform-sep) traversal segment.\n */\nfunction assertSafeResourceKeys(\n surface: string,\n index: number,\n resources: Record<string, string> | undefined,\n): void {\n if (resources == null) return;\n if (typeof resources !== \"object\" || Array.isArray(resources)) {\n throw new ConnectorConfigError(`${surface}[${index}].resources must be an object`);\n }\n for (const rel of Object.keys(resources)) {\n if (rel === \"\" || rel === \".\" || rel.trim() === \"\") {\n throw new ConnectorConfigError(\n `${surface}[${index}].resources key must be a non-empty relative path (got ${JSON.stringify(rel)})`,\n );\n }\n if (isAbsolute(rel)) {\n throw new ConnectorConfigError(\n `${surface}[${index}].resources key must be a relative path inside the skill dir, not absolute (got ${JSON.stringify(rel)})`,\n );\n }\n // Normalize with BOTH posix and native separators flattened so a Windows\n // \"..\\\\x\" or a posix \"../x\" is caught regardless of the host OS.\n const norm = normalize(rel.replace(/\\\\/g, \"/\"));\n const segs = norm.split(/[/\\\\]/);\n if (norm === \"..\" || norm.startsWith(\"../\") || norm.startsWith(\"..\\\\\") || segs.includes(\"..\")) {\n throw new ConnectorConfigError(\n `${surface}[${index}].resources key must not escape the skill dir via \"..\" (got ${JSON.stringify(rel)})`,\n );\n }\n }\n}\n\n/** Default name for a single-entry memory declaration. */\nconst MEMORY_DEFAULT_NAME = \"memory\";\n\n/**\n * Validate + normalize `memory` entries (the managed-block content surface).\n * - `name` defaults to \"memory\", then must be kebab-case and unique — it is\n * half of the block marker id (`<connectorId>/<name>`) and must stay stable;\n * - `content` must be a non-empty string, ≤ 16 KiB (hard cap — memory files\n * are injected into every prompt of every session on the host), and must\n * NOT contain the literal marker tokens `agent-connector:begin` /\n * `agent-connector:end` (they would corrupt marker scanning in the shared\n * file — rephrase the guidance instead). The 4 KiB SOFT budget is reported\n * at install time as a `warn` ChangeRecord, not a config error\n * (defineConnector has no warning channel).\n */\nfunction normalizeMemory(input: MemoryDef[] | undefined): MemoryDef[] {\n if (input == null) return [];\n if (!Array.isArray(input)) {\n throw new ConnectorConfigError(\"memory must be an array\");\n }\n const seen = new Set<string>();\n return input.map((entry, i) => {\n if (!entry || typeof entry !== \"object\" || Array.isArray(entry)) {\n throw new ConnectorConfigError(`memory[${i}] must be an object`);\n }\n const name =\n entry.name === undefined\n ? MEMORY_DEFAULT_NAME\n : assertSurfaceName(\"memory\", entry.name, i);\n assertNoDuplicate(\"memory\", seen, name, i);\n const content = assertNonEmptyString(\"memory\", i, \"content\", entry.content);\n const bytes = Buffer.byteLength(content, \"utf8\");\n if (bytes > MEMORY_CONTENT_HARD_CAP_BYTES) {\n throw new ConnectorConfigError(\n `memory[${i}].content exceeds the ${MEMORY_CONTENT_HARD_CAP_BYTES}-byte hard cap ` +\n `(got ${bytes} bytes); memory is inlined into every prompt of every targeted host — keep it terse`,\n );\n }\n for (const token of [MANAGED_BLOCK_BEGIN_TOKEN, MANAGED_BLOCK_END_TOKEN]) {\n if (content.includes(token)) {\n throw new ConnectorConfigError(\n `memory[${i}].content must not contain the literal marker token \"${token}\" ` +\n `(it would corrupt managed-block scanning in the shared memory file); rephrase the guidance`,\n );\n }\n }\n if (entry.description !== undefined && typeof entry.description !== \"string\") {\n throw new ConnectorConfigError(`memory[${i}].description must be a string`);\n }\n return { ...entry, name };\n });\n}\n\n/** Default name for the (singular) statusline declaration. */\nconst STATUSLINE_DEFAULT_NAME = \"statusline\";\n\n/**\n * Validate + normalize the SINGULAR `statusline` (a HUD handler surface):\n * - `render` MUST be a function (it is the renderer, re-imported at runtime\n * like a hook handler);\n * - `name` defaults to \"statusline\", then must be kebab-case (the shared\n * surface-name validator);\n * - `description`, when present, must be a string.\n * Returns undefined when no statusline is declared (it is optional and singular,\n * unlike the memory[] array).\n */\nfunction normalizeStatusline(\n input: StatuslineDef | undefined,\n): StatuslineDef | undefined {\n if (input == null) return undefined;\n if (typeof input !== \"object\" || Array.isArray(input)) {\n throw new ConnectorConfigError(\"statusline must be an object\");\n }\n if (typeof input.render !== \"function\") {\n throw new ConnectorConfigError(\"statusline.render must be a function\");\n }\n const name =\n input.name === undefined\n ? STATUSLINE_DEFAULT_NAME\n : assertSurfaceName(\"statusline\", input.name, 0);\n if (input.description !== undefined && typeof input.description !== \"string\") {\n throw new ConnectorConfigError(\"statusline.description must be a string\");\n }\n // Per-host render override map: registered platform ids only, each render a\n // function (author-time hard error, mirroring the hook hosts-map validation).\n validateHostsMap(input.hosts, \"statusline.hosts\", \"render\");\n return { ...input, name };\n}\n\n/**\n * Validate + normalize `actions` (the user-invokable action handler surface):\n * - the value must be an array;\n * - each entry's `id` must be kebab-case (the shared surface-name validator)\n * and UNIQUE within the connector (ConnectorConfigError on dup — the id is\n * the verb's positional arg, so a duplicate would be ambiguous);\n * - `run` MUST be a function (it is the handler, re-imported at runtime like a\n * hook handler / statusline render);\n * - `description`, when present, must be a string;\n * - the per-host `hosts:` override map is validated via the shared\n * validateHostsMap (registered platform ids only, each `run` a function).\n * Returns [] when no actions are declared (defaults applied, like the other\n * array surfaces).\n */\nfunction normalizeActions(input: ActionDef[] | undefined): ActionDef[] {\n if (input == null) return [];\n if (!Array.isArray(input)) {\n throw new ConnectorConfigError(\"actions must be an array\");\n }\n const seen = new Set<string>();\n return input.map((action, i) => {\n if (!action || typeof action !== \"object\" || Array.isArray(action)) {\n throw new ConnectorConfigError(`actions[${i}] must be an object`);\n }\n const id = assertSurfaceName(\"actions\", action.id, i, \"id\");\n assertNoDuplicate(\"actions\", seen, id, i, \"id\");\n if (typeof action.run !== \"function\") {\n throw new ConnectorConfigError(`actions[${i}].run must be a function`);\n }\n if (action.description !== undefined && typeof action.description !== \"string\") {\n throw new ConnectorConfigError(`actions[${i}].description must be a string`);\n }\n // Per-host run override map: registered platform ids only, each run a\n // function (author-time hard error, mirroring the statusline/hook hosts-map).\n validateHostsMap(action.hosts, `actions.${id}.hosts`, \"run\");\n return { ...action, id };\n });\n}\n\n/**\n * Typed identity helper for authoring a status line in its own module:\n * export const myStatusline = defineStatusline({ render: (ctx) => \"…\" });\n * Mirrors the (informal) defineX helpers; gives the developer full type\n * inference on {@link StatuslineContext} without importing the type by hand.\n */\nexport const defineStatusline = (def: StatuslineDef): StatuslineDef => def;\n\n// ─────────────────────────────────────────────────────────────────────────\n// Typed identity helpers (the `define*` authoring family)\n//\n// Each is a one-line identity function: it returns its argument UNCHANGED and\n// does NOT validate or mutate (validation still happens centrally in\n// defineConnector). Their only job is ergonomics — authoring a surface in its\n// own module with full type inference + autocomplete on the *Def shape, and a\n// single import site — mirroring the existing {@link defineStatusline}.\n// ─────────────────────────────────────────────────────────────────────────\n\n/**\n * Typed identity helper for authoring ONE normalized lifecycle hook in its own\n * module, EVENT-PARAMETERIZED so the handler's payload narrows to that event:\n *\n * export const onPre = defineHook(\"PreToolUse\", {\n * handler(evt) { evt.toolName // ← typed as a PreToolUseEvent, not the union\n * return { decision: \"deny\", reason: \"no\" };\n * },\n * });\n *\n * The leading `event` argument exists ONLY to infer `E`; the def is returned\n * unchanged (identity — validation still happens in defineConnector). Passing\n * `HookDefinition` without an event would widen the handler param to the full\n * {@link HookEventName} union and lose per-event narrowing, so the event tag is\n * required.\n */\nexport const defineHook = <E extends HookEventName>(\n event: E,\n def: HookDefinition<E>,\n): HookDefinition<E> => {\n void event; // tag-only: used solely to infer E (the def carries no event field)\n return def;\n};\n\n/**\n * Typed identity helper for authoring a slash {@link CommandDef} in its own\n * module. Returns the def unchanged (kebab-case name + prompt are validated by\n * defineConnector when the connector is assembled).\n */\nexport const defineCommand = (def: CommandDef): CommandDef => def;\n\n/**\n * Typed identity helper for authoring an Agent {@link SkillDef} in its own\n * module. Returns the def unchanged (name/description/body + safe resource keys\n * are validated by defineConnector).\n */\nexport const defineSkill = (def: SkillDef): SkillDef => def;\n\n/**\n * Typed identity helper for authoring a {@link SubagentDef} in its own module.\n * Returns the def unchanged (name/description/prompt validated by defineConnector).\n */\nexport const defineSubagent = (def: SubagentDef): SubagentDef => def;\n\n/**\n * Typed identity helper for authoring a {@link MemoryDef} (standing-guidance\n * managed block) in its own module. Returns the def unchanged (name/content +\n * byte budget + marker-token guard validated by defineConnector).\n */\nexport const defineMemory = (def: MemoryDef): MemoryDef => def;\n\n/**\n * Typed identity helper for authoring a user-invokable {@link ActionDef} in its\n * own module. Returns the def unchanged (kebab-case unique id + run-is-function\n * + the per-host hosts map validated by defineConnector when the connector is\n * assembled).\n */\nexport const defineAction = (def: ActionDef): ActionDef => def;\n\n/**\n * Typed identity helper for authoring a declarative {@link ConfigPatchDef}\n * (set-if-absent host-config key patch) in its own module. Returns the def\n * unchanged (leaf-path grammar + namespace guard + required reason validated by\n * defineConnector when it appears under `platforms[<id>].configPatch`).\n */\nexport const defineConfigPatch = (def: ConfigPatchDef): ConfigPatchDef => def;\n\n/**\n * Typed identity helper for authoring a {@link NativeHookDef} (host-native\n * passthrough hook) in its own module. Returns the def unchanged (event-name\n * collision + handler-is-function validated by defineConnector when it appears\n * under `platforms[<id>].nativeHooks`).\n */\nexport const defineNativeHook = (def: NativeHookDef): NativeHookDef => def;\n\nfunction normalizeSubagents(input: SubagentDef[] | undefined): SubagentDef[] {\n if (input == null) return [];\n if (!Array.isArray(input)) {\n throw new ConnectorConfigError(\"subagents must be an array\");\n }\n const seen = new Set<string>();\n return input.map((agent, i) => {\n if (!agent || typeof agent !== \"object\") {\n throw new ConnectorConfigError(`subagents[${i}] must be an object`);\n }\n const name = assertSurfaceName(\"subagents\", agent.name, i);\n assertNoDuplicate(\"subagents\", seen, name, i);\n assertNonEmptyString(\"subagents\", i, \"description\", agent.description);\n assertNonEmptyString(\"subagents\", i, \"prompt\", agent.prompt);\n return { ...agent, name };\n });\n}\n\nfunction normalizeServer(server: ConnectorConfig[\"server\"]): ResolvedConnector[\"server\"] {\n if (!server) return undefined;\n const wrapDefault = server.transport === \"stdio\";\n return {\n ...server,\n enabled: server.enabled ?? true,\n tools: server.tools ?? { include: [\"*\"] },\n wrapForTelemetry: server.wrapForTelemetry ?? wrapDefault,\n };\n}\n","/**\n * core/mcp-standard — pinned literals + guards for the official MCP standards\n * agent-connector EMITS (registry server.json, MCPB bundle) or SPEAKS (the\n * connection-lifecycle wire used by `doctor --probe`).\n *\n * Each pinned constant is the CURRENT released value verified 2026-06-05 against\n * the upstream spec/schema. They are deliberately centralized + annotated\n * MUST-VERIFY-AT-IMPLEMENTATION: a newer spec revision can supersede any of them\n * without breaking us, so the bump is a one-line change here, never scattered.\n *\n * Sources:\n * • server.schema.json 2025-12-11 — https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json\n * • MCPB manifest 0.3 — github.com/anthropics/mcpb (MANIFEST.md)\n * • MCP protocol 2025-11-25 — modelcontextprotocol.io/specification/2025-11-25\n * (latest RELEASED revision. 2026-07-28 is a release-candidate only — do NOT\n * advance to it until it publishes as a stable dated revision. The probe\n * offers this version but ACCEPTS whatever a server negotiates, so the\n * offered literal being stale never breaks interop — only this constant.)\n */\n\nimport type { Transport } from \"./types.js\";\n\n/** Registry server.json JSON Schema URL (released 2025-12-11). MUST-VERIFY on bump. */\nexport const MCP_SERVER_SCHEMA_URL =\n \"https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json\";\n\n/** Current MCPB bundle manifest_version (anthropics/mcpb). MUST-VERIFY on bump. */\nexport const MCPB_MANIFEST_VERSION = \"0.3\";\n\n/**\n * Latest RELEASED MCP protocol revision `doctor --probe` offers in `initialize`.\n * Current = 2025-11-25. MUST-VERIFY on bump; stay on the latest *released*\n * revision (2026-07-28 is RC-only as of 2026-06). Negotiation accepts whatever\n * the server returns, so this is the offered value, not a hard requirement.\n */\nexport const MCP_PROTOCOL_VERSION = \"2025-11-25\";\n\n/** Default npm registry base URL stamped into server.json npm packages. */\nexport const NPM_REGISTRY_BASE_URL = \"https://registry.npmjs.org\";\n\n/**\n * server.json transport.type enum — the EXACT values the 2025-12-11 schema\n * accepts (packages[].transport.type and remotes[].type). Our `http` Transport\n * maps to the spec slug \"streamable-http\"; \"ws\" is non-spec (see below).\n */\nexport type RegistryTransportType = \"stdio\" | \"streamable-http\" | \"sse\";\n\n/**\n * Map our {@link Transport} union to the registry/server.json transport slug.\n * Returns null for \"ws\" — WebSocket is NOT a spec transport (it can only exist\n * as a vendor custom transport, e.g. Claude Code's non-spec type:\"ws\"), so a\n * conformant artifact must REJECT it rather than emit an invalid type. The spec\n * defines exactly stdio + streamable-http, with sse the deprecated HTTP+SSE.\n */\nexport function registryTransportType(transport: Transport): RegistryTransportType | null {\n switch (transport) {\n case \"stdio\":\n return \"stdio\";\n case \"http\":\n return \"streamable-http\";\n case \"sse\":\n return \"sse\";\n case \"ws\":\n return null;\n }\n}\n\n/**\n * Is `v` a CONCRETE version the MCP Registry accepts? The registry rejects\n * ranges (\"^1.2.3\", \"~1.2.3\", \">=1.2.3\", \"1.x\", \"1.*\"); only a pinned SemVer\n * (optionally with a -prerelease / +build suffix) is valid. \"0.0.0\" is concrete\n * (so it passes this guard) but is the unset placeholder — callers warn on it\n * separately via {@link isPlaceholderVersion}.\n */\nexport function isConcreteSemver(v: string): boolean {\n return /^\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z.-]+)?(?:\\+[0-9A-Za-z.-]+)?$/.test(v);\n}\n\n/** The unset default version a connector ships with until the dev sets a real one. */\nexport function isPlaceholderVersion(v: string): boolean {\n return v === \"0.0.0\";\n}\n\n/**\n * Reverse-DNS registry namespace pattern (the part BEFORE the \"/\" in a\n * server.json `name`). The full name regex is\n * `^[a-zA-Z0-9.-]+/[a-zA-Z0-9._-]+$`; the namespace side allows letters, digits,\n * dots and hyphens (NO underscore) — e.g. \"io.github.acme\" or \"com.acme\".\n */\nexport const REGISTRY_NAMESPACE_RE = /^[a-zA-Z0-9.-]+$/;\n\n/** The full server.json `name` regex (namespace \"/\" server-name), per the schema. */\nexport const REGISTRY_NAME_RE = /^[a-zA-Z0-9.-]+\\/[a-zA-Z0-9._-]+$/;\n"],"mappings":"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","names":[]}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
CURSOR_EVENT_MAP,
|
|
4
4
|
CURSOR_HOOKS_VERSION
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-ZSMGHEB5.js";
|
|
6
6
|
import {
|
|
7
7
|
MCPB_MANIFEST_VERSION,
|
|
8
8
|
MCP_SERVER_SCHEMA_URL,
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
isConcreteSemver,
|
|
12
12
|
isPlaceholderVersion,
|
|
13
13
|
registryTransportType
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-UVBAH263.js";
|
|
15
15
|
import {
|
|
16
16
|
writeTomlString
|
|
17
17
|
} from "./chunk-OPXAP3AC.js";
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
renderCommandMd,
|
|
20
20
|
renderSkillMd,
|
|
21
21
|
renderSubagentMd
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-RHML2NOB.js";
|
|
23
23
|
import {
|
|
24
24
|
buildHomeBinHookCommand,
|
|
25
25
|
buildServeWrapperCommand,
|
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
ensureDir,
|
|
30
30
|
firstSymlinkInPath,
|
|
31
31
|
homeBinPath
|
|
32
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-2HCJV6UO.js";
|
|
33
33
|
|
|
34
34
|
// src/core/package.ts
|
|
35
35
|
import { existsSync as existsSync2, readFileSync } from "fs";
|
|
@@ -1062,4 +1062,4 @@ export {
|
|
|
1062
1062
|
packageConnectorAll,
|
|
1063
1063
|
installInstructions
|
|
1064
1064
|
};
|
|
1065
|
-
//# sourceMappingURL=chunk-
|
|
1065
|
+
//# sourceMappingURL=chunk-ZEFUDBTY.js.map
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
import {
|
|
9
9
|
BaseAdapter,
|
|
10
10
|
renderSkillMd
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-RHML2NOB.js";
|
|
12
12
|
import {
|
|
13
13
|
buildWrappedStdio,
|
|
14
14
|
isHomeBinHookCommand
|
|
@@ -498,7 +498,7 @@ ${cmd.prompt}
|
|
|
498
498
|
case "SessionStart": {
|
|
499
499
|
const ev = {
|
|
500
500
|
...base,
|
|
501
|
-
source: normalizeSessionSource(
|
|
501
|
+
source: normalizeSessionSource(void 0)
|
|
502
502
|
};
|
|
503
503
|
return ev;
|
|
504
504
|
}
|
|
@@ -539,7 +539,10 @@ ${cmd.prompt}
|
|
|
539
539
|
error,
|
|
540
540
|
...typeof input.tool_use_id === "string" ? { toolUseId: input.tool_use_id } : {},
|
|
541
541
|
...typeof input.is_interrupt === "boolean" ? { isInterrupt: input.is_interrupt } : {},
|
|
542
|
-
|
|
542
|
+
// postToolUseFailure reports a BARE `duration` (ms), not `duration_ms`
|
|
543
|
+
// (cursor.com/docs/hooks ~904,918). duration_ms only exists on
|
|
544
|
+
// sessionEnd/subagentStop.
|
|
545
|
+
...typeof input.duration === "number" ? { durationMs: input.duration } : {}
|
|
543
546
|
};
|
|
544
547
|
return ev;
|
|
545
548
|
}
|
|
@@ -560,7 +563,9 @@ ${cmd.prompt}
|
|
|
560
563
|
...base,
|
|
561
564
|
...typeof agentId === "string" ? { agentId } : {},
|
|
562
565
|
...typeof agentType === "string" ? { agentType } : {},
|
|
563
|
-
|
|
566
|
+
// Cursor's subagentStop carries the subagent's output text under
|
|
567
|
+
// `summary`, NOT last_assistant_message (cursor.com/docs/hooks ~972,993).
|
|
568
|
+
...typeof input.summary === "string" ? { lastAssistantMessage: input.summary } : {},
|
|
564
569
|
...typeof input.stop_hook_active === "boolean" ? { stopHookActive: input.stop_hook_active } : {}
|
|
565
570
|
};
|
|
566
571
|
return ev;
|
|
@@ -641,4 +646,4 @@ export {
|
|
|
641
646
|
adapter,
|
|
642
647
|
cursor_default
|
|
643
648
|
};
|
|
644
|
-
//# sourceMappingURL=chunk-
|
|
649
|
+
//# sourceMappingURL=chunk-ZSMGHEB5.js.map
|