@bastani/atomic 0.9.11-alpha.9 → 0.9.11
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 +134 -0
- package/README.md +1 -1
- package/dist/builtin/intercom/CHANGELOG.md +6 -0
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/intercom/subagent-relay.ts +8 -5
- package/dist/builtin/mcp/CHANGELOG.md +10 -0
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/CHANGELOG.md +20 -0
- package/dist/builtin/subagents/agents/code-simplifier.md +2 -2
- package/dist/builtin/subagents/agents/codebase-analyzer.md +2 -2
- package/dist/builtin/subagents/agents/codebase-locator.md +2 -2
- package/dist/builtin/subagents/agents/codebase-online-researcher.md +2 -2
- package/dist/builtin/subagents/agents/codebase-pattern-finder.md +2 -2
- package/dist/builtin/subagents/agents/codebase-research-analyzer.md +2 -2
- package/dist/builtin/subagents/agents/codebase-research-locator.md +2 -2
- package/dist/builtin/subagents/agents/worker.md +2 -2
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/subagents/src/extension/notification-content.ts +14 -9
- package/dist/builtin/subagents/src/runs/background/notify.ts +20 -4
- package/dist/builtin/web-access/CHANGELOG.md +20 -0
- package/dist/builtin/web-access/content-tools.ts +1 -0
- package/dist/builtin/web-access/flat-string.ts +37 -0
- package/dist/builtin/web-access/github-api.ts +2 -1
- package/dist/builtin/web-access/github-extract.ts +3 -2
- package/dist/builtin/web-access/package.json +2 -2
- package/dist/builtin/workflows/CHANGELOG.md +57 -0
- package/dist/builtin/workflows/builtin/goal-ledger.ts +6 -4
- package/dist/builtin/workflows/builtin/goal-runner.ts +2 -1
- package/dist/builtin/workflows/builtin/goal.ts +1 -1
- package/dist/builtin/workflows/builtin/ralph-core.ts +8 -9
- package/dist/builtin/workflows/builtin/ralph-forked-prompts.ts +2 -4
- package/dist/builtin/workflows/builtin/ralph-models.ts +4 -4
- package/dist/builtin/workflows/builtin/ralph-runner.ts +5 -8
- package/dist/builtin/workflows/builtin/ralph.ts +2 -1
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/src/durable/completed-catalog.ts +14 -8
- package/dist/builtin/workflows/src/durable/completed-inspection.ts +10 -11
- package/dist/builtin/workflows/src/durable/resume-catalog.ts +1 -1
- package/dist/builtin/workflows/src/durable/resume-eligibility.ts +42 -0
- package/dist/builtin/workflows/src/durable/resume-runtime.ts +36 -37
- package/dist/builtin/workflows/src/durable/tool-primitive.ts +10 -2
- package/dist/builtin/workflows/src/engine/run.ts +1 -0
- package/dist/builtin/workflows/src/extension/extension-runtime-state.ts +12 -8
- package/dist/builtin/workflows/src/extension/hil-answer-notifications.ts +5 -2
- package/dist/builtin/workflows/src/extension/index.bundle.mjs +1966 -880
- package/dist/builtin/workflows/src/extension/lifecycle-notifications.ts +6 -3
- package/dist/builtin/workflows/src/extension/postmortem-deps.ts +3 -2
- package/dist/builtin/workflows/src/extension/render-result.ts +4 -11
- package/dist/builtin/workflows/src/extension/runtime-durable-resume.ts +17 -20
- package/dist/builtin/workflows/src/extension/runtime.ts +3 -3
- package/dist/builtin/workflows/src/extension/workflow-command-completions.ts +1 -1
- package/dist/builtin/workflows/src/extension/workflow-command-registration.ts +3 -7
- package/dist/builtin/workflows/src/extension/workflow-durable-resume-command.ts +21 -24
- package/dist/builtin/workflows/src/extension/workflow-resume-picker-rows.ts +38 -26
- package/dist/builtin/workflows/src/extension/workflow-resume-shadow.ts +2 -1
- package/dist/builtin/workflows/src/extension/workflow-run-control-command.ts +56 -64
- package/dist/builtin/workflows/src/extension/workflow-schema.ts +2 -2
- package/dist/builtin/workflows/src/extension/workflow-status-summary.ts +0 -5
- package/dist/builtin/workflows/src/extension/workflow-targets.ts +17 -20
- package/dist/builtin/workflows/src/extension/workflow-tool-content.ts +1 -1
- package/dist/builtin/workflows/src/extension/workflow-tool-control.ts +24 -51
- package/dist/builtin/workflows/src/extension/workflow-tool-inspection.ts +7 -29
- package/dist/builtin/workflows/src/extension/workflow-tool-send.ts +5 -13
- package/dist/builtin/workflows/src/extension/workflow-tool.ts +4 -13
- package/dist/builtin/workflows/src/runs/background/quit.ts +4 -3
- package/dist/builtin/workflows/src/runs/background/run-inspect.ts +8 -8
- package/dist/builtin/workflows/src/runs/background/status.ts +2 -1
- package/dist/builtin/workflows/src/runs/background/workflow-lifecycle-aggregate.ts +2 -1
- package/dist/builtin/workflows/src/runs/foreground/executor-direct-helpers.ts +5 -5
- package/dist/builtin/workflows/src/runs/foreground/executor-lifecycle.ts +4 -0
- package/dist/builtin/workflows/src/runs/foreground/executor-scheduler.ts +2 -0
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-call.ts +23 -8
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-factory.ts +6 -2
- package/dist/builtin/workflows/src/runs/foreground/executor-task-prompts.ts +5 -0
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-context.ts +56 -10
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-controller.ts +6 -0
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-output.ts +137 -6
- package/dist/builtin/workflows/src/shared/authoring-contract-ui.d.ts +2 -0
- package/dist/builtin/workflows/src/shared/authoring-contract-ui.ts +2 -0
- package/dist/builtin/workflows/src/shared/expanded-workflow-graph.ts +159 -10
- package/dist/builtin/workflows/src/shared/flat-string.ts +33 -0
- package/dist/builtin/workflows/src/shared/graph-store-snapshot.ts +144 -0
- package/dist/builtin/workflows/src/shared/persistence-session-entries.ts +2 -3
- package/dist/builtin/workflows/src/shared/run-id.ts +36 -0
- package/dist/builtin/workflows/src/shared/store-internal.ts +32 -3
- package/dist/builtin/workflows/src/shared/store-observation.ts +10 -0
- package/dist/builtin/workflows/src/shared/store-public-types.ts +8 -0
- package/dist/builtin/workflows/src/shared/store-run-methods.ts +14 -0
- package/dist/builtin/workflows/src/shared/store-types.ts +4 -0
- package/dist/builtin/workflows/src/shared/types.ts +2 -0
- package/dist/builtin/workflows/src/shared/workflow-artifacts.ts +261 -0
- package/dist/builtin/workflows/src/tui/dispatch-confirm.ts +39 -23
- package/dist/builtin/workflows/src/tui/graph-canvas.ts +26 -9
- package/dist/builtin/workflows/src/tui/graph-view-constants.ts +3 -0
- package/dist/builtin/workflows/src/tui/graph-view-graph-render.ts +95 -98
- package/dist/builtin/workflows/src/tui/graph-view-render.ts +7 -20
- package/dist/builtin/workflows/src/tui/graph-view-state.ts +160 -13
- package/dist/builtin/workflows/src/tui/layout.ts +8 -2
- package/dist/builtin/workflows/src/tui/node-card.ts +57 -45
- package/dist/builtin/workflows/src/tui/overlay-adapter.ts +4 -2
- package/dist/builtin/workflows/src/tui/prompt-card-render.ts +291 -21
- package/dist/builtin/workflows/src/tui/prompt-card.ts +1 -1
- package/dist/builtin/workflows/src/tui/renderers.ts +0 -1
- package/dist/builtin/workflows/src/tui/run-detail.ts +52 -35
- package/dist/builtin/workflows/src/tui/run-identity-rows.ts +97 -0
- package/dist/builtin/workflows/src/tui/session-overlays.ts +24 -3
- package/dist/builtin/workflows/src/tui/session-picker.ts +94 -41
- package/dist/builtin/workflows/src/tui/stage-chat-view-archive-history.ts +190 -26
- package/dist/builtin/workflows/src/tui/stage-chat-view-footer-status.ts +52 -18
- package/dist/builtin/workflows/src/tui/stage-chat-view-input.ts +9 -5
- package/dist/builtin/workflows/src/tui/stage-chat-view-state.ts +44 -4
- package/dist/builtin/workflows/src/tui/stage-chat-view-types.ts +3 -1
- package/dist/builtin/workflows/src/tui/stage-chat-view.ts +3 -2
- package/dist/builtin/workflows/src/tui/status-list.ts +67 -45
- package/dist/builtin/workflows/src/tui/store-widget-installer.ts +7 -6
- package/dist/builtin/workflows/src/tui/widget.ts +49 -40
- package/dist/builtin/workflows/src/tui/workflow-attach-pane.ts +15 -10
- package/dist/builtin/workflows/src/tui/workflow-resume-selector.ts +21 -8
- package/dist/core/agent-session-accessors.d.ts.map +1 -1
- package/dist/core/agent-session-accessors.js +5 -0
- package/dist/core/agent-session-accessors.js.map +1 -1
- package/dist/core/agent-session-auto-compaction.d.ts.map +1 -1
- package/dist/core/agent-session-auto-compaction.js +5 -0
- package/dist/core/agent-session-auto-compaction.js.map +1 -1
- package/dist/core/agent-session-compaction.d.ts.map +1 -1
- package/dist/core/agent-session-compaction.js +3 -0
- package/dist/core/agent-session-compaction.js.map +1 -1
- package/dist/core/agent-session-events.d.ts.map +1 -1
- package/dist/core/agent-session-events.js +2 -1
- package/dist/core/agent-session-events.js.map +1 -1
- package/dist/core/agent-session-message-queue.d.ts +3 -7
- package/dist/core/agent-session-message-queue.d.ts.map +1 -1
- package/dist/core/agent-session-message-queue.js +27 -13
- package/dist/core/agent-session-message-queue.js.map +1 -1
- package/dist/core/agent-session-methods.d.ts +5 -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-persistent-custom-messages.d.ts.map +1 -1
- package/dist/core/agent-session-persistent-custom-messages.js +6 -3
- package/dist/core/agent-session-persistent-custom-messages.js.map +1 -1
- package/dist/core/agent-session-post-tool-compaction.d.ts.map +1 -1
- package/dist/core/agent-session-post-tool-compaction.js +11 -2
- package/dist/core/agent-session-post-tool-compaction.js.map +1 -1
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +5 -3
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session-tree.d.ts.map +1 -1
- package/dist/core/agent-session-tree.js +4 -0
- package/dist/core/agent-session-tree.js.map +1 -1
- package/dist/core/agent-session-types.d.ts +4 -0
- 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 +2 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +1 -0
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage-backends.d.ts.map +1 -1
- package/dist/core/auth-storage-backends.js +12 -1
- package/dist/core/auth-storage-backends.js.map +1 -1
- package/dist/core/bounded-model-refresh.d.ts +14 -0
- package/dist/core/bounded-model-refresh.d.ts.map +1 -0
- package/dist/core/bounded-model-refresh.js +38 -0
- package/dist/core/bounded-model-refresh.js.map +1 -0
- package/dist/core/context-tool-pairing.d.ts +4 -4
- package/dist/core/context-tool-pairing.js +4 -4
- package/dist/core/context-tool-pairing.js.map +1 -1
- package/dist/core/http-dispatcher.d.ts.map +1 -1
- package/dist/core/http-dispatcher.js +26 -1
- package/dist/core/http-dispatcher.js.map +1 -1
- package/dist/core/messages.d.ts +18 -6
- package/dist/core/messages.d.ts.map +1 -1
- package/dist/core/messages.js +46 -18
- package/dist/core/messages.js.map +1 -1
- package/dist/core/model-refresh-timeout.d.ts +9 -0
- package/dist/core/model-refresh-timeout.d.ts.map +1 -0
- package/dist/core/model-refresh-timeout.js +9 -0
- package/dist/core/model-refresh-timeout.js.map +1 -0
- package/dist/core/model-runtime-snapshot.d.ts +3 -0
- package/dist/core/model-runtime-snapshot.d.ts.map +1 -1
- package/dist/core/model-runtime-snapshot.js +59 -0
- package/dist/core/model-runtime-snapshot.js.map +1 -1
- package/dist/core/model-runtime.d.ts +7 -1
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +72 -17
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +4 -3
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager-core.d.ts +1 -1
- package/dist/core/session-manager-core.d.ts.map +1 -1
- package/dist/core/session-manager-core.js +2 -2
- package/dist/core/session-manager-core.js.map +1 -1
- package/dist/core/session-manager-entries.d.ts +1 -1
- package/dist/core/session-manager-entries.d.ts.map +1 -1
- package/dist/core/session-manager-entries.js +2 -1
- package/dist/core/session-manager-entries.js.map +1 -1
- package/dist/core/session-manager-history.d.ts.map +1 -1
- package/dist/core/session-manager-history.js +2 -2
- package/dist/core/session-manager-history.js.map +1 -1
- package/dist/core/session-manager-types.d.ts +3 -0
- package/dist/core/session-manager-types.d.ts.map +1 -1
- package/dist/core/session-manager-types.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/main-app-mode.d.ts +1 -0
- package/dist/main-app-mode.d.ts.map +1 -1
- package/dist/main-app-mode.js +3 -0
- package/dist/main-app-mode.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +8 -3
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-actions.d.ts +7 -2
- package/dist/modes/interactive/components/chat-session-host-actions.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-actions.js +13 -4
- package/dist/modes/interactive/components/chat-session-host-actions.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-editor.d.ts +3 -1
- package/dist/modes/interactive/components/chat-session-host-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-editor.js +2 -2
- package/dist/modes/interactive/components/chat-session-host-editor.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-events.d.ts +3 -0
- package/dist/modes/interactive/components/chat-session-host-events.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-events.js +5 -4
- package/dist/modes/interactive/components/chat-session-host-events.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host.d.ts +16 -2
- package/dist/modes/interactive/components/chat-session-host.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host.js +35 -5
- package/dist/modes/interactive/components/chat-session-host.js.map +1 -1
- package/dist/modes/interactive/components/index.d.ts +1 -0
- package/dist/modes/interactive/components/index.d.ts.map +1 -1
- package/dist/modes/interactive/components/index.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts +0 -1
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +25 -35
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-editor-actions.js +2 -1
- package/dist/modes/interactive/interactive-editor-actions.js.map +1 -1
- package/dist/modes/interactive/interactive-input-handling.js +1 -1
- package/dist/modes/interactive/interactive-input-handling.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-surface.d.ts +4 -1
- 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-model-routing.js +4 -1
- package/dist/modes/interactive/interactive-model-routing.js.map +1 -1
- package/dist/modes/interactive/interactive-pause.d.ts +3 -1
- package/dist/modes/interactive/interactive-pause.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-pause.js +5 -1
- package/dist/modes/interactive/interactive-pause.js.map +1 -1
- package/dist/modes/interactive/interactive-queueing.js +3 -3
- package/dist/modes/interactive/interactive-queueing.js.map +1 -1
- package/dist/modes/interactive-engine/engine-health.d.ts +6 -0
- package/dist/modes/interactive-engine/engine-health.d.ts.map +1 -1
- package/dist/modes/interactive-engine/engine-health.js +15 -1
- package/dist/modes/interactive-engine/engine-health.js.map +1 -1
- package/dist/modes/interactive-engine/isolated-auth.js +1 -1
- package/dist/modes/interactive-engine/isolated-auth.js.map +1 -1
- package/dist/modes/interactive-engine/isolated-runtime.d.ts +1 -0
- package/dist/modes/interactive-engine/isolated-runtime.d.ts.map +1 -1
- package/dist/modes/interactive-engine/isolated-runtime.js +7 -1
- package/dist/modes/interactive-engine/isolated-runtime.js.map +1 -1
- package/dist/modes/interactive-engine/remote-model-catalog.d.ts.map +1 -1
- package/dist/modes/interactive-engine/remote-model-catalog.js +5 -1
- package/dist/modes/interactive-engine/remote-model-catalog.js.map +1 -1
- package/dist/modes/rpc/rpc-command-handler.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-command-handler.js +23 -7
- package/dist/modes/rpc/rpc-command-handler.js.map +1 -1
- package/dist/modes/rpc/rpc-input-scheduler.js +1 -1
- package/dist/modes/rpc/rpc-input-scheduler.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +2 -1
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/docs/custom-provider.md +3 -3
- package/docs/extensions.md +3 -1
- package/docs/index.md +10 -0
- package/docs/keybindings.md +1 -1
- package/docs/models.md +2 -0
- package/docs/providers.md +7 -3
- package/docs/quickstart.md +7 -1
- package/docs/session-format.md +2 -0
- package/docs/termux.md +3 -1
- package/docs/usage.md +3 -2
- package/docs/workflows.md +82 -46
- package/npm-shrinkwrap.json +59 -27
- package/package.json +3 -3
- package/dist/builtin/workflows/src/tui/toast.ts +0 -107
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
} from "../shared/returned-run-status.js";
|
|
8
8
|
import { isTopLevelWorkflowRun } from "../shared/run-visibility.js";
|
|
9
9
|
import type { Store } from "../shared/store.js";
|
|
10
|
+
import { readGraphStoreSnapshot, subscribeStoreInvalidation } from "../shared/store-observation.js";
|
|
10
11
|
import type {
|
|
11
12
|
PendingPrompt,
|
|
12
13
|
PromptKind,
|
|
@@ -175,7 +176,9 @@ export function installWorkflowLifecycleNotifications(options: WorkflowLifecycle
|
|
|
175
176
|
const notifyOn = new Set<WorkflowLifecycleNoticeKind>(options.config.notifyOn);
|
|
176
177
|
const state = options.state ?? createWorkflowLifecycleNotificationState();
|
|
177
178
|
let delivery!: ReturnType<typeof createLifecycleNoticeDelivery>;
|
|
178
|
-
if (options.seedExisting !== false)
|
|
179
|
+
if (options.seedExisting !== false) {
|
|
180
|
+
seedWorkflowLifecycleNotificationState(state, readGraphStoreSnapshot(options.store));
|
|
181
|
+
}
|
|
179
182
|
|
|
180
183
|
const emit = (details: WorkflowLifecycleNoticeDetails): boolean | Promise<boolean> => {
|
|
181
184
|
try {
|
|
@@ -266,8 +269,8 @@ export function installWorkflowLifecycleNotifications(options: WorkflowLifecycle
|
|
|
266
269
|
if (notifyOn.has(details.kind)) delivery.deliver(key, details);
|
|
267
270
|
}
|
|
268
271
|
|
|
269
|
-
const unsubscribe = options.store
|
|
270
|
-
inspect(options.store
|
|
272
|
+
const unsubscribe = subscribeStoreInvalidation(options.store, () => inspect(readGraphStoreSnapshot(options.store)));
|
|
273
|
+
inspect(readGraphStoreSnapshot(options.store));
|
|
271
274
|
return () => {
|
|
272
275
|
unsubscribe();
|
|
273
276
|
delivery.dispose();
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
import { stageControlRegistry } from "../runs/foreground/stage-control-registry.js";
|
|
23
23
|
import type { StageAdapters } from "../runs/foreground/stage-runner.js";
|
|
24
24
|
import { store } from "../shared/store.js";
|
|
25
|
+
import { readGraphStoreSnapshot } from "../shared/store-observation.js";
|
|
25
26
|
|
|
26
27
|
export interface PostMortemResolverDeps {
|
|
27
28
|
readonly adapters: StageAdapters;
|
|
@@ -33,7 +34,7 @@ function resolveStageCwd(runId: string): string | undefined {
|
|
|
33
34
|
try {
|
|
34
35
|
const backend = getDurableBackend();
|
|
35
36
|
const owningHandle = backend.getWorkflow(runId);
|
|
36
|
-
const run = store
|
|
37
|
+
const run = readGraphStoreSnapshot(store).runs.find((candidate) => candidate.id === runId);
|
|
37
38
|
const rootRunId = run?.rootRunId ?? owningHandle?.rootWorkflowId;
|
|
38
39
|
const cwdHandle = rootRunId === undefined ? owningHandle : (backend.getWorkflow(rootRunId) ?? owningHandle);
|
|
39
40
|
return cwdHandle?.workflowCwd ?? cwdHandle?.invocationCwd ?? undefined;
|
|
@@ -61,7 +62,7 @@ export function createPostMortemHandleResolver(
|
|
|
61
62
|
deps: PostMortemResolverDeps,
|
|
62
63
|
): (runId: string, stageId: string) => EnsurePostMortemStageHandleResult | undefined {
|
|
63
64
|
return (runId, stageId) => {
|
|
64
|
-
const run = store
|
|
65
|
+
const run = readGraphStoreSnapshot(store).runs.find((candidate) => candidate.id === runId);
|
|
65
66
|
const stage = run?.stages.find((candidate) => candidate.id === stageId);
|
|
66
67
|
if (stage === undefined) return undefined;
|
|
67
68
|
return ensurePostMortemStageHandle(runId, stage, postMortemDepsForRun(runId, deps));
|
|
@@ -442,9 +442,7 @@ export function renderResult(result: WorkflowToolResult, opts?: RenderResultOpts
|
|
|
442
442
|
const r = result as StageListResult;
|
|
443
443
|
if (r.error) return renderNotice("WORKFLOW STAGES", `${r.runId || "(none)"}: ${r.error}`, opts, themed);
|
|
444
444
|
const counts = r.stages
|
|
445
|
-
.map(
|
|
446
|
-
(s) => `${s.name} (${s.id.slice(0, 12)}): ${s.status}${s.skippedReason ? ` — ${s.skippedReason}` : ""}`,
|
|
447
|
-
)
|
|
445
|
+
.map((s) => `${s.name} (${s.id}): ${s.status}${s.skippedReason ? ` — ${s.skippedReason}` : ""}`)
|
|
448
446
|
.join("; ");
|
|
449
447
|
return renderNotice("WORKFLOW STAGES", `${r.runId}: ${r.filter} — ${counts || "no stages"}`, opts, themed);
|
|
450
448
|
}
|
|
@@ -456,7 +454,7 @@ export function renderResult(result: WorkflowToolResult, opts?: RenderResultOpts
|
|
|
456
454
|
const extra = r.stage.error ? ` — ${r.stage.error}` : r.stage.result ? ` — ${r.stage.result}` : "";
|
|
457
455
|
return renderNotice(
|
|
458
456
|
"WORKFLOW STAGE",
|
|
459
|
-
`${r.runId}: ${r.stage.name} (${r.stage.id
|
|
457
|
+
`${r.runId}: ${r.stage.name} (${r.stage.id}) ${r.stage.status}${extra}`,
|
|
460
458
|
opts,
|
|
461
459
|
themed,
|
|
462
460
|
);
|
|
@@ -468,7 +466,7 @@ export function renderResult(result: WorkflowToolResult, opts?: RenderResultOpts
|
|
|
468
466
|
const suffix = r.truncated ? " (truncated)" : "";
|
|
469
467
|
return renderNotice(
|
|
470
468
|
"WORKFLOW TRANSCRIPT",
|
|
471
|
-
`${r.runId}/${r.stageId
|
|
469
|
+
`${r.runId}/${r.stageId} ${r.source}: ${text}${suffix}`,
|
|
472
470
|
opts,
|
|
473
471
|
themed,
|
|
474
472
|
);
|
|
@@ -476,12 +474,7 @@ export function renderResult(result: WorkflowToolResult, opts?: RenderResultOpts
|
|
|
476
474
|
|
|
477
475
|
case "send": {
|
|
478
476
|
const r = result as SendResult;
|
|
479
|
-
return renderNotice(
|
|
480
|
-
"WORKFLOW SEND",
|
|
481
|
-
`${r.runId}/${r.stageId.slice(0, 12)} ${r.delivery}: ${r.message}`,
|
|
482
|
-
opts,
|
|
483
|
-
themed,
|
|
484
|
-
);
|
|
477
|
+
return renderNotice("WORKFLOW SEND", `${r.runId}/${r.stageId} ${r.delivery}: ${r.message}`, opts, themed);
|
|
485
478
|
}
|
|
486
479
|
|
|
487
480
|
case "pause": {
|
|
@@ -25,17 +25,17 @@ import { discoverWorkflows } from "./discovery.js";
|
|
|
25
25
|
|
|
26
26
|
export interface DurableResumeRuntime {
|
|
27
27
|
resumeDurableWorkflow(
|
|
28
|
-
|
|
28
|
+
workflowId: string,
|
|
29
29
|
options?: { readonly policy?: WorkflowExecutionPolicy },
|
|
30
30
|
): Promise<ResumeDurableResult>;
|
|
31
31
|
listDurableResumable(): readonly ResumableWorkflowEntry[];
|
|
32
|
-
prepareDurableResumable(
|
|
32
|
+
prepareDurableResumable(workflowId?: string): Promise<readonly ResumableWorkflowEntry[]>;
|
|
33
33
|
prepareDurableCatalog?(): Promise<DurableWorkflowCatalogEntries>;
|
|
34
34
|
/** Hydrate a bounded set of known DBOS workflow ids. */
|
|
35
35
|
prepareDurableResumableForIds?(workflowIds: readonly string[]): Promise<readonly ResumableWorkflowEntry[]>;
|
|
36
36
|
prepareCompletedDurable?(): Promise<readonly ResumableWorkflowEntry[]>;
|
|
37
37
|
openCompletedDurableWorkflow?(
|
|
38
|
-
|
|
38
|
+
workflowId: string,
|
|
39
39
|
catalog?: readonly ResumableWorkflowEntry[],
|
|
40
40
|
): OpenCompletedDurableResult;
|
|
41
41
|
}
|
|
@@ -60,18 +60,18 @@ export function createDurableResumeRuntime(deps: DurableResumeRuntimeDeps): Dura
|
|
|
60
60
|
const ids = deps.store
|
|
61
61
|
.runs()
|
|
62
62
|
.map((run) => run.id)
|
|
63
|
-
.filter((id) => target === undefined || id === target
|
|
63
|
+
.filter((id) => target === undefined || id === target);
|
|
64
64
|
for (const id of ids) await backend.hydrateWorkflow(id);
|
|
65
65
|
};
|
|
66
66
|
let preparedCatalog: readonly ResumableWorkflowEntry[] = [];
|
|
67
67
|
return {
|
|
68
|
-
async resumeDurableWorkflow(
|
|
68
|
+
async resumeDurableWorkflow(workflowId, options): Promise<ResumeDurableResult> {
|
|
69
69
|
await deps.ensureReady();
|
|
70
70
|
const backend = getDurableBackend();
|
|
71
71
|
if (preparedCatalog.length === 0) {
|
|
72
|
-
preparedCatalog = await prepareRuntimeDurableResumable(() => backend,
|
|
72
|
+
preparedCatalog = await prepareRuntimeDurableResumable(() => backend, workflowId);
|
|
73
73
|
}
|
|
74
|
-
const resolved = resolveCatalogEntry(
|
|
74
|
+
const resolved = resolveCatalogEntry(workflowId, preparedCatalog);
|
|
75
75
|
if (resolved !== undefined) await backend.hydrateWorkflow(resolved.workflowId);
|
|
76
76
|
const adapterDeps: ResumeDurableDeps = {
|
|
77
77
|
registry: deps.registry,
|
|
@@ -81,17 +81,17 @@ export function createDurableResumeRuntime(deps: DurableResumeRuntimeDeps): Dura
|
|
|
81
81
|
(await discoverWorkflows({ cwd: cwd ?? deps.runtimeCwd })).registry.get(name),
|
|
82
82
|
...(deps.jobs !== undefined ? { jobs: deps.jobs } : {}),
|
|
83
83
|
};
|
|
84
|
-
return await resumeDurableWorkflowAdapter(
|
|
84
|
+
return await resumeDurableWorkflowAdapter(workflowId, adapterDeps, preparedCatalog);
|
|
85
85
|
},
|
|
86
86
|
listDurableResumable(): readonly ResumableWorkflowEntry[] {
|
|
87
87
|
return getDurableBackend().listResumableWorkflows();
|
|
88
88
|
},
|
|
89
|
-
async prepareDurableResumable(
|
|
89
|
+
async prepareDurableResumable(workflowId) {
|
|
90
90
|
await deps.ensureReady();
|
|
91
91
|
const backend = getDurableBackend();
|
|
92
92
|
try {
|
|
93
|
-
await hydrateStoredWorkflowCandidates(backend,
|
|
94
|
-
preparedCatalog = await prepareRuntimeDurableResumable(() => backend,
|
|
93
|
+
await hydrateStoredWorkflowCandidates(backend, workflowId);
|
|
94
|
+
preparedCatalog = await prepareRuntimeDurableResumable(() => backend, workflowId);
|
|
95
95
|
return preparedCatalog;
|
|
96
96
|
} finally {
|
|
97
97
|
purgeSuppressedWorkflowRuns(backend, deps.store);
|
|
@@ -131,12 +131,12 @@ export function createDurableResumeRuntime(deps: DurableResumeRuntimeDeps): Dura
|
|
|
131
131
|
purgeSuppressedWorkflowRuns(backend, deps.store);
|
|
132
132
|
}
|
|
133
133
|
},
|
|
134
|
-
openCompletedDurableWorkflow(
|
|
134
|
+
openCompletedDurableWorkflow(workflowId, catalog) {
|
|
135
135
|
const backend = getDurableBackend();
|
|
136
|
-
const entry = resolveCatalogEntry(
|
|
137
|
-
const handle = backend.getWorkflow(entry?.workflowId ??
|
|
136
|
+
const entry = resolveCatalogEntry(workflowId, catalog ?? []);
|
|
137
|
+
const handle = backend.getWorkflow(entry?.workflowId ?? workflowId);
|
|
138
138
|
return openCompletedSnapshot(
|
|
139
|
-
|
|
139
|
+
workflowId,
|
|
140
140
|
{
|
|
141
141
|
durableBackend: backend,
|
|
142
142
|
store: deps.store,
|
|
@@ -152,11 +152,8 @@ export function createDurableResumeRuntime(deps: DurableResumeRuntimeDeps): Dura
|
|
|
152
152
|
}
|
|
153
153
|
|
|
154
154
|
function resolveCatalogEntry(
|
|
155
|
-
|
|
155
|
+
workflowId: string,
|
|
156
156
|
catalog: readonly ResumableWorkflowEntry[],
|
|
157
157
|
): ResumableWorkflowEntry | undefined {
|
|
158
|
-
|
|
159
|
-
if (exact !== undefined) return exact;
|
|
160
|
-
const matches = catalog.filter((entry) => entry.workflowId.startsWith(workflowIdOrPrefix));
|
|
161
|
-
return matches.length === 1 ? matches[0] : undefined;
|
|
158
|
+
return catalog.find((entry) => entry.workflowId === workflowId);
|
|
162
159
|
}
|
|
@@ -172,11 +172,11 @@ export function createExtensionRuntime(opts: ExtensionRuntimeOpts = {}): Extensi
|
|
|
172
172
|
}
|
|
173
173
|
|
|
174
174
|
function matchesResumeStageIdentifier(stage: RunSnapshot["stages"][number], identifier: string): boolean {
|
|
175
|
-
return stage.id === identifier || stage.name === identifier
|
|
175
|
+
return stage.id === identifier || stage.name === identifier;
|
|
176
176
|
}
|
|
177
177
|
|
|
178
178
|
function stageLabel(stage: RunSnapshot["stages"][number]): string {
|
|
179
|
-
return `${stage.name} (${stage.id
|
|
179
|
+
return `${stage.name} (${stage.id})`;
|
|
180
180
|
}
|
|
181
181
|
|
|
182
182
|
function resolveUniqueResumeStage(
|
|
@@ -261,7 +261,7 @@ export function createExtensionRuntime(opts: ExtensionRuntimeOpts = {}): Extensi
|
|
|
261
261
|
};
|
|
262
262
|
}
|
|
263
263
|
const stageMessage = (verb: string, runId: string): string =>
|
|
264
|
-
`${verb} workflow "${def.name}" from run ${source.id
|
|
264
|
+
`${verb} workflow "${def.name}" from run ${source.id} at stage ${resolvedStage.stageId} (run ${runId}).`;
|
|
265
265
|
const launchContinuation = () =>
|
|
266
266
|
launchDetachedUntilStartup(def, sourceInputs, {
|
|
267
267
|
...runOptions(options?.policy),
|
|
@@ -43,7 +43,7 @@ function workflowNameItems(runtime: ExtensionRuntime): PiArgumentCompletion[] {
|
|
|
43
43
|
function runIdItems(): PiArgumentCompletion[] {
|
|
44
44
|
return topLevelWorkflowRuns(store.runs()).map((run) => ({
|
|
45
45
|
value: `${run.id} `,
|
|
46
|
-
label: run.id
|
|
46
|
+
label: run.id,
|
|
47
47
|
description: `${run.name} — ${run.status}`,
|
|
48
48
|
}));
|
|
49
49
|
}
|
|
@@ -35,7 +35,7 @@ import {
|
|
|
35
35
|
import { workflowPolicyFromContext } from "./workflow-policy.js";
|
|
36
36
|
import { normalizeWorkflowReloadReport, type WorkflowReloadReport } from "./workflow-reload-report.js";
|
|
37
37
|
import { handleRunControlCommand, type WorkflowRunControlDeps } from "./workflow-run-control-command.js";
|
|
38
|
-
import { overlaySurfaceFromContext, reloadFailureMessage,
|
|
38
|
+
import { overlaySurfaceFromContext, reloadFailureMessage, resolveRunId } from "./workflow-targets.js";
|
|
39
39
|
|
|
40
40
|
export interface WorkflowSlashCommandDeps {
|
|
41
41
|
runtimeProxy: ExtensionRuntime;
|
|
@@ -150,13 +150,9 @@ async function workflowSlashHandler(
|
|
|
150
150
|
if (subcommand === "status") {
|
|
151
151
|
const target = parts[1];
|
|
152
152
|
if (target && !target.startsWith("--")) {
|
|
153
|
-
const resolved =
|
|
153
|
+
const resolved = resolveRunId(target);
|
|
154
|
+
if (resolved.kind === "malformed") return fail(resolved.message);
|
|
154
155
|
if (resolved.kind === "not_found") return fail(`Run not found: ${target}`);
|
|
155
|
-
if (resolved.kind === "ambiguous") {
|
|
156
|
-
return fail(
|
|
157
|
-
`Ambiguous run prefix "${target}" matches: ${resolved.matches.map((id) => id.slice(0, 12)).join(", ")}`,
|
|
158
|
-
);
|
|
159
|
-
}
|
|
160
156
|
const inspected = inspectRun(resolved.runId);
|
|
161
157
|
if (!inspected.ok) return fail(`Run not found: ${target}`);
|
|
162
158
|
emitChatSurface(pi, { kind: "detail", detail: inspected.detail });
|
|
@@ -2,10 +2,13 @@ import { listOpenableCompletedWorkflows } from "../durable/completed-catalog.js"
|
|
|
2
2
|
import { openCompletedDurableWorkflow } from "../durable/completed-inspection.js";
|
|
3
3
|
import { getDurableBackend } from "../durable/factory.js";
|
|
4
4
|
import { formatResumableWorkflowList } from "../durable/resume-catalog.js";
|
|
5
|
+
import { isWorkflowRunResumable } from "../durable/resume-eligibility.js";
|
|
5
6
|
import { type DurableWorkflowDeleteOutcome, deleteDurableWorkflowIfSafe } from "../durable/retention-policy.js";
|
|
6
7
|
import type { ResumableWorkflowEntry } from "../durable/types.js";
|
|
8
|
+
import { isFullRunId, malformedRunIdMessage } from "../shared/run-id.js";
|
|
7
9
|
import { store } from "../shared/store.js";
|
|
8
10
|
import type { RunSnapshot } from "../shared/store-types.js";
|
|
11
|
+
import { workflowRunResumeCandidate } from "../shared/workflow-artifacts.js";
|
|
9
12
|
import type { GraphOverlayPort } from "../tui/overlay-adapter.js";
|
|
10
13
|
import { openWorkflowResumeSelector } from "../tui/workflow-resume-selector.js";
|
|
11
14
|
import type { ExtensionAPI, PiCommandContext } from "./public-types.js";
|
|
@@ -37,12 +40,12 @@ export interface WorkflowResumeTarget {
|
|
|
37
40
|
|
|
38
41
|
export type WorkflowResumeTargetResolution =
|
|
39
42
|
| WorkflowResumeTarget
|
|
40
|
-
| { readonly kind: "
|
|
43
|
+
| { readonly kind: "malformed"; readonly message: string }
|
|
41
44
|
| { readonly kind: "not_found" };
|
|
42
45
|
|
|
43
46
|
export async function prepareWorkflowResumeCatalog(
|
|
44
47
|
runtime: ExtensionRuntime,
|
|
45
|
-
|
|
48
|
+
suppressedLiveIds: ReadonlySet<string>,
|
|
46
49
|
target?: string,
|
|
47
50
|
): Promise<WorkflowResumeCatalog> {
|
|
48
51
|
const shared = await runtime.prepareDurableCatalog?.();
|
|
@@ -50,8 +53,11 @@ export async function prepareWorkflowResumeCatalog(
|
|
|
50
53
|
const backend = getDurableBackend();
|
|
51
54
|
const isDisplayLoadable = (entry: ResumableWorkflowEntry): boolean =>
|
|
52
55
|
shared !== undefined || backend.isWorkflowLoadable(entry.workflowId);
|
|
56
|
+
// The durable catalog is already produced by `listResumableWorkflows()`, which
|
|
57
|
+
// applies `isDurableWorkflowResumable`; re-filtering here would only drop rows
|
|
58
|
+
// a hydrating backend has not yet materialized.
|
|
53
59
|
const resumable = filterSelectorDurableEntries(runtime, prepared).filter(
|
|
54
|
-
(entry) => !
|
|
60
|
+
(entry) => !suppressedLiveIds.has(entry.workflowId) && isDisplayLoadable(entry),
|
|
55
61
|
);
|
|
56
62
|
const completed =
|
|
57
63
|
shared?.completed ??
|
|
@@ -60,7 +66,7 @@ export async function prepareWorkflowResumeCatalog(
|
|
|
60
66
|
: listOpenableCompletedWorkflows(backend));
|
|
61
67
|
return {
|
|
62
68
|
resumable,
|
|
63
|
-
completed: completed.filter((entry) =>
|
|
69
|
+
completed: completed.filter((entry) => isDisplayLoadable(entry)),
|
|
64
70
|
};
|
|
65
71
|
}
|
|
66
72
|
|
|
@@ -99,8 +105,8 @@ export async function handleDurableResume(
|
|
|
99
105
|
// directory a second time for the same command invocation.
|
|
100
106
|
catalog.completed,
|
|
101
107
|
);
|
|
102
|
-
if (resolved.kind === "
|
|
103
|
-
fail(
|
|
108
|
+
if (resolved.kind === "malformed") {
|
|
109
|
+
fail(resolved.message);
|
|
104
110
|
return true;
|
|
105
111
|
}
|
|
106
112
|
if (resolved.kind === "completed") {
|
|
@@ -191,21 +197,16 @@ export function resolveWorkflowResumeTarget(
|
|
|
191
197
|
name: run.name,
|
|
192
198
|
});
|
|
193
199
|
}
|
|
200
|
+
if (!isFullRunId(target)) return { kind: "malformed", message: malformedRunIdMessage(target) };
|
|
194
201
|
const exact = targets.get(target);
|
|
195
|
-
|
|
196
|
-
const matches = [...targets.values()].filter((candidate) => candidate.workflowId.startsWith(target));
|
|
197
|
-
if (matches.length === 0) return { kind: "not_found" };
|
|
198
|
-
if (matches.length === 1) return matches[0]!;
|
|
199
|
-
return { kind: "ambiguous", matches };
|
|
202
|
+
return exact ?? { kind: "not_found" };
|
|
200
203
|
}
|
|
201
204
|
|
|
202
205
|
function isExplicitResumeCandidate(run: RunSnapshot): boolean {
|
|
203
|
-
if (run.status === "completed"
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
if (run.status === "running") return true;
|
|
208
|
-
return run.resumable === true && run.failureRecoverability === "recoverable";
|
|
206
|
+
if (run.status === "completed") return true;
|
|
207
|
+
return (
|
|
208
|
+
isWorkflowRunResumable(workflowRunResumeCandidate(run)) || (run.endedAt === undefined && run.status === "running")
|
|
209
|
+
);
|
|
209
210
|
}
|
|
210
211
|
|
|
211
212
|
async function resumeDurableTarget(
|
|
@@ -247,14 +248,14 @@ function openCompletedTarget(
|
|
|
247
248
|
|
|
248
249
|
function openCompleted(
|
|
249
250
|
runtime: ExtensionRuntime,
|
|
250
|
-
|
|
251
|
+
workflowId: string,
|
|
251
252
|
catalog: readonly ResumableWorkflowEntry[],
|
|
252
253
|
beforeRestoreCompleted?: (snapshots: readonly RunSnapshot[]) => void,
|
|
253
254
|
) {
|
|
254
255
|
return (
|
|
255
|
-
runtime.openCompletedDurableWorkflow?.(
|
|
256
|
+
runtime.openCompletedDurableWorkflow?.(workflowId, catalog) ??
|
|
256
257
|
openCompletedDurableWorkflow(
|
|
257
|
-
|
|
258
|
+
workflowId,
|
|
258
259
|
{
|
|
259
260
|
durableBackend: getDurableBackend(),
|
|
260
261
|
store,
|
|
@@ -264,7 +265,3 @@ function openCompleted(
|
|
|
264
265
|
)
|
|
265
266
|
);
|
|
266
267
|
}
|
|
267
|
-
|
|
268
|
-
function formatMatches(entries: readonly WorkflowResumeTarget[]): string {
|
|
269
|
-
return entries.map((entry) => `${entry.name} (${entry.workflowId.slice(0, 8)})`).join(", ");
|
|
270
|
-
}
|
|
@@ -9,51 +9,63 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import { getDurableBackend } from "../durable/factory.js";
|
|
12
|
+
import { isWorkflowRunResumable } from "../durable/resume-eligibility.js";
|
|
12
13
|
import type { ResumableWorkflowEntry } from "../durable/types.js";
|
|
13
14
|
import { topLevelWorkflowRuns } from "../shared/run-visibility.js";
|
|
14
15
|
import type { Store } from "../shared/store.js";
|
|
16
|
+
import { subscribeStoreInvalidation } from "../shared/store-observation.js";
|
|
15
17
|
import type { RunSnapshot } from "../shared/store-types.js";
|
|
18
|
+
import { workflowRunResumeCandidate } from "../shared/workflow-artifacts.js";
|
|
16
19
|
import type { WorkflowResumeRefresh } from "../tui/workflow-resume-selector.js";
|
|
17
20
|
import type { ExtensionRuntime } from "./runtime.js";
|
|
18
21
|
import { prepareWorkflowResumeCatalog } from "./workflow-durable-resume-command.js";
|
|
19
|
-
import {
|
|
22
|
+
import { classifyDurableResumeShadow } from "./workflow-resume-shadow.js";
|
|
20
23
|
|
|
21
24
|
export interface ResumePickerLiveSource {
|
|
22
25
|
readonly liveRuns: readonly RunSnapshot[];
|
|
23
|
-
|
|
26
|
+
/** Live ids whose resumable durable duplicates must be suppressed. */
|
|
27
|
+
readonly suppressedLiveIds: ReadonlySet<string>;
|
|
24
28
|
}
|
|
25
29
|
|
|
26
|
-
|
|
27
|
-
|
|
30
|
+
/** A live run is resumable when the shared predicate accepts it and the durable
|
|
31
|
+
* backend has not explicitly deleted it. A live paused/quit run resumes through
|
|
32
|
+
* its live stage controls, so it must NOT require a durable checkpoint here;
|
|
33
|
+
* a restored snapshot that depends on durable state is filtered by its shadow
|
|
34
|
+
* classification instead.
|
|
35
|
+
*/
|
|
36
|
+
function isResumableLiveRun(run: RunSnapshot): boolean {
|
|
37
|
+
if (!getDurableBackend().isWorkflowLoadable(run.id)) return false;
|
|
38
|
+
return isWorkflowRunResumable(workflowRunResumeCandidate(run));
|
|
28
39
|
}
|
|
29
40
|
|
|
30
41
|
export function collectResumePickerLiveRuns(runStore: Store): ResumePickerLiveSource {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
);
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
isActiveRecoverableBlock(run)) &&
|
|
42
|
-
getDurableBackend().isWorkflowLoadable(run.id),
|
|
43
|
-
);
|
|
42
|
+
// `eligible` rows are re-listed from the durable catalog, and `ineligible`
|
|
43
|
+
// rows have no durable checkpoint or pending prompt progress, so the resume
|
|
44
|
+
// path would refuse them. Only `not_shadow` runs can actually be resumed here.
|
|
45
|
+
const runs = topLevelWorkflowRuns(runStore.runs());
|
|
46
|
+
const shadowClassification = new Map(runs.map((run) => [run.id, classifyDurableResumeShadow(run, runStore)]));
|
|
47
|
+
const isOfferable = (run: RunSnapshot): boolean => shadowClassification.get(run.id) === "not_shadow";
|
|
48
|
+
const resumableById = new Map(runs.map((run) => [run.id, isResumableLiveRun(run)]));
|
|
49
|
+
const liveRuns = runs.filter((run) => isOfferable(run) && resumableById.get(run.id) === true);
|
|
50
|
+
const isCurrentlyRunning = (run: RunSnapshot): boolean =>
|
|
51
|
+
run.endedAt === undefined && run.status === "running" && run.exitReason !== "quit";
|
|
44
52
|
const activeLiveIds = new Set(
|
|
45
|
-
|
|
53
|
+
runs
|
|
46
54
|
.filter(
|
|
47
55
|
(run) =>
|
|
48
|
-
|
|
49
|
-
run
|
|
50
|
-
run.
|
|
51
|
-
!isActiveRecoverableBlock(run) &&
|
|
52
|
-
run.exitReason !== "quit",
|
|
56
|
+
shadowClassification.get(run.id) !== "eligible" &&
|
|
57
|
+
isCurrentlyRunning(run) &&
|
|
58
|
+
resumableById.get(run.id) !== true,
|
|
53
59
|
)
|
|
54
60
|
.map((run) => run.id),
|
|
55
61
|
);
|
|
56
|
-
|
|
62
|
+
// A non-running snapshot rejected by the shared predicate must not reappear as
|
|
63
|
+
// a resumable durable row. Completed inspection rows remain visible separately.
|
|
64
|
+
const rejectedLiveIds = new Set(
|
|
65
|
+
runs.filter((run) => !isCurrentlyRunning(run) && resumableById.get(run.id) !== true).map((run) => run.id),
|
|
66
|
+
);
|
|
67
|
+
const suppressedLiveIds = new Set([...activeLiveIds, ...rejectedLiveIds]);
|
|
68
|
+
return { liveRuns, suppressedLiveIds };
|
|
57
69
|
}
|
|
58
70
|
|
|
59
71
|
export interface ResumePickerLiveUpdateOptions {
|
|
@@ -66,10 +78,10 @@ export function resumePickerLiveUpdateOptions(
|
|
|
66
78
|
runtime: ExtensionRuntime,
|
|
67
79
|
): ResumePickerLiveUpdateOptions {
|
|
68
80
|
return {
|
|
69
|
-
watch: (onChange) => runStore
|
|
81
|
+
watch: (onChange) => subscribeStoreInvalidation(runStore, onChange),
|
|
70
82
|
refresh: async () => {
|
|
71
83
|
const current = collectResumePickerLiveRuns(runStore);
|
|
72
|
-
const catalog = await prepareWorkflowResumeCatalog(runtime, current.
|
|
84
|
+
const catalog = await prepareWorkflowResumeCatalog(runtime, current.suppressedLiveIds);
|
|
73
85
|
return {
|
|
74
86
|
liveRuns: current.liveRuns,
|
|
75
87
|
catalog: { durable: catalog.resumable, completed: catalog.completed },
|
|
@@ -5,6 +5,7 @@ import { getLoadableDurableWorkflow } from "../durable/workflow-status-transitio
|
|
|
5
5
|
import { type JobTracker, jobTracker } from "../runs/background/job-tracker.js";
|
|
6
6
|
import { type StageControlRegistry, stageControlRegistry } from "../runs/foreground/stage-control-registry.js";
|
|
7
7
|
import { expandWorkflowGraph } from "../shared/expanded-workflow-graph.js";
|
|
8
|
+
import { readGraphStoreSnapshot } from "../shared/store-observation.js";
|
|
8
9
|
import type { Store } from "../shared/store-public-types.js";
|
|
9
10
|
import type { RunSnapshot } from "../shared/store-types.js";
|
|
10
11
|
|
|
@@ -28,7 +29,7 @@ export function classifyDurableResumeShadow(
|
|
|
28
29
|
const jobs = deps.jobs ?? jobTracker;
|
|
29
30
|
if (jobs.has(run.id)) return "not_shadow";
|
|
30
31
|
const controls = deps.stageControls ?? stageControlRegistry;
|
|
31
|
-
const graph = expandWorkflowGraph(store
|
|
32
|
+
const graph = expandWorkflowGraph(readGraphStoreSnapshot(store), run.id);
|
|
32
33
|
const controlRunIds = new Set<string>([run.id]);
|
|
33
34
|
for (const stage of graph.stages) controlRunIds.add(stage.workflowGraphTarget.runId);
|
|
34
35
|
if ([...controlRunIds].some((runId) => controls.run(runId).stages().length > 0)) return "not_shadow";
|