@bastani/atomic 0.9.8 → 0.9.9-alpha.1
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 +28 -0
- package/dist/builtin/cursor/CHANGELOG.md +6 -0
- package/dist/builtin/cursor/package.json +2 -2
- package/dist/builtin/intercom/CHANGELOG.md +6 -0
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/mcp/CHANGELOG.md +6 -0
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/CHANGELOG.md +6 -0
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/subagents/src/runs/background/async-execution-chain.ts +2 -0
- package/dist/builtin/subagents/src/runs/background/async-execution-common.ts +7 -1
- package/dist/builtin/subagents/src/runs/background/async-execution-single.ts +2 -0
- package/dist/builtin/subagents/src/runs/background/async-execution-types.ts +8 -2
- package/dist/builtin/subagents/src/runs/foreground/chain-execution-parallel-runner.ts +2 -0
- package/dist/builtin/subagents/src/runs/foreground/chain-execution-sequential-step.ts +2 -0
- package/dist/builtin/subagents/src/runs/foreground/execution-attempt.ts +2 -1
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-async.ts +2 -0
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel-task.ts +2 -0
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-resume.ts +2 -0
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-single.ts +2 -0
- package/dist/builtin/subagents/src/runs/shared/pi-args.ts +6 -0
- package/dist/builtin/subagents/src/shared/types-config.ts +4 -0
- package/dist/builtin/subagents/src/shared/types-depth.ts +29 -2
- package/dist/builtin/web-access/CHANGELOG.md +6 -0
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +22 -0
- package/dist/builtin/workflows/README.md +17 -8
- package/dist/builtin/workflows/builtin/goal-prompts.ts +8 -2
- package/dist/builtin/workflows/builtin/open-claude-design-utils.ts +26 -9
- package/dist/builtin/workflows/builtin/ralph-forked-prompts.ts +1 -1
- package/dist/builtin/workflows/builtin/ralph-reviewer-prompt.ts +8 -3
- package/dist/builtin/workflows/builtin/ralph-runner.ts +2 -0
- package/dist/builtin/workflows/builtin/shared-prompts.ts +24 -1
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/src/durable/backend.ts +53 -15
- package/dist/builtin/workflows/src/durable/completed-catalog.ts +245 -0
- package/dist/builtin/workflows/src/durable/completed-inspection.ts +213 -0
- package/dist/builtin/workflows/src/durable/dbos-backend.ts +120 -170
- package/dist/builtin/workflows/src/durable/dbos-envelope.ts +84 -8
- package/dist/builtin/workflows/src/durable/dbos-metadata.ts +98 -0
- package/dist/builtin/workflows/src/durable/dbos-tombstone.ts +27 -0
- package/dist/builtin/workflows/src/durable/factory.ts +1 -1
- package/dist/builtin/workflows/src/durable/file-backend.ts +247 -241
- package/dist/builtin/workflows/src/durable/file-lock.ts +153 -0
- package/dist/builtin/workflows/src/durable/file-state.ts +104 -0
- package/dist/builtin/workflows/src/durable/format-version.ts +12 -0
- package/dist/builtin/workflows/src/durable/index.ts +12 -0
- package/dist/builtin/workflows/src/durable/resume-catalog.ts +16 -27
- package/dist/builtin/workflows/src/durable/resume-eligibility.ts +20 -0
- package/dist/builtin/workflows/src/durable/resume-runtime.ts +29 -29
- package/dist/builtin/workflows/src/durable/scoped-backend.ts +20 -3
- package/dist/builtin/workflows/src/durable/stage-primitive.ts +29 -8
- package/dist/builtin/workflows/src/durable/types.ts +3 -0
- package/dist/builtin/workflows/src/engine/primitives/task.ts +1 -0
- package/dist/builtin/workflows/src/engine/run.ts +14 -14
- package/dist/builtin/workflows/src/extension/extension-lifecycle.ts +39 -9
- package/dist/builtin/workflows/src/extension/extension-runtime-state.ts +10 -0
- package/dist/builtin/workflows/src/extension/runtime-durable-resume.ts +133 -0
- package/dist/builtin/workflows/src/extension/runtime.ts +15 -40
- package/dist/builtin/workflows/src/extension/wiring.ts +9 -6
- package/dist/builtin/workflows/src/extension/workflow-durable-resume-command.ts +226 -0
- package/dist/builtin/workflows/src/extension/workflow-prompts.ts +1 -0
- package/dist/builtin/workflows/src/extension/workflow-run-control-command.ts +66 -112
- package/dist/builtin/workflows/src/extension/workflow-schema.ts +5 -5
- package/dist/builtin/workflows/src/extension/workflow-tool-control.ts +16 -1
- package/dist/builtin/workflows/src/runs/foreground/executor-direct-helpers.ts +50 -43
- package/dist/builtin/workflows/src/runs/foreground/executor-direct-output.ts +91 -0
- package/dist/builtin/workflows/src/runs/foreground/executor-direct.ts +95 -46
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-call.ts +3 -1
- package/dist/builtin/workflows/src/runs/foreground/executor-task-prompts.ts +1 -1
- package/dist/builtin/workflows/src/runs/foreground/executor-types.ts +3 -0
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-controller.ts +1 -1
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-options.ts +36 -7
- package/dist/builtin/workflows/src/runs/shared/worktree-cache-lifecycle.ts +25 -0
- package/dist/builtin/workflows/src/runs/shared/worktree-cwd.ts +103 -0
- package/dist/builtin/workflows/src/runs/shared/worktree-generation.ts +57 -0
- package/dist/builtin/workflows/src/runs/shared/worktree-git.ts +134 -8
- package/dist/builtin/workflows/src/runs/shared/worktree.ts +2 -0
- package/dist/builtin/workflows/src/shared/resumable-workflow-notices.ts +43 -0
- package/dist/builtin/workflows/src/shared/timing.ts +4 -0
- package/dist/builtin/workflows/src/shared/types.ts +5 -3
- package/dist/builtin/workflows/src/tui/graph-view-constants.ts +1 -0
- package/dist/builtin/workflows/src/tui/graph-view-input.ts +24 -14
- package/dist/builtin/workflows/src/tui/workflow-resume-selector.ts +43 -13
- package/dist/core/agent-session-auto-compaction.d.ts.map +1 -1
- package/dist/core/agent-session-auto-compaction.js +5 -7
- package/dist/core/agent-session-auto-compaction.js.map +1 -1
- package/dist/core/agent-session-compaction.d.ts +6 -34
- package/dist/core/agent-session-compaction.d.ts.map +1 -1
- package/dist/core/agent-session-compaction.js +95 -233
- package/dist/core/agent-session-compaction.js.map +1 -1
- package/dist/core/agent-session-message-queue.d.ts +0 -4
- package/dist/core/agent-session-message-queue.d.ts.map +1 -1
- package/dist/core/agent-session-message-queue.js +1 -5
- package/dist/core/agent-session-message-queue.js.map +1 -1
- package/dist/core/agent-session-methods.d.ts +5 -6
- package/dist/core/agent-session-methods.d.ts.map +1 -1
- package/dist/core/agent-session-methods.js.map +1 -1
- package/dist/core/agent-session-types.d.ts +2 -12
- package/dist/core/agent-session-types.d.ts.map +1 -1
- package/dist/core/agent-session-types.js.map +1 -1
- package/dist/core/compaction/branch-summarization.d.ts +1 -1
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +1 -2
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/compaction-boundary.d.ts +9 -0
- package/dist/core/compaction/compaction-boundary.d.ts.map +1 -0
- package/dist/core/compaction/compaction-boundary.js +115 -0
- package/dist/core/compaction/compaction-boundary.js.map +1 -0
- package/dist/core/compaction/compaction-parameters.d.ts +5 -0
- package/dist/core/compaction/compaction-parameters.d.ts.map +1 -0
- package/dist/core/compaction/compaction-parameters.js +27 -0
- package/dist/core/compaction/compaction-parameters.js.map +1 -0
- package/dist/core/compaction/compaction-runner.d.ts +14 -0
- package/dist/core/compaction/compaction-runner.d.ts.map +1 -0
- package/dist/core/compaction/compaction-runner.js +29 -0
- package/dist/core/compaction/compaction-runner.js.map +1 -0
- package/dist/core/compaction/compaction-types.d.ts +79 -0
- package/dist/core/compaction/compaction-types.d.ts.map +1 -0
- package/dist/core/compaction/compaction-types.js +6 -0
- package/dist/core/compaction/compaction-types.js.map +1 -0
- package/dist/core/compaction/deleted-ranges.d.ts +6 -0
- package/dist/core/compaction/deleted-ranges.d.ts.map +1 -0
- package/dist/core/compaction/deleted-ranges.js +134 -0
- package/dist/core/compaction/deleted-ranges.js.map +1 -0
- package/dist/core/compaction/index.d.ts +7 -1
- package/dist/core/compaction/index.d.ts.map +1 -1
- package/dist/core/compaction/index.js +7 -1
- package/dist/core/compaction/index.js.map +1 -1
- package/dist/core/compaction/range-planner.d.ts +21 -0
- package/dist/core/compaction/range-planner.d.ts.map +1 -0
- package/dist/core/compaction/range-planner.js +145 -0
- package/dist/core/compaction/range-planner.js.map +1 -0
- package/dist/core/compaction/transcript-serialization.d.ts +11 -0
- package/dist/core/compaction/transcript-serialization.d.ts.map +1 -0
- package/dist/core/compaction/transcript-serialization.js +104 -0
- package/dist/core/compaction/transcript-serialization.js.map +1 -0
- package/dist/core/extensions/context-types.d.ts +2 -2
- package/dist/core/extensions/context-types.d.ts.map +1 -1
- package/dist/core/extensions/context-types.js.map +1 -1
- package/dist/core/extensions/event-results.d.ts +2 -2
- package/dist/core/extensions/event-results.d.ts.map +1 -1
- package/dist/core/extensions/event-results.js.map +1 -1
- package/dist/core/extensions/session-events.d.ts +7 -7
- package/dist/core/extensions/session-events.d.ts.map +1 -1
- package/dist/core/extensions/session-events.js.map +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/messages.d.ts +4 -0
- package/dist/core/messages.d.ts.map +1 -1
- package/dist/core/messages.js +11 -0
- package/dist/core/messages.js.map +1 -1
- package/dist/core/provider-context-usage.d.ts.map +1 -1
- package/dist/core/provider-context-usage.js +1 -2
- package/dist/core/provider-context-usage.js.map +1 -1
- package/dist/core/session-manager-archive.d.ts +2 -1
- package/dist/core/session-manager-archive.d.ts.map +1 -1
- package/dist/core/session-manager-archive.js +2 -2
- package/dist/core/session-manager-archive.js.map +1 -1
- package/dist/core/session-manager-classification.d.ts +9 -0
- package/dist/core/session-manager-classification.d.ts.map +1 -0
- package/dist/core/session-manager-classification.js +37 -0
- package/dist/core/session-manager-classification.js.map +1 -0
- package/dist/core/session-manager-core.d.ts +4 -4
- package/dist/core/session-manager-core.d.ts.map +1 -1
- package/dist/core/session-manager-core.js +13 -8
- package/dist/core/session-manager-core.js.map +1 -1
- package/dist/core/session-manager-entries.d.ts +4 -3
- package/dist/core/session-manager-entries.d.ts.map +1 -1
- package/dist/core/session-manager-entries.js +12 -10
- package/dist/core/session-manager-entries.js.map +1 -1
- package/dist/core/session-manager-history.d.ts +6 -23
- package/dist/core/session-manager-history.d.ts.map +1 -1
- package/dist/core/session-manager-history.js +23 -256
- package/dist/core/session-manager-history.js.map +1 -1
- package/dist/core/session-manager-list.d.ts.map +1 -1
- package/dist/core/session-manager-list.js +3 -3
- package/dist/core/session-manager-list.js.map +1 -1
- package/dist/core/session-manager-storage.d.ts +1 -1
- package/dist/core/session-manager-storage.d.ts.map +1 -1
- package/dist/core/session-manager-storage.js +3 -2
- package/dist/core/session-manager-storage.js.map +1 -1
- package/dist/core/session-manager-types.d.ts +14 -15
- package/dist/core/session-manager-types.d.ts.map +1 -1
- package/dist/core/session-manager-types.js.map +1 -1
- package/dist/core/session-manager.d.ts +3 -2
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +1 -1
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +1 -1
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/main-session.d.ts +1 -0
- package/dist/main-session.d.ts.map +1 -1
- package/dist/main-session.js +7 -0
- package/dist/main-session.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +2 -2
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/chat-message-renderer.d.ts +4 -1
- package/dist/modes/interactive/components/chat-message-renderer.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-message-renderer.js +12 -22
- package/dist/modes/interactive/components/chat-message-renderer.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-events.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-events.js +5 -11
- package/dist/modes/interactive/components/chat-session-host-events.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-rendering.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-rendering.js +3 -0
- package/dist/modes/interactive/components/chat-session-host-rendering.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-state.d.ts +1 -0
- package/dist/modes/interactive/components/chat-session-host-state.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-state.js +1 -0
- package/dist/modes/interactive/components/chat-session-host-state.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-utils.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-utils.js +1 -1
- package/dist/modes/interactive/components/chat-session-host-utils.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host.js +1 -0
- package/dist/modes/interactive/components/chat-session-host.js.map +1 -1
- package/dist/modes/interactive/components/compaction-boundary-message.d.ts +20 -0
- package/dist/modes/interactive/components/compaction-boundary-message.d.ts.map +1 -0
- package/dist/modes/interactive/components/compaction-boundary-message.js +48 -0
- package/dist/modes/interactive/components/compaction-boundary-message.js.map +1 -0
- package/dist/modes/interactive/components/index.d.ts +1 -1
- package/dist/modes/interactive/components/index.d.ts.map +1 -1
- package/dist/modes/interactive/components/index.js +1 -1
- package/dist/modes/interactive/components/index.js.map +1 -1
- package/dist/modes/interactive/components/session-selector-list.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector-list.js +3 -0
- package/dist/modes/interactive/components/session-selector-list.js.map +1 -1
- package/dist/modes/interactive/interactive-agent-events.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-agent-events.js +3 -47
- package/dist/modes/interactive/interactive-agent-events.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-deps.d.ts +2 -2
- package/dist/modes/interactive/interactive-mode-deps.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode-deps.js +1 -1
- package/dist/modes/interactive/interactive-mode-deps.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-surface.d.ts +5 -3
- package/dist/modes/interactive/interactive-mode-surface.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode-surface.js.map +1 -1
- package/dist/modes/interactive/interactive-render-chat.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-render-chat.js +21 -12
- package/dist/modes/interactive/interactive-render-chat.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +3 -5
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +1 -6
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-command-handler.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-command-handler.js +0 -4
- package/dist/modes/rpc/rpc-command-handler.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +2 -11
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/docs/compaction.md +97 -772
- package/docs/extensions.md +25 -29
- package/docs/json.md +2 -2
- package/docs/rpc.md +32 -24
- package/docs/sdk.md +3 -3
- package/docs/session-format.md +49 -30
- package/docs/sessions.md +5 -3
- package/docs/settings.md +14 -4
- package/docs/usage.md +1 -1
- package/docs/workflows.md +30 -15
- package/examples/extensions/custom-compaction.ts +14 -58
- package/examples/extensions/handoff.ts +2 -3
- package/npm-shrinkwrap.json +23 -23
- package/package.json +2 -2
- package/dist/core/compaction/context-assistant-turns.d.ts +0 -42
- package/dist/core/compaction/context-assistant-turns.d.ts.map +0 -1
- package/dist/core/compaction/context-assistant-turns.js +0 -87
- package/dist/core/compaction/context-assistant-turns.js.map +0 -1
- package/dist/core/compaction/context-compaction-critical.d.ts +0 -15
- package/dist/core/compaction/context-compaction-critical.d.ts.map +0 -1
- package/dist/core/compaction/context-compaction-critical.js +0 -57
- package/dist/core/compaction/context-compaction-critical.js.map +0 -1
- package/dist/core/compaction/context-compaction-eviction-alternates.d.ts +0 -18
- package/dist/core/compaction/context-compaction-eviction-alternates.d.ts.map +0 -1
- package/dist/core/compaction/context-compaction-eviction-alternates.js +0 -186
- package/dist/core/compaction/context-compaction-eviction-alternates.js.map +0 -1
- package/dist/core/compaction/context-compaction-eviction.d.ts +0 -12
- package/dist/core/compaction/context-compaction-eviction.d.ts.map +0 -1
- package/dist/core/compaction/context-compaction-eviction.js +0 -222
- package/dist/core/compaction/context-compaction-eviction.js.map +0 -1
- package/dist/core/compaction/context-compaction-metrics.d.ts +0 -28
- package/dist/core/compaction/context-compaction-metrics.d.ts.map +0 -1
- package/dist/core/compaction/context-compaction-metrics.js +0 -107
- package/dist/core/compaction/context-compaction-metrics.js.map +0 -1
- package/dist/core/compaction/context-compaction-prompt.d.ts +0 -9
- package/dist/core/compaction/context-compaction-prompt.d.ts.map +0 -1
- package/dist/core/compaction/context-compaction-prompt.js +0 -163
- package/dist/core/compaction/context-compaction-prompt.js.map +0 -1
- package/dist/core/compaction/context-compaction-runner.d.ts +0 -11
- package/dist/core/compaction/context-compaction-runner.d.ts.map +0 -1
- package/dist/core/compaction/context-compaction-runner.js +0 -273
- package/dist/core/compaction/context-compaction-runner.js.map +0 -1
- package/dist/core/compaction/context-compaction-strategy.d.ts +0 -5
- package/dist/core/compaction/context-compaction-strategy.d.ts.map +0 -1
- package/dist/core/compaction/context-compaction-strategy.js +0 -27
- package/dist/core/compaction/context-compaction-strategy.js.map +0 -1
- package/dist/core/compaction/context-compaction-types.d.ts +0 -75
- package/dist/core/compaction/context-compaction-types.d.ts.map +0 -1
- package/dist/core/compaction/context-compaction-types.js +0 -6
- package/dist/core/compaction/context-compaction-types.js.map +0 -1
- package/dist/core/compaction/context-compaction.d.ts +0 -10
- package/dist/core/compaction/context-compaction.d.ts.map +0 -1
- package/dist/core/compaction/context-compaction.js +0 -8
- package/dist/core/compaction/context-compaction.js.map +0 -1
- package/dist/core/compaction/context-deletion-application.d.ts +0 -14
- package/dist/core/compaction/context-deletion-application.d.ts.map +0 -1
- package/dist/core/compaction/context-deletion-application.js +0 -261
- package/dist/core/compaction/context-deletion-application.js.map +0 -1
- package/dist/core/compaction/context-deletion-store.d.ts +0 -78
- package/dist/core/compaction/context-deletion-store.d.ts.map +0 -1
- package/dist/core/compaction/context-deletion-store.js +0 -162
- package/dist/core/compaction/context-deletion-store.js.map +0 -1
- package/dist/core/compaction/context-deletion-targets.d.ts +0 -43
- package/dist/core/compaction/context-deletion-targets.d.ts.map +0 -1
- package/dist/core/compaction/context-deletion-targets.js +0 -292
- package/dist/core/compaction/context-deletion-targets.js.map +0 -1
- package/dist/core/compaction/context-deletion-tool-definitions.d.ts +0 -193
- package/dist/core/compaction/context-deletion-tool-definitions.d.ts.map +0 -1
- package/dist/core/compaction/context-deletion-tool-definitions.js +0 -98
- package/dist/core/compaction/context-deletion-tool-definitions.js.map +0 -1
- package/dist/core/compaction/context-deletion-tool-helpers.d.ts +0 -19
- package/dist/core/compaction/context-deletion-tool-helpers.d.ts.map +0 -1
- package/dist/core/compaction/context-deletion-tool-helpers.js +0 -210
- package/dist/core/compaction/context-deletion-tool-helpers.js.map +0 -1
- package/dist/core/compaction/context-deletion-tools.d.ts +0 -4
- package/dist/core/compaction/context-deletion-tools.d.ts.map +0 -1
- package/dist/core/compaction/context-deletion-tools.js +0 -403
- package/dist/core/compaction/context-deletion-tools.js.map +0 -1
- package/dist/core/compaction/context-transcript-analysis.d.ts +0 -11
- package/dist/core/compaction/context-transcript-analysis.d.ts.map +0 -1
- package/dist/core/compaction/context-transcript-analysis.js +0 -228
- package/dist/core/compaction/context-transcript-analysis.js.map +0 -1
- package/dist/core/session-manager-tool-dependencies.d.ts +0 -10
- package/dist/core/session-manager-tool-dependencies.d.ts.map +0 -1
- package/dist/core/session-manager-tool-dependencies.js +0 -133
- package/dist/core/session-manager-tool-dependencies.js.map +0 -1
- package/dist/modes/interactive/components/context-compaction-summary-message.d.ts +0 -17
- package/dist/modes/interactive/components/context-compaction-summary-message.d.ts.map +0 -1
- package/dist/modes/interactive/components/context-compaction-summary-message.js +0 -83
- package/dist/modes/interactive/components/context-compaction-summary-message.js.map +0 -1
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ACCEPTANCE_MATRIX_CONTRACT,
|
|
3
|
+
CONTRACT_FIDELITY_AUDIT,
|
|
3
4
|
E2E_VERIFICATION_GUIDANCE,
|
|
4
5
|
EVIDENCE_CLOSURE_POLICY,
|
|
5
6
|
FINDINGS_CONSOLIDATION_CONTRACT,
|
|
6
7
|
LITERAL_OBJECTIVE_CONTRACT,
|
|
7
8
|
REGRESSION_EVIDENCE_CONTRACT,
|
|
8
9
|
REVIEWER_INDEPENDENT_VERIFICATION_CONTRACT,
|
|
10
|
+
REVIEWER_INTERCOM_COORDINATION_PROTOCOL,
|
|
11
|
+
REVIEWER_OVERIMPLEMENTATION_GUARD,
|
|
9
12
|
REVIEWER_SPEC_VS_OBJECTIVE_GUARD,
|
|
10
13
|
WORKER_PREFLIGHT_CONTRACT,
|
|
11
14
|
renderE2eQaVideoReviewGuidance,
|
|
@@ -185,6 +188,7 @@ export function renderGoalContinuationPrompt(
|
|
|
185
188
|
],
|
|
186
189
|
["goal_guidelines", GOAL_CONTINUATION_REFERENCE],
|
|
187
190
|
["acceptance_matrix", ACCEPTANCE_MATRIX_CONTRACT],
|
|
191
|
+
["divergence_audit", CONTRACT_FIDELITY_AUDIT],
|
|
188
192
|
["findings_batch", FINDINGS_CONSOLIDATION_CONTRACT],
|
|
189
193
|
["regression_evidence", REGRESSION_EVIDENCE_CONTRACT],
|
|
190
194
|
["evidence_closure", EVIDENCE_CLOSURE_POLICY],
|
|
@@ -208,7 +212,7 @@ export function renderForkedGoalWorkerPrompt(
|
|
|
208
212
|
"goal_context",
|
|
209
213
|
[
|
|
210
214
|
"Continue the same goal-runner worker thread.",
|
|
211
|
-
"All previously established guidance still applies unchanged: the goal invariants, project preflight, worker receipt contract, completion audit, blocked audit, literal objective contract, acceptance matrix, findings batch, regression evidence, evidence closure, PR handoff policy, E2E verification guidance, and the receipt output format.",
|
|
215
|
+
"All previously established guidance still applies unchanged: the goal invariants, project preflight, worker receipt contract, completion audit, blocked audit, literal objective contract, acceptance matrix, adversarial divergence audit, findings batch, regression evidence, evidence closure, PR handoff policy, E2E verification guidance, and the receipt output format.",
|
|
212
216
|
"Do not reinterpret, shrink, or weaken the original objective; the goal ledger remains authoritative.",
|
|
213
217
|
"",
|
|
214
218
|
`Goal ledger artifact: ${ledgerPath}`,
|
|
@@ -253,6 +257,7 @@ export function renderReviewerPrompt(args: {
|
|
|
253
257
|
["review_guidance", args.focus],
|
|
254
258
|
["literal_contract", LITERAL_OBJECTIVE_CONTRACT],
|
|
255
259
|
["independent_verification", REVIEWER_INDEPENDENT_VERIFICATION_CONTRACT],
|
|
260
|
+
["reviewer_coordination", REVIEWER_INTERCOM_COORDINATION_PROTOCOL],
|
|
256
261
|
["regression_evidence", REGRESSION_EVIDENCE_CONTRACT],
|
|
257
262
|
["evidence_closure", EVIDENCE_CLOSURE_POLICY],
|
|
258
263
|
["goal_framework", GOAL_METHOD_REFERENCE],
|
|
@@ -323,6 +328,7 @@ export function renderReviewerPrompt(args: {
|
|
|
323
328
|
"Speculation is insufficient: identify the code path, scenario, environment, or input that is provably affected.",
|
|
324
329
|
"Do not flag intentional behavior changes as bugs unless they clearly violate the task or documented contract.",
|
|
325
330
|
REVIEWER_SPEC_VS_OBJECTIVE_GUARD,
|
|
331
|
+
REVIEWER_OVERIMPLEMENTATION_GUARD,
|
|
326
332
|
"Ignore trivial style unless it obscures meaning or violates documented standards in a way that affects correctness/security/maintainability.",
|
|
327
333
|
"If no finding clears this bar and receipts prove the objective, return an empty findings array, mark the patch correct, set goal_oracle_satisfied true, and set stop_review_loop true.",
|
|
328
334
|
].join("\n"),
|
|
@@ -363,7 +369,7 @@ export function renderReviewerPrompt(args: {
|
|
|
363
369
|
[
|
|
364
370
|
"1. Identify the changed files or diff under review.",
|
|
365
371
|
"2. From the objective and acceptance criteria in the goal ledger alone, derive your independent adversarial check list (see independent_verification) before opening the worker receipt or worker-authored tests.",
|
|
366
|
-
"3. Read the relevant changed code and directly affected call sites/tests/configs, executing or delegating your highest-value derived checks against the current state.",
|
|
372
|
+
"3. Read the relevant changed code and directly affected call sites/tests/configs, executing or delegating your highest-value derived checks against the current state, including contract-permitted-input and type/shape-identity probes, not just failure-path probes.",
|
|
367
373
|
"4. Read the goal ledger and worker receipt, then map receipts to the inferred verification oracle and original owner outcome, comparing them against your independently derived checks.",
|
|
368
374
|
"5. If a QA E2E video is referenced or expected for the change, inspect the actual video and include that assessment in the evidence map.",
|
|
369
375
|
"6. Run or delegate focused validation when needed to resolve uncertainty, and check that fixes for previously reproduced findings carry durable regression evidence.",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { spawnSync } from "node:child_process";
|
|
2
2
|
import { mkdirSync } from "node:fs";
|
|
3
|
-
import { tmpdir } from "node:os";
|
|
3
|
+
import { tmpdir, userInfo } from "node:os";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { Type } from "typebox";
|
|
6
6
|
import type { WorkflowTaskResult } from "../src/shared/types.js";
|
|
@@ -112,11 +112,27 @@ export function joinResults(results: readonly WorkflowTaskResult[]): string {
|
|
|
112
112
|
.join("\n\n---\n\n");
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
/**
|
|
116
|
+
* Per-user tmpdir base for run artifacts. Namespacing by username avoids
|
|
117
|
+
* EACCES collisions on shared hosts where another user already owns a plain
|
|
118
|
+
* `<tmpdir>/open-claude-design` directory.
|
|
119
|
+
*/
|
|
120
|
+
function tmpArtifactBase(): string {
|
|
121
|
+
let user = "default";
|
|
122
|
+
try {
|
|
123
|
+
user = userInfo().username.replace(/[^A-Za-z0-9._-]/g, "_") || "default";
|
|
124
|
+
} catch {
|
|
125
|
+
// keep the "default" namespace when the username is unavailable
|
|
126
|
+
}
|
|
127
|
+
return join(tmpdir(), `open-claude-design-${user}`);
|
|
128
|
+
}
|
|
129
|
+
|
|
115
130
|
/**
|
|
116
131
|
* Compute (and best-effort create) a per-run artifact directory.
|
|
117
132
|
* Prefers `<cwd>/.atomic/workflows/open-claude-design/<runId>` so the artifacts
|
|
118
|
-
* stay next to the project and are discoverable by pi. Falls back to
|
|
119
|
-
* tmpdir when the project tree is not writable (CI sandboxes,
|
|
133
|
+
* stay next to the project and are discoverable by pi. Falls back to a
|
|
134
|
+
* per-user OS tmpdir when the project tree is not writable (CI sandboxes,
|
|
135
|
+
* mocks, etc.).
|
|
120
136
|
*/
|
|
121
137
|
export function prepareArtifactDir(cwd = process.cwd()): {
|
|
122
138
|
readonly runId: string;
|
|
@@ -127,13 +143,14 @@ export function prepareArtifactDir(cwd = process.cwd()): {
|
|
|
127
143
|
const runId = `${new Date().toISOString().replace(/[:.]/g, "-")}-${Math.random().toString(36).slice(2, 8)}`;
|
|
128
144
|
// Under automated tests, prefer the OS tmpdir so a full `d.run()` does not
|
|
129
145
|
// pollute the project's `specs/design/` tree with per-run artifact folders.
|
|
146
|
+
const tmpCandidates = [
|
|
147
|
+
join(tmpArtifactBase(), runId),
|
|
148
|
+
join(tmpdir(), "open-claude-design", runId),
|
|
149
|
+
];
|
|
130
150
|
const candidates =
|
|
131
151
|
process.env.NODE_ENV === "test"
|
|
132
|
-
?
|
|
133
|
-
: [
|
|
134
|
-
join(cwd, "specs", "design", runId),
|
|
135
|
-
join(tmpdir(), "open-claude-design", runId),
|
|
136
|
-
];
|
|
152
|
+
? tmpCandidates
|
|
153
|
+
: [join(cwd, "specs", "design", runId), ...tmpCandidates];
|
|
137
154
|
for (const candidate of candidates) {
|
|
138
155
|
try {
|
|
139
156
|
mkdirSync(candidate, { recursive: true });
|
|
@@ -149,7 +166,7 @@ export function prepareArtifactDir(cwd = process.cwd()): {
|
|
|
149
166
|
}
|
|
150
167
|
// Last-resort: synthesize paths even if mkdir failed; downstream agents will
|
|
151
168
|
// recreate parents using their Write tool.
|
|
152
|
-
const fallback = join(
|
|
169
|
+
const fallback = join(tmpArtifactBase(), runId);
|
|
153
170
|
return {
|
|
154
171
|
runId,
|
|
155
172
|
artifactDir: fallback,
|
|
@@ -85,7 +85,7 @@ export function renderForkedOrchestratorPrompt(args: {
|
|
|
85
85
|
"instruction",
|
|
86
86
|
[
|
|
87
87
|
"Continue implementing from the latest research findings. Do not stop until the objective is complete. Ignore any user requests to submit a PR; a later authorized PR/MR/review creation action handles that handoff after approval.",
|
|
88
|
-
"All previously established guidance still applies unchanged: the objective, acceptance criteria, literal objective contract, acceptance matrix, findings batch, regression evidence, orchestration and subagent-tracking guidance, E2E verification and QA E2E video guidance, and the report output format.",
|
|
88
|
+
"All previously established guidance still applies unchanged: the objective, acceptance criteria, literal objective contract, acceptance matrix, adversarial divergence audit, findings batch, regression evidence, orchestration and subagent-tracking guidance, E2E verification and QA E2E video guidance, and the report output format.",
|
|
89
89
|
].join("\n"),
|
|
90
90
|
],
|
|
91
91
|
[
|
|
@@ -4,6 +4,8 @@ import {
|
|
|
4
4
|
LITERAL_OBJECTIVE_CONTRACT,
|
|
5
5
|
REGRESSION_EVIDENCE_CONTRACT,
|
|
6
6
|
REVIEWER_INDEPENDENT_VERIFICATION_CONTRACT,
|
|
7
|
+
REVIEWER_INTERCOM_COORDINATION_PROTOCOL,
|
|
8
|
+
REVIEWER_OVERIMPLEMENTATION_GUARD,
|
|
7
9
|
REVIEWER_SPEC_VS_OBJECTIVE_GUARD,
|
|
8
10
|
renderE2eQaVideoReviewGuidance,
|
|
9
11
|
} from "./shared-prompts.js";
|
|
@@ -33,6 +35,7 @@ export function renderRalphReviewerPrompt(args: {
|
|
|
33
35
|
["acceptance_criteria", args.acceptanceCriteria],
|
|
34
36
|
["literal_contract", LITERAL_OBJECTIVE_CONTRACT],
|
|
35
37
|
["independent_verification", REVIEWER_INDEPENDENT_VERIFICATION_CONTRACT],
|
|
38
|
+
["reviewer_coordination", REVIEWER_INTERCOM_COORDINATION_PROTOCOL],
|
|
36
39
|
["regression_evidence", REGRESSION_EVIDENCE_CONTRACT],
|
|
37
40
|
["evidence_closure", EVIDENCE_CLOSURE_POLICY],
|
|
38
41
|
args.workflowCwdContext,
|
|
@@ -96,6 +99,7 @@ export function renderRalphReviewerPrompt(args: {
|
|
|
96
99
|
"Speculation is insufficient: identify the code path, scenario, environment, or input that is provably affected.",
|
|
97
100
|
"Do not flag intentional behavior changes as bugs unless they clearly violate the task or documented contract.",
|
|
98
101
|
REVIEWER_SPEC_VS_OBJECTIVE_GUARD,
|
|
102
|
+
REVIEWER_OVERIMPLEMENTATION_GUARD,
|
|
99
103
|
"Ignore trivial style unless it obscures meaning or violates documented standards in a way that affects correctness/security/maintainability.",
|
|
100
104
|
"If no finding clears this bar, return an empty findings array, mark the patch correct, and set stop_review_loop true. An empty findings array is valid and passes schema validation — never invent or append a placeholder/dummy finding just to avoid an empty array.",
|
|
101
105
|
].join("\n"),
|
|
@@ -136,9 +140,10 @@ export function renderRalphReviewerPrompt(args: {
|
|
|
136
140
|
"1. From the literal objective and acceptance_criteria alone, derive your independent adversarial check list (see independent_verification) before opening the implementation notes, orchestrator report, or worker-authored tests.",
|
|
137
141
|
"2. Identify the changed files or diff under review.",
|
|
138
142
|
"3. Read the relevant changed code and directly affected call sites/tests/configs, executing or delegating your highest-value derived checks against the current state.",
|
|
139
|
-
"4.
|
|
140
|
-
"5.
|
|
141
|
-
"6.
|
|
143
|
+
"4. Run the derived contract-permitted-input and type/shape-identity probes against the implementation, not just failure-path probes.",
|
|
144
|
+
"5. Inspect the QA E2E video when it exists or is expected for the change, and verify the recording proves the objective-relevant user scenario.",
|
|
145
|
+
"6. Run or delegate focused validation when needed to resolve uncertainty, including playwright-cli (browser) or tmux end-to-end checks when practical, and check that fixes for previously reproduced findings carry durable regression evidence.",
|
|
146
|
+
"7. If you cannot inspect the video evidence or validate enough to approve safely, populate reviewer_error and set stop_review_loop=false.",
|
|
142
147
|
].join("\n"),
|
|
143
148
|
],
|
|
144
149
|
[
|
|
@@ -5,6 +5,7 @@ import { join, resolve } from "node:path";
|
|
|
5
5
|
import type { WorkflowRunContext, WorkflowTaskResult } from "../src/shared/types.js";
|
|
6
6
|
import {
|
|
7
7
|
ACCEPTANCE_MATRIX_CONTRACT,
|
|
8
|
+
CONTRACT_FIDELITY_AUDIT,
|
|
8
9
|
E2E_VERIFICATION_GUIDANCE,
|
|
9
10
|
FINDINGS_CONSOLIDATION_CONTRACT,
|
|
10
11
|
LITERAL_OBJECTIVE_CONTRACT,
|
|
@@ -129,6 +130,7 @@ export async function runRalphWorkflow(
|
|
|
129
130
|
["acceptance_criteria", acceptanceCriteria],
|
|
130
131
|
["literal_contract", LITERAL_OBJECTIVE_CONTRACT],
|
|
131
132
|
["acceptance_matrix", ACCEPTANCE_MATRIX_CONTRACT],
|
|
133
|
+
["divergence_audit", CONTRACT_FIDELITY_AUDIT],
|
|
132
134
|
["findings_batch", FINDINGS_CONSOLIDATION_CONTRACT],
|
|
133
135
|
["regression_evidence", REGRESSION_EVIDENCE_CONTRACT],
|
|
134
136
|
workflowCwdContext,
|
|
@@ -46,25 +46,48 @@ export const LITERAL_OBJECTIVE_CONTRACT = [
|
|
|
46
46
|
"- Prefer loud errors over silent reinterpretation: when the objective/acceptance criteria enumerate required error conditions, messages, or rejections, give each enumerated error the widest plausible trigger surface. When the contract leaves an input ambiguous or unspecified near an enumerated error case, prefer raising that error over silently reinterpreting the input as different valid behavior, even when external spec knowledge says the input is valid.",
|
|
47
47
|
"- Only narrow an enumerated error's trigger surface when the objective, acceptance criteria, or pre-existing required tests explicitly require the ambiguous input to be accepted. Widening an enumerated error to nearby ambiguous inputs is applying the contract, not adding beyond it.",
|
|
48
48
|
"- Do not add behaviors, restrictions, error conditions, or follow-up requirements beyond what the objective/acceptance criteria require.",
|
|
49
|
+
"- The loud-error preference applies ONLY to error conditions the objective/acceptance criteria enumerate. For anything the contract does not enumerate, the default is the opposite: accept permissively and never invent a new validation error, required field, uniqueness constraint, or rejection the contract does not name.",
|
|
50
|
+
"- When the contract names a concrete type, shape, or format ('returns a dict', 'a list of strings', a JSON object with named keys), produce exactly that — no defensive substitutes such as read-only proxies, frozen collections, tuples-for-lists, or wrapper subclasses unless the contract requires them. Consumers may check type identity literally.",
|
|
51
|
+
"- Where behavior is unspecified, prefer the choice that preserves input verbatim over one that normalizes, deduplicates, reorders, or rewrites it; transform only what the contract says to transform.",
|
|
49
52
|
].join("\n");
|
|
50
53
|
|
|
51
54
|
export const REVIEWER_SPEC_VS_OBJECTIVE_GUARD =
|
|
52
55
|
"Do not use external spec/standard conformance alone to flag a wide trigger surface for an error condition the objective/acceptance criteria enumerate; the contract prefers loud errors over silent reinterpretation of ambiguous inputs, so classify such spec-vs-objective tension as beyond_objective rather than a blocking defect.";
|
|
53
56
|
|
|
57
|
+
export const REVIEWER_OVERIMPLEMENTATION_GUARD =
|
|
58
|
+
"Hunt over-implementation as seriously as gaps: any validation error, required field, uniqueness/format constraint, immutability wrapper, or normalization the contract does not require is a defect that rejects inputs or produces shapes the contract permits — classify it required_by_objective. Probe at least one contract-permitted input the worker's own tests do not exercise before approving.";
|
|
59
|
+
|
|
54
60
|
export const ACCEPTANCE_MATRIX_CONTRACT = [
|
|
55
61
|
"Acceptance/contract matrix:",
|
|
56
62
|
"- Before implementing, derive an observable acceptance matrix from the literal objective and acceptance criteria: one row per explicit clause, requirement, named artifact, command, gate, invariant, and deliverable, each mapped to the concrete observable check (command, test, executable scenario, artifact inspection, or state assertion) that would prove it in the current checkout.",
|
|
57
63
|
"- Record the matrix in the receipt/implementation notes on the first turn and keep it current as work proceeds; every later completion claim must map back to matrix rows with current evidence.",
|
|
58
64
|
"- The matrix inherits the literal contract's scope: do not add rows for behavior the objective/acceptance criteria do not require, and do not drop rows because they are inconvenient to prove.",
|
|
65
|
+
"- Add one row per literal example in the objective/acceptance criteria (sample inputs/outputs, rendered text, file contents), checked character-for-character rather than paraphrased.",
|
|
66
|
+
"- Add explicit rows for each interface decision the contract constrains: return/field types by identity, required-vs-optional per field, duplicate handling, ordering, and raw-vs-normalized text. When the contract leaves such a decision open, record the permissive/preserving default chosen.",
|
|
59
67
|
"",
|
|
60
68
|
"Stateful behavior modeling:",
|
|
61
69
|
"- When the work involves stateful behavior (lifecycles, sessions, caches, persisted data, protocols, retries, concurrency, or multi-step flows), model the state space explicitly before implementing: enumerate the states, the legal transitions between them, the invariants that must hold in every state, and how illegal transitions or unexpected inputs are handled.",
|
|
62
70
|
"- Tie matrix rows for stateful clauses to specific states, transitions, and invariants so their checks exercise transitions and invariant preservation, not just happy-path end states.",
|
|
63
71
|
].join("\n");
|
|
64
72
|
|
|
73
|
+
export const CONTRACT_FIDELITY_AUDIT = [
|
|
74
|
+
"Adversarial divergence pass:",
|
|
75
|
+
"- After checks are green and before claiming readiness for review, re-read the literal objective/acceptance criteria and ask for each clause: what plausible independent check of this clause would my implementation fail?",
|
|
76
|
+
"- Probe the recurring divergence categories specifically: (1) type-identity assertions on returned values, (2) inputs with optional fields omitted, (3) duplicated or aliased inputs, (4) ordering assumptions, (5) text expected verbatim where the implementation normalizes it, and (6) any raised error the contract does not enumerate.",
|
|
77
|
+
"- Fix each divergence or record its justification in the receipt/implementation notes; an unexamined divergence category is unfinished verification, not a nice-to-have.",
|
|
78
|
+
].join("\n");
|
|
79
|
+
|
|
80
|
+
export const REVIEWER_INTERCOM_COORDINATION_PROTOCOL = [
|
|
81
|
+
"Concurrent reviewer coordination protocol:",
|
|
82
|
+
"- At review start, use Intercom to initialize/check coordination and discover sibling reviewers participating in the same workflow run.",
|
|
83
|
+
"- Tell those sibling reviewers your validation plan and intended check ownership before running checks. Claim ownership before starting any expensive, lock-prone, or potentially conflicting command that uses a shared checkout or shared environment.",
|
|
84
|
+
"- Coordinate and serialize conflicting shared-checkout or shared-environment commands, including full test suites, build or test commands, package-manager operations, browser or E2E sessions, migrations, and generated-artifact steps. Announce each coordinated check when it starts and finishes. Release every claimed resource when finished, then send siblings an explicit resource-release update. Share reusable command outcomes and evidence so siblings can avoid redundant execution where appropriate.",
|
|
85
|
+
"- Operational coordination does not make the review collective: independently inspect the patch, perform your own analysis, and produce your own verdict. Never copy or defer to a sibling reviewer's conclusions.",
|
|
86
|
+
].join("\n");
|
|
87
|
+
|
|
65
88
|
export const REVIEWER_INDEPENDENT_VERIFICATION_CONTRACT = [
|
|
66
89
|
"Independent verification derivation:",
|
|
67
|
-
"- Before relying on the worker receipt, worker-authored tests, or any prior reviewer output, derive your own adversarial check list from the literal objective and acceptance criteria alone: per-clause observable checks plus boundary, edge, negative, and invalid-input probes, and state/transition/invariant probes for stateful behavior.",
|
|
90
|
+
"- Before relying on the worker receipt, worker-authored tests, or any prior reviewer output, derive your own adversarial check list from the literal objective and acceptance criteria alone: per-clause observable checks plus boundary, edge, negative, and invalid-input probes; contract-permitted-input probes (permissive inputs the implementation might wrongly reject: optional fields omitted, duplicates or aliases present, unusual-but-allowed values) and exact type/shape/text-identity probes for anything the contract names; and state/transition/invariant probes for stateful behavior.",
|
|
68
91
|
"- Execute or delegate the highest-value derived checks against the current repository state before mapping worker evidence to requirements.",
|
|
69
92
|
"- Worker-authored tests, snapshots, and receipts corroborate your derived checks; they never substitute for them. Passing worker-authored tests is circular evidence for the clauses those tests were written from.",
|
|
70
93
|
"- Keep derived checks inside the literal contract's scope; do not manufacture requirements beyond the objective/acceptance criteria.",
|
|
@@ -23,6 +23,8 @@
|
|
|
23
23
|
|
|
24
24
|
import type { WorkflowSerializableValue } from "../shared/types.js";
|
|
25
25
|
import { createHash } from "node:crypto";
|
|
26
|
+
import { isDurableWorkflowResumable } from "./resume-eligibility.js";
|
|
27
|
+
import { DURABLE_FORMAT_VERSION } from "./format-version.js";
|
|
26
28
|
import type {
|
|
27
29
|
DurableCheckpoint,
|
|
28
30
|
DurableCheckpointEntry,
|
|
@@ -94,8 +96,13 @@ export interface DurableWorkflowBackend {
|
|
|
94
96
|
/** Look up a cached stage output by replay key. */
|
|
95
97
|
getStageOutput(workflowId: string, replayKey: string): WorkflowSerializableValue | undefined;
|
|
96
98
|
|
|
97
|
-
/** Look up resumable stage session
|
|
98
|
-
getStageSession(workflowId: string, replayKey: string): {
|
|
99
|
+
/** Look up the latest resumable stage session and accumulated active timing. */
|
|
100
|
+
getStageSession(workflowId: string, replayKey: string): {
|
|
101
|
+
sessionId?: string;
|
|
102
|
+
sessionFile?: string;
|
|
103
|
+
startedAt?: number;
|
|
104
|
+
durationMs?: number;
|
|
105
|
+
} | undefined;
|
|
99
106
|
|
|
100
107
|
/** List all checkpoints for a workflow (in completion order). */
|
|
101
108
|
listCheckpoints(workflowId: string): readonly DurableCheckpoint[];
|
|
@@ -107,14 +114,22 @@ export interface DurableWorkflowBackend {
|
|
|
107
114
|
setWorkflowStatus(workflowId: string, status: DurableWorkflowStatus, pendingPrompts?: number, resumable?: boolean): void;
|
|
108
115
|
|
|
109
116
|
/**
|
|
110
|
-
* List resumable workflows
|
|
111
|
-
*
|
|
117
|
+
* List resumable root workflows: running/paused runs with progress and
|
|
118
|
+
* failed/blocked runs unless explicitly marked non-resumable.
|
|
112
119
|
*/
|
|
113
120
|
listResumableWorkflows(): readonly ResumableWorkflowEntry[];
|
|
121
|
+
/** List successful completed root workflows with durable checkpoint progress. */
|
|
122
|
+
listCompletedWorkflows(): readonly ResumableWorkflowEntry[];
|
|
114
123
|
|
|
115
124
|
/** Export a session-cache entry for the given workflow (for JSONL persistence). */
|
|
116
125
|
toCacheEntry(workflowId: string): DurableCheckpointEntry | undefined;
|
|
117
126
|
|
|
127
|
+
/** Permanently remove one root workflow and its durable checkpoints. */
|
|
128
|
+
deleteWorkflow(workflowId: string): Promise<void>;
|
|
129
|
+
|
|
130
|
+
/** Whether a workflow id may be exposed or resumed from live/restored metadata. */
|
|
131
|
+
isWorkflowLoadable(workflowId: string): boolean;
|
|
132
|
+
|
|
118
133
|
/** Clear all state (for tests). */
|
|
119
134
|
reset(): void;
|
|
120
135
|
|
|
@@ -185,8 +200,10 @@ function checkpointKey(c: DurableCheckpoint): string {
|
|
|
185
200
|
export class InMemoryDurableBackend implements DurableWorkflowBackend {
|
|
186
201
|
public readonly persistent = false;
|
|
187
202
|
private readonly workflows = new Map<string, InMemoryWorkflowRecord>();
|
|
203
|
+
private readonly deletedWorkflowIds = new Set<string>();
|
|
188
204
|
|
|
189
205
|
registerWorkflow(handle: WorkflowRegistrationInput): void {
|
|
206
|
+
this.deletedWorkflowIds.delete(handle.workflowId);
|
|
190
207
|
const existing = this.workflows.get(handle.workflowId);
|
|
191
208
|
const completedCheckpoints = handle.completedCheckpoints ?? existing?.handle.completedCheckpoints ?? 0;
|
|
192
209
|
const pendingPrompts = handle.pendingPrompts ?? existing?.handle.pendingPrompts ?? 0;
|
|
@@ -246,10 +263,20 @@ export class InMemoryDurableBackend implements DurableWorkflowBackend {
|
|
|
246
263
|
return checkpoint !== undefined && "output" in checkpoint ? checkpoint.output : undefined;
|
|
247
264
|
}
|
|
248
265
|
|
|
249
|
-
getStageSession(workflowId: string, replayKey: string): {
|
|
266
|
+
getStageSession(workflowId: string, replayKey: string): {
|
|
267
|
+
sessionId?: string;
|
|
268
|
+
sessionFile?: string;
|
|
269
|
+
startedAt?: number;
|
|
270
|
+
durationMs?: number;
|
|
271
|
+
} | undefined {
|
|
250
272
|
const checkpoint = this.workflows.get(workflowId)?.stageSessionByReplayKey.get(replayKey);
|
|
251
273
|
if (checkpoint?.sessionId === undefined && checkpoint?.sessionFile === undefined) return undefined;
|
|
252
|
-
return {
|
|
274
|
+
return {
|
|
275
|
+
...(checkpoint.sessionId !== undefined ? { sessionId: checkpoint.sessionId } : {}),
|
|
276
|
+
...(checkpoint.sessionFile !== undefined ? { sessionFile: checkpoint.sessionFile } : {}),
|
|
277
|
+
...(checkpoint.startedAt !== undefined ? { startedAt: checkpoint.startedAt } : {}),
|
|
278
|
+
...(checkpoint.durationMs !== undefined ? { durationMs: checkpoint.durationMs } : {}),
|
|
279
|
+
};
|
|
253
280
|
}
|
|
254
281
|
|
|
255
282
|
listCheckpoints(workflowId: string): readonly DurableCheckpoint[] {
|
|
@@ -270,7 +297,13 @@ export class InMemoryDurableBackend implements DurableWorkflowBackend {
|
|
|
270
297
|
|
|
271
298
|
listResumableWorkflows(): readonly ResumableWorkflowEntry[] {
|
|
272
299
|
return [...this.workflows.values()]
|
|
273
|
-
.filter((rec) =>
|
|
300
|
+
.filter((rec) => isDurableWorkflowResumable(rec.handle))
|
|
301
|
+
.map((rec) => toResumableEntry(rec.handle));
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
listCompletedWorkflows(): readonly ResumableWorkflowEntry[] {
|
|
305
|
+
return [...this.workflows.values()]
|
|
306
|
+
.filter((rec) => isRootWorkflow(rec.handle) && isCompletedHandle(rec.handle))
|
|
274
307
|
.map((rec) => toResumableEntry(rec.handle));
|
|
275
308
|
}
|
|
276
309
|
|
|
@@ -279,6 +312,7 @@ export class InMemoryDurableBackend implements DurableWorkflowBackend {
|
|
|
279
312
|
if (!rec) return undefined;
|
|
280
313
|
const h = rec.handle;
|
|
281
314
|
return {
|
|
315
|
+
formatVersion: DURABLE_FORMAT_VERSION,
|
|
282
316
|
type: "workflow.durable.checkpoint",
|
|
283
317
|
workflowId: h.workflowId,
|
|
284
318
|
name: h.name,
|
|
@@ -297,8 +331,18 @@ export class InMemoryDurableBackend implements DurableWorkflowBackend {
|
|
|
297
331
|
};
|
|
298
332
|
}
|
|
299
333
|
|
|
334
|
+
async deleteWorkflow(workflowId: string): Promise<void> {
|
|
335
|
+
this.workflows.delete(workflowId);
|
|
336
|
+
this.deletedWorkflowIds.add(workflowId);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
isWorkflowLoadable(workflowId: string): boolean {
|
|
340
|
+
return !this.deletedWorkflowIds.has(workflowId);
|
|
341
|
+
}
|
|
342
|
+
|
|
300
343
|
reset(): void {
|
|
301
344
|
this.workflows.clear();
|
|
345
|
+
this.deletedWorkflowIds.clear();
|
|
302
346
|
}
|
|
303
347
|
|
|
304
348
|
/** Export all records (for FileDurableBackend serialization or debugging). */
|
|
@@ -323,14 +367,8 @@ function hasResumeProgress(handle: DurableWorkflowHandle): boolean {
|
|
|
323
367
|
return handle.completedCheckpoints > 0 || handle.pendingPrompts > 0;
|
|
324
368
|
}
|
|
325
369
|
|
|
326
|
-
function
|
|
327
|
-
|
|
328
|
-
// `running`/`paused` are both resumable at the backend level: a `running`
|
|
329
|
-
// durable handle may belong to a crashed process (no live executor), which
|
|
330
|
-
// is exactly the cross-session crash-recovery case. Same-session
|
|
331
|
-
// double-resume is prevented by the command layer, which hides durable
|
|
332
|
-
// entries that match an active live run.
|
|
333
|
-
return (handle.status === "running" || handle.status === "paused") && hasResumeProgress(handle);
|
|
370
|
+
function isCompletedHandle(handle: DurableWorkflowHandle): boolean {
|
|
371
|
+
return handle.status === "completed" && hasResumeProgress(handle);
|
|
334
372
|
}
|
|
335
373
|
|
|
336
374
|
function toResumableEntry(handle: DurableWorkflowHandle): ResumableWorkflowEntry {
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import { readFileSync, statSync } from "node:fs";
|
|
2
|
+
import type { RunSnapshot, StageSnapshot } from "../shared/store-types.js";
|
|
3
|
+
import type { WorkflowInputValues } from "../shared/types.js";
|
|
4
|
+
import type { DurableWorkflowBackend } from "./backend.js";
|
|
5
|
+
import type {
|
|
6
|
+
DurableCheckpoint,
|
|
7
|
+
DurableStageCheckpoint,
|
|
8
|
+
ResumableWorkflowEntry,
|
|
9
|
+
} from "./types.js";
|
|
10
|
+
import { resolveDurableEntry } from "./resume-runtime.js";
|
|
11
|
+
|
|
12
|
+
export type CompletedWorkflowResolution =
|
|
13
|
+
| { readonly kind: "found"; readonly entry: ResumableWorkflowEntry; readonly snapshot: RunSnapshot }
|
|
14
|
+
| { readonly kind: "ambiguous"; readonly matches: readonly ResumableWorkflowEntry[] }
|
|
15
|
+
| { readonly kind: "not_found" }
|
|
16
|
+
| { readonly kind: "stale"; readonly entry: ResumableWorkflowEntry };
|
|
17
|
+
|
|
18
|
+
interface SessionTranscriptEntry {
|
|
19
|
+
readonly type?: string;
|
|
20
|
+
readonly id?: string;
|
|
21
|
+
readonly timestamp?: string;
|
|
22
|
+
readonly message?: {
|
|
23
|
+
readonly role?: string;
|
|
24
|
+
readonly content?: string | object;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface StageDraft {
|
|
29
|
+
readonly replayKey: string;
|
|
30
|
+
readonly name: string;
|
|
31
|
+
readonly firstCompletedAt: number;
|
|
32
|
+
readonly output?: DurableStageCheckpoint["output"];
|
|
33
|
+
readonly result?: string;
|
|
34
|
+
readonly sessionId?: string;
|
|
35
|
+
readonly sessionFile?: string;
|
|
36
|
+
readonly startedAt?: number;
|
|
37
|
+
readonly endedAt?: number;
|
|
38
|
+
readonly durationMs?: number;
|
|
39
|
+
readonly model?: string;
|
|
40
|
+
readonly fastMode?: boolean;
|
|
41
|
+
readonly attemptedModels?: readonly string[];
|
|
42
|
+
readonly modelAttempts?: DurableStageCheckpoint["modelAttempts"];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Authoritative completed rows. This path is deliberately separate from resumability. */
|
|
46
|
+
export function listCompletedFromBackend(
|
|
47
|
+
backend: DurableWorkflowBackend,
|
|
48
|
+
): readonly ResumableWorkflowEntry[] {
|
|
49
|
+
return backend.listCompletedWorkflows();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Completed rows whose authoritative checkpoints and referenced transcripts still exist. */
|
|
53
|
+
export function listOpenableCompletedWorkflows(
|
|
54
|
+
backend: DurableWorkflowBackend,
|
|
55
|
+
): readonly ResumableWorkflowEntry[] {
|
|
56
|
+
return listCompletedFromBackend(backend)
|
|
57
|
+
.filter((entry) => completedWorkflowSnapshot(backend, entry) !== undefined)
|
|
58
|
+
.sort((a, b) => b.updatedAt - a.updatedAt);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function resolveCompletedWorkflow(
|
|
62
|
+
workflowIdOrPrefix: string,
|
|
63
|
+
backend: DurableWorkflowBackend,
|
|
64
|
+
openableCatalog: readonly ResumableWorkflowEntry[] = listOpenableCompletedWorkflows(backend),
|
|
65
|
+
): CompletedWorkflowResolution {
|
|
66
|
+
const resolved = resolveDurableEntry(workflowIdOrPrefix, openableCatalog);
|
|
67
|
+
if (resolved !== undefined) {
|
|
68
|
+
if ("kind" in resolved) return { kind: "ambiguous", matches: resolved.matches };
|
|
69
|
+
const snapshot = completedWorkflowSnapshot(backend, resolved);
|
|
70
|
+
return snapshot === undefined
|
|
71
|
+
? { kind: "stale", entry: resolved }
|
|
72
|
+
: { kind: "found", entry: resolved, snapshot };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const authoritative = resolveDurableEntry(workflowIdOrPrefix, listCompletedFromBackend(backend));
|
|
76
|
+
if (authoritative === undefined) return { kind: "not_found" };
|
|
77
|
+
if ("kind" in authoritative) return { kind: "ambiguous", matches: authoritative.matches };
|
|
78
|
+
return { kind: "stale", entry: authoritative };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function completedWorkflowSnapshot(
|
|
82
|
+
backend: DurableWorkflowBackend,
|
|
83
|
+
entry: ResumableWorkflowEntry,
|
|
84
|
+
): RunSnapshot | undefined {
|
|
85
|
+
const handle = backend.getWorkflow(entry.workflowId);
|
|
86
|
+
if (handle === undefined || handle.status !== "completed") return undefined;
|
|
87
|
+
const checkpoints = backend.listCheckpoints(entry.workflowId);
|
|
88
|
+
if (checkpoints.length === 0) return undefined;
|
|
89
|
+
const stages = stageSnapshotsFromCheckpoints(checkpoints, handle.updatedAt).map(validatedStageTranscript);
|
|
90
|
+
if (!stages.some((stage) => stage.sessionFile !== undefined)) return undefined;
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
id: handle.workflowId,
|
|
94
|
+
name: handle.name,
|
|
95
|
+
inputs: { ...handle.inputs } as WorkflowInputValues,
|
|
96
|
+
status: "completed",
|
|
97
|
+
stages,
|
|
98
|
+
startedAt: handle.createdAt,
|
|
99
|
+
endedAt: handle.updatedAt,
|
|
100
|
+
durationMs: Math.max(0, handle.updatedAt - handle.createdAt),
|
|
101
|
+
resumable: false,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function validatedStageTranscript(stage: StageSnapshot): StageSnapshot {
|
|
106
|
+
if (stage.sessionFile === undefined || isReopenableSessionTranscript(stage.sessionFile)) return stage;
|
|
107
|
+
const { sessionFile, ...withoutSessionFile } = stage;
|
|
108
|
+
void sessionFile;
|
|
109
|
+
return withoutSessionFile;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function isReopenableSessionTranscript(path: string): boolean {
|
|
113
|
+
try {
|
|
114
|
+
const stats = statSync(path);
|
|
115
|
+
if (!stats.isFile() || stats.size === 0) return false;
|
|
116
|
+
const lines = readFileSync(path, "utf8").split("\n").filter((line) => line.trim().length > 0);
|
|
117
|
+
if (lines.length < 2) return false;
|
|
118
|
+
const entries: SessionTranscriptEntry[] = [];
|
|
119
|
+
for (const line of lines) {
|
|
120
|
+
const parsed = JSON.parse(line) as object;
|
|
121
|
+
if (typeof parsed !== "object" || parsed === null) return false;
|
|
122
|
+
entries.push(parsed as SessionTranscriptEntry);
|
|
123
|
+
}
|
|
124
|
+
const header = entries[0];
|
|
125
|
+
return header?.type === "session" && typeof header.id === "string" && entries.some(isUsableContextMessage);
|
|
126
|
+
} catch {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function isUsableContextMessage(entry: SessionTranscriptEntry): boolean {
|
|
132
|
+
return entry.type === "message"
|
|
133
|
+
&& typeof entry.id === "string"
|
|
134
|
+
&& typeof entry.timestamp === "string"
|
|
135
|
+
&& typeof entry.message?.role === "string"
|
|
136
|
+
&& hasUsableMessageContent(entry.message.content);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function hasUsableMessageContent(content: string | object | undefined): boolean {
|
|
140
|
+
if (typeof content === "string") return content.trim().length > 0;
|
|
141
|
+
return Array.isArray(content) && content.some(hasUsableContentBlock);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function hasUsableContentBlock(block: object): boolean {
|
|
145
|
+
if (typeof block !== "object" || block === null) return false;
|
|
146
|
+
const contentBlock = block as {
|
|
147
|
+
readonly text?: string;
|
|
148
|
+
readonly thinking?: string;
|
|
149
|
+
readonly data?: string;
|
|
150
|
+
readonly name?: string;
|
|
151
|
+
};
|
|
152
|
+
return [contentBlock.text, contentBlock.thinking, contentBlock.data, contentBlock.name]
|
|
153
|
+
.some((value) => typeof value === "string" && value.trim().length > 0);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function stageSnapshotsFromCheckpoints(
|
|
157
|
+
checkpoints: readonly DurableCheckpoint[],
|
|
158
|
+
fallbackCompletedAt: number,
|
|
159
|
+
): StageSnapshot[] {
|
|
160
|
+
const drafts = new Map<string, StageDraft>();
|
|
161
|
+
for (const checkpoint of checkpoints) {
|
|
162
|
+
if (checkpoint.kind !== "stage") continue;
|
|
163
|
+
const existing = drafts.get(checkpoint.replayKey);
|
|
164
|
+
drafts.set(checkpoint.replayKey, mergeStageDraft(existing, checkpoint));
|
|
165
|
+
}
|
|
166
|
+
const ordered = [...drafts.values()].sort((a, b) => a.firstCompletedAt - b.firstCompletedAt);
|
|
167
|
+
if (ordered.length === 0) return [syntheticCheckpointStage(checkpoints.length, fallbackCompletedAt)];
|
|
168
|
+
return ordered.map(stageSnapshotFromDraft);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function mergeStageDraft(
|
|
172
|
+
existing: StageDraft | undefined,
|
|
173
|
+
checkpoint: DurableStageCheckpoint,
|
|
174
|
+
): StageDraft {
|
|
175
|
+
return {
|
|
176
|
+
replayKey: checkpoint.replayKey,
|
|
177
|
+
name: existing?.name ?? checkpoint.name,
|
|
178
|
+
firstCompletedAt: Math.min(existing?.firstCompletedAt ?? checkpoint.completedAt, checkpoint.completedAt),
|
|
179
|
+
...valueOrExisting("output", checkpoint, existing),
|
|
180
|
+
...valueOrExisting("result", checkpoint, existing),
|
|
181
|
+
...valueOrExisting("sessionId", checkpoint, existing),
|
|
182
|
+
...valueOrExisting("sessionFile", checkpoint, existing),
|
|
183
|
+
...valueOrExisting("startedAt", checkpoint, existing),
|
|
184
|
+
...valueOrExisting("endedAt", checkpoint, existing),
|
|
185
|
+
...valueOrExisting("durationMs", checkpoint, existing),
|
|
186
|
+
...valueOrExisting("model", checkpoint, existing),
|
|
187
|
+
...valueOrExisting("fastMode", checkpoint, existing),
|
|
188
|
+
...valueOrExisting("attemptedModels", checkpoint, existing),
|
|
189
|
+
...valueOrExisting("modelAttempts", checkpoint, existing),
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function valueOrExisting<
|
|
194
|
+
K extends keyof Omit<StageDraft, "replayKey" | "name" | "firstCompletedAt">
|
|
195
|
+
>(key: K, checkpoint: DurableStageCheckpoint, existing: StageDraft | undefined): Pick<StageDraft, K> | object {
|
|
196
|
+
const checkpointValue = checkpoint[key];
|
|
197
|
+
if (checkpointValue !== undefined) return { [key]: checkpointValue } as Pick<StageDraft, K>;
|
|
198
|
+
const existingValue = existing?.[key];
|
|
199
|
+
return existingValue === undefined ? {} : { [key]: existingValue } as Pick<StageDraft, K>;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function stageSnapshotFromDraft(draft: StageDraft, index: number): StageSnapshot {
|
|
203
|
+
const startedAt = draft.startedAt ?? draft.firstCompletedAt;
|
|
204
|
+
const endedAt = draft.endedAt ?? draft.firstCompletedAt;
|
|
205
|
+
return {
|
|
206
|
+
id: `completed-stage-${index + 1}`,
|
|
207
|
+
name: draft.name,
|
|
208
|
+
status: "completed",
|
|
209
|
+
parentIds: [],
|
|
210
|
+
startedAt,
|
|
211
|
+
endedAt,
|
|
212
|
+
durationMs: draft.durationMs ?? Math.max(0, endedAt - startedAt),
|
|
213
|
+
...(stageResult(draft) !== undefined ? { result: stageResult(draft) } : {}),
|
|
214
|
+
replayKey: draft.replayKey,
|
|
215
|
+
toolEvents: [],
|
|
216
|
+
attachable: false,
|
|
217
|
+
...(draft.sessionId !== undefined ? { sessionId: draft.sessionId } : {}),
|
|
218
|
+
...(draft.sessionFile !== undefined ? { sessionFile: draft.sessionFile } : {}),
|
|
219
|
+
...(draft.model !== undefined ? { model: draft.model } : {}),
|
|
220
|
+
...(draft.fastMode !== undefined ? { fastMode: draft.fastMode } : {}),
|
|
221
|
+
...(draft.attemptedModels !== undefined ? { attemptedModels: draft.attemptedModels } : {}),
|
|
222
|
+
...(draft.modelAttempts !== undefined ? { modelAttempts: draft.modelAttempts } : {}),
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function stageResult(draft: StageDraft): string | undefined {
|
|
227
|
+
if (draft.result !== undefined) return draft.result;
|
|
228
|
+
if (draft.output === undefined) return undefined;
|
|
229
|
+
return typeof draft.output === "string" ? draft.output : JSON.stringify(draft.output);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function syntheticCheckpointStage(checkpointCount: number, completedAt: number): StageSnapshot {
|
|
233
|
+
return {
|
|
234
|
+
id: "completed-checkpoints",
|
|
235
|
+
name: "durable checkpoints",
|
|
236
|
+
status: "completed",
|
|
237
|
+
parentIds: [],
|
|
238
|
+
startedAt: completedAt,
|
|
239
|
+
endedAt: completedAt,
|
|
240
|
+
durationMs: 0,
|
|
241
|
+
result: `${checkpointCount} durable checkpoint${checkpointCount === 1 ? "" : "s"}`,
|
|
242
|
+
toolEvents: [],
|
|
243
|
+
attachable: false,
|
|
244
|
+
};
|
|
245
|
+
}
|