@gajae-code/coding-agent 0.10.2 → 0.11.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 (476) hide show
  1. package/CHANGELOG.md +58 -2
  2. package/dist/types/append-only-mode.d.ts +1 -1
  3. package/dist/types/async/job-manager.d.ts +46 -7
  4. package/dist/types/cli/args.d.ts +4 -5
  5. package/dist/types/cli/daemon-cli.d.ts +12 -1
  6. package/dist/types/cli/notify-cli.d.ts +21 -1
  7. package/dist/types/cli.d.ts +3 -0
  8. package/dist/types/commands/daemon.d.ts +39 -0
  9. package/dist/types/commands/launch.d.ts +3 -0
  10. package/dist/types/commands/notify.d.ts +28 -1
  11. package/dist/types/commands/sdk.d.ts +33 -0
  12. package/dist/types/config/atomic-yaml-patch.d.ts +85 -0
  13. package/dist/types/config/model-profile-activation.d.ts +35 -15
  14. package/dist/types/config/model-profiles.d.ts +11 -5
  15. package/dist/types/config/model-registry.d.ts +3 -3
  16. package/dist/types/config/model-resolver.d.ts +39 -6
  17. package/dist/types/config/model-selector-value.d.ts +17 -0
  18. package/dist/types/config/models-config-schema.d.ts +10 -6
  19. package/dist/types/config/settings-schema.d.ts +133 -6
  20. package/dist/types/config/settings.d.ts +63 -35
  21. package/dist/types/coordinator-mcp/model-preset.d.ts +7 -6
  22. package/dist/types/coordinator-mcp/server.d.ts +6 -49
  23. package/dist/types/daemon/builtin.d.ts +6 -5
  24. package/dist/types/daemon/control-types.d.ts +1 -1
  25. package/dist/types/discovery/mcp-json.d.ts +12 -1
  26. package/dist/types/extensibility/custom-tools/types.d.ts +1 -1
  27. package/dist/types/extensibility/extensions/compact-handler.d.ts +4 -2
  28. package/dist/types/extensibility/extensions/get-commands-handler.d.ts +2 -2
  29. package/dist/types/extensibility/extensions/loader.d.ts +10 -1
  30. package/dist/types/extensibility/extensions/runner.d.ts +3 -3
  31. package/dist/types/extensibility/extensions/types.d.ts +141 -16
  32. package/dist/types/extensibility/hooks/types.d.ts +1 -1
  33. package/dist/types/gjc-runtime/launch-tmux.d.ts +3 -2
  34. package/dist/types/gjc-runtime/psmux-detect.d.ts +3 -0
  35. package/dist/types/gjc-runtime/session-state-sidecar.d.ts +3 -0
  36. package/dist/types/gjc-runtime/team-runtime.d.ts +3 -4
  37. package/dist/types/gjc-runtime/tmux-owner-isolation-cli.d.ts +13 -0
  38. package/dist/types/gjc-runtime/tmux-sessions.d.ts +4 -1
  39. package/dist/types/gjc-runtime/ultragoal-receipt-freshness.d.ts +11 -0
  40. package/dist/types/gjc-runtime/windows-powershell-command.d.ts +9 -0
  41. package/dist/types/harness-control-plane/operate.d.ts +5 -5
  42. package/dist/types/harness-control-plane/owner.d.ts +18 -4
  43. package/dist/types/harness-control-plane/receipts.d.ts +0 -1
  44. package/dist/types/harness-control-plane/sdk-transport.d.ts +43 -0
  45. package/dist/types/harness-control-plane/session-transport.d.ts +48 -0
  46. package/dist/types/harness-control-plane/types.d.ts +3 -4
  47. package/dist/types/lsp/index.d.ts +1 -1
  48. package/dist/types/main.d.ts +32 -38
  49. package/dist/types/modes/acp/acp-agent.d.ts +224 -53
  50. package/dist/types/modes/acp/acp-client-bridge.d.ts +1 -0
  51. package/dist/types/modes/acp/acp-mode.d.ts +6 -15
  52. package/dist/types/modes/acp/permission-mode.d.ts +4 -0
  53. package/dist/types/modes/acp/startup-options.d.ts +6 -0
  54. package/dist/types/modes/components/agent-dashboard.d.ts +3 -0
  55. package/dist/types/modes/components/model-selector.d.ts +1 -0
  56. package/dist/types/modes/components/notifications-settings-editor.d.ts +135 -0
  57. package/dist/types/modes/components/settings-selector.d.ts +6 -4
  58. package/dist/types/modes/components/welcome.d.ts +1 -1
  59. package/dist/types/modes/controllers/command-controller.d.ts +2 -2
  60. package/dist/types/modes/controllers/extension-ui-controller.d.ts +1 -0
  61. package/dist/types/modes/controllers/selector-controller.d.ts +35 -1
  62. package/dist/types/modes/index.d.ts +0 -4
  63. package/dist/types/modes/interactive-mode.d.ts +5 -2
  64. package/dist/types/modes/runtime-init.d.ts +2 -2
  65. package/dist/types/modes/shared/agent-wire/approval-gate.d.ts +6 -9
  66. package/dist/types/modes/shared/agent-wire/deep-interview-gate.d.ts +4 -6
  67. package/dist/types/modes/shared/agent-wire/event-contract.d.ts +6 -6
  68. package/dist/types/modes/shared/agent-wire/event-envelope.d.ts +4 -9
  69. package/dist/types/modes/shared/agent-wire/event-observation.d.ts +1 -1
  70. package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +170 -30
  71. package/dist/types/modes/shared/agent-wire/workflow-gate-schema.d.ts +7 -7
  72. package/dist/types/modes/shared/agent-wire/workflow-gate-types.d.ts +105 -0
  73. package/dist/types/modes/types.d.ts +7 -2
  74. package/dist/types/runtime-mcp/client.d.ts +2 -0
  75. package/dist/types/runtime-mcp/config.d.ts +5 -1
  76. package/dist/types/runtime-mcp/manager.d.ts +8 -1
  77. package/dist/types/runtime-mcp/types.d.ts +4 -0
  78. package/dist/types/sdk/acp/adapter.d.ts +67 -0
  79. package/dist/types/sdk/acp/index.d.ts +2 -0
  80. package/dist/types/sdk/broker/broker.d.ts +53 -0
  81. package/dist/types/sdk/broker/discovery.d.ts +30 -0
  82. package/dist/types/sdk/broker/ensure.d.ts +42 -0
  83. package/dist/types/sdk/broker/identity.d.ts +3 -0
  84. package/dist/types/sdk/broker/index.d.ts +8 -0
  85. package/dist/types/sdk/broker/lifecycle-ledger.d.ts +95 -0
  86. package/dist/types/sdk/broker/lifecycle.d.ts +85 -0
  87. package/dist/types/sdk/broker/process-incarnation.d.ts +14 -0
  88. package/dist/types/sdk/broker/runtime.d.ts +33 -0
  89. package/dist/types/sdk/broker/session-index.d.ts +57 -0
  90. package/dist/types/sdk/broker/state-version.d.ts +8 -0
  91. package/dist/types/sdk/broker/transport.d.ts +9 -0
  92. package/dist/types/sdk/bus/chat-command-policy.d.ts +49 -0
  93. package/dist/types/sdk/bus/chat-daemon-cli.d.ts +21 -0
  94. package/dist/types/sdk/bus/chat-daemon-control.d.ts +111 -0
  95. package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +77 -0
  96. package/dist/types/sdk/bus/chat-effect-journal.d.ts +84 -0
  97. package/dist/types/{notifications → sdk/bus}/config-commands.d.ts +7 -2
  98. package/dist/types/sdk/bus/config.d.ts +274 -0
  99. package/dist/types/sdk/bus/conversation-store.d.ts +72 -0
  100. package/dist/types/sdk/bus/discord-conversation.d.ts +58 -0
  101. package/dist/types/sdk/bus/discord-daemon.d.ts +50 -0
  102. package/dist/types/sdk/bus/discord-live-provider.d.ts +70 -0
  103. package/dist/types/sdk/bus/discord-provider.d.ts +85 -0
  104. package/dist/types/{notifications → sdk/bus}/html-format.d.ts +2 -2
  105. package/dist/types/{notifications → sdk/bus}/index.d.ts +113 -13
  106. package/dist/types/{notifications → sdk/bus}/lifecycle-control-runtime.d.ts +4 -2
  107. package/dist/types/{notifications → sdk/bus}/lifecycle-orchestrator.d.ts +18 -21
  108. package/dist/types/{notifications → sdk/bus}/managed-daemon.d.ts +1 -1
  109. package/dist/types/sdk/bus/native-runtime-compatibility.d.ts +13 -0
  110. package/dist/types/sdk/bus/notification-orchestration.d.ts +170 -0
  111. package/dist/types/{notifications → sdk/bus}/notification-service.d.ts +7 -1
  112. package/dist/types/sdk/bus/session-control.d.ts +83 -0
  113. package/dist/types/sdk/bus/slack-conversation.d.ts +56 -0
  114. package/dist/types/sdk/bus/slack-daemon.d.ts +60 -0
  115. package/dist/types/sdk/bus/slack-live-provider.d.ts +59 -0
  116. package/dist/types/sdk/bus/slack-provider.d.ts +55 -0
  117. package/dist/types/{notifications → sdk/bus}/telegram-cli.d.ts +4 -4
  118. package/dist/types/{notifications → sdk/bus}/telegram-daemon-cli.d.ts +14 -5
  119. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +12 -0
  120. package/dist/types/{notifications → sdk/bus}/telegram-daemon-control.d.ts +2 -2
  121. package/dist/types/{notifications → sdk/bus}/telegram-daemon.d.ts +78 -17
  122. package/dist/types/{notifications → sdk/bus}/telegram-reference.d.ts +2 -2
  123. package/dist/types/sdk/bus/telegram-setup.d.ts +128 -0
  124. package/dist/types/{notifications → sdk/bus}/topic-registry.d.ts +11 -0
  125. package/dist/types/sdk/cli/index.d.ts +1 -0
  126. package/dist/types/sdk/cli/session-cli.d.ts +19 -0
  127. package/dist/types/sdk/client/client.d.ts +1 -0
  128. package/dist/types/sdk/client/discovery.d.ts +27 -0
  129. package/dist/types/sdk/client/index.d.ts +2 -0
  130. package/dist/types/sdk/host/control/dispatch.d.ts +34 -0
  131. package/dist/types/sdk/host/control/index.d.ts +2 -0
  132. package/dist/types/sdk/host/control/operations.d.ts +65 -0
  133. package/dist/types/sdk/host/events.d.ts +35 -0
  134. package/dist/types/sdk/host/host.d.ts +35 -0
  135. package/dist/types/sdk/host/index.d.ts +4 -0
  136. package/dist/types/sdk/host/query/cursor.d.ts +62 -0
  137. package/dist/types/sdk/host/query/handlers.d.ts +70 -0
  138. package/dist/types/sdk/host/query/index.d.ts +3 -0
  139. package/dist/types/sdk/host/query/revision-store.d.ts +60 -0
  140. package/dist/types/sdk/host/reverse-leases.d.ts +45 -0
  141. package/dist/types/sdk/host/types.d.ts +32 -0
  142. package/dist/types/sdk/index.d.ts +6 -0
  143. package/dist/types/sdk/lifecycle-session.d.ts +14 -0
  144. package/dist/types/sdk/mcp/index.d.ts +1 -0
  145. package/dist/types/sdk/mcp/server.d.ts +37 -0
  146. package/dist/types/sdk/models.d.ts +44 -0
  147. package/dist/types/sdk/protocol/adapter-validation.d.ts +14 -0
  148. package/dist/types/sdk/protocol/operation-registry.d.ts +24 -0
  149. package/dist/types/{sdk.d.ts → sdk/session.d.ts} +44 -38
  150. package/dist/types/sdk/startup-capability.d.ts +50 -0
  151. package/dist/types/session/agent-session.d.ts +114 -21
  152. package/dist/types/session/default-model-selection.d.ts +25 -0
  153. package/dist/types/session/fallback-chain-controller.d.ts +52 -0
  154. package/dist/types/session/session-manager.d.ts +58 -1
  155. package/dist/types/setup/credential-auto-import.d.ts +36 -6
  156. package/dist/types/tools/ask-answer-registry.d.ts +1 -1
  157. package/dist/types/tools/browser/benchmark/detector-report.d.ts +63 -0
  158. package/dist/types/tools/browser/benchmark/run-suite.d.ts +18 -0
  159. package/dist/types/tools/browser/launch.d.ts +22 -0
  160. package/dist/types/tools/browser/profile-discovery.d.ts +31 -0
  161. package/dist/types/tools/browser/profile-posture.d.ts +37 -0
  162. package/dist/types/tools/browser/profile-reuse.d.ts +39 -0
  163. package/dist/types/tools/browser/profile-warmup.d.ts +39 -0
  164. package/dist/types/tools/browser/registry.d.ts +19 -0
  165. package/dist/types/tools/browser/tab-protocol.d.ts +4 -0
  166. package/dist/types/tools/index.d.ts +8 -8
  167. package/dist/types/tools/subagent-render.d.ts +1 -0
  168. package/dist/types/tools/subagent.d.ts +6 -1
  169. package/package.json +34 -13
  170. package/scripts/build-sdk-package-smoke.ts +99 -0
  171. package/scripts/capture-notifications-settings-showcase.ts +435 -0
  172. package/scripts/compile-args.ts +4 -2
  173. package/scripts/g005-daemon-smoke.ts +4 -5
  174. package/scripts/g011-daemon-path-smoke.ts +5 -5
  175. package/scripts/generate-sdk-adapter-parity-manifest.ts +163 -0
  176. package/scripts/generate-sdk-operation-inventory.ts +867 -0
  177. package/scripts/generate-telegram-baseline-manifest.ts +128 -0
  178. package/scripts/manifest-schema.ts +124 -0
  179. package/scripts/run-test-manifest.ts +153 -0
  180. package/scripts/run-threat-model-check.ts +157 -0
  181. package/scripts/verify-gjc-sdk-canonicalization.ts +3467 -0
  182. package/scripts/verify-gjc-sdk-rename.ts +90 -0
  183. package/src/append-only-mode.ts +1 -1
  184. package/src/async/job-manager.ts +406 -63
  185. package/src/cli/args.ts +43 -12
  186. package/src/cli/auth-gateway-cli.ts +2 -2
  187. package/src/cli/config-cli.ts +2 -1
  188. package/src/cli/daemon-cli.ts +63 -14
  189. package/src/cli/list-models.ts +1 -1
  190. package/src/cli/notify-cli.ts +288 -286
  191. package/src/cli.ts +21 -2
  192. package/src/commands/daemon.ts +50 -6
  193. package/src/commands/harness.ts +93 -36
  194. package/src/commands/launch.ts +5 -2
  195. package/src/commands/mcp-serve.ts +19 -12
  196. package/src/commands/notify.ts +36 -3
  197. package/src/commands/sdk.ts +426 -0
  198. package/src/commit/agentic/agent.ts +1 -0
  199. package/src/config/atomic-yaml-patch.ts +423 -0
  200. package/src/config/model-profile-activation.ts +240 -89
  201. package/src/config/model-profiles.ts +18 -15
  202. package/src/config/model-registry.ts +51 -26
  203. package/src/config/model-resolver.ts +138 -51
  204. package/src/config/model-selector-value.ts +50 -0
  205. package/src/config/models-config-schema.ts +14 -21
  206. package/src/config/settings-schema.ts +128 -10
  207. package/src/config/settings.ts +1120 -158
  208. package/src/coordinator-mcp/model-preset.ts +74 -20
  209. package/src/coordinator-mcp/server.ts +1597 -3052
  210. package/src/daemon/builtin.ts +8 -5
  211. package/src/daemon/control-types.ts +1 -1
  212. package/src/defaults/gjc/skills/team/SKILL.md +4 -4
  213. package/src/discovery/mcp-json.ts +327 -20
  214. package/src/extensibility/custom-tools/types.ts +1 -1
  215. package/src/extensibility/extensions/compact-handler.ts +3 -3
  216. package/src/extensibility/extensions/get-commands-handler.ts +2 -2
  217. package/src/extensibility/extensions/loader.ts +69 -5
  218. package/src/extensibility/extensions/runner.ts +112 -4
  219. package/src/extensibility/extensions/types.ts +176 -17
  220. package/src/extensibility/hooks/types.ts +1 -1
  221. package/src/gjc-runtime/launch-tmux.ts +170 -86
  222. package/src/gjc-runtime/psmux-detect.ts +82 -4
  223. package/src/gjc-runtime/session-state-sidecar.ts +41 -31
  224. package/src/gjc-runtime/team-runtime.ts +54 -35
  225. package/src/gjc-runtime/tmux-owner-isolation-cli.ts +53 -17
  226. package/src/gjc-runtime/tmux-owner-isolation.ts +1 -1
  227. package/src/gjc-runtime/tmux-sessions.ts +19 -13
  228. package/src/gjc-runtime/ultragoal-guard.ts +108 -14
  229. package/src/gjc-runtime/ultragoal-receipt-freshness.ts +102 -1
  230. package/src/gjc-runtime/ultragoal-runtime.ts +227 -11
  231. package/src/gjc-runtime/windows-powershell-command.ts +58 -0
  232. package/src/harness-control-plane/operate.ts +9 -9
  233. package/src/harness-control-plane/owner.ts +283 -39
  234. package/src/harness-control-plane/receipts.ts +0 -1
  235. package/src/harness-control-plane/sdk-transport.ts +395 -0
  236. package/src/harness-control-plane/session-transport.ts +94 -0
  237. package/src/harness-control-plane/types.ts +1 -1
  238. package/src/internal-urls/docs-index.generated.ts +34 -35
  239. package/src/lsp/client.ts +42 -6
  240. package/src/lsp/index.ts +2 -2
  241. package/src/main.ts +299 -204
  242. package/src/modes/DESIGN.md +258 -0
  243. package/src/modes/acp/acp-agent.ts +1228 -2612
  244. package/src/modes/acp/acp-client-bridge.ts +2 -20
  245. package/src/modes/acp/acp-event-mapper.ts +18 -2
  246. package/src/modes/acp/acp-mode.ts +8 -36
  247. package/src/modes/acp/permission-mode.ts +25 -0
  248. package/src/modes/acp/startup-options.ts +6 -0
  249. package/src/modes/components/agent-dashboard.ts +37 -17
  250. package/src/modes/components/model-selector.ts +93 -35
  251. package/src/modes/components/notifications-settings-editor.ts +1379 -0
  252. package/src/modes/components/settings-selector.ts +60 -11
  253. package/src/modes/components/welcome.ts +4 -4
  254. package/src/modes/controllers/command-controller.ts +10 -17
  255. package/src/modes/controllers/event-controller.ts +11 -16
  256. package/src/modes/controllers/extension-ui-controller.ts +396 -28
  257. package/src/modes/controllers/selector-controller.ts +674 -36
  258. package/src/modes/index.ts +0 -22
  259. package/src/modes/interactive-mode.ts +87 -36
  260. package/src/modes/runtime-init.ts +298 -6
  261. package/src/modes/shared/agent-wire/approval-gate.ts +9 -11
  262. package/src/modes/shared/agent-wire/deep-interview-gate.ts +10 -11
  263. package/src/modes/shared/agent-wire/event-contract.ts +7 -8
  264. package/src/modes/shared/agent-wire/event-envelope.ts +9 -17
  265. package/src/modes/shared/agent-wire/event-observation.ts +16 -7
  266. package/src/modes/shared/agent-wire/workflow-gate-broker.ts +1258 -87
  267. package/src/modes/shared/agent-wire/workflow-gate-schema.ts +15 -15
  268. package/src/modes/shared/agent-wire/workflow-gate-types.ts +113 -0
  269. package/src/modes/types.ts +7 -2
  270. package/src/runtime-mcp/client.ts +94 -19
  271. package/src/runtime-mcp/config.ts +27 -15
  272. package/src/runtime-mcp/manager.ts +343 -105
  273. package/src/runtime-mcp/oauth-flow.ts +42 -12
  274. package/src/runtime-mcp/transports/http.ts +49 -19
  275. package/src/runtime-mcp/transports/stdio.ts +47 -28
  276. package/src/runtime-mcp/types.ts +10 -0
  277. package/src/sdk/acp/adapter.ts +418 -0
  278. package/src/sdk/acp/index.ts +2 -0
  279. package/src/sdk/broker/broker.ts +642 -0
  280. package/src/sdk/broker/discovery.ts +113 -0
  281. package/src/sdk/broker/ensure.ts +307 -0
  282. package/src/sdk/broker/identity.ts +42 -0
  283. package/src/sdk/broker/index.ts +8 -0
  284. package/src/sdk/broker/internal-source-marker-2178.txt +1 -0
  285. package/src/sdk/broker/internal-source.bunfig.toml +1 -0
  286. package/src/sdk/broker/lifecycle-ledger.ts +286 -0
  287. package/src/sdk/broker/lifecycle.ts +2157 -0
  288. package/src/sdk/broker/process-incarnation.ts +159 -0
  289. package/src/sdk/broker/runtime.ts +164 -0
  290. package/src/sdk/broker/session-index.ts +318 -0
  291. package/src/sdk/broker/state-version.ts +23 -0
  292. package/src/sdk/broker/transport.ts +125 -0
  293. package/src/sdk/bus/chat-command-policy.ts +107 -0
  294. package/src/sdk/bus/chat-daemon-cli.ts +214 -0
  295. package/src/sdk/bus/chat-daemon-control.ts +713 -0
  296. package/src/sdk/bus/chat-daemon-runtime.ts +526 -0
  297. package/src/sdk/bus/chat-effect-journal.ts +355 -0
  298. package/src/{notifications → sdk/bus}/config-commands.ts +39 -10
  299. package/src/sdk/bus/config.ts +433 -0
  300. package/src/sdk/bus/conversation-store.ts +391 -0
  301. package/src/sdk/bus/discord-conversation.ts +85 -0
  302. package/src/sdk/bus/discord-daemon.ts +2292 -0
  303. package/src/sdk/bus/discord-live-provider.ts +521 -0
  304. package/src/sdk/bus/discord-provider.ts +56 -0
  305. package/src/{notifications → sdk/bus}/html-format.ts +2 -2
  306. package/src/sdk/bus/index.ts +3979 -0
  307. package/src/{notifications → sdk/bus}/lifecycle-commands.ts +2 -0
  308. package/src/{notifications → sdk/bus}/lifecycle-control-runtime.ts +225 -196
  309. package/src/{notifications → sdk/bus}/lifecycle-orchestrator.ts +161 -74
  310. package/src/{notifications → sdk/bus}/managed-daemon.ts +2 -2
  311. package/src/sdk/bus/native-runtime-compatibility.ts +42 -0
  312. package/src/sdk/bus/natives-augment.d.ts +38 -0
  313. package/src/sdk/bus/notification-orchestration.ts +535 -0
  314. package/src/{notifications → sdk/bus}/notification-service.ts +106 -12
  315. package/src/sdk/bus/session-control.ts +333 -0
  316. package/src/sdk/bus/slack-conversation.ts +74 -0
  317. package/src/sdk/bus/slack-daemon.ts +2144 -0
  318. package/src/sdk/bus/slack-live-provider.ts +380 -0
  319. package/src/sdk/bus/slack-provider.ts +76 -0
  320. package/src/{notifications → sdk/bus}/telegram-cli.ts +8 -8
  321. package/src/sdk/bus/telegram-daemon-cli.ts +330 -0
  322. package/src/sdk/bus/telegram-daemon-contract.ts +14 -0
  323. package/src/{notifications → sdk/bus}/telegram-daemon-control.ts +4 -4
  324. package/src/{notifications → sdk/bus}/telegram-daemon.ts +603 -63
  325. package/src/{notifications → sdk/bus}/telegram-reference.ts +2 -2
  326. package/src/sdk/bus/telegram-setup.ts +663 -0
  327. package/src/{notifications → sdk/bus}/topic-registry.ts +32 -0
  328. package/src/sdk/cli/index.ts +1 -0
  329. package/src/sdk/cli/session-cli.ts +275 -0
  330. package/src/sdk/client/client.ts +1 -0
  331. package/src/sdk/client/discovery.ts +108 -0
  332. package/src/sdk/client/index.ts +2 -0
  333. package/src/sdk/host/control/dispatch.ts +367 -0
  334. package/src/sdk/host/control/index.ts +10 -0
  335. package/src/sdk/host/control/operations.ts +63 -0
  336. package/src/sdk/host/events.ts +91 -0
  337. package/src/sdk/host/host.ts +296 -0
  338. package/src/sdk/host/index.ts +4 -0
  339. package/src/sdk/host/query/cursor.ts +189 -0
  340. package/src/sdk/host/query/handlers.ts +533 -0
  341. package/src/sdk/host/query/index.ts +3 -0
  342. package/src/sdk/host/query/revision-store.ts +1126 -0
  343. package/src/sdk/host/reverse-leases.ts +325 -0
  344. package/src/sdk/host/types.ts +29 -0
  345. package/src/sdk/index.ts +13 -0
  346. package/src/sdk/lifecycle-session.ts +39 -0
  347. package/src/sdk/mcp/index.ts +1 -0
  348. package/src/sdk/mcp/server.ts +332 -0
  349. package/src/sdk/models.ts +168 -0
  350. package/src/sdk/protocol/adapter-validation.ts +48 -0
  351. package/src/sdk/protocol/operation-inventory.generated.json +5654 -0
  352. package/src/sdk/protocol/operation-registry.ts +312 -0
  353. package/src/{sdk.ts → sdk/session.ts} +339 -212
  354. package/src/sdk/startup-capability.ts +189 -0
  355. package/src/session/agent-session.ts +2650 -944
  356. package/src/session/default-model-selection.ts +93 -0
  357. package/src/session/fallback-chain-controller.ts +136 -0
  358. package/src/session/session-manager.ts +438 -11
  359. package/src/session/session-storage.ts +8 -1
  360. package/src/setup/credential-auto-import.ts +290 -35
  361. package/src/setup/hermes/templates/operator-instructions.v1.md +3 -5
  362. package/src/slash-commands/builtin-registry.ts +2 -1
  363. package/src/task/executor.ts +62 -13
  364. package/src/task/index.ts +26 -16
  365. package/src/tools/ask-answer-registry.ts +1 -1
  366. package/src/tools/ask.ts +13 -8
  367. package/src/tools/browser/STEALTH-THIRD-PARTY-NOTICES.md +26 -0
  368. package/src/tools/browser/benchmark/detector-report.ts +157 -0
  369. package/src/tools/browser/benchmark/run-suite.ts +39 -0
  370. package/src/tools/browser/launch.ts +124 -19
  371. package/src/tools/browser/profile-discovery.ts +63 -0
  372. package/src/tools/browser/profile-posture.ts +59 -0
  373. package/src/tools/browser/profile-reuse.ts +102 -0
  374. package/src/tools/browser/profile-warmup.ts +109 -0
  375. package/src/tools/browser/registry.ts +87 -11
  376. package/src/tools/browser/tab-protocol.ts +1 -0
  377. package/src/tools/browser/tab-supervisor.ts +1 -0
  378. package/src/tools/browser/tab-worker.ts +1 -1
  379. package/src/tools/browser.ts +6 -0
  380. package/src/tools/index.ts +8 -8
  381. package/src/tools/puppeteer/14_stealth_permissions.txt +57 -0
  382. package/src/tools/puppeteer/15_stealth_webrtc.txt +60 -0
  383. package/src/tools/subagent-render.ts +19 -8
  384. package/src/tools/subagent.ts +84 -32
  385. package/src/tools/telegram-send.ts +2 -2
  386. package/vendor/insane-search/MANIFEST.json +2 -1
  387. package/vendor/insane-search/engine/bias_check.py +4 -1
  388. package/vendor/insane-search/engine/phase0.py +26 -1
  389. package/dist/types/harness-control-plane/rpc-adapter.d.ts +0 -69
  390. package/dist/types/modes/bridge/auth.d.ts +0 -12
  391. package/dist/types/modes/bridge/bridge-client-bridge.d.ts +0 -9
  392. package/dist/types/modes/bridge/bridge-mode.d.ts +0 -47
  393. package/dist/types/modes/bridge/bridge-ui-context.d.ts +0 -88
  394. package/dist/types/modes/bridge/event-stream.d.ts +0 -8
  395. package/dist/types/modes/rpc/host-tools.d.ts +0 -1
  396. package/dist/types/modes/rpc/host-uris.d.ts +0 -1
  397. package/dist/types/modes/rpc/rpc-client.d.ts +0 -299
  398. package/dist/types/modes/rpc/rpc-mode.d.ts +0 -86
  399. package/dist/types/modes/rpc/rpc-socket-security.d.ts +0 -10
  400. package/dist/types/modes/rpc/rpc-types.d.ts +0 -810
  401. package/dist/types/modes/shared/agent-wire/command-contract.d.ts +0 -18
  402. package/dist/types/modes/shared/agent-wire/command-dispatch.d.ts +0 -37
  403. package/dist/types/modes/shared/agent-wire/command-validation.d.ts +0 -2
  404. package/dist/types/modes/shared/agent-wire/handshake.d.ts +0 -56
  405. package/dist/types/modes/shared/agent-wire/host-tool-bridge.d.ts +0 -16
  406. package/dist/types/modes/shared/agent-wire/host-uri-bridge.d.ts +0 -17
  407. package/dist/types/modes/shared/agent-wire/protocol.d.ts +0 -25
  408. package/dist/types/modes/shared/agent-wire/responses.d.ts +0 -4
  409. package/dist/types/modes/shared/agent-wire/scopes.d.ts +0 -18
  410. package/dist/types/modes/shared/agent-wire/session-registry.d.ts +0 -25
  411. package/dist/types/modes/shared/agent-wire/ui-request-broker.d.ts +0 -42
  412. package/dist/types/modes/shared/agent-wire/ui-result.d.ts +0 -27
  413. package/dist/types/modes/shared/agent-wire/unattended-action-policy.d.ts +0 -29
  414. package/dist/types/modes/shared/agent-wire/unattended-audit.d.ts +0 -68
  415. package/dist/types/modes/shared/agent-wire/unattended-run-controller.d.ts +0 -166
  416. package/dist/types/modes/shared/agent-wire/unattended-session.d.ts +0 -127
  417. package/dist/types/notifications/config.d.ts +0 -132
  418. package/src/harness-control-plane/rpc-adapter.ts +0 -290
  419. package/src/modes/bridge/auth.ts +0 -41
  420. package/src/modes/bridge/bridge-client-bridge.ts +0 -47
  421. package/src/modes/bridge/bridge-mode.ts +0 -675
  422. package/src/modes/bridge/bridge-ui-context.ts +0 -200
  423. package/src/modes/bridge/event-stream.ts +0 -70
  424. package/src/modes/rpc/host-tools.ts +0 -1
  425. package/src/modes/rpc/host-uris.ts +0 -1
  426. package/src/modes/rpc/rpc-client.ts +0 -1166
  427. package/src/modes/rpc/rpc-mode.ts +0 -1029
  428. package/src/modes/rpc/rpc-socket-security.ts +0 -115
  429. package/src/modes/rpc/rpc-types.ts +0 -637
  430. package/src/modes/shared/agent-wire/command-contract.ts +0 -18
  431. package/src/modes/shared/agent-wire/command-dispatch.ts +0 -498
  432. package/src/modes/shared/agent-wire/command-validation.ts +0 -181
  433. package/src/modes/shared/agent-wire/handshake.ts +0 -157
  434. package/src/modes/shared/agent-wire/host-tool-bridge.ts +0 -197
  435. package/src/modes/shared/agent-wire/host-uri-bridge.ts +0 -236
  436. package/src/modes/shared/agent-wire/protocol.ts +0 -46
  437. package/src/modes/shared/agent-wire/responses.ts +0 -17
  438. package/src/modes/shared/agent-wire/scopes.ts +0 -94
  439. package/src/modes/shared/agent-wire/session-registry.ts +0 -109
  440. package/src/modes/shared/agent-wire/ui-request-broker.ts +0 -150
  441. package/src/modes/shared/agent-wire/ui-result.ts +0 -48
  442. package/src/modes/shared/agent-wire/unattended-action-policy.ts +0 -365
  443. package/src/modes/shared/agent-wire/unattended-audit.ts +0 -176
  444. package/src/modes/shared/agent-wire/unattended-run-controller.ts +0 -426
  445. package/src/modes/shared/agent-wire/unattended-session.ts +0 -528
  446. package/src/notifications/config.ts +0 -219
  447. package/src/notifications/index.ts +0 -1835
  448. package/src/notifications/telegram-daemon-cli.ts +0 -243
  449. package/src/tools/puppeteer/09_stealth_locale.txt +0 -46
  450. /package/dist/types/{notifications → sdk/bus}/attachment-registry.d.ts +0 -0
  451. /package/dist/types/{notifications → sdk/bus}/chat-adapters.d.ts +0 -0
  452. /package/dist/types/{notifications → sdk/bus}/daemon-paths.d.ts +0 -0
  453. /package/dist/types/{notifications → sdk/bus}/engine.d.ts +0 -0
  454. /package/dist/types/{notifications → sdk/bus}/helpers.d.ts +0 -0
  455. /package/dist/types/{notifications → sdk/bus}/lifecycle-commands.d.ts +0 -0
  456. /package/dist/types/{notifications → sdk/bus}/operator-runtime.d.ts +0 -0
  457. /package/dist/types/{notifications → sdk/bus}/rate-limit-pool.d.ts +0 -0
  458. /package/dist/types/{notifications → sdk/bus}/recent-activity.d.ts +0 -0
  459. /package/dist/types/{notifications → sdk/bus}/reply-sent-store.d.ts +0 -0
  460. /package/dist/types/{notifications → sdk/bus}/rich-draft.d.ts +0 -0
  461. /package/dist/types/{notifications → sdk/bus}/rich-render.d.ts +0 -0
  462. /package/dist/types/{notifications → sdk/bus}/threaded-inbound.d.ts +0 -0
  463. /package/dist/types/{notifications → sdk/bus}/threaded-render.d.ts +0 -0
  464. /package/src/{notifications → sdk/bus}/attachment-registry.ts +0 -0
  465. /package/src/{notifications → sdk/bus}/chat-adapters.ts +0 -0
  466. /package/src/{notifications → sdk/bus}/daemon-paths.ts +0 -0
  467. /package/src/{notifications → sdk/bus}/engine.ts +0 -0
  468. /package/src/{notifications → sdk/bus}/helpers.ts +0 -0
  469. /package/src/{notifications → sdk/bus}/operator-runtime.ts +0 -0
  470. /package/src/{notifications → sdk/bus}/rate-limit-pool.ts +0 -0
  471. /package/src/{notifications → sdk/bus}/recent-activity.ts +0 -0
  472. /package/src/{notifications → sdk/bus}/reply-sent-store.ts +0 -0
  473. /package/src/{notifications → sdk/bus}/rich-draft.ts +0 -0
  474. /package/src/{notifications → sdk/bus}/rich-render.ts +0 -0
  475. /package/src/{notifications → sdk/bus}/threaded-inbound.ts +0 -0
  476. /package/src/{notifications → sdk/bus}/threaded-render.ts +0 -0
@@ -12,19 +12,30 @@ import {
12
12
  GJC_MODEL_ASSIGNMENT_TARGETS,
13
13
  type GjcModelAssignmentTargetId,
14
14
  isAuthenticated,
15
+ kNoAuth,
15
16
  type ModelRegistry,
16
17
  } from "./model-registry";
17
- import { formatModelSelectorValue, resolveModelRoleValue } from "./model-resolver";
18
+ import {
19
+ formatModelSelectorValue,
20
+ parseModelString,
21
+ resolveModelChainWithAuth,
22
+ resolveModelRoleValue,
23
+ } from "./model-resolver";
24
+ import { type ModelSelectorValue, normalizeModelSelectorValue } from "./model-selector-value";
18
25
  import type { Settings } from "./settings";
19
26
 
20
27
  const LEGACY_MODEL_PROFILE_ALIASES: ReadonlyMap<string, string> = new Map([["codex-standard", "codex-medium"]]);
21
28
 
22
- type ModelProfileActivationSession = Pick<AgentSession, "model" | "thinkingLevel" | "sessionId"> & {
29
+ type ModelProfileActivationSession = Pick<
30
+ AgentSession,
31
+ "model" | "thinkingLevel" | "sessionId" | "getConfiguredModelChain" | "setConfiguredModelChain"
32
+ > & {
23
33
  setModelTemporary?: AgentSession["setModelTemporary"];
24
34
  setActiveModelProfile?: (name: string | undefined) => void;
25
35
  getActiveModelProfile?: () => string | undefined;
26
36
  getSessionDefaultModelSelector?: () => string | undefined;
27
37
  recordResumeDefaultModel?: (selector: string) => void;
38
+ seedDefaultFallbackResolution?: (activeIndex: number, skips: Array<{ selector: string; reason: string }>) => void;
28
39
  };
29
40
 
30
41
  export interface PrepareModelProfileActivationOptions {
@@ -50,15 +61,22 @@ export interface ApplyModelProfileActivationOptions {
50
61
  export interface PreparedModelProfileActivation {
51
62
  profileName: string;
52
63
  session: ModelProfileActivationSession & { setModelTemporary: AgentSession["setModelTemporary"] };
53
- settings: Pick<Settings, "clearOverride" | "get" | "getGlobal" | "override" | "set" | "flush">;
64
+ settings: Pick<Settings, "clearOverride" | "get" | "getGlobal" | "override" | "set" | "unset" | "flush">;
54
65
  previousModel: Model<Api> | undefined;
55
66
  previousThinkingLevel: ThinkingLevel | undefined;
56
- previousAgentModelOverrides: Record<string, string>;
57
- previousModelRoles: Record<string, string>;
67
+ previousAgentModelOverrides: Record<string, ModelSelectorValue>;
68
+ previousModelRoles: Record<string, ModelSelectorValue>;
69
+ previousDefaultChain: readonly string[] | undefined;
58
70
  defaultModel: Model<Api> | undefined;
59
71
  defaultThinkingLevel: ThinkingLevel | undefined;
60
- modelRoles: Record<string, string>;
61
- agentModelOverrides: Record<string, string>;
72
+ /** Full configured default fallback chain with resolvable entries clamped. */
73
+ defaultChain: readonly string[];
74
+ /** Index of the authenticated default-chain entry selected for activation. */
75
+ defaultActiveIndex: number | undefined;
76
+ /** Resolution-time skips that occurred before selecting the default entry. */
77
+ defaultResolutionSkips: Array<{ selector: string; reason: string }>;
78
+ modelRoles: Record<string, ModelSelectorValue>;
79
+ agentModelOverrides: Record<string, ModelSelectorValue>;
62
80
  previousActiveModelProfile: string | undefined;
63
81
  /**
64
82
  * The session resume default ("provider/id") captured BEFORE activation —
@@ -72,9 +90,9 @@ export interface PreparedModelProfileActivation {
72
90
  export interface MaterializeModelProfileAssignmentOptions {
73
91
  session: Pick<
74
92
  ModelProfileActivationSession,
75
- "model" | "thinkingLevel" | "setActiveModelProfile" | "getActiveModelProfile"
93
+ "model" | "thinkingLevel" | "getConfiguredModelChain" | "setActiveModelProfile" | "getActiveModelProfile"
76
94
  >;
77
- settings: Pick<Settings, "clearOverride" | "get" | "override" | "set">;
95
+ settings: Pick<Settings, "clearOverride" | "get" | "override" | "set" | "unset">;
78
96
  role: GjcModelAssignmentTargetId;
79
97
  selector: string;
80
98
  }
@@ -82,9 +100,9 @@ export interface MaterializeModelProfileAssignmentOptions {
82
100
  export interface MaterializeModelProfileAssignmentsOptions {
83
101
  session: Pick<
84
102
  ModelProfileActivationSession,
85
- "model" | "thinkingLevel" | "setActiveModelProfile" | "getActiveModelProfile"
103
+ "model" | "thinkingLevel" | "getConfiguredModelChain" | "setActiveModelProfile" | "getActiveModelProfile"
86
104
  >;
87
- settings: Pick<Settings, "clearOverride" | "get" | "override" | "set">;
105
+ settings: Pick<Settings, "clearOverride" | "get" | "override" | "set" | "unset">;
88
106
  assignments: ReadonlyMap<GjcModelAssignmentTargetId, string> | Partial<Record<GjcModelAssignmentTargetId, string>>;
89
107
  }
90
108
 
@@ -107,6 +125,35 @@ function getMaterializedAssignments(
107
125
  return result;
108
126
  }
109
127
 
128
+ function materializeConfiguredDefaultChain(
129
+ session: Pick<ModelProfileActivationSession, "model" | "thinkingLevel" | "getConfiguredModelChain">,
130
+ ): ModelSelectorValue | undefined {
131
+ const configuredChain = session.getConfiguredModelChain("default") ?? [];
132
+ if (!session.model) {
133
+ return configuredChain.length === 0
134
+ ? undefined
135
+ : configuredChain.length === 1
136
+ ? configuredChain[0]
137
+ : [...configuredChain];
138
+ }
139
+
140
+ const activeSelector = formatModelSelectorValue(
141
+ `${session.model.provider}/${session.model.id}`,
142
+ session.thinkingLevel,
143
+ );
144
+ const exactIndex = configuredChain.indexOf(activeSelector);
145
+ const activeIndex =
146
+ exactIndex !== -1
147
+ ? exactIndex
148
+ : configuredChain.findIndex(entry => {
149
+ const parsed = parseModelString(entry);
150
+ return parsed?.provider === session.model?.provider && parsed?.id === session.model?.id;
151
+ });
152
+ const effectiveChain =
153
+ activeIndex === -1 ? [activeSelector] : [activeSelector, ...configuredChain.slice(activeIndex + 1)];
154
+ return effectiveChain.length === 1 ? effectiveChain[0] : effectiveChain;
155
+ }
156
+
110
157
  export function materializeActiveModelProfileAssignment(options: MaterializeModelProfileAssignmentOptions): boolean {
111
158
  const activeProfile = options.session.getActiveModelProfile?.() ?? options.settings.get("modelProfile.default");
112
159
  if (!activeProfile) return false;
@@ -117,11 +164,9 @@ export function materializeActiveModelProfileAssignment(options: MaterializeMode
117
164
 
118
165
  if (options.role === "default") {
119
166
  nextModelRoles.default = options.selector;
120
- } else if (!nextModelRoles.default && options.session.model) {
121
- nextModelRoles.default = formatModelSelectorValue(
122
- `${options.session.model.provider}/${options.session.model.id}`,
123
- options.session.thinkingLevel,
124
- );
167
+ } else if (!nextModelRoles.default) {
168
+ const defaultChain = materializeConfiguredDefaultChain(options.session);
169
+ if (defaultChain) nextModelRoles.default = defaultChain;
125
170
  }
126
171
 
127
172
  if (target.settingsPath === "modelRoles") {
@@ -132,7 +177,7 @@ export function materializeActiveModelProfileAssignment(options: MaterializeMode
132
177
 
133
178
  options.settings.set("modelRoles", nextModelRoles);
134
179
  options.settings.set("task.agentModelOverrides", nextAgentModelOverrides);
135
- options.settings.set("modelProfile.default", undefined);
180
+ options.settings.unset("modelProfile.default");
136
181
  options.settings.clearOverride("modelProfile.default");
137
182
  options.settings.override("modelRoles", nextModelRoles);
138
183
  options.settings.override("task.agentModelOverrides", nextAgentModelOverrides);
@@ -151,11 +196,9 @@ export function materializeActiveModelProfileAssignments(options: MaterializeMod
151
196
  const nextAgentModelOverrides = { ...options.settings.get("task.agentModelOverrides") };
152
197
  const includesDefault = materializedAssignments.some(([role]) => role === "default");
153
198
 
154
- if (!includesDefault && !nextModelRoles.default && options.session.model) {
155
- nextModelRoles.default = formatModelSelectorValue(
156
- `${options.session.model.provider}/${options.session.model.id}`,
157
- options.session.thinkingLevel,
158
- );
199
+ if (!includesDefault && !nextModelRoles.default) {
200
+ const defaultChain = materializeConfiguredDefaultChain(options.session);
201
+ if (defaultChain) nextModelRoles.default = defaultChain;
159
202
  }
160
203
 
161
204
  for (const [role, selector] of materializedAssignments) {
@@ -169,7 +212,7 @@ export function materializeActiveModelProfileAssignments(options: MaterializeMod
169
212
 
170
213
  options.settings.set("modelRoles", nextModelRoles);
171
214
  options.settings.set("task.agentModelOverrides", nextAgentModelOverrides);
172
- options.settings.set("modelProfile.default", undefined);
215
+ options.settings.unset("modelProfile.default");
173
216
  options.settings.clearOverride("modelProfile.default");
174
217
  options.settings.override("modelRoles", nextModelRoles);
175
218
  options.settings.override("task.agentModelOverrides", nextAgentModelOverrides);
@@ -177,6 +220,18 @@ export function materializeActiveModelProfileAssignments(options: MaterializeMod
177
220
  return true;
178
221
  }
179
222
 
223
+ export class ModelProfileCredentialError extends Error {
224
+ readonly profileLabel: string;
225
+ readonly providers: readonly string[];
226
+
227
+ constructor(profileLabel: string, providers: readonly string[]) {
228
+ super(formatModelProfileCredentialError(profileLabel, providers));
229
+ this.name = "ModelProfileCredentialError";
230
+ this.profileLabel = profileLabel;
231
+ this.providers = [...providers];
232
+ }
233
+ }
234
+
180
235
  export function formatModelProfileCredentialError(profileLabel: string, providers: readonly string[]): string {
181
236
  return `Model profile "${profileLabel}" requires credentials for: ${providers.join(", ")}. Run /login and configure the missing provider(s), then retry.`;
182
237
  }
@@ -214,34 +269,81 @@ function rewriteSelectorProvider(
214
269
  return replacement + selector.substring(slash);
215
270
  }
216
271
 
272
+ function rewriteSelectorValueProvider(
273
+ selectorValue: ModelSelectorValue,
274
+ authenticatedProviders: ReadonlySet<string>,
275
+ alternativeGroups: readonly (readonly string[])[],
276
+ ): ModelSelectorValue {
277
+ const selectors = normalizeModelSelectorValue(selectorValue).map(selector =>
278
+ rewriteSelectorProvider(selector, authenticatedProviders, alternativeGroups),
279
+ );
280
+ return selectors.length === 1 && typeof selectorValue === "string" ? selectors[0] : selectors;
281
+ }
282
+
217
283
  function rewriteBindingsProviders(
218
284
  bindings: {
219
- defaultSelector?: string;
220
- modelRoles: Record<string, string>;
221
- agentModelOverrides: Record<string, string>;
285
+ defaultSelector?: ModelSelectorValue;
286
+ modelRoles: Record<string, ModelSelectorValue>;
287
+ agentModelOverrides: Record<string, ModelSelectorValue>;
222
288
  },
223
289
  authenticatedProviders: ReadonlySet<string>,
224
290
  alternativeGroups: readonly (readonly string[])[],
225
- ): { defaultSelector?: string; modelRoles: Record<string, string>; agentModelOverrides: Record<string, string> } {
291
+ ): {
292
+ defaultSelector?: ModelSelectorValue;
293
+ modelRoles: Record<string, ModelSelectorValue>;
294
+ agentModelOverrides: Record<string, ModelSelectorValue>;
295
+ } {
226
296
  return {
227
297
  defaultSelector: bindings.defaultSelector
228
- ? rewriteSelectorProvider(bindings.defaultSelector, authenticatedProviders, alternativeGroups)
298
+ ? rewriteSelectorValueProvider(bindings.defaultSelector, authenticatedProviders, alternativeGroups)
229
299
  : undefined,
230
300
  modelRoles: Object.fromEntries(
231
- Object.entries(bindings.modelRoles).map(([role, sel]) => [
301
+ Object.entries(bindings.modelRoles).map(([role, selector]) => [
232
302
  role,
233
- rewriteSelectorProvider(sel, authenticatedProviders, alternativeGroups),
303
+ rewriteSelectorValueProvider(selector, authenticatedProviders, alternativeGroups),
234
304
  ]),
235
305
  ),
236
306
  agentModelOverrides: Object.fromEntries(
237
- Object.entries(bindings.agentModelOverrides).map(([role, sel]) => [
307
+ Object.entries(bindings.agentModelOverrides).map(([role, selector]) => [
238
308
  role,
239
- rewriteSelectorProvider(sel, authenticatedProviders, alternativeGroups),
309
+ rewriteSelectorValueProvider(selector, authenticatedProviders, alternativeGroups),
240
310
  ]),
241
311
  ),
242
312
  };
243
313
  }
244
314
 
315
+ function formatMaterializedSelector(selector: string, model: Model<Api>): string {
316
+ const clampedSelector = formatClampedModelSelector(selector, model);
317
+ const explicitThinkingLevel = parseModelString(selector)?.thinkingLevel;
318
+ if (!explicitThinkingLevel || parseModelString(clampedSelector)?.thinkingLevel) return clampedSelector;
319
+ return formatModelSelectorValue(clampedSelector, explicitThinkingLevel);
320
+ }
321
+
322
+ function resolveAndClampSelectorValue(
323
+ selectorValue: ModelSelectorValue,
324
+ availableModels: Model<Api>[],
325
+ options: { settings: Settings; modelRegistry: ModelRegistry },
326
+ profileLabel: string,
327
+ role: string,
328
+ ): ModelSelectorValue {
329
+ const selectors = normalizeModelSelectorValue(selectorValue);
330
+ const clamped: string[] = [];
331
+ let resolvedAny = false;
332
+ for (const selector of selectors) {
333
+ const resolved = resolveModelRoleValue(selector, availableModels, options);
334
+ if (resolved.model) {
335
+ clamped.push(formatMaterializedSelector(selector, resolved.model));
336
+ resolvedAny = true;
337
+ } else {
338
+ clamped.push(selector);
339
+ }
340
+ }
341
+ if (!resolvedAny && role === "default") {
342
+ throw new Error(`Model profile "${profileLabel}" ${role} selector did not resolve: ${selectors[0]}`);
343
+ }
344
+ return clamped.length === 1 && typeof selectorValue === "string" ? clamped[0] : clamped;
345
+ }
346
+
245
347
  export async function prepareModelProfileActivation(
246
348
  options: PrepareModelProfileActivationOptions,
247
349
  ): Promise<PreparedModelProfileActivation> {
@@ -254,79 +356,98 @@ export async function prepareModelProfileActivation(
254
356
  }
255
357
  const profileLabel = formatModelProfileDisplayLabel(profile);
256
358
 
257
- const allProviders = aggregateModelProfileRequiredProviders(profile.requiredProviders, profile);
359
+ const requiredProviders = aggregateModelProfileRequiredProviders(profile.requiredProviders, profile);
258
360
  const alternativeGroups = profile.alternativeProviderGroups ?? [];
259
361
  const alternativeSet = new Set(alternativeGroups.flat());
260
362
 
261
363
  const missingProviders: string[] = [];
262
364
  const authenticatedProviders: string[] = [];
263
- for (const provider of allProviders) {
365
+ for (const provider of requiredProviders) {
264
366
  const apiKey = await options.modelRegistry.getApiKeyForProvider(provider, options.session.sessionId);
265
- if (!isAuthenticated(apiKey)) {
367
+ if (apiKey !== kNoAuth && !isAuthenticated(apiKey)) {
266
368
  missingProviders.push(provider);
267
369
  } else {
268
370
  authenticatedProviders.push(provider);
269
371
  }
270
372
  }
271
373
 
272
- // Check strict (non-alternative) providers — all must be authenticated.
273
- const strictMissing = missingProviders.filter(p => !alternativeSet.has(p));
374
+ // Required providers are the only activation prerequisites. Mapped fallback
375
+ // providers are resolution-time candidates and intentionally do not gate here.
376
+ const strictMissing = missingProviders.filter(provider => !alternativeSet.has(provider));
274
377
  if (strictMissing.length > 0) {
275
- throw new Error(formatModelProfileCredentialError(profileLabel, strictMissing));
378
+ throw new ModelProfileCredentialError(profileLabel, strictMissing);
276
379
  }
277
-
278
- // Check alternative groups — at least one provider per group must be authenticated.
279
380
  for (const group of alternativeGroups) {
280
- const groupAuthenticated = group.some(p => authenticatedProviders.includes(p));
381
+ const groupAuthenticated = group.some(provider => authenticatedProviders.includes(provider));
281
382
  if (!groupAuthenticated) {
282
- throw new Error(formatModelProfileCredentialError(profileLabel, [...group]));
383
+ throw new ModelProfileCredentialError(profileLabel, [...group]);
283
384
  }
284
385
  }
285
386
 
286
- if (authenticatedProviders.length === 0) {
287
- throw new Error(formatModelProfileCredentialError(profileLabel, missingProviders));
288
- }
289
-
290
387
  const availableModels = options.modelRegistry.getAll();
291
388
  let bindings = resolveProfileBindings(profile);
292
389
  if (missingProviders.length > 0 && alternativeGroups.length > 0) {
293
390
  bindings = rewriteBindingsProviders(bindings, new Set(authenticatedProviders), alternativeGroups);
294
391
  }
295
- const resolvedDefault = bindings.defaultSelector
296
- ? resolveModelRoleValue(bindings.defaultSelector, availableModels, {
297
- settings: options.settings as Settings,
298
- modelRegistry: options.modelRegistry,
299
- })
300
- : undefined;
301
- if (bindings.defaultSelector && !resolvedDefault?.model) {
302
- throw new Error(`Model profile "${profileLabel}" default selector did not resolve: ${bindings.defaultSelector}`);
392
+ const defaultSelectors = bindings.defaultSelector ? normalizeModelSelectorValue(bindings.defaultSelector) : [];
393
+ const defaultChain =
394
+ defaultSelectors.length > 0
395
+ ? normalizeModelSelectorValue(
396
+ resolveAndClampSelectorValue(
397
+ bindings.defaultSelector!,
398
+ availableModels,
399
+ { settings: options.settings as Settings, modelRegistry: options.modelRegistry as ModelRegistry },
400
+ profileLabel,
401
+ "default",
402
+ ),
403
+ )
404
+ : [];
405
+ const defaultResolution = await resolveModelChainWithAuth(
406
+ defaultChain,
407
+ {
408
+ ...options.modelRegistry,
409
+ getAvailable: () => availableModels,
410
+ getApiKey: (model, sessionId) =>
411
+ options.modelRegistry.getApiKeyForProvider(model.provider, sessionId, model.baseUrl),
412
+ } as ModelRegistry,
413
+ options.settings as Settings,
414
+ options.session.sessionId,
415
+ { managedFallback: true },
416
+ );
417
+ const defaultModel = defaultResolution.model;
418
+ const defaultThinkingLevel = defaultResolution.thinkingLevel;
419
+ const defaultActiveIndex = defaultModel ? defaultResolution.activeIndex : undefined;
420
+ const defaultResolutionSkips = defaultResolution.skips;
421
+ if (bindings.defaultSelector && !defaultModel) {
422
+ throw new Error(`Model profile "${profileLabel}" default selectors did not resolve to an authenticated model`);
303
423
  }
304
424
 
305
- const modelRoles: Record<string, string> = {};
306
- for (const [role, selector] of Object.entries(bindings.modelRoles) as [GjcModelAssignmentTargetId, string][]) {
307
- const resolved = resolveModelRoleValue(selector, availableModels, {
308
- settings: options.settings as Settings,
309
- modelRegistry: options.modelRegistry,
310
- });
311
- if (!resolved.model) {
312
- throw new Error(`Model profile "${profileLabel}" ${role} selector did not resolve: ${selector}`);
313
- }
314
- modelRoles[role] = formatClampedModelSelector(selector, resolved.model);
425
+ const modelRoles: Record<string, ModelSelectorValue> = {};
426
+ for (const [role, selectorValue] of Object.entries(bindings.modelRoles) as [
427
+ GjcModelAssignmentTargetId,
428
+ ModelSelectorValue,
429
+ ][]) {
430
+ modelRoles[role] = resolveAndClampSelectorValue(
431
+ selectorValue,
432
+ availableModels,
433
+ { settings: options.settings as Settings, modelRegistry: options.modelRegistry as ModelRegistry },
434
+ profileLabel,
435
+ role,
436
+ );
315
437
  }
316
438
 
317
- const agentModelOverrides: Record<string, string> = {};
318
- for (const [role, selector] of Object.entries(bindings.agentModelOverrides) as [
439
+ const agentModelOverrides: Record<string, ModelSelectorValue> = {};
440
+ for (const [role, selectorValue] of Object.entries(bindings.agentModelOverrides) as [
319
441
  GjcModelAssignmentTargetId,
320
- string,
442
+ ModelSelectorValue,
321
443
  ][]) {
322
- const resolved = resolveModelRoleValue(selector, availableModels, {
323
- settings: options.settings as Settings,
324
- modelRegistry: options.modelRegistry,
325
- });
326
- if (!resolved.model) {
327
- throw new Error(`Model profile "${profileLabel}" ${role} selector did not resolve: ${selector}`);
328
- }
329
- agentModelOverrides[role] = formatClampedModelSelector(selector, resolved.model);
444
+ agentModelOverrides[role] = resolveAndClampSelectorValue(
445
+ selectorValue,
446
+ availableModels,
447
+ { settings: options.settings as Settings, modelRegistry: options.modelRegistry as ModelRegistry },
448
+ profileLabel,
449
+ role,
450
+ );
330
451
  }
331
452
 
332
453
  return {
@@ -337,8 +458,13 @@ export async function prepareModelProfileActivation(
337
458
  previousThinkingLevel: options.session.thinkingLevel,
338
459
  previousAgentModelOverrides: { ...options.settings.get("task.agentModelOverrides") },
339
460
  previousModelRoles: { ...options.settings.get("modelRoles") },
340
- defaultModel: resolvedDefault?.model,
341
- defaultThinkingLevel: resolvedDefault?.thinkingLevel,
461
+ previousDefaultChain: options.session.getConfiguredModelChain("default"),
462
+
463
+ defaultModel,
464
+ defaultThinkingLevel,
465
+ defaultActiveIndex,
466
+ defaultResolutionSkips,
467
+ defaultChain,
342
468
  modelRoles,
343
469
  agentModelOverrides,
344
470
  previousActiveModelProfile: options.session.getActiveModelProfile?.(),
@@ -363,14 +489,33 @@ export async function applyPreparedModelProfileActivation(
363
489
  let defaultChanged = false;
364
490
  let modelRolesChanged = false;
365
491
  let defaultThinkingChanged = false;
492
+ let defaultChainChanged = false;
366
493
 
367
494
  try {
495
+ if (prepared.defaultChain.length > 0) {
496
+ prepared.session.setConfiguredModelChain(
497
+ "default",
498
+ prepared.defaultChain,
499
+ "profile-activation",
500
+ prepared.profileName,
501
+ true,
502
+ );
503
+ if (prepared.defaultActiveIndex !== undefined) {
504
+ prepared.session.seedDefaultFallbackResolution?.(
505
+ prepared.defaultActiveIndex,
506
+ prepared.defaultResolutionSkips,
507
+ );
508
+ }
509
+
510
+ defaultChainChanged = true;
511
+ }
368
512
  if (prepared.defaultModel) {
369
513
  await prepared.session.setModelTemporary(
370
514
  prepared.defaultModel,
371
515
  options.thinkingLevelOverride ?? prepared.defaultThinkingLevel,
372
516
  {
373
517
  persistAsSessionDefault: true,
518
+ cause: "profile-activation",
374
519
  },
375
520
  );
376
521
  modelChanged = true;
@@ -413,6 +558,15 @@ export async function applyPreparedModelProfileActivation(
413
558
  if (overridesChanged) {
414
559
  prepared.settings.override("task.agentModelOverrides", previousAgentModelOverrides);
415
560
  }
561
+ if (defaultChainChanged) {
562
+ prepared.session.setConfiguredModelChain(
563
+ "default",
564
+ prepared.previousDefaultChain ?? [],
565
+ "rollback",
566
+ prepared.previousActiveModelProfile,
567
+ true,
568
+ );
569
+ }
416
570
  prepared.session.setActiveModelProfile?.(previousActiveModelProfile);
417
571
  if (modelChanged) {
418
572
  // Runtime rolls back to the pre-activation live model. That model may
@@ -420,7 +574,7 @@ export async function applyPreparedModelProfileActivation(
420
574
  // so it is recorded as role:"temporary" (NOT the resume default) to
421
575
  // preserve the issue #849 protection.
422
576
  if (previousModel) {
423
- await prepared.session.setModelTemporary(previousModel, previousThinkingLevel);
577
+ await prepared.session.setModelTemporary(previousModel, previousThinkingLevel, { cause: "rollback" });
424
578
  }
425
579
  // The happy path already appended the profile main model as the resume
426
580
  // default (role:"default"). Re-assert the pre-activation resume default
@@ -439,10 +593,10 @@ export async function applyPreparedModelProfileActivation(
439
593
  }
440
594
 
441
595
  export interface MaterializeModelProfileForDeletionResult {
442
- modelRoles: Record<string, string>;
443
- agentModelOverrides: Record<string, string>;
444
- previousModelRoles: Record<string, string>;
445
- previousAgentModelOverrides: Record<string, string>;
596
+ modelRoles: Record<string, ModelSelectorValue>;
597
+ agentModelOverrides: Record<string, ModelSelectorValue>;
598
+ previousModelRoles: Record<string, ModelSelectorValue>;
599
+ previousAgentModelOverrides: Record<string, ModelSelectorValue>;
446
600
  previousDefaultProfile: string | undefined;
447
601
  previousPersistedDefaultProfile: string | undefined;
448
602
  previousActiveModelProfile: string | undefined;
@@ -450,7 +604,7 @@ export interface MaterializeModelProfileForDeletionResult {
450
604
 
451
605
  export async function materializeModelProfileForDeletion(
452
606
  options: PrepareModelProfileActivationOptions & {
453
- settings: Pick<Settings, "clearOverride" | "flush" | "get" | "getGlobal" | "override" | "set">;
607
+ settings: Pick<Settings, "clearOverride" | "flush" | "get" | "getGlobal" | "override" | "set" | "unset">;
454
608
  },
455
609
  ): Promise<MaterializeModelProfileForDeletionResult> {
456
610
  const prepared = await prepareModelProfileActivation(options);
@@ -458,12 +612,9 @@ export async function materializeModelProfileForDeletion(
458
612
  const previousPersistedDefaultProfile = prepared.settings.getGlobal("modelProfile.default");
459
613
  const nextModelRoles = {
460
614
  ...prepared.previousModelRoles,
461
- ...(prepared.defaultModel
615
+ ...(prepared.defaultChain.length > 0
462
616
  ? {
463
- default: formatModelSelectorValue(
464
- `${prepared.defaultModel.provider}/${prepared.defaultModel.id}`,
465
- prepared.defaultThinkingLevel,
466
- ),
617
+ default: prepared.defaultChain.length === 1 ? prepared.defaultChain[0] : [...prepared.defaultChain],
467
618
  }
468
619
  : {}),
469
620
  ...prepared.modelRoles,
@@ -476,7 +627,7 @@ export async function materializeModelProfileForDeletion(
476
627
  try {
477
628
  prepared.settings.set("modelRoles", nextModelRoles);
478
629
  prepared.settings.set("task.agentModelOverrides", nextAgentModelOverrides);
479
- prepared.settings.set("modelProfile.default", undefined);
630
+ prepared.settings.unset("modelProfile.default");
480
631
  prepared.settings.clearOverride("modelProfile.default");
481
632
  prepared.settings.override("modelRoles", nextModelRoles);
482
633
  prepared.settings.override("task.agentModelOverrides", nextAgentModelOverrides);
@@ -1,5 +1,6 @@
1
1
  import { sanitizeText } from "@gajae-code/utils";
2
2
  import type { GjcModelAssignmentTargetId } from "./model-registry";
3
+ import { type ModelSelectorValue, normalizeModelSelectorValue } from "./model-selector-value";
3
4
  import type { ModelsConfig } from "./models-config-schema";
4
5
 
5
6
  export type ModelProfileRole = GjcModelAssignmentTargetId;
@@ -18,14 +19,14 @@ export interface ModelProfileDefinition {
18
19
  * means any single xiaomi credential satisfies the group.
19
20
  */
20
21
  alternativeProviderGroups?: readonly (readonly string[])[];
21
- modelMapping: Partial<Record<ModelProfileRole, string>>;
22
+ modelMapping: Partial<Record<ModelProfileRole, ModelSelectorValue>>;
22
23
  source: "builtin" | "user";
23
24
  }
24
25
 
25
26
  export interface ResolvedProfileBinding {
26
- defaultSelector?: string;
27
- modelRoles: Record<string, string>;
28
- agentModelOverrides: Partial<Record<Exclude<ModelProfileRole, "default">, string>>;
27
+ defaultSelector?: ModelSelectorValue;
28
+ modelRoles: Record<string, ModelSelectorValue>;
29
+ agentModelOverrides: Partial<Record<Exclude<ModelProfileRole, "default">, ModelSelectorValue>>;
29
30
  }
30
31
 
31
32
  function parseModelSelectorProvider(selector: string): string | undefined {
@@ -36,29 +37,31 @@ function parseModelSelectorProvider(selector: string): string | undefined {
36
37
 
37
38
  export function deriveModelProfileMappedProviders(definition: Pick<ModelProfileDefinition, "modelMapping">): string[] {
38
39
  const providers = new Set<string>();
39
- for (const selector of Object.values(definition.modelMapping)) {
40
- if (!selector) continue;
41
- const provider = parseModelSelectorProvider(selector);
42
- if (provider) providers.add(provider);
40
+ for (const selectorValue of Object.values(definition.modelMapping)) {
41
+ for (const selector of normalizeModelSelectorValue(selectorValue)) {
42
+ const provider = parseModelSelectorProvider(selector);
43
+ if (provider) providers.add(provider);
44
+ }
43
45
  }
44
46
  return [...providers].sort((a, b) => a.localeCompare(b));
45
47
  }
46
48
 
49
+ /**
50
+ * Return the providers explicitly declared as hard prerequisites.
51
+ * Model mappings may reference fallback providers, but those references are
52
+ * resolution-time candidates rather than activation requirements.
53
+ */
47
54
  export function aggregateModelProfileRequiredProviders(
48
55
  requiredProviders: readonly string[],
49
- definition: Pick<ModelProfileDefinition, "modelMapping">,
56
+ _definition: Pick<ModelProfileDefinition, "modelMapping">,
50
57
  ): string[] {
51
- const providers = new Set(requiredProviders);
52
- for (const provider of deriveModelProfileMappedProviders(definition)) {
53
- providers.add(provider);
54
- }
55
- return [...providers];
58
+ return [...new Set(requiredProviders)];
56
59
  }
57
60
 
58
61
  const profile = (
59
62
  name: string,
60
63
  requiredProviders: string[],
61
- modelMapping: Partial<Record<ModelProfileRole, string>>,
64
+ modelMapping: Partial<Record<ModelProfileRole, ModelSelectorValue>>,
62
65
  alternativeProviderGroups?: readonly (readonly string[])[],
63
66
  ): ModelProfileDefinition => ({
64
67
  name,