@assethub/cli 0.1.9 → 0.1.11
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 +49 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +97 -61
- package/dist/setup.d.ts +50 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +180 -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
|
|
|
@@ -406,3 +440,16 @@ assethub graph lineage --canvas <canvas-id> --artifact <asset-id> --direction an
|
|
|
406
440
|
The graph commands currently cover recorded CLI/API executions and evaluations.
|
|
407
441
|
They do not enumerate every historical UI artifact graph or provide a workspace-wide
|
|
408
442
|
mesh library search. A canvas with only older UI activity can return an empty graph.
|
|
443
|
+
|
|
444
|
+
## Inspect available MCP operations
|
|
445
|
+
|
|
446
|
+
```sh
|
|
447
|
+
assethub mcp tools --profile my-workspace
|
|
448
|
+
assethub mcp tools image_generate --profile my-workspace
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
The first command returns a compact list of tools and their action annotations.
|
|
452
|
+
The second returns the live description and input schema for one tool, including
|
|
453
|
+
required fields. Both use the selected profile and the same bounded checks as
|
|
454
|
+
`doctor --mcp`; they do not invoke tools or spend credits. Hosted MCP requires
|
|
455
|
+
Internal access. Discover names first because server capabilities can change.
|
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 tools [tool-name] [--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,yyXAiHjB,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,10 @@ 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 tools [tool-name] [--profile <name>] [--timeout-ms <n>]
|
|
73
|
+
assethub mcp config --client cursor|codex [--base-url <url>]
|
|
69
74
|
assethub auth login --api-key <key> [--base-url <url>] [--profile <name>]
|
|
70
75
|
assethub auth login --api-key-stdin [--base-url <url>] [--profile <name>]
|
|
71
76
|
assethub auth login --access-token-stdin [--base-url <url>] [--profile <name>]
|
|
@@ -139,9 +144,10 @@ Usage:
|
|
|
139
144
|
|
|
140
145
|
Global options:
|
|
141
146
|
--api-key <key> Overrides saved auth and ASSETHUB_API_KEY.
|
|
142
|
-
--base-url <url>
|
|
143
|
-
--profile <name>
|
|
147
|
+
--base-url <url> Override the selected API origin. Default: ${defaultBaseUrl}.
|
|
148
|
+
--profile <name> Select this saved profile ahead of environment credentials and origin.
|
|
144
149
|
--config <path> Auth config path. Defaults to ~/.assethub/config.json.
|
|
150
|
+
--version Show installed package version.
|
|
145
151
|
--help Show help.
|
|
146
152
|
|
|
147
153
|
Examples:
|
|
@@ -339,7 +345,7 @@ const defaultFileNameForMediaType = (mediaType) => mediaType === 'image' ? 'stdi
|
|
|
339
345
|
const getSourceResourceIdFlag = (flags) => getFlag(flags, 'source-resource-id') ??
|
|
340
346
|
getFlag(flags, 'source-id') ??
|
|
341
347
|
getFlag(flags, 'resource-id');
|
|
342
|
-
const getProfileName = (flags) =>
|
|
348
|
+
const getProfileName = (flags) => hasFlag(flags, 'profile') ? requireFlag(flags, 'profile') : defaultProfileName;
|
|
343
349
|
const getConfigPath = (flags) => getFlag(flags, 'config') ??
|
|
344
350
|
env.ASSETHUB_CLI_CONFIG ??
|
|
345
351
|
join(homedir(), '.assethub', 'config.json');
|
|
@@ -394,49 +400,32 @@ const readStdinBlob = async (type) => await new Promise((resolve, reject) => {
|
|
|
394
400
|
stdin.on('error', reject);
|
|
395
401
|
});
|
|
396
402
|
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
|
-
}
|
|
403
|
+
const explicitProfile = hasFlag(flags, 'profile') ? requireFlag(flags, 'profile') : undefined;
|
|
404
|
+
const overrideKey = hasFlag(flags, 'api-key') ? requireFlag(flags, 'api-key') : undefined;
|
|
405
|
+
const config = !overrideKey || explicitProfile
|
|
406
|
+
? await readAuthConfig(getConfigPath(flags))
|
|
420
407
|
: undefined;
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
408
|
+
const profile = explicitProfile ?? config?.defaultProfile ?? defaultProfileName;
|
|
409
|
+
const storedProfile = config?.profiles?.[profile];
|
|
410
|
+
const selected = Boolean(explicitProfile || storedProfile?.workspaceId);
|
|
411
|
+
if (selected && (!storedProfile || (!storedProfile.apiKey && !overrideKey)))
|
|
412
|
+
throw new Error('Selected profile has no workspace API key. Use workspace use <id> or auth login --api-key-stdin --profile <name>.');
|
|
413
|
+
const baseUrl = getFlag(flags, 'base-url') ??
|
|
414
|
+
(selected
|
|
415
|
+
? storedProfile.baseUrl
|
|
416
|
+
: env.ASSETHUB_API_BASE_URL ?? storedProfile?.baseUrl ?? defaultBaseUrl);
|
|
417
|
+
if (overrideKey)
|
|
418
|
+
return { apiKey: overrideKey, baseUrl, profile, source: 'flag' };
|
|
419
|
+
if (selected && storedProfile?.apiKey) {
|
|
420
|
+
if (storedProfile.workspaceId &&
|
|
421
|
+
new URL(baseUrl).origin !== new URL(storedProfile.baseUrl).origin)
|
|
427
422
|
throw new Error('Selected workspace belongs to another API origin; select a workspace for this origin or supply an explicit API key');
|
|
428
|
-
return
|
|
423
|
+
return { apiKey: storedProfile.apiKey, baseUrl, profile, source: 'profile' };
|
|
429
424
|
}
|
|
430
|
-
if (env.ASSETHUB_API_KEY
|
|
431
|
-
return {
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
profile,
|
|
435
|
-
source: 'env',
|
|
436
|
-
};
|
|
437
|
-
}
|
|
438
|
-
if (storedAuth)
|
|
439
|
-
return storedAuth;
|
|
425
|
+
if (env.ASSETHUB_API_KEY?.trim())
|
|
426
|
+
return { apiKey: env.ASSETHUB_API_KEY, baseUrl, profile, source: 'env' };
|
|
427
|
+
if (storedProfile?.apiKey)
|
|
428
|
+
return { apiKey: storedProfile.apiKey, baseUrl, profile, source: 'profile' };
|
|
440
429
|
throw new Error('Missing workspace API key. Use "workspace use <id>" after user login, "auth login --api-key-stdin", or ASSETHUB_API_KEY.');
|
|
441
430
|
};
|
|
442
431
|
const createContext = async (flags, args) => {
|
|
@@ -1230,20 +1219,21 @@ const commandModels = async (subcommand, positionals, ctx) => {
|
|
|
1230
1219
|
const workspaceAuth = async (flags) => {
|
|
1231
1220
|
const configPath = getConfigPath(flags);
|
|
1232
1221
|
const config = await readAuthConfig(configPath);
|
|
1233
|
-
const
|
|
1222
|
+
const explicitProfile = hasFlag(flags, 'profile') ? requireFlag(flags, 'profile') : undefined;
|
|
1223
|
+
const profile = explicitProfile ?? config.defaultProfile ?? defaultProfileName;
|
|
1234
1224
|
const stored = config.profiles?.[profile];
|
|
1235
|
-
const
|
|
1225
|
+
const environmentToken = explicitProfile ? undefined : env.ASSETHUB_ACCESS_TOKEN?.trim();
|
|
1226
|
+
const accessToken = environmentToken || stored?.accessToken;
|
|
1236
1227
|
if (!accessToken)
|
|
1237
1228
|
throw new Error('Workspace management requires user authentication: auth login --access-token-stdin or ASSETHUB_ACCESS_TOKEN');
|
|
1238
1229
|
const baseUrl = getFlag(flags, 'base-url') ??
|
|
1239
|
-
env.ASSETHUB_API_BASE_URL ??
|
|
1240
|
-
stored?.baseUrl ??
|
|
1230
|
+
(explicitProfile ? stored?.baseUrl : env.ASSETHUB_API_BASE_URL ?? stored?.baseUrl) ??
|
|
1241
1231
|
defaultBaseUrl;
|
|
1242
|
-
if (!
|
|
1232
|
+
if (!environmentToken &&
|
|
1243
1233
|
stored &&
|
|
1244
1234
|
new URL(baseUrl).origin !== new URL(stored.baseUrl).origin)
|
|
1245
1235
|
throw new Error('Saved user authentication belongs to another API origin; log in for this origin');
|
|
1246
|
-
const workspaceMfaToken = env.ASSETHUB_WORKSPACE_MFA?.trim() ||
|
|
1236
|
+
const workspaceMfaToken = (!explicitProfile && env.ASSETHUB_WORKSPACE_MFA?.trim()) ||
|
|
1247
1237
|
(stored && new URL(baseUrl).origin === new URL(stored.baseUrl).origin
|
|
1248
1238
|
? stored.workspaceMfaToken
|
|
1249
1239
|
: undefined);
|
|
@@ -1258,6 +1248,11 @@ const workspaceAuth = async (flags) => {
|
|
|
1258
1248
|
};
|
|
1259
1249
|
};
|
|
1260
1250
|
const commandWorkspace = async (subcommand, positionals, flags) => {
|
|
1251
|
+
const suppliedKey = hasFlag(flags, 'api-key')
|
|
1252
|
+
? requireFlag(flags, 'api-key')
|
|
1253
|
+
: hasFlag(flags, 'profile')
|
|
1254
|
+
? undefined
|
|
1255
|
+
: env.ASSETHUB_API_KEY?.trim();
|
|
1261
1256
|
const auth = await workspaceAuth(flags);
|
|
1262
1257
|
if (subcommand === 'list') {
|
|
1263
1258
|
print(await auth.client.list());
|
|
@@ -1301,7 +1296,6 @@ const commandWorkspace = async (subcommand, positionals, flags) => {
|
|
|
1301
1296
|
new URL(entry.baseUrl).origin === new URL(auth.baseUrl).origin &&
|
|
1302
1297
|
entry.apiKey);
|
|
1303
1298
|
let apiKey;
|
|
1304
|
-
const suppliedKey = getFlag(flags, 'api-key') ?? env.ASSETHUB_API_KEY?.trim();
|
|
1305
1299
|
for (const candidate of new Set([cached?.[1].apiKey, suppliedKey])) {
|
|
1306
1300
|
if (!candidate)
|
|
1307
1301
|
continue;
|
|
@@ -1431,7 +1425,7 @@ const commandAuth = async (subcommand, flags) => {
|
|
|
1431
1425
|
if (subcommand === 'status') {
|
|
1432
1426
|
const config = await readAuthConfig(configPath);
|
|
1433
1427
|
const current = config.profiles?.[getFlag(flags, 'profile') ?? config.defaultProfile ?? profile];
|
|
1434
|
-
if (env.ASSETHUB_ACCESS_TOKEN?.trim() ||
|
|
1428
|
+
if ((!hasFlag(flags, 'profile') && env.ASSETHUB_ACCESS_TOKEN?.trim()) ||
|
|
1435
1429
|
(current?.accessToken && !current.apiKey)) {
|
|
1436
1430
|
const auth = await workspaceAuth(flags);
|
|
1437
1431
|
const account = await auth.client.list();
|
|
@@ -1462,22 +1456,15 @@ const commandAuth = async (subcommand, flags) => {
|
|
|
1462
1456
|
}
|
|
1463
1457
|
if (subcommand === 'logout') {
|
|
1464
1458
|
const config = await readAuthConfig(configPath);
|
|
1465
|
-
const profiles = config.profiles ?? {};
|
|
1466
1459
|
const selectedProfile = getFlag(flags, 'profile') ?? config.defaultProfile ?? profile;
|
|
1460
|
+
const profiles = config.profiles ?? {};
|
|
1467
1461
|
const existed = profiles[selectedProfile] != null;
|
|
1468
1462
|
delete profiles[selectedProfile];
|
|
1469
1463
|
await writeAuthConfig(configPath, {
|
|
1470
|
-
defaultProfile: config.defaultProfile === selectedProfile
|
|
1471
|
-
? undefined
|
|
1472
|
-
: config.defaultProfile,
|
|
1464
|
+
defaultProfile: config.defaultProfile === selectedProfile ? undefined : config.defaultProfile,
|
|
1473
1465
|
profiles,
|
|
1474
1466
|
});
|
|
1475
|
-
print({
|
|
1476
|
-
success: true,
|
|
1477
|
-
profile: selectedProfile,
|
|
1478
|
-
removed: existed,
|
|
1479
|
-
configPath,
|
|
1480
|
-
});
|
|
1467
|
+
print({ success: true, profile: selectedProfile, removed: existed, configPath });
|
|
1481
1468
|
return;
|
|
1482
1469
|
}
|
|
1483
1470
|
throw new Error('Unknown auth command. Use "auth login", "auth status", or "auth logout".');
|
|
@@ -3220,11 +3207,60 @@ const parseNonNegativeIntegerFlag = (flags, name) => {
|
|
|
3220
3207
|
};
|
|
3221
3208
|
const run = async () => {
|
|
3222
3209
|
const parsed = parseArgs(argv.slice(2));
|
|
3210
|
+
if (hasFlag(parsed.flags, 'version')) {
|
|
3211
|
+
stdout.write(`${await cliVersion()}\n`);
|
|
3212
|
+
return;
|
|
3213
|
+
}
|
|
3223
3214
|
if (hasFlag(parsed.flags, 'help') || parsed.positionals.length === 0) {
|
|
3224
3215
|
stdout.write(usage);
|
|
3225
3216
|
return;
|
|
3226
3217
|
}
|
|
3227
3218
|
const [command, subcommand] = parsed.positionals;
|
|
3219
|
+
if (command === 'mcp' && subcommand === 'tools') {
|
|
3220
|
+
stderr.write('Discovering AssetHub MCP tools…\n');
|
|
3221
|
+
const report = await diagnose({
|
|
3222
|
+
resolveAuth: () => resolveAuth(parsed.flags),
|
|
3223
|
+
includeMcp: true,
|
|
3224
|
+
includeTools: true,
|
|
3225
|
+
timeoutMs: parsePositiveIntegerFlag(parsed.flags, 'timeout-ms', 15000),
|
|
3226
|
+
});
|
|
3227
|
+
if (!report.ok) {
|
|
3228
|
+
print(report);
|
|
3229
|
+
process.exitCode = 2;
|
|
3230
|
+
return;
|
|
3231
|
+
}
|
|
3232
|
+
const check = report.checks.find(check => check.name === 'mcp');
|
|
3233
|
+
const tools = check && 'tools' in check ? check.tools ?? [] : [];
|
|
3234
|
+
const name = parsed.positionals[2];
|
|
3235
|
+
if (name) {
|
|
3236
|
+
const tool = tools.find(tool => tool.name === name);
|
|
3237
|
+
if (!tool)
|
|
3238
|
+
throw new Error(`Unknown MCP tool: ${name}. Use mcp tools to list available names.`);
|
|
3239
|
+
print({ tool });
|
|
3240
|
+
}
|
|
3241
|
+
else {
|
|
3242
|
+
print({ total: tools.length, tools: tools.map(({ name, title, annotations }) => ({ name, title, annotations })) });
|
|
3243
|
+
}
|
|
3244
|
+
return;
|
|
3245
|
+
}
|
|
3246
|
+
if (command === 'mcp') {
|
|
3247
|
+
if (subcommand !== 'config')
|
|
3248
|
+
throw new Error('Use mcp tools [tool-name] or mcp config --client cursor|codex');
|
|
3249
|
+
stdout.write(mcpConfig(requireFlag(parsed.flags, 'client'), getFlag(parsed.flags, 'base-url') ?? env.ASSETHUB_API_BASE_URL ?? defaultBaseUrl));
|
|
3250
|
+
return;
|
|
3251
|
+
}
|
|
3252
|
+
if (command === 'doctor') {
|
|
3253
|
+
stderr.write('Checking AssetHub connection…\n');
|
|
3254
|
+
const report = await diagnose({
|
|
3255
|
+
resolveAuth: () => resolveAuth(parsed.flags),
|
|
3256
|
+
includeMcp: hasFlag(parsed.flags, 'mcp'),
|
|
3257
|
+
timeoutMs: parsePositiveIntegerFlag(parsed.flags, 'timeout-ms', 15000),
|
|
3258
|
+
});
|
|
3259
|
+
print(report);
|
|
3260
|
+
if (!report.ok)
|
|
3261
|
+
process.exitCode = 2;
|
|
3262
|
+
return;
|
|
3263
|
+
}
|
|
3228
3264
|
if (command === 'project') {
|
|
3229
3265
|
if (subcommand !== 'ingest')
|
|
3230
3266
|
throw new Error('Use project ingest <source-dir> --out-dir <directory>');
|
package/dist/setup.d.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
+
export declare const cliVersion: () => Promise<string>;
|
|
3
|
+
export declare const mcpConfig: (client: string, baseUrl: string) => string;
|
|
4
|
+
type Check = {
|
|
5
|
+
name: 'api' | 'mcp' | 'configuration';
|
|
6
|
+
status: 'pass' | 'fail';
|
|
7
|
+
code?: string;
|
|
8
|
+
message?: string;
|
|
9
|
+
hint?: string;
|
|
10
|
+
workspaceId?: string;
|
|
11
|
+
executionStatus?: string;
|
|
12
|
+
toolCount?: number;
|
|
13
|
+
tools?: Tool[];
|
|
14
|
+
};
|
|
15
|
+
type Auth = {
|
|
16
|
+
apiKey: string;
|
|
17
|
+
baseUrl: string;
|
|
18
|
+
profile: string;
|
|
19
|
+
source: string;
|
|
20
|
+
};
|
|
21
|
+
export declare const diagnose: ({ resolveAuth, includeMcp, timeoutMs, includeTools, }: {
|
|
22
|
+
resolveAuth: () => Promise<Auth>;
|
|
23
|
+
includeMcp: boolean;
|
|
24
|
+
timeoutMs: number;
|
|
25
|
+
includeTools?: boolean;
|
|
26
|
+
}) => Promise<{
|
|
27
|
+
ok: boolean;
|
|
28
|
+
version: string;
|
|
29
|
+
nodeVersion: string;
|
|
30
|
+
checks: {
|
|
31
|
+
name: "configuration";
|
|
32
|
+
status: "fail";
|
|
33
|
+
code: string;
|
|
34
|
+
message: string;
|
|
35
|
+
hint: string;
|
|
36
|
+
}[];
|
|
37
|
+
auth?: undefined;
|
|
38
|
+
} | {
|
|
39
|
+
ok: boolean;
|
|
40
|
+
version: string;
|
|
41
|
+
nodeVersion: string;
|
|
42
|
+
auth: {
|
|
43
|
+
profile: string;
|
|
44
|
+
source: string;
|
|
45
|
+
baseUrl: string;
|
|
46
|
+
};
|
|
47
|
+
checks: [Check, ...Check[]];
|
|
48
|
+
}>;
|
|
49
|
+
export {};
|
|
50
|
+
//# sourceMappingURL=setup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,oCAAoC,CAAA;AAE5D,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;IAClB,KAAK,CAAC,EAAE,IAAI,EAAE,CAAA;CACf,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,uDAK5B;IACD,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAChC,UAAU,EAAE,OAAO,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB;;;;;;;;;;;;;;;;;;;;;;EA2GA,CAAA"}
|
package/dist/setup.js
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
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, includeTools = false, }) => {
|
|
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
|
+
const tools = [];
|
|
142
|
+
let cursor;
|
|
143
|
+
const cursors = new Set();
|
|
144
|
+
do {
|
|
145
|
+
const page = await client.listTools(cursor ? { cursor } : {}, {
|
|
146
|
+
signal,
|
|
147
|
+
timeout: timeoutMs,
|
|
148
|
+
});
|
|
149
|
+
toolCount += page.tools.length;
|
|
150
|
+
if (includeTools)
|
|
151
|
+
tools.push(...page.tools);
|
|
152
|
+
cursor = page.nextCursor;
|
|
153
|
+
if (cursor && cursors.has(cursor))
|
|
154
|
+
throw new Error('Repeated tool cursor');
|
|
155
|
+
if (cursor)
|
|
156
|
+
cursors.add(cursor);
|
|
157
|
+
} while (cursor);
|
|
158
|
+
if (!toolCount)
|
|
159
|
+
throw new Error('No MCP tools');
|
|
160
|
+
return { name: 'mcp', status: 'pass', toolCount, ...(includeTools ? { tools } : {}) };
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
163
|
+
return failedCheck('mcp', error instanceof StreamableHTTPError ? error.code : undefined, signal.aborted);
|
|
164
|
+
}
|
|
165
|
+
finally {
|
|
166
|
+
await client.close();
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
const checks = await Promise.all([
|
|
170
|
+
apiCheck(),
|
|
171
|
+
...(includeMcp ? [mcpCheck()] : []),
|
|
172
|
+
]);
|
|
173
|
+
return {
|
|
174
|
+
ok: checks.every(check => check.status === 'pass'),
|
|
175
|
+
version,
|
|
176
|
+
nodeVersion: process.version,
|
|
177
|
+
auth: { profile: auth.profile, source: auth.source, baseUrl: auth.baseUrl },
|
|
178
|
+
checks,
|
|
179
|
+
};
|
|
180
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@assethub/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
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",
|