@ken-jo/agent-connector 0.1.0 → 0.3.0

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.
Files changed (174) hide show
  1. package/README.md +183 -24
  2. package/dist/{amp-QSFH2V7Y.js → amp-YGV66GJT.js} +9 -2
  3. package/dist/amp-YGV66GJT.js.map +1 -0
  4. package/dist/{antigravity-CX2YLSY7.js → antigravity-7IBYFO6P.js} +4 -3
  5. package/dist/{antigravity-cli-YQDFVV4U.js → antigravity-cli-JEOUP2VN.js} +4 -3
  6. package/dist/{antigravity-cli-YQDFVV4U.js.map → antigravity-cli-JEOUP2VN.js.map} +1 -1
  7. package/dist/{chunk-LTT56GI3.js → chunk-3JCRUROU.js} +18 -5
  8. package/dist/chunk-3JCRUROU.js.map +1 -0
  9. package/dist/chunk-44HUXXC6.js +284 -0
  10. package/dist/chunk-44HUXXC6.js.map +1 -0
  11. package/dist/{chunk-54EMKTTX.js → chunk-DS3LUFVN.js} +21 -21
  12. package/dist/chunk-DS3LUFVN.js.map +1 -0
  13. package/dist/chunk-GSGDG2BV.js +568 -0
  14. package/dist/chunk-GSGDG2BV.js.map +1 -0
  15. package/dist/{chunk-TRKWUNO4.js → chunk-KQSNDFBN.js} +13 -2
  16. package/dist/chunk-KQSNDFBN.js.map +1 -0
  17. package/dist/{chunk-KHO5WNTP.js → chunk-KVAAFYRR.js} +18 -2
  18. package/dist/chunk-KVAAFYRR.js.map +1 -0
  19. package/dist/chunk-N6HH7K6P.js +494 -0
  20. package/dist/chunk-N6HH7K6P.js.map +1 -0
  21. package/dist/{chunk-XUCWLJY5.js → chunk-NJU275US.js} +30 -30
  22. package/dist/{chunk-WCETQWWK.js → chunk-OP4KBXUO.js} +1 -17
  23. package/dist/chunk-OP4KBXUO.js.map +1 -0
  24. package/dist/{chunk-TIIP3RG2.js → chunk-PD4VFEBY.js} +342 -2
  25. package/dist/chunk-PD4VFEBY.js.map +1 -0
  26. package/dist/chunk-QADSG2JY.js +1989 -0
  27. package/dist/chunk-QADSG2JY.js.map +1 -0
  28. package/dist/{chunk-WV63X7IK.js → chunk-SCVBYSF7.js} +2 -2
  29. package/dist/chunk-SCVBYSF7.js.map +1 -0
  30. package/dist/{package-DLOVE2E4.js → chunk-WNREHWKL.js} +26 -115
  31. package/dist/chunk-WNREHWKL.js.map +1 -0
  32. package/dist/{chunk-YNZU6PAV.js → chunk-ZAM4M7LI.js} +74 -21
  33. package/dist/chunk-ZAM4M7LI.js.map +1 -0
  34. package/dist/claude-code-4275HQU4.js +1432 -0
  35. package/dist/claude-code-4275HQU4.js.map +1 -0
  36. package/dist/cli/sdk.js +4 -3
  37. package/dist/cli/sdk.js.map +1 -1
  38. package/dist/cli.js +1 -1
  39. package/dist/{codebuff-QX57FJDN.js → codebuff-LE3KBZGM.js} +9 -2
  40. package/dist/codebuff-LE3KBZGM.js.map +1 -0
  41. package/dist/{codex-JFQTS6LU.js → codex-4BY2ZJIW.js} +148 -7
  42. package/dist/codex-4BY2ZJIW.js.map +1 -0
  43. package/dist/{copilot-cli-MTCGHZ2T.js → copilot-cli-IPISKO3V.js} +109 -2
  44. package/dist/copilot-cli-IPISKO3V.js.map +1 -0
  45. package/dist/{crush-I7PK3FGI.js → crush-X3E25EQG.js} +31 -3
  46. package/dist/crush-X3E25EQG.js.map +1 -0
  47. package/dist/{cursor-4TMXKJOZ.js → cursor-UH3W622V.js} +66 -5
  48. package/dist/cursor-UH3W622V.js.map +1 -0
  49. package/dist/{detect-WIAGVYS4.js → detect-MNDHGLSV.js} +7 -3
  50. package/dist/detect-MNDHGLSV.js.map +1 -0
  51. package/dist/{doctor-EZW2K4NI.js → doctor-N5KZDD55.js} +45 -7
  52. package/dist/doctor-N5KZDD55.js.map +1 -0
  53. package/dist/{droid-KN6VRMMT.js → droid-T5VBRXZF.js} +32 -3
  54. package/dist/droid-T5VBRXZF.js.map +1 -0
  55. package/dist/{gemini-cli-Y35FFK4M.js → gemini-cli-ZSUK55UA.js} +51 -3
  56. package/dist/gemini-cli-ZSUK55UA.js.map +1 -0
  57. package/dist/{goose-ZTGTSUFJ.js → goose-M3RR3CZG.js} +63 -4
  58. package/dist/goose-M3RR3CZG.js.map +1 -0
  59. package/dist/{hermes-H2KV44GK.js → hermes-CUNKIAR5.js} +76 -3
  60. package/dist/hermes-CUNKIAR5.js.map +1 -0
  61. package/dist/{hook-YVDILAMZ.js → hook-7LUOKIXH.js} +28 -13
  62. package/dist/hook-7LUOKIXH.js.map +1 -0
  63. package/dist/index.d.ts +2 -2
  64. package/dist/index.js +3 -1
  65. package/dist/install-TQTT4F3I.js +89 -0
  66. package/dist/install-TQTT4F3I.js.map +1 -0
  67. package/dist/{jetbrains-copilot-HWA3DMH7.js → jetbrains-copilot-C3HDGGML.js} +16 -2
  68. package/dist/jetbrains-copilot-C3HDGGML.js.map +1 -0
  69. package/dist/kilo-PKAJCWPX.js +852 -0
  70. package/dist/kilo-PKAJCWPX.js.map +1 -0
  71. package/dist/{kilo-cli-EAQTHXUW.js → kilo-cli-QWUVXG2O.js} +186 -7
  72. package/dist/kilo-cli-QWUVXG2O.js.map +1 -0
  73. package/dist/{kimi-GQ7VXNYT.js → kimi-EVD7YKXS.js} +167 -9
  74. package/dist/kimi-EVD7YKXS.js.map +1 -0
  75. package/dist/{kiro-VQTT6LO2.js → kiro-UQRY6EIO.js} +98 -4
  76. package/dist/kiro-UQRY6EIO.js.map +1 -0
  77. package/dist/{leaderboard-K6ON3SWW.js → leaderboard-MUJ7DURM.js} +3 -3
  78. package/dist/{mux-T2TV4CIQ.js → mux-5CI5FP2W.js} +9 -2
  79. package/dist/mux-5CI5FP2W.js.map +1 -0
  80. package/dist/{omp-PB4VDKS6.js → omp-AXA7XY22.js} +13 -2
  81. package/dist/omp-AXA7XY22.js.map +1 -0
  82. package/dist/{openclaw-ETN2M63O.js → openclaw-UZ5BMCGQ.js} +101 -4
  83. package/dist/openclaw-UZ5BMCGQ.js.map +1 -0
  84. package/dist/{opencode-FZ33JKUZ.js → opencode-NZBRLJN3.js} +53 -7
  85. package/dist/opencode-NZBRLJN3.js.map +1 -0
  86. package/dist/package-SYPA5POO.js +130 -0
  87. package/dist/package-SYPA5POO.js.map +1 -0
  88. package/dist/{pi-CIU2QHT4.js → pi-WMTUX6ES.js} +106 -23
  89. package/dist/pi-WMTUX6ES.js.map +1 -0
  90. package/dist/{qwen-code-5POCNU6P.js → qwen-code-MRRIUQ3P.js} +187 -6
  91. package/dist/qwen-code-MRRIUQ3P.js.map +1 -0
  92. package/dist/{roo-code-IOIUXRDE.js → roo-code-NI5UU6JB.js} +26 -2
  93. package/dist/roo-code-NI5UU6JB.js.map +1 -0
  94. package/dist/runtime/index.d.ts +38 -4
  95. package/dist/runtime/index.js +11 -6
  96. package/dist/{serve-HVWWY4B6.js → serve-XJOSA7BY.js} +9 -8
  97. package/dist/{serve-HVWWY4B6.js.map → serve-XJOSA7BY.js.map} +1 -1
  98. package/dist/{status-FE7TECZD.js → status-DYSS6BOR.js} +19 -9
  99. package/dist/status-DYSS6BOR.js.map +1 -0
  100. package/dist/{telemetry-36GESKQQ.js → telemetry-IJ4GP2Q3.js} +5 -4
  101. package/dist/{telemetry-36GESKQQ.js.map → telemetry-IJ4GP2Q3.js.map} +1 -1
  102. package/dist/{trae-JSNDZFKL.js → trae-CQC72RHH.js} +9 -2
  103. package/dist/trae-CQC72RHH.js.map +1 -0
  104. package/dist/types-CNigfEuR.d.ts +757 -0
  105. package/dist/uninstall-3DXIBRCV.js +162 -0
  106. package/dist/uninstall-3DXIBRCV.js.map +1 -0
  107. package/dist/{upgrade-JV2VK242.js → upgrade-GJEB3ITY.js} +29 -10
  108. package/dist/upgrade-GJEB3ITY.js.map +1 -0
  109. package/dist/{usage-6ER6EMEY.js → usage-2BJLM3GJ.js} +3 -3
  110. package/dist/{usage-event-JKBI6XCF.js → usage-event-472X3DOY.js} +8 -7
  111. package/dist/{usage-event-JKBI6XCF.js.map → usage-event-472X3DOY.js.map} +1 -1
  112. package/dist/{vscode-copilot-CK3NO54M.js → vscode-copilot-4RVRTCKV.js} +53 -4
  113. package/dist/vscode-copilot-4RVRTCKV.js.map +1 -0
  114. package/dist/{warp-QNVDXOG4.js → warp-X6MB67NT.js} +110 -4
  115. package/dist/warp-X6MB67NT.js.map +1 -0
  116. package/dist/{zed-VRJKWYUR.js → zed-NTCYW4V2.js} +120 -5
  117. package/dist/zed-NTCYW4V2.js.map +1 -0
  118. package/package.json +4 -3
  119. package/dist/amp-QSFH2V7Y.js.map +0 -1
  120. package/dist/chunk-54EMKTTX.js.map +0 -1
  121. package/dist/chunk-7MSDGHJW.js +0 -316
  122. package/dist/chunk-7MSDGHJW.js.map +0 -1
  123. package/dist/chunk-KHO5WNTP.js.map +0 -1
  124. package/dist/chunk-LTT56GI3.js.map +0 -1
  125. package/dist/chunk-TIIP3RG2.js.map +0 -1
  126. package/dist/chunk-TRKWUNO4.js.map +0 -1
  127. package/dist/chunk-WCETQWWK.js.map +0 -1
  128. package/dist/chunk-WV63X7IK.js.map +0 -1
  129. package/dist/chunk-XNAM7F35.js +0 -276
  130. package/dist/chunk-XNAM7F35.js.map +0 -1
  131. package/dist/chunk-YNZU6PAV.js.map +0 -1
  132. package/dist/claude-code-HKDV7T32.js +0 -637
  133. package/dist/claude-code-HKDV7T32.js.map +0 -1
  134. package/dist/codebuff-QX57FJDN.js.map +0 -1
  135. package/dist/codex-JFQTS6LU.js.map +0 -1
  136. package/dist/copilot-cli-MTCGHZ2T.js.map +0 -1
  137. package/dist/crush-I7PK3FGI.js.map +0 -1
  138. package/dist/cursor-4TMXKJOZ.js.map +0 -1
  139. package/dist/detect-WIAGVYS4.js.map +0 -1
  140. package/dist/doctor-EZW2K4NI.js.map +0 -1
  141. package/dist/droid-KN6VRMMT.js.map +0 -1
  142. package/dist/gemini-cli-Y35FFK4M.js.map +0 -1
  143. package/dist/goose-ZTGTSUFJ.js.map +0 -1
  144. package/dist/hermes-H2KV44GK.js.map +0 -1
  145. package/dist/hook-YVDILAMZ.js.map +0 -1
  146. package/dist/install-HQRYZOQ2.js +0 -60
  147. package/dist/install-HQRYZOQ2.js.map +0 -1
  148. package/dist/jetbrains-copilot-HWA3DMH7.js.map +0 -1
  149. package/dist/kilo-QXJRCSLT.js +0 -384
  150. package/dist/kilo-QXJRCSLT.js.map +0 -1
  151. package/dist/kilo-cli-EAQTHXUW.js.map +0 -1
  152. package/dist/kimi-GQ7VXNYT.js.map +0 -1
  153. package/dist/kiro-VQTT6LO2.js.map +0 -1
  154. package/dist/mux-T2TV4CIQ.js.map +0 -1
  155. package/dist/omp-PB4VDKS6.js.map +0 -1
  156. package/dist/openclaw-ETN2M63O.js.map +0 -1
  157. package/dist/opencode-FZ33JKUZ.js.map +0 -1
  158. package/dist/package-DLOVE2E4.js.map +0 -1
  159. package/dist/pi-CIU2QHT4.js.map +0 -1
  160. package/dist/qwen-code-5POCNU6P.js.map +0 -1
  161. package/dist/roo-code-IOIUXRDE.js.map +0 -1
  162. package/dist/status-FE7TECZD.js.map +0 -1
  163. package/dist/trae-JSNDZFKL.js.map +0 -1
  164. package/dist/types-CYUB1OTr.d.ts +0 -427
  165. package/dist/uninstall-IGCKNOSF.js +0 -72
  166. package/dist/uninstall-IGCKNOSF.js.map +0 -1
  167. package/dist/upgrade-JV2VK242.js.map +0 -1
  168. package/dist/vscode-copilot-CK3NO54M.js.map +0 -1
  169. package/dist/warp-QNVDXOG4.js.map +0 -1
  170. package/dist/zed-VRJKWYUR.js.map +0 -1
  171. /package/dist/{antigravity-CX2YLSY7.js.map → antigravity-7IBYFO6P.js.map} +0 -0
  172. /package/dist/{chunk-XUCWLJY5.js.map → chunk-NJU275US.js.map} +0 -0
  173. /package/dist/{leaderboard-K6ON3SWW.js.map → leaderboard-MUJ7DURM.js.map} +0 -0
  174. /package/dist/{usage-6ER6EMEY.js.map → usage-2BJLM3GJ.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli/commands/doctor.ts","../src/runtime/probe.ts"],"sourcesContent":["/**\n * cli/commands/doctor — health-check every detected platform.\n *\n * For each detected host (or the explicit --targets list) we load its adapter,\n * build a uniform InstallContext, and run adapter.doctor(ctx). Results are\n * printed as pass/warn/fail with any suggested fix. Exit code is non-zero when\n * any check fails (warns alone do not fail the command).\n *\n * The connector context comes from the local config when present; otherwise a\n * minimal id-only connector is used so path-only checks still run.\n */\n\nimport { parseArgs } from \"node:util\";\n\nimport type {\n DiagnosticResult,\n InstallScope,\n PlatformId,\n ResolvedConnector,\n} from \"../../core/types.js\";\nimport type { InstallContext } from \"../../adapters/spi.js\";\nimport { detectInstalledPlatforms } from \"../../adapters/detect.js\";\nimport { loadAdapter, REGISTERED_PLATFORM_IDS } from \"../../adapters/registry.js\";\nimport {\n findConnectorConfig,\n listRegisteredConnectors,\n loadConnectorFromPath,\n} from \"../../core/load-connector.js\";\nimport { dataRoot, homeBinPath } from \"../../core/paths.js\";\nimport { probeStdioServer } from \"../../runtime/probe.js\";\nimport { fail, parseScope, parseTargets, print } from \"../app.js\";\n\nconst STATUS_GLYPH: Record<DiagnosticResult[\"status\"], string> = {\n pass: \"[pass]\",\n warn: \"[warn]\",\n fail: \"[FAIL]\",\n};\n\n/**\n * Resolve which connector(s) doctor should health-check, in precedence order:\n * 1. An explicit --connector path, or a local agent-connector.config.* file.\n * 2. Every connector registered under the data-root (what is actually\n * installed). This is the common case — `doctor` from anywhere reports on\n * the real installs, not a guess from the working directory.\n * 3. A minimal id-only placeholder so path-only checks still run.\n */\nasync function resolveDoctorConnectors(\n connectorPath: string | undefined,\n projectDir: string,\n): Promise<ResolvedConnector[]> {\n const configPath = connectorPath ?? findConnectorConfig(projectDir);\n if (configPath) {\n try {\n const { connector } = await loadConnectorFromPath(configPath);\n return [connector];\n } catch {\n /* fall through */\n }\n }\n\n const registered = listRegisteredConnectors();\n if (registered.length > 0) return registered;\n\n return [\n {\n id: \"agent-connector\",\n displayName: \"agent-connector\",\n version: \"0.0.0\",\n hooks: {},\n hookEvents: [],\n telemetry: {\n enabled: true,\n modelFamilyHint: \"auto\",\n measureToolDefs: true,\n hostNativeUsage: false,\n store: \"ndjson\",\n calibration: { anthropicCountTokens: false },\n },\n commands: [],\n skills: [],\n subagents: [],\n platforms: {},\n targets: \"auto\",\n },\n ];\n}\n\nfunction buildContext(\n connector: ResolvedConnector,\n id: PlatformId,\n scope: InstallScope,\n projectDir: string,\n): InstallContext {\n return {\n connector,\n scope: connector.platforms[id]?.scope ?? scope,\n projectDir,\n homeBinPath: homeBinPath(),\n dataRoot: dataRoot(),\n dryRun: true,\n };\n}\n\nexport async function run(argv: string[]): Promise<number> {\n const { values } = parseArgs({\n args: argv,\n options: {\n scope: { type: \"string\", default: \"user\" },\n targets: { type: \"string\" },\n connector: { type: \"string\" },\n project: { type: \"string\" },\n json: { type: \"boolean\", default: false },\n probe: { type: \"boolean\", default: false },\n },\n allowPositionals: false,\n });\n\n const projectDir = values.project ?? process.cwd();\n\n const scope = parseScope(values.scope);\n if (scope == null) return fail(`invalid --scope \"${values.scope}\" (use user|project)`);\n\n const connectors = await resolveDoctorConnectors(values.connector, projectDir);\n const multi = connectors.length > 1;\n\n // Target set: explicit --targets (intersected with the registry) or all\n // detected installed platforms.\n const explicit = parseTargets(values.targets);\n let ids: PlatformId[];\n if (explicit && explicit.length > 0) {\n ids = explicit.filter((id) => REGISTERED_PLATFORM_IDS.has(id));\n } else {\n const detected = await detectInstalledPlatforms(projectDir);\n ids = detected.map((p) => p.id);\n }\n\n if (ids.length === 0 && !values.probe) {\n print(\"doctor: no target platforms (none detected; pass --targets to force).\");\n return 0;\n }\n\n const byPlatform: { platform: PlatformId; results: DiagnosticResult[] }[] = [];\n let anyFail = false;\n\n for (const id of ids) {\n const adapter = await loadAdapter(id);\n if (!adapter) {\n byPlatform.push({\n platform: id,\n results: [\n {\n check: `${id}: adapter`,\n status: \"fail\",\n message: `no adapter registered for ${id}`,\n },\n ],\n });\n anyFail = true;\n continue;\n }\n const results: DiagnosticResult[] = [];\n for (const connector of connectors) {\n const ctx = buildContext(connector, id, scope, projectDir);\n let r: DiagnosticResult[];\n try {\n r = adapter.doctor(ctx);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n r = [{ check: `${adapter.name}: doctor`, status: \"fail\", message }];\n }\n // When checking multiple connectors, tag each check with the connector id.\n results.push(\n ...(multi\n ? r.map((d) => ({ ...d, check: `(${connector.id}) ${d.check}` }))\n : r),\n );\n }\n if (results.some((d) => d.status === \"fail\")) anyFail = true;\n byPlatform.push({ platform: id, results });\n }\n\n // ── Live MCP probe (--probe): connector-scoped, not platform-scoped ──────\n // Spawns each connector's REAL stdio server and runs initialize → ping →\n // tools/list. Probe FAILs fold into the doctor exit code.\n const probes: { connector: string; results: DiagnosticResult[] }[] = [];\n if (values.probe) {\n for (const connector of connectors) {\n const s = connector.server;\n if (!s || s.transport !== \"stdio\" || !s.command) {\n probes.push({\n connector: connector.id,\n results: [\n {\n check: `${connector.id}: MCP probe`,\n status: \"warn\",\n message: s\n ? `transport \"${s.transport}\" is not stdio — live probe skipped`\n : \"no server to probe\",\n },\n ],\n });\n continue;\n }\n const results = await probeStdioServer(s.command, s.args ?? [], {\n label: connector.id,\n ...(s.env ? { env: s.env } : {}),\n });\n if (results.some((d) => d.status === \"fail\")) anyFail = true;\n probes.push({ connector: connector.id, results });\n }\n }\n\n if (values.json) {\n print(JSON.stringify(values.probe ? { platforms: byPlatform, probes } : byPlatform, null, 2));\n return anyFail ? 1 : 0;\n }\n\n for (const { platform, results } of byPlatform) {\n print(`${platform}:`);\n for (const r of results) {\n print(` ${STATUS_GLYPH[r.status]} ${r.check} — ${r.message}`);\n if (r.fix) print(` fix: ${r.fix}`);\n }\n print(\"\");\n }\n for (const { connector, results } of probes) {\n print(`probe ${connector}:`);\n for (const r of results) {\n print(` ${STATUS_GLYPH[r.status]} ${r.check} — ${r.message}`);\n if (r.fix) print(` fix: ${r.fix}`);\n }\n print(\"\");\n }\n print(anyFail ? \"doctor: one or more checks FAILED.\" : \"doctor: all checks passed.\");\n return anyFail ? 1 : 0;\n}\n","/**\n * runtime/probe — a live MCP connection-lifecycle probe for `doctor --probe`.\n *\n * Where `doctor` checks files on disk, this spawns the connector's REAL stdio\n * server and speaks the MCP wire protocol to it: initialize → (read negotiated\n * protocolVersion + capabilities + serverInfo) → notifications/initialized →\n * ping (liveness) → tools/list (gated on the tools capability). It reuses the\n * SAME newline-delimited JSON-RPC framing + id-correlation as the telemetry\n * proxy (telemetry/jsonrpc), so the probe and the serve path read the wire\n * identically. Each step becomes a DiagnosticResult so doctor renders/aggregates\n * it uniformly; a dead/unlaunchable server FAILs (non-zero doctor exit).\n *\n * Negotiation rule: we OFFER {@link MCP_PROTOCOL_VERSION} but ACCEPT whatever\n * version the server returns (we only report it), per the spec — never a\n * hardcoded equality. There is no MCP shutdown message; we close stdin then\n * SIGTERM/SIGKILL.\n */\n\nimport type { DiagnosticResult } from \"../core/types.js\";\nimport { MCP_PROTOCOL_VERSION } from \"../core/mcp-standard.js\";\nimport { spawnChild } from \"../core/spawn-child.js\";\nimport { type JsonRpcMessage, LineBuffer, idKey, isObject } from \"../telemetry/jsonrpc.js\";\n\nconst DEFAULT_TIMEOUT_MS = 5000;\n\nexport interface ProbeOptions {\n /** Per-step timeout in ms (default 5000). */\n timeoutMs?: number;\n /** Prefix for each DiagnosticResult.check (e.g. the connector id). */\n label?: string;\n /** Env merged over process.env for the spawned server (${env:VAR} resolved). */\n env?: Record<string, string>;\n /** Protocol version offered in initialize. Default {@link MCP_PROTOCOL_VERSION}. */\n protocolVersion?: string;\n}\n\nfunction diag(\n status: DiagnosticResult[\"status\"],\n check: string,\n message: string,\n fix?: string,\n): DiagnosticResult {\n return { check, status, message, ...(fix ? { fix } : {}) };\n}\n\nfunction errMsg(e: unknown): string {\n return e instanceof Error ? e.message : String(e);\n}\n\n/** Resolve `${env:VAR}` references in env values against the current process env. */\nfunction resolveEnv(env: Record<string, string> | undefined): Record<string, string> {\n const out: Record<string, string> = {};\n for (const [k, v] of Object.entries(env ?? {})) {\n out[k] = v.replace(/\\$\\{env:([A-Za-z_][A-Za-z0-9_]*)\\}/g, (_m, name) => process.env[name] ?? \"\");\n }\n return out;\n}\n\n/**\n * Spawn the stdio MCP server `command args` and run a real lifecycle probe.\n * Always resolves (never rejects) with one DiagnosticResult per step.\n */\nexport async function probeStdioServer(\n command: string,\n args: string[],\n opts: ProbeOptions = {},\n): Promise<DiagnosticResult[]> {\n const label = opts.label ? `${opts.label}: ` : \"\";\n const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const protocolVersion = opts.protocolVersion ?? MCP_PROTOCOL_VERSION;\n const results: DiagnosticResult[] = [];\n\n // spawnChild resolves a bare Windows package runner (npx/uvx → .cmd/.exe) so\n // the probe agrees with the live serve path; no-op on macOS/Linux.\n const child = spawnChild(command, args, {\n stdio: [\"pipe\", \"pipe\", \"inherit\"],\n env: { ...process.env, ...resolveEnv(opts.env) },\n });\n\n interface Pending {\n resolve: (m: JsonRpcMessage) => void;\n reject: (e: Error) => void;\n }\n const pending = new Map<string, Pending>();\n let spawnErr: Error | null = null;\n let exitCode: number | null = null;\n\n const rejectAll = (e: Error): void => {\n for (const p of pending.values()) p.reject(e);\n pending.clear();\n };\n child.on(\"error\", (e) => {\n spawnErr = e;\n rejectAll(e);\n });\n child.on(\"exit\", (code) => {\n exitCode = code ?? 0;\n rejectAll(new Error(`server exited (code ${exitCode}) before responding`));\n });\n\n const lines = new LineBuffer((line) => {\n let parsed: unknown;\n try {\n parsed = JSON.parse(line);\n } catch {\n return; // non-JSON stdout noise — ignore\n }\n if (!isObject(parsed)) return;\n const k = idKey((parsed as JsonRpcMessage).id);\n if (k && pending.has(k)) {\n const p = pending.get(k)!;\n pending.delete(k);\n p.resolve(parsed as JsonRpcMessage);\n }\n });\n child.stdout?.on(\"data\", (c: Buffer) => lines.push(c));\n\n const send = (m: JsonRpcMessage): void => {\n if (child.stdin && child.stdin.writable) child.stdin.write(`${JSON.stringify(m)}\\n`);\n };\n const request = (id: number | string, method: string, params?: unknown): Promise<JsonRpcMessage> => {\n const key = idKey(id)!;\n return new Promise<JsonRpcMessage>((resolve, reject) => {\n const timer = setTimeout(() => {\n pending.delete(key);\n reject(new Error(`no response within ${timeoutMs}ms`));\n }, timeoutMs);\n if (typeof timer.unref === \"function\") timer.unref();\n pending.set(key, {\n resolve: (m) => {\n clearTimeout(timer);\n resolve(m);\n },\n reject: (e) => {\n clearTimeout(timer);\n reject(e);\n },\n });\n send({ jsonrpc: \"2.0\", id, method, ...(params !== undefined ? { params } : {}) });\n });\n };\n\n const cleanup = (): DiagnosticResult[] => {\n try {\n if (child.stdin && child.stdin.writable) child.stdin.end();\n } catch {\n /* ignore */\n }\n try {\n child.kill(\"SIGTERM\");\n } catch {\n /* ignore */\n }\n const killTimer = setTimeout(() => {\n try {\n child.kill(\"SIGKILL\");\n } catch {\n /* ignore */\n }\n }, 500);\n if (typeof killTimer.unref === \"function\") killTimer.unref();\n return results;\n };\n\n // 1. initialize\n let initResult: Record<string, unknown>;\n try {\n const res = await request(1, \"initialize\", {\n protocolVersion,\n capabilities: {},\n clientInfo: { name: \"agent-connector-probe\", version: \"1\" },\n });\n if (isObject(res.error)) {\n results.push(\n diag(\"fail\", `${label}MCP initialize`, `server returned error: ${JSON.stringify(res.error)}`),\n );\n return cleanup();\n }\n initResult = isObject(res.result) ? res.result : {};\n } catch (e) {\n if (spawnErr) {\n results.push(\n diag(\n \"fail\",\n `${label}MCP initialize`,\n `server not launchable: ${errMsg(spawnErr)}`,\n `check that \"${command}\" is installed and on PATH`,\n ),\n );\n } else if (exitCode !== null) {\n // On Windows an unresolvable command surfaces as an early non-zero exit\n // (cmd.exe \"command not found\") rather than a spawn 'error' event, so fold\n // the not-launchable hint in here too — useful whether the command is\n // missing or the server genuinely crashed before initialize.\n results.push(\n diag(\n \"fail\",\n `${label}MCP initialize`,\n `server not launchable, or it exited (code ${exitCode}) before initialize`,\n `check that \"${command}\" is installed and on PATH`,\n ),\n );\n } else {\n results.push(diag(\"fail\", `${label}MCP initialize`, errMsg(e)));\n }\n return cleanup();\n }\n\n const serverInfo = isObject(initResult.serverInfo) ? initResult.serverInfo : {};\n const sName = typeof serverInfo.name === \"string\" ? serverInfo.name : \"unknown\";\n const sVer = typeof serverInfo.version === \"string\" ? serverInfo.version : \"?\";\n const negotiated =\n typeof initResult.protocolVersion === \"string\" ? initResult.protocolVersion : \"(none)\";\n results.push(diag(\"pass\", `${label}MCP initialize`, `serverInfo ${sName}@${sVer}, protocol ${negotiated}`));\n\n // capabilities (presence = feature offered)\n const caps = isObject(initResult.capabilities) ? initResult.capabilities : {};\n const capNames = [\"tools\", \"resources\", \"prompts\", \"logging\", \"completions\"].filter((c) => c in caps);\n results.push(\n diag(\"pass\", `${label}capabilities`, capNames.length > 0 ? capNames.join(\", \") : \"(none advertised)\"),\n );\n\n // 2. initialized notification (required before normal requests)\n send({ jsonrpc: \"2.0\", method: \"notifications/initialized\" });\n\n // 3. ping — liveness confirm (warn, not fail, on timeout)\n try {\n await request(\"probe-ping\", \"ping\");\n results.push(diag(\"pass\", `${label}ping`, \"alive\"));\n } catch (e) {\n results.push(diag(\"warn\", `${label}ping`, `no ping response (${errMsg(e)})`));\n }\n\n // 4. tools/list — only if the server advertised a tools capability\n if (\"tools\" in caps) {\n try {\n const res = await request(2, \"tools/list\", {});\n const r = isObject(res.result) ? res.result : {};\n const tools = Array.isArray(r.tools) ? r.tools : [];\n results.push(diag(\"pass\", `${label}tools/list`, `${tools.length} tool(s)`));\n } catch (e) {\n results.push(diag(\"fail\", `${label}tools/list`, `no tools/list response (${errMsg(e)})`));\n }\n } else {\n results.push(\n diag(\"warn\", `${label}tools/list`, \"skipped — server advertised no tools capability\"),\n );\n }\n\n return cleanup();\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/adapters/droid/index.ts"],"sourcesContent":["/**\n * adapters/droid — Droid (Factory AI) platform adapter for agent-connector.\n *\n * Droid is a **json-stdio** host with TWO native config surfaces that live in\n * DIFFERENT files (so getServerConfigPath ≠ getHookConfigPath):\n *\n * 1. MCP servers — `mcp.json` (root key `mcpServers`):\n * - user scope → ~/.factory/mcp.json\n * - project scope → <projectDir>/.factory/mcp.json\n * Native stdio entry shape: { type:\"stdio\", command, args, env, disabled };\n * a remote server registers a URL ({ type:\"http\", url, headers, disabled }).\n *\n * 2. Hooks — a SEPARATE `hooks.json` (root key `hooks`) under the same\n * `.factory` dir. Droid ships a FULL Claude-compatible lifecycle hook\n * system (live-confirmed): PascalCase event names, Claude snake_case stdin\n * wire fields, and a Claude-shaped `hookSpecificOutput` reply. Hook\n * registrations use the Claude NESTED-rule shape:\n * { hooks: { <Event>: [ { matcher?, hooks:[{ type:\"command\", command }] } ] } }\n *\n * Supported events (Claude-compatible): PreToolUse, PostToolUse,\n * UserPromptSubmit, Stop. Droid exposes no PreCompact / SessionStart /\n * SessionEnd / Notification, so those degrade to a warn/skip at install time.\n *\n * Reply protocol is Claude-shaped JSON on stdout (exit 0 + `hookSpecificOutput`\n * with permissionDecision allow|deny|ask, plus additionalContext). Droid cannot\n * rewrite already-emitted tool output, so canModifyOutput is false; it CAN\n * inject session context (additionalContext) so canInjectSessionContext is true.\n *\n * Env handling: env/header/url refs are resolved to literals at install time via\n * resolveEnvRefsDeep — the safe default matching the Kiro/Qwen adapters. Droid\n * also accepts native ${VAR}, but resolve-to-literal avoids surprises.\n */\n\nimport { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport { BaseAdapter } from \"../base.js\";\nimport type { Adapter, HookReply, InstallContext, NormalizedEvent } from \"../spi.js\";\nimport type {\n ChangeRecord,\n DetectedPlatform,\n HealthCheck,\n HookEventName,\n HookParadigm,\n HookResponse,\n PlatformCapabilities,\n PlatformId,\n PostToolUseEvent,\n PreToolUseEvent,\n ServerDef,\n StopEvent,\n Transport,\n UserPromptSubmitEvent,\n} from \"../../core/types.js\";\nimport { resolveEnvRefsDeep } from \"../../core/interpolate.js\";\nimport {\n buildHomeBinHookCommand,\n buildServeWrapperCommand,\n isHomeBinHookCommand,\n shouldWrapForTelemetry,\n} from \"../../core/spawn.js\";\n\nconst HOST: PlatformId = \"droid\";\nconst MCP_ROOT_KEY = \"mcpServers\";\n\n/**\n * Canonical events Droid actually fires. Droid's hook event names are\n * Claude-identical (PascalCase), so the canonical name is registered directly.\n * PreCompact / SessionStart / SessionEnd / Notification have no Droid equivalent\n * and are reported as a warn/skip at install time.\n */\nconst SUPPORTED_EVENTS: ReadonlySet<HookEventName> = new Set<HookEventName>([\n \"PreToolUse\",\n \"PostToolUse\",\n \"UserPromptSubmit\",\n \"Stop\",\n]);\n\n/**\n * Native MCP server entry shapes Droid accepts under `mcpServers`.\n * A stdio entry carries an explicit `type: \"stdio\"` discriminator and a\n * `disabled` flag; remote transports register a URL.\n */\ninterface DroidStdioServer {\n type: \"stdio\";\n command: string;\n args?: string[];\n env?: Record<string, string>;\n disabled: boolean;\n}\ninterface DroidHttpServer {\n type: \"http\";\n url: string;\n headers?: Record<string, string>;\n disabled: boolean;\n}\n\n/** A single Droid native hook registration entry (Claude-shaped, nested). */\ninterface DroidHookEntry {\n matcher: string;\n hooks: Array<{ type: \"command\"; command: string }>;\n}\n\n/** The shape of Droid's hooks.json (only the parts we touch). */\ninterface DroidHooksFile {\n hooks?: Record<string, DroidHookEntry[]>;\n [key: string]: unknown;\n}\n\n/** Raw Droid CLI hook stdin payload (Claude-compatible snake_case wire fields). */\ninterface DroidWireInput {\n session_id?: string;\n transcript_path?: string;\n cwd?: string;\n hook_event_name?: string;\n tool_name?: string;\n tool_input?: Record<string, unknown>;\n tool_response?: unknown;\n prompt?: string;\n stop_hook_active?: boolean;\n /** Injected by the entrypoint so the runtime knows which connector to dispatch. */\n connector?: unknown;\n}\n\nexport class DroidAdapter extends BaseAdapter implements Adapter {\n readonly id: PlatformId = HOST;\n readonly name = \"Droid (Factory)\";\n readonly paradigm: HookParadigm = \"json-stdio\";\n\n readonly capabilities: PlatformCapabilities = {\n preToolUse: true,\n postToolUse: true,\n preCompact: false,\n sessionStart: false,\n sessionEnd: false,\n userPromptSubmit: true,\n stop: true,\n notification: false,\n // Droid's PreToolUse can deny/ask (Claude-shaped), but it cannot rewrite\n // already-emitted tool output. canModifyArgs left false until confirmed.\n canModifyArgs: false,\n canModifyOutput: false,\n // Droid honors additionalContext on the stdout reply.\n canInjectSessionContext: true,\n // Droid registers stdio and Streamable HTTP MCP servers.\n transports: [\"stdio\", \"http\"],\n };\n\n // ── Detection ────────────────────────────────────────────────────────────\n\n detectInstalled(projectDir: string): DetectedPlatform {\n const userDir = join(homedir(), \".factory\");\n const userMcp = join(userDir, \"mcp.json\");\n const projDir = join(projectDir, \".factory\");\n const projMcp = join(projDir, \"mcp.json\");\n\n const userInstalled = existsSync(userDir) || existsSync(userMcp);\n const projInstalled = existsSync(projDir) || existsSync(projMcp);\n const installed = userInstalled || projInstalled;\n const scope = projInstalled && !userInstalled ? \"project\" : \"user\";\n const configPath = scope === \"project\" ? projMcp : userMcp;\n\n return {\n id: this.id,\n name: this.name,\n installed,\n paradigm: this.paradigm,\n capabilities: this.capabilities,\n configPath,\n scope,\n reason: installed\n ? `found Droid config (${scope}) at ${configPath}`\n : `no .factory config at ${userDir} or ${projDir}`,\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, \".factory\")\n : join(homedir(), \".factory\");\n }\n\n getServerConfigPath(ctx: InstallContext): string {\n return join(this.getConfigDir(ctx), \"mcp.json\");\n }\n\n /** Hooks live in a SEPARATE hooks.json under the same `.factory` dir. */\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 droid\"\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 Droid's native mcpServers entry. */\n private renderServerEntry(\n ctx: InstallContext,\n server: ServerDef,\n ): DroidStdioServer | DroidHttpServer {\n const transport: Transport = server.transport;\n const disabled = server.enabled === false;\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 if (shouldWrapForTelemetry(server, ctx.connector.telemetry)) {\n const wrapped = buildServeWrapperCommand(\n ctx.homeBinPath,\n ctx.connector.id,\n command,\n args,\n ctx.scope,\n this.id,\n );\n command = wrapped.command;\n args = wrapped.args;\n }\n\n // Resolve every ${env:VAR} to a literal at install time (safe path).\n const entry: DroidStdioServer = {\n type: \"stdio\",\n command: resolveEnvRefsDeep(command),\n disabled,\n };\n if (args.length > 0) entry.args = resolveEnvRefsDeep(args);\n const env = this.renderEnv(server.env);\n if (env) entry.env = env;\n return entry;\n }\n\n // http (and any other remote transport) — Droid registers a URL.\n const entry: DroidHttpServer = {\n type: \"http\",\n url: resolveEnvRefsDeep(server.url ?? \"\"),\n disabled,\n };\n const headers = this.renderEnv(server.headers);\n if (headers) entry.headers = headers;\n return entry;\n }\n\n /**\n * Render env/header values. Resolve `${env:VAR}` references to literals at\n * install time (the safe path; Droid would also accept native ${VAR}).\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 return resolveEnvRefsDeep({ ...env });\n }\n\n // ── Hook install / uninstall (separate hooks.json, nested-rule shape) ─────\n\n installHooks(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n if (connector.platforms[HOST]?.hooks === false) {\n return [{ platform: this.id, action: \"skip\", detail: \"hooks disabled for droid\" }];\n }\n if (connector.hookEvents.length === 0) {\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no hooks\" }];\n }\n\n const hookPath = this.getHookConfigPath(ctx);\n // Merge into any existing hooks.json so the user's own hooks survive.\n const file = this.readJson<DroidHooksFile>(hookPath) ?? {};\n const hooks = (file.hooks ??= {});\n\n const changes: ChangeRecord[] = [];\n let mutated = false;\n\n for (const event of connector.hookEvents) {\n if (!SUPPORTED_EVENTS.has(event)) {\n changes.push({\n platform: this.id,\n action: \"warn\",\n path: hookPath,\n detail: `${event} has no Droid hook equivalent — skipped`,\n });\n continue;\n }\n\n // Droid's event names are Claude-identical (PascalCase) — register the\n // canonical event name directly.\n const command = buildHomeBinHookCommand(ctx.homeBinPath, HOST, event, connector.id);\n const matcher = connector.hooks[event]?.matcher ?? \"\";\n const entry: DroidHookEntry = {\n matcher,\n hooks: [{ type: \"command\", command }],\n };\n\n const bucket = (hooks[event] ??= []);\n const existingIdx = bucket.findIndex((e) => this.entryHasOurCommand(e, ctx));\n\n if (existingIdx >= 0) {\n if (JSON.stringify(bucket[existingIdx]) === JSON.stringify(entry)) {\n changes.push({\n platform: this.id,\n action: \"skip\",\n path: hookPath,\n detail: `hooks.${event} already registered`,\n });\n continue;\n }\n bucket[existingIdx] = entry;\n changes.push({\n platform: this.id,\n action: \"update\",\n path: hookPath,\n detail: `hooks.${event}`,\n });\n } else {\n bucket.push(entry);\n changes.push({\n platform: this.id,\n action: \"create\",\n path: hookPath,\n detail: `hooks.${event}`,\n });\n }\n mutated = true;\n }\n\n if (mutated) this.writeJson(hookPath, file, ctx.dryRun);\n return changes;\n }\n\n uninstallHooks(ctx: InstallContext): ChangeRecord[] {\n const hookPath = this.getHookConfigPath(ctx);\n const file = this.readJson<DroidHooksFile>(hookPath);\n const hooks = file?.hooks;\n if (!file || !hooks) {\n return [\n {\n platform: this.id,\n action: \"skip\",\n path: hookPath,\n detail: \"no hooks section present\",\n },\n ];\n }\n\n const changes: ChangeRecord[] = [];\n let mutated = false;\n\n for (const event of Object.keys(hooks)) {\n const bucket = hooks[event];\n if (!Array.isArray(bucket)) continue;\n\n // Strip our hook command from each entry; drop entries left empty so we\n // never remove another connector's (or the user's own) hook commands. The\n // id token is anchored (isHomeBinHookCommand) so a shared-prefix connector\n // id is never affected.\n const next: DroidHookEntry[] = [];\n let removed = 0;\n for (const e of bucket) {\n const innerBefore = e.hooks?.length ?? 0;\n const inner = (e.hooks ?? []).filter((h) => !this.isOurCommand(h.command, ctx));\n removed += innerBefore - inner.length;\n if (inner.length > 0) next.push({ matcher: e.matcher ?? \"\", hooks: inner });\n }\n\n if (removed > 0) {\n if (next.length > 0) hooks[event] = next;\n else delete hooks[event];\n changes.push({\n platform: this.id,\n action: \"remove\",\n path: hookPath,\n detail: `hooks.${event} (${removed})`,\n });\n mutated = true;\n }\n }\n\n if (mutated) this.writeJson(hookPath, file, ctx.dryRun);\n if (changes.length === 0) {\n changes.push({\n platform: this.id,\n action: \"skip\",\n path: hookPath,\n detail: \"no matching hook entries\",\n });\n }\n return changes;\n }\n\n private entryHasOurCommand(entry: DroidHookEntry, ctx: InstallContext): boolean {\n return (entry.hooks ?? []).some((h) => this.isOurCommand(h.command, ctx));\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 // ── Diagnostics ──────────────────────────────────────────────────────────\n\n override getHealthChecks(ctx: InstallContext): readonly HealthCheck[] {\n const mcpPath = this.getServerConfigPath(ctx);\n const hookPath = this.getHookConfigPath(ctx);\n const connectorId = ctx.connector.id;\n const homeBin = ctx.homeBinPath;\n const hookEvents = ctx.connector.hookEvents;\n return [\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}: server entry registered`,\n check: () => {\n const cfg = this.readJson<{ [k: string]: Record<string, unknown> }>(mcpPath);\n const bucket = cfg?.[MCP_ROOT_KEY];\n if (!cfg || !bucket) {\n return { status: \"FAIL\", detail: `no ${MCP_ROOT_KEY} in ${mcpPath}` };\n }\n return connectorId in bucket\n ? { status: \"OK\", detail: `${MCP_ROOT_KEY}.${connectorId} present` }\n : {\n status: \"FAIL\",\n detail: `no ${MCP_ROOT_KEY}.${connectorId} in ${mcpPath}`,\n };\n },\n },\n {\n name: `${this.name}: hook command registered`,\n check: () => {\n if (hookEvents.length === 0) {\n return { status: \"OK\", detail: \"no hooks declared\" };\n }\n const file = this.readJson<DroidHooksFile>(hookPath);\n if (!file) return { status: \"FAIL\", detail: `cannot read ${hookPath}` };\n const hooks = file.hooks ?? {};\n const registered = Object.values(hooks).some((entries) =>\n (entries ?? []).some((e) =>\n (e.hooks ?? []).some((h) =>\n isHomeBinHookCommand(h.command, homeBin, connectorId),\n ),\n ),\n );\n return registered\n ? { status: \"OK\", detail: \"hook command present\" }\n : { status: \"FAIL\", detail: `no hook for ${connectorId} in ${hookPath}` };\n },\n },\n ];\n }\n\n // ── Runtime: parse Droid stdin JSON → normalized event ────────────────────\n\n parseEvent(event: HookEventName, raw: unknown): NormalizedEvent {\n const input = (raw ?? {}) as DroidWireInput;\n const connectorId = typeof input.connector === \"string\" ? input.connector : \"\";\n const sessionId = typeof input.session_id === \"string\" ? input.session_id : \"\";\n const projectDir = typeof input.cwd === \"string\" ? input.cwd : undefined;\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 ev: PostToolUseEvent = {\n ...base,\n toolName: input.tool_name ?? \"\",\n toolInput: input.tool_input ?? {},\n ...(toolResponseToString(input.tool_response) !== undefined\n ? { toolOutput: toolResponseToString(input.tool_response) }\n : {}),\n };\n return ev;\n }\n case \"UserPromptSubmit\": {\n const ev: UserPromptSubmitEvent = {\n ...base,\n prompt: typeof input.prompt === \"string\" ? input.prompt : \"\",\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 default: {\n // Droid never delivers PreCompact / SessionStart / SessionEnd /\n // Notification (no native equivalent). If the runtime dispatches one\n // anyway, surface it loudly rather than silently mis-parse.\n throw new Error(`unsupported droid hook event: ${String(event)}`);\n }\n }\n }\n\n // ── Runtime: normalized response → Droid native (Claude-shaped) hook reply ─\n\n formatReply(event: HookEventName, response: HookResponse): HookReply {\n const hookEventName = event;\n const decision = response.decision ?? \"allow\";\n\n // deny → block the action with a reason (exit 0; JSON carries the decision).\n if (decision === \"deny\") {\n return this.stdout({\n hookSpecificOutput: {\n hookEventName,\n permissionDecision: \"deny\",\n permissionDecisionReason: response.reason ?? \"Blocked by hook\",\n },\n });\n }\n\n // ask → prompt the user to confirm.\n if (decision === \"ask\") {\n return this.stdout({\n hookSpecificOutput: {\n hookEventName,\n permissionDecision: \"ask\",\n permissionDecisionReason: response.reason ?? \"Confirmation required by hook\",\n },\n });\n }\n\n // context → inject soft guidance (Droid honors additionalContext).\n if (decision === \"context\" && response.additionalContext) {\n return this.stdout({\n hookSpecificOutput: { hookEventName, additionalContext: response.additionalContext },\n });\n }\n\n // allow / modify (unsupported — exit-code/decision protocol only) / void →\n // pass through with exit 0.\n return { exitCode: 0 };\n }\n\n private stdout(payload: unknown): HookReply {\n return { exitCode: 0, stdout: JSON.stringify(payload) };\n }\n}\n\n/** Coerce a Droid PostToolUse `tool_response` into a string for the normalized event. */\nfunction toolResponseToString(value: unknown): string | undefined {\n if (value == null) return undefined;\n if (typeof value === \"string\") return value;\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n}\n\nexport const adapter = new DroidAdapter();\nexport default adapter;\n"],"mappings":"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","names":["entry"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/adapters/gemini-cli/index.ts"],"sourcesContent":["/**\n * adapters/gemini-cli — Gemini CLI platform adapter for agent-connector.\n *\n * Gemini CLI (Google) is a json-stdio host: the host pipes a JSON payload to a\n * hook command on stdin and reads a JSON control object / exit code back — the\n * same paradigm as Claude Code. Two things make Gemini distinct, and both are\n * handled below:\n *\n * 1. TRANSPORT IS SELECTED BY KEY (not a `type` field). Under `mcpServers`, a\n * stdio server is `{ command, args, env }`; an SSE server is `{ url }`; a\n * streamable-HTTP server is `{ httpUrl }`. We render stdio with\n * command/args/env and remote transports with the matching key.\n * 2. Gemini's hook EVENT VOCABULARY differs from the Claude-compatible hosts,\n * so our normalized event names are mapped to Gemini's:\n * PreToolUse → BeforeTool\n * PostToolUse → AfterTool\n * PreCompact → PreCompress\n * SessionStart→ SessionStart\n * UserPromptSubmit → BeforeAgent (BeforeAgent fires on prompt submit;\n * additionalContext is appended)\n * SessionEnd → SessionEnd\n * Notification→ Notification\n * `Stop` has no Gemini equivalent and is reported as a warn/skip at install.\n *\n * Native config (JSON):\n * - MCP servers: user → ~/.gemini/settings.json; project → .gemini/settings.json\n * (system scope is /etc/gemini-cli/settings.json — not a target we write).\n * Root key \"mcpServers\".\n * - Hooks: the SAME settings.json, top-level \"hooks\" key, keyed by the Gemini\n * event name, each value an array of `{ matcher, hooks: [{ type:\"command\",\n * command }] }` (the nested shape; Gemini accepts ONLY type \"command\").\n * - Reply (stdout, exit 0):\n * deny → { decision:\"deny\", reason }\n * modify → { hookSpecificOutput:{ tool_input } } (merged with original)\n * context → { hookSpecificOutput:{ additionalContext } }\n * PostToolUse output rewrite → { decision:\"deny\", reason:<newOutput> }\n * (Gemini replaces tool output via a deny+reason on AfterTool).\n * ask → no native \"ask\"; degrade to deny to stay fail-safe.\n *\n * NOTE: Gemini's AfterModel hook payload carries `usageMetadata.totalTokenCount`\n * (per-LLM-call real token usage — the one host-native usage signal in the\n * matrix). This is the OPT-IN host-native usage enricher (4a): when host-native\n * capture is enabled (telemetry.hostNativeUsage, or AGENT_CONNECTOR_HOST_NATIVE=1\n * at install), installHooks ALSO writes an AfterModel hook whose command is the\n * hidden `<homeBin> usage-event gemini-cli --connector <id>` entrypoint. That\n * records a DISTINCT `model_turn` telemetry row (confidence host-native) covering\n * the whole conversation turn — never summed with the per-MCP `serve`-proxy rows.\n * AfterModel is NOT a normalized connector event (no handler dispatch); it is a\n * host-native-only sink. When the opt-in is OFF, the hook is NOT installed and\n * telemetry continues to flow only through the `serve` proxy.\n *\n * Env handling: Gemini's native settings interpolation token is `${VAR}`/`$VAR`,\n * not the framework's `${env:VAR}` syntax. Rather than depend on that, env /\n * header / url refs are resolved to literals at install time via\n * resolveEnvRefsDeep — the safe default for a host without `${env:VAR}` support\n * (matching the Codex / Copilot CLI adapters).\n *\n * Grounded in docs/research/understand-report.md §2 (Platform Integration\n * Matrix, \"Gemini CLI\" row) and context-mode's proven gemini-cli adapter.\n */\n\nimport { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport { BaseAdapter } 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 NotificationEvent,\n PlatformCapabilities,\n PlatformId,\n PostToolUseEvent,\n PreCompactEvent,\n PreToolUseEvent,\n ServerDef,\n SessionEndEvent,\n SessionStartEvent,\n SkillDef,\n SubagentDef,\n Transport,\n UserPromptSubmitEvent,\n} from \"../../core/types.js\";\nimport { resolveEnvRefsDeep } from \"../../core/interpolate.js\";\nimport { writeTomlString } from \"../../core/toml.js\";\nimport {\n buildHomeBinHookCommand,\n buildServeWrapperCommand,\n buildUsageEventCommand,\n isHomeBinHookCommand,\n isHostNativeUsageEnabled,\n isUsageEventCommand,\n shouldWrapForTelemetry,\n} from \"../../core/spawn.js\";\n\nconst HOST: PlatformId = \"gemini-cli\";\nconst MCP_ROOT_KEY = \"mcpServers\";\n\n/**\n * Gemini-native hook event names (settings.json top-level `hooks` keys).\n * Only the events Gemini fires for the JSON-stdio command paradigm we use.\n */\nconst GEMINI_EVENT = {\n BeforeTool: \"BeforeTool\",\n AfterTool: \"AfterTool\",\n PreCompress: \"PreCompress\",\n SessionStart: \"SessionStart\",\n SessionEnd: \"SessionEnd\",\n BeforeAgent: \"BeforeAgent\",\n Notification: \"Notification\",\n /** Fires AFTER each model turn; payload carries `usageMetadata` (opt-in 4a). */\n AfterModel: \"AfterModel\",\n} as const;\n\n/**\n * Map our normalized event names to Gemini's native hook event names. Only the\n * events Gemini actually supports are present; `Stop` has no Gemini equivalent\n * and is reported as a warn/skip at install time.\n */\nconst EVENT_MAP: Partial<Record<HookEventName, string>> = {\n PreToolUse: GEMINI_EVENT.BeforeTool,\n PostToolUse: GEMINI_EVENT.AfterTool,\n PreCompact: GEMINI_EVENT.PreCompress,\n SessionStart: GEMINI_EVENT.SessionStart,\n SessionEnd: GEMINI_EVENT.SessionEnd,\n UserPromptSubmit: GEMINI_EVENT.BeforeAgent,\n Notification: GEMINI_EVENT.Notification,\n};\n\n/** A single Gemini native hook registration entry (nested, Claude-shaped). */\ninterface GeminiHookEntry {\n matcher: string;\n hooks: Array<{ type: \"command\"; command: string }>;\n}\n\n/** The shape of Gemini's settings.json (only the parts we touch). */\ninterface GeminiSettingsFile {\n mcpServers?: Record<string, unknown>;\n hooks?: Record<string, GeminiHookEntry[]>;\n [key: string]: unknown;\n}\n\n/**\n * Native MCP server entry shapes Gemini accepts under `mcpServers`. Gemini\n * selects the transport by which key is present (NOT a `type` field):\n * stdio → command / args / env\n * SSE → url\n * streamable-HTTP→ httpUrl\n */\ninterface GeminiStdioServer {\n command: string;\n args?: string[];\n env?: Record<string, string>;\n cwd?: string;\n}\ninterface GeminiSseServer {\n url: string;\n headers?: Record<string, string>;\n}\ninterface GeminiHttpServer {\n httpUrl: string;\n headers?: Record<string, string>;\n}\n\n/** Raw Gemini CLI hook stdin payload (snake_case wire fields). */\ninterface GeminiWireInput {\n connector?: unknown;\n tool_name?: string;\n tool_input?: Record<string, unknown>;\n tool_output?: string;\n is_error?: boolean;\n session_id?: string;\n cwd?: string;\n source?: string;\n trigger?: string;\n reason?: string;\n prompt?: string;\n message?: string;\n}\n\nexport class GeminiCliAdapter extends BaseAdapter implements Adapter {\n readonly id: PlatformId = HOST;\n readonly name = \"Gemini CLI\";\n readonly paradigm: HookParadigm = \"json-stdio\";\n\n readonly capabilities: PlatformCapabilities = {\n // Gemini fires Before/AfterTool, PreCompress, SessionStart/End, BeforeAgent\n // (≈ UserPromptSubmit), and Notification. It has no `Stop` equivalent.\n preToolUse: true,\n postToolUse: true,\n preCompact: true,\n sessionStart: true,\n sessionEnd: true,\n userPromptSubmit: true,\n stop: false,\n notification: true,\n // BeforeTool can rewrite tool input (hookSpecificOutput.tool_input); unlike\n // the Claude-family hosts, AfterTool CAN replace already-emitted tool output\n // (via a deny + reason), so output modification is supported here.\n canModifyArgs: true,\n canModifyOutput: true,\n canInjectSessionContext: true,\n // Transport is selected by key: command/args (stdio), url (sse), httpUrl (http).\n transports: [\"stdio\", \"sse\", \"http\"],\n // Content surfaces: Gemini CLI supports all three. Commands are authored as\n // TOML (description + prompt with {{args}} placeholders); skills follow the\n // uniform <geminiDir>/skills/<name>/SKILL.md layout; subagents are md+fm.\n supportsCommands: true,\n supportsSkills: true,\n supportsSubagents: true,\n };\n\n // ── Detection ────────────────────────────────────────────────────────────\n\n detectInstalled(projectDir: string): DetectedPlatform {\n const userDir = join(homedir(), \".gemini\");\n const userSettings = join(userDir, \"settings.json\");\n const projectDirGemini = join(projectDir, \".gemini\");\n const projectSettings = join(projectDirGemini, \"settings.json\");\n const userInstalled = existsSync(userDir) || existsSync(userSettings);\n const projInstalled = existsSync(projectDirGemini) || existsSync(projectSettings);\n const installed = userInstalled || projInstalled;\n // Report the scope/path that actually matched, so a project-only install\n // isn't misreported as a (non-existent) user install.\n const scope = projInstalled && !userInstalled ? \"project\" : \"user\";\n const configPath = scope === \"project\" ? projectSettings : userSettings;\n return {\n id: this.id,\n name: this.name,\n installed,\n paradigm: this.paradigm,\n capabilities: this.capabilities,\n configPath,\n scope,\n reason: installed\n ? scope === \"project\"\n ? `found project Gemini CLI config at ${projectSettings}`\n : `found Gemini CLI config under ${userDir}`\n : `no Gemini CLI 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, \".gemini\")\n : join(homedir(), \".gemini\");\n }\n\n /** MCP servers live in settings.json under `mcpServers`. */\n getServerConfigPath(ctx: InstallContext): string {\n return join(this.getConfigDir(ctx), \"settings.json\");\n }\n\n /** Hooks live in the SAME settings.json under the top-level `hooks` key. */\n getHookConfigPath(ctx: InstallContext): string {\n return join(this.getConfigDir(ctx), \"settings.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 gemini-cli\"\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 /**\n * Render a normalized ServerDef into Gemini's native mcpServers entry. The\n * transport is encoded by WHICH KEY is present, not a `type` field.\n */\n private renderServerEntry(\n ctx: InstallContext,\n server: ServerDef,\n ): GeminiStdioServer | GeminiSseServer | GeminiHttpServer {\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 if (shouldWrapForTelemetry(server, ctx.connector.telemetry)) {\n const wrapped = buildServeWrapperCommand(\n ctx.homeBinPath,\n ctx.connector.id,\n command,\n args,\n ctx.scope,\n this.id,\n );\n command = wrapped.command;\n args = wrapped.args;\n }\n\n const entry: GeminiStdioServer = { command: resolveEnvRefsDeep(command) };\n if (args.length > 0) entry.args = args.map((a) => resolveEnvRefsDeep(a));\n const env = this.renderEnv(server.env);\n if (env) entry.env = env;\n if (server.cwd) entry.cwd = resolveEnvRefsDeep(server.cwd);\n return entry;\n }\n\n // SSE transport → `url` key.\n if (transport === \"sse\") {\n const entry: GeminiSseServer = { url: resolveEnvRefsDeep(server.url ?? \"\") };\n const headers = this.renderEnv(server.headers);\n if (headers) entry.headers = headers;\n return entry;\n }\n\n // http (streamable-HTTP) and any other remote transport → `httpUrl` key.\n const entry: GeminiHttpServer = { httpUrl: resolveEnvRefsDeep(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. Gemini's native settings token is `${VAR}` (not\n * the framework's `${env:VAR}`), so refs resolve to literals at install time —\n * the safe default for a host without `${env:VAR}` interpolation.\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 return resolveEnvRefsDeep({ ...env });\n }\n\n // ── Hook install / uninstall ─────────────────────────────────────────────\n\n installHooks(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n if (connector.platforms[HOST]?.hooks === false) {\n return [{ platform: this.id, action: \"skip\", detail: \"hooks disabled for gemini-cli\" }];\n }\n // The opt-in host-native usage hook (4a) is a host-native-only sink that does\n // NOT need a connector handler — so it may be installed even for a connector\n // that declares no normalized hook events.\n const hostNative = isHostNativeUsageEnabled(connector.telemetry);\n if (connector.hookEvents.length === 0 && !hostNative) {\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no hooks\" }];\n }\n\n const settingsPath = this.getHookConfigPath(ctx);\n const settings = this.readJson<GeminiSettingsFile>(settingsPath) ?? {};\n const hooks = (settings.hooks ??= {});\n\n const changes: ChangeRecord[] = [];\n let mutated = false;\n\n for (const event of connector.hookEvents) {\n const geminiEvent = EVENT_MAP[event];\n if (!geminiEvent) {\n // No Gemini equivalent for this normalized event (e.g. Stop) — report.\n changes.push({\n platform: this.id,\n action: \"warn\",\n path: settingsPath,\n detail: `${event} has no Gemini CLI hook equivalent — skipped`,\n });\n continue;\n }\n\n const command = buildHomeBinHookCommand(ctx.homeBinPath, HOST, event, connector.id);\n const matcher = connector.hooks[event]?.matcher ?? \"\";\n const entry: GeminiHookEntry = {\n matcher,\n hooks: [{ type: \"command\", command }],\n };\n\n const bucket = (hooks[geminiEvent] ??= []);\n const existingIdx = bucket.findIndex((e) => this.entryHasOurCommand(e, ctx));\n\n if (existingIdx >= 0) {\n if (JSON.stringify(bucket[existingIdx]) === JSON.stringify(entry)) {\n changes.push({\n platform: this.id,\n action: \"skip\",\n path: settingsPath,\n detail: `hooks.${geminiEvent} already registered`,\n });\n continue;\n }\n bucket[existingIdx] = entry;\n changes.push({\n platform: this.id,\n action: \"update\",\n path: settingsPath,\n detail: `hooks.${geminiEvent}`,\n });\n } else {\n bucket.push(entry);\n changes.push({\n platform: this.id,\n action: \"create\",\n path: settingsPath,\n detail: `hooks.${geminiEvent}`,\n });\n }\n mutated = true;\n }\n\n // OPT-IN host-native usage hook (4a): when enabled, register an AfterModel\n // hook whose command is the hidden `usage-event` entrypoint. It carries no\n // matcher (it is not a tool event) and records a DISTINCT `model_turn` row.\n if (hostNative) {\n if (this.installUsageHook(hooks, ctx, settingsPath, changes)) mutated = true;\n }\n\n if (mutated) this.writeJson(settingsPath, settings, ctx.dryRun);\n return changes;\n }\n\n /**\n * Register the opt-in AfterModel host-native usage hook (4a) into `hooks`.\n * Idempotent: a byte-identical entry skips, a drifted one updates. Returns true\n * when the file was mutated. The command is the hidden `usage-event` entrypoint\n * (NOT a connector hook), so it carries an empty matcher.\n */\n private installUsageHook(\n hooks: Record<string, GeminiHookEntry[]>,\n ctx: InstallContext,\n settingsPath: string,\n changes: ChangeRecord[],\n ): boolean {\n const command = buildUsageEventCommand(ctx.homeBinPath, HOST, ctx.connector.id);\n const entry: GeminiHookEntry = {\n matcher: \"\",\n hooks: [{ type: \"command\", command }],\n };\n const bucket = (hooks[GEMINI_EVENT.AfterModel] ??= []);\n const existingIdx = bucket.findIndex((e) =>\n (e.hooks ?? []).some((h) => isUsageEventCommand(h.command, ctx.homeBinPath, ctx.connector.id)),\n );\n\n if (existingIdx >= 0) {\n if (JSON.stringify(bucket[existingIdx]) === JSON.stringify(entry)) {\n changes.push({\n platform: this.id,\n action: \"skip\",\n path: settingsPath,\n detail: `hooks.${GEMINI_EVENT.AfterModel} (host-native usage) already registered`,\n });\n return false;\n }\n bucket[existingIdx] = entry;\n changes.push({\n platform: this.id,\n action: \"update\",\n path: settingsPath,\n detail: `hooks.${GEMINI_EVENT.AfterModel} (host-native usage)`,\n });\n } else {\n bucket.push(entry);\n changes.push({\n platform: this.id,\n action: \"create\",\n path: settingsPath,\n detail: `hooks.${GEMINI_EVENT.AfterModel} (host-native usage)`,\n });\n }\n return true;\n }\n\n uninstallHooks(ctx: InstallContext): ChangeRecord[] {\n const settingsPath = this.getHookConfigPath(ctx);\n const settings = this.readJson<GeminiSettingsFile>(settingsPath);\n const hooks = settings?.hooks;\n if (!settings || !hooks) {\n return [\n {\n platform: this.id,\n action: \"skip\",\n path: settingsPath,\n detail: \"no hooks section present\",\n },\n ];\n }\n\n const changes: ChangeRecord[] = [];\n let mutated = false;\n\n for (const geminiEvent of Object.keys(hooks)) {\n const bucket = hooks[geminiEvent];\n if (!Array.isArray(bucket)) continue;\n\n // Strip our hook command from each entry; drop entries left empty so we\n // never remove another connector's (or the user's own) hook commands.\n const next: GeminiHookEntry[] = [];\n let removed = 0;\n for (const e of bucket) {\n const innerBefore = e.hooks?.length ?? 0;\n const inner = (e.hooks ?? []).filter((h) => !this.isOurCommand(h.command, ctx));\n removed += innerBefore - inner.length;\n if (inner.length > 0) next.push({ matcher: e.matcher ?? \"\", hooks: inner });\n }\n\n if (removed > 0) {\n if (next.length > 0) hooks[geminiEvent] = next;\n else delete hooks[geminiEvent];\n changes.push({\n platform: this.id,\n action: \"remove\",\n path: settingsPath,\n detail: `hooks.${geminiEvent} (${removed})`,\n });\n mutated = true;\n }\n }\n\n if (mutated) this.writeJson(settingsPath, settings, ctx.dryRun);\n if (changes.length === 0) {\n changes.push({\n platform: this.id,\n action: \"skip\",\n path: settingsPath,\n detail: \"no matching hook entries\",\n });\n }\n return changes;\n }\n\n private entryHasOurCommand(entry: GeminiHookEntry, ctx: InstallContext): boolean {\n return (entry.hooks ?? []).some((h) => this.isOurCommand(h.command, ctx));\n }\n\n /**\n * True when a hook command is ONE OF OURS for this connector — either the\n * universal `hook` dispatcher OR the opt-in `usage-event` sink. Both are\n * anchored on the connector id (see isHomeBinHookCommand) so a shared-prefix id\n * can't collide, and so uninstall reverses the AfterModel usage hook too.\n */\n private isOurCommand(command: string | undefined, ctx: InstallContext): boolean {\n return (\n isHomeBinHookCommand(command, ctx.homeBinPath, ctx.connector.id) ||\n isUsageEventCommand(command, ctx.homeBinPath, ctx.connector.id)\n );\n }\n\n // ── Content surfaces: commands / skills / subagents ──────────────────────\n // CONTENT-ONLY: pure native-file writers under <geminiDir>/{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[\"gemini-cli\"]\n // per-surface false to skip. Commands are TOML (Gemini's native format, with\n // {{args}} placeholders preserved verbatim); skills/subagents mirror the\n // Claude reference (uniform SKILL.md + md+frontmatter subagents).\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: <geminiDir>/commands/<name>.toml. */\n private commandPath(ctx: InstallContext, name: string): string {\n return join(this.commandsDir(ctx), `${name}.toml`);\n }\n /** Native skill dir: <geminiDir>/skills/<name>. */\n private skillDir(ctx: InstallContext, name: string): string {\n return join(this.skillsDir(ctx), name);\n }\n /** Native subagent file path: <geminiDir>/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 gemini-cli\" }];\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(this.commandPath(ctx, cmd.name), this.renderCommand(cmd), ctx.dryRun),\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 command to Gemini's native TOML: { description, prompt }. Gemini\n * uses `{{args}}` placeholders in the prompt; the prompt body is passed\n * through verbatim so any placeholders are preserved.\n */\n private renderCommand(cmd: CommandDef): string {\n const obj: Record<string, unknown> = {};\n if (cmd.description !== undefined) obj.description = cmd.description;\n obj.prompt = cmd.prompt;\n return writeTomlString(obj);\n }\n\n // ── 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 gemini-cli\" }];\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\"), this.renderSkill(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 /**\n * Render a skill's SKILL.md: frontmatter (name, description + optional model,\n * allowed-tools, disable-model-invocation) + body. Uniform across platforms.\n */\n private renderSkill(skill: SkillDef): string {\n const frontmatter: Record<string, unknown> = {\n name: skill.name,\n description: skill.description,\n };\n if (skill.model !== undefined) frontmatter.model = skill.model;\n const allow = skill.tools?.allow;\n if (allow && allow.length > 0) frontmatter[\"allowed-tools\"] = allow.join(\", \");\n if (skill.disableModelInvocation !== undefined) {\n frontmatter[\"disable-model-invocation\"] = skill.disableModelInvocation;\n }\n if (skill.extra) Object.assign(frontmatter, skill.extra);\n return this.renderFrontmatterMd(frontmatter, skill.body);\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 gemini-cli\" }];\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(this.subagentPath(ctx, agent.name), this.renderSubagent(agent), ctx.dryRun),\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 subagent to md+frontmatter (name, description, tools, model) + prompt body. */\n private renderSubagent(agent: SubagentDef): string {\n const frontmatter: Record<string, unknown> = {\n name: agent.name,\n description: agent.description,\n };\n const allow = agent.tools?.allow;\n if (allow && allow.length > 0) frontmatter.tools = allow.join(\", \");\n if (agent.model !== undefined) frontmatter.model = agent.model;\n if (agent.extra) Object.assign(frontmatter, agent.extra);\n return this.renderFrontmatterMd(frontmatter, agent.prompt);\n }\n\n // ── Diagnostics ──────────────────────────────────────────────────────────\n\n override getHealthChecks(ctx: InstallContext): readonly HealthCheck[] {\n const settingsPath = this.getServerConfigPath(ctx);\n const connectorId = ctx.connector.id;\n const homeBin = ctx.homeBinPath;\n const hookEvents = ctx.connector.hookEvents;\n const checks: HealthCheck[] = [\n {\n name: `${this.name}: settings.json present`,\n check: () =>\n existsSync(settingsPath)\n ? { status: \"OK\", detail: settingsPath }\n : { status: \"FAIL\", detail: `not found: ${settingsPath}` },\n },\n {\n name: `${this.name}: hook command registered`,\n check: () => {\n if (hookEvents.length === 0) {\n return { status: \"OK\", detail: \"no hooks declared\" };\n }\n const settings = this.readJson<GeminiSettingsFile>(settingsPath);\n if (!settings) return { status: \"FAIL\", detail: `cannot read ${settingsPath}` };\n const hooks = settings.hooks ?? {};\n const registered = Object.values(hooks).some((entries) =>\n (entries ?? []).some((e) =>\n (e.hooks ?? []).some((h) =>\n isHomeBinHookCommand(h.command, homeBin, connectorId),\n ),\n ),\n );\n return registered\n ? { status: \"OK\", detail: \"hook command present\" }\n : { status: \"FAIL\", detail: `no hook for ${connectorId} in ${settingsPath}` };\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 Gemini stdin JSON → normalized event ──────────────────\n\n parseEvent(event: HookEventName, raw: unknown): NormalizedEvent {\n const input = (raw ?? {}) as GeminiWireInput;\n const connectorId = typeof input.connector === \"string\" ? input.connector : \"\";\n const sessionId = typeof input.session_id === \"string\" ? input.session_id : \"\";\n const projectDir = typeof input.cwd === \"string\" ? input.cwd : undefined;\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 ev: PostToolUseEvent = {\n ...base,\n toolName: input.tool_name ?? \"\",\n toolInput: input.tool_input ?? {},\n ...(input.tool_output !== undefined ? { toolOutput: input.tool_output } : {}),\n ...(input.is_error === true ? { isError: true } : {}),\n };\n return ev;\n }\n case \"SessionStart\": {\n const ev: SessionStartEvent = {\n ...base,\n source: normalizeSessionSource(input.source),\n };\n return ev;\n }\n case \"SessionEnd\": {\n const ev: SessionEndEvent = {\n ...base,\n ...(typeof input.reason === \"string\" ? { reason: input.reason } : {}),\n };\n return ev;\n }\n case \"UserPromptSubmit\": {\n const ev: UserPromptSubmitEvent = {\n ...base,\n prompt: typeof input.prompt === \"string\" ? input.prompt : \"\",\n };\n return ev;\n }\n case \"PreCompact\": {\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 \"Notification\": {\n const ev: NotificationEvent = {\n ...base,\n message: typeof input.message === \"string\" ? input.message : \"\",\n };\n return ev;\n }\n default: {\n // Gemini never delivers `Stop` (no native equivalent). If the runtime\n // dispatches one anyway, surface it as an explicit unsupported error so\n // the mismatch is loud rather than silently mis-parsed.\n throw new Error(`unsupported gemini-cli hook event: ${String(event)}`);\n }\n }\n }\n\n // ── Runtime: normalized response → Gemini native hook reply ──────────────\n\n formatReply(event: HookEventName, response: HookResponse): HookReply {\n const decision = response.decision ?? \"allow\";\n\n // deny → Gemini blocks via a top-level `decision:\"deny\"` + reason (NOT the\n // Claude-style permissionDecision wrapper).\n if (decision === \"deny\") {\n return this.stdout({\n decision: \"deny\",\n reason: response.reason ?? \"Blocked by hook\",\n });\n }\n\n // ask → Gemini has no native \"ask\"; degrade to deny to stay fail-safe.\n if (decision === \"ask\") {\n return this.stdout({\n decision: \"deny\",\n reason: response.reason ?? \"Action requires user confirmation (security policy)\",\n });\n }\n\n // modify → rewrite BeforeTool input. Gemini merges tool_input with the\n // original; output rewrite on AfterTool is expressed as deny + reason.\n if (decision === \"modify\") {\n if (event === \"PreToolUse\" && response.updatedInput) {\n return this.stdout({\n hookSpecificOutput: { tool_input: response.updatedInput },\n });\n }\n if (event === \"PostToolUse\" && response.updatedOutput !== undefined) {\n return this.stdout({ decision: \"deny\", reason: response.updatedOutput });\n }\n // Nothing to apply; fall through to allow.\n }\n\n // context → inject soft guidance via hookSpecificOutput.additionalContext\n // (also the SessionStart / BeforeAgent context-injection path).\n if (decision === \"context\" && response.additionalContext) {\n return this.stdout({\n hookSpecificOutput: { additionalContext: response.additionalContext },\n });\n }\n\n // allow / void / unsupported-degradation → pass through with exit 0.\n return { exitCode: 0 };\n }\n\n private stdout(payload: unknown): HookReply {\n return { exitCode: 0, stdout: JSON.stringify(payload) };\n }\n}\n\nfunction normalizeSessionSource(source: string | undefined): SessionStartEvent[\"source\"] {\n switch (source) {\n case \"compact\":\n return \"compact\";\n case \"resume\":\n return \"resume\";\n case \"clear\":\n return \"clear\";\n default:\n return \"startup\";\n }\n}\n\nexport const adapter = new GeminiCliAdapter();\nexport default adapter;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AA6DA,SAAS,kBAAkB;AAC3B,SAAS,eAAe;AACxB,SAAS,YAAY;AAsCrB,IAAM,OAAmB;AACzB,IAAM,eAAe;AAMrB,IAAM,eAAe;AAAA,EACnB,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,aAAa;AAAA,EACb,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,cAAc;AAAA;AAAA,EAEd,YAAY;AACd;AAOA,IAAM,YAAoD;AAAA,EACxD,YAAY,aAAa;AAAA,EACzB,aAAa,aAAa;AAAA,EAC1B,YAAY,aAAa;AAAA,EACzB,cAAc,aAAa;AAAA,EAC3B,YAAY,aAAa;AAAA,EACzB,kBAAkB,aAAa;AAAA,EAC/B,cAAc,aAAa;AAC7B;AAqDO,IAAM,mBAAN,cAA+B,YAA+B;AAAA,EAC1D,KAAiB;AAAA,EACjB,OAAO;AAAA,EACP,WAAyB;AAAA,EAEzB,eAAqC;AAAA;AAAA;AAAA,IAG5C,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,MAAM;AAAA,IACN,cAAc;AAAA;AAAA;AAAA;AAAA,IAId,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,yBAAyB;AAAA;AAAA,IAEzB,YAAY,CAAC,SAAS,OAAO,MAAM;AAAA;AAAA;AAAA;AAAA,IAInC,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,mBAAmB;AAAA,EACrB;AAAA;AAAA,EAIA,gBAAgB,YAAsC;AACpD,UAAM,UAAU,KAAK,QAAQ,GAAG,SAAS;AACzC,UAAM,eAAe,KAAK,SAAS,eAAe;AAClD,UAAM,mBAAmB,KAAK,YAAY,SAAS;AACnD,UAAM,kBAAkB,KAAK,kBAAkB,eAAe;AAC9D,UAAM,gBAAgB,WAAW,OAAO,KAAK,WAAW,YAAY;AACpE,UAAM,gBAAgB,WAAW,gBAAgB,KAAK,WAAW,eAAe;AAChF,UAAM,YAAY,iBAAiB;AAGnC,UAAM,QAAQ,iBAAiB,CAAC,gBAAgB,YAAY;AAC5D,UAAM,aAAa,UAAU,YAAY,kBAAkB;AAC3D,WAAO;AAAA,MACL,IAAI,KAAK;AAAA,MACT,MAAM,KAAK;AAAA,MACX;AAAA,MACA,UAAU,KAAK;AAAA,MACf,cAAc,KAAK;AAAA,MACnB;AAAA,MACA;AAAA,MACA,QAAQ,YACJ,UAAU,YACR,sCAAsC,eAAe,KACrD,iCAAiC,OAAO,KAC1C,2BAA2B,OAAO;AAAA,MACtC,YAAY,YAAY,SAAS;AAAA,IACnC;AAAA,EACF;AAAA;AAAA,EAIA,aAAa,KAA6B;AACxC,WAAO,IAAI,UAAU,YACjB,KAAK,IAAI,YAAY,SAAS,IAC9B,KAAK,QAAQ,GAAG,SAAS;AAAA,EAC/B;AAAA;AAAA,EAGA,oBAAoB,KAA6B;AAC/C,WAAO,KAAK,KAAK,aAAa,GAAG,GAAG,eAAe;AAAA,EACrD;AAAA;AAAA,EAGA,kBAAkB,KAA6B;AAC7C,WAAO,KAAK,KAAK,aAAa,GAAG,GAAG,eAAe;AAAA,EACrD;AAAA;AAAA,EAIA,cAAc,KAAqC;AACjD,UAAM,EAAE,UAAU,IAAI;AACtB,UAAM,WAAW,UAAU,UAAU,IAAI,GAAG;AAC5C,QAAI,CAAC,UAAU,UAAU,aAAa,OAAO;AAC3C,aAAO;AAAA,QACL;AAAA,UACE,UAAU,KAAK;AAAA,UACf,QAAQ;AAAA,UACR,QAAQ,UAAU,SACd,gDACA;AAAA,QACN;AAAA,MACF;AAAA,IACF;AAGA,UAAM,SACJ,YAAY,OAAO,aAAa,WAC5B,EAAE,GAAG,UAAU,QAAQ,GAAG,SAAS,IACnC,UAAU;AAEhB,UAAM,aAAa,KAAK,oBAAoB,GAAG;AAC/C,UAAM,QAAQ,KAAK,kBAAkB,KAAK,MAAM;AAEhD,WAAO;AAAA,MACL,KAAK,mBAAmB,YAAY,cAAc,UAAU,IAAI,OAAO,IAAI,MAAM;AAAA,IACnF;AAAA,EACF;AAAA,EAEA,gBAAgB,KAAqC;AACnD,UAAM,aAAa,KAAK,oBAAoB,GAAG;AAC/C,WAAO;AAAA,MACL,KAAK,qBAAqB,YAAY,cAAc,IAAI,UAAU,IAAI,IAAI,MAAM;AAAA,IAClF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,kBACN,KACA,QACwD;AACxD,UAAM,YAAuB,OAAO;AAEpC,QAAI,cAAc,SAAS;AACzB,UAAI,UAAU,OAAO,WAAW;AAChC,UAAI,OAAO,CAAC,GAAI,OAAO,QAAQ,CAAC,CAAE;AAIlC,UAAI,uBAAuB,QAAQ,IAAI,UAAU,SAAS,GAAG;AAC3D,cAAM,UAAU;AAAA,UACd,IAAI;AAAA,UACJ,IAAI,UAAU;AAAA,UACd;AAAA,UACA;AAAA,UACA,IAAI;AAAA,UACJ,KAAK;AAAA,QACP;AACA,kBAAU,QAAQ;AAClB,eAAO,QAAQ;AAAA,MACjB;AAEA,YAAMA,SAA2B,EAAE,SAAS,mBAAmB,OAAO,EAAE;AACxE,UAAI,KAAK,SAAS,EAAG,CAAAA,OAAM,OAAO,KAAK,IAAI,CAAC,MAAM,mBAAmB,CAAC,CAAC;AACvE,YAAM,MAAM,KAAK,UAAU,OAAO,GAAG;AACrC,UAAI,IAAK,CAAAA,OAAM,MAAM;AACrB,UAAI,OAAO,IAAK,CAAAA,OAAM,MAAM,mBAAmB,OAAO,GAAG;AACzD,aAAOA;AAAA,IACT;AAGA,QAAI,cAAc,OAAO;AACvB,YAAMA,SAAyB,EAAE,KAAK,mBAAmB,OAAO,OAAO,EAAE,EAAE;AAC3E,YAAMC,WAAU,KAAK,UAAU,OAAO,OAAO;AAC7C,UAAIA,SAAS,CAAAD,OAAM,UAAUC;AAC7B,aAAOD;AAAA,IACT;AAGA,UAAM,QAA0B,EAAE,SAAS,mBAAmB,OAAO,OAAO,EAAE,EAAE;AAChF,UAAM,UAAU,KAAK,UAAU,OAAO,OAAO;AAC7C,QAAI,QAAS,OAAM,UAAU;AAC7B,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,UACN,KACoC;AACpC,QAAI,CAAC,OAAO,OAAO,KAAK,GAAG,EAAE,WAAW,EAAG,QAAO;AAClD,WAAO,mBAAmB,EAAE,GAAG,IAAI,CAAC;AAAA,EACtC;AAAA;AAAA,EAIA,aAAa,KAAqC;AAChD,UAAM,EAAE,UAAU,IAAI;AACtB,QAAI,UAAU,UAAU,IAAI,GAAG,UAAU,OAAO;AAC9C,aAAO,CAAC,EAAE,UAAU,KAAK,IAAI,QAAQ,QAAQ,QAAQ,gCAAgC,CAAC;AAAA,IACxF;AAIA,UAAM,aAAa,yBAAyB,UAAU,SAAS;AAC/D,QAAI,UAAU,WAAW,WAAW,KAAK,CAAC,YAAY;AACpD,aAAO,CAAC,EAAE,UAAU,KAAK,IAAI,QAAQ,QAAQ,QAAQ,8BAA8B,CAAC;AAAA,IACtF;AAEA,UAAM,eAAe,KAAK,kBAAkB,GAAG;AAC/C,UAAM,WAAW,KAAK,SAA6B,YAAY,KAAK,CAAC;AACrE,UAAM,QAAS,SAAS,UAAU,CAAC;AAEnC,UAAM,UAA0B,CAAC;AACjC,QAAI,UAAU;AAEd,eAAW,SAAS,UAAU,YAAY;AACxC,YAAM,cAAc,UAAU,KAAK;AACnC,UAAI,CAAC,aAAa;AAEhB,gBAAQ,KAAK;AAAA,UACX,UAAU,KAAK;AAAA,UACf,QAAQ;AAAA,UACR,MAAM;AAAA,UACN,QAAQ,GAAG,KAAK;AAAA,QAClB,CAAC;AACD;AAAA,MACF;AAEA,YAAM,UAAU,wBAAwB,IAAI,aAAa,MAAM,OAAO,UAAU,EAAE;AAClF,YAAM,UAAU,UAAU,MAAM,KAAK,GAAG,WAAW;AACnD,YAAM,QAAyB;AAAA,QAC7B;AAAA,QACA,OAAO,CAAC,EAAE,MAAM,WAAW,QAAQ,CAAC;AAAA,MACtC;AAEA,YAAM,SAAU,MAAM,WAAW,MAAM,CAAC;AACxC,YAAM,cAAc,OAAO,UAAU,CAAC,MAAM,KAAK,mBAAmB,GAAG,GAAG,CAAC;AAE3E,UAAI,eAAe,GAAG;AACpB,YAAI,KAAK,UAAU,OAAO,WAAW,CAAC,MAAM,KAAK,UAAU,KAAK,GAAG;AACjE,kBAAQ,KAAK;AAAA,YACX,UAAU,KAAK;AAAA,YACf,QAAQ;AAAA,YACR,MAAM;AAAA,YACN,QAAQ,SAAS,WAAW;AAAA,UAC9B,CAAC;AACD;AAAA,QACF;AACA,eAAO,WAAW,IAAI;AACtB,gBAAQ,KAAK;AAAA,UACX,UAAU,KAAK;AAAA,UACf,QAAQ;AAAA,UACR,MAAM;AAAA,UACN,QAAQ,SAAS,WAAW;AAAA,QAC9B,CAAC;AAAA,MACH,OAAO;AACL,eAAO,KAAK,KAAK;AACjB,gBAAQ,KAAK;AAAA,UACX,UAAU,KAAK;AAAA,UACf,QAAQ;AAAA,UACR,MAAM;AAAA,UACN,QAAQ,SAAS,WAAW;AAAA,QAC9B,CAAC;AAAA,MACH;AACA,gBAAU;AAAA,IACZ;AAKA,QAAI,YAAY;AACd,UAAI,KAAK,iBAAiB,OAAO,KAAK,cAAc,OAAO,EAAG,WAAU;AAAA,IAC1E;AAEA,QAAI,QAAS,MAAK,UAAU,cAAc,UAAU,IAAI,MAAM;AAC9D,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,iBACN,OACA,KACA,cACA,SACS;AACT,UAAM,UAAU,uBAAuB,IAAI,aAAa,MAAM,IAAI,UAAU,EAAE;AAC9E,UAAM,QAAyB;AAAA,MAC7B,SAAS;AAAA,MACT,OAAO,CAAC,EAAE,MAAM,WAAW,QAAQ,CAAC;AAAA,IACtC;AACA,UAAM,SAAU,MAAM,aAAa,UAAU,MAAM,CAAC;AACpD,UAAM,cAAc,OAAO;AAAA,MAAU,CAAC,OACnC,EAAE,SAAS,CAAC,GAAG,KAAK,CAAC,MAAM,oBAAoB,EAAE,SAAS,IAAI,aAAa,IAAI,UAAU,EAAE,CAAC;AAAA,IAC/F;AAEA,QAAI,eAAe,GAAG;AACpB,UAAI,KAAK,UAAU,OAAO,WAAW,CAAC,MAAM,KAAK,UAAU,KAAK,GAAG;AACjE,gBAAQ,KAAK;AAAA,UACX,UAAU,KAAK;AAAA,UACf,QAAQ;AAAA,UACR,MAAM;AAAA,UACN,QAAQ,SAAS,aAAa,UAAU;AAAA,QAC1C,CAAC;AACD,eAAO;AAAA,MACT;AACA,aAAO,WAAW,IAAI;AACtB,cAAQ,KAAK;AAAA,QACX,UAAU,KAAK;AAAA,QACf,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,QAAQ,SAAS,aAAa,UAAU;AAAA,MAC1C,CAAC;AAAA,IACH,OAAO;AACL,aAAO,KAAK,KAAK;AACjB,cAAQ,KAAK;AAAA,QACX,UAAU,KAAK;AAAA,QACf,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,QAAQ,SAAS,aAAa,UAAU;AAAA,MAC1C,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AAAA,EAEA,eAAe,KAAqC;AAClD,UAAM,eAAe,KAAK,kBAAkB,GAAG;AAC/C,UAAM,WAAW,KAAK,SAA6B,YAAY;AAC/D,UAAM,QAAQ,UAAU;AACxB,QAAI,CAAC,YAAY,CAAC,OAAO;AACvB,aAAO;AAAA,QACL;AAAA,UACE,UAAU,KAAK;AAAA,UACf,QAAQ;AAAA,UACR,MAAM;AAAA,UACN,QAAQ;AAAA,QACV;AAAA,MACF;AAAA,IACF;AAEA,UAAM,UAA0B,CAAC;AACjC,QAAI,UAAU;AAEd,eAAW,eAAe,OAAO,KAAK,KAAK,GAAG;AAC5C,YAAM,SAAS,MAAM,WAAW;AAChC,UAAI,CAAC,MAAM,QAAQ,MAAM,EAAG;AAI5B,YAAM,OAA0B,CAAC;AACjC,UAAI,UAAU;AACd,iBAAW,KAAK,QAAQ;AACtB,cAAM,cAAc,EAAE,OAAO,UAAU;AACvC,cAAM,SAAS,EAAE,SAAS,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,aAAa,EAAE,SAAS,GAAG,CAAC;AAC9E,mBAAW,cAAc,MAAM;AAC/B,YAAI,MAAM,SAAS,EAAG,MAAK,KAAK,EAAE,SAAS,EAAE,WAAW,IAAI,OAAO,MAAM,CAAC;AAAA,MAC5E;AAEA,UAAI,UAAU,GAAG;AACf,YAAI,KAAK,SAAS,EAAG,OAAM,WAAW,IAAI;AAAA,YACrC,QAAO,MAAM,WAAW;AAC7B,gBAAQ,KAAK;AAAA,UACX,UAAU,KAAK;AAAA,UACf,QAAQ;AAAA,UACR,MAAM;AAAA,UACN,QAAQ,SAAS,WAAW,KAAK,OAAO;AAAA,QAC1C,CAAC;AACD,kBAAU;AAAA,MACZ;AAAA,IACF;AAEA,QAAI,QAAS,MAAK,UAAU,cAAc,UAAU,IAAI,MAAM;AAC9D,QAAI,QAAQ,WAAW,GAAG;AACxB,cAAQ,KAAK;AAAA,QACX,UAAU,KAAK;AAAA,QACf,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,QAAQ;AAAA,MACV,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,mBAAmB,OAAwB,KAA8B;AAC/E,YAAQ,MAAM,SAAS,CAAC,GAAG,KAAK,CAAC,MAAM,KAAK,aAAa,EAAE,SAAS,GAAG,CAAC;AAAA,EAC1E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,aAAa,SAA6B,KAA8B;AAC9E,WACE,qBAAqB,SAAS,IAAI,aAAa,IAAI,UAAU,EAAE,KAC/D,oBAAoB,SAAS,IAAI,aAAa,IAAI,UAAU,EAAE;AAAA,EAElE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWQ,YAAY,KAA6B;AAC/C,WAAO,KAAK,KAAK,aAAa,GAAG,GAAG,UAAU;AAAA,EAChD;AAAA,EACQ,UAAU,KAA6B;AAC7C,WAAO,KAAK,KAAK,aAAa,GAAG,GAAG,QAAQ;AAAA,EAC9C;AAAA,EACQ,UAAU,KAA6B;AAC7C,WAAO,KAAK,KAAK,aAAa,GAAG,GAAG,QAAQ;AAAA,EAC9C;AAAA;AAAA,EAGQ,YAAY,KAAqB,MAAsB;AAC7D,WAAO,KAAK,KAAK,YAAY,GAAG,GAAG,GAAG,IAAI,OAAO;AAAA,EACnD;AAAA;AAAA,EAEQ,SAAS,KAAqB,MAAsB;AAC1D,WAAO,KAAK,KAAK,UAAU,GAAG,GAAG,IAAI;AAAA,EACvC;AAAA;AAAA,EAEQ,aAAa,KAAqB,MAAsB;AAC9D,WAAO,KAAK,KAAK,UAAU,GAAG,GAAG,GAAG,IAAI,KAAK;AAAA,EAC/C;AAAA;AAAA,EAIS,gBAAgB,KAAqC;AAC5D,UAAM,EAAE,UAAU,IAAI;AACtB,QAAI,UAAU,UAAU,IAAI,GAAG,aAAa,OAAO;AACjD,aAAO,CAAC,EAAE,UAAU,KAAK,IAAI,QAAQ,QAAQ,QAAQ,mCAAmC,CAAC;AAAA,IAC3F;AACA,QAAI,UAAU,SAAS,WAAW,GAAG;AACnC,aAAO,CAAC,EAAE,UAAU,KAAK,IAAI,QAAQ,QAAQ,QAAQ,iCAAiC,CAAC;AAAA,IACzF;AACA,WAAO,UAAU,SAAS;AAAA,MAAI,CAAC,QAC7B,KAAK,iBAAiB,KAAK,YAAY,KAAK,IAAI,IAAI,GAAG,KAAK,cAAc,GAAG,GAAG,IAAI,MAAM;AAAA,IAC5F;AAAA,EACF;AAAA,EAES,kBAAkB,KAAqC;AAC9D,UAAM,EAAE,UAAU,IAAI;AACtB,QAAI,UAAU,SAAS,WAAW,GAAG;AACnC,aAAO,CAAC,EAAE,UAAU,KAAK,IAAI,QAAQ,QAAQ,QAAQ,iCAAiC,CAAC;AAAA,IACzF;AACA,WAAO,UAAU,SAAS;AAAA,MAAI,CAAC,QAC7B,KAAK,kBAAkB,KAAK,YAAY,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM;AAAA,IACpE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,cAAc,KAAyB;AAC7C,UAAM,MAA+B,CAAC;AACtC,QAAI,IAAI,gBAAgB,OAAW,KAAI,cAAc,IAAI;AACzD,QAAI,SAAS,IAAI;AACjB,WAAO,gBAAgB,GAAG;AAAA,EAC5B;AAAA;AAAA,EAIS,cAAc,KAAqC;AAC1D,UAAM,EAAE,UAAU,IAAI;AACtB,QAAI,UAAU,UAAU,IAAI,GAAG,WAAW,OAAO;AAC/C,aAAO,CAAC,EAAE,UAAU,KAAK,IAAI,QAAQ,QAAQ,QAAQ,iCAAiC,CAAC;AAAA,IACzF;AACA,QAAI,UAAU,OAAO,WAAW,GAAG;AACjC,aAAO,CAAC,EAAE,UAAU,KAAK,IAAI,QAAQ,QAAQ,QAAQ,+BAA+B,CAAC;AAAA,IACvF;AACA,UAAM,UAA0B,CAAC;AACjC,eAAW,SAAS,UAAU,QAAQ;AACpC,YAAM,MAAM,KAAK,SAAS,KAAK,MAAM,IAAI;AACzC,cAAQ;AAAA,QACN,KAAK,iBAAiB,KAAK,KAAK,UAAU,GAAG,KAAK,YAAY,KAAK,GAAG,IAAI,MAAM;AAAA,MAClF;AAIA,iBAAW,CAAC,KAAK,QAAQ,KAAK,OAAO,QAAQ,MAAM,aAAa,CAAC,CAAC,GAAG;AACnE,cAAM,SAAS,KAAK,cAAc,KAAK,GAAG;AAC1C,YAAI,WAAW,MAAM;AACnB,kBAAQ,KAAK;AAAA,YACX,UAAU,KAAK;AAAA,YACf,QAAQ;AAAA,YACR,QAAQ,mBAAmB,GAAG;AAAA,UAChC,CAAC;AACD;AAAA,QACF;AACA,gBAAQ,KAAK,KAAK,iBAAiB,QAAQ,UAAU,IAAI,MAAM,CAAC;AAAA,MAClE;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAES,gBAAgB,KAAqC;AAC5D,UAAM,EAAE,UAAU,IAAI;AACtB,QAAI,UAAU,OAAO,WAAW,GAAG;AACjC,aAAO,CAAC,EAAE,UAAU,KAAK,IAAI,QAAQ,QAAQ,QAAQ,+BAA+B,CAAC;AAAA,IACvF;AACA,UAAM,UAA0B,CAAC;AACjC,eAAW,SAAS,UAAU,QAAQ;AACpC,YAAM,MAAM,KAAK,SAAS,KAAK,MAAM,IAAI;AAGzC,cAAQ,KAAK,KAAK,kBAAkB,KAAK,KAAK,UAAU,GAAG,IAAI,MAAM,CAAC;AACtE,iBAAW,OAAO,OAAO,KAAK,MAAM,aAAa,CAAC,CAAC,GAAG;AACpD,cAAM,SAAS,KAAK,cAAc,KAAK,GAAG;AAC1C,YAAI,WAAW,KAAM;AACrB,gBAAQ,KAAK,KAAK,kBAAkB,QAAQ,IAAI,MAAM,CAAC;AAAA,MACzD;AAGA,cAAQ,KAAK,KAAK,iBAAiB,KAAK,IAAI,MAAM,CAAC;AAAA,IACrD;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,YAAY,OAAyB;AAC3C,UAAM,cAAuC;AAAA,MAC3C,MAAM,MAAM;AAAA,MACZ,aAAa,MAAM;AAAA,IACrB;AACA,QAAI,MAAM,UAAU,OAAW,aAAY,QAAQ,MAAM;AACzD,UAAM,QAAQ,MAAM,OAAO;AAC3B,QAAI,SAAS,MAAM,SAAS,EAAG,aAAY,eAAe,IAAI,MAAM,KAAK,IAAI;AAC7E,QAAI,MAAM,2BAA2B,QAAW;AAC9C,kBAAY,0BAA0B,IAAI,MAAM;AAAA,IAClD;AACA,QAAI,MAAM,MAAO,QAAO,OAAO,aAAa,MAAM,KAAK;AACvD,WAAO,KAAK,oBAAoB,aAAa,MAAM,IAAI;AAAA,EACzD;AAAA;AAAA,EAIS,iBAAiB,KAAqC;AAC7D,UAAM,EAAE,UAAU,IAAI;AACtB,QAAI,UAAU,UAAU,IAAI,GAAG,cAAc,OAAO;AAClD,aAAO,CAAC,EAAE,UAAU,KAAK,IAAI,QAAQ,QAAQ,QAAQ,oCAAoC,CAAC;AAAA,IAC5F;AACA,QAAI,UAAU,UAAU,WAAW,GAAG;AACpC,aAAO,CAAC,EAAE,UAAU,KAAK,IAAI,QAAQ,QAAQ,QAAQ,kCAAkC,CAAC;AAAA,IAC1F;AACA,WAAO,UAAU,UAAU;AAAA,MAAI,CAAC,UAC9B,KAAK,iBAAiB,KAAK,aAAa,KAAK,MAAM,IAAI,GAAG,KAAK,eAAe,KAAK,GAAG,IAAI,MAAM;AAAA,IAClG;AAAA,EACF;AAAA,EAES,mBAAmB,KAAqC;AAC/D,UAAM,EAAE,UAAU,IAAI;AACtB,QAAI,UAAU,UAAU,WAAW,GAAG;AACpC,aAAO,CAAC,EAAE,UAAU,KAAK,IAAI,QAAQ,QAAQ,QAAQ,kCAAkC,CAAC;AAAA,IAC1F;AACA,WAAO,UAAU,UAAU;AAAA,MAAI,CAAC,UAC9B,KAAK,kBAAkB,KAAK,aAAa,KAAK,MAAM,IAAI,GAAG,IAAI,MAAM;AAAA,IACvE;AAAA,EACF;AAAA;AAAA,EAGQ,eAAe,OAA4B;AACjD,UAAM,cAAuC;AAAA,MAC3C,MAAM,MAAM;AAAA,MACZ,aAAa,MAAM;AAAA,IACrB;AACA,UAAM,QAAQ,MAAM,OAAO;AAC3B,QAAI,SAAS,MAAM,SAAS,EAAG,aAAY,QAAQ,MAAM,KAAK,IAAI;AAClE,QAAI,MAAM,UAAU,OAAW,aAAY,QAAQ,MAAM;AACzD,QAAI,MAAM,MAAO,QAAO,OAAO,aAAa,MAAM,KAAK;AACvD,WAAO,KAAK,oBAAoB,aAAa,MAAM,MAAM;AAAA,EAC3D;AAAA;AAAA,EAIS,gBAAgB,KAA6C;AACpE,UAAM,eAAe,KAAK,oBAAoB,GAAG;AACjD,UAAM,cAAc,IAAI,UAAU;AAClC,UAAM,UAAU,IAAI;AACpB,UAAM,aAAa,IAAI,UAAU;AACjC,UAAM,SAAwB;AAAA,MAC5B;AAAA,QACE,MAAM,GAAG,KAAK,IAAI;AAAA,QAClB,OAAO,MACL,WAAW,YAAY,IACnB,EAAE,QAAQ,MAAM,QAAQ,aAAa,IACrC,EAAE,QAAQ,QAAQ,QAAQ,cAAc,YAAY,GAAG;AAAA,MAC/D;AAAA,MACA;AAAA,QACE,MAAM,GAAG,KAAK,IAAI;AAAA,QAClB,OAAO,MAAM;AACX,cAAI,WAAW,WAAW,GAAG;AAC3B,mBAAO,EAAE,QAAQ,MAAM,QAAQ,oBAAoB;AAAA,UACrD;AACA,gBAAM,WAAW,KAAK,SAA6B,YAAY;AAC/D,cAAI,CAAC,SAAU,QAAO,EAAE,QAAQ,QAAQ,QAAQ,eAAe,YAAY,GAAG;AAC9E,gBAAM,QAAQ,SAAS,SAAS,CAAC;AACjC,gBAAM,aAAa,OAAO,OAAO,KAAK,EAAE;AAAA,YAAK,CAAC,aAC3C,WAAW,CAAC,GAAG;AAAA,cAAK,CAAC,OACnB,EAAE,SAAS,CAAC,GAAG;AAAA,gBAAK,CAAC,MACpB,qBAAqB,EAAE,SAAS,SAAS,WAAW;AAAA,cACtD;AAAA,YACF;AAAA,UACF;AACA,iBAAO,aACH,EAAE,QAAQ,MAAM,QAAQ,uBAAuB,IAC/C,EAAE,QAAQ,QAAQ,QAAQ,eAAe,WAAW,OAAO,YAAY,GAAG;AAAA,QAChF;AAAA,MACF;AAAA,IACF;AAIA,eAAW,OAAO,IAAI,UAAU,UAAU;AACxC,YAAM,IAAI,KAAK,YAAY,KAAK,IAAI,IAAI;AACxC,aAAO,KAAK;AAAA,QACV,MAAM,GAAG,KAAK,IAAI,aAAa,IAAI,IAAI;AAAA,QACvC,OAAO,MACL,WAAW,CAAC,IAAI,EAAE,QAAQ,MAAM,QAAQ,EAAE,IAAI,EAAE,QAAQ,QAAQ,QAAQ,cAAc,CAAC,GAAG;AAAA,MAC9F,CAAC;AAAA,IACH;AACA,eAAW,SAAS,IAAI,UAAU,QAAQ;AACxC,YAAM,IAAI,KAAK,KAAK,SAAS,KAAK,MAAM,IAAI,GAAG,UAAU;AACzD,aAAO,KAAK;AAAA,QACV,MAAM,GAAG,KAAK,IAAI,WAAW,MAAM,IAAI;AAAA,QACvC,OAAO,MACL,WAAW,CAAC,IAAI,EAAE,QAAQ,MAAM,QAAQ,EAAE,IAAI,EAAE,QAAQ,QAAQ,QAAQ,cAAc,CAAC,GAAG;AAAA,MAC9F,CAAC;AAAA,IACH;AACA,eAAW,SAAS,IAAI,UAAU,WAAW;AAC3C,YAAM,IAAI,KAAK,aAAa,KAAK,MAAM,IAAI;AAC3C,aAAO,KAAK;AAAA,QACV,MAAM,GAAG,KAAK,IAAI,cAAc,MAAM,IAAI;AAAA,QAC1C,OAAO,MACL,WAAW,CAAC,IAAI,EAAE,QAAQ,MAAM,QAAQ,EAAE,IAAI,EAAE,QAAQ,QAAQ,QAAQ,cAAc,CAAC,GAAG;AAAA,MAC9F,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAIA,WAAW,OAAsB,KAA+B;AAC9D,UAAM,QAAS,OAAO,CAAC;AACvB,UAAM,cAAc,OAAO,MAAM,cAAc,WAAW,MAAM,YAAY;AAC5E,UAAM,YAAY,OAAO,MAAM,eAAe,WAAW,MAAM,aAAa;AAC5E,UAAM,aAAa,OAAO,MAAM,QAAQ,WAAW,MAAM,MAAM;AAE/D,UAAM,OAAO;AAAA,MACX,cAAc;AAAA,MACd;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAI,eAAe,SAAY,EAAE,WAAW,IAAI,CAAC;AAAA,IACnD;AAEA,YAAQ,OAAO;AAAA,MACb,KAAK,cAAc;AACjB,cAAM,KAAsB;AAAA,UAC1B,GAAG;AAAA,UACH,UAAU,MAAM,aAAa;AAAA,UAC7B,WAAW,MAAM,cAAc,CAAC;AAAA,QAClC;AACA,eAAO;AAAA,MACT;AAAA,MACA,KAAK,eAAe;AAClB,cAAM,KAAuB;AAAA,UAC3B,GAAG;AAAA,UACH,UAAU,MAAM,aAAa;AAAA,UAC7B,WAAW,MAAM,cAAc,CAAC;AAAA,UAChC,GAAI,MAAM,gBAAgB,SAAY,EAAE,YAAY,MAAM,YAAY,IAAI,CAAC;AAAA,UAC3E,GAAI,MAAM,aAAa,OAAO,EAAE,SAAS,KAAK,IAAI,CAAC;AAAA,QACrD;AACA,eAAO;AAAA,MACT;AAAA,MACA,KAAK,gBAAgB;AACnB,cAAM,KAAwB;AAAA,UAC5B,GAAG;AAAA,UACH,QAAQ,uBAAuB,MAAM,MAAM;AAAA,QAC7C;AACA,eAAO;AAAA,MACT;AAAA,MACA,KAAK,cAAc;AACjB,cAAM,KAAsB;AAAA,UAC1B,GAAG;AAAA,UACH,GAAI,OAAO,MAAM,WAAW,WAAW,EAAE,QAAQ,MAAM,OAAO,IAAI,CAAC;AAAA,QACrE;AACA,eAAO;AAAA,MACT;AAAA,MACA,KAAK,oBAAoB;AACvB,cAAM,KAA4B;AAAA,UAChC,GAAG;AAAA,UACH,QAAQ,OAAO,MAAM,WAAW,WAAW,MAAM,SAAS;AAAA,QAC5D;AACA,eAAO;AAAA,MACT;AAAA,MACA,KAAK,cAAc;AACjB,cAAM,KAAsB;AAAA,UAC1B,GAAG;AAAA,UACH,GAAI,MAAM,YAAY,UAAU,MAAM,YAAY,WAC9C,EAAE,SAAS,MAAM,QAAQ,IACzB,CAAC;AAAA,QACP;AACA,eAAO;AAAA,MACT;AAAA,MACA,KAAK,gBAAgB;AACnB,cAAM,KAAwB;AAAA,UAC5B,GAAG;AAAA,UACH,SAAS,OAAO,MAAM,YAAY,WAAW,MAAM,UAAU;AAAA,QAC/D;AACA,eAAO;AAAA,MACT;AAAA,MACA,SAAS;AAIP,cAAM,IAAI,MAAM,sCAAsC,OAAO,KAAK,CAAC,EAAE;AAAA,MACvE;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAIA,YAAY,OAAsB,UAAmC;AACnE,UAAM,WAAW,SAAS,YAAY;AAItC,QAAI,aAAa,QAAQ;AACvB,aAAO,KAAK,OAAO;AAAA,QACjB,UAAU;AAAA,QACV,QAAQ,SAAS,UAAU;AAAA,MAC7B,CAAC;AAAA,IACH;AAGA,QAAI,aAAa,OAAO;AACtB,aAAO,KAAK,OAAO;AAAA,QACjB,UAAU;AAAA,QACV,QAAQ,SAAS,UAAU;AAAA,MAC7B,CAAC;AAAA,IACH;AAIA,QAAI,aAAa,UAAU;AACzB,UAAI,UAAU,gBAAgB,SAAS,cAAc;AACnD,eAAO,KAAK,OAAO;AAAA,UACjB,oBAAoB,EAAE,YAAY,SAAS,aAAa;AAAA,QAC1D,CAAC;AAAA,MACH;AACA,UAAI,UAAU,iBAAiB,SAAS,kBAAkB,QAAW;AACnE,eAAO,KAAK,OAAO,EAAE,UAAU,QAAQ,QAAQ,SAAS,cAAc,CAAC;AAAA,MACzE;AAAA,IAEF;AAIA,QAAI,aAAa,aAAa,SAAS,mBAAmB;AACxD,aAAO,KAAK,OAAO;AAAA,QACjB,oBAAoB,EAAE,mBAAmB,SAAS,kBAAkB;AAAA,MACtE,CAAC;AAAA,IACH;AAGA,WAAO,EAAE,UAAU,EAAE;AAAA,EACvB;AAAA,EAEQ,OAAO,SAA6B;AAC1C,WAAO,EAAE,UAAU,GAAG,QAAQ,KAAK,UAAU,OAAO,EAAE;AAAA,EACxD;AACF;AAEA,SAAS,uBAAuB,QAAyD;AACvF,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAEO,IAAM,UAAU,IAAI,iBAAiB;AAC5C,IAAO,qBAAQ;","names":["entry","headers"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/adapters/goose/index.ts"],"sourcesContent":["/**\n * adapters/goose — Block's Goose platform adapter for agent-connector.\n *\n * Goose is a json-stdio host, but its two config surfaces use DIFFERENT formats:\n *\n * - MCP servers (Goose calls them \"extensions\") live in a YAML config under the\n * root key `extensions`. The native stdio entry shape is Goose-specific:\n * { type: \"stdio\", cmd: <exe>, args: [...], envs: {...}, timeout, enabled }\n * NOTE the field is `cmd` (NOT `command`) and the env map is `envs` (NOT\n * `env`). Because the file is YAML, the BaseAdapter JSON helpers do not apply\n * — we merge via core/yaml's readYaml/writeYaml, preserving any other config.\n *\n * - Hooks use Goose's Open Plugins system, which stores hook registrations in\n * JSON at <root>/.agents/plugins/<plugin-name>/hooks/hooks.json (project root\n * = <projectDir>/.agents; user root = ~/.agents):\n * { hooks: { <Event>: [ { matcher?, hooks:[{ type:\"command\", command }] } ] } }\n * The shape is the Claude-style NESTED rule (an optional `matcher` plus an\n * inner `hooks` array), and there is NO top-level `version` key. This file is\n * plain JSON, so the standard fs/JSON helpers are used for it.\n *\n * Wire protocol (parse) is Claude-compatible JSON on stdin, except Goose names\n * the working directory field `working_dir` (not `cwd`). The deny reply is\n * Goose's `{ decision: \"block\", reason }` (NOT Claude's hookSpecificOutput\n * permissionDecision shape).\n *\n * Native config locations (user scope):\n * - Linux/macOS: ~/.config/goose/config.yaml\n * - Windows: %APPDATA%/Block/goose/config/config.yaml\n */\n\nimport { existsSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\n\nimport { BaseAdapter } from \"../base.js\";\nimport type { Adapter, HookReply, InstallContext, NormalizedEvent } from \"../spi.js\";\nimport type {\n ChangeRecord,\n DetectedPlatform,\n HealthCheck,\n HookEventName,\n HookParadigm,\n HookResponse,\n NotificationEvent,\n PlatformCapabilities,\n PlatformId,\n PostToolUseEvent,\n PreCompactEvent,\n PreToolUseEvent,\n SessionEndEvent,\n SessionStartEvent,\n ServerDef,\n StopEvent,\n UserPromptSubmitEvent,\n} from \"../../core/types.js\";\nimport { ensureDir } from \"../../core/paths.js\";\nimport { readYaml, writeYaml } from \"../../core/yaml.js\";\nimport { resolveEnvRefsDeep } from \"../../core/interpolate.js\";\nimport {\n buildHomeBinHookCommand,\n buildServeWrapperCommand,\n isHomeBinHookCommand,\n shouldWrapForTelemetry,\n} from \"../../core/spawn.js\";\n\nconst HOST: PlatformId = \"goose\";\n/** Root key under which Goose stores MCP servers (\"extensions\") in config.yaml. */\nconst MCP_ROOT_KEY = \"extensions\";\n\n/**\n * Map each normalized hook event to the matching capability flag on this\n * adapter. The adapter's own `capabilities` literal is the single source of\n * truth for what Goose's Open-Plugins runtime delivers (PreToolUse/PostToolUse/\n * SessionStart); installHooks filters declared events through this map so an\n * unsupported event (e.g. UserPromptSubmit) is never written verbatim into\n * hooks.json — it is reported as a graceful warn/skip instead.\n */\nconst EVENT_CAPABILITY: Record<HookEventName, keyof PlatformCapabilities> = {\n SessionStart: \"sessionStart\",\n SessionEnd: \"sessionEnd\",\n UserPromptSubmit: \"userPromptSubmit\",\n PreToolUse: \"preToolUse\",\n PostToolUse: \"postToolUse\",\n PreCompact: \"preCompact\",\n Stop: \"stop\",\n Notification: \"notification\",\n};\n\n/**\n * Goose extension (MCP server) entry — note the Goose-specific field names:\n * `cmd` (not `command`) and `envs` (not `env`).\n */\ninterface GooseStdioExtension {\n type: \"stdio\";\n cmd: string;\n args: string[];\n envs?: Record<string, string>;\n timeout: number;\n enabled: boolean;\n}\n\n/** One inner command entry inside a hook rule. */\ninterface GooseHookCommand {\n type: \"command\";\n command: string;\n}\n\n/**\n * One nested-rule entry under a hook event. Goose's Open Plugins spec uses the\n * Claude-shaped nested rule: an optional `matcher` plus an inner `hooks` array\n * of `{ type, command }` commands (NOT a flat list of commands).\n */\ninterface GooseHookRule {\n matcher?: string;\n hooks: GooseHookCommand[];\n}\n\n/**\n * Goose Open-Plugins hooks.json shape: `{ hooks: { <Event>: [ rule, ... ] } }`.\n * There is NO top-level `version` key in the spec.\n */\ninterface GooseHooksFile {\n hooks: Record<string, GooseHookRule[]>;\n}\n\n/** Raw Goose hook stdin payload (Claude-compatible JSON). */\ninterface GooseWireInput {\n session_id?: string;\n /** Goose names the working directory `working_dir`; `cwd` is a fallback. */\n working_dir?: string;\n cwd?: string;\n hook_event_name?: string;\n tool_name?: string;\n tool_input?: Record<string, unknown>;\n tool_response?: unknown;\n source?: string;\n reason?: string;\n prompt?: string;\n trigger?: string;\n stop_hook_active?: boolean;\n message?: string;\n is_error?: boolean;\n /** Injected by the entrypoint so the runtime knows which connector to dispatch. */\n connector?: string;\n}\n\nexport class GooseAdapter extends BaseAdapter implements Adapter {\n readonly id: PlatformId = HOST;\n readonly name = \"Goose\";\n readonly paradigm: HookParadigm = \"json-stdio\";\n\n readonly capabilities: PlatformCapabilities = {\n preToolUse: true,\n postToolUse: true,\n preCompact: false,\n sessionStart: true,\n sessionEnd: false,\n userPromptSubmit: false,\n stop: false,\n notification: false,\n // Open Plugins documents PreToolUse/PostToolUse/SessionStart; argument\n // rewrite is not guaranteed across versions, so default to the safe value.\n canModifyArgs: false,\n canModifyOutput: false,\n canInjectSessionContext: true,\n transports: [\"stdio\", \"sse\", \"http\"],\n };\n\n // ── Detection ────────────────────────────────────────────────────────────\n\n detectInstalled(_projectDir: string): DetectedPlatform {\n const configPath = this.userConfigPath();\n const configDir = dirname(configPath);\n const installed = existsSync(configDir) || existsSync(configPath);\n return {\n id: this.id,\n name: this.name,\n installed,\n paradigm: this.paradigm,\n capabilities: this.capabilities,\n configPath,\n scope: \"user\",\n reason: installed\n ? `found Goose config at ${configPath}`\n : `no Goose config at ${configPath}`,\n confidence: installed ? \"high\" : \"low\",\n };\n }\n\n // ── Native paths ─────────────────────────────────────────────────────────\n\n override getConfigDir(_ctx: InstallContext): string {\n return dirname(this.userConfigPath());\n }\n\n /** MCP config: the YAML config.yaml (user scope). */\n override getServerConfigPath(_ctx: InstallContext): string {\n return this.userConfigPath();\n }\n\n /**\n * Hooks: Open-Plugins hooks.json under the `.agents/plugins/<plugin-name>/`\n * dir. The connector id is the plugin name. Project scope roots at\n * `<projectDir>/.agents`; user scope roots at `~/.agents`.\n */\n override getHookConfigPath(ctx: InstallContext): string {\n const root = ctx.scope === \"project\" ? ctx.projectDir : homedir();\n return join(root, \".agents\", \"plugins\", ctx.connector.id, \"hooks\", \"hooks.json\");\n }\n\n /**\n * OS-correct user config.yaml path:\n * - Windows: %APPDATA%/Block/goose/config/config.yaml\n * - macOS/Linux: ~/.config/goose/config.yaml\n */\n private userConfigPath(): string {\n if (process.platform === \"win32\") {\n const appData =\n process.env.APPDATA && process.env.APPDATA.trim() !== \"\"\n ? process.env.APPDATA\n : join(homedir(), \"AppData\", \"Roaming\");\n return join(appData, \"Block\", \"goose\", \"config\", \"config.yaml\");\n }\n return join(homedir(), \".config\", \"goose\", \"config.yaml\");\n }\n\n // ── MCP server install / uninstall (YAML — merge via readYaml/writeYaml) ──\n\n override installServer(ctx: InstallContext): ChangeRecord[] {\n const { connector, dryRun } = ctx;\n const path = this.getServerConfigPath(ctx);\n const server = this.effectiveServer(ctx);\n\n if (!server) {\n return [\n {\n platform: this.id,\n action: \"skip\",\n path,\n detail: connector.server\n ? \"server registration disabled for goose\"\n : \"connector declares no MCP server\",\n },\n ];\n }\n\n const entry = this.renderExtension(ctx, server);\n\n // Merge into existing YAML, preserving every other config key + extension.\n const cfg = readYaml<Record<string, unknown>>(path) ?? {};\n const bucketRaw = cfg[MCP_ROOT_KEY];\n const bucket: Record<string, unknown> =\n bucketRaw && typeof bucketRaw === \"object\" && !Array.isArray(bucketRaw)\n ? (bucketRaw as Record<string, unknown>)\n : {};\n cfg[MCP_ROOT_KEY] = bucket;\n\n const before = JSON.stringify(bucket[connector.id]);\n const after = JSON.stringify(entry);\n let action: ChangeRecord[\"action\"];\n if (before === undefined) action = \"create\";\n else if (before === after) action = \"skip\";\n else action = \"update\";\n\n if (action !== \"skip\") {\n bucket[connector.id] = entry;\n writeYaml(path, cfg, dryRun);\n }\n return [{ platform: this.id, action, path, detail: `${MCP_ROOT_KEY}.${connector.id}` }];\n }\n\n override uninstallServer(ctx: InstallContext): ChangeRecord[] {\n const { connector, dryRun } = ctx;\n const path = this.getServerConfigPath(ctx);\n const cfg = readYaml<Record<string, unknown>>(path);\n const bucketRaw = cfg?.[MCP_ROOT_KEY];\n if (\n !cfg ||\n !bucketRaw ||\n typeof bucketRaw !== \"object\" ||\n Array.isArray(bucketRaw) ||\n !(connector.id in (bucketRaw as Record<string, unknown>))\n ) {\n return [\n {\n platform: this.id,\n action: \"skip\",\n path,\n detail: `${MCP_ROOT_KEY}.${connector.id} absent`,\n },\n ];\n }\n delete (bucketRaw as Record<string, unknown>)[connector.id];\n writeYaml(path, cfg, dryRun);\n return [\n { platform: this.id, action: \"remove\", path, detail: `${MCP_ROOT_KEY}.${connector.id}` },\n ];\n }\n\n /**\n * Render a normalized ServerDef into Goose's native extension entry. Goose has\n * no native env interpolation, so `${env:VAR}` refs are resolved to literals at\n * install time. Honors the telemetry serve-wrapper (cmd=homeBin, args=[serve…]).\n */\n private renderExtension(ctx: InstallContext, server: ServerDef): GooseStdioExtension {\n let cmd = server.command ?? \"\";\n let args = [...(server.args ?? [])];\n\n if (shouldWrapForTelemetry(server, ctx.connector.telemetry)) {\n const wrapped = buildServeWrapperCommand(\n ctx.homeBinPath,\n ctx.connector.id,\n cmd,\n args,\n ctx.scope,\n this.id,\n );\n cmd = wrapped.command;\n args = wrapped.args;\n }\n\n cmd = resolveEnvRefsDeep(cmd);\n args = resolveEnvRefsDeep(args);\n\n const timeoutMs = server.timeoutMs;\n const timeout =\n typeof timeoutMs === \"number\" && timeoutMs > 0 ? Math.round(timeoutMs / 1000) : 300;\n\n const entry: GooseStdioExtension = {\n type: \"stdio\",\n cmd,\n args,\n timeout,\n enabled: server.enabled !== false,\n };\n\n if (server.env && Object.keys(server.env).length > 0) {\n const envs: Record<string, string> = {};\n for (const [k, v] of Object.entries(resolveEnvRefsDeep(server.env))) {\n envs[k] = String(v);\n }\n entry.envs = envs;\n }\n return entry;\n }\n\n // ── Hook install / uninstall (JSON Open-Plugins hooks.json) ───────────────\n\n override installHooks(ctx: InstallContext): ChangeRecord[] {\n const { connector, dryRun } = ctx;\n const path = this.getHookConfigPath(ctx);\n\n if (connector.platforms[HOST]?.hooks === false) {\n return [{ platform: this.id, action: \"skip\", path, detail: \"hooks disabled for goose\" }];\n }\n const events = connector.hookEvents;\n if (events.length === 0) {\n return [{ platform: this.id, action: \"skip\", path, detail: \"connector declares no hooks\" }];\n }\n\n const file = this.readHooksFile(path);\n const changes: ChangeRecord[] = [];\n let mutated = false;\n\n for (const event of events) {\n // CAPABILITY FILTER: only write events Goose's Open-Plugins runtime\n // actually delivers. Derive support from THIS adapter's capabilities (the\n // single source of truth) so an event Goose does not support (e.g.\n // UserPromptSubmit) is reported as a graceful warn and never written\n // verbatim into hooks.json — mirroring the cursor adapter's pattern.\n if (this.capabilities[EVENT_CAPABILITY[event]] !== true) {\n changes.push({\n platform: this.id,\n action: \"warn\",\n path,\n detail: `${event} unsupported on goose — skipped`,\n });\n continue;\n }\n\n const command = buildHomeBinHookCommand(ctx.homeBinPath, HOST, event, connector.id);\n const matcher = connector.hooks[event]?.matcher ?? \"\";\n const desired: GooseHookRule = {\n matcher,\n hooks: [{ type: \"command\", command }],\n };\n const bucket = (file.hooks[event] ??= []);\n const idx = bucket.findIndex((rule) => this.ruleHasOurCommand(rule, ctx));\n\n if (idx >= 0) {\n if (JSON.stringify(bucket[idx]) === JSON.stringify(desired)) {\n changes.push({ platform: this.id, action: \"skip\", path, detail: `hooks.${event}` });\n continue;\n }\n bucket[idx] = desired;\n changes.push({ platform: this.id, action: \"update\", path, detail: `hooks.${event}` });\n } else {\n bucket.push(desired);\n changes.push({ platform: this.id, action: \"create\", path, detail: `hooks.${event}` });\n }\n mutated = true;\n }\n\n if (mutated) this.writeHooksFile(path, file, dryRun);\n return changes;\n }\n\n override uninstallHooks(ctx: InstallContext): ChangeRecord[] {\n const path = this.getHookConfigPath(ctx);\n const file = this.readJson<GooseHooksFile>(path);\n if (!file || !file.hooks || typeof file.hooks !== \"object\") {\n return [{ platform: this.id, action: \"skip\", path, detail: \"no hooks.json\" }];\n }\n\n const changes: ChangeRecord[] = [];\n let mutated = false;\n for (const event of Object.keys(file.hooks)) {\n const bucket = file.hooks[event];\n if (!Array.isArray(bucket)) continue;\n\n // Strip our command from each rule's inner `hooks` array; drop rules left\n // empty so we never remove another connector's (or the user's own) hooks.\n const next: GooseHookRule[] = [];\n let removed = 0;\n for (const rule of bucket) {\n const innerBefore = rule.hooks?.length ?? 0;\n const inner = (rule.hooks ?? []).filter((h) => !this.isOurCommand(h.command, ctx));\n removed += innerBefore - inner.length;\n if (inner.length > 0) {\n next.push({ ...(rule.matcher !== undefined ? { matcher: rule.matcher } : {}), hooks: inner });\n }\n }\n\n if (removed === 0) continue;\n mutated = true;\n if (next.length > 0) file.hooks[event] = next;\n else delete file.hooks[event];\n changes.push({\n platform: this.id,\n action: \"remove\",\n path,\n detail: `hooks.${event} (${removed})`,\n });\n }\n\n if (mutated) this.writeHooksFile(path, file, ctx.dryRun);\n if (changes.length === 0) {\n return [{ platform: this.id, action: \"skip\", path, detail: \"no matching hook entries\" }];\n }\n return changes;\n }\n\n /** True when a hook command is ours (anchored home-bin + connector id). */\n private isOurCommand(command: string | undefined, ctx: InstallContext): boolean {\n return isHomeBinHookCommand(command, ctx.homeBinPath, ctx.connector.id);\n }\n\n /** True when any inner command of a nested rule is ours. */\n private ruleHasOurCommand(rule: GooseHookRule, ctx: InstallContext): boolean {\n return (rule.hooks ?? []).some((h) => this.isOurCommand(h.command, ctx));\n }\n\n private readHooksFile(path: string): GooseHooksFile {\n const existing = this.readJson<GooseHooksFile>(path);\n if (existing && existing.hooks && typeof existing.hooks === \"object\") {\n return { hooks: existing.hooks };\n }\n return { hooks: {} };\n }\n\n private writeHooksFile(path: string, file: GooseHooksFile, dryRun: boolean): void {\n if (dryRun) return;\n ensureDir(dirname(path));\n writeFileSync(path, `${JSON.stringify(file, null, 2)}\\n`, \"utf8\");\n }\n\n // ── Diagnostics ──────────────────────────────────────────────────────────\n\n override getHealthChecks(ctx: InstallContext): readonly HealthCheck[] {\n const serverPath = this.getServerConfigPath(ctx);\n const hookPath = this.getHookConfigPath(ctx);\n const id = ctx.connector.id;\n const homeBin = ctx.homeBinPath;\n const hookEvents = ctx.connector.hookEvents;\n return [\n {\n name: `${this.name}: config.yaml present`,\n check: () =>\n existsSync(serverPath)\n ? { status: \"OK\", detail: serverPath }\n : { status: \"FAIL\", detail: `not found: ${serverPath}` },\n },\n {\n name: `${this.name}: ${MCP_ROOT_KEY}.${id} registered`,\n check: () => {\n const cfg = readYaml<Record<string, unknown>>(serverPath);\n const bucket = cfg?.[MCP_ROOT_KEY];\n const present =\n typeof bucket === \"object\" &&\n bucket !== null &&\n !Array.isArray(bucket) &&\n id in (bucket as Record<string, unknown>);\n return present\n ? { status: \"OK\", detail: `${MCP_ROOT_KEY}.${id}` }\n : { status: \"FAIL\", detail: `${MCP_ROOT_KEY}.${id} not found in ${serverPath}` };\n },\n },\n {\n name: `${this.name}: hook command registered`,\n check: () => {\n if (hookEvents.length === 0) return { status: \"OK\", detail: \"no hooks declared\" };\n const file = this.readJson<GooseHooksFile>(hookPath);\n if (!file || !file.hooks) {\n return { status: \"FAIL\", detail: `cannot read ${hookPath}` };\n }\n const registered = Object.values(file.hooks).some((bucket) =>\n (bucket ?? []).some((rule) =>\n (rule.hooks ?? []).some((h) => isHomeBinHookCommand(h.command, homeBin, id)),\n ),\n );\n return registered\n ? { status: \"OK\", detail: \"hook command present\" }\n : { status: \"FAIL\", detail: `no hook for ${id} in ${hookPath}` };\n },\n },\n ];\n }\n\n // ── Runtime: parse Goose stdin JSON → normalized event ───────────────────\n\n parseEvent(event: HookEventName, raw: unknown): NormalizedEvent {\n const input = (raw ?? {}) as GooseWireInput;\n // Goose sends the working directory as `working_dir`; fall back to `cwd`.\n const projectDir =\n typeof input.working_dir === \"string\"\n ? input.working_dir\n : typeof input.cwd === \"string\"\n ? input.cwd\n : undefined;\n const base = {\n hostPlatform: HOST,\n connectorId: typeof input.connector === \"string\" ? input.connector : \"\",\n sessionId: typeof input.session_id === \"string\" ? input.session_id : \"\",\n ...(projectDir !== undefined ? { projectDir } : {}),\n raw,\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 ev: PostToolUseEvent = {\n ...base,\n toolName: input.tool_name ?? \"\",\n toolInput: input.tool_input ?? {},\n ...(toolResponseToString(input.tool_response) !== undefined\n ? { toolOutput: toolResponseToString(input.tool_response) }\n : {}),\n ...(typeof input.is_error === \"boolean\" ? { isError: input.is_error } : {}),\n };\n return ev;\n }\n case \"SessionStart\": {\n const ev: SessionStartEvent = { ...base, source: normalizeSource(input.source) };\n return ev;\n }\n case \"SessionEnd\": {\n const ev: SessionEndEvent = {\n ...base,\n ...(typeof input.reason === \"string\" ? { reason: input.reason } : {}),\n };\n return ev;\n }\n case \"UserPromptSubmit\": {\n const ev: UserPromptSubmitEvent = {\n ...base,\n prompt: typeof input.prompt === \"string\" ? input.prompt : \"\",\n };\n return ev;\n }\n case \"PreCompact\": {\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 \"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 \"Notification\": {\n const ev: NotificationEvent = {\n ...base,\n message: typeof input.message === \"string\" ? input.message : \"\",\n };\n return ev;\n }\n default: {\n const _never: never = event;\n throw new Error(`unsupported goose hook event: ${String(_never)}`);\n }\n }\n }\n\n // ── Runtime: normalized response → Goose native hook reply (Claude-shaped) ─\n\n formatReply(_event: HookEventName, response: HookResponse): HookReply {\n const decision = response.decision ?? \"allow\";\n\n // deny → Goose blocks via `{ decision: \"block\", reason }` on stdout JSON\n // (NOT Claude's hookSpecificOutput.permissionDecision shape).\n if (decision === \"deny\") {\n return this.stdout({\n decision: \"block\",\n reason: response.reason ?? \"Blocked by hook\",\n });\n }\n\n // ask → Goose has no native \"ask\"; degrade to block to stay fail-safe.\n if (decision === \"ask\") {\n return this.stdout({\n decision: \"block\",\n reason: response.reason ?? \"Confirmation required by hook\",\n });\n }\n\n if (decision === \"context\" && response.additionalContext) {\n return this.stdout({ additionalContext: response.additionalContext });\n }\n\n // allow / modify (unsupported) / void → pass through.\n return { exitCode: 0 };\n }\n\n private stdout(payload: unknown): HookReply {\n return { exitCode: 0, stdout: JSON.stringify(payload) };\n }\n\n // ── Internal helpers ──────────────────────────────────────────────────────\n\n /** Resolve the per-platform server override into an effective ServerDef. */\n private effectiveServer(ctx: InstallContext): ServerDef | undefined {\n const override = ctx.connector.platforms[this.id]?.server;\n if (override === false) return undefined;\n const base = ctx.connector.server;\n if (!base) return undefined;\n return override && typeof override === \"object\" ? { ...base, ...override } : base;\n }\n}\n\n/** Coerce a Goose PostToolUse `tool_response` into a string. */\nfunction toolResponseToString(value: unknown): string | undefined {\n if (value == null) return undefined;\n if (typeof value === \"string\") return value;\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n}\n\nfunction normalizeSource(raw: string | undefined): SessionStartEvent[\"source\"] {\n switch (raw) {\n case \"compact\":\n return \"compact\";\n case \"resume\":\n return \"resume\";\n case \"clear\":\n return \"clear\";\n default:\n return \"startup\";\n }\n}\n\nexport const adapter = new GooseAdapter();\nexport default adapter;\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/adapters/hermes/index.ts"],"sourcesContent":["/**\n * adapters/hermes — Hermes Agent platform adapter for agent-connector.\n *\n * Hermes is a json-stdio host whose ENTIRE configuration — both the MCP servers\n * and the lifecycle hooks — lives in a single user-scope YAML file:\n *\n * ~/.hermes/config.yaml\n *\n * Because the file is YAML, the BaseAdapter JSON helpers do not apply; this\n * adapter merges via core/yaml's readYaml/writeYaml, preserving any unrelated\n * config the user has authored.\n *\n * - MCP servers: top-level snake_case root key `mcp_servers`. The stdio entry\n * uses the portable field names { command, args, env } (unlike Goose's\n * cmd/envs). Hermes has no native env interpolation, so `${env:VAR}` refs are\n * resolved to literals at install time.\n *\n * - Hooks: a top-level `hooks` map keyed by Hermes' NATIVE snake_case event\n * names (pre_tool_call / post_tool_call / on_session_start / on_session_end —\n * NOT the canonical PascalCase names; see EVENT_TO_HERMES). Each value is a\n * list of shell-hook entries { matcher, command:\"<homeBin> hook …\", timeout }.\n * The command keeps the canonical event token so the runtime dispatcher\n * (parseEvent/formatReply) stays consistent. Hermes shell hooks pipe the\n * event JSON to the command on stdin and read the reply JSON from stdout —\n * the same wire protocol as Claude Code, so the runtime parse/format mirror\n * the Claude adapter (a Claude-like JSON shape; the exact Hermes field map is\n * documented inline where it could vary).\n *\n * Since hooks are external shell commands (not an in-process plugin), Hermes\n * cannot let a hook rewrite tool arguments — canModifyArgs is false. Hermes has\n * no SSE transport, so only stdio + http are advertised.\n */\n\nimport { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\n\nimport { BaseAdapter } from \"../base.js\";\nimport type { Adapter, HookReply, InstallContext, NormalizedEvent } from \"../spi.js\";\nimport type {\n ChangeRecord,\n DetectedPlatform,\n HealthCheck,\n HookEventName,\n HookParadigm,\n HookResponse,\n NotificationEvent,\n PlatformCapabilities,\n PlatformId,\n PostToolUseEvent,\n PreCompactEvent,\n PreToolUseEvent,\n SessionEndEvent,\n SessionStartEvent,\n ServerDef,\n StopEvent,\n UserPromptSubmitEvent,\n} from \"../../core/types.js\";\nimport { readYaml, writeYaml } from \"../../core/yaml.js\";\nimport { resolveEnvRefsDeep } from \"../../core/interpolate.js\";\nimport {\n buildHomeBinHookCommand,\n buildServeWrapperCommand,\n isHomeBinHookCommand,\n shouldWrapForTelemetry,\n} from \"../../core/spawn.js\";\n\nconst HOST: PlatformId = \"hermes\";\n/** Root key under which Hermes stores MCP servers in config.yaml (snake_case). */\nconst MCP_ROOT_KEY = \"mcp_servers\";\n/** Top-level key under which Hermes stores shell hooks in config.yaml. */\nconst HOOKS_KEY = \"hooks\";\n/** Default per-hook timeout (seconds) when the connector declares none. */\nconst DEFAULT_HOOK_TIMEOUT = 60;\n\n/**\n * Canonical → Hermes native hook event name. Hermes keys its `hooks:` block by\n * its OWN snake_case lifecycle names (pre_tool_call / post_tool_call /\n * on_session_start / on_session_end — see docs/research/platform-research.json),\n * NOT the canonical PascalCase names. A connector event is only wired when it\n * appears here AND is declared by the connector; everything else is reported as\n * a warn/skip at install time.\n */\nconst EVENT_TO_HERMES: Partial<Record<HookEventName, string>> = {\n PreToolUse: \"pre_tool_call\",\n PostToolUse: \"post_tool_call\",\n SessionStart: \"on_session_start\",\n SessionEnd: \"on_session_end\",\n};\n\n/** Hermes stdio MCP entry — portable field names (command/args/env). */\ninterface HermesStdioServer {\n command: string;\n args?: string[];\n env?: Record<string, string>;\n}\n\n/** One Hermes shell-hook entry. */\ninterface HermesHookEntry {\n /** Tool-name matcher (empty = all). Tool events only; \"\" elsewhere. */\n matcher: string;\n /** The home-bin hook command Hermes invokes (event JSON on stdin). */\n command: string;\n /** Hook timeout in seconds. */\n timeout: number;\n}\n\n/** Raw Hermes hook stdin payload. Hermes uses snake_case pre_tool_call /\n * post_tool_call event tokens; field names below cover both its tool-call and\n * session payloads. Shape kept Claude-like where Hermes does not document it. */\ninterface HermesWireInput {\n session_id?: string;\n cwd?: string;\n event?: string;\n hook_event_name?: string;\n tool_name?: string;\n tool_input?: Record<string, unknown>;\n tool_response?: unknown;\n tool_output?: unknown;\n source?: string;\n reason?: string;\n prompt?: string;\n trigger?: string;\n stop_hook_active?: boolean;\n message?: string;\n is_error?: boolean;\n /** Injected by the entrypoint so the runtime knows which connector to dispatch. */\n connector?: string;\n}\n\nexport class HermesAdapter extends BaseAdapter implements Adapter {\n readonly id: PlatformId = HOST;\n readonly name = \"Hermes Agent\";\n readonly paradigm: HookParadigm = \"json-stdio\";\n\n readonly capabilities: PlatformCapabilities = {\n preToolUse: true,\n postToolUse: true,\n preCompact: false,\n // Hermes exposes on_session_start / on_session_end lifecycle hooks.\n sessionStart: true,\n sessionEnd: true,\n userPromptSubmit: false,\n stop: false,\n notification: false,\n // Shell hooks cannot rewrite tool args/output in-process.\n canModifyArgs: false,\n canModifyOutput: false,\n canInjectSessionContext: true,\n // Hermes has no SSE transport.\n transports: [\"stdio\", \"http\"],\n };\n\n // ── Detection ────────────────────────────────────────────────────────────\n\n detectInstalled(_projectDir: string): DetectedPlatform {\n const configPath = this.userConfigPath();\n const configDir = dirname(configPath);\n const installed = existsSync(configDir) || existsSync(configPath);\n return {\n id: this.id,\n name: this.name,\n installed,\n paradigm: this.paradigm,\n capabilities: this.capabilities,\n configPath,\n scope: \"user\",\n reason: installed\n ? `found Hermes config at ${configPath}`\n : `no Hermes config at ${configPath}`,\n confidence: installed ? \"high\" : \"low\",\n };\n }\n\n // ── Native paths (server + hooks share the SAME file) ─────────────────────\n\n override getConfigDir(_ctx: InstallContext): string {\n return dirname(this.userConfigPath());\n }\n\n override getServerConfigPath(_ctx: InstallContext): string {\n return this.userConfigPath();\n }\n\n /** Same file as the server config — Hermes hooks live in config.yaml. */\n override getHookConfigPath(_ctx: InstallContext): string {\n return this.userConfigPath();\n }\n\n private userConfigPath(): string {\n return join(homedir(), \".hermes\", \"config.yaml\");\n }\n\n // ── MCP server install / uninstall (YAML mcp_servers) ─────────────────────\n\n override installServer(ctx: InstallContext): ChangeRecord[] {\n const { connector, dryRun } = ctx;\n const path = this.getServerConfigPath(ctx);\n const server = this.effectiveServer(ctx);\n\n if (!server) {\n return [\n {\n platform: this.id,\n action: \"skip\",\n path,\n detail: connector.server\n ? \"server registration disabled for hermes\"\n : \"connector declares no MCP server\",\n },\n ];\n }\n if (server.transport !== \"stdio\" || !server.command) {\n return [\n {\n platform: this.id,\n action: \"skip\",\n path,\n detail: `transport \"${server.transport}\" not registrable in ${MCP_ROOT_KEY} (stdio only)`,\n },\n ];\n }\n\n const entry = this.renderServerEntry(ctx, server);\n\n const cfg = readYaml<Record<string, unknown>>(path) ?? {};\n const bucket = this.objectBucket(cfg, MCP_ROOT_KEY);\n const before = JSON.stringify(bucket[connector.id]);\n const after = JSON.stringify(entry);\n let action: ChangeRecord[\"action\"];\n if (before === undefined) action = \"create\";\n else if (before === after) action = \"skip\";\n else action = \"update\";\n\n if (action !== \"skip\") {\n bucket[connector.id] = entry;\n writeYaml(path, cfg, dryRun);\n }\n return [{ platform: this.id, action, path, detail: `${MCP_ROOT_KEY}.${connector.id}` }];\n }\n\n override uninstallServer(ctx: InstallContext): ChangeRecord[] {\n const { connector, dryRun } = ctx;\n const path = this.getServerConfigPath(ctx);\n const cfg = readYaml<Record<string, unknown>>(path);\n const bucketRaw = cfg?.[MCP_ROOT_KEY];\n if (\n !cfg ||\n !bucketRaw ||\n typeof bucketRaw !== \"object\" ||\n Array.isArray(bucketRaw) ||\n !(connector.id in (bucketRaw as Record<string, unknown>))\n ) {\n return [\n {\n platform: this.id,\n action: \"skip\",\n path,\n detail: `${MCP_ROOT_KEY}.${connector.id} absent`,\n },\n ];\n }\n delete (bucketRaw as Record<string, unknown>)[connector.id];\n writeYaml(path, cfg, dryRun);\n return [\n { platform: this.id, action: \"remove\", path, detail: `${MCP_ROOT_KEY}.${connector.id}` },\n ];\n }\n\n /**\n * Render the stdio MCP entry. Hermes has no native interpolation, so env-refs\n * resolve to literals here. Honors the telemetry serve-wrapper.\n */\n private renderServerEntry(ctx: InstallContext, server: ServerDef): HermesStdioServer {\n let command = server.command as string;\n let args = [...(server.args ?? [])];\n\n if (shouldWrapForTelemetry(server, ctx.connector.telemetry)) {\n const wrapped = buildServeWrapperCommand(\n ctx.homeBinPath,\n ctx.connector.id,\n command,\n args,\n ctx.scope,\n this.id,\n );\n command = wrapped.command;\n args = wrapped.args;\n }\n\n command = resolveEnvRefsDeep(command);\n args = resolveEnvRefsDeep(args);\n\n const entry: HermesStdioServer = { command };\n if (args.length > 0) entry.args = args;\n if (server.env && Object.keys(server.env).length > 0) {\n const env: Record<string, string> = {};\n for (const [k, v] of Object.entries(resolveEnvRefsDeep(server.env))) {\n env[k] = String(v);\n }\n entry.env = env;\n }\n return entry;\n }\n\n // ── Hook install / uninstall (YAML hooks map in the SAME config.yaml) ─────\n\n override installHooks(ctx: InstallContext): ChangeRecord[] {\n const { connector, dryRun } = ctx;\n const path = this.getHookConfigPath(ctx);\n\n if (connector.platforms[HOST]?.hooks === false) {\n return [{ platform: this.id, action: \"skip\", path, detail: \"hooks disabled for hermes\" }];\n }\n const events = connector.hookEvents;\n if (events.length === 0) {\n return [{ platform: this.id, action: \"skip\", path, detail: \"connector declares no hooks\" }];\n }\n\n const cfg = readYaml<Record<string, unknown>>(path) ?? {};\n const hooks = this.hooksBucket(cfg);\n const changes: ChangeRecord[] = [];\n let mutated = false;\n\n for (const event of events) {\n const hermesEvent = EVENT_TO_HERMES[event];\n if (!hermesEvent) {\n // No Hermes equivalent for this canonical event — report and skip.\n changes.push({\n platform: this.id,\n action: \"warn\",\n path,\n detail: `${event} has no Hermes hook equivalent — skipped`,\n });\n continue;\n }\n\n // The hook command keeps the CANONICAL event token so the runtime\n // dispatcher (parseEvent/formatReply) stays consistent; only the YAML KEY\n // the entry is filed under is the native Hermes name.\n const command = buildHomeBinHookCommand(ctx.homeBinPath, HOST, event, connector.id);\n const matcher = connector.hooks[event]?.matcher ?? \"\";\n const timeout = this.hookTimeout(connector.server);\n const desired: HermesHookEntry = { matcher, command, timeout };\n\n const bucket = Array.isArray(hooks[hermesEvent])\n ? (hooks[hermesEvent] as HermesHookEntry[])\n : (hooks[hermesEvent] = [] as HermesHookEntry[]);\n const idx = bucket.findIndex((e) => this.isOurCommand(e?.command, ctx));\n\n if (idx >= 0) {\n if (JSON.stringify(bucket[idx]) === JSON.stringify(desired)) {\n changes.push({ platform: this.id, action: \"skip\", path, detail: `${HOOKS_KEY}.${hermesEvent}` });\n continue;\n }\n bucket[idx] = desired;\n changes.push({ platform: this.id, action: \"update\", path, detail: `${HOOKS_KEY}.${hermesEvent}` });\n } else {\n bucket.push(desired);\n changes.push({ platform: this.id, action: \"create\", path, detail: `${HOOKS_KEY}.${hermesEvent}` });\n }\n mutated = true;\n }\n\n if (mutated) writeYaml(path, cfg, dryRun);\n return changes;\n }\n\n override uninstallHooks(ctx: InstallContext): ChangeRecord[] {\n const path = this.getHookConfigPath(ctx);\n const cfg = readYaml<Record<string, unknown>>(path);\n const hooksRaw = cfg?.[HOOKS_KEY];\n if (\n !cfg ||\n !hooksRaw ||\n typeof hooksRaw !== \"object\" ||\n Array.isArray(hooksRaw)\n ) {\n return [{ platform: this.id, action: \"skip\", path, detail: \"no hooks section present\" }];\n }\n const hooks = hooksRaw as Record<string, unknown>;\n\n const changes: ChangeRecord[] = [];\n let mutated = false;\n for (const event of Object.keys(hooks)) {\n const bucket = hooks[event];\n if (!Array.isArray(bucket)) continue;\n const kept = (bucket as HermesHookEntry[]).filter(\n (e) => !this.isOurCommand(e?.command, ctx),\n );\n if (kept.length === bucket.length) continue;\n mutated = true;\n if (kept.length > 0) hooks[event] = kept;\n else delete hooks[event];\n changes.push({\n platform: this.id,\n action: \"remove\",\n path,\n detail: `${HOOKS_KEY}.${event} (${bucket.length - kept.length})`,\n });\n }\n\n if (mutated) writeYaml(path, cfg, ctx.dryRun);\n if (changes.length === 0) {\n return [{ platform: this.id, action: \"skip\", path, detail: \"no matching hook entries\" }];\n }\n return changes;\n }\n\n /** True when a hook command is ours (anchored home-bin + connector id). */\n private isOurCommand(command: string | undefined, ctx: InstallContext): boolean {\n return isHomeBinHookCommand(command, ctx.homeBinPath, ctx.connector.id);\n }\n\n private hookTimeout(server: ServerDef | undefined): number {\n const ms = server?.timeoutMs;\n if (typeof ms === \"number\" && ms > 0) return Math.round(ms / 1000);\n return DEFAULT_HOOK_TIMEOUT;\n }\n\n // ── Diagnostics ──────────────────────────────────────────────────────────\n\n override getHealthChecks(ctx: InstallContext): readonly HealthCheck[] {\n const path = this.getServerConfigPath(ctx);\n const id = ctx.connector.id;\n const homeBin = ctx.homeBinPath;\n const hookEvents = ctx.connector.hookEvents;\n return [\n {\n name: `${this.name}: config.yaml present`,\n check: () =>\n existsSync(path)\n ? { status: \"OK\", detail: path }\n : { status: \"FAIL\", detail: `not found: ${path}` },\n },\n {\n name: `${this.name}: ${MCP_ROOT_KEY}.${id} registered`,\n check: () => {\n const cfg = readYaml<Record<string, unknown>>(path);\n const bucket = cfg?.[MCP_ROOT_KEY];\n const present =\n typeof bucket === \"object\" &&\n bucket !== null &&\n !Array.isArray(bucket) &&\n id in (bucket as Record<string, unknown>);\n return present\n ? { status: \"OK\", detail: `${MCP_ROOT_KEY}.${id}` }\n : { status: \"FAIL\", detail: `${MCP_ROOT_KEY}.${id} not found in ${path}` };\n },\n },\n {\n name: `${this.name}: hook command registered`,\n check: () => {\n if (hookEvents.length === 0) return { status: \"OK\", detail: \"no hooks declared\" };\n const cfg = readYaml<Record<string, unknown>>(path);\n const hooks = cfg?.[HOOKS_KEY];\n if (!hooks || typeof hooks !== \"object\" || Array.isArray(hooks)) {\n return { status: \"FAIL\", detail: `no ${HOOKS_KEY} section in ${path}` };\n }\n const registered = Object.values(hooks as Record<string, unknown>).some(\n (bucket) =>\n Array.isArray(bucket) &&\n (bucket as HermesHookEntry[]).some((e) =>\n isHomeBinHookCommand(e?.command, homeBin, id),\n ),\n );\n return registered\n ? { status: \"OK\", detail: \"hook command present\" }\n : { status: \"FAIL\", detail: `no hook for ${id} in ${path}` };\n },\n },\n ];\n }\n\n // ── Runtime: parse Hermes stdin JSON → normalized event ──────────────────\n\n parseEvent(event: HookEventName, raw: unknown): NormalizedEvent {\n const input = (raw ?? {}) as HermesWireInput;\n const base = {\n hostPlatform: HOST,\n connectorId: typeof input.connector === \"string\" ? input.connector : \"\",\n sessionId: typeof input.session_id === \"string\" ? input.session_id : \"\",\n ...(typeof input.cwd === \"string\" ? { projectDir: input.cwd } : {}),\n raw,\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 // Hermes may carry the result under tool_output or tool_response.\n const out = toStringOrUndefined(input.tool_output ?? input.tool_response);\n const ev: PostToolUseEvent = {\n ...base,\n toolName: input.tool_name ?? \"\",\n toolInput: input.tool_input ?? {},\n ...(out !== undefined ? { toolOutput: out } : {}),\n ...(typeof input.is_error === \"boolean\" ? { isError: input.is_error } : {}),\n };\n return ev;\n }\n case \"SessionStart\": {\n const ev: SessionStartEvent = { ...base, source: normalizeSource(input.source) };\n return ev;\n }\n case \"SessionEnd\": {\n const ev: SessionEndEvent = {\n ...base,\n ...(typeof input.reason === \"string\" ? { reason: input.reason } : {}),\n };\n return ev;\n }\n case \"UserPromptSubmit\": {\n const ev: UserPromptSubmitEvent = {\n ...base,\n prompt: typeof input.prompt === \"string\" ? input.prompt : \"\",\n };\n return ev;\n }\n case \"PreCompact\": {\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 \"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 \"Notification\": {\n const ev: NotificationEvent = {\n ...base,\n message: typeof input.message === \"string\" ? input.message : \"\",\n };\n return ev;\n }\n default: {\n const _never: never = event;\n throw new Error(`unsupported hermes hook event: ${String(_never)}`);\n }\n }\n }\n\n // ── Runtime: normalized response → Hermes native hook reply ──────────────\n // Hermes shell hooks read a JSON reply from stdout (exit 0 = allow). We emit a\n // Claude-like `hookSpecificOutput` wrapper; if Hermes' exact reply schema\n // differs, this is the single place to adjust the mapping.\n\n formatReply(event: HookEventName, response: HookResponse): HookReply {\n const decision = response.decision ?? \"allow\";\n\n if (decision === \"deny\") {\n return this.stdout({\n hookSpecificOutput: {\n hookEventName: event,\n permissionDecision: \"deny\",\n permissionDecisionReason: response.reason ?? \"Blocked by hook\",\n },\n });\n }\n\n if (decision === \"ask\") {\n return this.stdout({\n hookSpecificOutput: {\n hookEventName: event,\n permissionDecision: \"ask\",\n permissionDecisionReason: response.reason ?? \"Confirmation required by hook\",\n },\n });\n }\n\n if (decision === \"context\" && response.additionalContext) {\n return this.stdout({\n hookSpecificOutput: { hookEventName: event, additionalContext: response.additionalContext },\n });\n }\n\n // allow / modify (unsupported — shell hooks can't rewrite args) / void.\n return { exitCode: 0 };\n }\n\n private stdout(payload: unknown): HookReply {\n return { exitCode: 0, stdout: JSON.stringify(payload) };\n }\n\n // ── Internal helpers ──────────────────────────────────────────────────────\n\n /** Resolve the per-platform server override into an effective ServerDef. */\n private effectiveServer(ctx: InstallContext): ServerDef | undefined {\n const override = ctx.connector.platforms[this.id]?.server;\n if (override === false) return undefined;\n const base = ctx.connector.server;\n if (!base) return undefined;\n return override && typeof override === \"object\" ? { ...base, ...override } : base;\n }\n\n /** Get-or-create an object bucket (map) at `cfg[key]`. */\n private objectBucket(cfg: Record<string, unknown>, key: string): Record<string, unknown> {\n const existing = cfg[key];\n if (existing && typeof existing === \"object\" && !Array.isArray(existing)) {\n return existing as Record<string, unknown>;\n }\n const fresh: Record<string, unknown> = {};\n cfg[key] = fresh;\n return fresh;\n }\n\n /** Get-or-create the hooks map at `cfg.hooks`. */\n private hooksBucket(cfg: Record<string, unknown>): Record<string, unknown> {\n return this.objectBucket(cfg, HOOKS_KEY);\n }\n}\n\n/** Coerce an unknown value into a string for the normalized event. */\nfunction toStringOrUndefined(value: unknown): string | undefined {\n if (value == null) return undefined;\n if (typeof value === \"string\") return value;\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n}\n\nfunction normalizeSource(raw: string | undefined): SessionStartEvent[\"source\"] {\n switch (raw) {\n case \"compact\":\n return \"compact\";\n case \"resume\":\n return \"resume\";\n case \"clear\":\n return \"clear\";\n default:\n return \"startup\";\n }\n}\n\nexport const adapter = new HermesAdapter();\nexport default adapter;\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli/commands/hook.ts"],"sourcesContent":["/**\n * cli/commands/hook — the universal json-stdio hook entrypoint.\n *\n * agent-connector hook <platform> <event> --connector <id>\n *\n * This is the single command every host's hook config points at (via the stable\n * home binary). It reads the ENTIRE host payload from stdin, dispatches through\n * runHook, writes any stdout/stderr the adapter produced, and exits with the\n * adapter's exit code (the host interprets it as allow/deny/etc.).\n *\n * Fail-open is the runtime's contract: runHook never rejects, so a framework or\n * handler bug can't wedge a host's tool call.\n */\n\nimport { parseArgs } from \"node:util\";\n\nimport type { HookEventName } from \"../../core/types.js\";\nimport { runHook } from \"../../runtime/index.js\";\nimport { fail } from \"../app.js\";\n\nconst HOOK_EVENTS: ReadonlySet<string> = new Set<HookEventName>([\n \"SessionStart\",\n \"SessionEnd\",\n \"UserPromptSubmit\",\n \"PreToolUse\",\n \"PostToolUse\",\n \"PreCompact\",\n \"Stop\",\n \"Notification\",\n]);\n\n/** Read all of a readable stream to a UTF-8 string. */\nasync function readAll(stream: NodeJS.ReadStream): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of stream) {\n chunks.push(typeof chunk === \"string\" ? Buffer.from(chunk) : chunk);\n }\n return Buffer.concat(chunks).toString(\"utf8\");\n}\n\nexport async function run(argv: string[]): Promise<number> {\n const { values, positionals } = parseArgs({\n args: argv,\n options: {\n connector: { type: \"string\" },\n },\n allowPositionals: true,\n });\n\n const platformId = positionals[0];\n const event = positionals[1];\n if (!platformId || !event) {\n return fail(\"usage: agent-connector hook <platform> <event> --connector <id>\");\n }\n if (!HOOK_EVENTS.has(event)) {\n return fail(`unknown hook event \"${event}\"`);\n }\n const connectorId = values.connector;\n if (!connectorId || connectorId.trim() === \"\") {\n return fail(\"hook requires --connector <id>\");\n }\n\n // Read the entire host payload before dispatching.\n const stdin = await readAll(process.stdin);\n\n const reply = await runHook({\n platformId,\n event: event as HookEventName,\n connectorId,\n stdin,\n });\n\n if (reply.stdout !== undefined && reply.stdout !== \"\") {\n process.stdout.write(reply.stdout);\n }\n if (reply.stderr !== undefined && reply.stderr !== \"\") {\n process.stderr.write(reply.stderr.endsWith(\"\\n\") ? reply.stderr : `${reply.stderr}\\n`);\n }\n\n process.exit(reply.exitCode);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAcA,SAAS,iBAAiB;AAM1B,IAAM,cAAmC,oBAAI,IAAmB;AAAA,EAC9D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAGD,eAAe,QAAQ,QAA4C;AACjE,QAAM,SAAmB,CAAC;AAC1B,mBAAiB,SAAS,QAAQ;AAChC,WAAO,KAAK,OAAO,UAAU,WAAW,OAAO,KAAK,KAAK,IAAI,KAAK;AAAA,EACpE;AACA,SAAO,OAAO,OAAO,MAAM,EAAE,SAAS,MAAM;AAC9C;AAEA,eAAsB,IAAI,MAAiC;AACzD,QAAM,EAAE,QAAQ,YAAY,IAAI,UAAU;AAAA,IACxC,MAAM;AAAA,IACN,SAAS;AAAA,MACP,WAAW,EAAE,MAAM,SAAS;AAAA,IAC9B;AAAA,IACA,kBAAkB;AAAA,EACpB,CAAC;AAED,QAAM,aAAa,YAAY,CAAC;AAChC,QAAM,QAAQ,YAAY,CAAC;AAC3B,MAAI,CAAC,cAAc,CAAC,OAAO;AACzB,WAAO,KAAK,iEAAiE;AAAA,EAC/E;AACA,MAAI,CAAC,YAAY,IAAI,KAAK,GAAG;AAC3B,WAAO,KAAK,uBAAuB,KAAK,GAAG;AAAA,EAC7C;AACA,QAAM,cAAc,OAAO;AAC3B,MAAI,CAAC,eAAe,YAAY,KAAK,MAAM,IAAI;AAC7C,WAAO,KAAK,gCAAgC;AAAA,EAC9C;AAGA,QAAM,QAAQ,MAAM,QAAQ,QAAQ,KAAK;AAEzC,QAAM,QAAQ,MAAM,QAAQ;AAAA,IAC1B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,MAAI,MAAM,WAAW,UAAa,MAAM,WAAW,IAAI;AACrD,YAAQ,OAAO,MAAM,MAAM,MAAM;AAAA,EACnC;AACA,MAAI,MAAM,WAAW,UAAa,MAAM,WAAW,IAAI;AACrD,YAAQ,OAAO,MAAM,MAAM,OAAO,SAAS,IAAI,IAAI,MAAM,SAAS,GAAG,MAAM,MAAM;AAAA,CAAI;AAAA,EACvF;AAEA,UAAQ,KAAK,MAAM,QAAQ;AAC7B;","names":[]}
@@ -1,60 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- installConnector
4
- } from "./chunk-7MSDGHJW.js";
5
- import {
6
- fail,
7
- parseScope,
8
- parseTargets,
9
- print,
10
- renderInstallResult
11
- } from "./chunk-54EMKTTX.js";
12
- import "./chunk-KHO5WNTP.js";
13
- import "./chunk-XUCWLJY5.js";
14
- import {
15
- findConnectorConfig,
16
- loadConnectorFromPath
17
- } from "./chunk-LTT56GI3.js";
18
- import "./chunk-XNAM7F35.js";
19
- import "./chunk-TRQKHP7D.js";
20
-
21
- // src/cli/commands/install.ts
22
- import { parseArgs } from "util";
23
- async function run(argv) {
24
- const { values } = parseArgs({
25
- args: argv,
26
- options: {
27
- scope: { type: "string", default: "user" },
28
- targets: { type: "string" },
29
- connector: { type: "string" },
30
- project: { type: "string" },
31
- "dry-run": { type: "boolean", default: false }
32
- },
33
- allowPositionals: false
34
- });
35
- const projectDir = values.project ?? process.cwd();
36
- const configPath = values.connector ?? findConnectorConfig(projectDir);
37
- if (!configPath) {
38
- return fail(
39
- "no connector config found. Pass --connector <path> or add an agent-connector.config.{mjs,js,json} to your project."
40
- );
41
- }
42
- const scope = parseScope(values.scope);
43
- if (scope == null) return fail(`invalid --scope "${values.scope}" (use user|project)`);
44
- const { connector, modulePath } = await loadConnectorFromPath(configPath);
45
- const targets = parseTargets(values.targets);
46
- const result = await installConnector({
47
- connector,
48
- modulePath,
49
- scope,
50
- projectDir,
51
- dryRun: values["dry-run"],
52
- ...targets ? { targets } : {}
53
- });
54
- print(renderInstallResult(result, "install"));
55
- return result.changes.some((c) => c.action === "warn") ? 1 : 0;
56
- }
57
- export {
58
- run
59
- };
60
- //# sourceMappingURL=install-HQRYZOQ2.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli/commands/install.ts"],"sourcesContent":["/**\n * cli/commands/install — deploy a connector across its target platforms.\n *\n * Resolves the connector config (--connector <path>, else findConnectorConfig\n * walking up from the project dir), loads it into a live ResolvedConnector, and\n * hands it to the installer orchestration. The resulting ChangeRecords are\n * rendered as a readable diff; --dry-run renders the plan without writing.\n */\n\nimport { parseArgs } from \"node:util\";\n\nimport { installConnector } from \"../../core/installer.js\";\nimport { findConnectorConfig, loadConnectorFromPath } from \"../../core/load-connector.js\";\nimport { fail, parseScope, parseTargets, print, renderInstallResult } from \"../app.js\";\n\nexport async function run(argv: string[]): Promise<number> {\n const { values } = parseArgs({\n args: argv,\n options: {\n scope: { type: \"string\", default: \"user\" },\n targets: { type: \"string\" },\n connector: { type: \"string\" },\n project: { type: \"string\" },\n \"dry-run\": { type: \"boolean\", default: false },\n },\n allowPositionals: false,\n });\n\n const projectDir = values.project ?? process.cwd();\n const configPath = values.connector ?? findConnectorConfig(projectDir);\n if (!configPath) {\n return fail(\n \"no connector config found. Pass --connector <path> or add an \" +\n \"agent-connector.config.{mjs,js,json} to your project.\",\n );\n }\n\n const scope = parseScope(values.scope);\n if (scope == null) return fail(`invalid --scope \"${values.scope}\" (use user|project)`);\n\n const { connector, modulePath } = await loadConnectorFromPath(configPath);\n const targets = parseTargets(values.targets);\n\n const result = await installConnector({\n connector,\n modulePath,\n scope,\n projectDir,\n dryRun: values[\"dry-run\"],\n ...(targets ? { targets } : {}),\n });\n\n print(renderInstallResult(result, \"install\"));\n return result.changes.some((c) => c.action === \"warn\") ? 1 : 0;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AASA,SAAS,iBAAiB;AAM1B,eAAsB,IAAI,MAAiC;AACzD,QAAM,EAAE,OAAO,IAAI,UAAU;AAAA,IAC3B,MAAM;AAAA,IACN,SAAS;AAAA,MACP,OAAO,EAAE,MAAM,UAAU,SAAS,OAAO;AAAA,MACzC,SAAS,EAAE,MAAM,SAAS;AAAA,MAC1B,WAAW,EAAE,MAAM,SAAS;AAAA,MAC5B,SAAS,EAAE,MAAM,SAAS;AAAA,MAC1B,WAAW,EAAE,MAAM,WAAW,SAAS,MAAM;AAAA,IAC/C;AAAA,IACA,kBAAkB;AAAA,EACpB,CAAC;AAED,QAAM,aAAa,OAAO,WAAW,QAAQ,IAAI;AACjD,QAAM,aAAa,OAAO,aAAa,oBAAoB,UAAU;AACrE,MAAI,CAAC,YAAY;AACf,WAAO;AAAA,MACL;AAAA,IAEF;AAAA,EACF;AAEA,QAAM,QAAQ,WAAW,OAAO,KAAK;AACrC,MAAI,SAAS,KAAM,QAAO,KAAK,oBAAoB,OAAO,KAAK,sBAAsB;AAErF,QAAM,EAAE,WAAW,WAAW,IAAI,MAAM,sBAAsB,UAAU;AACxE,QAAM,UAAU,aAAa,OAAO,OAAO;AAE3C,QAAM,SAAS,MAAM,iBAAiB;AAAA,IACpC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ,OAAO,SAAS;AAAA,IACxB,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;AAAA,EAC/B,CAAC;AAED,QAAM,oBAAoB,QAAQ,SAAS,CAAC;AAC5C,SAAO,OAAO,QAAQ,KAAK,CAAC,MAAM,EAAE,WAAW,MAAM,IAAI,IAAI;AAC/D;","names":[]}