@aicopycoders/exodus 2026.9.2000-beta.5 → 2026.9.2000-beta.6
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
|
@@ -8,10 +8,31 @@ export interface ClipWord {
|
|
|
8
8
|
s: number;
|
|
9
9
|
e: number;
|
|
10
10
|
}
|
|
11
|
+
export type ClipQcTakeNeighbours = {
|
|
12
|
+
state: "not-applicable";
|
|
13
|
+
} | {
|
|
14
|
+
state: "not-attached";
|
|
15
|
+
} | {
|
|
16
|
+
state: "none-accepted";
|
|
17
|
+
} | {
|
|
18
|
+
state: "attached";
|
|
19
|
+
scenes: number[];
|
|
20
|
+
};
|
|
21
|
+
export interface ClipQcTake {
|
|
22
|
+
kind: "take" | "soft-retry";
|
|
23
|
+
failCodes: string[];
|
|
24
|
+
warnCodes: string[];
|
|
25
|
+
neighbours: ClipQcTakeNeighbours;
|
|
26
|
+
judgeWording?: {
|
|
27
|
+
code: string;
|
|
28
|
+
wording: string;
|
|
29
|
+
}[];
|
|
30
|
+
}
|
|
11
31
|
export interface ClipQc {
|
|
12
32
|
verdict: "pass" | "fail";
|
|
13
33
|
attempts: number;
|
|
14
34
|
neighbours?: number[];
|
|
35
|
+
takes?: ClipQcTake[];
|
|
15
36
|
}
|
|
16
37
|
export interface ClipFinding {
|
|
17
38
|
check: string;
|
|
@@ -21,6 +42,9 @@ export interface ClipFinding {
|
|
|
21
42
|
judgeDetail?: string;
|
|
22
43
|
judgeSeverity?: "fail" | "warn";
|
|
23
44
|
}
|
|
45
|
+
export declare function qcWithoutJudgeWording(qc: ClipQc): ClipQc;
|
|
46
|
+
export declare const NO_TAKE_HISTORY_LINE = "no history recorded for this clip";
|
|
47
|
+
export declare function renderQcTakeHistory(takes: ClipQcTake[] | undefined): string[];
|
|
24
48
|
export type ArtifactSubset = {
|
|
25
49
|
type: "storyboard";
|
|
26
50
|
storyboard?: unknown;
|
|
@@ -277,7 +301,7 @@ export interface VideoManifest {
|
|
|
277
301
|
failed: PullFailure[];
|
|
278
302
|
provenance?: RunProvenance;
|
|
279
303
|
}
|
|
280
|
-
export declare const CAST_LEDGER_BASE
|
|
304
|
+
export declare const CAST_LEDGER_BASE: number;
|
|
281
305
|
export interface PullPlan {
|
|
282
306
|
downloads: PullDownload[];
|
|
283
307
|
texts: PullTextFile[];
|
package/dist/commands/video.js
CHANGED
|
@@ -6,6 +6,7 @@ import { displayRunStatus, formatApiError } from "../lib/format.js";
|
|
|
6
6
|
import { missingRouteLine } from "../lib/route-support.js";
|
|
7
7
|
import { hasBinary } from "../lib/preflight.js";
|
|
8
8
|
import { ASSET_UPLOAD_POLICY, pauseAheadLine, } from "./workflow.js";
|
|
9
|
+
import { HELPER_LEDGER_BASE } from "../lib/helperLedgerBase.js";
|
|
9
10
|
export const helpText = `
|
|
10
11
|
exodus video — make a video ad from a saved workflow, pull every piece, upload your cut
|
|
11
12
|
|
|
@@ -149,6 +150,40 @@ const ASSETS_PATH = "/api/v2/workflows/assets";
|
|
|
149
150
|
function withoutJudgeFields({ judgeDetail: _d, judgeSeverity: _s, ...rest }) {
|
|
150
151
|
return rest;
|
|
151
152
|
}
|
|
153
|
+
export function qcWithoutJudgeWording(qc) {
|
|
154
|
+
if (!qc.takes)
|
|
155
|
+
return qc;
|
|
156
|
+
return {
|
|
157
|
+
...qc,
|
|
158
|
+
takes: qc.takes.map(({ judgeWording: _w, ...rest }) => rest),
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
export const NO_TAKE_HISTORY_LINE = "no history recorded for this clip";
|
|
162
|
+
const TAKE_NEIGHBOUR_SENTENCE = {
|
|
163
|
+
"not-applicable": () => "never compared",
|
|
164
|
+
"not-attached": () => "no neighbours attached",
|
|
165
|
+
"none-accepted": () => "no accepted neighbours yet",
|
|
166
|
+
attached: ({ scenes }) => `compared against scene${scenes.length === 1 ? "" : "s"} ${scenes.join(", ")}`,
|
|
167
|
+
};
|
|
168
|
+
export function renderQcTakeHistory(takes) {
|
|
169
|
+
if (!takes || takes.length === 0)
|
|
170
|
+
return [NO_TAKE_HISTORY_LINE];
|
|
171
|
+
const lines = [];
|
|
172
|
+
takes.forEach((take, index) => {
|
|
173
|
+
const say = TAKE_NEIGHBOUR_SENTENCE[take.neighbours.state];
|
|
174
|
+
const parts = [
|
|
175
|
+
take.failCodes.length ? `failed ${take.failCodes.join(", ")}` : "passed",
|
|
176
|
+
...(take.warnCodes.length ? [`warned ${take.warnCodes.join(", ")}`] : []),
|
|
177
|
+
say(take.neighbours),
|
|
178
|
+
];
|
|
179
|
+
const bonus = take.kind === "soft-retry" ? " (bonus take)" : "";
|
|
180
|
+
lines.push(`take ${index + 1}${bonus}: ${parts.join("; ")}`);
|
|
181
|
+
for (const { code, wording } of take.judgeWording ?? []) {
|
|
182
|
+
lines.push(` checker said (${code}): ${wording}`);
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
return lines;
|
|
186
|
+
}
|
|
152
187
|
export function asVideoRun(data) {
|
|
153
188
|
const run = (data ?? {});
|
|
154
189
|
return { ...run, nodes: Array.isArray(run.nodes) ? run.nodes : [] };
|
|
@@ -363,6 +398,13 @@ export function stopLines(stop, runId, runUrl) {
|
|
|
363
398
|
}
|
|
364
399
|
if (stop.at === "failed") {
|
|
365
400
|
if (stop.repair) {
|
|
401
|
+
if (!stop.step) {
|
|
402
|
+
return [
|
|
403
|
+
"This run stopped at a step that can't be picked back up from here.",
|
|
404
|
+
"Start a fresh run to get this ad made.",
|
|
405
|
+
`Open the run: ${runUrl}`,
|
|
406
|
+
];
|
|
407
|
+
}
|
|
366
408
|
return [
|
|
367
409
|
`${stepName(stop.step)} failed${stop.error ? `: ${stop.error}` : "."}`,
|
|
368
410
|
`Try that step again: exodus workflow repair ${runId} retry`,
|
|
@@ -412,7 +454,10 @@ export function planFailureLines(node, runId) {
|
|
|
412
454
|
}
|
|
413
455
|
return lines;
|
|
414
456
|
}
|
|
415
|
-
export const CAST_LEDGER_BASE =
|
|
457
|
+
export const CAST_LEDGER_BASE = HELPER_LEDGER_BASE + 10000;
|
|
458
|
+
function isPullSceneIndex(sceneIndex) {
|
|
459
|
+
return sceneIndex >= 0 && sceneIndex < HELPER_LEDGER_BASE;
|
|
460
|
+
}
|
|
416
461
|
const FALLBACK_EXT = {
|
|
417
462
|
image: "png",
|
|
418
463
|
video: "mp4",
|
|
@@ -429,6 +474,10 @@ function extFor(url, family) {
|
|
|
429
474
|
export function scenePrefix(sceneIndex) {
|
|
430
475
|
return `scene-${String(sceneIndex).padStart(2, "0")}`;
|
|
431
476
|
}
|
|
477
|
+
function clipQcOf(item) {
|
|
478
|
+
const artifact = item?.artifact;
|
|
479
|
+
return artifact && artifact.type === "video" ? artifact.qc?.takes : undefined;
|
|
480
|
+
}
|
|
432
481
|
function outputsOfNodeKind(run, kind) {
|
|
433
482
|
return run.nodes.filter((n) => n.kind === kind).flatMap((n) => n.outputs ?? []);
|
|
434
483
|
}
|
|
@@ -611,6 +660,8 @@ export function planPull(run, items, opts) {
|
|
|
611
660
|
for (const frame of artifact.frames ?? []) {
|
|
612
661
|
if (!frame.imageUrl)
|
|
613
662
|
continue;
|
|
663
|
+
if (!isPullSceneIndex(frame.sceneIndex))
|
|
664
|
+
continue;
|
|
614
665
|
keyframeByScene.set(frame.sceneIndex, keyframeDownload(frame.sceneIndex, frame.imageUrl));
|
|
615
666
|
}
|
|
616
667
|
}
|
|
@@ -628,7 +679,7 @@ export function planPull(run, items, opts) {
|
|
|
628
679
|
};
|
|
629
680
|
continue;
|
|
630
681
|
}
|
|
631
|
-
if (typeof artifact.sceneIndex !== "number" || artifact.sceneIndex
|
|
682
|
+
if (typeof artifact.sceneIndex !== "number" || !isPullSceneIndex(artifact.sceneIndex))
|
|
632
683
|
continue;
|
|
633
684
|
voiceByScene.set(artifact.sceneIndex, {
|
|
634
685
|
download: {
|
|
@@ -669,6 +720,8 @@ export function planPull(run, items, opts) {
|
|
|
669
720
|
}
|
|
670
721
|
if (artifact.type !== "video" || typeof artifact.sceneIndex !== "number")
|
|
671
722
|
continue;
|
|
723
|
+
if (!isPullSceneIndex(artifact.sceneIndex))
|
|
724
|
+
continue;
|
|
672
725
|
const clip = clipFromArtifact(artifact.sceneIndex, artifact);
|
|
673
726
|
if (!clip)
|
|
674
727
|
continue;
|
|
@@ -678,6 +731,8 @@ export function planPull(run, items, opts) {
|
|
|
678
731
|
const frameItemByScene = new Map();
|
|
679
732
|
const sceneFrameNodeIds = new Set(run.nodes.filter((n) => n.kind === "scene-frames").map((n) => n.nodeId));
|
|
680
733
|
for (const item of items) {
|
|
734
|
+
if (!isPullSceneIndex(item.sceneIndex))
|
|
735
|
+
continue;
|
|
681
736
|
if (item.itemKind === "clip")
|
|
682
737
|
clipItemByScene.set(item.sceneIndex, item);
|
|
683
738
|
if (item.itemKind === "frame" && sceneFrameNodeIds.has(item.nodeId)) {
|
|
@@ -709,7 +764,7 @@ export function planPull(run, items, opts) {
|
|
|
709
764
|
...frameItemByScene.keys(),
|
|
710
765
|
]),
|
|
711
766
|
]
|
|
712
|
-
.filter((sceneIndex) => sceneIndex
|
|
767
|
+
.filter((sceneIndex) => isPullSceneIndex(sceneIndex))
|
|
713
768
|
.sort((a, b) => a - b);
|
|
714
769
|
const scenes = sceneIndexes.map((sceneIndex) => {
|
|
715
770
|
const clip = clipByScene.get(sceneIndex);
|
|
@@ -744,7 +799,7 @@ export function planPull(run, items, opts) {
|
|
|
744
799
|
: "this-file",
|
|
745
800
|
voice: voice?.download.file ?? null,
|
|
746
801
|
keyframe: keyframeByScene.get(sceneIndex)?.file ?? null,
|
|
747
|
-
qc: clip?.qc
|
|
802
|
+
qc: clip?.qc ? qcWithoutJudgeWording(clip.qc) : null,
|
|
748
803
|
revoiced: clip ? clip.revoiced : null,
|
|
749
804
|
speechTrimmed: clip ? clip.speechTrimmed : null,
|
|
750
805
|
rawStorageId: clip ? clip.rawStorageId : null,
|
|
@@ -1090,6 +1145,11 @@ export async function statusFlow(runId, json, deps) {
|
|
|
1090
1145
|
lines.push(`${String(sceneIndex).padEnd(5)} ${itemWord(row.clip).padEnd(8)} ${itemWord(row.voiceover).padEnd(8)} ${itemWord(row.frame)}`);
|
|
1091
1146
|
if (row.clip?.lastRedo)
|
|
1092
1147
|
lines.push(` clip: ${row.clip.lastRedo.label}`);
|
|
1148
|
+
if (row.clip?.lastRedo || row.clip?.flagged) {
|
|
1149
|
+
for (const line of renderQcTakeHistory(clipQcOf(row.clip))) {
|
|
1150
|
+
lines.push(` ${line}`);
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1093
1153
|
if (row.voiceover?.lastRedo)
|
|
1094
1154
|
lines.push(` voice: ${row.voiceover.lastRedo.label}`);
|
|
1095
1155
|
if (row.frame?.lastRedo)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const HELPER_LEDGER_BASE = 900000;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const HELPER_LEDGER_BASE = 900000;
|