@assethub/cli 0.1.11 → 0.1.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -33,6 +33,29 @@ explicit overrides. `auth logout` removes the selected saved profile (or the
33
33
  saved default); environment credentials remain under your shell’s control.
34
34
  Diagnostics omit API keys and raw server error bodies.
35
35
 
36
+ ## Historical meshes and artifact graphs
37
+
38
+ Internal preview: these reads require workspace feature access. Lists are scoped
39
+ to the selected workspace, including assets created in the UI. Mesh search
40
+ includes parts, revisions, and archived meshes, and excludes samples.
41
+
42
+ ```sh
43
+ assethub mesh list --query "helmet" --limit 25
44
+ assethub mesh get mesh_123
45
+ assethub mesh download mesh_123 --out-dir ./meshes
46
+ assethub graph list --limit 25
47
+ assethub graph show --graph "$GRAPH_ID"
48
+ assethub graph export --graph "$GRAPH_ID" --out ./graph.json
49
+ assethub graph lineage --graph "$GRAPH_ID" --artifact "$NODE_ID" --direction ancestors
50
+ ```
51
+
52
+ Pass each `nextCursor` as `--cursor` until it is null; a graph page can be empty
53
+ while its cursor advances past duplicates. Graph catalogs include generated and
54
+ uploaded graphs. Use `--source upload` to read uploaded snapshots. Graph exports
55
+ contain the full saved graph and blob references; they do not download blob bytes.
56
+ `--canvas` keeps the existing CLI/API execution history view and cannot be combined
57
+ with `--graph`. Mesh IDs returned by search can be passed to `composer run`.
58
+
36
59
  ## Agent generation with canvas history
37
60
 
38
61
  This release uses the Internal `api_canvas_execution` gate. Run `assethub capabilities`
@@ -453,3 +476,43 @@ The second returns the live description and input schema for one tool, including
453
476
  required fields. Both use the selected profile and the same bounded checks as
454
477
  `doctor --mcp`; they do not invoke tools or spend credits. Hosted MCP requires
455
478
  Internal access. Discover names first because server capabilities can change.
479
+
480
+
481
+ ### Team members (Internal preview)
482
+
483
+ Use a **user access token** with `auth login --access-token-stdin`. A workspace
484
+ API key cannot invite people or change membership. Commands use the selected
485
+ workspace; `--workspace <id>` explicitly selects a target without changing your
486
+ saved selection. Membership reads require team membership; changes require admin
487
+ permission. The target workspace's MFA and IP restrictions apply.
488
+
489
+ ```sh
490
+ assethub workspace members --workspace <workspace-id>
491
+ assethub workspace invite --workspace <workspace-id> --email colleague@example.com
492
+ assethub workspace set-role <user-id> --role admin --workspace <workspace-id>
493
+ assethub workspace remove-member <user-id> --workspace <workspace-id>
494
+ ```
495
+
496
+ Invite defaults to `user`; use `--role admin` deliberately. Invitations grant
497
+ membership and send email. An existing member returns `already_member`, preserving
498
+ their role and avoiding another email. Use `workspace invite --email ... --resend`
499
+ only to explicitly resend or recover failed delivery. If a request is interrupted,
500
+ check `workspace members` first. Removal revokes workspace membership, not the
501
+ user's account. The final admin cannot be demoted or removed.
502
+
503
+ For MCP account operations, add a separate server using:
504
+
505
+ ```sh
506
+ assethub mcp config --client codex --account
507
+ assethub mcp config --client cursor --account
508
+ assethub mcp tools --account --profile <user-profile>
509
+ ```
510
+
511
+ The generated configuration references `ASSETHUB_ACCESS_TOKEN` and
512
+ `ASSETHUB_WORKSPACE_MFA_COOKIE` without printing credentials. Set the latter to
513
+ `ah_workspace_mfa=<signed-cookie-value>` from the same verified browser session
514
+ (or an empty string if workspace MFA is not required). Pass these environment
515
+ variables to your MCP client and reconnect. This server uses
516
+ `https://app.assethub.io/api/workspaces/mcp` and exposes `workspace_list`,
517
+ `workspace_members_list`, `workspace_member_invite`, `workspace_member_set_role`,
518
+ and `workspace_member_remove`. Keep the existing API-key MCP server for generation.
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 --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";
5
+ export declare const usage = "AssetHub CLI\n\nInternal preview: canvas/context/layout, moodboards and member management require workspace feature access.\n\nUsage:\n assethub --version\n assethub doctor [--mcp] [--profile <name>] [--timeout-ms <n>]\n assethub mcp tools [tool-name] [--account] [--profile <name>] [--timeout-ms <n>]\n assethub mcp config --client cursor|codex [--account] [--base-url <url>]\n assethub auth login --api-key <key> [--base-url <url>] [--profile <name>]\n assethub auth login --api-key-stdin [--base-url <url>] [--profile <name>]\n assethub auth login --access-token-stdin [--base-url <url>] [--profile <name>]\n assethub auth status [--profile <name>]\n assethub auth logout [--profile <name>]\n assethub workspace list|get\n assethub workspace create --name <name> [--operation-id <uuid>]\n assethub workspace use <workspace-id>\n assethub workspace members [--workspace <id>]\n assethub workspace invite --email <email> [--role user|admin] [--resend] [--workspace <id>]\n assethub workspace set-role <user-id> --role user|admin [--workspace <id>]\n assethub workspace remove-member <user-id> [--workspace <id>]\n assethub workspace prepare|sync|analyze|verify --internal --manifest <json> --state <json>\n assethub workspace self-check --internal\n assethub workspace context put --internal --org <uuid> --actor <uuid> --canvas <id> --file <json> [--if-version <n>] [--order <uuid>]\n assethub workspace context get --internal --org <uuid> --actor <uuid> --canvas <id> [--out <json>] [--order <uuid>]\n assethub project ingest <source-dir> --out-dir <directory> [--exclude-dir <relative-path>...]\n assethub language text|vision --input-json @<json> --operation-id <uuid> [--out <json>]\n assethub canvas 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 list [--cursor <cursor>] [--limit <n>]\n assethub graph show|export [--canvas <id> | --graph <id>] [--source generated|upload] [--artifact <node-id>] [--out <path>] [--allow-truncated]\n assethub graph lineage --artifact <node-id> [--canvas <id> | --graph <id>] [--source generated|upload] [--direction ancestors|descendants|both] [--depth <n>] [--out <path>]\n assethub evaluate list\n assethub evaluations submit --artifact <asset-id> --report <json|file|@file|@-> [--agent <name>] [--canvas <id>] [--reference <asset-id>...] [--run <run-id>] [--operation-id <uuid>] [--require-pass]\n assethub evaluations list [--canvas <id>] [--artifact <asset-id>]\n assethub evaluations get <evaluation-id>\n assethub image generate --input-json <json|@file|@-> [--canvas <id>] [--operation-id <uuid>] [--agent <name>] [--derived-from-run <run-id>] [--from-node <graphId/nodeId> --graph-revision <rev>] [--wait]\n assethub mesh generate --input-json <json|@file|@-> [--canvas <id>] [--operation-id <uuid>] [--agent <name>] [--derived-from-run <run-id>] [--from-node <graphId/nodeId> --graph-revision <rev>] [--wait]\n assethub mesh list [--query <text>] [--cursor <cursor>] [--limit <n>]\n assethub mesh get <mesh-asset-id>\n assethub mesh download <mesh-asset-id> --out-dir <directory>\n assethub image generate --prompt <text> [--file <path> | --source-url <url> | --stdin | --stdin-base64 | --stdin-data-uri | --stdin-json | --source-json <json|@file|@-> | --data-uri <uri> | --clipboard] [--file-name <name>] [--content-type <type>] [--model-id <id>] [--batch-size <n>] [--wait] [--download --out-dir <dir>] [--canvas <id>] [--operation-id <uuid>] [--api-version v2]\n assethub image generate --prompt <text> --source-resource-id <id> --api-version v2 [--model-id <id>] [--batch-size <n>] [--wait]\n assethub mesh generate (--file <path> | --source-url <url> | --source-resource-id <id> | --file-ref-json <json> | --stdin | --stdin-base64 | --stdin-data-uri | --stdin-json | --source-json <json|@file|@-> | --data-uri <uri>) [--file-name <name>] [--content-type <type>] [--model-id <id>] [--name <name>] [--wait] [--download --out-dir <dir>]\n assethub mesh retopo (--source-resource-id <id> | --source-url <url> | --file-ref-json <json> | --stdin | --stdin-base64 | --stdin-data-uri | --stdin-json | --source-json <json|@file|@-> | --data-uri <uri>) --model-id <id> [--file-name <name>] [--content-type <type>] [--wait] [--download --out-dir <dir>]\n assethub rig check (--file <path> | --source-url <url> | --source-resource-id <id> | --file-ref-json <json> | --stdin | --stdin-base64 | --stdin-data-uri | --stdin-json | --source-json <json|@file|@-> | --data-uri <uri>) [--name <name>] [--wait] [--download --out-dir <dir>]\n assethub rig create (--file <path> | --source-url <url> | --source-resource-id <id> | --file-ref-json <json> | --stdin | --stdin-base64 | --stdin-data-uri | --stdin-json | --source-json <json|@file|@-> | --data-uri <uri>) [--model v1.0-20240301|v2.5-20260210] [--rig-type biped|quadruped|hexapod|octopod|avian|serpentine|aquatic] [--spec tripo|mixamo] [--out-format glb|fbx] [--name <name>] [--wait] [--download --out-dir <dir>]\n assethub animate presets [--model v1.0-20240301|v2.5-20260210] [--rig-type <type>]\n assethub animate retarget --resource-id <id> --animation <preset-id> [--animation <preset-id>... up to 5 total] [--out-format glb|fbx] [--bake-animation true|false] [--export-with-geometry true|false] [--animate-in-place true|false] [--name <name>] [--wait] [--download --out-dir <dir>]\n assethub jobs get <job-id> [--download --out-dir <dir>]\n assethub jobs watch <job-id> [--interval-ms <ms>] [--timeout-ms <ms>] [--download --out-dir <dir>]\n assethub production analyze (--file <path> | --source-url <url> | --source-id <id> | --image-url <url> | --file-ref-json <json> | --stdin | --stdin-base64 | --stdin-data-uri | --stdin-json | --source-json <json|@file|@-> | --data-uri <uri> | --clipboard) [--file-name <name>] [--content-type <type>] [--part-extractor <name>] [--name <name>] [--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
  *
@@ -1 +1 @@
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"}
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,+7YAyHjB,CAAA;AAmpED;;;;;;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;AAkqCD,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
@@ -64,13 +64,13 @@ const isInternalPartExtractorId = (value) => value.trim().includes('_');
64
64
  const execFileAsync = promisify(execFile);
65
65
  export const usage = `AssetHub CLI
66
66
 
67
- Internal preview: canvas/context/layout and moodboards require workspace feature access.
67
+ Internal preview: canvas/context/layout, moodboards and member management require workspace feature access.
68
68
 
69
69
  Usage:
70
70
  assethub --version
71
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>]
72
+ assethub mcp tools [tool-name] [--account] [--profile <name>] [--timeout-ms <n>]
73
+ assethub mcp config --client cursor|codex [--account] [--base-url <url>]
74
74
  assethub auth login --api-key <key> [--base-url <url>] [--profile <name>]
75
75
  assethub auth login --api-key-stdin [--base-url <url>] [--profile <name>]
76
76
  assethub auth login --access-token-stdin [--base-url <url>] [--profile <name>]
@@ -79,6 +79,10 @@ Usage:
79
79
  assethub workspace list|get
80
80
  assethub workspace create --name <name> [--operation-id <uuid>]
81
81
  assethub workspace use <workspace-id>
82
+ assethub workspace members [--workspace <id>]
83
+ assethub workspace invite --email <email> [--role user|admin] [--resend] [--workspace <id>]
84
+ assethub workspace set-role <user-id> --role user|admin [--workspace <id>]
85
+ assethub workspace remove-member <user-id> [--workspace <id>]
82
86
  assethub workspace prepare|sync|analyze|verify --internal --manifest <json> --state <json>
83
87
  assethub workspace self-check --internal
84
88
  assethub workspace context put --internal --org <uuid> --actor <uuid> --canvas <id> --file <json> [--if-version <n>] [--order <uuid>]
@@ -110,14 +114,18 @@ Usage:
110
114
  assethub runs list [--canvas <id>] [--cursor <cursor>] [--limit <n>]
111
115
  assethub runs get|watch <run-id> [--timeout-ms <n>]
112
116
  assethub runs resume <operation-id> [--wait]
113
- assethub graph show|export [--canvas <id>] [--artifact <node-id>] [--out <path>] [--allow-truncated]
114
- assethub graph lineage --artifact <node-id> [--canvas <id>] [--direction ancestors|descendants|both] [--depth <n>]
117
+ assethub graph list [--cursor <cursor>] [--limit <n>]
118
+ assethub graph show|export [--canvas <id> | --graph <id>] [--source generated|upload] [--artifact <node-id>] [--out <path>] [--allow-truncated]
119
+ assethub graph lineage --artifact <node-id> [--canvas <id> | --graph <id>] [--source generated|upload] [--direction ancestors|descendants|both] [--depth <n>] [--out <path>]
115
120
  assethub evaluate list
116
121
  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]
117
122
  assethub evaluations list [--canvas <id>] [--artifact <asset-id>]
118
123
  assethub evaluations get <evaluation-id>
119
124
  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]
120
125
  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]
126
+ assethub mesh list [--query <text>] [--cursor <cursor>] [--limit <n>]
127
+ assethub mesh get <mesh-asset-id>
128
+ assethub mesh download <mesh-asset-id> --out-dir <directory>
121
129
  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]
122
130
  assethub image generate --prompt <text> --source-resource-id <id> --api-version v2 [--model-id <id>] [--batch-size <n>] [--wait]
123
131
  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>]
@@ -1244,6 +1252,7 @@ const workspaceAuth = async (flags) => {
1244
1252
  accessToken,
1245
1253
  workspaceMfaToken,
1246
1254
  baseUrl,
1255
+ selectedWorkspaceId: environmentToken ? undefined : stored?.workspaceId,
1247
1256
  client: createWorkspaceClient({ accessToken, workspaceMfaToken, baseUrl }),
1248
1257
  };
1249
1258
  };
@@ -1254,13 +1263,35 @@ const commandWorkspace = async (subcommand, positionals, flags) => {
1254
1263
  ? undefined
1255
1264
  : env.ASSETHUB_API_KEY?.trim();
1256
1265
  const auth = await workspaceAuth(flags);
1266
+ if (['members', 'invite', 'set-role', 'remove-member'].includes(subcommand ?? '')) {
1267
+ let workspaceId = getFlag(flags, 'workspace') ?? auth.selectedWorkspaceId;
1268
+ if (!workspaceId)
1269
+ workspaceId = (await auth.client.list()).workspaces.find(item => item.active)?.id;
1270
+ if (!workspaceId)
1271
+ throw new Error('Specify --workspace <id> or select one with workspace use <id>');
1272
+ if (subcommand === 'members') {
1273
+ print(await auth.client.listMembers(workspaceId));
1274
+ return;
1275
+ }
1276
+ const role = subcommand === 'invite' ? getFlag(flags, 'role') ?? 'user' : subcommand === 'set-role' ? requireFlag(flags, 'role') : undefined;
1277
+ if (role !== undefined && role !== 'user' && role !== 'admin')
1278
+ throw new Error('--role must be user or admin');
1279
+ stderr.write(`[workspace] ${subcommand} in ${workspaceId}…\n`);
1280
+ if (subcommand === 'invite')
1281
+ print(await auth.client.inviteMember(workspaceId, { email: requireFlag(flags, 'email'), role: role, ...(hasFlag(flags, 'resend') ? { resend: true } : {}) }));
1282
+ else if (subcommand === 'set-role')
1283
+ print(await auth.client.setMemberRole(workspaceId, { userId: requirePositional(positionals, 2, 'user-id'), role: role }));
1284
+ else
1285
+ print(await auth.client.removeMember(workspaceId, requirePositional(positionals, 2, 'user-id')));
1286
+ return;
1287
+ }
1257
1288
  if (subcommand === 'list') {
1258
1289
  print(await auth.client.list());
1259
1290
  return;
1260
1291
  }
1261
1292
  if (subcommand === 'get') {
1262
1293
  const account = await auth.client.list();
1263
- const selected = auth.config.profiles?.[auth.profile]?.workspaceId;
1294
+ const selected = auth.selectedWorkspaceId;
1264
1295
  const workspace = account.workspaces.find(item => selected ? item.id === selected : item.active);
1265
1296
  if (!workspace)
1266
1297
  throw new Error('No workspace selected; use workspace use <id>');
@@ -1718,7 +1749,25 @@ const commandComposer = async (subcommand, ctx) => {
1718
1749
  });
1719
1750
  await printRecorded(ctx, queued);
1720
1751
  };
1721
- const commandMesh = async (subcommand, ctx) => {
1752
+ const commandMesh = async (subcommand, positionals, ctx) => {
1753
+ if (subcommand === 'list') {
1754
+ print(await ctx.client.v2.listMeshes({
1755
+ query: getFlag(ctx.flags, 'query'),
1756
+ ...pageOptions(ctx.flags),
1757
+ }));
1758
+ return;
1759
+ }
1760
+ if (subcommand === 'get') {
1761
+ print(await ctx.client.v2.getAsset(requirePositional(positionals, 2, 'mesh-asset-id')));
1762
+ return;
1763
+ }
1764
+ if (subcommand === 'download') {
1765
+ const assetId = requirePositional(positionals, 2, 'mesh-asset-id');
1766
+ const asset = await ctx.client.v2.getAsset(assetId);
1767
+ const downloads = await maybeDownloadUrls({ ...ctx.flags, download: true }, asset);
1768
+ print({ asset, downloads });
1769
+ return;
1770
+ }
1722
1771
  if (subcommand === 'generate') {
1723
1772
  const inputJson = getFlag(ctx.flags, 'input-json');
1724
1773
  const input = inputJson
@@ -1771,7 +1820,7 @@ const commandMesh = async (subcommand, ctx) => {
1771
1820
  print(await withOptionalDownloads(ctx.flags, { queued, job }));
1772
1821
  return;
1773
1822
  }
1774
- throw new Error('Unknown mesh command. Use "mesh generate" or "mesh retopo".');
1823
+ throw new Error('Unknown mesh command. Use "mesh list|get|download|generate|retopo".');
1775
1824
  };
1776
1825
  /**
1777
1826
  * Accepted values for the rig/animate enum flags, kept next to the commands
@@ -2994,25 +3043,44 @@ const commandMoodboard = async (subcommand, positionals, ctx) => {
2994
3043
  process.exitCode = 1;
2995
3044
  };
2996
3045
  const commandGraph = async (subcommand, ctx) => {
3046
+ const graphId = getFlag(ctx.flags, 'graph');
3047
+ if (getFlag(ctx.flags, 'source') && !graphId)
3048
+ throw new Error('--source requires --graph');
3049
+ if (graphId && getFlag(ctx.flags, 'canvas'))
3050
+ throw new Error('cannot combine --graph and --canvas');
3051
+ if (subcommand === 'list') {
3052
+ print(await ctx.client.v2.listGraphs(pageOptions(ctx.flags)));
3053
+ return;
3054
+ }
2997
3055
  if (!['show', 'lineage', 'export'].includes(subcommand ?? ''))
2998
- throw new Error('Use graph show|lineage|export');
2999
- const { canvas } = await canvasForRead(ctx);
3056
+ throw new Error('Use graph list|show|lineage|export');
3000
3057
  const direction = getFlag(ctx.flags, 'direction') ?? 'both';
3001
3058
  if (!['ancestors', 'descendants', 'both'].includes(direction))
3002
3059
  throw new Error('--direction must be ancestors, descendants, or both');
3003
- const graph = await ctx.client.v2.getCanvasGraph(canvas.id, {
3004
- artifactId: subcommand === 'lineage'
3005
- ? requireFlag(ctx.flags, 'artifact')
3006
- : getFlag(ctx.flags, 'artifact'),
3007
- direction: direction,
3008
- depth: parsePositiveIntegerFlag(ctx.flags, 'depth', 5),
3009
- });
3010
- if (subcommand === 'export' &&
3060
+ const artifactId = subcommand === 'lineage'
3061
+ ? requireFlag(ctx.flags, 'artifact')
3062
+ : getFlag(ctx.flags, 'artifact');
3063
+ const graph = graphId
3064
+ ? await ctx.client.v2.getGraph(graphId, {
3065
+ source: parseEnumFlag(ctx.flags, 'source', ['generated', 'upload']),
3066
+ artifactId,
3067
+ direction: direction,
3068
+ depth: parsePositiveIntegerFlag(ctx.flags, 'depth', 5),
3069
+ })
3070
+ : await (async () => {
3071
+ const { canvas } = await canvasForRead(ctx);
3072
+ return ctx.client.v2.getCanvasGraph(canvas.id, {
3073
+ artifactId,
3074
+ direction: direction,
3075
+ depth: parsePositiveIntegerFlag(ctx.flags, 'depth', 5),
3076
+ });
3077
+ })();
3078
+ if ((subcommand === 'export' || getFlag(ctx.flags, 'out')) &&
3011
3079
  graph.truncated &&
3012
3080
  !hasFlag(ctx.flags, 'allow-truncated'))
3013
3081
  throw new Error('Graph exceeds export bounds; narrow with --artifact or explicitly use --allow-truncated');
3014
3082
  const out = getFlag(ctx.flags, 'out');
3015
- if (subcommand === 'export' && out) {
3083
+ if (out) {
3016
3084
  await writeFile(resolve(out), JSON.stringify(graph, null, 2) + '\n', {
3017
3085
  mode: 0o600,
3018
3086
  });
@@ -3219,7 +3287,13 @@ const run = async () => {
3219
3287
  if (command === 'mcp' && subcommand === 'tools') {
3220
3288
  stderr.write('Discovering AssetHub MCP tools…\n');
3221
3289
  const report = await diagnose({
3222
- resolveAuth: () => resolveAuth(parsed.flags),
3290
+ resolveAuth: async () => {
3291
+ if (!hasFlag(parsed.flags, 'account'))
3292
+ return resolveAuth(parsed.flags);
3293
+ const auth = await workspaceAuth(parsed.flags);
3294
+ return { apiKey: auth.accessToken, workspaceMfaToken: auth.workspaceMfaToken, baseUrl: auth.baseUrl, profile: auth.profile, source: 'user' };
3295
+ },
3296
+ account: hasFlag(parsed.flags, 'account'),
3223
3297
  includeMcp: true,
3224
3298
  includeTools: true,
3225
3299
  timeoutMs: parsePositiveIntegerFlag(parsed.flags, 'timeout-ms', 15000),
@@ -3246,7 +3320,7 @@ const run = async () => {
3246
3320
  if (command === 'mcp') {
3247
3321
  if (subcommand !== 'config')
3248
3322
  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));
3323
+ stdout.write(mcpConfig(requireFlag(parsed.flags, 'client'), getFlag(parsed.flags, 'base-url') ?? env.ASSETHUB_API_BASE_URL ?? defaultBaseUrl, hasFlag(parsed.flags, 'account')));
3250
3324
  return;
3251
3325
  }
3252
3326
  if (command === 'doctor') {
@@ -3278,7 +3352,7 @@ const run = async () => {
3278
3352
  return;
3279
3353
  }
3280
3354
  if (command === 'workspace') {
3281
- if (['list', 'get', 'create', 'use'].includes(subcommand ?? '')) {
3355
+ if (['list', 'get', 'create', 'use', 'members', 'invite', 'set-role', 'remove-member'].includes(subcommand ?? '')) {
3282
3356
  await commandWorkspace(subcommand, parsed.positionals, parsed.flags);
3283
3357
  return;
3284
3358
  }
@@ -3359,7 +3433,7 @@ const run = async () => {
3359
3433
  await commandImage(subcommand, ctx);
3360
3434
  return;
3361
3435
  case 'mesh':
3362
- await commandMesh(subcommand, ctx);
3436
+ await commandMesh(subcommand, parsed.positionals, ctx);
3363
3437
  return;
3364
3438
  case 'rig':
3365
3439
  await commandRig(subcommand, ctx);
package/dist/setup.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { Tool } from '@modelcontextprotocol/sdk/types.js';
2
2
  export declare const cliVersion: () => Promise<string>;
3
- export declare const mcpConfig: (client: string, baseUrl: string) => string;
3
+ export declare const mcpConfig: (client: string, baseUrl: string, account?: boolean) => string;
4
4
  type Check = {
5
5
  name: 'api' | 'mcp' | 'configuration';
6
6
  status: 'pass' | 'fail';
@@ -17,12 +17,14 @@ type Auth = {
17
17
  baseUrl: string;
18
18
  profile: string;
19
19
  source: string;
20
+ workspaceMfaToken?: string;
20
21
  };
21
- export declare const diagnose: ({ resolveAuth, includeMcp, timeoutMs, includeTools, }: {
22
+ export declare const diagnose: ({ resolveAuth, includeMcp, timeoutMs, includeTools, account, }: {
22
23
  resolveAuth: () => Promise<Auth>;
23
24
  includeMcp: boolean;
24
25
  timeoutMs: number;
25
26
  includeTools?: boolean;
27
+ account?: boolean;
26
28
  }) => Promise<{
27
29
  ok: boolean;
28
30
  version: string;
@@ -1 +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"}
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,EAAE,iBAAe,KAAG,MAsB5E,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,CAAC;IAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAAC,CAAA;AA2D1G,eAAO,MAAM,QAAQ,GAAU,gEAM5B;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;IACtB,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;;;;;;;;;;;;;;;;;;;;;;EAiHA,CAAA"}
package/dist/setup.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { readFile } from 'node:fs/promises';
2
- import { AssetHubApiError, createAssetHubClient } from '@assethub/api-client';
2
+ import { AssetHubApiError, createAssetHubClient, createWorkspaceClient, WorkspaceClientError } from '@assethub/api-client';
3
3
  export const cliVersion = async () => JSON.parse(await readFile(new URL('../package.json', import.meta.url), 'utf8')).version;
4
4
  const validatedBaseUrl = (baseUrl) => {
5
5
  const url = new URL(baseUrl);
@@ -11,22 +11,24 @@ const validatedBaseUrl = (baseUrl) => {
11
11
  throw new Error('Use HTTPS for remote servers; HTTP is supported only on localhost.');
12
12
  return url.href.replace(/\/+$/, '');
13
13
  };
14
- export const mcpConfig = (client, baseUrl) => {
15
- const url = `${validatedBaseUrl(baseUrl)}/api/mcp`;
14
+ export const mcpConfig = (client, baseUrl, account = false) => {
15
+ const url = `${validatedBaseUrl(baseUrl)}${account ? '/api/workspaces/mcp' : '/api/mcp'}`;
16
+ const name = account ? 'assethub-workspaces' : 'assethub';
17
+ const token = account ? 'ASSETHUB_ACCESS_TOKEN' : 'ASSETHUB_API_KEY';
16
18
  if (client === 'cursor')
17
19
  return (JSON.stringify({
18
20
  mcpServers: {
19
- assethub: {
21
+ [name]: {
20
22
  url,
21
- headers: { Authorization: 'Bearer ${env:ASSETHUB_API_KEY}' },
23
+ headers: { Authorization: `Bearer \${env:${token}}`, ...(account ? { Cookie: '${env:ASSETHUB_WORKSPACE_MFA_COOKIE}' } : {}) },
22
24
  },
23
25
  },
24
26
  }, null, 2) + '\n');
25
27
  if (client === 'codex')
26
- return `[mcp_servers.assethub]\nurl = ${JSON.stringify(url)}\nbearer_token_env_var = "ASSETHUB_API_KEY"\n`;
28
+ return `[mcp_servers.${name}]\nurl = ${JSON.stringify(url)}\nbearer_token_env_var = "${token}"\n${account ? 'env_http_headers = { Cookie = "ASSETHUB_WORKSPACE_MFA_COOKIE" }\n' : ''}`;
27
29
  throw new Error('Use mcp config --client cursor|codex');
28
30
  };
29
- const failedCheck = (name, status, timedOut) => {
31
+ const failedCheck = (name, status, timedOut, account = false) => {
30
32
  if (timedOut)
31
33
  return {
32
34
  name,
@@ -40,8 +42,8 @@ const failedCheck = (name, status, timedOut) => {
40
42
  name,
41
43
  status: 'fail',
42
44
  code: 'UNAUTHORIZED',
43
- message: 'The API key was rejected.',
44
- hint: 'Run assethub auth login --api-key-stdin with a current workspace key.',
45
+ message: account ? 'The user access token was rejected.' : 'The API key was rejected.',
46
+ hint: account ? 'Run assethub auth login --access-token-stdin with a current user token.' : 'Run assethub auth login --api-key-stdin with a current workspace key.',
45
47
  };
46
48
  if (status === 403)
47
49
  return {
@@ -57,7 +59,7 @@ const failedCheck = (name, status, timedOut) => {
57
59
  status: 'fail',
58
60
  code: 'MCP_UNAVAILABLE',
59
61
  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.',
62
+ hint: account ? 'Workspace MCP is in Internal preview. Check access for the signed-in user.' : 'Hosted MCP is in Internal preview. Check access for the account that created the API key.',
61
63
  };
62
64
  if (status === 429)
63
65
  return {
@@ -77,7 +79,7 @@ const failedCheck = (name, status, timedOut) => {
77
79
  hint: 'Check the API origin, network, and service status; then retry.',
78
80
  };
79
81
  };
80
- export const diagnose = async ({ resolveAuth, includeMcp, timeoutMs, includeTools = false, }) => {
82
+ export const diagnose = async ({ resolveAuth, includeMcp, timeoutMs, includeTools = false, account = false, }) => {
81
83
  const version = await cliVersion();
82
84
  let auth;
83
85
  try {
@@ -110,6 +112,10 @@ export const diagnose = async ({ resolveAuth, includeMcp, timeoutMs, includeTool
110
112
  });
111
113
  const apiCheck = async () => {
112
114
  try {
115
+ if (account) {
116
+ await createWorkspaceClient({ accessToken: auth.apiKey, workspaceMfaToken: auth.workspaceMfaToken, baseUrl: auth.baseUrl, fetch: boundedFetch }).list();
117
+ return { name: 'api', status: 'pass' };
118
+ }
113
119
  const capabilities = await createAssetHubClient({
114
120
  apiKey: auth.apiKey,
115
121
  baseUrl: auth.baseUrl,
@@ -125,7 +131,7 @@ export const diagnose = async ({ resolveAuth, includeMcp, timeoutMs, includeTool
125
131
  };
126
132
  }
127
133
  catch (error) {
128
- return failedCheck('api', error instanceof AssetHubApiError ? error.status : undefined, signal.aborted);
134
+ return failedCheck('api', error instanceof AssetHubApiError || error instanceof WorkspaceClientError ? error.status : undefined, signal.aborted, account);
129
135
  }
130
136
  };
131
137
  const mcpCheck = async () => {
@@ -133,9 +139,9 @@ export const diagnose = async ({ resolveAuth, includeMcp, timeoutMs, includeTool
133
139
  const { StreamableHTTPClientTransport, StreamableHTTPError } = await import('@modelcontextprotocol/sdk/client/streamableHttp.js');
134
140
  const client = new Client({ name: 'assethub-cli-doctor', version });
135
141
  try {
136
- await client.connect(new StreamableHTTPClientTransport(new URL(`${auth.baseUrl}/api/mcp`), {
142
+ await client.connect(new StreamableHTTPClientTransport(new URL(`${auth.baseUrl}${account ? '/api/workspaces/mcp' : '/api/mcp'}`), {
137
143
  fetch: boundedFetch,
138
- requestInit: { headers: { Authorization: `Bearer ${auth.apiKey}` } },
144
+ requestInit: { headers: { Authorization: `Bearer ${auth.apiKey}`, ...(account && auth.workspaceMfaToken ? { Cookie: `ah_workspace_mfa=${encodeURIComponent(auth.workspaceMfaToken)}` } : {}) } },
139
145
  }), { signal, timeout: timeoutMs });
140
146
  let toolCount = 0;
141
147
  const tools = [];
@@ -160,7 +166,7 @@ export const diagnose = async ({ resolveAuth, includeMcp, timeoutMs, includeTool
160
166
  return { name: 'mcp', status: 'pass', toolCount, ...(includeTools ? { tools } : {}) };
161
167
  }
162
168
  catch (error) {
163
- return failedCheck('mcp', error instanceof StreamableHTTPError ? error.code : undefined, signal.aborted);
169
+ return failedCheck('mcp', error instanceof StreamableHTTPError ? error.code : undefined, signal.aborted, account);
164
170
  }
165
171
  finally {
166
172
  await client.close();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@assethub/cli",
3
- "version": "0.1.11",
3
+ "version": "0.1.13",
4
4
  "description": "Command line interface for AssetHub.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -30,7 +30,7 @@
30
30
  "access": "public"
31
31
  },
32
32
  "dependencies": {
33
- "@assethub/api-client": "^0.1.4",
33
+ "@assethub/api-client": "^0.1.6",
34
34
  "@modelcontextprotocol/sdk": "^1.30.0"
35
35
  },
36
36
  "repository": {