@assethub/cli 0.1.9 → 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 +36 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +69 -61
- 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.
|
|
@@ -393,7 +424,10 @@ assethub composer run --from-run <run-id> --transforms-json @transforms.json --w
|
|
|
393
424
|
Selection reuses a valid API key for that workspace or creates one when permitted.
|
|
394
425
|
Membership, API key creation permissions, and workspace MFA still apply. Complete
|
|
395
426
|
required MFA in AssetHub and provide its signed proof through
|
|
396
|
-
`ASSETHUB_WORKSPACE_MFA
|
|
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.
|
|
397
431
|
|
|
398
432
|
Existing Production outputs can be inspected and downloaded without regenerating:
|
|
399
433
|
|
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 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";
|
|
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';
|
|
@@ -66,6 +67,9 @@ 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>]
|
|
71
75
|
assethub auth login --access-token-stdin [--base-url <url>] [--profile <name>]
|
|
@@ -139,9 +143,10 @@ Usage:
|
|
|
139
143
|
|
|
140
144
|
Global options:
|
|
141
145
|
--api-key <key> Overrides saved auth and ASSETHUB_API_KEY.
|
|
142
|
-
--base-url <url>
|
|
143
|
-
--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.
|
|
144
148
|
--config <path> Auth config path. Defaults to ~/.assethub/config.json.
|
|
149
|
+
--version Show installed package version.
|
|
145
150
|
--help Show help.
|
|
146
151
|
|
|
147
152
|
Examples:
|
|
@@ -339,7 +344,7 @@ const defaultFileNameForMediaType = (mediaType) => mediaType === 'image' ? 'stdi
|
|
|
339
344
|
const getSourceResourceIdFlag = (flags) => getFlag(flags, 'source-resource-id') ??
|
|
340
345
|
getFlag(flags, 'source-id') ??
|
|
341
346
|
getFlag(flags, 'resource-id');
|
|
342
|
-
const getProfileName = (flags) =>
|
|
347
|
+
const getProfileName = (flags) => hasFlag(flags, 'profile') ? requireFlag(flags, 'profile') : defaultProfileName;
|
|
343
348
|
const getConfigPath = (flags) => getFlag(flags, 'config') ??
|
|
344
349
|
env.ASSETHUB_CLI_CONFIG ??
|
|
345
350
|
join(homedir(), '.assethub', 'config.json');
|
|
@@ -394,49 +399,32 @@ const readStdinBlob = async (type) => await new Promise((resolve, reject) => {
|
|
|
394
399
|
stdin.on('error', reject);
|
|
395
400
|
});
|
|
396
401
|
const resolveAuth = async (flags) => {
|
|
397
|
-
const
|
|
398
|
-
const
|
|
399
|
-
const
|
|
400
|
-
|
|
401
|
-
return {
|
|
402
|
-
apiKey: apiKeyFromFlags,
|
|
403
|
-
baseUrl: baseUrlFromFlags ?? env.ASSETHUB_API_BASE_URL ?? defaultBaseUrl,
|
|
404
|
-
profile,
|
|
405
|
-
source: 'flag',
|
|
406
|
-
};
|
|
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
|
-
}
|
|
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))
|
|
420
406
|
: undefined;
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
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)
|
|
427
421
|
throw new Error('Selected workspace belongs to another API origin; select a workspace for this origin or supply an explicit API key');
|
|
428
|
-
return
|
|
422
|
+
return { apiKey: storedProfile.apiKey, baseUrl, profile, source: 'profile' };
|
|
429
423
|
}
|
|
430
|
-
if (env.ASSETHUB_API_KEY
|
|
431
|
-
return {
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
profile,
|
|
435
|
-
source: 'env',
|
|
436
|
-
};
|
|
437
|
-
}
|
|
438
|
-
if (storedAuth)
|
|
439
|
-
return storedAuth;
|
|
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' };
|
|
440
428
|
throw new Error('Missing workspace API key. Use "workspace use <id>" after user login, "auth login --api-key-stdin", or ASSETHUB_API_KEY.');
|
|
441
429
|
};
|
|
442
430
|
const createContext = async (flags, args) => {
|
|
@@ -1230,20 +1218,21 @@ const commandModels = async (subcommand, positionals, ctx) => {
|
|
|
1230
1218
|
const workspaceAuth = async (flags) => {
|
|
1231
1219
|
const configPath = getConfigPath(flags);
|
|
1232
1220
|
const config = await readAuthConfig(configPath);
|
|
1233
|
-
const
|
|
1221
|
+
const explicitProfile = hasFlag(flags, 'profile') ? requireFlag(flags, 'profile') : undefined;
|
|
1222
|
+
const profile = explicitProfile ?? config.defaultProfile ?? defaultProfileName;
|
|
1234
1223
|
const stored = config.profiles?.[profile];
|
|
1235
|
-
const
|
|
1224
|
+
const environmentToken = explicitProfile ? undefined : env.ASSETHUB_ACCESS_TOKEN?.trim();
|
|
1225
|
+
const accessToken = environmentToken || stored?.accessToken;
|
|
1236
1226
|
if (!accessToken)
|
|
1237
1227
|
throw new Error('Workspace management requires user authentication: auth login --access-token-stdin or ASSETHUB_ACCESS_TOKEN');
|
|
1238
1228
|
const baseUrl = getFlag(flags, 'base-url') ??
|
|
1239
|
-
env.ASSETHUB_API_BASE_URL ??
|
|
1240
|
-
stored?.baseUrl ??
|
|
1229
|
+
(explicitProfile ? stored?.baseUrl : env.ASSETHUB_API_BASE_URL ?? stored?.baseUrl) ??
|
|
1241
1230
|
defaultBaseUrl;
|
|
1242
|
-
if (!
|
|
1231
|
+
if (!environmentToken &&
|
|
1243
1232
|
stored &&
|
|
1244
1233
|
new URL(baseUrl).origin !== new URL(stored.baseUrl).origin)
|
|
1245
1234
|
throw new Error('Saved user authentication belongs to another API origin; log in for this origin');
|
|
1246
|
-
const workspaceMfaToken = env.ASSETHUB_WORKSPACE_MFA?.trim() ||
|
|
1235
|
+
const workspaceMfaToken = (!explicitProfile && env.ASSETHUB_WORKSPACE_MFA?.trim()) ||
|
|
1247
1236
|
(stored && new URL(baseUrl).origin === new URL(stored.baseUrl).origin
|
|
1248
1237
|
? stored.workspaceMfaToken
|
|
1249
1238
|
: undefined);
|
|
@@ -1258,6 +1247,11 @@ const workspaceAuth = async (flags) => {
|
|
|
1258
1247
|
};
|
|
1259
1248
|
};
|
|
1260
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();
|
|
1261
1255
|
const auth = await workspaceAuth(flags);
|
|
1262
1256
|
if (subcommand === 'list') {
|
|
1263
1257
|
print(await auth.client.list());
|
|
@@ -1301,7 +1295,6 @@ const commandWorkspace = async (subcommand, positionals, flags) => {
|
|
|
1301
1295
|
new URL(entry.baseUrl).origin === new URL(auth.baseUrl).origin &&
|
|
1302
1296
|
entry.apiKey);
|
|
1303
1297
|
let apiKey;
|
|
1304
|
-
const suppliedKey = getFlag(flags, 'api-key') ?? env.ASSETHUB_API_KEY?.trim();
|
|
1305
1298
|
for (const candidate of new Set([cached?.[1].apiKey, suppliedKey])) {
|
|
1306
1299
|
if (!candidate)
|
|
1307
1300
|
continue;
|
|
@@ -1431,7 +1424,7 @@ const commandAuth = async (subcommand, flags) => {
|
|
|
1431
1424
|
if (subcommand === 'status') {
|
|
1432
1425
|
const config = await readAuthConfig(configPath);
|
|
1433
1426
|
const current = config.profiles?.[getFlag(flags, 'profile') ?? config.defaultProfile ?? profile];
|
|
1434
|
-
if (env.ASSETHUB_ACCESS_TOKEN?.trim() ||
|
|
1427
|
+
if ((!hasFlag(flags, 'profile') && env.ASSETHUB_ACCESS_TOKEN?.trim()) ||
|
|
1435
1428
|
(current?.accessToken && !current.apiKey)) {
|
|
1436
1429
|
const auth = await workspaceAuth(flags);
|
|
1437
1430
|
const account = await auth.client.list();
|
|
@@ -1462,22 +1455,15 @@ const commandAuth = async (subcommand, flags) => {
|
|
|
1462
1455
|
}
|
|
1463
1456
|
if (subcommand === 'logout') {
|
|
1464
1457
|
const config = await readAuthConfig(configPath);
|
|
1465
|
-
const profiles = config.profiles ?? {};
|
|
1466
1458
|
const selectedProfile = getFlag(flags, 'profile') ?? config.defaultProfile ?? profile;
|
|
1459
|
+
const profiles = config.profiles ?? {};
|
|
1467
1460
|
const existed = profiles[selectedProfile] != null;
|
|
1468
1461
|
delete profiles[selectedProfile];
|
|
1469
1462
|
await writeAuthConfig(configPath, {
|
|
1470
|
-
defaultProfile: config.defaultProfile === selectedProfile
|
|
1471
|
-
? undefined
|
|
1472
|
-
: config.defaultProfile,
|
|
1463
|
+
defaultProfile: config.defaultProfile === selectedProfile ? undefined : config.defaultProfile,
|
|
1473
1464
|
profiles,
|
|
1474
1465
|
});
|
|
1475
|
-
print({
|
|
1476
|
-
success: true,
|
|
1477
|
-
profile: selectedProfile,
|
|
1478
|
-
removed: existed,
|
|
1479
|
-
configPath,
|
|
1480
|
-
});
|
|
1466
|
+
print({ success: true, profile: selectedProfile, removed: existed, configPath });
|
|
1481
1467
|
return;
|
|
1482
1468
|
}
|
|
1483
1469
|
throw new Error('Unknown auth command. Use "auth login", "auth status", or "auth logout".');
|
|
@@ -3220,11 +3206,33 @@ const parseNonNegativeIntegerFlag = (flags, name) => {
|
|
|
3220
3206
|
};
|
|
3221
3207
|
const run = async () => {
|
|
3222
3208
|
const parsed = parseArgs(argv.slice(2));
|
|
3209
|
+
if (hasFlag(parsed.flags, 'version')) {
|
|
3210
|
+
stdout.write(`${await cliVersion()}\n`);
|
|
3211
|
+
return;
|
|
3212
|
+
}
|
|
3223
3213
|
if (hasFlag(parsed.flags, 'help') || parsed.positionals.length === 0) {
|
|
3224
3214
|
stdout.write(usage);
|
|
3225
3215
|
return;
|
|
3226
3216
|
}
|
|
3227
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
|
+
}
|
|
3228
3236
|
if (command === 'project') {
|
|
3229
3237
|
if (subcommand !== 'ingest')
|
|
3230
3238
|
throw new Error('Use project ingest <source-dir> --out-dir <directory>');
|
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.4"
|
|
33
|
+
"@assethub/api-client": "^0.1.4",
|
|
34
|
+
"@modelcontextprotocol/sdk": "^1.30.0"
|
|
34
35
|
},
|
|
35
36
|
"repository": {
|
|
36
37
|
"type": "git",
|