@bastani/atomic 0.9.5-alpha.7 → 0.9.5-alpha.9
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 +33 -2
- package/dist/builtin/cursor/package.json +2 -2
- package/dist/builtin/intercom/CHANGELOG.md +17 -0
- package/dist/builtin/intercom/README.md +27 -21
- package/dist/builtin/intercom/broker/broker.ts +3 -6
- package/dist/builtin/intercom/broker/paths.ts +42 -5
- package/dist/builtin/intercom/broker/spawn.ts +78 -10
- package/dist/builtin/intercom/config.ts +6 -3
- package/dist/builtin/intercom/contact-supervisor-tool.ts +6 -4
- package/dist/builtin/intercom/index-heavy.ts +1 -1
- package/dist/builtin/intercom/index.ts +162 -130
- package/dist/builtin/intercom/intercom-tool.ts +9 -3
- package/dist/builtin/intercom/package.json +10 -1
- package/dist/builtin/intercom/result-renderers.ts +1 -1
- package/dist/builtin/intercom/ui/compose.ts +2 -2
- package/dist/builtin/intercom/ui/inline-message.ts +2 -2
- package/dist/builtin/intercom/ui/session-list.ts +2 -2
- package/dist/builtin/mcp/CHANGELOG.md +11 -0
- package/dist/builtin/mcp/README.md +6 -6
- package/dist/builtin/mcp/direct-tools.ts +41 -23
- package/dist/builtin/mcp/index.ts +31 -4
- package/dist/builtin/mcp/init.ts +4 -43
- package/dist/builtin/mcp/metadata-hydration.ts +37 -0
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/mcp/proxy-info-modes.ts +67 -14
- package/dist/builtin/mcp/startup-warmup.ts +98 -0
- package/dist/builtin/mcp/tool-result-renderer.ts +3 -3
- package/dist/builtin/subagents/CHANGELOG.md +18 -0
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/subagents/src/extension/index.ts +14 -25
- package/dist/builtin/subagents/src/extension/startup-maintenance.ts +89 -0
- package/dist/builtin/subagents/src/runs/background/async-execution-common.ts +23 -18
- package/dist/builtin/subagents/src/runs/background/result-watcher.ts +20 -10
- package/dist/builtin/subagents/src/runs/background/subagent-runner-streaming.ts +13 -3
- package/dist/builtin/subagents/src/runs/foreground/execution-attempt.ts +10 -2
- package/dist/builtin/subagents/src/runs/shared/pi-spawn.ts +28 -1
- package/dist/builtin/subagents/src/tui/render-event-formatting.ts +15 -48
- package/dist/builtin/subagents/src/tui/render-layout.ts +9 -0
- package/dist/builtin/subagents/src/tui/render-widget-graph.ts +27 -25
- package/dist/builtin/subagents/src/tui/render-widget.ts +72 -66
- package/dist/builtin/subagents/src/tui/render.ts +1 -1
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +29 -0
- package/dist/builtin/workflows/README.md +4 -2
- package/dist/builtin/workflows/builtin/goal-artifacts.ts +3 -1
- package/dist/builtin/workflows/builtin/goal-prompts.ts +23 -2
- package/dist/builtin/workflows/builtin/goal-reducer.ts +21 -0
- package/dist/builtin/workflows/builtin/goal-review.ts +60 -6
- package/dist/builtin/workflows/builtin/goal-runner.ts +71 -22
- package/dist/builtin/workflows/builtin/goal-types.ts +7 -1
- package/dist/builtin/workflows/builtin/ralph-core.ts +52 -4
- package/dist/builtin/workflows/builtin/ralph-review-gate.ts +10 -3
- package/dist/builtin/workflows/builtin/ralph-reviewer-prompt.ts +23 -2
- package/dist/builtin/workflows/builtin/ralph-runner.ts +38 -16
- package/dist/builtin/workflows/builtin/review-convergence.ts +111 -0
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/skills/create-spec/SKILL.md +2 -0
- package/dist/builtin/workflows/skills/impeccable/SKILL.md +16 -13
- package/dist/builtin/workflows/skills/impeccable/reference/adapt.md +1 -0
- package/dist/builtin/workflows/skills/impeccable/reference/adapt.native.md +58 -0
- package/dist/builtin/workflows/skills/impeccable/reference/android.md +40 -0
- package/dist/builtin/workflows/skills/impeccable/reference/animate.md +2 -0
- package/dist/builtin/workflows/skills/impeccable/reference/audit.md +2 -0
- package/dist/builtin/workflows/skills/impeccable/reference/audit.native.md +139 -0
- package/dist/builtin/workflows/skills/impeccable/reference/bolder.md +69 -62
- package/dist/builtin/workflows/skills/impeccable/reference/critique.md +21 -7
- package/dist/builtin/workflows/skills/impeccable/reference/document.md +1 -1
- package/dist/builtin/workflows/skills/impeccable/reference/hooks.md +92 -0
- package/dist/builtin/workflows/skills/impeccable/reference/init.md +29 -7
- package/dist/builtin/workflows/skills/impeccable/reference/ios.md +45 -0
- package/dist/builtin/workflows/skills/impeccable/reference/layout.md +25 -1
- package/dist/builtin/workflows/skills/impeccable/reference/typeset.md +23 -1
- package/dist/builtin/workflows/skills/impeccable/scripts/context-signals.mjs +2 -1
- package/dist/builtin/workflows/skills/impeccable/scripts/context.mjs +75 -14
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/browser/injected/index.mjs +1 -1
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/cli/main.mjs +31 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/design-system.mjs +64 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/detect-antipatterns-browser.js +118 -11
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/engines/regex/detect-text.mjs +16 -11
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/registry/antipatterns.mjs +66 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/rules/checks.mjs +42 -10
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/shared/fonts.mjs +30 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/shared/page.mjs +4 -6
- package/dist/builtin/workflows/skills/impeccable/scripts/hook-admin.mjs +660 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/hook-before-edit.mjs +516 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/hook-lib.mjs +1764 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/hook.mjs +61 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/lib/impeccable-config.mjs +4 -2
- package/dist/builtin/workflows/skills/impeccable/scripts/lib/is-generated.mjs +2 -2
- package/dist/builtin/workflows/skills/impeccable/scripts/live/svelte-component.mjs +13 -16
- package/dist/builtin/workflows/skills/impeccable/scripts/live-accept.mjs +17 -11
- package/dist/builtin/workflows/skills/impeccable/scripts/live-browser.js +104 -37
- package/dist/builtin/workflows/skills/impeccable/scripts/live-wrap.mjs +9 -0
- package/dist/builtin/workflows/src/durable/backend.ts +12 -0
- package/dist/builtin/workflows/src/durable/child-primitive.ts +12 -8
- package/dist/builtin/workflows/src/durable/dbos-backend.ts +63 -2
- package/dist/builtin/workflows/src/durable/dbos-envelope.ts +28 -0
- package/dist/builtin/workflows/src/durable/resume-catalog.ts +12 -0
- package/dist/builtin/workflows/src/durable/resume-runtime.ts +5 -2
- package/dist/builtin/workflows/src/durable/stage-primitive.ts +165 -27
- package/dist/builtin/workflows/src/durable/types.ts +30 -1
- package/dist/builtin/workflows/src/engine/primitives/task.ts +1 -0
- package/dist/builtin/workflows/src/engine/run-durable-finalize.ts +1 -2
- package/dist/builtin/workflows/src/engine/run-returned-status.ts +50 -16
- package/dist/builtin/workflows/src/engine/run.ts +32 -32
- package/dist/builtin/workflows/src/engine/runtime.ts +5 -0
- package/dist/builtin/workflows/src/extension/extension-factory.ts +3 -0
- package/dist/builtin/workflows/src/extension/extension-lifecycle.ts +9 -2
- package/dist/builtin/workflows/src/extension/extension-runtime-state.ts +137 -27
- package/dist/builtin/workflows/src/extension/lifecycle-notifications.ts +22 -6
- package/dist/builtin/workflows/src/extension/public-types.ts +1 -1
- package/dist/builtin/workflows/src/extension/workflow-command-completions.ts +13 -1
- package/dist/builtin/workflows/src/extension/workflow-command-registration.ts +19 -4
- package/dist/builtin/workflows/src/extension/workflow-command-surfaces.ts +9 -0
- package/dist/builtin/workflows/src/extension/workflow-prompts.ts +2 -0
- package/dist/builtin/workflows/src/extension/workflow-run-control-command.ts +48 -23
- package/dist/builtin/workflows/src/extension/workflow-tool-control.ts +20 -8
- package/dist/builtin/workflows/src/extension/workflow-tool.ts +24 -8
- package/dist/builtin/workflows/src/runs/background/status.ts +4 -3
- package/dist/builtin/workflows/src/runs/foreground/executor-continuation.ts +13 -3
- package/dist/builtin/workflows/src/runs/foreground/executor-direct-helpers.ts +29 -8
- package/dist/builtin/workflows/src/runs/foreground/executor-hil.ts +2 -1
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-factory.ts +4 -3
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-controller.ts +18 -19
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-unresolved-overflow.ts +38 -0
- package/dist/builtin/workflows/src/runs/shared/worktree-git.ts +155 -20
- package/dist/builtin/workflows/src/runs/shared/worktree-types.ts +6 -0
- package/dist/builtin/workflows/src/runs/shared/worktree.ts +2 -1
- package/dist/builtin/workflows/src/shared/persistence-restore-helpers.ts +18 -1
- package/dist/builtin/workflows/src/shared/persistence-restore.ts +23 -5
- package/dist/builtin/workflows/src/shared/persistence-session-entries.ts +4 -0
- package/dist/builtin/workflows/src/shared/returned-run-status.ts +116 -0
- package/dist/builtin/workflows/src/shared/workflow-failures-decisions.ts +2 -0
- package/dist/builtin/workflows/src/tui/graph-view-render-helpers.ts +21 -3
- package/dist/builtin/workflows/src/tui/graph-view-state.ts +3 -0
- package/dist/builtin/workflows/src/tui/graph-view-types.ts +3 -0
- package/dist/builtin/workflows/src/tui/status-list.ts +22 -15
- package/dist/builtin/workflows/src/tui/workflow-attach-pane.ts +4 -4
- package/dist/bun/internal-intercom-broker.d.ts +6 -0
- package/dist/bun/internal-intercom-broker.d.ts.map +1 -0
- package/dist/bun/internal-intercom-broker.js +39 -0
- package/dist/bun/internal-intercom-broker.js.map +1 -0
- package/dist/bun/split-loader.d.ts.map +1 -1
- package/dist/bun/split-loader.js +21 -8
- package/dist/bun/split-loader.js.map +1 -1
- package/dist/core/agent-session-auto-compaction.d.ts +21 -2
- package/dist/core/agent-session-auto-compaction.d.ts.map +1 -1
- package/dist/core/agent-session-auto-compaction.js +163 -11
- package/dist/core/agent-session-auto-compaction.js.map +1 -1
- package/dist/core/agent-session-events.d.ts.map +1 -1
- package/dist/core/agent-session-events.js +10 -1
- package/dist/core/agent-session-events.js.map +1 -1
- package/dist/core/agent-session-methods.d.ts +12 -3
- 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-models.d.ts +2 -2
- package/dist/core/agent-session-models.d.ts.map +1 -1
- package/dist/core/agent-session-models.js.map +1 -1
- package/dist/core/agent-session-prompt.d.ts.map +1 -1
- package/dist/core/agent-session-prompt.js +1 -0
- package/dist/core/agent-session-prompt.js.map +1 -1
- package/dist/core/agent-session-retry.d.ts +2 -0
- package/dist/core/agent-session-retry.d.ts.map +1 -1
- package/dist/core/agent-session-retry.js +152 -4
- package/dist/core/agent-session-retry.js.map +1 -1
- package/dist/core/agent-session-services.d.ts +1 -0
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +1 -0
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session-types.d.ts +15 -1
- package/dist/core/agent-session-types.d.ts.map +1 -1
- package/dist/core/agent-session-types.js.map +1 -1
- package/dist/core/agent-session.d.ts +6 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +6 -0
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/compaction/context-compaction-runner.d.ts.map +1 -1
- package/dist/core/compaction/context-compaction-runner.js +36 -20
- package/dist/core/compaction/context-compaction-runner.js.map +1 -1
- package/dist/core/copilot-anthropic-sse-repair.d.ts +23 -0
- package/dist/core/copilot-anthropic-sse-repair.d.ts.map +1 -0
- package/dist/core/copilot-anthropic-sse-repair.js +340 -0
- package/dist/core/copilot-anthropic-sse-repair.js.map +1 -0
- package/dist/core/copilot-gemini-reasoning.d.ts +16 -8
- package/dist/core/copilot-gemini-reasoning.d.ts.map +1 -1
- package/dist/core/copilot-gemini-reasoning.js +27 -22
- package/dist/core/copilot-gemini-reasoning.js.map +1 -1
- package/dist/core/copilot-hosts.d.ts +12 -0
- package/dist/core/copilot-hosts.d.ts.map +1 -0
- package/dist/core/copilot-hosts.js +33 -0
- package/dist/core/copilot-hosts.js.map +1 -0
- package/dist/core/extensions/agent-events.d.ts +1 -1
- package/dist/core/extensions/agent-events.d.ts.map +1 -1
- package/dist/core/extensions/agent-events.js.map +1 -1
- package/dist/core/extensions/loader-virtual-modules.d.ts +8 -1
- package/dist/core/extensions/loader-virtual-modules.d.ts.map +1 -1
- package/dist/core/extensions/loader-virtual-modules.js +2 -1
- package/dist/core/extensions/loader-virtual-modules.js.map +1 -1
- package/dist/core/footer-data-provider.d.ts +6 -0
- package/dist/core/footer-data-provider.d.ts.map +1 -1
- package/dist/core/footer-data-provider.js +72 -29
- package/dist/core/footer-data-provider.js.map +1 -1
- package/dist/core/http-dispatcher.d.ts.map +1 -1
- package/dist/core/http-dispatcher.js +5 -5
- package/dist/core/http-dispatcher.js.map +1 -1
- package/dist/core/openai-responses-payload-sanitizer.d.ts +1 -0
- package/dist/core/openai-responses-payload-sanitizer.d.ts.map +1 -1
- package/dist/core/openai-responses-payload-sanitizer.js +24 -9
- package/dist/core/openai-responses-payload-sanitizer.js.map +1 -1
- package/dist/core/sdk-types.d.ts +2 -0
- package/dist/core/sdk-types.d.ts.map +1 -1
- package/dist/core/sdk-types.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +1 -0
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/settings-manager-basic-accessors.d.ts +1 -0
- package/dist/core/settings-manager-basic-accessors.d.ts.map +1 -1
- package/dist/core/settings-manager-basic-accessors.js +6 -0
- package/dist/core/settings-manager-basic-accessors.js.map +1 -1
- package/dist/core/settings-types.d.ts +1 -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.d.ts +2 -0
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +141 -0
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/index-extensions.d.ts +1 -1
- package/dist/index-extensions.d.ts.map +1 -1
- package/dist/index-extensions.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/main-deferred-startup.d.ts +12 -0
- package/dist/main-deferred-startup.d.ts.map +1 -1
- package/dist/main-deferred-startup.js +23 -2
- package/dist/main-deferred-startup.js.map +1 -1
- package/dist/main-early-input.d.ts +41 -0
- package/dist/main-early-input.d.ts.map +1 -0
- package/dist/main-early-input.js +154 -0
- package/dist/main-early-input.js.map +1 -0
- package/dist/main.d.ts +0 -6
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +20 -14
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-actions.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-actions.js +0 -1
- package/dist/modes/interactive/components/chat-session-host-actions.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 +15 -0
- package/dist/modes/interactive/components/chat-session-host-events.js.map +1 -1
- package/dist/modes/interactive/interactive-agent-events.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-agent-events.js +25 -0
- package/dist/modes/interactive/interactive-agent-events.js.map +1 -1
- package/dist/modes/interactive/interactive-autocomplete.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-autocomplete.js +21 -9
- package/dist/modes/interactive/interactive-autocomplete.js.map +1 -1
- package/dist/modes/interactive/interactive-deferred-startup.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-deferred-startup.js +41 -28
- package/dist/modes/interactive/interactive-deferred-startup.js.map +1 -1
- package/dist/modes/interactive/interactive-hotkeys-debug.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-hotkeys-debug.js +1 -0
- package/dist/modes/interactive/interactive-hotkeys-debug.js.map +1 -1
- package/dist/modes/interactive/interactive-input-handling.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-input-handling.js +318 -185
- package/dist/modes/interactive/interactive-input-handling.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-base.d.ts +12 -0
- package/dist/modes/interactive/interactive-mode-base.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode-base.js +39 -0
- package/dist/modes/interactive/interactive-mode-base.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-deps.d.ts +1 -1
- 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 +6 -2
- 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-mode-types.d.ts +3 -0
- package/dist/modes/interactive/interactive-mode-types.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode-types.js.map +1 -1
- package/dist/modes/interactive/interactive-model-routing.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-model-routing.js +3 -1
- package/dist/modes/interactive/interactive-model-routing.js.map +1 -1
- package/dist/modes/interactive/interactive-process-lifecycle.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-process-lifecycle.js +0 -3
- package/dist/modes/interactive/interactive-process-lifecycle.js.map +1 -1
- package/dist/modes/interactive/interactive-render-chat.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-render-chat.js +36 -10
- package/dist/modes/interactive/interactive-render-chat.js.map +1 -1
- package/dist/modes/interactive/interactive-session-routing.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-session-routing.js +5 -1
- package/dist/modes/interactive/interactive-session-routing.js.map +1 -1
- package/dist/modes/interactive/interactive-startup.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-startup.js +26 -22
- package/dist/modes/interactive/interactive-startup.js.map +1 -1
- package/dist/modes/interactive/theme/global-theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/global-theme.js +26 -2
- package/dist/modes/interactive/theme/global-theme.js.map +1 -1
- package/dist/utils/fs-watch.d.ts +24 -1
- package/dist/utils/fs-watch.d.ts.map +1 -1
- package/dist/utils/fs-watch.js +60 -5
- package/dist/utils/fs-watch.js.map +1 -1
- package/docs/compaction.md +8 -0
- package/docs/development.md +4 -0
- package/docs/extensions.md +5 -0
- package/docs/json.md +3 -1
- package/docs/providers.md +1 -0
- package/docs/quickstart.md +1 -1
- package/docs/rpc.md +3 -1
- package/docs/settings.md +27 -1
- package/docs/subagents.md +4 -0
- package/docs/terminal-setup.md +4 -0
- package/docs/usage.md +2 -2
- package/docs/windows.md +4 -0
- package/docs/workflows.md +21 -9
- package/npm-shrinkwrap.json +513 -23
- package/package.json +3 -2
|
@@ -1,11 +1,5 @@
|
|
|
1
|
-
import type { RunSnapshot } from "../shared/store-types.js";
|
|
2
|
-
import type {
|
|
3
|
-
WorkflowDefinition,
|
|
4
|
-
WorkflowInputValues,
|
|
5
|
-
WorkflowOutputValues,
|
|
6
|
-
WorkflowRunContext,
|
|
7
|
-
WorkflowSerializableValue,
|
|
8
|
-
} from "../shared/types.js";
|
|
1
|
+
import type { RunSnapshot, StageSnapshot } from "../shared/store-types.js";
|
|
2
|
+
import type { WorkflowDefinition, WorkflowInputValues, WorkflowOutputValues, WorkflowRunContext } from "../shared/types.js";
|
|
9
3
|
import type { WorkflowFailure } from "../shared/workflow-failures.js";
|
|
10
4
|
import { classifyWorkflowFailure } from "../shared/workflow-failures.js";
|
|
11
5
|
import { store as defaultStore } from "../shared/store.js";
|
|
@@ -25,7 +19,7 @@ import { stageControlRegistry as defaultStageControlRegistry } from "../runs/for
|
|
|
25
19
|
import type { RunOpts, RunResult } from "../runs/foreground/executor-types.js";
|
|
26
20
|
import { unknownErrorMessage, findWorkflowExitSignal, parentWorkflowExitAbortReason } from "../runs/foreground/executor-abort.js";
|
|
27
21
|
import { resolveAndValidateInputs, resolveInputConcurrency, resolveInputRuntimeDefaults } from "../runs/foreground/executor-inputs.js";
|
|
28
|
-
import { workflowCwdWithInputWorktree } from "../runs/foreground/executor-direct-helpers.js";
|
|
22
|
+
import { createGitWorktreeSetupCache, workflowCwdWithInputWorktree, workflowInvocationMetadata } from "../runs/foreground/executor-direct-helpers.js";
|
|
29
23
|
import { createStageScheduler } from "../runs/foreground/executor-scheduler.js";
|
|
30
24
|
import { createRunFinalizers } from "../runs/foreground/executor-run-finalizers.js";
|
|
31
25
|
import { buildPromptNodeUiAdapter } from "../runs/foreground/executor-prompt-nodes.js";
|
|
@@ -45,12 +39,12 @@ import { classifyReturnedRunStatus } from "./run-returned-status.js";
|
|
|
45
39
|
import { createToolPrimitive, createCheckpointIdGenerator } from "../durable/tool-primitive.js";
|
|
46
40
|
import { persistDurableCacheEntry } from "../durable/resume-catalog.js";
|
|
47
41
|
import { createDurableStagePrimitive, createDurableTaskPrimitive, recordStageCheckpoint, createStageReplayKeyGenerator, recordCachedStageWithTracker } from "../durable/stage-primitive.js";
|
|
42
|
+
import type { DurableCompletedStageCheckpoint } from "../durable/stage-primitive.js";
|
|
48
43
|
import { createDurableChildWorkflowPrimitive } from "../durable/child-primitive.js";
|
|
49
44
|
import { ScopedDurableBackend, type DurableScope } from "../durable/scoped-backend.js";
|
|
50
45
|
import { finalizeDurableTerminalStatus } from "./run-durable-finalize.js";
|
|
51
46
|
import { createDurableStageSessionRecorder } from "./run-durable-stage-session.js";
|
|
52
47
|
import type { DurableWorkflowBackend } from "../durable/backend.js";
|
|
53
|
-
import type { StageSnapshot } from "../shared/store-types.js";
|
|
54
48
|
|
|
55
49
|
function nextEventLoopTurn(): Promise<void> {
|
|
56
50
|
return new Promise((resolve) => setTimeout(resolve, 0));
|
|
@@ -158,11 +152,11 @@ export async function run<
|
|
|
158
152
|
|
|
159
153
|
const tracker = new GraphFrontierTracker();
|
|
160
154
|
const inputConcurrency = resolveInputConcurrency(def.inputs, resolvedInputs);
|
|
161
|
-
const inputRuntimeDefaults = resolveInputRuntimeDefaults(def, resolvedInputs);
|
|
155
|
+
const inputRuntimeDefaults = resolveInputRuntimeDefaults(def, resolvedInputs), gitWorktreeSetupCache = createGitWorktreeSetupCache();
|
|
162
156
|
const workflowInvocationCwd = opts.cwd ?? process.cwd();
|
|
163
157
|
let workflowCwd: string | undefined;
|
|
164
158
|
const resolveWorkflowCwd = (): string => {
|
|
165
|
-
workflowCwd ??= workflowCwdWithInputWorktree(inputRuntimeDefaults, workflowInvocationCwd);
|
|
159
|
+
workflowCwd ??= workflowCwdWithInputWorktree(inputRuntimeDefaults, workflowInvocationCwd, gitWorktreeSetupCache);
|
|
166
160
|
return workflowCwd;
|
|
167
161
|
};
|
|
168
162
|
const limiter = createRunLimiter(inputConcurrency ?? opts.config?.defaultConcurrency);
|
|
@@ -277,12 +271,14 @@ export async function run<
|
|
|
277
271
|
limiter,
|
|
278
272
|
inputRuntimeDefaults,
|
|
279
273
|
workflowInvocationCwd,
|
|
280
|
-
stageRegistry,
|
|
274
|
+
stageRegistry, gitWorktreeSetupCache,
|
|
281
275
|
exit,
|
|
282
276
|
classifyExecutorFailure,
|
|
283
277
|
});
|
|
284
278
|
const workflowBoundaryReplayCounts = new Map<string, number>();
|
|
285
279
|
const nextWorkflowBoundaryReplayKey = (name: string): string => {
|
|
280
|
+
const durableScopePrefix = pendingChildDurableScope?.scopePrefix;
|
|
281
|
+
if (durableScopePrefix !== undefined && durableScopePrefix.startsWith(`workflow:${name}:`)) return durableScopePrefix;
|
|
286
282
|
const next = (workflowBoundaryReplayCounts.get(name) ?? 0) + 1;
|
|
287
283
|
workflowBoundaryReplayCounts.set(name, next);
|
|
288
284
|
return `workflow:${name}:${next}`;
|
|
@@ -314,22 +310,19 @@ export async function run<
|
|
|
314
310
|
},
|
|
315
311
|
runWorkflow: run,
|
|
316
312
|
});
|
|
317
|
-
|
|
318
|
-
|
|
313
|
+
const durableRootWorkflowRegistration = {
|
|
314
|
+
workflowId: runId,
|
|
315
|
+
name: def.name,
|
|
316
|
+
inputs: resolvedInputs as Record<string, import("../shared/types.js").WorkflowSerializableValue>,
|
|
317
|
+
createdAt: runSnapshot.startedAt,
|
|
318
|
+
status: "running" as const,
|
|
319
|
+
rootWorkflowId: runId,
|
|
320
|
+
resumable: true,
|
|
321
|
+
...(opts.persistence !== undefined ? { sessionFile: undefined } : {}),
|
|
322
|
+
};
|
|
319
323
|
if (opts.continuation === undefined && opts.parentRun === undefined) {
|
|
320
|
-
|
|
321
|
-
durableBackend.registerWorkflow({
|
|
322
|
-
workflowId: runId,
|
|
323
|
-
name: def.name,
|
|
324
|
-
inputs: resolvedInputs as Record<string, import("../shared/types.js").WorkflowSerializableValue>,
|
|
325
|
-
createdAt: runSnapshot.startedAt,
|
|
326
|
-
status: "running",
|
|
327
|
-
rootWorkflowId: runId,
|
|
328
|
-
resumable: true,
|
|
329
|
-
...(opts.persistence !== undefined ? { sessionFile: undefined } : {}),
|
|
330
|
-
});
|
|
324
|
+
durableBackend.registerWorkflow({ ...durableRootWorkflowRegistration, invocationCwd: workflowInvocationCwd });
|
|
331
325
|
} else if (opts.parentRun === undefined) {
|
|
332
|
-
// Resuming a root workflow: mark it as running again in the backend.
|
|
333
326
|
durableBackend.setWorkflowStatus(runId, "running");
|
|
334
327
|
}
|
|
335
328
|
const tool = createToolPrimitive({
|
|
@@ -346,12 +339,13 @@ export async function run<
|
|
|
346
339
|
|
|
347
340
|
// Durable ctx.ui wrapper — caches completed user responses so a resumed workflow does not re-ask answered prompts.
|
|
348
341
|
const durableUiDeps = { workflowId: runId, backend: durableBackend, nextCheckpointId: checkpointIdGenerator };
|
|
349
|
-
const recordCachedStage = (name: string, replayKey: string,
|
|
350
|
-
recordCachedStageWithTracker(activeStore, tracker, runId, name, replayKey,
|
|
342
|
+
const recordCachedStage = (name: string, replayKey: string, checkpoint: DurableCompletedStageCheckpoint): void =>
|
|
343
|
+
recordCachedStageWithTracker(activeStore, tracker, runId, name, replayKey, checkpoint, completedStageReplayKeys);
|
|
351
344
|
const durableTask = createDurableTaskPrimitive({
|
|
352
345
|
workflowId: runId, backend: durableBackend,
|
|
353
346
|
nextReplayKey: (stageName) => stageReplayKeyGenerator(stageName), task: taskRunners.task,
|
|
354
|
-
recordCachedTask: (name, replayKey,
|
|
347
|
+
recordCachedTask: (name, replayKey, checkpoint, scope) =>
|
|
348
|
+
recordCachedStageWithTracker(activeStore, tracker, runId, name, replayKey, checkpoint, completedStageReplayKeys, scope),
|
|
355
349
|
});
|
|
356
350
|
const durableWorkflow = createDurableChildWorkflowPrimitive({
|
|
357
351
|
workflowId: runId, rootWorkflowId: opts.parentRun?.rootRunId ?? runId, backend: durableBackend,
|
|
@@ -411,6 +405,10 @@ export async function run<
|
|
|
411
405
|
}
|
|
412
406
|
}
|
|
413
407
|
|
|
408
|
+
if (opts.continuation === undefined && opts.parentRun === undefined) {
|
|
409
|
+
durableBackend.registerWorkflow({ ...durableRootWorkflowRegistration, ...workflowInvocationMetadata(inputRuntimeDefaults, workflowInvocationCwd, gitWorktreeSetupCache) });
|
|
410
|
+
}
|
|
411
|
+
|
|
414
412
|
const rawResult = await def.run(ctx);
|
|
415
413
|
if (ownController.signal.aborted) {
|
|
416
414
|
const selectedExit = findWorkflowExitSignal(ownController.signal.reason, exitScope);
|
|
@@ -424,9 +422,9 @@ export async function run<
|
|
|
424
422
|
assertWorkflowRunOutputs(def.name, result, def.outputs);
|
|
425
423
|
assertWorkflowCreatedStage(runSnapshot);
|
|
426
424
|
await durableBackend.flush?.();
|
|
427
|
-
const returned = classifyReturnedRunStatus(result);
|
|
425
|
+
const returned = classifyReturnedRunStatus(result, runSnapshot);
|
|
428
426
|
const recorded = activeStore.recordRunEnd(runId, returned.status, result, returned.error, returned.metadata);
|
|
429
|
-
appendRunEndWhenRecorded(opts.persistence, recorded, { runId, status: returned.status, result, ...(returned.error !== undefined ? { error: returned.error } : {}), ...(returned.metadata ?? {}), ts: Date.now() });
|
|
427
|
+
appendRunEndWhenRecorded(opts.persistence, recorded, { runId, status: returned.status, result, ...(returned.error !== undefined ? { error: returned.error } : {}), ...(returned.metadata ?? {}), ...(runSnapshot.endedAt !== undefined ? { endedAt: runSnapshot.endedAt } : {}), ...(runSnapshot.durationMs !== undefined ? { durationMs: runSnapshot.durationMs } : {}), ts: Date.now() });
|
|
430
428
|
durableBackend.setWorkflowStatus(runId, returned.status, undefined, returned.metadata?.resumable);
|
|
431
429
|
await durableBackend.flush?.();
|
|
432
430
|
if (opts.persistence && durableBackend.persistent) {
|
|
@@ -480,6 +478,8 @@ export async function run<
|
|
|
480
478
|
...(metadata.failedStageId !== undefined ? { failedStageId: metadata.failedStageId } : {}),
|
|
481
479
|
resumable: metadata.resumable,
|
|
482
480
|
...(metadata.retryAfterMs !== undefined ? { retryAfterMs: metadata.retryAfterMs } : {}),
|
|
481
|
+
...(runSnapshot.endedAt !== undefined ? { endedAt: runSnapshot.endedAt } : {}),
|
|
482
|
+
...(runSnapshot.durationMs !== undefined ? { durationMs: runSnapshot.durationMs } : {}),
|
|
483
483
|
ts: Date.now(),
|
|
484
484
|
});
|
|
485
485
|
return reconcileTerminalRunResult(runId, runSnapshot, activeStore, { status: "failed", error: metadata.errorMessage }, opts.onRunEnd);
|
|
@@ -13,6 +13,7 @@ import { createWorkflowStageFactory } from "../runs/foreground/executor-stage-fa
|
|
|
13
13
|
import { createWorkflowBoundaryFactory, type WorkflowBoundaryStage } from "../runs/foreground/executor-child-boundary.js";
|
|
14
14
|
import type { GraphFrontierTracker } from "./graph-inference.js";
|
|
15
15
|
import type { EngineChildRunOptions, EngineStageRuntimeOptions, EngineWorkflowBoundaryOptions } from "./options.js";
|
|
16
|
+
import type { GitWorktreeSetupCache } from "../runs/foreground/executor-direct-helpers.js";
|
|
16
17
|
|
|
17
18
|
export interface EngineRuntimeInput {
|
|
18
19
|
readonly runId: string;
|
|
@@ -31,6 +32,7 @@ export interface EngineRuntimeInput {
|
|
|
31
32
|
readonly limiter: ConcurrencyLimiter;
|
|
32
33
|
readonly inputRuntimeDefaults: Partial<StageOptions>;
|
|
33
34
|
readonly workflowInvocationCwd: string;
|
|
35
|
+
readonly gitWorktreeSetupCache: GitWorktreeSetupCache;
|
|
34
36
|
readonly stageRegistry: StageControlRegistry;
|
|
35
37
|
readonly exit: WorkflowExitManager;
|
|
36
38
|
readonly classifyExecutorFailure: LiveStageRuntime["classifyExecutorFailure"];
|
|
@@ -73,6 +75,7 @@ export class EngineRuntime {
|
|
|
73
75
|
readonly exit: WorkflowExitManager;
|
|
74
76
|
readonly inputRuntimeDefaults: Partial<StageOptions>;
|
|
75
77
|
readonly workflowInvocationCwd: string;
|
|
78
|
+
readonly gitWorktreeSetupCache: GitWorktreeSetupCache;
|
|
76
79
|
|
|
77
80
|
private readonly spawnAgentStage: (
|
|
78
81
|
name: string,
|
|
@@ -93,6 +96,7 @@ export class EngineRuntime {
|
|
|
93
96
|
this.exit = input.exit;
|
|
94
97
|
this.inputRuntimeDefaults = input.inputRuntimeDefaults;
|
|
95
98
|
this.workflowInvocationCwd = input.workflowInvocationCwd;
|
|
99
|
+
this.gitWorktreeSetupCache = input.gitWorktreeSetupCache;
|
|
96
100
|
|
|
97
101
|
// The runtime only wires host-injected ports; stage sessions are still
|
|
98
102
|
// created lazily by the stage runner through input.adapters.agentSession.
|
|
@@ -108,6 +112,7 @@ export class EngineRuntime {
|
|
|
108
112
|
limiter: input.limiter,
|
|
109
113
|
inputRuntimeDefaults: input.inputRuntimeDefaults,
|
|
110
114
|
workflowInvocationCwd: input.workflowInvocationCwd,
|
|
115
|
+
gitWorktreeSetupCache: input.gitWorktreeSetupCache,
|
|
111
116
|
stageRegistry: input.stageRegistry,
|
|
112
117
|
exit: input.exit,
|
|
113
118
|
classifyExecutorFailure: input.classifyExecutorFailure,
|
|
@@ -85,6 +85,7 @@ function factory(pi: ExtensionAPI): void {
|
|
|
85
85
|
(ctx) => runtimeState.runtimeForContext(ctx),
|
|
86
86
|
() => runtimeState.persistenceRef.current,
|
|
87
87
|
runtimeState.reloadWorkflowResources,
|
|
88
|
+
runtimeState.ensureWorkflowResourcesLoaded,
|
|
88
89
|
);
|
|
89
90
|
|
|
90
91
|
registerWorkflowTool(pi, executeWorkflowTool, runtimeState.runWithLifecycleSuppressedForPolicy);
|
|
@@ -93,12 +94,14 @@ function factory(pi: ExtensionAPI): void {
|
|
|
93
94
|
runtimeForContext: runtimeState.runtimeForContext,
|
|
94
95
|
overlay,
|
|
95
96
|
reloadWorkflowResources: runtimeState.reloadWorkflowResources,
|
|
97
|
+
ensureWorkflowResourcesLoaded: runtimeState.ensureWorkflowResourcesLoaded,
|
|
96
98
|
runWithLifecycleSuppressedForPolicy: runtimeState.runWithLifecycleSuppressedForPolicy,
|
|
97
99
|
runControl: {
|
|
98
100
|
pi,
|
|
99
101
|
overlay,
|
|
100
102
|
getPersistence: () => runtimeState.persistenceRef.current,
|
|
101
103
|
runtimeForContext: runtimeState.runtimeForContext,
|
|
104
|
+
ensureWorkflowResourcesLoaded: runtimeState.ensureWorkflowResourcesLoaded,
|
|
102
105
|
},
|
|
103
106
|
});
|
|
104
107
|
registerWorkflowMessageRenderers(pi);
|
|
@@ -58,7 +58,9 @@ export function registerWorkflowLifecycleHandlers(
|
|
|
58
58
|
});
|
|
59
59
|
|
|
60
60
|
pi.on("session_start", async (_event, ctx) => {
|
|
61
|
+
runtimeState.resetWorkflowDiscoveryForSession();
|
|
61
62
|
deAdvertiseAskUserQuestionWhenHeadless(pi, ctx?.hasUI);
|
|
63
|
+
await runtimeState.ensureWorkflowConfigLoaded();
|
|
62
64
|
killAllRuns({ store, cancellation: cancellationRegistry, persistence: runtimeState.persistenceRef.current });
|
|
63
65
|
store.clear();
|
|
64
66
|
clearForms();
|
|
@@ -66,10 +68,14 @@ export function registerWorkflowLifecycleHandlers(
|
|
|
66
68
|
resetWorkflowHilAnswerNotificationState(runtimeState.hilAnswerNotificationState);
|
|
67
69
|
stageControlRegistry.clear();
|
|
68
70
|
runtimeState.setIntercomParentSession(registerIntercomParentSession(pi));
|
|
69
|
-
await runtimeState.discoveryPromise;
|
|
70
71
|
runtimeState.setNotificationsActive(true);
|
|
72
|
+
runtimeState.startWorkflowDiscoveryWarmup(() => {
|
|
73
|
+
if (!ctx?.ui) return;
|
|
74
|
+
const diagnostics = formatStartupDiagnostics(null, runtimeState.discoveryRef.current);
|
|
75
|
+
if (diagnostics !== null) ctx.ui.notify?.(diagnostics, "warning");
|
|
76
|
+
});
|
|
71
77
|
if (ctx?.ui) {
|
|
72
|
-
const diagnostics = formatStartupDiagnostics(runtimeState.configLoadRef.current,
|
|
78
|
+
const diagnostics = formatStartupDiagnostics(runtimeState.configLoadRef.current, null);
|
|
73
79
|
if (diagnostics !== null) ctx.ui.notify?.(diagnostics, "warning");
|
|
74
80
|
deps.storeWidgetRef.current?.();
|
|
75
81
|
deps.storeWidgetRef.current = installStoreWidget({ ui: ctx.ui }, store);
|
|
@@ -108,6 +114,7 @@ export function registerWorkflowLifecycleHandlers(
|
|
|
108
114
|
}
|
|
109
115
|
deps.storeWidgetRef.current?.();
|
|
110
116
|
deps.storeWidgetRef.current = null;
|
|
117
|
+
runtimeState.resetWorkflowDiscoveryForSession();
|
|
111
118
|
runtimeState.setNotificationsActive(false);
|
|
112
119
|
});
|
|
113
120
|
}
|
|
@@ -44,11 +44,14 @@ export interface WorkflowExtensionRuntimeState {
|
|
|
44
44
|
runtimeProxy: ExtensionRuntime;
|
|
45
45
|
configLoadRef: { current: ConfigLoadResult | null };
|
|
46
46
|
discoveryRef: { current: DiscoveryResult | null };
|
|
47
|
-
discoveryPromise: Promise<void>;
|
|
48
47
|
lifecycleNotificationState: ReturnType<typeof createWorkflowLifecycleNotificationState>;
|
|
49
48
|
hilAnswerNotificationState: ReturnType<typeof createWorkflowHilAnswerNotificationState>;
|
|
50
49
|
runtimeForContext(ctx?: PiModelContext): ExtensionRuntime;
|
|
50
|
+
resetWorkflowDiscoveryForSession(): void;
|
|
51
|
+
ensureWorkflowConfigLoaded(): Promise<void>;
|
|
52
|
+
ensureWorkflowResourcesLoaded(options?: { allowInFlight?: boolean }): Promise<void>;
|
|
51
53
|
reloadWorkflowResources(options?: { allowInFlight?: boolean }): Promise<void>;
|
|
54
|
+
startWorkflowDiscoveryWarmup(onSettled?: () => void): void;
|
|
52
55
|
runWithLifecycleSuppressedForPolicy<T>(policy: WorkflowExecutionPolicy, fn: () => Promise<T>): Promise<T>;
|
|
53
56
|
setNotificationsActive(active: boolean): void;
|
|
54
57
|
setIntercomParentSession(session: string | null): void;
|
|
@@ -74,6 +77,7 @@ export function createWorkflowExtensionRuntimeState(
|
|
|
74
77
|
let lifecycleNotificationsUnsubscribe: (() => void) | null = null;
|
|
75
78
|
let hilAnswerNotificationsUnsubscribe: (() => void) | null = null;
|
|
76
79
|
let notificationsActive = false;
|
|
80
|
+
let notificationGeneration = 0;
|
|
77
81
|
const lifecycleNotificationState = createWorkflowLifecycleNotificationState();
|
|
78
82
|
const hilAnswerNotificationState = createWorkflowHilAnswerNotificationState();
|
|
79
83
|
const lifecycleNotificationConfigRef: { current: WorkflowLifecycleNotificationConfig } = {
|
|
@@ -185,32 +189,15 @@ export function createWorkflowExtensionRuntimeState(
|
|
|
185
189
|
}
|
|
186
190
|
|
|
187
191
|
let workflowReloadQueue: Promise<void> = Promise.resolve();
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
async function loadPackageWorkflowPaths(): Promise<string[]> {
|
|
194
|
-
const packageResources = (await pi.refreshWorkflowResources?.()) ?? pi.getWorkflowResources?.() ?? [];
|
|
195
|
-
return packageResources.filter((resource) => resource.enabled !== false).map((resource) => resource.path);
|
|
192
|
+
|
|
193
|
+
let lazyDiscoveryPromise: Promise<void> | null = null;
|
|
194
|
+
let workflowDiscoveryGeneration = 0;
|
|
195
|
+
function deferToMacrotask(): Promise<void> {
|
|
196
|
+
return new Promise((resolve) => setImmediate(resolve));
|
|
196
197
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
if (options?.allowInFlight !== true && activeRuns > 0) {
|
|
200
|
-
throw new WorkflowReloadBlockedError(reloadBlockedMessage(activeRuns));
|
|
201
|
-
}
|
|
202
|
-
if (options?.allowInFlight === true && activeRuns > 0 && process.env.ATOMIC_WORKFLOW_DEBUG === "1") {
|
|
203
|
-
console.warn(`Workflow reload bypassed in-flight guard with ${activeRuns} active run(s).`);
|
|
204
|
-
}
|
|
205
|
-
const configResult = await loadWorkflowConfig();
|
|
198
|
+
|
|
199
|
+
function applyWorkflowConfig(configResult: ConfigLoadResult): void {
|
|
206
200
|
configLoadRef.current = configResult;
|
|
207
|
-
const hasGlobal = configResult.globalConfig != null;
|
|
208
|
-
const hasProject = configResult.projectConfig != null;
|
|
209
|
-
const discoveryConfig = hasGlobal || hasProject
|
|
210
|
-
? toScopedDiscoveryConfig(configResult.globalConfig ?? null, configResult.projectConfig ?? null, { projectRoot: process.cwd() })
|
|
211
|
-
: undefined;
|
|
212
|
-
const result = await discoverWorkflows({ config: discoveryConfig, packageWorkflowPaths: await loadPackageWorkflowPaths() });
|
|
213
|
-
discoveryRef.current = result;
|
|
214
201
|
const effectiveConfig = withWorkflowDefaults(configResult.config ?? {});
|
|
215
202
|
runtimeConfigRef.current = {
|
|
216
203
|
maxDepth: effectiveConfig.maxDepth,
|
|
@@ -224,8 +211,11 @@ export function createWorkflowExtensionRuntimeState(
|
|
|
224
211
|
statusWriterRef.unsubscribe();
|
|
225
212
|
statusWriterRef = createStatusWriter(store, runtimeConfigRef.current);
|
|
226
213
|
persistenceRef.current = makePersistencePort(pi, effectiveConfig.persistRuns);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function rebuildRuntime(registry = runtimeRef.current.registry): void {
|
|
227
217
|
runtimeRef.current = createExtensionRuntime({
|
|
228
|
-
registry
|
|
218
|
+
registry,
|
|
229
219
|
cwd: process.cwd(),
|
|
230
220
|
adapters,
|
|
231
221
|
cancellation: cancellationRegistry,
|
|
@@ -237,23 +227,143 @@ export function createWorkflowExtensionRuntimeState(
|
|
|
237
227
|
});
|
|
238
228
|
}
|
|
239
229
|
|
|
230
|
+
function isWorkflowDiscoveryCurrent(generation: number): boolean {
|
|
231
|
+
return generation === workflowDiscoveryGeneration;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function resetWorkflowDiscoveryForSession(): void {
|
|
235
|
+
workflowDiscoveryGeneration += 1;
|
|
236
|
+
discoveryRef.current = null;
|
|
237
|
+
lazyDiscoveryPromise = null;
|
|
238
|
+
workflowReloadQueue = Promise.resolve();
|
|
239
|
+
rebuildRuntime(startupDiscovery.registry);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
async function ensureWorkflowConfigLoaded(): Promise<void> {
|
|
243
|
+
const generation = workflowDiscoveryGeneration;
|
|
244
|
+
const configResult = await loadWorkflowConfig();
|
|
245
|
+
if (!isWorkflowDiscoveryCurrent(generation)) return;
|
|
246
|
+
applyWorkflowConfig(configResult);
|
|
247
|
+
rebuildRuntime();
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function queueWorkflowResourceReload(options: { allowInFlight?: boolean } | undefined, generation: number): Promise<void> {
|
|
251
|
+
const reload = workflowReloadQueue.then(() => reloadWorkflowResourcesNow(options, generation));
|
|
252
|
+
workflowReloadQueue = reload.catch(() => {});
|
|
253
|
+
return reload;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function trackLazyDiscovery(pending: Promise<void>): Promise<void> {
|
|
257
|
+
lazyDiscoveryPromise = pending;
|
|
258
|
+
void pending.finally(() => {
|
|
259
|
+
if (lazyDiscoveryPromise === pending) lazyDiscoveryPromise = null;
|
|
260
|
+
}).catch(() => {});
|
|
261
|
+
return pending;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function reloadWorkflowResources(options?: { allowInFlight?: boolean }): Promise<void> {
|
|
265
|
+
const generation = workflowDiscoveryGeneration;
|
|
266
|
+
return trackLazyDiscovery(queueWorkflowResourceReload(options, generation));
|
|
267
|
+
}
|
|
268
|
+
async function loadPackageWorkflowPaths(): Promise<string[]> {
|
|
269
|
+
const packageResources = (await pi.refreshWorkflowResources?.()) ?? pi.getWorkflowResources?.() ?? [];
|
|
270
|
+
return packageResources.filter((resource) => resource.enabled !== false).map((resource) => resource.path);
|
|
271
|
+
}
|
|
272
|
+
async function reloadWorkflowResourcesNow(options: { allowInFlight?: boolean } | undefined, generation: number): Promise<void> {
|
|
273
|
+
const activeRuns = inFlightRunCount();
|
|
274
|
+
if (options?.allowInFlight !== true && activeRuns > 0) {
|
|
275
|
+
throw new WorkflowReloadBlockedError(reloadBlockedMessage(activeRuns));
|
|
276
|
+
}
|
|
277
|
+
if (options?.allowInFlight === true && activeRuns > 0 && process.env.ATOMIC_WORKFLOW_DEBUG === "1") {
|
|
278
|
+
console.warn(`Workflow reload bypassed in-flight guard with ${activeRuns} active run(s).`);
|
|
279
|
+
}
|
|
280
|
+
const configResult = await loadWorkflowConfig();
|
|
281
|
+
if (!isWorkflowDiscoveryCurrent(generation)) return;
|
|
282
|
+
applyWorkflowConfig(configResult);
|
|
283
|
+
const hasGlobal = configResult.globalConfig != null;
|
|
284
|
+
const hasProject = configResult.projectConfig != null;
|
|
285
|
+
const discoveryConfig = hasGlobal || hasProject
|
|
286
|
+
? toScopedDiscoveryConfig(configResult.globalConfig ?? null, configResult.projectConfig ?? null, { projectRoot: process.cwd() })
|
|
287
|
+
: undefined;
|
|
288
|
+
const packageWorkflowPaths = await loadPackageWorkflowPaths();
|
|
289
|
+
if (!isWorkflowDiscoveryCurrent(generation)) return;
|
|
290
|
+
const result = await discoverWorkflows({ config: discoveryConfig, packageWorkflowPaths });
|
|
291
|
+
if (!isWorkflowDiscoveryCurrent(generation)) return;
|
|
292
|
+
discoveryRef.current = result;
|
|
293
|
+
rebuildRuntime(result.registry);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
async function ensureWorkflowResourcesLoaded(options?: { allowInFlight?: boolean }): Promise<void> {
|
|
297
|
+
while (!pi.disableAsyncDiscovery && discoveryRef.current === null) {
|
|
298
|
+
const generation = workflowDiscoveryGeneration;
|
|
299
|
+
const pending = lazyDiscoveryPromise ?? trackLazyDiscovery(
|
|
300
|
+
queueWorkflowResourceReload({ allowInFlight: options?.allowInFlight ?? true }, generation),
|
|
301
|
+
);
|
|
302
|
+
await pending;
|
|
303
|
+
if (!isWorkflowDiscoveryCurrent(generation)) continue;
|
|
304
|
+
if (discoveryRef.current === null) {
|
|
305
|
+
lazyDiscoveryPromise = null;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function startWorkflowDiscoveryWarmup(onSettled?: () => void): void {
|
|
311
|
+
if (pi.disableAsyncDiscovery || discoveryRef.current !== null || lazyDiscoveryPromise !== null) return;
|
|
312
|
+
const notificationStart = notificationGeneration;
|
|
313
|
+
const discoveryStart = workflowDiscoveryGeneration;
|
|
314
|
+
const pending = (async () => {
|
|
315
|
+
await deferToMacrotask();
|
|
316
|
+
if (!isWorkflowDiscoveryCurrent(discoveryStart)) return;
|
|
317
|
+
await queueWorkflowResourceReload({ allowInFlight: true }, discoveryStart);
|
|
318
|
+
})();
|
|
319
|
+
lazyDiscoveryPromise = pending;
|
|
320
|
+
const isCurrentWarmup = (): boolean => lazyDiscoveryPromise === pending
|
|
321
|
+
&& notificationGeneration === notificationStart
|
|
322
|
+
&& isWorkflowDiscoveryCurrent(discoveryStart);
|
|
323
|
+
void pending
|
|
324
|
+
.catch((error) => {
|
|
325
|
+
if (isCurrentWarmup() && process.env.ATOMIC_WORKFLOW_DEBUG === "1") {
|
|
326
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
327
|
+
console.warn(`Workflow background discovery failed: ${message}`);
|
|
328
|
+
}
|
|
329
|
+
})
|
|
330
|
+
.finally(() => {
|
|
331
|
+
const current = isCurrentWarmup();
|
|
332
|
+
if (lazyDiscoveryPromise === pending) lazyDiscoveryPromise = null;
|
|
333
|
+
if (!current || !notificationsActive) return;
|
|
334
|
+
try {
|
|
335
|
+
onSettled?.();
|
|
336
|
+
} catch (error) {
|
|
337
|
+
if (process.env.ATOMIC_WORKFLOW_DEBUG === "1") {
|
|
338
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
339
|
+
console.warn(`Workflow background discovery callback failed: ${message}`);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
})
|
|
343
|
+
.catch(() => {});
|
|
344
|
+
}
|
|
345
|
+
|
|
240
346
|
return {
|
|
241
347
|
persistenceRef,
|
|
242
348
|
mcpPort,
|
|
243
349
|
runtimeProxy,
|
|
244
350
|
configLoadRef,
|
|
245
351
|
discoveryRef,
|
|
246
|
-
discoveryPromise: pi.disableAsyncDiscovery ? Promise.resolve() : reloadWorkflowResources({ allowInFlight: true }),
|
|
247
352
|
lifecycleNotificationState,
|
|
248
353
|
hilAnswerNotificationState,
|
|
249
354
|
runtimeForContext,
|
|
355
|
+
resetWorkflowDiscoveryForSession,
|
|
356
|
+
ensureWorkflowConfigLoaded,
|
|
357
|
+
ensureWorkflowResourcesLoaded,
|
|
250
358
|
reloadWorkflowResources,
|
|
359
|
+
startWorkflowDiscoveryWarmup,
|
|
251
360
|
runWithLifecycleSuppressedForPolicy(policy, fn) {
|
|
252
361
|
return policy.mode !== "non_interactive" || policy.awaitTerminalRun !== true
|
|
253
362
|
? fn()
|
|
254
363
|
: withWorkflowLifecycleNotificationsSuppressedAsync(lifecycleNotificationState, fn);
|
|
255
364
|
},
|
|
256
365
|
setNotificationsActive(active) {
|
|
366
|
+
notificationGeneration += 1;
|
|
257
367
|
notificationsActive = active;
|
|
258
368
|
reinstallLifecycleNotifications();
|
|
259
369
|
reinstallHilAnswerNotifications();
|
|
@@ -15,6 +15,13 @@ import type {
|
|
|
15
15
|
StoreSnapshot,
|
|
16
16
|
} from "../shared/store-types.js";
|
|
17
17
|
import { isTopLevelWorkflowRun } from "../shared/run-visibility.js";
|
|
18
|
+
import {
|
|
19
|
+
actionableReturnedStatusText,
|
|
20
|
+
effectiveRunStatus,
|
|
21
|
+
isReturnedBlockedWorkflowStatus,
|
|
22
|
+
normalizeReturnedWorkflowStatus,
|
|
23
|
+
structuredRecoverableWorkflowFailureText,
|
|
24
|
+
} from "../shared/returned-run-status.js";
|
|
18
25
|
import { deriveGraphThemeFromPiTheme, type GraphTheme } from "../tui/graph-theme.js";
|
|
19
26
|
import { renderWorkflowNoticeCard, type WorkflowNoticeTone } from "../tui/workflow-notice-card.js";
|
|
20
27
|
|
|
@@ -299,13 +306,13 @@ function makeTerminalNotice(
|
|
|
299
306
|
const failedStage = run.failedStageId
|
|
300
307
|
? run.stages.find((stage) => stage.id === run.failedStageId)
|
|
301
308
|
: undefined;
|
|
302
|
-
const error = run.error ?? (kind === "blocked" ? run.exitReason : undefined);
|
|
309
|
+
const error = run.error ?? returnedNoticeError(run, kind) ?? (kind === "blocked" ? run.exitReason : undefined);
|
|
303
310
|
return {
|
|
304
311
|
kind,
|
|
305
312
|
scope: "run",
|
|
306
313
|
runId: run.id,
|
|
307
314
|
workflowName: run.name,
|
|
308
|
-
status: run
|
|
315
|
+
status: effectiveRunStatus(run),
|
|
309
316
|
...(error ? { error: truncateSnippet(error) } : {}),
|
|
310
317
|
...(run.failedStageId ? { failedStageId: run.failedStageId } : {}),
|
|
311
318
|
...(failedStage ? { stageId: failedStage.id, stageName: failedStage.name } : {}),
|
|
@@ -330,13 +337,22 @@ function jsonString(value: string): string {
|
|
|
330
337
|
}
|
|
331
338
|
|
|
332
339
|
function terminalNoticeKind(run: RunSnapshot): "completed" | "failed" | "blocked" | undefined {
|
|
333
|
-
|
|
334
|
-
if (
|
|
335
|
-
|
|
336
|
-
if (returnedStatus === "failed" || returnedStatus === "blocked") return returnedStatus;
|
|
340
|
+
const status = effectiveRunStatus(run);
|
|
341
|
+
if (status === "failed" || status === "blocked") return status;
|
|
342
|
+
if (status !== "completed") return undefined;
|
|
337
343
|
return "completed";
|
|
338
344
|
}
|
|
339
345
|
|
|
346
|
+
function returnedNoticeError(run: RunSnapshot, kind: "completed" | "failed" | "blocked"): string | undefined {
|
|
347
|
+
const structuredFailureText = structuredRecoverableWorkflowFailureText(run);
|
|
348
|
+
if (kind === "blocked" && structuredFailureText !== undefined) return structuredFailureText;
|
|
349
|
+
const returnedStatus = normalizeReturnedWorkflowStatus(run.result?.["status"]);
|
|
350
|
+
if (returnedStatus === undefined) return undefined;
|
|
351
|
+
if (kind === "failed" && returnedStatus === "failed") return actionableReturnedStatusText(run.result);
|
|
352
|
+
if (kind === "blocked" && isReturnedBlockedWorkflowStatus(returnedStatus)) return actionableReturnedStatusText(run.result);
|
|
353
|
+
return undefined;
|
|
354
|
+
}
|
|
355
|
+
|
|
340
356
|
function terminalRunKey(kind: "completed" | "failed" | "blocked", runId: string): string {
|
|
341
357
|
return `${kind}:${runId}`;
|
|
342
358
|
}
|
|
@@ -61,7 +61,7 @@ export type PiArgumentCompletionResult = PiArgumentCompletion[] | null;
|
|
|
61
61
|
export interface PiCommandOptions {
|
|
62
62
|
description: string;
|
|
63
63
|
handler: (args: string, ctx: PiCommandContext) => Promise<void> | void;
|
|
64
|
-
getArgumentCompletions?: (partial: string) => PiArgumentCompletionResult
|
|
64
|
+
getArgumentCompletions?: (partial: string) => PiArgumentCompletionResult | Promise<PiArgumentCompletionResult>;
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
export interface PiRuntimeModel {
|
|
@@ -13,8 +13,9 @@ function completeToken(
|
|
|
13
13
|
: Math.max(argumentText.lastIndexOf(" "), argumentText.lastIndexOf("\t")) + 1;
|
|
14
14
|
const head = argumentText.slice(0, tokenStart);
|
|
15
15
|
const token = argumentText.slice(tokenStart);
|
|
16
|
+
const normalizedToken = token.trimEnd();
|
|
16
17
|
const filtered = candidates
|
|
17
|
-
.filter((candidate) => candidate.value.startsWith(token))
|
|
18
|
+
.filter((candidate) => candidate.value.startsWith(token) && candidate.value.trimEnd() !== normalizedToken)
|
|
18
19
|
.map((candidate) => ({ ...candidate, value: `${head}${candidate.value}` }));
|
|
19
20
|
return filtered.length > 0 ? filtered : null;
|
|
20
21
|
}
|
|
@@ -50,6 +51,17 @@ function runIdItems(): PiArgumentCompletion[] {
|
|
|
50
51
|
}));
|
|
51
52
|
}
|
|
52
53
|
|
|
54
|
+
export function workflowArgumentCompletionsNeedWorkflowResources(partial: string): boolean {
|
|
55
|
+
const parts = partial.trim().split(/\s+/).filter(Boolean);
|
|
56
|
+
const subcommand = parts[0] ?? "";
|
|
57
|
+
if (!partial.includes(" ")) return true;
|
|
58
|
+
if (!subcommand || subcommand === "inputs") return true;
|
|
59
|
+
if (["status", "connect", "resume", "attach", "pause", "interrupt", "kill", "reload"].includes(subcommand)) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
|
|
53
65
|
export function workflowArgumentCompletions(
|
|
54
66
|
partial: string,
|
|
55
67
|
runtime: ExtensionRuntime,
|
|
@@ -12,7 +12,7 @@ import type { GraphOverlayPort } from "../tui/overlay-adapter.js";
|
|
|
12
12
|
import type { ExtensionRuntime } from "./runtime.js";
|
|
13
13
|
import type { WorkflowInputEntry, WorkflowToolResult } from "./render-result.js";
|
|
14
14
|
import type { ExtensionAPI, PiCommandContext, PiArgumentCompletionResult } from "./public-types.js";
|
|
15
|
-
import { workflowArgumentCompletions } from "./workflow-command-completions.js";
|
|
15
|
+
import { workflowArgumentCompletions, workflowArgumentCompletionsNeedWorkflowResources } from "./workflow-command-completions.js";
|
|
16
16
|
import {
|
|
17
17
|
createWorkflowCommandReporter,
|
|
18
18
|
emitWorkflowCommandOutput,
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
type WorkflowCommandHandler,
|
|
24
24
|
type WorkflowCommandOutputDetails,
|
|
25
25
|
} from "./workflow-command-utils.js";
|
|
26
|
-
import { emitTerminalRunDetailSurface } from "./workflow-command-surfaces.js";
|
|
26
|
+
import { emitTerminalRunDetailSurface, formatWorkflowResourceLoadWarning } from "./workflow-command-surfaces.js";
|
|
27
27
|
import { handleRunControlCommand, type WorkflowRunControlDeps } from "./workflow-run-control-command.js";
|
|
28
28
|
import { workflowPolicyFromContext } from "./workflow-policy.js";
|
|
29
29
|
import {
|
|
@@ -39,6 +39,7 @@ export interface WorkflowSlashCommandDeps {
|
|
|
39
39
|
runtimeForContext: (ctx?: PiCommandContext) => ExtensionRuntime;
|
|
40
40
|
overlay: GraphOverlayPort;
|
|
41
41
|
reloadWorkflowResources: () => Promise<void> | void;
|
|
42
|
+
ensureWorkflowResourcesLoaded: () => Promise<void> | void;
|
|
42
43
|
runWithLifecycleSuppressedForPolicy: <T>(
|
|
43
44
|
policy: WorkflowExecutionPolicy,
|
|
44
45
|
fn: () => Promise<T>,
|
|
@@ -57,8 +58,11 @@ export function registerWorkflowSlashCommand(
|
|
|
57
58
|
{
|
|
58
59
|
description: "Run or inspect Atomic workflows. Usage: /workflow <name> [key=value…] | /workflow [list|status|connect|attach|interrupt|kill|pause|resume|inputs|reload] [args]",
|
|
59
60
|
handler: (args, ctx) => workflowSlashHandler(args, ctx, pi, deps),
|
|
60
|
-
getArgumentCompletions: (partial: string): PiArgumentCompletionResult =>
|
|
61
|
-
workflowArgumentCompletions(partial, deps.runtimeProxy)
|
|
61
|
+
getArgumentCompletions: (partial: string): PiArgumentCompletionResult | Promise<PiArgumentCompletionResult> => {
|
|
62
|
+
const buildCompletions = (): PiArgumentCompletionResult => workflowArgumentCompletions(partial, deps.runtimeProxy);
|
|
63
|
+
if (!workflowArgumentCompletionsNeedWorkflowResources(partial)) return buildCompletions();
|
|
64
|
+
return Promise.resolve(deps.ensureWorkflowResourcesLoaded()).then(buildCompletions).catch(buildCompletions);
|
|
65
|
+
},
|
|
62
66
|
},
|
|
63
67
|
workflowCommands,
|
|
64
68
|
);
|
|
@@ -76,10 +80,18 @@ async function workflowSlashHandler(
|
|
|
76
80
|
const fail = (msg: string): void => reporter.error(msg);
|
|
77
81
|
const withImplicitYesFlag = (tokens: string[]): string[] =>
|
|
78
82
|
tokens.some((t) => t === "--yes" || t === "-y") ? tokens : [...tokens, "-y"];
|
|
83
|
+
const ensureWorkflowResourcesVisible = async (): Promise<void> => {
|
|
84
|
+
try {
|
|
85
|
+
await deps.ensureWorkflowResourcesLoaded();
|
|
86
|
+
} catch (error) {
|
|
87
|
+
ctx.ui?.notify(formatWorkflowResourceLoadWarning(error), "warning");
|
|
88
|
+
}
|
|
89
|
+
};
|
|
79
90
|
const showWorkflowInputs = async (
|
|
80
91
|
workflowName: string,
|
|
81
92
|
command: WorkflowCommandOutputDetails["command"] = "inputs",
|
|
82
93
|
): Promise<void> => {
|
|
94
|
+
await ensureWorkflowResourcesVisible();
|
|
83
95
|
const result = await deps.runtimeForContext(ctx).dispatch({ workflow: workflowName, inputs: {}, action: "inputs" }, { policy });
|
|
84
96
|
if (result.action !== "inputs" || !("inputs" in result)) return;
|
|
85
97
|
const inputResult = result as Extract<WorkflowToolResult, { action: "inputs" }>;
|
|
@@ -99,6 +111,7 @@ async function workflowSlashHandler(
|
|
|
99
111
|
return;
|
|
100
112
|
}
|
|
101
113
|
if (!subcommand || subcommand === "list") {
|
|
114
|
+
await ensureWorkflowResourcesVisible();
|
|
102
115
|
const items = deps.runtimeProxy.registry.all().map((def) => ({
|
|
103
116
|
name: def.normalizedName,
|
|
104
117
|
description: def.description,
|
|
@@ -163,6 +176,7 @@ async function workflowSlashHandler(
|
|
|
163
176
|
typeof ctx.ui?.setEditorComponent === "function" || typeof ctx.ui?.custom === "function"
|
|
164
177
|
);
|
|
165
178
|
if (canOpenPicker) {
|
|
179
|
+
await ensureWorkflowResourcesVisible();
|
|
166
180
|
const schemaResult = await deps.runtimeForContext(ctx).dispatch({ workflow: workflowName, inputs: {}, action: "inputs" }, { policy });
|
|
167
181
|
const schema = schemaResult.action === "inputs" && "inputs" in schemaResult
|
|
168
182
|
? (schemaResult as Extract<WorkflowToolResult, { action: "inputs" }>)
|
|
@@ -185,6 +199,7 @@ async function workflowSlashHandler(
|
|
|
185
199
|
}
|
|
186
200
|
}
|
|
187
201
|
|
|
202
|
+
await ensureWorkflowResourcesVisible();
|
|
188
203
|
const result = await deps.runWithLifecycleSuppressedForPolicy(policy, () =>
|
|
189
204
|
deps.runtimeForContext(ctx).dispatch({ workflow: workflowName, inputs: mergedInputs, action: "run" }, { policy }),
|
|
190
205
|
);
|