@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
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { WorkflowPromptModelFailure } from "./stage-runner-messages.js";
|
|
2
|
+
|
|
3
|
+
export function unresolvedContextOverflowMessage(event: unknown): string | undefined {
|
|
4
|
+
if (event === null || typeof event !== "object") return undefined;
|
|
5
|
+
const record = event as Record<string, unknown>;
|
|
6
|
+
if (record["type"] !== "compaction_end" || record["unresolvedOverflow"] !== true) return undefined;
|
|
7
|
+
const message = record["errorMessage"];
|
|
8
|
+
return typeof message === "string" && message.trim().length > 0
|
|
9
|
+
? message
|
|
10
|
+
: "Context overflow recovery was exhausted for the current model.";
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function unresolvedContextOverflowFailure(message: string): WorkflowPromptModelFailure {
|
|
14
|
+
return new WorkflowPromptModelFailure({ message, code: "context_length_exceeded", stopReason: "error" });
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function isUnresolvedContextOverflowFailure(error: unknown): boolean {
|
|
18
|
+
if (!(error instanceof WorkflowPromptModelFailure)) return false;
|
|
19
|
+
const cause = error.cause;
|
|
20
|
+
if (cause === null || typeof cause !== "object") return false;
|
|
21
|
+
return (cause as { readonly code?: unknown }).code === "context_length_exceeded";
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function nextResumedContextOverflowFallbackIndex(error: unknown, currentIndex: number | undefined, candidateCount: number): number | "terminal" | undefined {
|
|
25
|
+
if (!isUnresolvedContextOverflowFailure(error) || currentIndex === undefined) return undefined;
|
|
26
|
+
const nextIndex = currentIndex + 1;
|
|
27
|
+
return nextIndex >= candidateCount ? "terminal" : nextIndex;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function terminatingToolCallId(event: unknown): string | undefined {
|
|
31
|
+
if (event === null || typeof event !== "object") return undefined;
|
|
32
|
+
const record = event as Record<string, unknown>;
|
|
33
|
+
const result = record["result"];
|
|
34
|
+
if (record["type"] !== "tool_execution_end" || result === null || typeof result !== "object") return undefined;
|
|
35
|
+
if ((result as Record<string, unknown>)["terminate"] !== true) return undefined;
|
|
36
|
+
const callId = record["toolCallId"];
|
|
37
|
+
return typeof callId === "string" && callId.length > 0 ? callId : undefined;
|
|
38
|
+
}
|
|
@@ -5,41 +5,160 @@ import { createGitEnvironment } from "@bastani/atomic";
|
|
|
5
5
|
import type { GitResult, GitWorktreeSetupOptions, GitWorktreeSetupResult } from "./worktree-types.js";
|
|
6
6
|
|
|
7
7
|
const DISABLED_GIT_HOOKS_PATH = process.platform === "win32" ? "NUL" : "/dev/null";
|
|
8
|
+
const GIT_COMMAND_TIMEOUT_MS = 60_000;
|
|
9
|
+
const GIT_READ_ONLY_PROBE_TIMEOUT_ATTEMPTS = 2;
|
|
8
10
|
|
|
9
|
-
export
|
|
10
|
-
|
|
11
|
+
export type GitRunner = (cwd: string, args: readonly string[]) => GitResult;
|
|
12
|
+
|
|
13
|
+
let gitRunnerOverride: GitRunner | undefined;
|
|
14
|
+
|
|
15
|
+
function gitCommandArgs(args: readonly string[]): string[] {
|
|
16
|
+
return [
|
|
11
17
|
"-c",
|
|
12
18
|
`core.hooksPath=${DISABLED_GIT_HOOKS_PATH}`,
|
|
13
19
|
"-c",
|
|
14
20
|
"core.fsmonitor=false",
|
|
15
21
|
...args,
|
|
16
|
-
]
|
|
22
|
+
];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function gitCommandArgv(args: readonly string[]): string[] {
|
|
26
|
+
return ["git", ...gitCommandArgs(args)];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function withGitResultDiagnostics(result: GitResult, cwd: string, args: readonly string[]): GitResult {
|
|
30
|
+
return {
|
|
31
|
+
...result,
|
|
32
|
+
argv: result.argv ?? gitCommandArgv(args),
|
|
33
|
+
cwd: result.cwd ?? cwd,
|
|
34
|
+
timeoutMs: result.timeoutMs ?? GIT_COMMAND_TIMEOUT_MS,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function runGitProcess(cwd: string, args: readonly string[]): GitResult {
|
|
39
|
+
const startedAt = Date.now();
|
|
40
|
+
const result = spawnSync("git", gitCommandArgs(args), {
|
|
17
41
|
cwd,
|
|
18
42
|
encoding: "utf-8",
|
|
19
|
-
env: createGitEnvironment({
|
|
20
|
-
|
|
43
|
+
env: createGitEnvironment({
|
|
44
|
+
GIT_OPTIONAL_LOCKS: "0",
|
|
45
|
+
GIT_TERMINAL_PROMPT: "0",
|
|
46
|
+
GCM_INTERACTIVE: "never",
|
|
47
|
+
}),
|
|
48
|
+
timeout: GIT_COMMAND_TIMEOUT_MS,
|
|
21
49
|
});
|
|
22
50
|
return {
|
|
23
51
|
stdout: result.stdout ?? "",
|
|
24
52
|
stderr: result.stderr ?? "",
|
|
25
|
-
status: result.status,
|
|
53
|
+
status: result.status ?? null,
|
|
54
|
+
signal: result.signal ?? null,
|
|
55
|
+
elapsedMs: Math.max(0, Date.now() - startedAt),
|
|
26
56
|
...(result.error === undefined ? {} : { error: result.error }),
|
|
27
57
|
};
|
|
28
58
|
}
|
|
29
59
|
|
|
30
|
-
export function
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
60
|
+
export function withGitRunnerForTest<T>(runner: GitRunner, callback: () => T): T {
|
|
61
|
+
const previous = gitRunnerOverride;
|
|
62
|
+
gitRunnerOverride = runner;
|
|
63
|
+
try {
|
|
64
|
+
return callback();
|
|
65
|
+
} finally {
|
|
66
|
+
gitRunnerOverride = previous;
|
|
36
67
|
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function runGit(cwd: string, args: readonly string[]): GitResult {
|
|
71
|
+
return withGitResultDiagnostics((gitRunnerOverride ?? runGitProcess)(cwd, args), cwd, args);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function runGitChecked(cwd: string, args: readonly string[]): string {
|
|
75
|
+
const result = runGit(cwd, args);
|
|
76
|
+
if (result.status !== 0) throw new Error(gitFailureMessage(result));
|
|
37
77
|
return result.stdout;
|
|
38
78
|
}
|
|
39
79
|
|
|
80
|
+
function gitErrorCode(error: Error): string | undefined {
|
|
81
|
+
return "code" in error ? String((error as Error & { readonly code?: unknown }).code) : undefined;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function isGitTimeoutResult(result: GitResult): boolean {
|
|
85
|
+
const error = result.error;
|
|
86
|
+
if (error === undefined) return false;
|
|
87
|
+
const code = gitErrorCode(error)?.toUpperCase();
|
|
88
|
+
const message = error.message.toLowerCase();
|
|
89
|
+
return code === "ETIMEDOUT" || message.includes("etimedout") || message.includes("timed out");
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function formatGitDiagnosticArg(value: string): string {
|
|
93
|
+
if (/^[A-Za-z0-9_./:@%+=,\\-]+$/.test(value)) return value;
|
|
94
|
+
return JSON.stringify(value);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function formatGitCommand(argv: readonly string[]): string {
|
|
98
|
+
return argv.map(formatGitDiagnosticArg).join(" ");
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function gitDiagnosticSuffix(result: GitResult): string {
|
|
102
|
+
const details: string[] = [];
|
|
103
|
+
if (result.argv !== undefined && result.argv.length > 0) details.push(`command: ${formatGitCommand(result.argv)}`);
|
|
104
|
+
if (result.cwd !== undefined) details.push(`cwd: ${result.cwd}`);
|
|
105
|
+
if (result.timeoutMs !== undefined) details.push(`timeout: ${result.timeoutMs}ms`);
|
|
106
|
+
if (result.elapsedMs !== undefined) details.push(`elapsed: ${result.elapsedMs}ms`);
|
|
107
|
+
details.push(`status: ${result.status === null ? "null" : result.status}`);
|
|
108
|
+
if (result.signal !== undefined) details.push(`signal: ${result.signal ?? "null"}`);
|
|
109
|
+
if (result.attempts !== undefined && result.attempts > 1) details.push(`attempts: ${result.attempts}`);
|
|
110
|
+
return details.length === 0 ? "" : ` (${details.join("; ")})`;
|
|
111
|
+
}
|
|
112
|
+
|
|
40
113
|
export function gitFailureMessage(result: GitResult): string {
|
|
41
|
-
if (result.error !== undefined)
|
|
42
|
-
|
|
114
|
+
if (result.error !== undefined) {
|
|
115
|
+
const code = gitErrorCode(result.error);
|
|
116
|
+
if (isGitTimeoutResult(result)) {
|
|
117
|
+
return `git command timed out after ${result.timeoutMs ?? GIT_COMMAND_TIMEOUT_MS}ms${code === undefined ? "" : ` (${code})`}: ${result.error.message}${gitDiagnosticSuffix(result)}`;
|
|
118
|
+
}
|
|
119
|
+
return `${code === undefined ? result.error.message : `${code}: ${result.error.message}`}${gitDiagnosticSuffix(result)}`;
|
|
120
|
+
}
|
|
121
|
+
return `${result.stderr.trim() || result.stdout.trim() || `git exited with status ${result.status}`}${gitDiagnosticSuffix(result)}`;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function runGitReadOnlyProbe(cwd: string, args: readonly string[]): GitResult {
|
|
125
|
+
let attempts = 1;
|
|
126
|
+
let result = runGit(cwd, args);
|
|
127
|
+
while (attempts < GIT_READ_ONLY_PROBE_TIMEOUT_ATTEMPTS && result.status !== 0 && isGitTimeoutResult(result)) {
|
|
128
|
+
attempts += 1;
|
|
129
|
+
result = runGit(cwd, args);
|
|
130
|
+
}
|
|
131
|
+
return attempts > 1 ? { ...result, attempts } : result;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export interface GitWorktreeSetupCache {
|
|
135
|
+
get(options: GitWorktreeSetupOptions): GitWorktreeSetupResult;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function gitWorktreeSetupCacheKey(options: GitWorktreeSetupOptions): string {
|
|
139
|
+
return JSON.stringify([
|
|
140
|
+
path.resolve(options.cwd),
|
|
141
|
+
options.gitWorktreeDir.trim(),
|
|
142
|
+
options.baseBranch?.trim() ?? "",
|
|
143
|
+
]);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export function createGitWorktreeSetupCache(): GitWorktreeSetupCache {
|
|
147
|
+
const results = new Map<string, GitWorktreeSetupResult>();
|
|
148
|
+
return {
|
|
149
|
+
get(options) {
|
|
150
|
+
const key = gitWorktreeSetupCacheKey(options);
|
|
151
|
+
const cached = results.get(key);
|
|
152
|
+
if (cached !== undefined) return cached;
|
|
153
|
+
const setup = setupGitWorktree(options);
|
|
154
|
+
results.set(key, setup);
|
|
155
|
+
return setup;
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export function setupGitWorktreeCached(options: GitWorktreeSetupOptions, cache?: GitWorktreeSetupCache): GitWorktreeSetupResult {
|
|
161
|
+
return cache?.get(options) ?? setupGitWorktree(options);
|
|
43
162
|
}
|
|
44
163
|
|
|
45
164
|
function quoteShellArg(value: string): string {
|
|
@@ -122,22 +241,38 @@ function pathExistsSync(value: string): boolean {
|
|
|
122
241
|
}
|
|
123
242
|
|
|
124
243
|
function repositoryRootForGitWorktree(cwd: string): string {
|
|
125
|
-
const result =
|
|
244
|
+
const result = runGitReadOnlyProbe(cwd, ["rev-parse", "--show-toplevel"]);
|
|
126
245
|
if (result.status !== 0) {
|
|
246
|
+
if (isGitTimeoutResult(result)) {
|
|
247
|
+
throw new Error(`Timed out while checking the Git repository for gitWorktreeDir from ${cwd}. Git reported: ${gitFailureMessage(result)}`);
|
|
248
|
+
}
|
|
127
249
|
throw new Error(`gitWorktreeDir requires the workflow to be invoked from inside a Git repository. Start from a Git checkout or omit gitWorktreeDir. Git reported: ${gitFailureMessage(result)}`);
|
|
128
250
|
}
|
|
129
251
|
return result.stdout.trim();
|
|
130
252
|
}
|
|
131
253
|
|
|
132
|
-
function
|
|
133
|
-
|
|
134
|
-
|
|
254
|
+
export function gitTopLevelFromResult(result: GitResult, cwd: string, description: string): string | undefined {
|
|
255
|
+
if (result.status !== 0) {
|
|
256
|
+
if (isGitTimeoutResult(result)) {
|
|
257
|
+
throw new Error(`Timed out while validating ${description}. Git reported: ${gitFailureMessage(result)}`);
|
|
258
|
+
}
|
|
259
|
+
return undefined;
|
|
260
|
+
}
|
|
135
261
|
return gitPathFromOutput(result.stdout, cwd);
|
|
136
262
|
}
|
|
137
263
|
|
|
264
|
+
function gitTopLevel(cwd: string): string | undefined {
|
|
265
|
+
return gitTopLevelFromResult(runGitReadOnlyProbe(cwd, ["rev-parse", "--show-toplevel"]), cwd, `gitWorktreeDir ${cwd}`);
|
|
266
|
+
}
|
|
267
|
+
|
|
138
268
|
function gitCommonDirForWorktree(cwd: string): string {
|
|
139
|
-
const result =
|
|
140
|
-
if (result.status !== 0)
|
|
269
|
+
const result = runGitReadOnlyProbe(cwd, ["rev-parse", "--git-common-dir"]);
|
|
270
|
+
if (result.status !== 0) {
|
|
271
|
+
if (isGitTimeoutResult(result)) {
|
|
272
|
+
throw new Error(`Timed out while validating Git common directory for gitWorktreeDir ${cwd}. Git reported: ${gitFailureMessage(result)}`);
|
|
273
|
+
}
|
|
274
|
+
throw new Error(`Failed to validate Git common directory for gitWorktreeDir ${cwd}. Git reported: ${gitFailureMessage(result)}`);
|
|
275
|
+
}
|
|
141
276
|
const gitPath = gitPathFromOutput(result.stdout, cwd);
|
|
142
277
|
if (gitPath === undefined) throw new Error("git rev-parse --git-common-dir returned an empty path");
|
|
143
278
|
return gitPath;
|
|
@@ -65,7 +65,13 @@ export interface GitResult {
|
|
|
65
65
|
stdout: string;
|
|
66
66
|
stderr: string;
|
|
67
67
|
status: number | null;
|
|
68
|
+
signal?: NodeJS.Signals | null;
|
|
68
69
|
error?: Error;
|
|
70
|
+
argv?: readonly string[];
|
|
71
|
+
cwd?: string;
|
|
72
|
+
timeoutMs?: number;
|
|
73
|
+
elapsedMs?: number;
|
|
74
|
+
attempts?: number;
|
|
69
75
|
}
|
|
70
76
|
|
|
71
77
|
export interface GitWorktreeSetupOptions {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { setupGitWorktree } from "./worktree-git.js";
|
|
1
|
+
export { createGitWorktreeSetupCache, setupGitWorktree, setupGitWorktreeCached } from "./worktree-git.js";
|
|
2
2
|
export {
|
|
3
3
|
cleanupWorktrees,
|
|
4
4
|
createWorktrees,
|
|
@@ -16,3 +16,4 @@ export type {
|
|
|
16
16
|
WorktreeSetup,
|
|
17
17
|
WorktreeTaskCwdConflict,
|
|
18
18
|
} from "./worktree-types.js";
|
|
19
|
+
export type { GitWorktreeSetupCache } from "./worktree-git.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Value } from "typebox/value";
|
|
2
2
|
import { workflowSerializableObjectSchema } from "./serializable.js";
|
|
3
3
|
import type { Store } from "./store.js";
|
|
4
|
-
import type { SessionEntry } from "./persistence-restore.js";
|
|
4
|
+
import type { NormalizedSessionEntry as SessionEntry } from "./persistence-restore.js";
|
|
5
5
|
import type {
|
|
6
6
|
RunStatus,
|
|
7
7
|
StageSnapshot,
|
|
@@ -255,6 +255,14 @@ function numericRetryAfterMs(value: unknown): number | undefined {
|
|
|
255
255
|
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : undefined;
|
|
256
256
|
}
|
|
257
257
|
|
|
258
|
+
function numericTimestamp(value: unknown): number | undefined {
|
|
259
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : undefined;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function numericDuration(value: unknown): number | undefined {
|
|
263
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : undefined;
|
|
264
|
+
}
|
|
265
|
+
|
|
258
266
|
export function findRunBlockedMetadata(
|
|
259
267
|
entries: readonly SessionEntry[],
|
|
260
268
|
runId: string,
|
|
@@ -360,6 +368,8 @@ export function restoreTerminalRuns(entries: readonly SessionEntry[], store: Sto
|
|
|
360
368
|
const retryAfterMs = numericRetryAfterMs(end["retryAfterMs"]);
|
|
361
369
|
const failureMessage = end["failureMessage"];
|
|
362
370
|
const failedStageId = end["failedStageId"];
|
|
371
|
+
const restoredEndedAt = numericTimestamp(end["endedAt"]);
|
|
372
|
+
const restoredDurationMs = numericDuration(end["durationMs"]);
|
|
363
373
|
store.recordRunEnd(
|
|
364
374
|
runId,
|
|
365
375
|
status,
|
|
@@ -378,6 +388,13 @@ export function restoreTerminalRuns(entries: readonly SessionEntry[], store: Sto
|
|
|
378
388
|
...(typeof exitReason === "string" ? { exitReason } : {}),
|
|
379
389
|
},
|
|
380
390
|
);
|
|
391
|
+
const restoredRun = store.runs().find((run) => run.id === runId);
|
|
392
|
+
if (restoredRun !== undefined && (restoredEndedAt !== undefined || restoredDurationMs !== undefined)) {
|
|
393
|
+
Object.assign(restoredRun, {
|
|
394
|
+
...(restoredEndedAt !== undefined ? { endedAt: restoredEndedAt } : {}),
|
|
395
|
+
...(restoredDurationMs !== undefined ? { durationMs: restoredDurationMs } : {}),
|
|
396
|
+
});
|
|
397
|
+
}
|
|
381
398
|
}
|
|
382
399
|
}
|
|
383
400
|
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
|
|
16
16
|
import type { Store } from "./store.js";
|
|
17
17
|
import type { RunSnapshot } from "./store-types.js";
|
|
18
|
-
import type { WorkflowInputValues } from "./types.js";
|
|
18
|
+
import type { WorkflowInputValues, WorkflowSerializableValue } from "./types.js";
|
|
19
19
|
|
|
20
20
|
// ---------------------------------------------------------------------------
|
|
21
21
|
// Config option
|
|
@@ -32,7 +32,25 @@ export type ResumeInFlight = "ask" | "auto" | "never";
|
|
|
32
32
|
export interface SessionEntry {
|
|
33
33
|
readonly id: string;
|
|
34
34
|
readonly type: string;
|
|
35
|
-
readonly payload
|
|
35
|
+
readonly payload?: Record<string, WorkflowSerializableValue>;
|
|
36
|
+
readonly customType?: string;
|
|
37
|
+
readonly data?: Record<string, WorkflowSerializableValue>;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface NormalizedSessionEntry {
|
|
41
|
+
readonly id: string;
|
|
42
|
+
readonly type: string;
|
|
43
|
+
readonly payload: Record<string, WorkflowSerializableValue>;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function normalizeSessionEntries(entries: readonly SessionEntry[]): readonly NormalizedSessionEntry[] {
|
|
47
|
+
return entries.flatMap((entry): readonly NormalizedSessionEntry[] => {
|
|
48
|
+
if (entry.type === "custom" && typeof entry.customType === "string" && entry.data !== undefined) {
|
|
49
|
+
return [{ id: entry.id, type: entry.customType, payload: entry.data }];
|
|
50
|
+
}
|
|
51
|
+
if (entry.payload !== undefined) return [{ id: entry.id, type: entry.type, payload: entry.payload }];
|
|
52
|
+
return [];
|
|
53
|
+
});
|
|
36
54
|
}
|
|
37
55
|
|
|
38
56
|
/** Structural type for pi's sessionManager (optional — degrades gracefully). */
|
|
@@ -69,7 +87,7 @@ export function scanInFlightRuns(entries: readonly SessionEntry[]): InFlightRun[
|
|
|
69
87
|
const started = new Map<string, { name: string; inputs: WorkflowInputValues; startTs: number; stageIds: string[] }>();
|
|
70
88
|
const ended = new Set<string>();
|
|
71
89
|
|
|
72
|
-
for (const entry of entries) {
|
|
90
|
+
for (const entry of normalizeSessionEntries(entries)) {
|
|
73
91
|
if (entry.type === "workflow.run.start") {
|
|
74
92
|
const runId = entry.payload["runId"];
|
|
75
93
|
const name = entry.payload["name"];
|
|
@@ -168,8 +186,8 @@ export function restoreOnSessionStart(
|
|
|
168
186
|
const getEntries = sessionManager.getEntries;
|
|
169
187
|
if (typeof getEntries !== "function") return;
|
|
170
188
|
|
|
171
|
-
const entries = getEntries.call(sessionManager);
|
|
172
|
-
const sessionEntries = entries
|
|
189
|
+
const entries = getEntries.call(sessionManager) as readonly SessionEntry[];
|
|
190
|
+
const sessionEntries = normalizeSessionEntries(entries);
|
|
173
191
|
restoreTerminalRuns(sessionEntries, store);
|
|
174
192
|
const inFlight = scanInFlightRuns(sessionEntries);
|
|
175
193
|
if (inFlight.length === 0) return;
|
|
@@ -112,6 +112,8 @@ export interface RunEndPayload {
|
|
|
112
112
|
readonly failedStageId?: string;
|
|
113
113
|
readonly resumable?: boolean;
|
|
114
114
|
readonly retryAfterMs?: number;
|
|
115
|
+
readonly endedAt?: number;
|
|
116
|
+
readonly durationMs?: number;
|
|
115
117
|
readonly ts: number;
|
|
116
118
|
}
|
|
117
119
|
|
|
@@ -254,6 +256,8 @@ export function appendRunEnd(api: PersistenceAPI, payload: RunEndPayload): void
|
|
|
254
256
|
...(terminalPayload.failedStageId !== undefined ? { failedStageId: terminalPayload.failedStageId } : {}),
|
|
255
257
|
...(terminalPayload.resumable !== undefined ? { resumable: terminalPayload.resumable } : {}),
|
|
256
258
|
...(terminalPayload.retryAfterMs !== undefined ? { retryAfterMs: terminalPayload.retryAfterMs } : {}),
|
|
259
|
+
...(terminalPayload.endedAt !== undefined ? { endedAt: terminalPayload.endedAt } : {}),
|
|
260
|
+
...(terminalPayload.durationMs !== undefined ? { durationMs: terminalPayload.durationMs } : {}),
|
|
257
261
|
ts: terminalPayload.ts,
|
|
258
262
|
});
|
|
259
263
|
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import type { RunEndMetadata } from "./store-public-types.js";
|
|
2
|
+
import type { RunSnapshot, RunStatus, StageSnapshot, WorkflowFailureKind } from "./store-types.js";
|
|
3
|
+
import type { WorkflowOutputValues } from "./types.js";
|
|
4
|
+
|
|
5
|
+
const RETURNED_BLOCKED_STATUSES = new Set([
|
|
6
|
+
"blocked",
|
|
7
|
+
"needs_human",
|
|
8
|
+
"incomplete",
|
|
9
|
+
"auth_blocked",
|
|
10
|
+
"active",
|
|
11
|
+
]);
|
|
12
|
+
|
|
13
|
+
export interface StructuredRecoverableWorkflowFailure {
|
|
14
|
+
readonly error: string;
|
|
15
|
+
readonly metadata: RunEndMetadata;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function normalizeReturnedWorkflowStatus(status: unknown): string | undefined {
|
|
19
|
+
if (typeof status !== "string") return undefined;
|
|
20
|
+
const normalized = status.trim().toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
21
|
+
return normalized.length > 0 ? normalized : undefined;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function isReturnedBlockedWorkflowStatus(status: string): boolean {
|
|
25
|
+
return RETURNED_BLOCKED_STATUSES.has(status);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function isReturnedResumableBlockedWorkflowStatus(status: string): boolean {
|
|
29
|
+
return status !== "blocked" && isReturnedBlockedWorkflowStatus(status);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function actionableReturnedStatusText(result: WorkflowOutputValues | undefined): string | undefined {
|
|
33
|
+
return stringResultField(result, "summary") ?? stringResultField(result, "remaining_work") ?? stringResultField(result, "result");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function structuredRecoverableWorkflowFailure(
|
|
37
|
+
run: Pick<RunSnapshot,
|
|
38
|
+
| "error"
|
|
39
|
+
| "failureKind"
|
|
40
|
+
| "failureCode"
|
|
41
|
+
| "failureRecoverability"
|
|
42
|
+
| "failureDisposition"
|
|
43
|
+
| "failureMessage"
|
|
44
|
+
| "failedStageId"
|
|
45
|
+
| "retryAfterMs"
|
|
46
|
+
| "stages"
|
|
47
|
+
>,
|
|
48
|
+
): StructuredRecoverableWorkflowFailure | undefined {
|
|
49
|
+
const runFailure = structuredRecoverableFailureFromSnapshot(run);
|
|
50
|
+
if (runFailure !== undefined) return runFailure;
|
|
51
|
+
if (run.failedStageId === undefined) return undefined;
|
|
52
|
+
|
|
53
|
+
const failedStage = run.stages.find((stage) => stage.id === run.failedStageId);
|
|
54
|
+
return failedStage === undefined
|
|
55
|
+
? undefined
|
|
56
|
+
: structuredRecoverableFailureFromSnapshot(failedStage, failedStage.id);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function structuredRecoverableWorkflowFailureText(
|
|
60
|
+
run: Pick<RunSnapshot,
|
|
61
|
+
| "error"
|
|
62
|
+
| "failureKind"
|
|
63
|
+
| "failureCode"
|
|
64
|
+
| "failureRecoverability"
|
|
65
|
+
| "failureDisposition"
|
|
66
|
+
| "failureMessage"
|
|
67
|
+
| "failedStageId"
|
|
68
|
+
| "retryAfterMs"
|
|
69
|
+
| "stages"
|
|
70
|
+
>,
|
|
71
|
+
): string | undefined {
|
|
72
|
+
return structuredRecoverableWorkflowFailure(run)?.error;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function effectiveRunStatus(run: RunSnapshot): RunStatus {
|
|
76
|
+
if (run.status !== "completed") return run.status;
|
|
77
|
+
if (structuredRecoverableWorkflowFailure(run) !== undefined) return "blocked";
|
|
78
|
+
const returnedStatus = normalizeReturnedWorkflowStatus(run.result?.["status"]);
|
|
79
|
+
if (returnedStatus === "failed") return "failed";
|
|
80
|
+
if (returnedStatus !== undefined && isReturnedBlockedWorkflowStatus(returnedStatus)) return "blocked";
|
|
81
|
+
return run.status;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function structuredRecoverableFailureFromSnapshot(
|
|
85
|
+
snapshot: Pick<RunSnapshot | StageSnapshot, "error" | "failureKind" | "failureCode" | "failureRecoverability" | "failureDisposition" | "failureMessage" | "retryAfterMs">,
|
|
86
|
+
failedStageId?: string,
|
|
87
|
+
): StructuredRecoverableWorkflowFailure | undefined {
|
|
88
|
+
if (snapshot.failureDisposition !== "active_blocked") return undefined;
|
|
89
|
+
if (snapshot.failureRecoverability !== "recoverable") return undefined;
|
|
90
|
+
if (!isRecoverableProviderFailureKind(snapshot.failureKind)) return undefined;
|
|
91
|
+
const error = snapshot.error ?? snapshot.failureMessage ?? "Workflow is blocked by a recoverable provider failure.";
|
|
92
|
+
return {
|
|
93
|
+
error,
|
|
94
|
+
metadata: {
|
|
95
|
+
failureKind: snapshot.failureKind,
|
|
96
|
+
...(snapshot.failureCode !== undefined ? { failureCode: snapshot.failureCode } : {}),
|
|
97
|
+
failureRecoverability: snapshot.failureRecoverability,
|
|
98
|
+
failureDisposition: snapshot.failureDisposition,
|
|
99
|
+
failureMessage: snapshot.failureMessage ?? error,
|
|
100
|
+
...(failedStageId !== undefined ? { failedStageId } : {}),
|
|
101
|
+
resumable: true,
|
|
102
|
+
...(snapshot.retryAfterMs !== undefined ? { retryAfterMs: snapshot.retryAfterMs } : {}),
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function isRecoverableProviderFailureKind(kind: WorkflowFailureKind | undefined): kind is "auth" | "rate_limit" | "provider" {
|
|
108
|
+
return kind === "auth" || kind === "rate_limit" || kind === "provider";
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
function stringResultField(result: WorkflowOutputValues | undefined, key: string): string | undefined {
|
|
114
|
+
const value = result?.[key];
|
|
115
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
|
|
116
|
+
}
|
|
@@ -186,6 +186,8 @@ const PROVIDER_UNAVAILABLE_PHRASES: readonly TokenMatch[] = [
|
|
|
186
186
|
["provider", "error"],
|
|
187
187
|
["model", "unavailable"],
|
|
188
188
|
["503"],
|
|
189
|
+
["git", "command", "timed", "out"],
|
|
190
|
+
["spawnsync", "git", "etimedout"],
|
|
189
191
|
];
|
|
190
192
|
|
|
191
193
|
const AUTH_CONTEXT = new Set([
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
OVERLAY_LINE_COUNT,
|
|
6
6
|
OVERLAY_VERTICAL_MARGIN_ROWS,
|
|
7
7
|
} from "./graph-view-constants.js";
|
|
8
|
+
import { WORKFLOW_STATUS_KEY } from "./workflow-status.js";
|
|
8
9
|
import { GraphViewState } from "./graph-view-state.js";
|
|
9
10
|
import { renderOutlinePill } from "./header.js";
|
|
10
11
|
import { NODE_H, NODE_W } from "./layout.js";
|
|
@@ -78,12 +79,25 @@ export abstract class GraphViewRenderHelpers extends GraphViewState {
|
|
|
78
79
|
* the header band: `backgroundPanel` chrome, outlined accent pill
|
|
79
80
|
* flush-left, hints flowing right on the centre row.
|
|
80
81
|
*/
|
|
82
|
+
protected _externalStatusText(): string | null {
|
|
83
|
+
const entries = Array.from(this.footerData?.getExtensionStatuses() ?? [])
|
|
84
|
+
.filter(([key, value]) => (
|
|
85
|
+
value.trim().length > 0 &&
|
|
86
|
+
key !== WORKFLOW_STATUS_KEY &&
|
|
87
|
+
!key.startsWith(`${WORKFLOW_STATUS_KEY}:`)
|
|
88
|
+
))
|
|
89
|
+
.sort(([a], [b]) => a.localeCompare(b));
|
|
90
|
+
if (entries.length === 0) return null;
|
|
91
|
+
return entries.map(([, value]) => value.trim()).join(" · ");
|
|
92
|
+
}
|
|
93
|
+
|
|
81
94
|
protected _renderStatusline(width: number): string[] {
|
|
82
95
|
const t = this.graphTheme;
|
|
83
96
|
const chromeBg = hexBg(t.backgroundPanel);
|
|
84
97
|
const text = hexToAnsi(t.text);
|
|
85
98
|
const muted = hexToAnsi(t.textMuted);
|
|
86
99
|
const dim = hexToAnsi(t.dim);
|
|
100
|
+
const accent = hexToAnsi(t.accent);
|
|
87
101
|
|
|
88
102
|
const {
|
|
89
103
|
top,
|
|
@@ -92,13 +106,17 @@ export abstract class GraphViewRenderHelpers extends GraphViewState {
|
|
|
92
106
|
visibleWidth: pillW,
|
|
93
107
|
} = renderOutlinePill(MODE_PILL_LABEL, t.accent, chromeBg);
|
|
94
108
|
|
|
95
|
-
// Hints — `<key> <label>` separated by ` · `.
|
|
109
|
+
// Hints — `<key> <label>` separated by ` · `. When other extensions
|
|
110
|
+
// publish status text (for example the async subagent widget), include it
|
|
111
|
+
// ahead of the controls so fullscreen workflow overlays do not hide it.
|
|
96
112
|
const sep = `${chromeBg} ${dim}·${RESET}${chromeBg} `;
|
|
97
|
-
const
|
|
113
|
+
const statusText = this._externalStatusText();
|
|
114
|
+
const statusSegment = statusText ? [`${accent}${statusText}${RESET}${chromeBg}`] : [];
|
|
115
|
+
const hintSegments = HINT_KEYS.map(
|
|
98
116
|
({ key, label }) =>
|
|
99
117
|
`${text}${BOLD}${key}${RESET}${chromeBg} ${muted}${label}${RESET}${chromeBg}`,
|
|
100
118
|
);
|
|
101
|
-
const hintsStyledRaw =
|
|
119
|
+
const hintsStyledRaw = [...statusSegment, ...hintSegments].join(sep);
|
|
102
120
|
|
|
103
121
|
const leftEdgePad = 1;
|
|
104
122
|
const rightEdgePad = 2;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ReadonlyFooterDataProvider } from "@bastani/atomic";
|
|
1
2
|
import type { Store } from "../shared/store.js";
|
|
2
3
|
import type {
|
|
3
4
|
PendingPrompt,
|
|
@@ -63,6 +64,7 @@ export abstract class GraphViewState {
|
|
|
63
64
|
protected getViewportRows?: () => number | undefined;
|
|
64
65
|
protected requestRender?: () => void;
|
|
65
66
|
protected piKeybindings?: unknown;
|
|
67
|
+
protected footerData?: ReadonlyFooterDataProvider;
|
|
66
68
|
|
|
67
69
|
/** Active HIL prompt state, set when `_rebuildLayout` sees a new prompt id. */
|
|
68
70
|
protected promptState: PromptCardState | null = null;
|
|
@@ -102,6 +104,7 @@ export abstract class GraphViewState {
|
|
|
102
104
|
this.getViewportRows = opts.getViewportRows;
|
|
103
105
|
this.requestRender = opts.requestRender;
|
|
104
106
|
this.piKeybindings = opts.piKeybindings;
|
|
107
|
+
this.footerData = opts.footerData;
|
|
105
108
|
|
|
106
109
|
this._unsubscribe = this.store.subscribe((snap) => {
|
|
107
110
|
this.currentSnapshot = snap;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ReadonlyFooterDataProvider } from "@bastani/atomic";
|
|
1
2
|
import type { Store } from "../shared/store.js";
|
|
2
3
|
import type { GraphTheme } from "./graph-theme.js";
|
|
3
4
|
|
|
@@ -66,4 +67,6 @@ export interface GraphViewOpts {
|
|
|
66
67
|
requestRender?: () => void;
|
|
67
68
|
/** Host Pi keybindings manager used by run-level prompt cards. */
|
|
68
69
|
piKeybindings?: unknown;
|
|
70
|
+
/** Host footer/status provider used to surface non-workflow extension statuses inside the fullscreen graph overlay. */
|
|
71
|
+
footerData?: ReadonlyFooterDataProvider;
|
|
69
72
|
}
|