@ken-jo/agent-connector 0.4.0 → 0.4.6

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 (185) hide show
  1. package/README.md +9 -9
  2. package/dist/{action-PLZW5BGX.js → action-EV63GAPY.js} +11 -10
  3. package/dist/{action-PLZW5BGX.js.map → action-EV63GAPY.js.map} +1 -1
  4. package/dist/amazon-q-COAL3764.js +276 -0
  5. package/dist/amazon-q-COAL3764.js.map +1 -0
  6. package/dist/amp-XJQ4TDAU.js +666 -0
  7. package/dist/amp-XJQ4TDAU.js.map +1 -0
  8. package/dist/{antigravity-ANDKF3K7.js → antigravity-AMKKKHS4.js} +4 -4
  9. package/dist/{antigravity-cli-LLRPDDOT.js → antigravity-cli-XERXEH5W.js} +4 -4
  10. package/dist/{chunk-MAH6QQTO.js → chunk-2X4EH2D7.js} +5 -4
  11. package/dist/chunk-2X4EH2D7.js.map +1 -0
  12. package/dist/{chunk-G3ER4SY5.js → chunk-5G4EPJ4Y.js} +9 -9
  13. package/dist/chunk-BMD7ANKF.js +237 -0
  14. package/dist/chunk-BMD7ANKF.js.map +1 -0
  15. package/dist/{chunk-IW77FFNX.js → chunk-CPLK7GTE.js} +41 -5
  16. package/dist/chunk-CPLK7GTE.js.map +1 -0
  17. package/dist/{chunk-ADTHT2FN.js → chunk-DCK5FADX.js} +10 -173
  18. package/dist/chunk-DCK5FADX.js.map +1 -0
  19. package/dist/{chunk-J3D5W5T2.js → chunk-EROJDXMW.js} +2 -2
  20. package/dist/{chunk-22Y24V7O.js → chunk-F5RX62T7.js} +2 -2
  21. package/dist/chunk-FAHIMJRU.js +177 -0
  22. package/dist/chunk-FAHIMJRU.js.map +1 -0
  23. package/dist/{chunk-BHUCB6LY.js → chunk-H67V7DEL.js} +8 -7
  24. package/dist/{chunk-BHUCB6LY.js.map → chunk-H67V7DEL.js.map} +1 -1
  25. package/dist/{chunk-BXGFUENQ.js → chunk-I5MLE6S7.js} +14 -1
  26. package/dist/{chunk-BXGFUENQ.js.map → chunk-I5MLE6S7.js.map} +1 -1
  27. package/dist/{chunk-LL4OBGRU.js → chunk-LQRAPXS4.js} +3 -3
  28. package/dist/{chunk-KGJWE6A2.js → chunk-MZF2YCXX.js} +2 -2
  29. package/dist/{chunk-KGXDYGNJ.js → chunk-QC5A3TFQ.js} +19 -19
  30. package/dist/{chunk-KGXDYGNJ.js.map → chunk-QC5A3TFQ.js.map} +1 -1
  31. package/dist/{chunk-CIRDOY2V.js → chunk-QOGMDOUX.js} +3 -3
  32. package/dist/{chunk-KGGBNKI4.js → chunk-RQPKL62M.js} +144 -21
  33. package/dist/chunk-RQPKL62M.js.map +1 -0
  34. package/dist/{chunk-6XHB6BE3.js → chunk-SCVBYSF7.js} +1 -1
  35. package/dist/{chunk-76FUSVIA.js → chunk-SRVAA2VN.js} +6 -5
  36. package/dist/chunk-SRVAA2VN.js.map +1 -0
  37. package/dist/chunk-WZA4CSGJ.js +28 -0
  38. package/dist/chunk-WZA4CSGJ.js.map +1 -0
  39. package/dist/{claude-code-MLWS7CW6.js → claude-code-T2LPFNC3.js} +20 -30
  40. package/dist/claude-code-T2LPFNC3.js.map +1 -0
  41. package/dist/cli/sdk.js +5 -4
  42. package/dist/cli/sdk.js.map +1 -1
  43. package/dist/cli.js +1 -1
  44. package/dist/cline-WRYMNS7Z.js +442 -0
  45. package/dist/cline-WRYMNS7Z.js.map +1 -0
  46. package/dist/{codebuff-SH2S3QAN.js → codebuff-PODYPOOP.js} +130 -5
  47. package/dist/codebuff-PODYPOOP.js.map +1 -0
  48. package/dist/{codex-BXA4FIF4.js → codex-O4G7D7KK.js} +61 -13
  49. package/dist/codex-O4G7D7KK.js.map +1 -0
  50. package/dist/continue-K43SUHLQ.js +790 -0
  51. package/dist/continue-K43SUHLQ.js.map +1 -0
  52. package/dist/{copilot-cli-ROIBTTDT.js → copilot-cli-Q3SSPT4V.js} +70 -12
  53. package/dist/copilot-cli-Q3SSPT4V.js.map +1 -0
  54. package/dist/{crush-QLEFLHUC.js → crush-MBEH2R3I.js} +130 -6
  55. package/dist/crush-MBEH2R3I.js.map +1 -0
  56. package/dist/{cursor-ASJPWZ4R.js → cursor-TMBXDYR4.js} +119 -19
  57. package/dist/cursor-TMBXDYR4.js.map +1 -0
  58. package/dist/{detect-ZIIS55LD.js → detect-AHJIUMBO.js} +5 -4
  59. package/dist/{detect-ZIIS55LD.js.map → detect-AHJIUMBO.js.map} +1 -1
  60. package/dist/{doctor-TJUGSQ5C.js → doctor-G5MLCPAB.js} +221 -95
  61. package/dist/doctor-G5MLCPAB.js.map +1 -0
  62. package/dist/{droid-NCSS3B5Y.js → droid-JC2NT6S4.js} +135 -13
  63. package/dist/droid-JC2NT6S4.js.map +1 -0
  64. package/dist/{gemini-cli-SLVWLXJW.js → gemini-cli-ILR7M5X3.js} +62 -10
  65. package/dist/gemini-cli-ILR7M5X3.js.map +1 -0
  66. package/dist/{goose-PBA7KTE5.js → goose-SFO5BBGW.js} +15 -8
  67. package/dist/goose-SFO5BBGW.js.map +1 -0
  68. package/dist/{hermes-ONDCECP2.js → hermes-3N7WN4WS.js} +329 -15
  69. package/dist/hermes-3N7WN4WS.js.map +1 -0
  70. package/dist/{hook-OU522ABV.js → hook-76JBKTUX.js} +14 -11
  71. package/dist/hook-76JBKTUX.js.map +1 -0
  72. package/dist/index.d.ts +2 -2
  73. package/dist/index.js +3 -2
  74. package/dist/{install-UDCBL7HP.js → install-R7252QFH.js} +11 -10
  75. package/dist/{install-UDCBL7HP.js.map → install-R7252QFH.js.map} +1 -1
  76. package/dist/{introspect-DuZSPSHB.d.ts → introspect-Cn3MSA4_.d.ts} +1 -1
  77. package/dist/{jetbrains-copilot-YABZ3HFA.js → jetbrains-copilot-NRZHI5PC.js} +85 -18
  78. package/dist/jetbrains-copilot-NRZHI5PC.js.map +1 -0
  79. package/dist/{kilo-F3ZDZKCT.js → kilo-IX4T3OHJ.js} +115 -19
  80. package/dist/kilo-IX4T3OHJ.js.map +1 -0
  81. package/dist/{kilo-cli-3HWPWBY4.js → kilo-cli-2AYCXBQD.js} +109 -13
  82. package/dist/kilo-cli-2AYCXBQD.js.map +1 -0
  83. package/dist/{kimi-NV72FVAO.js → kimi-2YFK2GBA.js} +87 -25
  84. package/dist/kimi-2YFK2GBA.js.map +1 -0
  85. package/dist/{kiro-C5W6AGDR.js → kiro-YL6AWUYG.js} +3 -3
  86. package/dist/{leaderboard-TIBVONVT.js → leaderboard-V6VWA5ZV.js} +3 -3
  87. package/dist/{mimo-code-IMM5YM3M.js → mimo-code-FTMGSKMQ.js} +41 -5
  88. package/dist/mimo-code-FTMGSKMQ.js.map +1 -0
  89. package/dist/{mux-DSSH4AFS.js → mux-5XZFB44C.js} +156 -6
  90. package/dist/mux-5XZFB44C.js.map +1 -0
  91. package/dist/{nemoclaw-3EVNKD3I.js → nemoclaw-CQYXZVQN.js} +4 -4
  92. package/dist/{omp-Z6FRNDPN.js → omp-2QMEY6HD.js} +138 -18
  93. package/dist/omp-2QMEY6HD.js.map +1 -0
  94. package/dist/{openclaw-7G437NT7.js → openclaw-UZC437RW.js} +4 -4
  95. package/dist/{opencode-Q6KBSAKW.js → opencode-L4BGFP25.js} +87 -27
  96. package/dist/opencode-L4BGFP25.js.map +1 -0
  97. package/dist/{package-RMPN57YZ.js → package-DNLQTPNN.js} +8 -7
  98. package/dist/{package-RMPN57YZ.js.map → package-DNLQTPNN.js.map} +1 -1
  99. package/dist/{pi-LZT6WWAZ.js → pi-PVVPVWKG.js} +3 -2
  100. package/dist/{pi-LZT6WWAZ.js.map → pi-PVVPVWKG.js.map} +1 -1
  101. package/dist/{qwen-code-WQBKRPWJ.js → qwen-code-G4CXKUHR.js} +426 -10
  102. package/dist/qwen-code-G4CXKUHR.js.map +1 -0
  103. package/dist/{roo-code-GWSNU3OW.js → roo-code-67TYJIQR.js} +3 -3
  104. package/dist/runtime/index.d.ts +1 -1
  105. package/dist/runtime/index.js +9 -8
  106. package/dist/sdk/index.d.ts +3 -3
  107. package/dist/sdk/index.js +4 -3
  108. package/dist/sdk/index.js.map +1 -1
  109. package/dist/sdk/test.d.ts +2 -2
  110. package/dist/sdk/test.js +6 -5
  111. package/dist/sdk/test.js.map +1 -1
  112. package/dist/{serve-D3GO36UT.js → serve-EOVWYBGZ.js} +11 -10
  113. package/dist/{serve-D3GO36UT.js.map → serve-EOVWYBGZ.js.map} +1 -1
  114. package/dist/{status-KOSKCETC.js → status-VTD6XXLW.js} +7 -6
  115. package/dist/{status-KOSKCETC.js.map → status-VTD6XXLW.js.map} +1 -1
  116. package/dist/{statusline-ZNTCL5YC.js → statusline-3ET5YPQ5.js} +10 -9
  117. package/dist/{statusline-ZNTCL5YC.js.map → statusline-3ET5YPQ5.js.map} +1 -1
  118. package/dist/{telemetry-XIKUUGTQ.js → telemetry-QCTMKDBQ.js} +6 -5
  119. package/dist/{telemetry-XIKUUGTQ.js.map → telemetry-QCTMKDBQ.js.map} +1 -1
  120. package/dist/{trae-NWT3TMSZ.js → trae-7CZZGOGI.js} +3 -3
  121. package/dist/{types-BEKsAium.d.ts → types-_6arHbX9.d.ts} +67 -24
  122. package/dist/{uninstall-2LBLQVFA.js → uninstall-FL3SH2DT.js} +11 -10
  123. package/dist/{uninstall-2LBLQVFA.js.map → uninstall-FL3SH2DT.js.map} +1 -1
  124. package/dist/{upgrade-ZC2S7VRN.js → upgrade-SLFG2FCT.js} +11 -10
  125. package/dist/{upgrade-ZC2S7VRN.js.map → upgrade-SLFG2FCT.js.map} +1 -1
  126. package/dist/{usage-E2A4O2CY.js → usage-IRBLVUZM.js} +3 -3
  127. package/dist/{usage-event-JKMC4QC4.js → usage-event-VFF77WYY.js} +10 -9
  128. package/dist/{usage-event-JKMC4QC4.js.map → usage-event-VFF77WYY.js.map} +1 -1
  129. package/dist/{vscode-copilot-ALV45XF6.js → vscode-copilot-MF2CDNMT.js} +23 -10
  130. package/dist/vscode-copilot-MF2CDNMT.js.map +1 -0
  131. package/dist/{warp-H6IX4U3J.js → warp-VKG55TAT.js} +55 -4
  132. package/dist/warp-VKG55TAT.js.map +1 -0
  133. package/dist/windsurf-FU5G4SHF.js +443 -0
  134. package/dist/windsurf-FU5G4SHF.js.map +1 -0
  135. package/dist/{zed-RH34TNSW.js → zed-SFUHL3GS.js} +3 -3
  136. package/package.json +2 -2
  137. package/dist/amp-B524U6LO.js +0 -300
  138. package/dist/amp-B524U6LO.js.map +0 -1
  139. package/dist/chunk-3PFFTFCU.js +0 -190
  140. package/dist/chunk-3PFFTFCU.js.map +0 -1
  141. package/dist/chunk-76FUSVIA.js.map +0 -1
  142. package/dist/chunk-ADTHT2FN.js.map +0 -1
  143. package/dist/chunk-IW77FFNX.js.map +0 -1
  144. package/dist/chunk-KGGBNKI4.js.map +0 -1
  145. package/dist/chunk-MAH6QQTO.js.map +0 -1
  146. package/dist/claude-code-MLWS7CW6.js.map +0 -1
  147. package/dist/codebuff-SH2S3QAN.js.map +0 -1
  148. package/dist/codex-BXA4FIF4.js.map +0 -1
  149. package/dist/copilot-cli-ROIBTTDT.js.map +0 -1
  150. package/dist/crush-QLEFLHUC.js.map +0 -1
  151. package/dist/cursor-ASJPWZ4R.js.map +0 -1
  152. package/dist/doctor-TJUGSQ5C.js.map +0 -1
  153. package/dist/droid-NCSS3B5Y.js.map +0 -1
  154. package/dist/gemini-cli-SLVWLXJW.js.map +0 -1
  155. package/dist/goose-PBA7KTE5.js.map +0 -1
  156. package/dist/hermes-ONDCECP2.js.map +0 -1
  157. package/dist/hook-OU522ABV.js.map +0 -1
  158. package/dist/jetbrains-copilot-YABZ3HFA.js.map +0 -1
  159. package/dist/kilo-F3ZDZKCT.js.map +0 -1
  160. package/dist/kilo-cli-3HWPWBY4.js.map +0 -1
  161. package/dist/kimi-NV72FVAO.js.map +0 -1
  162. package/dist/mimo-code-IMM5YM3M.js.map +0 -1
  163. package/dist/mux-DSSH4AFS.js.map +0 -1
  164. package/dist/omp-Z6FRNDPN.js.map +0 -1
  165. package/dist/opencode-Q6KBSAKW.js.map +0 -1
  166. package/dist/qwen-code-WQBKRPWJ.js.map +0 -1
  167. package/dist/vscode-copilot-ALV45XF6.js.map +0 -1
  168. package/dist/warp-H6IX4U3J.js.map +0 -1
  169. /package/dist/{antigravity-ANDKF3K7.js.map → antigravity-AMKKKHS4.js.map} +0 -0
  170. /package/dist/{antigravity-cli-LLRPDDOT.js.map → antigravity-cli-XERXEH5W.js.map} +0 -0
  171. /package/dist/{chunk-G3ER4SY5.js.map → chunk-5G4EPJ4Y.js.map} +0 -0
  172. /package/dist/{chunk-J3D5W5T2.js.map → chunk-EROJDXMW.js.map} +0 -0
  173. /package/dist/{chunk-22Y24V7O.js.map → chunk-F5RX62T7.js.map} +0 -0
  174. /package/dist/{chunk-LL4OBGRU.js.map → chunk-LQRAPXS4.js.map} +0 -0
  175. /package/dist/{chunk-KGJWE6A2.js.map → chunk-MZF2YCXX.js.map} +0 -0
  176. /package/dist/{chunk-CIRDOY2V.js.map → chunk-QOGMDOUX.js.map} +0 -0
  177. /package/dist/{chunk-6XHB6BE3.js.map → chunk-SCVBYSF7.js.map} +0 -0
  178. /package/dist/{kiro-C5W6AGDR.js.map → kiro-YL6AWUYG.js.map} +0 -0
  179. /package/dist/{leaderboard-TIBVONVT.js.map → leaderboard-V6VWA5ZV.js.map} +0 -0
  180. /package/dist/{nemoclaw-3EVNKD3I.js.map → nemoclaw-CQYXZVQN.js.map} +0 -0
  181. /package/dist/{openclaw-7G437NT7.js.map → openclaw-UZC437RW.js.map} +0 -0
  182. /package/dist/{roo-code-GWSNU3OW.js.map → roo-code-67TYJIQR.js.map} +0 -0
  183. /package/dist/{trae-NWT3TMSZ.js.map → trae-7CZZGOGI.js.map} +0 -0
  184. /package/dist/{usage-E2A4O2CY.js.map → usage-IRBLVUZM.js.map} +0 -0
  185. /package/dist/{zed-RH34TNSW.js.map → zed-SFUHL3GS.js.map} +0 -0
@@ -0,0 +1,790 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ readYaml,
4
+ writeYaml
5
+ } from "./chunk-EXLS7BSI.js";
6
+ import {
7
+ extractSessionId,
8
+ toolResponseToString
9
+ } from "./chunk-WZA4CSGJ.js";
10
+ import {
11
+ resolveEnvRefsDeep
12
+ } from "./chunk-DBQMX75U.js";
13
+ import {
14
+ BaseAdapter
15
+ } from "./chunk-CPLK7GTE.js";
16
+ import "./chunk-7L6ITC4T.js";
17
+ import {
18
+ buildHomeBinHookCommand,
19
+ buildServeWrapperCommand,
20
+ isHomeBinHookCommand,
21
+ shouldWrapForTelemetry
22
+ } from "./chunk-I5MLE6S7.js";
23
+ import "./chunk-N6HH7K6P.js";
24
+ import "./chunk-TRQKHP7D.js";
25
+
26
+ // src/adapters/continue/index.ts
27
+ import { existsSync, statSync } from "fs";
28
+ import { homedir } from "os";
29
+ import { basename, join } from "path";
30
+ var HOST = "continue";
31
+ var MCP_ROOT_KEY = "mcpServers";
32
+ var SUPPORTED_EVENTS = /* @__PURE__ */ new Set([
33
+ "PreToolUse",
34
+ "PostToolUse",
35
+ "PostToolUseFailure",
36
+ "UserPromptSubmit",
37
+ "SessionStart",
38
+ "SessionEnd",
39
+ "Stop",
40
+ "Notification",
41
+ "SubagentStart",
42
+ "SubagentStop",
43
+ "PermissionRequest",
44
+ "PreCompact"
45
+ ]);
46
+ var ContinueAdapter = class extends BaseAdapter {
47
+ id = HOST;
48
+ name = "Continue";
49
+ paradigm = "json-stdio";
50
+ capabilities = {
51
+ // Memory surface: WIRED. Continue reads `.continue/rules/*.md` (NOT
52
+ // AGENTS.md), so the AGENTS.md-first BaseAdapter default does not apply — the
53
+ // installMemory/uninstallMemory overrides below write a DEDICATED
54
+ // agent-connector-owned file (<projectDir>/.continue/rules/agent-connector.md)
55
+ // that LEADS with `alwaysApply: true` frontmatter (always-included). Project
56
+ // scope only; user scope skip-warns (no verified user/global rules dir).
57
+ supportsMemory: true,
58
+ //
59
+ // json-stdio: the `cn` CLI ships a Claude-Code-COMPATIBLE hooks system (PR
60
+ // #11029). Every event in HOOK_EVENT_NAMES ∩ canonical fires natively; the
61
+ // names are PascalCase 1:1 with Claude. PreCompact IS in continue's set
62
+ // (PreCompactInput); only PostCompact is absent → that stays false (install
63
+ // warn-skips it).
64
+ preToolUse: true,
65
+ postToolUse: true,
66
+ postToolUseFailure: true,
67
+ preCompact: true,
68
+ sessionStart: true,
69
+ sessionEnd: true,
70
+ userPromptSubmit: true,
71
+ stop: true,
72
+ notification: true,
73
+ subagentStart: true,
74
+ subagentStop: true,
75
+ permissionRequest: true,
76
+ // Continue's PreToolUse output carries updatedInput (HookOutput
77
+ // PreToolUseHookOutput.updatedInput) → it CAN rewrite tool input. It cannot
78
+ // rewrite already-emitted tool output (PostToolUse exposes updatedMCPToolOutput,
79
+ // but — matching the claude-code adapter's conservative stance — we do not
80
+ // wire output rewrite). It honors hookSpecificOutput.additionalContext.
81
+ canModifyArgs: true,
82
+ canModifyOutput: false,
83
+ canInjectSessionContext: true,
84
+ // Continue registers stdio + remote (SSE / Streamable HTTP) MCP servers
85
+ // (primary-verified: type ∈ stdio|sse|streamable-http). Mapped to the
86
+ // framework's transport enum: stdio + sse + http (http = streamable-http).
87
+ transports: ["stdio", "sse", "http"],
88
+ // Native (passthrough) hooks: continue's HOOK_EVENT_NAMES carries five
89
+ // host-specific events with NO canonical analog — ConfigChange, TeammateIdle,
90
+ // TaskCompleted, WorktreeCreate, WorktreeRemove (each a real HookInput
91
+ // member, types.ts:214-241). They sit below the ≥3-host promotion bar, so a
92
+ // connector reaches them via platforms.continue.nativeHooks; installHooks
93
+ // files the event-name key VERBATIM and the generic uninstallHooks reverses
94
+ // it by connector-id ownership (same proven pattern as copilot-cli/hermes/
95
+ // jetbrains-copilot).
96
+ supportsNativeHooks: true
97
+ // Content surfaces: Continue's Rules/prompts are NOT wired here. Leave the
98
+ // supports* flags UNSET (base skip-warns).
99
+ };
100
+ // ── Detection ────────────────────────────────────────────────────────────
101
+ detectInstalled(projectDir) {
102
+ const userDir = this.userConfigDir();
103
+ const userCfg = join(userDir, "config.yaml");
104
+ const projCfg = join(projectDir, ".continue", "config.yaml");
105
+ const userInstalled = existsSync(userDir) || existsSync(userCfg);
106
+ const projInstalled = existsSync(projCfg);
107
+ const installed = userInstalled || projInstalled;
108
+ const scope = projInstalled && !userInstalled ? "project" : "user";
109
+ const configPath = scope === "project" ? projCfg : userCfg;
110
+ return {
111
+ id: this.id,
112
+ name: this.name,
113
+ installed,
114
+ paradigm: this.paradigm,
115
+ capabilities: this.capabilities,
116
+ configPath,
117
+ scope,
118
+ reason: installed ? `found Continue config (${scope}) at ${configPath}` : `no Continue config at ${userCfg} or ${projCfg}`,
119
+ confidence: installed ? "high" : "low"
120
+ };
121
+ }
122
+ // ── Native paths ─────────────────────────────────────────────────────────
123
+ /** ~/.continue (user) or <projectDir>/.continue (project). */
124
+ getConfigDir(ctx) {
125
+ return ctx.scope === "project" ? join(ctx.projectDir, ".continue") : this.userConfigDir();
126
+ }
127
+ /** MCP config: config.yaml under the per-scope .continue dir. */
128
+ getServerConfigPath(ctx) {
129
+ return join(this.getConfigDir(ctx), "config.yaml");
130
+ }
131
+ /**
132
+ * Hooks live in a SEPARATE settings.json (NOT the YAML config.yaml that holds
133
+ * MCP servers): user-global → <CONTINUE_GLOBAL_DIR|~/.continue>/settings.json;
134
+ * project → <projectDir>/.continue/settings.json (hookConfig.ts
135
+ * getSettingsFilePaths). The user-scope dir honors CONTINUE_GLOBAL_DIR exactly
136
+ * as the `cn` CLI's hook loader does — this is INTENTIONALLY independent of
137
+ * getConfigDir/userConfigDir (the MCP path), which the hook env must not perturb.
138
+ */
139
+ getHookConfigPath(ctx) {
140
+ const dir = ctx.scope === "project" ? join(ctx.projectDir, ".continue") : process.env.CONTINUE_GLOBAL_DIR || join(homedir(), ".continue");
141
+ return join(dir, "settings.json");
142
+ }
143
+ /** ~/.continue — homedir() covers %USERPROFILE% on Windows. */
144
+ userConfigDir() {
145
+ return join(homedir(), ".continue");
146
+ }
147
+ // ── Memory surface: the `.continue/rules` content tree ────────────────────
148
+ // A DEDICATED agent-connector-owned file that MUST LEAD with `alwaysApply:
149
+ // true` frontmatter (always-included). Because of that leading frontmatter we
150
+ // do NOT use the base managed-block engine (it appends a block at EOF and
151
+ // cannot guarantee a leading frontmatter, nor delete a file that retains
152
+ // frontmatter on uninstall) — instead we own the whole file via the
153
+ // content-file writers: install writes/updates it idempotently, uninstall
154
+ // deletes it. PROJECT SCOPE ONLY (the user/global rules dir is unverified).
155
+ /** <projectDir>/.continue/rules/agent-connector.md — the dedicated owned file. */
156
+ memoryFilePath(ctx) {
157
+ return join(ctx.projectDir, ".continue", "rules", "agent-connector.md");
158
+ }
159
+ /** True when `<projectDir>/.continue/rules` exists and is a regular FILE. */
160
+ rulesDirIsFile(ctx) {
161
+ const p = join(ctx.projectDir, ".continue", "rules");
162
+ if (!existsSync(p)) return false;
163
+ try {
164
+ return statSync(p).isFile();
165
+ } catch {
166
+ return false;
167
+ }
168
+ }
169
+ /**
170
+ * Compose the dedicated rule file: `alwaysApply: true` frontmatter (the
171
+ * always-on activation directive) + every declared memory entry's content,
172
+ * joined with a blank line. The connector's content is host-agnostic markdown
173
+ * (MemoryDef forbids its own frontmatter), so the directive is ours to add.
174
+ */
175
+ renderMemoryFile(ctx) {
176
+ const body = (ctx.connector.memory ?? []).map((m) => m.content.trim()).filter((c) => c.length > 0).join("\n\n");
177
+ return this.renderFrontmatterMd({ alwaysApply: true }, body);
178
+ }
179
+ installMemory(ctx) {
180
+ const { connector } = ctx;
181
+ const entries = connector.memory ?? [];
182
+ if (connector.platforms[this.id]?.memory === false) {
183
+ return [{ platform: this.id, action: "skip", detail: `memory disabled for ${this.id}` }];
184
+ }
185
+ if (entries.length === 0) {
186
+ return [{ platform: this.id, action: "skip", detail: "connector declares no memory" }];
187
+ }
188
+ if (ctx.scope !== "project") {
189
+ return [
190
+ {
191
+ platform: this.id,
192
+ action: "warn",
193
+ detail: `no ${ctx.scope}-scope rules dir verified for continue (.continue/rules is project-scope); ${entries.length} skipped`
194
+ }
195
+ ];
196
+ }
197
+ if (this.rulesDirIsFile(ctx)) {
198
+ return [
199
+ {
200
+ platform: this.id,
201
+ action: "warn",
202
+ path: join(ctx.projectDir, ".continue", "rules"),
203
+ detail: "existing .continue/rules is a file, not a directory; left untouched \u2014 convert it to a .continue/rules/ directory to receive agent-connector memory"
204
+ }
205
+ ];
206
+ }
207
+ return [this.writeContentFile(this.memoryFilePath(ctx), this.renderMemoryFile(ctx), ctx.dryRun)];
208
+ }
209
+ uninstallMemory(ctx) {
210
+ if (ctx.scope !== "project" || this.rulesDirIsFile(ctx)) {
211
+ const path = this.memoryFilePath(ctx);
212
+ return [
213
+ { platform: this.id, action: "skip", path, detail: `${basename(path)} absent` }
214
+ ];
215
+ }
216
+ return [this.removeContentFile(this.memoryFilePath(ctx), ctx.dryRun)];
217
+ }
218
+ // ── MCP server install / uninstall (YAML — ARRAY merge) ───────────────────
219
+ installServer(ctx) {
220
+ const { connector, dryRun } = ctx;
221
+ const path = this.getServerConfigPath(ctx);
222
+ const server = this.effectiveServer(ctx);
223
+ if (!server) {
224
+ return [
225
+ {
226
+ platform: this.id,
227
+ action: "skip",
228
+ path,
229
+ detail: connector.server ? "server registration disabled for continue" : "connector declares no MCP server"
230
+ }
231
+ ];
232
+ }
233
+ const entry = this.renderServerEntry(ctx, server);
234
+ const cfg = readYaml(path) ?? {};
235
+ const existingRoot = cfg[MCP_ROOT_KEY];
236
+ if (existingRoot !== void 0 && !Array.isArray(existingRoot)) {
237
+ return [{ platform: this.id, action: "skip", path, detail: `${MCP_ROOT_KEY} is not a YAML array \u2014 left untouched (manual fix needed)` }];
238
+ }
239
+ const list = this.serverArray(cfg);
240
+ const idx = list.findIndex((e) => this.entryName(e) === connector.id);
241
+ let action;
242
+ if (idx < 0) {
243
+ list.push(entry);
244
+ action = "create";
245
+ } else if (JSON.stringify(list[idx]) === JSON.stringify(entry)) {
246
+ action = "skip";
247
+ } else {
248
+ list[idx] = entry;
249
+ action = "update";
250
+ }
251
+ if (action !== "skip") {
252
+ cfg[MCP_ROOT_KEY] = list;
253
+ writeYaml(path, cfg, dryRun);
254
+ }
255
+ return [{ platform: this.id, action, path, detail: `${MCP_ROOT_KEY}[name=${connector.id}]` }];
256
+ }
257
+ uninstallServer(ctx) {
258
+ const { connector, dryRun } = ctx;
259
+ const path = this.getServerConfigPath(ctx);
260
+ const cfg = readYaml(path);
261
+ const rawList = cfg?.[MCP_ROOT_KEY];
262
+ if (!cfg || !Array.isArray(rawList)) {
263
+ return [
264
+ {
265
+ platform: this.id,
266
+ action: "skip",
267
+ path,
268
+ detail: `${MCP_ROOT_KEY}[name=${connector.id}] absent`
269
+ }
270
+ ];
271
+ }
272
+ const list = rawList;
273
+ const kept = list.filter((e) => this.entryName(e) !== connector.id);
274
+ if (kept.length === list.length) {
275
+ return [
276
+ {
277
+ platform: this.id,
278
+ action: "skip",
279
+ path,
280
+ detail: `${MCP_ROOT_KEY}[name=${connector.id}] absent`
281
+ }
282
+ ];
283
+ }
284
+ cfg[MCP_ROOT_KEY] = kept;
285
+ writeYaml(path, cfg, dryRun);
286
+ return [
287
+ { platform: this.id, action: "remove", path, detail: `${MCP_ROOT_KEY}[name=${connector.id}]` }
288
+ ];
289
+ }
290
+ /**
291
+ * Render a normalized ServerDef into Continue's native mcpServers entry.
292
+ * Continue has no documented native ${env:VAR} token — resolve every reference
293
+ * to a literal at install time (the safe path, matching amazon-q/goose/hermes).
294
+ * Honors the telemetry serve-wrapper for stdio.
295
+ */
296
+ renderServerEntry(ctx, server) {
297
+ const transport = server.transport;
298
+ if (transport === "stdio") {
299
+ let command = server.command ?? "";
300
+ let args = [...server.args ?? []];
301
+ if (shouldWrapForTelemetry(server, ctx.connector.telemetry)) {
302
+ const wrapped = buildServeWrapperCommand(
303
+ ctx.homeBinPath,
304
+ ctx.connector.id,
305
+ command,
306
+ args,
307
+ ctx.scope,
308
+ this.id
309
+ );
310
+ command = wrapped.command;
311
+ args = wrapped.args;
312
+ }
313
+ command = resolveEnvRefsDeep(command);
314
+ args = resolveEnvRefsDeep(args);
315
+ const entry = {
316
+ name: ctx.connector.id,
317
+ command
318
+ };
319
+ if (args.length > 0) entry.args = args;
320
+ const env = this.renderEnv(server.env);
321
+ if (env) entry.env = env;
322
+ if (typeof server.cwd === "string" && server.cwd.length > 0) {
323
+ entry.cwd = resolveEnvRefsDeep(server.cwd);
324
+ }
325
+ return entry;
326
+ }
327
+ const type = transport === "sse" ? "sse" : "streamable-http";
328
+ return {
329
+ name: ctx.connector.id,
330
+ type,
331
+ url: resolveEnvRefsDeep(server.url ?? "")
332
+ };
333
+ }
334
+ /**
335
+ * Render stdio env values. Continue has no documented native interpolation
336
+ * token, so resolve `${env:VAR}` references to literals at install time.
337
+ */
338
+ renderEnv(env) {
339
+ if (!env || Object.keys(env).length === 0) return void 0;
340
+ const out = {};
341
+ for (const [k, v] of Object.entries(resolveEnvRefsDeep({ ...env }))) {
342
+ out[k] = String(v);
343
+ }
344
+ return out;
345
+ }
346
+ // ── Hook install / uninstall (separate settings.json, Claude-shaped) ──────
347
+ // Continue's hooks live in settings.json (NOT the YAML config.yaml that holds
348
+ // MCP servers), under `hooks` keyed by PascalCase event, each value an array
349
+ // of { matcher?, hooks:[{ type:"command", command }] } — BYTE-IDENTICAL to
350
+ // Claude Code. Events outside SUPPORTED_EVENTS (PostCompact) warn-skip; the
351
+ // five host-specific events with no canonical analog (ConfigChange,
352
+ // TeammateIdle, TaskCompleted, WorktreeCreate, WorktreeRemove) ride the
353
+ // nativeHooks passthrough below. Merge-preserving: the user's own hooks + any
354
+ // sibling connector's hooks survive; uninstall strips ONLY this connector's
355
+ // home-bin command (anchored).
356
+ installHooks(ctx) {
357
+ const { connector } = ctx;
358
+ const override = connector.platforms[HOST];
359
+ const hooksDisabled = override?.hooks === false;
360
+ const normalizedEvents = hooksDisabled ? [] : connector.hookEvents;
361
+ const nativeHooks = override?.nativeHooks ?? {};
362
+ const nativeEvents = Object.keys(nativeHooks);
363
+ if (normalizedEvents.length === 0 && nativeEvents.length === 0) {
364
+ return [
365
+ {
366
+ platform: this.id,
367
+ action: "skip",
368
+ detail: hooksDisabled ? "hooks disabled for continue" : "connector declares no hooks"
369
+ }
370
+ ];
371
+ }
372
+ const hookPath = this.getHookConfigPath(ctx);
373
+ const file = this.readJson(hookPath) ?? {};
374
+ const hooks = file.hooks ??= {};
375
+ const changes = [];
376
+ let mutated = false;
377
+ for (const event of normalizedEvents) {
378
+ if (!SUPPORTED_EVENTS.has(event)) {
379
+ changes.push({
380
+ platform: this.id,
381
+ action: "warn",
382
+ path: hookPath,
383
+ detail: `${event} has no Continue hook equivalent \u2014 skipped`
384
+ });
385
+ continue;
386
+ }
387
+ const command = buildHomeBinHookCommand(ctx.homeBinPath, HOST, event, connector.id);
388
+ const matcher = connector.hooks[event]?.matcher ?? "";
389
+ const entry = {
390
+ matcher,
391
+ hooks: [{ type: "command", command }]
392
+ };
393
+ const bucket = hooks[event] ??= [];
394
+ const existingIdx = bucket.findIndex((e) => this.entryHasOurCommand(e, ctx));
395
+ if (existingIdx >= 0) {
396
+ if (JSON.stringify(bucket[existingIdx]) === JSON.stringify(entry)) {
397
+ changes.push({
398
+ platform: this.id,
399
+ action: "skip",
400
+ path: hookPath,
401
+ detail: `hooks.${event} already registered`
402
+ });
403
+ continue;
404
+ }
405
+ bucket[existingIdx] = entry;
406
+ changes.push({
407
+ platform: this.id,
408
+ action: "update",
409
+ path: hookPath,
410
+ detail: `hooks.${event}`
411
+ });
412
+ } else {
413
+ bucket.push(entry);
414
+ changes.push({
415
+ platform: this.id,
416
+ action: "create",
417
+ path: hookPath,
418
+ detail: `hooks.${event}`
419
+ });
420
+ }
421
+ mutated = true;
422
+ }
423
+ for (const nativeEvent of nativeEvents) {
424
+ const command = buildHomeBinHookCommand(ctx.homeBinPath, HOST, nativeEvent, connector.id);
425
+ const entry = {
426
+ matcher: nativeHooks[nativeEvent]?.matcher ?? "",
427
+ hooks: [{ type: "command", command }]
428
+ };
429
+ const bucket = hooks[nativeEvent] ??= [];
430
+ const existingIdx = bucket.findIndex((e) => e.hooks?.[0]?.command === command);
431
+ if (existingIdx >= 0) {
432
+ if (JSON.stringify(bucket[existingIdx]) === JSON.stringify(entry)) {
433
+ changes.push({
434
+ platform: this.id,
435
+ action: "skip",
436
+ path: hookPath,
437
+ detail: `hooks.${nativeEvent} (native) already registered`
438
+ });
439
+ continue;
440
+ }
441
+ bucket[existingIdx] = entry;
442
+ changes.push({
443
+ platform: this.id,
444
+ action: "update",
445
+ path: hookPath,
446
+ detail: `hooks.${nativeEvent} (native)`
447
+ });
448
+ } else {
449
+ bucket.push(entry);
450
+ changes.push({
451
+ platform: this.id,
452
+ action: "create",
453
+ path: hookPath,
454
+ detail: `hooks.${nativeEvent} (native)`
455
+ });
456
+ }
457
+ mutated = true;
458
+ }
459
+ if (mutated) this.writeJson(hookPath, file, ctx.dryRun);
460
+ return changes;
461
+ }
462
+ uninstallHooks(ctx) {
463
+ const hookPath = this.getHookConfigPath(ctx);
464
+ const file = this.readJson(hookPath);
465
+ const hooks = file?.hooks;
466
+ if (!file || !hooks) {
467
+ return [
468
+ {
469
+ platform: this.id,
470
+ action: "skip",
471
+ path: hookPath,
472
+ detail: "no hooks section present"
473
+ }
474
+ ];
475
+ }
476
+ const changes = [];
477
+ let mutated = false;
478
+ for (const event of Object.keys(hooks)) {
479
+ const bucket = hooks[event];
480
+ if (!Array.isArray(bucket)) continue;
481
+ const next = [];
482
+ let removed = 0;
483
+ for (const e of bucket) {
484
+ const innerBefore = e.hooks?.length ?? 0;
485
+ const inner = (e.hooks ?? []).filter((h) => !this.isOurCommand(h.command, ctx));
486
+ removed += innerBefore - inner.length;
487
+ if (inner.length > 0) next.push({ matcher: e.matcher ?? "", hooks: inner });
488
+ }
489
+ if (removed > 0) {
490
+ if (next.length > 0) hooks[event] = next;
491
+ else delete hooks[event];
492
+ changes.push({
493
+ platform: this.id,
494
+ action: "remove",
495
+ path: hookPath,
496
+ detail: `hooks.${event} (${removed})`
497
+ });
498
+ mutated = true;
499
+ }
500
+ }
501
+ if (mutated) this.writeJson(hookPath, file, ctx.dryRun);
502
+ if (changes.length === 0) {
503
+ changes.push({
504
+ platform: this.id,
505
+ action: "skip",
506
+ path: hookPath,
507
+ detail: "no matching hook entries"
508
+ });
509
+ }
510
+ return changes;
511
+ }
512
+ entryHasOurCommand(entry, ctx) {
513
+ return (entry.hooks ?? []).some((h) => this.isOurCommand(h.command, ctx));
514
+ }
515
+ /** True when a hook command references our home binary AND this connector id
516
+ * (anchored so a shared-prefix id can't collide — see isHomeBinHookCommand). */
517
+ isOurCommand(command, ctx) {
518
+ return isHomeBinHookCommand(command, ctx.homeBinPath, ctx.connector.id);
519
+ }
520
+ // ── Runtime: parse Continue stdin JSON → normalized event ────────────────
521
+ // Continue's stdin wire is Claude-identical snake_case (PR #11029 types.ts
522
+ // HookInput), so the claude-code wire helpers (ClaudeWireInput / extractSessionId
523
+ // / toolResponseToString) apply verbatim.
524
+ parseEvent(event, raw) {
525
+ const input = raw ?? {};
526
+ const connectorId = typeof input.connector === "string" ? input.connector : "";
527
+ const sessionId = extractSessionId(input);
528
+ const projectDir = typeof input.cwd === "string" ? input.cwd : void 0;
529
+ const base = {
530
+ hostPlatform: HOST,
531
+ connectorId,
532
+ sessionId,
533
+ raw,
534
+ ...projectDir !== void 0 ? { projectDir } : {}
535
+ };
536
+ switch (event) {
537
+ case "PreToolUse": {
538
+ const ev = {
539
+ ...base,
540
+ toolName: input.tool_name ?? "",
541
+ toolInput: input.tool_input ?? {}
542
+ };
543
+ return ev;
544
+ }
545
+ case "PostToolUse": {
546
+ const ev = {
547
+ ...base,
548
+ toolName: input.tool_name ?? "",
549
+ toolInput: input.tool_input ?? {},
550
+ ...toolResponseToString(input.tool_response) !== void 0 ? { toolOutput: toolResponseToString(input.tool_response) } : {}
551
+ };
552
+ return ev;
553
+ }
554
+ case "PostToolUseFailure": {
555
+ const ev = {
556
+ ...base,
557
+ toolName: input.tool_name ?? "",
558
+ toolInput: input.tool_input ?? {},
559
+ error: typeof input.error === "string" ? input.error : "",
560
+ ...typeof input.tool_use_id === "string" ? { toolUseId: input.tool_use_id } : {},
561
+ ...typeof input.is_interrupt === "boolean" ? { isInterrupt: input.is_interrupt } : {},
562
+ ...typeof input.duration_ms === "number" ? { durationMs: input.duration_ms } : {}
563
+ };
564
+ return ev;
565
+ }
566
+ case "UserPromptSubmit": {
567
+ const ev = {
568
+ ...base,
569
+ prompt: typeof input.prompt === "string" ? input.prompt : ""
570
+ };
571
+ return ev;
572
+ }
573
+ case "SessionStart": {
574
+ const ev = {
575
+ ...base,
576
+ source: normalizeSessionSource(input.source)
577
+ };
578
+ return ev;
579
+ }
580
+ case "SessionEnd": {
581
+ const ev = {
582
+ ...base,
583
+ ...typeof input.reason === "string" ? { reason: input.reason } : {}
584
+ };
585
+ return ev;
586
+ }
587
+ case "Stop": {
588
+ const ev = {
589
+ ...base,
590
+ ...typeof input.stop_hook_active === "boolean" ? { stopHookActive: input.stop_hook_active } : {}
591
+ };
592
+ return ev;
593
+ }
594
+ case "Notification": {
595
+ const ev = {
596
+ ...base,
597
+ message: typeof input.message === "string" ? input.message : ""
598
+ };
599
+ return ev;
600
+ }
601
+ case "PermissionRequest": {
602
+ const ev = {
603
+ ...base,
604
+ toolName: input.tool_name ?? "",
605
+ toolInput: input.tool_input ?? {},
606
+ ...Array.isArray(input.permission_suggestions) ? { permissionSuggestions: input.permission_suggestions } : {}
607
+ };
608
+ return ev;
609
+ }
610
+ case "SubagentStart": {
611
+ const ev = {
612
+ ...base,
613
+ ...typeof input.agent_id === "string" ? { agentId: input.agent_id } : {},
614
+ ...typeof input.agent_type === "string" ? { agentType: input.agent_type } : {}
615
+ };
616
+ return ev;
617
+ }
618
+ case "SubagentStop": {
619
+ const ev = {
620
+ ...base,
621
+ ...typeof input.agent_id === "string" ? { agentId: input.agent_id } : {},
622
+ ...typeof input.agent_type === "string" ? { agentType: input.agent_type } : {},
623
+ ...typeof input.agent_transcript_path === "string" ? { agentTranscriptPath: input.agent_transcript_path } : {},
624
+ ...typeof input.last_assistant_message === "string" ? { lastAssistantMessage: input.last_assistant_message } : {},
625
+ ...typeof input.stop_hook_active === "boolean" ? { stopHookActive: input.stop_hook_active } : {}
626
+ };
627
+ return ev;
628
+ }
629
+ case "PreCompact": {
630
+ const ev = {
631
+ ...base,
632
+ ...input.trigger === "auto" || input.trigger === "manual" ? { trigger: input.trigger } : {}
633
+ };
634
+ return ev;
635
+ }
636
+ default: {
637
+ throw new Error(`unsupported continue hook event: ${String(event)}`);
638
+ }
639
+ }
640
+ }
641
+ // ── Runtime: normalized response → Continue native (Claude-shaped) reply ──
642
+ // Continue's HookOutput is Claude-identical, so this mirrors the claude-code
643
+ // adapter's formatReply byte-for-byte:
644
+ // PermissionRequest → nested decision{ behavior:"allow"|"deny" } envelope;
645
+ // PostToolUseFailure / SubagentStart → context-only (deny degrades to
646
+ // additionalContext carrying the reason);
647
+ // Stop / SubagentStop / UserPromptSubmit / PostToolUse deny → TOP-LEVEL
648
+ // { decision:"block", reason };
649
+ // other deny → hookSpecificOutput.permissionDecision:"deny"; ask → "ask";
650
+ // modify (PreToolUse) → updatedInput; context → additionalContext.
651
+ formatReply(event, response) {
652
+ const hookEventName = event;
653
+ const decision = response.decision ?? "allow";
654
+ if (event === "PermissionRequest") {
655
+ if (response.decision === "deny") {
656
+ return this.stdout({
657
+ hookSpecificOutput: {
658
+ hookEventName,
659
+ decision: { behavior: "deny", message: response.reason ?? "Blocked by hook" }
660
+ }
661
+ });
662
+ }
663
+ if (response.decision === "allow" || response.decision === "modify" && response.updatedInput) {
664
+ return this.stdout({
665
+ hookSpecificOutput: {
666
+ hookEventName,
667
+ decision: {
668
+ behavior: "allow",
669
+ ...response.updatedInput ? { updatedInput: response.updatedInput } : {}
670
+ }
671
+ }
672
+ });
673
+ }
674
+ return { exitCode: 0 };
675
+ }
676
+ if (event === "PostToolUseFailure" || event === "SubagentStart") {
677
+ const context = decision === "context" ? response.additionalContext : decision === "deny" ? response.reason ?? response.additionalContext : void 0;
678
+ if (context) {
679
+ return this.stdout({
680
+ hookSpecificOutput: { hookEventName, additionalContext: context }
681
+ });
682
+ }
683
+ return { exitCode: 0 };
684
+ }
685
+ if (decision === "deny") {
686
+ if (event === "Stop" || event === "SubagentStop" || event === "UserPromptSubmit" || event === "PostToolUse") {
687
+ return this.stdout({
688
+ decision: "block",
689
+ reason: response.reason ?? "Blocked by hook"
690
+ });
691
+ }
692
+ return this.stdout({
693
+ hookSpecificOutput: {
694
+ hookEventName,
695
+ permissionDecision: "deny",
696
+ permissionDecisionReason: response.reason ?? "Blocked by hook"
697
+ }
698
+ });
699
+ }
700
+ if (decision === "ask") {
701
+ return this.stdout({
702
+ hookSpecificOutput: {
703
+ hookEventName,
704
+ permissionDecision: "ask",
705
+ permissionDecisionReason: response.reason ?? "Confirmation required by hook"
706
+ }
707
+ });
708
+ }
709
+ if (decision === "modify") {
710
+ if (event === "PreToolUse" && response.updatedInput) {
711
+ return this.stdout({
712
+ hookSpecificOutput: { hookEventName, updatedInput: response.updatedInput }
713
+ });
714
+ }
715
+ }
716
+ if (decision === "context" && response.additionalContext) {
717
+ return this.stdout({
718
+ hookSpecificOutput: { hookEventName, additionalContext: response.additionalContext }
719
+ });
720
+ }
721
+ return { exitCode: 0 };
722
+ }
723
+ stdout(payload) {
724
+ return { exitCode: 0, stdout: JSON.stringify(payload) };
725
+ }
726
+ // ── Diagnostics ──────────────────────────────────────────────────────────
727
+ getHealthChecks(ctx) {
728
+ const path = this.getServerConfigPath(ctx);
729
+ const id = ctx.connector.id;
730
+ return [
731
+ {
732
+ name: `${this.name}: config.yaml present`,
733
+ check: () => existsSync(path) ? { status: "OK", detail: path } : { status: "FAIL", detail: `not found: ${path}` }
734
+ },
735
+ {
736
+ name: `${this.name}: ${MCP_ROOT_KEY}[name=${id}] registered`,
737
+ check: () => {
738
+ if (!ctx.connector.server) return { status: "OK", detail: "no MCP server declared" };
739
+ const cfg = readYaml(path);
740
+ const list = cfg?.[MCP_ROOT_KEY];
741
+ const present = Array.isArray(list) && list.some((e) => this.entryName(e) === id);
742
+ return present ? { status: "OK", detail: `${MCP_ROOT_KEY}[name=${id}]` } : { status: "FAIL", detail: `${MCP_ROOT_KEY}[name=${id}] not found in ${path}` };
743
+ }
744
+ }
745
+ ];
746
+ }
747
+ // ── Internal helpers ──────────────────────────────────────────────────────
748
+ /** Get-or-create the mcpServers ARRAY at `cfg.mcpServers` (tolerate non-array). */
749
+ serverArray(cfg) {
750
+ const existing = cfg[MCP_ROOT_KEY];
751
+ if (Array.isArray(existing)) return existing;
752
+ const fresh = [];
753
+ cfg[MCP_ROOT_KEY] = fresh;
754
+ return fresh;
755
+ }
756
+ /** The `name` of an array entry, or undefined when it is not a named object. */
757
+ entryName(entry) {
758
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) return void 0;
759
+ const name = entry.name;
760
+ return typeof name === "string" ? name : void 0;
761
+ }
762
+ /** Resolve the per-platform server override into an effective ServerDef. */
763
+ effectiveServer(ctx) {
764
+ const override = ctx.connector.platforms[this.id]?.server;
765
+ if (override === false) return void 0;
766
+ const base = ctx.connector.server;
767
+ if (!base) return void 0;
768
+ return override && typeof override === "object" ? { ...base, ...override } : base;
769
+ }
770
+ };
771
+ function normalizeSessionSource(source) {
772
+ switch (source) {
773
+ case "compact":
774
+ return "compact";
775
+ case "resume":
776
+ return "resume";
777
+ case "clear":
778
+ return "clear";
779
+ default:
780
+ return "startup";
781
+ }
782
+ }
783
+ var adapter = new ContinueAdapter();
784
+ var continue_default = adapter;
785
+ export {
786
+ ContinueAdapter,
787
+ adapter,
788
+ continue_default as default
789
+ };
790
+ //# sourceMappingURL=continue-K43SUHLQ.js.map