@bastani/atomic 0.9.13-alpha.2 → 0.9.13-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/README.md +1 -1
- package/dist/builtin/i-have-adhd/package.json +1 -1
- package/dist/builtin/intercom/CHANGELOG.md +14 -0
- package/dist/builtin/intercom/README.md +12 -12
- package/dist/builtin/intercom/incoming-message-delivery.ts +1 -1
- package/dist/builtin/intercom/index.ts +1 -1
- package/dist/builtin/intercom/intercom-tool.ts +1 -1
- package/dist/builtin/intercom/intercom-utils.ts +3 -6
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/intercom/result-renderers.ts +1 -1
- package/dist/builtin/intercom/session-target.ts +1 -15
- package/dist/builtin/intercom/skills/intercom/SKILL.md +6 -6
- package/dist/builtin/intercom/terminal-ordering-barrier.ts +2 -2
- package/dist/builtin/intercom/ui/inline-message.ts +7 -5
- package/dist/builtin/intercom/ui/session-list.ts +23 -10
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/CHANGELOG.md +19 -0
- package/dist/builtin/subagents/README.md +29 -73
- package/dist/builtin/subagents/package.json +2 -2
- package/dist/builtin/subagents/prompts/parallel-cleanup.md +1 -1
- package/dist/builtin/subagents/prompts/parallel-review.md +1 -1
- package/dist/builtin/subagents/prompts/review-loop.md +2 -2
- package/dist/builtin/subagents/skills/subagent/SKILL.md +23 -59
- package/dist/builtin/subagents/skills/tmux/SKILL.md +1 -1
- package/dist/builtin/subagents/src/extension/control-notices.ts +2 -3
- package/dist/builtin/subagents/src/extension/doctor.ts +2 -14
- package/dist/builtin/subagents/src/extension/fanout-child.ts +1 -17
- package/dist/builtin/subagents/src/extension/index.ts +9 -70
- package/dist/builtin/subagents/src/extension/notification-content.ts +1 -1
- package/dist/builtin/subagents/src/extension/prompt-guidance.ts +2 -2
- package/dist/builtin/subagents/src/extension/schemas.ts +2 -8
- package/dist/builtin/subagents/src/extension/tool-description.ts +2 -3
- package/dist/builtin/subagents/src/intercom/intercom-bridge.ts +1 -1
- package/dist/builtin/subagents/src/intercom/result-intercom.ts +5 -46
- package/dist/builtin/subagents/src/runs/{background → foreground}/completion-notification.ts +2 -2
- package/dist/builtin/subagents/src/runs/foreground/inprocess-run-sync.ts +25 -88
- package/dist/builtin/subagents/src/runs/{background → foreground}/notify.ts +5 -5
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-context.ts +11 -28
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel-task.ts +3 -0
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel.ts +2 -0
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-runtime.ts +0 -5
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-single.ts +30 -20
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-status.ts +4 -4
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-types.ts +0 -13
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor.ts +104 -48
- package/dist/builtin/subagents/src/runs/inprocess/index.ts +1 -1
- package/dist/builtin/subagents/src/runs/inprocess/runner.ts +5 -5
- package/dist/builtin/subagents/src/runs/inprocess/runtime-support/nested-api.ts +0 -7
- package/dist/builtin/subagents/src/runs/inprocess/runtime-support/nested-core.ts +0 -10
- package/dist/builtin/subagents/src/runs/inprocess/runtime-support/nested-projection.ts +3 -108
- package/dist/builtin/subagents/src/runs/inprocess/runtime-support/nested-sanitize.ts +0 -4
- package/dist/builtin/subagents/src/runs/shared/subagent-control.ts +1 -1
- package/dist/builtin/subagents/src/shared/formatters.ts +3 -5
- package/dist/builtin/subagents/src/shared/model-resolution.ts +78 -0
- package/dist/builtin/subagents/src/shared/status-format.ts +4 -11
- package/dist/builtin/subagents/src/shared/types-config.ts +10 -9
- package/dist/builtin/subagents/src/shared/types-nested.ts +127 -0
- package/dist/builtin/subagents/src/shared/types-results.ts +2 -8
- package/dist/builtin/subagents/src/shared/types-runtime.ts +0 -9
- package/dist/builtin/subagents/src/shared/types.ts +1 -1
- package/dist/builtin/subagents/src/shared/utils.ts +1 -109
- package/dist/builtin/subagents/src/slash/slash-commands.ts +7 -17
- package/dist/builtin/subagents/src/tui/render-event-formatting.ts +2 -252
- package/dist/builtin/subagents/src/tui/render-layout.ts +4 -4
- package/dist/builtin/subagents/src/tui/render-result.ts +0 -9
- package/dist/builtin/subagents/src/tui/render-stable-output.ts +1 -34
- package/dist/builtin/subagents/src/tui/render.ts +0 -2
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +12 -0
- package/dist/builtin/workflows/README.md +3 -3
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/src/durable/backend.ts +11 -0
- package/dist/builtin/workflows/src/durable/completed-catalog-stage-groups.ts +63 -25
- package/dist/builtin/workflows/src/durable/completed-catalog.ts +166 -25
- package/dist/builtin/workflows/src/durable/dbos-backend.ts +42 -24
- package/dist/builtin/workflows/src/durable/dbos-envelope.ts +2 -1
- package/dist/builtin/workflows/src/durable/run-timing.ts +28 -7
- package/dist/builtin/workflows/src/durable/scoped-backend.ts +4 -0
- package/dist/builtin/workflows/src/durable/targeted-inspection.ts +110 -0
- package/dist/builtin/workflows/src/engine/run-durable-stage-session.ts +2 -2
- package/dist/builtin/workflows/src/engine/runtime.ts +19 -2
- package/dist/builtin/workflows/src/extension/extension-runtime-state.ts +3 -0
- package/dist/builtin/workflows/src/extension/index.bundle.mjs +680 -152
- package/dist/builtin/workflows/src/extension/runtime-durable-resume.ts +6 -0
- package/dist/builtin/workflows/src/extension/ui-surface.ts +2 -0
- package/dist/builtin/workflows/src/extension/workflow-command-registration.ts +6 -1
- package/dist/builtin/workflows/src/extension/workflow-targets.ts +18 -10
- package/dist/builtin/workflows/src/extension/workflow-tool-inspection.ts +31 -16
- package/dist/builtin/workflows/src/extension/workflow-tool-send.ts +75 -3
- package/dist/builtin/workflows/src/extension/workflow-tool.ts +53 -6
- package/dist/builtin/workflows/src/runs/background/run-inspect.ts +5 -1
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-call.ts +94 -60
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-context.ts +1 -1
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-control.ts +7 -7
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-factory.ts +25 -4
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-types.ts +4 -1
- package/dist/builtin/workflows/src/runs/foreground/executor-types.ts +2 -0
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-controller.ts +142 -4
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-types.ts +2 -0
- package/dist/builtin/workflows/src/runs/foreground/stage-session-heartbeat.ts +88 -0
- package/dist/builtin/workflows/src/tui/run-detail.ts +25 -12
- package/dist/builtin/workflows/src/tui/workflow-resume-selector.ts +1 -0
- package/dist/core/agent-session-events.d.ts.map +1 -1
- package/dist/core/agent-session-events.js +16 -5
- package/dist/core/agent-session-events.js.map +1 -1
- package/dist/core/agent-session-export.d.ts.map +1 -1
- package/dist/core/agent-session-export.js +2 -1
- package/dist/core/agent-session-export.js.map +1 -1
- package/dist/core/agent-session-methods.d.ts +8 -4
- 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-prompt.d.ts.map +1 -1
- package/dist/core/agent-session-prompt.js +5 -0
- package/dist/core/agent-session-prompt.js.map +1 -1
- package/dist/core/agent-session-summary.d.ts +21 -0
- package/dist/core/agent-session-summary.d.ts.map +1 -0
- package/dist/core/agent-session-summary.js +156 -0
- package/dist/core/agent-session-summary.js.map +1 -0
- package/dist/core/agent-session-tool-registry.d.ts.map +1 -1
- package/dist/core/agent-session-tool-registry.js +0 -4
- package/dist/core/agent-session-tool-registry.js.map +1 -1
- package/dist/core/agent-session-transfer.d.ts.map +1 -1
- package/dist/core/agent-session-transfer.js +0 -2
- package/dist/core/agent-session-transfer.js.map +1 -1
- package/dist/core/agent-session-tree.d.ts.map +1 -1
- package/dist/core/agent-session-tree.js +6 -0
- package/dist/core/agent-session-tree.js.map +1 -1
- package/dist/core/agent-session.d.ts +7 -3
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +8 -5
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/atomic-guide-command.js +2 -2
- package/dist/core/atomic-guide-command.js.map +1 -1
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +1 -0
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/index.d.ts +1 -0
- package/dist/core/compaction/index.d.ts.map +1 -1
- package/dist/core/compaction/index.js +1 -0
- package/dist/core/compaction/index.js.map +1 -1
- package/dist/core/compaction/session-summarization.d.ts +41 -0
- package/dist/core/compaction/session-summarization.d.ts.map +1 -0
- package/dist/core/compaction/session-summarization.js +97 -0
- package/dist/core/compaction/session-summarization.js.map +1 -0
- package/dist/core/extensions/ui-types.d.ts +2 -0
- package/dist/core/extensions/ui-types.d.ts.map +1 -1
- package/dist/core/extensions/ui-types.js.map +1 -1
- package/dist/core/session-manager-core.d.ts +3 -1
- package/dist/core/session-manager-core.d.ts.map +1 -1
- package/dist/core/session-manager-core.js +9 -1
- package/dist/core/session-manager-core.js.map +1 -1
- package/dist/core/session-manager-entries.d.ts +24 -1
- package/dist/core/session-manager-entries.d.ts.map +1 -1
- package/dist/core/session-manager-entries.js +48 -0
- package/dist/core/session-manager-entries.js.map +1 -1
- package/dist/core/session-manager-list.d.ts.map +1 -1
- package/dist/core/session-manager-list.js +10 -0
- package/dist/core/session-manager-list.js.map +1 -1
- package/dist/core/session-manager-types.d.ts +10 -1
- package/dist/core/session-manager-types.d.ts.map +1 -1
- package/dist/core/session-manager-types.js.map +1 -1
- package/dist/core/settings-manager-basic-accessors.d.ts +3 -0
- package/dist/core/settings-manager-basic-accessors.d.ts.map +1 -1
- package/dist/core/settings-manager-basic-accessors.js +5 -0
- package/dist/core/settings-manager-basic-accessors.js.map +1 -1
- package/dist/core/settings-manager.d.ts +1 -1
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/settings-types.d.ts +4 -0
- package/dist/core/settings-types.d.ts.map +1 -1
- package/dist/core/settings-types.js.map +1 -1
- package/dist/core/slash-commands.js +2 -2
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/tools/bash.d.ts +0 -15
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +3 -81
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/fetch-url.d.ts +12 -0
- package/dist/core/tools/fetch-url.d.ts.map +1 -1
- package/dist/core/tools/fetch-url.js +76 -10
- package/dist/core/tools/fetch-url.js.map +1 -1
- package/dist/core/tools/index.js +4 -4
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/session-temp-dir.d.ts +2 -2
- package/dist/core/tools/session-temp-dir.d.ts.map +1 -1
- package/dist/core/tools/session-temp-dir.js +6 -7
- package/dist/core/tools/session-temp-dir.js.map +1 -1
- package/dist/core/usage-totals.js +1 -1
- package/dist/core/usage-totals.js.map +1 -1
- package/dist/modes/interactive/components/footer.js +1 -1
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/host-session-picker.d.ts.map +1 -1
- package/dist/modes/interactive/components/host-session-picker.js +1 -0
- package/dist/modes/interactive/components/host-session-picker.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 +29 -4
- package/dist/modes/interactive/components/session-selector-list.js.map +1 -1
- package/dist/modes/interactive/components/session-selector-search.js +1 -1
- package/dist/modes/interactive/components/session-selector-search.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector-content.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-selector-content.js +6 -0
- package/dist/modes/interactive/components/tree-selector-content.js.map +1 -1
- package/dist/modes/interactive-engine/protocol.d.ts.map +1 -1
- package/dist/modes/interactive-engine/protocol.js +4 -1
- package/dist/modes/interactive-engine/protocol.js.map +1 -1
- package/docs/environment-variables.md +1 -1
- package/docs/intercom.md +20 -21
- package/docs/quickstart.md +5 -1
- package/docs/sdk.md +1 -1
- package/docs/session-format.md +15 -0
- package/docs/sessions.md +8 -0
- package/docs/settings.md +6 -0
- package/docs/subagents.md +19 -31
- package/docs/tools.md +3 -5
- package/docs/usage.md +1 -1
- package/docs/windows.md +1 -1
- package/docs/workflows.md +60 -32
- package/npm-shrinkwrap.json +29 -29
- package/package.json +2 -2
- package/dist/builtin/subagents/src/runs/background/async-job-tracker.ts +0 -331
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-async.ts +0 -161
- package/dist/builtin/subagents/src/runs/inprocess/background-single.ts +0 -195
- package/dist/builtin/subagents/src/runs/inprocess/background.ts +0 -90
- package/dist/builtin/subagents/src/shared/types-async.ts +0 -247
- package/dist/builtin/subagents/src/tui/render-widget-graph.ts +0 -217
- package/dist/builtin/subagents/src/tui/render-widget.ts +0 -366
- package/dist/core/async/format.d.ts +0 -3
- package/dist/core/async/format.d.ts.map +0 -1
- package/dist/core/async/format.js +0 -52
- package/dist/core/async/format.js.map +0 -1
- package/dist/core/async/job-manager.d.ts +0 -40
- package/dist/core/async/job-manager.d.ts.map +0 -1
- package/dist/core/async/job-manager.js +0 -293
- package/dist/core/async/job-manager.js.map +0 -1
- package/dist/core/async/session-manager.d.ts +0 -16
- package/dist/core/async/session-manager.d.ts.map +0 -1
- package/dist/core/async/session-manager.js +0 -34
- package/dist/core/async/session-manager.js.map +0 -1
- package/dist/core/async/types.d.ts +0 -23
- package/dist/core/async/types.d.ts.map +0 -1
- package/dist/core/async/types.js +0 -2
- package/dist/core/async/types.js.map +0 -1
- package/dist/core/tools/bash-async-execution.d.ts +0 -27
- package/dist/core/tools/bash-async-execution.d.ts.map +0 -1
- package/dist/core/tools/bash-async-execution.js +0 -81
- package/dist/core/tools/bash-async-execution.js.map +0 -1
- package/dist/core/tools/bash-async-jobs.d.ts +0 -30
- package/dist/core/tools/bash-async-jobs.d.ts.map +0 -1
- package/dist/core/tools/bash-async-jobs.js +0 -87
- package/dist/core/tools/bash-async-jobs.js.map +0 -1
- package/dist/core/tools/bash-async-output.d.ts +0 -13
- package/dist/core/tools/bash-async-output.d.ts.map +0 -1
- package/dist/core/tools/bash-async-output.js +0 -122
- package/dist/core/tools/bash-async-output.js.map +0 -1
package/docs/subagents.md
CHANGED
|
@@ -25,28 +25,28 @@ Run a parallel review composition: one pass for current behavior, one for failur
|
|
|
25
25
|
Research the upstream library behavior online, then compare it with our local implementation.
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
Atomic decides whether delegation adds value, which specialist fits each bounded part, and whether the work should run as a single child, parallel group,
|
|
28
|
+
Atomic decides whether delegation adds value, which specialist fits each bounded part, and whether the work should run as a single child, parallel group, or forked-context run. Multiple steps, files, tests, validation, or parallelism alone do not require a workflow; clearly delegated long-running autonomous work that needs durable stages, checkpoints, resumability, HIL, gates, retries, or loops is usually better served by a workflow.
|
|
29
29
|
|
|
30
30
|
## Subagent execution is non-interactive
|
|
31
31
|
|
|
32
|
-
Supported subagent launches start immediately without opening a preview/editor prompt or waiting for terminal input. This applies to single, parallel,
|
|
32
|
+
Supported subagent launches start immediately without opening a preview/editor prompt or waiting for terminal input. This applies to single, parallel, forked, fanout, prompt-template, and human-entered `/run` and `/parallel` execution. Ask any necessary questions in the parent conversation before delegating.
|
|
33
33
|
|
|
34
|
-
The human slash commands remain registered and continue to use their separate parsing and event-bridge path, including
|
|
34
|
+
The human slash commands remain registered and continue to use their separate parsing and event-bridge path, including fork flags.
|
|
35
35
|
Prompt-template delegation comes from the separately installed `pi-prompt-template-model` extension, whose `requestDelegatedRun` emits `prompt-template:subagent:request`. If that caller must survive an extension reload, import `registerPromptTemplateBridgeRequestSettlement` from `@bastani/subagents`, register it before the emit, and unregister it from the normal response, cancellation, or abort path. The hook rejects the caller only when the old bridge drops a stale response emit; normal completion still arrives through `prompt-template:subagent:response`. Atomic cannot register this opt-in for an out-of-tree emitter.
|
|
36
36
|
|
|
37
37
|
Subagents now run and return their results directly. Atomic does not infer acceptance gates from prompt wording, inject `acceptance-report` instructions into child prompts, parse or strip `acceptance-report` blocks, or reject completed child runs because changed-file, test, or review evidence is missing. Put any evidence or validation requirements directly in the task text you give the parent or child agent.
|
|
38
38
|
|
|
39
39
|
## Foreground supervisor coordination
|
|
40
40
|
|
|
41
|
-
When a foreground child sends `intercom.ask`, `intercom.send`, or `contact_supervisor` coordination, Atomic first probes for the exact foreground owner. Only an exact live child reserves the request; Atomic then sends a generation-scoped detach commit and waits for that child to acknowledge it before placing the message in the parent's model-visible steering queue. This first-refusal ordering also applies when the parent is a busy workflow stage: detach completes before the request enters the stage AgentSession generation boundary, breaking the child-waits-for-reply / stage-waits-for-child cycle.
|
|
41
|
+
When a foreground child sends `intercom.ask`, `intercom.send`, or `contact_supervisor` coordination, Atomic first probes for the exact foreground owner. Only an exact live child reserves the request; Atomic then sends a generation-scoped detach commit and waits for that child to acknowledge it before placing the message in the parent's model-visible steering queue. This first-refusal ordering also applies when the parent is a busy workflow stage: detach completes before the request enters the stage AgentSession generation boundary, breaking the child-waits-for-reply / stage-waits-for-child cycle. Blocking `need_decision` and `interview_request` calls remain actionable through [Intercom](/intercom)'s pending/reply tracker, and the exact threaded reply resumes the retained child without delayed duplicate delivery. Unmatched messages retain existing routing—ordinary parents queue until idle, while open workflow stages fall back to their native generation admission.
|
|
42
42
|
|
|
43
|
-
Only the matching foreground child can authorize release of the parent `subagent` tool. For a parallel foreground group, that accepted commit releases foreground supervision for every active sibling as one unit, so a long-running sibling cannot keep a blocking child request trapped behind the aggregate tool call; tasks still waiting behind the concurrency limit are skipped and never launched unsupervised. Children are in-process `AgentSession` instances governed by the shared Rust control plane: there is no child OS process, idle watchdog, stdout drain, or detached placeholder to recover. A detached call becomes `continued` through `
|
|
43
|
+
Only the matching foreground child can authorize release of the parent `subagent` tool. For a parallel foreground group, that accepted commit releases foreground supervision for every active sibling as one unit, so a long-running sibling cannot keep a blocking child request trapped behind the aggregate tool call; tasks still waiting behind the concurrency limit are skipped and never launched unsupervised. Children are in-process `AgentSession` instances governed by the shared Rust control plane: there is no child OS process, idle watchdog, stdout drain, or detached placeholder to recover. A detached call becomes `continued` through `continue_detached`; its canonical child remains live and later delivers one terminal result. Fire-and-forget `intercom.send` and `progress_update` also release foreground supervision promptly, but do not create a reply waiter.
|
|
44
44
|
|
|
45
45
|
Blocking coordination is race-safe: a session holds at most one outbound reply waiter, and concurrent blocking requests (parallel `intercom.ask` calls, or `intercom.ask` racing `contact_supervisor`) settle atomically. One request wins the reservation; every other concurrent call returns a normal "Already waiting for a reply" tool error without crashing the agent process or disturbing the pending ask. Cancellation and send failures release only their own waiter, and threaded replies still resolve the exact winning request.
|
|
46
46
|
|
|
47
47
|
Subagent result announcements are also resilient in sessions that never receive an extension `session_start` (for example non-interactive in-process child sessions): the lazy Intercom runtime initializes from the most recent turn/tool lifecycle context and delivers self-addressed results locally. If no context is available at all, the relay acknowledges the announcement as undelivered — the `subagent` tool then falls back to returning results inline — instead of recording connection errors in the session transcript.
|
|
48
48
|
|
|
49
|
-
Intercom connection remains tool-driven. Foreground
|
|
49
|
+
Intercom connection remains tool-driven. Foreground launches do not import the heavy Intercom runtime or connect either the parent or bridged child automatically. If live child-to-parent coordination is needed, the parent model should invoke `intercom({ action: "status" })` before launch; the child then connects on its first `contact_supervisor` or `intercom` call. Cancellation or session replacement still invalidates the handshake generation, so stale acknowledgements cannot surface or detach a child.
|
|
50
50
|
|
|
51
51
|
Atomic's implementation adapts the prompt foreground release and later-result recovery contracts proven in `nicobailon/pi-subagents` commits `1b55c8c`, `589e51e`, `68fb528`, and `9dfe3df`; it retains Atomic's broker and raw-TypeScript architecture rather than copying upstream's filesystem transport.
|
|
52
52
|
|
|
@@ -98,44 +98,33 @@ Review the current diff with fresh-context specialists: analyze correctness, ins
|
|
|
98
98
|
|
|
99
99
|
Useful prompt templates include `/parallel-review`, `/review-loop`, `/parallel-research`, `/parallel-context-build`, `/parallel-handoff-plan`, and `/parallel-cleanup`. Treat them as reusable compositions, not as separate bundled agent names. Their task templates define the requested outcome, evidence and delegation boundaries, downstream output shape, and an explicit stop rule; preserve those contracts when adapting a template.
|
|
100
100
|
|
|
101
|
-
##
|
|
101
|
+
## Foreground work and control
|
|
102
102
|
|
|
103
|
-
Foreground subagents stream progress in the conversation and
|
|
103
|
+
Foreground subagents stream progress in the conversation and return their results before the call completes.
|
|
104
104
|
|
|
105
105
|
Natural-language examples:
|
|
106
106
|
|
|
107
107
|
```text
|
|
108
|
-
Run the local research scan
|
|
108
|
+
Run the local research scan.
|
|
109
109
|
```
|
|
110
110
|
|
|
111
111
|
```text
|
|
112
|
-
Show me the current
|
|
112
|
+
Show me the current subagent status.
|
|
113
113
|
```
|
|
114
114
|
|
|
115
115
|
Tool examples:
|
|
116
116
|
|
|
117
117
|
```ts
|
|
118
|
-
subagent({ agent: "codebase-analyzer", task: "Trace the auth flow with file references."
|
|
119
|
-
subagent({ action: "status" })
|
|
120
|
-
subagent({ action: "status", id: "<run-id>" })
|
|
121
|
-
subagent({ action: "interrupt", id: "<run-id>" })
|
|
122
|
-
subagent({ action: "resume", id: "<run-id>", message: "continue with the test failures" })
|
|
123
|
-
subagent({ action: "doctor" })
|
|
118
|
+
subagent({ agent: "codebase-analyzer", task: "Trace the auth flow with file references." })
|
|
124
119
|
```
|
|
125
120
|
|
|
126
|
-
Use `interrupt` when you want a resumable stop. Use `resume`
|
|
127
|
-
|
|
128
|
-
`async: true` means **do not wait**. Atomic admits an in-process child, returns its canonical child path immediately, and tracks the live child through the jobs widget. Intercom detach uses this exact same continuation mechanism, so a foreground child that asks its supervisor to coordinate becomes `continued` instead of returning a detached placeholder.
|
|
129
|
-
|
|
130
|
-
**`async: true` does not survive parent exit. The live child is owned by the parent process; quitting Atomic ends any in-flight async run. Only the persisted canonical identity and session file survive, and a later session can list that cold identity and resume it.**
|
|
121
|
+
Use `interrupt` when you want a resumable stop. Use `resume` for a follow-up to a reachable or retained child. Use `doctor` for read-only setup diagnostics.
|
|
131
122
|
|
|
132
123
|
Status, interrupt, list, and resume use the Rust registry and status watch for live children; terminal delivery is an in-memory bounded envelope with the artifact and run-history record persisted once. There is no PID polling, result-claim file, stale-run reconciliation, or detached runner process.
|
|
133
124
|
|
|
134
|
-
Inside workflow stages, completion delivery observes the stage generation boundary. A completion received before the boundary closes is queued through the stage AgentSession and processed before the stage publishes its terminal snapshot. A completion that arrives after close is routed once to the parent/main chat and cannot reopen or append to the completed stage transcript.
|
|
135
|
-
|
|
136
|
-
When a workflow graph overlay is open, Atomic also publishes the live async subagent summary into the shared status surface. The below-editor async widget remains available when the workflow overlay is hidden, and the overlay statusline keeps the run count/state visible while the graph fills the terminal.
|
|
125
|
+
Inside workflow stages, completion delivery observes the stage generation boundary. A completion received before the boundary closes is queued through the stage AgentSession and processed before the stage publishes its terminal snapshot. A completion that arrives after close is routed once to the parent/main chat and cannot reopen or append to the completed stage transcript. Explicit post-mortem stage chat is still available separately.
|
|
137
126
|
|
|
138
|
-
|
|
127
|
+
Live progress and completed results show each step's resolved model, effective reasoning level, and applied Codex fast-mode marker, including after a model fallback; parallel steps keep their metadata separate.
|
|
139
128
|
|
|
140
129
|
## Orchestrator model and group policy
|
|
141
130
|
|
|
@@ -143,7 +132,7 @@ Atomic applies the same delegation policy to any parent chat or workflow stage t
|
|
|
143
132
|
|
|
144
133
|
If an agent declares no model or fallback policy, the orchestrator consults the role guidance in [Model selection](/models/model-selection), then calls `workflow({ action: "models" })` when that tool is available. It may pin only a returned `fullId` and may add a thinking suffix only when the model entry lists that level. When the catalog tool is unavailable, the catalog is empty, or no recommended model is present, the child stays unpinned and the orchestrator reports the limit instead of inventing a model or inspecting credentials.
|
|
145
134
|
|
|
146
|
-
Each workflow invocation automatically receives one stable, non-`"default"` Intercom group as typed admission policy. Its stages and delegated children carry that group across single, parallel,
|
|
135
|
+
Each workflow invocation automatically receives one stable, non-`"default"` Intercom group as typed admission policy. Its stages and delegated children carry that group across single, parallel, and follow-up work unless a call explicitly overrides `group`. Outside workflows, children inherit the launching session's resolved group. This isolates workflow runs from unrelated runs and the main chat while `contact_supervisor` retains its authorized cross-group route.
|
|
147
136
|
|
|
148
137
|
## Context and execution modes
|
|
149
138
|
|
|
@@ -160,17 +149,16 @@ Fresh child sessions use normal Atomic package discovery when an agent omits `ex
|
|
|
160
149
|
|
|
161
150
|
Top-level parallel calls support up to 50 subagents after expanding each task's optional `count`. The extension's `parallel.maxTasks` setting defaults to 50 and can enforce a lower task limit; `parallel.concurrency` independently controls how many of those children run at once, while the Rust turn limiter admits at most four running turns per parent.
|
|
162
151
|
|
|
163
|
-
Subagent tasks, parallel items, and the top-level call accept a `group` field that sets the spawned child's [Intercom](/intercom) home group, so same-group subagents can intercom each other while staying isolated from other groups. A named string joins that group; `true` auto-generates one shared UUID group per parallel set. Precedence is `explicit subagent group > inherited current-session group > config > "default"`. Workflow stages carry their runtime-owned invocation group, so children launched without `group` automatically join the workflow group; callers do not need to copy or generate an ID. In other sessions, omission inherits that launching session's resolved group. The child group is applied only when the child has Intercom access (the peer `intercom` tool or subagent-only `contact_supervisor` tool); a child without Intercom receives no group. `contact_supervisor` still reaches the supervisor across group boundaries because Atomic requests a broker capability during typed admission and binds the child's registration to the issuing supervisor. Foreground
|
|
152
|
+
Subagent tasks, parallel items, and the top-level call accept a `group` field that sets the spawned child's [Intercom](/intercom) home group, so same-group subagents can intercom each other while staying isolated from other groups. A named string joins that group; `true` auto-generates one shared UUID group per parallel set. Precedence is `explicit subagent group > inherited current-session group > config > "default"`. Workflow stages carry their runtime-owned invocation group, so children launched without `group` automatically join the workflow group; callers do not need to copy or generate an ID. In other sessions, omission inherits that launching session's resolved group. The child group is applied only when the child has Intercom access (the peer `intercom` tool or subagent-only `contact_supervisor` tool); a child without Intercom receives no group. `contact_supervisor` still reaches the supervisor across group boundaries because Atomic requests a broker capability during typed admission and binds the child's registration to the issuing supervisor. Foreground paths use exact child scopes. The lightweight Intercom wrapper lazy-loads the authorization provider; provider failures abort launch, while hosts without a provider omit supervisor metadata instead of exposing a broken channel.
|
|
164
153
|
|
|
165
|
-
When a subagent call
|
|
154
|
+
When a subagent call or parallel task uses a `cwd`, Atomic validates that working directory before starting the child runtime. Missing or non-directory paths are reported as `cwd` problems instead of lower-level runtime errors.
|
|
166
155
|
|
|
167
|
-
Single-agent calls also accept `reads: string[] | false`. Atomic prepends those files as read context for foreground
|
|
156
|
+
Single-agent calls also accept `reads: string[] | false`. Atomic prepends those files as read context for foreground execution through the same in-process session path, including `/run agent[reads=a.md+b.md]`. Relative entries resolve against the effective child `cwd` (including a relative top-level `cwd` resolved from the parent); absolute entries are unchanged. Invalid values fail before the child session starts.
|
|
168
157
|
|
|
169
|
-
Single-agent calls accept `progress: boolean` in foreground
|
|
158
|
+
Single-agent calls accept `progress: boolean` in foreground and resumed mode. `progress: true` creates a run-scoped `progress.md` under isolated subagent artifact storage and instructs the child to maintain it without writing `progress.md` into the child `cwd`; `progress: false` disables an agent's `defaultProgress`. When `progress` is omitted, the agent's default is inherited, except that inherited progress is suppressed for read-only tasks (`progress: true` still explicitly opts in). Foreground runs remove this run-owned progress storage after the child exits when `artifacts: false`, including children temporarily detached for intercom coordination. This is separate from `includeProgress: true`, which only includes detailed runtime progress telemetry in the final tool result and does not create or maintain a file.
|
|
170
159
|
|
|
171
160
|
```ts
|
|
172
161
|
subagent({ agent: "worker", task: "Implement the approved fix.", progress: true })
|
|
173
|
-
subagent({ agent: "worker", task: "Implement it in the background.", progress: true, async: true })
|
|
174
162
|
```
|
|
175
163
|
|
|
176
164
|
## Nested and fanout boundaries
|
package/docs/tools.md
CHANGED
|
@@ -28,11 +28,9 @@ Before writing, Atomic verifies the current file against the tagged snapshot. If
|
|
|
28
28
|
|
|
29
29
|
## `bash` and `bashInterceptor`
|
|
30
30
|
|
|
31
|
-
The `bash` tool executes shell commands in the session workspace, with optional PTY
|
|
31
|
+
The `bash` tool executes shell commands in the session workspace, with optional PTY handling. When `pty: true` is requested, local execution uses the bundled Rust-backed PTY session; if the native PTY package is unavailable, Atomic degrades to normal pipe execution. Set `PI_NO_PTY=1` or `ATOMIC_NO_PTY=1` to force normal pipe execution. Foreground results include oh-my-pi-style `timeoutSeconds`, `requestedTimeoutSeconds`, `wallTimeMs`, and non-zero `exitCode` metadata, and preserve overflow output in a temporary `fullOutputPath` when output is truncated.
|
|
32
32
|
|
|
33
|
-
When
|
|
34
|
-
|
|
35
|
-
When explicitly enabled in settings, built-in bash interceptor rules block common shell substitutes for first-class tools (`cat`/`grep`/`find`/in-place `sed`/redirection, etc.) only when the corresponding tool is available. Enabled bash tool calls are also offered to `user_bash` extension handlers before local execution. Atomic checks the original command, the internal-URL-expanded command, configured-prefix forms, `spawnHook`-rewritten commands, and a leading `cd path && command` or `cd path; command`-stripped form only when structured `cwd` was omitted, so interceptors can route commands by effective working directory without overriding explicit `cwd`. The bash schema accepts `cwd`, `env`, `timeout`, `pty`, and `async`; `cwd` and `env` are honored by the local executor. Omitting `timeout` uses the 300-second default. An explicit timeout must be finite, greater than zero, and no more than Atomic's deliberate 3600-second ceiling; invalid values fail before execution instead of being defaulted or clamped. Valid fractional values are rounded down with a one-second floor. Normal sessions enable tracked async jobs with bounded retention. `bashInterceptor.enabled` defaults to `false`; interception is not auto-enabled.
|
|
33
|
+
When explicitly enabled in settings, built-in bash interceptor rules block common shell substitutes for first-class tools (`cat`/`grep`/`find`/in-place `sed`/redirection, etc.) only when the corresponding tool is available. Enabled bash tool calls are also offered to `user_bash` extension handlers before local execution. Atomic checks the original command, the internal-URL-expanded command, configured-prefix forms, `spawnHook`-rewritten commands, and a leading `cd path && command` or `cd path; command`-stripped form only when structured `cwd` was omitted, so interceptors can route commands by effective working directory without overriding explicit `cwd`. The bash schema accepts `cwd`, `env`, `timeout`, and `pty`; `cwd` and `env` are honored by the local executor. Omitting `timeout` uses the 300-second default. An explicit timeout must be finite, greater than zero, and no more than Atomic's deliberate 3600-second ceiling; invalid values fail before execution instead of being defaulted or clamped. Valid fractional values are rounded down with a one-second floor. `bashInterceptor.enabled` defaults to `false`; interception is not auto-enabled.
|
|
36
34
|
|
|
37
35
|
```json
|
|
38
36
|
{
|
|
@@ -54,7 +52,7 @@ Plain URL reads follow oh-my-pi's fetch-pipeline truncation contract: unselected
|
|
|
54
52
|
|
|
55
53
|
Output that does not fit in a tool result is written to a file, and the result points at it — `Full output: <path>` for `bash`, `Full output saved to: <path>` for any tool result that crosses the persistence threshold. Those files are storage, so Atomic bounds where they go, how large they get, and how long they live.
|
|
56
54
|
|
|
57
|
-
**Where.** A session that persists to disk keeps its tool results in `<sessionDir>/tool-results/`, unchanged. Everything else — `bash` overflow logs,
|
|
55
|
+
**Where.** A session that persists to disk keeps its tool results in `<sessionDir>/tool-results/`, unchanged. Everything else — `bash` overflow logs, streamed spill files, and tool results for in-memory sessions — goes under one owner- and session-scoped temp tree:
|
|
58
56
|
|
|
59
57
|
```text
|
|
60
58
|
<tmpdir>/atomic-<uid>/<session-id>/
|
package/docs/usage.md
CHANGED
|
@@ -377,7 +377,7 @@ atomic --tools read,search,find,ls -p "Review the code"
|
|
|
377
377
|
| `ATOMIC_NO_PTY` | Set to `1` to disable PTY use for bash commands (`PI_NO_PTY` is a legacy alias) |
|
|
378
378
|
| `VISUAL`, `EDITOR` | External editor for CTRL+G |
|
|
379
379
|
|
|
380
|
-
Every
|
|
380
|
+
Every bash execution runs in the foreground and receives one execution-time snapshot of the active session:
|
|
381
381
|
|
|
382
382
|
| Atomic variable | Exact compatibility alias | Value |
|
|
383
383
|
|-----------------|---------------------------|-------|
|
package/docs/windows.md
CHANGED
|
@@ -20,7 +20,7 @@ Paths copied from Git Bash, MSYS2, Cygwin, or WSL are accepted anywhere Atomic r
|
|
|
20
20
|
|
|
21
21
|
## Filesystem Watchers
|
|
22
22
|
|
|
23
|
-
On Windows, Atomic canonicalizes paths before starting native filesystem watchers. If a watcher target cannot be canonicalized or still contains an unsafe 8.3 short-name component such as `USERNA~1`, Atomic avoids native `fs.watch` for that target and uses polling where the feature supports it. This protects long-running sessions,
|
|
23
|
+
On Windows, Atomic canonicalizes paths before starting native filesystem watchers. If a watcher target cannot be canonicalized or still contains an unsafe 8.3 short-name component such as `USERNA~1`, Atomic avoids native `fs.watch` for that target and uses polling where the feature supports it. This protects long-running sessions, footer git status refreshes, and custom theme reloads from Windows/libuv path-prefix assertion crashes.
|
|
24
24
|
|
|
25
25
|
## Self-Update Behavior
|
|
26
26
|
|
package/docs/workflows.md
CHANGED
|
@@ -385,6 +385,7 @@ A natural-language request for a worktree does not configure runner isolation. I
|
|
|
385
385
|
|
|
386
386
|
```ts
|
|
387
387
|
// .atomic/workflows/issue-to-pr.ts
|
|
388
|
+
import { spawnSync } from "node:child_process";
|
|
388
389
|
import { workflow } from "@bastani/workflows";
|
|
389
390
|
import { Type, type Static } from "typebox";
|
|
390
391
|
|
|
@@ -396,12 +397,22 @@ const reviewDecision = Type.Object(
|
|
|
396
397
|
{ additionalProperties: false },
|
|
397
398
|
);
|
|
398
399
|
|
|
400
|
+
function spawnCommand(argv: readonly string[], cwd: string) {
|
|
401
|
+
const [command, ...args] = argv;
|
|
402
|
+
if (command === undefined) throw new Error("spawnCommand requires a command");
|
|
403
|
+
const result = spawnSync(command, args, { cwd, encoding: "utf8" });
|
|
404
|
+
// A command that could not be spawned at all arrives on `error` with a null
|
|
405
|
+
// status, so it has to be raised here or it reads as an ordinary failure.
|
|
406
|
+
if (result.error) throw result.error;
|
|
407
|
+
return result;
|
|
408
|
+
}
|
|
409
|
+
|
|
399
410
|
function runCommand(argv: readonly string[], cwd: string): string {
|
|
400
|
-
const result =
|
|
401
|
-
const stdout = result.stdout
|
|
402
|
-
const stderr = result.stderr
|
|
403
|
-
if (result.
|
|
404
|
-
throw new Error(`${argv.join(" ")} failed (${result.
|
|
411
|
+
const result = spawnCommand(argv, cwd);
|
|
412
|
+
const stdout = (result.stdout ?? "").trim();
|
|
413
|
+
const stderr = (result.stderr ?? "").trim();
|
|
414
|
+
if (result.status !== 0) {
|
|
415
|
+
throw new Error(`${argv.join(" ")} failed (${result.status})\n${stderr || stdout}`);
|
|
405
416
|
}
|
|
406
417
|
return stdout;
|
|
407
418
|
}
|
|
@@ -430,12 +441,12 @@ export default workflow({
|
|
|
430
441
|
const baseRef = ctx.inputs.base_ref;
|
|
431
442
|
|
|
432
443
|
await ctx.tool("select-feature-branch", { branch, base_ref: baseRef }, async () => {
|
|
433
|
-
const probe =
|
|
444
|
+
const probe = spawnCommand(
|
|
434
445
|
["git", "show-ref", "--verify", "--quiet", `refs/heads/${branch}`],
|
|
435
|
-
|
|
446
|
+
cwd,
|
|
436
447
|
);
|
|
437
|
-
if (probe.
|
|
438
|
-
if (probe.
|
|
448
|
+
if (probe.status === 0) return runCommand(["git", "switch", branch], cwd);
|
|
449
|
+
if (probe.status !== 1) throw new Error((probe.stderr ?? "").trim());
|
|
439
450
|
return runCommand(["git", "switch", "-c", branch, baseRef], cwd);
|
|
440
451
|
});
|
|
441
452
|
|
|
@@ -849,6 +860,8 @@ If required inputs are missing or ambiguous, Atomic asks for them or opens the i
|
|
|
849
860
|
|
|
850
861
|
## Writing a Workflow
|
|
851
862
|
|
|
863
|
+
**A workflow executes inside whichever host is running Atomic, so its code has to work on both.** Standalone binaries are Bun-compiled while npm installs run under Node, and the active host is what loads your workflow file — so a `Bun.*` global reaches a workflow only when Atomic itself is running under Bun, and fails with `Bun is not defined` otherwise. Installing Bun separately does not change this. Write workflow code against APIs both hosts provide: `node:child_process` instead of `Bun.spawn`/`Bun.spawnSync`, `node:fs` instead of `Bun.file`, `node:path` instead of Bun's path helpers. Every example on this page follows that rule; a snippet that deliberately requires one host is marked with a `host-specific:` comment naming it.
|
|
864
|
+
|
|
852
865
|
Workflow files are TypeScript modules that export a workflow definition:
|
|
853
866
|
|
|
854
867
|
```ts
|
|
@@ -1208,7 +1221,7 @@ interface StageSessionRuntime {
|
|
|
1208
1221
|
|
|
1209
1222
|
A session announces its queue by `queue_update`, so a queue that exists before Atomic's listeners reach that session is announced to nobody — which happens when a retiring session hands its pending messages to the session replacing it, and when a retained session is reopened for post-mortem chat holding what it was queued. Atomic reads these two methods once, as it attaches a session, and replays the missed snapshot to that stage's listeners; every later change still arrives as an ordinary event. An adapter that omits them loses nothing it had before: only a queue predating the attach is invisible, and a session that starts empty never had one.
|
|
1210
1223
|
|
|
1211
|
-
Externally produced traffic has a separate lifecycle rule. Intercom messages and
|
|
1224
|
+
Externally produced traffic has a separate lifecycle rule. Intercom messages and subagent completion notices received while a workflow stage generation is still open are admitted through the stage AgentSession's native steering/follow-up queue. For a busy stage, admission into the generation boundary happens synchronously before the exact foreground subagent owner's probe/commit detach handshake; model-visible queue insertion waits inside that admitted delivery until the handshake is claimed or falls back after an unclaimed/vanished owner. A commit accepted within a parallel foreground group releases aggregate supervision for every active sibling while retaining their process and eventual-result ownership. Reserving admission before the asynchronous handshake prevents terminal close from overtaking an in-flight Intercom delivery, while waiting inside the reservation prevents a blocking child request from queueing behind either a single foreground tool call or a parallel aggregate still waiting on another child. The stage drains already-admitted work before publishing its terminal snapshot, including schema-backed turns that have already called `structured_output`.
|
|
1212
1225
|
|
|
1213
1226
|
Closing the generation is atomic with admission: a notification admitted first belongs to that stage, while ordinary detached notifications arriving after close cannot reopen or mutate the completed stage and are surfaced once through the main-chat notification path instead. A blocking sibling `intercom.ask` is the deliberate exception: when the completed stage retains a valid conversation, Atomic schedules a post-mortem turn in that conversation so it can inspect the exact ask and reply without changing terminal workflow state. Failed running-stage admission and failed post-mortem admission return correlated actionable errors to the asker instead of consuming the full reply timeout.
|
|
1214
1227
|
|
|
@@ -2407,7 +2420,7 @@ Writes stage/task output to a path or disables output persistence with `false`.
|
|
|
2407
2420
|
|
|
2408
2421
|
The runner writes the stage's **final assistant message** to `output` after the stage ends, so that path belongs to the runner. A stage that declares `output:` also automatically gets a full, rendered, line-oriented transcript of its session, and one appended instruction telling the model that its final message becomes the artifact — the workflow definition does not need to describe any of this.
|
|
2409
2422
|
|
|
2410
|
-
An admitted external turn (for example,
|
|
2423
|
+
An admitted external turn (for example, a subagent completion) can arrive while the stage is still running and remains visible both to the model and in the companion transcript. The runner does not try to work out which turn was "really" the deliverable: that is an inference about intent, and an earlier revision that scored candidates by byte size got it wrong in both directions. If a late turn displaces the intended content, the transcript still holds it.
|
|
2411
2424
|
|
|
2412
2425
|
The companion transcript is written once under the durable Atomic config root at `~/.atomic/workflows/runs/<runId>/transcripts/` (or the equivalent configured agent root; `ATOMIC_WORKFLOW_ARTIFACT_DIR` overrides that root). It is never placed inside the repository tree or OS temporary storage: a home-scoped durable location survives both worktree deletion and OS temp purges, and staying outside the repo keeps full tool output — which may contain secrets — from being committed accidentally. Run-scoped artifact directories are pruned only when their durable/live run record is terminal (or the directory is an unowned orphan) and older than the exported `WORKFLOW_ARTIFACT_RETENTION_MS` policy. Running, paused, quit, blocked, and awaiting-input runs are exempt indefinitely because their artifacts are live resume dependencies. A **failed** run is terminal and does age out: it stays retryable, but the retention window is the grace period it gets, otherwise repeated recoverable failures would accumulate artifacts forever. When a terminal durable owner is aged out, the durable entry is deleted first; if authoritative deletion is unavailable or refuses, the artifact directory is preserved. Goal ledgers, Ralph implementation notes, and QA video paths share that same durable root and retention policy. The receipt names both absolute paths. Search the transcript with `rg`, then read only the narrow line ranges you need; do not read the whole transcript into a downstream prompt. The transcript is a secondary searchable record; the output artifact remains the curated handoff.
|
|
2413
2426
|
|
|
@@ -2631,7 +2644,7 @@ Sends a normal follow-on user turn to the retained stage session. This method st
|
|
|
2631
2644
|
|
|
2632
2645
|
Native sessions accept strings or text/image content blocks. Non-native fallback adapters accept only strings and reject block arrays; `deliverAs` affects streaming delivery only, and follow-on turns retain the stage MCP scope.
|
|
2633
2646
|
|
|
2634
|
-
Externally produced Intercom and
|
|
2647
|
+
Externally produced Intercom and subagent notices admitted before the generation closes drain through the same session. When a busy stage owns a foreground subagent, exact-owner detach gets first refusal before Intercom enters this boundary; unclaimed traffic then uses normal stage admission. Traffic arriving after the atomic close boundary cannot reopen the completed stage and is surfaced once through the main-chat path instead.
|
|
2635
2648
|
|
|
2636
2649
|
See [Stage follow-on user messages](#stage-follow-on-user-messages) for the full lifecycle and schema-backed example.
|
|
2637
2650
|
|
|
@@ -2763,6 +2776,8 @@ interface WorkflowModelAttempt extends WorkflowSerializableObject {
|
|
|
2763
2776
|
}
|
|
2764
2777
|
```
|
|
2765
2778
|
|
|
2779
|
+
When a stage explicitly configures `model` or `fallbackModels`, each recorded attempt can include usage aggregated from meaningful assistant responses in that attempt. The four token buckets remain separate, `cost` sums the provider-reported total cost, and `turns` counts the assistant usage records included in the aggregate. Usage from earlier retained or reattached session history is excluded, while billed error responses removed during a same-model retry remain attributed to that attempt. The `usage` property is omitted when the provider reports no meaningful token or cost signal. Stages that use only the default model without explicit fallback configuration do not currently create model-attempt records.
|
|
2780
|
+
|
|
2766
2781
|
### `WorkflowDetails`
|
|
2767
2782
|
|
|
2768
2783
|
```typescript
|
|
@@ -2979,7 +2994,7 @@ Surface behavior:
|
|
|
2979
2994
|
- **Tool and node detail** - Attached stage chats match main chat's tool-detail expansion behavior while keeping expansion state local to the workflow UI context. Press Ctrl+O (the configurable `app.tools.expand` binding) to expand every visible workflow node and tool card, including single, parallel, and nested subagent progress, current tool activity, and artifact paths; press it again to collapse them. The toggle works for active, completed, and archived stage views, including at the supported 40-column terminal minimum. A mounted prompt, custom question, or other input-owning overlay keeps the key instead of changing it.
|
|
2980
2995
|
- **Footer context** - An attached live stage chat carries the main chat's current-folder and Git-branch identity into its themed footer and mirrors live extension status lines such as the MCP server indicator. Branch changes trigger a repaint through the host's cached footer provider, and extension status changes are read from that same provider rather than recomputed by the workflow UI.
|
|
2981
2996
|
- **Working animation lifecycle** - Ordinary attached-stage work keeps the same exact one-cell `∀` visible while following the active workflow theme's dark → accent → bright/bold → accent → dark luminance ramp every 88ms. Every agent and SDK turn resets to the dark regular phase with a fresh lifecycle-relative cadence; turn, terminal, error, replacement, and disposal cleanup stop the active timer without stale repaint. In an eligible retained-stage chat, every accepted idle follow-up — including a workflow-authored `stage.sendUserMessage(...)` after a prior turn ended — shows Working on admission or attach, including while Atomic restores a saved retained conversation, and keeps it through prompt startup, pre-turn compaction, and agent handoff. Attaching or remounting mid-delivery paints immediately rather than waiting for the turn's first event. A message queued into a live turn with `followUp`/`steer` uses that turn's existing status instead of starting a new one. A no-turn result, prompt or restore error, or terminal completion removes it; once the last accepted post-terminal delivery settles, a leftover start cannot bring it back. An accepted manual retry clears stale status from the prior prompt before showing new pre-stream activity. `NO_COLOR` retains regular/bold activity without foreground-color escapes. Reduced motion uses a static regular accent `∀` without an animation timer; factual automatic retry, fallback, compaction, cancellation, and error copy retains precedence.
|
|
2982
|
-
- **
|
|
2997
|
+
- **Subagent statusline** - If a subagent is running while the fullscreen workflow graph is open, the graph statusline mirrors its summary so the run remains visible; hide the graph with `h`, leave it with `ctrl+x`, or reconnect later to return to the full below-editor widget.
|
|
2983
2998
|
- **Run control** - Use `interrupt`, `pause`, and `resume` for resumable live work. Pause/interrupt holds a stage's queued steering and follow-up items in place without dequeuing them or starting continuation; `resume` releases those items once in their existing per-queue order, but queue release alone does not start a model turn. `resume` on a non-paused run reopens the saved snapshot or overlay. Use `quit` to pause a live run gracefully while preserving it for `/workflow resume`.
|
|
2984
2999
|
- **Rediscovery** - Use `/workflow reload` after adding, editing, installing, or removing workflow resources or package manifest workflow entries and you want Atomic to rediscover them in-process ([Reloading workflow resources](#reloading-workflow-resources)).
|
|
2985
3000
|
- **Status listing** - `/workflow status` lists all retained active and terminal top-level runs by default; implementation-owned nested child runs are flattened into their parent workflow rather than listed separately. `/workflow status --all` is retained as a compatibility alias.
|
|
@@ -3038,6 +3053,7 @@ workflow({ action: "reload", reason: "added team workflow" })
|
|
|
3038
3053
|
Control behavior:
|
|
3039
3054
|
|
|
3040
3055
|
- `runId` requires the full 36-character run UUID for every lifecycle and inspection action, including `status`. User-facing status surfaces print that exact value, so pass it back verbatim; typed prefixes are rejected with a distinct `Run id must be a full 36-character UUID` diagnostic rather than resolved. Because ids are matched exactly and are unique, no run target is ambiguous. Status lists and run pickers show top-level user-launched workflows; nested child runs are implementation details of the expanded parent graph.
|
|
3056
|
+
- `status`, `stages`, `stage`, and `transcript` with an explicit full `runId` first use the current session store, then perform one exact DBOS hydration when that id is absent locally. This is inspection only: Atomic does not claim ownership, change status, run workflow code, or resume the workflow. A stale durable `running` root is shown as `crashed` with its resumability and an explicit `/workflow resume <id>` hint; fresh work owned by another Atomic process remains `running`, offers read-only status guidance, and stays protected from local control or resume. Deleted/tombstoned, absent, malformed, cyclic, orphaned, nonreciprocal, out-of-scope, and duplicate-node records report distinct failures instead of inventing a partial graph. `status` without `runId` remains current-session-only and never scans durable history.
|
|
3041
3057
|
- `status` without `runId` lists every top-level run in the session with a concise per-run summary: the full run id, workflow name, run status, started/ended timing with pause-adjusted elapsed time, currently active stages, and awaiting-input details (count plus the stage, prompt id, kind, and message for each pending human prompt). In-flight runs are listed first. The summaries carry the exact identifiers that `pause`/`resume`/`interrupt`/`quit`/`send` accept, so an orchestrating agent can list runs and act on them directly.
|
|
3042
3058
|
- `statusFilter` narrows the `status` run listing: run statuses (`pending`, `running`, `paused`, `blocked`, `completed`, `failed`, `skipped`, `cancelled`, `killed`) match runs directly, `awaiting_input` selects runs with at least one stage awaiting input or pending human prompt, and `all` (the default) includes everything.
|
|
3043
3059
|
- `format: "json"` on data-bearing inspection actions (`status`, `stages`, `stage`, `transcript`) returns the full structured result; the default text output for `status` is the concise per-run summary list.
|
|
@@ -3065,6 +3081,7 @@ Control behavior:
|
|
|
3065
3081
|
- `pause` is useful for pausing a live run or a single live stage without treating it as a destructive abort.
|
|
3066
3082
|
- `resume` can target a stage with `stageId`; the target may be an exact stage id or an exact stage name. `message` is forwarded to paused work. For a live interrupted streaming prompt, Atomic preserves the existing prompt loop without duplicating the user message and injects `Continue where you left off. If you believe you are finished with your original task (or a redefined task if the user told you), stop.` when required before normal readiness-gate completion. For a paused stage that was idle waiting for a new stage-chat turn, a non-empty message resumes the stage and starts exactly one fresh prompt containing that message; an empty resume releases the pause without creating a prompt.
|
|
3067
3083
|
- An explicit workflow-tool `resume` target that is absent from the current session store triggers targeted DBOS discovery before Atomic returns `Run not found`. The target must be a full run UUID; an eligible exact ID resumes under the original workflow ID, and a malformed target is rejected before any durable lookup happens. Resource-loading and durable-backend failures remain visible. Ordinary workflow-tool `status` listing stays session-local and does not eagerly hydrate durable history.
|
|
3084
|
+
- Exact-id durable inspection is separate from resume. `status`, `stages`, `stage`, and `transcript` may hydrate one missing-local root for read-only inspection, but they never claim it or execute replay. Only an explicit `resume` action enters the claim-and-dispatch path.
|
|
3068
3085
|
- Run-level `quit` gracefully pauses in-flight work, marks the run resumable, and leaves it available to `/workflow resume`. A run whose only in-flight work is a `ctx.tool` node is quit like any other: it pauses as resumable instead of reporting that there are no controllable stages.
|
|
3069
3086
|
- `reload` refreshes discovered workflow resources in-process; the optional `reason` is echoed in the result.
|
|
3070
3087
|
|
|
@@ -3192,7 +3209,7 @@ Atomic workflows use **DBOS/Postgres as their sole persistent workflow backend**
|
|
|
3192
3209
|
|
|
3193
3210
|
When the embedded binaries are unavailable for the platform, Atomic falls back to DBOS's reusable `dbos-db` Docker container. If no durable backend can be provisioned at all, workflows **degrade to a process-local in-memory backend with a loud warning** instead of refusing to run: the run executes normally, but its state does not survive the process and `/workflow resume` after exit has nothing to restore. Set `DBOS_SYSTEM_DATABASE_URL` to an existing Postgres to restore durability.
|
|
3194
3211
|
|
|
3195
|
-
**Multiple concurrent Atomic sessions.** Every Atomic process launches DBOS with a unique executor id, and running root workflows carry owner/heartbeat metadata
|
|
3212
|
+
**Multiple concurrent Atomic sessions.** Every Atomic process launches DBOS with a unique executor id, and running root workflows carry owner/heartbeat metadata. Once an active model stage has a session path, Atomic records that identity after the stage-start record and awaits the checkpoint before the first model use, then runs serialized, unref'd liveness checkpoints on a bounded 30-second cadence for the root and nested scoped workflows. Each accepted checkpoint refreshes root metadata; timers stop on every stage exit and cannot keep Atomic alive. A persistent checkpoint fault fails the active stage instead of disappearing in a detached timer. A stage that is shutting down drains the checkpoint still in flight rather than abandoning it, so a failure that lands after the model turn finished is reported instead of discarded, and a stage whose final durability checkpoint fails is recorded as `failed` rather than `completed` — its caller receives the error and its concurrency slot is released either way. **Running workflows are never resume targets**: a running row with a fresh heartbeat is hidden from every session's picker and refused by direct `/workflow resume <id>` — resuming a workflow that is executing elsewhere would double-dispatch it. Once the heartbeat goes stale (about two minutes after a crash), an exact inspection or the resume picker reports the workflow as `crashed`.
|
|
3196
3213
|
|
|
3197
3214
|
When two sessions race to resume the same paused workflow, a durable first-writer-wins claim decides exactly one winner; the loser reconciles to the authoritative state and reports that the workflow changed while resume was pending.
|
|
3198
3215
|
|
|
@@ -3203,7 +3220,7 @@ When two sessions race to resume the same paused workflow, a durable first-write
|
|
|
3203
3220
|
- **Durable child identity before dispatch**: before a nested `ctx.workflow(...)` can run child code or a child side effect, Atomic persists and awaits a versioned boundary-start record containing its stable boundary and child run ids, root/parent ownership, source order and parents, composed replay scope, alias, workflow, lifecycle state, and a deterministic fingerprint of the definition plus exact validated inputs. Distinct-input parallel calls keep stable independent scopes even when restart reverses dispatch order; identical calls share that fingerprint and use their own ordinal. Replay validates and reuses that identity before allocating any UUID.
|
|
3204
3221
|
- **Symmetric nested scopes**: child effects stay stored under the durable root, while every child sees only its own local checkpoint view. Each nesting layer strips exactly one scope and never suffix-matches sibling or root data, so the rule composes at any depth.
|
|
3205
3222
|
- **Stable durable graph**: tool, stage, task, chain, parallel, and child-workflow checkpoints preserve stable source identity/order, parent DAG edges, actual status, owning-run/boundary metadata, timing, output summary, model, retained chat-session references, and exact `{ runId, stageId }` targets. Fresh-process resume and completed inspection reconstruct tool-only, nested-child, mixed, and parallel topology directly from DBOS.
|
|
3206
|
-
- **DBOS-only discovery**: `/workflow resume`, `/workflows`, completed inspection, deletion, and targeted lookup hydrate/query DBOS. Session JSONL remains only a chat transcript referenced by a current checkpoint; it is not a workflow catalog or discovery source.
|
|
3223
|
+
- **DBOS-only discovery and exact inspection**: `/workflow resume`, `/workflows`, completed inspection, deletion, and targeted lookup hydrate/query DBOS. An explicit full run id on `status`, `stages`, `stage`, or `transcript` hydrates only that root when the current-session store misses; a no-id status listing stays session-local. Session JSONL remains only a chat transcript referenced by a current checkpoint; it is not a workflow catalog or discovery source.
|
|
3207
3224
|
- **Fail-closed compatibility**: prior local and pre-current records are not converted. A completed current-format child boundary created before boundary-start or invocation-fingerprint identity is accepted only when child checkpoints reciprocally prove the same root, parent run, boundary, child, and scope. Active records without a provable invocation fingerprint, and malformed, duplicate, stale, nonreciprocal, mixed, aliased, cyclic, orphaned, or unsupported topology, are hidden or refused before cache/control/child dispatch without inventing a child link or executing repair work.
|
|
3208
3225
|
- **Topology validation boundary**: authoring and discovery guidance cannot prove dynamic acyclicity. Runtime topology work must validate each materialized parent edge incrementally during execution and replay, and DBOS hydration must reject cyclic restored topology before exposing cache, control, or child dispatch.
|
|
3209
3226
|
- **Cross-session safety**: per-process executor identity, owner/heartbeat liveness on running handles, and claim-guarded status transitions prevent double dispatch when several Atomic sessions share the database.
|
|
@@ -3212,7 +3229,7 @@ When two sessions race to resume the same paused workflow, a durable first-write
|
|
|
3212
3229
|
|
|
3213
3230
|
**Resume after editing a workflow.** Replay identity combines the workflow id with stable content hashes and call order. Child calls additionally bind the child definition to the exact validated input value, with a per-identical-invocation ordinal. Editing definitions, inputs, or `ctx.*` call structure can intentionally invalidate matches. Finish or delete retained runs before deploying incompatible workflow changes. Atomic refuses a stored child boundary whose fingerprint, replay scope, alias, workflow, ownership, source order, or parentage no longer matches instead of attaching it to the changed call site.
|
|
3214
3231
|
|
|
3215
|
-
Durable `/workflow resume` preserves completed stage metadata, active-stage elapsed time, total run elapsed time, source order and parent edges, actual lifecycle status, nested ownership, and exact control targets. A completed nested boundary, its completed child stages, `ctx.tool` effects, and answered `ctx.ui` responses are cache hits; only incomplete child or downstream parent work continues. Raw stage-chat prompt answers represented by `StageSnapshot.promptAnswerState` remain live-memory-only and are not DBOS-persisted. While
|
|
3232
|
+
Durable `/workflow resume` preserves completed stage metadata, active-stage elapsed time, total run elapsed time, source order and parent edges, actual lifecycle status, nested ownership, and exact control targets. A completed nested boundary, its completed child stages, `ctx.tool` effects, and answered `ctx.ui` responses are cache hits; only incomplete child or downstream parent work continues. Raw stage-chat prompt answers represented by `StageSnapshot.promptAnswerState` remain live-memory-only and are not DBOS-persisted. While a model stage or task is active, Atomic persists its session identity as soon as the path exists and refreshes pause-adjusted duration plus root liveness at most once per serialized 30-second heartbeat. Nested stages route the same checkpoint through their scoped backend to the durable root. Graceful quit forces an exact stage and run timing checkpoint even inside the ordinary update bucket; normal completion also persists the final accumulated run total.
|
|
3216
3233
|
|
|
3217
3234
|
Each new Atomic process that reopens unfinished work starts from the latest saved baseline, so repeated process-boundary resumes keep stable boundary/child ids, status, graph, and lifecycle duration cumulative without double-counting pauses. A stage paused at ten seconds resumes at ten seconds, and the main-chat dashboard reports prior-session elapsed plus current-session elapsed. Completed inspection uses that same accumulated run timing rather than DBOS record wall-clock age.
|
|
3218
3235
|
|
|
@@ -3314,7 +3331,7 @@ Fresh completed inspection does not currently persist the workflow's declared ro
|
|
|
3314
3331
|
|
|
3315
3332
|
Targets resolve across top-level live, resumable durable, and completed entries as one namespace, matched by full UUID only. An exact loadable paused top-level live target resumes directly from in-session state without enumerating the durable completed-history catalog; this keeps explicit live resume responsive even when retained durable history is large and preserves live-over-durable precedence for duplicate IDs. If a stale or concurrent catalog view presents the same failed root as both resumable and read-only history, the resumable durable target wins. Nested child runs remain excluded from this top-level target namespace even when addressed by an exact ID.
|
|
3316
3333
|
|
|
3317
|
-
The non-interactive `workflow
|
|
3334
|
+
The non-interactive `workflow` surface uses exact targeted DBOS lookup for explicit ids. `resume` loads workflow resources, queries and revalidates the authoritative resumable record, then claims and dispatches only when the caller explicitly requested resume. `status`, `stages`, `stage`, and `transcript` hydrate one exact missing-local root into an isolated read-only snapshot and never dispatch. This targeted path does not change `workflow({ action: "status" })` without a run id: an empty session-local listing neither scans DBOS nor implies that DBOS deleted the workflow.
|
|
3318
3335
|
|
|
3319
3336
|
A target that is not a full UUID is rejected before the combined catalog is consulted, so a truncated id never reaches durable lookup. Read-only inspection behavior is otherwise unchanged. A current completed or non-resumable failed backend row with valid graph checkpoints remains inspectable even if every retained stage conversation is unavailable. Missing, empty, directory, context-empty, or partially malformed transcript paths are stripped from chat attachment while the graph stays read-only and visible.
|
|
3320
3337
|
|
|
@@ -3327,7 +3344,7 @@ Validation uses the final retained transcript for a repeated stage replay key, s
|
|
|
3327
3344
|
| **Internally cancelled workflow** | Marked `cancelled` in durable state and excluded from `/workflow resume` discovery. Start a new workflow run if you intentionally want to retry cancelled work. |
|
|
3328
3345
|
| **Stage failure (recoverable)** | Workflow marked `failed` or `blocked` and remains resumable by default. `/workflow resume <id>` continues from the last completed checkpoint unless durable metadata explicitly sets `resumable: false`. |
|
|
3329
3346
|
| **Stage failure (non-recoverable)** | Workflow marked `failed` or `blocked` with `resumable: false`, so it cannot resume execution. A failed root with saved checkpoint progress may still appear in read-only history for inspection; a blocked root does not. |
|
|
3330
|
-
| **Process crash** | Workflow remains `running` in durable state.
|
|
3347
|
+
| **Process crash** | Workflow remains `running` in durable state. Exact-id status/inspection reconstructs its retained checkpoint DAG as `crashed` once the owner heartbeat is stale and shows whether explicit resume is available. `/workflow resume <id>` is still required to claim the root and continue from the last completed checkpoint. |
|
|
3331
3348
|
| **`ctx.tool` retry/default failure** | When `retriesAllowed: true`, the tool function is retried with exponential backoff. Cancellation is checked before each attempt, during retry backoff, and through the callback's own `signal`. Without `failureMode: "return"`, an exhausted callback error propagates and the workflow fails. |
|
|
3332
3349
|
| **Recoverable `ctx.tool` failure** | With `failureMode: "return"`, exhausted callback failures are durably returned after retries. The tool node remains failed, downstream handoff is explicit, and replay returns the same outcome with `cached: true`. Cancellation and storage faults still throw. |
|
|
3333
3350
|
| **`ctx.tool` node quit/interrupt** | `quit`/`interrupt` with a tool node id or name aborts that call's signal, marks the node `cancelled`, and leaves sibling stages and tools running. The action returns `status: "cancelled"` with the separately observed `workflowStatus`; it never reports the run as paused. No replayable `tool:` checkpoint and no `return_failure` outcome are written — return mode writes only inspection metadata — so resume re-runs exactly that call at the same ordinal and node id. |
|
|
@@ -4678,17 +4695,28 @@ The parent should verify each child before creating the next boundary. If a gate
|
|
|
4678
4695
|
The calls below are deliberately unrolled. Repeat the downstream shape for the planned slices, giving every call a fresh child boundary and distinct tracked nodes; do not reopen an ancestor or add a back-edge.
|
|
4679
4696
|
|
|
4680
4697
|
```ts
|
|
4698
|
+
import { spawnSync } from "node:child_process";
|
|
4681
4699
|
import { resolve } from "node:path";
|
|
4682
4700
|
import { Type } from "typebox";
|
|
4683
4701
|
import { workflow } from "@bastani/workflows";
|
|
4684
4702
|
import { goal } from "@bastani/workflows/builtin";
|
|
4685
4703
|
|
|
4704
|
+
function spawnCommand(argv: readonly string[], cwd: string) {
|
|
4705
|
+
const [command, ...args] = argv;
|
|
4706
|
+
if (command === undefined) throw new Error("spawnCommand requires a command");
|
|
4707
|
+
const result = spawnSync(command, args, { cwd, encoding: "utf8" });
|
|
4708
|
+
// A command that could not be spawned at all arrives on `error` with a null
|
|
4709
|
+
// status, so it has to be raised here or it reads as an ordinary failure.
|
|
4710
|
+
if (result.error) throw result.error;
|
|
4711
|
+
return result;
|
|
4712
|
+
}
|
|
4713
|
+
|
|
4686
4714
|
function runCommand(argv: readonly string[], cwd: string): string {
|
|
4687
|
-
const result =
|
|
4688
|
-
const stdout = result.stdout
|
|
4689
|
-
const stderr = result.stderr
|
|
4690
|
-
if (result.
|
|
4691
|
-
throw new Error(`${argv.join(" ")} failed (${result.
|
|
4715
|
+
const result = spawnCommand(argv, cwd);
|
|
4716
|
+
const stdout = (result.stdout ?? "").trim();
|
|
4717
|
+
const stderr = (result.stderr ?? "").trim();
|
|
4718
|
+
if (result.status !== 0) {
|
|
4719
|
+
throw new Error(`${argv.join(" ")} failed (${result.status})\n${stderr || stdout}`);
|
|
4692
4720
|
}
|
|
4693
4721
|
return stdout;
|
|
4694
4722
|
}
|
|
@@ -4719,28 +4747,28 @@ export default workflow({
|
|
|
4719
4747
|
toolName,
|
|
4720
4748
|
{ branch, base_branch: baseBranch, git_worktree_dir: gitWorktreeDir },
|
|
4721
4749
|
async () => {
|
|
4722
|
-
const current =
|
|
4750
|
+
const current = spawnCommand(
|
|
4723
4751
|
["git", "-C", worktreePath, "branch", "--show-current"],
|
|
4724
|
-
|
|
4752
|
+
repoRoot,
|
|
4725
4753
|
);
|
|
4726
|
-
if (current.
|
|
4727
|
-
const checkedOutBranch = current.stdout
|
|
4754
|
+
if (current.status === 0) {
|
|
4755
|
+
const checkedOutBranch = (current.stdout ?? "").trim();
|
|
4728
4756
|
if (checkedOutBranch !== branch) {
|
|
4729
4757
|
throw new Error(`${worktreePath} is checked out on ${checkedOutBranch || "detached HEAD"}, expected ${branch}`);
|
|
4730
4758
|
}
|
|
4731
4759
|
return { branch, worktree: worktreePath };
|
|
4732
4760
|
}
|
|
4733
4761
|
|
|
4734
|
-
const branchProbe =
|
|
4762
|
+
const branchProbe = spawnCommand(
|
|
4735
4763
|
["git", "show-ref", "--verify", "--quiet", `refs/heads/${branch}`],
|
|
4736
|
-
|
|
4764
|
+
repoRoot,
|
|
4737
4765
|
);
|
|
4738
|
-
if (branchProbe.
|
|
4766
|
+
if (branchProbe.status === 0) {
|
|
4739
4767
|
runCommand(["git", "worktree", "add", worktreePath, branch], repoRoot);
|
|
4740
|
-
} else if (branchProbe.
|
|
4768
|
+
} else if (branchProbe.status === 1) {
|
|
4741
4769
|
runCommand(["git", "worktree", "add", "-b", branch, worktreePath, baseBranch], repoRoot);
|
|
4742
4770
|
} else {
|
|
4743
|
-
throw new Error(branchProbe.stderr
|
|
4771
|
+
throw new Error((branchProbe.stderr ?? "").trim() || `could not inspect branch ${branch}`);
|
|
4744
4772
|
}
|
|
4745
4773
|
return { branch, worktree: worktreePath };
|
|
4746
4774
|
},
|