@kenkaiiii/ggcoder 4.3.232 → 4.3.234

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 (348) hide show
  1. package/README.md +1 -2
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +7 -89
  4. package/dist/cli.js.map +1 -1
  5. package/dist/core/agent-session.d.ts.map +1 -1
  6. package/dist/core/agent-session.js +2 -2
  7. package/dist/core/agent-session.js.map +1 -1
  8. package/dist/core/prompt-commands.d.ts.map +1 -1
  9. package/dist/core/prompt-commands.js +8 -16
  10. package/dist/core/prompt-commands.js.map +1 -1
  11. package/dist/core/prompt-commands.test.js +14 -44
  12. package/dist/core/prompt-commands.test.js.map +1 -1
  13. package/dist/core/runtime-mode.d.ts +0 -11
  14. package/dist/core/runtime-mode.d.ts.map +1 -1
  15. package/dist/core/runtime-mode.js +0 -9
  16. package/dist/core/runtime-mode.js.map +1 -1
  17. package/dist/core/session-restore-display.test.js +4 -110
  18. package/dist/core/session-restore-display.test.js.map +1 -1
  19. package/dist/interactive.d.ts.map +1 -1
  20. package/dist/interactive.js +1 -1
  21. package/dist/interactive.js.map +1 -1
  22. package/dist/system-prompt.d.ts +1 -2
  23. package/dist/system-prompt.d.ts.map +1 -1
  24. package/dist/system-prompt.js +11 -58
  25. package/dist/system-prompt.js.map +1 -1
  26. package/dist/system-prompt.test.js +3 -158
  27. package/dist/system-prompt.test.js.map +1 -1
  28. package/dist/tools/bash.d.ts +1 -4
  29. package/dist/tools/bash.d.ts.map +1 -1
  30. package/dist/tools/bash.js +3 -12
  31. package/dist/tools/bash.js.map +1 -1
  32. package/dist/tools/checkpoint-hook.test.js +3 -3
  33. package/dist/tools/checkpoint-hook.test.js.map +1 -1
  34. package/dist/tools/edit.d.ts +1 -4
  35. package/dist/tools/edit.d.ts.map +1 -1
  36. package/dist/tools/edit.js +5 -13
  37. package/dist/tools/edit.js.map +1 -1
  38. package/dist/tools/enter-plan.js +1 -1
  39. package/dist/tools/enter-plan.js.map +1 -1
  40. package/dist/tools/index.d.ts +0 -9
  41. package/dist/tools/index.d.ts.map +1 -1
  42. package/dist/tools/index.js +4 -8
  43. package/dist/tools/index.js.map +1 -1
  44. package/dist/tools/prompt-hints.d.ts.map +1 -1
  45. package/dist/tools/prompt-hints.js +0 -2
  46. package/dist/tools/prompt-hints.js.map +1 -1
  47. package/dist/tools/screenshot.d.ts +1 -1
  48. package/dist/tools/subagent.d.ts +1 -4
  49. package/dist/tools/subagent.d.ts.map +1 -1
  50. package/dist/tools/subagent.js +2 -5
  51. package/dist/tools/subagent.js.map +1 -1
  52. package/dist/tools/write.d.ts +1 -4
  53. package/dist/tools/write.d.ts.map +1 -1
  54. package/dist/tools/write.js +5 -13
  55. package/dist/tools/write.js.map +1 -1
  56. package/dist/ui/App.d.ts +5 -20
  57. package/dist/ui/App.d.ts.map +1 -1
  58. package/dist/ui/App.js +134 -309
  59. package/dist/ui/App.js.map +1 -1
  60. package/dist/ui/app-items.d.ts +23 -25
  61. package/dist/ui/app-items.d.ts.map +1 -1
  62. package/dist/ui/app-items.js +37 -0
  63. package/dist/ui/app-items.js.map +1 -1
  64. package/dist/ui/app-items.test.d.ts +2 -0
  65. package/dist/ui/app-items.test.d.ts.map +1 -0
  66. package/dist/ui/app-items.test.js +38 -0
  67. package/dist/ui/app-items.test.js.map +1 -0
  68. package/dist/ui/app-state-persistence.test.js +14 -318
  69. package/dist/ui/app-state-persistence.test.js.map +1 -1
  70. package/dist/ui/chat-layout-pinning.test.js +74 -4
  71. package/dist/ui/chat-layout-pinning.test.js.map +1 -1
  72. package/dist/ui/components/AssistantMessage.test.js +6 -9
  73. package/dist/ui/components/AssistantMessage.test.js.map +1 -1
  74. package/dist/ui/components/Banner.js +1 -1
  75. package/dist/ui/components/Banner.js.map +1 -1
  76. package/dist/ui/components/ChatFooterPane.d.ts +1 -5
  77. package/dist/ui/components/ChatFooterPane.d.ts.map +1 -1
  78. package/dist/ui/components/ChatFooterPane.js +3 -4
  79. package/dist/ui/components/ChatFooterPane.js.map +1 -1
  80. package/dist/ui/components/ChatInputStack.d.ts +3 -1
  81. package/dist/ui/components/ChatInputStack.d.ts.map +1 -1
  82. package/dist/ui/components/ChatInputStack.js +4 -3
  83. package/dist/ui/components/ChatInputStack.js.map +1 -1
  84. package/dist/ui/components/ChatScreen.d.ts +3 -16
  85. package/dist/ui/components/ChatScreen.d.ts.map +1 -1
  86. package/dist/ui/components/ChatScreen.js +2 -3
  87. package/dist/ui/components/ChatScreen.js.map +1 -1
  88. package/dist/ui/components/Footer.d.ts +3 -8
  89. package/dist/ui/components/Footer.d.ts.map +1 -1
  90. package/dist/ui/components/Footer.js +5 -25
  91. package/dist/ui/components/Footer.js.map +1 -1
  92. package/dist/ui/components/InputArea.d.ts +1 -9
  93. package/dist/ui/components/InputArea.d.ts.map +1 -1
  94. package/dist/ui/components/InputArea.js +2 -44
  95. package/dist/ui/components/InputArea.js.map +1 -1
  96. package/dist/ui/components/LiveToolPanel.d.ts +30 -0
  97. package/dist/ui/components/LiveToolPanel.d.ts.map +1 -0
  98. package/dist/ui/components/LiveToolPanel.js +66 -0
  99. package/dist/ui/components/LiveToolPanel.js.map +1 -0
  100. package/dist/ui/components/ToolExecution.js +0 -2
  101. package/dist/ui/components/ToolExecution.js.map +1 -1
  102. package/dist/ui/components/TranscriptViewport.d.ts +1 -1
  103. package/dist/ui/components/TranscriptViewport.js +1 -1
  104. package/dist/ui/footer-jump-regression.test.js +12 -2
  105. package/dist/ui/footer-jump-regression.test.js.map +1 -1
  106. package/dist/ui/footer-status-layout.test.js +4 -12
  107. package/dist/ui/footer-status-layout.test.js.map +1 -1
  108. package/dist/ui/hooks/useChatLayoutMeasurements.d.ts +3 -4
  109. package/dist/ui/hooks/useChatLayoutMeasurements.d.ts.map +1 -1
  110. package/dist/ui/hooks/useChatLayoutMeasurements.js +26 -4
  111. package/dist/ui/hooks/useChatLayoutMeasurements.js.map +1 -1
  112. package/dist/ui/hooks/useModeState.d.ts +4 -19
  113. package/dist/ui/hooks/useModeState.d.ts.map +1 -1
  114. package/dist/ui/hooks/useModeState.js +5 -45
  115. package/dist/ui/hooks/useModeState.js.map +1 -1
  116. package/dist/ui/hooks/usePixelFixFlow.js +2 -2
  117. package/dist/ui/layout-decisions.d.ts +11 -34
  118. package/dist/ui/layout-decisions.d.ts.map +1 -1
  119. package/dist/ui/layout-decisions.js +15 -42
  120. package/dist/ui/layout-decisions.js.map +1 -1
  121. package/dist/ui/live-area-height.d.ts.map +1 -1
  122. package/dist/ui/live-area-height.js +6 -1
  123. package/dist/ui/live-area-height.js.map +1 -1
  124. package/dist/ui/live-frame-height.test.js +26 -1
  125. package/dist/ui/live-frame-height.test.js.map +1 -1
  126. package/dist/ui/plan-overlay.test.js +1 -1
  127. package/dist/ui/plan-overlay.test.js.map +1 -1
  128. package/dist/ui/prompt-routing.d.ts +1 -19
  129. package/dist/ui/prompt-routing.d.ts.map +1 -1
  130. package/dist/ui/prompt-routing.js +1 -79
  131. package/dist/ui/prompt-routing.js.map +1 -1
  132. package/dist/ui/render.d.ts +3 -18
  133. package/dist/ui/render.d.ts.map +1 -1
  134. package/dist/ui/render.js +0 -10
  135. package/dist/ui/render.js.map +1 -1
  136. package/dist/ui/scroll-stabilization.test.js +1 -7
  137. package/dist/ui/scroll-stabilization.test.js.map +1 -1
  138. package/dist/ui/slash-command-images.test.js +11 -86
  139. package/dist/ui/slash-command-images.test.js.map +1 -1
  140. package/dist/ui/streaming-flush-bounce.test.d.ts +2 -0
  141. package/dist/ui/streaming-flush-bounce.test.d.ts.map +1 -0
  142. package/dist/ui/streaming-flush-bounce.test.js +156 -0
  143. package/dist/ui/streaming-flush-bounce.test.js.map +1 -0
  144. package/dist/ui/submit-prompt-command.d.ts +1 -16
  145. package/dist/ui/submit-prompt-command.d.ts.map +1 -1
  146. package/dist/ui/submit-prompt-command.js +4 -54
  147. package/dist/ui/submit-prompt-command.js.map +1 -1
  148. package/dist/ui/submit-slash-commands.d.ts +0 -1
  149. package/dist/ui/submit-slash-commands.d.ts.map +1 -1
  150. package/dist/ui/submit-slash-commands.js +0 -4
  151. package/dist/ui/submit-slash-commands.js.map +1 -1
  152. package/dist/ui/terminal-history-status-renderers.d.ts +0 -1
  153. package/dist/ui/terminal-history-status-renderers.d.ts.map +1 -1
  154. package/dist/ui/terminal-history-status-renderers.js +0 -3
  155. package/dist/ui/terminal-history-status-renderers.js.map +1 -1
  156. package/dist/ui/terminal-history.d.ts.map +1 -1
  157. package/dist/ui/terminal-history.js +11 -56
  158. package/dist/ui/terminal-history.js.map +1 -1
  159. package/dist/ui/terminal-history.test.js +6 -33
  160. package/dist/ui/terminal-history.test.js.map +1 -1
  161. package/dist/ui/tool-line-summary.d.ts +29 -0
  162. package/dist/ui/tool-line-summary.d.ts.map +1 -0
  163. package/dist/ui/tool-line-summary.js +153 -0
  164. package/dist/ui/tool-line-summary.js.map +1 -0
  165. package/dist/ui/transcript/TranscriptRenderer.d.ts +1 -1
  166. package/dist/ui/transcript/TranscriptRenderer.d.ts.map +1 -1
  167. package/dist/ui/transcript/TranscriptRenderer.js +18 -12
  168. package/dist/ui/transcript/TranscriptRenderer.js.map +1 -1
  169. package/dist/ui/transcript/presentation.d.ts +1 -17
  170. package/dist/ui/transcript/presentation.d.ts.map +1 -1
  171. package/dist/ui/transcript/presentation.js +0 -26
  172. package/dist/ui/transcript/presentation.js.map +1 -1
  173. package/dist/ui/transcript/spacing.d.ts +2 -2
  174. package/dist/ui/transcript/spacing.d.ts.map +1 -1
  175. package/dist/ui/transcript/spacing.js +14 -9
  176. package/dist/ui/transcript/spacing.js.map +1 -1
  177. package/dist/ui/transcript/spacing.test.js +5 -8
  178. package/dist/ui/transcript/spacing.test.js.map +1 -1
  179. package/dist/ui/transcript/tool-presentation.js +1 -1
  180. package/dist/ui/transcript/tool-presentation.js.map +1 -1
  181. package/dist/ui/transcript/transcript-lines.d.ts.map +1 -1
  182. package/dist/ui/transcript/transcript-lines.js +4 -0
  183. package/dist/ui/transcript/transcript-lines.js.map +1 -1
  184. package/dist/ui/tui-history-parity.test.js +0 -47
  185. package/dist/ui/tui-history-parity.test.js.map +1 -1
  186. package/dist/ui/tui-simulation.test.js +2 -1
  187. package/dist/ui/tui-simulation.test.js.map +1 -1
  188. package/package.json +3 -3
  189. package/dist/core/goal-controller.d.ts +0 -82
  190. package/dist/core/goal-controller.d.ts.map +0 -1
  191. package/dist/core/goal-controller.js +0 -838
  192. package/dist/core/goal-controller.js.map +0 -1
  193. package/dist/core/goal-controller.test.d.ts +0 -2
  194. package/dist/core/goal-controller.test.d.ts.map +0 -1
  195. package/dist/core/goal-controller.test.js +0 -1279
  196. package/dist/core/goal-controller.test.js.map +0 -1
  197. package/dist/core/goal-engine.d.ts +0 -61
  198. package/dist/core/goal-engine.d.ts.map +0 -1
  199. package/dist/core/goal-engine.js +0 -123
  200. package/dist/core/goal-engine.js.map +0 -1
  201. package/dist/core/goal-engine.test.d.ts +0 -2
  202. package/dist/core/goal-engine.test.d.ts.map +0 -1
  203. package/dist/core/goal-engine.test.js +0 -295
  204. package/dist/core/goal-engine.test.js.map +0 -1
  205. package/dist/core/goal-integration.d.ts +0 -80
  206. package/dist/core/goal-integration.d.ts.map +0 -1
  207. package/dist/core/goal-integration.js +0 -296
  208. package/dist/core/goal-integration.js.map +0 -1
  209. package/dist/core/goal-integration.test.d.ts +0 -2
  210. package/dist/core/goal-integration.test.d.ts.map +0 -1
  211. package/dist/core/goal-integration.test.js +0 -369
  212. package/dist/core/goal-integration.test.js.map +0 -1
  213. package/dist/core/goal-lifecycle-smoke.test.d.ts +0 -2
  214. package/dist/core/goal-lifecycle-smoke.test.d.ts.map +0 -1
  215. package/dist/core/goal-lifecycle-smoke.test.js +0 -248
  216. package/dist/core/goal-lifecycle-smoke.test.js.map +0 -1
  217. package/dist/core/goal-overhead-harness.d.ts +0 -33
  218. package/dist/core/goal-overhead-harness.d.ts.map +0 -1
  219. package/dist/core/goal-overhead-harness.js +0 -268
  220. package/dist/core/goal-overhead-harness.js.map +0 -1
  221. package/dist/core/goal-prerequisites.d.ts +0 -23
  222. package/dist/core/goal-prerequisites.d.ts.map +0 -1
  223. package/dist/core/goal-prerequisites.js +0 -114
  224. package/dist/core/goal-prerequisites.js.map +0 -1
  225. package/dist/core/goal-prerequisites.test.d.ts +0 -2
  226. package/dist/core/goal-prerequisites.test.d.ts.map +0 -1
  227. package/dist/core/goal-prerequisites.test.js +0 -154
  228. package/dist/core/goal-prerequisites.test.js.map +0 -1
  229. package/dist/core/goal-references.d.ts +0 -14
  230. package/dist/core/goal-references.d.ts.map +0 -1
  231. package/dist/core/goal-references.js +0 -153
  232. package/dist/core/goal-references.js.map +0 -1
  233. package/dist/core/goal-references.test.d.ts +0 -2
  234. package/dist/core/goal-references.test.d.ts.map +0 -1
  235. package/dist/core/goal-references.test.js +0 -77
  236. package/dist/core/goal-references.test.js.map +0 -1
  237. package/dist/core/goal-store.d.ts +0 -289
  238. package/dist/core/goal-store.d.ts.map +0 -1
  239. package/dist/core/goal-store.js +0 -1156
  240. package/dist/core/goal-store.js.map +0 -1
  241. package/dist/core/goal-store.test.d.ts +0 -2
  242. package/dist/core/goal-store.test.d.ts.map +0 -1
  243. package/dist/core/goal-store.test.js +0 -530
  244. package/dist/core/goal-store.test.js.map +0 -1
  245. package/dist/core/goal-verifier.d.ts +0 -17
  246. package/dist/core/goal-verifier.d.ts.map +0 -1
  247. package/dist/core/goal-verifier.js +0 -87
  248. package/dist/core/goal-verifier.js.map +0 -1
  249. package/dist/core/goal-verifier.test.d.ts +0 -2
  250. package/dist/core/goal-verifier.test.d.ts.map +0 -1
  251. package/dist/core/goal-verifier.test.js +0 -131
  252. package/dist/core/goal-verifier.test.js.map +0 -1
  253. package/dist/core/goal-worker-dev-server-lifecycle.test.d.ts +0 -2
  254. package/dist/core/goal-worker-dev-server-lifecycle.test.d.ts.map +0 -1
  255. package/dist/core/goal-worker-dev-server-lifecycle.test.js +0 -68
  256. package/dist/core/goal-worker-dev-server-lifecycle.test.js.map +0 -1
  257. package/dist/core/goal-worker.d.ts +0 -61
  258. package/dist/core/goal-worker.d.ts.map +0 -1
  259. package/dist/core/goal-worker.js +0 -467
  260. package/dist/core/goal-worker.js.map +0 -1
  261. package/dist/core/goal-worker.test.d.ts +0 -2
  262. package/dist/core/goal-worker.test.d.ts.map +0 -1
  263. package/dist/core/goal-worker.test.js +0 -493
  264. package/dist/core/goal-worker.test.js.map +0 -1
  265. package/dist/core/goal-worktree.d.ts +0 -108
  266. package/dist/core/goal-worktree.d.ts.map +0 -1
  267. package/dist/core/goal-worktree.js +0 -300
  268. package/dist/core/goal-worktree.js.map +0 -1
  269. package/dist/core/goal-worktree.test.d.ts +0 -2
  270. package/dist/core/goal-worktree.test.d.ts.map +0 -1
  271. package/dist/core/goal-worktree.test.js +0 -448
  272. package/dist/core/goal-worktree.test.js.map +0 -1
  273. package/dist/tools/goal-mode.test.d.ts +0 -2
  274. package/dist/tools/goal-mode.test.d.ts.map +0 -1
  275. package/dist/tools/goal-mode.test.js +0 -121
  276. package/dist/tools/goal-mode.test.js.map +0 -1
  277. package/dist/tools/goals.d.ts +0 -143
  278. package/dist/tools/goals.d.ts.map +0 -1
  279. package/dist/tools/goals.js +0 -1038
  280. package/dist/tools/goals.js.map +0 -1
  281. package/dist/tools/goals.test.d.ts +0 -2
  282. package/dist/tools/goals.test.d.ts.map +0 -1
  283. package/dist/tools/goals.test.js +0 -1444
  284. package/dist/tools/goals.test.js.map +0 -1
  285. package/dist/ui/components/GoalOverlay.d.ts +0 -83
  286. package/dist/ui/components/GoalOverlay.d.ts.map +0 -1
  287. package/dist/ui/components/GoalOverlay.js +0 -710
  288. package/dist/ui/components/GoalOverlay.js.map +0 -1
  289. package/dist/ui/components/GoalPickerMenu.d.ts +0 -9
  290. package/dist/ui/components/GoalPickerMenu.d.ts.map +0 -1
  291. package/dist/ui/components/GoalPickerMenu.js +0 -37
  292. package/dist/ui/components/GoalPickerMenu.js.map +0 -1
  293. package/dist/ui/components/GoalStatusBar.d.ts +0 -26
  294. package/dist/ui/components/GoalStatusBar.d.ts.map +0 -1
  295. package/dist/ui/components/GoalStatusBar.js +0 -130
  296. package/dist/ui/components/GoalStatusBar.js.map +0 -1
  297. package/dist/ui/components/GoalStatusBar.test.d.ts +0 -2
  298. package/dist/ui/components/GoalStatusBar.test.d.ts.map +0 -1
  299. package/dist/ui/components/GoalStatusBar.test.js +0 -17
  300. package/dist/ui/components/GoalStatusBar.test.js.map +0 -1
  301. package/dist/ui/goal-events.d.ts +0 -125
  302. package/dist/ui/goal-events.d.ts.map +0 -1
  303. package/dist/ui/goal-events.js +0 -407
  304. package/dist/ui/goal-events.js.map +0 -1
  305. package/dist/ui/goal-events.test.d.ts +0 -2
  306. package/dist/ui/goal-events.test.d.ts.map +0 -1
  307. package/dist/ui/goal-events.test.js +0 -416
  308. package/dist/ui/goal-events.test.js.map +0 -1
  309. package/dist/ui/goal-lifecycle-orchestration.test.d.ts +0 -2
  310. package/dist/ui/goal-lifecycle-orchestration.test.d.ts.map +0 -1
  311. package/dist/ui/goal-lifecycle-orchestration.test.js +0 -555
  312. package/dist/ui/goal-lifecycle-orchestration.test.js.map +0 -1
  313. package/dist/ui/goal-overlay.test.d.ts +0 -2
  314. package/dist/ui/goal-overlay.test.d.ts.map +0 -1
  315. package/dist/ui/goal-overlay.test.js +0 -384
  316. package/dist/ui/goal-overlay.test.js.map +0 -1
  317. package/dist/ui/goal-progress.d.ts +0 -31
  318. package/dist/ui/goal-progress.d.ts.map +0 -1
  319. package/dist/ui/goal-progress.js +0 -149
  320. package/dist/ui/goal-progress.js.map +0 -1
  321. package/dist/ui/goal-run-helpers.d.ts +0 -12
  322. package/dist/ui/goal-run-helpers.d.ts.map +0 -1
  323. package/dist/ui/goal-run-helpers.js +0 -42
  324. package/dist/ui/goal-run-helpers.js.map +0 -1
  325. package/dist/ui/goal-status-bar.test.d.ts +0 -2
  326. package/dist/ui/goal-status-bar.test.d.ts.map +0 -1
  327. package/dist/ui/goal-status-bar.test.js +0 -174
  328. package/dist/ui/goal-status-bar.test.js.map +0 -1
  329. package/dist/ui/goal-summary.d.ts +0 -14
  330. package/dist/ui/goal-summary.d.ts.map +0 -1
  331. package/dist/ui/goal-summary.js +0 -194
  332. package/dist/ui/goal-summary.js.map +0 -1
  333. package/dist/ui/hooks/useGoalOrchestration.d.ts +0 -82
  334. package/dist/ui/hooks/useGoalOrchestration.d.ts.map +0 -1
  335. package/dist/ui/hooks/useGoalOrchestration.js +0 -863
  336. package/dist/ui/hooks/useGoalOrchestration.js.map +0 -1
  337. package/dist/ui/hooks/useGoalPickerController.d.ts +0 -22
  338. package/dist/ui/hooks/useGoalPickerController.d.ts.map +0 -1
  339. package/dist/ui/hooks/useGoalPickerController.js +0 -35
  340. package/dist/ui/hooks/useGoalPickerController.js.map +0 -1
  341. package/dist/ui/prompt-routing.test.d.ts +0 -2
  342. package/dist/ui/prompt-routing.test.d.ts.map +0 -1
  343. package/dist/ui/prompt-routing.test.js +0 -48
  344. package/dist/ui/prompt-routing.test.js.map +0 -1
  345. package/dist/ui/transcript/GoalRows.d.ts +0 -10
  346. package/dist/ui/transcript/GoalRows.d.ts.map +0 -1
  347. package/dist/ui/transcript/GoalRows.js +0 -35
  348. package/dist/ui/transcript/GoalRows.js.map +0 -1
@@ -1,1156 +0,0 @@
1
- import { createHash, randomUUID } from "node:crypto";
2
- import { readFileSync, writeFileSync } from "node:fs";
3
- import { mkdir, open, readdir, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
4
- import { homedir } from "node:os";
5
- import { basename, join, resolve } from "node:path";
6
- export function foldGoalTaskIntegration(value) {
7
- return value === "manual" ? "manual" : "candidate";
8
- }
9
- const GOALS_BASE_ENV = "GG_GOALS_BASE";
10
- const DEFAULT_PROJECT_DIR_NAME = "projects";
11
- let writeQueue = Promise.resolve();
12
- function goalsBaseDir() {
13
- return process.env[GOALS_BASE_ENV] ?? join(homedir(), ".gg", "goals", DEFAULT_PROJECT_DIR_NAME);
14
- }
15
- export function normalizeProjectPath(cwd) {
16
- return resolve(cwd);
17
- }
18
- function nowIso() {
19
- return new Date().toISOString();
20
- }
21
- function mergeGoalTasks(existing, input) {
22
- if (!input)
23
- return existing;
24
- const byId = new Map(input.map((task) => [task.id, task]));
25
- const merged = existing.map((task) => {
26
- const next = byId.get(task.id);
27
- if (!next)
28
- return task;
29
- return {
30
- ...task,
31
- ...next,
32
- status: task.status !== next.status || task.attempts > next.attempts ? task.status : next.status,
33
- attempts: Math.max(task.attempts, next.attempts),
34
- workerId: task.workerId ?? next.workerId,
35
- dependsOn: task.dependsOn ?? next.dependsOn,
36
- parallelGroup: task.parallelGroup ?? next.parallelGroup,
37
- expectedChangedScope: task.expectedChangedScope ?? next.expectedChangedScope,
38
- integration: task.integration ?? next.integration,
39
- verification: task.verification ?? next.verification,
40
- lastSummary: task.lastSummary ?? next.lastSummary,
41
- };
42
- });
43
- for (const task of input) {
44
- if (!existing.some((item) => item.id === task.id))
45
- merged.push(task);
46
- }
47
- return merged;
48
- }
49
- function mergeGoalEvidence(existing, input) {
50
- if (!input)
51
- return existing;
52
- const byId = new Map(existing.map((item) => [item.id, item]));
53
- const merged = [...existing];
54
- for (const item of input) {
55
- if (!byId.has(item.id))
56
- merged.push(item);
57
- }
58
- return merged;
59
- }
60
- function mergeGoalReferences(existing, input) {
61
- if (!input)
62
- return existing;
63
- const merged = [...existing];
64
- const seen = new Set(existing
65
- .map((item) => item.id)
66
- .concat(existing.map((item) => `${item.kind}:${item.value ?? item.path ?? item.content ?? item.label}`)));
67
- for (const item of input) {
68
- const identity = `${item.kind}:${item.value ?? item.path ?? item.content ?? item.label}`;
69
- if (seen.has(item.id) || seen.has(identity))
70
- continue;
71
- seen.add(item.id);
72
- seen.add(identity);
73
- merged.push(item);
74
- }
75
- return merged;
76
- }
77
- function isObject(value) {
78
- return typeof value === "object" && value !== null && !Array.isArray(value);
79
- }
80
- function stringArray(value) {
81
- return Array.isArray(value)
82
- ? value.filter((item) => typeof item === "string")
83
- : [];
84
- }
85
- function optionalString(value) {
86
- return typeof value === "string" && value.length > 0 ? value : undefined;
87
- }
88
- function isRunStatus(value) {
89
- return (value === "draft" ||
90
- value === "blocked" ||
91
- value === "ready" ||
92
- value === "running" ||
93
- value === "verifying" ||
94
- value === "passed" ||
95
- value === "failed" ||
96
- value === "paused");
97
- }
98
- function isTaskStatus(value) {
99
- return (value === "pending" ||
100
- value === "running" ||
101
- value === "verifying" ||
102
- value === "done" ||
103
- value === "failed" ||
104
- value === "blocked");
105
- }
106
- function isTaskIntegration(value) {
107
- return value === "candidate" || value === "manual";
108
- }
109
- function isPrerequisiteStatus(value) {
110
- return value === "unknown" || value === "met" || value === "missing";
111
- }
112
- function isPrerequisiteKind(value) {
113
- return value === "local" || value === "external";
114
- }
115
- function isEvidenceKind(value) {
116
- return (value === "log" ||
117
- value === "command" ||
118
- value === "screenshot" ||
119
- value === "file" ||
120
- value === "summary");
121
- }
122
- function isEvidenceMechanism(value) {
123
- return (value === "command" ||
124
- value === "test" ||
125
- value === "script" ||
126
- value === "fixture" ||
127
- value === "log" ||
128
- value === "screenshot" ||
129
- value === "video" ||
130
- value === "browser" ||
131
- value === "device" ||
132
- value === "source" ||
133
- value === "file" ||
134
- value === "manual");
135
- }
136
- function isGoalReferenceKind(value) {
137
- return (value === "prompt" ||
138
- value === "url" ||
139
- value === "repo" ||
140
- value === "file" ||
141
- value === "image" ||
142
- value === "text");
143
- }
144
- function isEvidencePlanStatus(value) {
145
- return value === "planned" || value === "ready" || value === "blocked";
146
- }
147
- function isVerificationStatus(value) {
148
- return value === "pass" || value === "fail" || value === "unknown";
149
- }
150
- function normalizeVerification(value) {
151
- if (!isObject(value))
152
- return undefined;
153
- return {
154
- status: isVerificationStatus(value.status) ? value.status : "unknown",
155
- summary: typeof value.summary === "string" ? value.summary : "",
156
- ...(optionalString(value.command) ? { command: optionalString(value.command) } : {}),
157
- ...(typeof value.exitCode === "number" ? { exitCode: value.exitCode } : {}),
158
- ...(optionalString(value.outputPath) ? { outputPath: optionalString(value.outputPath) } : {}),
159
- checkedAt: typeof value.checkedAt === "string" ? value.checkedAt : nowIso(),
160
- };
161
- }
162
- function normalizePrerequisite(value) {
163
- if (!isObject(value))
164
- return null;
165
- const label = typeof value.label === "string" ? value.label : "Prerequisite";
166
- return {
167
- id: typeof value.id === "string" ? value.id : randomUUID(),
168
- label,
169
- status: isPrerequisiteStatus(value.status) ? value.status : "unknown",
170
- ...(isPrerequisiteKind(value.kind) ? { kind: value.kind } : {}),
171
- ...(optionalString(value.checkCommand)
172
- ? { checkCommand: optionalString(value.checkCommand) }
173
- : {}),
174
- ...(optionalString(value.instructions)
175
- ? { instructions: optionalString(value.instructions) }
176
- : {}),
177
- ...(optionalString(value.evidence) ? { evidence: optionalString(value.evidence) } : {}),
178
- };
179
- }
180
- function normalizeHarnessItem(value) {
181
- if (!isObject(value))
182
- return null;
183
- const label = typeof value.label === "string" ? value.label : "Harness";
184
- return {
185
- id: typeof value.id === "string" ? value.id : randomUUID(),
186
- label,
187
- ...(optionalString(value.command) ? { command: optionalString(value.command) } : {}),
188
- ...(optionalString(value.path) ? { path: optionalString(value.path) } : {}),
189
- ...(optionalString(value.description)
190
- ? { description: optionalString(value.description) }
191
- : {}),
192
- };
193
- }
194
- function normalizeEvidencePlanItem(value) {
195
- if (!isObject(value))
196
- return null;
197
- const label = typeof value.label === "string" ? value.label : "Evidence path";
198
- const description = typeof value.description === "string" ? value.description : label;
199
- return {
200
- id: typeof value.id === "string" ? value.id : randomUUID(),
201
- label,
202
- mechanism: isEvidenceMechanism(value.mechanism) ? value.mechanism : "command",
203
- description,
204
- status: isEvidencePlanStatus(value.status) ? value.status : "planned",
205
- ...(optionalString(value.command) ? { command: optionalString(value.command) } : {}),
206
- ...(optionalString(value.path) ? { path: optionalString(value.path) } : {}),
207
- ...(optionalString(value.instructions)
208
- ? { instructions: optionalString(value.instructions) }
209
- : {}),
210
- ...(optionalString(value.evidence) ? { evidence: optionalString(value.evidence) } : {}),
211
- };
212
- }
213
- function normalizeReference(value) {
214
- if (!isObject(value))
215
- return null;
216
- const label = typeof value.label === "string" ? value.label : "Goal reference";
217
- return {
218
- id: typeof value.id === "string" ? value.id : randomUUID(),
219
- kind: isGoalReferenceKind(value.kind) ? value.kind : "text",
220
- label,
221
- ...(optionalString(value.value) ? { value: optionalString(value.value) } : {}),
222
- ...(optionalString(value.path) ? { path: optionalString(value.path) } : {}),
223
- ...(optionalString(value.mediaType) ? { mediaType: optionalString(value.mediaType) } : {}),
224
- ...(optionalString(value.description)
225
- ? { description: optionalString(value.description) }
226
- : {}),
227
- ...(optionalString(value.content) ? { content: optionalString(value.content) } : {}),
228
- ...(optionalString(value.source) ? { source: optionalString(value.source) } : {}),
229
- };
230
- }
231
- function normalizeTaskWorktree(value) {
232
- if (!isObject(value))
233
- return undefined;
234
- const baseRef = optionalString(value.baseRef);
235
- const branchName = optionalString(value.branchName);
236
- const worktreePath = optionalString(value.path);
237
- const rawStatus = value.status;
238
- const status = rawStatus === "planned" || rawStatus === "created" || rawStatus === "failed"
239
- ? rawStatus
240
- : undefined;
241
- if (!baseRef || !branchName || !worktreePath || !status)
242
- return undefined;
243
- return {
244
- baseRef,
245
- branchName,
246
- path: worktreePath,
247
- status,
248
- ...(optionalString(value.error) ? { error: optionalString(value.error) } : {}),
249
- };
250
- }
251
- function normalizeTaskCandidate(value) {
252
- if (!isObject(value))
253
- return undefined;
254
- const baseRef = optionalString(value.baseRef);
255
- const headSha = optionalString(value.headSha);
256
- const branchName = optionalString(value.branchName);
257
- if (!baseRef || !headSha || !branchName)
258
- return undefined;
259
- return {
260
- baseRef,
261
- headSha,
262
- branchName,
263
- changedFiles: stringArray(value.changedFiles),
264
- committed: value.committed !== false,
265
- };
266
- }
267
- function normalizeTask(value) {
268
- if (!isObject(value))
269
- return null;
270
- const title = typeof value.title === "string" ? value.title : "Goal task";
271
- const prompt = typeof value.prompt === "string" ? value.prompt : title;
272
- return {
273
- id: typeof value.id === "string" ? value.id : randomUUID(),
274
- title,
275
- prompt,
276
- status: isTaskStatus(value.status) ? value.status : "pending",
277
- ...(optionalString(value.workerId) ? { workerId: optionalString(value.workerId) } : {}),
278
- attempts: typeof value.attempts === "number" && value.attempts >= 0 ? value.attempts : 0,
279
- ...(stringArray(value.dependsOn).length > 0 ? { dependsOn: stringArray(value.dependsOn) } : {}),
280
- ...(optionalString(value.parallelGroup)
281
- ? { parallelGroup: optionalString(value.parallelGroup) }
282
- : {}),
283
- ...(stringArray(value.expectedChangedScope).length > 0
284
- ? { expectedChangedScope: stringArray(value.expectedChangedScope) }
285
- : {}),
286
- integration: foldGoalTaskIntegration(isTaskIntegration(value.integration)
287
- ? value.integration
288
- : typeof value.mergeStrategy === "string"
289
- ? value.mergeStrategy
290
- : undefined),
291
- ...(normalizeTaskWorktree(value.worktree)
292
- ? { worktree: normalizeTaskWorktree(value.worktree) }
293
- : {}),
294
- ...(normalizeTaskCandidate(value.candidate)
295
- ? { candidate: normalizeTaskCandidate(value.candidate) }
296
- : {}),
297
- ...(normalizeVerification(value.verification)
298
- ? { verification: normalizeVerification(value.verification) }
299
- : {}),
300
- ...(optionalString(value.lastSummary)
301
- ? { lastSummary: optionalString(value.lastSummary) }
302
- : {}),
303
- };
304
- }
305
- function normalizeEvidence(value) {
306
- if (!isObject(value))
307
- return null;
308
- const label = typeof value.label === "string" ? value.label : "Evidence";
309
- return {
310
- id: typeof value.id === "string" ? value.id : randomUUID(),
311
- kind: isEvidenceKind(value.kind) ? value.kind : "summary",
312
- label,
313
- ...(optionalString(value.path) ? { path: optionalString(value.path) } : {}),
314
- ...(optionalString(value.content) ? { content: optionalString(value.content) } : {}),
315
- createdAt: typeof value.createdAt === "string" ? value.createdAt : nowIso(),
316
- };
317
- }
318
- function normalizeVerifier(value) {
319
- if (!isObject(value))
320
- return undefined;
321
- const description = typeof value.description === "string" ? value.description : "Goal verifier";
322
- return {
323
- description,
324
- ...(optionalString(value.command) ? { command: optionalString(value.command) } : {}),
325
- ...(optionalString(value.cwd) ? { cwd: optionalString(value.cwd) } : {}),
326
- ...(normalizeVerification(value.lastResult)
327
- ? { lastResult: normalizeVerification(value.lastResult) }
328
- : {}),
329
- };
330
- }
331
- function isIntegrationStatus(value) {
332
- return value === "none" || value === "applied" || value === "committed";
333
- }
334
- function normalizeIntegration(value) {
335
- if (!isObject(value))
336
- return undefined;
337
- if (!isIntegrationStatus(value.status))
338
- return undefined;
339
- return {
340
- status: value.status,
341
- ...(optionalString(value.headSha) ? { headSha: optionalString(value.headSha) } : {}),
342
- ...(optionalString(value.baseRef) ? { baseRef: optionalString(value.baseRef) } : {}),
343
- ...(stringArray(value.files).length > 0 ? { files: stringArray(value.files) } : {}),
344
- updatedAt: typeof value.updatedAt === "string" ? value.updatedAt : nowIso(),
345
- };
346
- }
347
- /**
348
- * Back-compat shim: infer the typed integration state from legacy evidence
349
- * labels for runs persisted before {@link GoalIntegrationState} existed. This is
350
- * the ONLY place label-matching is allowed to survive; it migrates old runs once.
351
- */
352
- function inferIntegrationFromEvidence(evidence) {
353
- const committed = evidence.find((item) => item.label === "Integrated Goal changes committed");
354
- const applied = evidence.find((item) => item.label === "Integrated worktree applied to main" ||
355
- item.label === "Goal decision: apply_integration_to_main");
356
- if (!committed && !applied)
357
- return undefined;
358
- const source = committed ?? applied;
359
- return {
360
- status: committed ? "committed" : "applied",
361
- updatedAt: source.createdAt,
362
- };
363
- }
364
- /**
365
- * Back-compat shim: infer the most recent non-audit worker completion time from
366
- * legacy "Worker <id> done/failed" evidence for runs persisted before
367
- * {@link GoalRun.lastSubstantiveWorkerAt} existed.
368
- */
369
- function inferLastSubstantiveWorkerAt(evidence) {
370
- const workerEvidence = evidence
371
- .filter((item) => /^Worker\s+\S+\s+(done|failed)$/.test(item.label))
372
- .map((item) => item.createdAt)
373
- .sort((a, b) => b.localeCompare(a));
374
- return workerEvidence[0];
375
- }
376
- function normalizeCompletionAudit(value) {
377
- if (!isObject(value))
378
- return undefined;
379
- return {
380
- status: isVerificationStatus(value.status) ? value.status : "unknown",
381
- summary: typeof value.summary === "string" ? value.summary : "",
382
- checkedAt: typeof value.checkedAt === "string" ? value.checkedAt : nowIso(),
383
- ...(optionalString(value.verifierCheckedAt)
384
- ? { verifierCheckedAt: optionalString(value.verifierCheckedAt) }
385
- : {}),
386
- ...(optionalString(value.outputPath) ? { outputPath: optionalString(value.outputPath) } : {}),
387
- };
388
- }
389
- function normalizeRun(value, fallbackProjectPath) {
390
- if (!isObject(value))
391
- return null;
392
- const title = typeof value.title === "string" ? value.title : "Untitled goal";
393
- const goal = typeof value.goal === "string" ? value.goal : title;
394
- const createdAt = typeof value.createdAt === "string" ? value.createdAt : nowIso();
395
- const projectPath = typeof value.projectPath === "string" ? value.projectPath : fallbackProjectPath;
396
- const prerequisites = Array.isArray(value.prerequisites)
397
- ? value.prerequisites
398
- .map(normalizePrerequisite)
399
- .filter((item) => !!item)
400
- : [];
401
- const tasks = Array.isArray(value.tasks)
402
- ? value.tasks.map(normalizeTask).filter((item) => !!item)
403
- : [];
404
- const computedStatus = deriveRunnableStatus(isRunStatus(value.status) ? value.status : "draft", prerequisites);
405
- const evidence = Array.isArray(value.evidence)
406
- ? value.evidence.map(normalizeEvidence).filter((item) => !!item)
407
- : [];
408
- const integration = normalizeIntegration(value.integration) ?? inferIntegrationFromEvidence(evidence);
409
- const lastSubstantiveWorkerAt = optionalString(value.lastSubstantiveWorkerAt) ?? inferLastSubstantiveWorkerAt(evidence);
410
- return {
411
- id: typeof value.id === "string" ? value.id : randomUUID(),
412
- title,
413
- goal,
414
- status: computedStatus,
415
- createdAt,
416
- updatedAt: typeof value.updatedAt === "string" ? value.updatedAt : createdAt,
417
- projectPath,
418
- successCriteria: stringArray(value.successCriteria),
419
- prerequisites,
420
- harness: Array.isArray(value.harness)
421
- ? value.harness.map(normalizeHarnessItem).filter((item) => !!item)
422
- : [],
423
- evidencePlan: Array.isArray(value.evidencePlan)
424
- ? value.evidencePlan
425
- .map(normalizeEvidencePlanItem)
426
- .filter((item) => !!item)
427
- : [],
428
- references: Array.isArray(value.references)
429
- ? value.references.map(normalizeReference).filter((item) => !!item)
430
- : [],
431
- tasks,
432
- evidence,
433
- ...(normalizeVerifier(value.verifier) ? { verifier: normalizeVerifier(value.verifier) } : {}),
434
- ...(normalizeCompletionAudit(value.completionAudit)
435
- ? { completionAudit: normalizeCompletionAudit(value.completionAudit) }
436
- : {}),
437
- ...(integration ? { integration } : {}),
438
- ...(lastSubstantiveWorkerAt ? { lastSubstantiveWorkerAt } : {}),
439
- blockers: dedupeGoalBlockers(stringArray(value.blockers)),
440
- ...(optionalString(value.activeWorkerId)
441
- ? { activeWorkerId: optionalString(value.activeWorkerId) }
442
- : {}),
443
- ...(optionalString(value.continueRequestedAt)
444
- ? { continueRequestedAt: optionalString(value.continueRequestedAt) }
445
- : {}),
446
- };
447
- }
448
- function sortNewestFirst(runs) {
449
- return [...runs].sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
450
- }
451
- function isActiveGoalRun(run) {
452
- return (run.status === "running" ||
453
- run.status === "verifying" ||
454
- run.activeWorkerId !== undefined ||
455
- run.tasks.some((task) => task.status === "running" || task.status === "verifying"));
456
- }
457
- function omittedActiveGoalRuns(previousRuns, nextRuns) {
458
- const nextIds = new Set(nextRuns.map((run) => run.id));
459
- return previousRuns.filter((run) => isActiveGoalRun(run) && !nextIds.has(run.id));
460
- }
461
- export function dedupeGoalBlockers(blockers) {
462
- return Array.from(new Set(blockers.map((item) => item.trim()).filter(Boolean)));
463
- }
464
- export function appendGoalBlockers(blockers, nextBlockers) {
465
- const additions = typeof nextBlockers === "string" ? [nextBlockers] : (nextBlockers ?? []);
466
- return dedupeGoalBlockers([...blockers, ...additions]);
467
- }
468
- function deriveRunnableStatus(requestedStatus, prerequisites) {
469
- if (requestedStatus === "passed" ||
470
- requestedStatus === "failed" ||
471
- requestedStatus === "paused") {
472
- return requestedStatus;
473
- }
474
- if (hasBlockingGoalPrerequisites(prerequisites))
475
- return "blocked";
476
- return requestedStatus;
477
- }
478
- function enqueueWrite(fn) {
479
- const result = writeQueue.then(fn);
480
- writeQueue = result.then(() => { }, () => { });
481
- return result;
482
- }
483
- /**
484
- * Persist runs to disk. MUST be called while holding the goal-store lock (it is
485
- * not reentrant). Re-reads on-disk state for the omitted-active-run guard, then
486
- * writes goals.json + meta.json + journals atomically.
487
- */
488
- async function writeGoalRunsFileCore(normalizedCwd, runs) {
489
- const dir = projectDir(normalizedCwd);
490
- await mkdir(dir, { recursive: true });
491
- const goalsPath = join(dir, "goals.json");
492
- const existingRuns = await readGoalRunsFile(normalizedCwd);
493
- const omittedActive = omittedActiveGoalRuns(existingRuns, runs);
494
- if (omittedActive.length > 0) {
495
- const timestamp = nowIso();
496
- const rejectedIds = new Set(omittedActive.map((run) => run.id));
497
- const repairedRuns = existingRuns.map((run) => rejectedIds.has(run.id)
498
- ? {
499
- ...run,
500
- evidence: [
501
- ...run.evidence,
502
- createGoalEvidence({
503
- kind: "summary",
504
- label: "Goal store write rejected",
505
- content: "Rejected an attempted Goal overwrite that omitted active work; preserving existing durable state.",
506
- createdAt: timestamp,
507
- }),
508
- ],
509
- updatedAt: timestamp,
510
- }
511
- : run);
512
- await atomicWriteJson(goalsPath, sortNewestFirst(repairedRuns));
513
- await Promise.all(repairedRuns.map((run) => writeGoalProgressJournalFromRun(normalizedCwd, run)));
514
- return;
515
- }
516
- const sorted = sortNewestFirst([...runs]);
517
- await atomicWriteJson(goalsPath, sorted);
518
- await atomicWriteJson(join(dir, "meta.json"), {
519
- path: normalizedCwd,
520
- name: basename(normalizedCwd),
521
- });
522
- await Promise.all(sorted.map((run) => writeGoalProgressJournalFromRun(normalizedCwd, run)));
523
- }
524
- async function writeGoalRunsFile(cwd, runs) {
525
- const normalizedCwd = normalizeProjectPath(cwd);
526
- const dir = projectDir(normalizedCwd);
527
- await withGoalStoreLock(dir, () => writeGoalRunsFileCore(normalizedCwd, runs));
528
- }
529
- /**
530
- * Cross-process-atomic read-modify-write. Reads the current runs INSIDE the
531
- * store lock, applies `mutate`, and writes the result before releasing the lock
532
- * so concurrent processes (the parent orchestrator and worker subprocesses both
533
- * writing via the goals tool) can never lose each other's field-level updates.
534
- */
535
- async function mutateGoalRunsLocked(cwd, mutate) {
536
- return enqueueWrite(async () => {
537
- const normalizedCwd = normalizeProjectPath(cwd);
538
- const dir = projectDir(normalizedCwd);
539
- return withGoalStoreLock(dir, async () => {
540
- const runs = await readGoalRunsFile(normalizedCwd);
541
- const outcome = await mutate(runs);
542
- if (outcome.write !== false) {
543
- await writeGoalRunsFileCore(normalizedCwd, outcome.runs);
544
- }
545
- return outcome.result;
546
- });
547
- });
548
- }
549
- const GOAL_STORE_LOCK_WAIT_MS = 10_000;
550
- const GOAL_STORE_STALE_LOCK_MS = 30_000;
551
- function isProcessAlive(pid) {
552
- if (!Number.isInteger(pid) || pid <= 0)
553
- return false;
554
- try {
555
- process.kill(pid, 0);
556
- return true;
557
- }
558
- catch (error) {
559
- const code = error.code;
560
- return code === "EPERM";
561
- }
562
- }
563
- async function shouldRemoveGoalStoreLock(lockPath) {
564
- let lockStats;
565
- try {
566
- lockStats = await stat(lockPath);
567
- }
568
- catch {
569
- return false;
570
- }
571
- if (Date.now() - lockStats.mtimeMs > GOAL_STORE_STALE_LOCK_MS)
572
- return true;
573
- try {
574
- const [pidLine] = (await readFile(lockPath, "utf-8")).split("\n");
575
- const pid = Number(pidLine?.trim());
576
- return !isProcessAlive(pid);
577
- }
578
- catch {
579
- return false;
580
- }
581
- }
582
- async function withGoalStoreLock(dir, fn) {
583
- await mkdir(dir, { recursive: true });
584
- const lockPath = join(dir, "goals.lock");
585
- const deadline = Date.now() + GOAL_STORE_LOCK_WAIT_MS;
586
- for (;;) {
587
- let handle;
588
- try {
589
- handle = await open(lockPath, "wx");
590
- await handle.writeFile(`${process.pid}\n${new Date().toISOString()}\n`, "utf-8");
591
- await handle.close();
592
- try {
593
- return await fn();
594
- }
595
- finally {
596
- await rm(lockPath, { force: true });
597
- }
598
- }
599
- catch (err) {
600
- await handle?.close().catch(() => undefined);
601
- if (err.code !== "EEXIST")
602
- throw err;
603
- if (await shouldRemoveGoalStoreLock(lockPath)) {
604
- await rm(lockPath, { force: true });
605
- continue;
606
- }
607
- if (Date.now() > deadline)
608
- throw err;
609
- await new Promise((resolve) => setTimeout(resolve, 25));
610
- }
611
- }
612
- }
613
- async function atomicWriteJson(path, value) {
614
- const tmpPath = `${path}.${process.pid}.${Date.now()}.tmp`;
615
- await writeFile(tmpPath, JSON.stringify(value, null, 2) + "\n", "utf-8");
616
- await rename(tmpPath, path);
617
- }
618
- async function readGoalRunsFile(cwd) {
619
- const normalizedCwd = normalizeProjectPath(cwd);
620
- try {
621
- const data = await readFile(join(projectDir(normalizedCwd), "goals.json"), "utf-8");
622
- const parsed = JSON.parse(data);
623
- if (!Array.isArray(parsed))
624
- return [];
625
- return sortNewestFirst(parsed
626
- .map((item) => normalizeRun(item, normalizedCwd))
627
- .filter((run) => run !== null));
628
- }
629
- catch {
630
- return [];
631
- }
632
- }
633
- export function hashPath(cwd) {
634
- return createHash("sha256").update(normalizeProjectPath(cwd)).digest("hex").slice(0, 16);
635
- }
636
- export function projectDir(cwd) {
637
- return join(goalsBaseDir(), hashPath(cwd));
638
- }
639
- async function discoverGoalRunsById(id) {
640
- try {
641
- const entries = await readdir(goalsBaseDir(), { withFileTypes: true });
642
- const matches = [];
643
- for (const entry of entries) {
644
- if (!entry.isDirectory())
645
- continue;
646
- try {
647
- const dir = join(goalsBaseDir(), entry.name);
648
- const meta = await readProjectMeta(dir);
649
- const fallbackProjectPath = meta?.path ?? dir;
650
- const data = await readFile(join(dir, "goals.json"), "utf-8");
651
- const parsed = JSON.parse(data);
652
- if (!Array.isArray(parsed))
653
- continue;
654
- for (const item of parsed) {
655
- const run = normalizeRun(item, fallbackProjectPath);
656
- if (run && (run.id === id || run.id.startsWith(id)))
657
- matches.push(run);
658
- }
659
- }
660
- catch {
661
- continue;
662
- }
663
- }
664
- return sortNewestFirst(matches)[0] ?? null;
665
- }
666
- catch {
667
- return null;
668
- }
669
- }
670
- async function readProjectMeta(dir) {
671
- try {
672
- const parsed = JSON.parse(await readFile(join(dir, "meta.json"), "utf-8"));
673
- return isObject(parsed) && typeof parsed.path === "string" ? { path: parsed.path } : null;
674
- }
675
- catch {
676
- return null;
677
- }
678
- }
679
- export function createGoalTask(input) {
680
- return {
681
- id: input.id ?? randomUUID(),
682
- title: input.title,
683
- prompt: input.prompt,
684
- status: input.status ?? "pending",
685
- ...(input.workerId ? { workerId: input.workerId } : {}),
686
- attempts: input.attempts ?? 0,
687
- ...(input.dependsOn && input.dependsOn.length > 0 ? { dependsOn: input.dependsOn } : {}),
688
- ...(input.parallelGroup ? { parallelGroup: input.parallelGroup } : {}),
689
- ...(input.expectedChangedScope && input.expectedChangedScope.length > 0
690
- ? { expectedChangedScope: input.expectedChangedScope }
691
- : {}),
692
- integration: foldGoalTaskIntegration(input.integration ?? input.mergeStrategy),
693
- ...(input.worktree ? { worktree: input.worktree } : {}),
694
- ...(input.candidate ? { candidate: input.candidate } : {}),
695
- ...(input.verification ? { verification: input.verification } : {}),
696
- ...(input.lastSummary ? { lastSummary: input.lastSummary } : {}),
697
- };
698
- }
699
- export function createGoalEvidence(input) {
700
- return {
701
- id: input.id ?? randomUUID(),
702
- kind: input.kind,
703
- label: input.label,
704
- ...(input.path ? { path: input.path } : {}),
705
- ...(input.content ? { content: input.content } : {}),
706
- createdAt: input.createdAt ?? nowIso(),
707
- };
708
- }
709
- export function createGoalRun(cwd, input) {
710
- const normalizedCwd = normalizeProjectPath(cwd);
711
- const timestamp = nowIso();
712
- const prerequisites = input.prerequisites ?? [];
713
- const status = deriveRunnableStatus(input.status ?? "draft", prerequisites);
714
- return {
715
- id: input.id ?? randomUUID(),
716
- title: input.title,
717
- goal: input.goal,
718
- status,
719
- createdAt: timestamp,
720
- updatedAt: timestamp,
721
- projectPath: normalizedCwd,
722
- successCriteria: input.successCriteria ?? [],
723
- prerequisites,
724
- harness: input.harness ?? [],
725
- evidencePlan: input.evidencePlan ?? [],
726
- references: input.references ?? [],
727
- tasks: input.tasks ?? [],
728
- evidence: input.evidence ?? [],
729
- ...(input.verifier ? { verifier: input.verifier } : {}),
730
- ...(input.completionAudit ? { completionAudit: input.completionAudit } : {}),
731
- ...(input.integration ? { integration: input.integration } : {}),
732
- ...(input.lastSubstantiveWorkerAt
733
- ? { lastSubstantiveWorkerAt: input.lastSubstantiveWorkerAt }
734
- : {}),
735
- blockers: dedupeGoalBlockers(input.blockers ?? []),
736
- ...(input.activeWorkerId ? { activeWorkerId: input.activeWorkerId } : {}),
737
- ...(input.continueRequestedAt ? { continueRequestedAt: input.continueRequestedAt } : {}),
738
- };
739
- }
740
- export async function loadGoalRuns(cwd) {
741
- return readGoalRunsFile(cwd);
742
- }
743
- export function loadGoalRunsSync(cwd) {
744
- const normalizedCwd = normalizeProjectPath(cwd);
745
- try {
746
- const data = readFileSync(join(projectDir(normalizedCwd), "goals.json"), "utf-8");
747
- const parsed = JSON.parse(data);
748
- if (!Array.isArray(parsed))
749
- return [];
750
- return sortNewestFirst(parsed
751
- .map((item) => normalizeRun(item, normalizedCwd))
752
- .filter((run) => run !== null));
753
- }
754
- catch {
755
- return [];
756
- }
757
- }
758
- export async function saveGoalRuns(cwd, runs) {
759
- return enqueueWrite(() => writeGoalRunsFile(cwd, runs));
760
- }
761
- export function saveGoalRunsSync(cwd, runs) {
762
- const normalizedCwd = normalizeProjectPath(cwd);
763
- const sorted = sortNewestFirst([...runs]);
764
- writeFileSync(join(projectDir(normalizedCwd), "goals.json"), JSON.stringify(sorted, null, 2) + "\n", "utf-8");
765
- }
766
- export async function reconcileActiveGoalRuns(cwd, options = {}) {
767
- return mutateGoalRunsLocked(cwd, (runs) => {
768
- const timestamp = nowIso();
769
- const repairedRunIds = [];
770
- let evidenceCount = 0;
771
- const nextRuns = runs.map((run) => {
772
- let next = run;
773
- const evidence = [];
774
- const blockers = new Set(run.blockers);
775
- let repaired = false;
776
- if (run.activeWorkerId && !options.isWorkerActive?.(run.activeWorkerId, run)) {
777
- const workerId = run.activeWorkerId;
778
- next = { ...next, activeWorkerId: undefined };
779
- evidence.push(createGoalEvidence({
780
- kind: "summary",
781
- label: "Goal worker reconciled",
782
- content: `Cleared stale activeWorkerId ${workerId}; no in-memory Goal worker was observed after startup/runtime reconciliation.`,
783
- createdAt: timestamp,
784
- }));
785
- repaired = true;
786
- }
787
- const tasks = next.tasks.map((task) => {
788
- if (task.status !== "running" && task.status !== "verifying")
789
- return task;
790
- const workerId = task.workerId;
791
- if (workerId && options.isWorkerActive?.(workerId, run))
792
- return task;
793
- repaired = true;
794
- evidence.push(createGoalEvidence({
795
- kind: "summary",
796
- label: "Goal task reconciled",
797
- content: `Reset stale task "${task.title}" (${task.id}) from ${task.status} to pending; no in-memory worker/verifier was observed.`,
798
- createdAt: timestamp,
799
- }));
800
- return {
801
- ...task,
802
- status: "pending",
803
- lastSummary: `Reset from stale ${task.status} state during Goal reconciliation.`,
804
- };
805
- });
806
- next = { ...next, tasks };
807
- if (next.status === "running") {
808
- const hasRunningWorker = next.activeWorkerId !== undefined &&
809
- options.isWorkerActive?.(next.activeWorkerId, run) === true;
810
- const hasActiveTask = next.tasks.some((task) => (task.status === "running" || task.status === "verifying") &&
811
- task.workerId !== undefined &&
812
- options.isWorkerActive?.(task.workerId, run) === true);
813
- if (!hasRunningWorker && !hasActiveTask) {
814
- next = { ...next, status: "ready" };
815
- repaired = true;
816
- }
817
- }
818
- else if (next.status === "verifying" && !options.isVerifierActive?.(next)) {
819
- const blocker = "Verifier was interrupted; rerun or continue the Goal to verify again.";
820
- blockers.add(blocker);
821
- evidence.push(createGoalEvidence({
822
- kind: "summary",
823
- label: "Goal verifier reconciled",
824
- content: "Reset stale verifying state to ready because no in-memory verifier process was observed.",
825
- createdAt: timestamp,
826
- }));
827
- next = { ...next, status: "ready" };
828
- repaired = true;
829
- }
830
- if (!repaired)
831
- return run;
832
- repairedRunIds.push(run.id);
833
- evidenceCount += evidence.length;
834
- return {
835
- ...next,
836
- evidence: [...next.evidence, ...evidence],
837
- blockers: dedupeGoalBlockers([...blockers]),
838
- updatedAt: timestamp,
839
- };
840
- });
841
- return {
842
- runs: nextRuns,
843
- write: repairedRunIds.length > 0,
844
- result: { runs: sortNewestFirst(nextRuns), repairedRunIds, evidenceCount },
845
- };
846
- });
847
- }
848
- export async function upsertGoalRun(cwd, input) {
849
- return mutateGoalRunsLocked(cwd, (runs) => {
850
- const existingIndex = input.id ? runs.findIndex((run) => run.id === input.id) : -1;
851
- const existing = existingIndex >= 0 ? runs[existingIndex] : undefined;
852
- const merged = existing
853
- ? {
854
- ...existing,
855
- ...input,
856
- id: existing.id,
857
- projectPath: normalizeProjectPath(cwd),
858
- createdAt: existing.createdAt,
859
- updatedAt: nowIso(),
860
- successCriteria: input.successCriteria ?? existing.successCriteria,
861
- prerequisites: input.prerequisites ?? existing.prerequisites,
862
- harness: input.harness ?? existing.harness,
863
- evidencePlan: input.evidencePlan ?? existing.evidencePlan,
864
- references: mergeGoalReferences(existing.references ?? [], input.references),
865
- tasks: mergeGoalTasks(existing.tasks, input.tasks),
866
- evidence: mergeGoalEvidence(existing.evidence, input.evidence),
867
- blockers: input.blockers
868
- ? dedupeGoalBlockers(input.blockers)
869
- : dedupeGoalBlockers(existing.blockers),
870
- status: deriveRunnableStatus(input.status ?? existing.status, input.prerequisites ?? existing.prerequisites),
871
- }
872
- : createGoalRun(cwd, input);
873
- const nextRuns = existingIndex >= 0 ? [...runs] : [merged, ...runs];
874
- if (existingIndex >= 0)
875
- nextRuns[existingIndex] = merged;
876
- return { runs: nextRuns, result: merged };
877
- });
878
- }
879
- export async function getGoalRun(cwd, id) {
880
- const runs = await loadGoalRuns(cwd);
881
- return (runs.find((run) => run.id === id || run.id.startsWith(id)) ?? (await discoverGoalRunsById(id)));
882
- }
883
- export async function getActiveGoalRun(cwd) {
884
- const runs = await loadGoalRuns(cwd);
885
- return (runs.find((run) => run.status === "running" || run.status === "verifying") ??
886
- runs.find((run) => run.status === "ready" || run.status === "blocked") ??
887
- runs.find((run) => run.status === "draft" || run.status === "paused") ??
888
- runs[0] ??
889
- null);
890
- }
891
- export async function appendGoalDecision(cwd, runId, decision) {
892
- const parts = [`kind=${decision.kind}`];
893
- if ("reason" in decision && decision.reason)
894
- parts.push(`reason=${decision.reason}`);
895
- if ("content" in decision && decision.content)
896
- parts.push(decision.content);
897
- if ("task" in decision && decision.task) {
898
- const task = decision.task;
899
- parts.push(`task=${task.id}`, `title=${task.title}`);
900
- if (task.workerId)
901
- parts.push(`worker=${task.workerId}`);
902
- }
903
- if ("attempts" in decision && typeof decision.attempts === "number")
904
- parts.push(`attempts=${decision.attempts}`);
905
- if ("workerId" in decision && decision.workerId)
906
- parts.push(`worker=${decision.workerId}`);
907
- if ("command" in decision && decision.command)
908
- parts.push(`verifier=${decision.command}`);
909
- if ("status" in decision && decision.status)
910
- parts.push(`status=${decision.status}`);
911
- parts.push(`timestamp=${nowIso()}`);
912
- return appendGoalEvidence(cwd, runId, {
913
- kind: "summary",
914
- label: `Goal decision: ${decision.kind}`,
915
- content: parts.join("; "),
916
- });
917
- }
918
- export async function appendGoalEvidence(cwd, runId, input) {
919
- const discovered = await getGoalRun(cwd, runId);
920
- const writeCwd = discovered?.projectPath ?? cwd;
921
- return mutateGoalRunsLocked(writeCwd, (runs) => {
922
- const index = runs.findIndex((run) => run.id === runId || run.id.startsWith(runId));
923
- if (index === -1)
924
- return { runs, result: null, write: false };
925
- const run = runs[index];
926
- const updated = {
927
- ...run,
928
- evidence: [...run.evidence, createGoalEvidence(input)],
929
- updatedAt: nowIso(),
930
- };
931
- const nextRuns = [...runs];
932
- nextRuns[index] = updated;
933
- return { runs: nextRuns, result: updated };
934
- });
935
- }
936
- export async function updateGoalTask(cwd, runId, taskId, patch) {
937
- const discovered = await getGoalRun(cwd, runId);
938
- const writeCwd = discovered?.projectPath ?? cwd;
939
- return mutateGoalRunsLocked(writeCwd, (runs) => {
940
- const runIndex = runs.findIndex((run) => run.id === runId || run.id.startsWith(runId));
941
- if (runIndex === -1)
942
- return { runs, result: null, write: false };
943
- const run = runs[runIndex];
944
- const taskIndex = run.tasks.findIndex((task) => task.id === taskId || task.id.startsWith(taskId));
945
- const tasks = [...run.tasks];
946
- if (taskIndex === -1) {
947
- if ("title" in patch && "prompt" in patch && patch.title && patch.prompt) {
948
- tasks.push(createGoalTask({
949
- ...patch,
950
- title: patch.title,
951
- prompt: patch.prompt,
952
- }));
953
- }
954
- else {
955
- return { runs, result: null, write: false };
956
- }
957
- }
958
- else {
959
- const existingTask = tasks[taskIndex];
960
- tasks[taskIndex] = {
961
- ...existingTask,
962
- ...patch,
963
- id: existingTask.id,
964
- title: patch.title ?? existingTask.title,
965
- prompt: patch.prompt ?? existingTask.prompt,
966
- };
967
- }
968
- const updated = { ...run, tasks, updatedAt: nowIso() };
969
- const nextRuns = [...runs];
970
- nextRuns[runIndex] = updated;
971
- return { runs: nextRuns, result: updated };
972
- });
973
- }
974
- /**
975
- * Record the typed integration state from code (git truth), so the controller
976
- * never has to parse evidence labels to know whether candidates reached main.
977
- */
978
- export async function setGoalIntegrationState(cwd, runId, state) {
979
- const discovered = await getGoalRun(cwd, runId);
980
- const writeCwd = discovered?.projectPath ?? cwd;
981
- return mutateGoalRunsLocked(writeCwd, (runs) => {
982
- const index = runs.findIndex((run) => run.id === runId || run.id.startsWith(runId));
983
- if (index === -1)
984
- return { runs, result: null, write: false };
985
- const run = runs[index];
986
- const updated = { ...run, integration: state, updatedAt: nowIso() };
987
- const nextRuns = [...runs];
988
- nextRuns[index] = updated;
989
- return { runs: nextRuns, result: updated };
990
- });
991
- }
992
- /**
993
- * Stamp the most recent substantive (non-audit, non-integration) worker
994
- * completion time, driving verifier/audit staleness deterministically.
995
- */
996
- export async function recordGoalSubstantiveWorker(cwd, runId, atIso) {
997
- const discovered = await getGoalRun(cwd, runId);
998
- const writeCwd = discovered?.projectPath ?? cwd;
999
- return mutateGoalRunsLocked(writeCwd, (runs) => {
1000
- const index = runs.findIndex((run) => run.id === runId || run.id.startsWith(runId));
1001
- if (index === -1)
1002
- return { runs, result: null, write: false };
1003
- const run = runs[index];
1004
- const updated = { ...run, lastSubstantiveWorkerAt: atIso, updatedAt: nowIso() };
1005
- const nextRuns = [...runs];
1006
- nextRuns[index] = updated;
1007
- return { runs: nextRuns, result: updated };
1008
- });
1009
- }
1010
- /**
1011
- * Infer whether a prerequisite is locally resolvable by the agent or genuinely
1012
- * external (user-supplied). An explicit `kind` wins; otherwise a runnable
1013
- * `checkCommand` implies the agent can both check and satisfy it locally.
1014
- */
1015
- export function prerequisiteKind(item) {
1016
- if (item.kind)
1017
- return item.kind;
1018
- return item.checkCommand?.trim() ? "local" : "external";
1019
- }
1020
- function isUnmetGoalPrerequisite(item) {
1021
- return item.status !== "met" || !item.evidence?.trim();
1022
- }
1023
- /**
1024
- * Local unmet prerequisites no longer block the Goal — the controller schedules
1025
- * a worker task to resolve them. Only unmet **external** prerequisites (true
1026
- * user-supplied inputs) are blocking.
1027
- */
1028
- export function isBlockingGoalPrerequisite(item) {
1029
- return isUnmetGoalPrerequisite(item) && prerequisiteKind(item) === "external";
1030
- }
1031
- export function isUnmetLocalGoalPrerequisite(item) {
1032
- return isUnmetGoalPrerequisite(item) && prerequisiteKind(item) === "local";
1033
- }
1034
- export function unmetLocalGoalPrerequisites(run) {
1035
- return run.prerequisites.filter(isUnmetLocalGoalPrerequisite);
1036
- }
1037
- export function goalHasUnmetLocalPrerequisites(run) {
1038
- return run.prerequisites.some(isUnmetLocalGoalPrerequisite);
1039
- }
1040
- export function hasBlockingGoalPrerequisites(prerequisites) {
1041
- return prerequisites.some(isBlockingGoalPrerequisite);
1042
- }
1043
- export function goalHasBlockingPrerequisites(run) {
1044
- return hasBlockingGoalPrerequisites(run.prerequisites);
1045
- }
1046
- export function formatGoalPrerequisiteInstruction(item) {
1047
- const instructions = item.instructions?.trim();
1048
- if (instructions)
1049
- return instructions;
1050
- if (item.status === "met" && !item.evidence?.trim()) {
1051
- return "Prerequisite is marked met but has no recorded check evidence; verify it locally and record non-secret evidence.";
1052
- }
1053
- if (item.status === "unknown") {
1054
- return "Check this prerequisite locally and record non-secret evidence before workers can start.";
1055
- }
1056
- return "User must provide this prerequisite.";
1057
- }
1058
- export function formatGoalBlockingPrerequisiteList(prerequisites) {
1059
- const missing = prerequisites.filter(isBlockingGoalPrerequisite);
1060
- if (missing.length === 0)
1061
- return "Goal has no missing user prerequisites.";
1062
- return missing
1063
- .map((item) => `${item.label}: ${formatGoalPrerequisiteInstruction(item)}`)
1064
- .join("; ");
1065
- }
1066
- export function formatGoalBlockingPrerequisites(run) {
1067
- return formatGoalBlockingPrerequisiteList(run.prerequisites);
1068
- }
1069
- export function summarizeGoalCountsFromRuns(runs) {
1070
- const counts = {
1071
- total: runs.length,
1072
- active: 0,
1073
- blocked: 0,
1074
- pending: 0,
1075
- running: 0,
1076
- passed: 0,
1077
- failed: 0,
1078
- };
1079
- for (const run of runs) {
1080
- if (run.status === "blocked")
1081
- counts.blocked++;
1082
- if (run.status === "running" || run.status === "verifying")
1083
- counts.running++;
1084
- if (run.status === "passed")
1085
- counts.passed++;
1086
- if (run.status === "failed")
1087
- counts.failed++;
1088
- if (run.status === "draft" || run.status === "ready" || run.status === "paused")
1089
- counts.pending++;
1090
- if (run.status !== "passed" && run.status !== "failed")
1091
- counts.active++;
1092
- }
1093
- return counts;
1094
- }
1095
- export async function summarizeGoalCounts(cwd) {
1096
- return summarizeGoalCountsFromRuns(await loadGoalRuns(cwd));
1097
- }
1098
- async function writeGoalProgressJournalFromRun(cwd, run) {
1099
- const dir = join(projectDir(cwd), "journals");
1100
- await mkdir(dir, { recursive: true });
1101
- const path = join(dir, `${run.id}.md`);
1102
- const lines = [
1103
- `# ${run.title}`,
1104
- "",
1105
- `Status: ${run.status}`,
1106
- `Goal: ${run.goal}`,
1107
- "",
1108
- "## Success criteria",
1109
- ...(run.successCriteria.length
1110
- ? run.successCriteria.map((item) => `- ${item}`)
1111
- : ["- none recorded"]),
1112
- "",
1113
- "## Prerequisites",
1114
- ...(run.prerequisites.length
1115
- ? run.prerequisites.map((item) => `- [${item.status}] ${item.label}${item.evidence ? ` — ${item.evidence}` : ""}`)
1116
- : ["- none"]),
1117
- "",
1118
- "## References",
1119
- ...(run.references?.length
1120
- ? run.references.map((item) => `- [${item.kind}] ${item.id}: ${item.label}${item.value ? ` — ${item.value}` : ""}${item.path ? ` (${item.path})` : ""}`)
1121
- : ["- none"]),
1122
- "",
1123
- "## Tasks",
1124
- ...(run.tasks.length
1125
- ? run.tasks.map((task) => `- [${task.status}] ${task.title} (attempts: ${task.attempts})${task.lastSummary ? ` — ${task.lastSummary}` : ""}`)
1126
- : ["- none"]),
1127
- "",
1128
- "## Verifier",
1129
- run.verifier?.lastResult
1130
- ? `- ${run.verifier.lastResult.status}: ${run.verifier.lastResult.summary}${run.verifier.lastResult.outputPath ? ` (${run.verifier.lastResult.outputPath})` : ""}`
1131
- : `- ${run.verifier?.command ?? "none"}`,
1132
- "",
1133
- "## Final completion audit",
1134
- run.completionAudit
1135
- ? `- ${run.completionAudit.status}: ${run.completionAudit.summary}${run.completionAudit.outputPath ? ` (${run.completionAudit.outputPath})` : ""}`
1136
- : "- none",
1137
- "",
1138
- "## Blockers",
1139
- ...(run.blockers.length ? run.blockers.map((item) => `- ${item}`) : ["- none"]),
1140
- "",
1141
- "## Recent evidence",
1142
- ...run.evidence
1143
- .slice(-10)
1144
- .map((item) => `- ${item.createdAt} [${item.kind}] ${item.label}${item.path ? ` (${item.path})` : ""}${item.content ? ` — ${item.content}` : ""}`),
1145
- "",
1146
- ];
1147
- await writeFile(path, lines.join("\n"), "utf-8");
1148
- return path;
1149
- }
1150
- export async function writeGoalProgressJournal(cwd, runId) {
1151
- const run = await getGoalRun(cwd, runId);
1152
- if (!run)
1153
- return null;
1154
- return writeGoalProgressJournalFromRun(run.projectPath, run);
1155
- }
1156
- //# sourceMappingURL=goal-store.js.map