@assethub/cli 0.1.25 → 0.1.27

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
@@ -67,6 +67,8 @@ authentication. Existing workspace keys and user-token login remain supported.
67
67
  ```sh
68
68
  assethub --version
69
69
  assethub doctor --mcp --profile my-workspace
70
+ assethub init --dry-run
71
+ assethub init
70
72
  assethub mcp config --client cursor
71
73
  assethub mcp config --client codex
72
74
  ```
@@ -87,6 +89,19 @@ Use the same key as your CLI profile. Personal profiles include the selected
87
89
  For a different API origin, pass
88
90
  `--base-url https://your-host/prefix` (HTTP is accepted only for localhost).
89
91
 
92
+ `init` sets up every supported coding agent found on this machine — Claude Code,
93
+ Codex, and Cursor — in one step. It writes the hosted MCP entry into each agent's
94
+ own configuration (merging with what is already there), installs the bundled
95
+ `assethub` skill under `~/.agents/skills/assethub`, and links it into each agent's
96
+ skill directory so the agent knows the correct command sequence, cost rules, and
97
+ recovery steps without being told. Pass `--agent <name>` to choose agents
98
+ explicitly, `--project` to write project-level MCP files into the current
99
+ directory instead of your home, and `--dry-run` to see the plan without writing.
100
+ `init` never stores a key: the MCP entries read `ASSETHUB_API_KEY` from the
101
+ agent's environment. Directories that `init` did not create are left untouched.
102
+ After a CLI upgrade, the next command refreshes the installed skill automatically.
103
+ Set `ASSETHUB_CLI_HOME` to redirect all of these writes, for example in tests.
104
+
90
105
  Explicit `--profile` uses that profile's key and origin, ahead of environment
91
106
  variables, including user tokens and workspace MFA proofs. A missing profile fails.
92
107
  Without an explicit profile, a personal profile or a workspace selected with
@@ -247,8 +262,10 @@ has its own saved operation ID, with the execution linked to the analysis run.
247
262
  For Internal `V3.6.1` (`V3.6.1 Primary Images First`), `V3.6.3`
248
263
  (`V3.6.3 Fast Analysis`, CLI 0.1.16+), `V3.6.4`
249
264
  (`V3.6.4 Fast Analysis`, CLI 0.1.17+), `V3.6.5 Primary Images` and
250
- `Chibi Character (Pluffy) v3.1` (both CLI 0.1.20+), analysis runs the complete
251
- Artifact Graph split. `--all-ready` waits for that one receipt and does not start a
265
+ `Chibi Character (Pluffy) v3.1` (both CLI 0.1.20+), `V3.7 Artist Skills`,
266
+ `V3.7.1 Building Modules` (both CLI 0.1.23+/0.1.24+), `V3.0.9 Garment
267
+ Boundaries`, and `Humanoid Assembly (internal)` (both CLI 0.1.26+), analysis
268
+ runs the complete Artifact Graph split. `--all-ready` waits for that one receipt and does not start a
252
269
  second production execution. Resume an interrupted graph split with
253
270
  `runs resume <operation-id>`; `--task-id`, `--mission-id`,
254
271
  `--part-extraction-mode`, and classic `--order-id` continuation are unsupported.
@@ -522,6 +539,13 @@ Part extraction uses the same names shown in the AssetHub product: `V1.5`,
522
539
  `V3.6.4` (`V3.6.4 Fast Analysis`), `V3.6.5` (`V3.6.5 Primary Images`),
523
540
  and `pluffy` (`Chibi Character (Pluffy) v3.1`). CLI 0.1.20 adds the latter two;
524
541
  `3.6.5`, `pluffy v3.1`, and `pluffy 3.1` are also accepted aliases.
542
+ `V3.7 Artist Skills` (`v3.7`; also known as `V3.0.7 Artist Skills`) and
543
+ `V3.7.1 Building Modules` (`v3.7.1`; also known as `V3.0.8 Building Modules`)
544
+ support `--skill-mode`. `V3.0.9 Garment Boundaries` (`v3.0.9`) and
545
+ `Humanoid Assembly (internal)` (`humanoid assembly`, `humanoid-assembly`,
546
+ `humanoid_assembly_auto`; CLI 0.1.26+) are additional Internal-only graph
547
+ extractors; use the exact quoted public name or one of its aliases with
548
+ `--part-extractor`.
525
549
  Run `production agents` to check availability and `supportedOnGraphEndpoint`
526
550
  before selecting a graph version. These aliases do not change the V1.5 default
527
551
  or grant access to Internal models; the server still authorizes the account.
@@ -545,6 +569,11 @@ assethub canvas list
545
569
  assethub canvas use <canvas-id>
546
570
  assethub composer models
547
571
  assethub composer run --part <mesh-id> --part <mesh-id> --reference <image-id> --wait
572
+ # Composer V6 (auto-assemble) requires each part's reference image; attach it
573
+ # with `<mesh-id>:<part-image-asset-id>` (the image that mesh was generated
574
+ # from) when the mesh has no other lineage the run can resolve it from.
575
+ assethub composer run --part <mesh-id>:<part-image-id> --part <mesh-id>:<part-image-id> \
576
+ --reference <image-id> --model part_composer_v6_auto_assemble --wait
548
577
  assethub composer run --from-run <run-id> --transforms-json @transforms.json --wait
549
578
  assethub composer refine --list-modes
550
579
  assethub composer refine --from-run <run-id> --instruction "align the feet" \
@@ -0,0 +1,69 @@
1
+ export declare const AGENT_IDS: readonly ["claude-code", "codex", "cursor"];
2
+ export type AgentId = (typeof AGENT_IDS)[number];
3
+ type AgentSpec = {
4
+ id: AgentId;
5
+ name: string;
6
+ /** Presence of this directory under home means the agent is installed. */
7
+ detectDir: string;
8
+ globalMcpPath: string;
9
+ projectMcpPath: string;
10
+ skillDir: string;
11
+ format: 'claude' | 'cursor' | 'codex';
12
+ };
13
+ /** `ASSETHUB_CLI_HOME` keeps tests and sandboxes from writing into the real home directory. */
14
+ export declare const cliHome: () => string;
15
+ export declare const packagedSkillDir: () => string;
16
+ export declare const canonicalSkillDir: (home: string) => string;
17
+ export declare const mcpServerEntry: (format: AgentSpec["format"], baseUrl: string, workspaceId?: string) => Record<string, unknown>;
18
+ type WriteStatus = 'created' | 'updated' | 'unchanged';
19
+ type SkillStatus = 'installed' | 'updated' | 'unchanged' | 'kept-existing';
20
+ export declare const installSkill: ({ home, version, dryRun, }: {
21
+ home: string;
22
+ version: string;
23
+ dryRun: boolean;
24
+ }) => Promise<{
25
+ path: string;
26
+ status: SkillStatus;
27
+ version?: string;
28
+ }>;
29
+ type LinkStatus = 'linked' | 'relinked' | 'unchanged' | 'kept-existing';
30
+ /**
31
+ * Refresh an installed skill after a CLI upgrade. Runs before every command;
32
+ * the steady-state cost is one small file read. Never throws — a read-only or
33
+ * missing home must not fail the user's actual command.
34
+ */
35
+ export declare const syncInstalledSkill: () => Promise<void>;
36
+ export type InitOptions = {
37
+ baseUrl: string;
38
+ workspaceId?: string;
39
+ /** Agent ids to configure; defaults to every agent detected under home. */
40
+ agents?: string[];
41
+ /** Write project-level MCP config into the working directory instead of the user's home. */
42
+ project?: boolean;
43
+ dryRun?: boolean;
44
+ cwd?: string;
45
+ home?: string;
46
+ };
47
+ export type InitReport = {
48
+ version: string;
49
+ dryRun: boolean;
50
+ scope: 'global' | 'project';
51
+ skill: Awaited<ReturnType<typeof installSkill>>;
52
+ agents: {
53
+ id: AgentId;
54
+ name: string;
55
+ detected: boolean;
56
+ mcp: {
57
+ path: string;
58
+ status: WriteStatus;
59
+ };
60
+ skill: {
61
+ path: string;
62
+ status: LinkStatus;
63
+ };
64
+ }[];
65
+ next: string[];
66
+ };
67
+ export declare const initAgents: (options: InitOptions) => Promise<InitReport>;
68
+ export {};
69
+ //# sourceMappingURL=agentSetup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agentSetup.d.ts","sourceRoot":"","sources":["../src/agentSetup.ts"],"names":[],"mappings":"AAgCA,eAAO,MAAM,SAAS,6CAA8C,CAAA;AACpE,MAAM,MAAM,OAAO,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,CAAC,CAAA;AAEhD,KAAK,SAAS,GAAG;IACf,EAAE,EAAE,OAAO,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,0EAA0E;IAC1E,SAAS,EAAE,MAAM,CAAA;IACjB,aAAa,EAAE,MAAM,CAAA;IACrB,cAAc,EAAE,MAAM,CAAA;IACtB,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAA;CACtC,CAAA;AAoCD,+FAA+F;AAC/F,eAAO,MAAM,OAAO,QAAO,MAA4C,CAAA;AAEvE,eAAO,MAAM,gBAAgB,QAAO,MACiC,CAAA;AAErE,eAAO,MAAM,iBAAiB,GAAI,MAAM,MAAM,KAAG,MACJ,CAAA;AA2B7C,eAAO,MAAM,cAAc,GACzB,QAAQ,SAAS,CAAC,QAAQ,CAAC,EAC3B,SAAS,MAAM,EACf,cAAc,MAAM,KACnB,MAAM,CAAC,MAAM,EAAE,OAAO,CAYxB,CAAA;AAED,KAAK,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,WAAW,CAAA;AA2EtD,KAAK,WAAW,GAAG,WAAW,GAAG,SAAS,GAAG,WAAW,GAAG,eAAe,CAAA;AAmC1E,eAAO,MAAM,YAAY,GAAU,4BAIhC;IACD,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,OAAO,CAAA;CAChB,KAAG,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,WAAW,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAC,CAwBhE,CAAA;AAED,KAAK,UAAU,GAAG,QAAQ,GAAG,UAAU,GAAG,WAAW,GAAG,eAAe,CAAA;AAkCvE;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,QAAa,OAAO,CAAC,IAAI,CAevD,CAAA;AAID,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,2EAA2E;IAC3E,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;IACjB,4FAA4F;IAC5F,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,OAAO,CAAA;IACf,KAAK,EAAE,QAAQ,GAAG,SAAS,CAAA;IAC3B,KAAK,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC,CAAA;IAC/C,MAAM,EAAE;QACN,EAAE,EAAE,OAAO,CAAA;QACX,IAAI,EAAE,MAAM,CAAA;QACZ,QAAQ,EAAE,OAAO,CAAA;QACjB,GAAG,EAAE;YAAC,IAAI,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,WAAW,CAAA;SAAC,CAAA;QACxC,KAAK,EAAE;YAAC,IAAI,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,UAAU,CAAA;SAAC,CAAA;KAC1C,EAAE,CAAA;IACH,IAAI,EAAE,MAAM,EAAE,CAAA;CACf,CAAA;AAED,eAAO,MAAM,UAAU,GAAU,SAAS,WAAW,KAAG,OAAO,CAAC,UAAU,CA4EzE,CAAA"}
@@ -0,0 +1,311 @@
1
+ /**
2
+ * `assethub init` and the skill sync that keeps its output current.
3
+ *
4
+ * Coding agents learn a tool from two local files: an MCP server entry in their
5
+ * own config, and a skill directory they read on demand. `init` writes both for
6
+ * every supported agent found on this machine, merging into existing config
7
+ * rather than replacing it, and never touching credentials — the MCP entries
8
+ * reference `ASSETHUB_API_KEY` from the agent's environment.
9
+ *
10
+ * The skill is copied once to `~/.agents/skills/assethub` and symlinked into
11
+ * each agent's skill directory. A version marker lets every later command
12
+ * refresh the copy when the CLI has been upgraded, so agents never read rules
13
+ * written for a version they are no longer running.
14
+ */
15
+ import { cp, lstat, mkdir, readFile, readlink, rename, rm, stat, symlink, writeFile, } from 'node:fs/promises';
16
+ import { homedir } from 'node:os';
17
+ import { dirname, join, relative, resolve } from 'node:path';
18
+ import { cwd as processCwd, env, pid } from 'node:process';
19
+ import { fileURLToPath } from 'node:url';
20
+ import { cliVersion, mcpConfig, validatedBaseUrl } from './setup.js';
21
+ export const AGENT_IDS = ['claude-code', 'codex', 'cursor'];
22
+ const AGENTS = [
23
+ {
24
+ id: 'claude-code',
25
+ name: 'Claude Code',
26
+ detectDir: '.claude',
27
+ globalMcpPath: '.claude.json',
28
+ projectMcpPath: '.mcp.json',
29
+ skillDir: '.claude/skills',
30
+ format: 'claude',
31
+ },
32
+ {
33
+ id: 'codex',
34
+ name: 'Codex',
35
+ detectDir: '.codex',
36
+ globalMcpPath: '.codex/config.toml',
37
+ projectMcpPath: '.codex/config.toml',
38
+ skillDir: '.codex/skills',
39
+ format: 'codex',
40
+ },
41
+ {
42
+ id: 'cursor',
43
+ name: 'Cursor',
44
+ detectDir: '.cursor',
45
+ globalMcpPath: '.cursor/mcp.json',
46
+ projectMcpPath: '.cursor/mcp.json',
47
+ skillDir: '.cursor/skills',
48
+ format: 'cursor',
49
+ },
50
+ ];
51
+ const SERVER_NAME = 'assethub';
52
+ const SKILL_NAME = 'assethub';
53
+ const VERSION_MARKER = '.assethub-cli-version';
54
+ /** `ASSETHUB_CLI_HOME` keeps tests and sandboxes from writing into the real home directory. */
55
+ export const cliHome = () => env.ASSETHUB_CLI_HOME || homedir();
56
+ export const packagedSkillDir = () => fileURLToPath(new URL(`../skills/${SKILL_NAME}/`, import.meta.url));
57
+ export const canonicalSkillDir = (home) => join(home, '.agents', 'skills', SKILL_NAME);
58
+ const isEnoent = (error) => typeof error === 'object' &&
59
+ error !== null &&
60
+ error.code === 'ENOENT';
61
+ const readText = async (path) => {
62
+ try {
63
+ return await readFile(path, 'utf8');
64
+ }
65
+ catch (error) {
66
+ if (isEnoent(error))
67
+ return undefined;
68
+ throw error;
69
+ }
70
+ };
71
+ const isDirectory = async (path) => {
72
+ try {
73
+ return (await stat(path)).isDirectory();
74
+ }
75
+ catch (error) {
76
+ if (isEnoent(error))
77
+ return false;
78
+ throw error;
79
+ }
80
+ };
81
+ // ── MCP configuration ────────────────────────────────────────────────
82
+ export const mcpServerEntry = (format, baseUrl, workspaceId) => {
83
+ const url = `${validatedBaseUrl(baseUrl)}/api/mcp`;
84
+ // Cursor expands `${env:NAME}`; Claude Code expands `${NAME}`. Neither file ever holds the key.
85
+ const key = format === 'cursor' ? '${env:ASSETHUB_API_KEY}' : '${ASSETHUB_API_KEY}';
86
+ return {
87
+ ...(format === 'claude' ? { type: 'http' } : {}),
88
+ url,
89
+ headers: {
90
+ Authorization: `Bearer ${key}`,
91
+ ...(workspaceId ? { 'X-AssetHub-Workspace': workspaceId } : {}),
92
+ },
93
+ };
94
+ };
95
+ const writeJsonServer = async (path, entry, dryRun) => {
96
+ const text = await readText(path);
97
+ let document = {};
98
+ if (text !== undefined) {
99
+ let parsed;
100
+ try {
101
+ parsed = JSON.parse(text);
102
+ }
103
+ catch {
104
+ throw new Error(`${path} is not valid JSON. Fix or move it, then rerun init.`);
105
+ }
106
+ if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed))
107
+ throw new Error(`${path} must contain a JSON object.`);
108
+ document = parsed;
109
+ }
110
+ // A malformed `mcpServers` is the user's data too; refuse rather than replace it.
111
+ if (document.mcpServers !== undefined &&
112
+ (typeof document.mcpServers !== 'object' ||
113
+ document.mcpServers === null ||
114
+ Array.isArray(document.mcpServers)))
115
+ throw new Error(`${path} has a non-object "mcpServers" value. Fix or move it, then rerun init.`);
116
+ const servers = (document.mcpServers ?? {});
117
+ if (JSON.stringify(servers[SERVER_NAME]) === JSON.stringify(entry))
118
+ return 'unchanged';
119
+ const next = { ...document, mcpServers: { ...servers, [SERVER_NAME]: entry } };
120
+ if (!dryRun) {
121
+ await mkdir(dirname(path), { recursive: true });
122
+ await writeFile(path, `${JSON.stringify(next, null, 2)}\n`);
123
+ }
124
+ return text === undefined ? 'created' : 'updated';
125
+ };
126
+ /** Replaces or appends one `[mcp_servers.assethub]` table; every other line is kept verbatim. */
127
+ const writeTomlSection = async (path, section, dryRun) => {
128
+ const header = `[mcp_servers.${SERVER_NAME}]`;
129
+ const body = section.trimEnd();
130
+ const text = await readText(path);
131
+ const lines = (text ?? '').split('\n');
132
+ const start = lines.findIndex(line => line.trim() === header);
133
+ let next;
134
+ if (start === -1) {
135
+ const base = (text ?? '').trimEnd();
136
+ next = `${base ? `${base}\n\n` : ''}${body}\n`;
137
+ }
138
+ else {
139
+ const endOffset = lines
140
+ .slice(start + 1)
141
+ .findIndex(line => /^\s*\[/.test(line));
142
+ const end = endOffset === -1 ? lines.length : start + 1 + endOffset;
143
+ if (lines.slice(start, end).join('\n').trimEnd() === body)
144
+ return 'unchanged';
145
+ const before = lines.slice(0, start).join('\n').trimEnd();
146
+ const after = lines.slice(end).join('\n').trim();
147
+ next = `${before ? `${before}\n\n` : ''}${body}\n${after ? `\n${after}\n` : ''}`;
148
+ }
149
+ if (!dryRun) {
150
+ await mkdir(dirname(path), { recursive: true });
151
+ await writeFile(path, next);
152
+ }
153
+ return text === undefined ? 'created' : 'updated';
154
+ };
155
+ const readMarker = async (dir) => (await readText(join(dir, VERSION_MARKER)))?.trim();
156
+ /**
157
+ * Stage the new copy beside the target, then swap with two renames, so the
158
+ * installed skill is never deleted before its replacement is complete. A
159
+ * failed swap puts the previous copy back. Two CLIs syncing at the same
160
+ * moment use distinct staging names; whichever copy lands is complete, and
161
+ * the loser's error is swallowed by the caller.
162
+ */
163
+ const replaceSkillDir = async (source, target, version) => {
164
+ const staging = `${target}.next-${pid}`;
165
+ const previous = `${target}.prev-${pid}`;
166
+ await rm(staging, { recursive: true, force: true });
167
+ await mkdir(dirname(target), { recursive: true });
168
+ await cp(source, staging, { recursive: true });
169
+ await writeFile(join(staging, VERSION_MARKER), `${version}\n`);
170
+ const hadTarget = await isDirectory(target);
171
+ if (hadTarget)
172
+ await rename(target, previous);
173
+ try {
174
+ await rename(staging, target);
175
+ }
176
+ catch (error) {
177
+ if (hadTarget)
178
+ await rename(previous, target).catch(() => undefined);
179
+ await rm(staging, { recursive: true, force: true });
180
+ throw error;
181
+ }
182
+ if (hadTarget)
183
+ await rm(previous, { recursive: true, force: true });
184
+ };
185
+ export const installSkill = async ({ home, version, dryRun, }) => {
186
+ const source = packagedSkillDir();
187
+ if (!(await isDirectory(source)))
188
+ throw new Error('This CLI installation does not include the packaged agent skill.');
189
+ const target = canonicalSkillDir(home);
190
+ const marker = await readMarker(target);
191
+ // A directory without our marker is the user's own; leave it alone.
192
+ const status = marker === undefined
193
+ ? (await isDirectory(target))
194
+ ? 'kept-existing'
195
+ : 'installed'
196
+ : marker === version
197
+ ? 'unchanged'
198
+ : 'updated';
199
+ if (!dryRun && (status === 'installed' || status === 'updated'))
200
+ await replaceSkillDir(source, target, version);
201
+ return {
202
+ path: target,
203
+ status,
204
+ ...(status === 'kept-existing' ? {} : { version }),
205
+ };
206
+ };
207
+ const linkSkill = async (agentSkillsDir, canonical, dryRun) => {
208
+ const link = join(agentSkillsDir, SKILL_NAME);
209
+ const relativeTarget = relative(agentSkillsDir, canonical);
210
+ let existing;
211
+ try {
212
+ existing = await lstat(link);
213
+ }
214
+ catch (error) {
215
+ if (!isEnoent(error))
216
+ throw error;
217
+ }
218
+ if (existing?.isSymbolicLink()) {
219
+ if (resolve(agentSkillsDir, await readlink(link)) === canonical)
220
+ return { path: link, status: 'unchanged' };
221
+ if (!dryRun) {
222
+ await rm(link);
223
+ await symlink(relativeTarget, link, 'dir');
224
+ }
225
+ return { path: link, status: 'relinked' };
226
+ }
227
+ if (existing)
228
+ return { path: link, status: 'kept-existing' };
229
+ if (!dryRun) {
230
+ await mkdir(agentSkillsDir, { recursive: true });
231
+ await symlink(relativeTarget, link, 'dir');
232
+ }
233
+ return { path: link, status: 'linked' };
234
+ };
235
+ let synced = false;
236
+ /**
237
+ * Refresh an installed skill after a CLI upgrade. Runs before every command;
238
+ * the steady-state cost is one small file read. Never throws — a read-only or
239
+ * missing home must not fail the user's actual command.
240
+ */
241
+ export const syncInstalledSkill = async () => {
242
+ if (synced)
243
+ return;
244
+ synced = true;
245
+ try {
246
+ const target = canonicalSkillDir(cliHome());
247
+ const installed = await readMarker(target);
248
+ if (installed === undefined)
249
+ return;
250
+ const version = await cliVersion();
251
+ if (installed === version)
252
+ return;
253
+ const source = packagedSkillDir();
254
+ if (!(await isDirectory(source)))
255
+ return;
256
+ await replaceSkillDir(source, target, version);
257
+ }
258
+ catch {
259
+ // best effort
260
+ }
261
+ };
262
+ export const initAgents = async (options) => {
263
+ const home = options.home ?? cliHome();
264
+ const cwd = options.cwd ?? processCwd();
265
+ const dryRun = options.dryRun ?? false;
266
+ const version = await cliVersion();
267
+ const requested = options.agents ?? [];
268
+ const unknown = requested.filter(id => !AGENT_IDS.includes(id));
269
+ if (unknown.length > 0)
270
+ throw new Error(`Unknown agent: ${unknown.join(', ')}. Use --agent ${AGENT_IDS.join('|')}.`);
271
+ const detected = new Map(await Promise.all(AGENTS.map(async (agent) => [agent.id, await isDirectory(join(home, agent.detectDir))])));
272
+ const selected = requested.length > 0
273
+ ? AGENTS.filter(agent => requested.includes(agent.id))
274
+ : AGENTS.filter(agent => detected.get(agent.id));
275
+ if (selected.length === 0)
276
+ throw new Error(`No supported coding agent found under ${home}. Pass --agent ${AGENT_IDS.join('|')} to choose one.`);
277
+ const skill = await installSkill({ home, version, dryRun });
278
+ const agents = [];
279
+ for (const spec of selected) {
280
+ const mcpPath = options.project
281
+ ? join(cwd, spec.projectMcpPath)
282
+ : join(home, spec.globalMcpPath);
283
+ const mcp = spec.format === 'codex'
284
+ ? await writeTomlSection(mcpPath, mcpConfig('codex', options.baseUrl, false, options.workspaceId), dryRun)
285
+ : await writeJsonServer(mcpPath, mcpServerEntry(spec.format, options.baseUrl, options.workspaceId), dryRun);
286
+ const link = await linkSkill(join(home, spec.skillDir), skill.path, dryRun);
287
+ agents.push({
288
+ id: spec.id,
289
+ name: spec.name,
290
+ detected: detected.get(spec.id) ?? false,
291
+ mcp: { path: mcpPath, status: mcp },
292
+ skill: link,
293
+ });
294
+ }
295
+ return {
296
+ version,
297
+ dryRun,
298
+ scope: options.project ? 'project' : 'global',
299
+ skill,
300
+ agents,
301
+ next: [
302
+ ...(env.ASSETHUB_API_KEY
303
+ ? []
304
+ : [
305
+ "Provide ASSETHUB_API_KEY in each agent's environment; the MCP entries read it from there and never store it.",
306
+ ]),
307
+ 'Restart the agent so it reloads MCP servers and skills.',
308
+ 'Run `assethub doctor --mcp` to verify the connection.',
309
+ ],
310
+ };
311
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"execution.d.ts","sourceRoot":"","sources":["../src/execution.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"execution.d.ts","sourceRoot":"","sources":["../src/execution.ts"],"names":[],"mappings":"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"}
package/dist/execution.js CHANGED
@@ -43,6 +43,9 @@ export class CliExecutionError extends Error {
43
43
  this.runId = runId;
44
44
  }
45
45
  }
46
+ /** A floor under `--interval-ms` for `waitForExecution`'s own poll cadence. */
47
+ const MIN_POLL_INTERVAL_MS = 1_000;
48
+ const POLL_JITTER_MS = 250;
46
49
  /** Kept only for SIGINT reporting; interrupting the client never cancels server work. */
47
50
  export const activeExecution = {};
48
51
  export const childOperationId = (parent, step) => {
@@ -247,6 +250,11 @@ export const waitForExecution = async (client, runId, options = {}) => {
247
250
  activeExecution.runId = runId;
248
251
  const deadline = Date.now() + (options.timeoutMs ?? 900_000);
249
252
  const timeout = () => new CliExecutionError(`Wait timed out; server execution continues. Use runs watch ${runId}.`, 3, activeExecution.operationId, activeExecution.execution, runId);
253
+ // A floor under --interval-ms and a touch of jitter on every poll: several
254
+ // `--wait` invocations started together (e.g. parallel `mesh generate`)
255
+ // otherwise poll in lockstep and collide on the same rate-limit window.
256
+ const pollIntervalMs = () => Math.max(options.intervalMs ?? 5_000, MIN_POLL_INTERVAL_MS) +
257
+ Math.floor(Math.random() * POLL_JITTER_MS);
250
258
  while (true) {
251
259
  const signal = AbortSignal.timeout(Math.max(1, deadline - Date.now()));
252
260
  let execution;
@@ -256,6 +264,16 @@ export const waitForExecution = async (client, runId, options = {}) => {
256
264
  catch (error) {
257
265
  if (signal.aborted)
258
266
  throw timeout();
267
+ // The client already retries a 429 internally (Retry-After/backoff);
268
+ // one only reaches here once that budget is exhausted. Server work
269
+ // keeps running regardless, so a rate limit is never a wait failure —
270
+ // treat it like "no update yet" and keep polling within the deadline.
271
+ if (error instanceof AssetHubApiError && error.status === 429) {
272
+ if (Date.now() >= deadline)
273
+ throw timeout();
274
+ await delay(Math.min(pollIntervalMs(), Math.max(0, deadline - Date.now())));
275
+ continue;
276
+ }
259
277
  throw new CliExecutionError(error instanceof Error ? error.message : String(error), error instanceof AssetHubApiError && error.status < 500 ? 2 : 1, activeExecution.operationId, activeExecution.execution, runId);
260
278
  }
261
279
  activeExecution.execution = execution;
@@ -267,6 +285,6 @@ export const waitForExecution = async (client, runId, options = {}) => {
267
285
  return execution;
268
286
  if (Date.now() >= deadline)
269
287
  throw timeout();
270
- await delay(Math.min(options.intervalMs ?? 5_000, Math.max(0, deadline - Date.now())));
288
+ await delay(Math.min(pollIntervalMs(), Math.max(0, deadline - Date.now())));
271
289
  }
272
290
  };
package/dist/index.d.ts CHANGED
@@ -22,7 +22,7 @@ type CommandContext = {
22
22
  */
23
23
  args: string[];
24
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";
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 init [--agent claude-code|codex|cursor...] [--project] [--dry-run] [--base-url <url>] [--workspace <id>] [--profile <name>]\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-image-asset-id>] [--part <mesh-asset-id>[:<part-image-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 init --dry-run\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
26
  export declare const commandSkills: (subcommand: string | undefined, positionals: string[], ctx: CommandContext) => Promise<void>;
27
27
  /**
28
28
  * The `animate retarget` request, built from flags alone.
@@ -1 +1 @@
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;AAi2CD;;;;;;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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AA6BA,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;AA4ID,eAAO,MAAM,KAAK,28cA+IjB,CAAA;AA2gDD,eAAO,MAAM,aAAa,GACxB,YAAY,MAAM,GAAG,SAAS,EAC9B,aAAa,MAAM,EAAE,EACrB,KAAK,cAAc,KAClB,OAAO,CAAC,IAAI,CA6Hd,CAAA;AA61CD;;;;;;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
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { setTimeout as delay } from 'node:timers/promises';
3
3
  import { cliVersion, diagnose, mcpConfig } from './setup.js';
4
+ import { AGENT_IDS, initAgents, syncInstalledSkill } from './agentSetup.js';
4
5
  import { ingestProjectSources } from './projectSources.js';
5
6
  import { downloadCanvas } from './canvasDownload.js';
6
7
  import { executeNodeMeshBatch, resumeNodeMeshBatch, } from './nodeMeshBatch.js';
@@ -30,15 +31,6 @@ const defaultImageModelId = 'imageGen.nanoBanana2.openrouter';
30
31
  const defaultMeshModelId = 'meshGen.hunyuan31';
31
32
  const defaultProfileName = 'default';
32
33
  const defaultPartExtractorName = 'V1.5';
33
- const artifactGraphPartExtractorApiValues = new Set([
34
- 'ah_agent_graph_v3_6_1',
35
- 'ah_agent_graph_v3_6_3',
36
- 'ah_agent_graph_v3_6_4',
37
- 'ah_agent_graph_v3_6_5',
38
- 'ah_agent_graph_pluffy_v3_1',
39
- 'ah_agent_graph_v3_7',
40
- 'ah_agent_graph_v3_7_1',
41
- ]);
42
34
  const partExtractorOptions = [
43
35
  {
44
36
  publicName: 'V1.5',
@@ -80,17 +72,34 @@ const partExtractorOptions = [
80
72
  apiValue: 'ah_agent_graph_pluffy_v3_1',
81
73
  aliases: ['pluffy', 'pluffy v3.1', 'pluffy 3.1'],
82
74
  },
75
+ {
76
+ publicName: 'V3.0.9 Garment Boundaries',
77
+ apiValue: 'ah_agent_graph_v3_7_2',
78
+ aliases: ['v3.0.9', '3.0.9'],
79
+ },
83
80
  {
84
81
  publicName: 'V3.7 Artist Skills',
85
82
  apiValue: 'ah_agent_graph_v3_7',
86
- aliases: ['v3.7', '3.7'],
83
+ // The web picker and `production agents` call it V3.0.7.
84
+ aliases: ['v3.7', '3.7', 'v3.0.7 artist skills', 'v3.0.7', '3.0.7'],
87
85
  },
88
86
  {
89
87
  publicName: 'V3.7.1 Building Modules',
90
88
  apiValue: 'ah_agent_graph_v3_7_1',
91
- aliases: ['v3.7.1', '3.7.1'],
89
+ // The web picker and `production agents` call it V3.0.8.
90
+ aliases: ['v3.7.1', '3.7.1', 'v3.0.8 building modules', 'v3.0.8', '3.0.8'],
91
+ },
92
+ {
93
+ publicName: 'Humanoid Assembly (internal)',
94
+ apiValue: 'ah_agent_graph_humanoid_assembly_auto',
95
+ aliases: ['humanoid assembly', 'humanoid-assembly', 'humanoid_assembly_auto'],
92
96
  },
93
97
  ];
98
+ // Graph-engine extractors run through the artifact-graph endpoint. Derived from
99
+ // the option list so a newly listed graph agent cannot miss the graph path.
100
+ const artifactGraphPartExtractorApiValues = new Set(partExtractorOptions
101
+ .map(option => option.apiValue)
102
+ .filter(apiValue => apiValue.startsWith('ah_agent_graph_')));
94
103
  const partExtractorPublicNames = partExtractorOptions
95
104
  .map(option => option.publicName)
96
105
  .join(', ');
@@ -100,7 +109,12 @@ const partExtractorByInput = new Map(partExtractorOptions.flatMap(option => [
100
109
  ...option.aliases.map(alias => [normalizePartExtractorName(alias), option]),
101
110
  ]));
102
111
  const partExtractorPublicNameByApiValue = new Map(partExtractorOptions.map(option => [option.apiValue, option.publicName]));
103
- const isInternalPartExtractorId = (value) => value.trim().includes('_');
112
+ // Every registered internal apiValue is an `ah_...` id (see partExtractorOptions
113
+ // above). Matching that prefix instead of a blanket "contains an underscore"
114
+ // check keeps this from rejecting a public alias that happens to use
115
+ // underscores (e.g. 'humanoid_assembly_auto', mirroring the engine profile
116
+ // name) while still catching every real internal id.
117
+ const isInternalPartExtractorId = (value) => value.trim().toLowerCase().startsWith('ah_');
104
118
  const execFileAsync = promisify(execFile);
105
119
  export const usage = `AssetHub CLI
106
120
 
@@ -109,6 +123,7 @@ CLI and MCP are available to all AssetHub users. Workspace permissions and featu
109
123
  Usage:
110
124
  assethub --version
111
125
  assethub doctor [--mcp] [--profile <name>] [--timeout-ms <n>]
126
+ assethub init [--agent claude-code|codex|cursor...] [--project] [--dry-run] [--base-url <url>] [--workspace <id>] [--profile <name>]
112
127
  assethub mcp tools [tool-name] [--account] [--profile <name>] [--timeout-ms <n>]
113
128
  assethub mcp config --client cursor|codex [--account] [--base-url <url>]
114
129
  assethub auth login --api-key <key> [--base-url <url>] [--profile <name>]
@@ -162,7 +177,7 @@ Usage:
162
177
  assethub composer refine --list-modes
163
178
  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>]
164
179
  assethub composer refine --input-json <json|@file> [--canvas <id>] [--operation-id <uuid>] [--wait] [--download --out-dir <dir>]
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]
180
+ assethub composer run --part <mesh-asset-id>[:<part-image-asset-id>] [--part <mesh-asset-id>[:<part-image-asset-id>]...] --reference <image-asset-id> [--model <id>] [--mode quick|quality] [--transforms-json <json|@file>] [--canvas <id>] [--wait]
166
181
  assethub composer run --input-json <json|@file> [--canvas <id>] [--operation-id <uuid>] [--wait] [--download --out-dir <dir>]
167
182
  assethub composer run --from-run <run-id> [--transforms-json <json|@file>] [--mode quick|quality] [--wait]
168
183
  assethub composer run --node <shape:id> --canvas <id> [--model <id>] [--mode quick|quality] [--operation-id <uuid>] [--wait]
@@ -221,6 +236,7 @@ Global options:
221
236
  Examples:
222
237
  ASSETHUB_API_KEY=ah_live_xxx assethub models list
223
238
  assethub auth login --api-key-stdin
239
+ assethub init --dry-run
224
240
  assethub models list --ids-only
225
241
  assethub files upload ./input.png --media-type image
226
242
  assethub source create --file ./input.png --media-type image
@@ -728,6 +744,25 @@ const assertFlagHasValue = (value, flagDescription) => {
728
744
  }
729
745
  return value;
730
746
  };
747
+ /**
748
+ * Parses one `--part` value for `composer run`/`composer refine` into a
749
+ * composer part. Plain `<mesh-asset-id>` composes without a part-reference
750
+ * image (Composer V6 then requires it via `--input-json` or falls back to
751
+ * the mesh's own thumbnail, if enabled). `<mesh-asset-id>:<part-image-asset-id>`
752
+ * attaches the image the part's mesh was generated from, matching what the
753
+ * canvas node graph supplies automatically for UI-driven runs.
754
+ */
755
+ const parsePartFlagValue = (raw) => {
756
+ const value = assertFlagHasValue(raw, '--part <mesh-asset-id>[:<part-image-asset-id>]');
757
+ const separatorIndex = value.indexOf(':');
758
+ if (separatorIndex === -1)
759
+ return { assetId: value };
760
+ const assetId = value.slice(0, separatorIndex);
761
+ const partImageAssetId = value.slice(separatorIndex + 1);
762
+ if (!assetId || !partImageAssetId)
763
+ throw new Error('--part must be <mesh-asset-id> or <mesh-asset-id>:<part-image-asset-id>');
764
+ return { assetId, partImageAssetId };
765
+ };
731
766
  const sourceInputCount = (flags) => [
732
767
  getSourceResourceIdFlag(flags) != null,
733
768
  getSourceUrlFlag(flags) != null,
@@ -2243,9 +2278,7 @@ const commandComposerRefine = async (ctx) => {
2243
2278
  : previous
2244
2279
  ? composerInputFromRun(previous, 'mesh.refine')
2245
2280
  : {
2246
- parts: parts.map(assetId => ({
2247
- assetId: assertFlagHasValue(assetId, '--part <asset-id>'),
2248
- })),
2281
+ parts: parts.map(parsePartFlagValue),
2249
2282
  fullBodyImageAssetId: requireFlag(ctx.flags, 'reference'),
2250
2283
  };
2251
2284
  delete input.executionContext;
@@ -2354,9 +2387,7 @@ const commandComposer = async (subcommand, ctx) => {
2354
2387
  : json
2355
2388
  ? await readJsonArgument(json, '--input-json')
2356
2389
  : {
2357
- parts: parts.map(assetId => ({
2358
- assetId: assertFlagHasValue(assetId, '--part <asset-id>'),
2359
- })),
2390
+ parts: parts.map(parsePartFlagValue),
2360
2391
  fullBodyImageAssetId: requireFlag(ctx.flags, 'reference'),
2361
2392
  };
2362
2393
  delete input.executionContext;
@@ -4003,6 +4034,20 @@ const parseNonNegativeIntegerFlag = (flags, name) => {
4003
4034
  }
4004
4035
  return parsed;
4005
4036
  };
4037
+ /** Base URL and workspace an MCP entry should target: explicit flags, then the selected profile, then defaults. */
4038
+ const resolveMcpTarget = async (flags) => {
4039
+ const config = await readAuthConfig(getConfigPath(flags));
4040
+ const explicitProfile = getFlag(flags, 'profile');
4041
+ const stored = config.profiles?.[explicitProfile ?? config.defaultProfile ?? defaultProfileName];
4042
+ if (explicitProfile && !stored)
4043
+ throw new Error('Selected profile does not exist');
4044
+ const selected = explicitProfile || stored?.workspaceId || isPersonalProfile(stored);
4045
+ const baseUrl = getFlag(flags, 'base-url') ??
4046
+ (selected ? stored?.baseUrl : env.ASSETHUB_API_BASE_URL ?? stored?.baseUrl) ?? defaultBaseUrl;
4047
+ const workspaceId = getFlag(flags, 'workspace') ??
4048
+ (stored && new URL(baseUrl).origin === new URL(stored.baseUrl).origin ? stored.workspaceId : undefined);
4049
+ return { baseUrl, workspaceId };
4050
+ };
4006
4051
  const run = async () => {
4007
4052
  const parsed = parseArgs(argv.slice(2));
4008
4053
  if (hasFlag(parsed.flags, 'version')) {
@@ -4014,6 +4059,20 @@ const run = async () => {
4014
4059
  return;
4015
4060
  }
4016
4061
  const [command, subcommand] = parsed.positionals;
4062
+ if (command !== 'init')
4063
+ await syncInstalledSkill();
4064
+ if (command === 'init') {
4065
+ if (subcommand)
4066
+ throw new Error(`Use init [--agent ${AGENT_IDS.join('|')}] [--project] [--dry-run]`);
4067
+ const target = await resolveMcpTarget(parsed.flags);
4068
+ print(await initAgents({
4069
+ ...target,
4070
+ agents: getFlagValues(parsed.flags, 'agent').map(value => assertFlagHasValue(value, '--agent <name>')),
4071
+ project: hasFlag(parsed.flags, 'project'),
4072
+ dryRun: hasFlag(parsed.flags, 'dry-run'),
4073
+ }));
4074
+ return;
4075
+ }
4017
4076
  if (command === 'mcp' && subcommand === 'tools') {
4018
4077
  stderr.write('Discovering AssetHub MCP tools…\n');
4019
4078
  const report = await diagnose({
@@ -4050,16 +4109,7 @@ const run = async () => {
4050
4109
  if (command === 'mcp') {
4051
4110
  if (subcommand !== 'config')
4052
4111
  throw new Error('Use mcp tools [tool-name] or mcp config --client cursor|codex');
4053
- const config = await readAuthConfig(getConfigPath(parsed.flags));
4054
- const explicitProfile = getFlag(parsed.flags, 'profile');
4055
- const stored = config.profiles?.[explicitProfile ?? config.defaultProfile ?? defaultProfileName];
4056
- if (explicitProfile && !stored)
4057
- throw new Error('Selected profile does not exist');
4058
- const selected = explicitProfile || stored?.workspaceId || isPersonalProfile(stored);
4059
- const baseUrl = getFlag(parsed.flags, 'base-url') ??
4060
- (selected ? stored?.baseUrl : env.ASSETHUB_API_BASE_URL ?? stored?.baseUrl) ?? defaultBaseUrl;
4061
- const workspaceId = getFlag(parsed.flags, 'workspace') ??
4062
- (stored && new URL(baseUrl).origin === new URL(stored.baseUrl).origin ? stored.workspaceId : undefined);
4112
+ const { baseUrl, workspaceId } = await resolveMcpTarget(parsed.flags);
4063
4113
  stdout.write(mcpConfig(requireFlag(parsed.flags, 'client'), baseUrl, hasFlag(parsed.flags, 'account'), workspaceId));
4064
4114
  return;
4065
4115
  }
package/dist/setup.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { Tool } from '@modelcontextprotocol/sdk/types.js';
2
2
  export declare const cliVersion: () => Promise<string>;
3
+ export declare const validatedBaseUrl: (baseUrl: string) => string;
3
4
  export declare const mcpConfig: (client: string, baseUrl: string, account?: boolean, workspaceId?: string) => string;
4
5
  type Check = {
5
6
  name: 'api' | 'mcp' | 'configuration';
@@ -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,EAAE,iBAAe,EAAE,cAAc,MAAM,KAAG,MAsBlG,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,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAAC,CAAA;AA2DhI,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;;;;;;;;;;;;;;;;;;;;;;EAkHA,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;AAEX,eAAO,MAAM,gBAAgB,GAAI,SAAS,MAAM,KAAG,MAelD,CAAA;AAED,eAAO,MAAM,SAAS,GAAI,QAAQ,MAAM,EAAE,SAAS,MAAM,EAAE,iBAAe,EAAE,cAAc,MAAM,KAAG,MAsBlG,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,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAAC,CAAA;AA2DhI,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;;;;;;;;;;;;;;;;;;;;;;EAkHA,CAAA"}
package/dist/setup.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { readFile } from 'node:fs/promises';
2
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
- const validatedBaseUrl = (baseUrl) => {
4
+ export const validatedBaseUrl = (baseUrl) => {
5
5
  const url = new URL(baseUrl);
6
6
  if (url.username || url.password || url.search || url.hash)
7
7
  throw new Error('Use an API URL without credentials, query, or fragment.');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@assethub/cli",
3
- "version": "0.1.25",
3
+ "version": "0.1.27",
4
4
  "description": "Command line interface for AssetHub.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -17,6 +17,7 @@
17
17
  },
18
18
  "files": [
19
19
  "dist",
20
+ "skills",
20
21
  "README.md",
21
22
  "LICENSE"
22
23
  ],
@@ -30,7 +31,7 @@
30
31
  "access": "public"
31
32
  },
32
33
  "dependencies": {
33
- "@assethub/api-client": "^0.1.12",
34
+ "@assethub/api-client": "^0.1.13",
34
35
  "@modelcontextprotocol/sdk": "^1.30.0"
35
36
  },
36
37
  "repository": {
@@ -0,0 +1,131 @@
1
+ ---
2
+ name: assethub
3
+ description: |
4
+ Use the AssetHub CLI (`assethub`) and hosted MCP to generate and process 3D assets: images, meshes, parts, rigs, animations, textures, and full production runs. AssetHub handles the AI providers, credits, and job tracking.
5
+
6
+ TRIGGER when:
7
+ - Generating or editing an image, concept, or reference for a 3D asset
8
+ - Turning an image or prompt into a 3D mesh, splitting it into parts, or composing parts
9
+ - Rigging, animating, retopologizing, texturing, or converting a mesh
10
+ - Running a 3D production pipeline, checking a job, or recovering a run
11
+ - Asking what models or operations are available, or what something will cost
12
+ - Recording whether a generated asset is acceptable
13
+
14
+ DO NOT TRIGGER for:
15
+ - Installing or configuring the CLI (use `assethub init`, `assethub auth login`)
16
+ - Managing workspace members (use `assethub workspace ...`)
17
+ ---
18
+
19
+ # AssetHub CLI
20
+
21
+ `assethub` is a client, not an agent. It calls the AssetHub API, prints one JSON object to stdout, and puts progress on stderr. You decide what to do; it does it and tells you what happened.
22
+
23
+ ## Output contract
24
+
25
+ - stdout is exactly one JSON object. Parse it. Never scrape stderr.
26
+ - Exit codes: `0` accepted or completed · `1` terminal failure · `2` input, auth, capability, or budget error · `3` timeout, history pending, or needs review · `130` interrupted.
27
+ - **Exit 3 is not a failure.** The server-side job keeps running. The JSON still carries `runId` and `operationId`; use them to resume or watch instead of starting again.
28
+ - Errors arrive as `{"error": {"code", "message"}}` plus any known `runId` / `operationId`.
29
+
30
+ ## The ritual
31
+
32
+ Always in this order. Skipping a step is how credits get wasted.
33
+
34
+ ### 1. Check what this key can do
35
+
36
+ ```bash
37
+ assethub capabilities
38
+ ```
39
+
40
+ Tells you which operations, models, and history features this workspace key allows. If it fails with a missing-key error, the user needs `assethub auth login --api-key-stdin` (never pass a key as an argument) or `ASSETHUB_API_KEY` in the environment. A personal key also needs `assethub workspace use <workspace-id>`.
41
+
42
+ ### 2. Find the operation
43
+
44
+ Prefer the dedicated commands (`image generate`, `mesh generate`, `parts split`, `rig create`, `animate retarget`, `production analyze` …). For anything else, search the live catalog:
45
+
46
+ ```bash
47
+ assethub api search "compose parts"
48
+ assethub api describe "POST /mesh/compose"
49
+ ```
50
+
51
+ `describe` returns the exact input schema and required fields. **Read it before you call.** Do not guess parameter names.
52
+
53
+ ### 3. Pick the model deliberately
54
+
55
+ ```bash
56
+ assethub models list --domain mesh
57
+ assethub models get <model-id>
58
+ ```
59
+
60
+ The default model is not always the right one. A model's catalog entry carries its credit plan. If the user has already tried a model and it failed, choose a different one rather than retrying the same thing.
61
+
62
+ ### 4. Run, with an operation ID for anything paid
63
+
64
+ ```bash
65
+ assethub image generate --prompt "stylized wooden crate" --wait --download --out-dir ./out/crate
66
+ assethub mesh generate --source-id <image-asset-id> --canvas <canvas-id> --wait
67
+ assethub api call "POST /mesh/compose" --input-json @request.json --operation-id $(uuidgen)
68
+ ```
69
+
70
+ - `--wait` blocks until the job finishes and returns the final result. Without it you get a job or run ID to watch.
71
+ - `--download --out-dir <dir>` fetches every output artifact and writes a `manifest.json`.
72
+ - `--operation-id <uuid>` makes a paid request idempotent. Reuse the **same** ID with the **same** input to retry; a new candidate needs a new ID.
73
+ - Generation returns `execution` with the canvas URL, run and job IDs, and the output asset IDs. Chain those IDs into the next step with `--source-id`.
74
+
75
+ ### 5. Wait or recover — never resubmit blindly
76
+
77
+ ```bash
78
+ assethub jobs watch <job-id> --download --out-dir ./out
79
+ assethub runs watch <run-id>
80
+ assethub runs resume <operation-id> --wait
81
+ ```
82
+
83
+ After a timeout, an interrupted command, or any uncertain response, `runs resume <operation-id>` replays the identical request and returns the existing result. It never charges twice. Starting a fresh command does.
84
+
85
+ ### 6. Record the verdict
86
+
87
+ ```bash
88
+ assethub evaluations submit --canvas <canvas-id> --artifact <asset-id> \
89
+ --report ./review.json --agent <your-name> --require-pass
90
+ ```
91
+
92
+ `review.json` must have `schemaVersion: "assethub.evaluation-submission.v1"`, a `rubric`, a `verdict` of `pass` | `fail` | `needs_review`, `criteria`, `referenceAssetIds`, and `evidenceAssetIds`. Inspect the downloaded artifact before you write the verdict; a verdict you did not check is worse than none. `--require-pass` exits 1 on fail and 3 on needs_review, so a pipeline can stop on a bad result. An agent verdict is never creator approval.
93
+
94
+ ## Cost safety
95
+
96
+ - `production run` defaults to `full_auto`, which never pauses for a human. **Always pass `--max-cost-credits <n>`.** The server caps `--max-iterations` at 5.
97
+ - Over MCP the same rule applies: always set `maxCostCredits` on `production_run`.
98
+ - `assethub account get` shows the balance. Check it before a batch.
99
+ - Prefer a dedicated, scoped API key for agent work rather than a full-access one.
100
+
101
+ ## Rules learned the hard way
102
+
103
+ - Never put an API key in a command argument or a config file. Use `--api-key-stdin` or the environment.
104
+ - Part extractor names are the public product names: `V1.5`, `V2.0 alpha`, `V2.1 alpha`. Internal IDs are not accepted.
105
+ - `parts split` and `parts compare` with `--preprocess-prompt` create a second production order; use `--all-ready`, not `--task-id`.
106
+ - Every generation should land on a canvas. Pass `--canvas <id>` to keep a job's steps together; without it the CLI makes one canvas per working directory. `assethub canvas open <id>` shows the user what happened.
107
+ - A complaint like "the mesh has extra limbs" is usually an input problem: stray lines, shadows, or inconsistent views. Clean the image (`image edit`) before switching models.
108
+ - Input can come from a file, a URL, stdin bytes, base64, a data URI, an OpenAI- or Anthropic-style JSON attachment (`--stdin-json`), or the clipboard. You never need to write a temporary file first.
109
+ - Large or complex requests: `--input-json @request.json` with the schema from `api describe`.
110
+
111
+ ## Reusable methods (workspace skills)
112
+
113
+ ```bash
114
+ assethub skills list
115
+ assethub skills get <skill-id>
116
+ ```
117
+
118
+ A workspace skill is a saved method that already worked in this workspace. Read them before inventing a new approach to a problem the team has solved. Skills set to `automatic` apply on matching runs without asking.
119
+
120
+ ## MCP equivalents
121
+
122
+ The hosted MCP (`https://app.assethub.io/api/mcp`) exposes the same API. `capabilities_get` ↔ `capabilities`; `operation_search` / `operation_describe` / `operation_call` ↔ `api search` / `describe` / `call`; `job_poll` ↔ `jobs watch`; `evaluation_submit` ↔ `evaluations submit`. Whichever surface you use, follow the same ritual.
123
+
124
+ ## Diagnose
125
+
126
+ ```bash
127
+ assethub doctor --mcp
128
+ assethub --version
129
+ ```
130
+
131
+ `doctor` checks the key, the workspace, and MCP tool discovery without spending credits. Exit 2 means a check failed and the JSON says which and what to do.