@aicopycoders/exodus 2026.8.1100 → 2026.8.1200
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/workflow.js +29 -11
- package/package.json +1 -1
|
@@ -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, runStatusLabel, storedWorkflowStatusForms, TERMINAL_RUN_STATUSES, } from "../lib/runStatus.js";
|
|
7
|
+
import { normalizeRunStatus, runStatusLabel, storedWorkflowStatusForms, workflowRunPresentation, RUN_STATUS_LABELS, TERMINAL_RUN_STATUSES, } from "../lib/runStatus.js";
|
|
8
8
|
import { workflowToYaml, parseWorkflowText } from "../lib/workflowText.js";
|
|
9
9
|
import { missingRouteLine } from "../lib/route-support.js";
|
|
10
10
|
import { getChannel } from "../lib/channel.js";
|
|
@@ -429,6 +429,17 @@ function gateParkedNodeId(status, pauseReason, pausedNodeId) {
|
|
|
429
429
|
}
|
|
430
430
|
return undefined;
|
|
431
431
|
}
|
|
432
|
+
function runVerdict(run) {
|
|
433
|
+
const presented = workflowRunPresentation(run.status, run.pauseReason);
|
|
434
|
+
if ((presented.status === "succeeded" || presented.status === "succeeded-with-warnings") &&
|
|
435
|
+
(run.counts?.failed ?? 0) > 0 &&
|
|
436
|
+
run.deliveries !== undefined &&
|
|
437
|
+
run.deliveries.length > 0 &&
|
|
438
|
+
!run.deliveries.some((d) => d.status === "delivered")) {
|
|
439
|
+
return `${RUN_STATUS_LABELS.failed} — nothing delivered`;
|
|
440
|
+
}
|
|
441
|
+
return presented.detail ? `${presented.label} — ${presented.detail}` : presented.label;
|
|
442
|
+
}
|
|
432
443
|
const RETIRED_GATE_VERB_POINTER = "The Gate node retired in 2.0 — runs now pause at a Checkpoint box on the canvas. " +
|
|
433
444
|
"Use: exodus workflow checkpoint <runId> [approve|edit|retry|cancel]";
|
|
434
445
|
export function formatPauseNotice(pauseReason, runId, dashboardUrl) {
|
|
@@ -948,7 +959,7 @@ export function formatWorkflowList(workflows) {
|
|
|
948
959
|
export function formatRecentRuns(runs) {
|
|
949
960
|
if (runs.length === 0)
|
|
950
961
|
return "No workflow runs found for the active brand.";
|
|
951
|
-
return table(["workflow", "status", "created", "id"], runs.map((r) => [r.workflowName,
|
|
962
|
+
return table(["workflow", "status", "created", "id"], runs.map((r) => [r.workflowName, runVerdict(r), dateOnly(r.createdAt), r._id]));
|
|
952
963
|
}
|
|
953
964
|
export function formatWorkflowVersions(versions) {
|
|
954
965
|
if (versions.length === 0) {
|
|
@@ -1026,7 +1037,7 @@ export function formatWorkflowRun(run) {
|
|
|
1026
1037
|
lines.push(`workflowId: ${run.workflowId}`);
|
|
1027
1038
|
if (run.triggerRunId)
|
|
1028
1039
|
lines.push(`triggerRunId: ${run.triggerRunId}`);
|
|
1029
|
-
lines.push(`verdict: ${
|
|
1040
|
+
lines.push(`verdict: ${runVerdict(run)}${counts ? ` (${counts})` : ""}`);
|
|
1030
1041
|
if (run.isTerminal)
|
|
1031
1042
|
lines.push("terminal: yes");
|
|
1032
1043
|
if (run.error)
|
|
@@ -1051,8 +1062,9 @@ export function formatWorkflowRun(run) {
|
|
|
1051
1062
|
if (run.deliveries && run.deliveries.length > 0) {
|
|
1052
1063
|
lines.push("");
|
|
1053
1064
|
lines.push(`Deliveries (${run.deliveries.length}):`);
|
|
1054
|
-
for (const delivery of run.deliveries)
|
|
1055
|
-
lines.push(...deliveryLines(delivery));
|
|
1065
|
+
for (const delivery of run.deliveries) {
|
|
1066
|
+
lines.push(...deliveryLines(delivery, parkedNodeId));
|
|
1067
|
+
}
|
|
1056
1068
|
}
|
|
1057
1069
|
if (run.outputs && run.outputs.length > 0) {
|
|
1058
1070
|
lines.push("");
|
|
@@ -1070,9 +1082,10 @@ export function formatWorkflowRun(run) {
|
|
|
1070
1082
|
}
|
|
1071
1083
|
return lines.join("\n");
|
|
1072
1084
|
}
|
|
1085
|
+
const NOT_YET_APPROVED = "awaiting approval, not yet approved";
|
|
1073
1086
|
function runOutputLines(output, awaitingReview = false) {
|
|
1074
1087
|
const slug = output.botSlug ? ` (${output.botSlug})` : "";
|
|
1075
|
-
const review = awaitingReview ?
|
|
1088
|
+
const review = awaitingReview ? ` — ${NOT_YET_APPROVED}` : "";
|
|
1076
1089
|
if (output.type === "image") {
|
|
1077
1090
|
return [` ${output.label} [image]${slug}: ${output.imageUrl ?? output.imageId ?? "(no url)"}${review}`];
|
|
1078
1091
|
}
|
|
@@ -1102,14 +1115,19 @@ function runOutputLines(output, awaitingReview = false) {
|
|
|
1102
1115
|
const note = normalized.length > 400 ? "\n (truncated — use --json for the full text)" : "";
|
|
1103
1116
|
return [` ${output.label} [text]${slug}${review}:`, ` ${body}${note}`];
|
|
1104
1117
|
}
|
|
1105
|
-
function deliveryLines(delivery) {
|
|
1106
|
-
const
|
|
1107
|
-
|
|
1108
|
-
|
|
1118
|
+
function deliveryLines(delivery, parkedNodeId) {
|
|
1119
|
+
const heldArtifact = (a) => parkedNodeId !== undefined && a.nodeId === parkedNodeId;
|
|
1120
|
+
const held = delivery.status === "delivered" && delivery.artifacts.some(heldArtifact);
|
|
1121
|
+
const status = held
|
|
1122
|
+
? `held — ${NOT_YET_APPROVED}`
|
|
1123
|
+
: delivery.status === "unfulfilled" && delivery.error
|
|
1124
|
+
? `unfulfilled — ${delivery.error}`
|
|
1125
|
+
: delivery.status;
|
|
1109
1126
|
const lines = [` ${delivery.label} (${delivery.key}) · ${delivery.type} · ${status}`];
|
|
1110
1127
|
for (const artifact of delivery.artifacts) {
|
|
1111
|
-
for (const line of runOutputLines(artifact))
|
|
1128
|
+
for (const line of runOutputLines(artifact, heldArtifact(artifact))) {
|
|
1112
1129
|
lines.push(` ${line}`);
|
|
1130
|
+
}
|
|
1113
1131
|
}
|
|
1114
1132
|
return lines;
|
|
1115
1133
|
}
|