@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
@@ -1,475 +0,0 @@
1
- import * as childProcess from "node:child_process";
2
- import * as fs from "node:fs";
3
- import * as path from "node:path";
4
- import { Text } from "@gajae-code/tui";
5
- import { formatBytes } from "@gajae-code/utils";
6
- import * as z from "zod/v4";
7
- import type { ToolDefinition } from "../../extensibility/extensions";
8
- import type { Theme } from "../../modes/theme/theme";
9
- import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, truncateTail } from "../../session/streaming-output";
10
- import { replaceTabs, shortenPath } from "../../tools/render-utils";
11
- import * as git from "../../utils/git";
12
- import { parseWorkDirDirtyPaths } from "../git";
13
- import {
14
- EXPERIMENT_MAX_BYTES,
15
- EXPERIMENT_MAX_LINES,
16
- formatElapsed,
17
- formatNum,
18
- killTree,
19
- parseAsiLines,
20
- parseMetricLines,
21
- tryGitPrefix,
22
- tryGitStatus,
23
- } from "../helpers";
24
- import { buildExperimentState } from "../state";
25
- import { openAutoresearchStorageIfExists } from "../storage";
26
- import type { AutoresearchToolFactoryOptions, RunDetails, RunExperimentProgressDetails } from "../types";
27
- import { DEFAULT_HARNESS_COMMAND } from "./init-experiment";
28
-
29
- const runExperimentSchema = z.object({
30
- timeout_seconds: z.number().describe("timeout in seconds (default 600)").optional(),
31
- });
32
-
33
- interface ProcessExecutionResult {
34
- exitCode: number | null;
35
- killed: boolean;
36
- logPath: string;
37
- output: string;
38
- }
39
-
40
- interface ProgressSnapshot {
41
- elapsed: string;
42
- runDirectory: string;
43
- fullOutputPath: string;
44
- tailOutput: string;
45
- truncation?: RunExperimentProgressDetails["truncation"];
46
- }
47
-
48
- export function createRunExperimentTool(
49
- options: AutoresearchToolFactoryOptions,
50
- ): ToolDefinition<typeof runExperimentSchema, RunDetails | RunExperimentProgressDetails> {
51
- return {
52
- name: "run_experiment",
53
- label: "Run Experiment",
54
- description:
55
- "Run any benchmark command. Output is captured automatically; `METRIC name=value` and `ASI key=value` lines printed by the command are parsed.",
56
- parameters: runExperimentSchema,
57
- defaultInactive: true,
58
- async execute(_toolCallId, params, signal, onUpdate, ctx) {
59
- const storage = await openAutoresearchStorageIfExists(ctx.cwd);
60
- const currentBranch = (await git.branch.current(ctx.cwd)) ?? null;
61
- const session = storage?.getActiveSessionForBranch(currentBranch) ?? null;
62
- if (!storage || !session) {
63
- return {
64
- content: [
65
- {
66
- type: "text",
67
- text: "Error: no active autoresearch session for the current branch. Call init_experiment first.",
68
- },
69
- ],
70
- };
71
- }
72
-
73
- const runtime = options.getRuntime(ctx);
74
-
75
- const abandonedPriorRun = (() => {
76
- const pending = storage.getPendingRun(session.id);
77
- if (!pending) return null;
78
- storage.abandonPendingRuns(session.id);
79
- return pending.id;
80
- })();
81
-
82
- const resolvedCommand = DEFAULT_HARNESS_COMMAND;
83
- const preRunStatus = await tryGitStatus(ctx.cwd);
84
- const workDirPrefix = await tryGitPrefix(ctx.cwd);
85
- const preRunDirtyPaths = parseWorkDirDirtyPaths(preRunStatus, workDirPrefix);
86
-
87
- const startedAt = Date.now();
88
- const insertedRun = storage.insertRun({
89
- sessionId: session.id,
90
- segment: session.currentSegment,
91
- command: resolvedCommand,
92
- logPath: "", // patched after we know the run id
93
- preRunDirtyPaths,
94
- startedAt,
95
- });
96
-
97
- const runDirectory = path.join(storage.projectDir, "runs", String(insertedRun.id).padStart(4, "0"));
98
- const benchmarkLogPath = path.join(runDirectory, "benchmark.log");
99
- fs.mkdirSync(runDirectory, { recursive: true });
100
- storage.updateRunLogPath(insertedRun.id, benchmarkLogPath);
101
-
102
- runtime.lastRunDuration = null;
103
- runtime.lastRunAsi = null;
104
- runtime.lastRunArtifactDir = runDirectory;
105
- runtime.lastRunNumber = insertedRun.id;
106
- runtime.lastRunSummary = null;
107
- runtime.runningExperiment = {
108
- startedAt,
109
- command: resolvedCommand,
110
- runDirectory,
111
- runNumber: insertedRun.id,
112
- };
113
- options.dashboard.updateWidget(ctx, runtime);
114
- options.dashboard.requestRender();
115
-
116
- const timeoutMs = Math.max(0, Math.floor((params.timeout_seconds ?? 600) * 1000));
117
- let execution: ProcessExecutionResult;
118
- try {
119
- execution = await executeProcess({
120
- command: ["bash", "-lc", resolvedCommand],
121
- cwd: ctx.cwd,
122
- logPath: benchmarkLogPath,
123
- timeoutMs,
124
- signal,
125
- onProgress: details => {
126
- onUpdate?.({
127
- content: [{ type: "text", text: details.tailOutput }],
128
- details: {
129
- phase: "running",
130
- elapsed: details.elapsed,
131
- truncation: details.truncation,
132
- fullOutputPath: details.fullOutputPath,
133
- runDirectory: details.runDirectory,
134
- },
135
- });
136
- },
137
- });
138
- } finally {
139
- runtime.runningExperiment = null;
140
- options.dashboard.updateWidget(ctx, runtime);
141
- options.dashboard.requestRender();
142
- }
143
-
144
- const completedAt = Date.now();
145
- const durationMs = completedAt - startedAt;
146
- const durationSeconds = durationMs / 1000;
147
- runtime.lastRunDuration = durationSeconds;
148
-
149
- const llmTruncation = truncateTail(execution.output, {
150
- maxBytes: EXPERIMENT_MAX_BYTES,
151
- maxLines: EXPERIMENT_MAX_LINES,
152
- });
153
- const displayTruncation = truncateTail(execution.output, {
154
- maxBytes: DEFAULT_MAX_BYTES,
155
- maxLines: DEFAULT_MAX_LINES,
156
- });
157
-
158
- const parsedMetricsMap = parseMetricLines(execution.output);
159
- const parsedMetrics = parsedMetricsMap.size > 0 ? Object.fromEntries(parsedMetricsMap.entries()) : null;
160
- const parsedPrimary = parsedMetricsMap.get(session.primaryMetric) ?? null;
161
- const parsedAsi = parseAsiLines(execution.output);
162
- runtime.lastRunAsi = parsedAsi;
163
-
164
- storage.markRunCompleted({
165
- runId: insertedRun.id,
166
- completedAt,
167
- durationMs,
168
- exitCode: execution.exitCode,
169
- timedOut: execution.killed,
170
- parsedPrimary,
171
- parsedMetrics,
172
- parsedAsi,
173
- });
174
-
175
- const passed = execution.exitCode === 0 && !execution.killed;
176
- const resultDetails: RunDetails = {
177
- runNumber: insertedRun.id,
178
- runDirectory,
179
- benchmarkLogPath,
180
- command: resolvedCommand,
181
- exitCode: execution.exitCode,
182
- durationSeconds,
183
- passed,
184
- crashed: execution.exitCode !== 0 || execution.killed,
185
- timedOut: execution.killed,
186
- tailOutput: displayTruncation.content,
187
- parsedMetrics,
188
- parsedPrimary,
189
- parsedAsi,
190
- metricName: session.primaryMetric,
191
- metricUnit: session.metricUnit,
192
- preRunDirtyPaths,
193
- abandonedPriorRun,
194
- truncation: llmTruncation.truncated ? llmTruncation : undefined,
195
- fullOutputPath: execution.logPath,
196
- };
197
-
198
- runtime.lastRunSummary = {
199
- command: resolvedCommand,
200
- durationSeconds,
201
- parsedAsi,
202
- parsedMetrics,
203
- parsedPrimary,
204
- passed,
205
- preRunDirtyPaths,
206
- runDirectory,
207
- runNumber: insertedRun.id,
208
- exitCode: execution.exitCode,
209
- timedOut: execution.killed,
210
- };
211
- runtime.autoResumeArmed = true;
212
- runtime.lastAutoResumePendingRunNumber = null;
213
-
214
- // Refresh state to reflect any prior abandonment changes (logged set unchanged).
215
- const refreshedSession = storage.getSessionById(session.id);
216
- if (refreshedSession) {
217
- runtime.state = buildExperimentState(refreshedSession, storage.listLoggedRuns(session.id));
218
- }
219
- options.dashboard.updateWidget(ctx, runtime);
220
- options.dashboard.requestRender();
221
-
222
- const headerLines: string[] = [];
223
- if (abandonedPriorRun !== null) {
224
- headerLines.push(`Note: abandoned prior pending run #${abandonedPriorRun} before starting this run.`);
225
- }
226
- const warningPrefix = headerLines.length > 0 ? `${headerLines.join("\n")}\n\n` : "";
227
-
228
- return {
229
- content: [
230
- {
231
- type: "text",
232
- text: warningPrefix + buildRunText(resultDetails, llmTruncation.content, runtime.state.bestMetric),
233
- },
234
- ],
235
- details: resultDetails,
236
- };
237
- },
238
- renderCall(_args, _options, theme): Text {
239
- return new Text(
240
- `${theme.fg("toolTitle", theme.bold("run_experiment"))} ${theme.fg("muted", DEFAULT_HARNESS_COMMAND)}`,
241
- 0,
242
- 0,
243
- );
244
- },
245
- renderResult(result, options, theme): Text {
246
- if (isProgressDetails(result.details)) {
247
- const header = theme.fg("warning", `Running ${result.details.elapsed}...`);
248
- const preview = replaceTabs(result.content.find(part => part.type === "text")?.text ?? "");
249
- return new Text(preview ? `${header}\n${theme.fg("dim", preview)}` : header, 0, 0);
250
- }
251
- const details = result.details;
252
- if (!details || !isRunDetails(details)) {
253
- return new Text(replaceTabs(result.content.find(part => part.type === "text")?.text ?? ""), 0, 0);
254
- }
255
- const statusText = renderStatus(details, theme);
256
- if (!options.expanded && details.tailOutput.trim().length === 0) {
257
- return new Text(statusText, 0, 0);
258
- }
259
- const preview = replaceTabs(
260
- options.expanded ? details.tailOutput : details.tailOutput.split("\n").slice(-5).join("\n"),
261
- );
262
- const suffix =
263
- options.expanded && details.truncation && details.fullOutputPath
264
- ? `\n${theme.fg("warning", `Full output: ${shortenPath(details.fullOutputPath)}`)}`
265
- : "";
266
- return new Text(preview ? `${statusText}\n${theme.fg("dim", preview)}${suffix}` : statusText, 0, 0);
267
- },
268
- };
269
- }
270
- async function executeProcess(opts: {
271
- command: string[];
272
- cwd: string;
273
- logPath: string;
274
- timeoutMs: number;
275
- signal?: AbortSignal;
276
- onProgress?(details: ProgressSnapshot): void;
277
- }): Promise<ProcessExecutionResult> {
278
- const { promise, resolve, reject } = Promise.withResolvers<ProcessExecutionResult>();
279
- const child = childProcess.spawn(opts.command[0] ?? "bash", opts.command.slice(1), {
280
- cwd: opts.cwd,
281
- detached: true,
282
- stdio: ["ignore", "pipe", "pipe"],
283
- });
284
-
285
- const tailChunks: Buffer[] = [];
286
- let chunksBytes = 0;
287
- let killedByTimeout = false;
288
- let resolved = false;
289
- let writeStream: fs.WriteStream | undefined = fs.createWriteStream(opts.logPath);
290
- let forceKillTimeout: NodeJS.Timeout | undefined;
291
-
292
- const closeWriteStream = (): Promise<void> => {
293
- if (!writeStream) return Promise.resolve();
294
- const stream = writeStream;
295
- writeStream = undefined;
296
- return new Promise<void>((resolveClose, rejectClose) => {
297
- stream.end((error?: Error | null) => {
298
- if (error) {
299
- rejectClose(error);
300
- return;
301
- }
302
- resolveClose();
303
- });
304
- });
305
- };
306
-
307
- const cleanup = (): void => {
308
- if (progressTimer) clearInterval(progressTimer);
309
- if (timeoutHandle) clearTimeout(timeoutHandle);
310
- if (forceKillTimeout) clearTimeout(forceKillTimeout);
311
- opts.signal?.removeEventListener("abort", abortHandler);
312
- };
313
-
314
- const finish = (callback: () => void): void => {
315
- if (resolved) return;
316
- resolved = true;
317
- cleanup();
318
- callback();
319
- };
320
-
321
- const appendChunk = (data: Buffer): void => {
322
- writeStream?.write(data);
323
- tailChunks.push(data);
324
- chunksBytes += data.length;
325
- while (chunksBytes > DEFAULT_MAX_BYTES * 2 && tailChunks.length > 1) {
326
- const removed = tailChunks.shift();
327
- if (removed) chunksBytes -= removed.length;
328
- }
329
- };
330
-
331
- const snapshot = (): ProgressSnapshot => {
332
- const tail = truncateTail(Buffer.concat(tailChunks).toString("utf8"), {
333
- maxBytes: DEFAULT_MAX_BYTES,
334
- maxLines: DEFAULT_MAX_LINES,
335
- });
336
- return {
337
- elapsed: formatElapsed(Date.now() - startedAt),
338
- runDirectory: path.dirname(opts.logPath),
339
- fullOutputPath: opts.logPath,
340
- tailOutput: tail.content,
341
- truncation: tail.truncated ? tail : undefined,
342
- };
343
- };
344
-
345
- const killTreeWithEscalation = (): void => {
346
- if (!child.pid) return;
347
- killTree(child.pid);
348
- forceKillTimeout = setTimeout(() => {
349
- if (child.pid) killTree(child.pid, "SIGKILL");
350
- }, 1_000);
351
- forceKillTimeout.unref?.();
352
- };
353
-
354
- const startedAt = Date.now();
355
- const progressTimer = opts.onProgress
356
- ? setInterval(() => {
357
- opts.onProgress?.(snapshot());
358
- }, 1000)
359
- : undefined;
360
- const timeoutHandle =
361
- opts.timeoutMs > 0
362
- ? setTimeout(() => {
363
- killedByTimeout = true;
364
- killTreeWithEscalation();
365
- }, opts.timeoutMs)
366
- : undefined;
367
-
368
- const abortHandler = (): void => {
369
- killTreeWithEscalation();
370
- };
371
- if (opts.signal?.aborted) {
372
- abortHandler();
373
- } else {
374
- opts.signal?.addEventListener("abort", abortHandler, { once: true });
375
- }
376
-
377
- child.stdout?.on("data", data => {
378
- appendChunk(data);
379
- });
380
- child.stderr?.on("data", data => {
381
- appendChunk(data);
382
- });
383
- child.on("error", error => {
384
- void closeWriteStream().finally(() => {
385
- finish(() => reject(error));
386
- });
387
- });
388
- child.on("close", async code => {
389
- try {
390
- await closeWriteStream();
391
- if (opts.signal?.aborted) {
392
- finish(() => reject(new Error("aborted")));
393
- return;
394
- }
395
- const output = await fs.promises.readFile(opts.logPath, "utf8");
396
- finish(() =>
397
- resolve({
398
- exitCode: code,
399
- killed: killedByTimeout,
400
- logPath: opts.logPath,
401
- output,
402
- }),
403
- );
404
- } catch (error) {
405
- finish(() => reject(error));
406
- }
407
- });
408
-
409
- return promise;
410
- }
411
-
412
- function buildRunText(details: RunDetails, outputPreview: string, bestMetric: number | null): string {
413
- const lines: string[] = [];
414
- lines.push(`Run #${details.runNumber} directory: ${details.runDirectory}`);
415
- if (details.timedOut) {
416
- lines.push(`TIMEOUT after ${details.durationSeconds.toFixed(1)}s`);
417
- } else if (details.exitCode !== 0) {
418
- lines.push(`FAILED with exit code ${details.exitCode} in ${details.durationSeconds.toFixed(1)}s`);
419
- } else {
420
- lines.push(`PASSED in ${details.durationSeconds.toFixed(1)}s`);
421
- }
422
- if (bestMetric !== null) {
423
- lines.push(`Current baseline ${details.metricName}: ${formatNum(bestMetric, details.metricUnit)}`);
424
- }
425
- if (details.parsedPrimary !== null) {
426
- lines.push(`Parsed ${details.metricName}: ${details.parsedPrimary}`);
427
- lines.push(`Next log_experiment metric: ${details.parsedPrimary}`);
428
- }
429
- if (details.parsedMetrics) {
430
- const secondaryEntries = Object.entries(details.parsedMetrics)
431
- .filter(([name]) => name !== details.metricName)
432
- .map(([name, value]) => [name, value] as const);
433
- const secondary = secondaryEntries.map(([name, value]) => `${name}=${value}`);
434
- if (secondary.length > 0) {
435
- lines.push(`Parsed metrics: ${secondary.join(", ")}`);
436
- lines.push(`Next log_experiment metrics: ${JSON.stringify(Object.fromEntries(secondaryEntries))}`);
437
- }
438
- }
439
- if (details.parsedAsi) {
440
- lines.push(`Parsed ASI keys: ${Object.keys(details.parsedAsi).join(", ")}`);
441
- }
442
- lines.push("");
443
- lines.push(outputPreview);
444
- if (details.truncation && details.fullOutputPath) {
445
- lines.push("");
446
- lines.push(
447
- `Output truncated (${formatBytes(EXPERIMENT_MAX_BYTES)} limit). Full output: ${details.fullOutputPath}`,
448
- );
449
- }
450
- return lines.join("\n").trimEnd();
451
- }
452
-
453
- function renderStatus(details: RunDetails, theme: Theme): string {
454
- if (details.timedOut) {
455
- return theme.fg("error", `TIMEOUT ${details.durationSeconds.toFixed(1)}s`);
456
- }
457
- if (details.exitCode !== 0) {
458
- return theme.fg("error", `FAIL exit=${details.exitCode} ${details.durationSeconds.toFixed(1)}s`);
459
- }
460
- const metric =
461
- details.parsedPrimary !== null
462
- ? ` ${details.metricName}=${formatNum(details.parsedPrimary, details.metricUnit)}`
463
- : "";
464
- return theme.fg("success", `PASS ${details.durationSeconds.toFixed(1)}s${metric}`);
465
- }
466
-
467
- function isRunDetails(value: unknown): value is RunDetails {
468
- if (typeof value !== "object" || value === null) return false;
469
- return "command" in value && "durationSeconds" in value;
470
- }
471
-
472
- function isProgressDetails(value: unknown): value is RunExperimentProgressDetails {
473
- if (typeof value !== "object" || value === null) return false;
474
- return "phase" in value && (value as { phase: unknown }).phase === "running";
475
- }
@@ -1,109 +0,0 @@
1
- import { Text } from "@gajae-code/tui";
2
- import * as z from "zod/v4";
3
- import type { ToolDefinition } from "../../extensibility/extensions";
4
- import type { Theme } from "../../modes/theme/theme";
5
- import { replaceTabs, truncateToWidth } from "../../tools/render-utils";
6
- import * as git from "../../utils/git";
7
- import { buildExperimentState } from "../state";
8
- import { openAutoresearchStorageIfExists } from "../storage";
9
- import type { AutoresearchToolFactoryOptions } from "../types";
10
-
11
- const updateNotesSchema = z.object({
12
- body: z.string().describe("replacement notes body"),
13
- append_idea: z.string().describe("append as bullet under Ideas instead of replacing body").optional(),
14
- });
15
-
16
- interface UpdateNotesDetails {
17
- notes: string;
18
- }
19
-
20
- export function createUpdateNotesTool(
21
- options: AutoresearchToolFactoryOptions,
22
- ): ToolDefinition<typeof updateNotesSchema, UpdateNotesDetails> {
23
- return {
24
- name: "update_notes",
25
- label: "Update Notes",
26
- description:
27
- "Persist the durable autoresearch playbook (goal, scope notes, hypotheses, ideas backlog) on the active session. Pass `body` to replace the entire notes blob, or `append_idea` to append a single bullet under an `## Ideas` section.",
28
- parameters: updateNotesSchema,
29
- defaultInactive: true,
30
- async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
31
- const storage = await openAutoresearchStorageIfExists(ctx.cwd);
32
- const currentBranch = (await git.branch.current(ctx.cwd)) ?? null;
33
- const session = storage?.getActiveSessionForBranch(currentBranch) ?? null;
34
- if (!storage || !session) {
35
- return {
36
- content: [
37
- {
38
- type: "text",
39
- text: "Error: no active autoresearch session for the current branch. Call init_experiment first.",
40
- },
41
- ],
42
- };
43
- }
44
-
45
- const nextNotes =
46
- params.append_idea !== undefined && params.append_idea.trim().length > 0
47
- ? appendIdea(session.notes, params.append_idea.trim())
48
- : params.body;
49
-
50
- storage.updateSession(session.id, { notes: nextNotes });
51
- const refreshed = storage.getSessionById(session.id);
52
- const loggedRuns = storage.listLoggedRuns(session.id);
53
- const runtime = options.getRuntime(ctx);
54
- if (refreshed) {
55
- runtime.state = buildExperimentState(refreshed, loggedRuns);
56
- }
57
- options.dashboard.updateWidget(ctx, runtime);
58
-
59
- return {
60
- content: [
61
- {
62
- type: "text",
63
- text:
64
- params.append_idea !== undefined
65
- ? `Appended idea (${nextNotes.length} chars total).`
66
- : `Notes updated (${nextNotes.length} chars).`,
67
- },
68
- ],
69
- details: { notes: nextNotes },
70
- };
71
- },
72
- renderCall(args, _options, theme): Text {
73
- const preview = args.append_idea ?? args.body.slice(0, 100);
74
- return new Text(
75
- `${theme.fg("toolTitle", theme.bold("update_notes"))} ${theme.fg("muted", truncateToWidth(replaceTabs(preview), 100))}`,
76
- 0,
77
- 0,
78
- );
79
- },
80
- renderResult(result, _options, theme: Theme): Text {
81
- const text = replaceTabs(result.content.find(part => part.type === "text")?.text ?? "");
82
- return new Text(theme.fg("muted", text), 0, 0);
83
- },
84
- };
85
- }
86
-
87
- const IDEAS_HEADING = "## Ideas";
88
-
89
- function appendIdea(currentNotes: string, idea: string): string {
90
- const trimmed = currentNotes.trimEnd();
91
- if (trimmed.length === 0) {
92
- return `${IDEAS_HEADING}\n- ${idea}\n`;
93
- }
94
- if (trimmed.includes(IDEAS_HEADING)) {
95
- const lines = trimmed.split("\n");
96
- const ideasIndex = lines.findIndex(line => line.trim() === IDEAS_HEADING);
97
- // find end of ideas section (next heading or end of file)
98
- let insertAt = lines.length;
99
- for (let i = ideasIndex + 1; i < lines.length; i += 1) {
100
- if (/^#{1,6}\s/.test(lines[i] ?? "")) {
101
- insertAt = i;
102
- break;
103
- }
104
- }
105
- lines.splice(insertAt, 0, `- ${idea}`);
106
- return `${lines.join("\n")}\n`;
107
- }
108
- return `${trimmed}\n\n${IDEAS_HEADING}\n- ${idea}\n`;
109
- }
@@ -1,19 +0,0 @@
1
- /**
2
- * `gjc rlm` — opt-in Jupyter-style research session with a persistent Python kernel.
3
- */
4
- import { Command } from "@gajae-code/utils/cli";
5
- import { runRlmCommand } from "../rlm";
6
-
7
- export default class Rlm extends Command {
8
- static description = "Opt-in research session: persistent Python kernel, live notebook, synthesized report";
9
- static strict = false;
10
- static examples = [
11
- "# Start an interactive research session\n gjc rlm",
12
- '# Seed the session with an initial question\n gjc rlm "What drives the spike in the orders table?"',
13
- "# Point the session at a data description\n gjc rlm --data ./datasets/DATA.md",
14
- ];
15
-
16
- async run(): Promise<void> {
17
- await runRlmCommand(this.argv);
18
- }
19
- }