@caupulican/pi-adaptative 0.81.38 → 0.81.39

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 (433) hide show
  1. package/CHANGELOG.md +79 -0
  2. package/dist/bundled-resources/extensions/tmux-agent-manager/README.md +18 -1
  3. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.d.ts +131 -0
  4. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.d.ts.map +1 -0
  5. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.js +196 -0
  6. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.js.map +1 -0
  7. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.ts +308 -0
  8. package/dist/bundled-resources/extensions/tmux-agent-manager/index.d.ts +22 -2
  9. package/dist/bundled-resources/extensions/tmux-agent-manager/index.d.ts.map +1 -1
  10. package/dist/bundled-resources/extensions/tmux-agent-manager/index.js +585 -24
  11. package/dist/bundled-resources/extensions/tmux-agent-manager/index.js.map +1 -1
  12. package/dist/bundled-resources/extensions/tmux-agent-manager/index.ts +749 -27
  13. package/dist/bundled-resources/runtimes/pi-shell-engine/commands/__init__.py +43 -0
  14. package/dist/bundled-resources/runtimes/pi-shell-engine/commands/fs.py +270 -0
  15. package/dist/bundled-resources/runtimes/pi-shell-engine/commands/search.py +252 -0
  16. package/dist/bundled-resources/runtimes/pi-shell-engine/commands/strings.py +399 -0
  17. package/dist/bundled-resources/runtimes/pi-shell-engine/commands/text.py +575 -0
  18. package/dist/bundled-resources/runtimes/pi-shell-engine/context.py +52 -0
  19. package/dist/bundled-resources/runtimes/pi-shell-engine/errors.py +49 -0
  20. package/dist/bundled-resources/runtimes/pi-shell-engine/exec.py +734 -0
  21. package/dist/bundled-resources/runtimes/pi-shell-engine/expand.py +238 -0
  22. package/dist/bundled-resources/runtimes/pi-shell-engine/main.py +132 -0
  23. package/dist/bundled-resources/runtimes/pi-shell-engine/nodes.py +116 -0
  24. package/dist/bundled-resources/runtimes/pi-shell-engine/parser.py +287 -0
  25. package/dist/bundled-resources/runtimes/pi-shell-engine/proc.py +137 -0
  26. package/dist/bundled-resources/runtimes/pi-shell-engine/state.py +100 -0
  27. package/dist/bundled-resources/runtimes/pi-shell-engine/tokens.py +579 -0
  28. package/dist/bundled-resources/skills/tool-call-repair/SKILL.md +19 -9
  29. package/dist/bundled-resources/skills/tool-call-repair/references/failure-grammar.md +22 -5
  30. package/dist/bundled-resources/skills/tool-call-repair/references/repair-catalogue.md +5 -5
  31. package/dist/bundled-resources/skills/tool-call-repair/references/text-protocol-grammar.md +28 -7
  32. package/dist/cli/args.d.ts +3 -0
  33. package/dist/cli/args.d.ts.map +1 -1
  34. package/dist/cli/args.js +15 -0
  35. package/dist/cli/args.js.map +1 -1
  36. package/dist/core/agent-paths.d.ts +49 -0
  37. package/dist/core/agent-paths.d.ts.map +1 -0
  38. package/dist/core/agent-paths.js +107 -0
  39. package/dist/core/agent-paths.js.map +1 -0
  40. package/dist/core/agent-session-services.d.ts.map +1 -1
  41. package/dist/core/agent-session-services.js +3 -3
  42. package/dist/core/agent-session-services.js.map +1 -1
  43. package/dist/core/agent-session.d.ts +234 -17
  44. package/dist/core/agent-session.d.ts.map +1 -1
  45. package/dist/core/agent-session.js +484 -62
  46. package/dist/core/agent-session.js.map +1 -1
  47. package/dist/core/autonomy/contracts.d.ts +9 -0
  48. package/dist/core/autonomy/contracts.d.ts.map +1 -1
  49. package/dist/core/autonomy/contracts.js.map +1 -1
  50. package/dist/core/autonomy/lane-tracker.d.ts +10 -1
  51. package/dist/core/autonomy/lane-tracker.d.ts.map +1 -1
  52. package/dist/core/autonomy/lane-tracker.js +5 -1
  53. package/dist/core/autonomy/lane-tracker.js.map +1 -1
  54. package/dist/core/background-lane-controller.d.ts +122 -6
  55. package/dist/core/background-lane-controller.d.ts.map +1 -1
  56. package/dist/core/background-lane-controller.js +446 -89
  57. package/dist/core/background-lane-controller.js.map +1 -1
  58. package/dist/core/bash-execution-controller.d.ts +4 -0
  59. package/dist/core/bash-execution-controller.d.ts.map +1 -1
  60. package/dist/core/bash-execution-controller.js +7 -1
  61. package/dist/core/bash-execution-controller.js.map +1 -1
  62. package/dist/core/compaction-support.d.ts +13 -3
  63. package/dist/core/compaction-support.d.ts.map +1 -1
  64. package/dist/core/compaction-support.js +43 -7
  65. package/dist/core/compaction-support.js.map +1 -1
  66. package/dist/core/context/context-audit.d.ts +33 -1
  67. package/dist/core/context/context-audit.d.ts.map +1 -1
  68. package/dist/core/context/context-audit.js +31 -5
  69. package/dist/core/context/context-audit.js.map +1 -1
  70. package/dist/core/context-gc.d.ts.map +1 -1
  71. package/dist/core/context-gc.js +16 -1
  72. package/dist/core/context-gc.js.map +1 -1
  73. package/dist/core/context-pipeline.d.ts +26 -4
  74. package/dist/core/context-pipeline.d.ts.map +1 -1
  75. package/dist/core/context-pipeline.js +137 -14
  76. package/dist/core/context-pipeline.js.map +1 -1
  77. package/dist/core/cost-guard.d.ts +19 -3
  78. package/dist/core/cost-guard.d.ts.map +1 -1
  79. package/dist/core/cost-guard.js +18 -3
  80. package/dist/core/cost-guard.js.map +1 -1
  81. package/dist/core/delegation/session-worker-result.d.ts +34 -4
  82. package/dist/core/delegation/session-worker-result.d.ts.map +1 -1
  83. package/dist/core/delegation/session-worker-result.js +64 -4
  84. package/dist/core/delegation/session-worker-result.js.map +1 -1
  85. package/dist/core/delegation/worker-result.d.ts +42 -1
  86. package/dist/core/delegation/worker-result.d.ts.map +1 -1
  87. package/dist/core/delegation/worker-result.js +68 -0
  88. package/dist/core/delegation/worker-result.js.map +1 -1
  89. package/dist/core/extensions/loader.d.ts.map +1 -1
  90. package/dist/core/extensions/loader.js +20 -0
  91. package/dist/core/extensions/loader.js.map +1 -1
  92. package/dist/core/extensions/runner.d.ts.map +1 -1
  93. package/dist/core/extensions/runner.js +1 -0
  94. package/dist/core/extensions/runner.js.map +1 -1
  95. package/dist/core/extensions/types.d.ts +51 -0
  96. package/dist/core/extensions/types.d.ts.map +1 -1
  97. package/dist/core/extensions/types.js.map +1 -1
  98. package/dist/core/goal-loop-controller.d.ts +17 -1
  99. package/dist/core/goal-loop-controller.d.ts.map +1 -1
  100. package/dist/core/goal-loop-controller.js +79 -11
  101. package/dist/core/goal-loop-controller.js.map +1 -1
  102. package/dist/core/goals/goal-continuation-controller.d.ts +48 -2
  103. package/dist/core/goals/goal-continuation-controller.d.ts.map +1 -1
  104. package/dist/core/goals/goal-continuation-controller.js +77 -0
  105. package/dist/core/goals/goal-continuation-controller.js.map +1 -1
  106. package/dist/core/goals/goal-continuation-defaults.d.ts +39 -0
  107. package/dist/core/goals/goal-continuation-defaults.d.ts.map +1 -1
  108. package/dist/core/goals/goal-continuation-defaults.js +42 -0
  109. package/dist/core/goals/goal-continuation-defaults.js.map +1 -1
  110. package/dist/core/goals/goal-continuation-prompt.d.ts +4 -0
  111. package/dist/core/goals/goal-continuation-prompt.d.ts.map +1 -1
  112. package/dist/core/goals/goal-continuation-prompt.js +51 -10
  113. package/dist/core/goals/goal-continuation-prompt.js.map +1 -1
  114. package/dist/core/goals/goal-runtime-snapshot.d.ts +101 -2
  115. package/dist/core/goals/goal-runtime-snapshot.d.ts.map +1 -1
  116. package/dist/core/goals/goal-runtime-snapshot.js +87 -4
  117. package/dist/core/goals/goal-runtime-snapshot.js.map +1 -1
  118. package/dist/core/goals/goal-state.d.ts +89 -1
  119. package/dist/core/goals/goal-state.d.ts.map +1 -1
  120. package/dist/core/goals/goal-state.js +71 -5
  121. package/dist/core/goals/goal-state.js.map +1 -1
  122. package/dist/core/goals/goal-tool-core.d.ts +56 -2
  123. package/dist/core/goals/goal-tool-core.d.ts.map +1 -1
  124. package/dist/core/goals/goal-tool-core.js +111 -5
  125. package/dist/core/goals/goal-tool-core.js.map +1 -1
  126. package/dist/core/goals/session-goal-state.d.ts +11 -2
  127. package/dist/core/goals/session-goal-state.d.ts.map +1 -1
  128. package/dist/core/goals/session-goal-state.js +32 -17
  129. package/dist/core/goals/session-goal-state.js.map +1 -1
  130. package/dist/core/keybindings.d.ts +10 -0
  131. package/dist/core/keybindings.d.ts.map +1 -1
  132. package/dist/core/keybindings.js +10 -2
  133. package/dist/core/keybindings.js.map +1 -1
  134. package/dist/core/learning/observation-store.d.ts +12 -3
  135. package/dist/core/learning/observation-store.d.ts.map +1 -1
  136. package/dist/core/learning/observation-store.js +30 -15
  137. package/dist/core/learning/observation-store.js.map +1 -1
  138. package/dist/core/learning/skill-curator.d.ts +5 -1
  139. package/dist/core/learning/skill-curator.d.ts.map +1 -1
  140. package/dist/core/learning/skill-curator.js +21 -19
  141. package/dist/core/learning/skill-curator.js.map +1 -1
  142. package/dist/core/local-runtime-controller.d.ts +65 -3
  143. package/dist/core/local-runtime-controller.d.ts.map +1 -1
  144. package/dist/core/local-runtime-controller.js +186 -26
  145. package/dist/core/local-runtime-controller.js.map +1 -1
  146. package/dist/core/memory/providers/file-store.d.ts +1 -1
  147. package/dist/core/memory/providers/file-store.d.ts.map +1 -1
  148. package/dist/core/memory/providers/file-store.js +6 -6
  149. package/dist/core/memory/providers/file-store.js.map +1 -1
  150. package/dist/core/model-capability.d.ts +34 -0
  151. package/dist/core/model-capability.d.ts.map +1 -1
  152. package/dist/core/model-capability.js +42 -1
  153. package/dist/core/model-capability.js.map +1 -1
  154. package/dist/core/model-router/tool-escalation.d.ts +15 -0
  155. package/dist/core/model-router/tool-escalation.d.ts.map +1 -1
  156. package/dist/core/model-router/tool-escalation.js +23 -1
  157. package/dist/core/model-router/tool-escalation.js.map +1 -1
  158. package/dist/core/model-router-controller.d.ts +34 -7
  159. package/dist/core/model-router-controller.d.ts.map +1 -1
  160. package/dist/core/model-router-controller.js +95 -16
  161. package/dist/core/model-router-controller.js.map +1 -1
  162. package/dist/core/models/adaptation-store.d.ts +7 -0
  163. package/dist/core/models/adaptation-store.d.ts.map +1 -1
  164. package/dist/core/models/adaptation-store.js +47 -11
  165. package/dist/core/models/adaptation-store.js.map +1 -1
  166. package/dist/core/models/default-model-suggestions.d.ts.map +1 -1
  167. package/dist/core/models/default-model-suggestions.js +17 -0
  168. package/dist/core/models/default-model-suggestions.js.map +1 -1
  169. package/dist/core/models/fitness-store.d.ts +3 -0
  170. package/dist/core/models/fitness-store.d.ts.map +1 -1
  171. package/dist/core/models/fitness-store.js +11 -2
  172. package/dist/core/models/fitness-store.js.map +1 -1
  173. package/dist/core/models/llamacpp-runtime.d.ts +180 -0
  174. package/dist/core/models/llamacpp-runtime.d.ts.map +1 -0
  175. package/dist/core/models/llamacpp-runtime.js +475 -0
  176. package/dist/core/models/llamacpp-runtime.js.map +1 -0
  177. package/dist/core/models/local-registration.d.ts +40 -0
  178. package/dist/core/models/local-registration.d.ts.map +1 -1
  179. package/dist/core/models/local-registration.js +94 -5
  180. package/dist/core/models/local-registration.js.map +1 -1
  181. package/dist/core/models/local-runtime.d.ts.map +1 -1
  182. package/dist/core/models/local-runtime.js +6 -5
  183. package/dist/core/models/local-runtime.js.map +1 -1
  184. package/dist/core/models/model-ref.d.ts +7 -0
  185. package/dist/core/models/model-ref.d.ts.map +1 -1
  186. package/dist/core/models/model-ref.js +26 -0
  187. package/dist/core/models/model-ref.js.map +1 -1
  188. package/dist/core/models/needle-runtime.d.ts +257 -0
  189. package/dist/core/models/needle-runtime.d.ts.map +1 -0
  190. package/dist/core/models/needle-runtime.js +519 -0
  191. package/dist/core/models/needle-runtime.js.map +1 -0
  192. package/dist/core/models/prism-llamacpp-lifecycle.d.ts +89 -0
  193. package/dist/core/models/prism-llamacpp-lifecycle.d.ts.map +1 -0
  194. package/dist/core/models/prism-llamacpp-lifecycle.js +121 -0
  195. package/dist/core/models/prism-llamacpp-lifecycle.js.map +1 -0
  196. package/dist/core/package-manager.d.ts.map +1 -1
  197. package/dist/core/package-manager.js +11 -10
  198. package/dist/core/package-manager.js.map +1 -1
  199. package/dist/core/process-matrix/codes.d.ts +72 -0
  200. package/dist/core/process-matrix/codes.d.ts.map +1 -0
  201. package/dist/core/process-matrix/codes.js +15 -0
  202. package/dist/core/process-matrix/codes.js.map +1 -0
  203. package/dist/core/process-matrix/runtime.d.ts +63 -0
  204. package/dist/core/process-matrix/runtime.d.ts.map +1 -0
  205. package/dist/core/process-matrix/runtime.js +310 -0
  206. package/dist/core/process-matrix/runtime.js.map +1 -0
  207. package/dist/core/process-matrix/store.d.ts +22 -0
  208. package/dist/core/process-matrix/store.d.ts.map +1 -0
  209. package/dist/core/process-matrix/store.js +80 -0
  210. package/dist/core/process-matrix/store.js.map +1 -0
  211. package/dist/core/process-matrix/supervisor.d.ts +72 -0
  212. package/dist/core/process-matrix/supervisor.d.ts.map +1 -0
  213. package/dist/core/process-matrix/supervisor.js +130 -0
  214. package/dist/core/process-matrix/supervisor.js.map +1 -0
  215. package/dist/core/profile-registry.d.ts +7 -0
  216. package/dist/core/profile-registry.d.ts.map +1 -1
  217. package/dist/core/profile-registry.js +20 -0
  218. package/dist/core/profile-registry.js.map +1 -1
  219. package/dist/core/python-runtime.d.ts.map +1 -1
  220. package/dist/core/python-runtime.js +3 -3
  221. package/dist/core/python-runtime.js.map +1 -1
  222. package/dist/core/reflection-controller.d.ts +29 -5
  223. package/dist/core/reflection-controller.d.ts.map +1 -1
  224. package/dist/core/reflection-controller.js +215 -126
  225. package/dist/core/reflection-controller.js.map +1 -1
  226. package/dist/core/reload-blockers.d.ts +36 -0
  227. package/dist/core/reload-blockers.d.ts.map +1 -1
  228. package/dist/core/reload-blockers.js +44 -0
  229. package/dist/core/reload-blockers.js.map +1 -1
  230. package/dist/core/resource-loader.d.ts.map +1 -1
  231. package/dist/core/resource-loader.js +8 -7
  232. package/dist/core/resource-loader.js.map +1 -1
  233. package/dist/core/runtime-builder.d.ts +58 -5
  234. package/dist/core/runtime-builder.d.ts.map +1 -1
  235. package/dist/core/runtime-builder.js +209 -25
  236. package/dist/core/runtime-builder.js.map +1 -1
  237. package/dist/core/scout-controller.d.ts +6 -0
  238. package/dist/core/scout-controller.d.ts.map +1 -1
  239. package/dist/core/scout-controller.js +66 -52
  240. package/dist/core/scout-controller.js.map +1 -1
  241. package/dist/core/sdk.d.ts.map +1 -1
  242. package/dist/core/sdk.js +3 -3
  243. package/dist/core/sdk.js.map +1 -1
  244. package/dist/core/session-role.d.ts +31 -0
  245. package/dist/core/session-role.d.ts.map +1 -0
  246. package/dist/core/session-role.js +52 -0
  247. package/dist/core/session-role.js.map +1 -0
  248. package/dist/core/settings-manager.d.ts +42 -3
  249. package/dist/core/settings-manager.d.ts.map +1 -1
  250. package/dist/core/settings-manager.js +94 -60
  251. package/dist/core/settings-manager.js.map +1 -1
  252. package/dist/core/system-prompt-builder.d.ts +12 -0
  253. package/dist/core/system-prompt-builder.d.ts.map +1 -1
  254. package/dist/core/system-prompt-builder.js +6 -0
  255. package/dist/core/system-prompt-builder.js.map +1 -1
  256. package/dist/core/system-prompt.d.ts +14 -1
  257. package/dist/core/system-prompt.d.ts.map +1 -1
  258. package/dist/core/system-prompt.js +20 -3
  259. package/dist/core/system-prompt.js.map +1 -1
  260. package/dist/core/tasks/session-task-state.d.ts +11 -2
  261. package/dist/core/tasks/session-task-state.d.ts.map +1 -1
  262. package/dist/core/tasks/session-task-state.js +27 -11
  263. package/dist/core/tasks/session-task-state.js.map +1 -1
  264. package/dist/core/tasks/task-contract-monitor.d.ts +45 -0
  265. package/dist/core/tasks/task-contract-monitor.d.ts.map +1 -0
  266. package/dist/core/tasks/task-contract-monitor.js +56 -0
  267. package/dist/core/tasks/task-contract-monitor.js.map +1 -0
  268. package/dist/core/tasks/task-state.d.ts +8 -0
  269. package/dist/core/tasks/task-state.d.ts.map +1 -1
  270. package/dist/core/tasks/task-state.js +28 -1
  271. package/dist/core/tasks/task-state.js.map +1 -1
  272. package/dist/core/tool-gate-controller.d.ts.map +1 -1
  273. package/dist/core/tool-gate-controller.js +5 -0
  274. package/dist/core/tool-gate-controller.js.map +1 -1
  275. package/dist/core/tool-recovery-log-records.d.ts +7 -0
  276. package/dist/core/tool-recovery-log-records.d.ts.map +1 -1
  277. package/dist/core/tool-recovery-log-records.js +14 -6
  278. package/dist/core/tool-recovery-log-records.js.map +1 -1
  279. package/dist/core/tool-selection/promotion.d.ts +54 -0
  280. package/dist/core/tool-selection/promotion.d.ts.map +1 -0
  281. package/dist/core/tool-selection/promotion.js +81 -0
  282. package/dist/core/tool-selection/promotion.js.map +1 -0
  283. package/dist/core/tool-selection/tool-performance-store.d.ts +37 -0
  284. package/dist/core/tool-selection/tool-performance-store.d.ts.map +1 -1
  285. package/dist/core/tool-selection/tool-performance-store.js +87 -3
  286. package/dist/core/tool-selection/tool-performance-store.js.map +1 -1
  287. package/dist/core/tool-selection/tool-selection-controller.d.ts +45 -0
  288. package/dist/core/tool-selection/tool-selection-controller.d.ts.map +1 -1
  289. package/dist/core/tool-selection/tool-selection-controller.js +96 -0
  290. package/dist/core/tool-selection/tool-selection-controller.js.map +1 -1
  291. package/dist/core/tools/bash.d.ts +18 -0
  292. package/dist/core/tools/bash.d.ts.map +1 -1
  293. package/dist/core/tools/bash.js +95 -16
  294. package/dist/core/tools/bash.js.map +1 -1
  295. package/dist/core/tools/delegate-status.d.ts +14 -0
  296. package/dist/core/tools/delegate-status.d.ts.map +1 -1
  297. package/dist/core/tools/delegate-status.js +82 -7
  298. package/dist/core/tools/delegate-status.js.map +1 -1
  299. package/dist/core/tools/delegate.d.ts.map +1 -1
  300. package/dist/core/tools/delegate.js +25 -8
  301. package/dist/core/tools/delegate.js.map +1 -1
  302. package/dist/core/tools/goal.d.ts +94 -3
  303. package/dist/core/tools/goal.d.ts.map +1 -1
  304. package/dist/core/tools/goal.js +165 -15
  305. package/dist/core/tools/goal.js.map +1 -1
  306. package/dist/core/tools/model-fitness.d.ts +7 -0
  307. package/dist/core/tools/model-fitness.d.ts.map +1 -1
  308. package/dist/core/tools/model-fitness.js +2 -2
  309. package/dist/core/tools/model-fitness.js.map +1 -1
  310. package/dist/core/tools/shell-contract-router.d.ts +6 -1
  311. package/dist/core/tools/shell-contract-router.d.ts.map +1 -1
  312. package/dist/core/tools/shell-contract-router.js +23 -2
  313. package/dist/core/tools/shell-contract-router.js.map +1 -1
  314. package/dist/core/tools/shell-session.d.ts +89 -0
  315. package/dist/core/tools/shell-session.d.ts.map +1 -0
  316. package/dist/core/tools/shell-session.js +432 -0
  317. package/dist/core/tools/shell-session.js.map +1 -0
  318. package/dist/core/tools/task-steps.d.ts +4 -0
  319. package/dist/core/tools/task-steps.d.ts.map +1 -1
  320. package/dist/core/tools/task-steps.js +63 -8
  321. package/dist/core/tools/task-steps.js.map +1 -1
  322. package/dist/core/tools/tmux-dispatch.d.ts +86 -0
  323. package/dist/core/tools/tmux-dispatch.d.ts.map +1 -0
  324. package/dist/core/tools/tmux-dispatch.js +91 -0
  325. package/dist/core/tools/tmux-dispatch.js.map +1 -0
  326. package/dist/core/tools/windows-shell-engine.d.ts +42 -0
  327. package/dist/core/tools/windows-shell-engine.d.ts.map +1 -0
  328. package/dist/core/tools/windows-shell-engine.js +153 -0
  329. package/dist/core/tools/windows-shell-engine.js.map +1 -0
  330. package/dist/core/tools/windows-shell-state.d.ts +40 -0
  331. package/dist/core/tools/windows-shell-state.d.ts.map +1 -0
  332. package/dist/core/tools/windows-shell-state.js +59 -0
  333. package/dist/core/tools/windows-shell-state.js.map +1 -0
  334. package/dist/core/tools/worktree-sync.d.ts +24 -0
  335. package/dist/core/tools/worktree-sync.d.ts.map +1 -0
  336. package/dist/core/tools/worktree-sync.js +338 -0
  337. package/dist/core/tools/worktree-sync.js.map +1 -0
  338. package/dist/core/trust-manager.d.ts +4 -1
  339. package/dist/core/trust-manager.d.ts.map +1 -1
  340. package/dist/core/trust-manager.js +20 -2
  341. package/dist/core/trust-manager.js.map +1 -1
  342. package/dist/core/util/atomic-file.d.ts +55 -0
  343. package/dist/core/util/atomic-file.d.ts.map +1 -0
  344. package/dist/core/util/atomic-file.js +255 -0
  345. package/dist/core/util/atomic-file.js.map +1 -0
  346. package/dist/core/util/minimatch-cache.d.ts +33 -0
  347. package/dist/core/util/minimatch-cache.d.ts.map +1 -0
  348. package/dist/core/util/minimatch-cache.js +0 -0
  349. package/dist/core/util/minimatch-cache.js.map +1 -0
  350. package/dist/core/worktree-sync/codes.d.ts +227 -0
  351. package/dist/core/worktree-sync/codes.d.ts.map +1 -0
  352. package/dist/core/worktree-sync/codes.js +14 -0
  353. package/dist/core/worktree-sync/codes.js.map +1 -0
  354. package/dist/core/worktree-sync/git-engine.d.ts +156 -0
  355. package/dist/core/worktree-sync/git-engine.d.ts.map +1 -0
  356. package/dist/core/worktree-sync/git-engine.js +1191 -0
  357. package/dist/core/worktree-sync/git-engine.js.map +1 -0
  358. package/dist/core/worktree-sync/lane-gate.d.ts +75 -0
  359. package/dist/core/worktree-sync/lane-gate.d.ts.map +1 -0
  360. package/dist/core/worktree-sync/lane-gate.js +360 -0
  361. package/dist/core/worktree-sync/lane-gate.js.map +1 -0
  362. package/dist/core/worktree-sync/runtime.d.ts +47 -0
  363. package/dist/core/worktree-sync/runtime.d.ts.map +1 -0
  364. package/dist/core/worktree-sync/runtime.js +96 -0
  365. package/dist/core/worktree-sync/runtime.js.map +1 -0
  366. package/dist/core/worktree-sync/store.d.ts +69 -0
  367. package/dist/core/worktree-sync/store.d.ts.map +1 -0
  368. package/dist/core/worktree-sync/store.js +247 -0
  369. package/dist/core/worktree-sync/store.js.map +1 -0
  370. package/dist/core/worktree-sync/watcher.d.ts +29 -0
  371. package/dist/core/worktree-sync/watcher.d.ts.map +1 -0
  372. package/dist/core/worktree-sync/watcher.js +93 -0
  373. package/dist/core/worktree-sync/watcher.js.map +1 -0
  374. package/dist/main.d.ts.map +1 -1
  375. package/dist/main.js +94 -0
  376. package/dist/main.js.map +1 -1
  377. package/dist/migrations.d.ts +9 -0
  378. package/dist/migrations.d.ts.map +1 -1
  379. package/dist/migrations.js +38 -0
  380. package/dist/migrations.js.map +1 -1
  381. package/dist/modes/interactive/auto-learn-controller.d.ts +16 -1
  382. package/dist/modes/interactive/auto-learn-controller.d.ts.map +1 -1
  383. package/dist/modes/interactive/auto-learn-controller.js +50 -8
  384. package/dist/modes/interactive/auto-learn-controller.js.map +1 -1
  385. package/dist/modes/interactive/components/profile-resource-editor.d.ts.map +1 -1
  386. package/dist/modes/interactive/components/profile-resource-editor.js +23 -1
  387. package/dist/modes/interactive/components/profile-resource-editor.js.map +1 -1
  388. package/dist/modes/interactive/interactive-mode.d.ts +1 -0
  389. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  390. package/dist/modes/interactive/interactive-mode.js +4 -0
  391. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  392. package/dist/modes/interactive/local-model-commands.d.ts +43 -0
  393. package/dist/modes/interactive/local-model-commands.d.ts.map +1 -1
  394. package/dist/modes/interactive/local-model-commands.js +290 -3
  395. package/dist/modes/interactive/local-model-commands.js.map +1 -1
  396. package/dist/modes/interactive/session-flow-commands.d.ts.map +1 -1
  397. package/dist/modes/interactive/session-flow-commands.js +24 -4
  398. package/dist/modes/interactive/session-flow-commands.js.map +1 -1
  399. package/dist/utils/fs-watch.d.ts +11 -0
  400. package/dist/utils/fs-watch.d.ts.map +1 -1
  401. package/dist/utils/fs-watch.js +20 -2
  402. package/dist/utils/fs-watch.js.map +1 -1
  403. package/dist/utils/highlight-js-languages.d.ts +4 -0
  404. package/dist/utils/highlight-js-languages.d.ts.map +1 -0
  405. package/dist/utils/highlight-js-languages.js +573 -0
  406. package/dist/utils/highlight-js-languages.js.map +1 -0
  407. package/dist/utils/shell.d.ts +7 -1
  408. package/dist/utils/shell.d.ts.map +1 -1
  409. package/dist/utils/shell.js +21 -6
  410. package/dist/utils/shell.js.map +1 -1
  411. package/dist/utils/syntax-highlight.d.ts.map +1 -1
  412. package/dist/utils/syntax-highlight.js +53 -5
  413. package/dist/utils/syntax-highlight.js.map +1 -1
  414. package/dist/utils/tools-manager.d.ts.map +1 -1
  415. package/dist/utils/tools-manager.js +112 -1
  416. package/dist/utils/tools-manager.js.map +1 -1
  417. package/docs/process-matrix.md +120 -0
  418. package/docs/settings.md +3 -0
  419. package/docs/tmux-agent-manager.md +85 -2
  420. package/docs/windows.md +52 -3
  421. package/docs/work-directory.md +29 -0
  422. package/docs/worktree-sync.md +250 -0
  423. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  424. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  425. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  426. package/examples/extensions/sandbox/package-lock.json +2 -2
  427. package/examples/extensions/sandbox/package.json +1 -1
  428. package/examples/extensions/with-deps/package-lock.json +2 -2
  429. package/examples/extensions/with-deps/package.json +1 -1
  430. package/npm-shrinkwrap.json +12 -12
  431. package/package.json +10 -4
  432. package/docs/integration-sweep-builder-blueprint-2026-07-09.md +0 -365
  433. package/docs/integration-sweep-resume-2026-07-09.md +0 -407
@@ -1,19 +1,118 @@
1
- import type { SessionEntry } from "@caupulican/pi-agent-core/node";
1
+ import type { SessionManager } from "@caupulican/pi-agent-core/node";
2
2
  import type { EvidenceBundle, LearningDecision, WorkerResult } from "../autonomy/contracts.ts";
3
+ import type { LaneRecord } from "../autonomy/lane-tracker.ts";
4
+ import type { TaskStepStatus } from "../tasks/task-state.ts";
3
5
  import { type GoalContinuationDecision } from "./goal-continuation-controller.ts";
4
6
  import type { GoalState } from "./goal-state.ts";
5
7
  export interface GoalRuntimeSnapshotSettings {
6
8
  maxStallTurns: number;
7
9
  }
10
+ /**
11
+ * A read-only projection of one OPEN (non-terminal) task_steps step, included in the goal
12
+ * runtime snapshot purely for cross-visibility. This is NOT a shared state machine: the goal
13
+ * loop never writes back to task state through this snapshot, and the task store stays the
14
+ * single source of truth for its own steps.
15
+ */
16
+ export interface GoalRuntimeOpenTaskStep {
17
+ id: string;
18
+ status: TaskStepStatus;
19
+ content: string;
20
+ }
21
+ /**
22
+ * Live, per-worktree-sync-lane status for one lane bound to a dispatched worker, as the caller
23
+ * (runtime-builder / whatever host process has live git-engine access) derives it. `boundLaneId` is
24
+ * the host `LaneRecord.laneId` the lane's registration was correlated to
25
+ * (`LaneRegistration.boundLaneId`, same id-space as `Requirement.boundLaneId`) -- `undefined` for a
26
+ * lane never bound to a dispatch. `fresh`/`stale` mirror `LaneFacts`; `syncRequired` is the
27
+ * staleness-propagation verdict (`WorktreeSyncPolicy`-derived); `rebaseInProgress` marks a sync that
28
+ * stopped on conflicts (a rebase left in progress) -- see `core/worktree-sync/git-engine.ts`.
29
+ */
30
+ export interface GoalRuntimeWorktreeLaneStatus {
31
+ laneKey: string;
32
+ boundLaneId?: string;
33
+ fresh: boolean;
34
+ stale: boolean;
35
+ syncRequired: boolean;
36
+ rebaseInProgress: boolean;
37
+ }
38
+ /**
39
+ * Per-requirement projection of {@link GoalRuntimeWorktreeLaneStatus}, joined via
40
+ * `requirement.boundLaneId === status.boundLaneId` -- read-only cross-visibility for snapshot
41
+ * consumers (e.g. a future continuation-prompt render), mirroring `openTaskSteps`'s role. This is
42
+ * NOT what feeds `evaluateGoalContinuation` (that reads the raw `boundLaneId`-keyed sets directly);
43
+ * it exists purely so a requirement's worktree state is visible without re-deriving the join.
44
+ */
45
+ export interface GoalRuntimeRequirementWorktreeState {
46
+ requirementId: string;
47
+ laneKey: string;
48
+ fresh: boolean;
49
+ stale: boolean;
50
+ syncRequired: boolean;
51
+ rebaseInProgress: boolean;
52
+ }
8
53
  export interface GoalRuntimeSnapshot {
9
54
  goalState?: GoalState;
10
55
  latestEvidenceBundle?: EvidenceBundle;
11
56
  workerResults: readonly WorkerResult[];
12
57
  learningDecisions: readonly LearningDecision[];
13
58
  continuation: GoalContinuationDecision;
59
+ /**
60
+ * Open (non-terminal) task_steps steps on the active branch, latest-wins. Read-only.
61
+ * Optional (like `goalState`/`latestEvidenceBundle`) so hand-built snapshots in existing
62
+ * tests/call sites that predate this field keep compiling unchanged; `buildGoalRuntimeSnapshot`
63
+ * itself always populates a concrete array (possibly empty).
64
+ */
65
+ openTaskSteps?: readonly GoalRuntimeOpenTaskStep[];
66
+ /**
67
+ * Per-requirement worktree-sync state, present only for requirements whose `boundLaneId` matches
68
+ * a `worktreeLaneStatus` entry supplied to the builder. Optional (like `openTaskSteps`) so every
69
+ * pre-existing caller/test keeps compiling unchanged; omitted entirely (not an empty array) when
70
+ * the builder was never given `worktreeLaneStatus`, since "no data supplied" and "data supplied,
71
+ * nothing bound" are genuinely different states worth distinguishing.
72
+ */
73
+ requirementWorktreeStates?: readonly GoalRuntimeRequirementWorktreeState[];
14
74
  }
75
+ /**
76
+ * Branch-scoped: every resolver here reads from ONE source (the active branch), so the goal
77
+ * state, evidence bundle, worker results, learning decisions, and open task steps in the
78
+ * returned snapshot are never a mix of the current branch and a sibling branch's history.
79
+ */
15
80
  export declare function buildGoalRuntimeSnapshot(args: {
16
- entries: readonly SessionEntry[];
81
+ sessionManager: Pick<SessionManager, "getLatestCustomEntryOnBranch" | "getBranch">;
17
82
  settings: GoalRuntimeSnapshotSettings;
83
+ /**
84
+ * Live lane records (queued/running/terminal), independent of branch scoping. Used ONLY to (a)
85
+ * detect a worker in flight against the active goal's open requirement ("waiting" — see
86
+ * `evaluateGoalContinuation`'s `inFlightGoalLaneIds`), and (b) surface this goal's cumulative
87
+ * worker/subagent spend (advisory — see `GoalState.continuationWorkerSpendUsd`). Optional so
88
+ * every pre-existing caller (hand-built snapshots, tests) that predates lane-awareness keeps
89
+ * compiling and behaving byte-identically: omitting it disables both the "waiting" branch and the
90
+ * worker-spend overlay, and never changes any OTHER continuation outcome.
91
+ */
92
+ laneRecords?: readonly LaneRecord[];
93
+ /**
94
+ * Current time as an ISO-string factory, threaded into `evaluateGoalContinuation`'s never-hang
95
+ * wait-timeout check (`now`/`maxWorkerWaitMs` — see there) alongside `maxWorkerWaitMs` below.
96
+ * Defaults to the real wall clock. A factory (not a plain string) so a caller/test can inject a
97
+ * fixed clock without freezing global `Date`.
98
+ */
99
+ now?: () => string;
100
+ /**
101
+ * Maximum milliseconds a bound in-flight requirement may wait before the continuation escalates
102
+ * to `worker_wait_timeout` instead of `"waiting"` forever (see `evaluateGoalContinuation`).
103
+ * Defaults to `DEFAULT_GOAL_WORKER_WAIT_MS`.
104
+ */
105
+ maxWorkerWaitMs?: number;
106
+ /**
107
+ * Live per-lane worktree-sync status, independent of branch scoping -- exactly like `laneRecords`,
108
+ * this builder performs NO I/O of its own; the caller derives this array (e.g. from
109
+ * `core/worktree-sync/git-engine.ts`'s live status) and supplies it ready-made. Used to (a) build
110
+ * `requirementWorktreeStates` (per-requirement projection, matched via `boundLaneId`) and (b)
111
+ * derive the `laneSyncConflictLaneKeys`/`syncRequiredLaneKeys` sets threaded into
112
+ * `evaluateGoalContinuation`. Optional so every pre-existing caller (predating worktree-sync
113
+ * awareness) keeps compiling and behaving byte-identically: omitting it disables both, and never
114
+ * changes any OTHER continuation outcome.
115
+ */
116
+ worktreeLaneStatus?: readonly GoalRuntimeWorktreeLaneStatus[];
18
117
  }): GoalRuntimeSnapshot;
19
118
  //# sourceMappingURL=goal-runtime-snapshot.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"goal-runtime-snapshot.d.ts","sourceRoot":"","sources":["../../../src/core/goals/goal-runtime-snapshot.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAI/F,OAAO,EAA4B,KAAK,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AAC5G,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAGjD,MAAM,WAAW,2BAA2B;IAC3C,aAAa,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IACnC,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,oBAAoB,CAAC,EAAE,cAAc,CAAC;IACtC,aAAa,EAAE,SAAS,YAAY,EAAE,CAAC;IACvC,iBAAiB,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAC/C,YAAY,EAAE,wBAAwB,CAAC;CACvC;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE;IAC9C,OAAO,EAAE,SAAS,YAAY,EAAE,CAAC;IACjC,QAAQ,EAAE,2BAA2B,CAAC;CACtC,GAAG,mBAAmB,CAkBtB","sourcesContent":["import type { SessionEntry } from \"@caupulican/pi-agent-core/node\";\nimport type { EvidenceBundle, LearningDecision, WorkerResult } from \"../autonomy/contracts.ts\";\nimport { getWorkerResultSnapshots } from \"../delegation/session-worker-result.ts\";\nimport { getLearningDecisionSnapshots } from \"../learning/session-learning-decision.ts\";\nimport { getLatestEvidenceBundleSnapshot } from \"../research/session-evidence-bundle.ts\";\nimport { evaluateGoalContinuation, type GoalContinuationDecision } from \"./goal-continuation-controller.ts\";\nimport type { GoalState } from \"./goal-state.ts\";\nimport { getLatestGoalStateSnapshot } from \"./session-goal-state.ts\";\n\nexport interface GoalRuntimeSnapshotSettings {\n\tmaxStallTurns: number;\n}\n\nexport interface GoalRuntimeSnapshot {\n\tgoalState?: GoalState;\n\tlatestEvidenceBundle?: EvidenceBundle;\n\tworkerResults: readonly WorkerResult[];\n\tlearningDecisions: readonly LearningDecision[];\n\tcontinuation: GoalContinuationDecision;\n}\n\nexport function buildGoalRuntimeSnapshot(args: {\n\tentries: readonly SessionEntry[];\n\tsettings: GoalRuntimeSnapshotSettings;\n}): GoalRuntimeSnapshot {\n\tconst goalState = getLatestGoalStateSnapshot(args.entries);\n\tconst latestEvidenceBundle = getLatestEvidenceBundleSnapshot(args.entries);\n\tconst workerResults = getWorkerResultSnapshots(args.entries);\n\tconst learningDecisions = getLearningDecisionSnapshots(args.entries);\n\n\tconst continuation = evaluateGoalContinuation({\n\t\tstate: goalState,\n\t\tsettings: { maxStallTurns: args.settings.maxStallTurns },\n\t});\n\n\treturn {\n\t\tgoalState,\n\t\tlatestEvidenceBundle,\n\t\tworkerResults,\n\t\tlearningDecisions,\n\t\tcontinuation,\n\t};\n}\n"]}
1
+ {"version":3,"file":"goal-runtime-snapshot.d.ts","sourceRoot":"","sources":["../../../src/core/goals/goal-runtime-snapshot.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC/F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAK9D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,EAA4B,KAAK,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AAE5G,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAGjD,MAAM,WAAW,2BAA2B;IAC3C,aAAa,EAAE,MAAM,CAAC;CACtB;AAED;;;;;GAKG;AACH,MAAM,WAAW,uBAAuB;IACvC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,cAAc,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,6BAA6B;IAC7C,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,YAAY,EAAE,OAAO,CAAC;IACtB,gBAAgB,EAAE,OAAO,CAAC;CAC1B;AAED;;;;;;GAMG;AACH,MAAM,WAAW,mCAAmC;IACnD,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,YAAY,EAAE,OAAO,CAAC;IACtB,gBAAgB,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,mBAAmB;IACnC,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,oBAAoB,CAAC,EAAE,cAAc,CAAC;IACtC,aAAa,EAAE,SAAS,YAAY,EAAE,CAAC;IACvC,iBAAiB,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAC/C,YAAY,EAAE,wBAAwB,CAAC;IACvC;;;;;OAKG;IACH,aAAa,CAAC,EAAE,SAAS,uBAAuB,EAAE,CAAC;IACnD;;;;;;OAMG;IACH,yBAAyB,CAAC,EAAE,SAAS,mCAAmC,EAAE,CAAC;CAC3E;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE;IAC9C,cAAc,EAAE,IAAI,CAAC,cAAc,EAAE,8BAA8B,GAAG,WAAW,CAAC,CAAC;IACnF,QAAQ,EAAE,2BAA2B,CAAC;IACtC;;;;;;;;OAQG;IACH,WAAW,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IACpC;;;;;OAKG;IACH,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;;;;;OASG;IACH,kBAAkB,CAAC,EAAE,SAAS,6BAA6B,EAAE,CAAC;CAC9D,GAAG,mBAAmB,CA4FtB","sourcesContent":["import type { SessionManager } from \"@caupulican/pi-agent-core/node\";\nimport type { EvidenceBundle, LearningDecision, WorkerResult } from \"../autonomy/contracts.ts\";\nimport type { LaneRecord } from \"../autonomy/lane-tracker.ts\";\nimport { getWorkerResultSnapshots } from \"../delegation/session-worker-result.ts\";\nimport { getLearningDecisionSnapshots } from \"../learning/session-learning-decision.ts\";\nimport { getLatestEvidenceBundleSnapshot } from \"../research/session-evidence-bundle.ts\";\nimport { getLatestTaskStepsStateSnapshot } from \"../tasks/session-task-state.ts\";\nimport type { TaskStepStatus } from \"../tasks/task-state.ts\";\nimport { evaluateGoalContinuation, type GoalContinuationDecision } from \"./goal-continuation-controller.ts\";\nimport { DEFAULT_GOAL_WORKER_WAIT_MS } from \"./goal-continuation-defaults.ts\";\nimport type { GoalState } from \"./goal-state.ts\";\nimport { getLatestGoalStateSnapshot } from \"./session-goal-state.ts\";\n\nexport interface GoalRuntimeSnapshotSettings {\n\tmaxStallTurns: number;\n}\n\n/**\n * A read-only projection of one OPEN (non-terminal) task_steps step, included in the goal\n * runtime snapshot purely for cross-visibility. This is NOT a shared state machine: the goal\n * loop never writes back to task state through this snapshot, and the task store stays the\n * single source of truth for its own steps.\n */\nexport interface GoalRuntimeOpenTaskStep {\n\tid: string;\n\tstatus: TaskStepStatus;\n\tcontent: string;\n}\n\n/**\n * Live, per-worktree-sync-lane status for one lane bound to a dispatched worker, as the caller\n * (runtime-builder / whatever host process has live git-engine access) derives it. `boundLaneId` is\n * the host `LaneRecord.laneId` the lane's registration was correlated to\n * (`LaneRegistration.boundLaneId`, same id-space as `Requirement.boundLaneId`) -- `undefined` for a\n * lane never bound to a dispatch. `fresh`/`stale` mirror `LaneFacts`; `syncRequired` is the\n * staleness-propagation verdict (`WorktreeSyncPolicy`-derived); `rebaseInProgress` marks a sync that\n * stopped on conflicts (a rebase left in progress) -- see `core/worktree-sync/git-engine.ts`.\n */\nexport interface GoalRuntimeWorktreeLaneStatus {\n\tlaneKey: string;\n\tboundLaneId?: string;\n\tfresh: boolean;\n\tstale: boolean;\n\tsyncRequired: boolean;\n\trebaseInProgress: boolean;\n}\n\n/**\n * Per-requirement projection of {@link GoalRuntimeWorktreeLaneStatus}, joined via\n * `requirement.boundLaneId === status.boundLaneId` -- read-only cross-visibility for snapshot\n * consumers (e.g. a future continuation-prompt render), mirroring `openTaskSteps`'s role. This is\n * NOT what feeds `evaluateGoalContinuation` (that reads the raw `boundLaneId`-keyed sets directly);\n * it exists purely so a requirement's worktree state is visible without re-deriving the join.\n */\nexport interface GoalRuntimeRequirementWorktreeState {\n\trequirementId: string;\n\tlaneKey: string;\n\tfresh: boolean;\n\tstale: boolean;\n\tsyncRequired: boolean;\n\trebaseInProgress: boolean;\n}\n\nexport interface GoalRuntimeSnapshot {\n\tgoalState?: GoalState;\n\tlatestEvidenceBundle?: EvidenceBundle;\n\tworkerResults: readonly WorkerResult[];\n\tlearningDecisions: readonly LearningDecision[];\n\tcontinuation: GoalContinuationDecision;\n\t/**\n\t * Open (non-terminal) task_steps steps on the active branch, latest-wins. Read-only.\n\t * Optional (like `goalState`/`latestEvidenceBundle`) so hand-built snapshots in existing\n\t * tests/call sites that predate this field keep compiling unchanged; `buildGoalRuntimeSnapshot`\n\t * itself always populates a concrete array (possibly empty).\n\t */\n\topenTaskSteps?: readonly GoalRuntimeOpenTaskStep[];\n\t/**\n\t * Per-requirement worktree-sync state, present only for requirements whose `boundLaneId` matches\n\t * a `worktreeLaneStatus` entry supplied to the builder. Optional (like `openTaskSteps`) so every\n\t * pre-existing caller/test keeps compiling unchanged; omitted entirely (not an empty array) when\n\t * the builder was never given `worktreeLaneStatus`, since \"no data supplied\" and \"data supplied,\n\t * nothing bound\" are genuinely different states worth distinguishing.\n\t */\n\trequirementWorktreeStates?: readonly GoalRuntimeRequirementWorktreeState[];\n}\n\n/**\n * Branch-scoped: every resolver here reads from ONE source (the active branch), so the goal\n * state, evidence bundle, worker results, learning decisions, and open task steps in the\n * returned snapshot are never a mix of the current branch and a sibling branch's history.\n */\nexport function buildGoalRuntimeSnapshot(args: {\n\tsessionManager: Pick<SessionManager, \"getLatestCustomEntryOnBranch\" | \"getBranch\">;\n\tsettings: GoalRuntimeSnapshotSettings;\n\t/**\n\t * Live lane records (queued/running/terminal), independent of branch scoping. Used ONLY to (a)\n\t * detect a worker in flight against the active goal's open requirement (\"waiting\" — see\n\t * `evaluateGoalContinuation`'s `inFlightGoalLaneIds`), and (b) surface this goal's cumulative\n\t * worker/subagent spend (advisory — see `GoalState.continuationWorkerSpendUsd`). Optional so\n\t * every pre-existing caller (hand-built snapshots, tests) that predates lane-awareness keeps\n\t * compiling and behaving byte-identically: omitting it disables both the \"waiting\" branch and the\n\t * worker-spend overlay, and never changes any OTHER continuation outcome.\n\t */\n\tlaneRecords?: readonly LaneRecord[];\n\t/**\n\t * Current time as an ISO-string factory, threaded into `evaluateGoalContinuation`'s never-hang\n\t * wait-timeout check (`now`/`maxWorkerWaitMs` — see there) alongside `maxWorkerWaitMs` below.\n\t * Defaults to the real wall clock. A factory (not a plain string) so a caller/test can inject a\n\t * fixed clock without freezing global `Date`.\n\t */\n\tnow?: () => string;\n\t/**\n\t * Maximum milliseconds a bound in-flight requirement may wait before the continuation escalates\n\t * to `worker_wait_timeout` instead of `\"waiting\"` forever (see `evaluateGoalContinuation`).\n\t * Defaults to `DEFAULT_GOAL_WORKER_WAIT_MS`.\n\t */\n\tmaxWorkerWaitMs?: number;\n\t/**\n\t * Live per-lane worktree-sync status, independent of branch scoping -- exactly like `laneRecords`,\n\t * this builder performs NO I/O of its own; the caller derives this array (e.g. from\n\t * `core/worktree-sync/git-engine.ts`'s live status) and supplies it ready-made. Used to (a) build\n\t * `requirementWorktreeStates` (per-requirement projection, matched via `boundLaneId`) and (b)\n\t * derive the `laneSyncConflictLaneKeys`/`syncRequiredLaneKeys` sets threaded into\n\t * `evaluateGoalContinuation`. Optional so every pre-existing caller (predating worktree-sync\n\t * awareness) keeps compiling and behaving byte-identically: omitting it disables both, and never\n\t * changes any OTHER continuation outcome.\n\t */\n\tworktreeLaneStatus?: readonly GoalRuntimeWorktreeLaneStatus[];\n}): GoalRuntimeSnapshot {\n\tconst branchEntries = args.sessionManager.getBranch();\n\tlet goalState = getLatestGoalStateSnapshot(args.sessionManager);\n\tconst latestEvidenceBundle = getLatestEvidenceBundleSnapshot(branchEntries);\n\tconst workerResults = getWorkerResultSnapshots(branchEntries);\n\tconst learningDecisions = getLearningDecisionSnapshots(branchEntries);\n\n\t// Reuses the SAME branch-scoped primitive as goal-state resolution (getLatestCustomEntryOnBranch),\n\t// so the task-steps summary below can never leak a sibling branch's checklist either.\n\tconst taskStepsState = getLatestTaskStepsStateSnapshot(args.sessionManager);\n\tconst openTaskSteps: GoalRuntimeOpenTaskStep[] = (taskStepsState?.steps ?? [])\n\t\t.filter((step) => step.status !== \"completed\" && step.status !== \"cancelled\")\n\t\t.map((step) => ({ id: step.id, status: step.status, content: step.activeForm || step.content }));\n\n\tlet inFlightGoalLaneIds: ReadonlySet<string> | undefined;\n\tif (goalState && args.laneRecords) {\n\t\tconst goalId = goalState.goalId;\n\t\tconst inFlight = new Set<string>();\n\t\t// Live-derived, not durably persisted: the goal-state event log has no reducer branch that\n\t\t// writes `continuationWorkerSpendUsd` (see its doc comment on `GoalState`), so every read\n\t\t// re-sums THIS goal's own lane records instead of trusting a stale/zero persisted value.\n\t\t// `costUsd` is set today for in-process worker/research lane completions (LaneTracker.complete);\n\t\t// it is NOT yet set for tmux-worker completions (`ManagedLaneEvent` carries no cost claim), so\n\t\t// this sum is accurate for in-process lanes and a documented undercount for tmux workers until\n\t\t// `reportSpawnedUsage` threads a goalId/lane correlation through. Forward-compatible: the moment\n\t\t// tmux-worker costUsd is populated, this same sum picks it up with no further change here.\n\t\tlet workerSpendUsd = 0;\n\t\tfor (const record of args.laneRecords) {\n\t\t\tif (record.goalId !== goalId) continue;\n\t\t\tif (record.status === \"queued\" || record.status === \"running\") inFlight.add(record.laneId);\n\t\t\tworkerSpendUsd += record.costUsd ?? 0;\n\t\t}\n\t\tinFlightGoalLaneIds = inFlight;\n\t\tgoalState = { ...goalState, continuationWorkerSpendUsd: workerSpendUsd };\n\t}\n\n\t// Worktree-sync surfacing: (a) a per-requirement projection (matched via `boundLaneId`, purely for\n\t// snapshot consumers -- never read by `evaluateGoalContinuation` itself), and (b) the\n\t// `boundLaneId`-keyed sets `evaluateGoalContinuation` actually matches against\n\t// `Requirement.boundLaneId`, same id-space and matching pattern as `inFlightGoalLaneIds` above.\n\t// Disjoint by construction: a lane with `rebaseInProgress` feeds the conflict set only, never both.\n\tlet requirementWorktreeStates: GoalRuntimeRequirementWorktreeState[] | undefined;\n\tconst laneSyncConflictLaneKeys = new Set<string>();\n\tconst syncRequiredLaneKeys = new Set<string>();\n\tif (args.worktreeLaneStatus) {\n\t\tfor (const status of args.worktreeLaneStatus) {\n\t\t\tif (status.boundLaneId === undefined) continue;\n\t\t\tif (status.rebaseInProgress) laneSyncConflictLaneKeys.add(status.boundLaneId);\n\t\t\telse if (status.syncRequired) syncRequiredLaneKeys.add(status.boundLaneId);\n\t\t}\n\t\tif (goalState) {\n\t\t\tconst states: GoalRuntimeRequirementWorktreeState[] = [];\n\t\t\tfor (const requirement of goalState.requirements) {\n\t\t\t\tif (requirement.boundLaneId === undefined) continue;\n\t\t\t\tconst status = args.worktreeLaneStatus.find(\n\t\t\t\t\t(candidate) => candidate.boundLaneId === requirement.boundLaneId,\n\t\t\t\t);\n\t\t\t\tif (!status) continue;\n\t\t\t\tstates.push({\n\t\t\t\t\trequirementId: requirement.id,\n\t\t\t\t\tlaneKey: status.laneKey,\n\t\t\t\t\tfresh: status.fresh,\n\t\t\t\t\tstale: status.stale,\n\t\t\t\t\tsyncRequired: status.syncRequired,\n\t\t\t\t\trebaseInProgress: status.rebaseInProgress,\n\t\t\t\t});\n\t\t\t}\n\t\t\trequirementWorktreeStates = states;\n\t\t}\n\t}\n\n\tconst now = (args.now ?? (() => new Date().toISOString()))();\n\tconst maxWorkerWaitMs = args.maxWorkerWaitMs ?? DEFAULT_GOAL_WORKER_WAIT_MS;\n\tconst continuation = evaluateGoalContinuation({\n\t\tstate: goalState,\n\t\tsettings: { maxStallTurns: args.settings.maxStallTurns },\n\t\tinFlightGoalLaneIds,\n\t\tnow,\n\t\tmaxWorkerWaitMs,\n\t\tlaneSyncConflictLaneKeys: laneSyncConflictLaneKeys.size > 0 ? laneSyncConflictLaneKeys : undefined,\n\t\tsyncRequiredLaneKeys: syncRequiredLaneKeys.size > 0 ? syncRequiredLaneKeys : undefined,\n\t});\n\n\treturn {\n\t\tgoalState,\n\t\tlatestEvidenceBundle,\n\t\tworkerResults,\n\t\tlearningDecisions,\n\t\tcontinuation,\n\t\topenTaskSteps,\n\t\t...(requirementWorktreeStates !== undefined ? { requirementWorktreeStates } : {}),\n\t};\n}\n"]}
@@ -1,16 +1,97 @@
1
1
  import { getWorkerResultSnapshots } from "../delegation/session-worker-result.js";
2
2
  import { getLearningDecisionSnapshots } from "../learning/session-learning-decision.js";
3
3
  import { getLatestEvidenceBundleSnapshot } from "../research/session-evidence-bundle.js";
4
+ import { getLatestTaskStepsStateSnapshot } from "../tasks/session-task-state.js";
4
5
  import { evaluateGoalContinuation } from "./goal-continuation-controller.js";
6
+ import { DEFAULT_GOAL_WORKER_WAIT_MS } from "./goal-continuation-defaults.js";
5
7
  import { getLatestGoalStateSnapshot } from "./session-goal-state.js";
8
+ /**
9
+ * Branch-scoped: every resolver here reads from ONE source (the active branch), so the goal
10
+ * state, evidence bundle, worker results, learning decisions, and open task steps in the
11
+ * returned snapshot are never a mix of the current branch and a sibling branch's history.
12
+ */
6
13
  export function buildGoalRuntimeSnapshot(args) {
7
- const goalState = getLatestGoalStateSnapshot(args.entries);
8
- const latestEvidenceBundle = getLatestEvidenceBundleSnapshot(args.entries);
9
- const workerResults = getWorkerResultSnapshots(args.entries);
10
- const learningDecisions = getLearningDecisionSnapshots(args.entries);
14
+ const branchEntries = args.sessionManager.getBranch();
15
+ let goalState = getLatestGoalStateSnapshot(args.sessionManager);
16
+ const latestEvidenceBundle = getLatestEvidenceBundleSnapshot(branchEntries);
17
+ const workerResults = getWorkerResultSnapshots(branchEntries);
18
+ const learningDecisions = getLearningDecisionSnapshots(branchEntries);
19
+ // Reuses the SAME branch-scoped primitive as goal-state resolution (getLatestCustomEntryOnBranch),
20
+ // so the task-steps summary below can never leak a sibling branch's checklist either.
21
+ const taskStepsState = getLatestTaskStepsStateSnapshot(args.sessionManager);
22
+ const openTaskSteps = (taskStepsState?.steps ?? [])
23
+ .filter((step) => step.status !== "completed" && step.status !== "cancelled")
24
+ .map((step) => ({ id: step.id, status: step.status, content: step.activeForm || step.content }));
25
+ let inFlightGoalLaneIds;
26
+ if (goalState && args.laneRecords) {
27
+ const goalId = goalState.goalId;
28
+ const inFlight = new Set();
29
+ // Live-derived, not durably persisted: the goal-state event log has no reducer branch that
30
+ // writes `continuationWorkerSpendUsd` (see its doc comment on `GoalState`), so every read
31
+ // re-sums THIS goal's own lane records instead of trusting a stale/zero persisted value.
32
+ // `costUsd` is set today for in-process worker/research lane completions (LaneTracker.complete);
33
+ // it is NOT yet set for tmux-worker completions (`ManagedLaneEvent` carries no cost claim), so
34
+ // this sum is accurate for in-process lanes and a documented undercount for tmux workers until
35
+ // `reportSpawnedUsage` threads a goalId/lane correlation through. Forward-compatible: the moment
36
+ // tmux-worker costUsd is populated, this same sum picks it up with no further change here.
37
+ let workerSpendUsd = 0;
38
+ for (const record of args.laneRecords) {
39
+ if (record.goalId !== goalId)
40
+ continue;
41
+ if (record.status === "queued" || record.status === "running")
42
+ inFlight.add(record.laneId);
43
+ workerSpendUsd += record.costUsd ?? 0;
44
+ }
45
+ inFlightGoalLaneIds = inFlight;
46
+ goalState = { ...goalState, continuationWorkerSpendUsd: workerSpendUsd };
47
+ }
48
+ // Worktree-sync surfacing: (a) a per-requirement projection (matched via `boundLaneId`, purely for
49
+ // snapshot consumers -- never read by `evaluateGoalContinuation` itself), and (b) the
50
+ // `boundLaneId`-keyed sets `evaluateGoalContinuation` actually matches against
51
+ // `Requirement.boundLaneId`, same id-space and matching pattern as `inFlightGoalLaneIds` above.
52
+ // Disjoint by construction: a lane with `rebaseInProgress` feeds the conflict set only, never both.
53
+ let requirementWorktreeStates;
54
+ const laneSyncConflictLaneKeys = new Set();
55
+ const syncRequiredLaneKeys = new Set();
56
+ if (args.worktreeLaneStatus) {
57
+ for (const status of args.worktreeLaneStatus) {
58
+ if (status.boundLaneId === undefined)
59
+ continue;
60
+ if (status.rebaseInProgress)
61
+ laneSyncConflictLaneKeys.add(status.boundLaneId);
62
+ else if (status.syncRequired)
63
+ syncRequiredLaneKeys.add(status.boundLaneId);
64
+ }
65
+ if (goalState) {
66
+ const states = [];
67
+ for (const requirement of goalState.requirements) {
68
+ if (requirement.boundLaneId === undefined)
69
+ continue;
70
+ const status = args.worktreeLaneStatus.find((candidate) => candidate.boundLaneId === requirement.boundLaneId);
71
+ if (!status)
72
+ continue;
73
+ states.push({
74
+ requirementId: requirement.id,
75
+ laneKey: status.laneKey,
76
+ fresh: status.fresh,
77
+ stale: status.stale,
78
+ syncRequired: status.syncRequired,
79
+ rebaseInProgress: status.rebaseInProgress,
80
+ });
81
+ }
82
+ requirementWorktreeStates = states;
83
+ }
84
+ }
85
+ const now = (args.now ?? (() => new Date().toISOString()))();
86
+ const maxWorkerWaitMs = args.maxWorkerWaitMs ?? DEFAULT_GOAL_WORKER_WAIT_MS;
11
87
  const continuation = evaluateGoalContinuation({
12
88
  state: goalState,
13
89
  settings: { maxStallTurns: args.settings.maxStallTurns },
90
+ inFlightGoalLaneIds,
91
+ now,
92
+ maxWorkerWaitMs,
93
+ laneSyncConflictLaneKeys: laneSyncConflictLaneKeys.size > 0 ? laneSyncConflictLaneKeys : undefined,
94
+ syncRequiredLaneKeys: syncRequiredLaneKeys.size > 0 ? syncRequiredLaneKeys : undefined,
14
95
  });
15
96
  return {
16
97
  goalState,
@@ -18,6 +99,8 @@ export function buildGoalRuntimeSnapshot(args) {
18
99
  workerResults,
19
100
  learningDecisions,
20
101
  continuation,
102
+ openTaskSteps,
103
+ ...(requirementWorktreeStates !== undefined ? { requirementWorktreeStates } : {}),
21
104
  };
22
105
  }
23
106
  //# sourceMappingURL=goal-runtime-snapshot.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"goal-runtime-snapshot.js","sourceRoot":"","sources":["../../../src/core/goals/goal-runtime-snapshot.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAC;AAClF,OAAO,EAAE,4BAA4B,EAAE,MAAM,0CAA0C,CAAC;AACxF,OAAO,EAAE,+BAA+B,EAAE,MAAM,wCAAwC,CAAC;AACzF,OAAO,EAAE,wBAAwB,EAAiC,MAAM,mCAAmC,CAAC;AAE5G,OAAO,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAC;AAcrE,MAAM,UAAU,wBAAwB,CAAC,IAGxC,EAAuB;IACvB,MAAM,SAAS,GAAG,0BAA0B,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC3D,MAAM,oBAAoB,GAAG,+BAA+B,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC3E,MAAM,aAAa,GAAG,wBAAwB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC7D,MAAM,iBAAiB,GAAG,4BAA4B,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAErE,MAAM,YAAY,GAAG,wBAAwB,CAAC;QAC7C,KAAK,EAAE,SAAS;QAChB,QAAQ,EAAE,EAAE,aAAa,EAAE,IAAI,CAAC,QAAQ,CAAC,aAAa,EAAE;KACxD,CAAC,CAAC;IAEH,OAAO;QACN,SAAS;QACT,oBAAoB;QACpB,aAAa;QACb,iBAAiB;QACjB,YAAY;KACZ,CAAC;AAAA,CACF","sourcesContent":["import type { SessionEntry } from \"@caupulican/pi-agent-core/node\";\nimport type { EvidenceBundle, LearningDecision, WorkerResult } from \"../autonomy/contracts.ts\";\nimport { getWorkerResultSnapshots } from \"../delegation/session-worker-result.ts\";\nimport { getLearningDecisionSnapshots } from \"../learning/session-learning-decision.ts\";\nimport { getLatestEvidenceBundleSnapshot } from \"../research/session-evidence-bundle.ts\";\nimport { evaluateGoalContinuation, type GoalContinuationDecision } from \"./goal-continuation-controller.ts\";\nimport type { GoalState } from \"./goal-state.ts\";\nimport { getLatestGoalStateSnapshot } from \"./session-goal-state.ts\";\n\nexport interface GoalRuntimeSnapshotSettings {\n\tmaxStallTurns: number;\n}\n\nexport interface GoalRuntimeSnapshot {\n\tgoalState?: GoalState;\n\tlatestEvidenceBundle?: EvidenceBundle;\n\tworkerResults: readonly WorkerResult[];\n\tlearningDecisions: readonly LearningDecision[];\n\tcontinuation: GoalContinuationDecision;\n}\n\nexport function buildGoalRuntimeSnapshot(args: {\n\tentries: readonly SessionEntry[];\n\tsettings: GoalRuntimeSnapshotSettings;\n}): GoalRuntimeSnapshot {\n\tconst goalState = getLatestGoalStateSnapshot(args.entries);\n\tconst latestEvidenceBundle = getLatestEvidenceBundleSnapshot(args.entries);\n\tconst workerResults = getWorkerResultSnapshots(args.entries);\n\tconst learningDecisions = getLearningDecisionSnapshots(args.entries);\n\n\tconst continuation = evaluateGoalContinuation({\n\t\tstate: goalState,\n\t\tsettings: { maxStallTurns: args.settings.maxStallTurns },\n\t});\n\n\treturn {\n\t\tgoalState,\n\t\tlatestEvidenceBundle,\n\t\tworkerResults,\n\t\tlearningDecisions,\n\t\tcontinuation,\n\t};\n}\n"]}
1
+ {"version":3,"file":"goal-runtime-snapshot.js","sourceRoot":"","sources":["../../../src/core/goals/goal-runtime-snapshot.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SessionManager } from \"@caupulican/pi-agent-core/node\";\nimport type { EvidenceBundle, LearningDecision, WorkerResult } from \"../autonomy/contracts.ts\";\nimport type { LaneRecord } from \"../autonomy/lane-tracker.ts\";\nimport { getWorkerResultSnapshots } from \"../delegation/session-worker-result.ts\";\nimport { getLearningDecisionSnapshots } from \"../learning/session-learning-decision.ts\";\nimport { getLatestEvidenceBundleSnapshot } from \"../research/session-evidence-bundle.ts\";\nimport { getLatestTaskStepsStateSnapshot } from \"../tasks/session-task-state.ts\";\nimport type { TaskStepStatus } from \"../tasks/task-state.ts\";\nimport { evaluateGoalContinuation, type GoalContinuationDecision } from \"./goal-continuation-controller.ts\";\nimport { DEFAULT_GOAL_WORKER_WAIT_MS } from \"./goal-continuation-defaults.ts\";\nimport type { GoalState } from \"./goal-state.ts\";\nimport { getLatestGoalStateSnapshot } from \"./session-goal-state.ts\";\n\nexport interface GoalRuntimeSnapshotSettings {\n\tmaxStallTurns: number;\n}\n\n/**\n * A read-only projection of one OPEN (non-terminal) task_steps step, included in the goal\n * runtime snapshot purely for cross-visibility. This is NOT a shared state machine: the goal\n * loop never writes back to task state through this snapshot, and the task store stays the\n * single source of truth for its own steps.\n */\nexport interface GoalRuntimeOpenTaskStep {\n\tid: string;\n\tstatus: TaskStepStatus;\n\tcontent: string;\n}\n\n/**\n * Live, per-worktree-sync-lane status for one lane bound to a dispatched worker, as the caller\n * (runtime-builder / whatever host process has live git-engine access) derives it. `boundLaneId` is\n * the host `LaneRecord.laneId` the lane's registration was correlated to\n * (`LaneRegistration.boundLaneId`, same id-space as `Requirement.boundLaneId`) -- `undefined` for a\n * lane never bound to a dispatch. `fresh`/`stale` mirror `LaneFacts`; `syncRequired` is the\n * staleness-propagation verdict (`WorktreeSyncPolicy`-derived); `rebaseInProgress` marks a sync that\n * stopped on conflicts (a rebase left in progress) -- see `core/worktree-sync/git-engine.ts`.\n */\nexport interface GoalRuntimeWorktreeLaneStatus {\n\tlaneKey: string;\n\tboundLaneId?: string;\n\tfresh: boolean;\n\tstale: boolean;\n\tsyncRequired: boolean;\n\trebaseInProgress: boolean;\n}\n\n/**\n * Per-requirement projection of {@link GoalRuntimeWorktreeLaneStatus}, joined via\n * `requirement.boundLaneId === status.boundLaneId` -- read-only cross-visibility for snapshot\n * consumers (e.g. a future continuation-prompt render), mirroring `openTaskSteps`'s role. This is\n * NOT what feeds `evaluateGoalContinuation` (that reads the raw `boundLaneId`-keyed sets directly);\n * it exists purely so a requirement's worktree state is visible without re-deriving the join.\n */\nexport interface GoalRuntimeRequirementWorktreeState {\n\trequirementId: string;\n\tlaneKey: string;\n\tfresh: boolean;\n\tstale: boolean;\n\tsyncRequired: boolean;\n\trebaseInProgress: boolean;\n}\n\nexport interface GoalRuntimeSnapshot {\n\tgoalState?: GoalState;\n\tlatestEvidenceBundle?: EvidenceBundle;\n\tworkerResults: readonly WorkerResult[];\n\tlearningDecisions: readonly LearningDecision[];\n\tcontinuation: GoalContinuationDecision;\n\t/**\n\t * Open (non-terminal) task_steps steps on the active branch, latest-wins. Read-only.\n\t * Optional (like `goalState`/`latestEvidenceBundle`) so hand-built snapshots in existing\n\t * tests/call sites that predate this field keep compiling unchanged; `buildGoalRuntimeSnapshot`\n\t * itself always populates a concrete array (possibly empty).\n\t */\n\topenTaskSteps?: readonly GoalRuntimeOpenTaskStep[];\n\t/**\n\t * Per-requirement worktree-sync state, present only for requirements whose `boundLaneId` matches\n\t * a `worktreeLaneStatus` entry supplied to the builder. Optional (like `openTaskSteps`) so every\n\t * pre-existing caller/test keeps compiling unchanged; omitted entirely (not an empty array) when\n\t * the builder was never given `worktreeLaneStatus`, since \"no data supplied\" and \"data supplied,\n\t * nothing bound\" are genuinely different states worth distinguishing.\n\t */\n\trequirementWorktreeStates?: readonly GoalRuntimeRequirementWorktreeState[];\n}\n\n/**\n * Branch-scoped: every resolver here reads from ONE source (the active branch), so the goal\n * state, evidence bundle, worker results, learning decisions, and open task steps in the\n * returned snapshot are never a mix of the current branch and a sibling branch's history.\n */\nexport function buildGoalRuntimeSnapshot(args: {\n\tsessionManager: Pick<SessionManager, \"getLatestCustomEntryOnBranch\" | \"getBranch\">;\n\tsettings: GoalRuntimeSnapshotSettings;\n\t/**\n\t * Live lane records (queued/running/terminal), independent of branch scoping. Used ONLY to (a)\n\t * detect a worker in flight against the active goal's open requirement (\"waiting\" — see\n\t * `evaluateGoalContinuation`'s `inFlightGoalLaneIds`), and (b) surface this goal's cumulative\n\t * worker/subagent spend (advisory — see `GoalState.continuationWorkerSpendUsd`). Optional so\n\t * every pre-existing caller (hand-built snapshots, tests) that predates lane-awareness keeps\n\t * compiling and behaving byte-identically: omitting it disables both the \"waiting\" branch and the\n\t * worker-spend overlay, and never changes any OTHER continuation outcome.\n\t */\n\tlaneRecords?: readonly LaneRecord[];\n\t/**\n\t * Current time as an ISO-string factory, threaded into `evaluateGoalContinuation`'s never-hang\n\t * wait-timeout check (`now`/`maxWorkerWaitMs` — see there) alongside `maxWorkerWaitMs` below.\n\t * Defaults to the real wall clock. A factory (not a plain string) so a caller/test can inject a\n\t * fixed clock without freezing global `Date`.\n\t */\n\tnow?: () => string;\n\t/**\n\t * Maximum milliseconds a bound in-flight requirement may wait before the continuation escalates\n\t * to `worker_wait_timeout` instead of `\"waiting\"` forever (see `evaluateGoalContinuation`).\n\t * Defaults to `DEFAULT_GOAL_WORKER_WAIT_MS`.\n\t */\n\tmaxWorkerWaitMs?: number;\n\t/**\n\t * Live per-lane worktree-sync status, independent of branch scoping -- exactly like `laneRecords`,\n\t * this builder performs NO I/O of its own; the caller derives this array (e.g. from\n\t * `core/worktree-sync/git-engine.ts`'s live status) and supplies it ready-made. Used to (a) build\n\t * `requirementWorktreeStates` (per-requirement projection, matched via `boundLaneId`) and (b)\n\t * derive the `laneSyncConflictLaneKeys`/`syncRequiredLaneKeys` sets threaded into\n\t * `evaluateGoalContinuation`. Optional so every pre-existing caller (predating worktree-sync\n\t * awareness) keeps compiling and behaving byte-identically: omitting it disables both, and never\n\t * changes any OTHER continuation outcome.\n\t */\n\tworktreeLaneStatus?: readonly GoalRuntimeWorktreeLaneStatus[];\n}): GoalRuntimeSnapshot {\n\tconst branchEntries = args.sessionManager.getBranch();\n\tlet goalState = getLatestGoalStateSnapshot(args.sessionManager);\n\tconst latestEvidenceBundle = getLatestEvidenceBundleSnapshot(branchEntries);\n\tconst workerResults = getWorkerResultSnapshots(branchEntries);\n\tconst learningDecisions = getLearningDecisionSnapshots(branchEntries);\n\n\t// Reuses the SAME branch-scoped primitive as goal-state resolution (getLatestCustomEntryOnBranch),\n\t// so the task-steps summary below can never leak a sibling branch's checklist either.\n\tconst taskStepsState = getLatestTaskStepsStateSnapshot(args.sessionManager);\n\tconst openTaskSteps: GoalRuntimeOpenTaskStep[] = (taskStepsState?.steps ?? [])\n\t\t.filter((step) => step.status !== \"completed\" && step.status !== \"cancelled\")\n\t\t.map((step) => ({ id: step.id, status: step.status, content: step.activeForm || step.content }));\n\n\tlet inFlightGoalLaneIds: ReadonlySet<string> | undefined;\n\tif (goalState && args.laneRecords) {\n\t\tconst goalId = goalState.goalId;\n\t\tconst inFlight = new Set<string>();\n\t\t// Live-derived, not durably persisted: the goal-state event log has no reducer branch that\n\t\t// writes `continuationWorkerSpendUsd` (see its doc comment on `GoalState`), so every read\n\t\t// re-sums THIS goal's own lane records instead of trusting a stale/zero persisted value.\n\t\t// `costUsd` is set today for in-process worker/research lane completions (LaneTracker.complete);\n\t\t// it is NOT yet set for tmux-worker completions (`ManagedLaneEvent` carries no cost claim), so\n\t\t// this sum is accurate for in-process lanes and a documented undercount for tmux workers until\n\t\t// `reportSpawnedUsage` threads a goalId/lane correlation through. Forward-compatible: the moment\n\t\t// tmux-worker costUsd is populated, this same sum picks it up with no further change here.\n\t\tlet workerSpendUsd = 0;\n\t\tfor (const record of args.laneRecords) {\n\t\t\tif (record.goalId !== goalId) continue;\n\t\t\tif (record.status === \"queued\" || record.status === \"running\") inFlight.add(record.laneId);\n\t\t\tworkerSpendUsd += record.costUsd ?? 0;\n\t\t}\n\t\tinFlightGoalLaneIds = inFlight;\n\t\tgoalState = { ...goalState, continuationWorkerSpendUsd: workerSpendUsd };\n\t}\n\n\t// Worktree-sync surfacing: (a) a per-requirement projection (matched via `boundLaneId`, purely for\n\t// snapshot consumers -- never read by `evaluateGoalContinuation` itself), and (b) the\n\t// `boundLaneId`-keyed sets `evaluateGoalContinuation` actually matches against\n\t// `Requirement.boundLaneId`, same id-space and matching pattern as `inFlightGoalLaneIds` above.\n\t// Disjoint by construction: a lane with `rebaseInProgress` feeds the conflict set only, never both.\n\tlet requirementWorktreeStates: GoalRuntimeRequirementWorktreeState[] | undefined;\n\tconst laneSyncConflictLaneKeys = new Set<string>();\n\tconst syncRequiredLaneKeys = new Set<string>();\n\tif (args.worktreeLaneStatus) {\n\t\tfor (const status of args.worktreeLaneStatus) {\n\t\t\tif (status.boundLaneId === undefined) continue;\n\t\t\tif (status.rebaseInProgress) laneSyncConflictLaneKeys.add(status.boundLaneId);\n\t\t\telse if (status.syncRequired) syncRequiredLaneKeys.add(status.boundLaneId);\n\t\t}\n\t\tif (goalState) {\n\t\t\tconst states: GoalRuntimeRequirementWorktreeState[] = [];\n\t\t\tfor (const requirement of goalState.requirements) {\n\t\t\t\tif (requirement.boundLaneId === undefined) continue;\n\t\t\t\tconst status = args.worktreeLaneStatus.find(\n\t\t\t\t\t(candidate) => candidate.boundLaneId === requirement.boundLaneId,\n\t\t\t\t);\n\t\t\t\tif (!status) continue;\n\t\t\t\tstates.push({\n\t\t\t\t\trequirementId: requirement.id,\n\t\t\t\t\tlaneKey: status.laneKey,\n\t\t\t\t\tfresh: status.fresh,\n\t\t\t\t\tstale: status.stale,\n\t\t\t\t\tsyncRequired: status.syncRequired,\n\t\t\t\t\trebaseInProgress: status.rebaseInProgress,\n\t\t\t\t});\n\t\t\t}\n\t\t\trequirementWorktreeStates = states;\n\t\t}\n\t}\n\n\tconst now = (args.now ?? (() => new Date().toISOString()))();\n\tconst maxWorkerWaitMs = args.maxWorkerWaitMs ?? DEFAULT_GOAL_WORKER_WAIT_MS;\n\tconst continuation = evaluateGoalContinuation({\n\t\tstate: goalState,\n\t\tsettings: { maxStallTurns: args.settings.maxStallTurns },\n\t\tinFlightGoalLaneIds,\n\t\tnow,\n\t\tmaxWorkerWaitMs,\n\t\tlaneSyncConflictLaneKeys: laneSyncConflictLaneKeys.size > 0 ? laneSyncConflictLaneKeys : undefined,\n\t\tsyncRequiredLaneKeys: syncRequiredLaneKeys.size > 0 ? syncRequiredLaneKeys : undefined,\n\t});\n\n\treturn {\n\t\tgoalState,\n\t\tlatestEvidenceBundle,\n\t\tworkerResults,\n\t\tlearningDecisions,\n\t\tcontinuation,\n\t\topenTaskSteps,\n\t\t...(requirementWorktreeStates !== undefined ? { requirementWorktreeStates } : {}),\n\t};\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  export type GoalStatus = "active" | "completed" | "blocked" | "cancelled";
2
2
  export type RequirementStatus = "open" | "satisfied" | "blocked";
3
- export type GoalEvidenceKind = "file" | "test" | "tool" | "user" | "finding";
3
+ export type GoalEvidenceKind = "file" | "test" | "tool" | "user" | "finding" | "worker";
4
4
  export interface GoalState {
5
5
  goalId: string;
6
6
  userGoal: string;
@@ -13,6 +13,46 @@ export interface GoalState {
13
13
  lastProgressAt: string;
14
14
  stallTurns: number;
15
15
  blockedReason?: string;
16
+ /**
17
+ * Cumulative continuation turns submitted for this goal across EVERY `continueGoalLoop`
18
+ * invocation for its lifetime (idle-driven auto-continues and manual continues alike) —
19
+ * durable via goal-state persistence, so it survives process restarts and idle cycles.
20
+ * Optional because snapshots persisted before this field existed carry no value; treat
21
+ * `undefined` as `0` everywhere it is read (see `applyGoalEvent`'s `record_continuation_budget`
22
+ * case and `goal-loop-controller.ts`'s budget check).
23
+ */
24
+ continuationTurnsUsed?: number;
25
+ /**
26
+ * Cumulative ACTIVE wall-clock milliseconds spent running continuation passes for this goal —
27
+ * the sum of each individual pass's own await duration, NOT wall-clock time elapsed between
28
+ * passes or during idle gaps. Same backward-compat/undefined-as-0 note as `continuationTurnsUsed`.
29
+ */
30
+ continuationWallClockMs?: number;
31
+ /**
32
+ * Cumulative USD attributed to this goal's own continuation passes, derived from the session's
33
+ * own model spend (`getCostSummary().ownCost` at the persistence dep) — deliberately excludes
34
+ * worker/subagent spend, which is tracked and budgeted separately. Same backward-compat note.
35
+ */
36
+ continuationSpendUsd?: number;
37
+ /**
38
+ * Bookkeeping only: the session's own cumulative cost reading as of the last recorded pass,
39
+ * used to derive the NEXT pass's spend delta (`event.sessionCostUsd - continuationSpendCheckpointUsd`)
40
+ * while keeping `applyGoalEvent` pure (it consumes one externally-observed absolute reading per
41
+ * call rather than reaching for session state itself). Not meaningful read in isolation; `undefined`
42
+ * means no pass has been recorded yet, so the first recorded pass establishes the checkpoint with a
43
+ * zero delta rather than mis-attributing all pre-goal-loop session spend to that one pass.
44
+ */
45
+ continuationSpendCheckpointUsd?: number;
46
+ /**
47
+ * Cumulative USD attributed to WORKER/SUBAGENT spend for this goal's lanes (in-process worker
48
+ * usage via `addSpawnedUsage`, out-of-process tmux-worker usage via the advisory
49
+ * `reportSpawnedUsage` claim) — the counterpart this goal's OWN model spend excludes (see
50
+ * {@link continuationSpendUsd}). Populated by the runtime that sums lane spend by goalId; this
51
+ * field is only the durable slot. Same backward-compat/undefined-as-0 note as the other
52
+ * continuation budget fields. Advisory for out-of-process (tmux) workers — never a hard cap
53
+ * across the process boundary.
54
+ */
55
+ continuationWorkerSpendUsd?: number;
16
56
  }
17
57
  export interface Requirement {
18
58
  id: string;
@@ -22,12 +62,33 @@ export interface Requirement {
22
62
  blockedReason?: string;
23
63
  createdAt: string;
24
64
  updatedAt: string;
65
+ /**
66
+ * LaneId of a worker dispatched against this requirement (set by the `dispatch_worker` event).
67
+ * Recording a binding never satisfies the requirement by itself -- the worker's own completion
68
+ * later populates `"worker"`-kind evidence and prompts an explicit `satisfy_requirement` pass.
69
+ */
70
+ boundLaneId?: string;
71
+ /**
72
+ * ISO timestamp of the moment `boundLaneId` was most recently bound to a REAL lane -- the clock
73
+ * the never-hang wait-timeout (`evaluateGoalContinuation`'s `worker_wait_timeout` reasonCode)
74
+ * reads to detect a worker that has hung past `maxWorkerWaitMs`. Stamped ONLY when a
75
+ * `dispatch_worker` event carries a lane id; a declined dispatch (no lane) leaves this field
76
+ * untouched, so no clock starts for a worker that never actually launched.
77
+ */
78
+ boundAt?: string;
25
79
  }
26
80
  export interface GoalEvidenceRef {
27
81
  id: string;
28
82
  kind: GoalEvidenceKind;
29
83
  summary: string;
30
84
  uri?: string;
85
+ /**
86
+ * Whether `uri` was checked against session records ("tool" evidence, a toolCallId) or the
87
+ * filesystem ("file" evidence, a path) at add_evidence time. `true`/`false` only when the
88
+ * ref was checkable; `undefined` when the evidence kind carries no checkable ref (e.g.
89
+ * "user"/"finding"/"test", or a "tool"/"file" entry with no `uri`).
90
+ */
91
+ verified?: boolean;
31
92
  createdAt: string;
32
93
  }
33
94
  export type GoalEvent = {
@@ -49,12 +110,26 @@ export type GoalEvent = {
49
110
  type: "reopen_requirement";
50
111
  id: string;
51
112
  now: string;
113
+ } | {
114
+ type: "dispatch_worker";
115
+ /** Requirement id the worker is bound to. */
116
+ id: string;
117
+ /** Instructions the worker was (or will be) dispatched with. */
118
+ instructions: string;
119
+ /**
120
+ * LaneId returned by the tool-layer dispatch side effect. Undefined when that side effect
121
+ * is unwired/stubbed -- the binding is then recorded with no lane target yet.
122
+ */
123
+ laneId?: string;
124
+ now: string;
52
125
  } | {
53
126
  type: "add_evidence";
54
127
  id: string;
55
128
  kind: GoalEvidenceKind;
56
129
  summary: string;
57
130
  uri?: string;
131
+ /** See {@link GoalEvidenceRef.verified}; computed by the tool layer before the event is applied. */
132
+ verified?: boolean;
58
133
  now: string;
59
134
  } | {
60
135
  type: "progress";
@@ -62,6 +137,19 @@ export type GoalEvent = {
62
137
  } | {
63
138
  type: "no_progress";
64
139
  now: string;
140
+ } | {
141
+ type: "record_continuation_budget";
142
+ /** Turns submitted in this pass (currently always 1 — the loop calls once per submitted pass). */
143
+ turns: number;
144
+ /** This pass's own active wall-clock duration, in milliseconds. */
145
+ wallClockMs: number;
146
+ /**
147
+ * The session's own cumulative model spend (`getCostSummary().ownCost`) AT THE TIME this pass
148
+ * was recorded — an absolute reading, not a pre-computed delta. See
149
+ * `GoalState.continuationSpendCheckpointUsd` for how the reducer derives the delta.
150
+ */
151
+ sessionCostUsd: number;
152
+ now: string;
65
153
  } | {
66
154
  type: "complete_goal";
67
155
  now: string;
@@ -1 +1 @@
1
- {"version":3,"file":"goal-state.d.ts","sourceRoot":"","sources":["../../../src/core/goals/goal-state.ts"],"names":[],"mappings":"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","sourcesContent":["export type GoalStatus = \"active\" | \"completed\" | \"blocked\" | \"cancelled\";\nexport type RequirementStatus = \"open\" | \"satisfied\" | \"blocked\";\nexport type GoalEvidenceKind = \"file\" | \"test\" | \"tool\" | \"user\" | \"finding\";\n\nexport interface GoalState {\n\tgoalId: string;\n\tuserGoal: string;\n\tstatus: GoalStatus;\n\trequirements: readonly Requirement[];\n\tevidence: readonly GoalEvidenceRef[];\n\tevents: readonly GoalEvent[];\n\tcreatedAt: string;\n\tupdatedAt: string;\n\tlastProgressAt: string;\n\tstallTurns: number;\n\tblockedReason?: string;\n}\n\nexport interface Requirement {\n\tid: string;\n\ttext: string;\n\tstatus: RequirementStatus;\n\tevidenceIds: readonly string[];\n\tblockedReason?: string;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\nexport interface GoalEvidenceRef {\n\tid: string;\n\tkind: GoalEvidenceKind;\n\tsummary: string;\n\turi?: string;\n\tcreatedAt: string;\n}\n\nexport type GoalEvent =\n\t| { type: \"add_requirement\"; id: string; text: string; now: string }\n\t| { type: \"satisfy_requirement\"; id: string; evidenceIds: readonly string[]; now: string }\n\t| { type: \"block_requirement\"; id: string; blockedReason: string; now: string }\n\t| { type: \"reopen_requirement\"; id: string; now: string }\n\t| {\n\t\t\ttype: \"add_evidence\";\n\t\t\tid: string;\n\t\t\tkind: GoalEvidenceKind;\n\t\t\tsummary: string;\n\t\t\turi?: string;\n\t\t\tnow: string;\n\t }\n\t| { type: \"progress\"; now: string }\n\t| { type: \"no_progress\"; now: string }\n\t| { type: \"complete_goal\"; now: string }\n\t| { type: \"complete_goal_manually\"; now: string }\n\t| { type: \"block_goal\"; reason: string; now: string }\n\t| { type: \"resume_goal\"; now: string }\n\t| { type: \"cancel_goal\"; now: string };\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) return false;\n\tconst prototype = Object.getPrototypeOf(value);\n\treturn prototype === Object.prototype || prototype === null;\n}\n\nfunction isStringArray(value: unknown): value is readonly string[] {\n\treturn Array.isArray(value) && value.every((item) => typeof item === \"string\");\n}\n\nfunction isGoalStatus(value: unknown): value is GoalStatus {\n\treturn value === \"active\" || value === \"completed\" || value === \"blocked\" || value === \"cancelled\";\n}\n\nfunction isRequirementStatus(value: unknown): value is RequirementStatus {\n\treturn value === \"open\" || value === \"satisfied\" || value === \"blocked\";\n}\n\nfunction isGoalEvidenceKind(value: unknown): value is GoalEvidenceKind {\n\treturn value === \"file\" || value === \"test\" || value === \"tool\" || value === \"user\" || value === \"finding\";\n}\n\nfunction hasOptionalString(record: Record<string, unknown>, key: string): boolean {\n\treturn record[key] === undefined || typeof record[key] === \"string\";\n}\n\nfunction isRequirement(value: unknown): value is Requirement {\n\tif (!isRecord(value)) return false;\n\treturn (\n\t\ttypeof value.id === \"string\" &&\n\t\ttypeof value.text === \"string\" &&\n\t\tisRequirementStatus(value.status) &&\n\t\tisStringArray(value.evidenceIds) &&\n\t\ttypeof value.createdAt === \"string\" &&\n\t\ttypeof value.updatedAt === \"string\" &&\n\t\thasOptionalString(value, \"blockedReason\")\n\t);\n}\n\nfunction isGoalEvidenceRef(value: unknown): value is GoalEvidenceRef {\n\tif (!isRecord(value)) return false;\n\treturn (\n\t\ttypeof value.id === \"string\" &&\n\t\tisGoalEvidenceKind(value.kind) &&\n\t\ttypeof value.summary === \"string\" &&\n\t\ttypeof value.createdAt === \"string\" &&\n\t\thasOptionalString(value, \"uri\")\n\t);\n}\n\nfunction isGoalEvent(value: unknown): value is GoalEvent {\n\tif (!isRecord(value) || typeof value.type !== \"string\" || typeof value.now !== \"string\") return false;\n\tswitch (value.type) {\n\t\tcase \"add_requirement\":\n\t\t\treturn typeof value.id === \"string\" && typeof value.text === \"string\";\n\t\tcase \"satisfy_requirement\":\n\t\t\treturn typeof value.id === \"string\" && isStringArray(value.evidenceIds);\n\t\tcase \"block_requirement\":\n\t\t\treturn typeof value.id === \"string\" && typeof value.blockedReason === \"string\";\n\t\tcase \"reopen_requirement\":\n\t\t\treturn typeof value.id === \"string\";\n\t\tcase \"add_evidence\":\n\t\t\treturn (\n\t\t\t\ttypeof value.id === \"string\" &&\n\t\t\t\tisGoalEvidenceKind(value.kind) &&\n\t\t\t\ttypeof value.summary === \"string\" &&\n\t\t\t\thasOptionalString(value, \"uri\")\n\t\t\t);\n\t\tcase \"progress\":\n\t\tcase \"no_progress\":\n\t\tcase \"complete_goal\":\n\t\tcase \"complete_goal_manually\":\n\t\tcase \"resume_goal\":\n\t\tcase \"cancel_goal\":\n\t\t\treturn true;\n\t\tcase \"block_goal\":\n\t\t\treturn typeof value.reason === \"string\";\n\t\tdefault:\n\t\t\treturn false;\n\t}\n}\n\nexport function isGoalState(value: unknown): value is GoalState {\n\tif (!isRecord(value)) return false;\n\treturn (\n\t\ttypeof value.goalId === \"string\" &&\n\t\ttypeof value.userGoal === \"string\" &&\n\t\tisGoalStatus(value.status) &&\n\t\tArray.isArray(value.requirements) &&\n\t\tvalue.requirements.every(isRequirement) &&\n\t\tArray.isArray(value.evidence) &&\n\t\tvalue.evidence.every(isGoalEvidenceRef) &&\n\t\tArray.isArray(value.events) &&\n\t\tvalue.events.every(isGoalEvent) &&\n\t\ttypeof value.createdAt === \"string\" &&\n\t\ttypeof value.updatedAt === \"string\" &&\n\t\ttypeof value.lastProgressAt === \"string\" &&\n\t\ttypeof value.stallTurns === \"number\" &&\n\t\tNumber.isFinite(value.stallTurns) &&\n\t\thasOptionalString(value, \"blockedReason\")\n\t);\n}\n\nfunction cloneRequirement(requirement: Requirement): Requirement {\n\treturn {\n\t\t...requirement,\n\t\tevidenceIds: [...requirement.evidenceIds],\n\t};\n}\n\nfunction cloneGoalEvidenceRef(evidence: GoalEvidenceRef): GoalEvidenceRef {\n\treturn { ...evidence };\n}\n\nfunction cloneGoalEvent(event: GoalEvent): GoalEvent {\n\tif (event.type === \"satisfy_requirement\") {\n\t\treturn { ...event, evidenceIds: [...event.evidenceIds] };\n\t}\n\treturn { ...event };\n}\n\nfunction cloneGoalState(state: GoalState): GoalState {\n\treturn {\n\t\t...state,\n\t\trequirements: state.requirements.map(cloneRequirement),\n\t\tevidence: state.evidence.map(cloneGoalEvidenceRef),\n\t\tevents: state.events.map(cloneGoalEvent),\n\t};\n}\n\nexport function cloneGoalStateForStorage(state: GoalState): GoalState {\n\treturn cloneGoalState(state);\n}\n\nexport function createGoalState(args: { goalId: string; userGoal: string; now: string }): GoalState {\n\treturn {\n\t\tgoalId: args.goalId,\n\t\tuserGoal: args.userGoal,\n\t\tstatus: \"active\",\n\t\trequirements: [],\n\t\tevidence: [],\n\t\tevents: [],\n\t\tcreatedAt: args.now,\n\t\tupdatedAt: args.now,\n\t\tlastProgressAt: args.now,\n\t\tstallTurns: 0,\n\t};\n}\n\nexport function applyGoalEvent(state: GoalState, event: GoalEvent): GoalState {\n\tconst newState: GoalState = {\n\t\t...state,\n\t\trequirements: state.requirements.map(cloneRequirement),\n\t\tevidence: state.evidence.map(cloneGoalEvidenceRef),\n\t\tevents: [...state.events.map(cloneGoalEvent), cloneGoalEvent(event)],\n\t\tupdatedAt: event.now,\n\t};\n\n\tswitch (event.type) {\n\t\tcase \"add_requirement\": {\n\t\t\tconst existingIndex = newState.requirements.findIndex((requirement) => requirement.id === event.id);\n\t\t\tconst newRequirement: Requirement = {\n\t\t\t\tid: event.id,\n\t\t\t\ttext: event.text,\n\t\t\t\tstatus: \"open\",\n\t\t\t\tevidenceIds: [],\n\t\t\t\tcreatedAt: existingIndex >= 0 ? newState.requirements[existingIndex].createdAt : event.now,\n\t\t\t\tupdatedAt: event.now,\n\t\t\t};\n\t\t\tif (existingIndex >= 0) {\n\t\t\t\tconst updatedRequirements = [...newState.requirements];\n\t\t\t\tupdatedRequirements[existingIndex] = newRequirement;\n\t\t\t\tnewState.requirements = updatedRequirements;\n\t\t\t} else {\n\t\t\t\tnewState.requirements = [...newState.requirements, newRequirement];\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"satisfy_requirement\": {\n\t\t\tconst existingIndex = newState.requirements.findIndex((requirement) => requirement.id === event.id);\n\t\t\tif (existingIndex >= 0) {\n\t\t\t\tconst requirement = newState.requirements[existingIndex];\n\t\t\t\tconst updatedRequirements = [...newState.requirements];\n\t\t\t\tupdatedRequirements[existingIndex] = {\n\t\t\t\t\t...requirement,\n\t\t\t\t\tstatus: \"satisfied\",\n\t\t\t\t\tevidenceIds: [...event.evidenceIds],\n\t\t\t\t\tupdatedAt: event.now,\n\t\t\t\t\tblockedReason: undefined,\n\t\t\t\t};\n\t\t\t\tnewState.requirements = updatedRequirements;\n\t\t\t}\n\t\t\tnewState.lastProgressAt = event.now;\n\t\t\tnewState.stallTurns = 0;\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"block_requirement\": {\n\t\t\tconst existingIndex = newState.requirements.findIndex((requirement) => requirement.id === event.id);\n\t\t\tif (existingIndex >= 0) {\n\t\t\t\tconst requirement = newState.requirements[existingIndex];\n\t\t\t\tconst updatedRequirements = [...newState.requirements];\n\t\t\t\tupdatedRequirements[existingIndex] = {\n\t\t\t\t\t...requirement,\n\t\t\t\t\tstatus: \"blocked\",\n\t\t\t\t\tblockedReason: event.blockedReason,\n\t\t\t\t\tupdatedAt: event.now,\n\t\t\t\t};\n\t\t\t\tnewState.requirements = updatedRequirements;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"reopen_requirement\": {\n\t\t\tconst existingIndex = newState.requirements.findIndex((requirement) => requirement.id === event.id);\n\t\t\tif (existingIndex >= 0) {\n\t\t\t\tconst requirement = newState.requirements[existingIndex];\n\t\t\t\tconst updatedRequirements = [...newState.requirements];\n\t\t\t\tupdatedRequirements[existingIndex] = {\n\t\t\t\t\t...requirement,\n\t\t\t\t\tstatus: \"open\",\n\t\t\t\t\tblockedReason: undefined,\n\t\t\t\t\tupdatedAt: event.now,\n\t\t\t\t};\n\t\t\t\tnewState.requirements = updatedRequirements;\n\t\t\t}\n\t\t\tnewState.lastProgressAt = event.now;\n\t\t\tnewState.stallTurns = 0;\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"add_evidence\": {\n\t\t\tconst existingIndex = newState.evidence.findIndex((evidence) => evidence.id === event.id);\n\t\t\tconst newEvidence: GoalEvidenceRef = {\n\t\t\t\tid: event.id,\n\t\t\t\tkind: event.kind,\n\t\t\t\tsummary: event.summary,\n\t\t\t\turi: event.uri,\n\t\t\t\tcreatedAt: existingIndex >= 0 ? newState.evidence[existingIndex].createdAt : event.now,\n\t\t\t};\n\t\t\tif (existingIndex >= 0) {\n\t\t\t\tconst updatedEvidence = [...newState.evidence];\n\t\t\t\tupdatedEvidence[existingIndex] = newEvidence;\n\t\t\t\tnewState.evidence = updatedEvidence;\n\t\t\t} else {\n\t\t\t\tnewState.evidence = [...newState.evidence, newEvidence];\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"progress\": {\n\t\t\tnewState.lastProgressAt = event.now;\n\t\t\tnewState.stallTurns = 0;\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"no_progress\": {\n\t\t\tnewState.stallTurns = state.stallTurns + 1;\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"complete_goal\": {\n\t\t\tconst hasUnsatisfied = newState.requirements.some((requirement) => requirement.status !== \"satisfied\");\n\t\t\tif (!hasUnsatisfied) {\n\t\t\t\tnewState.status = \"completed\";\n\t\t\t\tnewState.blockedReason = undefined;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"complete_goal_manually\": {\n\t\t\tnewState.status = \"completed\";\n\t\t\tnewState.blockedReason = undefined;\n\t\t\tnewState.lastProgressAt = event.now;\n\t\t\tnewState.stallTurns = 0;\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"block_goal\": {\n\t\t\tnewState.status = \"blocked\";\n\t\t\tnewState.blockedReason = event.reason;\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"resume_goal\": {\n\t\t\tnewState.status = \"active\";\n\t\t\tnewState.blockedReason = undefined;\n\t\t\tnewState.lastProgressAt = event.now;\n\t\t\tnewState.stallTurns = 0;\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"cancel_goal\": {\n\t\t\tnewState.status = \"cancelled\";\n\t\t\tnewState.blockedReason = undefined;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn newState;\n}\n\nexport function shouldContinueGoalLoop(args: { state: GoalState; maxStallTurns: number; now: string }): boolean {\n\tif (args.state.status !== \"active\") {\n\t\treturn false;\n\t}\n\tif (args.state.stallTurns >= args.maxStallTurns) {\n\t\treturn false;\n\t}\n\treturn true;\n}\n\nexport function serializeGoalState(state: GoalState): string {\n\treturn JSON.stringify(cloneGoalState(state), null, 2);\n}\n\nexport function parseGoalState(text: string): GoalState | undefined {\n\ttry {\n\t\tconst parsed: unknown = JSON.parse(text);\n\t\tif (!isGoalState(parsed)) return undefined;\n\t\treturn cloneGoalState(parsed);\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n"]}
1
+ {"version":3,"file":"goal-state.d.ts","sourceRoot":"","sources":["../../../src/core/goals/goal-state.ts"],"names":[],"mappings":"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","sourcesContent":["export type GoalStatus = \"active\" | \"completed\" | \"blocked\" | \"cancelled\";\nexport type RequirementStatus = \"open\" | \"satisfied\" | \"blocked\";\nexport type GoalEvidenceKind = \"file\" | \"test\" | \"tool\" | \"user\" | \"finding\" | \"worker\";\n\nexport interface GoalState {\n\tgoalId: string;\n\tuserGoal: string;\n\tstatus: GoalStatus;\n\trequirements: readonly Requirement[];\n\tevidence: readonly GoalEvidenceRef[];\n\tevents: readonly GoalEvent[];\n\tcreatedAt: string;\n\tupdatedAt: string;\n\tlastProgressAt: string;\n\tstallTurns: number;\n\tblockedReason?: string;\n\t/**\n\t * Cumulative continuation turns submitted for this goal across EVERY `continueGoalLoop`\n\t * invocation for its lifetime (idle-driven auto-continues and manual continues alike) —\n\t * durable via goal-state persistence, so it survives process restarts and idle cycles.\n\t * Optional because snapshots persisted before this field existed carry no value; treat\n\t * `undefined` as `0` everywhere it is read (see `applyGoalEvent`'s `record_continuation_budget`\n\t * case and `goal-loop-controller.ts`'s budget check).\n\t */\n\tcontinuationTurnsUsed?: number;\n\t/**\n\t * Cumulative ACTIVE wall-clock milliseconds spent running continuation passes for this goal —\n\t * the sum of each individual pass's own await duration, NOT wall-clock time elapsed between\n\t * passes or during idle gaps. Same backward-compat/undefined-as-0 note as `continuationTurnsUsed`.\n\t */\n\tcontinuationWallClockMs?: number;\n\t/**\n\t * Cumulative USD attributed to this goal's own continuation passes, derived from the session's\n\t * own model spend (`getCostSummary().ownCost` at the persistence dep) — deliberately excludes\n\t * worker/subagent spend, which is tracked and budgeted separately. Same backward-compat note.\n\t */\n\tcontinuationSpendUsd?: number;\n\t/**\n\t * Bookkeeping only: the session's own cumulative cost reading as of the last recorded pass,\n\t * used to derive the NEXT pass's spend delta (`event.sessionCostUsd - continuationSpendCheckpointUsd`)\n\t * while keeping `applyGoalEvent` pure (it consumes one externally-observed absolute reading per\n\t * call rather than reaching for session state itself). Not meaningful read in isolation; `undefined`\n\t * means no pass has been recorded yet, so the first recorded pass establishes the checkpoint with a\n\t * zero delta rather than mis-attributing all pre-goal-loop session spend to that one pass.\n\t */\n\tcontinuationSpendCheckpointUsd?: number;\n\t/**\n\t * Cumulative USD attributed to WORKER/SUBAGENT spend for this goal's lanes (in-process worker\n\t * usage via `addSpawnedUsage`, out-of-process tmux-worker usage via the advisory\n\t * `reportSpawnedUsage` claim) — the counterpart this goal's OWN model spend excludes (see\n\t * {@link continuationSpendUsd}). Populated by the runtime that sums lane spend by goalId; this\n\t * field is only the durable slot. Same backward-compat/undefined-as-0 note as the other\n\t * continuation budget fields. Advisory for out-of-process (tmux) workers — never a hard cap\n\t * across the process boundary.\n\t */\n\tcontinuationWorkerSpendUsd?: number;\n}\n\nexport interface Requirement {\n\tid: string;\n\ttext: string;\n\tstatus: RequirementStatus;\n\tevidenceIds: readonly string[];\n\tblockedReason?: string;\n\tcreatedAt: string;\n\tupdatedAt: string;\n\t/**\n\t * LaneId of a worker dispatched against this requirement (set by the `dispatch_worker` event).\n\t * Recording a binding never satisfies the requirement by itself -- the worker's own completion\n\t * later populates `\"worker\"`-kind evidence and prompts an explicit `satisfy_requirement` pass.\n\t */\n\tboundLaneId?: string;\n\t/**\n\t * ISO timestamp of the moment `boundLaneId` was most recently bound to a REAL lane -- the clock\n\t * the never-hang wait-timeout (`evaluateGoalContinuation`'s `worker_wait_timeout` reasonCode)\n\t * reads to detect a worker that has hung past `maxWorkerWaitMs`. Stamped ONLY when a\n\t * `dispatch_worker` event carries a lane id; a declined dispatch (no lane) leaves this field\n\t * untouched, so no clock starts for a worker that never actually launched.\n\t */\n\tboundAt?: string;\n}\n\nexport interface GoalEvidenceRef {\n\tid: string;\n\tkind: GoalEvidenceKind;\n\tsummary: string;\n\turi?: string;\n\t/**\n\t * Whether `uri` was checked against session records (\"tool\" evidence, a toolCallId) or the\n\t * filesystem (\"file\" evidence, a path) at add_evidence time. `true`/`false` only when the\n\t * ref was checkable; `undefined` when the evidence kind carries no checkable ref (e.g.\n\t * \"user\"/\"finding\"/\"test\", or a \"tool\"/\"file\" entry with no `uri`).\n\t */\n\tverified?: boolean;\n\tcreatedAt: string;\n}\n\nexport type GoalEvent =\n\t| { type: \"add_requirement\"; id: string; text: string; now: string }\n\t| { type: \"satisfy_requirement\"; id: string; evidenceIds: readonly string[]; now: string }\n\t| { type: \"block_requirement\"; id: string; blockedReason: string; now: string }\n\t| { type: \"reopen_requirement\"; id: string; now: string }\n\t| {\n\t\t\ttype: \"dispatch_worker\";\n\t\t\t/** Requirement id the worker is bound to. */\n\t\t\tid: string;\n\t\t\t/** Instructions the worker was (or will be) dispatched with. */\n\t\t\tinstructions: string;\n\t\t\t/**\n\t\t\t * LaneId returned by the tool-layer dispatch side effect. Undefined when that side effect\n\t\t\t * is unwired/stubbed -- the binding is then recorded with no lane target yet.\n\t\t\t */\n\t\t\tlaneId?: string;\n\t\t\tnow: string;\n\t }\n\t| {\n\t\t\ttype: \"add_evidence\";\n\t\t\tid: string;\n\t\t\tkind: GoalEvidenceKind;\n\t\t\tsummary: string;\n\t\t\turi?: string;\n\t\t\t/** See {@link GoalEvidenceRef.verified}; computed by the tool layer before the event is applied. */\n\t\t\tverified?: boolean;\n\t\t\tnow: string;\n\t }\n\t| { type: \"progress\"; now: string }\n\t| { type: \"no_progress\"; now: string }\n\t| {\n\t\t\ttype: \"record_continuation_budget\";\n\t\t\t/** Turns submitted in this pass (currently always 1 — the loop calls once per submitted pass). */\n\t\t\tturns: number;\n\t\t\t/** This pass's own active wall-clock duration, in milliseconds. */\n\t\t\twallClockMs: number;\n\t\t\t/**\n\t\t\t * The session's own cumulative model spend (`getCostSummary().ownCost`) AT THE TIME this pass\n\t\t\t * was recorded — an absolute reading, not a pre-computed delta. See\n\t\t\t * `GoalState.continuationSpendCheckpointUsd` for how the reducer derives the delta.\n\t\t\t */\n\t\t\tsessionCostUsd: number;\n\t\t\tnow: string;\n\t }\n\t| { type: \"complete_goal\"; now: string }\n\t| { type: \"complete_goal_manually\"; now: string }\n\t| { type: \"block_goal\"; reason: string; now: string }\n\t| { type: \"resume_goal\"; now: string }\n\t| { type: \"cancel_goal\"; now: string };\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) return false;\n\tconst prototype = Object.getPrototypeOf(value);\n\treturn prototype === Object.prototype || prototype === null;\n}\n\nfunction isStringArray(value: unknown): value is readonly string[] {\n\treturn Array.isArray(value) && value.every((item) => typeof item === \"string\");\n}\n\nfunction isGoalStatus(value: unknown): value is GoalStatus {\n\treturn value === \"active\" || value === \"completed\" || value === \"blocked\" || value === \"cancelled\";\n}\n\nfunction isRequirementStatus(value: unknown): value is RequirementStatus {\n\treturn value === \"open\" || value === \"satisfied\" || value === \"blocked\";\n}\n\nfunction isGoalEvidenceKind(value: unknown): value is GoalEvidenceKind {\n\treturn (\n\t\tvalue === \"file\" ||\n\t\tvalue === \"test\" ||\n\t\tvalue === \"tool\" ||\n\t\tvalue === \"user\" ||\n\t\tvalue === \"finding\" ||\n\t\tvalue === \"worker\"\n\t);\n}\n\nfunction hasOptionalString(record: Record<string, unknown>, key: string): boolean {\n\treturn record[key] === undefined || typeof record[key] === \"string\";\n}\n\nfunction hasOptionalBoolean(record: Record<string, unknown>, key: string): boolean {\n\treturn record[key] === undefined || typeof record[key] === \"boolean\";\n}\n\nfunction hasOptionalFiniteNumber(record: Record<string, unknown>, key: string): boolean {\n\treturn record[key] === undefined || (typeof record[key] === \"number\" && Number.isFinite(record[key]));\n}\n\nfunction isRequirement(value: unknown): value is Requirement {\n\tif (!isRecord(value)) return false;\n\treturn (\n\t\ttypeof value.id === \"string\" &&\n\t\ttypeof value.text === \"string\" &&\n\t\tisRequirementStatus(value.status) &&\n\t\tisStringArray(value.evidenceIds) &&\n\t\ttypeof value.createdAt === \"string\" &&\n\t\ttypeof value.updatedAt === \"string\" &&\n\t\thasOptionalString(value, \"blockedReason\") &&\n\t\thasOptionalString(value, \"boundLaneId\") &&\n\t\thasOptionalString(value, \"boundAt\")\n\t);\n}\n\nfunction isGoalEvidenceRef(value: unknown): value is GoalEvidenceRef {\n\tif (!isRecord(value)) return false;\n\treturn (\n\t\ttypeof value.id === \"string\" &&\n\t\tisGoalEvidenceKind(value.kind) &&\n\t\ttypeof value.summary === \"string\" &&\n\t\ttypeof value.createdAt === \"string\" &&\n\t\thasOptionalString(value, \"uri\") &&\n\t\thasOptionalBoolean(value, \"verified\")\n\t);\n}\n\nfunction isGoalEvent(value: unknown): value is GoalEvent {\n\tif (!isRecord(value) || typeof value.type !== \"string\" || typeof value.now !== \"string\") return false;\n\tswitch (value.type) {\n\t\tcase \"add_requirement\":\n\t\t\treturn typeof value.id === \"string\" && typeof value.text === \"string\";\n\t\tcase \"satisfy_requirement\":\n\t\t\treturn typeof value.id === \"string\" && isStringArray(value.evidenceIds);\n\t\tcase \"block_requirement\":\n\t\t\treturn typeof value.id === \"string\" && typeof value.blockedReason === \"string\";\n\t\tcase \"reopen_requirement\":\n\t\t\treturn typeof value.id === \"string\";\n\t\tcase \"dispatch_worker\":\n\t\t\treturn (\n\t\t\t\ttypeof value.id === \"string\" && typeof value.instructions === \"string\" && hasOptionalString(value, \"laneId\")\n\t\t\t);\n\t\tcase \"add_evidence\":\n\t\t\treturn (\n\t\t\t\ttypeof value.id === \"string\" &&\n\t\t\t\tisGoalEvidenceKind(value.kind) &&\n\t\t\t\ttypeof value.summary === \"string\" &&\n\t\t\t\thasOptionalString(value, \"uri\") &&\n\t\t\t\thasOptionalBoolean(value, \"verified\")\n\t\t\t);\n\t\tcase \"progress\":\n\t\tcase \"no_progress\":\n\t\tcase \"complete_goal\":\n\t\tcase \"complete_goal_manually\":\n\t\tcase \"resume_goal\":\n\t\tcase \"cancel_goal\":\n\t\t\treturn true;\n\t\tcase \"block_goal\":\n\t\t\treturn typeof value.reason === \"string\";\n\t\tcase \"record_continuation_budget\":\n\t\t\treturn (\n\t\t\t\ttypeof value.turns === \"number\" &&\n\t\t\t\tNumber.isFinite(value.turns) &&\n\t\t\t\ttypeof value.wallClockMs === \"number\" &&\n\t\t\t\tNumber.isFinite(value.wallClockMs) &&\n\t\t\t\ttypeof value.sessionCostUsd === \"number\" &&\n\t\t\t\tNumber.isFinite(value.sessionCostUsd)\n\t\t\t);\n\t\tdefault:\n\t\t\treturn false;\n\t}\n}\n\nexport function isGoalState(value: unknown): value is GoalState {\n\tif (!isRecord(value)) return false;\n\treturn (\n\t\ttypeof value.goalId === \"string\" &&\n\t\ttypeof value.userGoal === \"string\" &&\n\t\tisGoalStatus(value.status) &&\n\t\tArray.isArray(value.requirements) &&\n\t\tvalue.requirements.every(isRequirement) &&\n\t\tArray.isArray(value.evidence) &&\n\t\tvalue.evidence.every(isGoalEvidenceRef) &&\n\t\tArray.isArray(value.events) &&\n\t\tvalue.events.every(isGoalEvent) &&\n\t\ttypeof value.createdAt === \"string\" &&\n\t\ttypeof value.updatedAt === \"string\" &&\n\t\ttypeof value.lastProgressAt === \"string\" &&\n\t\ttypeof value.stallTurns === \"number\" &&\n\t\tNumber.isFinite(value.stallTurns) &&\n\t\thasOptionalString(value, \"blockedReason\") &&\n\t\thasOptionalFiniteNumber(value, \"continuationTurnsUsed\") &&\n\t\thasOptionalFiniteNumber(value, \"continuationWallClockMs\") &&\n\t\thasOptionalFiniteNumber(value, \"continuationSpendUsd\") &&\n\t\thasOptionalFiniteNumber(value, \"continuationSpendCheckpointUsd\") &&\n\t\thasOptionalFiniteNumber(value, \"continuationWorkerSpendUsd\")\n\t);\n}\n\nfunction cloneRequirement(requirement: Requirement): Requirement {\n\treturn {\n\t\t...requirement,\n\t\tevidenceIds: [...requirement.evidenceIds],\n\t};\n}\n\nfunction cloneGoalEvidenceRef(evidence: GoalEvidenceRef): GoalEvidenceRef {\n\treturn { ...evidence };\n}\n\nfunction cloneGoalEvent(event: GoalEvent): GoalEvent {\n\tif (event.type === \"satisfy_requirement\") {\n\t\treturn { ...event, evidenceIds: [...event.evidenceIds] };\n\t}\n\treturn { ...event };\n}\n\nfunction cloneGoalState(state: GoalState): GoalState {\n\treturn {\n\t\t...state,\n\t\trequirements: state.requirements.map(cloneRequirement),\n\t\tevidence: state.evidence.map(cloneGoalEvidenceRef),\n\t\tevents: state.events.map(cloneGoalEvent),\n\t};\n}\n\nexport function cloneGoalStateForStorage(state: GoalState): GoalState {\n\treturn cloneGoalState(state);\n}\n\nexport function createGoalState(args: { goalId: string; userGoal: string; now: string }): GoalState {\n\treturn {\n\t\tgoalId: args.goalId,\n\t\tuserGoal: args.userGoal,\n\t\tstatus: \"active\",\n\t\trequirements: [],\n\t\tevidence: [],\n\t\tevents: [],\n\t\tcreatedAt: args.now,\n\t\tupdatedAt: args.now,\n\t\tlastProgressAt: args.now,\n\t\tstallTurns: 0,\n\t\tcontinuationTurnsUsed: 0,\n\t\tcontinuationWallClockMs: 0,\n\t\tcontinuationSpendUsd: 0,\n\t\tcontinuationWorkerSpendUsd: 0,\n\t};\n}\n\nexport function applyGoalEvent(state: GoalState, event: GoalEvent): GoalState {\n\tconst newState: GoalState = {\n\t\t...state,\n\t\trequirements: state.requirements.map(cloneRequirement),\n\t\tevidence: state.evidence.map(cloneGoalEvidenceRef),\n\t\tevents: [...state.events.map(cloneGoalEvent), cloneGoalEvent(event)],\n\t\tupdatedAt: event.now,\n\t};\n\n\tswitch (event.type) {\n\t\tcase \"add_requirement\": {\n\t\t\tconst existingIndex = newState.requirements.findIndex((requirement) => requirement.id === event.id);\n\t\t\tconst newRequirement: Requirement = {\n\t\t\t\tid: event.id,\n\t\t\t\ttext: event.text,\n\t\t\t\tstatus: \"open\",\n\t\t\t\tevidenceIds: [],\n\t\t\t\tcreatedAt: existingIndex >= 0 ? newState.requirements[existingIndex].createdAt : event.now,\n\t\t\t\tupdatedAt: event.now,\n\t\t\t};\n\t\t\tif (existingIndex >= 0) {\n\t\t\t\tconst updatedRequirements = [...newState.requirements];\n\t\t\t\tupdatedRequirements[existingIndex] = newRequirement;\n\t\t\t\tnewState.requirements = updatedRequirements;\n\t\t\t} else {\n\t\t\t\tnewState.requirements = [...newState.requirements, newRequirement];\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"satisfy_requirement\": {\n\t\t\tconst existingIndex = newState.requirements.findIndex((requirement) => requirement.id === event.id);\n\t\t\tif (existingIndex >= 0) {\n\t\t\t\tconst requirement = newState.requirements[existingIndex];\n\t\t\t\tconst updatedRequirements = [...newState.requirements];\n\t\t\t\tupdatedRequirements[existingIndex] = {\n\t\t\t\t\t...requirement,\n\t\t\t\t\tstatus: \"satisfied\",\n\t\t\t\t\tevidenceIds: [...event.evidenceIds],\n\t\t\t\t\tupdatedAt: event.now,\n\t\t\t\t\tblockedReason: undefined,\n\t\t\t\t};\n\t\t\t\tnewState.requirements = updatedRequirements;\n\t\t\t}\n\t\t\tnewState.lastProgressAt = event.now;\n\t\t\tnewState.stallTurns = 0;\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"block_requirement\": {\n\t\t\tconst existingIndex = newState.requirements.findIndex((requirement) => requirement.id === event.id);\n\t\t\tif (existingIndex >= 0) {\n\t\t\t\tconst requirement = newState.requirements[existingIndex];\n\t\t\t\tconst updatedRequirements = [...newState.requirements];\n\t\t\t\tupdatedRequirements[existingIndex] = {\n\t\t\t\t\t...requirement,\n\t\t\t\t\tstatus: \"blocked\",\n\t\t\t\t\tblockedReason: event.blockedReason,\n\t\t\t\t\tupdatedAt: event.now,\n\t\t\t\t};\n\t\t\t\tnewState.requirements = updatedRequirements;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"reopen_requirement\": {\n\t\t\tconst existingIndex = newState.requirements.findIndex((requirement) => requirement.id === event.id);\n\t\t\tif (existingIndex >= 0) {\n\t\t\t\tconst requirement = newState.requirements[existingIndex];\n\t\t\t\tconst updatedRequirements = [...newState.requirements];\n\t\t\t\tupdatedRequirements[existingIndex] = {\n\t\t\t\t\t...requirement,\n\t\t\t\t\tstatus: \"open\",\n\t\t\t\t\tblockedReason: undefined,\n\t\t\t\t\tupdatedAt: event.now,\n\t\t\t\t};\n\t\t\t\tnewState.requirements = updatedRequirements;\n\t\t\t}\n\t\t\tnewState.lastProgressAt = event.now;\n\t\t\tnewState.stallTurns = 0;\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"dispatch_worker\": {\n\t\t\t// Records the requirement<->lane binding ONLY -- never satisfies the requirement and never\n\t\t\t// touches lastProgressAt/stallTurns. The worker's own completion later populates \"worker\"\n\t\t\t// evidence and prompts an explicit satisfy_requirement pass through the existing gate.\n\t\t\tconst existingIndex = newState.requirements.findIndex((requirement) => requirement.id === event.id);\n\t\t\tif (existingIndex >= 0) {\n\t\t\t\tconst requirement = newState.requirements[existingIndex];\n\t\t\t\tconst updatedRequirements = [...newState.requirements];\n\t\t\t\tupdatedRequirements[existingIndex] = {\n\t\t\t\t\t...requirement,\n\t\t\t\t\tboundLaneId: event.laneId,\n\t\t\t\t\t// Start (or keep) the wait-timeout clock ONLY when this dispatch actually bound a real\n\t\t\t\t\t// lane -- a declined dispatch (no laneId) preserves whatever boundAt was already there.\n\t\t\t\t\tboundAt: event.laneId ? event.now : requirement.boundAt,\n\t\t\t\t\tupdatedAt: event.now,\n\t\t\t\t};\n\t\t\t\tnewState.requirements = updatedRequirements;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"add_evidence\": {\n\t\t\tconst existingIndex = newState.evidence.findIndex((evidence) => evidence.id === event.id);\n\t\t\tconst newEvidence: GoalEvidenceRef = {\n\t\t\t\tid: event.id,\n\t\t\t\tkind: event.kind,\n\t\t\t\tsummary: event.summary,\n\t\t\t\turi: event.uri,\n\t\t\t\tverified: event.verified,\n\t\t\t\tcreatedAt: existingIndex >= 0 ? newState.evidence[existingIndex].createdAt : event.now,\n\t\t\t};\n\t\t\tif (existingIndex >= 0) {\n\t\t\t\tconst updatedEvidence = [...newState.evidence];\n\t\t\t\tupdatedEvidence[existingIndex] = newEvidence;\n\t\t\t\tnewState.evidence = updatedEvidence;\n\t\t\t} else {\n\t\t\t\tnewState.evidence = [...newState.evidence, newEvidence];\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"progress\": {\n\t\t\tnewState.lastProgressAt = event.now;\n\t\t\tnewState.stallTurns = 0;\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"no_progress\": {\n\t\t\tnewState.stallTurns = state.stallTurns + 1;\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"record_continuation_budget\": {\n\t\t\tconst previousCheckpoint = state.continuationSpendCheckpointUsd;\n\t\t\t// No prior checkpoint (first pass ever recorded for this goal): there is no valid \"before\"\n\t\t\t// reading to diff against, so attribute a zero delta for this one pass rather than mis-count\n\t\t\t// all pre-goal-loop session spend into it. Every subsequent pass gets an accurate delta.\n\t\t\tconst spendDelta =\n\t\t\t\tpreviousCheckpoint === undefined ? 0 : Math.max(0, event.sessionCostUsd - previousCheckpoint);\n\t\t\tnewState.continuationTurnsUsed = (state.continuationTurnsUsed ?? 0) + event.turns;\n\t\t\tnewState.continuationWallClockMs = (state.continuationWallClockMs ?? 0) + event.wallClockMs;\n\t\t\tnewState.continuationSpendUsd = (state.continuationSpendUsd ?? 0) + spendDelta;\n\t\t\tnewState.continuationSpendCheckpointUsd = event.sessionCostUsd;\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"complete_goal\": {\n\t\t\tconst hasUnsatisfied = newState.requirements.some((requirement) => requirement.status !== \"satisfied\");\n\t\t\tif (!hasUnsatisfied) {\n\t\t\t\tnewState.status = \"completed\";\n\t\t\t\tnewState.blockedReason = undefined;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"complete_goal_manually\": {\n\t\t\tnewState.status = \"completed\";\n\t\t\tnewState.blockedReason = undefined;\n\t\t\tnewState.lastProgressAt = event.now;\n\t\t\tnewState.stallTurns = 0;\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"block_goal\": {\n\t\t\tnewState.status = \"blocked\";\n\t\t\tnewState.blockedReason = event.reason;\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"resume_goal\": {\n\t\t\tnewState.status = \"active\";\n\t\t\tnewState.blockedReason = undefined;\n\t\t\tnewState.lastProgressAt = event.now;\n\t\t\tnewState.stallTurns = 0;\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"cancel_goal\": {\n\t\t\tnewState.status = \"cancelled\";\n\t\t\tnewState.blockedReason = undefined;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn newState;\n}\n\nexport function shouldContinueGoalLoop(args: { state: GoalState; maxStallTurns: number; now: string }): boolean {\n\tif (args.state.status !== \"active\") {\n\t\treturn false;\n\t}\n\tif (args.state.stallTurns >= args.maxStallTurns) {\n\t\treturn false;\n\t}\n\treturn true;\n}\n\nexport function serializeGoalState(state: GoalState): string {\n\treturn JSON.stringify(cloneGoalState(state), null, 2);\n}\n\nexport function parseGoalState(text: string): GoalState | undefined {\n\ttry {\n\t\tconst parsed: unknown = JSON.parse(text);\n\t\tif (!isGoalState(parsed)) return undefined;\n\t\treturn cloneGoalState(parsed);\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n"]}