@assethub/cli 0.1.22 → 0.1.24

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
@@ -2,6 +2,31 @@
2
2
 
3
3
  Command line interface for AssetHub.
4
4
 
5
+ ## API discovery and Workspace Skills
6
+
7
+ Use `api search [query]` to discover the authenticated server catalog and
8
+ `api describe "METHOD /path"` to inspect an exact request contract. `api call`
9
+ accepts `--path-json`, `--query-json`, and `--input-json` (inline JSON or `@file`).
10
+ Mutations require an explicit stable `--operation-id <uuid>`. Preserve that UUID
11
+ and exact inputs; inspect any returned run ID before retrying uncertain work.
12
+ The server's workspace, gate, billing, and terminal-result rules still apply.
13
+
14
+ `skills list|get|learn|update|controls|prepare|proposal|accept` uses the existing
15
+ Workspace Skills API. Read `--help` for required revisions and JSON inputs.
16
+ For V3.7 Artist Skills or V3.7.1 Building Modules, `production analyze` and new
17
+ `parts split` analyses accept
18
+ `--skill-mode auto|manual|off` and up to three distinct `--skill-id <id>` values.
19
+ Manual selection requires IDs; off rejects them. The server resolves authorized
20
+ published skill revisions and keeps Internal gates and actor checks in force.
21
+ Existing `parts split --order-id` operations reject skill flags; use
22
+ `runs resume` to recover the saved operation with its original selection.
23
+
24
+ For complete-object graph models, add `--context <canvas-id> --context-version <n>`
25
+ to `production analyze` to apply that exact saved Must/Avoid guidance. Both flags
26
+ are required together; `--context` also selects the execution canvas and must
27
+ match `--canvas` when supplied. Stale revisions and unsupported engines fail
28
+ before generation. Guidance does not expand the model's supported part boundaries.
29
+
5
30
  ## Personal API keys
6
31
 
7
32
  Log in once with a personal key, then select its workspace:
package/dist/index.d.ts CHANGED
@@ -1,8 +1,29 @@
1
1
  #!/usr/bin/env node
2
- import { type AnimationRetargetRequest, type Intervention, type RigRequest } from '@assethub/api-client';
2
+ import { type AnimationRetargetRequest, type Intervention, type RigRequest, createAssetHubClient } 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\nCLI and MCP are available to all AssetHub users. Workspace permissions and feature availability apply.\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 [--query <text>] [--limit <1-100>] [--cursor <cursor>]\n assethub workspace 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 download --canvas <id> --out-dir <directory> [--mesh <mesh_asset_id>]\n assethub canvas nodes --canvas <id>\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 refine --list-modes\n assethub composer refine --from-run <run-id> --instruction <text> [--mode standard|thorough|placement|workshop|blender] [--max-rounds <n>] [--transforms-json <json|@file>] [--wait] [--download --out-dir <dir>]\n assethub composer refine --input-json <json|@file> [--canvas <id>] [--operation-id <uuid>] [--wait] [--download --out-dir <dir>]\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 composer run --node <shape:id> --canvas <id> [--model <id>] [--mode quick|quality] [--operation-id <uuid>] [--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 generate --node <shape:id> --canvas <id> [--model-id <id>] [--params-json <json|@file>] [--operation-id <uuid>] [--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 --workspace <id> Select workspace scope for this command without changing saved selection.\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
+ type ResolvedAuth = {
6
+ apiKey: string;
7
+ authentication?: 'personal';
8
+ workspaceId?: string;
9
+ baseUrl: string;
10
+ profile: string;
11
+ source: 'flag' | 'env' | 'profile';
12
+ };
13
+ type CommandContext = {
14
+ client: ReturnType<typeof createAssetHubClient>;
15
+ flags: Flags;
16
+ auth: ResolvedAuth;
17
+ /**
18
+ * The raw argument slice, kept alongside the parsed flags because `Flags` is
19
+ * keyed by flag name and so cannot say which of two different flags came
20
+ * first. `production intervene` needs that order: an intervention batch's seq
21
+ * order in the log is the operator's own order of decisions.
22
+ */
23
+ args: string[];
24
+ };
25
+ export declare const usage = "AssetHub CLI\n\nCLI and MCP are available to all AssetHub users. Workspace permissions and feature availability apply.\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 [--query <text>] [--limit <1-100>] [--cursor <cursor>]\n assethub workspace 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 download --canvas <id> --out-dir <directory> [--mesh <mesh_asset_id>]\n assethub canvas nodes --canvas <id>\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 api search [query]\n assethub api describe \"<METHOD /path>\"\n assethub api call \"<METHOD /path>\" [--path-json <json|@file>] [--query-json <json|@file>] [--input-json <json|@file|@->] [--operation-id <uuid>]\n assethub skills list [--cursor <cursor>]\n assethub skills get <skill-id> [--revision <n>]\n assethub skills learn --input-json <json|@file|@-> --operation-id <uuid>\n assethub skills update <skill-id> --input-json <json|@file|@->\n assethub skills controls <skill-id> --revision <n> --grant-revision <n> --mode automatic|manual|off [--share]\n assethub skills prepare --input-json <json|@file|@->\n assethub skills proposal <proposal-id>\n assethub skills accept <proposal-id> --input-json <json|@file|@->\n assethub composer models\n assethub composer refine --list-modes\n assethub composer refine --from-run <run-id> --instruction <text> [--mode standard|thorough|placement|workshop|blender|codex] [--max-rounds <n>] [--transforms-json <json|@file>] [--wait] [--download --out-dir <dir>]\n assethub composer refine --input-json <json|@file> [--canvas <id>] [--operation-id <uuid>] [--wait] [--download --out-dir <dir>]\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 composer run --node <shape:id> --canvas <id> [--model <id>] [--mode quick|quality] [--operation-id <uuid>] [--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 generate --node <shape:id> --canvas <id> [--model-id <id>] [--params-json <json|@file>] [--operation-id <uuid>] [--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>] [--skill-mode auto|manual|off] [--skill-id <id>...] [--context <canvas-id> --context-version <n>] [--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>] [--skill-mode auto|manual|off] [--skill-id <id>...] [--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 --workspace <id> Select workspace scope for this command without changing saved selection.\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";
26
+ export declare const commandSkills: (subcommand: string | undefined, positionals: string[], ctx: CommandContext) => Promise<void>;
6
27
  /**
7
28
  * The `animate retarget` request, built from flags alone.
8
29
  *
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AA4BA,OAAO,EAIL,KAAK,wBAAwB,EAO7B,KAAK,YAAY,EAEjB,KAAK,UAAU,EAgBhB,MAAM,sBAAsB,CAAA;AAc7B,OAAO,EAAC,kBAAkB,EAAc,MAAM,gCAAgC,CAAA;AAI9E,KAAK,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,EAAE,CAAC,CAAA;AA2JxD,eAAO,MAAM,KAAK,s3aAkIjB,CAAA;AA4sFD;;;;;;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;AAgsCD,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":";AA4BA,OAAO,EAQL,KAAK,wBAAwB,EAO7B,KAAK,YAAY,EAEjB,KAAK,UAAU,EAef,oBAAoB,EACrB,MAAM,sBAAsB,CAAA;AAc7B,OAAO,EAAC,kBAAkB,EAAc,MAAM,gCAAgC,CAAA;AAI9E,KAAK,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,EAAE,CAAC,CAAA;AAuBxD,KAAK,YAAY,GAAG;IAClB,MAAM,EAAE,MAAM,CAAA;IACd,cAAc,CAAC,EAAE,UAAU,CAAA;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS,CAAA;CACnC,CAAA;AAED,KAAK,cAAc,GAAG;IACpB,MAAM,EAAE,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAA;IAC/C,KAAK,EAAE,KAAK,CAAA;IACZ,IAAI,EAAE,YAAY,CAAA;IAClB;;;;;OAKG;IACH,IAAI,EAAE,MAAM,EAAE,CAAA;CACf,CAAA;AA4HD,eAAO,MAAM,KAAK,wvcA6IjB,CAAA;AAi/CD,eAAO,MAAM,aAAa,GACxB,YAAY,MAAM,GAAG,SAAS,EAC9B,aAAa,MAAM,EAAE,EACrB,KAAK,cAAc,KAClB,OAAO,CAAC,IAAI,CA6Hd,CAAA;AA41CD;;;;;;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;AA+tCD,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
@@ -15,7 +15,7 @@ import { basename, dirname, extname, join, resolve } from 'node:path';
15
15
  import { argv, env, exit, stdin, stderr, stdout } from 'node:process';
16
16
  import { fileURLToPath } from 'node:url';
17
17
  import { promisify } from 'node:util';
18
- import { AssetHubApiError, WorkspaceClientError, createWorkspaceClient, createAssetHubClient, } from '@assethub/api-client';
18
+ import { AssetHubApiError, callApiOperation, describeApiOperation, discoverApiOperations, searchApiOperations, WorkspaceClientError, createWorkspaceClient, createAssetHubClient, } from '@assethub/api-client';
19
19
  import { resolveCanvasSelection, saveCanvasSelection } from './canvas.js';
20
20
  import { activeExecution, childOperationId, CliExecutionError, executeRecorded, hasRecordedOperation, openExecutionSession, resumeRecorded, waitForExecution, } from './execution.js';
21
21
  import { buildRunUploadPlan, formatBytes } from './runsUpload/buildRunUpload.js';
@@ -36,6 +36,8 @@ const artifactGraphPartExtractorApiValues = new Set([
36
36
  'ah_agent_graph_v3_6_4',
37
37
  'ah_agent_graph_v3_6_5',
38
38
  'ah_agent_graph_pluffy_v3_1',
39
+ 'ah_agent_graph_v3_7',
40
+ 'ah_agent_graph_v3_7_1',
39
41
  ]);
40
42
  const partExtractorOptions = [
41
43
  {
@@ -78,6 +80,16 @@ const partExtractorOptions = [
78
80
  apiValue: 'ah_agent_graph_pluffy_v3_1',
79
81
  aliases: ['pluffy', 'pluffy v3.1', 'pluffy 3.1'],
80
82
  },
83
+ {
84
+ publicName: 'V3.7 Artist Skills',
85
+ apiValue: 'ah_agent_graph_v3_7',
86
+ aliases: ['v3.7', '3.7'],
87
+ },
88
+ {
89
+ publicName: 'V3.7.1 Building Modules',
90
+ apiValue: 'ah_agent_graph_v3_7_1',
91
+ aliases: ['v3.7.1', '3.7.1'],
92
+ },
81
93
  ];
82
94
  const partExtractorPublicNames = partExtractorOptions
83
95
  .map(option => option.publicName)
@@ -135,9 +147,20 @@ Usage:
135
147
  assethub files upload <file> --media-type image|mesh
136
148
  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>]
137
149
  assethub capabilities
150
+ assethub api search [query]
151
+ assethub api describe "<METHOD /path>"
152
+ assethub api call "<METHOD /path>" [--path-json <json|@file>] [--query-json <json|@file>] [--input-json <json|@file|@->] [--operation-id <uuid>]
153
+ assethub skills list [--cursor <cursor>]
154
+ assethub skills get <skill-id> [--revision <n>]
155
+ assethub skills learn --input-json <json|@file|@-> --operation-id <uuid>
156
+ assethub skills update <skill-id> --input-json <json|@file|@->
157
+ assethub skills controls <skill-id> --revision <n> --grant-revision <n> --mode automatic|manual|off [--share]
158
+ assethub skills prepare --input-json <json|@file|@->
159
+ assethub skills proposal <proposal-id>
160
+ assethub skills accept <proposal-id> --input-json <json|@file|@->
138
161
  assethub composer models
139
162
  assethub composer refine --list-modes
140
- assethub composer refine --from-run <run-id> --instruction <text> [--mode standard|thorough|placement|workshop|blender] [--max-rounds <n>] [--transforms-json <json|@file>] [--wait] [--download --out-dir <dir>]
163
+ assethub composer refine --from-run <run-id> --instruction <text> [--mode standard|thorough|placement|workshop|blender|codex] [--max-rounds <n>] [--transforms-json <json|@file>] [--wait] [--download --out-dir <dir>]
141
164
  assethub composer refine --input-json <json|@file> [--canvas <id>] [--operation-id <uuid>] [--wait] [--download --out-dir <dir>]
142
165
  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]
143
166
  assethub composer run --input-json <json|@file> [--canvas <id>] [--operation-id <uuid>] [--wait] [--download --out-dir <dir>]
@@ -172,7 +195,7 @@ Usage:
172
195
  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>]
173
196
  assethub jobs get <job-id> [--download --out-dir <dir>]
174
197
  assethub jobs watch <job-id> [--interval-ms <ms>] [--timeout-ms <ms>] [--download --out-dir <dir>]
175
- 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>]
198
+ 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>] [--skill-mode auto|manual|off] [--skill-id <id>...] [--context <canvas-id> --context-version <n>] [--wait] [--download --out-dir <dir>]
176
199
  assethub production agents
177
200
  assethub production automation --input-json <json|@file|@-> [--canvas <id>] [--operation-id <uuid>] [--wait]
178
201
  assethub production status <order-id> [--wait] [--download --out-dir <dir>]
@@ -182,7 +205,7 @@ Usage:
182
205
  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>]
183
206
  assethub production interventions <order-id>
184
207
  assethub runs upload <path> [--graph-id <id>] [--stream-id <id>] [--rev <n>] [--description <text>] [--tag <tag>...] [--skip-register] [--dry-run]
185
- 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>]
208
+ 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>] [--skill-mode auto|manual|off] [--skill-id <id>...] [--wait] [--task-id <id>...] [--mission-id <id>] [--all-ready] [--download --out-dir <dir>]
186
209
  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>]
187
210
  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>]
188
211
 
@@ -313,6 +336,30 @@ const resolvePartExtractorApiValue = (value) => {
313
336
  return option.apiValue;
314
337
  };
315
338
  const resolvePartExtractorForAnalyze = (flags) => resolvePartExtractorApiValue(getPartExtractorFlag(flags) ?? defaultPartExtractorName);
339
+ const resolveProductionSkillSelection = (flags, agentVersion) => {
340
+ const mode = getFlag(flags, 'skill-mode');
341
+ const skillIds = getFlagValues(flags, 'skill-id').map(value => assertFlagHasValue(value, '--skill-id <id>'));
342
+ if (mode == null) {
343
+ if (skillIds.length > 0)
344
+ throw new Error('--skill-id requires --skill-mode');
345
+ return undefined;
346
+ }
347
+ if (mode !== 'auto' && mode !== 'manual' && mode !== 'off')
348
+ throw new Error('--skill-mode must be "auto", "manual", or "off"');
349
+ if (!['ah_agent_graph_v3_7', 'ah_agent_graph_v3_7_1'].includes(agentVersion))
350
+ throw new Error('--skill-mode requires V3.7 Artist Skills or V3.7.1 Building Modules');
351
+ if (skillIds.length > 3)
352
+ throw new Error('--skill-id accepts at most 3 values');
353
+ if (new Set(skillIds).size !== skillIds.length)
354
+ throw new Error('--skill-id values must be unique');
355
+ if (skillIds.some(skillId => !/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/.test(skillId)))
356
+ throw new Error('--skill-id contains an invalid workspace skill ID');
357
+ if (mode === 'manual' && skillIds.length === 0)
358
+ throw new Error('--skill-mode manual requires at least one --skill-id');
359
+ if (mode === 'off' && skillIds.length > 0)
360
+ throw new Error('--skill-mode off does not accept --skill-id');
361
+ return { mode, skillIds };
362
+ };
316
363
  const publicPartExtractorName = (value) => {
317
364
  if (value == null) {
318
365
  return null;
@@ -1275,6 +1322,112 @@ const commandSource = async (subcommand, ctx) => {
1275
1322
  }
1276
1323
  print({ source, fileRef: source.fileRef, mediaType });
1277
1324
  };
1325
+ const commandApi = async (subcommand, positionals, ctx) => {
1326
+ if (!['search', 'describe', 'call'].includes(subcommand ?? ''))
1327
+ throw new Error('Use api search|describe|call. Mutations require --operation-id.');
1328
+ const discovery = await discoverApiOperations(ctx.client);
1329
+ if (subcommand === 'search') {
1330
+ print({
1331
+ operations: searchApiOperations(discovery.catalog, positionals.slice(2).join(' ')),
1332
+ });
1333
+ return;
1334
+ }
1335
+ const operation = requirePositional(positionals, 2, 'operation');
1336
+ if (subcommand === 'describe') {
1337
+ const found = discovery.catalog.get(operation);
1338
+ if (!found)
1339
+ throw new Error('Unknown operation. Use api search first.');
1340
+ print(describeApiOperation(found, discovery.specs[found.path.startsWith('/api/v1/') ? 'v1' : 'v2']));
1341
+ return;
1342
+ }
1343
+ const pathJson = getFlag(ctx.flags, 'path-json');
1344
+ const queryJson = getFlag(ctx.flags, 'query-json');
1345
+ const bodyJson = getFlag(ctx.flags, 'input-json');
1346
+ const operationId = getFlag(ctx.flags, 'operation-id');
1347
+ activeExecution.operationId = operationId;
1348
+ try {
1349
+ print(await callApiOperation(ctx.client, discovery, {
1350
+ operation,
1351
+ operationId,
1352
+ path: pathJson
1353
+ ? (await readJsonArgument(pathJson, '--path-json'))
1354
+ : undefined,
1355
+ query: queryJson
1356
+ ? (await readJsonArgument(queryJson, '--query-json'))
1357
+ : undefined,
1358
+ body: bodyJson
1359
+ ? await readJsonArgument(bodyJson, '--input-json')
1360
+ : undefined,
1361
+ }));
1362
+ }
1363
+ catch (error) {
1364
+ if (error instanceof AssetHubApiError && error.runId)
1365
+ activeExecution.runId = error.runId;
1366
+ throw error;
1367
+ }
1368
+ };
1369
+ export const commandSkills = async (subcommand, positionals, ctx) => {
1370
+ if (subcommand === 'list') {
1371
+ print(await ctx.client.v2.listWorkspaceSkills({
1372
+ cursor: getFlag(ctx.flags, 'cursor'),
1373
+ }));
1374
+ return;
1375
+ }
1376
+ if (subcommand === 'get') {
1377
+ print(await ctx.client.v2.getWorkspaceSkill(requirePositional(positionals, 2, 'skill-id'), {
1378
+ revision: hasFlag(ctx.flags, 'revision')
1379
+ ? parsePositiveIntegerFlag(ctx.flags, 'revision', 1)
1380
+ : undefined,
1381
+ }));
1382
+ return;
1383
+ }
1384
+ if (subcommand === 'controls') {
1385
+ const mode = parseEnumFlag(ctx.flags, 'mode', [
1386
+ 'automatic',
1387
+ 'manual',
1388
+ 'off',
1389
+ ]);
1390
+ if (!mode)
1391
+ throw new Error('Missing required flag: --mode');
1392
+ requireFlag(ctx.flags, 'revision');
1393
+ requireFlag(ctx.flags, 'grant-revision');
1394
+ print(await ctx.client.v2.setWorkspaceSkillControls(requirePositional(positionals, 2, 'skill-id'), {
1395
+ expectedRevision: parsePositiveIntegerFlag(ctx.flags, 'revision', 1),
1396
+ expectedGrantRevision: parsePositiveIntegerFlag(ctx.flags, 'grant-revision', 1),
1397
+ mode,
1398
+ ...(hasFlag(ctx.flags, 'share') ? { share: true } : {}),
1399
+ }));
1400
+ return;
1401
+ }
1402
+ if (subcommand === 'proposal') {
1403
+ print(await ctx.client.v2.getWorkspaceSkillProposal(requirePositional(positionals, 2, 'proposal-id')));
1404
+ return;
1405
+ }
1406
+ if (['learn', 'prepare'].includes(subcommand ?? '')) {
1407
+ const input = await readJsonArgument(requireFlag(ctx.flags, 'input-json'), '--input-json');
1408
+ const operationId = subcommand === 'learn'
1409
+ ? requireFlag(ctx.flags, 'operation-id')
1410
+ : undefined;
1411
+ if (operationId != null &&
1412
+ !/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(operationId))
1413
+ throw new Error('--operation-id must be a UUID; reuse the same ID and input after an uncertain response');
1414
+ if (operationId != null)
1415
+ activeExecution.operationId = operationId;
1416
+ print(subcommand === 'learn'
1417
+ ? await ctx.client.v2.learnWorkspaceSkill(input, { idempotencyKey: operationId })
1418
+ : await ctx.client.v2.prepareWorkspaceSkillProposal(input));
1419
+ return;
1420
+ }
1421
+ if (['update', 'accept'].includes(subcommand ?? '')) {
1422
+ const id = requirePositional(positionals, 2, subcommand === 'update' ? 'skill-id' : 'proposal-id');
1423
+ const input = await readJsonArgument(requireFlag(ctx.flags, 'input-json'), '--input-json');
1424
+ print(subcommand === 'update'
1425
+ ? await ctx.client.v2.updateWorkspaceSkill(id, input)
1426
+ : await ctx.client.v2.acceptWorkspaceSkillProposal(id, input));
1427
+ return;
1428
+ }
1429
+ throw new Error('Use skills list|get|learn|update|controls|prepare|proposal|accept');
1430
+ };
1278
1431
  const commandModels = async (subcommand, positionals, ctx) => {
1279
1432
  if (subcommand === 'list') {
1280
1433
  const domain = getFlag(ctx.flags, 'domain');
@@ -1966,6 +2119,7 @@ const meshRefinementModes = [
1966
2119
  'placement',
1967
2120
  'workshop',
1968
2121
  'blender',
2122
+ 'codex',
1969
2123
  ];
1970
2124
  const refinementTransforms = (value, flag) => {
1971
2125
  if (value == null || typeof value !== 'object' || Array.isArray(value))
@@ -1997,6 +2151,10 @@ const refinementModeInfo = (capabilities, mode) => {
1997
2151
  throw new Error(`Refinement mode ${mode} is unavailable${info.reason ? `: ${info.reason}` : ''}`);
1998
2152
  return info;
1999
2153
  };
2154
+ const refinementContinuationFields = [
2155
+ 'geometryBackend', 'referenceMode', 'calibration', 'referenceViews',
2156
+ 'geometrySources', 'reviewContext', 'background',
2157
+ ];
2000
2158
  /** Reuse the frozen sources and latest editable scene, never replay server-only receipt fields. */
2001
2159
  const composerInputFromRun = (previous, operation) => {
2002
2160
  const source = previous.resolvedInput ?? previous.input ?? previous.requestedInput ?? {};
@@ -2012,7 +2170,14 @@ const composerInputFromRun = (previous, operation) => {
2012
2170
  'quickRunId',
2013
2171
  'quickScene',
2014
2172
  ]
2015
- : ['fullBodyImageAssetId', 'agentRuntime', 'mode', 'instruction', 'maxRounds'];
2173
+ : [
2174
+ 'fullBodyImageAssetId',
2175
+ 'agentRuntime',
2176
+ 'mode',
2177
+ 'instruction',
2178
+ 'maxRounds',
2179
+ ...refinementContinuationFields,
2180
+ ];
2016
2181
  const input = Object.fromEntries(fields
2017
2182
  .filter(key => source[key] !== undefined)
2018
2183
  .map(key => [key, source[key]]));
@@ -2036,6 +2201,13 @@ const composerInputFromRun = (previous, operation) => {
2036
2201
  if (transforms != null)
2037
2202
  input.transforms = transforms;
2038
2203
  if (operation === 'mesh.refine') {
2204
+ for (const key of ['calibration', 'referenceViews', 'geometrySources']) {
2205
+ if (previous.refinement?.[key] != null)
2206
+ input[key] = previous.refinement[key];
2207
+ }
2208
+ const reviewContext = previous.refinement?.report?.reviewContext;
2209
+ if (reviewContext != null)
2210
+ input.reviewContext = reviewContext;
2039
2211
  const referenceTransform = previous.composition?.referenceTransform ?? source.referenceTransform;
2040
2212
  if (referenceTransform != null)
2041
2213
  input.referenceTransform = referenceTransform;
@@ -2097,6 +2269,8 @@ const commandComposerRefine = async (ctx) => {
2097
2269
  capabilities.defaultMode;
2098
2270
  if (!meshRefinementModes.includes(mode))
2099
2271
  throw new Error(`--mode must be one of: ${meshRefinementModes.join(', ')}`);
2272
+ if (mode !== 'codex' && (input.geometryBackend || input.referenceMode === 'all_angles' || input.background))
2273
+ throw new Error('Saved Blender-backend, all-angle or background settings require codex mode; use --input-json with settings matching the new mode');
2100
2274
  const modeInfo = refinementModeInfo(capabilities, mode);
2101
2275
  const maxRoundsFlag = getFlag(ctx.flags, 'max-rounds');
2102
2276
  const inputMaxRounds = input.maxRounds;
@@ -2129,6 +2303,9 @@ const commandComposerRefine = async (ctx) => {
2129
2303
  operation: 'mesh.refine',
2130
2304
  });
2131
2305
  const body = {
2306
+ ...Object.fromEntries(refinementContinuationFields
2307
+ .filter(key => input[key] !== undefined)
2308
+ .map(key => [key, input[key]])),
2132
2309
  parts: refinementParts,
2133
2310
  fullBodyImageAssetId: input.fullBodyImageAssetId,
2134
2311
  transforms,
@@ -2893,9 +3070,9 @@ const readOpsJsonFlag = async (flags) => {
2893
3070
  }
2894
3071
  return parsed;
2895
3072
  };
2896
- const productionSession = (ctx, operation) => openExecutionSession({
3073
+ const productionSession = (ctx, operation, canvasId = selectedCanvasId(ctx.flags)) => openExecutionSession({
2897
3074
  ...stateOptions(ctx),
2898
- canvasId: selectedCanvasId(ctx.flags),
3075
+ canvasId,
2899
3076
  operation,
2900
3077
  });
2901
3078
  const commandProduction = async (subcommand, positionals, ctx) => {
@@ -2904,11 +3081,28 @@ const commandProduction = async (subcommand, positionals, ctx) => {
2904
3081
  return;
2905
3082
  }
2906
3083
  if (subcommand === 'analyze') {
2907
- const session = await productionSession(ctx, 'production.analyze');
3084
+ const agentVersion = resolvePartExtractorForAnalyze(ctx.flags);
3085
+ const skillSelection = resolveProductionSkillSelection(ctx.flags, agentVersion);
3086
+ const projectContext = hasFlag(ctx.flags, 'context') || hasFlag(ctx.flags, 'context-version')
3087
+ ? {
3088
+ canvasId: Number(requireFlag(ctx.flags, 'context')),
3089
+ version: Number(requireFlag(ctx.flags, 'context-version')),
3090
+ }
3091
+ : undefined;
3092
+ if (projectContext) {
3093
+ if (Object.values(projectContext).some(value => !Number.isSafeInteger(value) || value <= 0))
3094
+ throw new Error('--context and --context-version must be positive integers');
3095
+ const canvasId = selectedCanvasId(ctx.flags);
3096
+ if (canvasId != null && canvasId !== projectContext.canvasId)
3097
+ throw new Error('--context must match --canvas');
3098
+ }
3099
+ const session = await productionSession(ctx, 'production.analyze', projectContext?.canvasId);
2908
3100
  const analyzed = await executeRecorded(session, 'production.analyze', {
2909
3101
  ...(await resolveProductionAnalyzeSource(ctx)),
2910
- agentVersion: resolvePartExtractorForAnalyze(ctx.flags),
3102
+ agentVersion,
2911
3103
  name: getFlag(ctx.flags, 'name'),
3104
+ ...(skillSelection == null ? {} : { skillSelection }),
3105
+ ...(projectContext == null ? {} : { projectContext }),
2912
3106
  }, executionOptions(ctx.flags));
2913
3107
  await printRecorded(ctx, analyzed);
2914
3108
  return;
@@ -3091,11 +3285,16 @@ const commandParts = async (subcommand, ctx) => {
3091
3285
  let orderId = source == null ? getFlag(ctx.flags, 'order-id') : undefined;
3092
3286
  if (orderId != null) {
3093
3287
  orderId = assertFlagHasValue(orderId, '--order-id <id>');
3288
+ if (hasFlag(ctx.flags, 'skill-mode') || hasFlag(ctx.flags, 'skill-id'))
3289
+ throw new Error('--skill-mode and --skill-id cannot be changed with --order-id; use runs resume to preserve the saved selection');
3094
3290
  }
3095
3291
  const partExtractorFlag = getPartExtractorFlag(ctx.flags);
3096
3292
  const requestedAgentVersion = orderId == null || partExtractorFlag != null
3097
3293
  ? resolvePartExtractorApiValue(partExtractorFlag ?? defaultPartExtractorName)
3098
3294
  : undefined;
3295
+ const skillSelection = requestedAgentVersion == null
3296
+ ? undefined
3297
+ : resolveProductionSkillSelection(ctx.flags, requestedAgentVersion);
3099
3298
  if (requestedAgentVersion != null &&
3100
3299
  artifactGraphPartExtractorApiValues.has(requestedAgentVersion)) {
3101
3300
  const publicName = publicPartExtractorName(requestedAgentVersion);
@@ -3115,6 +3314,7 @@ const commandParts = async (subcommand, ctx) => {
3115
3314
  ...(source ?? (await resolveProductionAnalyzeSource(ctx))),
3116
3315
  agentVersion: resolvePartExtractorForAnalyze(ctx.flags),
3117
3316
  name: getFlag(ctx.flags, 'name'),
3317
+ ...(skillSelection == null ? {} : { skillSelection }),
3118
3318
  }, { ...executionOptions(ctx.flags), operationId });
3119
3319
  analyzed = result;
3120
3320
  execution = result.execution;
@@ -3930,6 +4130,12 @@ const run = async () => {
3930
4130
  }
3931
4131
  const ctx = await createContext(parsed.flags, argv.slice(2));
3932
4132
  switch (command) {
4133
+ case 'api':
4134
+ await commandApi(subcommand, parsed.positionals, ctx);
4135
+ return;
4136
+ case 'skills':
4137
+ await commandSkills(subcommand, parsed.positionals, ctx);
4138
+ return;
3933
4139
  case 'composer':
3934
4140
  await commandComposer(subcommand, ctx);
3935
4141
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@assethub/cli",
3
- "version": "0.1.22",
3
+ "version": "0.1.24",
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.10",
33
+ "@assethub/api-client": "^0.1.11",
34
34
  "@modelcontextprotocol/sdk": "^1.30.0"
35
35
  },
36
36
  "repository": {