@gajae-code/coding-agent 0.11.1 → 0.11.3
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 +64 -0
- package/dist/types/cli/config-cli.d.ts +11 -1
- package/dist/types/cli/launch-disposition.d.ts +23 -0
- package/dist/types/cli/notify-cli.d.ts +1 -0
- package/dist/types/cli/session-picker.d.ts +2 -1
- package/dist/types/cli/setup-cli.d.ts +1 -1
- package/dist/types/commands/mcp-serve.d.ts +33 -0
- package/dist/types/commands/mcp.d.ts +1 -1
- package/dist/types/commands/notify.d.ts +0 -2
- package/dist/types/commands/sdk.d.ts +1 -1
- package/dist/types/config/atomic-yaml-patch.d.ts +18 -0
- package/dist/types/config/file-lock.d.ts +14 -4
- package/dist/types/config/keybindings.d.ts +42 -1
- package/dist/types/config/model-auth.d.ts +3 -0
- package/dist/types/config/model-bindings-applier.d.ts +13 -0
- package/dist/types/config/model-discovery-manager.d.ts +49 -0
- package/dist/types/config/model-equivalence.d.ts +20 -0
- package/dist/types/config/model-registry.d.ts +16 -15
- package/dist/types/config/model-resolver.d.ts +28 -18
- package/dist/types/config/models-config-schema.d.ts +11 -0
- package/dist/types/config/settings-schema.d.ts +141 -11
- package/dist/types/config/settings.d.ts +14 -11
- package/dist/types/coordinator-mcp/policy.d.ts +5 -0
- package/dist/types/coordinator-mcp/question-gate-codec.d.ts +129 -0
- package/dist/types/coordinator-mcp/question-state.d.ts +356 -0
- package/dist/types/coordinator-mcp/server.d.ts +4 -0
- package/dist/types/discovery/helpers.d.ts +0 -6
- package/dist/types/edit/index.d.ts +3 -0
- package/dist/types/eval/py/env.d.ts +9 -0
- package/dist/types/extensibility/extensions/loader.d.ts +2 -1
- package/dist/types/extensibility/extensions/runner.d.ts +2 -2
- package/dist/types/extensibility/extensions/types.d.ts +34 -3
- package/dist/types/extensibility/hooks/runner.d.ts +1 -1
- package/dist/types/extensibility/shared-events.d.ts +2 -0
- package/dist/types/gjc-runtime/deep-interview-recorder.d.ts +10 -1
- package/dist/types/gjc-runtime/deep-interview-state.d.ts +44 -0
- package/dist/types/gjc-runtime/goal-mode-request.d.ts +11 -1
- package/dist/types/gjc-runtime/launch-worktree.d.ts +4 -2
- package/dist/types/gjc-runtime/linux-proc.d.ts +29 -0
- package/dist/types/gjc-runtime/session-resolution.d.ts +2 -2
- package/dist/types/gjc-runtime/state-migrations.d.ts +1 -1
- package/dist/types/gjc-runtime/state-writer.d.ts +2 -1
- package/dist/types/gjc-runtime/team-launch.d.ts +59 -0
- package/dist/types/gjc-runtime/team-notify.d.ts +45 -0
- package/dist/types/gjc-runtime/team-runtime.d.ts +29 -121
- package/dist/types/gjc-runtime/team-store.d.ts +160 -0
- package/dist/types/gjc-runtime/team-workers.d.ts +78 -0
- package/dist/types/gjc-runtime/tmux-owner-isolation.d.ts +8 -0
- package/dist/types/gjc-runtime/ultragoal-change-set.d.ts +13 -0
- package/dist/types/gjc-runtime/ultragoal-evidence.d.ts +38 -0
- package/dist/types/gjc-runtime/ultragoal-guard.d.ts +7 -0
- package/dist/types/gjc-runtime/ultragoal-pipeline.d.ts +23 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +55 -33
- package/dist/types/gjc-runtime/workflow-cli-common.d.ts +8 -0
- package/dist/types/gjc-runtime/workflow-manifest.d.ts +3 -0
- package/dist/types/goals/continuation-timeout-guard.d.ts +22 -0
- package/dist/types/goals/runtime.d.ts +1 -0
- package/dist/types/goals/state.d.ts +8 -0
- package/dist/types/harness-control-plane/lifecycle-reconciliation.d.ts +17 -0
- package/dist/types/harness-control-plane/phase-rollup.d.ts +4 -7
- package/dist/types/harness-control-plane/receipt-ingest.d.ts +5 -0
- package/dist/types/harness-control-plane/receipt-spool.d.ts +4 -0
- package/dist/types/hindsight/state.d.ts +11 -4
- package/dist/types/lsp/lspmux.d.ts +5 -3
- package/dist/types/lsp/path-trust.d.ts +1 -0
- package/dist/types/main.d.ts +4 -2
- package/dist/types/memories/storage.d.ts +1 -0
- package/dist/types/modes/action-registry.d.ts +29 -0
- package/dist/types/modes/components/chrome.d.ts +14 -0
- package/dist/types/modes/components/command-palette.d.ts +27 -0
- package/dist/types/modes/components/custom-provider-wizard.d.ts +1 -0
- package/dist/types/modes/components/index.d.ts +2 -1
- package/dist/types/modes/components/pet-selector.d.ts +1 -1
- package/dist/types/modes/components/plan-preview-overlay.d.ts +43 -0
- package/dist/types/modes/components/queue-mode-selector.d.ts +1 -1
- package/dist/types/modes/components/queue-pane.d.ts +12 -0
- package/dist/types/modes/components/read-tool-group.d.ts +6 -0
- package/dist/types/modes/components/session-observer-overlay.d.ts +3 -4
- package/dist/types/modes/components/sessions-dashboard.d.ts +32 -0
- package/dist/types/modes/components/settings-selector.d.ts +1 -1
- package/dist/types/modes/components/show-images-selector.d.ts +1 -1
- package/dist/types/modes/components/status-line/types.d.ts +1 -1
- package/dist/types/modes/components/status-line.d.ts +1 -94
- package/dist/types/modes/components/tasks-pane.d.ts +15 -0
- package/dist/types/modes/components/theme-selector.d.ts +1 -1
- package/dist/types/modes/components/tool-execution.d.ts +15 -0
- package/dist/types/modes/components/tool-status-header.d.ts +111 -0
- package/dist/types/modes/components/transcript-viewer-overlay.d.ts +42 -0
- package/dist/types/modes/controllers/goal-mode-controller.d.ts +62 -0
- package/dist/types/modes/controllers/input-controller.d.ts +8 -1
- package/dist/types/modes/controllers/mode-gate.d.ts +8 -0
- package/dist/types/modes/controllers/plan-mode-controller.d.ts +65 -0
- package/dist/types/modes/controllers/selector-controller.d.ts +15 -3
- package/dist/types/modes/controllers/stt-controller.d.ts +26 -0
- package/dist/types/modes/interactive-mode.d.ts +19 -17
- package/dist/types/modes/jobs-observer.d.ts +2 -0
- package/dist/types/modes/prompt-action-autocomplete.d.ts +4 -0
- package/dist/types/modes/shared/agent-wire/deep-interview-gate.d.ts +4 -11
- package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +20 -2
- package/dist/types/modes/shared/agent-wire/workflow-gate-types.d.ts +31 -0
- package/dist/types/modes/tasks-aggregator.d.ts +39 -0
- package/dist/types/modes/transcript-item-registry.d.ts +60 -0
- package/dist/types/modes/types.d.ts +20 -13
- package/dist/types/modes/utils/ui-helpers.d.ts +2 -2
- package/dist/types/runtime-mcp/manager.d.ts +1 -1
- package/dist/types/sdk/broker/broker.d.ts +78 -12
- package/dist/types/sdk/broker/lifecycle-codec.d.ts +4 -0
- package/dist/types/sdk/broker/lifecycle-ledger.d.ts +15 -1
- package/dist/types/sdk/broker/lifecycle.d.ts +6 -2
- package/dist/types/sdk/broker/process-incarnation.d.ts +2 -0
- package/dist/types/sdk/broker/session-index.d.ts +0 -1
- package/dist/types/sdk/broker/state-version.d.ts +2 -0
- package/dist/types/sdk/bus/chat-effect-journal.d.ts +1 -0
- package/dist/types/sdk/bus/config-commands.d.ts +1 -1
- package/dist/types/sdk/bus/config.d.ts +11 -0
- package/dist/types/sdk/bus/daemon-paths.d.ts +1 -0
- package/dist/types/sdk/bus/html-format.d.ts +3 -2
- package/dist/types/sdk/bus/index.d.ts +29 -0
- package/dist/types/sdk/bus/lifecycle-control-runtime.d.ts +4 -0
- package/dist/types/sdk/bus/notification-service.d.ts +20 -0
- package/dist/types/sdk/bus/rate-limit-pool.d.ts +13 -2
- package/dist/types/sdk/bus/recent-activity.d.ts +21 -12
- package/dist/types/sdk/bus/rich-document.d.ts +7 -0
- package/dist/types/sdk/bus/rich-render.d.ts +18 -41
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +9 -4
- package/dist/types/sdk/bus/telegram-daemon.d.ts +46 -3
- package/dist/types/sdk/bus/threaded-inbound.d.ts +1 -1
- package/dist/types/sdk/bus/threaded-render.d.ts +13 -0
- package/dist/types/sdk/bus/topic-registry.d.ts +24 -2
- package/dist/types/sdk/host/control/operations.d.ts +1 -1
- package/dist/types/sdk/host/host.d.ts +2 -0
- package/dist/types/sdk/index.d.ts +1 -0
- package/dist/types/sdk/session-directory.d.ts +56 -0
- package/dist/types/sdk/session.d.ts +2 -0
- package/dist/types/session/agent-session.d.ts +82 -47
- package/dist/types/session/agent-storage.d.ts +7 -0
- package/dist/types/session/fallback-chain-controller.d.ts +10 -2
- package/dist/types/session/internal/managed-session-scope.d.ts +102 -0
- package/dist/types/session/internal/managed-session-storage.d.ts +38 -0
- package/dist/types/session/messages.d.ts +16 -0
- package/dist/types/session/session-manager-internal.d.ts +14 -0
- package/dist/types/session/session-manager.d.ts +82 -12
- package/dist/types/session/session-storage.d.ts +43 -3
- package/dist/types/session/volatile-context-pruning.d.ts +15 -0
- package/dist/types/skill-state/{deep-interview-mutation-guard.d.ts → workflow-mutation-guard.d.ts} +24 -8
- package/dist/types/skill-state/workflow-state-contract.d.ts +1 -3
- package/dist/types/slash-commands/builtin-registry.d.ts +4 -1
- package/dist/types/system-prompt.d.ts +2 -11
- package/dist/types/task/executor.d.ts +3 -1
- package/dist/types/thinking.d.ts +7 -0
- package/dist/types/tool-discovery/tool-index.d.ts +1 -50
- package/dist/types/tools/ask.d.ts +64 -2
- package/dist/types/tools/bash.d.ts +3 -0
- package/dist/types/tools/browser/dead-tab-recovery.d.ts +24 -0
- package/dist/types/tools/browser/tab-supervisor.d.ts +21 -0
- package/dist/types/tools/cron.d.ts +2 -0
- package/dist/types/tools/fetch.d.ts +1 -0
- package/dist/types/tools/index.d.ts +30 -15
- package/dist/types/tools/output-meta.d.ts +1 -0
- package/dist/types/tools/read.d.ts +5 -0
- package/dist/types/tools/search-tool-bm25.d.ts +3 -4
- package/dist/types/tools/subagent.d.ts +1 -0
- package/dist/types/utils/event-bus.d.ts +1 -1
- package/dist/types/utils/file-mentions.d.ts +3 -3
- package/dist/types/web/search/index.d.ts +3 -1
- package/package.json +21 -9
- package/scripts/build-sdk-package-smoke.ts +34 -1
- package/scripts/generate-hotkeys-docs.ts +74 -0
- package/scripts/generate-sdk-operation-inventory.ts +64 -20
- package/scripts/verify-gjc-sdk-canonicalization.ts +182 -2
- package/src/async/job-manager.ts +49 -6
- package/src/cli/config-cli.ts +75 -2
- package/src/cli/launch-disposition.ts +42 -0
- package/src/cli/notify-cli.ts +92 -26
- package/src/cli/session-picker.ts +20 -3
- package/src/cli/setup-cli.ts +1 -1
- package/src/cli.ts +1 -1
- package/src/commands/config.ts +1 -1
- package/src/commands/harness.ts +34 -106
- package/src/commands/launch.ts +6 -4
- package/src/commands/mcp-serve.ts +85 -8
- package/src/commands/mcp.ts +2 -2
- package/src/commands/notify.ts +8 -4
- package/src/commands/sdk.ts +61 -40
- package/src/commands/ultragoal.ts +4 -1
- package/src/config/atomic-yaml-patch.ts +80 -13
- package/src/config/file-lock.ts +105 -43
- package/src/config/keybindings.ts +64 -20
- package/src/config/model-auth.ts +9 -0
- package/src/config/model-bindings-applier.ts +139 -0
- package/src/config/model-discovery-manager.ts +224 -0
- package/src/config/model-equivalence.ts +66 -0
- package/src/config/model-registry.ts +169 -302
- package/src/config/model-resolver.ts +361 -369
- package/src/config/models-config-schema.ts +5 -4
- package/src/config/settings-schema.ts +214 -12
- package/src/config/settings.ts +458 -482
- package/src/coordinator-mcp/policy.ts +76 -11
- package/src/coordinator-mcp/question-gate-codec.ts +274 -0
- package/src/coordinator-mcp/question-state.ts +778 -0
- package/src/coordinator-mcp/server.ts +1702 -238
- package/src/debug/index.ts +1 -1
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +13 -1
- package/src/defaults/gjc/skills/team/SKILL.md +16 -0
- package/src/discovery/helpers.ts +1 -50
- package/src/edit/index.ts +64 -0
- package/src/eval/py/env.ts +26 -0
- package/src/eval/py/kernel.ts +5 -3
- package/src/extensibility/extensions/loader.ts +9 -1
- package/src/extensibility/extensions/runner.ts +12 -3
- package/src/extensibility/extensions/types.ts +39 -1
- package/src/extensibility/gjc-plugins/installer.ts +16 -16
- package/src/extensibility/hooks/runner.ts +2 -2
- package/src/extensibility/runtime-skill-discovery.ts +33 -13
- package/src/extensibility/shared-events.ts +2 -0
- package/src/gjc-runtime/deep-interview-recorder.ts +63 -3
- package/src/gjc-runtime/deep-interview-runtime.ts +76 -27
- package/src/gjc-runtime/deep-interview-state.ts +317 -5
- package/src/gjc-runtime/goal-mode-request.ts +55 -8
- package/src/gjc-runtime/launch-tmux.ts +2 -5
- package/src/gjc-runtime/launch-worktree.ts +5 -5
- package/src/gjc-runtime/linux-proc.ts +71 -0
- package/src/gjc-runtime/ralplan-runtime.ts +74 -90
- package/src/gjc-runtime/session-resolution.ts +18 -3
- package/src/gjc-runtime/session-state-sidecar.ts +6 -107
- package/src/gjc-runtime/state-migrations.ts +1 -1
- package/src/gjc-runtime/state-runtime.ts +327 -249
- package/src/gjc-runtime/state-writer.ts +36 -40
- package/src/gjc-runtime/team-launch.ts +319 -0
- package/src/gjc-runtime/team-notify.ts +326 -0
- package/src/gjc-runtime/team-runtime.ts +1099 -1482
- package/src/gjc-runtime/team-store.ts +828 -0
- package/src/gjc-runtime/team-workers.ts +962 -0
- package/src/gjc-runtime/tmux-owner-isolation-cli.ts +2 -11
- package/src/gjc-runtime/tmux-owner-isolation.ts +14 -9
- package/src/gjc-runtime/tmux-sessions.ts +4 -21
- package/src/gjc-runtime/ultragoal-change-set.ts +172 -0
- package/src/gjc-runtime/ultragoal-evidence.ts +874 -0
- package/src/gjc-runtime/ultragoal-guard.ts +29 -5
- package/src/gjc-runtime/ultragoal-pipeline.ts +306 -0
- package/src/gjc-runtime/ultragoal-runtime.ts +84 -1311
- package/src/gjc-runtime/workflow-cli-common.ts +30 -0
- package/src/gjc-runtime/workflow-manifest.generated.json +58 -0
- package/src/gjc-runtime/workflow-manifest.ts +18 -0
- package/src/goals/continuation-timeout-guard.ts +79 -0
- package/src/goals/runtime.ts +7 -5
- package/src/goals/state.ts +18 -0
- package/src/harness-control-plane/lifecycle-reconciliation.ts +64 -0
- package/src/harness-control-plane/phase-rollup.ts +4 -7
- package/src/harness-control-plane/receipt-ingest.ts +5 -0
- package/src/harness-control-plane/receipt-spool.ts +51 -7
- package/src/harness-control-plane/session-lease.ts +12 -130
- package/src/hindsight/backend.ts +26 -27
- package/src/hindsight/state.ts +101 -32
- package/src/hooks/skill-state.ts +17 -11
- package/src/internal-urls/docs-index.generated.ts +21 -18
- package/src/lsp/client.ts +1 -1
- package/src/lsp/config.ts +145 -26
- package/src/lsp/index.ts +1 -1
- package/src/lsp/lspmux.ts +39 -10
- package/src/lsp/path-trust.ts +81 -0
- package/src/main.ts +127 -30
- package/src/memories/index.ts +1 -0
- package/src/memories/storage.ts +6 -2
- package/src/modes/action-registry.ts +165 -0
- package/src/modes/components/chrome.ts +40 -0
- package/src/modes/components/command-palette.ts +168 -0
- package/src/modes/components/custom-editor.ts +1 -1
- package/src/modes/components/custom-provider-wizard.ts +51 -14
- package/src/modes/components/index.ts +2 -1
- package/src/modes/components/pet-selector.ts +11 -17
- package/src/modes/components/plan-preview-overlay.ts +295 -0
- package/src/modes/components/queue-mode-selector.ts +10 -27
- package/src/modes/components/queue-pane.ts +79 -0
- package/src/modes/components/read-tool-group.ts +13 -0
- package/src/modes/components/session-observer-overlay.ts +207 -772
- package/src/modes/components/sessions-dashboard.ts +181 -0
- package/src/modes/components/settings-selector.ts +1 -1
- package/src/modes/components/show-images-selector.ts +10 -24
- package/src/modes/components/status-line/types.ts +1 -1
- package/src/modes/components/status-line.ts +1 -969
- package/src/modes/components/tasks-pane.ts +73 -0
- package/src/modes/components/theme-selector.ts +11 -31
- package/src/modes/components/tool-execution.ts +22 -0
- package/src/modes/components/tool-status-header.ts +1056 -0
- package/src/modes/components/transcript-viewer-overlay.ts +384 -0
- package/src/modes/controllers/btw-controller.ts +1 -0
- package/src/modes/controllers/event-controller.ts +3 -2
- package/src/modes/controllers/extension-ui-controller.ts +24 -1
- package/src/modes/controllers/goal-mode-controller.ts +474 -0
- package/src/modes/controllers/input-controller.ts +764 -229
- package/src/modes/controllers/mode-gate.ts +24 -0
- package/src/modes/controllers/plan-mode-controller.ts +517 -0
- package/src/modes/controllers/selector-controller.ts +225 -10
- package/src/modes/controllers/stt-controller.ts +125 -0
- package/src/modes/interactive-mode.ts +289 -1150
- package/src/modes/jobs-observer.ts +3 -0
- package/src/modes/prompt-action-autocomplete.ts +7 -0
- package/src/modes/runtime-init.ts +8 -0
- package/src/modes/shared/agent-wire/deep-interview-gate.ts +31 -106
- package/src/modes/shared/agent-wire/workflow-gate-broker.ts +71 -16
- package/src/modes/shared/agent-wire/workflow-gate-types.ts +177 -0
- package/src/modes/tasks-aggregator.ts +199 -0
- package/src/modes/transcript-item-registry.ts +229 -0
- package/src/modes/types.ts +45 -18
- package/src/modes/utils/ui-helpers.ts +17 -9
- package/src/prompts/agent-fragments/ralplan-persistence.md +6 -0
- package/src/prompts/agent-fragments/restricted-bash.md +1 -0
- package/src/prompts/agents/architect.md +2 -8
- package/src/prompts/agents/critic.md +2 -8
- package/src/prompts/agents/executor.md +3 -0
- package/src/prompts/agents/planner.md +4 -12
- package/src/prompts/system/custom-system-prompt.md +1 -23
- package/src/prompts/system/plan-mode-approved.md +8 -0
- package/src/prompts/system/system-prompt.md +17 -96
- package/src/prompts/tools/bash.md +4 -4
- package/src/prompts/tools/browser.md +15 -52
- package/src/prompts/tools/find.md +2 -2
- package/src/prompts/tools/hashline.md +13 -55
- package/src/prompts/tools/read.md +3 -6
- package/src/prompts/tools/search-tool-bm25.md +0 -2
- package/src/prompts/tools/search.md +2 -4
- package/src/prompts/tools/skill-discovery.md +1 -2
- package/src/prompts/tools/task.md +1 -1
- package/src/runtime-mcp/manager.ts +1 -1
- package/src/sdk/broker/broker.ts +206 -78
- package/src/sdk/broker/discovery.ts +1 -1
- package/src/sdk/broker/ensure.ts +3 -1
- package/src/sdk/broker/lifecycle-codec.ts +11 -0
- package/src/sdk/broker/lifecycle-ledger.ts +371 -74
- package/src/sdk/broker/lifecycle.ts +1399 -142
- package/src/sdk/broker/process-incarnation.ts +5 -13
- package/src/sdk/broker/session-index.ts +145 -56
- package/src/sdk/broker/state-version.ts +21 -0
- package/src/sdk/broker/transport.ts +1 -1
- package/src/sdk/bus/chat-daemon-cli.ts +2 -0
- package/src/sdk/bus/chat-daemon-control.ts +8 -28
- package/src/sdk/bus/chat-effect-journal.ts +10 -2
- package/src/sdk/bus/config-commands.ts +5 -4
- package/src/sdk/bus/config.ts +98 -0
- package/src/sdk/bus/conversation-store.ts +5 -29
- package/src/sdk/bus/daemon-paths.ts +2 -0
- package/src/sdk/bus/html-format.ts +20 -3
- package/src/sdk/bus/index.ts +782 -94
- package/src/sdk/bus/lifecycle-control-runtime.ts +91 -33
- package/src/sdk/bus/natives-augment.d.ts +26 -1
- package/src/sdk/bus/notification-service.ts +168 -20
- package/src/sdk/bus/rate-limit-pool.ts +58 -14
- package/src/sdk/bus/recent-activity.ts +188 -74
- package/src/sdk/bus/rich-document.ts +258 -0
- package/src/sdk/bus/rich-render.ts +62 -70
- package/src/sdk/bus/telegram-daemon-cli.ts +15 -59
- package/src/sdk/bus/telegram-daemon-contract.ts +9 -4
- package/src/sdk/bus/telegram-daemon.ts +1389 -237
- package/src/sdk/bus/threaded-inbound.ts +8 -3
- package/src/sdk/bus/threaded-render.ts +57 -1
- package/src/sdk/bus/topic-registry.ts +120 -13
- package/src/sdk/host/control/dispatch.ts +14 -2
- package/src/sdk/host/control/operations.ts +6 -1
- package/src/sdk/host/host.ts +44 -2
- package/src/sdk/host/query/handlers.ts +20 -22
- package/src/sdk/host/query/revision-store.ts +80 -57
- package/src/sdk/index.ts +1 -0
- package/src/sdk/protocol/operation-inventory.generated.json +943 -1907
- package/src/sdk/session-directory.ts +141 -0
- package/src/sdk/session.ts +462 -480
- package/src/session/agent-session.ts +1700 -583
- package/src/session/agent-storage.ts +18 -0
- package/src/session/cache-economics.ts +25 -8
- package/src/session/fallback-chain-controller.ts +53 -3
- package/src/session/internal/managed-session-scope.ts +2226 -0
- package/src/session/internal/managed-session-storage.ts +453 -0
- package/src/session/messages.ts +91 -2
- package/src/session/session-manager-internal.ts +33 -0
- package/src/session/session-manager.ts +1112 -333
- package/src/session/session-storage.ts +444 -39
- package/src/session/volatile-context-pruning.ts +78 -0
- package/src/setup/credential-auto-import.ts +2 -1
- package/src/setup/hermes/templates/operator-instructions.v1.md +1 -1
- package/src/setup/provider-onboarding.ts +36 -61
- package/src/setup/provider-presets.json +5 -0
- package/src/skill-state/active-state.ts +3 -13
- package/src/skill-state/{deep-interview-mutation-guard.ts → workflow-mutation-guard.ts} +47 -29
- package/src/skill-state/workflow-state-contract.ts +6 -41
- package/src/slash-commands/builtin-registry.ts +46 -11
- package/src/system-prompt.ts +37 -44
- package/src/task/agents.ts +19 -1
- package/src/task/executor.ts +90 -6
- package/src/task/index.ts +36 -21
- package/src/thinking.ts +21 -6
- package/src/tool-discovery/tool-index.ts +2 -134
- package/src/tools/ask.ts +157 -21
- package/src/tools/ast-edit.ts +1 -1
- package/src/tools/bash.ts +38 -0
- package/src/tools/browser/dead-tab-recovery.ts +78 -0
- package/src/tools/browser/tab-supervisor.ts +282 -36
- package/src/tools/computer.ts +10 -3
- package/src/tools/cron.ts +30 -16
- package/src/tools/eval.ts +1 -2
- package/src/tools/fetch.ts +11 -4
- package/src/tools/index.ts +76 -24
- package/src/tools/output-meta.ts +19 -7
- package/src/tools/read.ts +219 -64
- package/src/tools/resource-gc.ts +2 -2
- package/src/tools/search-tool-bm25.ts +11 -74
- package/src/tools/subagent.ts +43 -2
- package/src/utils/event-bus.ts +9 -4
- package/src/utils/file-mentions.ts +4 -4
- package/src/web/search/index.ts +3 -3
- package/dist/types/discovery/plugin-dir-roots.d.ts +0 -15
- package/dist/types/runtime-mcp/discoverable-tool-metadata.d.ts +0 -7
- package/src/discovery/plugin-dir-roots.ts +0 -28
- package/src/runtime-mcp/discoverable-tool-metadata.ts +0 -25
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export class CommandError extends Error {
|
|
2
|
+
constructor(
|
|
3
|
+
public readonly exitStatus: number,
|
|
4
|
+
message: string,
|
|
5
|
+
) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = "CommandError";
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function flagValue(args: readonly string[], flag: string): string | undefined {
|
|
12
|
+
const index = args.indexOf(flag);
|
|
13
|
+
return index < 0 ? undefined : args[index + 1];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function hasFlag(args: readonly string[], flag: string): boolean {
|
|
17
|
+
return args.includes(flag);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function isPlainObject(value: unknown): value is Record<string, unknown> {
|
|
21
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const PATH_COMPONENT_RE = /^[A-Za-z0-9_-][A-Za-z0-9._-]{0,63}$/;
|
|
25
|
+
|
|
26
|
+
export function assertSafePathComponent(value: string, label: string): void {
|
|
27
|
+
if (!PATH_COMPONENT_RE.test(value) || value.includes("..")) {
|
|
28
|
+
throw new CommandError(2, `invalid path component for --${label}: ${value}`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"deep-interview": {
|
|
3
|
+
"canonicalOverrides": [],
|
|
3
4
|
"graphLabel": "Deep Interview",
|
|
4
5
|
"hudFields": [
|
|
5
6
|
"current_phase",
|
|
@@ -10,6 +11,7 @@
|
|
|
10
11
|
"topology"
|
|
11
12
|
],
|
|
12
13
|
"initialState": "interviewing",
|
|
14
|
+
"phaseLock": [],
|
|
13
15
|
"retention": [
|
|
14
16
|
{
|
|
15
17
|
"category": "state",
|
|
@@ -42,6 +44,14 @@
|
|
|
42
44
|
"terminal": true
|
|
43
45
|
}
|
|
44
46
|
],
|
|
47
|
+
"stopReleasingPhases": [
|
|
48
|
+
"complete",
|
|
49
|
+
"completed",
|
|
50
|
+
"failed",
|
|
51
|
+
"cancelled",
|
|
52
|
+
"canceled",
|
|
53
|
+
"inactive"
|
|
54
|
+
],
|
|
45
55
|
"terminalStates": [
|
|
46
56
|
"handoff",
|
|
47
57
|
"complete"
|
|
@@ -318,6 +328,16 @@
|
|
|
318
328
|
]
|
|
319
329
|
},
|
|
320
330
|
"ralplan": {
|
|
331
|
+
"canonicalOverrides": [
|
|
332
|
+
"final",
|
|
333
|
+
"handoff",
|
|
334
|
+
"complete",
|
|
335
|
+
"completed",
|
|
336
|
+
"failed",
|
|
337
|
+
"cancelled",
|
|
338
|
+
"canceled",
|
|
339
|
+
"inactive"
|
|
340
|
+
],
|
|
321
341
|
"graphLabel": "Ralplan",
|
|
322
342
|
"hudFields": [
|
|
323
343
|
"current_phase",
|
|
@@ -328,6 +348,16 @@
|
|
|
328
348
|
"plan_path"
|
|
329
349
|
],
|
|
330
350
|
"initialState": "planner",
|
|
351
|
+
"phaseLock": [
|
|
352
|
+
"final",
|
|
353
|
+
"handoff",
|
|
354
|
+
"complete",
|
|
355
|
+
"completed",
|
|
356
|
+
"failed",
|
|
357
|
+
"cancelled",
|
|
358
|
+
"canceled",
|
|
359
|
+
"inactive"
|
|
360
|
+
],
|
|
331
361
|
"retention": [
|
|
332
362
|
{
|
|
333
363
|
"category": "state",
|
|
@@ -378,6 +408,14 @@
|
|
|
378
408
|
"terminal": true
|
|
379
409
|
}
|
|
380
410
|
],
|
|
411
|
+
"stopReleasingPhases": [
|
|
412
|
+
"complete",
|
|
413
|
+
"completed",
|
|
414
|
+
"failed",
|
|
415
|
+
"cancelled",
|
|
416
|
+
"canceled",
|
|
417
|
+
"inactive"
|
|
418
|
+
],
|
|
381
419
|
"terminalStates": [
|
|
382
420
|
"final",
|
|
383
421
|
"handoff"
|
|
@@ -704,6 +742,7 @@
|
|
|
704
742
|
]
|
|
705
743
|
},
|
|
706
744
|
"team": {
|
|
745
|
+
"canonicalOverrides": [],
|
|
707
746
|
"graphLabel": "Team",
|
|
708
747
|
"hudFields": [
|
|
709
748
|
"current_phase",
|
|
@@ -714,6 +753,7 @@
|
|
|
714
753
|
"integration"
|
|
715
754
|
],
|
|
716
755
|
"initialState": "starting",
|
|
756
|
+
"phaseLock": [],
|
|
717
757
|
"retention": [
|
|
718
758
|
{
|
|
719
759
|
"category": "state",
|
|
@@ -774,6 +814,14 @@
|
|
|
774
814
|
"terminal": true
|
|
775
815
|
}
|
|
776
816
|
],
|
|
817
|
+
"stopReleasingPhases": [
|
|
818
|
+
"complete",
|
|
819
|
+
"completed",
|
|
820
|
+
"failed",
|
|
821
|
+
"cancelled",
|
|
822
|
+
"canceled",
|
|
823
|
+
"inactive"
|
|
824
|
+
],
|
|
777
825
|
"terminalStates": [
|
|
778
826
|
"complete",
|
|
779
827
|
"failed",
|
|
@@ -1150,6 +1198,7 @@
|
|
|
1150
1198
|
]
|
|
1151
1199
|
},
|
|
1152
1200
|
"ultragoal": {
|
|
1201
|
+
"canonicalOverrides": [],
|
|
1153
1202
|
"graphLabel": "Ultragoal",
|
|
1154
1203
|
"hudFields": [
|
|
1155
1204
|
"current_phase",
|
|
@@ -1160,6 +1209,7 @@
|
|
|
1160
1209
|
"brief_path"
|
|
1161
1210
|
],
|
|
1162
1211
|
"initialState": "goal-planning",
|
|
1212
|
+
"phaseLock": [],
|
|
1163
1213
|
"retention": [
|
|
1164
1214
|
{
|
|
1165
1215
|
"category": "state",
|
|
@@ -1212,6 +1262,14 @@
|
|
|
1212
1262
|
"terminal": true
|
|
1213
1263
|
}
|
|
1214
1264
|
],
|
|
1265
|
+
"stopReleasingPhases": [
|
|
1266
|
+
"complete",
|
|
1267
|
+
"completed",
|
|
1268
|
+
"failed",
|
|
1269
|
+
"cancelled",
|
|
1270
|
+
"canceled",
|
|
1271
|
+
"inactive"
|
|
1272
|
+
],
|
|
1215
1273
|
"terminalStates": [
|
|
1216
1274
|
"missing",
|
|
1217
1275
|
"failed",
|
|
@@ -52,6 +52,9 @@ export interface SkillManifest {
|
|
|
52
52
|
retention: RetentionPolicy[];
|
|
53
53
|
hudFields: string[];
|
|
54
54
|
graphLabel: string;
|
|
55
|
+
stopReleasingPhases: readonly string[];
|
|
56
|
+
phaseLock: readonly string[];
|
|
57
|
+
canonicalOverrides: readonly string[];
|
|
55
58
|
}
|
|
56
59
|
|
|
57
60
|
const STATE_RETENTION: RetentionPolicy = { category: "state", keep: 1 };
|
|
@@ -116,6 +119,9 @@ function manifest(input: {
|
|
|
116
119
|
retention: RetentionPolicy[];
|
|
117
120
|
hudFields: string[];
|
|
118
121
|
graphLabel: string;
|
|
122
|
+
stopReleasingPhases?: readonly string[];
|
|
123
|
+
phaseLock?: readonly string[];
|
|
124
|
+
canonicalOverrides?: readonly string[];
|
|
119
125
|
initialState?: string;
|
|
120
126
|
}): SkillManifest {
|
|
121
127
|
const staleInitialState = initialPhaseForSkill(input.skill);
|
|
@@ -131,6 +137,16 @@ function manifest(input: {
|
|
|
131
137
|
retention: input.retention,
|
|
132
138
|
hudFields: input.hudFields,
|
|
133
139
|
graphLabel: input.graphLabel,
|
|
140
|
+
stopReleasingPhases: input.stopReleasingPhases ?? [
|
|
141
|
+
"complete",
|
|
142
|
+
"completed",
|
|
143
|
+
"failed",
|
|
144
|
+
"cancelled",
|
|
145
|
+
"canceled",
|
|
146
|
+
"inactive",
|
|
147
|
+
],
|
|
148
|
+
phaseLock: input.phaseLock ?? [],
|
|
149
|
+
canonicalOverrides: input.canonicalOverrides ?? [],
|
|
134
150
|
};
|
|
135
151
|
}
|
|
136
152
|
|
|
@@ -207,6 +223,8 @@ export const WORKFLOW_MANIFEST: Record<CanonicalGjcWorkflowSkill, SkillManifest>
|
|
|
207
223
|
retention: [STATE_RETENTION, ARTIFACT_RETENTION, LEDGER_RETENTION, PRUNE_RETENTION, FORCE_RETENTION],
|
|
208
224
|
hudFields: ["current_phase", "mode", "run_id", "stage", "stage_n", "plan_path"],
|
|
209
225
|
graphLabel: "Ralplan",
|
|
226
|
+
phaseLock: ["final", "handoff", "complete", "completed", "failed", "cancelled", "canceled", "inactive"],
|
|
227
|
+
canonicalOverrides: ["final", "handoff", "complete", "completed", "failed", "cancelled", "canceled", "inactive"],
|
|
210
228
|
}),
|
|
211
229
|
ultragoal: manifest({
|
|
212
230
|
skill: "ultragoal",
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
export type ToolOutcomeKind = "timeout" | "success" | "other-error";
|
|
2
|
+
|
|
3
|
+
export interface TimeoutToolOutcome {
|
|
4
|
+
toolName: string;
|
|
5
|
+
argsKey: string;
|
|
6
|
+
kind: ToolOutcomeKind;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface TimeoutHoldState {
|
|
10
|
+
heldSnapshotKey?: string;
|
|
11
|
+
fingerprint?: string;
|
|
12
|
+
streak: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
16
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function canonicalizeArgs(value: unknown): unknown {
|
|
20
|
+
if (Array.isArray(value)) {
|
|
21
|
+
return value.map(item => canonicalizeArgs(item));
|
|
22
|
+
}
|
|
23
|
+
if (isRecord(value)) {
|
|
24
|
+
const canonical: Record<string, unknown> = {};
|
|
25
|
+
for (const key of Object.keys(value).sort()) {
|
|
26
|
+
if (value[key] !== undefined) {
|
|
27
|
+
canonical[key] = canonicalizeArgs(value[key]);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return canonical;
|
|
31
|
+
}
|
|
32
|
+
return value;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function toResultText(result: unknown): string {
|
|
36
|
+
if (typeof result === "string") return result;
|
|
37
|
+
if (!isRecord(result) || !Array.isArray(result.content)) return "";
|
|
38
|
+
return result.content
|
|
39
|
+
.filter(
|
|
40
|
+
(content): content is { type: "text"; text: string } =>
|
|
41
|
+
isRecord(content) && content.type === "text" && typeof content.text === "string",
|
|
42
|
+
)
|
|
43
|
+
.map(content => content.text)
|
|
44
|
+
.join("\n");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function classifyToolOutcome(isError: unknown, text: string): ToolOutcomeKind {
|
|
48
|
+
if (isError !== true) return "success";
|
|
49
|
+
return /\btimed out\b|\btimeout\b/i.test(text) ? "timeout" : "other-error";
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function canonicalArgsKey(args: unknown): string {
|
|
53
|
+
return JSON.stringify(canonicalizeArgs(args ?? null)) ?? "null";
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function turnTimeoutFingerprint(outcomes: readonly TimeoutToolOutcome[]): string | null {
|
|
57
|
+
if (outcomes.length === 0 || outcomes.some(outcome => outcome.kind !== "timeout")) return null;
|
|
58
|
+
const [first] = outcomes;
|
|
59
|
+
if (!first || outcomes.some(outcome => outcome.toolName !== first.toolName || outcome.argsKey !== first.argsKey)) {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
return `${first.toolName}\u0000${first.argsKey}`;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function decideTimeoutHold(
|
|
66
|
+
prev: TimeoutHoldState,
|
|
67
|
+
turn: { snapshotKey: string; fingerprint: string | null },
|
|
68
|
+
): { hold: boolean; next: TimeoutHoldState } {
|
|
69
|
+
if (turn.fingerprint === null) {
|
|
70
|
+
return { hold: false, next: { heldSnapshotKey: undefined, fingerprint: undefined, streak: 0 } };
|
|
71
|
+
}
|
|
72
|
+
const continues =
|
|
73
|
+
prev.streak >= 1 && prev.fingerprint === turn.fingerprint && prev.heldSnapshotKey === turn.snapshotKey;
|
|
74
|
+
const streak = continues ? prev.streak + 1 : 1;
|
|
75
|
+
return {
|
|
76
|
+
hold: streak >= 2,
|
|
77
|
+
next: { heldSnapshotKey: turn.snapshotKey, fingerprint: turn.fingerprint, streak },
|
|
78
|
+
};
|
|
79
|
+
}
|
package/src/goals/runtime.ts
CHANGED
|
@@ -294,28 +294,30 @@ export class GoalRuntime {
|
|
|
294
294
|
await this.#withAccounting(() => this.#flushUsageLocked(currentUsage));
|
|
295
295
|
}
|
|
296
296
|
|
|
297
|
-
#createGoalState(objective: string): GoalModeState {
|
|
297
|
+
#createGoalState(input: { objective: string; provenance?: Goal["provenance"] }): GoalModeState {
|
|
298
298
|
const now = this.#now();
|
|
299
299
|
const goal: Goal = {
|
|
300
300
|
id: String(Snowflake.next()),
|
|
301
|
-
objective,
|
|
301
|
+
objective: input.objective,
|
|
302
302
|
status: "active",
|
|
303
303
|
tokensUsed: 0,
|
|
304
304
|
timeUsedSeconds: 0,
|
|
305
305
|
createdAt: now,
|
|
306
306
|
updatedAt: now,
|
|
307
|
+
...(input.provenance ? { provenance: input.provenance } : {}),
|
|
307
308
|
};
|
|
308
309
|
return { enabled: true, mode: "active", goal };
|
|
309
310
|
}
|
|
310
311
|
|
|
311
|
-
async createGoal(input: { objective: string }): Promise<GoalModeState> {
|
|
312
|
+
async createGoal(input: { objective: string; provenance?: Goal["provenance"] }): Promise<GoalModeState> {
|
|
312
313
|
const objective = validateGoalObjective(input.objective, "create");
|
|
313
314
|
return await this.#withAccounting(async () => {
|
|
314
315
|
const existing = this.#getStateClone();
|
|
315
316
|
if (existing?.goal && existing.goal.status !== "dropped" && existing.goal.status !== "complete") {
|
|
316
317
|
throw new Error("cannot create a new goal because this session already has a goal");
|
|
317
318
|
}
|
|
318
|
-
const state = this.#createGoalState(objective);
|
|
319
|
+
const state = this.#createGoalState({ objective, provenance: input.provenance ?? { source: "user" } });
|
|
320
|
+
|
|
319
321
|
this.#markActiveAccounting(state.goal);
|
|
320
322
|
await this.#commitState(state, { persist: "goal" });
|
|
321
323
|
return state;
|
|
@@ -330,7 +332,7 @@ export class GoalRuntime {
|
|
|
330
332
|
throw new Error("cannot replace goal because no goal is active");
|
|
331
333
|
}
|
|
332
334
|
await this.#flushUsageLocked();
|
|
333
|
-
const state = this.#createGoalState(objective);
|
|
335
|
+
const state = this.#createGoalState({ objective, provenance: { source: "user" } });
|
|
334
336
|
this.#markActiveAccounting(state.goal);
|
|
335
337
|
await this.#commitState(state, { persist: "goal" });
|
|
336
338
|
return state;
|
package/src/goals/state.ts
CHANGED
|
@@ -2,6 +2,8 @@ import type { UsageStatistics } from "../session/session-manager";
|
|
|
2
2
|
|
|
3
3
|
export type GoalStatus = "active" | "paused" | "complete" | "dropped";
|
|
4
4
|
|
|
5
|
+
export type GoalProvenance = { source: "ultragoal"; runId: string; goalId: string } | { source: "user" };
|
|
6
|
+
|
|
5
7
|
export interface Goal {
|
|
6
8
|
id: string;
|
|
7
9
|
objective: string;
|
|
@@ -10,6 +12,7 @@ export interface Goal {
|
|
|
10
12
|
timeUsedSeconds: number;
|
|
11
13
|
createdAt: number;
|
|
12
14
|
updatedAt: number;
|
|
15
|
+
provenance?: GoalProvenance;
|
|
13
16
|
}
|
|
14
17
|
|
|
15
18
|
export interface GoalModeState {
|
|
@@ -47,6 +50,20 @@ export function normalizeGoal(candidate: unknown): Goal | null {
|
|
|
47
50
|
if (status !== "active" && status !== "paused" && status !== "complete" && status !== "dropped") {
|
|
48
51
|
return null;
|
|
49
52
|
}
|
|
53
|
+
const provenance = value.provenance;
|
|
54
|
+
if (
|
|
55
|
+
provenance !== undefined &&
|
|
56
|
+
(!provenance ||
|
|
57
|
+
typeof provenance !== "object" ||
|
|
58
|
+
((provenance as Record<string, unknown>).source === "ultragoal" &&
|
|
59
|
+
(typeof (provenance as Record<string, unknown>).runId !== "string" ||
|
|
60
|
+
typeof (provenance as Record<string, unknown>).goalId !== "string")) ||
|
|
61
|
+
((provenance as Record<string, unknown>).source !== "ultragoal" &&
|
|
62
|
+
(provenance as Record<string, unknown>).source !== "user"))
|
|
63
|
+
) {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
|
|
50
67
|
return {
|
|
51
68
|
id: value.id,
|
|
52
69
|
objective: value.objective,
|
|
@@ -55,6 +72,7 @@ export function normalizeGoal(candidate: unknown): Goal | null {
|
|
|
55
72
|
timeUsedSeconds: value.timeUsedSeconds,
|
|
56
73
|
createdAt: value.createdAt,
|
|
57
74
|
updatedAt: value.updatedAt,
|
|
75
|
+
...(provenance ? { provenance: provenance as GoalProvenance } : {}),
|
|
58
76
|
};
|
|
59
77
|
}
|
|
60
78
|
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { Observation, SessionState } from "./types";
|
|
2
|
+
|
|
3
|
+
export const OWNER_STARTUP_BLOCKER = "owner-died-before-first-prompt";
|
|
4
|
+
|
|
5
|
+
export interface CompletedTerminalEvent {
|
|
6
|
+
cursor: number;
|
|
7
|
+
createdAt: string;
|
|
8
|
+
kind: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function isOwnerLivenessBlocker(blocker: string): boolean {
|
|
12
|
+
return blocker === "detached-owner-not-live" || blocker.startsWith("owner-vanished:");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function needsVanishedOwnerBlock(
|
|
16
|
+
state: SessionState,
|
|
17
|
+
observation: Observation,
|
|
18
|
+
completedTerminal: CompletedTerminalEvent | null,
|
|
19
|
+
): boolean {
|
|
20
|
+
if (observation.ownerLive || state.lifecycle !== "observing") return false;
|
|
21
|
+
if (completedTerminal || observation.observedSignals.includes("completed")) return false;
|
|
22
|
+
return observation.observedSignals.some(
|
|
23
|
+
signal => signal === "prompt-accepted" || signal === "tool-call" || signal === "streaming",
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export async function reconcileOwnerLifecycle(input: {
|
|
28
|
+
state: SessionState;
|
|
29
|
+
observation: Observation;
|
|
30
|
+
completedTerminal: CompletedTerminalEvent | null;
|
|
31
|
+
startupBlocked: boolean;
|
|
32
|
+
persist: (state: SessionState) => Promise<void>;
|
|
33
|
+
nowIso: () => string;
|
|
34
|
+
}): Promise<SessionState> {
|
|
35
|
+
const { state, observation, completedTerminal } = input;
|
|
36
|
+
if (
|
|
37
|
+
completedTerminal &&
|
|
38
|
+
!observation.ownerLive &&
|
|
39
|
+
observation.gitDelta === "clean" &&
|
|
40
|
+
state.lifecycle !== "completed" &&
|
|
41
|
+
state.lifecycle !== "retired"
|
|
42
|
+
) {
|
|
43
|
+
state.lifecycle = "completed";
|
|
44
|
+
state.blockers = state.blockers.filter(blocker => !isOwnerLivenessBlocker(blocker));
|
|
45
|
+
state.updatedAt = input.nowIso();
|
|
46
|
+
await input.persist(state);
|
|
47
|
+
}
|
|
48
|
+
if (needsVanishedOwnerBlock(state, observation, completedTerminal)) {
|
|
49
|
+
const blocker = `owner-vanished:${observation.gitDelta}`;
|
|
50
|
+
state.lifecycle = "blocked";
|
|
51
|
+
state.blockers = state.blockers.includes(blocker) ? state.blockers : [...state.blockers, blocker];
|
|
52
|
+
state.updatedAt = input.nowIso();
|
|
53
|
+
await input.persist(state);
|
|
54
|
+
}
|
|
55
|
+
if (input.startupBlocked && state.lifecycle !== "completed" && state.lifecycle !== "retired") {
|
|
56
|
+
state.lifecycle = "blocked";
|
|
57
|
+
state.blockers = state.blockers.includes(OWNER_STARTUP_BLOCKER)
|
|
58
|
+
? state.blockers
|
|
59
|
+
: [...state.blockers, OWNER_STARTUP_BLOCKER];
|
|
60
|
+
state.updatedAt = input.nowIso();
|
|
61
|
+
await input.persist(state);
|
|
62
|
+
}
|
|
63
|
+
return state;
|
|
64
|
+
}
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Phase-boundary receipt rollup builder (receipt-of-receipts).
|
|
2
|
+
* EXPERIMENTAL: Phase-boundary receipt rollup builder (receipt-of-receipts).
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* the standard receipt envelope and validated fail-closed like every other
|
|
8
|
-
* family (see `validatePhaseRollup` in receipts.ts). Pure builder — no runtime
|
|
9
|
-
* injection behavior is changed here.
|
|
4
|
+
* This builder is not wired into finalize or retire yet; child receipts remain
|
|
5
|
+
* authoritative until a lifecycle integration preserves their supersession
|
|
6
|
+
* semantics. It is retained for controlled integration experiments only.
|
|
10
7
|
*/
|
|
11
8
|
import type { TaskResultReceipt } from "../task/receipt";
|
|
12
9
|
import {
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EXPERIMENTAL: Receipt ingestion is a pure evaluator and is not yet wired to
|
|
3
|
+
* finalize or retire lifecycle mutation. Callers must not treat its result as
|
|
4
|
+
* authoritative lifecycle persistence.
|
|
5
|
+
*/
|
|
1
6
|
import type { CompletionEvidence, ReceiptEnvelope, ReviewVerdictEvidence } from "./receipts";
|
|
2
7
|
import { validateReceipt } from "./receipts";
|
|
3
8
|
import { canTransition } from "./state-machine";
|
|
@@ -21,6 +21,46 @@ export interface ReceiptSpoolAppendResult {
|
|
|
21
21
|
const receiptSpoolDirStorage = new AsyncLocalStorage<string | undefined>();
|
|
22
22
|
const spoolQueues = new Map<string, Promise<void>>();
|
|
23
23
|
const noop = (): void => undefined;
|
|
24
|
+
|
|
25
|
+
interface ReceiptSpoolCursorCache {
|
|
26
|
+
mtimeMs: number;
|
|
27
|
+
size: number;
|
|
28
|
+
highest: bigint;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const cursorCache = new Map<string, ReceiptSpoolCursorCache>();
|
|
32
|
+
let fullScanCount = 0;
|
|
33
|
+
|
|
34
|
+
/** @internal Test-only instrumentation for steady-state spool scan coverage. */
|
|
35
|
+
export function receiptSpoolFullScanCountForTesting(): number {
|
|
36
|
+
return fullScanCount;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** @internal Test-only cache reset. */
|
|
40
|
+
export function resetReceiptSpoolCursorCacheForTesting(): void {
|
|
41
|
+
cursorCache.clear();
|
|
42
|
+
fullScanCount = 0;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function spoolStat(spoolFile: string): Promise<{ mtimeMs: number; size: number } | undefined> {
|
|
46
|
+
try {
|
|
47
|
+
const stats = await fs.stat(spoolFile);
|
|
48
|
+
return { mtimeMs: stats.mtimeMs, size: stats.size };
|
|
49
|
+
} catch (error) {
|
|
50
|
+
if ((error as NodeJS.ErrnoException).code === "ENOENT") return undefined;
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function sameSpoolRevision(a: ReceiptSpoolCursorCache, b: { mtimeMs: number; size: number }): boolean {
|
|
56
|
+
return a.mtimeMs === b.mtimeMs && a.size === b.size;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function cacheHighestCursor(spoolFile: string, highest: bigint): Promise<void> {
|
|
60
|
+
const revision = await spoolStat(spoolFile);
|
|
61
|
+
if (revision) cursorCache.set(spoolFile, { ...revision, highest });
|
|
62
|
+
}
|
|
63
|
+
|
|
24
64
|
export async function withReceiptSpoolDir<T>(spoolDir: string, fn: () => Promise<T>): Promise<T> {
|
|
25
65
|
const trimmed = spoolDir.trim();
|
|
26
66
|
if (!trimmed) throw new Error("receipt_spool_dir_empty");
|
|
@@ -55,14 +95,16 @@ export function formatReceiptSpoolCursor(cursor: bigint): string {
|
|
|
55
95
|
|
|
56
96
|
export async function readHighestReceiptSpoolCursor(spoolDir: string): Promise<bigint> {
|
|
57
97
|
const spoolFile = receiptSpoolPath(spoolDir);
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
if ((error as NodeJS.ErrnoException).code === "ENOENT") return 0n;
|
|
63
|
-
throw error;
|
|
98
|
+
const revision = await spoolStat(spoolFile);
|
|
99
|
+
if (!revision) {
|
|
100
|
+
cursorCache.delete(spoolFile);
|
|
101
|
+
return 0n;
|
|
64
102
|
}
|
|
103
|
+
const cached = cursorCache.get(spoolFile);
|
|
104
|
+
if (cached && sameSpoolRevision(cached, revision)) return cached.highest;
|
|
65
105
|
|
|
106
|
+
fullScanCount++;
|
|
107
|
+
const raw = await fs.readFile(spoolFile, "utf8");
|
|
66
108
|
let highest = 0n;
|
|
67
109
|
for (const line of raw.split("\n")) {
|
|
68
110
|
const trimmed = line.trim();
|
|
@@ -72,9 +114,10 @@ export async function readHighestReceiptSpoolCursor(spoolDir: string): Promise<b
|
|
|
72
114
|
const cursor = parseCursor(parsed.cursor);
|
|
73
115
|
if (cursor !== undefined && cursor > highest) highest = cursor;
|
|
74
116
|
} catch {
|
|
75
|
-
// A crash may leave a torn tail;
|
|
117
|
+
// A crash may leave a torn tail; a full scan ignores it and re-establishes the cache.
|
|
76
118
|
}
|
|
77
119
|
}
|
|
120
|
+
cursorCache.set(spoolFile, { ...revision, highest });
|
|
78
121
|
return highest;
|
|
79
122
|
}
|
|
80
123
|
|
|
@@ -111,6 +154,7 @@ export async function appendReceiptToSpool(
|
|
|
111
154
|
} finally {
|
|
112
155
|
await handle.close();
|
|
113
156
|
}
|
|
157
|
+
await cacheHighestCursor(spoolFile, BigInt(cursor));
|
|
114
158
|
return { cursor, path: spoolFile };
|
|
115
159
|
},
|
|
116
160
|
{ staleMs: 30_000, retries: 100, retryDelayMs: 25 },
|