@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
|
@@ -13,6 +13,7 @@ import type { RunOpts } from "./executor-types.js";
|
|
|
13
13
|
import { run } from "./executor-run.js";
|
|
14
14
|
import {
|
|
15
15
|
cleanupPreparedWorktrees,
|
|
16
|
+
createGitWorktreeSetupCache,
|
|
16
17
|
collectWorktreeDiffs,
|
|
17
18
|
defineDirectWorkflow,
|
|
18
19
|
directModelRequestsFromChain,
|
|
@@ -23,8 +24,9 @@ import {
|
|
|
23
24
|
prepareDirectWorktrees,
|
|
24
25
|
validateDirectModels,
|
|
25
26
|
workflowDetailsFromRun,
|
|
26
|
-
|
|
27
|
+
type GitWorktreeSetupCache,
|
|
27
28
|
} from "./executor-direct-helpers.js";
|
|
29
|
+
import { writeDirectOutput } from "./executor-direct-output.js";
|
|
28
30
|
import {
|
|
29
31
|
directTaskPrompt,
|
|
30
32
|
directTaskToStep,
|
|
@@ -57,27 +59,36 @@ export async function runTask(
|
|
|
57
59
|
} catch (err) {
|
|
58
60
|
return failedDirectDetails("single", runId, 1, err, options);
|
|
59
61
|
}
|
|
60
|
-
const
|
|
62
|
+
const workflowInvocationCwd = runOptions.cwd ?? process.cwd();
|
|
63
|
+
const prepared = prepareDirectWorktrees([taskWithDefaults], options, runId, "single", workflowInvocationCwd);
|
|
61
64
|
const preparedTask = prepared.tasks[0]!;
|
|
65
|
+
const gitWorktreeSetupCache = createGitWorktreeSetupCache();
|
|
62
66
|
const direct = defineDirectWorkflow("direct-task", async (ctx) => {
|
|
67
|
+
const rawResult = await ctx.task(preparedTask.name, directTaskToStep(preparedTask));
|
|
68
|
+
const { result, artifact } = await writeDirectOutput(
|
|
69
|
+
preparedTask, rawResult, workflowInvocationCwd, prepared.outputIsolations?.[0], gitWorktreeSetupCache,
|
|
70
|
+
);
|
|
71
|
+
const worktreeDiffs = collectWorktreeDiffs(prepared, options.artifacts !== false);
|
|
72
|
+
return {
|
|
73
|
+
results: [result],
|
|
74
|
+
text: result.text,
|
|
75
|
+
artifacts: [
|
|
76
|
+
...worktreeDiffs.artifacts,
|
|
77
|
+
...(artifact === undefined ? [] : [artifact]),
|
|
78
|
+
],
|
|
79
|
+
...(worktreeDiffs.summary === undefined ? {} : { worktreeSummary: worktreeDiffs.summary }),
|
|
80
|
+
};
|
|
81
|
+
});
|
|
82
|
+
let runResult;
|
|
83
|
+
try {
|
|
84
|
+
runResult = await run(direct, {}, { ...runOptions, runId, gitWorktreeSetupCache });
|
|
85
|
+
} finally {
|
|
63
86
|
try {
|
|
64
|
-
|
|
65
|
-
const { result, artifact } = await writeDirectOutput(preparedTask, rawResult);
|
|
66
|
-
const worktreeDiffs = collectWorktreeDiffs(prepared, options.artifacts !== false);
|
|
67
|
-
return {
|
|
68
|
-
results: [result],
|
|
69
|
-
text: result.text,
|
|
70
|
-
artifacts: [
|
|
71
|
-
...worktreeDiffs.artifacts,
|
|
72
|
-
...(artifact === undefined ? [] : [artifact]),
|
|
73
|
-
],
|
|
74
|
-
...(worktreeDiffs.summary === undefined ? {} : { worktreeSummary: worktreeDiffs.summary }),
|
|
75
|
-
};
|
|
87
|
+
gitWorktreeSetupCache.dispose();
|
|
76
88
|
} finally {
|
|
77
89
|
cleanupPreparedWorktrees(prepared);
|
|
78
90
|
}
|
|
79
|
-
}
|
|
80
|
-
const runResult = await run(direct, {}, { ...runOptions, runId });
|
|
91
|
+
}
|
|
81
92
|
const results = (runResult.result?.["results"] ?? []) as WorkflowTaskResult[];
|
|
82
93
|
return workflowDetailsFromRun("single", runResult, results, options, validationWarnings);
|
|
83
94
|
}
|
|
@@ -96,35 +107,44 @@ export async function runParallel(
|
|
|
96
107
|
} catch (err) {
|
|
97
108
|
return failedDirectDetails("parallel", runId, expanded.length, err, options);
|
|
98
109
|
}
|
|
99
|
-
const
|
|
110
|
+
const workflowInvocationCwd = runOptions.cwd ?? process.cwd();
|
|
111
|
+
const prepared = prepareDirectWorktrees(expanded, options, runId, "parallel", workflowInvocationCwd);
|
|
112
|
+
const gitWorktreeSetupCache = createGitWorktreeSetupCache();
|
|
100
113
|
const direct = defineDirectWorkflow("direct-parallel", async (ctx) => {
|
|
114
|
+
const steps = prepared.tasks.map((task) => directTaskToStep(task));
|
|
115
|
+
const rawResults = await ctx.parallel(steps, {
|
|
116
|
+
task: options.task,
|
|
117
|
+
concurrency: options.concurrency,
|
|
118
|
+
failFast: options.failFast,
|
|
119
|
+
});
|
|
120
|
+
const persisted = await Promise.all(
|
|
121
|
+
rawResults.map((result, index) => writeDirectOutput(
|
|
122
|
+
prepared.tasks[index]!, result, workflowInvocationCwd, prepared.outputIsolations?.[index], gitWorktreeSetupCache,
|
|
123
|
+
)),
|
|
124
|
+
);
|
|
125
|
+
const results = persisted.map((item) => item.result);
|
|
126
|
+
const worktreeDiffs = collectWorktreeDiffs(prepared, options.artifacts !== false);
|
|
127
|
+
const artifacts = [
|
|
128
|
+
...worktreeDiffs.artifacts,
|
|
129
|
+
...persisted.flatMap((item) => item.artifact === undefined ? [] : [item.artifact]),
|
|
130
|
+
];
|
|
131
|
+
return {
|
|
132
|
+
results,
|
|
133
|
+
count: results.length,
|
|
134
|
+
artifacts,
|
|
135
|
+
...(worktreeDiffs.summary === undefined ? {} : { worktreeSummary: worktreeDiffs.summary }),
|
|
136
|
+
};
|
|
137
|
+
});
|
|
138
|
+
let runResult;
|
|
139
|
+
try {
|
|
140
|
+
runResult = await run(direct, {}, { ...runOptions, runId, gitWorktreeSetupCache });
|
|
141
|
+
} finally {
|
|
101
142
|
try {
|
|
102
|
-
|
|
103
|
-
const rawResults = await ctx.parallel(steps, {
|
|
104
|
-
task: options.task,
|
|
105
|
-
concurrency: options.concurrency,
|
|
106
|
-
failFast: options.failFast,
|
|
107
|
-
});
|
|
108
|
-
const persisted = await Promise.all(
|
|
109
|
-
rawResults.map((result, index) => writeDirectOutput(prepared.tasks[index]!, result)),
|
|
110
|
-
);
|
|
111
|
-
const results = persisted.map((item) => item.result);
|
|
112
|
-
const worktreeDiffs = collectWorktreeDiffs(prepared, options.artifacts !== false);
|
|
113
|
-
const artifacts = [
|
|
114
|
-
...worktreeDiffs.artifacts,
|
|
115
|
-
...persisted.flatMap((item) => item.artifact === undefined ? [] : [item.artifact]),
|
|
116
|
-
];
|
|
117
|
-
return {
|
|
118
|
-
results,
|
|
119
|
-
count: results.length,
|
|
120
|
-
artifacts,
|
|
121
|
-
...(worktreeDiffs.summary === undefined ? {} : { worktreeSummary: worktreeDiffs.summary }),
|
|
122
|
-
};
|
|
143
|
+
gitWorktreeSetupCache.dispose();
|
|
123
144
|
} finally {
|
|
124
145
|
cleanupPreparedWorktrees(prepared);
|
|
125
146
|
}
|
|
126
|
-
}
|
|
127
|
-
const runResult = await run(direct, {}, { ...runOptions, runId });
|
|
147
|
+
}
|
|
128
148
|
const results = (runResult.result?.["results"] ?? []) as WorkflowTaskResult[];
|
|
129
149
|
return workflowDetailsFromRun("parallel", runResult, results, options, validationWarnings);
|
|
130
150
|
}
|
|
@@ -137,6 +157,8 @@ async function runDirectChainStep(
|
|
|
137
157
|
prior: WorkflowTaskResult | readonly WorkflowTaskResult[] | undefined,
|
|
138
158
|
options: WorkflowDirectOptions,
|
|
139
159
|
runId: string,
|
|
160
|
+
workflowInvocationCwd: string,
|
|
161
|
+
gitWorktreeSetupCache: GitWorktreeSetupCache,
|
|
140
162
|
): Promise<{ results: WorkflowTaskResult[]; artifacts: WorkflowArtifact[] }> {
|
|
141
163
|
if ("parallel" in step) {
|
|
142
164
|
const stepOptions = {
|
|
@@ -146,7 +168,9 @@ async function runDirectChainStep(
|
|
|
146
168
|
...(step.baseBranch !== undefined ? { baseBranch: step.baseBranch } : {}),
|
|
147
169
|
};
|
|
148
170
|
const expanded = expandedParallelTasks(step.parallel.map((item) => directTaskWithDefaults(item, stepOptions)));
|
|
149
|
-
const prepared = prepareDirectWorktrees(
|
|
171
|
+
const prepared = prepareDirectWorktrees(
|
|
172
|
+
expanded, stepOptions, `${runId}-s${index}`, `step-${index}`, workflowInvocationCwd,
|
|
173
|
+
);
|
|
150
174
|
try {
|
|
151
175
|
const steps = prepared.tasks.map((item) =>
|
|
152
176
|
directTaskToStep(item, directTaskPrompt(item) ?? "{previous}", item.previous ?? prior),
|
|
@@ -159,7 +183,10 @@ async function runDirectChainStep(
|
|
|
159
183
|
} as WorkflowParallelOptions);
|
|
160
184
|
const persisted = await Promise.all(
|
|
161
185
|
rawResults.map((result, taskIndex) =>
|
|
162
|
-
writeDirectOutput(
|
|
186
|
+
writeDirectOutput(
|
|
187
|
+
{ ...prepared.tasks[taskIndex]!, chainDir: options.chainDir }, result, workflowInvocationCwd,
|
|
188
|
+
prepared.outputIsolations?.[taskIndex], gitWorktreeSetupCache,
|
|
189
|
+
),
|
|
163
190
|
),
|
|
164
191
|
);
|
|
165
192
|
const worktreeDiffs = collectWorktreeDiffs(prepared, stepOptions.artifacts !== false);
|
|
@@ -176,7 +203,9 @@ async function runDirectChainStep(
|
|
|
176
203
|
}
|
|
177
204
|
|
|
178
205
|
const prompt = directTaskPrompt(step) ?? (index === 0 ? "{task}" : "{previous}");
|
|
179
|
-
const prepared = prepareDirectWorktrees(
|
|
206
|
+
const prepared = prepareDirectWorktrees(
|
|
207
|
+
[directTaskWithDefaults(step, options)], options, `${runId}-s${index}`, `step-${index}`, workflowInvocationCwd,
|
|
208
|
+
);
|
|
180
209
|
const preparedStep = prepared.tasks[0]!;
|
|
181
210
|
try {
|
|
182
211
|
const rawResult = await ctx.task(
|
|
@@ -186,7 +215,10 @@ async function runDirectChainStep(
|
|
|
186
215
|
...(typeof options.chainDir === "string" ? { chainDir: options.chainDir } : {}),
|
|
187
216
|
} as WorkflowTaskOptions,
|
|
188
217
|
);
|
|
189
|
-
const { result, artifact } = await writeDirectOutput(
|
|
218
|
+
const { result, artifact } = await writeDirectOutput(
|
|
219
|
+
{ ...preparedStep, chainDir: options.chainDir }, rawResult, workflowInvocationCwd,
|
|
220
|
+
prepared.outputIsolations?.[0], gitWorktreeSetupCache,
|
|
221
|
+
);
|
|
190
222
|
const worktreeDiffs = collectWorktreeDiffs(prepared, options.artifacts !== false);
|
|
191
223
|
return {
|
|
192
224
|
results: [result],
|
|
@@ -215,19 +247,36 @@ export async function runChain(
|
|
|
215
247
|
} catch (err) {
|
|
216
248
|
return failedDirectDetails("chain", runId, chain.length, err, options);
|
|
217
249
|
}
|
|
250
|
+
const workflowInvocationCwd = runOptions.cwd ?? process.cwd();
|
|
251
|
+
const gitWorktreeSetupCache = createGitWorktreeSetupCache();
|
|
218
252
|
const direct = defineDirectWorkflow("direct-chain", async (ctx) => {
|
|
219
253
|
const results: WorkflowTaskResult[] = [];
|
|
220
254
|
const artifacts: WorkflowArtifact[] = [];
|
|
221
255
|
let prior: WorkflowTaskResult | readonly WorkflowTaskResult[] | undefined;
|
|
222
256
|
for (let index = 0; index < chain.length; index += 1) {
|
|
223
|
-
const step = await runDirectChainStep(
|
|
257
|
+
const step = await runDirectChainStep(
|
|
258
|
+
ctx,
|
|
259
|
+
chain[index]!,
|
|
260
|
+
index,
|
|
261
|
+
options.task ?? "",
|
|
262
|
+
prior,
|
|
263
|
+
options,
|
|
264
|
+
runId,
|
|
265
|
+
workflowInvocationCwd,
|
|
266
|
+
gitWorktreeSetupCache,
|
|
267
|
+
);
|
|
224
268
|
results.push(...step.results);
|
|
225
269
|
artifacts.push(...step.artifacts);
|
|
226
270
|
prior = step.results.length === 1 ? step.results[0] : step.results;
|
|
227
271
|
}
|
|
228
272
|
return { results, count: results.length, artifacts };
|
|
229
273
|
});
|
|
230
|
-
|
|
274
|
+
let runResult;
|
|
275
|
+
try {
|
|
276
|
+
runResult = await run(direct, {}, { ...runOptions, runId, gitWorktreeSetupCache });
|
|
277
|
+
} finally {
|
|
278
|
+
gitWorktreeSetupCache.dispose();
|
|
279
|
+
}
|
|
231
280
|
const results = (runResult.result?.["results"] ?? []) as WorkflowTaskResult[];
|
|
232
281
|
return workflowDetailsFromRun("chain", runResult, results, options, validationWarnings);
|
|
233
282
|
}
|
|
@@ -7,6 +7,7 @@ import { raceAbort } from "./executor-abort.js";
|
|
|
7
7
|
import { hasExplicitFastModeCandidate } from "./executor-direct-helpers.js";
|
|
8
8
|
import { applyFailureToStage } from "./executor-lifecycle.js";
|
|
9
9
|
import { isTerminalStage } from "./executor-scheduler.js";
|
|
10
|
+
import { rebasedStageStartedAt } from "../../shared/timing.js";
|
|
10
11
|
|
|
11
12
|
export interface TrackedStageCallOptions {
|
|
12
13
|
readonly eagerSession?: boolean;
|
|
@@ -110,8 +111,9 @@ export function createTrackedStageCaller(input: {
|
|
|
110
111
|
}
|
|
111
112
|
}
|
|
112
113
|
if (trackStageLifecycle) {
|
|
114
|
+
const now = Date.now();
|
|
113
115
|
runtime.stageSnapshot.status = "running";
|
|
114
|
-
runtime.stageSnapshot.startedAt
|
|
116
|
+
runtime.stageSnapshot.startedAt ??= rebasedStageStartedAt(input.options?.durableAccumulatedDurationMs, now);
|
|
115
117
|
const hasNoExplicitModelConfig = input.options?.model === undefined && input.options?.fallbackModels === undefined;
|
|
116
118
|
const promptAdapterHandlesInitialPrompt = input.adapters.prompt !== undefined;
|
|
117
119
|
if (callOptions.eagerSession && !promptAdapterHandlesInitialPrompt && (hasNoExplicitModelConfig || await hasExplicitFastModeCandidate({
|
|
@@ -69,7 +69,7 @@ export function resolveWorkflowPath(filePath: string, baseDir: string | undefine
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
export function taskBaseDir(options: Pick<WorkflowTaskExecutionOptions, "chainDir" | "cwd">): string | undefined {
|
|
72
|
-
if (typeof options.chainDir === "string" && options.chainDir.length > 0) {
|
|
72
|
+
if (typeof options.chainDir === "string" && options.chainDir.trim().length > 0) {
|
|
73
73
|
return resolveWorkflowPath(options.chainDir, process.cwd());
|
|
74
74
|
}
|
|
75
75
|
if (typeof options.cwd === "string" && options.cwd.length > 0) {
|
|
@@ -15,6 +15,7 @@ import type { WorkflowRegistry } from "../../workflows/registry.js";
|
|
|
15
15
|
import type { CancellationRegistry } from "../background/cancellation-registry.js";
|
|
16
16
|
import type { StageAdapters } from "./stage-runner.js";
|
|
17
17
|
import type { StageControlRegistry } from "./stage-control-registry.js";
|
|
18
|
+
import type { GitWorktreeSetupCache } from "../shared/worktree.js";
|
|
18
19
|
|
|
19
20
|
export interface ResolvedInputs extends WorkflowInputValues {}
|
|
20
21
|
|
|
@@ -68,6 +69,8 @@ export interface RunOpts extends Omit<AuthoringContract.RunOpts, "adapters" | "s
|
|
|
68
69
|
stageControlRegistry?: StageControlRegistry;
|
|
69
70
|
/** Pre-allocated runId. */
|
|
70
71
|
runId?: string;
|
|
72
|
+
/** Internal reusable-worktree cache shared with direct output persistence. */
|
|
73
|
+
gitWorktreeSetupCache?: GitWorktreeSetupCache;
|
|
71
74
|
/** Replay completed stages from a failed source run, then resume at this stage. */
|
|
72
75
|
continuation?: RunContinuationOpts;
|
|
73
76
|
/**
|
|
@@ -306,7 +306,7 @@ export class StageSessionController {
|
|
|
306
306
|
const stageOptions = this.stageOptionsForCandidate(candidate, resumeOptions);
|
|
307
307
|
const created = this.opts.adapters.agentSession
|
|
308
308
|
? await this.opts.adapters.agentSession.create(
|
|
309
|
-
stripWorkflowOnlyOptions(stageOptions, this.opts.defaultSessionDir) as StageSessionCreateOptions,
|
|
309
|
+
stripWorkflowOnlyOptions(stageOptions, this.opts.defaultSessionDir, this.meta) as StageSessionCreateOptions,
|
|
310
310
|
{ ...this.meta, stageOptions },
|
|
311
311
|
)
|
|
312
312
|
: missingAdapter(consumer);
|
|
@@ -1,15 +1,38 @@
|
|
|
1
1
|
import { SessionManager, type CreateAgentSessionOptions } from "@bastani/atomic";
|
|
2
|
-
import type { StageOptions } from "../../shared/types.js";
|
|
2
|
+
import type { StageExecutionMeta, StageOptions } from "../../shared/types.js";
|
|
3
3
|
import type { AgentSessionConsumer } from "./stage-runner-types.js";
|
|
4
4
|
|
|
5
|
+
function workflowSessionOptions(meta: StageExecutionMeta) {
|
|
6
|
+
return {
|
|
7
|
+
internal: true as const,
|
|
8
|
+
workflow: { runId: meta.runId, stageId: meta.stageId, stageName: meta.stageName },
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function workflowOrchestrationContext(meta: StageExecutionMeta): NonNullable<CreateAgentSessionOptions["orchestrationContext"]> {
|
|
13
|
+
return {
|
|
14
|
+
kind: "workflow-stage",
|
|
15
|
+
workflowRunId: meta.runId,
|
|
16
|
+
workflowStageId: meta.stageId,
|
|
17
|
+
workflowStageName: meta.stageName,
|
|
18
|
+
constraints: { disableWorkflowTool: true, maxSubagentDepth: 5 },
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
5
22
|
export function stripWorkflowOnlyOptions(
|
|
6
23
|
options: StageOptions | undefined,
|
|
7
|
-
defaultSessionDir
|
|
24
|
+
defaultSessionDir: string | undefined,
|
|
25
|
+
meta: StageExecutionMeta,
|
|
8
26
|
): CreateAgentSessionOptions {
|
|
27
|
+
const classification = workflowSessionOptions(meta);
|
|
28
|
+
const orchestrationContext = workflowOrchestrationContext(meta);
|
|
9
29
|
if (!options) {
|
|
10
30
|
return defaultSessionDir === undefined
|
|
11
|
-
? {}
|
|
12
|
-
: {
|
|
31
|
+
? { orchestrationContext }
|
|
32
|
+
: {
|
|
33
|
+
orchestrationContext,
|
|
34
|
+
sessionManager: SessionManager.create(process.cwd(), defaultSessionDir, classification),
|
|
35
|
+
};
|
|
13
36
|
}
|
|
14
37
|
const {
|
|
15
38
|
schema: _schema,
|
|
@@ -20,6 +43,7 @@ export function stripWorkflowOnlyOptions(
|
|
|
20
43
|
forkFromSessionFile,
|
|
21
44
|
resumeFromSessionFile,
|
|
22
45
|
durableReplayKey: _durableReplayKey,
|
|
46
|
+
durableAccumulatedDurationMs: _durableAccumulatedDurationMs,
|
|
23
47
|
sessionDir,
|
|
24
48
|
gitWorktreeDir: _gitWorktreeDir,
|
|
25
49
|
baseBranch: _baseBranch,
|
|
@@ -31,12 +55,17 @@ export function stripWorkflowOnlyOptions(
|
|
|
31
55
|
if (resumeFromSessionFile !== undefined) {
|
|
32
56
|
sessionOptions.sessionManager = SessionManager.open(resumeFromSessionFile, effectiveSessionDir, cwd);
|
|
33
57
|
} else if (context === "fork" && forkFromSessionFile !== undefined) {
|
|
34
|
-
sessionOptions.sessionManager = SessionManager.forkFrom(
|
|
58
|
+
sessionOptions.sessionManager = SessionManager.forkFrom(
|
|
59
|
+
forkFromSessionFile,
|
|
60
|
+
cwd,
|
|
61
|
+
effectiveSessionDir,
|
|
62
|
+
classification,
|
|
63
|
+
);
|
|
35
64
|
} else if (effectiveSessionDir !== undefined) {
|
|
36
|
-
sessionOptions.sessionManager = SessionManager.create(cwd, effectiveSessionDir);
|
|
65
|
+
sessionOptions.sessionManager = SessionManager.create(cwd, effectiveSessionDir, classification);
|
|
37
66
|
}
|
|
38
67
|
}
|
|
39
|
-
return sessionOptions as CreateAgentSessionOptions;
|
|
68
|
+
return { ...sessionOptions, orchestrationContext } as CreateAgentSessionOptions;
|
|
40
69
|
}
|
|
41
70
|
|
|
42
71
|
export function missingAdapter(consumer: AgentSessionConsumer): never {
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { createGitWorktreeSetupCache, type GitWorktreeSetupCache } from "./worktree-git.js";
|
|
2
|
+
|
|
3
|
+
export interface GitWorktreeSetupCacheOwner {
|
|
4
|
+
readonly cache: GitWorktreeSetupCache;
|
|
5
|
+
release(finalizer: () => void): void;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function createGitWorktreeSetupCacheOwner(
|
|
9
|
+
suppliedCache?: GitWorktreeSetupCache,
|
|
10
|
+
): GitWorktreeSetupCacheOwner {
|
|
11
|
+
const cache = suppliedCache ?? createGitWorktreeSetupCache();
|
|
12
|
+
const ownsCache = suppliedCache === undefined;
|
|
13
|
+
let released = false;
|
|
14
|
+
return {
|
|
15
|
+
cache,
|
|
16
|
+
release(finalizer) {
|
|
17
|
+
try {
|
|
18
|
+
if (!released && ownsCache) cache.dispose();
|
|
19
|
+
released = true;
|
|
20
|
+
} finally {
|
|
21
|
+
finalizer();
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { lstatSync, realpathSync } from "node:fs";
|
|
2
|
+
import { dirname, isAbsolute, relative, resolve, sep } from "node:path";
|
|
3
|
+
import type { GitWorktreeSetupResult } from "./worktree-types.js";
|
|
4
|
+
|
|
5
|
+
function relativePathWithin(root: string, candidate: string): string | undefined {
|
|
6
|
+
const path = relative(root, candidate);
|
|
7
|
+
return path === ".." || path.startsWith(`..${sep}`) || isAbsolute(path) ? undefined : path;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function existingRealPathThroughAncestor(path: string, description: string): string {
|
|
11
|
+
let existing = resolve(path);
|
|
12
|
+
const missing: string[] = [];
|
|
13
|
+
while (true) {
|
|
14
|
+
try {
|
|
15
|
+
return resolve(realpathSync.native(existing), ...missing);
|
|
16
|
+
} catch (error) {
|
|
17
|
+
let existingEntry: ReturnType<typeof lstatSync> | undefined;
|
|
18
|
+
try {
|
|
19
|
+
existingEntry = lstatSync(existing);
|
|
20
|
+
} catch {
|
|
21
|
+
// Missing components are resolved through their nearest existing ancestor.
|
|
22
|
+
}
|
|
23
|
+
const code = error && typeof error === "object" && "code" in error
|
|
24
|
+
? String((error as { readonly code?: unknown }).code)
|
|
25
|
+
: undefined;
|
|
26
|
+
const parent = dirname(existing);
|
|
27
|
+
if (existingEntry?.isSymbolicLink() === true || (code !== "ENOENT" && code !== "ENOTDIR") || parent === existing) {
|
|
28
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
29
|
+
throw new Error(`atomic-workflows: cannot resolve ${description} ${path}: ${message}`);
|
|
30
|
+
}
|
|
31
|
+
missing.unshift(existing.slice(parent.length + (parent.endsWith(sep) ? 0 : 1)));
|
|
32
|
+
existing = parent;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function existingRealPath(path: string, description: string): string {
|
|
38
|
+
try {
|
|
39
|
+
return realpathSync.native(path);
|
|
40
|
+
} catch (error) {
|
|
41
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
42
|
+
throw new Error(`atomic-workflows: cannot resolve ${description} ${path}: ${message}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function resolveWorktreeStageCwd(
|
|
47
|
+
cwd: string | undefined,
|
|
48
|
+
setup: GitWorktreeSetupResult,
|
|
49
|
+
): string | undefined {
|
|
50
|
+
const worktreeRoot = existingRealPath(setup.worktreeRoot, "gitWorktreeDir");
|
|
51
|
+
const repositoryRoot = existingRealPath(setup.repositoryRoot, "invoking checkout");
|
|
52
|
+
if (cwd === undefined || cwd.length === 0) return undefined;
|
|
53
|
+
|
|
54
|
+
const absoluteInput = isAbsolute(cwd);
|
|
55
|
+
const candidate = absoluteInput ? cwd : resolve(setup.cwd, cwd);
|
|
56
|
+
if (!absoluteInput && relativePathWithin(setup.worktreeRoot, candidate) === undefined) {
|
|
57
|
+
throw new Error(`atomic-workflows: relative cwd ${cwd} escapes gitWorktreeDir ${setup.worktreeRoot}; choose a cwd inside the worktree.`);
|
|
58
|
+
}
|
|
59
|
+
const candidateRealPath = existingRealPath(candidate, "cwd");
|
|
60
|
+
const worktreeRelative = relativePathWithin(worktreeRoot, candidateRealPath);
|
|
61
|
+
if (worktreeRelative !== undefined) return resolve(setup.worktreeRoot, worktreeRelative);
|
|
62
|
+
if (!isAbsolute(cwd)) {
|
|
63
|
+
throw new Error(`atomic-workflows: relative cwd ${cwd} escapes gitWorktreeDir ${setup.worktreeRoot}; choose a path that remains inside the selected worktree.`);
|
|
64
|
+
}
|
|
65
|
+
if (relativePathWithin(setup.worktreeRoot, candidate) !== undefined) {
|
|
66
|
+
throw new Error(`atomic-workflows: cwd ${cwd} resolves outside gitWorktreeDir ${setup.worktreeRoot}; remove the escaping symlink or choose a cwd inside the worktree.`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const repositoryRelative = absoluteInput
|
|
70
|
+
? relativePathWithin(repositoryRoot, candidateRealPath)
|
|
71
|
+
: undefined;
|
|
72
|
+
if (repositoryRelative === undefined) {
|
|
73
|
+
throw new Error(`atomic-workflows: cwd ${cwd} is outside gitWorktreeDir ${setup.worktreeRoot}; use a cwd inside the invoking repository so Atomic can remap it, or omit cwd.`);
|
|
74
|
+
}
|
|
75
|
+
const mappedCwd = resolve(setup.worktreeRoot, repositoryRelative);
|
|
76
|
+
const mappedRealPath = existingRealPath(mappedCwd, "remapped worktree cwd");
|
|
77
|
+
if (relativePathWithin(worktreeRoot, mappedRealPath) === undefined) {
|
|
78
|
+
throw new Error(`atomic-workflows: cwd ${cwd} remaps through a path that resolves outside gitWorktreeDir ${setup.worktreeRoot}; remove the escaping symlink or omit cwd.`);
|
|
79
|
+
}
|
|
80
|
+
return mappedCwd;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
export function resolveContainedRelativePath(
|
|
85
|
+
root: string,
|
|
86
|
+
baseDir: string,
|
|
87
|
+
relativePath: string,
|
|
88
|
+
description: string,
|
|
89
|
+
): string {
|
|
90
|
+
if (isAbsolute(relativePath) || relativePath.split(/[\\/]+/).includes("..")) {
|
|
91
|
+
throw new Error(`atomic-workflows: relative output ${relativePath} escapes ${description} ${root}; use a path without parent traversal.`);
|
|
92
|
+
}
|
|
93
|
+
const candidate = resolve(baseDir, relativePath);
|
|
94
|
+
if (relativePathWithin(resolve(root), candidate) === undefined) {
|
|
95
|
+
throw new Error(`atomic-workflows: relative output ${relativePath} escapes ${description} ${root}.`);
|
|
96
|
+
}
|
|
97
|
+
const realRoot = existingRealPath(root, description);
|
|
98
|
+
const realCandidate = existingRealPathThroughAncestor(candidate, "relative output");
|
|
99
|
+
if (relativePathWithin(realRoot, realCandidate) === undefined) {
|
|
100
|
+
throw new Error(`atomic-workflows: relative output ${relativePath} resolves outside ${description} ${root} through a symlink.`);
|
|
101
|
+
}
|
|
102
|
+
return candidate;
|
|
103
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
|
|
4
|
+
export interface GitWorktreeGenerationAnchor {
|
|
5
|
+
assertCurrent(): void;
|
|
6
|
+
dispose(): void;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function sameFileIdentity(left: fs.BigIntStats, right: fs.BigIntStats): boolean {
|
|
10
|
+
return left.dev === right.dev && left.ino === right.ino;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function openMainCheckoutAnchor(gitDir: string): GitWorktreeGenerationAnchor {
|
|
14
|
+
let disposed = false;
|
|
15
|
+
return {
|
|
16
|
+
assertCurrent() {
|
|
17
|
+
if (disposed) throw new Error(`cached .git identity anchor is already disposed: ${gitDir}`);
|
|
18
|
+
if (!fs.lstatSync(gitDir).isDirectory()) {
|
|
19
|
+
throw new Error(`cached main-checkout .git directory is no longer current: ${gitDir}`);
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
dispose() {
|
|
23
|
+
disposed = true;
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function openGitWorktreeGenerationAnchor(worktreeRoot: string): GitWorktreeGenerationAnchor {
|
|
29
|
+
const gitFile = path.join(worktreeRoot, ".git");
|
|
30
|
+
if (fs.lstatSync(gitFile).isDirectory()) return openMainCheckoutAnchor(gitFile);
|
|
31
|
+
const descriptor = fs.openSync(gitFile, "r");
|
|
32
|
+
let disposed = false;
|
|
33
|
+
|
|
34
|
+
const anchor: GitWorktreeGenerationAnchor = {
|
|
35
|
+
assertCurrent() {
|
|
36
|
+
if (disposed) throw new Error(`cached .git identity anchor is already disposed: ${gitFile}`);
|
|
37
|
+
const held = fs.fstatSync(descriptor, { bigint: true });
|
|
38
|
+
const current = fs.lstatSync(gitFile, { bigint: true });
|
|
39
|
+
if (!current.isFile() || !sameFileIdentity(held, current)) {
|
|
40
|
+
throw new Error(`cached .git identity anchor no longer matches the selected checkout: ${gitFile}`);
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
dispose() {
|
|
44
|
+
if (disposed) return;
|
|
45
|
+
disposed = true;
|
|
46
|
+
fs.closeSync(descriptor);
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
anchor.assertCurrent();
|
|
52
|
+
return anchor;
|
|
53
|
+
} catch (error) {
|
|
54
|
+
anchor.dispose();
|
|
55
|
+
throw error;
|
|
56
|
+
}
|
|
57
|
+
}
|