@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
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import type { Store } from "../shared/store.js";
|
|
2
|
+
import type { RunSnapshot, StageSnapshot } from "../shared/store-types.js";
|
|
3
|
+
import { createStageContext, type StageAdapters } from "../runs/foreground/stage-runner.js";
|
|
4
|
+
import {
|
|
5
|
+
stageControlRegistry as defaultStageControlRegistry,
|
|
6
|
+
type AgentSessionEventListener,
|
|
7
|
+
type StageControlHandle,
|
|
8
|
+
type StageControlRegistry,
|
|
9
|
+
} from "../runs/foreground/stage-control-registry.js";
|
|
10
|
+
import type { DurableWorkflowBackend } from "./backend.js";
|
|
11
|
+
import {
|
|
12
|
+
listOpenableCompletedWorkflows,
|
|
13
|
+
resolveCompletedWorkflow,
|
|
14
|
+
} from "./completed-catalog.js";
|
|
15
|
+
import type { ResumableWorkflowEntry } from "./types.js";
|
|
16
|
+
|
|
17
|
+
export type OpenCompletedDurableResult =
|
|
18
|
+
| { readonly ok: true; readonly runId: string; readonly workflowId: string; readonly name: string; readonly message: string }
|
|
19
|
+
| { readonly ok: false; readonly reason: "not_found" | "ambiguous" | "stale" | "active"; readonly message: string };
|
|
20
|
+
|
|
21
|
+
export interface OpenCompletedDurableDeps {
|
|
22
|
+
readonly durableBackend: DurableWorkflowBackend;
|
|
23
|
+
readonly store: Store;
|
|
24
|
+
readonly adapters?: StageAdapters;
|
|
25
|
+
readonly stageControlRegistry?: StageControlRegistry;
|
|
26
|
+
readonly cwd?: string;
|
|
27
|
+
readonly defaultSessionDir?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface CompletedChatRegistration {
|
|
31
|
+
readonly handle: StageControlHandle;
|
|
32
|
+
readonly unregister: () => void;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const completedChatRegistrations = new WeakMap<
|
|
36
|
+
StageControlRegistry,
|
|
37
|
+
Map<string, CompletedChatRegistration>
|
|
38
|
+
>();
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Open a completed durable workflow as an immutable run snapshot. The only
|
|
42
|
+
* mutable surface is a lazily reopened stage chat, which appends follow-up
|
|
43
|
+
* conversation to its retained Atomic session without dispatching the workflow.
|
|
44
|
+
*/
|
|
45
|
+
export function openCompletedDurableWorkflow(
|
|
46
|
+
workflowIdOrPrefix: string,
|
|
47
|
+
deps: OpenCompletedDurableDeps,
|
|
48
|
+
catalog: readonly ResumableWorkflowEntry[] = listOpenableCompletedWorkflows(deps.durableBackend),
|
|
49
|
+
): OpenCompletedDurableResult {
|
|
50
|
+
const resolved = resolveCompletedWorkflow(workflowIdOrPrefix, deps.durableBackend, catalog);
|
|
51
|
+
if (resolved.kind === "not_found") {
|
|
52
|
+
return failure("not_found", `No completed durable workflow found for id/prefix: ${workflowIdOrPrefix}`);
|
|
53
|
+
}
|
|
54
|
+
if (resolved.kind === "ambiguous") {
|
|
55
|
+
const matches = resolved.matches.map((entry) => `${entry.name} (${entry.workflowId.slice(0, 8)})`).join(", ");
|
|
56
|
+
return failure("ambiguous", `Ambiguous completed workflow prefix "${workflowIdOrPrefix}" matches: ${matches}`);
|
|
57
|
+
}
|
|
58
|
+
if (resolved.kind === "stale") {
|
|
59
|
+
return failure(
|
|
60
|
+
"stale",
|
|
61
|
+
`Completed workflow ${resolved.entry.workflowId.slice(0, 8)} is stale or missing durable checkpoint/session data and cannot be opened.`,
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const existing = deps.store.runs().find((run) => run.id === resolved.snapshot.id);
|
|
66
|
+
if (existing !== undefined && existing.status !== "completed") {
|
|
67
|
+
return failure(
|
|
68
|
+
"active",
|
|
69
|
+
`Workflow ${resolved.snapshot.id.slice(0, 8)} is already active in this session; attach with /workflow connect ${resolved.snapshot.id.slice(0, 8)} instead.`,
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
const snapshot = resolved.snapshot;
|
|
73
|
+
if (existing !== undefined) deps.store.removeRun(existing.id);
|
|
74
|
+
deps.store.recordRunStart(snapshot);
|
|
75
|
+
registerCompletedChatHandles(snapshot, deps);
|
|
76
|
+
return {
|
|
77
|
+
ok: true,
|
|
78
|
+
runId: snapshot.id,
|
|
79
|
+
workflowId: snapshot.id,
|
|
80
|
+
name: snapshot.name,
|
|
81
|
+
message: `Opened completed durable workflow "${snapshot.name}" (${snapshot.id.slice(0, 8)}) for read-only inspection and follow-up chat.`,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function failure(
|
|
86
|
+
reason: "not_found" | "ambiguous" | "stale" | "active",
|
|
87
|
+
message: string,
|
|
88
|
+
): OpenCompletedDurableResult {
|
|
89
|
+
return { ok: false, reason, message };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function registerCompletedChatHandles(
|
|
93
|
+
snapshot: RunSnapshot,
|
|
94
|
+
deps: OpenCompletedDurableDeps,
|
|
95
|
+
): void {
|
|
96
|
+
if (deps.adapters?.agentSession === undefined) return;
|
|
97
|
+
const registry = deps.stageControlRegistry ?? defaultStageControlRegistry;
|
|
98
|
+
const registrations = completedChatRegistrations.get(registry) ?? new Map();
|
|
99
|
+
completedChatRegistrations.set(registry, registrations);
|
|
100
|
+
const desiredKeys = new Set(
|
|
101
|
+
snapshot.stages
|
|
102
|
+
.filter((stage) => stage.sessionFile !== undefined)
|
|
103
|
+
.map((stage) => completedChatKey(snapshot.id, stage.id)),
|
|
104
|
+
);
|
|
105
|
+
for (const [key, registration] of registrations) {
|
|
106
|
+
if (!key.startsWith(`${snapshot.id}:`) || desiredKeys.has(key)) continue;
|
|
107
|
+
removeCompletedChatRegistration(registrations, key, registration);
|
|
108
|
+
}
|
|
109
|
+
for (const stage of snapshot.stages) {
|
|
110
|
+
if (stage.sessionFile === undefined) continue;
|
|
111
|
+
const key = completedChatKey(snapshot.id, stage.id);
|
|
112
|
+
const registration = registrations.get(key);
|
|
113
|
+
const existing = registry.get(snapshot.id, stage.id);
|
|
114
|
+
if (existing?.sessionFile === stage.sessionFile && !existing.isDisposed) continue;
|
|
115
|
+
if (registration !== undefined) {
|
|
116
|
+
removeCompletedChatRegistration(registrations, key, registration);
|
|
117
|
+
} else if (existing !== undefined) {
|
|
118
|
+
disposeCompletedChatHandle(existing);
|
|
119
|
+
}
|
|
120
|
+
const handle = createCompletedChatHandle(snapshot, stage, stage.sessionFile, deps.adapters, deps.cwd, deps.defaultSessionDir);
|
|
121
|
+
const unregister = registry.register(handle);
|
|
122
|
+
registrations.set(key, { handle, unregister });
|
|
123
|
+
registry.detachControl(snapshot.id, stage.id, handle);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function completedChatKey(runId: string, stageId: string): string {
|
|
128
|
+
return `${runId}:${stageId}`;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function removeCompletedChatRegistration(
|
|
132
|
+
registrations: Map<string, CompletedChatRegistration>,
|
|
133
|
+
key: string,
|
|
134
|
+
registration: CompletedChatRegistration,
|
|
135
|
+
): void {
|
|
136
|
+
registration.unregister();
|
|
137
|
+
registrations.delete(key);
|
|
138
|
+
disposeCompletedChatHandle(registration.handle);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function disposeCompletedChatHandle(handle: StageControlHandle): void {
|
|
142
|
+
void Promise.resolve(handle.dispose?.()).catch((error: Error) => {
|
|
143
|
+
console.warn("atomic-workflows: completed chat handle dispose failed", error);
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function createCompletedChatHandle(
|
|
148
|
+
run: RunSnapshot,
|
|
149
|
+
stage: StageSnapshot,
|
|
150
|
+
sessionFile: string,
|
|
151
|
+
adapters: StageAdapters,
|
|
152
|
+
cwd: string | undefined,
|
|
153
|
+
defaultSessionDir: string | undefined,
|
|
154
|
+
): StageControlHandle {
|
|
155
|
+
const context = createStageContext({
|
|
156
|
+
runId: run.id,
|
|
157
|
+
stageId: stage.id,
|
|
158
|
+
stageName: stage.name,
|
|
159
|
+
adapters,
|
|
160
|
+
stageOptions: {
|
|
161
|
+
resumeFromSessionFile: sessionFile,
|
|
162
|
+
...(cwd !== undefined ? { cwd } : {}),
|
|
163
|
+
},
|
|
164
|
+
...(defaultSessionDir !== undefined ? { defaultSessionDir } : {}),
|
|
165
|
+
});
|
|
166
|
+
let disposed = false;
|
|
167
|
+
const ensureAttached = async (): Promise<void> => {
|
|
168
|
+
if (disposed) throw new Error(`Completed stage chat "${stage.name}" is closed.`);
|
|
169
|
+
if (context.__sessionMeta().sessionFile === undefined) {
|
|
170
|
+
await context.__ensureSessionFromFile(sessionFile);
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
return {
|
|
174
|
+
runId: run.id,
|
|
175
|
+
stageId: stage.id,
|
|
176
|
+
stageName: stage.name,
|
|
177
|
+
status: "completed",
|
|
178
|
+
get sessionId() { return context.__sessionMeta().sessionId ?? stage.sessionId; },
|
|
179
|
+
get sessionFile() { return context.__sessionMeta().sessionFile ?? sessionFile; },
|
|
180
|
+
get isStreaming() { return context.isStreaming; },
|
|
181
|
+
get isDisposed() { return disposed; },
|
|
182
|
+
get messages() { return context.messages; },
|
|
183
|
+
get agentSession() { return context.__agentSession(); },
|
|
184
|
+
async ensureAttached() { await ensureAttached(); },
|
|
185
|
+
async prompt(text: string) {
|
|
186
|
+
await ensureAttached();
|
|
187
|
+
await context.prompt(text);
|
|
188
|
+
},
|
|
189
|
+
async steer(text: string) {
|
|
190
|
+
await ensureAttached();
|
|
191
|
+
await context.steer(text);
|
|
192
|
+
},
|
|
193
|
+
async followUp(text: string) {
|
|
194
|
+
await ensureAttached();
|
|
195
|
+
await context.followUp(text);
|
|
196
|
+
},
|
|
197
|
+
async pause() {
|
|
198
|
+
throw new Error("Completed workflow snapshots cannot be paused or resumed.");
|
|
199
|
+
},
|
|
200
|
+
async resume(message?: string) {
|
|
201
|
+
if (message !== undefined && message.trim().length > 0) {
|
|
202
|
+
await ensureAttached();
|
|
203
|
+
await context.prompt(message);
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
subscribe(listener: AgentSessionEventListener) { return context.subscribe(listener); },
|
|
207
|
+
async dispose() {
|
|
208
|
+
if (disposed) return;
|
|
209
|
+
disposed = true;
|
|
210
|
+
await context.__dispose();
|
|
211
|
+
},
|
|
212
|
+
};
|
|
213
|
+
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
/** DBOS-backed durable backend adapter, loaded only when configured. */
|
|
2
2
|
|
|
3
|
-
import type { DurableCheckpoint,
|
|
3
|
+
import type { DurableCheckpoint, DurableWorkflowHandle, DurableWorkflowStatus, ResumableWorkflowEntry } from "./types.js";
|
|
4
4
|
import type { WorkflowSerializableValue } from "../shared/types.js";
|
|
5
5
|
import type { WorkflowSerializableObject as DurableInputs } from "./types.js";
|
|
6
6
|
import { InMemoryDurableBackend, type DurableWorkflowBackend, type WorkflowRegistrationInput } from "./backend.js";
|
|
7
|
-
import { encodeCheckpoint,
|
|
7
|
+
import { encodeCheckpoint, classifyCheckpointPayload } from "./dbos-envelope.js";
|
|
8
|
+
import { classifyLatestMetadata, encodeMetadata, isMetadataStep, metadataStepName } from "./dbos-metadata.js";
|
|
9
|
+
import { DBOS_DELETION_STEP, classifyDbosDeletionTombstone, encodeDbosDeletionTombstone } from "./dbos-tombstone.js";
|
|
8
10
|
|
|
9
11
|
// ---------------------------------------------------------------------------
|
|
10
12
|
// SDK abstraction
|
|
@@ -28,6 +30,8 @@ export interface DbosSdkHandle {
|
|
|
28
30
|
readonly listStepRecords: (workflowId: string) => Promise<readonly DbosStepRecord[]>;
|
|
29
31
|
/** Record a checkpoint step output (envelope) to DBOS. */
|
|
30
32
|
readonly recordStepOutput: (workflowId: string, stepName: string, output: WorkflowSerializableValue) => Promise<void>;
|
|
33
|
+
/** Permanently delete a root workflow and all prefix checkpoint records. */
|
|
34
|
+
readonly deleteWorkflowData: (workflowId: string) => Promise<void>;
|
|
31
35
|
}
|
|
32
36
|
|
|
33
37
|
export interface DbosWorkflowInfo {
|
|
@@ -81,6 +85,7 @@ interface DbosStatic {
|
|
|
81
85
|
resumeWorkflow(workflowId: string): Promise<DbosWorkflowHandle>;
|
|
82
86
|
cancelWorkflow(workflowId: string, options?: { readonly cancelChildren?: boolean }): Promise<void>;
|
|
83
87
|
listWorkflows(input: Record<string, WorkflowSerializableValue>): Promise<readonly DbosStatus[]>;
|
|
88
|
+
deleteWorkflows(workflowIds: string[], deleteChildren?: boolean): Promise<void>;
|
|
84
89
|
}
|
|
85
90
|
|
|
86
91
|
export function isDbosConfigured(): boolean {
|
|
@@ -158,6 +163,17 @@ function createRealDbosHandle(
|
|
|
158
163
|
async recordStepOutput(workflowId, stepName, output) {
|
|
159
164
|
await dbos.startWorkflow(checkpointWorkflow, { workflowID: checkpointId(workflowId, stepName) })(workflowId, stepName, output);
|
|
160
165
|
},
|
|
166
|
+
async deleteWorkflowData(workflowId) {
|
|
167
|
+
const prefix = `${workflowId}:checkpoint:`;
|
|
168
|
+
const checkpointIds: string[] = [];
|
|
169
|
+
const pageSize = 1_000;
|
|
170
|
+
for (let offset = 0;; offset += pageSize) {
|
|
171
|
+
const page = await dbos.listWorkflows({ workflow_id_prefix: prefix, limit: pageSize, offset });
|
|
172
|
+
checkpointIds.push(...page.map((status) => status.workflowID ?? status.workflowId ?? "").filter((id) => id.length > 0));
|
|
173
|
+
if (page.length < pageSize) break;
|
|
174
|
+
}
|
|
175
|
+
await dbos.deleteWorkflows([...new Set([workflowId, ...checkpointIds])], true);
|
|
176
|
+
},
|
|
161
177
|
};
|
|
162
178
|
}
|
|
163
179
|
|
|
@@ -202,6 +218,9 @@ export class DbosDurableBackend implements DurableWorkflowBackend {
|
|
|
202
218
|
private readonly mem = new InMemoryDurableBackend();
|
|
203
219
|
private readonly sdk: DbosSdkHandle;
|
|
204
220
|
private readonly hydrated = new Set<string>();
|
|
221
|
+
private readonly incompatible = new Set<string>();
|
|
222
|
+
private readonly compatible = new Set<string>();
|
|
223
|
+
private readonly locallyRegistered = new Set<string>();
|
|
205
224
|
private writeQueue: Promise<void> = Promise.resolve();
|
|
206
225
|
private writeErrors: Error[] = [];
|
|
207
226
|
|
|
@@ -210,6 +229,9 @@ export class DbosDurableBackend implements DurableWorkflowBackend {
|
|
|
210
229
|
}
|
|
211
230
|
|
|
212
231
|
registerWorkflow(handle: WorkflowRegistrationInput): void {
|
|
232
|
+
this.incompatible.delete(handle.workflowId);
|
|
233
|
+
this.compatible.add(handle.workflowId);
|
|
234
|
+
this.locallyRegistered.add(handle.workflowId);
|
|
213
235
|
this.mem.registerWorkflow(handle);
|
|
214
236
|
this.enqueueWrite(async () => {
|
|
215
237
|
await this.sdk.startWorkflow(handle.workflowId, handle.name, handle.inputs);
|
|
@@ -218,12 +240,15 @@ export class DbosDurableBackend implements DurableWorkflowBackend {
|
|
|
218
240
|
}
|
|
219
241
|
|
|
220
242
|
recordCheckpoint(checkpoint: DurableCheckpoint): void {
|
|
243
|
+
if (!this.isWorkflowLoadable(checkpoint.workflowId)) return;
|
|
221
244
|
this.mem.recordCheckpoint(checkpoint);
|
|
222
245
|
this.enqueueWrite(() => this.persistCheckpoint(checkpoint));
|
|
223
246
|
}
|
|
224
247
|
|
|
225
248
|
async recordCheckpointAsync(checkpoint: DurableCheckpoint): Promise<void> {
|
|
249
|
+
if (!this.isWorkflowLoadable(checkpoint.workflowId)) return;
|
|
226
250
|
await this.enqueueWrite(async () => {
|
|
251
|
+
if (!this.isWorkflowLoadable(checkpoint.workflowId)) return;
|
|
227
252
|
await this.persistCheckpointRecord(checkpoint);
|
|
228
253
|
this.mem.recordCheckpoint(checkpoint);
|
|
229
254
|
await this.writeMetadata(checkpoint.workflowId);
|
|
@@ -247,17 +272,48 @@ export class DbosDurableBackend implements DurableWorkflowBackend {
|
|
|
247
272
|
getWorkflow(workflowId: string): DurableWorkflowHandle | undefined { return this.mem.getWorkflow(workflowId); }
|
|
248
273
|
|
|
249
274
|
setWorkflowStatus(workflowId: string, status: DurableWorkflowStatus, pendingPrompts?: number, resumable?: boolean): void {
|
|
275
|
+
if (!this.isWorkflowLoadable(workflowId)) return;
|
|
250
276
|
this.mem.setWorkflowStatus(workflowId, status, pendingPrompts, resumable);
|
|
251
277
|
this.enqueueWrite(async () => {
|
|
278
|
+
if (!this.isWorkflowLoadable(workflowId)) return;
|
|
252
279
|
if (status === "cancelled") await this.sdk.cancelWorkflow(workflowId);
|
|
253
280
|
else if (status === "running") await this.sdk.resumeWorkflow(workflowId);
|
|
254
281
|
await this.writeMetadata(workflowId);
|
|
255
282
|
});
|
|
256
283
|
}
|
|
257
284
|
|
|
258
|
-
listResumableWorkflows(): readonly ResumableWorkflowEntry[] {
|
|
259
|
-
|
|
260
|
-
|
|
285
|
+
listResumableWorkflows(): readonly ResumableWorkflowEntry[] {
|
|
286
|
+
return this.mem.listResumableWorkflows().filter((entry) => !this.incompatible.has(entry.workflowId));
|
|
287
|
+
}
|
|
288
|
+
listCompletedWorkflows(): readonly ResumableWorkflowEntry[] {
|
|
289
|
+
return this.mem.listCompletedWorkflows().filter((entry) => !this.incompatible.has(entry.workflowId));
|
|
290
|
+
}
|
|
291
|
+
toCacheEntry(workflowId: string) { return this.incompatible.has(workflowId) ? undefined : this.mem.toCacheEntry(workflowId); }
|
|
292
|
+
async deleteWorkflow(workflowId: string): Promise<void> {
|
|
293
|
+
this.incompatible.add(workflowId);
|
|
294
|
+
this.compatible.delete(workflowId);
|
|
295
|
+
this.locallyRegistered.delete(workflowId);
|
|
296
|
+
this.hydrated.delete(workflowId);
|
|
297
|
+
await this.mem.deleteWorkflow(workflowId);
|
|
298
|
+
await this.enqueueWrite(async () => {
|
|
299
|
+
await this.sdk.deleteWorkflowData(workflowId);
|
|
300
|
+
await this.sdk.recordStepOutput(workflowId, DBOS_DELETION_STEP, encodeDbosDeletionTombstone(workflowId));
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
isWorkflowLoadable(workflowId: string): boolean {
|
|
304
|
+
return !this.incompatible.has(workflowId)
|
|
305
|
+
&& (this.locallyRegistered.has(workflowId) || this.compatible.has(workflowId));
|
|
306
|
+
}
|
|
307
|
+
reset(): void {
|
|
308
|
+
this.mem.reset();
|
|
309
|
+
this.hydrated.clear();
|
|
310
|
+
this.incompatible.clear();
|
|
311
|
+
this.compatible.clear();
|
|
312
|
+
this.locallyRegistered.clear();
|
|
313
|
+
this.writeQueue = Promise.resolve();
|
|
314
|
+
this.writeErrors = [];
|
|
315
|
+
}
|
|
316
|
+
|
|
261
317
|
async flush(): Promise<void> {
|
|
262
318
|
await this.writeQueue;
|
|
263
319
|
if (this.writeErrors.length === 0) return;
|
|
@@ -266,63 +322,76 @@ export class DbosDurableBackend implements DurableWorkflowBackend {
|
|
|
266
322
|
throw first;
|
|
267
323
|
}
|
|
268
324
|
|
|
269
|
-
/**
|
|
270
|
-
* Hydrate a single workflow's handle and checkpoints from DBOS into the
|
|
271
|
-
* in-memory mirror. Idempotent: skips workflows already hydrated with
|
|
272
|
-
* checkpoints. Safe to call before synchronous replay reads.
|
|
273
|
-
*/
|
|
274
325
|
async hydrateWorkflow(workflowId: string): Promise<void> {
|
|
275
|
-
if (this.
|
|
326
|
+
if (this.locallyRegistered.has(workflowId)) return;
|
|
276
327
|
const info = await this.sdk.retrieveWorkflow(workflowId);
|
|
277
|
-
if (info !== undefined
|
|
278
|
-
this.
|
|
279
|
-
|
|
280
|
-
name: info.name,
|
|
281
|
-
inputs: info.inputs ?? {},
|
|
282
|
-
createdAt: info.createdAt,
|
|
283
|
-
status: dbosStatusToDurable(info.status),
|
|
284
|
-
});
|
|
328
|
+
if (info !== undefined) {
|
|
329
|
+
await this.hydrateInfo(info);
|
|
330
|
+
return;
|
|
285
331
|
}
|
|
286
|
-
const
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
if (isMetadataStep(rec.stepName)) continue;
|
|
290
|
-
const cp = decodeToCheckpoint(workflowId, rec.stepName, rec.output);
|
|
291
|
-
if (cp !== undefined) this.mem.recordCheckpoint(cp);
|
|
292
|
-
}
|
|
293
|
-
this.hydrated.add(workflowId);
|
|
332
|
+
const records = await this.sdk.listStepRecords(workflowId);
|
|
333
|
+
const deletion = classifyDbosDeletionTombstone(records, workflowId);
|
|
334
|
+
if (deletion !== "absent") await this.suppressWorkflow(workflowId);
|
|
294
335
|
}
|
|
295
336
|
|
|
296
|
-
/**
|
|
297
|
-
* Hydrate all resumable workflows from DBOS into the in-memory mirror.
|
|
298
|
-
* Called by the resume/list path before enumerating resumable entries so
|
|
299
|
-
* a fresh process discovers workflows persisted by a prior session.
|
|
300
|
-
*/
|
|
301
337
|
async hydrateResumableWorkflows(): Promise<void> {
|
|
302
338
|
const all = await this.sdk.listAllWorkflows();
|
|
303
339
|
for (const info of all) {
|
|
304
|
-
if (this.
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
340
|
+
if (this.locallyRegistered.has(info.workflowId)) continue;
|
|
341
|
+
await this.hydrateInfo(info);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
private async hydrateInfo(info: DbosWorkflowInfo): Promise<void> {
|
|
346
|
+
const records = await this.sdk.listStepRecords(info.workflowId);
|
|
347
|
+
const metadata = classifyLatestMetadata(records, info.workflowId);
|
|
348
|
+
if (metadata.kind === "legacy") {
|
|
349
|
+
await this.cleanupLegacyWorkflow(info.workflowId);
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
if (metadata.kind !== "current") {
|
|
353
|
+
await this.suppressWorkflow(info.workflowId);
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
const checkpoints: DurableCheckpoint[] = [];
|
|
357
|
+
for (const record of records) {
|
|
358
|
+
if (isMetadataStep(record.stepName) || record.stepName === DBOS_DELETION_STEP) continue;
|
|
359
|
+
const classified = classifyCheckpointPayload(info.workflowId, record.stepName, record.output);
|
|
360
|
+
if (classified.kind === "legacy") {
|
|
361
|
+
await this.cleanupLegacyWorkflow(info.workflowId);
|
|
362
|
+
return;
|
|
312
363
|
}
|
|
313
|
-
if (
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
for (const rec of stepRecords) {
|
|
317
|
-
if (isMetadataStep(rec.stepName)) continue;
|
|
318
|
-
const cp = decodeToCheckpoint(info.workflowId, rec.stepName, rec.output);
|
|
319
|
-
if (cp !== undefined) this.mem.recordCheckpoint(cp);
|
|
320
|
-
}
|
|
321
|
-
this.hydrated.add(info.workflowId);
|
|
364
|
+
if (classified.kind === "unknown") {
|
|
365
|
+
await this.suppressWorkflow(info.workflowId);
|
|
366
|
+
return;
|
|
322
367
|
}
|
|
368
|
+
checkpoints.push(classified.checkpoint);
|
|
369
|
+
}
|
|
370
|
+
await this.mem.deleteWorkflow(info.workflowId);
|
|
371
|
+
this.incompatible.delete(info.workflowId);
|
|
372
|
+
this.compatible.add(info.workflowId);
|
|
373
|
+
this.applyMetadata(info.workflowId, metadata.entry);
|
|
374
|
+
checkpoints.forEach((checkpoint) => this.mem.recordCheckpoint(checkpoint));
|
|
375
|
+
this.hydrated.add(info.workflowId);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
private async cleanupLegacyWorkflow(workflowId: string): Promise<void> {
|
|
379
|
+
try {
|
|
380
|
+
await this.deleteWorkflow(workflowId);
|
|
381
|
+
} catch {
|
|
382
|
+
// deleteWorkflow marks the in-memory mirror incompatible before durable
|
|
383
|
+
// cleanup. Its write queue records/logs the error, while hydration must
|
|
384
|
+
// still return a filtered catalog and allow later discovery to retry.
|
|
323
385
|
}
|
|
324
386
|
}
|
|
325
387
|
|
|
388
|
+
private async suppressWorkflow(workflowId: string): Promise<void> {
|
|
389
|
+
this.incompatible.add(workflowId);
|
|
390
|
+
this.compatible.delete(workflowId);
|
|
391
|
+
this.hydrated.delete(workflowId);
|
|
392
|
+
await this.mem.deleteWorkflow(workflowId);
|
|
393
|
+
}
|
|
394
|
+
|
|
326
395
|
private enqueueWrite(fn: () => Promise<void>): Promise<void> {
|
|
327
396
|
const next = this.writeQueue.then(fn, fn);
|
|
328
397
|
this.writeQueue = next.catch((err) => {
|
|
@@ -339,14 +408,7 @@ export class DbosDurableBackend implements DurableWorkflowBackend {
|
|
|
339
408
|
await this.sdk.recordStepOutput(workflowId, metadataStepName(entry.ts), encodeMetadata(entry));
|
|
340
409
|
}
|
|
341
410
|
|
|
342
|
-
private applyMetadata(workflowId: string,
|
|
343
|
-
const entries = records
|
|
344
|
-
.filter((r) => isMetadataStep(r.stepName))
|
|
345
|
-
.map((r) => decodeMetadata(r.output))
|
|
346
|
-
.filter((entry): entry is DurableCheckpointEntry => entry !== undefined)
|
|
347
|
-
.sort((a, b) => a.ts - b.ts);
|
|
348
|
-
const entry = entries.at(-1);
|
|
349
|
-
if (entry === undefined) return;
|
|
411
|
+
private applyMetadata(workflowId: string, entry: import("./types.js").DurableCheckpointEntry): void {
|
|
350
412
|
this.mem.registerWorkflow({
|
|
351
413
|
workflowId,
|
|
352
414
|
name: entry.name,
|
|
@@ -367,116 +429,4 @@ export class DbosDurableBackend implements DurableWorkflowBackend {
|
|
|
367
429
|
}
|
|
368
430
|
}
|
|
369
431
|
|
|
370
|
-
|
|
371
|
-
const METADATA_VERSION = 1;
|
|
372
|
-
|
|
373
|
-
function metadataStepName(ts: number): string {
|
|
374
|
-
return `${METADATA_STEP_PREFIX}:${ts}:${crypto.randomUUID()}`;
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
function isMetadataStep(stepName: string): boolean {
|
|
378
|
-
return stepName === METADATA_STEP_PREFIX || stepName.startsWith(`${METADATA_STEP_PREFIX}:`);
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
interface DbosMetadataEnvelope {
|
|
382
|
-
readonly __atomicDurableMetadata: true;
|
|
383
|
-
readonly version: 1;
|
|
384
|
-
readonly entry: WorkflowSerializableValue;
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
function encodeMetadata(entry: DurableCheckpointEntry): WorkflowSerializableValue {
|
|
388
|
-
return {
|
|
389
|
-
__atomicDurableMetadata: true,
|
|
390
|
-
version: METADATA_VERSION,
|
|
391
|
-
entry: {
|
|
392
|
-
type: entry.type,
|
|
393
|
-
workflowId: entry.workflowId,
|
|
394
|
-
name: entry.name,
|
|
395
|
-
inputs: entry.inputs,
|
|
396
|
-
status: entry.status,
|
|
397
|
-
completedCheckpoints: entry.completedCheckpoints,
|
|
398
|
-
pendingPrompts: entry.pendingPrompts,
|
|
399
|
-
...(entry.label !== undefined ? { label: entry.label } : {}),
|
|
400
|
-
...(entry.rootWorkflowId !== undefined ? { rootWorkflowId: entry.rootWorkflowId } : {}),
|
|
401
|
-
...(entry.resumable !== undefined ? { resumable: entry.resumable } : {}),
|
|
402
|
-
...(entry.invocationCwd !== undefined ? { invocationCwd: entry.invocationCwd } : {}),
|
|
403
|
-
...(entry.workflowCwd !== undefined ? { workflowCwd: entry.workflowCwd } : {}),
|
|
404
|
-
...(entry.repositoryRoot !== undefined ? { repositoryRoot: entry.repositoryRoot } : {}),
|
|
405
|
-
...(entry.gitWorktreeRoot !== undefined ? { gitWorktreeRoot: entry.gitWorktreeRoot } : {}),
|
|
406
|
-
ts: entry.ts,
|
|
407
|
-
},
|
|
408
|
-
};
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
function decodeMetadata(value: WorkflowSerializableValue): DurableCheckpointEntry | undefined {
|
|
412
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) return undefined;
|
|
413
|
-
const raw = value as Partial<DbosMetadataEnvelope>;
|
|
414
|
-
if (raw.__atomicDurableMetadata !== true || raw.version !== METADATA_VERSION) return undefined;
|
|
415
|
-
const entry = raw.entry;
|
|
416
|
-
if (entry === undefined) return undefined;
|
|
417
|
-
return parseDurableCheckpointEntry(entry);
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
function parseDurableCheckpointEntry(value: WorkflowSerializableValue): DurableCheckpointEntry | undefined {
|
|
421
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) return undefined;
|
|
422
|
-
const entry = value as Partial<DurableCheckpointEntry>;
|
|
423
|
-
if (entry.type !== "workflow.durable.checkpoint"
|
|
424
|
-
|| typeof entry.workflowId !== "string"
|
|
425
|
-
|| typeof entry.name !== "string"
|
|
426
|
-
|| typeof entry.inputs !== "object"
|
|
427
|
-
|| entry.inputs === null
|
|
428
|
-
|| Array.isArray(entry.inputs)
|
|
429
|
-
|| typeof entry.status !== "string"
|
|
430
|
-
|| !isDurableWorkflowStatus(entry.status)
|
|
431
|
-
|| typeof entry.completedCheckpoints !== "number"
|
|
432
|
-
|| typeof entry.pendingPrompts !== "number"
|
|
433
|
-
|| typeof entry.ts !== "number"
|
|
434
|
-
|| (entry.label !== undefined && typeof entry.label !== "string")
|
|
435
|
-
|| (entry.rootWorkflowId !== undefined && typeof entry.rootWorkflowId !== "string")
|
|
436
|
-
|| (entry.resumable !== undefined && typeof entry.resumable !== "boolean")
|
|
437
|
-
|| (entry.invocationCwd !== undefined && typeof entry.invocationCwd !== "string")
|
|
438
|
-
|| (entry.workflowCwd !== undefined && typeof entry.workflowCwd !== "string")
|
|
439
|
-
|| (entry.repositoryRoot !== undefined && typeof entry.repositoryRoot !== "string")
|
|
440
|
-
|| (entry.gitWorktreeRoot !== undefined && typeof entry.gitWorktreeRoot !== "string")) {
|
|
441
|
-
return undefined;
|
|
442
|
-
}
|
|
443
|
-
return {
|
|
444
|
-
type: "workflow.durable.checkpoint",
|
|
445
|
-
workflowId: entry.workflowId,
|
|
446
|
-
name: entry.name,
|
|
447
|
-
inputs: entry.inputs,
|
|
448
|
-
status: entry.status,
|
|
449
|
-
completedCheckpoints: entry.completedCheckpoints,
|
|
450
|
-
pendingPrompts: entry.pendingPrompts,
|
|
451
|
-
ts: entry.ts,
|
|
452
|
-
...(entry.label !== undefined ? { label: entry.label } : {}),
|
|
453
|
-
...(entry.rootWorkflowId !== undefined ? { rootWorkflowId: entry.rootWorkflowId } : {}),
|
|
454
|
-
...(entry.resumable !== undefined ? { resumable: entry.resumable } : {}),
|
|
455
|
-
...(entry.invocationCwd !== undefined ? { invocationCwd: entry.invocationCwd } : {}),
|
|
456
|
-
...(entry.workflowCwd !== undefined ? { workflowCwd: entry.workflowCwd } : {}),
|
|
457
|
-
...(entry.repositoryRoot !== undefined ? { repositoryRoot: entry.repositoryRoot } : {}),
|
|
458
|
-
...(entry.gitWorktreeRoot !== undefined ? { gitWorktreeRoot: entry.gitWorktreeRoot } : {}),
|
|
459
|
-
};
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
function isDurableWorkflowStatus(value: string): value is DurableWorkflowStatus {
|
|
463
|
-
return value === "running"
|
|
464
|
-
|| value === "paused"
|
|
465
|
-
|| value === "completed"
|
|
466
|
-
|| value === "failed"
|
|
467
|
-
|| value === "cancelled"
|
|
468
|
-
|| value === "blocked";
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
function dbosStatusToDurable(status: string): DurableWorkflowStatus {
|
|
472
|
-
switch (status) {
|
|
473
|
-
case "SUCCESS": return "completed";
|
|
474
|
-
case "ERROR": return "failed";
|
|
475
|
-
case "CANCELLED": return "cancelled";
|
|
476
|
-
case "PENDING":
|
|
477
|
-
case "ENQUEUED":
|
|
478
|
-
case "DELAYED":
|
|
479
|
-
return "running";
|
|
480
|
-
default: return "running";
|
|
481
|
-
}
|
|
482
|
-
}
|
|
432
|
+
// Metadata encoding/classification lives in dbos-metadata.ts to keep this adapter focused.
|