@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.
- package/CHANGELOG.md +79 -0
- package/dist/bundled-resources/extensions/tmux-agent-manager/README.md +18 -1
- package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.d.ts +131 -0
- package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.d.ts.map +1 -0
- package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.js +196 -0
- package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.js.map +1 -0
- package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.ts +308 -0
- package/dist/bundled-resources/extensions/tmux-agent-manager/index.d.ts +22 -2
- package/dist/bundled-resources/extensions/tmux-agent-manager/index.d.ts.map +1 -1
- package/dist/bundled-resources/extensions/tmux-agent-manager/index.js +585 -24
- package/dist/bundled-resources/extensions/tmux-agent-manager/index.js.map +1 -1
- package/dist/bundled-resources/extensions/tmux-agent-manager/index.ts +749 -27
- package/dist/bundled-resources/runtimes/pi-shell-engine/commands/__init__.py +43 -0
- package/dist/bundled-resources/runtimes/pi-shell-engine/commands/fs.py +270 -0
- package/dist/bundled-resources/runtimes/pi-shell-engine/commands/search.py +252 -0
- package/dist/bundled-resources/runtimes/pi-shell-engine/commands/strings.py +399 -0
- package/dist/bundled-resources/runtimes/pi-shell-engine/commands/text.py +575 -0
- package/dist/bundled-resources/runtimes/pi-shell-engine/context.py +52 -0
- package/dist/bundled-resources/runtimes/pi-shell-engine/errors.py +49 -0
- package/dist/bundled-resources/runtimes/pi-shell-engine/exec.py +734 -0
- package/dist/bundled-resources/runtimes/pi-shell-engine/expand.py +238 -0
- package/dist/bundled-resources/runtimes/pi-shell-engine/main.py +132 -0
- package/dist/bundled-resources/runtimes/pi-shell-engine/nodes.py +116 -0
- package/dist/bundled-resources/runtimes/pi-shell-engine/parser.py +287 -0
- package/dist/bundled-resources/runtimes/pi-shell-engine/proc.py +137 -0
- package/dist/bundled-resources/runtimes/pi-shell-engine/state.py +100 -0
- package/dist/bundled-resources/runtimes/pi-shell-engine/tokens.py +579 -0
- package/dist/bundled-resources/skills/tool-call-repair/SKILL.md +19 -9
- package/dist/bundled-resources/skills/tool-call-repair/references/failure-grammar.md +22 -5
- package/dist/bundled-resources/skills/tool-call-repair/references/repair-catalogue.md +5 -5
- package/dist/bundled-resources/skills/tool-call-repair/references/text-protocol-grammar.md +28 -7
- package/dist/cli/args.d.ts +3 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +15 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/core/agent-paths.d.ts +49 -0
- package/dist/core/agent-paths.d.ts.map +1 -0
- package/dist/core/agent-paths.js +107 -0
- package/dist/core/agent-paths.js.map +1 -0
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +3 -3
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session.d.ts +234 -17
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +484 -62
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/autonomy/contracts.d.ts +9 -0
- package/dist/core/autonomy/contracts.d.ts.map +1 -1
- package/dist/core/autonomy/contracts.js.map +1 -1
- package/dist/core/autonomy/lane-tracker.d.ts +10 -1
- package/dist/core/autonomy/lane-tracker.d.ts.map +1 -1
- package/dist/core/autonomy/lane-tracker.js +5 -1
- package/dist/core/autonomy/lane-tracker.js.map +1 -1
- package/dist/core/background-lane-controller.d.ts +122 -6
- package/dist/core/background-lane-controller.d.ts.map +1 -1
- package/dist/core/background-lane-controller.js +446 -89
- package/dist/core/background-lane-controller.js.map +1 -1
- package/dist/core/bash-execution-controller.d.ts +4 -0
- package/dist/core/bash-execution-controller.d.ts.map +1 -1
- package/dist/core/bash-execution-controller.js +7 -1
- package/dist/core/bash-execution-controller.js.map +1 -1
- package/dist/core/compaction-support.d.ts +13 -3
- package/dist/core/compaction-support.d.ts.map +1 -1
- package/dist/core/compaction-support.js +43 -7
- package/dist/core/compaction-support.js.map +1 -1
- package/dist/core/context/context-audit.d.ts +33 -1
- package/dist/core/context/context-audit.d.ts.map +1 -1
- package/dist/core/context/context-audit.js +31 -5
- package/dist/core/context/context-audit.js.map +1 -1
- package/dist/core/context-gc.d.ts.map +1 -1
- package/dist/core/context-gc.js +16 -1
- package/dist/core/context-gc.js.map +1 -1
- package/dist/core/context-pipeline.d.ts +26 -4
- package/dist/core/context-pipeline.d.ts.map +1 -1
- package/dist/core/context-pipeline.js +137 -14
- package/dist/core/context-pipeline.js.map +1 -1
- package/dist/core/cost-guard.d.ts +19 -3
- package/dist/core/cost-guard.d.ts.map +1 -1
- package/dist/core/cost-guard.js +18 -3
- package/dist/core/cost-guard.js.map +1 -1
- package/dist/core/delegation/session-worker-result.d.ts +34 -4
- package/dist/core/delegation/session-worker-result.d.ts.map +1 -1
- package/dist/core/delegation/session-worker-result.js +64 -4
- package/dist/core/delegation/session-worker-result.js.map +1 -1
- package/dist/core/delegation/worker-result.d.ts +42 -1
- package/dist/core/delegation/worker-result.d.ts.map +1 -1
- package/dist/core/delegation/worker-result.js +68 -0
- package/dist/core/delegation/worker-result.js.map +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +20 -0
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +1 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +51 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/goal-loop-controller.d.ts +17 -1
- package/dist/core/goal-loop-controller.d.ts.map +1 -1
- package/dist/core/goal-loop-controller.js +79 -11
- package/dist/core/goal-loop-controller.js.map +1 -1
- package/dist/core/goals/goal-continuation-controller.d.ts +48 -2
- package/dist/core/goals/goal-continuation-controller.d.ts.map +1 -1
- package/dist/core/goals/goal-continuation-controller.js +77 -0
- package/dist/core/goals/goal-continuation-controller.js.map +1 -1
- package/dist/core/goals/goal-continuation-defaults.d.ts +39 -0
- package/dist/core/goals/goal-continuation-defaults.d.ts.map +1 -1
- package/dist/core/goals/goal-continuation-defaults.js +42 -0
- package/dist/core/goals/goal-continuation-defaults.js.map +1 -1
- package/dist/core/goals/goal-continuation-prompt.d.ts +4 -0
- package/dist/core/goals/goal-continuation-prompt.d.ts.map +1 -1
- package/dist/core/goals/goal-continuation-prompt.js +51 -10
- package/dist/core/goals/goal-continuation-prompt.js.map +1 -1
- package/dist/core/goals/goal-runtime-snapshot.d.ts +101 -2
- package/dist/core/goals/goal-runtime-snapshot.d.ts.map +1 -1
- package/dist/core/goals/goal-runtime-snapshot.js +87 -4
- package/dist/core/goals/goal-runtime-snapshot.js.map +1 -1
- package/dist/core/goals/goal-state.d.ts +89 -1
- package/dist/core/goals/goal-state.d.ts.map +1 -1
- package/dist/core/goals/goal-state.js +71 -5
- package/dist/core/goals/goal-state.js.map +1 -1
- package/dist/core/goals/goal-tool-core.d.ts +56 -2
- package/dist/core/goals/goal-tool-core.d.ts.map +1 -1
- package/dist/core/goals/goal-tool-core.js +111 -5
- package/dist/core/goals/goal-tool-core.js.map +1 -1
- package/dist/core/goals/session-goal-state.d.ts +11 -2
- package/dist/core/goals/session-goal-state.d.ts.map +1 -1
- package/dist/core/goals/session-goal-state.js +32 -17
- package/dist/core/goals/session-goal-state.js.map +1 -1
- package/dist/core/keybindings.d.ts +10 -0
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +10 -2
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/learning/observation-store.d.ts +12 -3
- package/dist/core/learning/observation-store.d.ts.map +1 -1
- package/dist/core/learning/observation-store.js +30 -15
- package/dist/core/learning/observation-store.js.map +1 -1
- package/dist/core/learning/skill-curator.d.ts +5 -1
- package/dist/core/learning/skill-curator.d.ts.map +1 -1
- package/dist/core/learning/skill-curator.js +21 -19
- package/dist/core/learning/skill-curator.js.map +1 -1
- package/dist/core/local-runtime-controller.d.ts +65 -3
- package/dist/core/local-runtime-controller.d.ts.map +1 -1
- package/dist/core/local-runtime-controller.js +186 -26
- package/dist/core/local-runtime-controller.js.map +1 -1
- package/dist/core/memory/providers/file-store.d.ts +1 -1
- package/dist/core/memory/providers/file-store.d.ts.map +1 -1
- package/dist/core/memory/providers/file-store.js +6 -6
- package/dist/core/memory/providers/file-store.js.map +1 -1
- package/dist/core/model-capability.d.ts +34 -0
- package/dist/core/model-capability.d.ts.map +1 -1
- package/dist/core/model-capability.js +42 -1
- package/dist/core/model-capability.js.map +1 -1
- package/dist/core/model-router/tool-escalation.d.ts +15 -0
- package/dist/core/model-router/tool-escalation.d.ts.map +1 -1
- package/dist/core/model-router/tool-escalation.js +23 -1
- package/dist/core/model-router/tool-escalation.js.map +1 -1
- package/dist/core/model-router-controller.d.ts +34 -7
- package/dist/core/model-router-controller.d.ts.map +1 -1
- package/dist/core/model-router-controller.js +95 -16
- package/dist/core/model-router-controller.js.map +1 -1
- package/dist/core/models/adaptation-store.d.ts +7 -0
- package/dist/core/models/adaptation-store.d.ts.map +1 -1
- package/dist/core/models/adaptation-store.js +47 -11
- package/dist/core/models/adaptation-store.js.map +1 -1
- package/dist/core/models/default-model-suggestions.d.ts.map +1 -1
- package/dist/core/models/default-model-suggestions.js +17 -0
- package/dist/core/models/default-model-suggestions.js.map +1 -1
- package/dist/core/models/fitness-store.d.ts +3 -0
- package/dist/core/models/fitness-store.d.ts.map +1 -1
- package/dist/core/models/fitness-store.js +11 -2
- package/dist/core/models/fitness-store.js.map +1 -1
- package/dist/core/models/llamacpp-runtime.d.ts +180 -0
- package/dist/core/models/llamacpp-runtime.d.ts.map +1 -0
- package/dist/core/models/llamacpp-runtime.js +475 -0
- package/dist/core/models/llamacpp-runtime.js.map +1 -0
- package/dist/core/models/local-registration.d.ts +40 -0
- package/dist/core/models/local-registration.d.ts.map +1 -1
- package/dist/core/models/local-registration.js +94 -5
- package/dist/core/models/local-registration.js.map +1 -1
- package/dist/core/models/local-runtime.d.ts.map +1 -1
- package/dist/core/models/local-runtime.js +6 -5
- package/dist/core/models/local-runtime.js.map +1 -1
- package/dist/core/models/model-ref.d.ts +7 -0
- package/dist/core/models/model-ref.d.ts.map +1 -1
- package/dist/core/models/model-ref.js +26 -0
- package/dist/core/models/model-ref.js.map +1 -1
- package/dist/core/models/needle-runtime.d.ts +257 -0
- package/dist/core/models/needle-runtime.d.ts.map +1 -0
- package/dist/core/models/needle-runtime.js +519 -0
- package/dist/core/models/needle-runtime.js.map +1 -0
- package/dist/core/models/prism-llamacpp-lifecycle.d.ts +89 -0
- package/dist/core/models/prism-llamacpp-lifecycle.d.ts.map +1 -0
- package/dist/core/models/prism-llamacpp-lifecycle.js +121 -0
- package/dist/core/models/prism-llamacpp-lifecycle.js.map +1 -0
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +11 -10
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/process-matrix/codes.d.ts +72 -0
- package/dist/core/process-matrix/codes.d.ts.map +1 -0
- package/dist/core/process-matrix/codes.js +15 -0
- package/dist/core/process-matrix/codes.js.map +1 -0
- package/dist/core/process-matrix/runtime.d.ts +63 -0
- package/dist/core/process-matrix/runtime.d.ts.map +1 -0
- package/dist/core/process-matrix/runtime.js +310 -0
- package/dist/core/process-matrix/runtime.js.map +1 -0
- package/dist/core/process-matrix/store.d.ts +22 -0
- package/dist/core/process-matrix/store.d.ts.map +1 -0
- package/dist/core/process-matrix/store.js +80 -0
- package/dist/core/process-matrix/store.js.map +1 -0
- package/dist/core/process-matrix/supervisor.d.ts +72 -0
- package/dist/core/process-matrix/supervisor.d.ts.map +1 -0
- package/dist/core/process-matrix/supervisor.js +130 -0
- package/dist/core/process-matrix/supervisor.js.map +1 -0
- package/dist/core/profile-registry.d.ts +7 -0
- package/dist/core/profile-registry.d.ts.map +1 -1
- package/dist/core/profile-registry.js +20 -0
- package/dist/core/profile-registry.js.map +1 -1
- package/dist/core/python-runtime.d.ts.map +1 -1
- package/dist/core/python-runtime.js +3 -3
- package/dist/core/python-runtime.js.map +1 -1
- package/dist/core/reflection-controller.d.ts +29 -5
- package/dist/core/reflection-controller.d.ts.map +1 -1
- package/dist/core/reflection-controller.js +215 -126
- package/dist/core/reflection-controller.js.map +1 -1
- package/dist/core/reload-blockers.d.ts +36 -0
- package/dist/core/reload-blockers.d.ts.map +1 -1
- package/dist/core/reload-blockers.js +44 -0
- package/dist/core/reload-blockers.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +8 -7
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/runtime-builder.d.ts +58 -5
- package/dist/core/runtime-builder.d.ts.map +1 -1
- package/dist/core/runtime-builder.js +209 -25
- package/dist/core/runtime-builder.js.map +1 -1
- package/dist/core/scout-controller.d.ts +6 -0
- package/dist/core/scout-controller.d.ts.map +1 -1
- package/dist/core/scout-controller.js +66 -52
- package/dist/core/scout-controller.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +3 -3
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-role.d.ts +31 -0
- package/dist/core/session-role.d.ts.map +1 -0
- package/dist/core/session-role.js +52 -0
- package/dist/core/session-role.js.map +1 -0
- package/dist/core/settings-manager.d.ts +42 -3
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +94 -60
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/system-prompt-builder.d.ts +12 -0
- package/dist/core/system-prompt-builder.d.ts.map +1 -1
- package/dist/core/system-prompt-builder.js +6 -0
- package/dist/core/system-prompt-builder.js.map +1 -1
- package/dist/core/system-prompt.d.ts +14 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +20 -3
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tasks/session-task-state.d.ts +11 -2
- package/dist/core/tasks/session-task-state.d.ts.map +1 -1
- package/dist/core/tasks/session-task-state.js +27 -11
- package/dist/core/tasks/session-task-state.js.map +1 -1
- package/dist/core/tasks/task-contract-monitor.d.ts +45 -0
- package/dist/core/tasks/task-contract-monitor.d.ts.map +1 -0
- package/dist/core/tasks/task-contract-monitor.js +56 -0
- package/dist/core/tasks/task-contract-monitor.js.map +1 -0
- package/dist/core/tasks/task-state.d.ts +8 -0
- package/dist/core/tasks/task-state.d.ts.map +1 -1
- package/dist/core/tasks/task-state.js +28 -1
- package/dist/core/tasks/task-state.js.map +1 -1
- package/dist/core/tool-gate-controller.d.ts.map +1 -1
- package/dist/core/tool-gate-controller.js +5 -0
- package/dist/core/tool-gate-controller.js.map +1 -1
- package/dist/core/tool-recovery-log-records.d.ts +7 -0
- package/dist/core/tool-recovery-log-records.d.ts.map +1 -1
- package/dist/core/tool-recovery-log-records.js +14 -6
- package/dist/core/tool-recovery-log-records.js.map +1 -1
- package/dist/core/tool-selection/promotion.d.ts +54 -0
- package/dist/core/tool-selection/promotion.d.ts.map +1 -0
- package/dist/core/tool-selection/promotion.js +81 -0
- package/dist/core/tool-selection/promotion.js.map +1 -0
- package/dist/core/tool-selection/tool-performance-store.d.ts +37 -0
- package/dist/core/tool-selection/tool-performance-store.d.ts.map +1 -1
- package/dist/core/tool-selection/tool-performance-store.js +87 -3
- package/dist/core/tool-selection/tool-performance-store.js.map +1 -1
- package/dist/core/tool-selection/tool-selection-controller.d.ts +45 -0
- package/dist/core/tool-selection/tool-selection-controller.d.ts.map +1 -1
- package/dist/core/tool-selection/tool-selection-controller.js +96 -0
- package/dist/core/tool-selection/tool-selection-controller.js.map +1 -1
- package/dist/core/tools/bash.d.ts +18 -0
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +95 -16
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/delegate-status.d.ts +14 -0
- package/dist/core/tools/delegate-status.d.ts.map +1 -1
- package/dist/core/tools/delegate-status.js +82 -7
- package/dist/core/tools/delegate-status.js.map +1 -1
- package/dist/core/tools/delegate.d.ts.map +1 -1
- package/dist/core/tools/delegate.js +25 -8
- package/dist/core/tools/delegate.js.map +1 -1
- package/dist/core/tools/goal.d.ts +94 -3
- package/dist/core/tools/goal.d.ts.map +1 -1
- package/dist/core/tools/goal.js +165 -15
- package/dist/core/tools/goal.js.map +1 -1
- package/dist/core/tools/model-fitness.d.ts +7 -0
- package/dist/core/tools/model-fitness.d.ts.map +1 -1
- package/dist/core/tools/model-fitness.js +2 -2
- package/dist/core/tools/model-fitness.js.map +1 -1
- package/dist/core/tools/shell-contract-router.d.ts +6 -1
- package/dist/core/tools/shell-contract-router.d.ts.map +1 -1
- package/dist/core/tools/shell-contract-router.js +23 -2
- package/dist/core/tools/shell-contract-router.js.map +1 -1
- package/dist/core/tools/shell-session.d.ts +89 -0
- package/dist/core/tools/shell-session.d.ts.map +1 -0
- package/dist/core/tools/shell-session.js +432 -0
- package/dist/core/tools/shell-session.js.map +1 -0
- package/dist/core/tools/task-steps.d.ts +4 -0
- package/dist/core/tools/task-steps.d.ts.map +1 -1
- package/dist/core/tools/task-steps.js +63 -8
- package/dist/core/tools/task-steps.js.map +1 -1
- package/dist/core/tools/tmux-dispatch.d.ts +86 -0
- package/dist/core/tools/tmux-dispatch.d.ts.map +1 -0
- package/dist/core/tools/tmux-dispatch.js +91 -0
- package/dist/core/tools/tmux-dispatch.js.map +1 -0
- package/dist/core/tools/windows-shell-engine.d.ts +42 -0
- package/dist/core/tools/windows-shell-engine.d.ts.map +1 -0
- package/dist/core/tools/windows-shell-engine.js +153 -0
- package/dist/core/tools/windows-shell-engine.js.map +1 -0
- package/dist/core/tools/windows-shell-state.d.ts +40 -0
- package/dist/core/tools/windows-shell-state.d.ts.map +1 -0
- package/dist/core/tools/windows-shell-state.js +59 -0
- package/dist/core/tools/windows-shell-state.js.map +1 -0
- package/dist/core/tools/worktree-sync.d.ts +24 -0
- package/dist/core/tools/worktree-sync.d.ts.map +1 -0
- package/dist/core/tools/worktree-sync.js +338 -0
- package/dist/core/tools/worktree-sync.js.map +1 -0
- package/dist/core/trust-manager.d.ts +4 -1
- package/dist/core/trust-manager.d.ts.map +1 -1
- package/dist/core/trust-manager.js +20 -2
- package/dist/core/trust-manager.js.map +1 -1
- package/dist/core/util/atomic-file.d.ts +55 -0
- package/dist/core/util/atomic-file.d.ts.map +1 -0
- package/dist/core/util/atomic-file.js +255 -0
- package/dist/core/util/atomic-file.js.map +1 -0
- package/dist/core/util/minimatch-cache.d.ts +33 -0
- package/dist/core/util/minimatch-cache.d.ts.map +1 -0
- package/dist/core/util/minimatch-cache.js +0 -0
- package/dist/core/util/minimatch-cache.js.map +1 -0
- package/dist/core/worktree-sync/codes.d.ts +227 -0
- package/dist/core/worktree-sync/codes.d.ts.map +1 -0
- package/dist/core/worktree-sync/codes.js +14 -0
- package/dist/core/worktree-sync/codes.js.map +1 -0
- package/dist/core/worktree-sync/git-engine.d.ts +156 -0
- package/dist/core/worktree-sync/git-engine.d.ts.map +1 -0
- package/dist/core/worktree-sync/git-engine.js +1191 -0
- package/dist/core/worktree-sync/git-engine.js.map +1 -0
- package/dist/core/worktree-sync/lane-gate.d.ts +75 -0
- package/dist/core/worktree-sync/lane-gate.d.ts.map +1 -0
- package/dist/core/worktree-sync/lane-gate.js +360 -0
- package/dist/core/worktree-sync/lane-gate.js.map +1 -0
- package/dist/core/worktree-sync/runtime.d.ts +47 -0
- package/dist/core/worktree-sync/runtime.d.ts.map +1 -0
- package/dist/core/worktree-sync/runtime.js +96 -0
- package/dist/core/worktree-sync/runtime.js.map +1 -0
- package/dist/core/worktree-sync/store.d.ts +69 -0
- package/dist/core/worktree-sync/store.d.ts.map +1 -0
- package/dist/core/worktree-sync/store.js +247 -0
- package/dist/core/worktree-sync/store.js.map +1 -0
- package/dist/core/worktree-sync/watcher.d.ts +29 -0
- package/dist/core/worktree-sync/watcher.d.ts.map +1 -0
- package/dist/core/worktree-sync/watcher.js +93 -0
- package/dist/core/worktree-sync/watcher.js.map +1 -0
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +94 -0
- package/dist/main.js.map +1 -1
- package/dist/migrations.d.ts +9 -0
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +38 -0
- package/dist/migrations.js.map +1 -1
- package/dist/modes/interactive/auto-learn-controller.d.ts +16 -1
- package/dist/modes/interactive/auto-learn-controller.d.ts.map +1 -1
- package/dist/modes/interactive/auto-learn-controller.js +50 -8
- package/dist/modes/interactive/auto-learn-controller.js.map +1 -1
- package/dist/modes/interactive/components/profile-resource-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/profile-resource-editor.js +23 -1
- package/dist/modes/interactive/components/profile-resource-editor.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +4 -0
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/local-model-commands.d.ts +43 -0
- package/dist/modes/interactive/local-model-commands.d.ts.map +1 -1
- package/dist/modes/interactive/local-model-commands.js +290 -3
- package/dist/modes/interactive/local-model-commands.js.map +1 -1
- package/dist/modes/interactive/session-flow-commands.d.ts.map +1 -1
- package/dist/modes/interactive/session-flow-commands.js +24 -4
- package/dist/modes/interactive/session-flow-commands.js.map +1 -1
- package/dist/utils/fs-watch.d.ts +11 -0
- package/dist/utils/fs-watch.d.ts.map +1 -1
- package/dist/utils/fs-watch.js +20 -2
- package/dist/utils/fs-watch.js.map +1 -1
- package/dist/utils/highlight-js-languages.d.ts +4 -0
- package/dist/utils/highlight-js-languages.d.ts.map +1 -0
- package/dist/utils/highlight-js-languages.js +573 -0
- package/dist/utils/highlight-js-languages.js.map +1 -0
- package/dist/utils/shell.d.ts +7 -1
- package/dist/utils/shell.d.ts.map +1 -1
- package/dist/utils/shell.js +21 -6
- package/dist/utils/shell.js.map +1 -1
- package/dist/utils/syntax-highlight.d.ts.map +1 -1
- package/dist/utils/syntax-highlight.js +53 -5
- package/dist/utils/syntax-highlight.js.map +1 -1
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +112 -1
- package/dist/utils/tools-manager.js.map +1 -1
- package/docs/process-matrix.md +120 -0
- package/docs/settings.md +3 -0
- package/docs/tmux-agent-manager.md +85 -2
- package/docs/windows.md +52 -3
- package/docs/work-directory.md +29 -0
- package/docs/worktree-sync.md +250 -0
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +12 -12
- package/package.json +10 -4
- package/docs/integration-sweep-builder-blueprint-2026-07-09.md +0 -365
- package/docs/integration-sweep-resume-2026-07-09.md +0 -407
|
@@ -1,19 +1,118 @@
|
|
|
1
|
-
import type {
|
|
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
|
-
|
|
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
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
const
|
|
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"]}
|