@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
@@ -4,7 +4,7 @@ import { formatDuration, logger, prompt } from "@gajae-code/utils";
4
4
  import * as z from "zod/v4";
5
5
  import { type AsyncJob, AsyncJobManager, jobElapsedMs, type SubagentRecord } from "../async";
6
6
  import subagentDescription from "../prompts/tools/subagent.md" with { type: "text" };
7
- import type { AgentProgress, AgentSource, TaskToolDetails } from "../task/types";
7
+ import type { AgentProgress, AgentSource, LocalErrorSummary } from "../task/types";
8
8
  import { Ellipsis, truncateToWidth } from "../tui";
9
9
  import type { ToolSession } from "./index";
10
10
  import { replaceTabs } from "./render-utils";
@@ -85,6 +85,8 @@ export interface SubagentSnapshot {
85
85
  errorText?: string;
86
86
  /** Safe setup failure cause retained from the executor launch path. */
87
87
  setupFailureSummary?: string;
88
+ /** Safe, bounded summary of a terminal local (non-provider) failure (e.g. local_buffer_overflow). */
89
+ localErrorSummary?: LocalErrorSummary;
88
90
  resultPreview?: string;
89
91
  outputRef?: string;
90
92
  truncated?: boolean;
@@ -92,8 +94,8 @@ export interface SubagentSnapshot {
92
94
  steerMessage?: string;
93
95
  steerState?: "queued" | "resume_queued" | "resume_started";
94
96
  steerPauseRequested?: boolean;
95
- /** Live streaming progress for the awaited subagent (await panel only; UI detail). */
96
- progress?: AgentProgress;
97
+ /** Bounded live progress approved for the await panel and public tool details. */
98
+ progress?: SubagentLiveProgress;
97
99
  /** True when a live in-session progress producer exists for this subagent. */
98
100
  liveProgressAvailable?: boolean;
99
101
  /** Model the subagent actually runs on (after any auth fallback). */
@@ -106,6 +108,63 @@ export interface SubagentSnapshot {
106
108
  fastMode?: boolean;
107
109
  }
108
110
 
111
+ /**
112
+ * Public await-panel progress. This is deliberately not `AgentProgress`: raw
113
+ * progress contains model deltas, tool arguments, arbitrary output, and nested
114
+ * task payloads that must never enter tool-result, ACP, or telemetry envelopes.
115
+ */
116
+ export interface SubagentLiveProgress {
117
+ id: string;
118
+ status: AgentProgress["status"];
119
+ currentTool?: string;
120
+ recentTool?: string;
121
+ recentOutputSummary?: { lineCount: number };
122
+ fastMode?: boolean;
123
+ retryState?: {
124
+ attempt: number;
125
+ maxAttempts: number;
126
+ unbounded?: boolean;
127
+ kind: NonNullable<AgentProgress["retryState"]>["kind"];
128
+ provider?: string;
129
+ lastProviderProgressAtMs?: number;
130
+ delayMs: number;
131
+ startedAtMs: number;
132
+ };
133
+ retryFailure?: { attempt: number };
134
+ }
135
+
136
+ function toSubagentLiveProgress(progress: AgentProgress): SubagentLiveProgress {
137
+ return {
138
+ id: progress.id,
139
+ status: progress.status,
140
+ ...(progress.currentTool ? { currentTool: progress.currentTool } : {}),
141
+ ...(progress.currentTool === undefined && progress.recentTools[0]
142
+ ? { recentTool: progress.recentTools[0].tool }
143
+ : {}),
144
+ ...(progress.recentOutput.length > 0
145
+ ? { recentOutputSummary: { lineCount: Math.min(progress.recentOutput.length, 6) } }
146
+ : {}),
147
+ ...(progress.fastMode ? { fastMode: true } : {}),
148
+ ...(progress.retryState
149
+ ? {
150
+ retryState: {
151
+ attempt: progress.retryState.attempt,
152
+ maxAttempts: progress.retryState.maxAttempts,
153
+ ...(progress.retryState.unbounded ? { unbounded: true } : {}),
154
+ kind: progress.retryState.kind,
155
+ ...(progress.retryState.provider ? { provider: progress.retryState.provider } : {}),
156
+ ...(progress.retryState.lastProviderProgressAtMs !== undefined
157
+ ? { lastProviderProgressAtMs: progress.retryState.lastProviderProgressAtMs }
158
+ : {}),
159
+ delayMs: progress.retryState.delayMs,
160
+ startedAtMs: progress.retryState.startedAtMs,
161
+ },
162
+ }
163
+ : {}),
164
+ ...(progress.retryFailure ? { retryFailure: { attempt: progress.retryFailure.attempt } } : {}),
165
+ };
166
+ }
167
+
109
168
  export type SubagentAwaitOutcome = "completed" | "timed_out" | "interrupted";
110
169
 
111
170
  const AWAIT_INTERRUPTED_GUIDANCE =
@@ -723,6 +782,22 @@ export class SubagentTool implements AgentTool<typeof subagentSchema, SubagentTo
723
782
  if (snapshot.description) lines.push(`Description: ${snapshot.description}`);
724
783
  if (snapshot.outputRef) lines.push(`Output: ${snapshot.outputRef}`);
725
784
  if (snapshot.setupFailureSummary) lines.push(`Setup failure: ${snapshot.setupFailureSummary}`);
785
+ if (snapshot.localErrorSummary) {
786
+ const local = snapshot.localErrorSummary;
787
+ lines.push(`Local failure (${local.kind}): ${local.summary}`);
788
+ // Guidance is kind-conditional: an overflow is a local staging
789
+ // limit that reproduces on re-issue; a snapshot failure is a
790
+ // serialization defect, which re-issuing does NOT reproduce.
791
+ if (local.kind === "local_buffer_overflow") {
792
+ lines.push(
793
+ "This is a local gjc staging-buffer limit, not a provider or context-window failure; the same request reproduces it.",
794
+ );
795
+ } else if (local.kind === "local_snapshot_failure") {
796
+ lines.push(
797
+ "This is a local gjc event-serialization defect, not a provider failure; re-issuing is safe to retry.",
798
+ );
799
+ }
800
+ }
726
801
  if (snapshot.assignment) lines.push("Assignment:", "```", snapshot.assignment, "```");
727
802
  if (snapshot.steerMessage) {
728
803
  lines.push(`Steer (${snapshot.steerState ?? "queued"}):`, "```", snapshot.steerMessage, "```");
@@ -770,7 +845,7 @@ export class SubagentTool implements AgentTool<typeof subagentSchema, SubagentTo
770
845
  const progress = manager.getSubagentProgress(record.subagentId);
771
846
  return {
772
847
  liveProgressAvailable: true,
773
- ...(progress ? { progress } : {}),
848
+ ...(progress ? { progress: toSubagentLiveProgress(progress) } : {}),
774
849
  };
775
850
  }
776
851
 
@@ -853,6 +928,14 @@ export class SubagentTool implements AgentTool<typeof subagentSchema, SubagentTo
853
928
  ...(job.setupFailureSummary
854
929
  ? { setupFailureSummary: sanitizeText(job.setupFailureSummary, RECEIPT_PREVIEW_WIDTH) }
855
930
  : {}),
931
+ ...(job.localErrorSummary
932
+ ? {
933
+ localErrorSummary: {
934
+ kind: job.localErrorSummary.kind,
935
+ summary: sanitizeText(job.localErrorSummary.summary, RECEIPT_PREVIEW_WIDTH),
936
+ },
937
+ }
938
+ : {}),
856
939
  ...(outputRef ? { outputRef } : {}),
857
940
  ...(runningTimeoutGuidance ? { guidance: runningTimeoutGuidance } : {}),
858
941
  ...this.#modelFields(record),
@@ -1063,36 +1146,15 @@ function canonicalizeSnapshotForSignature(snapshot: SubagentSnapshot): unknown {
1063
1146
  };
1064
1147
  }
1065
1148
 
1066
- function canonicalizeProgressForSignature(progress: AgentProgress): unknown {
1149
+ function canonicalizeProgressForSignature(progress: SubagentLiveProgress): unknown {
1067
1150
  return {
1068
1151
  id: progress.id,
1069
- agent: progress.agent,
1070
- agentSource: progress.agentSource,
1071
1152
  status: progress.status,
1072
- task: progress.task,
1073
- assignment: progress.assignment ?? null,
1074
- description: progress.description ?? null,
1075
- lastIntent: progress.lastIntent ?? null,
1076
1153
  currentTool: progress.currentTool ?? null,
1077
- currentToolArgs: progress.currentToolArgs ?? null,
1078
- // currentToolStartMs intentionally excluded (only drives elapsed rendering).
1079
- recentTools: progress.recentTools.map(tool => ({ tool: tool.tool, args: tool.args })),
1080
- recentOutput: progress.recentOutput,
1081
- toolCount: progress.toolCount,
1082
- tokens: progress.tokens,
1083
- contextTokens: progress.contextTokens ?? null,
1084
- contextWindow: progress.contextWindow ?? null,
1085
- cost: progress.cost,
1086
- modelOverride: progress.modelOverride ?? null,
1087
- modelSubstitutionWarning: progress.modelSubstitutionWarning ?? null,
1088
- // The nested task panel renders this, so it must reach the signature or a
1089
- // fast-mode-only change would render differently while comparing byte-identical,
1090
- // suppressing the very update that introduces the glyph.
1154
+ recentTool: progress.recentTool ?? null,
1155
+ recentOutputSummary: progress.recentOutputSummary ?? null,
1091
1156
  fastMode: progress.fastMode ?? false,
1092
- // durationMs intentionally excluded (time-derived).
1093
- extractedToolData: progress.extractedToolData
1094
- ? canonicalizeExtractedToolDataForSignature(progress.extractedToolData)
1095
- : null,
1157
+ retryFailure: progress.retryFailure ?? null,
1096
1158
  retryState: progress.retryState
1097
1159
  ? {
1098
1160
  attempt: progress.retryState.attempt,
@@ -1101,52 +1163,7 @@ function canonicalizeProgressForSignature(progress: AgentProgress): unknown {
1101
1163
  kind: progress.retryState.kind,
1102
1164
  provider: progress.retryState.provider ?? null,
1103
1165
  delayMs: progress.retryState.delayMs,
1104
- errorMessage: progress.retryState.errorMessage,
1105
- // startedAtMs intentionally excluded (drives countdown only).
1106
1166
  }
1107
1167
  : null,
1108
- retryFailure: progress.retryFailure ?? null,
1109
- inflightTaskDetails: progress.inflightTaskDetails
1110
- ? canonicalizeTaskDetailsForSignature(progress.inflightTaskDetails)
1111
- : null,
1112
- };
1113
- }
1114
-
1115
- /**
1116
- * Nested `task` data (`extractedToolData.task` and `inflightTaskDetails`) is the
1117
- * one place the await signature reaches into a live, ticking structure: nested
1118
- * `AgentProgress` carries the same time-derived fields excluded above, and
1119
- * `TaskToolDetails` adds `totalDurationMs` / per-result `durationMs`. Signing it
1120
- * wholesale would defeat idle gating whenever an awaited subagent is itself inside
1121
- * a live `task` call, so these helpers canonicalize the rendered, non-time subset
1122
- * recursively (mutually recursive with `canonicalizeProgressForSignature`).
1123
- */
1124
- function canonicalizeExtractedToolDataForSignature(data: Record<string, unknown[]>): Record<string, unknown> {
1125
- const out: Record<string, unknown> = {};
1126
- for (const key of Object.keys(data)) {
1127
- // Only the `task` key holds time-ticking `TaskToolDetails`; other handler
1128
- // data (yield/report_finding/generic) is stable and passes through as-is.
1129
- out[key] = key === "task" ? (data[key] as TaskToolDetails[]).map(canonicalizeTaskDetailsForSignature) : data[key];
1130
- }
1131
- return out;
1132
- }
1133
-
1134
- function canonicalizeTaskDetailsForSignature(details: TaskToolDetails): unknown {
1135
- // `extractedToolData` is an untyped boundary (`Record<string, unknown[]>`), so
1136
- // guard each field instead of trusting the `TaskToolDetails` cast.
1137
- return {
1138
- // totalDurationMs intentionally excluded (time-derived).
1139
- results: Array.isArray(details.results) ? details.results.map(canonicalizeTaskResultForSignature) : null,
1140
- progress: Array.isArray(details.progress) ? details.progress.map(canonicalizeProgressForSignature) : null,
1141
- async: details.async
1142
- ? { state: details.async.state, jobId: details.async.jobId, type: details.async.type }
1143
- : null,
1144
1168
  };
1145
1169
  }
1146
-
1147
- function canonicalizeTaskResultForSignature(result: TaskToolDetails["results"][number]): unknown {
1148
- // Completed results do not tick, but drop `durationMs` so the only time-derived
1149
- // field in the receipt can never reintroduce idle churn.
1150
- const { durationMs: _durationMs, ...rest } = result;
1151
- return rest;
1152
- }
@@ -681,6 +681,35 @@ export const TOOL_CATALOG: Readonly<Record<string, ToolCatalogEntry>> = {
681
681
  "summary": "Execute Python or JavaScript code in an in-process eval backend",
682
682
  "concurrency": "exclusive"
683
683
  },
684
+ "python": {
685
+ "name": "python",
686
+ "label": "Python",
687
+ "description": "Execute Python in a persistent per-session REPL kernel.\n\nVariables, imports, and loaded data persist across calls in the current GJC session. The kernel runs in the session working directory. Each `execute` call is appended to a JSONL transcript under `.gjc/_session-{sessionid}/ipykernels/`; display artifacts are stored under `.gjc/_session-{sessionid}/ipykernels/artifacts/`.\n\n## Actions\n\n- `execute` (default) — run `code` in the persistent REPL. Requires `code`.\n- `clear` — dispose this session's Python kernel. The next `execute` starts a fresh kernel with no retained state.\n\n## Use\n\nUse this tool for stateful Python work. It is distinct from `eval`: each has a separate kernel and owner, so state is not shared between them.\n",
688
+ "parameters": {
689
+ "type": "object",
690
+ "properties": {
691
+ "action": {
692
+ "default": "execute",
693
+ "description": "\"execute\" runs `code` in the persistent per-session REPL and is the default. \"clear\" disposes this session's kernel; the next execute starts a fresh kernel.",
694
+ "type": "string",
695
+ "enum": [
696
+ "execute",
697
+ "clear"
698
+ ]
699
+ },
700
+ "code": {
701
+ "description": "Python source to execute when action is \"execute\" (required then, ignored for \"clear\").",
702
+ "type": "string"
703
+ }
704
+ },
705
+ "additionalProperties": false
706
+ },
707
+ "strict": true,
708
+ "deferrable": true,
709
+ "loadMode": "discoverable",
710
+ "summary": "Execute Python in a persistent per-session REPL kernel (every call is appended to the session transcript)",
711
+ "concurrency": "exclusive"
712
+ },
684
713
  "calc": {
685
714
  "name": "calc",
686
715
  "label": "Calc",
@@ -2058,6 +2087,15 @@ export const TOOL_CATALOG: Readonly<Record<string, ToolCatalogEntry>> = {
2058
2087
  "type": "string",
2059
2088
  "description": "per-task instructions; self-contained"
2060
2089
  },
2090
+ "tier": {
2091
+ "description": "Advisory unless autorouting is enabled; omitted routes as balanced.",
2092
+ "type": "string",
2093
+ "enum": [
2094
+ "fast",
2095
+ "balanced",
2096
+ "strong"
2097
+ ]
2098
+ },
2061
2099
  "executionMode": {
2062
2100
  "description": "typed executor mode: default keeps ordinary executor behavior; ultragoal-red-team injects the Ultragoal QA/red-team prompt fragment. Prefer this over free-form assignment text (#2698).",
2063
2101
  "type": "string",
@@ -2708,7 +2746,7 @@ export const TOOL_CATALOG: Readonly<Record<string, ToolCatalogEntry>> = {
2708
2746
  "skill_discovery": {
2709
2747
  "name": "skill_discovery",
2710
2748
  "label": "SkillDiscovery",
2711
- "description": "Discover project and user runtime skills without loading full skill content.\n\n<instruction>\n- Searches canonical GJC skill locations in precedence order: project `.gjc/skills` (ancestors from cwd to repo root, closest first), then user locations under the home directory: canonical `<config>/agent/skills`, configured legacy `<config>/skills`, and historical legacy `.gjc/skills`. `<config>` is the home-relative directory name from `GJC_CONFIG_DIR`, then `PI_CONFIG_DIR`, then `.gjc`; even an absolute-looking configured name is joined beneath `<home>`. Project scope shadows user scope; within a scope, earlier locations above win. Bundled GJC workflow skills (`deep-interview`, `ralplan`, `team`, `ultragoal`) are always available and cannot be replaced by filesystem skills.\n- Returns thin metadata only: name, description, source scope, path, and use conditions when present.\n- Claude Code (`.claude/skills`) and Codex (`.codex/skills`) layouts are explicit import sources into `.gjc`, never invokable candidates. They are not returned as candidates; instead, each convention skill found in a trusted scope is reported in `diagnostics` with the exact copy command that enables it (copy into `.gjc/skills`), so a skill placed in a documented convention location is discoverable in a normal session without being silently loaded.\n- Discovery is on by default in a normal session. When zero candidates are returned because discovery config is disabled (`skills.enabled` master switch, or `skills.trustProjectSkills` / `skills.trustUserSkills` scope trust), the result carries a `notice` explaining which setting blocked the search — an empty result without a `notice` means the searched scopes genuinely contain no matching skills.\n- When skills were scanned but not advertised (protected-name collision with a bundled workflow skill, include/ignore/disable policy filters, invalid frontmatter, shadowing), the result carries a bounded `diagnostics` list explaining why.\n- To load a selected skill's full `SKILL.md`, invoke it through the existing `skill` tool with the exact `name` returned here.\n</instruction>\n\nInput:\n- `query` (optional): words to match against skill name, description, source, or use conditions.\n- `source` (optional): `all`, `project`, or `user`.\n- `limit` (optional): maximum results, 1-50.",
2749
+ "description": "Discover project and user runtime skills without loading full skill content.\n\n<instruction>\n- Searches canonical GJC skill locations in precedence order: project `.gjc/skills` (ancestors from cwd to repo root, closest first), then user locations under the home directory: canonical `<config>/agent/skills`, configured legacy `<config>/skills`, and historical legacy `.gjc/skills`. `<config>` is the home-relative directory name from `GJC_CONFIG_DIR`, then `PI_CONFIG_DIR`, then `.gjc`; even an absolute-looking configured name is joined beneath `<home>`. Project scope shadows user scope; within a scope, earlier locations above win. Bundled GJC workflow skills (`autoresearch`, `deep-interview`, `ralplan`, `ultragoal`) are always available and cannot be replaced by filesystem skills.\n- Returns thin metadata only: name, description, source scope, path, and use conditions when present.\n- Claude Code (`.claude/skills`) and Codex (`.codex/skills`) layouts are explicit import sources into `.gjc`, never invokable candidates. They are not returned as candidates; instead, each convention skill found in a trusted scope is reported in `diagnostics` with the exact copy command that enables it (copy into `.gjc/skills`), so a skill placed in a documented convention location is discoverable in a normal session without being silently loaded.\n- Discovery is on by default in a normal session. When zero candidates are returned because discovery config is disabled (`skills.enabled` master switch, or `skills.trustProjectSkills` / `skills.trustUserSkills` scope trust), the result carries a `notice` explaining which setting blocked the search — an empty result without a `notice` means the searched scopes genuinely contain no matching skills.\n- When skills were scanned but not advertised (protected-name collision with a bundled workflow skill, include/ignore/disable policy filters, invalid frontmatter, shadowing), the result carries a bounded `diagnostics` list explaining why.\n- To load a selected skill's full `SKILL.md`, invoke it through the existing `skill` tool with the exact `name` returned here.\n</instruction>\n\nInput:\n- `query` (optional): words to match against skill name, description, source, or use conditions.\n- `source` (optional): `all`, `project`, or `user`.\n- `limit` (optional): maximum results, 1-50.",
2712
2750
  "parameters": {
2713
2751
  "type": "object",
2714
2752
  "properties": {
@@ -2799,7 +2837,7 @@ export const TOOL_CATALOG: Readonly<Record<string, ToolCatalogEntry>> = {
2799
2837
  "skill": {
2800
2838
  "name": "skill",
2801
2839
  "label": "Skill",
2802
- "description": "Invoke another available skill in the current turn.\n\n<conditions>\n- A SKILL document instructs you to chain into another skill on completion (e.g. ralplan → ultragoal)\n- You finished one skill's workflow and the next step requires another skill's full prompt context\n</conditions>\n\n<instruction>\n- `name` is the skill name as it appears in `/skill:<name>` (e.g. `ralplan`, `ultragoal`, `team`, `deep-interview`)\n- `args` is the free-form argument string the skill would receive after `/skill:<name>` on the command line\n- The tool loads the callee's SKILL.md into the current turn and handles native workflow caller→callee state handoff when the caller is one of the built-in GJC workflows.\n- The chain is refused while a native workflow caller is still active. If your current skill is one of `deep-interview`, `ralplan`, `ultragoal`, or `team` and has not yet reached a terminal phase, prepare it first with `gjc state <skill> write --input '{\"current_phase\":\"handoff\"}' --json`; no other handoff command is needed. Runtime project/user skills do not use `gjc state <skill>`.\n- Call once per chain step. To chain `A → B → C`, A calls `skill(B)`; B's next agent turn calls `skill(C)`.\n</instruction>\n\n<critical>\n- Do NOT use this tool to \"remind yourself\" of a skill you're already running. The current SKILL.md is already in your context.\n- Do NOT chain into the same skill recursively. If a skill's flow needs another iteration, follow its in-document instructions.\n- `name` MUST be one concrete skill name, NOT a glob or wildcard. Passing `*`, `?`, or a pattern like `git-*` is rejected immediately — the `--skills '*'` launch filter is unrelated to this tool's `name`.\n- The chained skill's planning/execution-boundary rules still apply. Chaining does not grant execution approval.\n</critical>\n\n<examples>\n# Hand off from ralplan to ultragoal after an approved plan\n{\"name\": \"ultragoal\", \"args\": \"track execution of .gjc/plans/ralplan/<run-id>/pending-approval.md\"}\n\n# Trigger deep-interview with no arguments\n{\"name\": \"deep-interview\"}\n</examples>",
2840
+ "description": "Invoke another available skill in the current turn.\n\n<conditions>\n- A SKILL document instructs you to chain into another skill on completion (e.g. ralplan → ultragoal)\n- You finished one skill's workflow and the next step requires another skill's full prompt context\n</conditions>\n\n<instruction>\n- `name` is the skill name as it appears in `/skill:<name>` (e.g. `ralplan`, `ultragoal`, `autoresearch`, `deep-interview`)\n- `args` is the free-form argument string the skill would receive after `/skill:<name>` on the command line\n- The tool loads the callee's SKILL.md into the current turn and handles native workflow caller→callee state handoff when the caller is one of the built-in GJC workflows.\n- The chain is refused while a native workflow caller is still mid-flight. `autoresearch` chains from any of its phases (`intake`/`research`/`verdict`) — a research mission is always handoff-ready. `deep-interview` chains once its final spec is persisted (phase `handoff`), and `ralplan` chains from `final` or `handoff`. Only a mid-flight `ralplan` or `ultragoal` needs preparation first: `gjc state <skill> write --input '{\"current_phase\":\"handoff\"}' --json`; no other handoff command is needed. Runtime project/user skills do not use `gjc state <skill>`.\n- Call once per chain step. To chain `A → B → C`, A calls `skill(B)`; B's next agent turn calls `skill(C)`.\n</instruction>\n\n<critical>\n- Do NOT use this tool to \"remind yourself\" of a skill you're already running. The current SKILL.md is already in your context.\n- Do NOT chain into the same skill recursively. If a skill's flow needs another iteration, follow its in-document instructions.\n- `name` MUST be one concrete skill name, NOT a glob or wildcard. Passing `*`, `?`, or a pattern like `git-*` is rejected immediately — the `--skills '*'` launch filter is unrelated to this tool's `name`.\n- The chained skill's planning/execution-boundary rules still apply. Chaining does not grant execution approval.\n</critical>\n\n<examples>\n# Hand off from ralplan to ultragoal after an approved plan\n{\"name\": \"ultragoal\", \"args\": \"track execution of .gjc/plans/ralplan/<run-id>/pending-approval.md\"}\n\n# Trigger deep-interview with no arguments\n{\"name\": \"deep-interview\"}\n</examples>",
2803
2841
  "parameters": {
2804
2842
  "type": "object",
2805
2843
  "properties": {
@@ -2856,6 +2894,30 @@ export const TOOL_CATALOG: Readonly<Record<string, ToolCatalogEntry>> = {
2856
2894
  "loadMode": "essential",
2857
2895
  "intent": "omit"
2858
2896
  },
2897
+ "move_session": {
2898
+ "name": "move_session",
2899
+ "label": "Move Session",
2900
+ "description": "Rescope the session to a narrower working directory.\n\nUse this only when the session's working directory is a broad launcher root (for example a\nmulti-repo workspace like `~/Projects`) and the task has clearly converged on one subdirectory\nor repository: after this call, every later turn resolves relative paths and the bash default\ncwd from the new directory, and project-scoped plugins/capabilities reload for it.\n\n- `path` must be an existing directory; relative paths resolve against the current session cwd.\n The canonical target must be strictly inside the current session directory — moves to a\n parent, a sibling project, or an unrelated absolute path are refused.\n- A session can be moved this way at most once, and never while another move is running; a\n rejected call does not consume the move. Use it once the target repo is identified — not\n speculatively — because the session file and caches move with the session.\n- This tool is unavailable in subagent sessions and restricted profiles; ask the top-level\n session to rescope instead.",
2901
+ "parameters": {
2902
+ "type": "object",
2903
+ "properties": {
2904
+ "path": {
2905
+ "type": "string",
2906
+ "description": "target directory: absolute, or relative to the current session cwd"
2907
+ }
2908
+ },
2909
+ "required": [
2910
+ "path"
2911
+ ],
2912
+ "additionalProperties": false
2913
+ },
2914
+ "strict": true,
2915
+ "deferrable": false,
2916
+ "loadMode": "essential",
2917
+ "nonAbortable": true,
2918
+ "concurrency": "exclusive",
2919
+ "intent": "omit"
2920
+ },
2859
2921
  "yield": {
2860
2922
  "name": "yield",
2861
2923
  "label": "Submit Result",
@@ -1,6 +1,5 @@
1
1
  import { Database } from "bun:sqlite";
2
2
  import * as fs from "node:fs/promises";
3
- import * as path from "node:path";
4
3
  import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@gajae-code/agent-core";
5
4
  import type { Component } from "@gajae-code/tui";
6
5
  import { Text } from "@gajae-code/tui";
@@ -17,6 +16,7 @@ import type { ToolSession } from "../sdk";
17
16
  import { Ellipsis, Hasher, type RenderCache, renderStatusLine, truncateToWidth } from "../tui";
18
17
  import { resolveFileDisplayMode } from "../utils/file-display-mode";
19
18
  import { parseArchivePathCandidates } from "./archive-reader";
19
+ import { formatFileWriteError, writeFileAtomically } from "./atomic-file-write";
20
20
  import { assertEditableFile } from "./auto-generated-guard";
21
21
  import {
22
22
  type ConflictEntry,
@@ -249,11 +249,6 @@ export class WriteTool implements AgentTool<typeof writeSchema, WriteToolDetails
249
249
  ): Promise<AgentToolResult<WriteToolDetails>> {
250
250
  const isZip = resolvedArchivePath.absolutePath.toLowerCase().endsWith(".zip");
251
251
 
252
- const parentDir = path.dirname(resolvedArchivePath.absolutePath);
253
- if (parentDir && parentDir !== ".") {
254
- await fs.mkdir(parentDir, { recursive: true });
255
- }
256
-
257
252
  if (isZip) {
258
253
  const zipEntries: Record<string, Uint8Array> = {};
259
254
 
@@ -275,9 +270,9 @@ export class WriteTool implements AgentTool<typeof writeSchema, WriteToolDetails
275
270
  try {
276
271
  const { zipSync } = await loadFflate();
277
272
  const zipBuffer = zipSync(zipEntries);
278
- await Bun.write(resolvedArchivePath.absolutePath, zipBuffer);
273
+ await writeFileAtomically(resolvedArchivePath.absolutePath, zipBuffer);
279
274
  } catch (error) {
280
- throw new ToolError(error instanceof Error ? error.message : String(error));
275
+ throw new ToolError(formatFileWriteError(error, resolvedArchivePath.absolutePath, { destUnchanged: true }));
281
276
  }
282
277
  } else {
283
278
  const archiveEntries: Record<string, string | File> = {};
@@ -304,9 +299,11 @@ export class WriteTool implements AgentTool<typeof writeSchema, WriteToolDetails
304
299
  archiveEntries[resolvedArchivePath.archiveSubPath] = content;
305
300
 
306
301
  try {
307
- await Bun.Archive.write(resolvedArchivePath.absolutePath, archiveEntries);
302
+ const archive = new Bun.Archive(archiveEntries);
303
+ const archiveBytes = await archive.bytes();
304
+ await writeFileAtomically(resolvedArchivePath.absolutePath, archiveBytes);
308
305
  } catch (error) {
309
- throw new ToolError(error instanceof Error ? error.message : String(error));
306
+ throw new ToolError(formatFileWriteError(error, resolvedArchivePath.absolutePath, { destUnchanged: true }));
310
307
  }
311
308
  }
312
309
 
@@ -748,9 +745,10 @@ export class WriteTool implements AgentTool<typeof writeSchema, WriteToolDetails
748
745
  try {
749
746
  await bridgePromise;
750
747
  } catch (error) {
751
- throw new ToolError(error instanceof Error ? error.message : String(error));
748
+ throw new ToolError(formatFileWriteError(error, absolutePath));
752
749
  }
753
750
  invalidateFsScanAfterWrite(absolutePath);
751
+ this.session.fileReadCache?.invalidate(absolutePath);
754
752
  const displayPath = formatPathRelativeToCwd(absolutePath, this.session.cwd);
755
753
  let resultText = `Successfully wrote ${cleanContent.length} bytes to ${displayPath}`;
756
754
  if (stripped) {
@@ -759,8 +757,14 @@ export class WriteTool implements AgentTool<typeof writeSchema, WriteToolDetails
759
757
  return { content: [{ type: "text", text: resultText }], details: {} };
760
758
  }
761
759
 
762
- const diagnostics = await this.#writethrough(absolutePath, cleanContent, signal, undefined, batchRequest);
760
+ let diagnostics: FileDiagnosticsResult | undefined;
761
+ try {
762
+ diagnostics = await this.#writethrough(absolutePath, cleanContent, signal, undefined, batchRequest);
763
+ } catch (error) {
764
+ throw new ToolError(formatFileWriteError(error, absolutePath));
765
+ }
763
766
  invalidateFsScanAfterWrite(absolutePath);
767
+ this.session.fileReadCache?.invalidate(absolutePath);
764
768
 
765
769
  const displayPath = formatPathRelativeToCwd(absolutePath, this.session.cwd);
766
770
  let resultText = `Successfully wrote ${cleanContent.length} bytes to ${displayPath}`;
@@ -0,0 +1,14 @@
1
+ /** Escape a string for interpolation inside a double- or single-quoted XML attribute. */
2
+ export function escapeXmlAttribute(input: string): string {
3
+ if (!/[&<>"']/.test(input)) return input;
4
+ let output = "";
5
+ for (const char of input) {
6
+ if (char === "&") output += "&amp;";
7
+ else if (char === "<") output += "&lt;";
8
+ else if (char === ">") output += "&gt;";
9
+ else if (char === '"') output += "&quot;";
10
+ else if (char === "'") output += "&apos;";
11
+ else output += char;
12
+ }
13
+ return output;
14
+ }
@@ -9,7 +9,7 @@
9
9
  import * as os from "node:os";
10
10
  import { type AuthStorage, getBundledModels } from "@gajae-code/ai/core";
11
11
  import { decodeJwt } from "@gajae-code/ai/utils/oauth/openai-codex";
12
- import { $env, readSseJson } from "@gajae-code/utils";
12
+ import { $env, readSseJson, sanitizeHeaderComponent } from "@gajae-code/utils";
13
13
  import packageJson from "../../../../package.json" with { type: "json" };
14
14
  import type { SearchResponse, SearchSource } from "../../../web/search/types";
15
15
  import { SearchProviderError } from "../../../web/search/types";
@@ -158,7 +158,7 @@ function buildCodexHeaders(accessToken: string, accountId: string): Record<strin
158
158
  "chatgpt-account-id": accountId,
159
159
  "OpenAI-Beta": "responses=experimental",
160
160
  originator: "pi",
161
- "User-Agent": `pi/${packageJson.version} (${os.platform()} ${os.release()}; ${os.arch()})`,
161
+ "User-Agent": `pi/${packageJson.version} (${sanitizeHeaderComponent(os.platform())} ${sanitizeHeaderComponent(os.release())}; ${sanitizeHeaderComponent(os.arch())})`,
162
162
  Accept: "text/event-stream",
163
163
  "Content-Type": "application/json",
164
164
  };
@@ -5,8 +5,8 @@ import {
5
5
  } from "./workflow-intent-report";
6
6
 
7
7
  export const WORKFLOW_INTENT_DIFF_CUSTOM_TYPE = "workflow-intent-diff";
8
- export const WORKFLOW_INTENT_ROUTES = ["direct", "deep-interview", "ralplan", "ultragoal", "team"] as const;
9
- export const WORKFLOW_ESCALATION_ROUTES = ["deep-interview", "ralplan", "ultragoal", "team"] as const;
8
+ export const WORKFLOW_INTENT_ROUTES = ["direct", "deep-interview", "ralplan", "ultragoal", "autoresearch"] as const;
9
+ export const WORKFLOW_ESCALATION_ROUTES = ["deep-interview", "ralplan", "ultragoal", "autoresearch"] as const;
10
10
 
11
11
  export type WorkflowIntentRoute = (typeof WORKFLOW_INTENT_ROUTES)[number];
12
12
  export type WorkflowEscalationRoute = (typeof WORKFLOW_ESCALATION_ROUTES)[number];
@@ -77,11 +77,12 @@ const ARCHITECTURE_SEQUENCE_PATTERNS = [
77
77
  /\bdestructive\b/i,
78
78
  ] as const;
79
79
 
80
- const TEAM_PATTERNS = [
81
- /\buse (?:a )?team\b/i,
82
- /\bcoordinated (?:persistent )?workers\b/i,
83
- /\bpersistent workers\b/i,
84
- /\bworker coordination\b/i,
80
+ const AUTORESEARCH_PATTERNS = [
81
+ /\buse (?:a )?autoresearch\b/i,
82
+ /\b(?:research|investigate|experiment|benchmark|measure)\b[^.!?\n]{0,60}\b(?:mission|finding|evidence|verdict|dataset|against|compare|hypothesis)\b/i,
83
+ /\b(?:mission|finding|evidence|verdict|dataset|against|compare|hypothesis)\b[^.!?\n]{0,60}\b(?:research|investigate|experiment|benchmark|measure)\b/i,
84
+ /\brun (?:a |the )?(?:bounded )?research (?:mission|task|investigation)\b/i,
85
+ /\b(?:benchmark|experiment)\b[^.!?\n]{0,40}\b(?:and|then|to)\b[^.!?\n]{0,40}\b(?:report|measure|compare)\b/i,
85
86
  ] as const;
86
87
 
87
88
  const ROOT_CAUSE_TRIGGERS = [
@@ -172,12 +173,12 @@ function classifyRoute(text: string): RouteMatch {
172
173
  };
173
174
  }
174
175
 
175
- if (matchesAny(text, TEAM_PATTERNS)) {
176
+ if (matchesAny(text, AUTORESEARCH_PATTERNS)) {
176
177
  return {
177
- route: "team",
178
- reason: "coordinated persistent workers requested",
179
- recommendedInvocation: "/skill:team",
180
- triggers: ["coordinated workers"],
178
+ route: "autoresearch",
179
+ reason: "goal-directed research mission requested",
180
+ recommendedInvocation: "/skill:autoresearch",
181
+ triggers: ["research mission"],
181
182
  };
182
183
  }
183
184
 
@@ -15,7 +15,7 @@ export interface WorkflowRouteCounts {
15
15
  readonly "deep-interview": number;
16
16
  readonly ralplan: number;
17
17
  readonly ultragoal: number;
18
- readonly team: number;
18
+ readonly autoresearch: number;
19
19
  }
20
20
 
21
21
  export interface WorkflowIntentReportEntry {
@@ -66,7 +66,7 @@ function emptyRouteCounts(): WorkflowRouteCounts {
66
66
  "deep-interview": 0,
67
67
  ralplan: 0,
68
68
  ultragoal: 0,
69
- team: 0,
69
+ autoresearch: 0,
70
70
  };
71
71
  }
72
72
 
@@ -87,8 +87,8 @@ function incrementRoute(counts: WorkflowRouteCounts, route: WorkflowIntentRoute)
87
87
  return { ...counts, ralplan: counts.ralplan + 1 };
88
88
  case "ultragoal":
89
89
  return { ...counts, ultragoal: counts.ultragoal + 1 };
90
- case "team":
91
- return { ...counts, team: counts.team + 1 };
90
+ case "autoresearch":
91
+ return { ...counts, autoresearch: counts.autoresearch + 1 };
92
92
  }
93
93
  }
94
94
 
@@ -102,8 +102,8 @@ function routeCount(counts: WorkflowRouteCounts, route: WorkflowIntentRoute): nu
102
102
  return counts.ralplan;
103
103
  case "ultragoal":
104
104
  return counts.ultragoal;
105
- case "team":
106
- return counts.team;
105
+ case "autoresearch":
106
+ return counts.autoresearch;
107
107
  }
108
108
  }
109
109
 
@@ -1,24 +0,0 @@
1
- import type { ASIData, MetricDirection, NumericMetricMap } from "./types";
2
- export declare const METRIC_LINE_PREFIX = "METRIC";
3
- export declare const ASI_LINE_PREFIX = "ASI";
4
- export declare const EXPERIMENT_MAX_LINES = 10;
5
- export declare const EXPERIMENT_MAX_BYTES: number;
6
- export declare function parseMetricLines(output: string): Map<string, number>;
7
- export declare function parseAsiLines(output: string): ASIData | null;
8
- export declare function mergeAsi(base: ASIData | null, override: ASIData | undefined): ASIData | undefined;
9
- export declare function commas(value: number): string;
10
- export declare function fmtNum(value: number, decimals?: number): string;
11
- export declare function formatNum(value: number | null, unit: string): string;
12
- export declare function formatElapsed(milliseconds: number): string;
13
- export declare function killTree(pid: number, signal?: NodeJS.Signals | number): void;
14
- export declare function isBetter(current: number, best: number, direction: MetricDirection): boolean;
15
- export declare function inferMetricUnitFromName(name: string): string;
16
- export declare function normalizePathSpec(value: string): string;
17
- export declare function pathMatchesSpec(pathValue: string, specValue: string): boolean;
18
- export declare function dedupeStrings(values: readonly string[]): string[];
19
- export declare function ensureNumericMetricMap(value: NumericMetricMap | undefined): NumericMetricMap;
20
- export declare function sanitizeAsi(value: {
21
- [key: string]: unknown;
22
- } | undefined): ASIData | undefined;
23
- export declare function tryGitStatus(cwd: string): Promise<string>;
24
- export declare function tryGitPrefix(cwd: string): Promise<string>;
@@ -1,2 +0,0 @@
1
- import type { ExtensionFactory } from "../extensibility/extensions";
2
- export declare const createAutoresearchExtension: ExtensionFactory;
@@ -1,17 +0,0 @@
1
- import type { SessionEntry } from "../session/session-manager";
2
- import type { RunRow, SessionRow } from "./storage";
3
- import type { AutoresearchRuntime, ExperimentResult, ExperimentState, MetricDef, MetricDirection, NumericMetricMap, ReconstructedControlState, RuntimeStore } from "./types";
4
- export declare function createExperimentState(): ExperimentState;
5
- export declare function createSessionRuntime(): AutoresearchRuntime;
6
- export declare function cloneExperimentState(state: ExperimentState): ExperimentState;
7
- export declare function currentResults(results: ExperimentResult[], segment: number): ExperimentResult[];
8
- export declare function findBaselineResult(results: ExperimentResult[], segment: number): ExperimentResult | null;
9
- export declare function findBaselineMetric(results: ExperimentResult[], segment: number): number | null;
10
- export declare function findBestKeptMetric(results: ExperimentResult[], segment: number, direction: MetricDirection): number | null;
11
- export declare function findBaselineRunNumber(results: ExperimentResult[], segment: number): number | null;
12
- export declare function findBaselineSecondary(results: ExperimentResult[], segment: number, knownMetrics: MetricDef[]): NumericMetricMap;
13
- export declare function sortedMedian(values: number[]): number;
14
- export declare function computeConfidence(results: ExperimentResult[], segment: number, direction: MetricDirection): number | null;
15
- export declare function buildExperimentState(session: SessionRow, loggedRuns: RunRow[]): ExperimentState;
16
- export declare function reconstructControlState(entries: SessionEntry[]): ReconstructedControlState;
17
- export declare function createRuntimeStore(): RuntimeStore;