@assethub/cli 0.1.31 → 0.1.33

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.
@@ -1,4 +1,5 @@
1
- // Keep only the conversation from a Claude Code transcript before it is saved
1
+ // Keep only the conversation from a Claude Code transcript (or a Codex rollout,
2
+ // converted to the same shape) before it is saved
2
3
  // or uploaded: the artist's prompts, the agent's replies, its tool calls and
3
4
  // their results, and compaction summaries. Everything else Claude Code writes
4
5
  // to the file (skill, tool and agent listings, the system prompt, hook
@@ -85,9 +86,118 @@ export const trimTranscriptEntry = (entry) => {
85
86
  },
86
87
  };
87
88
  };
89
+ /** Top-level record types of a Codex rollout (`~/.codex/sessions/.../rollout-*.jsonl`). */
90
+ const CODEX_LINE_TYPES = new Set(['session_meta', 'response_item', 'event_msg', 'turn_context', 'compacted']);
91
+ // Codex sends its context as user messages: AGENTS.md, and tagged blocks such
92
+ // as <environment_context> or <user_instructions>. They are not the artist's words.
93
+ const CODEX_CONTEXT_BLOCK = /<([A-Za-z][\w-]*(?:context|instructions|plugins))(?:\s[^>]*)?>[\s\S]*?<\/\1>\s*/g;
94
+ const codexUserText = (text) => /^\s*# AGENTS\.md instructions/.test(text) ? '' : cleanText(text.replace(CODEX_CONTEXT_BLOCK, ''));
95
+ const codexText = (content, blockType, clean) => (Array.isArray(content) ? content : [])
96
+ .map(block => (isObject(block) && block.type === blockType && typeof block.text === 'string' ? clean(block.text) : ''))
97
+ .filter(text => text.trim())
98
+ .join('\n');
99
+ // An exec result is JSON text with timing and token bookkeeping around the
100
+ // command's output; only the output is conversation.
101
+ const codexOutputText = (text) => {
102
+ if (text.trimStart().startsWith('{')) {
103
+ try {
104
+ const parsed = JSON.parse(text);
105
+ if (isObject(parsed) && typeof parsed.output === 'string')
106
+ return parsed.output;
107
+ }
108
+ catch {
109
+ // plain text that happens to start with a brace
110
+ }
111
+ }
112
+ return text;
113
+ };
114
+ /** Tool output: a string, `{output}`, or a list of `{type, text}` items (images are dropped). */
115
+ const codexToolOutput = (output) => {
116
+ if (typeof output === 'string')
117
+ return cleanText(codexOutputText(output));
118
+ if (Array.isArray(output))
119
+ return cleanText(output
120
+ .map(item => (isObject(item) && typeof item.text === 'string' ? codexOutputText(item.text) : ''))
121
+ .filter(Boolean)
122
+ .join('\n'));
123
+ if (isObject(output)) {
124
+ for (const key of ['output', 'content'])
125
+ if (typeof output[key] === 'string')
126
+ return cleanText(output[key]);
127
+ }
128
+ return output === undefined ? '' : JSON.stringify(output);
129
+ };
130
+ const codexArguments = (value) => {
131
+ if (typeof value !== 'string')
132
+ return value ?? {};
133
+ try {
134
+ return JSON.parse(value);
135
+ }
136
+ catch {
137
+ return { arguments: value };
138
+ }
139
+ };
140
+ const codexMessage = (type, timestamp, content) => ({
141
+ type,
142
+ ...(typeof timestamp === 'string' ? { timestamp } : {}),
143
+ message: { role: type, content },
144
+ });
145
+ /**
146
+ * One Codex rollout record as a conversation entry in the same shape as a
147
+ * trimmed Claude Code transcript, or undefined to drop it. Kept: the artist's
148
+ * prompts, the agent's replies, its tool calls and their output, and compaction
149
+ * summaries. Dropped: session metadata (base instructions, git, cwd), developer
150
+ * and context messages, reasoning, turn settings and the event stream, which
151
+ * repeats the messages.
152
+ */
153
+ export const codexEntry = (entry) => {
154
+ if (!isObject(entry) || !isObject(entry.payload))
155
+ return undefined;
156
+ const { payload, timestamp } = entry;
157
+ if (entry.type === 'compacted')
158
+ return typeof payload.message === 'string' && payload.message.trim() ? { type: 'summary', summary: payload.message } : undefined;
159
+ if (entry.type !== 'response_item')
160
+ return undefined;
161
+ switch (payload.type) {
162
+ case 'message': {
163
+ if (payload.role === 'user') {
164
+ const text = codexText(payload.content, 'input_text', codexUserText).trim();
165
+ return text ? codexMessage('user', timestamp, text) : undefined;
166
+ }
167
+ if (payload.role !== 'assistant')
168
+ return undefined;
169
+ const text = codexText(payload.content, 'output_text', cleanText);
170
+ return text.trim() ? codexMessage('assistant', timestamp, [{ type: 'text', text }]) : undefined;
171
+ }
172
+ case 'function_call':
173
+ case 'custom_tool_call':
174
+ case 'local_shell_call': {
175
+ const id = typeof payload.call_id === 'string' ? payload.call_id : payload.id;
176
+ if (typeof id !== 'string')
177
+ return undefined;
178
+ const name = typeof payload.name === 'string' ? payload.name : payload.type === 'local_shell_call' ? 'shell' : 'unknown';
179
+ const input = payload.type === 'function_call'
180
+ ? codexArguments(payload.arguments)
181
+ : payload.type === 'custom_tool_call'
182
+ ? { input: payload.input }
183
+ : (payload.action ?? {});
184
+ return codexMessage('assistant', timestamp, [{ type: 'tool_use', id, name, input }]);
185
+ }
186
+ case 'function_call_output':
187
+ case 'custom_tool_call_output': {
188
+ if (typeof payload.call_id !== 'string')
189
+ return undefined;
190
+ return codexMessage('user', timestamp, [{ type: 'tool_result', tool_use_id: payload.call_id, content: codexToolOutput(payload.output) }]);
191
+ }
192
+ default:
193
+ // reasoning, web search and anything else that is not conversation
194
+ return undefined;
195
+ }
196
+ };
88
197
  /**
89
- * Trim a JSONL transcript. A file that is not a Claude Code transcript (for
90
- * example a Codex rollout saved by hand) is returned unchanged.
198
+ * Trim a JSONL transcript: a Claude Code transcript, or a Codex rollout turned
199
+ * into the same conversation shape. A file in any other format is returned
200
+ * unchanged.
91
201
  */
92
202
  export const trimTranscript = (raw) => {
93
203
  const entries = raw
@@ -101,8 +211,10 @@ export const trimTranscript = (raw) => {
101
211
  return undefined;
102
212
  }
103
213
  });
104
- if (!entries.some(entry => isObject(entry) && CLAUDE_LINE_TYPES.has(String(entry.type))))
214
+ const isClaude = entries.some(entry => isObject(entry) && CLAUDE_LINE_TYPES.has(String(entry.type)));
215
+ const isCodex = !isClaude && entries.some(entry => isObject(entry) && CODEX_LINE_TYPES.has(String(entry.type)) && isObject(entry.payload));
216
+ if (!isClaude && !isCodex)
105
217
  return raw;
106
- const kept = entries.map(trimTranscriptEntry).filter((entry) => entry !== undefined);
218
+ const kept = entries.map(isCodex ? codexEntry : trimTranscriptEntry).filter((entry) => entry !== undefined);
107
219
  return kept.map(entry => `${JSON.stringify(entry)}\n`).join('');
108
220
  };
@@ -15,7 +15,7 @@ export type SessionImage = {
15
15
  export type SessionMeta = {
16
16
  sessionId: string;
17
17
  cwd: string;
18
- client: 'claude';
18
+ client: HookClient;
19
19
  lastEvent: string;
20
20
  savedAt: string;
21
21
  canvasId?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/hooks/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,OAAO,CAAA;AAE3C,MAAM,MAAM,SAAS,GAAG;IACtB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB,CAAA;AAED,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,gBAAgB,GAAG,UAAU,CAAA;AAEnE,MAAM,MAAM,YAAY,GAAG;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,CAAA;AAEvF,MAAM,MAAM,WAAW,GAAG;IACxB,SAAS,EAAE,MAAM,CAAA;IACjB,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,QAAQ,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,aAAa,CAAA;IACrB,MAAM,EAAE,YAAY,EAAE,CAAA;IACtB,+EAA+E;IAC/E,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,gGAAgG;IAChG,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,kEAAkE;IAClE,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,mEAAmE;IACnE,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,uFAAuF;IACvF,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,iEAAiE;IACjE,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,iFAAiF;IACjF,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,8FAA8F;IAC9F,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,EAAE,EAAE,OAAO,CAAA;IACX,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,sFAAsF;IACtF,SAAS,CAAC,EAAE,IAAI,CAAA;CACjB,CAAA"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/hooks/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,OAAO,CAAA;AAE3C,MAAM,MAAM,SAAS,GAAG;IACtB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB,CAAA;AAED,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,gBAAgB,GAAG,UAAU,CAAA;AAEnE,MAAM,MAAM,YAAY,GAAG;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,CAAA;AAEvF,MAAM,MAAM,WAAW,GAAG;IACxB,SAAS,EAAE,MAAM,CAAA;IACjB,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,UAAU,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,aAAa,CAAA;IACrB,MAAM,EAAE,YAAY,EAAE,CAAA;IACtB,+EAA+E;IAC/E,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,gGAAgG;IAChG,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,kEAAkE;IAClE,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,mEAAmE;IACnE,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,uFAAuF;IACvF,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,iEAAiE;IACjE,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,iFAAiF;IACjF,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,8FAA8F;IAC9F,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,EAAE,EAAE,OAAO,CAAA;IACX,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,sFAAsF;IACtF,SAAS,CAAC,EAAE,IAAI,CAAA;CACjB,CAAA"}
@@ -177,7 +177,7 @@ const uploadSessionUnlocked = async (sessionDir, options) => {
177
177
  graphId: sessionGraphId(basename(sessionDir)),
178
178
  rev,
179
179
  description: `Agent session ${meta.sessionId}`,
180
- tags: ['session', 'agent:claude'],
180
+ tags: ['session', `agent:${meta.client ?? 'claude'}`],
181
181
  now: now(),
182
182
  });
183
183
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -13,7 +13,7 @@ import { downloadCanvas } from './canvasDownload.js';
13
13
  import { downloadCanvasGraphZip } from './canvasGraphDownload.js';
14
14
  import { executeNodeMeshBatch, resumeNodeMeshBatch, } from './nodeMeshBatch.js';
15
15
  import { writeCanvasComparison } from './canvasComparison.js';
16
- import { productionBatchLabels, readProductionBatch, runProductionBatch, } from './productionBatch.js';
16
+ import { productionBatchImageName, productionBatchLabels, readProductionBatch, runProductionBatch, } from './productionBatch.js';
17
17
  import { importCanvasAssetWithState } from './canvasAssetImport.js';
18
18
  import { execFile, spawn } from 'node:child_process';
19
19
  import { createHash, randomUUID } from 'node:crypto';
@@ -27,7 +27,7 @@ import { promisify } from 'node:util';
27
27
  import { AssetHubApiError, WorkspaceClientError, createWorkspaceClient, createAssetHubClient, } from '@assethub/api-client';
28
28
  import { resolveCanvasSelection, saveCanvasSelection } from './canvas.js';
29
29
  import { activeExecution, CliExecutionError, executeRecorded, hasRecordedOperation, openExecutionSession, resumeRecorded, waitForExecution, } from './execution.js';
30
- import { runProgressLine } from './runProgress.js';
30
+ import { batchReporter, runReporter } from './progressReport.js';
31
31
  import { buildRunUploadPlan, formatBytes } from './runsUpload/buildRunUpload.js';
32
32
  import { readGraphFolder } from './runsUpload/graphFolder.js';
33
33
  import { uploadRun } from './runsUpload/uploadRun.js';
@@ -2081,19 +2081,8 @@ const defaultWaitMs = (flags) => {
2081
2081
  const watchOptions = (flags) => ({
2082
2082
  intervalMs: parsePositiveIntegerFlag(flags, 'interval-ms', 5000),
2083
2083
  timeoutMs: parsePositiveIntegerFlag(flags, 'timeout-ms', defaultWaitMs(flags)),
2084
- onProgress: progressPrinter(run => `[run] ${run.runId} ${run.status}${run.progress ? ` · ${runProgressLine(run)}` : ''}`),
2084
+ onProgress: runReporter({ write: text => stderr.write(text) }),
2085
2085
  });
2086
- /** Prints a run's line only when it changed since the last poll. */
2087
- const progressPrinter = (line) => {
2088
- let last = '';
2089
- return (run) => {
2090
- const next = line(run);
2091
- if (next === last)
2092
- return;
2093
- last = next;
2094
- stderr.write(`${next}\n`);
2095
- };
2096
- };
2097
2086
  const readJsonArgument = async (value, flag) => {
2098
2087
  const text = value === '@-'
2099
2088
  ? await readStdin()
@@ -3673,10 +3662,29 @@ const commandProductionBatch = async (ctx) => {
3673
3662
  if (saved && requestedCanvasId != null && requestedCanvasId !== saved.canvasId)
3674
3663
  throw new Error(`Batch ${operationId} runs on canvas ${saved.canvasId}; drop --canvas or pass that canvas`);
3675
3664
  const session = await productionSession(ctx, 'production.analyze', saved?.canvasId ?? requestedCanvasId);
3676
- stderr.write(`[batch] ${operationId} · ${entries.length} run(s) on canvas ${session.canvas.id}. Rerun with --operation-id ${operationId} to resume.\n`);
3677
3665
  const wait = hasFlag(ctx.flags, 'wait');
3678
3666
  const concurrency = parsePositiveIntegerFlag(ctx.flags, 'concurrency', 2);
3679
- const printItem = (item) => stderr.write(`[batch] ${item.key} ${item.label} ${item.status}${item.runId ? ` ${item.runId}` : ''}${item.execution?.progress ? ` · ${runProgressLine(item.execution)}` : ''}${item.message ? ` · ${item.message}` : ''}\n`);
3667
+ const report = batchReporter({
3668
+ write: text => stderr.write(text),
3669
+ operationId,
3670
+ agent: partExtractorOptions.find(option => option.apiValue === options.agentVersion)
3671
+ ?.publicName ?? String(options.agentVersion),
3672
+ canvasId: session.canvas.id,
3673
+ ...(wait ? { concurrency } : {}),
3674
+ images: entries.map(entry => ({
3675
+ key: entry.key,
3676
+ imageIndex: entry.index,
3677
+ repeat: entry.repeat,
3678
+ name: productionBatchImageName(sources[entry.index]),
3679
+ })),
3680
+ });
3681
+ report.header();
3682
+ const printItem = (item) => report.item(item);
3683
+ // A status table every 5 minutes while waiting; runs take about an hour.
3684
+ const tableTimer = wait
3685
+ ? setInterval(() => report.table('still running'), 5 * 60_000)
3686
+ : undefined;
3687
+ tableTimer?.unref();
3680
3688
  const result = await runProductionBatch(session, {
3681
3689
  operationId,
3682
3690
  request: { sources, repeat, options, agent, parentRunId },
@@ -3714,8 +3722,10 @@ const commandProductionBatch = async (ctx) => {
3714
3722
  }
3715
3723
  : {}),
3716
3724
  });
3725
+ clearInterval(tableTimer);
3717
3726
  if (!wait)
3718
3727
  result.items.forEach(printItem);
3728
+ report.table(!wait ? 'started' : result.timedOut ? 'stopped waiting' : 'done');
3719
3729
  const downloads = [];
3720
3730
  if (hasFlag(ctx.flags, 'download')) {
3721
3731
  const outDir = getFlag(ctx.flags, 'out-dir') ?? getFlag(ctx.flags, 'out');
@@ -52,6 +52,8 @@ export type ProductionBatchSource = {
52
52
  * two images must never share one. Files that share a name get their folder.
53
53
  */
54
54
  export declare const productionBatchLabels: (sources: readonly ProductionBatchSource[]) => string[];
55
+ /** The image as the user named it, for progress lines: `image (28).png`. */
56
+ export declare const productionBatchImageName: ({ flag, value }: ProductionBatchSource) => string;
55
57
  export declare const readProductionBatch: (stateDir: string, operationId: string) => Promise<ProductionBatchState | undefined>;
56
58
  export declare const runProductionBatch: (session: Session, options: {
57
59
  operationId: string;
@@ -1 +1 @@
1
- {"version":3,"file":"productionBatch.d.ts","sourceRoot":"","sources":["../src/productionBatch.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,gBAAgB,EAGtB,MAAM,sBAAsB,CAAA;AAE7B,OAAO,EAAkB,eAAe,EAAC,MAAM,gBAAgB,CAAA;AAG/D,KAAK,OAAO,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC,CAAC,CAAC,CAAA;AAEpD,MAAM,MAAM,mBAAmB,GAAG;IAChC,GAAG,EAAE,MAAM,CAAA;IACX,8DAA8D;IAC9D,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,MAAM,CAAA;IACd,gEAAgE;IAChE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC7B,mEAAmE;IACnE,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED;;;;GAIG;AACH,KAAK,oBAAoB,GAAG;IAC1B,OAAO,EAAE,CAAC,CAAA;IACV,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,8DAA8D;IAC9D,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,mBAAmB,EAAE,CAAA;CAC7B,CAAA;AAED,MAAM,MAAM,yBAAyB,GAAG;IACtC,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,MAAM,CAAA;IACd,8BAA8B;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,OAAO,EAAE,MAAM,CAAA;IACf,8DAA8D;IAC9D,MAAM,EAAE,SAAS,GAAG,YAAY,GAAG,UAAU,GAAG,QAAQ,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAA;IACpF,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,eAAe,CAAA;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,YAAY,CAAA;IACzC,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAKD;;;GAGG;AACH,eAAO,MAAM,qBAAqB,GAChC,SAAS,SAAS,qBAAqB,EAAE,KACxC,MAAM,EAuBR,CAAA;AASD,eAAO,MAAM,mBAAmB,GAC9B,UAAU,MAAM,EAChB,aAAa,MAAM,KAClB,OAAO,CAAC,oBAAoB,GAAG,SAAS,CAwB1C,CAAA;AAOD,eAAO,MAAM,kBAAkB,GAC7B,SAAS,OAAO,EAChB,SAAS;IACP,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,EAAE,OAAO,CAAA;IAChB,0EAA0E;IAC1E,UAAU,EAAE,MAAM,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAAA;IAChD,KAAK,CAAC,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAA;IACjC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,sFAAsF;IACtF,IAAI,CAAC,EAAE;QACL,WAAW,EAAE,MAAM,CAAA;QACnB,UAAU,EAAE,MAAM,CAAA;QAClB,SAAS,EAAE,MAAM,CAAA;QACjB,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,yBAAyB,KAAK,IAAI,CAAA;KACvD,CAAA;CACF,KACA,OAAO,CAAC;IACT,gBAAgB,EAAE,MAAM,CAAA;IACxB,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,yBAAyB,EAAE,CAAA;IAClC,QAAQ,EAAE,OAAO,CAAA;CAClB,CA2JA,CAAA"}
1
+ {"version":3,"file":"productionBatch.d.ts","sourceRoot":"","sources":["../src/productionBatch.ts"],"names":[],"mappings":"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"}
@@ -7,6 +7,16 @@ import { activeExecution, executeRecorded } from './execution.js';
7
7
  import { runProgressLine } from './runProgress.js';
8
8
  const stem = (path) => basename(path, extname(path));
9
9
  const safeLabel = (label) => label.replace(/[^\w.-]+/g, '_');
10
+ /**
11
+ * A source URL's file name, or its host when the path has none. Never the whole
12
+ * URL: a signed URL carries its credentials in the query string, and this name
13
+ * is printed in progress lines and used as a download folder.
14
+ */
15
+ const urlFileName = (value, strip = name => name) => {
16
+ const url = new URL(value);
17
+ const file = basename(url.pathname);
18
+ return file ? strip(file) : url.hostname;
19
+ };
10
20
  /**
11
21
  * One distinct label per image: it names the order and the download folder, so
12
22
  * two images must never share one. Files that share a name get their folder.
@@ -15,7 +25,7 @@ export const productionBatchLabels = (sources) => {
15
25
  const base = sources.map(({ flag, value }) => flag === 'file'
16
26
  ? stem(value)
17
27
  : flag === 'source-url'
18
- ? stem(new URL(value).pathname) || value
28
+ ? urlFileName(value, stem)
19
29
  : value);
20
30
  const count = (labels, label) => labels.filter(entry => entry === label).length;
21
31
  const withFolder = base.map((label, index) => {
@@ -30,6 +40,12 @@ export const productionBatchLabels = (sources) => {
30
40
  : label)
31
41
  .map(safeLabel);
32
42
  };
43
+ /** The image as the user named it, for progress lines: `image (28).png`. */
44
+ export const productionBatchImageName = ({ flag, value }) => flag === 'file'
45
+ ? basename(value)
46
+ : flag === 'source-url'
47
+ ? urlFileName(value)
48
+ : value;
33
49
  const uuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
34
50
  const statePath = (stateDir, operationId) => {
35
51
  if (!uuid.test(operationId))
@@ -0,0 +1,42 @@
1
+ import type { CanvasExecution } from '@assethub/api-client';
2
+ import type { ProductionBatchItemResult } from './productionBatch.js';
3
+ type Clock = () => Date;
4
+ type Write = (text: string) => void;
5
+ /** Where the run is: the summary with `Step 3 of 4` shortened to `3/4`. */
6
+ export declare const stepText: (execution: CanvasExecution) => string;
7
+ /**
8
+ * Why a run stopped, in plain words. The backend sends V4 findings as a
9
+ * Python-style list (`[{'code': ..., 'message': ...}]`); each becomes
10
+ * `message (code)`.
11
+ */
12
+ export declare const failureText: (execution: CanvasExecution) => string;
13
+ /** `runs watch`, `production analyze --wait` and friends: one run. */
14
+ export declare const runReporter: ({ write, now, }: {
15
+ write: Write;
16
+ now?: Clock;
17
+ }) => (execution: CanvasExecution) => void;
18
+ export type BatchImage = {
19
+ key: string;
20
+ imageIndex: number;
21
+ repeat: number;
22
+ name: string;
23
+ };
24
+ /**
25
+ * `production batch`: a header naming each image by letter (A, B, …; `A#2`
26
+ * for the second repeat), a line per real change, and a status table.
27
+ */
28
+ export declare const batchReporter: (options: {
29
+ write: Write;
30
+ now?: Clock;
31
+ operationId: string;
32
+ agent: string;
33
+ canvasId: number;
34
+ concurrency?: number;
35
+ images: BatchImage[];
36
+ }) => {
37
+ header: () => void;
38
+ item: (result: ProductionBatchItemResult) => void;
39
+ table: (title: string) => void;
40
+ };
41
+ export {};
42
+ //# sourceMappingURL=progressReport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progressReport.d.ts","sourceRoot":"","sources":["../src/progressReport.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,sBAAsB,CAAA;AAEzD,OAAO,KAAK,EAAC,yBAAyB,EAAC,MAAM,sBAAsB,CAAA;AAEnE,KAAK,KAAK,GAAG,MAAM,IAAI,CAAA;AACvB,KAAK,KAAK,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;AAqBnC,2EAA2E;AAC3E,eAAO,MAAM,QAAQ,GAAI,WAAW,eAAe,KAAG,MAGhC,CAAA;AAEtB;;;;GAIG;AACH,eAAO,MAAM,WAAW,GAAI,WAAW,eAAe,KAAG,MAMtD,CAAA;AAuFH,sEAAsE;AACtE,eAAO,MAAM,WAAW,GAAI,iBAGzB;IACD,KAAK,EAAE,KAAK,CAAA;IACZ,GAAG,CAAC,EAAE,KAAK,CAAA;CACZ,MAGS,WAAW,eAAe,SAanC,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,GAAG,EAAE,MAAM,CAAA;IACX,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,aAAa,GAAI,SAAS;IACrC,KAAK,EAAE,KAAK,CAAA;IACZ,GAAG,CAAC,EAAE,KAAK,CAAA;IACX,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,MAAM,EAAE,UAAU,EAAE,CAAA;CACrB;;mBA2CuB,yBAAyB;mBAqDzB,MAAM;CAsC7B,CAAA"}
@@ -0,0 +1,201 @@
1
+ // What `--wait` prints while runs work: one line per real change (a new step,
2
+ // another mesh ready, a part kept with an issue, the end of the run), with the
3
+ // local time, and for a batch the image's letter and file name. Part states
4
+ // that flicker (drawing, checking, redoing) never print a line on their own.
5
+ // A stopped run reports phase `done` and step 4 whatever stopped it, so where
6
+ // it stopped is the last step seen while it worked.
7
+ const stepNames = {
8
+ 1: 'Planning the parts',
9
+ 2: 'Making the base body',
10
+ 3: 'Making the parts',
11
+ 4: 'Assembling in Blender',
12
+ };
13
+ const pad2 = (value) => String(value).padStart(2, '0');
14
+ const clockTime = (date) => `${pad2(date.getHours())}:${pad2(date.getMinutes())}`;
15
+ const shortId = (id) => id.slice(0, 8);
16
+ const duration = (ms) => {
17
+ const minutes = Math.max(0, Math.round(ms / 60_000));
18
+ return minutes < 60
19
+ ? `${minutes} min`
20
+ : `${Math.floor(minutes / 60)} h ${pad2(minutes % 60)} min`;
21
+ };
22
+ /** Where the run is: the summary with `Step 3 of 4` shortened to `3/4`. */
23
+ export const stepText = (execution) => execution.progress
24
+ ? execution.progress.summary.replace(/^Step (\d+) of (\d+) · /, '$1/$2 ')
25
+ : execution.status;
26
+ /**
27
+ * Why a run stopped, in plain words. The backend sends V4 findings as a
28
+ * Python-style list (`[{'code': ..., 'message': ...}]`); each becomes
29
+ * `message (code)`.
30
+ */
31
+ export const failureText = (execution) => plainError(execution.error?.message ??
32
+ execution.progress?.outcome?.detail ??
33
+ execution.history.error ??
34
+ execution.status);
35
+ const plainError = (message, code) => {
36
+ const findings = [...message.matchAll(/\{([^{}]*)\}/g)].flatMap(([, body]) => {
37
+ const field = (name) => new RegExp(`['"]${name}['"]:\\s*['"]([^'"]*)['"]`).exec(body)?.[1];
38
+ const text = field('message');
39
+ return text
40
+ ? [`${text}${field('code') ? ` (${field('code')})` : ''}`]
41
+ : [];
42
+ });
43
+ if (message.trim().startsWith('[') && findings.length)
44
+ return findings.join('; ');
45
+ return code ? `${message} (${code})` : message;
46
+ };
47
+ const isFailure = (status) => status === 'failed' || status === 'cancelled';
48
+ const stoppedAt = (lastStep) => lastStep && stepNames[lastStep]
49
+ ? `at ${lastStep}/4 ${stepNames[lastStep]} · `
50
+ : '';
51
+ const terminalText = (execution, status, lastStep) => {
52
+ if (isFailure(status)) {
53
+ return `✗ FAILED · ${stoppedAt(lastStep)}${failureText(execution)}`;
54
+ }
55
+ if (status === 'completed')
56
+ return `✓ done · ${stepText(execution)}`;
57
+ if (status === 'needs_review')
58
+ return `⚠ needs review · ${stepText(execution)}`;
59
+ return `⚠ ${status} · ${stepText(execution)}`;
60
+ };
61
+ const isTerminal = (status) => !['queued', 'running', 'dispatched'].includes(status);
62
+ /** The step a still-working run is on, to say later where it stopped. */
63
+ const workingStep = (execution, status) => !isTerminal(status) ? execution.progress?.step : undefined;
64
+ /** Parts that became kept-with-an-issue or failed since the last report. */
65
+ const newIssues = (previous, next) => {
66
+ const before = new Map(previous?.progress?.parts.map(part => [part.label, part.state]));
67
+ return (next.progress?.parts ?? [])
68
+ .filter(part => (part.state === 'kept' || part.state === 'failed') &&
69
+ before.get(part.label) !== part.state)
70
+ .map(part => `${part.state === 'kept' ? '⚠ kept with an issue' : '✗ part needs a person'}: ${part.label}${part.note ? ` · ${part.note}` : ''}`);
71
+ };
72
+ /**
73
+ * The lines one run's new receipt adds: its step or its end when either
74
+ * changed, then any part that newly needs attention. `status` is the batch
75
+ * item's status when it differs from the receipt's; `lastStep` the last step
76
+ * seen while the run worked.
77
+ */
78
+ const changeLines = (previous, next, status = next.status, previousStatus = previous?.status, lastStep) => {
79
+ const text = isTerminal(status)
80
+ ? terminalText(next, status, lastStep)
81
+ : stepText(next);
82
+ const before = previous && previousStatus
83
+ ? isTerminal(previousStatus)
84
+ ? terminalText(previous, previousStatus)
85
+ : stepText(previous)
86
+ : undefined;
87
+ return [...(text !== before ? [text] : []), ...newIssues(previous, next)];
88
+ };
89
+ /** `runs watch`, `production analyze --wait` and friends: one run. */
90
+ export const runReporter = ({ write, now = () => new Date(), }) => {
91
+ let last;
92
+ let lastStep;
93
+ return (execution) => {
94
+ const lines = changeLines(last, execution, execution.status, last?.status, lastStep);
95
+ last = execution;
96
+ lastStep = workingStep(execution, execution.status) ?? lastStep;
97
+ for (const line of lines)
98
+ write(`${clockTime(now())} run ${shortId(execution.runId)} ${line}\n`);
99
+ };
100
+ };
101
+ /**
102
+ * `production batch`: a header naming each image by letter (A, B, …; `A#2`
103
+ * for the second repeat), a line per real change, and a status table.
104
+ */
105
+ export const batchReporter = (options) => {
106
+ const { write, images } = options;
107
+ const now = options.now ?? (() => new Date());
108
+ const repeats = images.some(image => image.repeat > 1);
109
+ const letter = (image) => `${image.imageIndex < 26 ? String.fromCharCode(65 + image.imageIndex) : image.imageIndex + 1}${repeats ? `#${image.repeat}` : ''}`;
110
+ const letterWidth = Math.max(...images.map(image => letter(image).length));
111
+ const nameWidth = Math.max(...images.map(image => image.name.length));
112
+ const who = (key) => {
113
+ const image = images.find(entry => entry.key === key);
114
+ return `${letter(image).padEnd(letterWidth)} ${image.name.padEnd(nameWidth)}`;
115
+ };
116
+ const state = new Map();
117
+ const say = (key, line) => write(`${clockTime(now())} ${who(key)} ${line}\n`);
118
+ const header = () => {
119
+ const runs = `${images.length} run${images.length === 1 ? '' : 's'}${options.concurrency ? `, ${options.concurrency} at a time` : ''}`;
120
+ write([
121
+ `Batch ${shortId(options.operationId)} · ${options.agent} · ${runs} · canvas ${options.canvasId}`,
122
+ ...images
123
+ .filter(image => !repeats || image.repeat === 1)
124
+ .map(image => ` ${String.fromCharCode(65 + image.imageIndex).padEnd(1)} ${image.name}`),
125
+ ` Resume with: --operation-id ${options.operationId}`,
126
+ '',
127
+ '',
128
+ ].join('\n'));
129
+ };
130
+ const item = (result) => {
131
+ const entry = state.get(result.key);
132
+ const previous = entry?.result;
133
+ const lines = [];
134
+ if (result.execution) {
135
+ if (!previous?.execution)
136
+ lines.push(isTerminal(result.status)
137
+ ? terminalText(result.execution, result.status)
138
+ : `started run ${shortId(result.execution.runId)} · ${stepText(result.execution)}`, ...newIssues(undefined, result.execution));
139
+ else
140
+ lines.push(...changeLines(previous.execution, result.execution, result.status, previous.status, entry?.lastStep));
141
+ }
142
+ else if (result.status === 'deferred') {
143
+ lines.push(`waiting for a free run slot · ${result.message ?? result.reason ?? ''}`);
144
+ }
145
+ else if (result.status === 'failed') {
146
+ lines.push(`✗ could not start · ${plainError(result.message ?? 'failed', result.code)}`);
147
+ }
148
+ const next = {
149
+ result,
150
+ startedAt: entry?.startedAt ??
151
+ (result.execution ? new Date(result.execution.createdAt) : undefined),
152
+ endedAt: entry?.endedAt ??
153
+ (result.execution && isTerminal(result.status) ? now() : undefined),
154
+ lastLine: entry?.lastLine,
155
+ lastStep: (result.execution && workingStep(result.execution, result.status)) ??
156
+ entry?.lastStep,
157
+ };
158
+ for (const line of lines) {
159
+ if (line === next.lastLine)
160
+ continue;
161
+ next.lastLine = line;
162
+ say(result.key, line);
163
+ }
164
+ state.set(result.key, next);
165
+ };
166
+ /** Every image's state now: printed every few minutes and at the end. */
167
+ const table = (title) => {
168
+ const rows = images.map(image => {
169
+ const entry = state.get(image.key);
170
+ const result = entry?.result;
171
+ const execution = result?.execution;
172
+ const [mark, detail] = !result
173
+ ? ['○ not started', '']
174
+ : execution
175
+ ? isFailure(result.status)
176
+ ? [
177
+ '✗ failed',
178
+ `${entry?.lastStep ? `at ${entry.lastStep}/4 · ` : ''}${failureText(execution)}`,
179
+ ]
180
+ : result.status === 'completed'
181
+ ? ['✓ done', stepText(execution)]
182
+ : isTerminal(result.status)
183
+ ? [`⚠ ${result.status.replace('_', ' ')}`, stepText(execution)]
184
+ : ['● running', stepText(execution)]
185
+ : result.status === 'deferred'
186
+ ? ['… waiting', result.message ?? result.reason ?? '']
187
+ : result.status === 'failed'
188
+ ? [
189
+ '✗ failed',
190
+ plainError(result.message ?? 'failed', result.code),
191
+ ]
192
+ : ['○ not started', ''];
193
+ const took = entry?.startedAt && !Number.isNaN(entry.startedAt.getTime())
194
+ ? ` ${duration((entry.endedAt ?? now()).getTime() - entry.startedAt.getTime())}`
195
+ : '';
196
+ return ` ${who(image.key)} ${mark.padEnd(12)}${detail}${took}`;
197
+ });
198
+ write(['', `── ${clockTime(now())} · ${title} ──`, ...rows, '', ''].join('\n'));
199
+ };
200
+ return { header, item, table };
201
+ };
@@ -53,6 +53,8 @@ type DoctorReport = {
53
53
  export type SetupDeps = {
54
54
  interactive: boolean;
55
55
  installHooks: InstallHooks;
56
+ /** Session saving is installed for this folder only. */
57
+ cwd: string;
56
58
  codexHome: string;
57
59
  now: () => Date;
58
60
  hasWorkingKey: () => Promise<boolean>;
@@ -108,6 +110,7 @@ export declare const runProcess: (file: string, args: string[]) => Promise<{
108
110
  export declare const defaultFileDeps: () => {
109
111
  platform: NodeJS.Platform;
110
112
  home: string;
113
+ cwd: string;
111
114
  codexHome: string;
112
115
  now: () => Date;
113
116
  findBinary: (name: string) => Promise<string | undefined>;
@@ -1 +1 @@
1
- {"version":3,"file":"setupCommand.d.ts","sourceRoot":"","sources":["../src/setupCommand.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"setupCommand.d.ts","sourceRoot":"","sources":["../src/setupCommand.ts"],"names":[],"mappings":"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"}