@assethub/cli 0.1.7 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -201,8 +201,8 @@ IDs/version/hash are recorded on the run. Retry an uncertain generation with
201
201
  `userNote`. `update <board-id> --input-json @file` creates a new immutable revision;
202
202
  `get`, `list`, and `archive` manage existing boards. Analysis uses the existing
203
203
  8-credit vision plan for a new attempt, resumes an active job, and reuses a ready
204
- revision. The combined generation limit is **6 content and style images**: Marza's
205
- 5 required identity/storyboard references leave room for 1 style representative.
204
+ revision. The combined generation limit is **6 content and style images**: five identity/storyboard references leave room
205
+ for one style representative.
206
206
 
207
207
  Image import persists upload identity before registration and recovers the same
208
208
  asset after an uncertain response; `--upload-id` resumes a known completed upload.
@@ -250,69 +250,9 @@ For example, create `layout.json` with those IDs:
250
250
  assethub canvas layout --canvas "$CANVAS_ID" --input-json @layout.json
251
251
  ```
252
252
 
253
- Internal workspace preparation (monorepo checkout only):
254
-
255
- ```sh
256
- infisical run --env=prod -- node --import tsx packages/assethub-cli/src/index.ts \
257
- workspace prepare --internal --manifest ./workspace.json --state ./workspace-state.json
258
- ```
259
-
260
- `workspace.json` provides `orgId`, `actorId`, `actorEmail`, `projectName`,
261
- `boardName`, `userNote`, and `references` / optional `inputs` and `outputs` arrays containing
262
- `path`, `name`, optional `section`, and optional `representative` (up to three
263
- references). An output can set `sourcePath` to an imported input path to retain a
264
- native canvas connection from storyboard to result. The internal actor must
265
- already belong to the selected workspace.
266
- This creates a native workflow canvas, owned image assets, and a native moodboard
267
- revision. `workspace sync` appends new images from the manifest; the original
268
- moodboard reference revision stays frozen. Preserve the state file for resuming.
269
- `workspace analyze` uses the native analysis model, prompt and parser with the
270
- existing OpenRouter environment, saving provider usage beside the state file.
271
- It uses only the saved revision's frozen references, checks the original owned
272
- assets again, and claims one analysis attempt before calling the provider.
273
- Resumed order and image identities, storage paths and source hashes are checked
274
- against owned records before reading storage or changing the canvas.
275
- `workspace verify` checks persisted native schema, ownership and uploaded hashes.
276
- Optional `contextNote` (up to 24,000 characters) adds a readable native text node
277
- beside the image groups. The full project context is saved separately below.
278
- `workspace self-check --internal` checks native schema, context roundtrips and
279
- conflict rejection without credentials.
280
-
281
- Save and recover a project's instructions without the local manifest/state:
282
-
283
- ```sh
284
- assethub workspace context put --internal --org <workspace-uuid> --actor <internal-user-uuid> \
285
- --canvas <canvas-id> --file ./project-context.json
286
- assethub workspace context get --internal --org <workspace-uuid> --actor <internal-user-uuid> \
287
- --canvas <canvas-id> --out ./recovered-context.json
288
- # To replace changed content, use the version returned by the latest get:
289
- assethub workspace context put --internal --org <workspace-uuid> --actor <internal-user-uuid> \
290
- --canvas <canvas-id> --file ./edited-context.json --if-version <current-version>
291
- ```
292
-
293
- The document is a JSON object of at most 256 KiB, with `schemaVersion: 1`, a
294
- nonempty `title`, `instructions: {must: string[], avoid: string[]}` (at least one
295
- required instruction), and a nonempty `sources` object array. Other JSON fields
296
- are retained. Source entries can use `remoteAssetId: <uuid> | null`; every
297
- explicit `assetId` / `*AssetId` / `*AssetIds` reference must belong to the workspace.
298
- An unuploaded source may retain a null ID and its provenance.
299
-
300
- The native order's `metadata.projectContext` holds the document, version, content
301
- SHA-256, timestamp and actor. Other metadata is preserved. A changed existing
302
- document requires `--if-version`; identical-content retries do not create a new
303
- version. The write also compares the order's `updated_at`, which the native
304
- `model_workflow_update_updated_at` trigger advances on every update, refusing
305
- concurrent changes to any order metadata. Documents stay in the request body,
306
- so large contexts do not exceed URI limits. If multiple active orders belong to
307
- a canvas, supply `--order`.
308
- The actor must be an internal user with a writable workspace membership; both
309
- project and order ownership are checked. `get --out` writes the original document
310
- and stdout includes its stored envelope. It does not require local CLI state.
311
-
312
- These commands require the existing internal Supabase service environment and
313
- reuse native workspace, moodboard and context contracts separately from the
314
- public API commands. This internal command is unavailable in a standalone
315
- published CLI installation.
253
+ Legacy `workspace --internal` commands and the experimental autopilot demo are
254
+ not available in the standalone distribution. Use the authenticated public
255
+ `canvas`, `moodboard`, and `canvas context` commands described above.
316
256
 
317
257
  ```sh
318
258
  export ASSETHUB_API_KEY=ah_live_xxx
@@ -432,3 +372,37 @@ Internal agent IDs are intentionally not part of the CLI interface.
432
372
 
433
373
  The CLI only uses AssetHub's public API surface and is designed so this package
434
374
  can be published independently from the private application monorepo.
375
+
376
+ ## Workspaces and existing parts
377
+
378
+ Workspace management uses a user access token, separately from workspace API keys.
379
+ Pass the token through standard input; never include it in command arguments.
380
+
381
+ ```sh
382
+ assethub auth login --access-token-stdin
383
+ assethub workspace list
384
+ assethub workspace create --name "Character concepts"
385
+ assethub workspace use <workspace-id>
386
+ assethub canvas list
387
+ assethub canvas use <canvas-id>
388
+ assethub composer models
389
+ assethub composer run --part <mesh-id> --part <mesh-id> --reference <image-id> --wait
390
+ assethub composer run --from-run <run-id> --transforms-json @transforms.json --wait
391
+ ```
392
+
393
+ Selection reuses a valid API key for that workspace or creates one when permitted.
394
+ Membership, API key creation permissions, and workspace MFA still apply. Complete
395
+ required MFA in AssetHub and provide its signed proof through
396
+ `ASSETHUB_WORKSPACE_MFA`. Generation uses normal workspace credits.
397
+
398
+ Existing Production outputs can be inspected and downloaded without regenerating:
399
+
400
+ ```sh
401
+ assethub production status <order-id> --download --out-dir ./existing-assets
402
+ assethub graph export --canvas <canvas-id> --out ./graph.json
403
+ assethub graph lineage --canvas <canvas-id> --artifact <asset-id> --direction ancestors
404
+ ```
405
+
406
+ The graph commands currently cover recorded CLI/API executions and evaluations.
407
+ They do not enumerate every historical UI artifact graph or provide a workspace-wide
408
+ mesh library search. A canvas with only older UI activity can return an empty graph.
@@ -1,5 +1,5 @@
1
- import { type AssetHubClient, type CanvasExecution, type ExecutionContext, type ImageGenerationRequest, type MeshGenerationRequest, type ProductionAnalyzeRequest, type ProductionExecuteRequest, type ProductionAutomationRequest } from '@assethub/api-client';
2
- declare const operations: readonly ["image.generate", "mesh.generate", "production.analyze", "production.execute", "production.automation"];
1
+ import { type AssetHubClient, type CanvasExecution, type ExecutionContext, type ImageGenerationRequest, type MeshGenerationRequest, type MeshComposeRequest, type ProductionAnalyzeRequest, type ProductionExecuteRequest, type ProductionAutomationRequest } from '@assethub/api-client';
2
+ declare const operations: readonly ["image.generate", "mesh.generate", "mesh.compose", "production.analyze", "production.execute", "production.automation"];
3
3
  type Operation = (typeof operations)[number];
4
4
  type SessionOptions = {
5
5
  client: AssetHubClient;
@@ -22,7 +22,7 @@ export declare const openExecutionSession: (options: SessionOptions) => Promise<
22
22
  create?: boolean;
23
23
  }>;
24
24
  type Session = Awaited<ReturnType<typeof openExecutionSession>>;
25
- type RequestBody = ImageGenerationRequest | MeshGenerationRequest | ProductionAnalyzeRequest | ProductionExecuteRequest | ProductionAutomationRequest;
25
+ type RequestBody = ImageGenerationRequest | MeshGenerationRequest | Omit<MeshComposeRequest, 'executionContext'> | ProductionAnalyzeRequest | ProductionExecuteRequest | ProductionAutomationRequest;
26
26
  export declare const hasRecordedOperation: (stateDir: string, operationId: string) => Promise<boolean>;
27
27
  type SubmitOptions = {
28
28
  operationId?: string;
@@ -47,8 +47,6 @@ export declare const activeExecution: {
47
47
  };
48
48
  export declare const executeRecorded: (session: Session, operation: Operation, body: RequestBody, options?: SubmitOptions) => Promise<{
49
49
  execution: CanvasExecution;
50
- } | {
51
- execution: CanvasExecution;
52
50
  jobId: string;
53
51
  imageGenId: string;
54
52
  status: "queued";
@@ -66,6 +64,9 @@ export declare const executeRecorded: (session: Session, operation: Operation, b
66
64
  modelId: string;
67
65
  inputMode: "image" | "multiview";
68
66
  imageCount: number;
67
+ } | {
68
+ execution: CanvasExecution;
69
+ triggerRunId?: string;
69
70
  } | {
70
71
  execution: CanvasExecution;
71
72
  engine?: "artifact-graph";
@@ -110,8 +111,6 @@ export declare const resumeRecorded: (options: Omit<SessionOptions, "canvasId" |
110
111
  expectedBody?: Record<string, unknown>;
111
112
  }) => Promise<{
112
113
  execution: CanvasExecution;
113
- } | {
114
- execution: CanvasExecution;
115
114
  jobId: string;
116
115
  imageGenId: string;
117
116
  status: "queued";
@@ -129,6 +128,9 @@ export declare const resumeRecorded: (options: Omit<SessionOptions, "canvasId" |
129
128
  modelId: string;
130
129
  inputMode: "image" | "multiview";
131
130
  imageCount: number;
131
+ } | {
132
+ execution: CanvasExecution;
133
+ triggerRunId?: string;
132
134
  } | {
133
135
  execution: CanvasExecution;
134
136
  engine?: "artifact-graph";
@@ -1 +1 @@
1
- {"version":3,"file":"execution.d.ts","sourceRoot":"","sources":["../src/execution.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"execution.d.ts","sourceRoot":"","sources":["../src/execution.ts"],"names":[],"mappings":"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"}
package/dist/execution.js CHANGED
@@ -7,6 +7,7 @@ import { readState, resolveCanvasSelection, writeState } from './canvas.js';
7
7
  const operations = [
8
8
  'image.generate',
9
9
  'mesh.generate',
10
+ 'mesh.compose',
10
11
  'production.analyze',
11
12
  'production.execute',
12
13
  'production.automation',
@@ -80,7 +81,12 @@ const submitSaved = async (session, saved, retryDelayMs = 250) => {
80
81
  if (saved.runId) {
81
82
  const execution = await session.client.v2.getRun(saved.runId);
82
83
  activeExecution.execution = execution;
83
- return { execution };
84
+ // An unacknowledged Composer receipt can precede a failed Trigger POST.
85
+ // Resume repeats its saved body/key; the server uses the same native key.
86
+ if (!(saved.operation === 'mesh.compose' &&
87
+ execution.status === 'queued' &&
88
+ execution.history.status === 'pending'))
89
+ return { execution };
84
90
  }
85
91
  for (let attempt = 0;; attempt++) {
86
92
  try {
@@ -91,6 +97,8 @@ const submitSaved = async (session, saved, retryDelayMs = 250) => {
91
97
  return session.client.v2.generateImage(saved.body, options);
92
98
  case 'mesh.generate':
93
99
  return session.client.v2.generateMesh(saved.body, options);
100
+ case 'mesh.compose':
101
+ return session.client.v2.composeMesh(saved.body, options);
94
102
  case 'production.analyze':
95
103
  return session.client.v1.analyzeProduction(saved.body, options);
96
104
  case 'production.execute':
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  import { type AnimationRetargetRequest, type Intervention, type RigRequest } from '@assethub/api-client';
3
3
  import { buildRunUploadPlan } from './runsUpload/buildRunUpload.js';
4
4
  type Flags = Record<string, string | boolean | string[]>;
5
- export declare const usage = "AssetHub CLI\n\nInternal preview: canvas/context/layout and moodboards require workspace feature access.\n\nUsage:\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 status [--profile <name>]\n assethub auth logout [--profile <name>]\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 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 canvas create [--name <name>] [--operation-id <uuid>]\n assethub canvas list [--cursor <cursor>] [--limit <n>]\n assethub canvas get|use|open [<id>]\n assethub runs list [--canvas <id>] [--cursor <cursor>] [--limit <n>]\n assethub runs get|watch <run-id> [--timeout-ms <n>]\n assethub runs resume <operation-id> [--wait]\n assethub graph show|export [--canvas <id>] [--artifact <node-id>] [--out <path>] [--allow-truncated]\n assethub graph lineage --artifact <node-id> [--canvas <id>] [--direction ancestors|descendants|both] [--depth <n>]\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 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>] [--wait] [--download --out-dir <dir>]\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 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 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>] [--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\nGlobal options:\n --api-key <key> Overrides saved auth and ASSETHUB_API_KEY.\n --base-url <url> Defaults to ASSETHUB_API_BASE_URL, saved auth, or https://app.assethub.io.\n --profile <name> Saved auth profile name. Defaults to default.\n --config <path> Auth config path. Defaults to ~/.assethub/config.json.\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 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 run --order-id ord_x --mission-id ms_x --run-mode full_auto --max-cost-credits 200 --wait\n assethub production watch ord_x\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 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";
5
+ export declare const usage = "AssetHub CLI\n\nInternal preview: canvas/context/layout and moodboards require workspace feature access.\n\nUsage:\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|get\n assethub workspace create --name <name> [--operation-id <uuid>]\n assethub workspace use <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 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 composer models\n assethub composer run --part <mesh-asset-id> [--part <mesh-asset-id>...] --reference <image-asset-id> [--model <id>] [--mode quick|quality] [--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 canvas create [--name <name>] [--operation-id <uuid>]\n assethub canvas list [--cursor <cursor>] [--limit <n>]\n assethub canvas get|use|open [<id>]\n assethub runs list [--canvas <id>] [--cursor <cursor>] [--limit <n>]\n assethub runs get|watch <run-id> [--timeout-ms <n>]\n assethub runs resume <operation-id> [--wait]\n assethub graph show|export [--canvas <id>] [--artifact <node-id>] [--out <path>] [--allow-truncated]\n assethub graph lineage --artifact <node-id> [--canvas <id>] [--direction ancestors|descendants|both] [--depth <n>]\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 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>] [--wait] [--download --out-dir <dir>]\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 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 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>] [--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\nGlobal options:\n --api-key <key> Overrides saved auth and ASSETHUB_API_KEY.\n --base-url <url> Defaults to ASSETHUB_API_BASE_URL, saved auth, or https://app.assethub.io.\n --profile <name> Saved auth profile name. Defaults to default.\n --config <path> Auth config path. Defaults to ~/.assethub/config.json.\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 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 run --order-id ord_x --mission-id ms_x --run-mode full_auto --max-cost-credits 200 --wait\n assethub production watch ord_x\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 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";
6
6
  /**
7
7
  * The `animate retarget` request, built from flags alone.
8
8
  *
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAqBA,OAAO,EAEL,KAAK,wBAAwB,EAO7B,KAAK,YAAY,EAEjB,KAAK,UAAU,EAWhB,MAAM,sBAAsB,CAAA;AAa7B,OAAO,EAAC,kBAAkB,EAAc,MAAM,gCAAgC,CAAA;AAI9E,KAAK,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,EAAE,CAAC,CAAA;AA0HxD,eAAO,MAAM,KAAK,80VAoGjB,CAAA;AAy0DD;;;;;;GAMG;AACH,eAAO,MAAM,6BAA6B,GACxC,OAAO,KAAK,KACX,wBA0BF,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,GAChC,OAAO,KAAK,KACX,IAAI,CAAC,UAAU,EAAE,QAAQ,CAM1B,CAAA;AA6fF;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,uBAAuB,GAClC,MAAM,SAAS,MAAM,EAAE,KACtB,YAAY,EAuGd,CAAA;AA8oCD,MAAM,MAAM,cAAc,GAAG;IAC3B,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAA;IAC5B,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;IACvB,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,MAAM,EAAE,OAAO,CAAA;IACf,YAAY,EAAE,OAAO,CAAA;CACtB,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,GAC9B,YAAY,MAAM,GAAG,SAAS,EAC9B,aAAa,MAAM,EAAE,EACrB,OAAO,KAAK,KACX,cAoBF,CAAA;AAED,KAAK,iBAAiB,GAAG,IAAI,CAC3B,OAAO,CAAC,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC,EAC5C,SAAS,GACT,UAAU,GACV,KAAK,GACL,WAAW,GACX,QAAQ,GACR,OAAO,GACP,OAAO,GACP,UAAU,CACb,CAAA;AAED,eAAO,MAAM,iBAAiB,GAC5B,WAAW,MAAM,EACjB,MAAM,iBAAiB;;;;;;;;;;;;;;CAUvB,CAAA;AAEF,eAAO,MAAM,sBAAsB,GACjC,SAAS,UAAU,CAAC,OAAO,iBAAiB,CAAC,EAC7C,MAAM,iBAAiB,EACvB,SAAS,MAAM;;;;;;;;;;;;;;;;;;;;;;;CAYf,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAqBA,OAAO,EAIL,KAAK,wBAAwB,EAO7B,KAAK,YAAY,EAEjB,KAAK,UAAU,EAYhB,MAAM,sBAAsB,CAAA;AAa7B,OAAO,EAAC,kBAAkB,EAAc,MAAM,gCAAgC,CAAA;AAI9E,KAAK,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,EAAE,CAAC,CAAA;AA8HxD,eAAO,MAAM,KAAK,+/WA4GjB,CAAA;AAsnED;;;;;;GAMG;AACH,eAAO,MAAM,6BAA6B,GACxC,OAAO,KAAK,KACX,wBA0BF,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,GAChC,OAAO,KAAK,KACX,IAAI,CAAC,UAAU,EAAE,QAAQ,CAM1B,CAAA;AA6fF;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,uBAAuB,GAClC,MAAM,SAAS,MAAM,EAAE,KACtB,YAAY,EAuGd,CAAA;AA8oCD,MAAM,MAAM,cAAc,GAAG;IAC3B,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAA;IAC5B,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;IACvB,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,MAAM,EAAE,OAAO,CAAA;IACf,YAAY,EAAE,OAAO,CAAA;CACtB,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,GAC9B,YAAY,MAAM,GAAG,SAAS,EAC9B,aAAa,MAAM,EAAE,EACrB,OAAO,KAAK,KACX,cAoBF,CAAA;AAED,KAAK,iBAAiB,GAAG,IAAI,CAC3B,OAAO,CAAC,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC,EAC5C,SAAS,GACT,UAAU,GACV,KAAK,GACL,WAAW,GACX,QAAQ,GACR,OAAO,GACP,OAAO,GACP,UAAU,CACb,CAAA;AAED,eAAO,MAAM,iBAAiB,GAC5B,WAAW,MAAM,EACjB,MAAM,iBAAiB;;;;;;;;;;;;;;CAUvB,CAAA;AAEF,eAAO,MAAM,sBAAsB,GACjC,SAAS,UAAU,CAAC,OAAO,iBAAiB,CAAC,EAC7C,MAAM,iBAAiB,EACvB,SAAS,MAAM;;;;;;;;;;;;;;;;;;;;;;;CAYf,CAAA"}
package/dist/index.js CHANGED
@@ -12,7 +12,7 @@ import { basename, dirname, extname, join, resolve } from 'node:path';
12
12
  import { argv, env, exit, stdin, stderr, stdout } from 'node:process';
13
13
  import { fileURLToPath } from 'node:url';
14
14
  import { promisify } from 'node:util';
15
- import { AssetHubApiError, createAssetHubClient, } from '@assethub/api-client';
15
+ import { AssetHubApiError, WorkspaceClientError, createWorkspaceClient, createAssetHubClient, } from '@assethub/api-client';
16
16
  import { resolveCanvasSelection, saveCanvasSelection } from './canvas.js';
17
17
  import { activeExecution, CliExecutionError, executeRecorded, hasRecordedOperation, openExecutionSession, resumeRecorded, waitForExecution, } from './execution.js';
18
18
  import { buildRunUploadPlan, formatBytes } from './runsUpload/buildRunUpload.js';
@@ -68,8 +68,12 @@ Internal preview: canvas/context/layout and moodboards require workspace feature
68
68
  Usage:
69
69
  assethub auth login --api-key <key> [--base-url <url>] [--profile <name>]
70
70
  assethub auth login --api-key-stdin [--base-url <url>] [--profile <name>]
71
+ assethub auth login --access-token-stdin [--base-url <url>] [--profile <name>]
71
72
  assethub auth status [--profile <name>]
72
73
  assethub auth logout [--profile <name>]
74
+ assethub workspace list|get
75
+ assethub workspace create --name <name> [--operation-id <uuid>]
76
+ assethub workspace use <workspace-id>
73
77
  assethub workspace prepare|sync|analyze|verify --internal --manifest <json> --state <json>
74
78
  assethub workspace self-check --internal
75
79
  assethub workspace context put --internal --org <uuid> --actor <uuid> --canvas <id> --file <json> [--if-version <n>] [--order <uuid>]
@@ -91,6 +95,10 @@ Usage:
91
95
  assethub files upload <file> --media-type image|mesh
92
96
  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>]
93
97
  assethub capabilities
98
+ assethub composer models
99
+ assethub composer run --part <mesh-asset-id> [--part <mesh-asset-id>...] --reference <image-asset-id> [--model <id>] [--mode quick|quality] [--transforms-json <json|@file>] [--canvas <id>] [--wait]
100
+ assethub composer run --input-json <json|@file> [--canvas <id>] [--operation-id <uuid>] [--wait] [--download --out-dir <dir>]
101
+ assethub composer run --from-run <run-id> [--transforms-json <json|@file>] [--mode quick|quality] [--wait]
94
102
  assethub canvas create [--name <name>] [--operation-id <uuid>]
95
103
  assethub canvas list [--cursor <cursor>] [--limit <n>]
96
104
  assethub canvas get|use|open [<id>]
@@ -356,11 +364,12 @@ const readAuthConfig = async (configPath) => {
356
364
  };
357
365
  const writeAuthConfig = async (configPath, config) => {
358
366
  await mkdir(dirname(configPath), { recursive: true, mode: 0o700 });
359
- await writeFile(`${configPath}.tmp`, `${JSON.stringify(config, null, 2)}\n`, {
367
+ const temporary = `${configPath}.${randomUUID()}.tmp`;
368
+ await writeFile(temporary, `${JSON.stringify(config, null, 2)}\n`, {
360
369
  mode: 0o600,
370
+ flag: 'wx',
361
371
  });
362
- await chmod(`${configPath}.tmp`, 0o600);
363
- await rename(`${configPath}.tmp`, configPath);
372
+ await rename(temporary, configPath);
364
373
  await chmod(configPath, 0o600);
365
374
  };
366
375
  const readStdin = async () => await new Promise((resolve, reject) => {
@@ -396,6 +405,28 @@ const resolveAuth = async (flags) => {
396
405
  source: 'flag',
397
406
  };
398
407
  }
408
+ const config = await readAuthConfig(getConfigPath(flags));
409
+ const storedName = getFlag(flags, 'profile') ?? config.defaultProfile ?? profile;
410
+ const storedProfile = config.profiles?.[storedName];
411
+ const storedAuth = storedProfile?.apiKey
412
+ ? {
413
+ apiKey: storedProfile.apiKey,
414
+ baseUrl: baseUrlFromFlags ??
415
+ env.ASSETHUB_API_BASE_URL ??
416
+ storedProfile.baseUrl,
417
+ profile: storedName,
418
+ source: 'profile',
419
+ }
420
+ : undefined;
421
+ // An explicit profile or workspace selection must control the next command,
422
+ // even if the shell still contains the previous organization's key.
423
+ if (storedAuth && (getFlag(flags, 'profile') || storedProfile?.workspaceId)) {
424
+ if (storedProfile?.workspaceId &&
425
+ new URL(storedAuth.baseUrl).origin !==
426
+ new URL(storedProfile.baseUrl).origin)
427
+ throw new Error('Selected workspace belongs to another API origin; select a workspace for this origin or supply an explicit API key');
428
+ return storedAuth;
429
+ }
399
430
  if (env.ASSETHUB_API_KEY != null && env.ASSETHUB_API_KEY.trim() !== '') {
400
431
  return {
401
432
  apiKey: env.ASSETHUB_API_KEY,
@@ -404,23 +435,9 @@ const resolveAuth = async (flags) => {
404
435
  source: 'env',
405
436
  };
406
437
  }
407
- const config = await readAuthConfig(getConfigPath(flags));
408
- const fallbackProfileName = profile === defaultProfileName ? config.defaultProfile : undefined;
409
- const storedProfile = config.profiles?.[profile] ??
410
- (fallbackProfileName != null
411
- ? config.profiles?.[fallbackProfileName]
412
- : undefined);
413
- if (storedProfile != null) {
414
- return {
415
- apiKey: storedProfile.apiKey,
416
- baseUrl: baseUrlFromFlags ?? env.ASSETHUB_API_BASE_URL ?? storedProfile.baseUrl,
417
- profile: config.profiles?.[profile] != null
418
- ? profile
419
- : (fallbackProfileName ?? profile),
420
- source: 'profile',
421
- };
422
- }
423
- throw new Error('Missing API key. Run "assethub auth login --api-key-stdin", set ASSETHUB_API_KEY, or pass --api-key.');
438
+ if (storedAuth)
439
+ return storedAuth;
440
+ throw new Error('Missing workspace API key. Use "workspace use <id>" after user login, "auth login --api-key-stdin", or ASSETHUB_API_KEY.');
424
441
  };
425
442
  const createContext = async (flags, args) => {
426
443
  const auth = await resolveAuth(flags);
@@ -1210,10 +1227,175 @@ const commandModels = async (subcommand, positionals, ctx) => {
1210
1227
  }
1211
1228
  throw new Error('Unknown models command. Use "models list" or "models get".');
1212
1229
  };
1230
+ const workspaceAuth = async (flags) => {
1231
+ const configPath = getConfigPath(flags);
1232
+ const config = await readAuthConfig(configPath);
1233
+ const profile = getFlag(flags, 'profile') ?? config.defaultProfile ?? defaultProfileName;
1234
+ const stored = config.profiles?.[profile];
1235
+ const accessToken = env.ASSETHUB_ACCESS_TOKEN?.trim() || stored?.accessToken;
1236
+ if (!accessToken)
1237
+ throw new Error('Workspace management requires user authentication: auth login --access-token-stdin or ASSETHUB_ACCESS_TOKEN');
1238
+ const baseUrl = getFlag(flags, 'base-url') ??
1239
+ env.ASSETHUB_API_BASE_URL ??
1240
+ stored?.baseUrl ??
1241
+ defaultBaseUrl;
1242
+ if (!env.ASSETHUB_ACCESS_TOKEN?.trim() &&
1243
+ stored &&
1244
+ new URL(baseUrl).origin !== new URL(stored.baseUrl).origin)
1245
+ throw new Error('Saved user authentication belongs to another API origin; log in for this origin');
1246
+ const workspaceMfaToken = env.ASSETHUB_WORKSPACE_MFA?.trim() ||
1247
+ (stored && new URL(baseUrl).origin === new URL(stored.baseUrl).origin
1248
+ ? stored.workspaceMfaToken
1249
+ : undefined);
1250
+ return {
1251
+ configPath,
1252
+ config,
1253
+ profile,
1254
+ accessToken,
1255
+ workspaceMfaToken,
1256
+ baseUrl,
1257
+ client: createWorkspaceClient({ accessToken, workspaceMfaToken, baseUrl }),
1258
+ };
1259
+ };
1260
+ const commandWorkspace = async (subcommand, positionals, flags) => {
1261
+ const auth = await workspaceAuth(flags);
1262
+ if (subcommand === 'list') {
1263
+ print(await auth.client.list());
1264
+ return;
1265
+ }
1266
+ if (subcommand === 'get') {
1267
+ const account = await auth.client.list();
1268
+ const selected = auth.config.profiles?.[auth.profile]?.workspaceId;
1269
+ const workspace = account.workspaces.find(item => selected ? item.id === selected : item.active);
1270
+ if (!workspace)
1271
+ throw new Error('No workspace selected; use workspace use <id>');
1272
+ print(workspace);
1273
+ return;
1274
+ }
1275
+ if (subcommand === 'create') {
1276
+ const name = requireFlag(flags, 'name');
1277
+ const operationId = getFlag(flags, 'operation-id') ?? randomUUID();
1278
+ activeExecution.operationId = operationId;
1279
+ // The caller can replay the printed identity after an uncertain HTTP response.
1280
+ stderr.write(`[workspace] operation ${operationId}\n`);
1281
+ print({
1282
+ ...(await auth.client.create({ name }, { idempotencyKey: operationId })),
1283
+ operationId,
1284
+ });
1285
+ return;
1286
+ }
1287
+ if (subcommand !== 'use')
1288
+ throw new Error('Use workspace list|get|create|use');
1289
+ const workspaceId = requirePositional(positionals, 2, 'workspace-id');
1290
+ const selected = await auth.client.select(workspaceId);
1291
+ if (selected.mfa.status === 'setup_required' ||
1292
+ selected.mfa.status === 'verify_required')
1293
+ throw new Error('Workspace requires MFA. Complete verification in AssetHub, then provide the signed ah_workspace_mfa cookie through ASSETHUB_WORKSPACE_MFA together with your user access token');
1294
+ const account = await auth.client.list();
1295
+ const workspace = account.workspaces.find(item => item.id === workspaceId);
1296
+ if (!workspace)
1297
+ throw new Error('Workspace is not available to this authenticated user');
1298
+ const profiles = auth.config.profiles ?? {};
1299
+ const cached = Object.entries(profiles).find(([, entry]) => entry.userId === account.userId &&
1300
+ entry.workspaceId === workspaceId &&
1301
+ new URL(entry.baseUrl).origin === new URL(auth.baseUrl).origin &&
1302
+ entry.apiKey);
1303
+ let apiKey;
1304
+ const suppliedKey = getFlag(flags, 'api-key') ?? env.ASSETHUB_API_KEY?.trim();
1305
+ for (const candidate of new Set([cached?.[1].apiKey, suppliedKey])) {
1306
+ if (!candidate)
1307
+ continue;
1308
+ try {
1309
+ const capabilities = await createAssetHubClient({
1310
+ apiKey: candidate,
1311
+ baseUrl: auth.baseUrl,
1312
+ }).v2.getCapabilities();
1313
+ if (capabilities.ownerId === workspaceId) {
1314
+ apiKey = candidate;
1315
+ break;
1316
+ }
1317
+ if (candidate === cached?.[1].apiKey)
1318
+ throw new Error('Saved API key does not belong to the selected workspace');
1319
+ }
1320
+ catch (error) {
1321
+ if (!(error instanceof AssetHubApiError) || error.status !== 401)
1322
+ throw error;
1323
+ }
1324
+ }
1325
+ if (!apiKey) {
1326
+ const issued = await auth.client.createApiKey(workspaceId, {
1327
+ name: 'AssetHub CLI',
1328
+ });
1329
+ if (issued.workspaceId !== workspaceId || !issued.key)
1330
+ throw new Error('Workspace API returned an invalid key scope');
1331
+ apiKey = issued.key;
1332
+ }
1333
+ const profile = cached?.[0] ?? `workspace-${account.userId}-${workspaceId}`;
1334
+ profiles[profile] = {
1335
+ apiKey,
1336
+ accessToken: auth.accessToken,
1337
+ workspaceMfaToken: auth.workspaceMfaToken,
1338
+ userId: account.userId,
1339
+ workspaceId,
1340
+ baseUrl: auth.baseUrl,
1341
+ updatedAt: new Date().toISOString(),
1342
+ };
1343
+ await writeAuthConfig(auth.configPath, {
1344
+ ...auth.config,
1345
+ defaultProfile: profile,
1346
+ profiles,
1347
+ });
1348
+ print({
1349
+ workspaceId,
1350
+ workspace,
1351
+ profile,
1352
+ selected: true,
1353
+ baseUrl: auth.baseUrl,
1354
+ });
1355
+ };
1213
1356
  const commandAuth = async (subcommand, flags) => {
1214
1357
  const profile = getProfileName(flags);
1215
1358
  const configPath = getConfigPath(flags);
1216
1359
  if (subcommand === 'login') {
1360
+ if (hasFlag(flags, 'access-token-stdin')) {
1361
+ if (hasFlag(flags, 'api-key-stdin') || getFlag(flags, 'api-key'))
1362
+ throw new Error('Choose user access-token login or API-key login');
1363
+ const accessToken = (await readStdin()).trim();
1364
+ const baseUrl = getFlag(flags, 'base-url') ??
1365
+ env.ASSETHUB_API_BASE_URL ??
1366
+ defaultBaseUrl;
1367
+ const workspaceMfaToken = env.ASSETHUB_WORKSPACE_MFA?.trim() || undefined;
1368
+ const account = await createWorkspaceClient({
1369
+ accessToken,
1370
+ workspaceMfaToken,
1371
+ baseUrl,
1372
+ }).list();
1373
+ const config = await readAuthConfig(configPath);
1374
+ await writeAuthConfig(configPath, {
1375
+ ...config,
1376
+ defaultProfile: profile,
1377
+ profiles: {
1378
+ ...config.profiles,
1379
+ [profile]: {
1380
+ accessToken,
1381
+ workspaceMfaToken,
1382
+ baseUrl,
1383
+ userId: account.userId,
1384
+ updatedAt: new Date().toISOString(),
1385
+ },
1386
+ },
1387
+ });
1388
+ print({
1389
+ success: true,
1390
+ authentication: 'user',
1391
+ userId: account.userId,
1392
+ profile,
1393
+ baseUrl,
1394
+ configPath,
1395
+ verified: true,
1396
+ });
1397
+ return;
1398
+ }
1217
1399
  const apiKey = hasFlag(flags, 'api-key-stdin')
1218
1400
  ? (await readStdin()).trim()
1219
1401
  : (getFlag(flags, 'api-key') ?? env.ASSETHUB_API_KEY ?? '').trim();
@@ -1247,6 +1429,22 @@ const commandAuth = async (subcommand, flags) => {
1247
1429
  return;
1248
1430
  }
1249
1431
  if (subcommand === 'status') {
1432
+ const config = await readAuthConfig(configPath);
1433
+ const current = config.profiles?.[getFlag(flags, 'profile') ?? config.defaultProfile ?? profile];
1434
+ if (env.ASSETHUB_ACCESS_TOKEN?.trim() ||
1435
+ (current?.accessToken && !current.apiKey)) {
1436
+ const auth = await workspaceAuth(flags);
1437
+ const account = await auth.client.list();
1438
+ print({
1439
+ authenticated: true,
1440
+ authentication: 'user',
1441
+ userId: account.userId,
1442
+ workspaceCount: account.workspaces.length,
1443
+ profile: auth.profile,
1444
+ baseUrl: auth.baseUrl,
1445
+ });
1446
+ return;
1447
+ }
1250
1448
  const auth = await resolveAuth(flags);
1251
1449
  const client = createAssetHubClient({
1252
1450
  apiKey: auth.apiKey,
@@ -1265,13 +1463,21 @@ const commandAuth = async (subcommand, flags) => {
1265
1463
  if (subcommand === 'logout') {
1266
1464
  const config = await readAuthConfig(configPath);
1267
1465
  const profiles = config.profiles ?? {};
1268
- const existed = profiles[profile] != null;
1269
- delete profiles[profile];
1466
+ const selectedProfile = getFlag(flags, 'profile') ?? config.defaultProfile ?? profile;
1467
+ const existed = profiles[selectedProfile] != null;
1468
+ delete profiles[selectedProfile];
1270
1469
  await writeAuthConfig(configPath, {
1271
- defaultProfile: config.defaultProfile === profile ? undefined : config.defaultProfile,
1470
+ defaultProfile: config.defaultProfile === selectedProfile
1471
+ ? undefined
1472
+ : config.defaultProfile,
1272
1473
  profiles,
1273
1474
  });
1274
- print({ success: true, profile, removed: existed, configPath });
1475
+ print({
1476
+ success: true,
1477
+ profile: selectedProfile,
1478
+ removed: existed,
1479
+ configPath,
1480
+ });
1275
1481
  return;
1276
1482
  }
1277
1483
  throw new Error('Unknown auth command. Use "auth login", "auth status", or "auth logout".');
@@ -1466,6 +1672,65 @@ const commandImage = async (subcommand, ctx) => {
1466
1672
  input.sources = await Promise.all(input.sources.map(source => recordedSource(ctx, source)));
1467
1673
  await printRecorded(ctx, await executeRecorded(session, 'image.generate', input, { ...executionOptions(ctx.flags), graphSource: graphInput?.graphSource }));
1468
1674
  };
1675
+ const commandComposer = async (subcommand, ctx) => {
1676
+ if (subcommand === 'models') {
1677
+ print(await ctx.client.v2.getMeshComposers());
1678
+ return;
1679
+ }
1680
+ if (subcommand !== 'run')
1681
+ throw new Error('Use composer models|run');
1682
+ const fromRun = getFlag(ctx.flags, 'from-run');
1683
+ const json = getFlag(ctx.flags, 'input-json');
1684
+ const parts = getFlagValues(ctx.flags, 'part');
1685
+ if ((fromRun && (json || parts.length || getFlag(ctx.flags, 'reference'))) ||
1686
+ (json && (parts.length || getFlag(ctx.flags, 'reference'))))
1687
+ throw new Error('Choose --from-run, --input-json, or --part with --reference');
1688
+ const previous = fromRun ? await ctx.client.v2.getRun(fromRun) : undefined;
1689
+ if (previous && previous.operation !== 'mesh.compose')
1690
+ throw new Error('--from-run must identify a mesh.compose execution');
1691
+ const input = previous
1692
+ ? { ...(previous.requestedInput ?? previous.input) }
1693
+ : json
1694
+ ? await readJsonArgument(json, '--input-json')
1695
+ : {
1696
+ parts: parts.map(assetId => ({
1697
+ assetId: assertFlagHasValue(assetId, '--part <asset-id>'),
1698
+ })),
1699
+ fullBodyImageAssetId: requireFlag(ctx.flags, 'reference'),
1700
+ };
1701
+ delete input.executionContext;
1702
+ if (!Array.isArray(input.parts) ||
1703
+ !input.parts.length ||
1704
+ !input.fullBodyImageAssetId)
1705
+ throw new Error('Composer requires parts[] and fullBodyImageAssetId');
1706
+ const mode = getFlag(ctx.flags, 'mode');
1707
+ if (mode != null && mode !== 'quick' && mode !== 'quality')
1708
+ throw new Error('--mode must be quick or quality');
1709
+ if (mode)
1710
+ input.mode = mode;
1711
+ const model = getFlag(ctx.flags, 'model');
1712
+ if (model)
1713
+ input.agentVersion = model;
1714
+ const name = getFlag(ctx.flags, 'name');
1715
+ if (name)
1716
+ input.projectName = name;
1717
+ const transforms = getFlag(ctx.flags, 'transforms-json');
1718
+ if (transforms)
1719
+ input.transforms = await readJsonArgument(transforms, '--transforms-json');
1720
+ const canvasId = selectedCanvasId(ctx.flags) ?? previous?.canvas.id;
1721
+ if (previous && canvasId !== previous.canvas.id)
1722
+ throw new Error('Recomposition must use the original canvas to retain lineage');
1723
+ const session = await openExecutionSession({
1724
+ ...stateOptions(ctx),
1725
+ canvasId,
1726
+ operation: 'mesh.compose',
1727
+ });
1728
+ const queued = await executeRecorded(session, 'mesh.compose', input, {
1729
+ ...executionOptions(ctx.flags),
1730
+ ...(previous ? { parentRunId: previous.runId } : {}),
1731
+ });
1732
+ await printRecorded(ctx, queued);
1733
+ };
1469
1734
  const commandMesh = async (subcommand, ctx) => {
1470
1735
  if (subcommand === 'generate') {
1471
1736
  const inputJson = getFlag(ctx.flags, 'input-json');
@@ -2977,6 +3242,10 @@ const run = async () => {
2977
3242
  return;
2978
3243
  }
2979
3244
  if (command === 'workspace') {
3245
+ if (['list', 'get', 'create', 'use'].includes(subcommand ?? '')) {
3246
+ await commandWorkspace(subcommand, parsed.positionals, parsed.flags);
3247
+ return;
3248
+ }
2980
3249
  if (!hasFlag(parsed.flags, 'internal')) {
2981
3250
  throw new Error('Workspace operations currently require --internal and the AssetHub monorepo with its existing Infisical environment.');
2982
3251
  }
@@ -3010,23 +3279,14 @@ const run = async () => {
3010
3279
  await commandAuth(subcommand, parsed.flags);
3011
3280
  return;
3012
3281
  }
3013
- // The experimental demo uses an unpublished workspace development dependency.
3014
- // Resolve it only for this command so standalone project commands can load.
3015
3282
  if (command === 'autopilot') {
3016
- const { commandAutopilot } = await import('./autopilot.js').catch((error) => {
3017
- if (error instanceof Error &&
3018
- 'code' in error &&
3019
- error.code === 'ERR_MODULE_NOT_FOUND' &&
3020
- error.message.includes('@assethub/autopilot-core')) {
3021
- throw new Error('The experimental autopilot demo requires the AssetHub monorepo with @assethub/autopilot-core installed. Standalone project workflow commands are available without it.');
3022
- }
3023
- throw error;
3024
- });
3025
- await commandAutopilot(parsed.positionals, parsed.flags);
3026
- return;
3283
+ throw new Error('The experimental autopilot demo requires the AssetHub monorepo with @assethub/autopilot-core installed. Standalone project workflow commands are available without it.');
3027
3284
  }
3028
3285
  const ctx = await createContext(parsed.flags, argv.slice(2));
3029
3286
  switch (command) {
3287
+ case 'composer':
3288
+ await commandComposer(subcommand, ctx);
3289
+ return;
3030
3290
  case 'language':
3031
3291
  await commandLanguage(subcommand, ctx);
3032
3292
  return;
@@ -3121,7 +3381,8 @@ if (isMainModule) {
3121
3381
  }
3122
3382
  print({
3123
3383
  error: {
3124
- code: error instanceof AssetHubApiError
3384
+ code: error instanceof AssetHubApiError ||
3385
+ error instanceof WorkspaceClientError
3125
3386
  ? error.code
3126
3387
  : error instanceof CliExecutionError && error.exitCode === 3
3127
3388
  ? 'WAIT_TIMEOUT'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@assethub/cli",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "description": "Command line interface for AssetHub.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -20,22 +20,25 @@
20
20
  "README.md",
21
21
  "LICENSE"
22
22
  ],
23
+ "scripts": {
24
+ "build": "tsc -p tsconfig.json && chmod +x dist/index.js",
25
+ "test": "vitest run",
26
+ "typecheck": "tsc -p tsconfig.typecheck.json --noEmit"
27
+ },
23
28
  "license": "MIT",
24
29
  "publishConfig": {
25
30
  "access": "public"
26
31
  },
27
32
  "dependencies": {
28
- "@assethub/api-client": "^0.1.2"
33
+ "@assethub/api-client": "^0.1.4"
29
34
  },
30
- "devDependencies": {
31
- "@types/node": "24.10.1",
32
- "typescript": "5.9.3",
33
- "vitest": "^4.1.5",
34
- "@assethub/autopilot-core": "0.0.1"
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "git+https://github.com/AssetHub-inc/assethub-cli.git",
38
+ "directory": "packages/assethub-cli"
35
39
  },
36
- "scripts": {
37
- "build": "tsc -p tsconfig.json && chmod +x dist/index.js",
38
- "test": "vitest run",
39
- "typecheck": "tsc -p tsconfig.typecheck.json --noEmit"
40
+ "homepage": "https://github.com/AssetHub-inc/assethub-cli#readme",
41
+ "bugs": {
42
+ "url": "https://github.com/AssetHub-inc/assethub-cli/issues"
40
43
  }
41
- }
44
+ }
@@ -1,13 +0,0 @@
1
- /**
2
- * `assethub autopilot` — drives the auto-split autopilot from the terminal,
3
- * rendering the shared event stream coding-agent style.
4
- *
5
- * The CLI is the primary frontend for the autopilot brain; the in-app chat
6
- * window is the same engine + event stream rendered inside the app. This
7
- * command currently runs against the deterministic MockBackend (`--demo`); the
8
- * real backend (AssetHub API / trigger.dev) is a drop-in AutopilotBackend.
9
- */
10
- type Flags = Record<string, string | boolean | string[]>;
11
- export declare const commandAutopilot: (positionals: string[], flags: Flags) => Promise<void>;
12
- export {};
13
- //# sourceMappingURL=autopilot.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"autopilot.d.ts","sourceRoot":"","sources":["../src/autopilot.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAiBH,KAAK,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,EAAE,CAAC,CAAA;AAmHxD,eAAO,MAAM,gBAAgB,GAC3B,aAAa,MAAM,EAAE,EACrB,OAAO,KAAK,KACX,OAAO,CAAC,IAAI,CAgDd,CAAA"}
package/dist/autopilot.js DELETED
@@ -1,158 +0,0 @@
1
- /**
2
- * `assethub autopilot` — drives the auto-split autopilot from the terminal,
3
- * rendering the shared event stream coding-agent style.
4
- *
5
- * The CLI is the primary frontend for the autopilot brain; the in-app chat
6
- * window is the same engine + event stream rendered inside the app. This
7
- * command currently runs against the deterministic MockBackend (`--demo`); the
8
- * real backend (AssetHub API / trigger.dev) is a drop-in AutopilotBackend.
9
- */
10
- import { createInterface } from 'node:readline/promises';
11
- import { stdin, stdout } from 'node:process';
12
- import { AutopilotEngine, MockBackend, demoConfig, formatEventLine, } from '@assethub/autopilot-core';
13
- // --- tiny ANSI helpers (no dependency) ---
14
- const useColor = stdout.isTTY === true;
15
- const paint = (code, s) => (useColor ? `[${code}m${s}` : s);
16
- const dim = (s) => paint('2', s);
17
- const bold = (s) => paint('1', s);
18
- const green = (s) => paint('32', s);
19
- const yellow = (s) => paint('33', s);
20
- const red = (s) => paint('31', s);
21
- const cyan = (s) => paint('36', s);
22
- const flagStr = (flags, name) => {
23
- const v = flags[name];
24
- return typeof v === 'string' ? v : Array.isArray(v) ? v[0] : undefined;
25
- };
26
- const flagBool = (flags, name) => flags[name] != null;
27
- const flagNum = (flags, name) => {
28
- const s = flagStr(flags, name);
29
- if (s == null)
30
- return undefined;
31
- const n = Number(s);
32
- return Number.isFinite(n) ? n : undefined;
33
- };
34
- /** Colorize the shared narration line for the terminal. */
35
- const colorize = (event, line) => {
36
- switch (event.type) {
37
- case 'run_started':
38
- return bold(cyan(line));
39
- case 'phase_changed':
40
- return bold(line);
41
- case 'log':
42
- if (event.level === 'success')
43
- return green(line);
44
- if (event.level === 'warn')
45
- return yellow(line);
46
- if (event.level === 'error')
47
- return red(line);
48
- return dim(line);
49
- case 'human_review_requested':
50
- return yellow(line);
51
- case 'human_review_resolved':
52
- return cyan(line);
53
- case 'credit_estimate':
54
- return dim(line);
55
- case 'run_finished':
56
- return event.status === 'complete' ? bold(green(line)) : bold(red(line));
57
- default:
58
- return line;
59
- }
60
- };
61
- const PLAN_GLYPH = {
62
- pending: '○',
63
- active: '◐',
64
- done: '●',
65
- skipped: '⊘',
66
- failed: '✗',
67
- };
68
- const renderPlan = (plan, indent = 0) => {
69
- const pad = ' '.repeat(indent);
70
- return plan
71
- .map((step) => {
72
- const head = `${pad}${PLAN_GLYPH[step.status]} ${step.label}${step.detail ? dim(` — ${step.detail}`) : ''}`;
73
- const kids = step.children?.length ? '\n' + renderPlan(step.children, indent + 1) : '';
74
- return head + kids;
75
- })
76
- .join('\n');
77
- };
78
- /** Interactive resolver reading a choice from the TTY; falls back to a policy when not a TTY. */
79
- const makeResolver = (opts) => {
80
- return async (request) => {
81
- const autoChoice = autoPolicy(request);
82
- if (opts.yolo || !opts.interactive) {
83
- if (!opts.quiet)
84
- stdout.write(dim(` → auto: ${autoChoice}\n`));
85
- return { requestId: request.requestId, choice: autoChoice };
86
- }
87
- const rl = createInterface({ input: stdin, output: stdout });
88
- try {
89
- const answer = (await rl.question(cyan(' choose [1..] (enter = auto): '))).trim();
90
- const idx = Number(answer);
91
- if (Number.isInteger(idx) && idx >= 1 && idx <= request.options.length) {
92
- return { requestId: request.requestId, choice: request.options[idx - 1].id };
93
- }
94
- return { requestId: request.requestId, choice: autoChoice };
95
- }
96
- finally {
97
- rl.close();
98
- }
99
- };
100
- };
101
- /** Default non-interactive policy: accept fail parts, pick the first (top-scored) tie candidate. */
102
- const autoPolicy = (request) => {
103
- if (request.kind === 'fail_part')
104
- return 'accept';
105
- return request.options[0].id;
106
- };
107
- const buildConfig = (flags) => {
108
- const base = demoConfig();
109
- return {
110
- ...base,
111
- maxRegenAttempts: flagNum(flags, 'max-regen') ?? base.maxRegenAttempts,
112
- regenStallRounds: flagNum(flags, 'stall-rounds') ?? base.regenStallRounds,
113
- tieEpsilon: flagNum(flags, 'tie-epsilon') ?? base.tieEpsilon,
114
- multiviewGoalId: flagStr(flags, 'multiview') ?? base.multiviewGoalId,
115
- abMode: flagStr(flags, 'ab-mode') === 'cross' ? 'cross' : base.abMode,
116
- creditBudget: flagNum(flags, 'credit-budget') ?? base.creditBudget,
117
- };
118
- };
119
- export const commandAutopilot = async (positionals, flags) => {
120
- const sourceImage = positionals[1] ?? flagStr(flags, 'file') ?? flagStr(flags, 'source-url') ?? 'mock://demo-source.png';
121
- const isDemo = flagBool(flags, 'demo');
122
- const asJson = flagBool(flags, 'json');
123
- if (!isDemo) {
124
- stdout.write(yellow('autopilot: only --demo (deterministic MockBackend) is wired up in this build.\n' +
125
- 'The real backend (AssetHub API / trigger.dev) is a drop-in AutopilotBackend — pass --demo to run the mock end-to-end.\n'));
126
- return;
127
- }
128
- const config = buildConfig(flags);
129
- const events = [];
130
- let lastPlan = [];
131
- const emit = (event) => {
132
- events.push(event);
133
- if (asJson)
134
- return; // collect only; print JSON at the end
135
- if (event.type === 'plan_updated') {
136
- lastPlan = event.plan;
137
- return;
138
- }
139
- const line = formatEventLine(event);
140
- if (line != null)
141
- stdout.write(colorize(event, line) + '\n');
142
- };
143
- const engine = new AutopilotEngine(new MockBackend(), config, {
144
- emit,
145
- resolveHumanReview: makeResolver({
146
- yolo: flagBool(flags, 'yolo'),
147
- interactive: stdin.isTTY === true && !asJson,
148
- quiet: asJson,
149
- }),
150
- runId: 'demo-run',
151
- });
152
- const summary = await engine.run(sourceImage);
153
- if (asJson) {
154
- stdout.write(`${JSON.stringify({ summary, events }, null, 2)}\n`);
155
- return;
156
- }
157
- stdout.write('\n' + bold('Plan') + '\n' + renderPlan(lastPlan) + '\n');
158
- };