@gajae-code/coding-agent 0.18.12 → 0.19.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 (305) hide show
  1. package/CHANGELOG.md +467 -0
  2. package/dist/types/capability/rule.d.ts +7 -2
  3. package/dist/types/cli/append-system-prompt.d.ts +6 -0
  4. package/dist/types/cli/args.d.ts +7 -2
  5. package/dist/types/cli/customize-doctor-precedence.d.ts +16 -0
  6. package/dist/types/cli/customize-doctor.d.ts +4 -3
  7. package/dist/types/cli/public-command-errors.d.ts +1 -0
  8. package/dist/types/cli/root-flags.d.ts +0 -12
  9. package/dist/types/cli/update-cli.d.ts +7 -2
  10. package/dist/types/cli-main.d.ts +0 -6
  11. package/dist/types/commands/launch.d.ts +0 -6
  12. package/dist/types/commands/migrate.d.ts +1 -1
  13. package/dist/types/commands/sdk.d.ts +8 -0
  14. package/dist/types/commit/map-reduce/index.d.ts +4 -4
  15. package/dist/types/config/autorouting-tier-map.d.ts +23 -1
  16. package/dist/types/config/config-hot-reload.d.ts +5 -0
  17. package/dist/types/config/file-lock.d.ts +44 -2
  18. package/dist/types/config/model-profile-activation.d.ts +19 -5
  19. package/dist/types/config/model-registry.d.ts +16 -3
  20. package/dist/types/config/model-resolver.d.ts +5 -4
  21. package/dist/types/config/settings-schema.d.ts +11 -1
  22. package/dist/types/coordinator-mcp/server.d.ts +4 -0
  23. package/dist/types/customization/import.d.ts +2 -0
  24. package/dist/types/customization/types.d.ts +1 -1
  25. package/dist/types/dap/session.d.ts +11 -2
  26. package/dist/types/discovery/helpers.d.ts +7 -2
  27. package/dist/types/edit/index.d.ts +5 -0
  28. package/dist/types/edit/modes/patch.d.ts +9 -0
  29. package/dist/types/eval/py/runtime.d.ts +9 -0
  30. package/dist/types/export/ttsr.d.ts +19 -0
  31. package/dist/types/extensibility/extensions/types.d.ts +5 -1
  32. package/dist/types/extensibility/slash-commands.d.ts +1 -0
  33. package/dist/types/gjc-runtime/ralplan-current-final.d.ts +54 -0
  34. package/dist/types/gjc-runtime/ralplan-runtime.d.ts +5 -0
  35. package/dist/types/gjc-runtime/tmux-sessions.d.ts +24 -0
  36. package/dist/types/gjc-runtime/ultragoal-change-set.d.ts +6 -0
  37. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +1 -0
  38. package/dist/types/harness-control-plane/receipt-spool.d.ts +4 -0
  39. package/dist/types/hindsight/content.d.ts +5 -6
  40. package/dist/types/internal-urls/types.d.ts +2 -0
  41. package/dist/types/lsp/clients/swiftlint-client.d.ts +0 -4
  42. package/dist/types/main.d.ts +23 -18
  43. package/dist/types/migrate/action-planner.d.ts +10 -1
  44. package/dist/types/migrate/adapters/codex.d.ts +1 -1
  45. package/dist/types/migrate/adapters/index.d.ts +35 -3
  46. package/dist/types/migrate/hook-module.d.ts +23 -0
  47. package/dist/types/migrate/report.d.ts +2 -1
  48. package/dist/types/migrate/types.d.ts +69 -2
  49. package/dist/types/modes/components/agent-dashboard.d.ts +1 -1
  50. package/dist/types/modes/components/model-selector.d.ts +43 -0
  51. package/dist/types/modes/prompt-suggestion-controller.d.ts +1 -1
  52. package/dist/types/modes/utils/host-status.d.ts +15 -11
  53. package/dist/types/runtime-mcp/project-host-values.d.ts +11 -5
  54. package/dist/types/sdk/broker/broker-exit.d.ts +1 -1
  55. package/dist/types/sdk/broker/broker.d.ts +22 -1
  56. package/dist/types/sdk/broker/ensure.d.ts +5 -2
  57. package/dist/types/sdk/broker/hop.d.ts +9 -0
  58. package/dist/types/sdk/broker/lifecycle.d.ts +22 -0
  59. package/dist/types/sdk/broker/session-index.d.ts +2 -0
  60. package/dist/types/sdk/broker/transport.d.ts +2 -0
  61. package/dist/types/sdk/bus/index.d.ts +21 -0
  62. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +7 -1
  63. package/dist/types/sdk/bus/telegram-daemon.d.ts +2 -0
  64. package/dist/types/sdk/bus/threaded-render.d.ts +2 -1
  65. package/dist/types/sdk/host/control/operations.d.ts +5 -1
  66. package/dist/types/sdk/host/events.d.ts +4 -0
  67. package/dist/types/sdk/host/host.d.ts +2 -1
  68. package/dist/types/sdk/host/prompt-image-upload.d.ts +43 -0
  69. package/dist/types/sdk/host/session-runtime.d.ts +8 -8
  70. package/dist/types/sdk/host/surface-policy.d.ts +2 -1
  71. package/dist/types/sdk/lifecycle/service.d.ts +12 -0
  72. package/dist/types/sdk/prompt-status.d.ts +11 -4
  73. package/dist/types/session/agent-session.d.ts +50 -8
  74. package/dist/types/session/session-manager.d.ts +16 -0
  75. package/dist/types/skill-state/workflow-mutation-guard.d.ts +13 -1
  76. package/dist/types/slash-commands/helpers/mcp.d.ts +5 -0
  77. package/dist/types/ssh/ssh-executor.d.ts +8 -1
  78. package/dist/types/system-prompt.d.ts +3 -2
  79. package/dist/types/task/role-body.d.ts +11 -0
  80. package/dist/types/tools/awaiting-input.d.ts +28 -0
  81. package/dist/types/tools/bash-allowed-prefixes.d.ts +6 -0
  82. package/dist/types/tools/bash-skill-urls.d.ts +4 -0
  83. package/dist/types/tools/bash.d.ts +7 -0
  84. package/dist/types/tools/descriptors.d.ts +13 -2
  85. package/dist/types/tools/fetch.d.ts +6 -0
  86. package/dist/types/tools/irc.d.ts +5 -3
  87. package/dist/types/tools/tmux-self-injection-guard.d.ts +2 -0
  88. package/dist/types/tools/ultragoal-ask-guard.d.ts +1 -1
  89. package/dist/types/tools/write.d.ts +2 -0
  90. package/dist/types/utils/file-mentions.d.ts +5 -0
  91. package/dist/types/utils/image-limits.d.ts +7 -0
  92. package/dist/types/utils/image-loading.d.ts +0 -1
  93. package/dist/types/utils/open.d.ts +0 -1
  94. package/dist/types/utils/pasted-image-loading.d.ts +1 -5
  95. package/dist/types/utils/prompt-suggestion.d.ts +2 -2
  96. package/dist/types/utils/shell-snapshot.d.ts +2 -0
  97. package/dist/types/utils/title-generator.d.ts +13 -3
  98. package/dist/types/web/search/providers/codex.d.ts +6 -7
  99. package/package.json +9 -8
  100. package/scripts/acp-conformance-agent.ts +12 -2
  101. package/scripts/generate-sdk-operation-inventory.ts +16 -0
  102. package/src/capability/fs.ts +31 -3
  103. package/src/capability/rule.ts +11 -2
  104. package/src/cli/append-system-prompt.ts +12 -0
  105. package/src/cli/args.ts +11 -7
  106. package/src/cli/customize-doctor-precedence.ts +31 -0
  107. package/src/cli/customize-doctor.ts +49 -39
  108. package/src/cli/fast-help.ts +0 -2
  109. package/src/cli/migrate-cli.ts +14 -3
  110. package/src/cli/public-command-errors.ts +2 -0
  111. package/src/cli/root-flags.ts +0 -2
  112. package/src/cli/update-cli.ts +247 -6
  113. package/src/commands/harness.ts +25 -15
  114. package/src/commands/migrate.ts +3 -3
  115. package/src/commands/sdk.ts +81 -11
  116. package/src/commit/agentic/agent.ts +6 -6
  117. package/src/commit/analysis/conventional.ts +14 -5
  118. package/src/commit/map-reduce/index.ts +7 -7
  119. package/src/commit/pipeline.ts +12 -12
  120. package/src/config/autorouting-tier-map.ts +20 -1
  121. package/src/config/config-file.ts +106 -3
  122. package/src/config/config-hot-reload.ts +8 -0
  123. package/src/config/file-lock.ts +1431 -304
  124. package/src/config/keybindings.ts +154 -7
  125. package/src/config/model-profile-activation.ts +177 -39
  126. package/src/config/model-registry.ts +380 -55
  127. package/src/config/model-resolver.ts +49 -21
  128. package/src/config/settings-schema.ts +13 -1
  129. package/src/config/settings.ts +2 -0
  130. package/src/coordinator-mcp/server.ts +37 -2
  131. package/src/crash/sanitize.ts +3 -1
  132. package/src/customization/import.ts +276 -7
  133. package/src/customization/inventory.ts +24 -8
  134. package/src/customization/types.ts +1 -0
  135. package/src/dap/client.ts +3 -2
  136. package/src/dap/session.ts +161 -36
  137. package/src/debug/crash-diagnostics.ts +87 -5
  138. package/src/debug/report-bundle.ts +71 -2
  139. package/src/discovery/builtin.ts +4 -3
  140. package/src/discovery/helpers.ts +24 -14
  141. package/src/edit/index.ts +191 -5
  142. package/src/edit/modes/patch.ts +27 -0
  143. package/src/eval/py/runtime.ts +44 -4
  144. package/src/exec/non-interactive-env.ts +0 -1
  145. package/src/export/html/index.ts +60 -20
  146. package/src/export/ttsr.ts +176 -1
  147. package/src/extensibility/extensions/loader.ts +2 -0
  148. package/src/extensibility/extensions/ouroboros-ooo-bridge.ts +63 -1
  149. package/src/extensibility/extensions/types.ts +5 -1
  150. package/src/extensibility/hooks/loader.ts +10 -2
  151. package/src/extensibility/plugins/marketplace/manager.ts +36 -10
  152. package/src/extensibility/slash-commands.ts +5 -0
  153. package/src/gjc-runtime/gc-runtime.ts +4 -1
  154. package/src/gjc-runtime/launch-tmux.ts +23 -13
  155. package/src/gjc-runtime/ralplan-current-final.ts +294 -0
  156. package/src/gjc-runtime/ralplan-runtime.ts +95 -1
  157. package/src/gjc-runtime/state-writer.ts +109 -5
  158. package/src/gjc-runtime/tmux-sessions.ts +93 -13
  159. package/src/gjc-runtime/ultragoal-change-set.ts +90 -11
  160. package/src/gjc-runtime/ultragoal-guard.ts +9 -1
  161. package/src/gjc-runtime/ultragoal-runtime.ts +15 -5
  162. package/src/harness-control-plane/finalize.ts +11 -0
  163. package/src/harness-control-plane/receipt-spool.ts +105 -28
  164. package/src/harness-control-plane/storage.ts +124 -6
  165. package/src/hindsight/content.ts +116 -16
  166. package/src/hindsight/mental-models.ts +22 -10
  167. package/src/hindsight/state.ts +7 -4
  168. package/src/hooks/native-skill-hook.ts +3 -1
  169. package/src/internal-urls/artifact-protocol.ts +3 -1
  170. package/src/internal-urls/docs-index.generated.ts +14 -14
  171. package/src/internal-urls/local-protocol.ts +28 -3
  172. package/src/internal-urls/types.ts +2 -0
  173. package/src/lsp/client.ts +2 -1
  174. package/src/lsp/clients/biome-client.ts +2 -0
  175. package/src/lsp/clients/swiftlint-client.ts +2 -0
  176. package/src/main.ts +330 -92
  177. package/src/memories/index.ts +25 -2
  178. package/src/migrate/action-planner.ts +517 -2
  179. package/src/migrate/adapters/claude-code.ts +141 -3
  180. package/src/migrate/adapters/codex.ts +57 -5
  181. package/src/migrate/adapters/index.ts +240 -5
  182. package/src/migrate/adapters/opencode.ts +4 -0
  183. package/src/migrate/executor.ts +141 -3
  184. package/src/migrate/hook-module.ts +193 -0
  185. package/src/migrate/report.ts +45 -1
  186. package/src/migrate/types.ts +73 -3
  187. package/src/modes/acp/acp-agent.ts +10 -1
  188. package/src/modes/components/agent-dashboard.ts +20 -4
  189. package/src/modes/components/customization/customization-dashboard.ts +7 -0
  190. package/src/modes/components/customization/import-wizard.ts +29 -3
  191. package/src/modes/components/model-selector.ts +157 -103
  192. package/src/modes/components/welcome.ts +3 -1
  193. package/src/modes/controllers/command-controller.ts +271 -16
  194. package/src/modes/controllers/event-controller.ts +1 -1
  195. package/src/modes/controllers/extension-ui-controller.ts +31 -1
  196. package/src/modes/controllers/goal-mode-controller.ts +79 -10
  197. package/src/modes/controllers/input-controller.ts +2 -0
  198. package/src/modes/controllers/plan-mode-controller.ts +49 -4
  199. package/src/modes/controllers/runtime-mcp-command-controller.ts +7 -6
  200. package/src/modes/controllers/selector-controller.ts +14 -1
  201. package/src/modes/interactive-mode.ts +55 -4
  202. package/src/modes/prompt-suggestion-controller.ts +1 -1
  203. package/src/modes/runtime-init.ts +5 -1
  204. package/src/modes/utils/host-status.ts +21 -10
  205. package/src/prompts/agent-fragments/browser-aside.md +2 -2
  206. package/src/prompts/system/irc-incoming.md +3 -1
  207. package/src/prompts/tools/irc.md +1 -1
  208. package/src/runtime-mcp/manager.ts +8 -3
  209. package/src/runtime-mcp/project-host-values.ts +12 -8
  210. package/src/runtime-mcp/tool-bridge.ts +68 -4
  211. package/src/runtime-mcp/transports/stdio.ts +2 -1
  212. package/src/sdk/broker/broker-exit.ts +2 -0
  213. package/src/sdk/broker/broker.ts +143 -4
  214. package/src/sdk/broker/ensure.ts +74 -6
  215. package/src/sdk/broker/hop.ts +13 -1
  216. package/src/sdk/broker/lifecycle-ledger.ts +3 -0
  217. package/src/sdk/broker/lifecycle.ts +102 -6
  218. package/src/sdk/broker/session-index.ts +29 -4
  219. package/src/sdk/broker/transport.ts +17 -1
  220. package/src/sdk/bus/chat-daemon-control.ts +2 -2
  221. package/src/sdk/bus/index.ts +408 -14
  222. package/src/sdk/bus/session-control.ts +2 -0
  223. package/src/sdk/bus/slack-daemon.ts +105 -9
  224. package/src/sdk/bus/telegram-daemon-contract.ts +7 -1
  225. package/src/sdk/bus/telegram-daemon.ts +10 -2
  226. package/src/sdk/bus/threaded-render.ts +20 -1
  227. package/src/sdk/cli/session-cli.ts +2 -0
  228. package/src/sdk/host/control/dispatch.ts +13 -1
  229. package/src/sdk/host/control/operations.ts +10 -1
  230. package/src/sdk/host/events.ts +67 -4
  231. package/src/sdk/host/host.ts +8 -2
  232. package/src/sdk/host/prompt-image-upload.ts +438 -0
  233. package/src/sdk/host/sdk-surface-parity.test.ts +15 -0
  234. package/src/sdk/host/session-runtime.test.ts +1537 -24
  235. package/src/sdk/host/session-runtime.ts +332 -36
  236. package/src/sdk/host/surface-policy.ts +4 -0
  237. package/src/sdk/host/websocket-transport.lifecycle.test.ts +90 -2
  238. package/src/sdk/host/websocket-transport.ts +19 -7
  239. package/src/sdk/lifecycle/service.ts +14 -1
  240. package/src/sdk/prompt-status.ts +6 -4
  241. package/src/sdk/protocol/adapter-validation.ts +28 -1
  242. package/src/sdk/protocol/operation-inventory.generated.json +160 -0
  243. package/src/sdk/protocol/operation-registry.ts +33 -3
  244. package/src/sdk/session.ts +123 -36
  245. package/src/session/agent-session.ts +1614 -329
  246. package/src/session/history-storage.ts +182 -12
  247. package/src/session/internal/managed-session-scope.ts +47 -18
  248. package/src/session/internal/managed-session-storage.ts +71 -1
  249. package/src/session/session-manager.ts +90 -5
  250. package/src/session-import/redact.ts +53 -2
  251. package/src/skill-state/workflow-mutation-guard.ts +1498 -18
  252. package/src/slash-commands/builtin-registry.ts +6 -3
  253. package/src/slash-commands/helpers/mcp.ts +11 -3
  254. package/src/ssh/ssh-executor.ts +9 -2
  255. package/src/stt/recorder.ts +26 -9
  256. package/src/system-prompt.ts +61 -16
  257. package/src/task/executor.ts +12 -8
  258. package/src/task/role-body.ts +84 -0
  259. package/src/task/token-log-mode.test.ts +162 -0
  260. package/src/task/token-log.ts +91 -2
  261. package/src/tools/archive-reader.ts +650 -37
  262. package/src/tools/ask.ts +1 -0
  263. package/src/tools/ast-grep.ts +7 -2
  264. package/src/tools/auto-generated-guard.ts +12 -3
  265. package/src/tools/awaiting-input.ts +114 -0
  266. package/src/tools/bash-allowed-prefixes.ts +61 -1
  267. package/src/tools/bash-skill-urls.ts +58 -5
  268. package/src/tools/bash.ts +99 -26
  269. package/src/tools/browser/tab-worker.ts +39 -13
  270. package/src/tools/browser.ts +17 -7
  271. package/src/tools/cron.ts +10 -1
  272. package/src/tools/debug.ts +9 -2
  273. package/src/tools/descriptors.test.ts +4 -4
  274. package/src/tools/descriptors.ts +16 -4
  275. package/src/tools/eval.ts +15 -0
  276. package/src/tools/fetch.ts +90 -2
  277. package/src/tools/gh.ts +27 -12
  278. package/src/tools/image-gen.ts +20 -6
  279. package/src/tools/irc.ts +5 -3
  280. package/src/tools/monitor.ts +9 -1
  281. package/src/tools/output-meta.ts +51 -3
  282. package/src/tools/read.ts +9 -2
  283. package/src/tools/recipe/runner.ts +23 -12
  284. package/src/tools/render-utils.ts +2 -2
  285. package/src/tools/search.ts +3 -2
  286. package/src/tools/ssh.ts +274 -8
  287. package/src/tools/subagent.ts +10 -4
  288. package/src/tools/tmux-self-injection-guard.ts +3301 -122
  289. package/src/tools/tool-catalog.generated.ts +1 -1
  290. package/src/tools/ultragoal-ask-guard.ts +13 -1
  291. package/src/tools/write.ts +7 -0
  292. package/src/tui/tree-list.ts +15 -1
  293. package/src/utils/commit-message-generator.ts +3 -2
  294. package/src/utils/external-editor.ts +21 -7
  295. package/src/utils/file-mentions.ts +46 -6
  296. package/src/utils/git.ts +38 -7
  297. package/src/utils/image-limits.ts +8 -0
  298. package/src/utils/image-loading.ts +1 -1
  299. package/src/utils/open.ts +73 -4
  300. package/src/utils/pasted-image-loading.ts +9 -8
  301. package/src/utils/prompt-suggestion.ts +5 -4
  302. package/src/utils/shell-snapshot.ts +9 -1
  303. package/src/utils/title-generator.ts +65 -20
  304. package/src/web/search/index.ts +2 -1
  305. package/src/web/search/providers/codex.ts +29 -32
@@ -76,7 +76,11 @@ async function writeSkillFileNoFollow(destination: string, content: string): Pro
76
76
  }
77
77
  }
78
78
 
79
- async function ensureInstructionDirectory(directory: string, project: boolean): Promise<void> {
79
+ async function ensureInstructionDirectory(
80
+ directory: string,
81
+ project: boolean,
82
+ label = "instruction destination",
83
+ ): Promise<void> {
80
84
  let trustedBase = path.dirname(directory);
81
85
  if (!project) {
82
86
  const home = path.resolve(getTrustedHomeDir());
@@ -92,7 +96,7 @@ async function ensureInstructionDirectory(directory: string, project: boolean):
92
96
  try {
93
97
  const stat = await fs.lstat(current);
94
98
  if (!stat.isDirectory() || stat.isSymbolicLink()) {
95
- throw new Error(`user instruction destination ancestor is not a real directory: ${current}`);
99
+ throw new Error(`user ${label} ancestor is not a real directory: ${current}`);
96
100
  }
97
101
  trustedBase = current;
98
102
  break;
@@ -105,7 +109,7 @@ async function ensureInstructionDirectory(directory: string, project: boolean):
105
109
  }
106
110
  }
107
111
  }
108
- await ensureRealDirectoryPathNoFollow(directory, trustedBase, "instruction destination", true, 0o700);
112
+ await ensureRealDirectoryPathNoFollow(directory, trustedBase, label, true, 0o700);
109
113
  }
110
114
 
111
115
  async function writeInstructionFileNoFollow(destination: string, content: string, project: boolean): Promise<void> {
@@ -122,6 +126,107 @@ async function writeInstructionFileNoFollow(destination: string, content: string
122
126
  }
123
127
  }
124
128
 
129
+ async function writeAgentFileNoFollow(
130
+ destination: string,
131
+ content: string,
132
+ project: boolean,
133
+ createOnly: boolean,
134
+ ): Promise<void> {
135
+ const destinationDirectory = path.dirname(destination);
136
+ if (project) {
137
+ const agentsRoot = path.dirname(destinationDirectory);
138
+ const agentRoot = path.dirname(agentsRoot);
139
+ await ensureRealDirectoryPathNoFollow(agentRoot, path.dirname(agentRoot), "agent destination", true, 0o700);
140
+ await ensureRealDirectoryPathNoFollow(agentsRoot, agentRoot, "agent destination", true, 0o700);
141
+ await ensureRealDirectoryPathNoFollow(destinationDirectory, agentsRoot, "agent destination", true, 0o700);
142
+ } else {
143
+ await ensureInstructionDirectory(destinationDirectory, false, "agent destination");
144
+ }
145
+ const handle = await fs.open(
146
+ destination,
147
+ createOnly
148
+ ? fsSync.constants.O_WRONLY | fsSync.constants.O_CREAT | fsSync.constants.O_EXCL | fsSync.constants.O_NOFOLLOW
149
+ : fsSync.constants.O_WRONLY |
150
+ fsSync.constants.O_CREAT |
151
+ fsSync.constants.O_TRUNC |
152
+ fsSync.constants.O_NOFOLLOW,
153
+ 0o666,
154
+ );
155
+ try {
156
+ await handle.writeFile(content, "utf-8");
157
+ } finally {
158
+ await handle.close();
159
+ }
160
+ }
161
+
162
+ /** Generated hook modules live beside the agent's own hooks, so they use the same no-follow rules. */
163
+ async function writeHookModuleNoFollow(destination: string, content: string, createOnly: boolean): Promise<void> {
164
+ await ensureInstructionDirectory(path.dirname(destination), false, "hook destination");
165
+ const handle = await fs.open(
166
+ destination,
167
+ createOnly
168
+ ? fsSync.constants.O_WRONLY | fsSync.constants.O_CREAT | fsSync.constants.O_EXCL | fsSync.constants.O_NOFOLLOW
169
+ : fsSync.constants.O_WRONLY |
170
+ fsSync.constants.O_CREAT |
171
+ fsSync.constants.O_TRUNC |
172
+ fsSync.constants.O_NOFOLLOW,
173
+ 0o666,
174
+ );
175
+ try {
176
+ await handle.writeFile(content, "utf-8");
177
+ } finally {
178
+ await handle.close();
179
+ }
180
+ }
181
+
182
+ async function writeCommandFileNoFollow(
183
+ destination: string,
184
+ content: string,
185
+ name: string,
186
+ project: boolean,
187
+ createOnly: boolean,
188
+ ): Promise<void> {
189
+ const destinationDirectory = path.dirname(destination);
190
+ if (project) {
191
+ const nameParts = name.split(":");
192
+ let commandsRoot = destinationDirectory;
193
+ for (let index = 1; index < nameParts.length; index++) commandsRoot = path.dirname(commandsRoot);
194
+ const agentRoot = path.dirname(commandsRoot);
195
+ await ensureRealDirectoryPathNoFollow(
196
+ agentRoot,
197
+ path.dirname(agentRoot),
198
+ "slash command destination",
199
+ true,
200
+ 0o700,
201
+ );
202
+ await ensureRealDirectoryPathNoFollow(commandsRoot, agentRoot, "slash command destination", true, 0o700);
203
+ await ensureRealDirectoryPathNoFollow(
204
+ destinationDirectory,
205
+ commandsRoot,
206
+ "slash command destination",
207
+ true,
208
+ 0o700,
209
+ );
210
+ } else {
211
+ await ensureInstructionDirectory(destinationDirectory, false, "slash command destination");
212
+ }
213
+
214
+ const handle = await fs.open(
215
+ destination,
216
+ fsSync.constants.O_WRONLY |
217
+ fsSync.constants.O_CREAT |
218
+ fsSync.constants.O_TRUNC |
219
+ fsSync.constants.O_NOFOLLOW |
220
+ (createOnly ? fsSync.constants.O_EXCL : 0),
221
+ 0o666,
222
+ );
223
+ try {
224
+ await handle.writeFile(content, "utf-8");
225
+ } finally {
226
+ await handle.close();
227
+ }
228
+ }
229
+
125
230
  export async function executeActions(
126
231
  actions: MigrateAction[],
127
232
  options?: { project?: boolean },
@@ -159,10 +264,43 @@ export async function executeActions(
159
264
  options?.project ?? false,
160
265
  );
161
266
  out.push(action);
267
+ } else if (action.type === "hook" && action.hook && action.destination) {
268
+ await writeHookModuleNoFollow(action.destination, action.hook.content, action.operation === "create");
269
+ out.push(action);
270
+ } else if (action.type === "agent" && action.agent && action.destination) {
271
+ await writeAgentFileNoFollow(
272
+ action.destination,
273
+ action.agent.content,
274
+ options?.project ?? false,
275
+ action.operation === "create",
276
+ );
277
+ out.push(action);
278
+ } else if (action.type === "command" && action.command && action.destination && action.name) {
279
+ await writeCommandFileNoFollow(
280
+ action.destination,
281
+ action.command.content,
282
+ action.name,
283
+ options?.project ?? false,
284
+ action.operation === "create",
285
+ );
286
+ out.push(action);
162
287
  } else {
163
288
  out.push(action);
164
289
  }
165
290
  } catch (error) {
291
+ if (
292
+ (action.type === "command" || action.type === "agent") &&
293
+ action.operation === "create" &&
294
+ (error as NodeJS.ErrnoException).code === "EEXIST"
295
+ ) {
296
+ out.push({
297
+ ...action,
298
+ operation: "skip",
299
+ status: "skipped_exists",
300
+ reason: "destination appeared after planning; refusing to overwrite it",
301
+ });
302
+ continue;
303
+ }
166
304
  out.push({
167
305
  ...action,
168
306
  operation: "fail",
@@ -0,0 +1,193 @@
1
+ /**
2
+ * Render a gjc hook module from imported foreign hook commands.
3
+ *
4
+ * Claude Code hooks are shell commands: the runtime writes a JSON payload to
5
+ * stdin and reads the exit code. `PreToolUse` blocks on exit 2 with stderr as the
6
+ * reason; every other event is observational. gjc hooks are TypeScript modules
7
+ * that subscribe to events in-process, so the importer reproduces the foreign
8
+ * contract rather than rewriting the commands.
9
+ *
10
+ * Only events whose semantics are unambiguous are translated. The payload keeps
11
+ * the foreign field names so an existing script that reads its JSON keeps working;
12
+ * fields this host cannot supply are omitted instead of guessed, which the module
13
+ * header states.
14
+ */
15
+ import type { HookCandidate, MigrateSource } from "./types";
16
+
17
+ /** Foreign event -> gjc hook event. Blocking events are marked separately. */
18
+ const EVENT_MAP: Record<string, { event: string; blocking: boolean }> = {
19
+ PreToolUse: { event: "tool_call", blocking: true },
20
+ PostToolUse: { event: "tool_result", blocking: false },
21
+ SessionStart: { event: "session_start", blocking: false },
22
+ Stop: { event: "turn_end", blocking: false },
23
+ };
24
+
25
+ export function isSupportedHookEvent(event: string): boolean {
26
+ return event in EVENT_MAP;
27
+ }
28
+
29
+ /** Foreign events this importer translates, for user-facing messages. */
30
+ export const SUPPORTED_HOOK_EVENTS: readonly string[] = Object.keys(EVENT_MAP);
31
+
32
+ interface RenderedHook {
33
+ event: string;
34
+ blocking: boolean;
35
+ matcher?: string;
36
+ command: string;
37
+ sourceEvent: string;
38
+ }
39
+
40
+ function constantName(event: string): string {
41
+ return event.replace(/[^a-z_]/g, "_").toUpperCase();
42
+ }
43
+
44
+ function renderHookLiteral(hook: RenderedHook): string {
45
+ const parts = [`event: ${JSON.stringify(hook.sourceEvent)}`, `command: ${JSON.stringify(hook.command)}`];
46
+ if (hook.matcher) parts.push(`matcher: ${JSON.stringify(hook.matcher)}`);
47
+ return `\t{ ${parts.join(", ")} },`;
48
+ }
49
+
50
+ /**
51
+ * Build the module source. The result is deterministic for a given candidate
52
+ * list, so a dry-run report and a live write describe the same file.
53
+ */
54
+ export function renderHookModule(source: MigrateSource, candidates: readonly HookCandidate[]): string {
55
+ const hooks: RenderedHook[] = [];
56
+ for (const candidate of candidates) {
57
+ const mapped = EVENT_MAP[candidate.event];
58
+ if (!mapped) continue;
59
+ hooks.push({
60
+ event: mapped.event,
61
+ blocking: mapped.blocking,
62
+ matcher: candidate.matcher,
63
+ command: candidate.command,
64
+ sourceEvent: candidate.event,
65
+ });
66
+ }
67
+ const byEvent = new Map<string, RenderedHook[]>();
68
+ for (const hook of hooks) {
69
+ const list = byEvent.get(hook.event) ?? [];
70
+ list.push(hook);
71
+ byEvent.set(hook.event, list);
72
+ }
73
+ const eventNames = [...byEvent.keys()].sort();
74
+ const blocks = eventNames
75
+ .map(event => {
76
+ const entries = (byEvent.get(event) ?? []).map(renderHookLiteral).join("\n");
77
+ return `const ${constantName(event)}_HOOKS: readonly ImportedHook[] = [\n${entries}\n];`;
78
+ })
79
+ .join("\n\n");
80
+ const registrations = eventNames
81
+ .map(event => {
82
+ const blocking = byEvent.get(event)?.some(hook => hook.blocking) ?? false;
83
+ const register = blocking ? "registerBlocking" : "registerObservational";
84
+ return `\t${register}(api, ${JSON.stringify(event)}, ${constantName(event)}_HOOKS);`;
85
+ })
86
+ .join("\n");
87
+
88
+ return `/**
89
+ * Generated by \`gjc migrate --from ${source}\`. Re-run with --force to regenerate.
90
+ *
91
+ * These hooks were shell commands in ${source}. Each command receives a JSON
92
+ * payload on stdin under the origin's field names; fields this runtime cannot
93
+ * supply (session id, transcript path) are omitted rather than invented.
94
+ * \`PreToolUse\` blocks the tool when the command exits 2 and uses its stderr as
95
+ * the reason, which is the origin contract; the other events only run the
96
+ * command.
97
+ */
98
+ import { spawn } from "node:child_process";
99
+
100
+ interface ImportedHook {
101
+ event: string;
102
+ command: string;
103
+ matcher?: string;
104
+ }
105
+
106
+ interface HookCommandResult {
107
+ code: number;
108
+ stdout: string;
109
+ stderr: string;
110
+ }
111
+
112
+ interface HookApi {
113
+ on(event: string, handler: (payload: unknown, context: { cwd?: string }) => unknown): void;
114
+ }
115
+
116
+ ${blocks}
117
+
118
+ function matches(matcher: string | undefined, toolName: string | undefined): boolean {
119
+ if (!matcher || !matcher.trim()) return true;
120
+ if (!toolName) return false;
121
+ try {
122
+ return new RegExp(\`^(?:\${matcher})$\`).test(toolName);
123
+ } catch {
124
+ return matcher === toolName;
125
+ }
126
+ }
127
+
128
+ function shellCommand(command: string): string[] {
129
+ return process.platform === "win32"
130
+ ? [process.env.ComSpec ?? "cmd.exe", "/d", "/s", "/c", command]
131
+ : ["/bin/bash", "-lc", command];
132
+ }
133
+
134
+ async function runHook(hook: ImportedHook, payload: unknown): Promise<HookCommandResult> {
135
+ const [file, ...args] = shellCommand(hook.command);
136
+ const child = spawn(file, args, { stdio: ["pipe", "pipe", "pipe"] });
137
+ child.stdin?.end(JSON.stringify(payload));
138
+ let stdout = "";
139
+ let stderr = "";
140
+ child.stdout?.on("data", chunk => {
141
+ stdout += String(chunk);
142
+ });
143
+ child.stderr?.on("data", chunk => {
144
+ stderr += String(chunk);
145
+ });
146
+ const code = await new Promise<number>(resolve => {
147
+ child.on("error", () => resolve(1));
148
+ child.on("close", value => resolve(value ?? 1));
149
+ });
150
+ return { code, stdout, stderr };
151
+ }
152
+
153
+ function registerBlocking(api: HookApi, event: string, hooks: readonly ImportedHook[]): void {
154
+ api.on(event, async (payload, context) => {
155
+ const record = payload as { toolName?: string; input?: unknown };
156
+ for (const hook of hooks) {
157
+ if (!matches(hook.matcher, record?.toolName)) continue;
158
+ const result = await runHook(hook, {
159
+ hook_event_name: hook.event,
160
+ tool_name: record?.toolName,
161
+ tool_input: record?.input,
162
+ cwd: context?.cwd,
163
+ });
164
+ if (result.code === 2) {
165
+ return { block: true, reason: result.stderr.trim() || \`blocked by imported \${hook.event} hook\` };
166
+ }
167
+ }
168
+ return undefined;
169
+ });
170
+ }
171
+
172
+ function registerObservational(api: HookApi, event: string, hooks: readonly ImportedHook[]): void {
173
+ api.on(event, async (payload, context) => {
174
+ const record = payload as { toolName?: string; input?: unknown; turnIndex?: number };
175
+ for (const hook of hooks) {
176
+ if (event === "tool_result" && !matches(hook.matcher, record?.toolName)) continue;
177
+ await runHook(hook, {
178
+ hook_event_name: hook.event,
179
+ tool_name: record?.toolName,
180
+ tool_input: record?.input,
181
+ turn_index: record?.turnIndex,
182
+ cwd: context?.cwd,
183
+ });
184
+ }
185
+ return undefined;
186
+ });
187
+ }
188
+
189
+ export default (api: HookApi): void => {
190
+ ${registrations}
191
+ };
192
+ `;
193
+ }
@@ -7,6 +7,7 @@
7
7
  import {
8
8
  emptyStatusCounts,
9
9
  isFailureStatus,
10
+ type ManualAction,
10
11
  type MigrateAction,
11
12
  type MigrateDestinations,
12
13
  type MigrateReport,
@@ -20,6 +21,7 @@ export interface BuildReportInput {
20
21
  warnings: MigrateWarning[];
21
22
  sources: MigrateSource[];
22
23
  destinations: MigrateDestinations;
24
+ manualActions: ManualAction[];
23
25
  dryRun: boolean;
24
26
  project: boolean;
25
27
  force: boolean;
@@ -30,6 +32,9 @@ export function buildReport(input: BuildReportInput): MigrateReport {
30
32
  const byType = {
31
33
  mcp: emptyStatusCounts(),
32
34
  skill: emptyStatusCounts(),
35
+ command: emptyStatusCounts(),
36
+ agent: emptyStatusCounts(),
37
+ hook: emptyStatusCounts(),
33
38
  instruction: emptyStatusCounts(),
34
39
  source: emptyStatusCounts(),
35
40
  };
@@ -52,6 +57,7 @@ export function buildReport(input: BuildReportInput): MigrateReport {
52
57
  sources: input.sources,
53
58
  destinations: input.destinations,
54
59
  summary: { total, byType, bySource },
60
+ manualActions: input.manualActions,
55
61
  actions: input.actions.map(action => ({
56
62
  source: action.source,
57
63
  type: action.type,
@@ -81,12 +87,42 @@ export function renderHuman(report: MigrateReport): string {
81
87
  lines.push(`gjc migrate${mode}: ${report.ok ? "ok" : "completed with failures"}`);
82
88
  lines.push(`Sources: ${report.sources.join(", ") || "none"}`);
83
89
  lines.push(
84
- `Destination: mcp=${report.destinations.mcpConfigPath} skills=${report.destinations.skillsDir} instructions=${report.destinations.instructionsPath}`,
90
+ `Destination: mcp=${report.destinations.mcpConfigPath} skills=${report.destinations.skillsDir} commands=${report.destinations.commandsDir} agents=${report.destinations.agentsDir} hooks=${report.destinations.hooksDir} instructions=${report.destinations.instructionsPath}`,
85
91
  );
86
92
  lines.push("");
87
93
  lines.push(`MCP: ${summarizeCounts(report.summary.byType.mcp)}`);
88
94
  lines.push(`Skills: ${summarizeCounts(report.summary.byType.skill)}`);
95
+ lines.push(`Commands: ${summarizeCounts(report.summary.byType.command)}`);
96
+ lines.push(`Agents: ${summarizeCounts(report.summary.byType.agent)}`);
97
+ lines.push(`Hooks: ${summarizeCounts(report.summary.byType.hook)}`);
89
98
  lines.push(`Instructions: ${summarizeCounts(report.summary.byType.instruction)}`);
99
+ const commandActions = report.actions.filter(action => action.type === "command");
100
+ if (commandActions.length > 0) {
101
+ lines.push("Slash commands:");
102
+ for (const action of commandActions) {
103
+ lines.push(
104
+ ` - [${action.source}] /${action.name ?? ""}: ${action.status}${action.reason ? ` (${action.reason})` : ""}`,
105
+ );
106
+ }
107
+ }
108
+ const agentActions = report.actions.filter(action => action.type === "agent");
109
+ if (agentActions.length > 0) {
110
+ lines.push("Subagents:");
111
+ for (const action of agentActions) {
112
+ lines.push(
113
+ ` - [${action.source}] ${action.name ?? ""}: ${action.status}${action.reason ? ` (${action.reason})` : ""}`,
114
+ );
115
+ }
116
+ }
117
+ const hookActions = report.actions.filter(action => action.type === "hook");
118
+ if (hookActions.length > 0) {
119
+ lines.push("Hooks:");
120
+ for (const action of hookActions) {
121
+ lines.push(
122
+ ` - [${action.source}] ${action.name ?? ""}: ${action.status}${action.reason ? ` (${action.reason})` : ""}`,
123
+ );
124
+ }
125
+ }
90
126
  const instructionActions = report.actions.filter(action => action.type === "instruction");
91
127
  if (instructionActions.length > 0) {
92
128
  lines.push("Instruction files:");
@@ -109,6 +145,14 @@ export function renderHuman(report: MigrateReport): string {
109
145
  }
110
146
  }
111
147
 
148
+ if (report.manualActions.length > 0) {
149
+ lines.push("");
150
+ lines.push("Manual actions:");
151
+ for (const m of report.manualActions) {
152
+ lines.push(` - [${m.source}] ${m.area}: ${m.detail}`);
153
+ }
154
+ }
155
+
112
156
  if (report.warnings.length > 0) {
113
157
  lines.push("");
114
158
  lines.push("Warnings:");
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Shared types for `gjc migrate`.
3
3
  *
4
- * Imports MCP servers, skills, and instruction files from other coding agents
4
+ * Imports MCP servers, skills, slash commands, and instruction files from other coding agents
5
5
  * (Claude Code, Codex, OpenCode) into native GJC config. See the consensus plan under
6
6
  * `.gjc/plans/ralplan/` for the full taxonomy and force/collision semantics.
7
7
  */
@@ -16,7 +16,7 @@ export const MIGRATE_SOURCES: readonly MigrateSource[] = ["claude-code", "codex"
16
16
  export const CANONICAL_SOURCE_ORDER: readonly MigrateSource[] = MIGRATE_SOURCES;
17
17
 
18
18
  /** What kind of thing an action/coverage row is about. */
19
- export type MigrateItemType = "mcp" | "skill" | "instruction" | "source";
19
+ export type MigrateItemType = "mcp" | "skill" | "command" | "agent" | "hook" | "instruction" | "source";
20
20
 
21
21
  /**
22
22
  * Per-item outcome taxonomy.
@@ -84,6 +84,24 @@ export interface InstructionCandidate {
84
84
  content: string;
85
85
  }
86
86
 
87
+ /** A Markdown subagent collected from a foreign coding-agent setup. */
88
+ export interface AgentCandidate {
89
+ source: MigrateSource;
90
+ /** Agent name exactly as it will be loaded from `<agentsDir>/<name>.md`. */
91
+ name: string;
92
+ /** Full Markdown content with normalized GJC frontmatter. */
93
+ content: string;
94
+ warnings: string[];
95
+ }
96
+
97
+ /** A Markdown slash command collected from a foreign coding-agent setup. */
98
+ export interface SlashCommandCandidate {
99
+ source: MigrateSource;
100
+ /** Name without the leading slash; nested path components use `:`. */
101
+ name: string;
102
+ content: string;
103
+ }
104
+
87
105
  /**
88
106
  * Source-level diagnostic for a single source/type pair (e.g. "codex mcp config
89
107
  * was malformed"). Distinct from per-item actions so absent/unreadable sources
@@ -96,12 +114,48 @@ export interface SourceDiagnostic {
96
114
  message: string;
97
115
  }
98
116
 
117
+ /**
118
+ * A foreign hook command that maps onto a gjc hook event.
119
+ *
120
+ * Claude Code hooks are shell commands that receive a JSON payload on stdin and
121
+ * signal a block with exit code 2; gjc hooks are TypeScript modules. The
122
+ * importer generates a module that reproduces that contract for the events whose
123
+ * semantics are unambiguous.
124
+ */
125
+ export interface HookCandidate {
126
+ source: MigrateSource;
127
+ /** Foreign event name, e.g. `PreToolUse`. */
128
+ event: string;
129
+ /** Tool-name matcher; empty or absent means every tool. */
130
+ matcher?: string;
131
+ /** Shell command exactly as the source declared it. */
132
+ command: string;
133
+ }
134
+
135
+ /**
136
+ * A source setting the migration cannot express in gjc. Reported instead of
137
+ * guessed at: silently translating an approval or hook policy would change what
138
+ * the agent is allowed to do. Secret values are never read, so detail may name
139
+ * keys but never their contents.
140
+ */
141
+ export interface ManualAction {
142
+ source: MigrateSource;
143
+ /** Setting area, e.g. `hooks`, `settings.model`, `env`. */
144
+ area: string;
145
+ /** One-line instruction naming the concrete follow-up. */
146
+ detail: string;
147
+ }
148
+
99
149
  /** Normalized candidates + diagnostics returned by an adapter. */
100
150
  export interface AdapterResult {
101
151
  mcpCandidates: McpCandidate[];
102
152
  skillCandidates: SkillCandidate[];
153
+ slashCommandCandidates: SlashCommandCandidate[];
154
+ agentCandidates: AgentCandidate[];
155
+ hookCandidates: HookCandidate[];
103
156
  instructionCandidates: InstructionCandidate[];
104
157
  diagnostics: SourceDiagnostic[];
158
+ manualActions: ManualAction[];
105
159
  }
106
160
 
107
161
  /** A single planned action consumed identically by dry-run and live execution. */
@@ -120,6 +174,9 @@ export interface MigrateAction {
120
174
  /** Resolved payload the executor needs; never serialized to the report. */
121
175
  mcp?: { config: MCPServerConfig; force: boolean };
122
176
  skill?: { content: string };
177
+ command?: { content: string };
178
+ agent?: { content: string };
179
+ hook?: { content: string };
123
180
  instruction?: { content: string };
124
181
  }
125
182
 
@@ -135,6 +192,10 @@ export type StatusCounts = Record<MigrationStatus, number>;
135
192
  export interface MigrateDestinations {
136
193
  mcpConfigPath: string;
137
194
  skillsDir: string;
195
+ commandsDir: string;
196
+ agentsDir: string;
197
+ /** Directory that receives generated hook modules. */
198
+ hooksDir: string;
138
199
  instructionsPath: string;
139
200
  }
140
201
 
@@ -148,7 +209,15 @@ export interface MigrateReport {
148
209
  destinations: MigrateDestinations;
149
210
  summary: {
150
211
  total: StatusCounts;
151
- byType: { mcp: StatusCounts; skill: StatusCounts; instruction: StatusCounts; source: StatusCounts };
212
+ byType: {
213
+ mcp: StatusCounts;
214
+ skill: StatusCounts;
215
+ command: StatusCounts;
216
+ agent: StatusCounts;
217
+ hook: StatusCounts;
218
+ instruction: StatusCounts;
219
+ source: StatusCounts;
220
+ };
152
221
  bySource: Record<MigrateSource, StatusCounts>;
153
222
  };
154
223
  actions: Array<{
@@ -163,6 +232,7 @@ export interface MigrateReport {
163
232
  warnings?: string[];
164
233
  }>;
165
234
  warnings: MigrateWarning[];
235
+ manualActions: ManualAction[];
166
236
  }
167
237
 
168
238
  /** Create a zeroed status-count record. */
@@ -631,6 +631,11 @@ function isAbortNoEffect(value: unknown): boolean {
631
631
  const result = object(candidate?.result) ?? candidate;
632
632
  return result?.turn === "no_active_turn" || result?.turn === "no_effect" || result?.turn === "no_store";
633
633
  }
634
+ function isAbortUncertain(value: unknown): boolean {
635
+ const candidate = object(value);
636
+ const result = object(candidate?.result) ?? candidate;
637
+ return result?.turn === "uncertain";
638
+ }
634
639
 
635
640
  function strictCorrelationFrom(...values: unknown[]): PromptCorrelation | undefined {
636
641
  const correlation: PromptCorrelation = {};
@@ -3064,12 +3069,16 @@ export class AcpAgent implements Agent {
3064
3069
  let acknowledgementScope = scope;
3065
3070
  if (
3066
3071
  !isAbortAcknowledged(acknowledgement, scope) &&
3067
- isAbortNoEffect(acknowledgement) &&
3072
+ (isAbortNoEffect(acknowledgement) || isAbortUncertain(acknowledgement)) &&
3068
3073
  (waiterWasUnacknowledged || waiterWasBeforeActivity) &&
3069
3074
  waiter &&
3070
3075
  record.activePrompt === waiter &&
3071
3076
  !waiter.settled
3072
3077
  ) {
3078
+ // An uncertain replay result is not proof that the worker stopped, but it
3079
+ // also must not erase a cancellation that arrived before prompt admission.
3080
+ // Retain the intent and retry once the prompt acknowledgement/start gives
3081
+ // the abort a concrete active turn to target.
3073
3082
  waiter.cancelBeforeAdmission = true;
3074
3083
  waiter.cancelBeforeAdmissionScope =
3075
3084
  waiter.cancelBeforeAdmissionScope === "owned" || scope === "owned" ? "owned" : "turn";
@@ -90,14 +90,22 @@ export function resolveAgentCreationModel(
90
90
  modelPatterns: string[],
91
91
  modelRegistry: ModelRegistry,
92
92
  settings: Settings | undefined,
93
+ credentialSessionId?: string,
93
94
  ) {
94
- const { model } = resolveModelOverride(modelPatterns, modelRegistry, settings);
95
+ const { model } = resolveModelOverride(
96
+ modelPatterns,
97
+ modelRegistry,
98
+ settings,
99
+ undefined,
100
+ undefined,
101
+ credentialSessionId,
102
+ );
95
103
  if (model) return model;
96
104
  if (modelPatterns.length > 0) {
97
105
  throw new Error(`Configured model selector(s) did not resolve: ${modelPatterns.join(", ")}.`);
98
106
  }
99
107
 
100
- const fallbackModel = modelRegistry.getAvailable()[0];
108
+ const fallbackModel = modelRegistry.getAvailable(credentialSessionId)[0];
101
109
  if (!fallbackModel) {
102
110
  throw new Error("No available model to generate agent specification.");
103
111
  }
@@ -612,7 +620,12 @@ export class AgentDashboard extends Container {
612
620
  settings?.getModelRole("default"),
613
621
  settings,
614
622
  );
615
- const selectedModel = resolveAgentCreationModel(modelPatterns, modelRegistry, settings);
623
+ const selectedModel = resolveAgentCreationModel(
624
+ modelPatterns,
625
+ modelRegistry,
626
+ settings,
627
+ this.modelContext.credentialSessionId,
628
+ );
616
629
 
617
630
  const systemPrompt = prompt.render(agentCreationArchitectPrompt, { TASK_TOOL_NAME: "task" });
618
631
  const userPrompt = prompt.render(agentCreationUserPrompt, { request: description });
@@ -701,7 +714,7 @@ export class AgentDashboard extends Container {
701
714
  if (!modelRegistry) return [];
702
715
  const query = input.trim().toLowerCase();
703
716
  if (!query) return [];
704
- const available = modelRegistry.getAvailable();
717
+ const available = modelRegistry.getAvailable(this.modelContext.credentialSessionId);
705
718
  const seen = new Set<string>();
706
719
  const matches: string[] = [];
707
720
  for (const model of available) {
@@ -757,6 +770,9 @@ export class AgentDashboard extends Container {
757
770
  patterns,
758
771
  modelRegistry,
759
772
  this.#settingsManager ?? undefined,
773
+ undefined,
774
+ undefined,
775
+ this.modelContext.credentialSessionId,
760
776
  );
761
777
  if (!model) return undefined;
762
778
  return {