@gajae-code/coding-agent 0.14.2 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (345) hide show
  1. package/CHANGELOG.md +120 -1
  2. package/dist/types/async/job-manager.d.ts +4 -1
  3. package/dist/types/autoresearch/dashboard.d.ts +29 -4
  4. package/dist/types/autoresearch/data-context.d.ts +25 -0
  5. package/dist/types/autoresearch/git.d.ts +65 -7
  6. package/dist/types/autoresearch/harness.d.ts +58 -0
  7. package/dist/types/autoresearch/prompts.d.ts +51 -0
  8. package/dist/types/autoresearch/runs.d.ts +173 -0
  9. package/dist/types/autoresearch/types.d.ts +9 -139
  10. package/dist/types/capability/types.d.ts +20 -0
  11. package/dist/types/cli/accounts-cli.d.ts +1 -0
  12. package/dist/types/commands/{rlm.d.ts → autoresearch.d.ts} +2 -4
  13. package/dist/types/config/autorouting-contract.d.ts +146 -0
  14. package/dist/types/config/autorouting-generator.d.ts +40 -0
  15. package/dist/types/config/autorouting-tier-map.d.ts +16844 -0
  16. package/dist/types/config/autorouting.d.ts +35 -0
  17. package/dist/types/config/model-discovery-manager.d.ts +8 -1
  18. package/dist/types/config/model-registry.d.ts +30 -1
  19. package/dist/types/config/provider-selection-policy.d.ts +23 -0
  20. package/dist/types/config/settings-schema.d.ts +61 -3
  21. package/dist/types/config/settings.d.ts +3 -0
  22. package/dist/types/coordinator/contract.d.ts +1 -1
  23. package/dist/types/coordinator-mcp/durability.d.ts +29 -0
  24. package/dist/types/coordinator-mcp/event-webhook.d.ts +50 -0
  25. package/dist/types/coordinator-mcp/question-state.d.ts +1 -1
  26. package/dist/types/coordinator-mcp/server.d.ts +14 -0
  27. package/dist/types/crash/index-store.d.ts +3 -0
  28. package/dist/types/crash/record-loader.d.ts +2 -0
  29. package/dist/types/crash/upstream/relay.d.ts +5 -3
  30. package/dist/types/cursor.d.ts +12 -0
  31. package/dist/types/defaults/gjc-defaults.d.ts +35 -1
  32. package/dist/types/defaults/gjc-skills.generated.d.ts +1 -1
  33. package/dist/types/discovery/helpers.d.ts +1 -1
  34. package/dist/types/edit/index.d.ts +2 -1
  35. package/dist/types/eval/py/executor.d.ts +2 -0
  36. package/dist/types/extensibility/extensions/loader.d.ts +32 -0
  37. package/dist/types/extensibility/gjc-plugins/types.d.ts +1 -1
  38. package/dist/types/extensibility/skills.d.ts +2 -0
  39. package/dist/types/gjc-runtime/autoresearch-runtime.d.ts +194 -0
  40. package/dist/types/gjc-runtime/gc-runtime.d.ts +1 -1
  41. package/dist/types/gjc-runtime/psmux-detect.d.ts +1 -1
  42. package/dist/types/gjc-runtime/python-transcript.d.ts +19 -0
  43. package/dist/types/gjc-runtime/ralplan-runtime.d.ts +2 -8
  44. package/dist/types/gjc-runtime/session-layout.d.ts +6 -3
  45. package/dist/types/gjc-runtime/state-renderer.d.ts +0 -22
  46. package/dist/types/gjc-runtime/state-schema.d.ts +7 -7
  47. package/dist/types/gjc-runtime/tmux-common.d.ts +2 -2
  48. package/dist/types/gjc-runtime/ultragoal-change-set.d.ts +38 -1
  49. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +2 -24
  50. package/dist/types/gjc-runtime/ultragoal-validation-policy.d.ts +73 -0
  51. package/dist/types/gjc-runtime/workflow-recovery-projection.d.ts +100 -0
  52. package/dist/types/hooks/skill-keywords.d.ts +1 -1
  53. package/dist/types/main.d.ts +0 -10
  54. package/dist/types/modes/acp/acp-agent.d.ts +13 -6
  55. package/dist/types/modes/components/model-selector.d.ts +14 -0
  56. package/dist/types/modes/components/skill-hud/render.d.ts +6 -1
  57. package/dist/types/modes/components/smart-routing-panel.d.ts +82 -0
  58. package/dist/types/modes/controllers/selector-controller.d.ts +14 -0
  59. package/dist/types/modes/interactive-mode.d.ts +3 -0
  60. package/dist/types/modes/types.d.ts +9 -0
  61. package/dist/types/rlm/artifacts.d.ts +4 -4
  62. package/dist/types/runtime/optional-runtime-services.d.ts +2 -1
  63. package/dist/types/runtime/workspace-tree-service.d.ts +5 -1
  64. package/dist/types/runtime-mcp/config.d.ts +6 -0
  65. package/dist/types/runtime-mcp/manager.d.ts +10 -0
  66. package/dist/types/sdk/acp/adapter.d.ts +0 -4
  67. package/dist/types/sdk/broker/broker.d.ts +1 -1
  68. package/dist/types/sdk/broker/lifecycle.d.ts +57 -2
  69. package/dist/types/sdk/broker/session-index.d.ts +15 -0
  70. package/dist/types/sdk/bus/chat-daemon-control.d.ts +6 -0
  71. package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +4 -0
  72. package/dist/types/sdk/bus/index.d.ts +8 -0
  73. package/dist/types/sdk/bus/kind-aware-reconciliation.d.ts +2 -0
  74. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +12 -2
  75. package/dist/types/sdk/client/client.d.ts +39 -4
  76. package/dist/types/sdk/host/host.d.ts +1 -0
  77. package/dist/types/sdk/host/internal-autorouting-state.d.ts +3 -0
  78. package/dist/types/sdk/host/model-pin.d.ts +29 -0
  79. package/dist/types/sdk/host/session-runtime.d.ts +2 -1
  80. package/dist/types/sdk/lifecycle-session.d.ts +13 -0
  81. package/dist/types/sdk/router/session-router.d.ts +27 -1
  82. package/dist/types/sdk/session.d.ts +11 -1
  83. package/dist/types/session/agent-session.d.ts +36 -6
  84. package/dist/types/session/artifacts.d.ts +16 -1
  85. package/dist/types/session/internal/managed-session-storage.d.ts +7 -0
  86. package/dist/types/session/session-manager.d.ts +84 -2
  87. package/dist/types/session/session-staging-paths.d.ts +3 -0
  88. package/dist/types/skill-state/canonical-skills.d.ts +1 -1
  89. package/dist/types/skill-state/workflow-hud.d.ts +12 -21
  90. package/dist/types/skill-state/workflow-mutation-guard.d.ts +1 -0
  91. package/dist/types/slash-commands/helpers/autorouting-status.d.ts +8 -0
  92. package/dist/types/system-prompt.d.ts +23 -0
  93. package/dist/types/task/executor.d.ts +35 -4
  94. package/dist/types/task/index.d.ts +17 -3
  95. package/dist/types/task/receipt.d.ts +3 -1
  96. package/dist/types/task/types.d.ts +144 -0
  97. package/dist/types/tools/atomic-file-write.d.ts +72 -0
  98. package/dist/types/tools/descriptors.d.ts +1 -0
  99. package/dist/types/tools/index.d.ts +36 -1
  100. package/dist/types/tools/move-session.d.ts +40 -0
  101. package/dist/types/tools/python.d.ts +12 -0
  102. package/dist/types/tools/resource-gc.d.ts +0 -3
  103. package/dist/types/tools/search.d.ts +8 -1
  104. package/dist/types/tools/skill.d.ts +9 -4
  105. package/dist/types/tools/subagent.d.ts +33 -3
  106. package/dist/types/utils/xml-escape.d.ts +2 -0
  107. package/dist/types/workflow/workflow-intent-diff.d.ts +2 -2
  108. package/dist/types/workflow/workflow-intent-report-consumer.d.ts +1 -1
  109. package/package.json +11 -12
  110. package/scripts/build-sdk-package-smoke.ts +7 -5
  111. package/scripts/check-autorouting-tier-map.ts +183 -0
  112. package/scripts/generate-sdk-operation-inventory.ts +12 -0
  113. package/scripts/generate-tool-catalog.ts +40 -5
  114. package/src/async/job-manager.ts +5 -2
  115. package/src/autoresearch/dashboard.ts +134 -314
  116. package/src/autoresearch/data-context.ts +35 -0
  117. package/src/autoresearch/git.ts +186 -26
  118. package/src/autoresearch/{helpers.ts → harness.ts} +65 -40
  119. package/src/autoresearch/{prompt-setup.md → prompts/prompt-setup.md} +7 -7
  120. package/src/autoresearch/prompts/prompt.md +103 -0
  121. package/src/autoresearch/prompts.ts +126 -0
  122. package/src/autoresearch/runs.ts +708 -0
  123. package/src/autoresearch/types.ts +9 -150
  124. package/src/capability/index.ts +4 -4
  125. package/src/capability/types.ts +20 -0
  126. package/src/cli/accounts-cli.ts +21 -5
  127. package/src/cli/config-cli.ts +25 -1
  128. package/src/cli/fast-help.ts +1 -2
  129. package/src/cli/list-models.ts +5 -8
  130. package/src/cli/setup-cli.ts +8 -0
  131. package/src/cli.ts +2 -21
  132. package/src/commands/autoresearch.ts +33 -0
  133. package/src/commands/coordinator.ts +15 -0
  134. package/src/commands/launch.ts +2 -4
  135. package/src/commands/quick-lane.ts +1 -1
  136. package/src/commands/sdk.ts +24 -0
  137. package/src/commands/state.ts +1 -1
  138. package/src/config/autorouting-contract.ts +474 -0
  139. package/src/config/autorouting-generator.ts +238 -0
  140. package/src/config/autorouting-tier-map.ts +6108 -0
  141. package/src/config/autorouting.ts +120 -0
  142. package/src/config/model-discovery-manager.ts +42 -11
  143. package/src/config/model-registry.ts +348 -68
  144. package/src/config/provider-selection-policy.ts +60 -9
  145. package/src/config/settings-schema.ts +195 -6
  146. package/src/config/settings.ts +62 -1
  147. package/src/config.ts +2 -3
  148. package/src/coordinator/contract.ts +0 -1
  149. package/src/coordinator-mcp/codex-handoff.ts +68 -42
  150. package/src/coordinator-mcp/durability.ts +200 -0
  151. package/src/coordinator-mcp/event-webhook.ts +278 -0
  152. package/src/coordinator-mcp/question-state.ts +109 -46
  153. package/src/coordinator-mcp/server.ts +932 -504
  154. package/src/crash/index-store.ts +126 -22
  155. package/src/crash/record-loader.ts +7 -0
  156. package/src/crash/upstream/relay.ts +82 -34
  157. package/src/cursor.ts +84 -1
  158. package/src/debug/index.ts +26 -0
  159. package/src/defaults/gjc/skills/autoresearch/SKILL.md +116 -0
  160. package/src/defaults/gjc/skills/autoresearch/auto-critic.md +46 -0
  161. package/src/defaults/gjc/skills/autoresearch/auto-iterate.md +42 -0
  162. package/src/defaults/gjc/skills/deep-interview/SKILL.md +17 -37
  163. package/src/defaults/gjc/skills/ralplan/SKILL.md +21 -18
  164. package/src/defaults/gjc/skills/ultragoal/SKILL.md +6 -17
  165. package/src/defaults/gjc/skills/ultragoal/ai-slop-cleaner.md +2 -2
  166. package/src/defaults/gjc-defaults.ts +89 -2
  167. package/src/defaults/gjc-skills.generated.ts +24 -17
  168. package/src/discovery/builtin.ts +18 -5
  169. package/src/discovery/helpers.ts +6 -6
  170. package/src/edit/index.ts +5 -2
  171. package/src/eval/py/executor.ts +8 -0
  172. package/src/extensibility/extensions/loader.ts +135 -13
  173. package/src/extensibility/extensions/wrapper.ts +1 -2
  174. package/src/extensibility/gjc-plugins/schema.ts +1 -1
  175. package/src/extensibility/runtime-skill-discovery.ts +2 -2
  176. package/src/extensibility/skill-management.ts +2 -3
  177. package/src/extensibility/skills.ts +16 -8
  178. package/src/gjc-runtime/autoresearch-runtime.ts +1509 -0
  179. package/src/gjc-runtime/gc-render.ts +0 -1
  180. package/src/gjc-runtime/gc-runtime.ts +1 -11
  181. package/src/gjc-runtime/launch-tmux.ts +3 -3
  182. package/src/gjc-runtime/psmux-detect.ts +2 -2
  183. package/src/gjc-runtime/python-transcript.ts +58 -0
  184. package/src/gjc-runtime/ralplan-runtime.ts +6 -18
  185. package/src/gjc-runtime/session-layout.ts +18 -7
  186. package/src/gjc-runtime/session-state-sidecar.ts +58 -9
  187. package/src/gjc-runtime/state-renderer.ts +0 -38
  188. package/src/gjc-runtime/state-runtime.ts +43 -22
  189. package/src/gjc-runtime/state-schema.ts +1 -1
  190. package/src/gjc-runtime/tmux-common.ts +7 -7
  191. package/src/gjc-runtime/ultragoal-change-set.ts +232 -11
  192. package/src/gjc-runtime/ultragoal-runtime.ts +309 -114
  193. package/src/gjc-runtime/ultragoal-validation-policy.ts +247 -0
  194. package/src/gjc-runtime/workflow-command-ref.ts +15 -11
  195. package/src/gjc-runtime/workflow-manifest.generated.json +413 -532
  196. package/src/gjc-runtime/workflow-manifest.ts +43 -83
  197. package/src/gjc-runtime/workflow-recovery-projection.ts +616 -0
  198. package/src/hooks/skill-keywords.ts +3 -3
  199. package/src/hooks/skill-state.ts +2 -2
  200. package/src/internal-urls/docs-index.generated.ts +26 -24
  201. package/src/lsp/index.ts +25 -5
  202. package/src/main.ts +2 -27
  203. package/src/modes/acp/acp-agent.ts +200 -75
  204. package/src/modes/components/model-selector.ts +216 -13
  205. package/src/modes/components/oauth-selector.ts +5 -5
  206. package/src/modes/components/skill-hud/render.ts +173 -35
  207. package/src/modes/components/smart-routing-panel.ts +531 -0
  208. package/src/modes/components/tool-status-header.ts +6 -3
  209. package/src/modes/controllers/command-controller.ts +17 -7
  210. package/src/modes/controllers/input-controller.ts +44 -9
  211. package/src/modes/controllers/runtime-mcp-command-controller.ts +4 -0
  212. package/src/modes/controllers/selector-controller.ts +298 -65
  213. package/src/modes/interactive-mode.ts +8 -1
  214. package/src/modes/shared/agent-wire/workflow-gate-types.ts +1 -1
  215. package/src/modes/types.ts +9 -1
  216. package/src/prompts/agents/planner.md +1 -1
  217. package/src/prompts/system/system-prompt.md +1 -1
  218. package/src/prompts/system/volatile-project-context.md +2 -1
  219. package/src/prompts/tools/move-session.md +15 -0
  220. package/src/prompts/tools/python.md +12 -0
  221. package/src/prompts/tools/skill-discovery.md +1 -1
  222. package/src/prompts/tools/skill.md +2 -2
  223. package/src/prompts/tools/task-summary.md +1 -0
  224. package/src/prompts/tools/task.md +6 -0
  225. package/src/rlm/artifacts.ts +12 -10
  226. package/src/runtime/optional-runtime-services.ts +3 -2
  227. package/src/runtime/workspace-tree-service.ts +11 -3
  228. package/src/runtime-mcp/config.ts +8 -1
  229. package/src/runtime-mcp/manager.ts +33 -0
  230. package/src/sdk/acp/adapter.ts +48 -1
  231. package/src/sdk/broker/broker.ts +30 -2
  232. package/src/sdk/broker/discovery.ts +217 -2
  233. package/src/sdk/broker/lifecycle.ts +385 -59
  234. package/src/sdk/broker/session-index.ts +243 -48
  235. package/src/sdk/broker/transport.ts +1 -0
  236. package/src/sdk/bus/chat-daemon-control.ts +8 -2
  237. package/src/sdk/bus/chat-daemon-runtime.ts +5 -0
  238. package/src/sdk/bus/index.ts +208 -11
  239. package/src/sdk/bus/kind-aware-reconciliation.ts +16 -0
  240. package/src/sdk/bus/reconciliation-store.ts +27 -5
  241. package/src/sdk/bus/telegram-daemon-contract.ts +12 -2
  242. package/src/sdk/client/client.ts +204 -22
  243. package/src/sdk/host/host.ts +16 -0
  244. package/src/sdk/host/internal-autorouting-state.ts +13 -0
  245. package/src/sdk/host/model-pin.ts +101 -0
  246. package/src/sdk/host/reverse-leases.ts +2 -1
  247. package/src/sdk/host/session-runtime.test.ts +224 -1
  248. package/src/sdk/host/session-runtime.ts +125 -37
  249. package/src/sdk/lifecycle/service.ts +3 -1
  250. package/src/sdk/lifecycle-session.ts +42 -1
  251. package/src/sdk/protocol/operation-inventory.generated.json +66 -0
  252. package/src/sdk/router/session-router.ts +375 -36
  253. package/src/sdk/session.ts +547 -47
  254. package/src/session/account-inventory.ts +1 -1
  255. package/src/session/agent-session.ts +765 -189
  256. package/src/session/artifacts.ts +234 -4
  257. package/src/session/internal/managed-session-storage.ts +91 -4
  258. package/src/session/provider-safety-stop-hint.ts +3 -2
  259. package/src/session/session-manager.ts +775 -16
  260. package/src/session/session-staging-paths.ts +8 -0
  261. package/src/setup/hermes/templates/operator-instructions.v1.md +0 -1
  262. package/src/setup/host-plugin-setup.ts +2 -2
  263. package/src/skill-state/active-state.ts +2 -2
  264. package/src/skill-state/canonical-skills.ts +1 -1
  265. package/src/skill-state/initial-phase.ts +1 -1
  266. package/src/skill-state/workflow-hud.ts +41 -41
  267. package/src/skill-state/workflow-mutation-guard.ts +26 -7
  268. package/src/slash-commands/builtin-registry.ts +77 -0
  269. package/src/slash-commands/helpers/autorouting-status.ts +55 -0
  270. package/src/system-prompt.ts +102 -5
  271. package/src/task/discovery.ts +2 -3
  272. package/src/task/executor.ts +617 -43
  273. package/src/task/index.ts +262 -15
  274. package/src/task/receipt.ts +30 -0
  275. package/src/task/render.ts +11 -1
  276. package/src/task/types.ts +316 -0
  277. package/src/tools/atomic-file-write.ts +594 -0
  278. package/src/tools/bisect.ts +3 -2
  279. package/src/tools/descriptors.test.ts +3 -0
  280. package/src/tools/descriptors.ts +24 -0
  281. package/src/tools/image-gen.ts +5 -1
  282. package/src/tools/index.ts +62 -5
  283. package/src/tools/move-session.ts +107 -0
  284. package/src/tools/python.ts +205 -0
  285. package/src/tools/read.ts +88 -15
  286. package/src/tools/renderers.ts +2 -0
  287. package/src/tools/resource-gc.ts +8 -177
  288. package/src/tools/search.ts +30 -6
  289. package/src/tools/skill-discovery.ts +1 -0
  290. package/src/tools/skill.ts +37 -7
  291. package/src/tools/subagent-render.ts +119 -13
  292. package/src/tools/subagent.ts +91 -74
  293. package/src/tools/tool-catalog.generated.ts +64 -2
  294. package/src/tools/write.ts +16 -12
  295. package/src/utils/xml-escape.ts +14 -0
  296. package/src/web/search/providers/codex.ts +2 -2
  297. package/src/workflow/workflow-intent-diff.ts +13 -12
  298. package/src/workflow/workflow-intent-report-consumer.ts +6 -6
  299. package/dist/types/autoresearch/helpers.d.ts +0 -24
  300. package/dist/types/autoresearch/index.d.ts +0 -2
  301. package/dist/types/autoresearch/state.d.ts +0 -17
  302. package/dist/types/autoresearch/storage.d.ts +0 -142
  303. package/dist/types/autoresearch/tools/init-experiment.d.ts +0 -31
  304. package/dist/types/autoresearch/tools/log-experiment.d.ts +0 -23
  305. package/dist/types/autoresearch/tools/run-experiment.d.ts +0 -8
  306. package/dist/types/autoresearch/tools/update-notes.d.ts +0 -12
  307. package/dist/types/commands/team.d.ts +0 -24
  308. package/dist/types/gjc-runtime/team-gc.d.ts +0 -7
  309. package/dist/types/gjc-runtime/team-launch.d.ts +0 -61
  310. package/dist/types/gjc-runtime/team-notify.d.ts +0 -45
  311. package/dist/types/gjc-runtime/team-runtime.d.ts +0 -336
  312. package/dist/types/gjc-runtime/team-store.d.ts +0 -168
  313. package/dist/types/gjc-runtime/team-worker-heartbeat.d.ts +0 -43
  314. package/dist/types/gjc-runtime/team-worker-memory-guard.d.ts +0 -92
  315. package/dist/types/gjc-runtime/team-workers.d.ts +0 -83
  316. package/dist/types/rlm/index.d.ts +0 -47
  317. package/dist/types/rlm/preset.d.ts +0 -23
  318. package/dist/types/rlm/python-tool.d.ts +0 -16
  319. package/src/autoresearch/command-resume.md +0 -14
  320. package/src/autoresearch/index.ts +0 -536
  321. package/src/autoresearch/prompt.md +0 -103
  322. package/src/autoresearch/resume-message.md +0 -10
  323. package/src/autoresearch/state.ts +0 -273
  324. package/src/autoresearch/storage.ts +0 -699
  325. package/src/autoresearch/tools/init-experiment.ts +0 -272
  326. package/src/autoresearch/tools/log-experiment.ts +0 -524
  327. package/src/autoresearch/tools/run-experiment.ts +0 -475
  328. package/src/autoresearch/tools/update-notes.ts +0 -109
  329. package/src/commands/rlm.ts +0 -19
  330. package/src/commands/team.ts +0 -238
  331. package/src/defaults/gjc/skills/deep-interview/auto-research-greenfield.md +0 -42
  332. package/src/defaults/gjc/skills/team/SKILL.md +0 -467
  333. package/src/gjc-runtime/team-gc.ts +0 -49
  334. package/src/gjc-runtime/team-launch.ts +0 -404
  335. package/src/gjc-runtime/team-notify.ts +0 -326
  336. package/src/gjc-runtime/team-runtime.ts +0 -5923
  337. package/src/gjc-runtime/team-store.ts +0 -878
  338. package/src/gjc-runtime/team-worker-heartbeat.ts +0 -149
  339. package/src/gjc-runtime/team-worker-memory-guard.ts +0 -363
  340. package/src/gjc-runtime/team-workers.ts +0 -1123
  341. package/src/prompts/system/rlm-report-command.md +0 -1
  342. package/src/prompts/system/rlm-research.md +0 -23
  343. package/src/rlm/index.ts +0 -365
  344. package/src/rlm/preset.ts +0 -76
  345. package/src/rlm/python-tool.ts +0 -68
@@ -10,10 +10,15 @@
10
10
  * project/user skills have no native workflow mode-state, so they are dispatched
11
11
  * directly and tracked by the prompt observer instead.
12
12
  *
13
- * Canonical workflow chaining is refused unless the caller's `current_phase` is
14
- * in `{complete, completed, handoff, failed, cancelled, canceled, inactive}`.
15
- * The agent declares readiness either by writing `current_phase: "handoff"` to
16
- * its mode-state or by running the handoff verb directly.
13
+ * Canonical workflow chaining is refused unless the caller's phase permits it:
14
+ * the generic terminal set `{complete, completed, handoff, failed, cancelled,
15
+ * canceled, inactive}`, the caller's manifest-declared terminal states (e.g.
16
+ * ralplan `final`), or — for autoresearch only — any phase with a declared
17
+ * handoff edge (`intake`/`research`/`verdict`): a research mission never
18
+ * mutates and guards no approval gate, its mission state is durable, so an
19
+ * ongoing or verdict-complete mission may hand off to planning at any point.
20
+ * ralplan/ultragoal keep the explicit write-to-handoff step for live phases:
21
+ * their mid-flight chaining is exactly what the approval-gate guard blocks.
17
22
  */
18
23
  import type { AgentTool, AgentToolResult } from "@gajae-code/agent-core";
19
24
  import * as z from "zod/v4";
@@ -1,6 +1,6 @@
1
1
  import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@gajae-code/agent-core";
2
2
  import * as z from "zod/v4";
3
- import type { AgentProgress, AgentSource } from "../task/types";
3
+ import type { AgentProgress, AgentSource, LocalErrorSummary } from "../task/types";
4
4
  import type { ToolSession } from "./index";
5
5
  declare const subagentSchema: z.ZodObject<{
6
6
  action: z.ZodEnum<{
@@ -45,6 +45,8 @@ export interface SubagentSnapshot {
45
45
  errorText?: string;
46
46
  /** Safe setup failure cause retained from the executor launch path. */
47
47
  setupFailureSummary?: string;
48
+ /** Safe, bounded summary of a terminal local (non-provider) failure (e.g. local_buffer_overflow). */
49
+ localErrorSummary?: LocalErrorSummary;
48
50
  resultPreview?: string;
49
51
  outputRef?: string;
50
52
  truncated?: boolean;
@@ -52,8 +54,8 @@ export interface SubagentSnapshot {
52
54
  steerMessage?: string;
53
55
  steerState?: "queued" | "resume_queued" | "resume_started";
54
56
  steerPauseRequested?: boolean;
55
- /** Live streaming progress for the awaited subagent (await panel only; UI detail). */
56
- progress?: AgentProgress;
57
+ /** Bounded live progress approved for the await panel and public tool details. */
58
+ progress?: SubagentLiveProgress;
57
59
  /** True when a live in-session progress producer exists for this subagent. */
58
60
  liveProgressAvailable?: boolean;
59
61
  /** Model the subagent actually runs on (after any auth fallback). */
@@ -65,6 +67,34 @@ export interface SubagentSnapshot {
65
67
  /** True when the effective subagent provider is in fast mode. */
66
68
  fastMode?: boolean;
67
69
  }
70
+ /**
71
+ * Public await-panel progress. This is deliberately not `AgentProgress`: raw
72
+ * progress contains model deltas, tool arguments, arbitrary output, and nested
73
+ * task payloads that must never enter tool-result, ACP, or telemetry envelopes.
74
+ */
75
+ export interface SubagentLiveProgress {
76
+ id: string;
77
+ status: AgentProgress["status"];
78
+ currentTool?: string;
79
+ recentTool?: string;
80
+ recentOutputSummary?: {
81
+ lineCount: number;
82
+ };
83
+ fastMode?: boolean;
84
+ retryState?: {
85
+ attempt: number;
86
+ maxAttempts: number;
87
+ unbounded?: boolean;
88
+ kind: NonNullable<AgentProgress["retryState"]>["kind"];
89
+ provider?: string;
90
+ lastProviderProgressAtMs?: number;
91
+ delayMs: number;
92
+ startedAtMs: number;
93
+ };
94
+ retryFailure?: {
95
+ attempt: number;
96
+ };
97
+ }
68
98
  export type SubagentAwaitOutcome = "completed" | "timed_out" | "interrupted";
69
99
  export interface SubagentToolDetails {
70
100
  subagents: SubagentSnapshot[];
@@ -0,0 +1,2 @@
1
+ /** Escape a string for interpolation inside a double- or single-quoted XML attribute. */
2
+ export declare function escapeXmlAttribute(input: string): string;
@@ -1,7 +1,7 @@
1
1
  import { type WorkflowClaimsLedger, type WorkflowConsensusReport } from "./workflow-intent-report";
2
2
  export declare const WORKFLOW_INTENT_DIFF_CUSTOM_TYPE = "workflow-intent-diff";
3
- export declare const WORKFLOW_INTENT_ROUTES: readonly ["direct", "deep-interview", "ralplan", "ultragoal", "team"];
4
- export declare const WORKFLOW_ESCALATION_ROUTES: readonly ["deep-interview", "ralplan", "ultragoal", "team"];
3
+ export declare const WORKFLOW_INTENT_ROUTES: readonly ["direct", "deep-interview", "ralplan", "ultragoal", "autoresearch"];
4
+ export declare const WORKFLOW_ESCALATION_ROUTES: readonly ["deep-interview", "ralplan", "ultragoal", "autoresearch"];
5
5
  export type WorkflowIntentRoute = (typeof WORKFLOW_INTENT_ROUTES)[number];
6
6
  export type WorkflowEscalationRoute = (typeof WORKFLOW_ESCALATION_ROUTES)[number];
7
7
  export type DirectTrackingMode = "custom-entry-only" | "not-direct";
@@ -7,7 +7,7 @@ export interface WorkflowRouteCounts {
7
7
  readonly "deep-interview": number;
8
8
  readonly ralplan: number;
9
9
  readonly ultragoal: number;
10
- readonly team: number;
10
+ readonly autoresearch: number;
11
11
  }
12
12
  export interface WorkflowIntentReportEntry {
13
13
  readonly entryId: string;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@gajae-code/coding-agent",
4
- "version": "0.14.2",
4
+ "version": "0.15.0",
5
5
  "description": "Gajae Code CLI with read, bash, edit, write tools and session management",
6
6
  "homepage": "https://gajae-code.com",
7
7
  "author": "Yeachan-Heo and Gajae Code Contributors",
@@ -33,6 +33,7 @@
33
33
  "check": "biome check . && bun run check:types",
34
34
  "check:runtime": "bun run generate-hotkeys-docs --check && bun run verify:sdk-canonicalization",
35
35
  "check:types": "tsc -p tsconfig.json --noEmit",
36
+ "check:autorouting-map": "bun scripts/check-autorouting-tier-map.ts",
36
37
  "lint": "biome lint .",
37
38
  "test": "bun test",
38
39
  "generate-hotkeys-docs": "bun scripts/generate-hotkeys-docs.ts",
@@ -55,12 +56,12 @@
55
56
  "@agentclientprotocol/sdk": "1.3.0",
56
57
  "@babel/parser": "^7.29.3",
57
58
  "@mozilla/readability": "^0.6.0",
58
- "@gajae-code/stats": "0.14.2",
59
- "@gajae-code/agent-core": "0.14.2",
60
- "@gajae-code/ai": "0.14.2",
61
- "@gajae-code/natives": "0.14.2",
62
- "@gajae-code/tui": "0.14.2",
63
- "@gajae-code/utils": "0.14.2",
59
+ "@gajae-code/stats": "0.15.0",
60
+ "@gajae-code/agent-core": "0.15.0",
61
+ "@gajae-code/ai": "0.15.0",
62
+ "@gajae-code/natives": "0.15.0",
63
+ "@gajae-code/tui": "0.15.0",
64
+ "@gajae-code/utils": "0.15.0",
64
65
  "@puppeteer/browsers": "^2.13.0",
65
66
  "@types/turndown": "5.0.6",
66
67
  "@xterm/headless": "^6.0.0",
@@ -85,7 +86,7 @@
85
86
  "@types/ws": "^8.5.13"
86
87
  },
87
88
  "engines": {
88
- "bun": ">=1.3.14"
89
+ "bun": ">=1.4.0"
89
90
  },
90
91
  "files": [
91
92
  "src",
@@ -150,6 +151,8 @@
150
151
  "./sdk/host/control/runtime-gate.js": null,
151
152
  "./sdk/host/control/runtime-gate": null,
152
153
  "./sdk/host/control/runtime-gate/*": null,
154
+ "./sdk/host/internal-autorouting-state.js": null,
155
+ "./sdk/host/internal-autorouting-state": null,
153
156
  "./sdk/lifecycle/broker-client.js": null,
154
157
  "./sdk/lifecycle/broker-client": null,
155
158
  "./sdk/lifecycle/broker-client/*": null,
@@ -200,10 +203,6 @@
200
203
  "types": "./dist/types/cli/commands/*.d.ts",
201
204
  "import": "./src/cli/commands/*.ts"
202
205
  },
203
- "./autoresearch": null,
204
- "./autoresearch/*": null,
205
- "./autoresearch/tools/*": null,
206
- "./commands/autoresearch": null,
207
206
  "./commands/ralph": null,
208
207
  "./commands/ultraqa": null,
209
208
  "./commands/ultrawork": null,
@@ -25,7 +25,8 @@ function run(command: string[], cwd: string): string {
25
25
  if (result.exitCode !== 0) {
26
26
  throw new Error(`${command.join(" ")} failed:\n${new TextDecoder().decode(result.stderr)}`);
27
27
  }
28
- return new TextDecoder().decode(result.stdout).trim();
28
+ const lines = new TextDecoder().decode(result.stdout).trim().split(/\r?\n/);
29
+ return lines.at(-1) ?? "";
29
30
  }
30
31
 
31
32
  function assertExport(module: Record<string, unknown>, name: string, subpath: string): void {
@@ -95,9 +96,10 @@ async function runSmoke(): Promise<Surface> {
95
96
  // Install the matching packed workspace artifacts so the smoke test exercises the
96
97
  // release dependency boundary without falling back to an older registry package.
97
98
  run(["bun", "install", "--ignore-scripts"], tempDir);
98
- const installedPackage = JSON.parse(
99
- await fs.readFile(path.join(tempDir, "node_modules", packageName, "package.json"), "utf8"),
100
- ) as { exports?: Record<string, unknown> };
99
+ const stagedPackageJsonPath = path.join(tempDir, "node_modules", packageName, "package.json");
100
+ const installedPackage = JSON.parse(await fs.readFile(stagedPackageJsonPath, "utf8")) as {
101
+ exports?: Record<string, unknown>;
102
+ };
101
103
  const installedAgentPackagePath = path.join(tempDir, "node_modules", "@gajae-code", "agent-core");
102
104
  const installedAgentPackageJsonPath = path.join(installedAgentPackagePath, "package.json");
103
105
  const installedAgentPackage = JSON.parse(await fs.readFile(installedAgentPackageJsonPath, "utf8")) as {
@@ -150,7 +152,7 @@ async function runSmoke(): Promise<Surface> {
150
152
  const probePath = path.join(tempDir, "probe.ts");
151
153
  await fs.writeFile(
152
154
  probePath,
153
- `import * as fs from "node:fs/promises";\nimport * as path from "node:path";\nimport * as root from ${JSON.stringify(packageName)};\nimport * as sdk from ${JSON.stringify(`${packageName}/sdk`)};\nimport * as bus from ${JSON.stringify(`${packageName}/sdk/bus`)};\nconst required = [[root, "createAgentSession", "root"], [root, "SESSION_DIRECTORY_API_VERSION", "root"], [root, "resolveManagedSessionScope", "root"], [root, "listManagedSessionCandidates", "root"], [sdk, "createAgentSession", "sdk"], [bus, "createNotificationsExtension", "sdk/bus"], [sdk, "SESSION_DIRECTORY_API_VERSION", "sdk"], [sdk, "resolveManagedSessionScope", "sdk"], [sdk, "listManagedSessionCandidates", "sdk"]] as const;\nfor (const [module, name, subpath] of required) if (!(name in module)) throw new Error(subpath + " missing " + name);\nconst sandbox = path.join(process.cwd(), "managed-listing-smoke");\nconst cwd = path.join(sandbox, "workspace", "a-b", "c");\nconst agentDir = path.join(sandbox, "agent");\nconst sessionsRoot = path.join(agentDir, "sessions");\nawait fs.mkdir(cwd, { recursive: true });\nconst resolved = await sdk.resolveManagedSessionScope({ cwd, agentDir, sessionsRoot });\nif (resolved.kind !== "resolved") throw new Error("packed resolver failed: " + resolved.message);\nawait fs.mkdir(resolved.scope.directoryPath, { recursive: true, mode: 0o700 });\nawait fs.chmod(sessionsRoot, 0o700);\nawait fs.chmod(resolved.scope.directoryPath, 0o700);\nawait fs.writeFile(path.join(resolved.scope.directoryPath, ".gjc-managed-session-scope.v2.json"), JSON.stringify({ schemaVersion: 1, layoutVersion: 2, identityVersion: 1, platform: process.platform === "win32" ? "win32" : "posix", canonicalPath: resolved.scope.canonicalCwd, identityDigest: resolved.scope.directoryName.slice(3) }) + "\\n", { mode: 0o600 });\nconst transcriptPath = path.join(resolved.scope.directoryPath, "packed-session.jsonl");\nawait fs.writeFile(transcriptPath, JSON.stringify({ type: "session", id: "packed-session", cwd }) + "\\n", { mode: 0o600 });\nconst snapshot = async () => Promise.all((await fs.readdir(sandbox, { recursive: true })).sort().map(async name => { const pathname = path.join(sandbox, name); const stat = await fs.lstat(pathname); return [name, stat.mode, stat.size, stat.mtimeMs, stat.isFile() ? await fs.readFile(pathname, "utf8") : null]; }));\nconst before = JSON.stringify(await snapshot());\nconst listing = await sdk.listManagedSessionCandidates({ scope: resolved.scope });\nif (listing.kind !== "complete" || listing.owned.length !== 1 || listing.owned[0]?.sessionId !== "packed-session") throw new Error("packed readonly listing failed: " + JSON.stringify(listing));\nconst after = JSON.stringify(await snapshot());\nif (after !== before) throw new Error("packed readonly listing mutated the filesystem");\nconst privateSubpath = ${JSON.stringify(`${packageName}/session/internal/managed-session-scope`)};\ntry { await import(privateSubpath); throw new Error("private managed-session scope subpath resolved"); } catch (error) {\n\tif (error instanceof Error && error.message === "private managed-session scope subpath resolved") throw error;\n\tconst message = String(error);\n\tconst exportsRejected = /Package subpath .* is not defined by "exports"/.test(message);\n\tconst bunRejected = message.startsWith("ResolveMessage: Cannot find module '" + privateSubpath + "' from '") && message.endsWith("/probe.ts'");\n\tif (!exportsRejected && !bunRejected) throw new Error("private managed-session scope failed for an unexpected reason: " + message);\n}\nprocess.stdout.write(JSON.stringify({ root: Object.keys(root).sort(), sdk: Object.keys(sdk).sort() }));\n`,
155
+ `import * as fs from "node:fs/promises";\nimport * as path from "node:path";\nimport * as root from ${JSON.stringify(packageName)};\nimport * as sdk from ${JSON.stringify(`${packageName}/sdk`)};\nimport * as bus from ${JSON.stringify(`${packageName}/sdk/bus`)};\nconst required = [[root, "createAgentSession", "root"], [root, "SESSION_DIRECTORY_API_VERSION", "root"], [root, "resolveManagedSessionScope", "root"], [root, "listManagedSessionCandidates", "root"], [sdk, "createAgentSession", "sdk"], [bus, "createNotificationsExtension", "sdk/bus"], [sdk, "SESSION_DIRECTORY_API_VERSION", "sdk"], [sdk, "resolveManagedSessionScope", "sdk"], [sdk, "listManagedSessionCandidates", "sdk"]] as const;\nfor (const [module, name, subpath] of required) if (!(name in module)) throw new Error(subpath + " missing " + name);\nconst sandbox = path.join(process.cwd(), "managed-listing-smoke");\nconst cwd = path.join(sandbox, "workspace", "a-b", "c");\nconst agentDir = path.join(sandbox, "agent");\nconst sessionsRoot = path.join(agentDir, "sessions");\nawait fs.mkdir(cwd, { recursive: true });\nconst resolved = await sdk.resolveManagedSessionScope({ cwd, agentDir, sessionsRoot });\nif (resolved.kind !== "resolved") throw new Error("packed resolver failed: " + resolved.message);\nawait fs.mkdir(resolved.scope.directoryPath, { recursive: true, mode: 0o700 });\nawait fs.chmod(sessionsRoot, 0o700);\nawait fs.chmod(resolved.scope.directoryPath, 0o700);\nawait fs.writeFile(path.join(resolved.scope.directoryPath, ".gjc-managed-session-scope.v2.json"), JSON.stringify({ schemaVersion: 1, layoutVersion: 2, identityVersion: 1, platform: process.platform === "win32" ? "win32" : "posix", canonicalPath: resolved.scope.canonicalCwd, identityDigest: resolved.scope.directoryName.slice(3) }) + "\\n", { mode: 0o600 });\nconst transcriptPath = path.join(resolved.scope.directoryPath, "packed-session.jsonl");\nawait fs.writeFile(transcriptPath, JSON.stringify({ type: "session", id: "packed-session", cwd }) + "\\n", { mode: 0o600 });\nconst snapshot = async () => Promise.all((await fs.readdir(sandbox, { recursive: true })).sort().map(async name => { const pathname = path.join(sandbox, name); const stat = await fs.lstat(pathname); return [name, stat.mode, stat.size, stat.mtimeMs, stat.isFile() ? await fs.readFile(pathname, "utf8") : null]; }));\nconst before = JSON.stringify(await snapshot());\nconst listing = await sdk.listManagedSessionCandidates({ scope: resolved.scope });\nif (listing.kind !== "complete" || listing.owned.length !== 1 || listing.owned[0]?.sessionId !== "packed-session") throw new Error("packed readonly listing failed: " + JSON.stringify(listing));\nconst after = JSON.stringify(await snapshot());\nif (after !== before) throw new Error("packed readonly listing mutated the filesystem");\nconst privateSubpath = ${JSON.stringify(`${packageName}/session/internal/managed-session-scope`)};\ntry { await import(privateSubpath); throw new Error("private managed-session scope subpath resolved"); } catch (error) {\n\tif (error instanceof Error && error.message === "private managed-session scope subpath resolved") throw error;\n\tconst message = String(error);\n\tconst exportsRejected = /Package subpath .* is not defined by "exports"/.test(message);\n\tconst bunRejected = (message.startsWith("ResolveMessage: Cannot find module '" + privateSubpath + "' from '") && message.endsWith("/probe.ts'")) || (message.startsWith("ResolveMessage: Cannot find package '" + ${JSON.stringify(packageName)} + "' imported from ") && message.endsWith("/probe.ts"));\n\tif (!exportsRejected && !bunRejected) throw new Error("private managed-session scope failed for an unexpected reason: " + message);\n}\nprocess.stdout.write(JSON.stringify({ root: Object.keys(root).sort(), sdk: Object.keys(sdk).sort() }));\n`,
154
156
  );
155
157
  await fs.appendFile(
156
158
  probePath,
@@ -0,0 +1,183 @@
1
+ #!/usr/bin/env bun
2
+
3
+ import * as fs from "node:fs/promises";
4
+ import * as path from "node:path";
5
+ import { RETIRED_MODEL_KEYS } from "../../ai/src/model-retirements";
6
+ import { isValidAutoroutingSelector } from "../src/config/autorouting-contract";
7
+ import {
8
+ CURATED_TIER_LABELS,
9
+ type CuratedTierLabels,
10
+ TIER_MAP_SKIP_LIST,
11
+ type TierMapSkipList,
12
+ } from "../src/config/autorouting-tier-map";
13
+
14
+ export const BASELINE_SKIP_RATIONALE = "pre-feature baseline; not yet curated";
15
+ const DISCOVERY_ONLY_PROVIDERS = new Set(["ollama", "vllm"]);
16
+ const RETIRED_KEYS = new Set<string>(RETIRED_MODEL_KEYS);
17
+
18
+ export type CommittedCatalogModel = {
19
+ id?: unknown;
20
+ provider?: unknown;
21
+ output?: unknown;
22
+ [key: string]: unknown;
23
+ };
24
+
25
+ export type CommittedCatalog = Record<string, Record<string, CommittedCatalogModel>>;
26
+
27
+ export type AutoroutingTierMapGateReport = {
28
+ inScopeKeys: string[];
29
+ labeledKeys: string[];
30
+ skippedKeys: string[];
31
+ unlabeledKeys: string[];
32
+ invalidLabelKeys: string[];
33
+ outOfScopeLabelKeys: string[];
34
+ invalidSkipKeys: string[];
35
+ staleSkipKeys: string[];
36
+ baselineSkipCount: number;
37
+ };
38
+
39
+ function modelKey(provider: string, id: string): string {
40
+ return `${provider}/${id}`;
41
+ }
42
+
43
+ function isImageGenerationOnly(model: CommittedCatalogModel): boolean {
44
+ return Array.isArray(model.output) && model.output.length > 0 && model.output.every(output => output === "image");
45
+ }
46
+
47
+ export function isInAutoroutingGateScope(provider: string, id: string, model: CommittedCatalogModel): boolean {
48
+ const key = modelKey(provider, id);
49
+ return (
50
+ isValidAutoroutingSelector(key) &&
51
+ !RETIRED_KEYS.has(key) &&
52
+ !DISCOVERY_ONLY_PROVIDERS.has(provider) &&
53
+ !isImageGenerationOnly(model)
54
+ );
55
+ }
56
+
57
+ export function committedCatalogKeys(catalog: CommittedCatalog): string[] {
58
+ const keys: string[] = [];
59
+ for (const [provider, models] of Object.entries(catalog)) {
60
+ if (models === null || typeof models !== "object" || Array.isArray(models)) continue;
61
+ for (const [id, model] of Object.entries(models)) {
62
+ if (isInAutoroutingGateScope(provider, id, model)) keys.push(modelKey(provider, id));
63
+ }
64
+ }
65
+ return keys.sort((left, right) => left.localeCompare(right));
66
+ }
67
+
68
+ export function getAutoroutingTierMapGateReport(
69
+ catalog: CommittedCatalog,
70
+ labels: CuratedTierLabels = CURATED_TIER_LABELS,
71
+ skips: TierMapSkipList = TIER_MAP_SKIP_LIST,
72
+ ): AutoroutingTierMapGateReport {
73
+ const catalogKeys = new Set(committedCatalogKeys(catalog));
74
+ const labeledKeys = Object.keys(labels).sort((left, right) => left.localeCompare(right));
75
+ const skippedKeys = Object.keys(skips).sort((left, right) => left.localeCompare(right));
76
+ const invalidLabelKeys = labeledKeys.filter(key => !catalogKeys.has(key));
77
+ const outOfScopeLabelKeys = labeledKeys.filter(key => {
78
+ const separator = key.indexOf("/");
79
+ const provider = separator > 0 ? key.slice(0, separator) : key;
80
+ const id = separator > 0 ? key.slice(separator + 1) : "";
81
+ const rawModel = catalog[provider]?.[id];
82
+ return rawModel !== undefined && !isInAutoroutingGateScope(provider, id, rawModel);
83
+ });
84
+ const unlabeledKeys = [...catalogKeys].filter(key => !Object.hasOwn(labels, key) && !Object.hasOwn(skips, key));
85
+ const inScopeKeys = [...catalogKeys];
86
+ const inScopeSkipped = skippedKeys.filter(key => catalogKeys.has(key));
87
+ const invalidSkipKeys = skippedKeys.filter(key => {
88
+ const entry = (skips as Record<string, { rationale?: unknown }>)[key];
89
+ const rationale = entry?.rationale;
90
+ return typeof rationale !== "string" || rationale.trim().length === 0 || !isValidAutoroutingSelector(key);
91
+ });
92
+ const staleSkipKeys = skippedKeys.filter(key => !catalogKeys.has(key) && !invalidSkipKeys.includes(key));
93
+ // A key that is both labeled and skipped would let a curated tier assignment hide
94
+ // behind a skip rationale; it is an invalid skip, not a stale one.
95
+ const bothLabeledAndSkipped = skippedKeys.filter(key => Object.hasOwn(labels, key));
96
+ invalidSkipKeys.push(...bothLabeledAndSkipped.filter(key => !invalidSkipKeys.includes(key)));
97
+ return {
98
+ inScopeKeys,
99
+ labeledKeys,
100
+ skippedKeys: inScopeSkipped,
101
+ unlabeledKeys: unlabeledKeys.sort((left, right) => left.localeCompare(right)),
102
+ invalidLabelKeys,
103
+ outOfScopeLabelKeys,
104
+ invalidSkipKeys,
105
+ staleSkipKeys,
106
+ baselineSkipCount: inScopeSkipped.filter(
107
+ key => (skips as Record<string, { baseline?: true }>)[key]?.baseline === true,
108
+ ).length,
109
+ };
110
+ }
111
+
112
+ export function findUnlabeledAutoroutingKeys(
113
+ catalog: CommittedCatalog,
114
+ labels: CuratedTierLabels = CURATED_TIER_LABELS,
115
+ skips: TierMapSkipList = TIER_MAP_SKIP_LIST,
116
+ ): string[] {
117
+ return getAutoroutingTierMapGateReport(catalog, labels, skips).unlabeledKeys;
118
+ }
119
+
120
+ export type AutoroutingTierMapGateResult = {
121
+ ok: boolean;
122
+ report: AutoroutingTierMapGateReport;
123
+ };
124
+
125
+ export function checkAutoroutingTierMap(
126
+ catalog: CommittedCatalog,
127
+ labels: CuratedTierLabels = CURATED_TIER_LABELS,
128
+ skips: TierMapSkipList = TIER_MAP_SKIP_LIST,
129
+ ): AutoroutingTierMapGateResult {
130
+ const report = getAutoroutingTierMapGateReport(catalog, labels, skips);
131
+ const ok =
132
+ report.unlabeledKeys.length === 0 &&
133
+ report.invalidLabelKeys.length === 0 &&
134
+ report.outOfScopeLabelKeys.length === 0 &&
135
+ report.invalidSkipKeys.length === 0 &&
136
+ report.staleSkipKeys.length === 0;
137
+ return { ok, report };
138
+ }
139
+
140
+ export async function loadCommittedCatalog(
141
+ repoRoot = path.resolve(import.meta.dir, "../../.."),
142
+ ): Promise<CommittedCatalog> {
143
+ const catalogPath = path.join(repoRoot, "packages/ai/src/models.json");
144
+ return JSON.parse(await fs.readFile(catalogPath, "utf8")) as CommittedCatalog;
145
+ }
146
+
147
+ export async function runAutoroutingTierMapGate(repoRoot?: string): Promise<AutoroutingTierMapGateResult> {
148
+ return checkAutoroutingTierMap(await loadCommittedCatalog(repoRoot));
149
+ }
150
+
151
+ export const checkTierMap = checkAutoroutingTierMap;
152
+ export const findUnlabeledKeys = findUnlabeledAutoroutingKeys;
153
+ export const runTierMapGate = runAutoroutingTierMapGate;
154
+
155
+ function printFailure(report: AutoroutingTierMapGateReport): void {
156
+ const failures = [
157
+ ...new Set([
158
+ ...report.unlabeledKeys,
159
+ ...report.invalidLabelKeys,
160
+ ...report.outOfScopeLabelKeys,
161
+ ...report.invalidSkipKeys,
162
+ ...report.staleSkipKeys,
163
+ ]),
164
+ ].sort((a, b) => a.localeCompare(b));
165
+ console.error("Autorouting tier-map gate failed.");
166
+ console.error("Offending provider/model-id keys:");
167
+ for (const key of failures) console.error(`- ${key}`);
168
+ console.error(
169
+ "Add each new key to CURATED_TIER_LABELS with reviewed tier/rank data, or add it to TIER_MAP_SKIP_LIST with a non-empty rationale; remove skip entries whose key left the catalog or the selector grammar.",
170
+ );
171
+ }
172
+
173
+ if (import.meta.main) {
174
+ const result = await runAutoroutingTierMapGate();
175
+ if (!result.ok) {
176
+ printFailure(result.report);
177
+ process.exitCode = 1;
178
+ } else {
179
+ console.log(
180
+ `Autorouting tier-map gate passed: ${result.report.inScopeKeys.length} in-scope keys; ${result.report.baselineSkipCount} baseline skips.`,
181
+ );
182
+ }
183
+ }
@@ -17,6 +17,8 @@ const LOCKED_EXCLUSIONS: Readonly<Record<string, string>> = {
17
17
  "internal terminal-abort bus seam, threaded via terminalAbortSeams; not a user-facing SDK control seam",
18
18
  "agent_session:abortPromptAndWaitWithTerminal":
19
19
  "internal terminal-abort fencing seam, threaded via terminalAbortSeams; not a user-facing SDK control seam",
20
+ "slash_command:routing":
21
+ "visual/local-only autorouting settings toggle and smart-routing panel entry, not a user-facing SDK control seam",
20
22
  "slash_command:settings": "visual/local-only command, not a user-facing SDK control seam",
21
23
  "slash_command:theme": "visual/local-only command, not a user-facing SDK control seam",
22
24
  "slash_command:copy": "visual/local-only command, not a user-facing SDK control seam",
@@ -73,6 +75,16 @@ const LOCKED_EXCLUSIONS: Readonly<Record<string, string>> = {
73
75
  "agent_session:setForcedToolChoice": "internal accessor/plumbing, not a user-facing control seam",
74
76
  "agent_session:getActiveSkillState": "internal accessor/plumbing, not a user-facing control seam",
75
77
  "agent_session:getActiveSkillPhase": "internal accessor/plumbing, not a user-facing control seam",
78
+ "agent_session:getEffectiveActiveWorkflowSkillState":
79
+ "internal restored-or-live workflow guard for session rescope, not a user-facing SDK control seam",
80
+ "agent_session:replaceOwnedMcpManager":
81
+ "internal cwd-rebinding helper for owned MCP authority after move_session, not a user-facing SDK control seam",
82
+ "agent_session:replaceNamedCustomTools":
83
+ "internal cwd-rebinding helper for named custom tools after move_session, not a user-facing SDK control seam",
84
+ "agent_session:replaceSkills":
85
+ "internal cwd-rebinding helper for session skills after move_session, not a user-facing SDK control seam",
86
+ "agent_session:retireWorkspaceTreeForRescope":
87
+ "internal cwd-rebinding helper that retires the cached workspace tree after move_session, not a user-facing SDK control seam",
76
88
  "agent_session:getDeepInterviewAskStage":
77
89
  "internal AskTool schema-selection accessor, not a user-facing SDK control seam",
78
90
  "agent_session:peekQueueInvoker": "internal accessor/plumbing, not a user-facing control seam",
@@ -1,3 +1,5 @@
1
+ import * as fs from "node:fs/promises";
2
+ import * as os from "node:os";
1
3
  import * as path from "node:path";
2
4
  import { toolWireSchema } from "@gajae-code/ai/utils/schema";
3
5
  import { TaskTool } from "../src/task";
@@ -80,7 +82,8 @@ function makeSettings() {
80
82
  "task.isolation.mode": "none",
81
83
  "task.simpleMode": "off",
82
84
  "task.simple": "default",
83
- "task.parentSpawns": "*",
85
+ "task.parentSpawns": "executor,architect,planner,critic",
86
+ "task.allowedAgents": ["executor", "architect", "planner", "critic"],
84
87
  disabledExtensions: [],
85
88
  "memory.backend": "off",
86
89
  "edit.fuzzyMatch": true,
@@ -94,14 +97,16 @@ function makeSettings() {
94
97
  getGroup: (group: string) => {
95
98
  if (group === "skills")
96
99
  return { enabled: true, enablePiUser: true, enablePiProject: true, customDirectories: [] };
97
- if (group === "task") return { disabledAgents: [] };
100
+ if (group === "task") return { disabledAgents: [], agents: [], allowedAgents: values["task.allowedAgents"] };
98
101
  return {};
99
102
  },
100
103
  getNotificationSettingsSnapshot: () => ({ enabled: false, telegram: {}, discord: {}, slack: {} }),
104
+ // The catalog documents the default configuration, where autorouting is off.
105
+ getEffectiveAutorouting: () => ({ active: false }),
101
106
  };
102
107
  }
103
108
 
104
- function makeSession(cwd: string = path.resolve(import.meta.dir, "../..")): any {
109
+ function makeSession(cwd: string): any {
105
110
  const settings = makeSettings();
106
111
  return {
107
112
  cwd,
@@ -113,6 +118,7 @@ function makeSession(cwd: string = path.resolve(import.meta.dir, "../..")): any
113
118
  hasEditTool: true,
114
119
  taskDepth: 0,
115
120
  currentAgentType: "executor",
121
+ rescopeSessionCwd: async () => ({ from: cwd, to: cwd }),
116
122
  getSessionFile: () => null,
117
123
  getSessionSpawns: () => null,
118
124
  getSessionId: () => "catalog",
@@ -316,7 +322,21 @@ export async function generateToolCatalogData(
316
322
  options: ToolCatalogGenerationOptions = {},
317
323
  ): Promise<Record<string, GeneratedToolCatalogEntry>> {
318
324
  const previousEditVariant = process.env.GJC_EDIT_VARIANT;
325
+ const previousHome = process.env.HOME;
326
+ const previousGjcConfigDir = process.env.GJC_CONFIG_DIR;
327
+ const previousPiConfigDir = process.env.PI_CONFIG_DIR;
328
+ const previousGjcCodingAgentDir = process.env.GJC_CODING_AGENT_DIR;
329
+ const previousPiCodingAgentDir = process.env.PI_CODING_AGENT_DIR;
330
+ const isolatedRoot = await fs.mkdtemp(path.join(os.tmpdir(), "gjc-tool-catalog-"));
331
+ const gitInit = Bun.spawnSync(["git", "init", "--quiet", isolatedRoot]);
332
+ if (gitInit.exitCode !== 0)
333
+ throw new Error(`Failed to initialize isolated tool-catalog repository: ${gitInit.stderr}`);
319
334
  process.env.GJC_EDIT_VARIANT = "replace";
335
+ process.env.HOME = path.join(isolatedRoot, "home");
336
+ process.env.GJC_CONFIG_DIR = ".gjc-catalog";
337
+ process.env.PI_CONFIG_DIR = ".gjc-catalog";
338
+ process.env.GJC_CODING_AGENT_DIR = path.join(isolatedRoot, "agent");
339
+ process.env.PI_CODING_AGENT_DIR = path.join(isolatedRoot, "agent");
320
340
  const platform = options.platform ?? process.platform;
321
341
  const arch = options.arch ?? process.arch;
322
342
  try {
@@ -328,7 +348,7 @@ export async function generateToolCatalogData(
328
348
  ...HIDDEN_TOOL_DESCRIPTORS,
329
349
  ...PLATFORM_EXCLUDED_TOOL_DESCRIPTORS,
330
350
  } as Record<string, any>;
331
- const session = makeSession(options.cwd);
351
+ const session = makeSession(isolatedRoot);
332
352
  const output: Record<string, GeneratedToolCatalogEntry> = {};
333
353
  for (const [name, descriptor] of Object.entries(all)) {
334
354
  let fallback: AuditedFallback | undefined;
@@ -432,10 +452,14 @@ export async function generateToolCatalogData(
432
452
  const choose = <T>(key: string, descriptorValue: T | undefined): T | undefined =>
433
453
  fallback ? (read(key) as T | undefined) : ((read(key) as T | undefined) ?? descriptorValue);
434
454
  const intent = choose("intent", descriptor.metadata.intent);
455
+ const description = choose("description", descriptor.metadata.description);
435
456
  const entry: GeneratedToolCatalogEntry = {
436
457
  name,
437
458
  label: choose("label", descriptor.presentation.label),
438
- description: choose("description", descriptor.metadata.description),
459
+ description:
460
+ name === "task" && typeof description === "string"
461
+ ? description.replace(/\n# reviewer\n[^\n]*\n\n/g, "")
462
+ : description,
439
463
  parameters: serializeCatalogValue(name, "parameters", parameters) as Record<string, unknown>,
440
464
  strict: choose("strict", descriptor.metadata.strict),
441
465
  hidden: choose("hidden", descriptor.metadata.hidden),
@@ -465,6 +489,17 @@ export async function generateToolCatalogData(
465
489
  } finally {
466
490
  if (previousEditVariant === undefined) delete process.env.GJC_EDIT_VARIANT;
467
491
  else process.env.GJC_EDIT_VARIANT = previousEditVariant;
492
+ if (previousHome === undefined) delete process.env.HOME;
493
+ else process.env.HOME = previousHome;
494
+ if (previousGjcConfigDir === undefined) delete process.env.GJC_CONFIG_DIR;
495
+ else process.env.GJC_CONFIG_DIR = previousGjcConfigDir;
496
+ if (previousPiConfigDir === undefined) delete process.env.PI_CONFIG_DIR;
497
+ else process.env.PI_CONFIG_DIR = previousPiConfigDir;
498
+ if (previousGjcCodingAgentDir === undefined) delete process.env.GJC_CODING_AGENT_DIR;
499
+ else process.env.GJC_CODING_AGENT_DIR = previousGjcCodingAgentDir;
500
+ if (previousPiCodingAgentDir === undefined) delete process.env.PI_CODING_AGENT_DIR;
501
+ else process.env.PI_CODING_AGENT_DIR = previousPiCodingAgentDir;
502
+ await fs.rm(isolatedRoot, { recursive: true, force: true });
468
503
  }
469
504
  }
470
505
 
@@ -6,7 +6,7 @@ import {
6
6
  retireOwnedRegistrationForDeadLetter,
7
7
  unregisterOwnedRegistration,
8
8
  } from "../session/terminal-abort";
9
- import type { AgentProgress, AgentSource } from "../task/types";
9
+ import type { AgentProgress, AgentSource, LocalErrorSummary } from "../task/types";
10
10
 
11
11
  const DELIVERY_RETRY_BASE_MS = 500;
12
12
  const DELIVERY_RETRY_MAX_MS = 30_000;
@@ -42,6 +42,8 @@ export interface AsyncJob {
42
42
  errorText?: string;
43
43
  /** Safe, bounded cause when session setup failed before the LLM began work. */
44
44
  setupFailureSummary?: string;
45
+ /** Safe, bounded summary of a terminal local (non-provider) failure kind. */
46
+ localErrorSummary?: LocalErrorSummary;
45
47
  metadata?: AsyncJobMetadata;
46
48
  /**
47
49
  * Registry id of the agent that registered the job (e.g. "0-Main",
@@ -85,7 +87,7 @@ export interface AsyncJobMetadata {
85
87
  */
86
88
  export type SubagentRunOutcome =
87
89
  | { kind: "completed"; text: string }
88
- | { kind: "failed"; text: string; setupFailureSummary?: string }
90
+ | { kind: "failed"; text: string; setupFailureSummary?: string; localErrorSummary?: LocalErrorSummary }
89
91
  | { kind: "paused"; note?: string };
90
92
 
91
93
  /** Canonical lifecycle of a subagent across pause/resume cycles. */
@@ -985,6 +987,7 @@ export class AsyncJobManager {
985
987
  if (outcome.kind === "failed") {
986
988
  job.status = "failed";
987
989
  job.setupFailureSummary = outcome.setupFailureSummary;
990
+ job.localErrorSummary = outcome.localErrorSummary;
988
991
  this.#freezeEndTime(job);
989
992
  job.errorText = outcome.text;
990
993
  this.#markRecordTerminal(id, "failed", job.generation);