@aicopycoders/exodus 2026.10.1700 → 2026.10.1701-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/commands/video.d.ts
CHANGED
package/dist/commands/video.js
CHANGED
|
@@ -3,6 +3,7 @@ import path from "node:path";
|
|
|
3
3
|
import { spawnSync } from "node:child_process";
|
|
4
4
|
import { apiGet, apiPost, getDashboardUrl } from "../lib/client.js";
|
|
5
5
|
import { displayRunStatus, formatApiError } from "../lib/format.js";
|
|
6
|
+
import { isWorkerStoppedPark } from "../lib/runStatus.js";
|
|
6
7
|
import { missingRouteLine } from "../lib/route-support.js";
|
|
7
8
|
import { hasBinary } from "../lib/preflight.js";
|
|
8
9
|
import { ASSET_UPLOAD_POLICY, pauseAheadLine, } from "./workflow.js";
|
|
@@ -411,6 +412,8 @@ export function classifyRun(run) {
|
|
|
411
412
|
if (run.isTerminal)
|
|
412
413
|
return { at: "finished", status: run.status };
|
|
413
414
|
if (isAwaitingApproval(run.status)) {
|
|
415
|
+
if (isWorkerStoppedPark(run))
|
|
416
|
+
return { at: "failed", repair: true, workerStopped: true };
|
|
414
417
|
if (run.pauseReason === "repair") {
|
|
415
418
|
const deadNode = run.nodes.find((n) => n.status === "failed");
|
|
416
419
|
const why = deadNode?.error ?? run.error;
|
|
@@ -591,6 +594,13 @@ export function stopLines(stop, runId, runUrl) {
|
|
|
591
594
|
];
|
|
592
595
|
}
|
|
593
596
|
if (stop.at === "failed") {
|
|
597
|
+
if (stop.workerStopped) {
|
|
598
|
+
return [
|
|
599
|
+
"The worker making this ad stopped partway. Finished steps are kept.",
|
|
600
|
+
`Carry on from where it stopped: exodus workflow repair ${runId} retry`,
|
|
601
|
+
`Or open the run: ${runUrl}`,
|
|
602
|
+
];
|
|
603
|
+
}
|
|
594
604
|
if (stop.repair) {
|
|
595
605
|
if (!stop.step) {
|
|
596
606
|
return [
|
|
@@ -2043,9 +2053,11 @@ export async function statusFlow(runId, json, deps) {
|
|
|
2043
2053
|
row[item.itemKind] = item;
|
|
2044
2054
|
byScene.set(item.sceneIndex, row);
|
|
2045
2055
|
}
|
|
2046
|
-
const headline = stop.at === "failed" && stop.
|
|
2047
|
-
? `Ad run ${runId} — Stopped,
|
|
2048
|
-
:
|
|
2056
|
+
const headline = stop.at === "failed" && stop.workerStopped
|
|
2057
|
+
? `Ad run ${runId} — Stopped, its worker went quiet`
|
|
2058
|
+
: stop.at === "failed" && stop.repair
|
|
2059
|
+
? `Ad run ${runId} — Stopped, a step failed`
|
|
2060
|
+
: `Ad run ${runId} — ${displayRunStatus(run.status)}`;
|
|
2049
2061
|
const lines = [
|
|
2050
2062
|
headline,
|
|
2051
2063
|
...(carryingOn(run) ? [CARRYING_ON_LINE] : []),
|
|
@@ -508,7 +508,9 @@ interface RunFlowOptions {
|
|
|
508
508
|
onProgressLine?: (line: string) => void;
|
|
509
509
|
onWarningLine?: (line: string) => void;
|
|
510
510
|
}
|
|
511
|
-
export declare function formatPauseNotice(pauseReason: WorkflowPauseReason | undefined, runId: string, dashboardUrl: string
|
|
511
|
+
export declare function formatPauseNotice(pauseReason: WorkflowPauseReason | undefined, runId: string, dashboardUrl: string, { workerStopped }?: {
|
|
512
|
+
workerStopped?: boolean;
|
|
513
|
+
}): string[];
|
|
512
514
|
export declare function parseRawInputFlags(occurrences: FlagOccurrence[]): Record<string, string>;
|
|
513
515
|
export declare function parseInputFlags(occurrences: FlagOccurrence[], readFile?: (path: string) => string): Record<string, string>;
|
|
514
516
|
export declare const ASSET_UPLOAD_POLICY: Record<WorkflowMediaType, {
|
|
@@ -4,7 +4,7 @@ import nodePath from "node:path";
|
|
|
4
4
|
import { apiGet, apiGetText, apiPost, apiPostDashboard, getDashboardUrl, } from "../lib/client.js";
|
|
5
5
|
import { formatApiError } from "../lib/format.js";
|
|
6
6
|
import { pollUntilDone } from "../lib/poll.js";
|
|
7
|
-
import { normalizeRunStatus, isTerminalRunStatus, storedWorkflowStatusForms, TERMINAL_RUN_STATUSES, } from "../lib/runStatus.js";
|
|
7
|
+
import { normalizeRunStatus, isTerminalRunStatus, storedWorkflowStatusForms, isWorkerStoppedPark, TERMINAL_RUN_STATUSES, } from "../lib/runStatus.js";
|
|
8
8
|
import { runVerdict } from "../lib/runVerdict.js";
|
|
9
9
|
import { runDisplayName, runHeadingWord, runTypeWord } from "../lib/runNames.js";
|
|
10
10
|
import { workflowToYaml, parseWorkflowText } from "../lib/workflowText.js";
|
|
@@ -354,9 +354,11 @@ Notes:
|
|
|
354
354
|
its own box on the canvas, sitting on a wire between two steps, so the diagram
|
|
355
355
|
shows exactly where a run will stop. A require-all collector that stalled
|
|
356
356
|
on a dead input is a "repair" park — retry it, skip the dead input, or kill the
|
|
357
|
-
run. A
|
|
358
|
-
|
|
359
|
-
|
|
357
|
+
run. A run whose worker stopped partway is also a "repair" park, with nothing
|
|
358
|
+
dead in it: retry carries it on from where it stopped and keeps every finished
|
|
359
|
+
step, and skip is refused. (#3820) A nested sub-workflow waiting on inputs is a
|
|
360
|
+
"slots" park — answer it with repeatable --slot key=value flags (run "answer"
|
|
361
|
+
with no --slot to list the slot ids it wants). The "gate" verbs retired in 2.0 along with the Gate node — the
|
|
360
362
|
command now prints a pointer at "checkpoint" and exits 1.
|
|
361
363
|
`.trim();
|
|
362
364
|
export function formatRulesLine(provenance) {
|
|
@@ -567,7 +569,7 @@ function gateParkedNodeId(status, pauseReason, pausedNodeId) {
|
|
|
567
569
|
}
|
|
568
570
|
const RETIRED_GATE_VERB_POINTER = "The Gate node retired in 2.0 — runs now pause at a Checkpoint box on the canvas. " +
|
|
569
571
|
"Use: exodus workflow checkpoint <runId> [approve|edit|retry|cancel]";
|
|
570
|
-
export function formatPauseNotice(pauseReason, runId, dashboardUrl) {
|
|
572
|
+
export function formatPauseNotice(pauseReason, runId, dashboardUrl, { workerStopped = false } = {}) {
|
|
571
573
|
if (!pauseReason) {
|
|
572
574
|
return [
|
|
573
575
|
" ⏸ paused at the cost gate — approve or edit the storyboard in the web app to continue.",
|
|
@@ -591,6 +593,13 @@ export function formatPauseNotice(pauseReason, runId, dashboardUrl) {
|
|
|
591
593
|
" Then run the workflow again.",
|
|
592
594
|
];
|
|
593
595
|
}
|
|
596
|
+
if (pauseReason === "repair" && workerStopped) {
|
|
597
|
+
return [
|
|
598
|
+
" ⏸ the worker stopped partway — retry carries on from where it stopped, finished steps are kept.",
|
|
599
|
+
` Resolve here: exodus workflow repair ${runId} retry|kill`,
|
|
600
|
+
` Or in the app: ${dashboardUrl}${RUN_PAGE_PREFIX}${runId}`,
|
|
601
|
+
];
|
|
602
|
+
}
|
|
594
603
|
const resolveVerb = pauseReason === "repair"
|
|
595
604
|
? `exodus workflow repair ${runId} retry|skip|kill`
|
|
596
605
|
: `exodus workflow answer ${runId} --slot key=value`;
|
|
@@ -2121,7 +2130,12 @@ async function waitForRun(runId, opts, deps) {
|
|
|
2121
2130
|
pausedNotified = true;
|
|
2122
2131
|
const dashboardUrl = deps.dashboardUrl ?? getDashboardUrl();
|
|
2123
2132
|
const pauseReason = raw["pauseReason"];
|
|
2124
|
-
|
|
2133
|
+
const workerStopped = isWorkerStoppedPark({
|
|
2134
|
+
status: raw["status"],
|
|
2135
|
+
pauseReason,
|
|
2136
|
+
error: raw["error"],
|
|
2137
|
+
});
|
|
2138
|
+
for (const line of formatPauseNotice(pauseReason, runId, dashboardUrl, { workerStopped })) {
|
|
2125
2139
|
opts.onProgressLine(line);
|
|
2126
2140
|
}
|
|
2127
2141
|
}
|
|
@@ -2996,6 +3010,10 @@ export async function repairFlow(runId, action, opts, deps) {
|
|
|
2996
3010
|
const pf = await preflightPark(runId, "repair", verb, opts.json, deps);
|
|
2997
3011
|
if (!pf.ok)
|
|
2998
3012
|
return pf.result;
|
|
3013
|
+
if (action === "skip" && isWorkerStoppedPark(pf.run)) {
|
|
3014
|
+
return errLine(`Run ${runId} has nothing to skip — its worker stopped partway. ` +
|
|
3015
|
+
`Carry on from where it stopped (finished steps are kept): exodus workflow repair ${runId} retry`, opts.json);
|
|
3016
|
+
}
|
|
2999
3017
|
if (action === "kill") {
|
|
3000
3018
|
const res = await deps.post(CANCEL_PATH, { runId });
|
|
3001
3019
|
if (!res.ok)
|
package/dist/lib/runStatus.d.ts
CHANGED
|
@@ -20,3 +20,9 @@ export declare function workflowRunPresentation(rawStatus: string | null | undef
|
|
|
20
20
|
tone: RunStatusTone;
|
|
21
21
|
detail?: string;
|
|
22
22
|
};
|
|
23
|
+
export declare const WORKER_STOPPED_PARK_ERROR = "timeout-zombie-sweep: worker stopped heartbeating; finished steps are kept";
|
|
24
|
+
export declare function isWorkerStoppedPark(run: {
|
|
25
|
+
status?: string | null;
|
|
26
|
+
pauseReason?: string | null;
|
|
27
|
+
error?: string | null;
|
|
28
|
+
}): boolean;
|
package/dist/lib/runStatus.js
CHANGED
|
@@ -137,3 +137,9 @@ export function workflowRunPresentation(rawStatus, pauseReason) {
|
|
|
137
137
|
detail,
|
|
138
138
|
};
|
|
139
139
|
}
|
|
140
|
+
export const WORKER_STOPPED_PARK_ERROR = "timeout-zombie-sweep: worker stopped heartbeating; finished steps are kept";
|
|
141
|
+
export function isWorkerStoppedPark(run) {
|
|
142
|
+
return (normalizeRunStatus(run.status) === "awaiting-approval" &&
|
|
143
|
+
run.pauseReason === "repair" &&
|
|
144
|
+
run.error === WORKER_STOPPED_PARK_ERROR);
|
|
145
|
+
}
|