@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,10 +1,130 @@
1
- import {
2
- categorizeComputerChangePath,
3
- normalizeChangeSetPath,
4
- type UltragoalChangeSet,
5
- type UltragoalChangeSetPath,
6
- type UltragoalChangeStatus,
7
- } from "./ultragoal-runtime";
1
+ import * as crypto from "node:crypto";
2
+ import * as fs from "node:fs/promises";
3
+ import * as path from "node:path";
4
+
5
+ export type UltragoalChangeStatus = "added" | "modified" | "deleted" | "renamed" | "copied" | "unknown";
6
+ export type UltragoalChangeCategory =
7
+ | "code"
8
+ | "generated-binding"
9
+ | "tool"
10
+ | "settings-registry"
11
+ | "prompt-doc-behavior"
12
+ | "docs-static"
13
+ | "other";
14
+
15
+ export interface UltragoalChangeSetPath {
16
+ path: string;
17
+ status: UltragoalChangeStatus;
18
+ oldPath?: string;
19
+ category?: UltragoalChangeCategory;
20
+ [key: string]: unknown;
21
+ }
22
+
23
+ export interface UltragoalChangeSet {
24
+ source: "checkpoint-git" | "review-pr" | "review-branch" | "review-worktree" | "review-spec";
25
+ baseRef?: string;
26
+ headRef?: string;
27
+ mergeBase?: string;
28
+ paths: UltragoalChangeSetPath[];
29
+ rawDiffStat?: string;
30
+ rawDiff?: string;
31
+ untrackedContentHash?: string;
32
+ untrackedContentHashVerified?: boolean;
33
+ captureIncomplete?: boolean;
34
+ trusted: true;
35
+ [key: string]: unknown;
36
+ }
37
+
38
+ export function normalizeRepoPath(value: string): string {
39
+ return value.replaceAll("\\", "/").replace(/^\.\//, "");
40
+ }
41
+
42
+ export function normalizeChangeSetPath(value: string): string {
43
+ return value.replace(/^\.\//, "");
44
+ }
45
+
46
+ export function categorizeComputerChangePath(pathValue: string): UltragoalChangeCategory {
47
+ const normalized = normalizeRepoPath(pathValue);
48
+ if (normalized.startsWith("crates/pi-natives/src/computer/")) return "code";
49
+ if (/^packages\/natives\/native\/index\.(?:d\.ts|js)$/.test(normalized)) return "generated-binding";
50
+ if (
51
+ normalized === "packages/coding-agent/src/tools/computer.ts" ||
52
+ normalized.startsWith("packages/coding-agent/src/tools/computer/")
53
+ )
54
+ return "tool";
55
+ if (
56
+ normalized === "packages/coding-agent/src/config/settings-schema.ts" ||
57
+ normalized === "packages/coding-agent/src/tools/index.ts" ||
58
+ normalized === "packages/coding-agent/src/tools/renderers.ts"
59
+ )
60
+ return "settings-registry";
61
+ if (
62
+ normalized === "packages/coding-agent/src/prompts/tools/computer.md" ||
63
+ normalized === "packages/coding-agent/src/defaults/gjc/skills/ultragoal/SKILL.md" ||
64
+ normalized === "packages/coding-agent/src/prompts/agents/executor.md"
65
+ )
66
+ return "prompt-doc-behavior";
67
+ if (normalized === "docs/tools/computer.md" || normalized === "docs/computer-use/README.md") return "docs-static";
68
+ return "other";
69
+ }
70
+
71
+ export function computeUltragoalReviewSourceHash(changeSet: UltragoalChangeSet | undefined): string | undefined {
72
+ if (!changeSet?.trusted || changeSet.captureIncomplete || changeSet.rawDiff === undefined) return undefined;
73
+ if (changeSet.paths.some(row => row.status === "unknown")) return undefined;
74
+ if (
75
+ changeSet.paths.some(row => row.status === "added") &&
76
+ (!changeSet.untrackedContentHash || changeSet.untrackedContentHashVerified !== true)
77
+ )
78
+ return undefined;
79
+ const basis = {
80
+ source: changeSet.source,
81
+ baseRef: changeSet.baseRef,
82
+ headRef: changeSet.headRef,
83
+ mergeBase: changeSet.mergeBase,
84
+ paths: changeSet.paths
85
+ .map(row => ({
86
+ path: normalizeRepoPath(row.path),
87
+ status: row.status,
88
+ oldPath: row.oldPath ? normalizeRepoPath(row.oldPath) : undefined,
89
+ }))
90
+ .sort((left, right) =>
91
+ `${left.path}\u0000${left.status}\u0000${left.oldPath ?? ""}`.localeCompare(
92
+ `${right.path}\u0000${right.status}\u0000${right.oldPath ?? ""}`,
93
+ ),
94
+ ),
95
+ rawDiff: changeSet.rawDiff,
96
+ untrackedContentHash: changeSet.untrackedContentHash,
97
+ };
98
+ return `sha256:${crypto.createHash("sha256").update(JSON.stringify(basis)).digest("hex")}`;
99
+ }
100
+
101
+ async function hashAddedFiles(cwd: string, paths: readonly UltragoalChangeSetPath[]): Promise<string | undefined> {
102
+ try {
103
+ const hasher = crypto.createHash("sha256");
104
+ const root = path.resolve(cwd);
105
+ for (const row of [...paths].sort((left, right) => left.path.localeCompare(right.path))) {
106
+ const filePath = path.resolve(root, row.path);
107
+ const relative = path.relative(root, filePath);
108
+ if (relative.startsWith("..") || path.isAbsolute(relative)) return undefined;
109
+ const stat = await fs.lstat(filePath);
110
+ hasher.update(row.path);
111
+ hasher.update("\0");
112
+ if (stat.isSymbolicLink()) {
113
+ hasher.update("symlink\0");
114
+ hasher.update(await fs.readlink(filePath));
115
+ } else if (stat.isFile()) {
116
+ hasher.update("file\0");
117
+ hasher.update(Buffer.from(await Bun.file(filePath).arrayBuffer()));
118
+ } else {
119
+ return undefined;
120
+ }
121
+ hasher.update("\0");
122
+ }
123
+ return `sha256:${hasher.digest("hex")}`;
124
+ } catch {
125
+ return undefined;
126
+ }
127
+ }
8
128
 
9
129
  export async function spawnText(
10
130
  command: string[],
@@ -126,7 +246,7 @@ export function ciDevChangedPathRows(): UltragoalChangeSetPath[] {
126
246
  .split(/\r?\n/)
127
247
  .filter(row => row.length > 0)
128
248
  .map(pathValue => ({
129
- path: normalizeChangeSetPath(pathValue),
249
+ path: normalizeRepoPath(pathValue),
130
250
  status: "unknown" as UltragoalChangeStatus,
131
251
  category: categorizeComputerChangePath(pathValue),
132
252
  }));
@@ -134,18 +254,37 @@ export function ciDevChangedPathRows(): UltragoalChangeSetPath[] {
134
254
 
135
255
  export function mergeChangeSetPaths(groups: UltragoalChangeSetPath[][]): UltragoalChangeSetPath[] {
136
256
  const byKey = new Map<string, UltragoalChangeSetPath>();
137
- for (const row of groups.flat()) byKey.set(`${row.oldPath ?? ""}\u0000${row.path}`, row);
257
+ for (const inputRow of groups.flat()) {
258
+ const row: UltragoalChangeSetPath = {
259
+ ...inputRow,
260
+ path: normalizeRepoPath(inputRow.path),
261
+ ...(inputRow.oldPath ? { oldPath: normalizeRepoPath(inputRow.oldPath) } : {}),
262
+ };
263
+ const key = `${row.oldPath ?? ""}\u0000${row.path}`;
264
+ const existing = byKey.get(key);
265
+ if (existing && existing.status !== "unknown" && row.status === "unknown") continue;
266
+ byKey.set(key, row);
267
+ }
138
268
  return [...byKey.values()];
139
269
  }
140
270
 
141
271
  export async function computeCheckpointChangeSet(cwd: string): Promise<UltragoalChangeSet | undefined> {
142
- const ciChangedPaths = ciDevChangedPathRows();
272
+ let ciChangedPaths = ciDevChangedPathRows();
143
273
  const inGit = await spawnText(["git", "rev-parse", "--is-inside-work-tree"], { cwd, timeoutMs: 3000 });
274
+ const workspace = process.env.GITHUB_WORKSPACE?.trim();
275
+ if (workspace) {
276
+ const topLevel = inGit.ok
277
+ ? await spawnText(["git", "rev-parse", "--show-toplevel"], { cwd, timeoutMs: 3000 })
278
+ : undefined;
279
+ if (!topLevel?.ok || path.resolve(topLevel.stdout.trim()) !== path.resolve(workspace)) ciChangedPaths = [];
280
+ }
144
281
  if (!inGit.ok || inGit.stdout.trim() !== "true") {
145
282
  if (ciChangedPaths.length === 0)
146
283
  return { source: "checkpoint-git", paths: [], captureIncomplete: true, trusted: true };
147
284
  return { source: "checkpoint-git", paths: ciChangedPaths, trusted: true };
148
285
  }
286
+ const captureWitness = await repositoryStateWitness(cwd);
287
+ await repositoryStateWitnessTestHook?.("after-initial", cwd);
149
288
  const baseRef = await resolveGitBase(cwd);
150
289
  const base = baseRef;
151
290
  const mergeBase = await spawnText(["git", "merge-base", "HEAD", baseRef], { cwd, timeoutMs: 3000 });
@@ -177,13 +316,26 @@ export async function computeCheckpointChangeSet(cwd: string): Promise<Ultragoal
177
316
  trusted: true,
178
317
  };
179
318
  }
319
+ const untrackedPaths = parseGitUntrackedPaths(untracked.stdout);
180
320
  const paths = mergeChangeSetPaths([
181
321
  parseGitNameStatus(committed.stdout),
182
322
  parseGitNameStatus(unstaged.stdout),
183
323
  parseGitNameStatus(staged.stdout),
184
- parseGitUntrackedPaths(untracked.stdout),
324
+ untrackedPaths,
185
325
  ciChangedPaths,
186
326
  ]);
327
+ const untrackedContentHash = await hashAddedFiles(
328
+ cwd,
329
+ paths.filter(row => row.status === "added"),
330
+ );
331
+ // #4560: the name-status, diff, and untracked reads above are independent
332
+ // git invocations. A concurrent repository change between them yields a
333
+ // snapshot that never existed on disk, which would let completion be
334
+ // committed against a source basis nothing was actually reviewed at.
335
+ // Re-read the content witness and mark the capture incomplete on
336
+ // drift so the boundary fails closed into the full heavyweight cohort.
337
+ const witness = await repositoryStateWitness(cwd);
338
+ const captureDrifted = witness === undefined || witness !== captureWitness;
187
339
  return {
188
340
  source: "checkpoint-git",
189
341
  baseRef,
@@ -195,10 +347,79 @@ export async function computeCheckpointChangeSet(cwd: string): Promise<Ultragoal
195
347
  committedDiff.ok && unstagedDiff.ok && stagedDiff.ok
196
348
  ? [committedDiff.stdout, unstagedDiff.stdout, stagedDiff.stdout].filter(Boolean).join("\n")
197
349
  : undefined,
350
+ ...(untrackedContentHash ? { untrackedContentHash, untrackedContentHashVerified: true } : {}),
351
+ captureIncomplete:
352
+ !stat.ok ||
353
+ !committedDiff.ok ||
354
+ !unstagedDiff.ok ||
355
+ !stagedDiff.ok ||
356
+ captureDrifted ||
357
+ (paths.some(row => row.status === "added") && !untrackedContentHash),
198
358
  trusted: true,
199
359
  };
200
360
  }
201
361
 
362
+ /**
363
+ * A content witness of overall repository state. HEAD and porcelain status are
364
+ * retained for cheap structural diagnostics, but the authoritative comparison
365
+ * also digests every tracked and non-ignored untracked path. A same-status edit
366
+ * therefore cannot pass the capture boundary merely because Git's status text
367
+ * stayed unchanged.
368
+ */
369
+ type RepositoryStateWitnessTestHook = (phase: "after-initial", cwd: string) => void | Promise<void>;
370
+
371
+ let repositoryStateWitnessTestHook: RepositoryStateWitnessTestHook | undefined;
372
+
373
+ /** @internal Test-only seam; production capture has no injected mutation hook. */
374
+ export function __setRepositoryStateWitnessTestHookForTests(hook: RepositoryStateWitnessTestHook | undefined): void {
375
+ repositoryStateWitnessTestHook = hook;
376
+ }
377
+
378
+ async function repositoryStateWitness(cwd: string): Promise<string | undefined> {
379
+ const [head, status, tracked, untracked] = await Promise.all([
380
+ spawnText(["git", "rev-parse", "HEAD"], { cwd, timeoutMs: 3000 }),
381
+ spawnText(["git", "status", "--porcelain=v1", "-z", "--untracked-files=all"], { cwd, timeoutMs: 5000 }),
382
+ spawnText(["git", "ls-files", "-z"], { cwd, timeoutMs: 5000 }),
383
+ spawnText(["git", "ls-files", "--others", "--exclude-standard", "-z"], { cwd, timeoutMs: 5000 }),
384
+ ]);
385
+ if (!head.ok || !status.ok || !tracked.ok || !untracked.ok) return undefined;
386
+ const paths = [
387
+ ...new Set([
388
+ ...parseGitUntrackedPaths(tracked.stdout).map(row => row.path),
389
+ ...parseGitUntrackedPaths(untracked.stdout).map(row => row.path),
390
+ ]),
391
+ ].sort((left, right) => left.localeCompare(right));
392
+ const content = crypto.createHash("sha256");
393
+ const root = path.resolve(cwd);
394
+ try {
395
+ for (const repoPath of paths) {
396
+ const filePath = path.resolve(root, repoPath);
397
+ const relative = path.relative(root, filePath);
398
+ if (relative.startsWith("..") || path.isAbsolute(relative)) return undefined;
399
+ content.update(repoPath);
400
+ content.update("\u0000");
401
+ const stat = await fs.lstat(filePath).catch(() => undefined);
402
+ if (!stat) {
403
+ content.update("missing\u0000");
404
+ continue;
405
+ }
406
+ if (stat.isSymbolicLink()) {
407
+ content.update("symlink\u0000");
408
+ content.update(await fs.readlink(filePath));
409
+ } else if (stat.isFile()) {
410
+ content.update("file\u0000");
411
+ content.update(Buffer.from(await Bun.file(filePath).arrayBuffer()));
412
+ } else {
413
+ content.update("other\u0000");
414
+ }
415
+ content.update("\u0000");
416
+ }
417
+ } catch {
418
+ return undefined;
419
+ }
420
+ return `${head.stdout.trim()}\u0000${status.stdout}\u0000sha256:${content.digest("hex")}`;
421
+ }
422
+
202
423
  export function parseUnifiedDiffPaths(diff: string): UltragoalChangeSetPath[] {
203
424
  const paths: UltragoalChangeSetPath[] = [];
204
425
  for (const line of diff.split("\n")) {