@gajae-code/coding-agent 0.16.7 → 0.17.1

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 (321) hide show
  1. package/CHANGELOG.md +180 -1
  2. package/dist/types/capability/fs.d.ts +37 -4
  3. package/dist/types/capability/index.d.ts +19 -0
  4. package/dist/types/capability/types.d.ts +9 -0
  5. package/dist/types/cli/doctor/args.d.ts +36 -0
  6. package/dist/types/cli/doctor/checks.d.ts +18 -0
  7. package/dist/types/cli/doctor/config-repairs.d.ts +38 -0
  8. package/dist/types/cli/doctor/context.d.ts +89 -0
  9. package/dist/types/cli/doctor/files.d.ts +27 -0
  10. package/dist/types/cli/doctor/ids.d.ts +20 -0
  11. package/dist/types/cli/doctor/install-repairs.d.ts +94 -0
  12. package/dist/types/cli/doctor/journal.d.ts +43 -0
  13. package/dist/types/cli/doctor/managed-link.d.ts +39 -0
  14. package/dist/types/cli/doctor/native-probe.d.ts +2 -0
  15. package/dist/types/cli/doctor/permission-repairs.d.ts +25 -0
  16. package/dist/types/cli/doctor/plugin-quarantine.d.ts +77 -0
  17. package/dist/types/cli/doctor/plugin-restore.d.ts +40 -0
  18. package/dist/types/cli/doctor/plugin-targets.d.ts +11 -0
  19. package/dist/types/cli/doctor/probe-client.d.ts +9 -0
  20. package/dist/types/cli/doctor/probe-types.d.ts +18 -0
  21. package/dist/types/cli/doctor/probe.d.ts +3 -0
  22. package/dist/types/cli/doctor/projection-probe.d.ts +2 -0
  23. package/dist/types/cli/doctor/repairs.d.ts +28 -0
  24. package/dist/types/cli/doctor/report.d.ts +27 -0
  25. package/dist/types/cli/doctor/runner.d.ts +4 -0
  26. package/dist/types/cli/doctor/safety.d.ts +10 -0
  27. package/dist/types/cli/doctor/service-repairs.d.ts +8 -0
  28. package/dist/types/cli/doctor/service-targets.d.ts +41 -0
  29. package/dist/types/cli/doctor/types.d.ts +145 -0
  30. package/dist/types/cli/doctor-cli.d.ts +7 -0
  31. package/dist/types/cli/doctor-supervisor.d.ts +121 -0
  32. package/dist/types/cli/doctor-worker.d.ts +29 -0
  33. package/dist/types/cli/install-activation.d.ts +158 -0
  34. package/dist/types/cli/macos-community-app.d.ts +41 -0
  35. package/dist/types/cli/mcp-cli.d.ts +0 -11
  36. package/dist/types/cli/update-cli.d.ts +41 -4
  37. package/dist/types/cli-main.d.ts +174 -0
  38. package/dist/types/cli.d.ts +1 -171
  39. package/dist/types/commands/doctor.d.ts +7 -0
  40. package/dist/types/commands/sdk.d.ts +17 -8
  41. package/dist/types/config/autorouting-tier-map.d.ts +19 -0
  42. package/dist/types/config/file-lock.d.ts +27 -3
  43. package/dist/types/config/model-preset-registry.d.ts +1 -0
  44. package/dist/types/config/model-registry.d.ts +12 -5
  45. package/dist/types/config/model-resolver.d.ts +16 -3
  46. package/dist/types/config/models-config-schema.d.ts +2 -0
  47. package/dist/types/config/settings-schema.d.ts +1 -1
  48. package/dist/types/coordinator-mcp/question-gate-codec.d.ts +1 -1
  49. package/dist/types/coordinator-mcp/session-reaper.d.ts +15 -5
  50. package/dist/types/cursor.d.ts +9 -9
  51. package/dist/types/discovery/agents-md.d.ts +6 -1
  52. package/dist/types/discovery/helpers.d.ts +36 -7
  53. package/dist/types/discovery/index.d.ts +1 -1
  54. package/dist/types/discovery/mcp-json.d.ts +2 -0
  55. package/dist/types/extensibility/extensions/loader.d.ts +22 -1
  56. package/dist/types/extensibility/gjc-plugins/lifecycle.d.ts +14 -1
  57. package/dist/types/extensibility/gjc-plugins/paths.d.ts +2 -1
  58. package/dist/types/extensibility/gjc-plugins/types.d.ts +25 -0
  59. package/dist/types/extensibility/plugins/manager.d.ts +33 -4
  60. package/dist/types/extensibility/plugins/marketplace/cache.d.ts +6 -0
  61. package/dist/types/extensibility/plugins/marketplace/manager.d.ts +186 -0
  62. package/dist/types/extensibility/plugins/marketplace/registry.d.ts +27 -0
  63. package/dist/types/extensibility/plugins/marketplace/source-resolver.d.ts +16 -1
  64. package/dist/types/extensibility/runtime-skill-discovery.d.ts +16 -3
  65. package/dist/types/gjc-runtime/autoresearch-runtime.d.ts +6 -0
  66. package/dist/types/gjc-runtime/launch-worktree.d.ts +53 -0
  67. package/dist/types/gjc-runtime/session-layout.d.ts +8 -0
  68. package/dist/types/gjc-runtime/session-state-lock.d.ts +15 -0
  69. package/dist/types/gjc-runtime/session-state-sidecar.d.ts +13 -0
  70. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +6 -0
  71. package/dist/types/main.d.ts +19 -1
  72. package/dist/types/modes/acp/acp-agent.d.ts +40 -0
  73. package/dist/types/modes/components/agent-dashboard.d.ts +1 -0
  74. package/dist/types/modes/components/model-selector.d.ts +2 -0
  75. package/dist/types/modes/interactive-mode.d.ts +1 -1
  76. package/dist/types/runtime-mcp/config-writer.d.ts +47 -0
  77. package/dist/types/runtime-mcp/policy-json-edit.d.ts +60 -0
  78. package/dist/types/runtime-mcp/startup-policy.d.ts +4 -0
  79. package/dist/types/runtime-mcp/types.d.ts +2 -2
  80. package/dist/types/sdk/acp/adapter.d.ts +5 -1
  81. package/dist/types/sdk/broker/broker.d.ts +51 -0
  82. package/dist/types/sdk/broker/daemon-entry.d.ts +39 -0
  83. package/dist/types/sdk/broker/discovery.d.ts +38 -0
  84. package/dist/types/sdk/broker/doctor-restart.d.ts +79 -0
  85. package/dist/types/sdk/broker/endpoint-authority.d.ts +7 -0
  86. package/dist/types/sdk/broker/ensure.d.ts +14 -0
  87. package/dist/types/sdk/broker/lifecycle.d.ts +2 -0
  88. package/dist/types/sdk/broker/process-incarnation.d.ts +50 -0
  89. package/dist/types/sdk/broker/runtime.d.ts +26 -0
  90. package/dist/types/sdk/broker/session-index.d.ts +13 -4
  91. package/dist/types/sdk/broker/worktree-occupancy.d.ts +14 -0
  92. package/dist/types/sdk/bus/chat-daemon-cli.d.ts +16 -0
  93. package/dist/types/sdk/bus/chat-daemon-control.d.ts +101 -6
  94. package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +16 -0
  95. package/dist/types/sdk/bus/daemon-startup-exclusion.d.ts +43 -0
  96. package/dist/types/sdk/bus/doctor-daemon-restart-client.d.ts +51 -0
  97. package/dist/types/sdk/bus/doctor-daemon-restart.d.ts +39 -0
  98. package/dist/types/sdk/bus/index.d.ts +2 -0
  99. package/dist/types/sdk/bus/notification-service.d.ts +3 -0
  100. package/dist/types/sdk/bus/telegram-daemon-cli.d.ts +11 -0
  101. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +1 -1
  102. package/dist/types/sdk/bus/telegram-daemon-control.d.ts +5 -0
  103. package/dist/types/sdk/bus/telegram-daemon-owner-registry.d.ts +1 -0
  104. package/dist/types/sdk/bus/telegram-daemon.d.ts +36 -5
  105. package/dist/types/sdk/cli/session-cli.d.ts +1 -0
  106. package/dist/types/sdk/host/session-runtime.d.ts +4 -0
  107. package/dist/types/sdk/host/surface-policy.d.ts +3 -1
  108. package/dist/types/sdk/lifecycle/service.d.ts +44 -10
  109. package/dist/types/sdk/prompt-deadline-lease.d.ts +6 -3
  110. package/dist/types/sdk/prompt-deadline-manager.d.ts +2 -2
  111. package/dist/types/sdk/prompt-failure.d.ts +47 -0
  112. package/dist/types/sdk/prompt-status.d.ts +19 -0
  113. package/dist/types/sdk/router/session-router.d.ts +3 -4
  114. package/dist/types/sdk/service-artifact-paths.d.ts +16 -0
  115. package/dist/types/sdk/session-authority.d.ts +9 -0
  116. package/dist/types/sdk/session.d.ts +3 -1
  117. package/dist/types/session/agent-session.d.ts +1 -1
  118. package/dist/types/session/blob-store.d.ts +1 -1
  119. package/dist/types/session/fallback-chain-controller.d.ts +3 -6
  120. package/dist/types/session/internal/managed-session-scope.d.ts +44 -0
  121. package/dist/types/session/primary-control-surface.d.ts +4 -0
  122. package/dist/types/session/session-manager.d.ts +6 -0
  123. package/dist/types/system-prompt.d.ts +6 -0
  124. package/dist/types/tools/ask.d.ts +25 -0
  125. package/dist/types/tools/image-gen.d.ts +0 -4
  126. package/dist/types/tools/skill-discovery.d.ts +7 -5
  127. package/dist/types/tools/ultragoal-ask-guard.d.ts +7 -4
  128. package/dist/types/utils/changelog.d.ts +0 -9
  129. package/dist/types/utils/mupdf-wasm.d.ts +1 -0
  130. package/package.json +9 -8
  131. package/scripts/compile-args.ts +8 -4
  132. package/src/capability/fs.ts +395 -17
  133. package/src/capability/index.ts +273 -10
  134. package/src/capability/types.ts +9 -0
  135. package/src/cli/customize-doctor.ts +18 -12
  136. package/src/cli/doctor/args.ts +236 -0
  137. package/src/cli/doctor/checks.ts +431 -0
  138. package/src/cli/doctor/config-repairs.ts +517 -0
  139. package/src/cli/doctor/context.ts +149 -0
  140. package/src/cli/doctor/files.ts +149 -0
  141. package/src/cli/doctor/ids.ts +115 -0
  142. package/src/cli/doctor/install-repairs.ts +335 -0
  143. package/src/cli/doctor/journal.ts +423 -0
  144. package/src/cli/doctor/managed-link.ts +514 -0
  145. package/src/cli/doctor/native-probe.ts +13 -0
  146. package/src/cli/doctor/permission-repairs.ts +242 -0
  147. package/src/cli/doctor/plugin-quarantine.ts +377 -0
  148. package/src/cli/doctor/plugin-restore.ts +59 -0
  149. package/src/cli/doctor/plugin-targets.ts +373 -0
  150. package/src/cli/doctor/probe-client.ts +195 -0
  151. package/src/cli/doctor/probe-types.ts +21 -0
  152. package/src/cli/doctor/probe.ts +42 -0
  153. package/src/cli/doctor/projection-probe.ts +249 -0
  154. package/src/cli/doctor/repairs.ts +1157 -0
  155. package/src/cli/doctor/report.ts +176 -0
  156. package/src/cli/doctor/runner.ts +342 -0
  157. package/src/cli/doctor/safety.ts +40 -0
  158. package/src/cli/doctor/service-repairs.ts +452 -0
  159. package/src/cli/doctor/service-targets.ts +274 -0
  160. package/src/cli/doctor/types.ts +164 -0
  161. package/src/cli/doctor-cli.ts +62 -0
  162. package/src/cli/doctor-supervisor.ts +571 -0
  163. package/src/cli/doctor-worker.ts +181 -0
  164. package/src/cli/install-activation.ts +666 -0
  165. package/src/cli/macos-community-app.ts +1449 -0
  166. package/src/cli/mcp-cli.ts +11 -21
  167. package/src/cli/nofile-limit.ts +5 -1
  168. package/src/cli/plugin-cli.ts +6 -1
  169. package/src/cli/update-cli.ts +362 -264
  170. package/src/cli-main.ts +517 -0
  171. package/src/cli.ts +64 -433
  172. package/src/commands/autoresearch.ts +11 -5
  173. package/src/commands/completion.ts +1 -1
  174. package/src/commands/doctor.ts +13 -0
  175. package/src/commands/sdk.ts +58 -10
  176. package/src/commands/ultragoal.ts +11 -5
  177. package/src/config/autorouting-tier-map.ts +7 -0
  178. package/src/config/file-lock.ts +736 -71
  179. package/src/config/mcp-schema.json +3 -3
  180. package/src/config/model-preset-registry.ts +1 -0
  181. package/src/config/model-registry.ts +80 -27
  182. package/src/config/model-resolver.ts +33 -4
  183. package/src/config/models-config-schema.ts +2 -0
  184. package/src/config/settings-schema.ts +6 -2
  185. package/src/coordinator-mcp/question-gate-codec.ts +1 -0
  186. package/src/coordinator-mcp/server.ts +534 -51
  187. package/src/coordinator-mcp/session-reaper.ts +64 -8
  188. package/src/cursor.ts +223 -53
  189. package/src/discovery/agents-md.ts +74 -8
  190. package/src/discovery/agents.ts +32 -7
  191. package/src/discovery/builtin.ts +184 -75
  192. package/src/discovery/claude-plugins.ts +85 -17
  193. package/src/discovery/cline.ts +38 -10
  194. package/src/discovery/cursor.ts +19 -6
  195. package/src/discovery/gemini.ts +62 -22
  196. package/src/discovery/github.ts +13 -3
  197. package/src/discovery/helpers.ts +483 -89
  198. package/src/discovery/index.ts +1 -0
  199. package/src/discovery/mcp-json.ts +36 -10
  200. package/src/discovery/opencode.ts +36 -19
  201. package/src/discovery/ssh.ts +11 -8
  202. package/src/discovery/windsurf.ts +12 -3
  203. package/src/exec/bash-executor.ts +10 -3
  204. package/src/exec/isolated-shell.ts +15 -2
  205. package/src/extensibility/extensions/loader.ts +88 -26
  206. package/src/extensibility/gjc-plugins/lifecycle.ts +189 -0
  207. package/src/extensibility/gjc-plugins/paths.ts +4 -1
  208. package/src/extensibility/gjc-plugins/types.ts +27 -0
  209. package/src/extensibility/plugins/manager.ts +200 -22
  210. package/src/extensibility/plugins/marketplace/cache.ts +55 -2
  211. package/src/extensibility/plugins/marketplace/manager.ts +1262 -162
  212. package/src/extensibility/plugins/marketplace/registry.ts +153 -0
  213. package/src/extensibility/plugins/marketplace/source-resolver.ts +116 -10
  214. package/src/extensibility/runtime-skill-discovery.ts +61 -9
  215. package/src/extensibility/skill-management.ts +7 -1
  216. package/src/gjc-runtime/autoresearch-runtime.ts +10 -1
  217. package/src/gjc-runtime/launch-worktree.test.ts +248 -0
  218. package/src/gjc-runtime/launch-worktree.ts +275 -38
  219. package/src/gjc-runtime/repository-binding.ts +26 -1
  220. package/src/gjc-runtime/session-layout.ts +10 -0
  221. package/src/gjc-runtime/session-state-lock.ts +330 -23
  222. package/src/gjc-runtime/session-state-sidecar.ts +328 -80
  223. package/src/gjc-runtime/ultragoal-runtime.ts +10 -1
  224. package/src/harness-control-plane/session-lease.ts +2 -2
  225. package/src/internal-urls/docs-index.generated.ts +28 -26
  226. package/src/main.ts +150 -29
  227. package/src/memories/index.ts +24 -2
  228. package/src/modes/acp/acp-agent.ts +522 -68
  229. package/src/modes/components/agent-dashboard.ts +3 -1
  230. package/src/modes/components/model-selector.ts +28 -19
  231. package/src/modes/components/plugin-settings.ts +2 -1
  232. package/src/modes/controllers/selector-controller.ts +15 -9
  233. package/src/modes/interactive-mode.ts +21 -3
  234. package/src/prompts/system/system-prompt.md +5 -1
  235. package/src/prompts/tools/browser.md +1 -1
  236. package/src/prompts/tools/move-session.md +4 -0
  237. package/src/prompts/tools/read.md +2 -1
  238. package/src/prompts/tools/skill-discovery.md +6 -5
  239. package/src/prompts/tools/task.md +1 -0
  240. package/src/runtime-mcp/config-writer.ts +228 -0
  241. package/src/runtime-mcp/oauth-discovery.ts +114 -14
  242. package/src/runtime-mcp/policy-json-edit.ts +129 -0
  243. package/src/runtime-mcp/startup-policy.ts +14 -0
  244. package/src/runtime-mcp/types.ts +2 -2
  245. package/src/sdk/acp/adapter.ts +27 -12
  246. package/src/sdk/broker/broker.ts +273 -44
  247. package/src/sdk/broker/daemon-entry.ts +119 -0
  248. package/src/sdk/broker/discovery.ts +173 -20
  249. package/src/sdk/broker/doctor-restart.ts +206 -0
  250. package/src/sdk/broker/endpoint-authority.ts +36 -0
  251. package/src/sdk/broker/ensure.ts +49 -14
  252. package/src/sdk/broker/lifecycle.ts +174 -42
  253. package/src/sdk/broker/process-incarnation.ts +86 -2
  254. package/src/sdk/broker/runtime.ts +145 -21
  255. package/src/sdk/broker/session-index.ts +136 -22
  256. package/src/sdk/broker/spawn-substrate.ts +4 -1
  257. package/src/sdk/broker/transport.ts +5 -0
  258. package/src/sdk/broker/worktree-occupancy.ts +21 -1
  259. package/src/sdk/bus/chat-daemon-cli.ts +63 -0
  260. package/src/sdk/bus/chat-daemon-control.ts +260 -64
  261. package/src/sdk/bus/chat-daemon-runtime.ts +141 -25
  262. package/src/sdk/bus/daemon-startup-exclusion.ts +119 -0
  263. package/src/sdk/bus/doctor-daemon-restart-client.ts +291 -0
  264. package/src/sdk/bus/doctor-daemon-restart.ts +92 -0
  265. package/src/sdk/bus/index.ts +252 -51
  266. package/src/sdk/bus/kind-aware-reconciliation.ts +76 -41
  267. package/src/sdk/bus/notification-service.ts +21 -3
  268. package/src/sdk/bus/reconciliation-store.ts +17 -11
  269. package/src/sdk/bus/telegram-daemon-cli.ts +91 -5
  270. package/src/sdk/bus/telegram-daemon-contract.ts +1 -1
  271. package/src/sdk/bus/telegram-daemon-control.ts +47 -0
  272. package/src/sdk/bus/telegram-daemon-owner-registry.ts +1 -1
  273. package/src/sdk/bus/telegram-daemon.ts +178 -13
  274. package/src/sdk/cli/session-cli.ts +100 -12
  275. package/src/sdk/host/host.ts +2 -7
  276. package/src/sdk/host/session-runtime.test.ts +329 -8
  277. package/src/sdk/host/session-runtime.ts +202 -50
  278. package/src/sdk/host/surface-policy.ts +8 -1
  279. package/src/sdk/lifecycle/service.ts +199 -22
  280. package/src/sdk/mcp/server.ts +1 -1
  281. package/src/sdk/prompt-deadline-lease.ts +12 -4
  282. package/src/sdk/prompt-deadline-manager.ts +5 -7
  283. package/src/sdk/prompt-failure.ts +148 -0
  284. package/src/sdk/prompt-status.ts +30 -1
  285. package/src/sdk/prompt-watchdog.ts +11 -3
  286. package/src/sdk/protocol/operation-inventory.generated.json +18 -0
  287. package/src/sdk/protocol/operation-registry.ts +20 -8
  288. package/src/sdk/router/session-router.ts +8 -3
  289. package/src/sdk/service-artifact-paths.ts +26 -0
  290. package/src/sdk/session-authority.ts +10 -0
  291. package/src/sdk/session.ts +361 -194
  292. package/src/session/agent-session.ts +398 -93
  293. package/src/session/blob-store.ts +9 -9
  294. package/src/session/fallback-chain-controller.ts +3 -7
  295. package/src/session/internal/managed-session-scope.ts +445 -29
  296. package/src/session/internal/managed-session-storage.ts +38 -6
  297. package/src/session/primary-control-surface.ts +12 -0
  298. package/src/session/session-manager.ts +11 -3
  299. package/src/session/session-storage.ts +1 -1
  300. package/src/session-import/codex.ts +6 -1
  301. package/src/session-import/redact.ts +7 -0
  302. package/src/skill-state/workflow-mutation-guard.ts +645 -39
  303. package/src/slash-commands/builtin-registry.ts +7 -3
  304. package/src/system-prompt.ts +8 -0
  305. package/src/task/executor.ts +36 -3
  306. package/src/task/types.ts +27 -5
  307. package/src/tools/ask.ts +114 -34
  308. package/src/tools/browser/actions.ts +2 -2
  309. package/src/tools/browser/tab-worker.ts +11 -8
  310. package/src/tools/descriptors.ts +6 -1
  311. package/src/tools/fetch.ts +7 -2
  312. package/src/tools/image-gen.ts +33 -34
  313. package/src/tools/read.ts +78 -32
  314. package/src/tools/skill-discovery.ts +17 -7
  315. package/src/tools/tool-catalog.generated.ts +8 -8
  316. package/src/tools/ultragoal-ask-guard.ts +16 -26
  317. package/src/utils/changelog.ts +7 -1
  318. package/src/utils/git.ts +3 -1
  319. package/src/utils/markit.ts +24 -2
  320. package/src/utils/mupdf-wasm.ts +26 -0
  321. package/src/web/search/providers/openai-compatible.ts +191 -14
@@ -92,7 +92,7 @@
92
92
  "type": "string"
93
93
  }
94
94
  },
95
- "description": "Explicit OAuth client settings for servers that need them during /mcp reauth or initial connect."
95
+ "description": "Client settings for an explicit MCP OAuth authorization consumer. These fields do not define a public standalone or ACP slash-command flow: those sessions do not expose /mcp reauth, /mcp test, or /mcp reconnect, and no public MCP OAuth authorization or reauthorization entry path is provided. Refreshing an already-stored credential does not read these: it uses the separate `auth` binding's clientId/clientSecret."
96
96
  },
97
97
  "serverBase": {
98
98
  "type": "object",
@@ -103,7 +103,7 @@
103
103
  },
104
104
  "autoload": {
105
105
  "type": "boolean",
106
- "description": "Whether an explicit runtime MCP consumer should connect this server automatically when that consumer starts (default: true). Ordinary standalone gjc, gjc --tmux, and print-mode sessions honor autoload for conventional registrations; false keeps the server configured for on-demand /mcp connection, and --no-mcp opts a session out."
106
+ "description": "Whether an explicit runtime MCP consumer should connect this server automatically when that consumer starts (default: true). Ordinary standalone gjc, gjc --tmux, and print-mode sessions honor autoload for conventional registrations, and --no-mcp opts a session out. false keeps the server stored but unloaded at startup: startup loading never connects it, and naming the file with --mcp-config does not override it, so set autoload to true or remove the key and start a new session. Autoload is necessary but not sufficient — enabled: false and disabledServers still block the server."
107
107
  },
108
108
  "sharing": {
109
109
  "type": "string",
@@ -112,7 +112,7 @@
112
112
  "shared"
113
113
  ],
114
114
  "default": "per-session",
115
- "description": "MCP connection pool identity mode; W2 defaults to one connection per session."
115
+ "description": "MCP connection pool identity mode; W2 defaults to one connection per session. Sharing is scoped to a single consumer process: separate processes never join the same pooled connection."
116
116
  },
117
117
  "timeout": {
118
118
  "type": "number",
@@ -374,6 +374,7 @@ const RegistryPresetSchema = z
374
374
  "azure-openai-responses",
375
375
  "bedrock-converse-stream",
376
376
  "cursor-agent",
377
+ "devin-acp",
377
378
  "google-gemini-cli",
378
379
  "google-generative-ai",
379
380
  "google-vertex",
@@ -777,6 +777,11 @@ function filterMaterializedRegistryProfiles(
777
777
  }
778
778
  return filtered;
779
779
  }
780
+ type SpecialProviderDescriptor = {
781
+ providerId: string;
782
+ resolveKey: (value: string | undefined) => string | undefined;
783
+ createOptions: (key: string) => ModelManagerOptions<Api>;
784
+ };
780
785
 
781
786
  const PROVIDER_BASE_URL_ENV_ALIASES: Record<string, readonly string[]> = {
782
787
  anthropic: ["ANTHROPIC_BASE_URL"],
@@ -1098,9 +1103,10 @@ function resolveOAuthAccountIdForAccessToken(
1098
1103
  authStorage: AuthStorage,
1099
1104
  provider: string,
1100
1105
  accessToken: string,
1106
+ sessionId?: string,
1101
1107
  owner?: object,
1102
1108
  ): string | undefined {
1103
- if (authStorage.getEffectiveCredentialType(provider, undefined, owner ? { owner } : undefined) !== "oauth") {
1109
+ if (authStorage.getEffectiveCredentialType(provider, sessionId, owner ? { owner } : undefined) !== "oauth") {
1104
1110
  return undefined;
1105
1111
  }
1106
1112
  const oauthCredentials = getOAuthCredentialsForProvider(authStorage, provider);
@@ -1851,7 +1857,7 @@ export class ModelRegistry {
1851
1857
  /**
1852
1858
  * Reload models from disk and refresh runtime provider discovery state.
1853
1859
  */
1854
- async refresh(strategy: ModelRefreshStrategy = "online-if-uncached"): Promise<void> {
1860
+ async refresh(strategy: ModelRefreshStrategy = "online-if-uncached", credentialSessionId?: string): Promise<void> {
1855
1861
  if (this.#disposed) return;
1856
1862
  await this.#enqueueCatalogMutation(async () => {
1857
1863
  if (this.#disposed) return;
@@ -1863,7 +1869,13 @@ export class ModelRegistry {
1863
1869
  try {
1864
1870
  this.#reloadStaticModels();
1865
1871
  this.#suppressedSelectors.clear();
1866
- await this.#refreshRuntimeDiscoveries(strategy, undefined, refreshGeneration, providerRefreshFence);
1872
+ await this.#refreshRuntimeDiscoveries(
1873
+ strategy,
1874
+ undefined,
1875
+ refreshGeneration,
1876
+ providerRefreshFence,
1877
+ credentialSessionId,
1878
+ );
1867
1879
  if (refreshGeneration === this.#catalogRefreshGeneration) this.#modelBindingsApplier.apply();
1868
1880
  } finally {
1869
1881
  this.#resumeRebuild();
@@ -1871,11 +1883,11 @@ export class ModelRegistry {
1871
1883
  });
1872
1884
  }
1873
1885
 
1874
- refreshInBackground(strategy: ModelRefreshStrategy = "online-if-uncached"): void {
1886
+ refreshInBackground(strategy: ModelRefreshStrategy = "online-if-uncached", credentialSessionId?: string): void {
1875
1887
  if (this.#backgroundRefresh) {
1876
1888
  return;
1877
1889
  }
1878
- const refreshPromise = this.refresh(strategy)
1890
+ const refreshPromise = this.refresh(strategy, credentialSessionId)
1879
1891
  .catch(error => {
1880
1892
  logger.warn("background model refresh failed", {
1881
1893
  error: error instanceof Error ? error.message : String(error),
@@ -1889,7 +1901,11 @@ export class ModelRegistry {
1889
1901
  this.#backgroundRefresh = refreshPromise;
1890
1902
  }
1891
1903
 
1892
- async refreshProvider(providerId: string, strategy: ModelRefreshStrategy = "online"): Promise<void> {
1904
+ async refreshProvider(
1905
+ providerId: string,
1906
+ strategy: ModelRefreshStrategy = "online",
1907
+ credentialSessionId?: string,
1908
+ ): Promise<void> {
1893
1909
  if (this.#disposed) return;
1894
1910
  const providerRefreshGeneration = (this.#providerRefreshGenerations.get(providerId) ?? 0) + 1;
1895
1911
  this.#providerRefreshGenerations.set(providerId, providerRefreshGeneration);
@@ -1905,10 +1921,16 @@ export class ModelRegistry {
1905
1921
  this.#suppressedSelectors.delete(selector);
1906
1922
  }
1907
1923
  }
1908
- await this.#refreshRuntimeDiscoveries(strategy, new Set([providerId]), refreshGeneration, {
1909
- providerId,
1910
- generation: providerRefreshGeneration,
1911
- });
1924
+ await this.#refreshRuntimeDiscoveries(
1925
+ strategy,
1926
+ new Set([providerId]),
1927
+ refreshGeneration,
1928
+ {
1929
+ providerId,
1930
+ generation: providerRefreshGeneration,
1931
+ },
1932
+ credentialSessionId,
1933
+ );
1912
1934
  if (
1913
1935
  refreshGeneration === this.#catalogRefreshGeneration &&
1914
1936
  this.#providerRefreshGenerations.get(providerId) === providerRefreshGeneration
@@ -3042,6 +3064,7 @@ export class ModelRegistry {
3042
3064
  providerFilter?: ReadonlySet<string>,
3043
3065
  refreshGeneration = this.#catalogRefreshGeneration,
3044
3066
  providerRefresh?: ProviderRefreshFence,
3067
+ credentialSessionId?: string,
3045
3068
  ): Promise<void> {
3046
3069
  const profileAvailabilityEvidenceBefore = this.#profileAvailabilityEvidenceFingerprint();
3047
3070
  const disabledProviders = getDisabledProviderIdsFromSettings(this.#settings);
@@ -3055,12 +3078,12 @@ export class ModelRegistry {
3055
3078
  ? Promise.resolve([] as ConfiguredDiscoveryResult[])
3056
3079
  : Promise.all(
3057
3080
  selectedDiscoverableProviders.map(provider =>
3058
- this.#discoverProviderModels(provider, strategy, providerRefresh),
3081
+ this.#discoverProviderModels(provider, strategy, providerRefresh, credentialSessionId),
3059
3082
  ),
3060
3083
  );
3061
3084
  const [configuredDiscoveryResults, builtInDiscovered] = await Promise.all([
3062
3085
  configuredDiscoveriesPromise,
3063
- this.#discoverBuiltInProviderModels(strategy, providerFilter, providerRefresh),
3086
+ this.#discoverBuiltInProviderModels(strategy, providerFilter, providerRefresh, credentialSessionId),
3064
3087
  ]);
3065
3088
  if (
3066
3089
  refreshGeneration !== this.#catalogRefreshGeneration ||
@@ -3301,6 +3324,7 @@ export class ModelRegistry {
3301
3324
  providerConfig: DiscoveryProviderConfig,
3302
3325
  strategy: ModelRefreshStrategy,
3303
3326
  providerRefresh?: ProviderRefreshFence,
3327
+ credentialSessionId?: string,
3304
3328
  ): Promise<ConfiguredDiscoveryResult> {
3305
3329
  const provider = providerConfig.provider;
3306
3330
  const preflightEpoch = this.#optionalAuthPreflightEpoch;
@@ -3330,6 +3354,7 @@ export class ModelRegistry {
3330
3354
  ignoreCredentiallessFallback: optionalAuth,
3331
3355
  refreshOAuth: true,
3332
3356
  baseUrl: providerConfig.baseUrl,
3357
+ credentialSessionId,
3333
3358
  }),
3334
3359
  );
3335
3360
  const currentAuthConfigurationGeneration = this.authStorage.getProviderConfigurationGeneration(provider);
@@ -3459,6 +3484,7 @@ export class ModelRegistry {
3459
3484
  : this.#peekApiKeyForProvider(provider.provider, {
3460
3485
  refreshOAuth: true,
3461
3486
  baseUrl: provider.baseUrl,
3487
+ credentialSessionId,
3462
3488
  }),
3463
3489
  isAuthenticated,
3464
3490
  fetchModels: async (provider, apiKey) => {
@@ -3565,6 +3591,7 @@ export class ModelRegistry {
3565
3591
  strategy: ModelRefreshStrategy,
3566
3592
  providerFilter?: ReadonlySet<string>,
3567
3593
  providerRefresh?: ProviderRefreshFence,
3594
+ credentialSessionId?: string,
3568
3595
  ): Promise<Model<Api>[]> {
3569
3596
  // Skip providers already handled by configured discovery (e.g. user-configured ollama with discovery.type)
3570
3597
  const configuredDiscoveryProviders = new Set(this.#discoveryManager.providers.map(p => p.provider));
@@ -3578,6 +3605,7 @@ export class ModelRegistry {
3578
3605
  const managerOptions = await this.#collectBuiltInModelManagerOptions(
3579
3606
  configuredDiscoveryProviders,
3580
3607
  providerFilter,
3608
+ credentialSessionId,
3581
3609
  );
3582
3610
  if (managerOptions.length === 0) {
3583
3611
  return [];
@@ -3588,15 +3616,8 @@ export class ModelRegistry {
3588
3616
  return discoveries.flat();
3589
3617
  }
3590
3618
 
3591
- async #collectBuiltInModelManagerOptions(
3592
- excludedProviderIds: ReadonlySet<string> = new Set(),
3593
- providerFilter?: ReadonlySet<string>,
3594
- ): Promise<ModelManagerDiscoveryOptions[]> {
3595
- const specialProviderDescriptors: Array<{
3596
- providerId: string;
3597
- resolveKey: (value: string | undefined) => string | undefined;
3598
- createOptions: (key: string) => ModelManagerOptions<Api>;
3599
- }> = [
3619
+ #specialProviderDescriptors(credentialSessionId?: string): SpecialProviderDescriptor[] {
3620
+ return [
3600
3621
  {
3601
3622
  providerId: "google-antigravity",
3602
3623
  resolveKey: extractGoogleOAuthToken,
@@ -3623,6 +3644,7 @@ export class ModelRegistry {
3623
3644
  this.authStorage,
3624
3645
  "openai-codex",
3625
3646
  accessToken,
3647
+ credentialSessionId,
3626
3648
  this.#authStorageConfigOwner,
3627
3649
  );
3628
3650
  return openaiCodexModelManagerOptions({
@@ -3632,6 +3654,14 @@ export class ModelRegistry {
3632
3654
  },
3633
3655
  },
3634
3656
  ];
3657
+ }
3658
+
3659
+ async #collectBuiltInModelManagerOptions(
3660
+ excludedProviderIds: ReadonlySet<string> = new Set(),
3661
+ providerFilter?: ReadonlySet<string>,
3662
+ credentialSessionId?: string,
3663
+ ): Promise<ModelManagerDiscoveryOptions[]> {
3664
+ const specialProviderDescriptors = this.#specialProviderDescriptors(credentialSessionId);
3635
3665
  const disabledProviders = getDisabledProviderIdsFromSettings(this.#settings);
3636
3666
  const standardProviderDescriptors = PROVIDER_DESCRIPTORS.filter(
3637
3667
  descriptor =>
@@ -3655,7 +3685,7 @@ export class ModelRegistry {
3655
3685
  // and failures there are handled gracefully.
3656
3686
  const peekKey = async (descriptor: { providerId: string }) => {
3657
3687
  const configurationGeneration = this.authStorage.getProviderConfigurationGeneration(descriptor.providerId);
3658
- const apiKey = await this.#peekApiKeyForProvider(descriptor.providerId);
3688
+ const apiKey = await this.#peekApiKeyForProvider(descriptor.providerId, { credentialSessionId });
3659
3689
  if (configurationGeneration !== this.authStorage.getProviderConfigurationGeneration(descriptor.providerId)) {
3660
3690
  return { apiKey: undefined, authGeneration: undefined };
3661
3691
  }
@@ -5387,6 +5417,27 @@ export class ModelRegistry {
5387
5417
  .map(provider => provider.provider);
5388
5418
  }
5389
5419
 
5420
+ /**
5421
+ * Providers whose catalogs can be filled by bounded official refresh:
5422
+ * configured discovery, built-in special OAuth dynamics, and standard
5423
+ * descriptor-backed providers. Unknown ids stay excluded. Disabled
5424
+ * providers are omitted. UI tabs still use getDiscoverableProviders.
5425
+ */
5426
+ getRefreshableProviders(): string[] {
5427
+ const disabledProviders = getDisabledProviderIdsFromSettings(this.#settings);
5428
+ const providers: string[] = [];
5429
+ const seen = new Set<string>();
5430
+ const add = (providerId: string) => {
5431
+ if (disabledProviders.has(providerId) || seen.has(providerId)) return;
5432
+ seen.add(providerId);
5433
+ providers.push(providerId);
5434
+ };
5435
+ for (const provider of this.#discoveryManager.providers) add(provider.provider);
5436
+ for (const descriptor of PROVIDER_DESCRIPTORS) add(descriptor.providerId);
5437
+ for (const descriptor of this.#specialProviderDescriptors()) add(descriptor.providerId);
5438
+ return providers;
5439
+ }
5440
+
5390
5441
  getProviderDiscoveryState(provider: string): ProviderDiscoveryState | undefined {
5391
5442
  return this.#discoveryManager.getState(provider);
5392
5443
  }
@@ -5645,6 +5696,7 @@ export class ModelRegistry {
5645
5696
  ignoreCredentiallessFallback?: boolean;
5646
5697
  refreshOAuth?: boolean;
5647
5698
  baseUrl?: string;
5699
+ credentialSessionId?: string;
5648
5700
  } = {},
5649
5701
  ): Promise<string | undefined> {
5650
5702
  this.#refreshRotatingConfigApiKey(provider);
@@ -5657,16 +5709,17 @@ export class ModelRegistry {
5657
5709
  return undefined;
5658
5710
  }
5659
5711
  if (options.refreshOAuth && this.authStorage.hasOAuth(provider)) {
5660
- return this.authStorage.getApiKey(provider, undefined, {
5712
+ return this.authStorage.getApiKey(provider, options.credentialSessionId, {
5661
5713
  baseUrl: options.baseUrl,
5662
5714
  owner: this.#authStorageConfigOwner,
5663
5715
  });
5664
5716
  }
5717
+ const peekOptions = options.credentialSessionId
5718
+ ? { owner: this.#authStorageConfigOwner, sessionId: options.credentialSessionId }
5719
+ : { owner: this.#authStorageConfigOwner };
5665
5720
  return options.ignoreCredentiallessFallback
5666
- ? this.authStorage.peekApiKey(provider, { owner: this.#authStorageConfigOwner })
5667
- : this.#getApiKeyOrNoAuth(provider, () =>
5668
- this.authStorage.peekApiKey(provider, { owner: this.#authStorageConfigOwner }),
5669
- );
5721
+ ? this.authStorage.peekApiKey(provider, peekOptions)
5722
+ : this.#getApiKeyOrNoAuth(provider, () => this.authStorage.peekApiKey(provider, peekOptions));
5670
5723
  }
5671
5724
 
5672
5725
  /**
@@ -86,14 +86,14 @@ export function resolveStartupModelRefreshSelectors(
86
86
 
87
87
  export async function refreshMissingQualifiedModelProviders(
88
88
  selectors: ModelSelectorValue | undefined,
89
- modelRegistry: Pick<ModelRegistry, "getAvailable" | "getDiscoverableProviders" | "refreshProvider">,
89
+ modelRegistry: Pick<ModelRegistry, "getAvailable" | "getRefreshableProviders" | "refreshProvider">,
90
90
  ): Promise<boolean> {
91
91
  const refreshedProviders = new Set<string>();
92
92
  for (const selector of normalizeModelSelectorValue(selectors)) {
93
93
  const parsedSelector = parseModelString(selector);
94
94
  if (!parsedSelector) continue;
95
95
  const provider = modelRegistry
96
- .getDiscoverableProviders()
96
+ .getRefreshableProviders()
97
97
  .find(candidate => candidate.toLowerCase() === parsedSelector.provider.toLowerCase());
98
98
  if (!provider || refreshedProviders.has(provider)) continue;
99
99
  const availableModels = modelRegistry.getAvailable();
@@ -1143,10 +1143,25 @@ export async function resolveModelChainWithAuth(
1143
1143
  }
1144
1144
  return { explicitThinkingLevel: false, activeIndex: modelPatterns.length, skips };
1145
1145
  }
1146
+ export function isExplicitProviderModelSelector(pattern: string): boolean {
1147
+ const normalized = pattern.trim();
1148
+ if (!normalized || isSessionInheritedAgentPattern(normalized)) return false;
1149
+ const suffix = splitSelectorThinkingSuffix(normalized);
1150
+ const selector = suffix.thinkingLevel ? suffix.selector : normalized;
1151
+ if (getModelRoleAlias(selector)) return false;
1152
+ if (/[*?[]/.test(selector)) return false;
1153
+ const parsed = parseModelString(selector);
1154
+ return parsed !== undefined && parsed.provider.length > 0 && parsed.id.length > 0;
1155
+ }
1156
+
1157
+ export function isExplicitProviderModelOverride(modelPatterns: readonly string[]): boolean {
1158
+ return modelPatterns.length > 0 && modelPatterns.every(isExplicitProviderModelSelector);
1159
+ }
1146
1160
 
1147
1161
  /**
1148
1162
  * Resolve a list of override patterns to the first matching model, with an
1149
- * auth-aware fallback to the parent session's active model.
1163
+ * auth-aware fallback to the parent session's active model for unqualified
1164
+ * aliases and role patterns.
1150
1165
  *
1151
1166
  * If the resolved subagent model has no working credentials (provider has no
1152
1167
  * usable auth), and the parent's active model resolves with working auth,
@@ -1155,6 +1170,14 @@ export async function resolveModelChainWithAuth(
1155
1170
  * `modelRoles.task` pointing at an unqualified id whose only available
1156
1171
  * provider variant has no configured credentials — see #985).
1157
1172
  *
1173
+ * Explicit `provider/model` selectors (including user-specified chains of
1174
+ * them) fail closed instead: a missing catalog entry or authentication
1175
+ * failure must not substitute the parent session's model or another
1176
+ * provider. Intentional chain tails still apply in order. Mixed chains that
1177
+ * include any unqualified/role entry keep parent fallback for the whole
1178
+ * chain, including explicit heads. Glob selectors (`*`, `?`, `[`) are not
1179
+ * exact pins.
1180
+ *
1158
1181
  * Keyless-by-design providers (llama.cpp, ollama, lm-studio) advertise the
1159
1182
  * `kNoAuth` sentinel from `getApiKey` to signal that they do not require
1160
1183
  * credentials. Those are treated as authenticated here so an explicitly
@@ -1163,7 +1186,9 @@ export async function resolveModelChainWithAuth(
1163
1186
  *
1164
1187
  * If neither the subagent nor the parent has working auth, returns the
1165
1188
  * primary resolution unchanged so the existing error path still surfaces
1166
- * a meaningful failure downstream.
1189
+ * a meaningful failure downstream. Explicit-only chains return no model
1190
+ * so callers can surface an actionable error. Canonical parent seeding is
1191
+ * independent of that fail-closed substitution guard.
1167
1192
  */
1168
1193
  export async function resolveModelOverrideWithAuthFallback(
1169
1194
  modelPatterns: string[],
@@ -1191,6 +1216,7 @@ export async function resolveModelOverrideWithAuthFallback(
1191
1216
  const skips: Array<{ selector: string; reason: string }> = [];
1192
1217
  let activeIndex = 0;
1193
1218
  const canonicalScope = canonicalSessionId ?? authSessionId;
1219
+ const explicitExactOnly = isExplicitProviderModelOverride(modelPatterns);
1194
1220
  if (canonicalScope && parentActiveModelPattern) {
1195
1221
  const parentActiveModel = resolveModelOverride(
1196
1222
  [parentActiveModelPattern],
@@ -1257,6 +1283,9 @@ export async function resolveModelOverrideWithAuthFallback(
1257
1283
  skips.push({ selector: pattern, reason: "unauthenticated" });
1258
1284
  activeIndex += 1;
1259
1285
  }
1286
+ if (explicitExactOnly) {
1287
+ return { explicitThinkingLevel: false, requestedModel, authFallbackUsed: false, activeIndex, skips };
1288
+ }
1260
1289
  const fallback = parentActiveModelPattern
1261
1290
  ? resolveModelOverride([parentActiveModelPattern], modelRegistry, settings, authSessionId, options?.aliasIntent)
1262
1291
  : { explicitThinkingLevel: false };
@@ -141,6 +141,7 @@ const ModelDefinitionSchema = z
141
141
  "google-gemini-cli",
142
142
  "ollama-chat",
143
143
  "cursor-agent",
144
+ "devin-acp",
144
145
  ])
145
146
  .optional(),
146
147
  baseUrl: z.string().min(1).optional(),
@@ -234,6 +235,7 @@ const ProviderConfigSchema = z
234
235
  "google-gemini-cli",
235
236
  "ollama-chat",
236
237
  "cursor-agent",
238
+ "devin-acp",
237
239
  ])
238
240
  .optional(),
239
241
  headers: z.record(z.string(), z.string()).optional(),
@@ -309,7 +309,11 @@ export const DEFAULT_BASH_INTERCEPTOR_RULES: BashInterceptorRule[] = [
309
309
  message: "Use the `edit` tool instead of awk -i inplace. It provides diff preview and fuzzy matching.",
310
310
  },
311
311
  {
312
- pattern: "^\\s*(echo|printf|cat\\s*<<)\\s+.*[^|]>\\s*\\S",
312
+ // The redirection must belong to the leading echo/printf/heredoc itself:
313
+ // `(?!&&)[^;|\n]` keeps the scan inside that one command, `(?<![02-9])`
314
+ // skips fd redirections like `2>/dev/null`, and `<<\S*` accepts the usual
315
+ // `<<EOF` / `<<'EOF'` heredoc spelling that has no space after `<<`.
316
+ pattern: "^\\s*(echo|printf|cat\\s*<<\\S*)\\s+(?:(?!&&)[^;|\\n])*(?<![02-9])>{1,2}\\s*\\S",
313
317
  tool: "write",
314
318
  message: "Use the `write` tool instead of echo/cat redirection. It handles encoding and provides confirmation.",
315
319
  },
@@ -412,7 +416,7 @@ export const SETTINGS_SCHEMA = {
412
416
  // SDK-owned prompt deadline. Hidden from the UI; ACP has no separate timeout.
413
417
  "sdk.promptDeadlineMs": {
414
418
  type: "number",
415
- default: 1_800_000,
419
+ default: 3_600_000,
416
420
  description: "SDK-owned prompt deadline; ACP has no separate timeout.",
417
421
  validate: (value: number) => Number.isSafeInteger(value) && value >= 60_000 && value <= 86_400_000,
418
422
  },
@@ -9,6 +9,7 @@ export type PublicReason =
9
9
  | "pagination_malformed"
10
10
  | "row_unrepresentable"
11
11
  | "missing_runtime_turn"
12
+ | "pending_registration"
12
13
  | "invalid_runtime_turn"
13
14
  | "invalid_gate_row"
14
15
  | "wrong_session"