@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
|
@@ -1 +0,0 @@
|
|
|
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 {\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\nconst ID_RE = /^[a-z0-9][a-z0-9-]*$/;\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 (typeof config.id !== \"string\" || !ID_RE.test(config.id)) {\n throw new ConnectorConfigError(\n `id must be kebab-case matching ${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":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/adapters/cursor/index.ts"],"sourcesContent":["/**\n * adapters/cursor — Cursor platform adapter for agent-connector.\n *\n * Generalized from context-mode's proven Cursor adapter: the served identity is\n * now `ctx.connector` (not a hardcoded \"context-mode\"), and every hook command\n * points at the single stable home binary (the shared hook-merge engine builds\n * the command) so one framework update propagates everywhere.\n *\n * Cursor is a json-stdio host:\n * - MCP servers: user scope → ~/.cursor/mcp.json (\"mcpServers\"); project scope\n * → <projectDir>/.cursor/mcp.json (\"mcpServers\").\n * - Hooks: <configDir>/hooks.json with shape `{ version, hooks: { <cursorEvent>:\n * [ { command, matcher? } ] } }`. Unlike Claude, each entry is a FLAT command\n * object (no `{ matcher, hooks:[...] }` wrapper).\n * - Reply: a JSON object on stdout (exit 0). deny/ask carry `permission` +\n * `user_message`; modify carries `updated_input`; context injects via\n * `agent_message` (PreToolUse) or `additional_context` (Post/SessionStart).\n *\n * Cursor supports its own `${env:VAR}` native interpolation, so env/header/url\n * values are rewritten to that native token rather than baked into the file.\n */\n\nimport { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport { BaseAdapter, type HookMergeDescriptor } from \"../base.js\";\nimport type { Adapter, HookReply, InstallContext, NormalizedEvent } from \"../spi.js\";\nimport type {\n ChangeRecord,\n CommandDef,\n DetectedPlatform,\n HealthCheck,\n HookEventName,\n HookParadigm,\n HookResponse,\n PlatformCapabilities,\n PlatformId,\n PostToolUseEvent,\n PostToolUseFailureEvent,\n PreCompactEvent,\n PreToolUseEvent,\n ServerDef,\n SessionEndEvent,\n SessionStartEvent,\n StopEvent,\n SubagentDef,\n SubagentStartEvent,\n SubagentStopEvent,\n Transport,\n UserPromptSubmitEvent,\n} from \"../../core/types.js\";\nimport { rewriteEnvRefs } from \"../../core/interpolate.js\";\nimport {\n buildWrappedStdio,\n isHomeBinHookCommand,\n} from \"../../core/spawn.js\";\nimport { renderSkillMd } from \"../claude-code/render.js\";\nimport { normalizeSessionSource } from \"../claude-code/wire.js\";\n\nconst HOST: PlatformId = \"cursor\";\nconst MCP_ROOT_KEY = \"mcpServers\";\n\n/**\n * Native hooks.json version Cursor expects. Exported as the SINGLE source of\n * truth for Cursor's hooks-file version, shared with the `cursor-plugin`\n * package emitter so the live install + the packaged bundle can never stamp\n * different versions (see core/package-formats/cursor.ts).\n */\nexport const CURSOR_HOOKS_VERSION = 1;\n\n/**\n * Cursor-native hook event names, in the lower-camel form Cursor reads from\n * hooks.json. The first four are the events the proven context-mode adapter\n * registers; postToolUseFailure / subagentStart / subagentStop are Cursor's\n * documented \"Subagent (Task tool) lifecycle\" + tool-failure hooks.\n */\nconst CURSOR_EVENT = {\n PreToolUse: \"preToolUse\",\n PostToolUse: \"postToolUse\",\n SessionStart: \"sessionStart\",\n Stop: \"stop\",\n PostToolUseFailure: \"postToolUseFailure\",\n SubagentStart: \"subagentStart\",\n SubagentStop: \"subagentStop\",\n // Lifecycle/prompt events Cursor 1.7+ documents (cursor.com/docs/hooks):\n // sessionEnd is fire-and-forget; preCompact is observational (cannot block);\n // beforeSubmitPrompt fires before a prompt is sent and CAN prevent submission\n // (Cursor itself matches beforeSubmitPrompt against the value \"UserPromptSubmit\").\n SessionEnd: \"sessionEnd\",\n PreCompact: \"preCompact\",\n UserPromptSubmit: \"beforeSubmitPrompt\",\n} as const;\n\n/**\n * Map our normalized event names to Cursor's native hook event names. Only the\n * events Cursor actually supports are present; everything else has no Cursor\n * equivalent and is reported as a skip/warn at install time.\n *\n * PermissionRequest is deliberately ABSENT: Cursor has no permission-dialog\n * event — its permission gate is the OUTPUT field `permission: \"allow\"|\"deny\"|\n * \"ask\"` of the before* hooks (beforeShellExecution / beforeMCPExecution /\n * beforeReadFile / preToolUse), not an observable event. Install reports the\n * standard skip-warn for it.\n *\n * Exported as the SINGLE source of truth for canonical→Cursor-native event\n * mapping, shared with the `cursor-plugin` package emitter (see\n * core/package-formats/cursor.ts) so the packaged bundle's hooks.json keys can\n * never silently diverge from the live install adapter's.\n */\nexport const CURSOR_EVENT_MAP: Partial<Record<HookEventName, string>> = {\n PreToolUse: CURSOR_EVENT.PreToolUse,\n PostToolUse: CURSOR_EVENT.PostToolUse,\n SessionStart: CURSOR_EVENT.SessionStart,\n Stop: CURSOR_EVENT.Stop,\n PostToolUseFailure: CURSOR_EVENT.PostToolUseFailure,\n SubagentStart: CURSOR_EVENT.SubagentStart,\n SubagentStop: CURSOR_EVENT.SubagentStop,\n SessionEnd: CURSOR_EVENT.SessionEnd,\n PreCompact: CURSOR_EVENT.PreCompact,\n UserPromptSubmit: CURSOR_EVENT.UserPromptSubmit,\n};\n\n/** A single Cursor native hook entry — a flat command object. */\ninterface CursorHookEntry {\n command: string;\n matcher?: string;\n}\n\n/** Native MCP server entry shapes Cursor accepts under `mcpServers`. */\ninterface CursorStdioServer {\n command: string;\n args?: string[];\n env?: Record<string, string>;\n cwd?: string;\n}\ninterface CursorHttpServer {\n url: string;\n headers?: Record<string, string>;\n}\n\n/** Raw Cursor hook stdin payload (snake_case wire fields). */\ninterface CursorWireInput {\n connector?: unknown;\n tool_name?: string;\n tool_input?: Record<string, unknown>;\n tool_output?: string;\n error_message?: string;\n cwd?: string;\n workspace_roots?: string[];\n conversation_id?: string;\n session_id?: string;\n generation_id?: string;\n source?: string;\n trigger?: string;\n status?: string;\n loop_count?: number;\n stop_hook_active?: boolean;\n\n // beforeSubmitPrompt (UserPromptSubmit) — the submitted prompt text.\n // sessionEnd — the documented end reason. Both field names are taken\n // verbatim from cursor.com/docs/hooks (snake_case wire).\n prompt?: string;\n reason?: string;\n\n // postToolUseFailure — Cursor's existing error vocabulary is error_message;\n // the Claude-compatible names are accepted defensively (unverified wire).\n error?: string;\n tool_use_id?: string;\n is_interrupt?: boolean;\n duration_ms?: number;\n\n // subagentStart / subagentStop (Task-tool lifecycle). Both name families are\n // parsed defensively: agent_* (Claude-compatible) and subagent_* (Cursor-ish).\n agent_id?: string;\n agent_type?: string;\n subagent_id?: string;\n subagent_type?: string;\n last_assistant_message?: string;\n}\n\nexport class CursorAdapter extends BaseAdapter implements Adapter {\n readonly id: PlatformId = HOST;\n readonly name = \"Cursor\";\n readonly paradigm: HookParadigm = \"json-stdio\";\n\n readonly capabilities: PlatformCapabilities = {\n // Memory surface: AGENTS.md-first managed block via the BaseAdapter default\n // (memoryTargets: project <projectDir>/AGENTS.md; user scope where documented).\n supportsMemory: true,\n // Cursor natively supports pre/post tool-use, session start/end, prompt\n // submission, context compaction, and stop (cursor.com/docs/hooks, v1.7+).\n preToolUse: true,\n postToolUse: true,\n preCompact: true,\n sessionStart: true,\n sessionEnd: true,\n userPromptSubmit: true,\n stop: true,\n notification: false,\n // Newer events: Cursor has dedicated postToolUseFailure + subagentStart/\n // subagentStop hooks. permissionRequest stays unset — Cursor's permission\n // gate is an OUTPUT field of its before* hooks, not an observable event\n // (see the EVENT_MAP note).\n postToolUseFailure: true,\n subagentStart: true,\n subagentStop: true,\n // Cursor's preToolUse can rewrite tool input (updated_input) but cannot\n // rewrite already-emitted tool output.\n canModifyArgs: true,\n canModifyOutput: false,\n canInjectSessionContext: true,\n transports: [\"stdio\", \"http\"],\n // Content surfaces: Cursor supports all three (commands, skills, subagents).\n supportsCommands: true,\n supportsSkills: true,\n supportsSubagents: true,\n // Native passthrough hooks: Cursor documents many granular hooks with NO\n // canonical analog — beforeShellExecution / afterShellExecution /\n // beforeMCPExecution / afterMCPExecution / beforeReadFile / afterFileEdit /\n // beforeTabFileRead / afterTabFileEdit / workspaceOpen / afterAgentResponse /\n // afterAgentThought (cursor.com/docs/hooks). They are\n // host-specific (below the >=3-host core bar; see\n // docs/research/host-specific-hook-events-design.md). A connector reaches them\n // by declaring platforms[\"cursor\"].nativeHooks; installHooks writes those\n // event-name keys verbatim into hooks.json, and the generic uninstall reverses\n // them.\n supportsNativeHooks: true,\n // Cursor has a command-driven status line (`/statusline` → `statusLine` in\n // ~/.cursor/cli-config.json, GLOBAL scope only) per the Cursor changelog, but\n // the config-key shape + the Claude-parity stdin payload are sourced from a\n // community tool (agent-status-pills), not first-party Cursor docs — payload\n // field names unverified. Deferred pending a live cursor-agent capture; not a\n // permanent gap; user-scope only when wired.\n };\n\n // ── Detection ────────────────────────────────────────────────────────────\n\n detectInstalled(projectDir: string): DetectedPlatform {\n const userDir = join(homedir(), \".cursor\");\n const userMcp = join(userDir, \"mcp.json\");\n const userHooks = join(userDir, \"hooks.json\");\n const projectDirCursor = join(projectDir, \".cursor\");\n const installed =\n existsSync(userDir) ||\n existsSync(userMcp) ||\n existsSync(userHooks) ||\n existsSync(projectDirCursor);\n return {\n id: this.id,\n name: this.name,\n installed,\n paradigm: this.paradigm,\n capabilities: this.capabilities,\n configPath: userMcp,\n scope: \"user\",\n reason: installed\n ? `found Cursor config under ${userDir}`\n : `no Cursor config at ${userDir}`,\n confidence: installed ? \"high\" : \"low\",\n };\n }\n\n // ── Native paths ─────────────────────────────────────────────────────────\n\n getConfigDir(ctx: InstallContext): string {\n return ctx.scope === \"project\"\n ? join(ctx.projectDir, \".cursor\")\n : join(homedir(), \".cursor\");\n }\n\n getServerConfigPath(ctx: InstallContext): string {\n return join(this.getConfigDir(ctx), \"mcp.json\");\n }\n\n getHookConfigPath(ctx: InstallContext): string {\n return join(this.getConfigDir(ctx), \"hooks.json\");\n }\n\n // ── MCP server install / uninstall ───────────────────────────────────────\n\n installServer(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n const override = connector.platforms[HOST]?.server;\n if (!connector.server || override === false) {\n return [\n {\n platform: this.id,\n action: \"skip\",\n detail: connector.server\n ? \"server registration disabled for cursor\"\n : \"connector declares no MCP server\",\n },\n ];\n }\n\n // Shallow-merge any per-platform server override into the base ServerDef.\n const server: ServerDef =\n override && typeof override === \"object\"\n ? { ...connector.server, ...override }\n : connector.server;\n\n const serverPath = this.getServerConfigPath(ctx);\n const entry = this.renderServerEntry(ctx, server);\n\n return [\n this.upsertServerInJson(serverPath, MCP_ROOT_KEY, connector.id, entry, ctx.dryRun),\n ];\n }\n\n uninstallServer(ctx: InstallContext): ChangeRecord[] {\n const serverPath = this.getServerConfigPath(ctx);\n return [\n this.removeServerFromJson(serverPath, MCP_ROOT_KEY, ctx.connector.id, ctx.dryRun),\n ];\n }\n\n /** Render a normalized ServerDef into Cursor's native mcpServers entry. */\n private renderServerEntry(\n ctx: InstallContext,\n server: ServerDef,\n ): CursorStdioServer | CursorHttpServer {\n const transport: Transport = server.transport;\n\n if (transport === \"stdio\") {\n let command = server.command ?? \"\";\n let args = [...(server.args ?? [])];\n\n // Transparent telemetry wrapping: route the real command through\n // `<homeBin> serve --connector <id> -- <command> <args...>`.\n ({ command, args } = buildWrappedStdio(ctx, server, this.id, command, args));\n\n const entry: CursorStdioServer = { command: this.rewrite(command) };\n if (args.length > 0) entry.args = args.map((a) => this.rewrite(a));\n const env = this.renderEnv(server.env);\n if (env) entry.env = env;\n if (server.cwd) entry.cwd = this.rewrite(server.cwd);\n return entry;\n }\n\n // http (and any other remote transport we surface) — Cursor registers a URL.\n const entry: CursorHttpServer = { url: this.rewrite(server.url ?? \"\") };\n const headers = this.renderEnv(server.headers);\n if (headers) entry.headers = headers;\n return entry;\n }\n\n /**\n * Render env/header values. Cursor supports its own `${env:VAR}` native\n * interpolation, so translate `${env:VAR}` refs to that native token rather\n * than baking secrets into the file. Literals pass through unchanged.\n */\n private renderEnv(\n env: Record<string, string> | undefined,\n ): Record<string, string> | undefined {\n if (!env || Object.keys(env).length === 0) return undefined;\n const out: Record<string, string> = {};\n for (const [k, v] of Object.entries(env)) out[k] = this.rewrite(v);\n return out;\n }\n\n /** Translate `${env:VAR(:-default)}` to Cursor's native `${env:VAR}` token. */\n private rewrite(value: string): string {\n return rewriteEnvRefs(value, cursorEnvToken);\n }\n\n // ── Hook install / uninstall ─────────────────────────────────────────────\n\n installHooks(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n const override = connector.platforms[HOST];\n\n // `hooks: false` disables only the NORMALIZED events. nativeHooks is a\n // sibling, cursor-scoped declaration on the same override and installs\n // regardless.\n const normalizedEvents = override?.hooks === false ? [] : connector.hookEvents;\n const nativeHooks = override?.nativeHooks ?? {};\n const nativeEvents = Object.keys(nativeHooks);\n\n if (normalizedEvents.length === 0 && nativeEvents.length === 0) {\n return [\n {\n platform: this.id,\n action: \"skip\",\n detail: override?.hooks === false ? \"hooks disabled for cursor\" : \"connector declares no hooks\",\n },\n ];\n }\n\n // Normalized events go through the engine's mapEvent/warn path; native\n // event-name keys ride the separate `native` pass (verbatim keys, EXACT\n // command, the `(native)` detail) — see the descriptor + base.upsertHookEntries.\n const pending = normalizedEvents.map((event) => ({\n event,\n matcher: connector.hooks[event]?.matcher ?? \"\",\n }));\n const native = nativeEvents.map((event) => ({\n event,\n matcher: nativeHooks[event]?.matcher ?? \"\",\n }));\n return this.upsertHookEntries(\n ctx,\n this.getHookConfigPath(ctx),\n pending,\n this.hookDescriptor(ctx),\n native,\n );\n }\n\n uninstallHooks(ctx: InstallContext): ChangeRecord[] {\n return this.removeHookEntries(ctx, this.getHookConfigPath(ctx), this.hookDescriptor(ctx));\n }\n\n /**\n * Cursor's hook-merge descriptor (FLAT shape `{ command, matcher? }`):\n * - mapEvent renames canonical → Cursor's lower-camel native key\n * (CURSOR_EVENT_MAP); an unmapped event warn-skips (no Cursor equivalent).\n * - renderEntry omits the `matcher` key when the matcher is falsy — this\n * `{command}` vs `{command,matcher}` distinction is load-bearing on-disk\n * bytes (Cursor's flat entry shape), reproduced exactly here.\n * - install find is connector-generic (ANY of our commands at the flat\n * `entry.command`); uninstall drops whole owned entries (flat — NO\n * stripInner). The version stamp is install-only via onMutate.\n * - the native pass uses EXACT-command ownership so a native key coinciding\n * with a normalized event's mapped key adds a SECOND distinct command\n * rather than clobbering the normalized entry.\n */\n private hookDescriptor(ctx: InstallContext): HookMergeDescriptor<CursorHookEntry> {\n return {\n mapEvent: (e) => CURSOR_EVENT_MAP[e as HookEventName],\n unmappedWarnDetail: (e) => `${e} has no Cursor hook equivalent — skipped`,\n renderEntry: (_event, matcher, command) =>\n matcher ? { command, matcher } : { command },\n entryOwnsCommand: (entry, _command) => this.isOurCommand(entry.command, ctx),\n ownsEntryForRemove: (c) => (entry) => this.isOurCommand(entry.command, c),\n skipDetail: (e) => `hooks.${e} already registered`,\n removeDetail: (e, n) => `hooks.${e} (${n})`,\n absentDetail: \"no hooks section present\",\n noMatchDetail: \"no matching hook entries\",\n onMutate: (file) => {\n (file as { version?: number }).version = CURSOR_HOOKS_VERSION;\n },\n nativeOwnsCommand: (entry, command) => entry.command === command,\n nativeSkipDetail: (e) => `hooks.${e} (native) already registered`,\n nativeMutateDetail: (e) => `hooks.${e} (native)`,\n };\n }\n\n /** True when a hook command references our home binary AND this connector id\n * (anchored so a shared-prefix id can't collide — see isHomeBinHookCommand). */\n private isOurCommand(command: string | undefined, ctx: InstallContext): boolean {\n return isHomeBinHookCommand(command, ctx.homeBinPath, ctx.connector.id);\n }\n\n // ── Content surfaces: commands / skills / subagents ──────────────────────\n // CONTENT-ONLY: pure native-file writers under <configDir>/{commands,skills,\n // agents}. No runtime dispatch, no home-bin pointer, no telemetry wrap. Each\n // method is idempotent (byte-identical → skip) via BaseAdapter.writeContentFile\n // and reversible via removeContentFile. Honors platforms[\"cursor\"] per-surface\n // false to skip. Cursor commands are BODY-ONLY markdown (no frontmatter);\n // skills are the uniform <name>/SKILL.md + resources; subagents are md+fm.\n\n private commandsDir(ctx: InstallContext): string {\n return join(this.getConfigDir(ctx), \"commands\");\n }\n private skillsDir(ctx: InstallContext): string {\n return join(this.getConfigDir(ctx), \"skills\");\n }\n private agentsDir(ctx: InstallContext): string {\n return join(this.getConfigDir(ctx), \"agents\");\n }\n\n /** Native command file path: <configDir>/commands/<name>.md. */\n private commandPath(ctx: InstallContext, name: string): string {\n return join(this.commandsDir(ctx), `${name}.md`);\n }\n /** Native skill dir: <configDir>/skills/<name>. */\n private skillDir(ctx: InstallContext, name: string): string {\n return join(this.skillsDir(ctx), name);\n }\n /** Native subagent file path: <configDir>/agents/<name>.md. */\n private subagentPath(ctx: InstallContext, name: string): string {\n return join(this.agentsDir(ctx), `${name}.md`);\n }\n\n // ── Commands ──────────────────────────────────────────────────────────────\n\n override installCommands(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n if (connector.platforms[HOST]?.commands === false) {\n return [{ platform: this.id, action: \"skip\", detail: \"commands disabled for cursor\" }];\n }\n if (connector.commands.length === 0) {\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no commands\" }];\n }\n return connector.commands.map((cmd) =>\n this.writeContentFile(\n this.commandPath(ctx, cmd.name),\n this.renderCommand(cmd),\n ctx.dryRun,\n ),\n );\n }\n\n override uninstallCommands(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n if (connector.commands.length === 0) {\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no commands\" }];\n }\n return connector.commands.map((cmd) =>\n this.removeContentFile(this.commandPath(ctx, cmd.name), ctx.dryRun),\n );\n }\n\n /**\n * Render a Cursor command: BODY-ONLY markdown (no frontmatter). Cursor reads\n * the file as the command prompt verbatim. We prepend the one-line description\n * as an HTML comment header when present so authoring intent survives the\n * round-trip without leaking into the rendered prompt. A description containing\n * \"-->\" would prematurely CLOSE the HTML comment and leak the remainder into\n * the prompt, so we neutralize that sequence before embedding it.\n */\n private renderCommand(cmd: CommandDef): string {\n if (!cmd.description) return `${cmd.prompt}\\n`;\n // Break any literal comment-close so it cannot terminate our header early.\n const safe = cmd.description.replace(/--+>/g, (m) => m.replace(/>/g, \">\"));\n return `<!-- ${safe} -->\\n\\n${cmd.prompt}\\n`;\n }\n\n // ── Skills ────────────────────────────────────────────────────────────────\n\n override installSkills(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n if (connector.platforms[HOST]?.skills === false) {\n return [{ platform: this.id, action: \"skip\", detail: \"skills disabled for cursor\" }];\n }\n if (connector.skills.length === 0) {\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no skills\" }];\n }\n const changes: ChangeRecord[] = [];\n for (const skill of connector.skills) {\n const dir = this.skillDir(ctx, skill.name);\n changes.push(\n this.writeContentFile(join(dir, \"SKILL.md\"), renderSkillMd(skill), ctx.dryRun),\n );\n // Bundle any resource files beside SKILL.md (relative path → contents).\n // Defense-in-depth: skip+warn on any key that escapes the skill dir\n // (config-time validation already rejects these, but never trust input).\n for (const [rel, contents] of Object.entries(skill.resources ?? {})) {\n const target = this.resolveWithin(dir, rel);\n if (target === null) {\n changes.push({\n platform: this.id,\n action: \"warn\",\n detail: `skill resource \"${rel}\" escapes the skill dir; skipped`,\n });\n continue;\n }\n changes.push(this.writeContentFile(target, contents, ctx.dryRun));\n }\n }\n return changes;\n }\n\n override uninstallSkills(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n if (connector.skills.length === 0) {\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no skills\" }];\n }\n const changes: ChangeRecord[] = [];\n for (const skill of connector.skills) {\n const dir = this.skillDir(ctx, skill.name);\n // Remove only the files we wrote (SKILL.md + declared resources), then the\n // skill dir itself when we own its full contents.\n changes.push(this.removeContentFile(join(dir, \"SKILL.md\"), ctx.dryRun));\n for (const rel of Object.keys(skill.resources ?? {})) {\n const target = this.resolveWithin(dir, rel);\n if (target === null) continue; // never delete outside the skill dir\n changes.push(this.removeContentFile(target, ctx.dryRun));\n }\n // Only remove the skill dir when WE own its full contents — never rm -rf a\n // dir that still holds user-added / sibling-tool / shared files.\n changes.push(this.removeDirIfEmpty(dir, ctx.dryRun));\n }\n return changes;\n }\n\n // ── Subagents ───────────────────────────────────────────────────────────────\n\n override installSubagents(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n if (connector.platforms[HOST]?.subagents === false) {\n return [{ platform: this.id, action: \"skip\", detail: \"subagents disabled for cursor\" }];\n }\n if (connector.subagents.length === 0) {\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no subagents\" }];\n }\n return connector.subagents.map((agent) =>\n this.writeContentFile(\n this.subagentPath(ctx, agent.name),\n this.renderSubagent(agent),\n ctx.dryRun,\n ),\n );\n }\n\n override uninstallSubagents(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n if (connector.subagents.length === 0) {\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no subagents\" }];\n }\n return connector.subagents.map((agent) =>\n this.removeContentFile(this.subagentPath(ctx, agent.name), ctx.dryRun),\n );\n }\n\n /** Render a Cursor subagent to md+frontmatter (name, description, model, readonly) + prompt body. */\n private renderSubagent(agent: SubagentDef): string {\n const frontmatter: Record<string, unknown> = {\n name: agent.name,\n description: agent.description,\n };\n if (agent.model !== undefined) frontmatter.model = agent.model;\n if (agent.readonly !== undefined) frontmatter.readonly = agent.readonly;\n if (agent.extra) Object.assign(frontmatter, agent.extra);\n return this.renderFrontmatterMd(frontmatter, agent.prompt);\n }\n\n // ── Diagnostics ──────────────────────────────────────────────────────────\n\n override getHealthChecks(ctx: InstallContext): readonly HealthCheck[] {\n const mcpPath = this.getServerConfigPath(ctx);\n const hooksPath = this.getHookConfigPath(ctx);\n const checks: HealthCheck[] = [\n {\n name: `${this.name}: mcp.json present`,\n check: () =>\n existsSync(mcpPath)\n ? { status: \"OK\", detail: mcpPath }\n : { status: \"FAIL\", detail: `not found: ${mcpPath}` },\n },\n {\n name: `${this.name}: hooks.json present`,\n check: () => {\n // Same \"only assert what the connector declares\" rule as the\n // content-surface checks below: a hookless connector never writes\n // hooks.json, so its absence is healthy, not a failure.\n if (ctx.connector.hookEvents.length === 0) {\n return { status: \"OK\", detail: \"no hooks declared\" };\n }\n return existsSync(hooksPath)\n ? { status: \"OK\", detail: hooksPath }\n : { status: \"FAIL\", detail: `not found: ${hooksPath}` };\n },\n },\n ];\n\n // Content-surface checks: only assert presence of the files this connector\n // declares (skip silently for surfaces it never asked for).\n for (const cmd of ctx.connector.commands) {\n const p = this.commandPath(ctx, cmd.name);\n checks.push({\n name: `${this.name}: command ${cmd.name} present`,\n check: () =>\n existsSync(p) ? { status: \"OK\", detail: p } : { status: \"FAIL\", detail: `not found: ${p}` },\n });\n }\n for (const skill of ctx.connector.skills) {\n const p = join(this.skillDir(ctx, skill.name), \"SKILL.md\");\n checks.push({\n name: `${this.name}: skill ${skill.name} present`,\n check: () =>\n existsSync(p) ? { status: \"OK\", detail: p } : { status: \"FAIL\", detail: `not found: ${p}` },\n });\n }\n for (const agent of ctx.connector.subagents) {\n const p = this.subagentPath(ctx, agent.name);\n checks.push({\n name: `${this.name}: subagent ${agent.name} present`,\n check: () =>\n existsSync(p) ? { status: \"OK\", detail: p } : { status: \"FAIL\", detail: `not found: ${p}` },\n });\n }\n return checks;\n }\n\n // ── Runtime: parse Cursor stdin JSON → normalized event ──────────────────\n\n parseEvent(event: HookEventName, raw: unknown): NormalizedEvent {\n const input = (raw ?? {}) as CursorWireInput;\n const connectorId = typeof input.connector === \"string\" ? input.connector : \"\";\n const sessionId = extractSessionId(input);\n const projectDir = this.getProjectDir(input);\n\n const base = {\n hostPlatform: HOST,\n connectorId,\n sessionId,\n raw,\n ...(projectDir !== undefined ? { projectDir } : {}),\n } as const;\n\n switch (event) {\n case \"PreToolUse\": {\n const ev: PreToolUseEvent = {\n ...base,\n toolName: input.tool_name ?? \"\",\n toolInput: input.tool_input ?? {},\n };\n return ev;\n }\n case \"PostToolUse\": {\n const toolOutput = input.tool_output ?? input.error_message;\n const ev: PostToolUseEvent = {\n ...base,\n toolName: input.tool_name ?? \"\",\n toolInput: input.tool_input ?? {},\n ...(toolOutput !== undefined ? { toolOutput } : {}),\n ...(input.error_message ? { isError: true } : {}),\n };\n return ev;\n }\n case \"SessionStart\": {\n const ev: SessionStartEvent = {\n ...base,\n source: normalizeSessionSource(input.source ?? input.trigger),\n };\n return ev;\n }\n case \"Stop\": {\n const ev: StopEvent = {\n ...base,\n ...(typeof input.stop_hook_active === \"boolean\"\n ? { stopHookActive: input.stop_hook_active }\n : {}),\n };\n return ev;\n }\n case \"SessionEnd\": {\n // Cursor sessionEnd: { session_id, reason, duration_ms, ... }. session_id\n // is already folded into base.sessionId via extractSessionId; only the\n // documented `reason` enum maps onto the normalized SessionEnd shape.\n const ev: SessionEndEvent = {\n ...base,\n ...(typeof input.reason === \"string\" ? { reason: input.reason } : {}),\n };\n return ev;\n }\n case \"UserPromptSubmit\": {\n // Cursor beforeSubmitPrompt: { prompt, attachments }. attachments has no\n // normalized field and is preserved via base.raw; only `prompt` maps.\n const ev: UserPromptSubmitEvent = {\n ...base,\n prompt: typeof input.prompt === \"string\" ? input.prompt : \"\",\n };\n return ev;\n }\n case \"PreCompact\": {\n // Cursor preCompact: { trigger: \"auto\"|\"manual\", context_*… }. Only the\n // documented `trigger` enum maps onto the normalized PreCompact shape.\n const ev: PreCompactEvent = {\n ...base,\n ...(input.trigger === \"auto\" || input.trigger === \"manual\"\n ? { trigger: input.trigger }\n : {}),\n };\n return ev;\n }\n case \"PostToolUseFailure\": {\n // Cursor's established error field is error_message; fall back to the\n // Claude-compatible `error` defensively.\n const error = input.error_message ?? input.error ?? \"\";\n const ev: PostToolUseFailureEvent = {\n ...base,\n toolName: input.tool_name ?? \"\",\n toolInput: input.tool_input ?? {},\n error,\n ...(typeof input.tool_use_id === \"string\"\n ? { toolUseId: input.tool_use_id }\n : {}),\n ...(typeof input.is_interrupt === \"boolean\"\n ? { isInterrupt: input.is_interrupt }\n : {}),\n ...(typeof input.duration_ms === \"number\"\n ? { durationMs: input.duration_ms }\n : {}),\n };\n return ev;\n }\n case \"SubagentStart\": {\n const agentId = input.agent_id ?? input.subagent_id;\n const agentType = input.agent_type ?? input.subagent_type;\n const ev: SubagentStartEvent = {\n ...base,\n ...(typeof agentId === \"string\" ? { agentId } : {}),\n ...(typeof agentType === \"string\" ? { agentType } : {}),\n };\n return ev;\n }\n case \"SubagentStop\": {\n const agentId = input.agent_id ?? input.subagent_id;\n const agentType = input.agent_type ?? input.subagent_type;\n const ev: SubagentStopEvent = {\n ...base,\n ...(typeof agentId === \"string\" ? { agentId } : {}),\n ...(typeof agentType === \"string\" ? { agentType } : {}),\n ...(typeof input.last_assistant_message === \"string\"\n ? { lastAssistantMessage: input.last_assistant_message }\n : {}),\n ...(typeof input.stop_hook_active === \"boolean\"\n ? { stopHookActive: input.stop_hook_active }\n : {}),\n };\n return ev;\n }\n default: {\n // Cursor never delivers Notification / PermissionRequest (no native\n // equivalent — permission is an OUTPUT field of its before* hooks, not\n // an event). If the runtime dispatches one anyway, fail loudly.\n throw new Error(`unsupported cursor hook event: ${String(event)}`);\n }\n }\n }\n\n private getProjectDir(input: CursorWireInput): string | undefined {\n return input.cwd ?? input.workspace_roots?.[0] ?? undefined;\n }\n\n // ── Runtime: normalized response → Cursor native hook reply ──────────────\n\n formatReply(event: HookEventName, response: HookResponse): HookReply {\n const decision = response.decision ?? \"allow\";\n\n // postToolUseFailure (feedback beside the error) and subagentStart (context\n // injected into the SUBAGENT's conversation) are observe/context-only on\n // Cursor: \"context\" emits additional_context, and a \"deny\" DEGRADES to the\n // same shape carrying the reason (the tool already failed / the spawn is\n // not blockable). Everything else is a minimal no-op payload (Cursor\n // rejects empty stdout as \"no valid response\").\n if (event === \"PostToolUseFailure\" || event === \"SubagentStart\") {\n const context =\n decision === \"context\"\n ? response.additionalContext\n : decision === \"deny\"\n ? response.reason ?? response.additionalContext\n : undefined;\n return this.stdout({ additional_context: context ?? \"\" });\n }\n\n // beforeSubmitPrompt (UserPromptSubmit) is a BLOCK gate, not a permission/\n // context surface: its only documented output is { continue, user_message }\n // (cursor.com/docs/hooks). A \"deny\" prevents submission (continue:false +\n // reason); it cannot inject context (no additional_context/agent_message\n // field), so every non-deny decision is a no-op continue:true.\n if (event === \"UserPromptSubmit\") {\n if (decision === \"deny\") {\n return this.stdout({\n continue: false,\n user_message: response.reason ?? \"Blocked by hook\",\n });\n }\n return this.stdout({ continue: true });\n }\n\n // sessionEnd is fire-and-forget (the response is logged but not used) and\n // preCompact is observational (cannot block or modify compaction) per\n // cursor.com/docs/hooks — neither carries a decision Cursor honors, so both\n // are an unconditional no-op passthrough (mirrors Stop).\n if (event === \"SessionEnd\" || event === \"PreCompact\") {\n return { exitCode: 0 };\n }\n\n // deny → block the action with a user-facing message. (On SubagentStop\n // this follows the adapter's Stop idiom — the deny carries Stop semantics.)\n if (decision === \"deny\") {\n return this.stdout({\n permission: \"deny\",\n user_message: response.reason ?? \"Blocked by hook\",\n });\n }\n\n // ask → prompt the user to confirm.\n if (decision === \"ask\") {\n return this.stdout({\n permission: \"ask\",\n user_message: response.reason ?? \"Confirmation required by hook\",\n });\n }\n\n // modify → rewrite PreToolUse input (only where Cursor supports it).\n if (decision === \"modify\") {\n if (event === \"PreToolUse\" && response.updatedInput) {\n return this.stdout({ updated_input: response.updatedInput });\n }\n // Output rewrite is unsupported on Cursor; fall through to allow.\n }\n\n // context → inject soft guidance. PreToolUse uses `agent_message`; Post and\n // SessionStart use `additional_context`.\n if (decision === \"context\" && response.additionalContext) {\n return event === \"PreToolUse\"\n ? this.stdout({ agent_message: response.additionalContext })\n : this.stdout({ additional_context: response.additionalContext });\n }\n\n // SessionStart always emits valid JSON even on a no-op (Cursor rejects empty\n // stdout as \"no valid response\").\n if (event === \"SessionStart\") {\n return this.stdout({ additional_context: response.additionalContext ?? \"\" });\n }\n\n // allow / void → minimal no-op payload (Cursor rejects empty stdout).\n if (event === \"PreToolUse\") return this.stdout({ agent_message: \"\" });\n if (event === \"PostToolUse\") return this.stdout({ additional_context: \"\" });\n return { exitCode: 0 };\n }\n\n private stdout(payload: unknown): HookReply {\n return { exitCode: 0, stdout: JSON.stringify(payload) };\n }\n}\n\n/** Cursor native interpolation token: `${env:VAR}` → `${env:VAR}` (passthrough). */\nfunction cursorEnvToken(name: string): string {\n return `\\${env:${name}}`;\n}\n\nfunction extractSessionId(input: CursorWireInput): string {\n if (typeof input.conversation_id === \"string\") return input.conversation_id;\n if (typeof input.session_id === \"string\") return input.session_id;\n return \"\";\n}\n\nexport const adapter = new CursorAdapter();\nexport default adapter;\n"],"mappings":"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","names":["entry"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/managed-block.ts"],"sourcesContent":["/**\n * core/managed-block — the marker-fenced MANAGED BLOCK engine behind the\n * `memory` content surface.\n *\n * Memory/rules files (AGENTS.md, CLAUDE.md, GEMINI.md, …) are SHARED,\n * user-authored files — unlike commands/skills/subagents, agent-connector does\n * not own them. Every write therefore goes through this one module, which\n * implements idempotent, hash-stamped, uninstall-reversible blocks:\n *\n * <!-- agent-connector:begin <connectorId>/<name> hash=<sha256-12> -->\n * <!-- Managed by agent-connector for \"<connectorId>\". Do not edit … -->\n * …guidance…\n * <!-- agent-connector:end <connectorId>/<name> -->\n *\n * Design rules (each grounded in surveyed prior art — ansible blockinfile,\n * conda init, OMC mergeClaudeMd, Ruler, doctoc):\n * • UNIQUE marker per block: the blockId (`<connectorId>/<entryName>`) lives\n * ON the marker line, so multiple connectors coexist in one file and each\n * update path only ever touches its own pair (ansible's documented\n * multi-block rule). The shared `agent-connector` namespace token lets\n * doctor/uninstall enumerate every block with one scan.\n * • `hash=` is the first 12 hex chars of sha256 over the NORMALIZED inner\n * region (CRLF→LF + trim — stable under prettier/EOL converters): O(1)\n * idempotence (unchanged → skip, no mtime/git churn) and tamper detection\n * (actual inner hash ≠ recorded ⇒ the user edited inside the block ⇒ warn,\n * never clobber without an explicit force).\n * • IN-PLACE replacement (conda semantics): zero bytes outside the marker\n * pair ever change — no move-to-top, no user blank-line reflow.\n * • Line-anchored matching that explicitly tolerates `\\r` line ends and a\n * FENCE-AWARE scanner (markers quoted inside ``` / ~~~ code fences never\n * match) — fixes the CRLF duplicate-block and quoted-marker classes.\n * • First-begin / FIRST-end-after pairing (never last-end): a missing end\n * marker must not swallow a sibling connector's block.\n * • HTML-comment markers are CORRECT for CLAUDE.md: Claude Code strips HTML\n * comments from CLAUDE.md before context injection (verified against docs\n * and the 2.1.172 binary), so the markers and the do-not-edit notice are\n * INVISIBLE to the model there while remaining fully parseable by us for\n * sync/doctor/uninstall. On AGENTS.md hosts (which inline the whole file\n * into the prompt) the short notice doubles as an in-prompt \"do not edit\"\n * instruction to the host's own agent. A `commentStyle: \"hash\"` variant\n * exists for future non-markdown targets (`#`-prefixed marker lines).\n *\n * The module also owns the per-connector MEMORY OWNERSHIP LEDGER\n * (`connectorDir(id)/memory-state.json`): the markers in the file remain the\n * source of truth for uninstall (a teammate's machine with no ledger still\n * uninstalls via the prefix scan); the ledger only adds the created-vs-modified\n * distinction (file deletion rights) and doctor diagnostics.\n */\n\nimport { createHash } from \"node:crypto\";\nimport {\n chmodSync,\n copyFileSync,\n existsSync,\n readFileSync,\n renameSync,\n rmSync,\n statSync,\n writeFileSync,\n} from \"node:fs\";\nimport { basename, dirname, join } from \"node:path\";\n\nimport { backupsDir, connectorDir, ensureDir } from \"./paths.js\";\n\n// ─────────────────────────────────────────────────────────────────────────\n// Grammar constants (shared with defineConnector's content validation)\n// ─────────────────────────────────────────────────────────────────────────\n\n/** Literal begin token. Connector memory content MUST NOT contain it. */\nexport const MANAGED_BLOCK_BEGIN_TOKEN = \"agent-connector:begin\";\n/** Literal end token. Connector memory content MUST NOT contain it. */\nexport const MANAGED_BLOCK_END_TOKEN = \"agent-connector:end\";\n\n/** Hard cap on one memory entry's content (ConnectorConfigError above this). */\nexport const MEMORY_CONTENT_HARD_CAP_BYTES = 16 * 1024;\n/**\n * Soft per-entry budget — exceeded → install-time `warn` ChangeRecord (memory\n * files are injected into EVERY prompt of EVERY session on the host; codex\n * additionally caps combined project docs at 32 KiB).\n */\nexport const MEMORY_CONTENT_SOFT_BUDGET_BYTES = 4 * 1024;\n\n/** Marker comment style: HTML comments (default, all v1 markdown targets) or `#` lines. */\nexport type BlockCommentStyle = \"html\" | \"hash\";\n\n// ─────────────────────────────────────────────────────────────────────────\n// Hashing / rendering\n// ─────────────────────────────────────────────────────────────────────────\n\n/** CRLF/CR → LF + trim: the normalization both hashing sides use. */\nfunction normalizeInner(s: string): string {\n return s.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\").trim();\n}\n\n/** First 12 hex chars of sha256 over the NORMALIZED inner region. */\nexport function hashBlockContent(inner: string): string {\n return createHash(\"sha256\").update(normalizeInner(inner), \"utf8\").digest(\"hex\").slice(0, 12);\n}\n\n/** The conda-style in-block warning, adapted for the LLM era (see header). */\nfunction defaultNotice(connectorId: string): string {\n return (\n `Managed by agent-connector for \"${connectorId}\". Do not edit between these markers: ` +\n `\\`agent-connector sync\\` rewrites this block; ` +\n `\\`agent-connector uninstall ${connectorId}\\` removes it.`\n );\n}\n\nfunction beginLine(blockId: string, hash: string, style: BlockCommentStyle): string {\n return style === \"hash\"\n ? `# ${MANAGED_BLOCK_BEGIN_TOKEN} ${blockId} hash=${hash}`\n : `<!-- ${MANAGED_BLOCK_BEGIN_TOKEN} ${blockId} hash=${hash} -->`;\n}\n\n/** END line is a fixed exact string (no hash) so a content change never strands it. */\nfunction endLine(blockId: string, style: BlockCommentStyle): string {\n return style === \"hash\"\n ? `# ${MANAGED_BLOCK_END_TOKEN} ${blockId}`\n : `<!-- ${MANAGED_BLOCK_END_TOKEN} ${blockId} -->`;\n}\n\nfunction noticeLine(notice: string, style: BlockCommentStyle): string {\n return style === \"hash\" ? `# ${notice}` : `<!-- ${notice} -->`;\n}\n\nexport interface RenderBlockOptions {\n /** `<connectorId>/<entryName>` (or the reserved `_shared/<name>` bridge prefix). */\n blockId: string;\n /** Connector id named in the default do-not-edit notice line. */\n connectorId: string;\n /** The guidance payload (plain markdown; normalized + trimmed on emit). */\n content: string;\n /** Marker comment style; default \"html\". */\n commentStyle?: BlockCommentStyle;\n /** Override the default notice line TEXT (without comment delimiters). */\n notice?: string;\n}\n\n/**\n * Render the block as LOGICAL lines (no EOL chars). The recorded `hash=`\n * covers the full inner region (notice line + content) so install and scan\n * compare like for like.\n */\nexport function renderBlockLines(opts: RenderBlockOptions): string[] {\n const style = opts.commentStyle ?? \"html\";\n const inner = [\n noticeLine(opts.notice ?? defaultNotice(opts.connectorId), style),\n ...normalizeInner(opts.content).split(\"\\n\"),\n ];\n const hash = hashBlockContent(inner.join(\"\\n\"));\n return [beginLine(opts.blockId, hash, style), ...inner, endLine(opts.blockId, style)];\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Scanning (fence-aware, line-anchored, CRLF-tolerant)\n// ─────────────────────────────────────────────────────────────────────────\n\n// Both comment styles are RECOGNIZED in one pass (a file may legitimately mix\n// styles only across rewrites; emission always uses the requested style).\nconst BEGIN_RE =\n /^(?:<!--\\s+agent-connector:begin\\s+(\\S+)\\s+hash=([0-9a-f]{12})\\s+-->|#\\s+agent-connector:begin\\s+(\\S+)\\s+hash=([0-9a-f]{12}))\\s*$/;\nconst END_RE = /^(?:<!--\\s+agent-connector:end\\s+(\\S+)\\s+-->|#\\s+agent-connector:end\\s+(\\S+))\\s*$/;\n\ninterface MarkerEvent {\n kind: \"begin\" | \"end\";\n blockId: string;\n /** Recorded hash (begin markers only). */\n hash?: string;\n /** Line index into the logical-lines array. */\n index: number;\n}\n\n/** Strip ONE trailing `\\r` — `raw.split(\"\\n\")` leaves it on CRLF files. */\nfunction stripCr(line: string): string {\n return line.endsWith(\"\\r\") ? line.slice(0, -1) : line;\n}\n\n/**\n * Scan logical lines for marker events, tracking ``` / ~~~ fence state so a\n * marker QUOTED inside a fenced code block never matches (the OMC class of\n * false positives, eliminated rather than just reduced).\n */\nfunction scanMarkers(logical: string[]): MarkerEvent[] {\n const events: MarkerEvent[] = [];\n let fence: { char: string; len: number } | null = null;\n for (let i = 0; i < logical.length; i++) {\n const line = logical[i]!;\n if (fence) {\n const close = line.match(/^ {0,3}(`{3,}|~{3,})\\s*$/);\n if (close && close[1]![0] === fence.char && close[1]!.length >= fence.len) fence = null;\n continue;\n }\n const open = line.match(/^ {0,3}(`{3,}|~{3,})/);\n if (open) {\n fence = { char: open[1]![0]!, len: open[1]!.length };\n continue;\n }\n const b = line.match(BEGIN_RE);\n if (b) {\n events.push({ kind: \"begin\", blockId: (b[1] ?? b[3])!, hash: (b[2] ?? b[4])!, index: i });\n continue;\n }\n const e = line.match(END_RE);\n if (e) events.push({ kind: \"end\", blockId: (e[1] ?? e[2])!, index: i });\n }\n return events;\n}\n\n/**\n * Logical lines of `raw` that sit OUTSIDE ``` / ~~~ code fences — for host\n * probes that must ignore quoted examples (e.g. the claude-code `@AGENTS.md`\n * import detection). Fence lines themselves are excluded.\n */\nexport function linesOutsideFences(raw: string): string[] {\n const body = raw.startsWith(\"\\uFEFF\") ? raw.slice(1) : raw;\n const logical = body.split(\"\\n\").map(stripCr);\n const out: string[] = [];\n let fence: { char: string; len: number } | null = null;\n for (const line of logical) {\n if (fence) {\n const close = line.match(/^ {0,3}(`{3,}|~{3,})\\s*$/);\n if (close && close[1]![0] === fence.char && close[1]!.length >= fence.len) fence = null;\n continue;\n }\n const open = line.match(/^ {0,3}(`{3,}|~{3,})/);\n if (open) {\n fence = { char: open[1]![0]!, len: open[1]!.length };\n continue;\n }\n out.push(line);\n }\n return out;\n}\n\ninterface BlockPair {\n blockId: string;\n begin: MarkerEvent;\n end: MarkerEvent;\n}\n\n/**\n * Pair markers per blockId: first begin, then the FIRST end at-or-after it.\n * A nested begin for the SAME id (inside an open pair) is treated as inner\n * content; unpaired markers are returned as strays. Per-id state means a\n * missing end for connector A can never swallow connector B's block.\n */\nfunction pairMarkers(events: MarkerEvent[]): { pairs: BlockPair[]; strays: MarkerEvent[] } {\n const open = new Map<string, MarkerEvent>();\n const pairs: BlockPair[] = [];\n const strays: MarkerEvent[] = [];\n for (const ev of events) {\n if (ev.kind === \"begin\") {\n if (!open.has(ev.blockId)) open.set(ev.blockId, ev);\n // else: a begin inside an open pair — inner content / abuse; the hash\n // check will flag the pair as drifted rather than guessing boundaries.\n } else {\n const b = open.get(ev.blockId);\n if (b) {\n pairs.push({ blockId: ev.blockId, begin: b, end: ev });\n open.delete(ev.blockId);\n } else {\n strays.push(ev);\n }\n }\n }\n for (const b of open.values()) strays.push(b);\n return { pairs, strays };\n}\n\n/** One discovered block (for doctor / refcount / uninstall enumeration). */\nexport interface ManagedBlockInfo {\n blockId: string;\n /** The hash recorded on the begin marker line. */\n recordedHash: string;\n /** Hash of the actual normalized inner region as found on disk. */\n actualHash: string;\n /** True when recordedHash ≠ actualHash — the user edited inside the block. */\n drifted: boolean;\n beginLine: number;\n endLine: number;\n}\n\n/** Enumerate every complete agent-connector block in `raw` (namespace scan). */\nexport function listManagedBlocks(raw: string): ManagedBlockInfo[] {\n const body = raw.startsWith(\"\\uFEFF\") ? raw.slice(1) : raw;\n const logical = body.split(\"\\n\").map(stripCr);\n const { pairs } = pairMarkers(scanMarkers(logical));\n return pairs.map((p) => {\n const inner = logical.slice(p.begin.index + 1, p.end.index).join(\"\\n\");\n const actualHash = hashBlockContent(inner);\n const recordedHash = p.begin.hash ?? \"\";\n return {\n blockId: p.blockId,\n recordedHash,\n actualHash,\n drifted: recordedHash !== actualHash,\n beginLine: p.begin.index,\n endLine: p.end.index,\n };\n });\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Pure text upsert / removal\n// ─────────────────────────────────────────────────────────────────────────\n\nexport interface UpsertBlockOptions extends RenderBlockOptions {\n /** Overwrite a USER-EDITED (drifted) block. Default false → warn + leave intact. */\n force?: boolean;\n}\n\nexport interface BlockTextResult {\n /** Resulting full text (=== input when nothing changed). */\n text: string;\n action: \"create\" | \"update\" | \"skip\" | \"warn\";\n detail: string;\n changed: boolean;\n /**\n * True when the rewrite was DESTRUCTIVE-ADJACENT (force-overwrote a drifted\n * block, collapsed duplicate pairs, or stripped stray markers) — the file\n * wrapper writes a timestamped backup before persisting such a change.\n */\n recovered: boolean;\n /** Hash of the (new) rendered inner region — recorded in the ledger. */\n hash: string;\n}\n\n/** Detect the file's dominant EOL; new/replaced lines are emitted with it. */\nfunction detectEol(body: string): \"\\n\" | \"\\r\\n\" {\n const crlf = (body.match(/\\r\\n/g) ?? []).length;\n const total = (body.match(/\\n/g) ?? []).length;\n return crlf > 0 && crlf >= total - crlf ? \"\\r\\n\" : \"\\n\";\n}\n\n/** Add `\\r` to logical lines when the file is CRLF (joined with \"\\n\" later). */\nfunction withEol(lines: string[], eol: \"\\n\" | \"\\r\\n\"): string[] {\n return eol === \"\\r\\n\" ? lines.map((l) => `${l}\\r`) : lines;\n}\n\n/**\n * Strip trailing newline(s) + whitespace-only line tails WITHOUT touching\n * trailing spaces on the last content line (bytes outside our block).\n */\nfunction trimTrailingBlank(body: string): string {\n let out = body;\n for (;;) {\n const m = out.match(/\\r?\\n[ \\t]*$/);\n if (!m) return out;\n out = out.slice(0, out.length - m[0].length);\n }\n}\n\n/** Append the rendered block at EOF with exactly ONE blank separator line. */\nfunction appendBlock(body: string, blockLines: string[], eol: \"\\n\" | \"\\r\\n\"): string {\n const blockText = blockLines.join(eol) + eol;\n if (body.trim() === \"\") return blockText;\n return trimTrailingBlank(body) + eol + eol + blockText;\n}\n\n/**\n * Idempotent upsert of one managed block into `raw` (pure; no I/O).\n * See the module header for the full algorithm contract.\n */\nexport function upsertBlockInText(raw: string, opts: UpsertBlockOptions): BlockTextResult {\n const bom = raw.startsWith(\"\\uFEFF\");\n const body = bom ? raw.slice(1) : raw;\n const eol = detectEol(body);\n const lines = body.split(\"\\n\"); // elements keep a trailing \"\\r\" on CRLF files\n const logical = lines.map(stripCr);\n\n const events = scanMarkers(logical).filter((e) => e.blockId === opts.blockId);\n const { pairs, strays } = pairMarkers(events);\n\n const newLines = renderBlockLines(opts);\n const newHash = hashBlockContent(newLines.slice(1, -1).join(\"\\n\"));\n const finish = (text: string, r: Omit<BlockTextResult, \"text\" | \"hash\">): BlockTextResult => ({\n text: bom ? `\\uFEFF${text}` : text,\n hash: newHash,\n ...r,\n });\n\n if (pairs.length > 0) {\n const { begin, end } = pairs[0]!;\n const recorded = begin.hash ?? \"\";\n const actualHash = hashBlockContent(logical.slice(begin.index + 1, end.index).join(\"\\n\"));\n const drifted = actualHash !== recorded;\n\n if (drifted && !opts.force) {\n return finish(body, {\n action: \"warn\",\n detail:\n `block ${opts.blockId} was edited inside the markers ` +\n `(recorded hash ${recorded}, found ${actualHash}); left untouched — ` +\n `re-run with --force to overwrite the in-block edits`,\n changed: false,\n recovered: false,\n });\n }\n\n const duplicates = pairs.slice(1);\n const needsWrite =\n drifted || recorded !== newHash || duplicates.length > 0 || strays.length > 0;\n if (!needsWrite) {\n return finish(body, {\n action: \"skip\",\n detail: `block ${opts.blockId} already up to date (hash ${newHash})`,\n changed: false,\n recovered: false,\n });\n }\n\n // Build the deletion set: the canonical pair region (replaced in place),\n // duplicate pairs (+ ONE adjacent blank line each), and stray marker LINES.\n const del = new Set<number>();\n for (let i = begin.index; i <= end.index; i++) del.add(i);\n for (const dup of duplicates) {\n for (let i = dup.begin.index; i <= dup.end.index; i++) del.add(i);\n reclaimBlankLine(logical, dup.begin.index, dup.end.index, del, lines.length);\n }\n for (const s of strays) del.add(s.index);\n\n const out: string[] = [];\n for (let i = 0; i < lines.length; i++) {\n if (i === begin.index) out.push(...withEol(newLines, eol));\n if (!del.has(i)) out.push(lines[i]!);\n }\n const notes: string[] = [];\n if (drifted) notes.push(\"in-block edits overwritten (--force; backup taken)\");\n if (duplicates.length > 0) notes.push(`${duplicates.length} duplicate pair(s) collapsed`);\n if (strays.length > 0) notes.push(`${strays.length} stray marker line(s) removed`);\n return finish(out.join(\"\\n\"), {\n action: \"update\",\n detail:\n `block ${opts.blockId} updated (hash ${recorded || \"?\"} → ${newHash})` +\n (notes.length > 0 ? `; ${notes.join(\"; \")}` : \"\"),\n changed: true,\n recovered: drifted || duplicates.length > 0 || strays.length > 0,\n });\n }\n\n if (strays.length > 0) {\n // Corruption recovery: strip ONLY the stray marker line(s) (never the text\n // between guessed boundaries), then proceed as not-found.\n const del = new Set(strays.map((s) => s.index));\n const cleaned = lines.filter((_, i) => !del.has(i)).join(\"\\n\");\n return finish(appendBlock(cleaned, newLines, eol), {\n action: \"create\",\n detail:\n `block ${opts.blockId} appended after recovery: ${strays.length} stray ` +\n `marker line(s) removed (backup taken)`,\n changed: true,\n recovered: true,\n });\n }\n\n // Not found → append at EOF (one blank separator; whole file when empty).\n return finish(appendBlock(body, newLines, eol), {\n action: \"create\",\n detail: `block ${opts.blockId} appended (hash ${newHash})`,\n changed: true,\n recovered: false,\n });\n}\n\n/**\n * Mark ONE blank line adjacent to a removed begin..end region for deletion\n * (prefer the line before; never the post-final-newline \"\" sentinel).\n */\nfunction reclaimBlankLine(\n logical: string[],\n beginIdx: number,\n endIdx: number,\n del: Set<number>,\n lineCount: number,\n): void {\n const before = beginIdx - 1;\n if (before >= 0 && !del.has(before) && logical[before]!.trim() === \"\") {\n del.add(before);\n return;\n }\n const after = endIdx + 1;\n // The final \"\" element of split(\"\\n\") on a newline-terminated file is the\n // trailing-newline sentinel, not a blank line — leave it alone.\n const isSentinel = after === lineCount - 1 && logical[after] === \"\";\n if (after < lineCount && !isSentinel && !del.has(after) && logical[after]!.trim() === \"\") {\n del.add(after);\n }\n}\n\nexport interface RemoveBlocksOptions {\n /** Remove the block with EXACTLY this id… */\n blockId?: string;\n /** …or every block whose id starts with this prefix (e.g. `<connectorId>/`). */\n blockIdPrefix?: string;\n}\n\nexport interface RemoveRecord {\n blockId: string;\n action: \"remove\" | \"warn\";\n detail: string;\n}\n\nexport interface RemoveBlocksResult {\n text: string;\n changed: boolean;\n records: RemoveRecord[];\n /** True when the remaining text is whitespace-only (file-deletion candidate). */\n fileNowEmpty: boolean;\n /** True when a drifted block was removed or stray markers were stripped. */\n recovered: boolean;\n}\n\n/**\n * Remove every matching managed block (begin..end inclusive + at most ONE\n * adjacent blank separator line — no blank-line accumulation across cycles).\n * Drifted blocks are removed WITH a warn (uninstall intent is explicit; the\n * file wrapper backs the file up first). Stray matching markers are stripped\n * line-only with a warn. Pure; no I/O.\n */\nexport function removeBlocksFromText(raw: string, match: RemoveBlocksOptions): RemoveBlocksResult {\n const bom = raw.startsWith(\"\\uFEFF\");\n const body = bom ? raw.slice(1) : raw;\n const lines = body.split(\"\\n\");\n const logical = lines.map(stripCr);\n\n const matches = (id: string): boolean =>\n (match.blockId !== undefined && id === match.blockId) ||\n (match.blockIdPrefix !== undefined && id.startsWith(match.blockIdPrefix));\n\n const { pairs, strays } = pairMarkers(scanMarkers(logical));\n const targetPairs = pairs.filter((p) => matches(p.blockId));\n const targetStrays = strays.filter((s) => matches(s.blockId));\n\n if (targetPairs.length === 0 && targetStrays.length === 0) {\n return { text: raw, changed: false, records: [], fileNowEmpty: false, recovered: false };\n }\n\n const del = new Set<number>();\n const records: RemoveRecord[] = [];\n let recovered = false;\n\n for (const p of targetPairs) {\n const recorded = p.begin.hash ?? \"\";\n const actualHash = hashBlockContent(\n logical.slice(p.begin.index + 1, p.end.index).join(\"\\n\"),\n );\n for (let i = p.begin.index; i <= p.end.index; i++) del.add(i);\n reclaimBlankLine(logical, p.begin.index, p.end.index, del, lines.length);\n if (actualHash !== recorded) {\n recovered = true;\n records.push({\n blockId: p.blockId,\n action: \"warn\",\n detail:\n `block ${p.blockId} had in-block edits (recorded hash ${recorded}, found ` +\n `${actualHash}); removed anyway (backup taken)`,\n });\n }\n records.push({ blockId: p.blockId, action: \"remove\", detail: `block ${p.blockId} removed` });\n }\n for (const s of targetStrays) {\n del.add(s.index);\n recovered = true;\n records.push({\n blockId: s.blockId,\n action: \"warn\",\n detail: `stray ${s.kind} marker for ${s.blockId} removed (marker line only)`,\n });\n }\n\n const text = lines.filter((_, i) => !del.has(i)).join(\"\\n\");\n return {\n text: bom ? `\\uFEFF${text}` : text,\n changed: true,\n records,\n fileNowEmpty: text.trim() === \"\",\n recovered,\n };\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// File-level wrappers (atomic write, backups, dry-run)\n// ─────────────────────────────────────────────────────────────────────────\n\nexport interface BlockFileChange {\n action: \"create\" | \"update\" | \"skip\" | \"warn\" | \"remove\";\n path: string;\n detail: string;\n /** True when the FILE did not exist and this upsert created it (ledger fact). */\n createdFile: boolean;\n /** Set when a pre-mutation backup was written (destructive/recovery paths only). */\n backupPath?: string;\n /** Hash of the rendered inner region (ledger / doctor). */\n hash: string;\n}\n\n/** Timestamped copy into backupsDir(); best-effort (null on failure). */\nfunction backupFile(path: string): string | null {\n try {\n ensureDir(backupsDir());\n const stamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n const dest = join(backupsDir(), `memory-${stamp}-${basename(path)}`);\n copyFileSync(path, dest);\n return dest;\n } catch {\n return null;\n }\n}\n\n/**\n * Atomic write: temp file in the SAME directory + rename, preserving the\n * destination's mode. Shrinks (does not eliminate) the read-modify-write race\n * with hosts that append to memory files mid-session (Claude `#` quick-memory).\n */\nfunction atomicWriteFile(path: string, text: string): void {\n const dir = dirname(path);\n ensureDir(dir);\n const tmp = join(dir, `.${basename(path)}.ac-tmp-${process.pid}-${Date.now()}`);\n try {\n writeFileSync(tmp, text, \"utf8\");\n try {\n chmodSync(tmp, statSync(path).mode);\n } catch {\n /* destination absent — default mode is fine */\n }\n renameSync(tmp, path);\n } catch (err) {\n rmSync(tmp, { force: true });\n throw err;\n }\n}\n\n/**\n * Upsert one managed block into the file at `path` (created when absent).\n * Re-reads immediately before computing+writing; honors dryRun (the action is\n * computed and reported, nothing is written).\n */\nexport function upsertManagedBlockFile(\n path: string,\n opts: UpsertBlockOptions & { dryRun: boolean },\n): BlockFileChange {\n let raw: string | null = null;\n if (existsSync(path)) {\n try {\n raw = readFileSync(path, \"utf8\");\n } catch {\n return {\n action: \"warn\",\n path,\n detail: `cannot read ${path}; memory block ${opts.blockId} not written`,\n createdFile: false,\n hash: \"\",\n };\n }\n }\n\n if (raw === null) {\n const lines = renderBlockLines(opts);\n const hash = hashBlockContent(lines.slice(1, -1).join(\"\\n\"));\n if (!opts.dryRun) atomicWriteFile(path, `${lines.join(\"\\n\")}\\n`);\n return {\n action: \"create\",\n path,\n detail: `created ${basename(path)} with block ${opts.blockId} (hash ${hash})`,\n createdFile: true,\n hash,\n };\n }\n\n const res = upsertBlockInText(raw, opts);\n const change: BlockFileChange = {\n action: res.action,\n path,\n detail: res.detail,\n createdFile: false,\n hash: res.hash,\n };\n if (res.changed && !opts.dryRun) {\n if (res.recovered) {\n const backup = backupFile(path);\n if (backup) change.backupPath = backup;\n }\n atomicWriteFile(path, res.text);\n }\n return change;\n}\n\n/**\n * Remove every matching managed block from the file at `path`. Missing file or\n * no matching markers → a single idempotent \"skip\". When the remaining content\n * is whitespace-only AND `deleteFileIfCreated` is true (the ledger recorded\n * that agent-connector created this file), the file itself is deleted (Ruler\n * revert semantics: delete only what we created).\n */\nexport function removeManagedBlocksFile(\n path: string,\n match: RemoveBlocksOptions,\n opts: { dryRun: boolean; deleteFileIfCreated?: boolean },\n): BlockFileChange[] {\n if (!existsSync(path)) {\n return [\n {\n action: \"skip\",\n path,\n detail: `${basename(path)} absent; nothing to remove`,\n createdFile: false,\n hash: \"\",\n },\n ];\n }\n let raw: string;\n try {\n raw = readFileSync(path, \"utf8\");\n } catch {\n return [\n {\n action: \"warn\",\n path,\n detail: `cannot read ${path}; managed blocks left in place`,\n createdFile: false,\n hash: \"\",\n },\n ];\n }\n\n const res = removeBlocksFromText(raw, match);\n if (!res.changed) {\n return [\n {\n action: \"skip\",\n path,\n detail: `no agent-connector blocks matching ${match.blockId ?? match.blockIdPrefix ?? \"?\"} in ${basename(path)}`,\n createdFile: false,\n hash: \"\",\n },\n ];\n }\n\n const changes: BlockFileChange[] = [];\n let backupPath: string | undefined;\n if (!opts.dryRun) {\n if (res.recovered) backupPath = backupFile(path) ?? undefined;\n if (res.fileNowEmpty && opts.deleteFileIfCreated) {\n rmSync(path, { force: true });\n } else {\n atomicWriteFile(path, res.text);\n }\n }\n for (const r of res.records) {\n changes.push({\n action: r.action,\n path,\n detail: r.detail,\n createdFile: false,\n hash: \"\",\n ...(backupPath && r.action === \"warn\" ? { backupPath } : {}),\n });\n }\n if (res.fileNowEmpty && opts.deleteFileIfCreated) {\n changes.push({\n action: \"remove\",\n path,\n detail: `${basename(path)} deleted (agent-connector created it; only whitespace remained)`,\n createdFile: false,\n hash: \"\",\n });\n }\n return changes;\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Memory ownership ledger — connectorDir(id)/memory-state.json\n// ─────────────────────────────────────────────────────────────────────────\n\nexport interface MemoryLedgerTarget {\n platform: string;\n scope: string;\n path: string;\n blockId: string;\n /** True when agent-connector CREATED the file (grants deletion rights). */\n createdFile: boolean;\n /** Inner-region hash we last wrote (doctor drift detection). */\n hash: string;\n}\n\nexport interface MemoryLedger {\n version: 1;\n targets: MemoryLedgerTarget[];\n}\n\nexport function memoryLedgerPath(connectorId: string): string {\n return join(connectorDir(connectorId), \"memory-state.json\");\n}\n\nexport function loadMemoryLedger(connectorId: string): MemoryLedger {\n const p = memoryLedgerPath(connectorId);\n if (!existsSync(p)) return { version: 1, targets: [] };\n try {\n const parsed = JSON.parse(readFileSync(p, \"utf8\")) as MemoryLedger;\n if (parsed && Array.isArray(parsed.targets)) return { version: 1, targets: parsed.targets };\n } catch {\n /* corrupt → fresh ledger; the markers remain the source of truth */\n }\n return { version: 1, targets: [] };\n}\n\n/** Persist the ledger; an EMPTY ledger deletes the file (no orphan state). */\nexport function saveMemoryLedger(connectorId: string, ledger: MemoryLedger): void {\n const p = memoryLedgerPath(connectorId);\n if (ledger.targets.length === 0) {\n rmSync(p, { force: true });\n return;\n }\n ensureDir(dirname(p));\n writeFileSync(p, `${JSON.stringify(ledger, null, 2)}\\n`, \"utf8\");\n}\n\n/** True when the connector has any recorded memory targets (uninstall guard). */\nexport function hasMemoryLedger(connectorId: string): boolean {\n return loadMemoryLedger(connectorId).targets.length > 0;\n}\n\n/**\n * Upsert one ledger row (keyed by platform+scope+path+blockId). The\n * `createdFile` fact is STICKY: once we created the file, deletion rights\n * survive later syncs that found it present.\n */\nexport function recordMemoryTarget(ledger: MemoryLedger, t: MemoryLedgerTarget): void {\n const i = ledger.targets.findIndex(\n (x) =>\n x.platform === t.platform &&\n x.scope === t.scope &&\n x.path === t.path &&\n x.blockId === t.blockId,\n );\n if (i >= 0) {\n ledger.targets[i] = { ...t, createdFile: ledger.targets[i]!.createdFile || t.createdFile };\n } else {\n ledger.targets.push(t);\n }\n}\n"],"mappings":"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","names":[]}
|