@assethub/cli 0.1.32 → 0.1.35

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,12 +1,18 @@
1
1
  import type { UploadOutcome } from './types.js';
2
2
  export declare const CODING_AGENT_SESSION_API_PREFIX = "/api/v2/coding-agent-sessions";
3
3
  export declare const UPLOAD_TIMEOUT_MS = 20000;
4
+ /** A session's upload lock older than this belongs to a crashed upload. */
5
+ export declare const UPLOAD_LOCK_STALE_MS: number;
6
+ /** How often a running upload refreshes its lock, well inside UPLOAD_LOCK_STALE_MS. */
7
+ export declare const UPLOAD_LOCK_HEARTBEAT_MS = 60000;
4
8
  export type UploadAuth = {
5
9
  apiKey: string;
6
10
  baseUrl: string;
7
11
  workspaceId?: string;
8
12
  };
9
13
  export type UploadOptions = {
14
+ /** How often a running upload refreshes its lock (tests shorten it). */
15
+ lockHeartbeatMs?: number;
10
16
  profile?: string;
11
17
  home?: string;
12
18
  env?: NodeJS.ProcessEnv;
@@ -1 +1 @@
1
- {"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../../src/hooks/upload.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAc,aAAa,EAAC,MAAM,YAAY,CAAA;AAG1D,eAAO,MAAM,+BAA+B,kCAAkC,CAAA;AAQ9E,eAAO,MAAM,iBAAiB,QAAS,CAAA;AAEvC,MAAM,MAAM,UAAU,GAAG;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAC,CAAA;AAEhF,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAA;IACvB,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;IACxB,IAAI,CAAC,EAAE,UAAU,CAAA;IACjB,GAAG,CAAC,EAAE,MAAM,IAAI,CAAA;IAChB,wEAAwE;IACxE,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAC5B,SAAS,IAAI,CAAC,aAAa,EAAE,SAAS,GAAG,MAAM,GAAG,KAAK,CAAC,KACvD,OAAO,CAAC,UAAU,GAAG,IAAI,CA2B3B,CAAA;AAED,iFAAiF;AACjF,eAAO,MAAM,YAAY,GAAI,gBAAgB,MAAM,KAAG,MACmB,CAAA;AAmBzE;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,GAC5B,MAAM,UAAU,EAChB,YAAW,OAAO,KAAyC,KAC1D,OAAO,CAAC,OAAO,CAgBjB,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,aAAa,GACxB,YAAY,MAAM,EAClB,UAAS,aAAkB,KAC1B,OAAO,CAAC,aAAa,CASvB,CAAA;AAoHD;;;;GAIG;AACH,eAAO,MAAM,aAAa,GACxB,UAAS,aAAa,GAAG;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAM,KAC/D,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,aAAa,CAAA;CAAC,EAAE,CAkBrD,CAAA"}
1
+ {"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../../src/hooks/upload.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAc,aAAa,EAAC,MAAM,YAAY,CAAA;AAG1D,eAAO,MAAM,+BAA+B,kCAAkC,CAAA;AAQ9E,eAAO,MAAM,iBAAiB,QAAS,CAAA;AACvC,2EAA2E;AAC3E,eAAO,MAAM,oBAAoB,QAAc,CAAA;AAC/C,uFAAuF;AACvF,eAAO,MAAM,wBAAwB,QAAS,CAAA;AAE9C,MAAM,MAAM,UAAU,GAAG;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAC,CAAA;AAEhF,MAAM,MAAM,aAAa,GAAG;IAC1B,wEAAwE;IACxE,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAA;IACvB,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;IACxB,IAAI,CAAC,EAAE,UAAU,CAAA;IACjB,GAAG,CAAC,EAAE,MAAM,IAAI,CAAA;IAChB,wEAAwE;IACxE,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAC5B,SAAS,IAAI,CAAC,aAAa,EAAE,SAAS,GAAG,MAAM,GAAG,KAAK,CAAC,KACvD,OAAO,CAAC,UAAU,GAAG,IAAI,CA2B3B,CAAA;AAED,iFAAiF;AACjF,eAAO,MAAM,YAAY,GAAI,gBAAgB,MAAM,KAAG,MACmB,CAAA;AAmBzE;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,GAC5B,MAAM,UAAU,EAChB,YAAW,OAAO,KAAyC,KAC1D,OAAO,CAAC,OAAO,CAgBjB,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,aAAa,GACxB,YAAY,MAAM,EAClB,UAAS,aAAkB,KAC1B,OAAO,CAAC,aAAa,CAmBvB,CAAA;AAoHD;;;;GAIG;AACH,eAAO,MAAM,aAAa,GACxB,UAAS,aAAa,GAAG;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAM,KAC/D,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,aAAa,CAAA;CAAC,EAAE,CAkBrD,CAAA"}
@@ -3,7 +3,7 @@
3
3
  // contract as `runs upload`, so the plan and transport are shared; only the
4
4
  // URL prefix and the extra `session` registration fields differ. Sessions are
5
5
  // owned by, and readable only by, the key's user.
6
- import { readFile } from 'node:fs/promises';
6
+ import { readFile, utimes } from 'node:fs/promises';
7
7
  import { basename, join } from 'node:path';
8
8
  import { buildRunUploadPlan } from '../runsUpload/buildRunUpload.js';
9
9
  import { controlRunUploadUrls } from '../runsUpload/controlEndpoints.js';
@@ -24,6 +24,10 @@ const canvasIdOf = (value) => {
24
24
  };
25
25
  const DAY_MS = 24 * 60 * 60 * 1000;
26
26
  export const UPLOAD_TIMEOUT_MS = 20_000;
27
+ /** A session's upload lock older than this belongs to a crashed upload. */
28
+ export const UPLOAD_LOCK_STALE_MS = 15 * 60_000;
29
+ /** How often a running upload refreshes its lock, well inside UPLOAD_LOCK_STALE_MS. */
30
+ export const UPLOAD_LOCK_HEARTBEAT_MS = 60_000;
27
31
  /**
28
32
  * Resolve the CLI profile's key + base URL from ~/.assethub/config.json.
29
33
  * src/index.ts's resolveAuth is module-private, so this mirrors its precedence
@@ -105,13 +109,23 @@ export const canUploadSessions = async (auth, fetchImpl = globalThis.fetch.bind(
105
109
  export const uploadSession = async (sessionDir, options = {}) => {
106
110
  if (!(await readMeta(sessionDir)))
107
111
  return { ok: false, reason: 'no-session' };
108
- const release = await acquireLock(join(sessionDir, '.upload.lock'), { waitMs: 0, staleMs: 15 * 60_000 });
112
+ const lockPath = join(sessionDir, '.upload.lock');
113
+ const release = await acquireLock(lockPath, { waitMs: 0, staleMs: UPLOAD_LOCK_STALE_MS });
109
114
  if (!release)
110
115
  return { ok: false, reason: 'upload-in-progress', throttled: true };
116
+ // A lock older than UPLOAD_LOCK_STALE_MS is taken over as a crashed upload's.
117
+ // Touching it while this upload runs keeps a long upload from looking crashed,
118
+ // so a later Stop, sweep or SessionEnd cannot start a second one beside it.
119
+ const heartbeat = setInterval(() => {
120
+ const now = new Date();
121
+ void utimes(lockPath, now, now).catch(() => { });
122
+ }, options.lockHeartbeatMs ?? UPLOAD_LOCK_HEARTBEAT_MS);
123
+ heartbeat.unref?.();
111
124
  try {
112
125
  return await uploadSessionUnlocked(sessionDir, options);
113
126
  }
114
127
  finally {
128
+ clearInterval(heartbeat);
115
129
  await release();
116
130
  }
117
131
  };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+ import { type SetupStepName } from './setupCommand.js';
2
3
  import { type InstallHooks } from './setupHooksBridge.js';
3
4
  import { type AnimationRetargetRequest, type Intervention, type RigRequest, createAssetHubClient } from '@assethub/api-client';
4
5
  import { buildRunUploadPlan } from './runsUpload/buildRunUpload.js';
@@ -23,8 +24,10 @@ type CommandContext = {
23
24
  */
24
25
  args: string[];
25
26
  };
26
- export declare const usage = "AssetHub CLI\n\nCLI and MCP are available to all AssetHub users. Workspace permissions and feature availability apply.\n\nUsage:\n assethub --version\n assethub setup [--client claude|codex|both] [--profile <name>] [--workspace <id>] [--api-key-stdin] [--base-url <url>] [--no-app-env] [--dry-run] [--yes] [--print-env] [--json]\n assethub env load [--profile <name>]\n assethub update [--check] [--dry-run] [--yes]\n assethub doctor [--mcp] [--profile <name>] [--timeout-ms <n>]\n assethub init [--agent claude-code|codex|cursor...] [--project] [--dry-run] [--base-url <url>] [--workspace <id>] [--profile <name>]\n assethub mcp tools [tool-name] [--account] [--profile <name>] [--timeout-ms <n>]\n assethub mcp config --client cursor|codex [--account] [--base-url <url>]\n assethub auth login --api-key <key> [--base-url <url>] [--profile <name>]\n assethub auth login --api-key-stdin [--base-url <url>] [--profile <name>]\n assethub auth login --access-token-stdin [--base-url <url>] [--profile <name>]\n assethub auth status [--profile <name>]\n assethub auth logout [--profile <name>]\n assethub workspace list [--query <text>] [--limit <1-100>] [--cursor <cursor>]\n assethub workspace get\n assethub workspace create --name <name> [--operation-id <uuid>]\n assethub workspace use <workspace-id>\n assethub workspace members [--workspace <id>]\n assethub workspace invite --email <email> [--role user|admin] [--resend] [--workspace <id>]\n assethub workspace set-role <user-id> --role user|admin [--workspace <id>]\n assethub workspace remove-member <user-id> [--workspace <id>]\n assethub workspace prepare|sync|analyze|verify --internal --manifest <json> --state <json>\n assethub workspace self-check --internal\n assethub workspace context put --internal --org <uuid> --actor <uuid> --canvas <id> --file <json> [--if-version <n>] [--order <uuid>]\n assethub workspace context get --internal --org <uuid> --actor <uuid> --canvas <id> [--out <json>] [--order <uuid>]\n assethub project ingest <source-dir> --out-dir <directory> [--exclude-dir <relative-path>...]\n assethub language text|vision --input-json @<json> --operation-id <uuid> [--out <json>]\n assethub canvas download --canvas <id> --out-dir <directory> [--mesh <mesh_asset_id>]\n assethub canvas nodes --canvas <id>\n assethub canvas import --canvas <id> --file <image> [--name <name>]\n assethub canvas context get --canvas <id> [--out <json>]\n assethub canvas context put --canvas <id> --file <json> [--if-version <n>]\n assethub canvas layout --canvas <id> --input-json @<json>\n assethub canvas compare --canvas <id> --source-id <asset-id> --asset-id <asset-id> --out <html>\n assethub moodboard create --input-json @<json> [--operation-id <uuid>]\n assethub moodboard list|get|update|archive [<board-id>] [--input-json @<json>]\n assethub moodboard analyze <board-id> [--revision <uuid>] [--wait]\n assethub image generate --canvas <id> --context <id> [--context-version <n>] [--context-source <key>] [--moodboard-revision <uuid>] --prompt <text> --wait\n assethub models list [--domain <domain>] [--ids-only] [--limit <n>]\n assethub models get <model-id>\n assethub files import <url> --media-type image|mesh\n assethub files upload <file> --media-type image|mesh\n assethub source create (--file <path> | --source-url <url> | --source-id <id> | --stdin | --stdin-base64 | --stdin-data-uri | --stdin-json | --source-json <json|@file|@-> | --data-uri <uri> | --clipboard) --media-type image|mesh [--file-name <name>] [--content-type <type>]\n assethub capabilities\n assethub api search [query]\n assethub api describe \"<METHOD /path>\"\n assethub api call \"<METHOD /path>\" [--path-json <json|@file>] [--query-json <json|@file>] [--input-json <json|@file|@->] [--operation-id <uuid>]\n assethub composer models\n assethub composer refine --list-modes\n assethub composer refine --from-run <run-id> --instruction <text> [--mode standard|thorough|placement|workshop|blender|codex] [--effort light|standard|thorough] [--max-rounds <n>] [--agent-model <provider:id|unambiguous-id>] [--transforms-json <json|@file>] [--wait] [--download --out-dir <dir>]\n assethub composer refine --input-json <json|@file> [--canvas <id>] [--operation-id <uuid>] [--wait] [--download --out-dir <dir>]\n assethub composer refine --from-run <run-id> --skill-assembly [--reasoning low|medium|high] [--agent-model <agents-api model>] [--wait]\n assethub composer run --part <mesh-asset-id>[=<part-image-id>] [--part <mesh-asset-id>[=<part-image-id>]...] --reference <image-asset-id> [--model <id>] [--agent-model <provider:id|unambiguous-id>] [--mode quick|quality] [--optimize off|light|medium|heavy] [--transforms-json <json|@file>] [--canvas <id>] [--wait]\n assethub composer run --part <mesh-asset-id>=<part-image-id>... --reference <image-asset-id> --model V6 [--optimize off|light|medium|heavy] [--canvas <id>] [--wait]\n assethub composer run --part <mesh-asset-id>... --reference <image-asset-id> --model V5.1 [--reasoning low|medium|high] [--agent-model <agents-api model>] [--transforms-json <json|@file>] [--canvas <id>] [--wait]\n assethub composer run --input-json <json|@file> [--canvas <id>] [--operation-id <uuid>] [--wait] [--download --out-dir <dir>]\n assethub composer run --from-run <run-id> [--transforms-json <json|@file>] [--mode quick|quality] [--wait]\n assethub composer run --node <shape:id> --canvas <id> [--model <id>] [--mode quick|quality] [--operation-id <uuid>] [--wait]\n assethub canvas create [--name <name>] [--operation-id <uuid>]\n assethub canvas list [--cursor <cursor>] [--limit <n>]\n assethub canvas get|use|open [<id>]\n assethub canvas graph-id <canvas-id>\n assethub runs list [--canvas <id>] [--cursor <cursor>] [--limit <n>]\n assethub runs get|watch|wait <run-id> [--interval-ms <ms>] [--timeout-ms <n>] [--summary] [--download --out-dir <dir>]\n assethub runs resume <operation-id> [--wait]\n assethub graph list [--cursor <cursor>] [--limit <n>]\n assethub graph show|export [--canvas <id> | --graph <id>] [--source generated|upload] [--artifact <node-id>] [--out <path>] [--allow-truncated]\n assethub graph lineage --artifact <node-id> [--canvas <id> | --graph <id>] [--source generated|upload] [--direction ancestors|descendants|both] [--depth <n>] [--out <path>]\n assethub graph snapshot <graph-id> [--offset <n>] [--limit <n>]\n assethub graph node <graph-id> <node-id>\n assethub graph image <graph-id> <node-id> [--out <path>]\n assethub evaluate list\n assethub evaluations submit --artifact <asset-id> --report <json|file|@file|@-> [--agent <name>] [--canvas <id>] [--reference <asset-id>...] [--run <run-id>] [--operation-id <uuid>] [--require-pass]\n assethub evaluations list [--canvas <id>] [--artifact <asset-id>]\n assethub evaluations get <evaluation-id>\n assethub image generate --input-json <json|@file|@-> [--canvas <id>] [--operation-id <uuid>] [--agent <name>] [--derived-from-run <run-id>] [--from-node <graphId/nodeId> --graph-revision <rev>] [--wait]\n assethub mesh generate --input-json <json|@file|@-> [--canvas <id>] [--operation-id <uuid>] [--agent <name>] [--derived-from-run <run-id>] [--from-node <graphId/nodeId> --graph-revision <rev>] [--wait]\n assethub mesh generate --node <shape:id> --canvas <id> [--model-id <id>] [--params-json <json|@file>] [--operation-id <uuid>] [--wait]\n assethub mesh list [--query <text>] [--cursor <cursor>] [--limit <n>]\n assethub mesh get <mesh-asset-id>\n assethub mesh download <mesh-asset-id> --out-dir <directory>\n assethub image generate --prompt <text> [--file <path> | --source-url <url> | --stdin | --stdin-base64 | --stdin-data-uri | --stdin-json | --source-json <json|@file|@-> | --data-uri <uri> | --clipboard] [--file-name <name>] [--content-type <type>] [--model-id <id>] [--batch-size <n>] [--wait] [--download --out-dir <dir>] [--canvas <id>] [--operation-id <uuid>] [--api-version v2]\n assethub image generate --prompt <text> --source-resource-id <id> --api-version v2 [--model-id <id>] [--batch-size <n>] [--wait]\n assethub mesh generate (--file <path> | --source-url <url> | --source-resource-id <id> | --file-ref-json <json> | --stdin | --stdin-base64 | --stdin-data-uri | --stdin-json | --source-json <json|@file|@-> | --data-uri <uri>) [--file-name <name>] [--content-type <type>] [--model-id <id>] [--name <name>] [--wait] [--download --out-dir <dir>]\n assethub mesh retopo (--source-resource-id <id> | --source-url <url> | --file-ref-json <json> | --stdin | --stdin-base64 | --stdin-data-uri | --stdin-json | --source-json <json|@file|@-> | --data-uri <uri>) --model-id <id> [--file-name <name>] [--content-type <type>] [--wait] [--download --out-dir <dir>]\n assethub rig check (--file <path> | --source-url <url> | --source-resource-id <id> | --file-ref-json <json> | --stdin | --stdin-base64 | --stdin-data-uri | --stdin-json | --source-json <json|@file|@-> | --data-uri <uri>) [--name <name>] [--wait] [--download --out-dir <dir>]\n assethub rig create (--file <path> | --source-url <url> | --source-resource-id <id> | --file-ref-json <json> | --stdin | --stdin-base64 | --stdin-data-uri | --stdin-json | --source-json <json|@file|@-> | --data-uri <uri>) [--model v1.0-20240301|v2.5-20260210] [--rig-type biped|quadruped|hexapod|octopod|avian|serpentine|aquatic] [--spec tripo|mixamo] [--out-format glb|fbx] [--name <name>] [--wait] [--download --out-dir <dir>]\n assethub animate presets [--model v1.0-20240301|v2.5-20260210] [--rig-type <type>]\n assethub animate retarget --resource-id <id> --animation <preset-id> [--animation <preset-id>... up to 5 total] [--out-format glb|fbx] [--bake-animation true|false] [--export-with-geometry true|false] [--animate-in-place true|false] [--name <name>] [--wait] [--download --out-dir <dir>]\n assethub jobs get <job-id> [--download --out-dir <dir>]\n assethub jobs watch <job-id> [--interval-ms <ms>] [--timeout-ms <ms>] [--download --out-dir <dir>]\n assethub production analyze (--file <path> | --source-url <url> | --source-id <id> | --image-url <url> | --file-ref-json <json> | --stdin | --stdin-base64 | --stdin-data-uri | --stdin-json | --source-json <json|@file|@-> | --data-uri <uri> | --clipboard) [--file-name <name>] [--content-type <type>] [--part-extractor <name>] [--name <name>] [--base-body <mesh-asset-id>] [--skill-planner-model <model>] [--auto-repair true|false] [--skill-mode auto|manual|off] [--skill-id <id>...] [--context <canvas-id> --context-version <n>] [--wait] [--download --out-dir <dir>]\n Production graph options: --pipeline-depth parts|mesh|composition [--assembly-policy concept-to-character-v1] [--mesh-generation-json <json|@file>]\n assethub production batch (--file <path>... | --files-dir <dir> | --source-id <id>... | --source-url <url>...) --part-extractor <name> [--repeat <n>] [--yes] [--canvas <id>] [--operation-id <uuid>] [--wait [--concurrency <n>]] [--download --out-dir <dir>]\n One production analyze per image \u00D7 --repeat, on one canvas. Takes the production analyze options. Rerun with the printed --operation-id to resume; nothing is started twice.\n assethub production agents\n assethub production automation --input-json <json|@file|@-> [--canvas <id>] [--operation-id <uuid>] [--wait]\n assethub production status <order-id> [--wait] [--download --out-dir <dir>]\n assethub production execute --order-id <id> --mission-id <id> --task-id <id> [--task-id <id>...] [--part-extractor <name>] [--part-extraction-mode fast|high_quality] [--wait] [--download --out-dir <dir>]\n assethub production run --order-id <id> --mission-id <id> [--run-mode full_auto|approval] [--task-id <id>...] [--part-extractor <name>] [--part-extraction-mode fast|high_quality] [--allowed-model-id <id>...] [--max-iterations <n>] [--max-cost-credits <n>] [--wait] [--download --out-dir <dir>]\n assethub production run --image <file|asset-id> [--canvas <id>] [--part-extractor <name>] [--compose v6|none] [--mesh-model <id>] [--max-parts <n>] [--max-cost <credits>] [--estimate] [--wait] [--download --out-dir <dir>] [--json]\n assethub production watch <order-id> [--interval-ms <ms>] [--timeout-ms <ms>] [--download --out-dir <dir>]\n assethub production intervene <order-id> (--exclude <target-id> | --include <target-id> | --add-part <name> | --rename <target-id>=<name> | --reject <target-id>[=<reason>] | --regenerate <target-id>=<mode> | --set-param <key>=<value> | --ops-json <json|@file|@->)... [--idempotency-key <key>]\n assethub production interventions <order-id>\n assethub production resume <run-id|order-id> [--expected-resume-count <n>] [--wait] [--timeout-ms <ms>] [--download --out-dir <dir>] (after a fix, pick a stopped or stalled graph run back up; no new charge)\n assethub runs upload <path> [--graph-id <id>] [--stream-id <id>] [--rev <n>] [--description <text>] [--tag <tag>...] [--skip-register] [--dry-run]\n assethub parts split (--file <path> | --source-url <url> | --source-id <id> | --image-url <url> | --file-ref-json <json> | --stdin | --stdin-base64 | --stdin-data-uri | --stdin-json | --source-json <json|@file|@-> | --data-uri <uri> | --clipboard | --order-id <id>) [--file-name <name>] [--content-type <type>] [--part-extractor <name>] [--base-body <mesh-asset-id>] [--skill-planner-model <model>] [--auto-repair true|false] [--skill-mode auto|manual|off] [--skill-id <id>...] [--wait] [--task-id <id>...] [--mission-id <id>] [--all-ready] [--download --out-dir <dir>]\n assethub parts compare (--file <path> | --source-url <url> | --source-id <id> | --image-url <url> | --file-ref-json <json> | --stdin | --stdin-base64 | --stdin-data-uri | --stdin-json | --source-json <json|@file|@-> | --data-uri <uri> | --clipboard) [--file-name <name>] [--content-type <type>] [--preprocess-prompt <text>] [--preprocess-model-id <id>] [--fail-on-preprocess-error] [--part-extractor <name>] [--wait] [--task-id <id>...] [--mission-id <id>] [--all-ready] [--download --out-dir <dir>]\n assethub autopilot [<image>] --demo [--yolo] [--json] [--max-regen <n>] [--stall-rounds <n>] [--tie-epsilon <x>] [--multiview 2-view|4-view|6-view] [--ab-mode serial|cross] [--credit-budget <n>]\n assethub memory memorize --canvas <id> [--nodes <shape-id>,<shape-id>,...] [--wait] [--timeout <s>]\n assethub memory replay <memory-id> --source <asset-id> [--wait] [--timeout <s>]\n assethub skills list [--cursor <cursor>]\n assethub skills get <skill-id> [--revision <n>]\n assethub skills memory <skill-id> [--revision <n>] [--images <dir>]\n assethub skills learn --input-json <json|@file|@-> --operation-id <uuid>\n assethub skills update <skill-id> --input-json <json|@file|@->\n assethub skills controls <skill-id> --revision <n> --grant-revision <n> --mode automatic|manual|off [--share]\n assethub skills prepare --input-json <json|@file|@->\n assethub skills proposal <proposal-id>\n assethub skills accept <proposal-id> --input-json <json|@file|@->\n assethub skills validate --input-json <json|@file|@-> [--build <build-id>]\n assethub skills schema\n assethub skills build --goal <text> (--canvas <id>... | --memory <id>...) [--instructions <text>] [--operation-id <uuid>] [--wait] [--dry-run]\n assethub skills official list\n assethub skills official install <skill-id> --revision <n> --content-sha256 <sha256> [--expected-revision <n>] [--expected-grant-revision <n>]\n assethub skills official prepare <skill-id> --input-json <json|@file|@->\n assethub skills official customize <skill-id> --input-json <json|@file|@->\n assethub org search <query>\n assethub org canvases --org <orgId>\n assethub graph export-canvas --org <orgId> --canvas <id>[,<id>...] [--wait] [--timeout <s>] [--out-dir <dir>]\n\nGlobal options:\n --api-key <key> Overrides saved auth and ASSETHUB_API_KEY.\n --base-url <url> Override the selected API origin. Default: https://app.assethub.io.\n --profile <name> Select this saved profile ahead of environment credentials and origin.\n --workspace <id> Select workspace scope for this command without changing saved selection.\n --config <path> Auth config path. Defaults to ~/.assethub/config.json.\n --version Show installed package version.\n --help Show help.\n\nExamples:\n ASSETHUB_API_KEY=ah_live_xxx assethub models list\n assethub auth login --api-key-stdin\n assethub init --dry-run\n assethub models list --ids-only\n assethub files upload ./input.png --media-type image\n assethub source create --file ./input.png --media-type image\n pbpaste | assethub source create --stdin-data-uri --media-type image\n assethub source create --clipboard --media-type image --file-name clipboard.png\n printf '{\"image_url\":{\"url\":\"data:image/png;base64,...\"}}' | assethub parts split --stdin-json --part-extractor \"V1.5\" --wait\n base64 -i ./input.png | assethub parts split --stdin-base64 --file-name input.png --content-type image/png --part-extractor \"V1.5\" --wait\n cat ./input.png | assethub parts split --stdin --file-name input.png --part-extractor \"V1.5\" --wait\n assethub image generate --prompt \"stylized prop concept\" --wait\n assethub mesh generate --file ./input.png --wait\n assethub animate presets --rig-type biped\n assethub rig create --source-resource-id mesh_x --rig-type biped --wait\n assethub animate retarget --resource-id rig_x --animation preset:idle --wait\n assethub production analyze --file ./input.png --part-extractor \"V1.5\" --wait\n assethub production analyze --file ./concept.png --part-extractor v4 --wait --download --out-dir ./character\n assethub production batch --file ./harpy.png --file ./satyr.png --repeat 2 --part-extractor v4 --yes --wait --download --out-dir ./batch\n assethub production run --order-id ord_x --mission-id ms_x --run-mode full_auto --max-cost-credits 200 --wait\n assethub production run --image ./character.png --estimate\n assethub production run --image ./character.png --compose v6 --max-cost 500 --wait --download --out-dir ./out/asset\n assethub production watch ord_x\n assethub runs get run_x --summary\n assethub runs wait run_x --timeout-ms 3600000\n assethub production intervene ord_x --exclude 7 --rename 3=\"left wing\" --idempotency-key review-2026-07-29\n assethub production interventions ord_x\n assethub production resume ord_x\n assethub production resume <run-id> --wait --download --out-dir ./character\n assethub runs upload ./out/pluffy-run-2026-07-30 --dry-run\n assethub runs upload ./out/pluffy-run-2026-07-30 --tag pluffy --description \"V3 humanoid, 18 parts\"\n assethub parts split --file ./input.png --part-extractor \"V1.5\" --wait --all-ready\n assethub parts compare --file ./input.png --preprocess-prompt \"clean white background, centered product photo\" --part-extractor \"V1.5\" --wait --all-ready\n";
27
- export declare const commandSetup: (flags: Flags, installHooks?: InstallHooks) => Promise<void>;
27
+ export declare const usage = "AssetHub CLI\n\nCLI and MCP are available to all AssetHub users. Workspace permissions and feature availability apply.\n\nUsage:\n assethub --version\n assethub setup [--agent claude-code|codex|cursor...] [--project] [--only <step,...>] [--skip <step,...>] [--no-skills] [--profile <name>] [--workspace <id>] [--api-key-stdin] [--base-url <url>] [--no-app-env] [--dry-run] [--yes] [--print-env] [--json]\n assethub env load [--profile <name>]\n assethub update [--check] [--dry-run] [--yes]\n assethub doctor [--mcp] [--setup [--agent <name>...] [--project]] [--profile <name>] [--timeout-ms <n>]\n assethub mcp tools [tool-name] [--account] [--profile <name>] [--timeout-ms <n>]\n assethub mcp config --client cursor|codex [--account] [--base-url <url>]\n assethub auth login --api-key <key> [--base-url <url>] [--profile <name>]\n assethub auth login --api-key-stdin [--base-url <url>] [--profile <name>]\n assethub auth login --access-token-stdin [--base-url <url>] [--profile <name>]\n assethub auth status [--profile <name>]\n assethub auth logout [--profile <name>]\n assethub workspace list [--query <text>] [--limit <1-100>] [--cursor <cursor>]\n assethub workspace get\n assethub workspace create --name <name> [--operation-id <uuid>]\n assethub workspace use <workspace-id>\n assethub workspace members [--workspace <id>]\n assethub workspace invite --email <email> [--role user|admin] [--resend] [--workspace <id>]\n assethub workspace set-role <user-id> --role user|admin [--workspace <id>]\n assethub workspace remove-member <user-id> [--workspace <id>]\n assethub workspace prepare|sync|analyze|verify --internal --manifest <json> --state <json>\n assethub workspace self-check --internal\n assethub workspace context put --internal --org <uuid> --actor <uuid> --canvas <id> --file <json> [--if-version <n>] [--order <uuid>]\n assethub workspace context get --internal --org <uuid> --actor <uuid> --canvas <id> [--out <json>] [--order <uuid>]\n assethub project ingest <source-dir> --out-dir <directory> [--exclude-dir <relative-path>...]\n assethub language text|vision --input-json @<json> --operation-id <uuid> [--out <json>]\n assethub canvas download --canvas <id> --out-dir <directory> [--mesh <mesh_asset_id>]\n assethub canvas nodes --canvas <id>\n assethub canvas import --canvas <id> --file <image> [--name <name>]\n assethub canvas context get --canvas <id> [--out <json>]\n assethub canvas context put --canvas <id> --file <json> [--if-version <n>]\n assethub canvas layout --canvas <id> --input-json @<json>\n assethub canvas compare --canvas <id> --source-id <asset-id> --asset-id <asset-id> --out <html>\n assethub moodboard create --input-json @<json> [--operation-id <uuid>]\n assethub moodboard list|get|update|archive [<board-id>] [--input-json @<json>]\n assethub moodboard analyze <board-id> [--revision <uuid>] [--wait]\n assethub image generate --canvas <id> --context <id> [--context-version <n>] [--context-source <key>] [--moodboard-revision <uuid>] --prompt <text> --wait\n assethub models list [--domain <domain>] [--ids-only] [--limit <n>]\n assethub models get <model-id>\n assethub files import <url> --media-type image|mesh\n assethub files upload <file> --media-type image|mesh\n assethub source create (--file <path> | --source-url <url> | --source-id <id> | --stdin | --stdin-base64 | --stdin-data-uri | --stdin-json | --source-json <json|@file|@-> | --data-uri <uri> | --clipboard) --media-type image|mesh [--file-name <name>] [--content-type <type>]\n assethub capabilities\n assethub api search [query]\n assethub api describe \"<METHOD /path>\"\n assethub api call \"<METHOD /path>\" [--path-json <json|@file>] [--query-json <json|@file>] [--input-json <json|@file|@->] [--operation-id <uuid>]\n assethub composer models\n assethub composer refine --list-modes\n assethub composer refine --from-run <run-id> --instruction <text> [--mode standard|thorough|placement|workshop|blender|codex] [--effort light|standard|thorough] [--max-rounds <n>] [--agent-model <provider:id|unambiguous-id>] [--transforms-json <json|@file>] [--wait] [--download --out-dir <dir>]\n assethub composer refine --input-json <json|@file> [--canvas <id>] [--operation-id <uuid>] [--wait] [--download --out-dir <dir>]\n assethub composer refine --from-run <run-id> --skill-assembly [--reasoning low|medium|high] [--agent-model <agents-api model>] [--wait]\n assethub composer run --part <mesh-asset-id>[=<part-image-id>] [--part <mesh-asset-id>[=<part-image-id>]...] --reference <image-asset-id> [--model <id>] [--agent-model <provider:id|unambiguous-id>] [--mode quick|quality] [--optimize off|light|medium|heavy] [--transforms-json <json|@file>] [--canvas <id>] [--wait]\n assethub composer run --part <mesh-asset-id>=<part-image-id>... --reference <image-asset-id> --model V6 [--optimize off|light|medium|heavy] [--canvas <id>] [--wait]\n assethub composer run --part <mesh-asset-id>... --reference <image-asset-id> --model V5.1 [--reasoning low|medium|high] [--agent-model <agents-api model>] [--transforms-json <json|@file>] [--canvas <id>] [--wait]\n assethub composer run --input-json <json|@file> [--canvas <id>] [--operation-id <uuid>] [--wait] [--download --out-dir <dir>]\n assethub composer run --from-run <run-id> [--transforms-json <json|@file>] [--mode quick|quality] [--wait]\n assethub composer run --node <shape:id> --canvas <id> [--model <id>] [--mode quick|quality] [--operation-id <uuid>] [--wait]\n assethub canvas create [--name <name>] [--operation-id <uuid>]\n assethub canvas list [--cursor <cursor>] [--limit <n>]\n assethub canvas get|use|open [<id>]\n assethub canvas graph-id <canvas-id>\n assethub runs list [--canvas <id>] [--cursor <cursor>] [--limit <n>]\n assethub runs get|watch|wait <run-id> [--interval-ms <ms>] [--timeout-ms <n>] [--summary] [--download --out-dir <dir>]\n assethub runs resume <operation-id> [--wait]\n assethub graph list [--cursor <cursor>] [--limit <n>]\n assethub graph show|export [--canvas <id> | --graph <id>] [--source generated|upload] [--artifact <node-id>] [--out <path>] [--allow-truncated]\n assethub graph lineage --artifact <node-id> [--canvas <id> | --graph <id>] [--source generated|upload] [--direction ancestors|descendants|both] [--depth <n>] [--out <path>]\n assethub graph snapshot <graph-id> [--offset <n>] [--limit <n>]\n assethub graph node <graph-id> <node-id>\n assethub graph image <graph-id> <node-id> [--out <path>]\n assethub evaluate list\n assethub evaluations submit --artifact <asset-id> --report <json|file|@file|@-> [--agent <name>] [--canvas <id>] [--reference <asset-id>...] [--run <run-id>] [--operation-id <uuid>] [--require-pass]\n assethub evaluations list [--canvas <id>] [--artifact <asset-id>]\n assethub evaluations get <evaluation-id>\n assethub image generate --input-json <json|@file|@-> [--canvas <id>] [--operation-id <uuid>] [--agent <name>] [--derived-from-run <run-id>] [--from-node <graphId/nodeId> --graph-revision <rev>] [--wait]\n assethub mesh generate --input-json <json|@file|@-> [--canvas <id>] [--operation-id <uuid>] [--agent <name>] [--derived-from-run <run-id>] [--from-node <graphId/nodeId> --graph-revision <rev>] [--wait]\n assethub mesh generate --node <shape:id> --canvas <id> [--model-id <id>] [--params-json <json|@file>] [--operation-id <uuid>] [--wait]\n assethub mesh list [--query <text>] [--cursor <cursor>] [--limit <n>]\n assethub mesh get <mesh-asset-id>\n assethub mesh download <mesh-asset-id> --out-dir <directory>\n assethub image generate --prompt <text> [--file <path> | --source-url <url> | --stdin | --stdin-base64 | --stdin-data-uri | --stdin-json | --source-json <json|@file|@-> | --data-uri <uri> | --clipboard] [--file-name <name>] [--content-type <type>] [--model-id <id>] [--batch-size <n>] [--wait] [--download --out-dir <dir>] [--canvas <id>] [--operation-id <uuid>] [--api-version v2]\n assethub image generate --prompt <text> --source-resource-id <id> --api-version v2 [--model-id <id>] [--batch-size <n>] [--wait]\n assethub mesh generate (--file <path> | --source-url <url> | --source-resource-id <id> | --file-ref-json <json> | --stdin | --stdin-base64 | --stdin-data-uri | --stdin-json | --source-json <json|@file|@-> | --data-uri <uri>) [--file-name <name>] [--content-type <type>] [--model-id <id>] [--name <name>] [--wait] [--download --out-dir <dir>]\n assethub mesh retopo (--source-resource-id <id> | --source-url <url> | --file-ref-json <json> | --stdin | --stdin-base64 | --stdin-data-uri | --stdin-json | --source-json <json|@file|@-> | --data-uri <uri>) --model-id <id> [--file-name <name>] [--content-type <type>] [--wait] [--download --out-dir <dir>]\n assethub rig check (--file <path> | --source-url <url> | --source-resource-id <id> | --file-ref-json <json> | --stdin | --stdin-base64 | --stdin-data-uri | --stdin-json | --source-json <json|@file|@-> | --data-uri <uri>) [--name <name>] [--wait] [--download --out-dir <dir>]\n assethub rig create (--file <path> | --source-url <url> | --source-resource-id <id> | --file-ref-json <json> | --stdin | --stdin-base64 | --stdin-data-uri | --stdin-json | --source-json <json|@file|@-> | --data-uri <uri>) [--model v1.0-20240301|v2.5-20260210] [--rig-type biped|quadruped|hexapod|octopod|avian|serpentine|aquatic] [--spec tripo|mixamo] [--out-format glb|fbx] [--name <name>] [--wait] [--download --out-dir <dir>]\n assethub animate presets [--model v1.0-20240301|v2.5-20260210] [--rig-type <type>]\n assethub animate retarget --resource-id <id> --animation <preset-id> [--animation <preset-id>... up to 5 total] [--out-format glb|fbx] [--bake-animation true|false] [--export-with-geometry true|false] [--animate-in-place true|false] [--name <name>] [--wait] [--download --out-dir <dir>]\n assethub jobs get <job-id> [--download --out-dir <dir>]\n assethub jobs watch <job-id> [--interval-ms <ms>] [--timeout-ms <ms>] [--download --out-dir <dir>]\n assethub production analyze (--file <path> | --source-url <url> | --source-id <id> | --image-url <url> | --file-ref-json <json> | --stdin | --stdin-base64 | --stdin-data-uri | --stdin-json | --source-json <json|@file|@-> | --data-uri <uri> | --clipboard) [--file-name <name>] [--content-type <type>] [--part-extractor <name>] [--name <name>] [--base-body <mesh-asset-id>] [--skill-planner-model <model>] [--auto-repair true|false] [--skill-mode auto|manual|off] [--skill-id <id>...] [--context <canvas-id> --context-version <n>] [--wait] [--download --out-dir <dir>]\n Production graph options: --pipeline-depth parts|mesh|composition [--assembly-policy concept-to-character-v1] [--mesh-generation-json <json|@file>]\n assethub production batch (--file <path>... | --files-dir <dir> | --source-id <id>... | --source-url <url>...) --part-extractor <name> [--repeat <n>] [--yes] [--canvas <id>] [--operation-id <uuid>] [--wait [--concurrency <n>]] [--download --out-dir <dir>]\n One production analyze per image \u00D7 --repeat, on one canvas. Takes the production analyze options. Rerun with the printed --operation-id to resume; nothing is started twice.\n assethub production agents\n assethub production automation --input-json <json|@file|@-> [--canvas <id>] [--operation-id <uuid>] [--wait]\n assethub production status <order-id> [--wait] [--download --out-dir <dir>]\n assethub production execute --order-id <id> --mission-id <id> --task-id <id> [--task-id <id>...] [--part-extractor <name>] [--part-extraction-mode fast|high_quality] [--wait] [--download --out-dir <dir>]\n assethub production run --order-id <id> --mission-id <id> [--run-mode full_auto|approval] [--task-id <id>...] [--part-extractor <name>] [--part-extraction-mode fast|high_quality] [--allowed-model-id <id>...] [--max-iterations <n>] [--max-cost-credits <n>] [--wait] [--download --out-dir <dir>]\n assethub production run --image <file|asset-id> [--canvas <id>] [--part-extractor <name>] [--compose v6|none] [--mesh-model <id>] [--max-parts <n>] [--max-cost <credits>] [--estimate] [--wait] [--download --out-dir <dir>] [--json]\n assethub production watch <order-id> [--interval-ms <ms>] [--timeout-ms <ms>] [--download --out-dir <dir>]\n assethub production intervene <order-id> (--exclude <target-id> | --include <target-id> | --add-part <name> | --rename <target-id>=<name> | --reject <target-id>[=<reason>] | --regenerate <target-id>=<mode> | --set-param <key>=<value> | --ops-json <json|@file|@->)... [--idempotency-key <key>]\n assethub production interventions <order-id>\n assethub production resume <run-id|order-id> [--expected-resume-count <n>] [--wait] [--timeout-ms <ms>] [--download --out-dir <dir>] (after a fix, pick a stopped or stalled graph run back up; no new charge)\n assethub runs upload <path> [--graph-id <id>] [--stream-id <id>] [--rev <n>] [--description <text>] [--tag <tag>...] [--skip-register] [--dry-run]\n assethub parts split (--file <path> | --source-url <url> | --source-id <id> | --image-url <url> | --file-ref-json <json> | --stdin | --stdin-base64 | --stdin-data-uri | --stdin-json | --source-json <json|@file|@-> | --data-uri <uri> | --clipboard | --order-id <id>) [--file-name <name>] [--content-type <type>] [--part-extractor <name>] [--base-body <mesh-asset-id>] [--skill-planner-model <model>] [--auto-repair true|false] [--skill-mode auto|manual|off] [--skill-id <id>...] [--wait] [--task-id <id>...] [--mission-id <id>] [--all-ready] [--download --out-dir <dir>]\n assethub parts compare (--file <path> | --source-url <url> | --source-id <id> | --image-url <url> | --file-ref-json <json> | --stdin | --stdin-base64 | --stdin-data-uri | --stdin-json | --source-json <json|@file|@-> | --data-uri <uri> | --clipboard) [--file-name <name>] [--content-type <type>] [--preprocess-prompt <text>] [--preprocess-model-id <id>] [--fail-on-preprocess-error] [--part-extractor <name>] [--wait] [--task-id <id>...] [--mission-id <id>] [--all-ready] [--download --out-dir <dir>]\n assethub autopilot [<image>] --demo [--yolo] [--json] [--max-regen <n>] [--stall-rounds <n>] [--tie-epsilon <x>] [--multiview 2-view|4-view|6-view] [--ab-mode serial|cross] [--credit-budget <n>]\n assethub memory memorize --canvas <id> [--nodes <shape-id>,<shape-id>,...] [--wait] [--timeout <s>]\n assethub memory replay <memory-id> --source <asset-id> [--wait] [--timeout <s>]\n assethub skills list [--cursor <cursor>]\n assethub skills get <skill-id> [--revision <n>]\n assethub skills memory <skill-id> [--revision <n>] [--images <dir>]\n assethub skills learn --input-json <json|@file|@-> --operation-id <uuid>\n assethub skills update <skill-id> --input-json <json|@file|@->\n assethub skills controls <skill-id> --revision <n> --grant-revision <n> --mode automatic|manual|off [--share]\n assethub skills prepare --input-json <json|@file|@->\n assethub skills proposal <proposal-id>\n assethub skills accept <proposal-id> --input-json <json|@file|@->\n assethub skills validate --input-json <json|@file|@-> [--build <build-id>]\n assethub skills schema\n assethub skills build --goal <text> (--canvas <id>... | --memory <id>...) [--instructions <text>] [--operation-id <uuid>] [--wait] [--dry-run]\n assethub skills official list\n assethub skills official install <skill-id> --revision <n> --content-sha256 <sha256> [--expected-revision <n>] [--expected-grant-revision <n>]\n assethub skills official prepare <skill-id> --input-json <json|@file|@->\n assethub skills official customize <skill-id> --input-json <json|@file|@->\n assethub org search <query>\n assethub org canvases --org <orgId>\n assethub graph export-canvas --org <orgId> --canvas <id>[,<id>...] [--wait] [--timeout <s>] [--out-dir <dir>]\n\nGlobal options:\n --api-key <key> Overrides saved auth and ASSETHUB_API_KEY.\n --base-url <url> Override the selected API origin. Default: https://app.assethub.io.\n --profile <name> Select this saved profile ahead of environment credentials and origin.\n --workspace <id> Select workspace scope for this command without changing saved selection.\n --config <path> Auth config path. Defaults to ~/.assethub/config.json.\n --version Show installed package version.\n --help Show help.\n\nExamples:\n ASSETHUB_API_KEY=ah_live_xxx assethub models list\n assethub auth login --api-key-stdin\n assethub setup --dry-run\n assethub setup --only skills --project\n assethub models list --ids-only\n assethub files upload ./input.png --media-type image\n assethub source create --file ./input.png --media-type image\n pbpaste | assethub source create --stdin-data-uri --media-type image\n assethub source create --clipboard --media-type image --file-name clipboard.png\n printf '{\"image_url\":{\"url\":\"data:image/png;base64,...\"}}' | assethub parts split --stdin-json --part-extractor \"V1.5\" --wait\n base64 -i ./input.png | assethub parts split --stdin-base64 --file-name input.png --content-type image/png --part-extractor \"V1.5\" --wait\n cat ./input.png | assethub parts split --stdin --file-name input.png --part-extractor \"V1.5\" --wait\n assethub image generate --prompt \"stylized prop concept\" --wait\n assethub mesh generate --file ./input.png --wait\n assethub animate presets --rig-type biped\n assethub rig create --source-resource-id mesh_x --rig-type biped --wait\n assethub animate retarget --resource-id rig_x --animation preset:idle --wait\n assethub production analyze --file ./input.png --part-extractor \"V1.5\" --wait\n assethub production analyze --file ./concept.png --part-extractor v4 --wait --download --out-dir ./character\n assethub production batch --file ./harpy.png --file ./satyr.png --repeat 2 --part-extractor v4 --yes --wait --download --out-dir ./batch\n assethub production run --order-id ord_x --mission-id ms_x --run-mode full_auto --max-cost-credits 200 --wait\n assethub production run --image ./character.png --estimate\n assethub production run --image ./character.png --compose v6 --max-cost 500 --wait --download --out-dir ./out/asset\n assethub production watch ord_x\n assethub runs get run_x --summary\n assethub runs wait run_x --timeout-ms 3600000\n assethub production intervene ord_x --exclude 7 --rename 3=\"left wing\" --idempotency-key review-2026-07-29\n assethub production interventions ord_x\n assethub production resume ord_x\n assethub production resume <run-id> --wait --download --out-dir ./character\n assethub runs upload ./out/pluffy-run-2026-07-30 --dry-run\n assethub runs upload ./out/pluffy-run-2026-07-30 --tag pluffy --description \"V3 humanoid, 18 parts\"\n assethub parts split --file ./input.png --part-extractor \"V1.5\" --wait --all-ready\n assethub parts compare --file ./input.png --preprocess-prompt \"clean white background, centered product photo\" --part-extractor \"V1.5\" --wait --all-ready\n";
28
+ export declare const commandSetup: (flags: Flags, installHooks?: InstallHooks, overrides?: {
29
+ skip?: SetupStepName[];
30
+ }) => Promise<void>;
28
31
  /**
29
32
  * The `animate retarget` request, built from flags alone.
30
33
  *
@@ -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
@@ -2,8 +2,8 @@
2
2
  import { childOperationId, expandProductionBatch, planProductionNodeMeshes, callApiOperation, describeApiOperation, discoverApiOperations, searchApiOperations, TERMINAL_WORKSPACE_SKILL_BUILD_STATUSES, WORKSPACE_SKILL_ENHANCE_SECTIONS, } from '@assethub/api-client';
3
3
  import { setTimeout as delay } from 'node:timers/promises';
4
4
  import { cliVersion, diagnose, mcpConfig } from './setup.js';
5
- import { AGENT_IDS, initAgents, syncInstalledSkill } from './agentSetup.js';
6
- import { confirmNo, confirmYes, defaultFileDeps, formatSetupSummary, pickFromList, promptHidden, runProcess, runSetup, } from './setupCommand.js';
5
+ import { AGENT_IDS, parseAgentIds, syncInstalledSkill } from './agentSetup.js';
6
+ import { confirmNo, confirmYes, defaultFileDeps, formatSetupSummary, pickFromList, promptHidden, runProcess, runSetup, SETUP_STEPS, } from './setupCommand.js';
7
7
  import { launchAgentProgram, loadKeyIntoLaunchd } from './appEnv.js';
8
8
  import { defaultInstallHooks } from './setupHooksBridge.js';
9
9
  import { canUploadSessions, installHooks as installSessionHooks, runHooksCommand } from './hooks/index.js';
@@ -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';
@@ -222,11 +222,10 @@ CLI and MCP are available to all AssetHub users. Workspace permissions and featu
222
222
 
223
223
  Usage:
224
224
  assethub --version
225
- assethub setup [--client claude|codex|both] [--profile <name>] [--workspace <id>] [--api-key-stdin] [--base-url <url>] [--no-app-env] [--dry-run] [--yes] [--print-env] [--json]
225
+ assethub setup [--agent claude-code|codex|cursor...] [--project] [--only <step,...>] [--skip <step,...>] [--no-skills] [--profile <name>] [--workspace <id>] [--api-key-stdin] [--base-url <url>] [--no-app-env] [--dry-run] [--yes] [--print-env] [--json]
226
226
  assethub env load [--profile <name>]
227
227
  assethub update [--check] [--dry-run] [--yes]
228
- assethub doctor [--mcp] [--profile <name>] [--timeout-ms <n>]
229
- assethub init [--agent claude-code|codex|cursor...] [--project] [--dry-run] [--base-url <url>] [--workspace <id>] [--profile <name>]
228
+ assethub doctor [--mcp] [--setup [--agent <name>...] [--project]] [--profile <name>] [--timeout-ms <n>]
230
229
  assethub mcp tools [tool-name] [--account] [--profile <name>] [--timeout-ms <n>]
231
230
  assethub mcp config --client cursor|codex [--account] [--base-url <url>]
232
231
  assethub auth login --api-key <key> [--base-url <url>] [--profile <name>]
@@ -364,7 +363,8 @@ Global options:
364
363
  Examples:
365
364
  ASSETHUB_API_KEY=ah_live_xxx assethub models list
366
365
  assethub auth login --api-key-stdin
367
- assethub init --dry-run
366
+ assethub setup --dry-run
367
+ assethub setup --only skills --project
368
368
  assethub models list --ids-only
369
369
  assethub files upload ./input.png --media-type image
370
370
  assethub source create --file ./input.png --media-type image
@@ -1906,11 +1906,41 @@ const commandAuth = async (subcommand, flags) => {
1906
1906
  };
1907
1907
  // One-command onboarding. Login and workspace selection reuse commandAuth and
1908
1908
  // commandWorkspace (their JSON output is suppressed); setupCommand.ts owns the
1909
- // client configuration and the summary.
1910
- export const commandSetup = async (flags, installHooks = defaultInstallHooks) => {
1911
- const client = getFlag(flags, 'client') ?? 'both';
1912
- if (client !== 'claude' && client !== 'codex' && client !== 'both')
1913
- throw new Error('--client must be claude, codex or both');
1909
+ // steps, the agent configuration and the summary.
1910
+ const parseSetupSelection = (flags) => {
1911
+ const agentValues = getFlagValues(flags, 'agent').map(value => assertFlagHasValue(value, '--agent <name>'));
1912
+ let agents = agentValues.length > 0 ? parseAgentIds(agentValues) : undefined;
1913
+ if (!agents && hasFlag(flags, 'client')) {
1914
+ // Older spelling: --client claude|codex|both.
1915
+ const client = getFlag(flags, 'client');
1916
+ if (client !== 'claude' && client !== 'codex' && client !== 'both')
1917
+ throw new Error('--client must be claude, codex or both (use --agent claude-code|codex|cursor)');
1918
+ agents = client === 'both' ? ['claude-code', 'codex'] : parseAgentIds([client]);
1919
+ }
1920
+ const stepValues = (name) => getFlagValues(flags, name)
1921
+ .map(value => assertFlagHasValue(value, `--${name} <step>`))
1922
+ .flatMap(value => value.split(','))
1923
+ .map(value => value.trim())
1924
+ .filter(Boolean);
1925
+ const known = (name, values) => {
1926
+ const unknown = values.filter(value => !SETUP_STEPS.includes(value));
1927
+ if (unknown.length > 0)
1928
+ throw new Error(`Unknown setup step for --${name}: ${unknown.join(', ')}. Steps: login, workspace, mcp, skills, app-env, doctor.`);
1929
+ return values;
1930
+ };
1931
+ const only = known('only', stepValues('only'));
1932
+ const skip = new Set(known('skip', stepValues('skip')));
1933
+ if (only.length > 0)
1934
+ for (const step of SETUP_STEPS)
1935
+ if (!only.includes(step))
1936
+ skip.add(step);
1937
+ if (hasFlag(flags, 'no-skills'))
1938
+ skip.add('skills');
1939
+ return { agents, skip: SETUP_STEPS.filter(step => skip.has(step)) };
1940
+ };
1941
+ /** The `runSetup` options and real dependencies for these flags; `setup`, `init` and `doctor --setup` share them. */
1942
+ const setupRun = async (flags, installHooks, overrides = {}) => {
1943
+ const selection = parseSetupSelection(flags);
1914
1944
  const config = await readAuthConfig(getConfigPath(flags));
1915
1945
  // Only name a profile the user chose or one that is saved: a synthetic profile
1916
1946
  // would make resolveAuth reject a fresh machine before its ASSETHUB_API_KEY fallback.
@@ -1933,8 +1963,10 @@ export const commandSetup = async (flags, installHooks = defaultInstallHooks) =>
1933
1963
  printSuppressed = false;
1934
1964
  }
1935
1965
  };
1936
- const result = await runSetup({
1937
- client,
1966
+ const options = {
1967
+ agents: selection.agents,
1968
+ project: hasFlag(flags, 'project'),
1969
+ skip: [...new Set([...selection.skip, ...(overrides.skip ?? [])])],
1938
1970
  workspace: getFlag(flags, 'workspace'),
1939
1971
  apiKeyStdin,
1940
1972
  apiKey: flagKey ?? envKey,
@@ -1942,17 +1974,20 @@ export const commandSetup = async (flags, installHooks = defaultInstallHooks) =>
1942
1974
  noHook: hasFlag(flags, 'no-hook'),
1943
1975
  noAppEnv: hasFlag(flags, 'no-app-env'),
1944
1976
  saveSessions: hasFlag(flags, 'save-sessions'),
1945
- dryRun: hasFlag(flags, 'dry-run'),
1977
+ dryRun: overrides.dryRun ?? hasFlag(flags, 'dry-run'),
1946
1978
  yes: hasFlag(flags, 'yes'),
1947
1979
  printEnv: hasFlag(flags, 'print-env'),
1948
- }, {
1980
+ };
1981
+ const deps = {
1949
1982
  ...defaultFileDeps(),
1950
1983
  launchAgentProgram: launchAgentProgram(process.execPath, realpathSync(argv[1] ?? fileURLToPath(import.meta.url)), ['env', 'load', ...(hasFlag(flags, 'profile') ? ['--profile', requireFlag(flags, 'profile')] : [])]),
1951
1984
  interactive: Boolean(stdin.isTTY && stderr.isTTY) && !apiKeyStdin,
1952
1985
  installHooks,
1953
- log: line => {
1954
- stderr.write(`${line}\n`);
1955
- },
1986
+ log: overrides.quietLog
1987
+ ? () => { }
1988
+ : line => {
1989
+ stderr.write(`${line}\n`);
1990
+ },
1956
1991
  hasWorkingKey: async () => {
1957
1992
  try {
1958
1993
  const auth = await resolveAuth(base);
@@ -1976,6 +2011,7 @@ export const commandSetup = async (flags, installHooks = defaultInstallHooks) =>
1976
2011
  }
1977
2012
  return commandAuth('login', loginFlags);
1978
2013
  }),
2014
+ resolveTarget: () => resolveMcpTarget(flags),
1979
2015
  resolveAuth: async () => {
1980
2016
  const auth = await resolveAuth(base);
1981
2017
  return { apiKey: auth.apiKey, baseUrl: auth.baseUrl, profile: auth.profile, workspaceId: auth.workspaceId };
@@ -2006,7 +2042,14 @@ export const commandSetup = async (flags, installHooks = defaultInstallHooks) =>
2006
2042
  includeMcp: true,
2007
2043
  timeoutMs: parsePositiveIntegerFlag(flags, 'timeout-ms', 15000),
2008
2044
  }),
2009
- });
2045
+ };
2046
+ return { options, deps };
2047
+ };
2048
+ export const commandSetup = async (flags, installHooks = defaultInstallHooks, overrides = {}) => {
2049
+ const { options, deps } = await setupRun(flags, installHooks, overrides);
2050
+ if (hasFlag(flags, 'client') && !hasFlag(flags, 'agent'))
2051
+ stderr.write('--client is deprecated; use --agent claude-code|codex|cursor.\n');
2052
+ const result = await runSetup(options, deps);
2010
2053
  if (hasFlag(flags, 'json'))
2011
2054
  print(result);
2012
2055
  else {
@@ -2017,6 +2060,29 @@ export const commandSetup = async (flags, installHooks = defaultInstallHooks) =>
2017
2060
  if (!result.ok)
2018
2061
  process.exitCode = 2;
2019
2062
  };
2063
+ /**
2064
+ * `doctor --setup`: the setup steps as a dry run that changes nothing, needs no
2065
+ * network, and fails when MCP config or the skill is missing or out of date.
2066
+ */
2067
+ const setupCheck = async (flags) => {
2068
+ const { options, deps } = await setupRun(flags, installSessionHooks, {
2069
+ skip: ['login', 'workspace', 'app-env', 'hook', 'doctor'],
2070
+ dryRun: true,
2071
+ quietLog: true,
2072
+ });
2073
+ const result = await runSetup(options, deps);
2074
+ const outdated = result.steps.filter(step => step.status === 'fail' || step.change === 'would-update');
2075
+ return {
2076
+ name: 'setup',
2077
+ status: outdated.length === 0 ? 'pass' : 'fail',
2078
+ ...(outdated.length > 0
2079
+ ? {
2080
+ message: outdated.map(step => `${step.name}: ${step.detail.replace(/ \(dry run\)$/, '')}`).join('; '),
2081
+ hint: `Run \`assethub setup${options.project ? ' --project' : ''}\` to fix it.`,
2082
+ }
2083
+ : { message: `${result.agents.join(', ')}: MCP config and skill are up to date` }),
2084
+ };
2085
+ };
2020
2086
  // `env load` is what the macOS login agent installed by `setup` runs: it copies
2021
2087
  // the saved key into launchd's user environment so Claude and Codex, started
2022
2088
  // from the Dock, can expand ${ASSETHUB_API_KEY} in their MCP config.
@@ -2081,19 +2147,8 @@ const defaultWaitMs = (flags) => {
2081
2147
  const watchOptions = (flags) => ({
2082
2148
  intervalMs: parsePositiveIntegerFlag(flags, 'interval-ms', 5000),
2083
2149
  timeoutMs: parsePositiveIntegerFlag(flags, 'timeout-ms', defaultWaitMs(flags)),
2084
- onProgress: progressPrinter(run => `[run] ${run.runId} ${run.status}${run.progress ? ` · ${runProgressLine(run)}` : ''}`),
2150
+ onProgress: runReporter({ write: text => stderr.write(text) }),
2085
2151
  });
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
2152
  const readJsonArgument = async (value, flag) => {
2098
2153
  const text = value === '@-'
2099
2154
  ? await readStdin()
@@ -3673,10 +3728,29 @@ const commandProductionBatch = async (ctx) => {
3673
3728
  if (saved && requestedCanvasId != null && requestedCanvasId !== saved.canvasId)
3674
3729
  throw new Error(`Batch ${operationId} runs on canvas ${saved.canvasId}; drop --canvas or pass that canvas`);
3675
3730
  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
3731
  const wait = hasFlag(ctx.flags, 'wait');
3678
3732
  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`);
3733
+ const report = batchReporter({
3734
+ write: text => stderr.write(text),
3735
+ operationId,
3736
+ agent: partExtractorOptions.find(option => option.apiValue === options.agentVersion)
3737
+ ?.publicName ?? String(options.agentVersion),
3738
+ canvasId: session.canvas.id,
3739
+ ...(wait ? { concurrency } : {}),
3740
+ images: entries.map(entry => ({
3741
+ key: entry.key,
3742
+ imageIndex: entry.index,
3743
+ repeat: entry.repeat,
3744
+ name: productionBatchImageName(sources[entry.index]),
3745
+ })),
3746
+ });
3747
+ report.header();
3748
+ const printItem = (item) => report.item(item);
3749
+ // A status table every 5 minutes while waiting; runs take about an hour.
3750
+ const tableTimer = wait
3751
+ ? setInterval(() => report.table('still running'), 5 * 60_000)
3752
+ : undefined;
3753
+ tableTimer?.unref();
3680
3754
  const result = await runProductionBatch(session, {
3681
3755
  operationId,
3682
3756
  request: { sources, repeat, options, agent, parentRunId },
@@ -3714,8 +3788,10 @@ const commandProductionBatch = async (ctx) => {
3714
3788
  }
3715
3789
  : {}),
3716
3790
  });
3791
+ clearInterval(tableTimer);
3717
3792
  if (!wait)
3718
3793
  result.items.forEach(printItem);
3794
+ report.table(!wait ? 'started' : result.timedOut ? 'stopped waiting' : 'done');
3719
3795
  const downloads = [];
3720
3796
  if (hasFlag(ctx.flags, 'download')) {
3721
3797
  const outDir = getFlag(ctx.flags, 'out-dir') ?? getFlag(ctx.flags, 'out');
@@ -5589,13 +5665,11 @@ const run = async () => {
5589
5665
  if (command === 'init') {
5590
5666
  if (subcommand)
5591
5667
  throw new Error(`Use init [--agent ${AGENT_IDS.join('|')}] [--project] [--dry-run]`);
5592
- const target = await resolveMcpTarget(parsed.flags);
5593
- print(await initAgents({
5594
- ...target,
5595
- agents: getFlagValues(parsed.flags, 'agent').map(value => assertFlagHasValue(value, '--agent <name>')),
5596
- project: hasFlag(parsed.flags, 'project'),
5597
- dryRun: hasFlag(parsed.flags, 'dry-run'),
5598
- }));
5668
+ // Kept for existing scripts: agent wiring only, as before, through setup's steps.
5669
+ stderr.write('`assethub init` is deprecated and will be removed in a later version; use `assethub setup` (or `assethub setup --only mcp,skills` for agent wiring only).\n');
5670
+ await commandSetup({ ...parsed.flags, json: true, yes: true }, installSessionHooks, {
5671
+ skip: ['login', 'workspace', 'app-env', 'hook', 'doctor'],
5672
+ });
5599
5673
  return;
5600
5674
  }
5601
5675
  if (command === 'mcp' && subcommand === 'tools') {
@@ -5672,11 +5746,15 @@ const run = async () => {
5672
5746
  }
5673
5747
  if (command === 'doctor') {
5674
5748
  stderr.write('Checking AssetHub connection…\n');
5675
- const report = await diagnose({
5749
+ const diagnosed = await diagnose({
5676
5750
  resolveAuth: () => resolveAuth(parsed.flags),
5677
5751
  includeMcp: hasFlag(parsed.flags, 'mcp'),
5678
5752
  timeoutMs: parsePositiveIntegerFlag(parsed.flags, 'timeout-ms', 15000),
5679
5753
  });
5754
+ const setup = hasFlag(parsed.flags, 'setup') ? await setupCheck(parsed.flags) : undefined;
5755
+ const report = setup
5756
+ ? { ...diagnosed, ok: diagnosed.ok && setup.status === 'pass', checks: [...diagnosed.checks, setup] }
5757
+ : diagnosed;
5680
5758
  print(report);
5681
5759
  if (!report.ok)
5682
5760
  process.exitCode = 2;
@@ -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"}