@assethub/cli 0.1.8 → 0.1.10
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 +69 -1
- package/dist/execution.d.ts +9 -7
- package/dist/execution.d.ts.map +1 -1
- package/dist/execution.js +9 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +329 -48
- package/dist/setup.d.ts +47 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +177 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -2,6 +2,37 @@
|
|
|
2
2
|
|
|
3
3
|
Command line interface for AssetHub.
|
|
4
4
|
|
|
5
|
+
## Connection diagnostics and MCP
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
assethub --version
|
|
9
|
+
assethub doctor --mcp --profile my-workspace
|
|
10
|
+
assethub mcp config --client cursor
|
|
11
|
+
assethub mcp config --client codex
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
`doctor` checks API access and the authenticated workspace. `--mcp` also checks
|
|
15
|
+
MCP initialization and tool discovery, without invoking any tool or generating
|
|
16
|
+
assets. It returns JSON and exit 0 when checks pass, or exit 2 with a diagnostic
|
|
17
|
+
and next step when a check fails. The default total timeout is 15 seconds; change
|
|
18
|
+
it with `--timeout-ms`. Hosted MCP currently requires Internal access for the key
|
|
19
|
+
creator, independently of regular API access.
|
|
20
|
+
|
|
21
|
+
`mcp config` outputs a Cursor JSON object or Codex TOML section to merge into
|
|
22
|
+
existing user settings. It does not write files or read your saved API key.
|
|
23
|
+
The generated settings read `ASSETHUB_API_KEY` from the AI client's environment.
|
|
24
|
+
Use the same workspace key as your CLI profile. For a different API origin, pass
|
|
25
|
+
`--base-url https://your-host/prefix` (HTTP is accepted only for localhost).
|
|
26
|
+
|
|
27
|
+
Explicit `--profile` uses that profile's key and origin, ahead of environment
|
|
28
|
+
variables, including user tokens and workspace MFA proofs. A missing profile fails.
|
|
29
|
+
Without an explicit profile, a workspace selected with `workspace use` takes
|
|
30
|
+
precedence over environment API credentials; otherwise the environment key
|
|
31
|
+
precedes the saved default. `--api-key` and `--base-url` remain
|
|
32
|
+
explicit overrides. `auth logout` removes the selected saved profile (or the
|
|
33
|
+
saved default); environment credentials remain under your shell’s control.
|
|
34
|
+
Diagnostics omit API keys and raw server error bodies.
|
|
35
|
+
|
|
5
36
|
## Agent generation with canvas history
|
|
6
37
|
|
|
7
38
|
This release uses the Internal `api_canvas_execution` gate. Run `assethub capabilities`
|
|
@@ -38,7 +69,7 @@ state directory private. `--operation-id <uuid>` supplies an operation identity;
|
|
|
38
69
|
retries and `runs resume <operation-id>` reuse its identical body and key. A new
|
|
39
70
|
candidate needs a new operation ID. `runs watch <run-id>` only reads status.
|
|
40
71
|
|
|
41
|
-
stdout contains final JSON; stderr contains progress. Exit codes are 0 for accepted/
|
|
72
|
+
stdout contains final JSON; stderr contains progress. Exceptions: `--version` prints the version, and `mcp config` prints the requested configuration. Exit codes are 0 for accepted/
|
|
42
73
|
completed, 1 for terminal failure/partial, 2 for input/auth/capability/budget errors,
|
|
43
74
|
3 for timeout/history pending/needs review, and 130 for Ctrl-C. Timeout and Ctrl-C
|
|
44
75
|
leave server execution running and return known identities.
|
|
@@ -372,3 +403,40 @@ Internal agent IDs are intentionally not part of the CLI interface.
|
|
|
372
403
|
|
|
373
404
|
The CLI only uses AssetHub's public API surface and is designed so this package
|
|
374
405
|
can be published independently from the private application monorepo.
|
|
406
|
+
|
|
407
|
+
## Workspaces and existing parts
|
|
408
|
+
|
|
409
|
+
Workspace management uses a user access token, separately from workspace API keys.
|
|
410
|
+
Pass the token through standard input; never include it in command arguments.
|
|
411
|
+
|
|
412
|
+
```sh
|
|
413
|
+
assethub auth login --access-token-stdin
|
|
414
|
+
assethub workspace list
|
|
415
|
+
assethub workspace create --name "Character concepts"
|
|
416
|
+
assethub workspace use <workspace-id>
|
|
417
|
+
assethub canvas list
|
|
418
|
+
assethub canvas use <canvas-id>
|
|
419
|
+
assethub composer models
|
|
420
|
+
assethub composer run --part <mesh-id> --part <mesh-id> --reference <image-id> --wait
|
|
421
|
+
assethub composer run --from-run <run-id> --transforms-json @transforms.json --wait
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
Selection reuses a valid API key for that workspace or creates one when permitted.
|
|
425
|
+
Membership, API key creation permissions, and workspace MFA still apply. Complete
|
|
426
|
+
required MFA in AssetHub and provide its signed proof through
|
|
427
|
+
`ASSETHUB_WORKSPACE_MFA` during user login to save it with the profile. Renew an
|
|
428
|
+
expired proof by logging in again. Explicit `--profile` uses its saved proof and
|
|
429
|
+
ignores environment credentials; an explicit `--api-key` can supply the workspace
|
|
430
|
+
key. Generation uses normal workspace credits.
|
|
431
|
+
|
|
432
|
+
Existing Production outputs can be inspected and downloaded without regenerating:
|
|
433
|
+
|
|
434
|
+
```sh
|
|
435
|
+
assethub production status <order-id> --download --out-dir ./existing-assets
|
|
436
|
+
assethub graph export --canvas <canvas-id> --out ./graph.json
|
|
437
|
+
assethub graph lineage --canvas <canvas-id> --artifact <asset-id> --direction ancestors
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
The graph commands currently cover recorded CLI/API executions and evaluations.
|
|
441
|
+
They do not enumerate every historical UI artifact graph or provide a workspace-wide
|
|
442
|
+
mesh library search. A canvas with only older UI activity can return an empty graph.
|
package/dist/execution.d.ts
CHANGED
|
@@ -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";
|
package/dist/execution.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"execution.d.ts","sourceRoot":"","sources":["../src/execution.ts"],"names":[],"mappings":"AAIA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,wBAAwB,EAC7B,KAAK,wBAAwB,EAC7B,KAAK,2BAA2B,EACjC,MAAM,sBAAsB,CAAA;AAG7B,QAAA,MAAM,UAAU,
|
|
1
|
+
{"version":3,"file":"execution.d.ts","sourceRoot":"","sources":["../src/execution.ts"],"names":[],"mappings":"AAIA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,EACvB,KAAK,wBAAwB,EAC7B,KAAK,wBAAwB,EAC7B,KAAK,2BAA2B,EACjC,MAAM,sBAAsB,CAAA;AAG7B,QAAA,MAAM,UAAU,mIAON,CAAA;AACV,KAAK,SAAS,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,CAAC,CAAA;AAC5C,KAAK,cAAc,GAAG;IACpB,MAAM,EAAE,cAAc,CAAA;IACtB,QAAQ,EAAE,MAAM,CAAA;IAChB,GAAG,EAAE,MAAM,CAAA;IACX,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB,CAAA;AACD,eAAO,MAAM,oBAAoB,GAAU,SAAS,cAAc;;;;;YAPxD,cAAc;cACZ,MAAM;SACX,MAAM;eACA,MAAM;gBACL,SAAS;aACZ,OAAO;EAoBjB,CAAA;AACD,KAAK,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC,CAAA;AAC/D,KAAK,WAAW,GACZ,sBAAsB,GACtB,qBAAqB,GACrB,IAAI,CAAC,kBAAkB,EAAE,kBAAkB,CAAC,GAC5C,wBAAwB,GACxB,wBAAwB,GACxB,2BAA2B,CAAA;AAU/B,eAAO,MAAM,oBAAoB,GAC/B,UAAU,MAAM,EAChB,aAAa,MAAM,qBACyD,CAAA;AAC9E,KAAK,aAAa,GAAG;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,KAAK,CAAC,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAA;IACjC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,MAAM,CAAC,EAAE,gBAAgB,CAAC,QAAQ,CAAC,CAAA;IACnC,WAAW,CAAC,EAAE,gBAAgB,CAAC,aAAa,CAAC,CAAA;CAC9C,CAAA;AAED,qBAAa,iBAAkB,SAAQ,KAAK;IAGxC,QAAQ,CAAC,QAAQ;IACjB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM;IAC7B,QAAQ,CAAC,SAAS,CAAC,EAAE,eAAe;IACpC,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS;gBAJlC,OAAO,EAAE,MAAM,EACN,QAAQ,SAAI,EACZ,WAAW,CAAC,EAAE,MAAM,YAAA,EACpB,SAAS,CAAC,EAAE,eAAe,YAAA,EAC3B,KAAK,GAAE,MAAM,GAAG,SAA4B;CAIxD;AAED,yFAAyF;AACzF,eAAO,MAAM,eAAe,EAAE;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,eAAe,CAAA;CACvB,CAAA;AAkKN,eAAO,MAAM,eAAe,GAC1B,SAAS,OAAO,EAChB,WAAW,SAAS,EACpB,MAAM,WAAW,EACjB,UAAS,aAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAsD5B,CAAA;AAED,eAAO,MAAM,cAAc,GACzB,SAAS,IAAI,CAAC,cAAc,EAAE,UAAU,GAAG,WAAW,CAAC,GAAG;IACxD,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACvC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkCF,CAAA;AAED,eAAO,MAAM,gBAAgB,GAC3B,QAAQ,cAAc,EACtB,OAAO,MAAM,EACb,UAAS;IACP,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,UAAU,CAAC,EAAE,CAAC,SAAS,EAAE,eAAe,KAAK,IAAI,CAAA;CAC7C,KACL,OAAO,CAAC,eAAe,CA2CzB,CAAA"}
|
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
|
-
|
|
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 --version\n assethub doctor [--mcp] [--profile <name>] [--timeout-ms <n>]\n assethub mcp config --client cursor|codex [--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|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> Override the selected API origin. Default: https://app.assethub.io.\n --profile <name> Select this saved profile ahead of environment credentials and origin.\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 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
|
*
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAsBA,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,iuXAgHjB,CAAA;AAimED;;;;;;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
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { setTimeout as delay } from 'node:timers/promises';
|
|
3
|
+
import { cliVersion, diagnose, mcpConfig } from './setup.js';
|
|
3
4
|
import { ingestProjectSources } from './projectSources.js';
|
|
4
5
|
import { writeCanvasComparison } from './canvasComparison.js';
|
|
5
6
|
import { importCanvasAssetWithState } from './canvasAssetImport.js';
|
|
@@ -12,7 +13,7 @@ import { basename, dirname, extname, join, resolve } from 'node:path';
|
|
|
12
13
|
import { argv, env, exit, stdin, stderr, stdout } from 'node:process';
|
|
13
14
|
import { fileURLToPath } from 'node:url';
|
|
14
15
|
import { promisify } from 'node:util';
|
|
15
|
-
import { AssetHubApiError, createAssetHubClient, } from '@assethub/api-client';
|
|
16
|
+
import { AssetHubApiError, WorkspaceClientError, createWorkspaceClient, createAssetHubClient, } from '@assethub/api-client';
|
|
16
17
|
import { resolveCanvasSelection, saveCanvasSelection } from './canvas.js';
|
|
17
18
|
import { activeExecution, CliExecutionError, executeRecorded, hasRecordedOperation, openExecutionSession, resumeRecorded, waitForExecution, } from './execution.js';
|
|
18
19
|
import { buildRunUploadPlan, formatBytes } from './runsUpload/buildRunUpload.js';
|
|
@@ -66,10 +67,17 @@ export const usage = `AssetHub CLI
|
|
|
66
67
|
Internal preview: canvas/context/layout and moodboards require workspace feature access.
|
|
67
68
|
|
|
68
69
|
Usage:
|
|
70
|
+
assethub --version
|
|
71
|
+
assethub doctor [--mcp] [--profile <name>] [--timeout-ms <n>]
|
|
72
|
+
assethub mcp config --client cursor|codex [--base-url <url>]
|
|
69
73
|
assethub auth login --api-key <key> [--base-url <url>] [--profile <name>]
|
|
70
74
|
assethub auth login --api-key-stdin [--base-url <url>] [--profile <name>]
|
|
75
|
+
assethub auth login --access-token-stdin [--base-url <url>] [--profile <name>]
|
|
71
76
|
assethub auth status [--profile <name>]
|
|
72
77
|
assethub auth logout [--profile <name>]
|
|
78
|
+
assethub workspace list|get
|
|
79
|
+
assethub workspace create --name <name> [--operation-id <uuid>]
|
|
80
|
+
assethub workspace use <workspace-id>
|
|
73
81
|
assethub workspace prepare|sync|analyze|verify --internal --manifest <json> --state <json>
|
|
74
82
|
assethub workspace self-check --internal
|
|
75
83
|
assethub workspace context put --internal --org <uuid> --actor <uuid> --canvas <id> --file <json> [--if-version <n>] [--order <uuid>]
|
|
@@ -91,6 +99,10 @@ Usage:
|
|
|
91
99
|
assethub files upload <file> --media-type image|mesh
|
|
92
100
|
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
101
|
assethub capabilities
|
|
102
|
+
assethub composer models
|
|
103
|
+
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]
|
|
104
|
+
assethub composer run --input-json <json|@file> [--canvas <id>] [--operation-id <uuid>] [--wait] [--download --out-dir <dir>]
|
|
105
|
+
assethub composer run --from-run <run-id> [--transforms-json <json|@file>] [--mode quick|quality] [--wait]
|
|
94
106
|
assethub canvas create [--name <name>] [--operation-id <uuid>]
|
|
95
107
|
assethub canvas list [--cursor <cursor>] [--limit <n>]
|
|
96
108
|
assethub canvas get|use|open [<id>]
|
|
@@ -131,9 +143,10 @@ Usage:
|
|
|
131
143
|
|
|
132
144
|
Global options:
|
|
133
145
|
--api-key <key> Overrides saved auth and ASSETHUB_API_KEY.
|
|
134
|
-
--base-url <url>
|
|
135
|
-
--profile <name>
|
|
146
|
+
--base-url <url> Override the selected API origin. Default: ${defaultBaseUrl}.
|
|
147
|
+
--profile <name> Select this saved profile ahead of environment credentials and origin.
|
|
136
148
|
--config <path> Auth config path. Defaults to ~/.assethub/config.json.
|
|
149
|
+
--version Show installed package version.
|
|
137
150
|
--help Show help.
|
|
138
151
|
|
|
139
152
|
Examples:
|
|
@@ -331,7 +344,7 @@ const defaultFileNameForMediaType = (mediaType) => mediaType === 'image' ? 'stdi
|
|
|
331
344
|
const getSourceResourceIdFlag = (flags) => getFlag(flags, 'source-resource-id') ??
|
|
332
345
|
getFlag(flags, 'source-id') ??
|
|
333
346
|
getFlag(flags, 'resource-id');
|
|
334
|
-
const getProfileName = (flags) =>
|
|
347
|
+
const getProfileName = (flags) => hasFlag(flags, 'profile') ? requireFlag(flags, 'profile') : defaultProfileName;
|
|
335
348
|
const getConfigPath = (flags) => getFlag(flags, 'config') ??
|
|
336
349
|
env.ASSETHUB_CLI_CONFIG ??
|
|
337
350
|
join(homedir(), '.assethub', 'config.json');
|
|
@@ -356,11 +369,12 @@ const readAuthConfig = async (configPath) => {
|
|
|
356
369
|
};
|
|
357
370
|
const writeAuthConfig = async (configPath, config) => {
|
|
358
371
|
await mkdir(dirname(configPath), { recursive: true, mode: 0o700 });
|
|
359
|
-
|
|
372
|
+
const temporary = `${configPath}.${randomUUID()}.tmp`;
|
|
373
|
+
await writeFile(temporary, `${JSON.stringify(config, null, 2)}\n`, {
|
|
360
374
|
mode: 0o600,
|
|
375
|
+
flag: 'wx',
|
|
361
376
|
});
|
|
362
|
-
await
|
|
363
|
-
await rename(`${configPath}.tmp`, configPath);
|
|
377
|
+
await rename(temporary, configPath);
|
|
364
378
|
await chmod(configPath, 0o600);
|
|
365
379
|
};
|
|
366
380
|
const readStdin = async () => await new Promise((resolve, reject) => {
|
|
@@ -385,42 +399,33 @@ const readStdinBlob = async (type) => await new Promise((resolve, reject) => {
|
|
|
385
399
|
stdin.on('error', reject);
|
|
386
400
|
});
|
|
387
401
|
const resolveAuth = async (flags) => {
|
|
388
|
-
const
|
|
389
|
-
const
|
|
390
|
-
const
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
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.');
|
|
402
|
+
const explicitProfile = hasFlag(flags, 'profile') ? requireFlag(flags, 'profile') : undefined;
|
|
403
|
+
const overrideKey = hasFlag(flags, 'api-key') ? requireFlag(flags, 'api-key') : undefined;
|
|
404
|
+
const config = !overrideKey || explicitProfile
|
|
405
|
+
? await readAuthConfig(getConfigPath(flags))
|
|
406
|
+
: undefined;
|
|
407
|
+
const profile = explicitProfile ?? config?.defaultProfile ?? defaultProfileName;
|
|
408
|
+
const storedProfile = config?.profiles?.[profile];
|
|
409
|
+
const selected = Boolean(explicitProfile || storedProfile?.workspaceId);
|
|
410
|
+
if (selected && (!storedProfile || (!storedProfile.apiKey && !overrideKey)))
|
|
411
|
+
throw new Error('Selected profile has no workspace API key. Use workspace use <id> or auth login --api-key-stdin --profile <name>.');
|
|
412
|
+
const baseUrl = getFlag(flags, 'base-url') ??
|
|
413
|
+
(selected
|
|
414
|
+
? storedProfile.baseUrl
|
|
415
|
+
: env.ASSETHUB_API_BASE_URL ?? storedProfile?.baseUrl ?? defaultBaseUrl);
|
|
416
|
+
if (overrideKey)
|
|
417
|
+
return { apiKey: overrideKey, baseUrl, profile, source: 'flag' };
|
|
418
|
+
if (selected && storedProfile?.apiKey) {
|
|
419
|
+
if (storedProfile.workspaceId &&
|
|
420
|
+
new URL(baseUrl).origin !== new URL(storedProfile.baseUrl).origin)
|
|
421
|
+
throw new Error('Selected workspace belongs to another API origin; select a workspace for this origin or supply an explicit API key');
|
|
422
|
+
return { apiKey: storedProfile.apiKey, baseUrl, profile, source: 'profile' };
|
|
423
|
+
}
|
|
424
|
+
if (env.ASSETHUB_API_KEY?.trim())
|
|
425
|
+
return { apiKey: env.ASSETHUB_API_KEY, baseUrl, profile, source: 'env' };
|
|
426
|
+
if (storedProfile?.apiKey)
|
|
427
|
+
return { apiKey: storedProfile.apiKey, baseUrl, profile, source: 'profile' };
|
|
428
|
+
throw new Error('Missing workspace API key. Use "workspace use <id>" after user login, "auth login --api-key-stdin", or ASSETHUB_API_KEY.');
|
|
424
429
|
};
|
|
425
430
|
const createContext = async (flags, args) => {
|
|
426
431
|
const auth = await resolveAuth(flags);
|
|
@@ -1210,10 +1215,180 @@ const commandModels = async (subcommand, positionals, ctx) => {
|
|
|
1210
1215
|
}
|
|
1211
1216
|
throw new Error('Unknown models command. Use "models list" or "models get".');
|
|
1212
1217
|
};
|
|
1218
|
+
const workspaceAuth = async (flags) => {
|
|
1219
|
+
const configPath = getConfigPath(flags);
|
|
1220
|
+
const config = await readAuthConfig(configPath);
|
|
1221
|
+
const explicitProfile = hasFlag(flags, 'profile') ? requireFlag(flags, 'profile') : undefined;
|
|
1222
|
+
const profile = explicitProfile ?? config.defaultProfile ?? defaultProfileName;
|
|
1223
|
+
const stored = config.profiles?.[profile];
|
|
1224
|
+
const environmentToken = explicitProfile ? undefined : env.ASSETHUB_ACCESS_TOKEN?.trim();
|
|
1225
|
+
const accessToken = environmentToken || stored?.accessToken;
|
|
1226
|
+
if (!accessToken)
|
|
1227
|
+
throw new Error('Workspace management requires user authentication: auth login --access-token-stdin or ASSETHUB_ACCESS_TOKEN');
|
|
1228
|
+
const baseUrl = getFlag(flags, 'base-url') ??
|
|
1229
|
+
(explicitProfile ? stored?.baseUrl : env.ASSETHUB_API_BASE_URL ?? stored?.baseUrl) ??
|
|
1230
|
+
defaultBaseUrl;
|
|
1231
|
+
if (!environmentToken &&
|
|
1232
|
+
stored &&
|
|
1233
|
+
new URL(baseUrl).origin !== new URL(stored.baseUrl).origin)
|
|
1234
|
+
throw new Error('Saved user authentication belongs to another API origin; log in for this origin');
|
|
1235
|
+
const workspaceMfaToken = (!explicitProfile && env.ASSETHUB_WORKSPACE_MFA?.trim()) ||
|
|
1236
|
+
(stored && new URL(baseUrl).origin === new URL(stored.baseUrl).origin
|
|
1237
|
+
? stored.workspaceMfaToken
|
|
1238
|
+
: undefined);
|
|
1239
|
+
return {
|
|
1240
|
+
configPath,
|
|
1241
|
+
config,
|
|
1242
|
+
profile,
|
|
1243
|
+
accessToken,
|
|
1244
|
+
workspaceMfaToken,
|
|
1245
|
+
baseUrl,
|
|
1246
|
+
client: createWorkspaceClient({ accessToken, workspaceMfaToken, baseUrl }),
|
|
1247
|
+
};
|
|
1248
|
+
};
|
|
1249
|
+
const commandWorkspace = async (subcommand, positionals, flags) => {
|
|
1250
|
+
const suppliedKey = hasFlag(flags, 'api-key')
|
|
1251
|
+
? requireFlag(flags, 'api-key')
|
|
1252
|
+
: hasFlag(flags, 'profile')
|
|
1253
|
+
? undefined
|
|
1254
|
+
: env.ASSETHUB_API_KEY?.trim();
|
|
1255
|
+
const auth = await workspaceAuth(flags);
|
|
1256
|
+
if (subcommand === 'list') {
|
|
1257
|
+
print(await auth.client.list());
|
|
1258
|
+
return;
|
|
1259
|
+
}
|
|
1260
|
+
if (subcommand === 'get') {
|
|
1261
|
+
const account = await auth.client.list();
|
|
1262
|
+
const selected = auth.config.profiles?.[auth.profile]?.workspaceId;
|
|
1263
|
+
const workspace = account.workspaces.find(item => selected ? item.id === selected : item.active);
|
|
1264
|
+
if (!workspace)
|
|
1265
|
+
throw new Error('No workspace selected; use workspace use <id>');
|
|
1266
|
+
print(workspace);
|
|
1267
|
+
return;
|
|
1268
|
+
}
|
|
1269
|
+
if (subcommand === 'create') {
|
|
1270
|
+
const name = requireFlag(flags, 'name');
|
|
1271
|
+
const operationId = getFlag(flags, 'operation-id') ?? randomUUID();
|
|
1272
|
+
activeExecution.operationId = operationId;
|
|
1273
|
+
// The caller can replay the printed identity after an uncertain HTTP response.
|
|
1274
|
+
stderr.write(`[workspace] operation ${operationId}\n`);
|
|
1275
|
+
print({
|
|
1276
|
+
...(await auth.client.create({ name }, { idempotencyKey: operationId })),
|
|
1277
|
+
operationId,
|
|
1278
|
+
});
|
|
1279
|
+
return;
|
|
1280
|
+
}
|
|
1281
|
+
if (subcommand !== 'use')
|
|
1282
|
+
throw new Error('Use workspace list|get|create|use');
|
|
1283
|
+
const workspaceId = requirePositional(positionals, 2, 'workspace-id');
|
|
1284
|
+
const selected = await auth.client.select(workspaceId);
|
|
1285
|
+
if (selected.mfa.status === 'setup_required' ||
|
|
1286
|
+
selected.mfa.status === 'verify_required')
|
|
1287
|
+
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');
|
|
1288
|
+
const account = await auth.client.list();
|
|
1289
|
+
const workspace = account.workspaces.find(item => item.id === workspaceId);
|
|
1290
|
+
if (!workspace)
|
|
1291
|
+
throw new Error('Workspace is not available to this authenticated user');
|
|
1292
|
+
const profiles = auth.config.profiles ?? {};
|
|
1293
|
+
const cached = Object.entries(profiles).find(([, entry]) => entry.userId === account.userId &&
|
|
1294
|
+
entry.workspaceId === workspaceId &&
|
|
1295
|
+
new URL(entry.baseUrl).origin === new URL(auth.baseUrl).origin &&
|
|
1296
|
+
entry.apiKey);
|
|
1297
|
+
let apiKey;
|
|
1298
|
+
for (const candidate of new Set([cached?.[1].apiKey, suppliedKey])) {
|
|
1299
|
+
if (!candidate)
|
|
1300
|
+
continue;
|
|
1301
|
+
try {
|
|
1302
|
+
const capabilities = await createAssetHubClient({
|
|
1303
|
+
apiKey: candidate,
|
|
1304
|
+
baseUrl: auth.baseUrl,
|
|
1305
|
+
}).v2.getCapabilities();
|
|
1306
|
+
if (capabilities.ownerId === workspaceId) {
|
|
1307
|
+
apiKey = candidate;
|
|
1308
|
+
break;
|
|
1309
|
+
}
|
|
1310
|
+
if (candidate === cached?.[1].apiKey)
|
|
1311
|
+
throw new Error('Saved API key does not belong to the selected workspace');
|
|
1312
|
+
}
|
|
1313
|
+
catch (error) {
|
|
1314
|
+
if (!(error instanceof AssetHubApiError) || error.status !== 401)
|
|
1315
|
+
throw error;
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
if (!apiKey) {
|
|
1319
|
+
const issued = await auth.client.createApiKey(workspaceId, {
|
|
1320
|
+
name: 'AssetHub CLI',
|
|
1321
|
+
});
|
|
1322
|
+
if (issued.workspaceId !== workspaceId || !issued.key)
|
|
1323
|
+
throw new Error('Workspace API returned an invalid key scope');
|
|
1324
|
+
apiKey = issued.key;
|
|
1325
|
+
}
|
|
1326
|
+
const profile = cached?.[0] ?? `workspace-${account.userId}-${workspaceId}`;
|
|
1327
|
+
profiles[profile] = {
|
|
1328
|
+
apiKey,
|
|
1329
|
+
accessToken: auth.accessToken,
|
|
1330
|
+
workspaceMfaToken: auth.workspaceMfaToken,
|
|
1331
|
+
userId: account.userId,
|
|
1332
|
+
workspaceId,
|
|
1333
|
+
baseUrl: auth.baseUrl,
|
|
1334
|
+
updatedAt: new Date().toISOString(),
|
|
1335
|
+
};
|
|
1336
|
+
await writeAuthConfig(auth.configPath, {
|
|
1337
|
+
...auth.config,
|
|
1338
|
+
defaultProfile: profile,
|
|
1339
|
+
profiles,
|
|
1340
|
+
});
|
|
1341
|
+
print({
|
|
1342
|
+
workspaceId,
|
|
1343
|
+
workspace,
|
|
1344
|
+
profile,
|
|
1345
|
+
selected: true,
|
|
1346
|
+
baseUrl: auth.baseUrl,
|
|
1347
|
+
});
|
|
1348
|
+
};
|
|
1213
1349
|
const commandAuth = async (subcommand, flags) => {
|
|
1214
1350
|
const profile = getProfileName(flags);
|
|
1215
1351
|
const configPath = getConfigPath(flags);
|
|
1216
1352
|
if (subcommand === 'login') {
|
|
1353
|
+
if (hasFlag(flags, 'access-token-stdin')) {
|
|
1354
|
+
if (hasFlag(flags, 'api-key-stdin') || getFlag(flags, 'api-key'))
|
|
1355
|
+
throw new Error('Choose user access-token login or API-key login');
|
|
1356
|
+
const accessToken = (await readStdin()).trim();
|
|
1357
|
+
const baseUrl = getFlag(flags, 'base-url') ??
|
|
1358
|
+
env.ASSETHUB_API_BASE_URL ??
|
|
1359
|
+
defaultBaseUrl;
|
|
1360
|
+
const workspaceMfaToken = env.ASSETHUB_WORKSPACE_MFA?.trim() || undefined;
|
|
1361
|
+
const account = await createWorkspaceClient({
|
|
1362
|
+
accessToken,
|
|
1363
|
+
workspaceMfaToken,
|
|
1364
|
+
baseUrl,
|
|
1365
|
+
}).list();
|
|
1366
|
+
const config = await readAuthConfig(configPath);
|
|
1367
|
+
await writeAuthConfig(configPath, {
|
|
1368
|
+
...config,
|
|
1369
|
+
defaultProfile: profile,
|
|
1370
|
+
profiles: {
|
|
1371
|
+
...config.profiles,
|
|
1372
|
+
[profile]: {
|
|
1373
|
+
accessToken,
|
|
1374
|
+
workspaceMfaToken,
|
|
1375
|
+
baseUrl,
|
|
1376
|
+
userId: account.userId,
|
|
1377
|
+
updatedAt: new Date().toISOString(),
|
|
1378
|
+
},
|
|
1379
|
+
},
|
|
1380
|
+
});
|
|
1381
|
+
print({
|
|
1382
|
+
success: true,
|
|
1383
|
+
authentication: 'user',
|
|
1384
|
+
userId: account.userId,
|
|
1385
|
+
profile,
|
|
1386
|
+
baseUrl,
|
|
1387
|
+
configPath,
|
|
1388
|
+
verified: true,
|
|
1389
|
+
});
|
|
1390
|
+
return;
|
|
1391
|
+
}
|
|
1217
1392
|
const apiKey = hasFlag(flags, 'api-key-stdin')
|
|
1218
1393
|
? (await readStdin()).trim()
|
|
1219
1394
|
: (getFlag(flags, 'api-key') ?? env.ASSETHUB_API_KEY ?? '').trim();
|
|
@@ -1247,6 +1422,22 @@ const commandAuth = async (subcommand, flags) => {
|
|
|
1247
1422
|
return;
|
|
1248
1423
|
}
|
|
1249
1424
|
if (subcommand === 'status') {
|
|
1425
|
+
const config = await readAuthConfig(configPath);
|
|
1426
|
+
const current = config.profiles?.[getFlag(flags, 'profile') ?? config.defaultProfile ?? profile];
|
|
1427
|
+
if ((!hasFlag(flags, 'profile') && env.ASSETHUB_ACCESS_TOKEN?.trim()) ||
|
|
1428
|
+
(current?.accessToken && !current.apiKey)) {
|
|
1429
|
+
const auth = await workspaceAuth(flags);
|
|
1430
|
+
const account = await auth.client.list();
|
|
1431
|
+
print({
|
|
1432
|
+
authenticated: true,
|
|
1433
|
+
authentication: 'user',
|
|
1434
|
+
userId: account.userId,
|
|
1435
|
+
workspaceCount: account.workspaces.length,
|
|
1436
|
+
profile: auth.profile,
|
|
1437
|
+
baseUrl: auth.baseUrl,
|
|
1438
|
+
});
|
|
1439
|
+
return;
|
|
1440
|
+
}
|
|
1250
1441
|
const auth = await resolveAuth(flags);
|
|
1251
1442
|
const client = createAssetHubClient({
|
|
1252
1443
|
apiKey: auth.apiKey,
|
|
@@ -1264,14 +1455,15 @@ const commandAuth = async (subcommand, flags) => {
|
|
|
1264
1455
|
}
|
|
1265
1456
|
if (subcommand === 'logout') {
|
|
1266
1457
|
const config = await readAuthConfig(configPath);
|
|
1458
|
+
const selectedProfile = getFlag(flags, 'profile') ?? config.defaultProfile ?? profile;
|
|
1267
1459
|
const profiles = config.profiles ?? {};
|
|
1268
|
-
const existed = profiles[
|
|
1269
|
-
delete profiles[
|
|
1460
|
+
const existed = profiles[selectedProfile] != null;
|
|
1461
|
+
delete profiles[selectedProfile];
|
|
1270
1462
|
await writeAuthConfig(configPath, {
|
|
1271
|
-
defaultProfile: config.defaultProfile ===
|
|
1463
|
+
defaultProfile: config.defaultProfile === selectedProfile ? undefined : config.defaultProfile,
|
|
1272
1464
|
profiles,
|
|
1273
1465
|
});
|
|
1274
|
-
print({ success: true, profile, removed: existed, configPath });
|
|
1466
|
+
print({ success: true, profile: selectedProfile, removed: existed, configPath });
|
|
1275
1467
|
return;
|
|
1276
1468
|
}
|
|
1277
1469
|
throw new Error('Unknown auth command. Use "auth login", "auth status", or "auth logout".');
|
|
@@ -1466,6 +1658,65 @@ const commandImage = async (subcommand, ctx) => {
|
|
|
1466
1658
|
input.sources = await Promise.all(input.sources.map(source => recordedSource(ctx, source)));
|
|
1467
1659
|
await printRecorded(ctx, await executeRecorded(session, 'image.generate', input, { ...executionOptions(ctx.flags), graphSource: graphInput?.graphSource }));
|
|
1468
1660
|
};
|
|
1661
|
+
const commandComposer = async (subcommand, ctx) => {
|
|
1662
|
+
if (subcommand === 'models') {
|
|
1663
|
+
print(await ctx.client.v2.getMeshComposers());
|
|
1664
|
+
return;
|
|
1665
|
+
}
|
|
1666
|
+
if (subcommand !== 'run')
|
|
1667
|
+
throw new Error('Use composer models|run');
|
|
1668
|
+
const fromRun = getFlag(ctx.flags, 'from-run');
|
|
1669
|
+
const json = getFlag(ctx.flags, 'input-json');
|
|
1670
|
+
const parts = getFlagValues(ctx.flags, 'part');
|
|
1671
|
+
if ((fromRun && (json || parts.length || getFlag(ctx.flags, 'reference'))) ||
|
|
1672
|
+
(json && (parts.length || getFlag(ctx.flags, 'reference'))))
|
|
1673
|
+
throw new Error('Choose --from-run, --input-json, or --part with --reference');
|
|
1674
|
+
const previous = fromRun ? await ctx.client.v2.getRun(fromRun) : undefined;
|
|
1675
|
+
if (previous && previous.operation !== 'mesh.compose')
|
|
1676
|
+
throw new Error('--from-run must identify a mesh.compose execution');
|
|
1677
|
+
const input = previous
|
|
1678
|
+
? { ...(previous.requestedInput ?? previous.input) }
|
|
1679
|
+
: json
|
|
1680
|
+
? await readJsonArgument(json, '--input-json')
|
|
1681
|
+
: {
|
|
1682
|
+
parts: parts.map(assetId => ({
|
|
1683
|
+
assetId: assertFlagHasValue(assetId, '--part <asset-id>'),
|
|
1684
|
+
})),
|
|
1685
|
+
fullBodyImageAssetId: requireFlag(ctx.flags, 'reference'),
|
|
1686
|
+
};
|
|
1687
|
+
delete input.executionContext;
|
|
1688
|
+
if (!Array.isArray(input.parts) ||
|
|
1689
|
+
!input.parts.length ||
|
|
1690
|
+
!input.fullBodyImageAssetId)
|
|
1691
|
+
throw new Error('Composer requires parts[] and fullBodyImageAssetId');
|
|
1692
|
+
const mode = getFlag(ctx.flags, 'mode');
|
|
1693
|
+
if (mode != null && mode !== 'quick' && mode !== 'quality')
|
|
1694
|
+
throw new Error('--mode must be quick or quality');
|
|
1695
|
+
if (mode)
|
|
1696
|
+
input.mode = mode;
|
|
1697
|
+
const model = getFlag(ctx.flags, 'model');
|
|
1698
|
+
if (model)
|
|
1699
|
+
input.agentVersion = model;
|
|
1700
|
+
const name = getFlag(ctx.flags, 'name');
|
|
1701
|
+
if (name)
|
|
1702
|
+
input.projectName = name;
|
|
1703
|
+
const transforms = getFlag(ctx.flags, 'transforms-json');
|
|
1704
|
+
if (transforms)
|
|
1705
|
+
input.transforms = await readJsonArgument(transforms, '--transforms-json');
|
|
1706
|
+
const canvasId = selectedCanvasId(ctx.flags) ?? previous?.canvas.id;
|
|
1707
|
+
if (previous && canvasId !== previous.canvas.id)
|
|
1708
|
+
throw new Error('Recomposition must use the original canvas to retain lineage');
|
|
1709
|
+
const session = await openExecutionSession({
|
|
1710
|
+
...stateOptions(ctx),
|
|
1711
|
+
canvasId,
|
|
1712
|
+
operation: 'mesh.compose',
|
|
1713
|
+
});
|
|
1714
|
+
const queued = await executeRecorded(session, 'mesh.compose', input, {
|
|
1715
|
+
...executionOptions(ctx.flags),
|
|
1716
|
+
...(previous ? { parentRunId: previous.runId } : {}),
|
|
1717
|
+
});
|
|
1718
|
+
await printRecorded(ctx, queued);
|
|
1719
|
+
};
|
|
1469
1720
|
const commandMesh = async (subcommand, ctx) => {
|
|
1470
1721
|
if (subcommand === 'generate') {
|
|
1471
1722
|
const inputJson = getFlag(ctx.flags, 'input-json');
|
|
@@ -2955,11 +3206,33 @@ const parseNonNegativeIntegerFlag = (flags, name) => {
|
|
|
2955
3206
|
};
|
|
2956
3207
|
const run = async () => {
|
|
2957
3208
|
const parsed = parseArgs(argv.slice(2));
|
|
3209
|
+
if (hasFlag(parsed.flags, 'version')) {
|
|
3210
|
+
stdout.write(`${await cliVersion()}\n`);
|
|
3211
|
+
return;
|
|
3212
|
+
}
|
|
2958
3213
|
if (hasFlag(parsed.flags, 'help') || parsed.positionals.length === 0) {
|
|
2959
3214
|
stdout.write(usage);
|
|
2960
3215
|
return;
|
|
2961
3216
|
}
|
|
2962
3217
|
const [command, subcommand] = parsed.positionals;
|
|
3218
|
+
if (command === 'mcp') {
|
|
3219
|
+
if (subcommand !== 'config')
|
|
3220
|
+
throw new Error('Use mcp config --client cursor|codex');
|
|
3221
|
+
stdout.write(mcpConfig(requireFlag(parsed.flags, 'client'), getFlag(parsed.flags, 'base-url') ?? env.ASSETHUB_API_BASE_URL ?? defaultBaseUrl));
|
|
3222
|
+
return;
|
|
3223
|
+
}
|
|
3224
|
+
if (command === 'doctor') {
|
|
3225
|
+
stderr.write('Checking AssetHub connection…\n');
|
|
3226
|
+
const report = await diagnose({
|
|
3227
|
+
resolveAuth: () => resolveAuth(parsed.flags),
|
|
3228
|
+
includeMcp: hasFlag(parsed.flags, 'mcp'),
|
|
3229
|
+
timeoutMs: parsePositiveIntegerFlag(parsed.flags, 'timeout-ms', 15000),
|
|
3230
|
+
});
|
|
3231
|
+
print(report);
|
|
3232
|
+
if (!report.ok)
|
|
3233
|
+
process.exitCode = 2;
|
|
3234
|
+
return;
|
|
3235
|
+
}
|
|
2963
3236
|
if (command === 'project') {
|
|
2964
3237
|
if (subcommand !== 'ingest')
|
|
2965
3238
|
throw new Error('Use project ingest <source-dir> --out-dir <directory>');
|
|
@@ -2977,6 +3250,10 @@ const run = async () => {
|
|
|
2977
3250
|
return;
|
|
2978
3251
|
}
|
|
2979
3252
|
if (command === 'workspace') {
|
|
3253
|
+
if (['list', 'get', 'create', 'use'].includes(subcommand ?? '')) {
|
|
3254
|
+
await commandWorkspace(subcommand, parsed.positionals, parsed.flags);
|
|
3255
|
+
return;
|
|
3256
|
+
}
|
|
2980
3257
|
if (!hasFlag(parsed.flags, 'internal')) {
|
|
2981
3258
|
throw new Error('Workspace operations currently require --internal and the AssetHub monorepo with its existing Infisical environment.');
|
|
2982
3259
|
}
|
|
@@ -3015,6 +3292,9 @@ const run = async () => {
|
|
|
3015
3292
|
}
|
|
3016
3293
|
const ctx = await createContext(parsed.flags, argv.slice(2));
|
|
3017
3294
|
switch (command) {
|
|
3295
|
+
case 'composer':
|
|
3296
|
+
await commandComposer(subcommand, ctx);
|
|
3297
|
+
return;
|
|
3018
3298
|
case 'language':
|
|
3019
3299
|
await commandLanguage(subcommand, ctx);
|
|
3020
3300
|
return;
|
|
@@ -3109,7 +3389,8 @@ if (isMainModule) {
|
|
|
3109
3389
|
}
|
|
3110
3390
|
print({
|
|
3111
3391
|
error: {
|
|
3112
|
-
code: error instanceof AssetHubApiError
|
|
3392
|
+
code: error instanceof AssetHubApiError ||
|
|
3393
|
+
error instanceof WorkspaceClientError
|
|
3113
3394
|
? error.code
|
|
3114
3395
|
: error instanceof CliExecutionError && error.exitCode === 3
|
|
3115
3396
|
? 'WAIT_TIMEOUT'
|
package/dist/setup.d.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export declare const cliVersion: () => Promise<string>;
|
|
2
|
+
export declare const mcpConfig: (client: string, baseUrl: string) => string;
|
|
3
|
+
type Check = {
|
|
4
|
+
name: 'api' | 'mcp' | 'configuration';
|
|
5
|
+
status: 'pass' | 'fail';
|
|
6
|
+
code?: string;
|
|
7
|
+
message?: string;
|
|
8
|
+
hint?: string;
|
|
9
|
+
workspaceId?: string;
|
|
10
|
+
executionStatus?: string;
|
|
11
|
+
toolCount?: number;
|
|
12
|
+
};
|
|
13
|
+
type Auth = {
|
|
14
|
+
apiKey: string;
|
|
15
|
+
baseUrl: string;
|
|
16
|
+
profile: string;
|
|
17
|
+
source: string;
|
|
18
|
+
};
|
|
19
|
+
export declare const diagnose: ({ resolveAuth, includeMcp, timeoutMs, }: {
|
|
20
|
+
resolveAuth: () => Promise<Auth>;
|
|
21
|
+
includeMcp: boolean;
|
|
22
|
+
timeoutMs: number;
|
|
23
|
+
}) => Promise<{
|
|
24
|
+
ok: boolean;
|
|
25
|
+
version: string;
|
|
26
|
+
nodeVersion: string;
|
|
27
|
+
checks: {
|
|
28
|
+
name: "configuration";
|
|
29
|
+
status: "fail";
|
|
30
|
+
code: string;
|
|
31
|
+
message: string;
|
|
32
|
+
hint: string;
|
|
33
|
+
}[];
|
|
34
|
+
auth?: undefined;
|
|
35
|
+
} | {
|
|
36
|
+
ok: boolean;
|
|
37
|
+
version: string;
|
|
38
|
+
nodeVersion: string;
|
|
39
|
+
auth: {
|
|
40
|
+
profile: string;
|
|
41
|
+
source: string;
|
|
42
|
+
baseUrl: string;
|
|
43
|
+
};
|
|
44
|
+
checks: [Check, ...Check[]];
|
|
45
|
+
}>;
|
|
46
|
+
export {};
|
|
47
|
+
//# sourceMappingURL=setup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,UAAU,QAAa,OAAO,CAAC,MAAM,CAKvC,CAAA;AAmBX,eAAO,MAAM,SAAS,GAAI,QAAQ,MAAM,EAAE,SAAS,MAAM,KAAG,MAoB3D,CAAA;AAED,KAAK,KAAK,GAAG;IACX,IAAI,EAAE,KAAK,GAAG,KAAK,GAAG,eAAe,CAAA;IACrC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAA;IACvB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED,KAAK,IAAI,GAAG;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAC,CAAA;AA0D9E,eAAO,MAAM,QAAQ,GAAU,yCAI5B;IACD,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAChC,UAAU,EAAE,OAAO,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;CAClB;;;;;;;;;;;;;;;;;;;;;;EAyGA,CAAA"}
|
package/dist/setup.js
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { AssetHubApiError, createAssetHubClient } from '@assethub/api-client';
|
|
3
|
+
export const cliVersion = async () => JSON.parse(await readFile(new URL('../package.json', import.meta.url), 'utf8')).version;
|
|
4
|
+
const validatedBaseUrl = (baseUrl) => {
|
|
5
|
+
const url = new URL(baseUrl);
|
|
6
|
+
if (url.username || url.password || url.search || url.hash)
|
|
7
|
+
throw new Error('Use an API URL without credentials, query, or fragment.');
|
|
8
|
+
if (url.protocol !== 'https:' &&
|
|
9
|
+
!(url.protocol === 'http:' &&
|
|
10
|
+
['localhost', '127.0.0.1', '[::1]'].includes(url.hostname)))
|
|
11
|
+
throw new Error('Use HTTPS for remote servers; HTTP is supported only on localhost.');
|
|
12
|
+
return url.href.replace(/\/+$/, '');
|
|
13
|
+
};
|
|
14
|
+
export const mcpConfig = (client, baseUrl) => {
|
|
15
|
+
const url = `${validatedBaseUrl(baseUrl)}/api/mcp`;
|
|
16
|
+
if (client === 'cursor')
|
|
17
|
+
return (JSON.stringify({
|
|
18
|
+
mcpServers: {
|
|
19
|
+
assethub: {
|
|
20
|
+
url,
|
|
21
|
+
headers: { Authorization: 'Bearer ${env:ASSETHUB_API_KEY}' },
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
}, null, 2) + '\n');
|
|
25
|
+
if (client === 'codex')
|
|
26
|
+
return `[mcp_servers.assethub]\nurl = ${JSON.stringify(url)}\nbearer_token_env_var = "ASSETHUB_API_KEY"\n`;
|
|
27
|
+
throw new Error('Use mcp config --client cursor|codex');
|
|
28
|
+
};
|
|
29
|
+
const failedCheck = (name, status, timedOut) => {
|
|
30
|
+
if (timedOut)
|
|
31
|
+
return {
|
|
32
|
+
name,
|
|
33
|
+
status: 'fail',
|
|
34
|
+
code: 'TIMEOUT',
|
|
35
|
+
message: 'Connection timed out.',
|
|
36
|
+
hint: 'Check your network or retry with --timeout-ms 30000.',
|
|
37
|
+
};
|
|
38
|
+
if (status === 401)
|
|
39
|
+
return {
|
|
40
|
+
name,
|
|
41
|
+
status: 'fail',
|
|
42
|
+
code: 'UNAUTHORIZED',
|
|
43
|
+
message: 'The API key was rejected.',
|
|
44
|
+
hint: 'Run assethub auth login --api-key-stdin with a current workspace key.',
|
|
45
|
+
};
|
|
46
|
+
if (status === 403)
|
|
47
|
+
return {
|
|
48
|
+
name,
|
|
49
|
+
status: 'fail',
|
|
50
|
+
code: 'FORBIDDEN',
|
|
51
|
+
message: 'This account or workspace does not have access.',
|
|
52
|
+
hint: 'Check the API key workspace and account access.',
|
|
53
|
+
};
|
|
54
|
+
if (name === 'mcp' && status === 404)
|
|
55
|
+
return {
|
|
56
|
+
name,
|
|
57
|
+
status: 'fail',
|
|
58
|
+
code: 'MCP_UNAVAILABLE',
|
|
59
|
+
message: 'Hosted MCP is unavailable for this account or API origin.',
|
|
60
|
+
hint: 'Hosted MCP is in Internal preview. Check access for the account that created the API key.',
|
|
61
|
+
};
|
|
62
|
+
if (status === 429)
|
|
63
|
+
return {
|
|
64
|
+
name,
|
|
65
|
+
status: 'fail',
|
|
66
|
+
code: 'RATE_LIMITED',
|
|
67
|
+
message: 'Too many requests.',
|
|
68
|
+
hint: 'Wait before retrying the check.',
|
|
69
|
+
};
|
|
70
|
+
// Server response text may contain credentials or private data. Report only
|
|
71
|
+
// fixed diagnostics; do not include arbitrary error messages in shareable output.
|
|
72
|
+
return {
|
|
73
|
+
name,
|
|
74
|
+
status: 'fail',
|
|
75
|
+
code: status && status >= 500 ? 'SERVER_ERROR' : 'CONNECTION_FAILED',
|
|
76
|
+
message: 'The connection check failed.',
|
|
77
|
+
hint: 'Check the API origin, network, and service status; then retry.',
|
|
78
|
+
};
|
|
79
|
+
};
|
|
80
|
+
export const diagnose = async ({ resolveAuth, includeMcp, timeoutMs, }) => {
|
|
81
|
+
const version = await cliVersion();
|
|
82
|
+
let auth;
|
|
83
|
+
try {
|
|
84
|
+
auth = await resolveAuth();
|
|
85
|
+
auth.baseUrl = validatedBaseUrl(auth.baseUrl);
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return {
|
|
89
|
+
ok: false,
|
|
90
|
+
version,
|
|
91
|
+
nodeVersion: process.version,
|
|
92
|
+
checks: [
|
|
93
|
+
{
|
|
94
|
+
name: 'configuration',
|
|
95
|
+
status: 'fail',
|
|
96
|
+
code: 'AUTH_CONFIGURATION',
|
|
97
|
+
message: 'No usable credentials or API origin for the selected profile.',
|
|
98
|
+
hint: 'Check --profile and --base-url. Select a workspace with assethub workspace use <id> after user login, or run assethub auth login --api-key-stdin.',
|
|
99
|
+
},
|
|
100
|
+
],
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
const signal = AbortSignal.timeout(timeoutMs);
|
|
104
|
+
// Bound the entire transport, including initialize and SSE, and do not follow
|
|
105
|
+
// redirects while carrying the workspace key.
|
|
106
|
+
const boundedFetch = (input, init) => fetch(input, {
|
|
107
|
+
...init,
|
|
108
|
+
redirect: 'error',
|
|
109
|
+
signal: init?.signal ? AbortSignal.any([init.signal, signal]) : signal,
|
|
110
|
+
});
|
|
111
|
+
const apiCheck = async () => {
|
|
112
|
+
try {
|
|
113
|
+
const capabilities = await createAssetHubClient({
|
|
114
|
+
apiKey: auth.apiKey,
|
|
115
|
+
baseUrl: auth.baseUrl,
|
|
116
|
+
fetch: boundedFetch,
|
|
117
|
+
}).v2.getCapabilities();
|
|
118
|
+
if (typeof capabilities.ownerId !== 'string' || !capabilities.ownerId)
|
|
119
|
+
throw new Error('Invalid capabilities');
|
|
120
|
+
return {
|
|
121
|
+
name: 'api',
|
|
122
|
+
status: 'pass',
|
|
123
|
+
workspaceId: capabilities.ownerId,
|
|
124
|
+
executionStatus: capabilities.executionContext?.status,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
return failedCheck('api', error instanceof AssetHubApiError ? error.status : undefined, signal.aborted);
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
const mcpCheck = async () => {
|
|
132
|
+
const { Client } = await import('@modelcontextprotocol/sdk/client/index.js');
|
|
133
|
+
const { StreamableHTTPClientTransport, StreamableHTTPError } = await import('@modelcontextprotocol/sdk/client/streamableHttp.js');
|
|
134
|
+
const client = new Client({ name: 'assethub-cli-doctor', version });
|
|
135
|
+
try {
|
|
136
|
+
await client.connect(new StreamableHTTPClientTransport(new URL(`${auth.baseUrl}/api/mcp`), {
|
|
137
|
+
fetch: boundedFetch,
|
|
138
|
+
requestInit: { headers: { Authorization: `Bearer ${auth.apiKey}` } },
|
|
139
|
+
}), { signal, timeout: timeoutMs });
|
|
140
|
+
let toolCount = 0;
|
|
141
|
+
let cursor;
|
|
142
|
+
const cursors = new Set();
|
|
143
|
+
do {
|
|
144
|
+
const page = await client.listTools(cursor ? { cursor } : {}, {
|
|
145
|
+
signal,
|
|
146
|
+
timeout: timeoutMs,
|
|
147
|
+
});
|
|
148
|
+
toolCount += page.tools.length;
|
|
149
|
+
cursor = page.nextCursor;
|
|
150
|
+
if (cursor && cursors.has(cursor))
|
|
151
|
+
throw new Error('Repeated tool cursor');
|
|
152
|
+
if (cursor)
|
|
153
|
+
cursors.add(cursor);
|
|
154
|
+
} while (cursor);
|
|
155
|
+
if (!toolCount)
|
|
156
|
+
throw new Error('No MCP tools');
|
|
157
|
+
return { name: 'mcp', status: 'pass', toolCount };
|
|
158
|
+
}
|
|
159
|
+
catch (error) {
|
|
160
|
+
return failedCheck('mcp', error instanceof StreamableHTTPError ? error.code : undefined, signal.aborted);
|
|
161
|
+
}
|
|
162
|
+
finally {
|
|
163
|
+
await client.close();
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
const checks = await Promise.all([
|
|
167
|
+
apiCheck(),
|
|
168
|
+
...(includeMcp ? [mcpCheck()] : []),
|
|
169
|
+
]);
|
|
170
|
+
return {
|
|
171
|
+
ok: checks.every(check => check.status === 'pass'),
|
|
172
|
+
version,
|
|
173
|
+
nodeVersion: process.version,
|
|
174
|
+
auth: { profile: auth.profile, source: auth.source, baseUrl: auth.baseUrl },
|
|
175
|
+
checks,
|
|
176
|
+
};
|
|
177
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@assethub/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.10",
|
|
4
4
|
"description": "Command line interface for AssetHub.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -30,7 +30,8 @@
|
|
|
30
30
|
"access": "public"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@assethub/api-client": "^0.1.
|
|
33
|
+
"@assethub/api-client": "^0.1.4",
|
|
34
|
+
"@modelcontextprotocol/sdk": "^1.30.0"
|
|
34
35
|
},
|
|
35
36
|
"repository": {
|
|
36
37
|
"type": "git",
|