@assethub/cli 0.1.33 → 0.1.36

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.
@@ -30,6 +30,8 @@ const spawnCli = (args, profile) => {
30
30
  };
31
31
  /** SessionEnd: upload this session, then retry up to SWEEP_LIMIT older pending ones. */
32
32
  export const spawnDetachedUpload = (sessionDir, profile) => spawnCli(['hooks', 'upload', '--session', sessionDir, '--auto', '--sweep', String(SWEEP_LIMIT)], profile);
33
+ /** Stop / PreCompact: upload this running session only; no sweep. */
34
+ export const spawnDetachedSessionUpload = (sessionDir, profile) => spawnCli(['hooks', 'upload', '--session', sessionDir, '--auto'], profile);
33
35
  /** SessionStart: retry up to SWEEP_LIMIT pending sessions. */
34
36
  export const spawnDetachedSweep = (profile) => spawnCli(['hooks', 'upload', '--pending', '--limit', String(SWEEP_LIMIT)], profile);
35
37
  export const retentionDays = (env) => {
@@ -155,6 +157,13 @@ const collectImages = async (sessionDir, transcript, cwd) => {
155
157
  export const ABANDONED_AFTER_MS = 2 * 60 * 60 * 1000;
156
158
  /** Sessions retried in the background per SessionStart / SessionEnd. */
157
159
  export const SWEEP_LIMIT = 3;
160
+ /**
161
+ * A running session is uploaded at most this often. Claude Code app sessions
162
+ * stay open for days and rarely reach SessionEnd, so without this they would
163
+ * only be uploaded once abandoned (ABANDONED_AFTER_MS quiet, then a new session).
164
+ */
165
+ export const WORKING_UPLOAD_INTERVAL_MS = 20 * 60 * 1000;
166
+ const WORKING_UPLOAD_EVENTS = new Set(['Stop', 'PreCompact']);
158
167
  /** Events that copy and redact the transcript now; the rest only mark it changed. */
159
168
  const FULL_SAVE_EVENTS = new Set(['SessionEnd', 'Manual']);
160
169
  /**
@@ -312,6 +321,17 @@ export const saveSession = async (options = {}) => {
312
321
  if (full)
313
322
  await materializeSession(sessionDir, { env, transcriptPath });
314
323
  const result = { sessionDir, event };
324
+ if (uploadOn && options.startWorkingUpload && WORKING_UPLOAD_EVENTS.has(event)) {
325
+ const latest = await readMeta(sessionDir);
326
+ // Counts uploads any path started (an earlier Stop, SessionEnd, a sweep).
327
+ const lastStart = Math.max(Date.parse(latest?.lastWorkingUploadAt ?? '') || 0, Date.parse(latest?.lastUploadAttemptAt ?? '') || 0);
328
+ if (latest && now.getTime() - lastStart >= WORKING_UPLOAD_INTERVAL_MS) {
329
+ // Stamped before spawning, so the next few turns do not start more.
330
+ await updateMeta(sessionDir, latest, current => ({ ...current, lastWorkingUploadAt: now.toISOString() }));
331
+ options.startWorkingUpload(sessionDir, options.upload?.profile);
332
+ result.uploadStarted = true;
333
+ }
334
+ }
315
335
  if (event === 'SessionEnd') {
316
336
  const days = retentionDays(env);
317
337
  if (days != null)
@@ -39,6 +39,8 @@ export type SessionMeta = {
39
39
  abandoned?: boolean;
40
40
  /** How far the graph is compacted after uploads failed for size or time (0 = none). */
41
41
  compactLevel?: number;
42
+ /** When Stop or PreCompact last started a background upload of this running session. */
43
+ lastWorkingUploadAt?: string;
42
44
  /** Failed uploads in a row; spaces out the automatic retries. */
43
45
  failedAttempts?: number;
44
46
  /** Size of the live transcript the local copy was made from (before masking). */
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/hooks/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,OAAO,CAAA;AAE3C,MAAM,MAAM,SAAS,GAAG;IACtB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB,CAAA;AAED,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,gBAAgB,GAAG,UAAU,CAAA;AAEnE,MAAM,MAAM,YAAY,GAAG;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,CAAA;AAEvF,MAAM,MAAM,WAAW,GAAG;IACxB,SAAS,EAAE,MAAM,CAAA;IACjB,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,UAAU,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,aAAa,CAAA;IACrB,MAAM,EAAE,YAAY,EAAE,CAAA;IACtB,+EAA+E;IAC/E,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,gGAAgG;IAChG,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,kEAAkE;IAClE,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,mEAAmE;IACnE,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,uFAAuF;IACvF,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,iEAAiE;IACjE,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,iFAAiF;IACjF,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,8FAA8F;IAC9F,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,EAAE,EAAE,OAAO,CAAA;IACX,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,sFAAsF;IACtF,SAAS,CAAC,EAAE,IAAI,CAAA;CACjB,CAAA"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/hooks/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,OAAO,CAAA;AAE3C,MAAM,MAAM,SAAS,GAAG;IACtB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB,CAAA;AAED,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,gBAAgB,GAAG,UAAU,CAAA;AAEnE,MAAM,MAAM,YAAY,GAAG;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,CAAA;AAEvF,MAAM,MAAM,WAAW,GAAG;IACxB,SAAS,EAAE,MAAM,CAAA;IACjB,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,UAAU,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,aAAa,CAAA;IACrB,MAAM,EAAE,YAAY,EAAE,CAAA;IACtB,+EAA+E;IAC/E,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,gGAAgG;IAChG,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,kEAAkE;IAClE,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,mEAAmE;IACnE,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,uFAAuF;IACvF,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,wFAAwF;IACxF,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,iEAAiE;IACjE,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,iFAAiF;IACjF,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,8FAA8F;IAC9F,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,EAAE,EAAE,OAAO,CAAA;IACX,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,sFAAsF;IACtF,SAAS,CAAC,EAAE,IAAI,CAAA;CACjB,CAAA"}
@@ -1,12 +1,18 @@
1
1
  import type { UploadOutcome } from './types.js';
2
2
  export declare const CODING_AGENT_SESSION_API_PREFIX = "/api/v2/coding-agent-sessions";
3
3
  export declare const UPLOAD_TIMEOUT_MS = 20000;
4
+ /** A session's upload lock older than this belongs to a crashed upload. */
5
+ export declare const UPLOAD_LOCK_STALE_MS: number;
6
+ /** How often a running upload refreshes its lock, well inside UPLOAD_LOCK_STALE_MS. */
7
+ export declare const UPLOAD_LOCK_HEARTBEAT_MS = 60000;
4
8
  export type UploadAuth = {
5
9
  apiKey: string;
6
10
  baseUrl: string;
7
11
  workspaceId?: string;
8
12
  };
9
13
  export type UploadOptions = {
14
+ /** How often a running upload refreshes its lock (tests shorten it). */
15
+ lockHeartbeatMs?: number;
10
16
  profile?: string;
11
17
  home?: string;
12
18
  env?: NodeJS.ProcessEnv;
@@ -1 +1 @@
1
- {"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../../src/hooks/upload.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAc,aAAa,EAAC,MAAM,YAAY,CAAA;AAG1D,eAAO,MAAM,+BAA+B,kCAAkC,CAAA;AAQ9E,eAAO,MAAM,iBAAiB,QAAS,CAAA;AAEvC,MAAM,MAAM,UAAU,GAAG;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAC,CAAA;AAEhF,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAA;IACvB,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;IACxB,IAAI,CAAC,EAAE,UAAU,CAAA;IACjB,GAAG,CAAC,EAAE,MAAM,IAAI,CAAA;IAChB,wEAAwE;IACxE,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAC5B,SAAS,IAAI,CAAC,aAAa,EAAE,SAAS,GAAG,MAAM,GAAG,KAAK,CAAC,KACvD,OAAO,CAAC,UAAU,GAAG,IAAI,CA2B3B,CAAA;AAED,iFAAiF;AACjF,eAAO,MAAM,YAAY,GAAI,gBAAgB,MAAM,KAAG,MACmB,CAAA;AAmBzE;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,GAC5B,MAAM,UAAU,EAChB,YAAW,OAAO,KAAyC,KAC1D,OAAO,CAAC,OAAO,CAgBjB,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,aAAa,GACxB,YAAY,MAAM,EAClB,UAAS,aAAkB,KAC1B,OAAO,CAAC,aAAa,CASvB,CAAA;AAoHD;;;;GAIG;AACH,eAAO,MAAM,aAAa,GACxB,UAAS,aAAa,GAAG;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAM,KAC/D,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,aAAa,CAAA;CAAC,EAAE,CAkBrD,CAAA"}
1
+ {"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../../src/hooks/upload.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAc,aAAa,EAAC,MAAM,YAAY,CAAA;AAG1D,eAAO,MAAM,+BAA+B,kCAAkC,CAAA;AAQ9E,eAAO,MAAM,iBAAiB,QAAS,CAAA;AACvC,2EAA2E;AAC3E,eAAO,MAAM,oBAAoB,QAAc,CAAA;AAC/C,uFAAuF;AACvF,eAAO,MAAM,wBAAwB,QAAS,CAAA;AAE9C,MAAM,MAAM,UAAU,GAAG;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAC,CAAA;AAEhF,MAAM,MAAM,aAAa,GAAG;IAC1B,wEAAwE;IACxE,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAA;IACvB,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;IACxB,IAAI,CAAC,EAAE,UAAU,CAAA;IACjB,GAAG,CAAC,EAAE,MAAM,IAAI,CAAA;IAChB,wEAAwE;IACxE,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAC5B,SAAS,IAAI,CAAC,aAAa,EAAE,SAAS,GAAG,MAAM,GAAG,KAAK,CAAC,KACvD,OAAO,CAAC,UAAU,GAAG,IAAI,CA2B3B,CAAA;AAED,iFAAiF;AACjF,eAAO,MAAM,YAAY,GAAI,gBAAgB,MAAM,KAAG,MACmB,CAAA;AAmBzE;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,GAC5B,MAAM,UAAU,EAChB,YAAW,OAAO,KAAyC,KAC1D,OAAO,CAAC,OAAO,CAgBjB,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,aAAa,GACxB,YAAY,MAAM,EAClB,UAAS,aAAkB,KAC1B,OAAO,CAAC,aAAa,CAmBvB,CAAA;AAoHD;;;;GAIG;AACH,eAAO,MAAM,aAAa,GACxB,UAAS,aAAa,GAAG;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAM,KAC/D,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,aAAa,CAAA;CAAC,EAAE,CAkBrD,CAAA"}
@@ -3,7 +3,7 @@
3
3
  // contract as `runs upload`, so the plan and transport are shared; only the
4
4
  // URL prefix and the extra `session` registration fields differ. Sessions are
5
5
  // owned by, and readable only by, the key's user.
6
- import { readFile } from 'node:fs/promises';
6
+ import { readFile, utimes } from 'node:fs/promises';
7
7
  import { basename, join } from 'node:path';
8
8
  import { buildRunUploadPlan } from '../runsUpload/buildRunUpload.js';
9
9
  import { controlRunUploadUrls } from '../runsUpload/controlEndpoints.js';
@@ -24,6 +24,10 @@ const canvasIdOf = (value) => {
24
24
  };
25
25
  const DAY_MS = 24 * 60 * 60 * 1000;
26
26
  export const UPLOAD_TIMEOUT_MS = 20_000;
27
+ /** A session's upload lock older than this belongs to a crashed upload. */
28
+ export const UPLOAD_LOCK_STALE_MS = 15 * 60_000;
29
+ /** How often a running upload refreshes its lock, well inside UPLOAD_LOCK_STALE_MS. */
30
+ export const UPLOAD_LOCK_HEARTBEAT_MS = 60_000;
27
31
  /**
28
32
  * Resolve the CLI profile's key + base URL from ~/.assethub/config.json.
29
33
  * src/index.ts's resolveAuth is module-private, so this mirrors its precedence
@@ -105,13 +109,23 @@ export const canUploadSessions = async (auth, fetchImpl = globalThis.fetch.bind(
105
109
  export const uploadSession = async (sessionDir, options = {}) => {
106
110
  if (!(await readMeta(sessionDir)))
107
111
  return { ok: false, reason: 'no-session' };
108
- const release = await acquireLock(join(sessionDir, '.upload.lock'), { waitMs: 0, staleMs: 15 * 60_000 });
112
+ const lockPath = join(sessionDir, '.upload.lock');
113
+ const release = await acquireLock(lockPath, { waitMs: 0, staleMs: UPLOAD_LOCK_STALE_MS });
109
114
  if (!release)
110
115
  return { ok: false, reason: 'upload-in-progress', throttled: true };
116
+ // A lock older than UPLOAD_LOCK_STALE_MS is taken over as a crashed upload's.
117
+ // Touching it while this upload runs keeps a long upload from looking crashed,
118
+ // so a later Stop, sweep or SessionEnd cannot start a second one beside it.
119
+ const heartbeat = setInterval(() => {
120
+ const now = new Date();
121
+ void utimes(lockPath, now, now).catch(() => { });
122
+ }, options.lockHeartbeatMs ?? UPLOAD_LOCK_HEARTBEAT_MS);
123
+ heartbeat.unref?.();
111
124
  try {
112
125
  return await uploadSessionUnlocked(sessionDir, options);
113
126
  }
114
127
  finally {
128
+ clearInterval(heartbeat);
115
129
  await release();
116
130
  }
117
131
  };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+ import { type SetupStepName } from './setupCommand.js';
2
3
  import { type InstallHooks } from './setupHooksBridge.js';
3
4
  import { type AnimationRetargetRequest, type Intervention, type RigRequest, createAssetHubClient } from '@assethub/api-client';
4
5
  import { buildRunUploadPlan } from './runsUpload/buildRunUpload.js';
@@ -23,8 +24,10 @@ type CommandContext = {
23
24
  */
24
25
  args: string[];
25
26
  };
26
- 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 setup [--client claude|codex|both] [--profile <name>] [--workspace <id>] [--api-key-stdin] [--base-url <url>] [--no-app-env] [--dry-run] [--yes] [--print-env] [--json]\n assethub env load [--profile <name>]\n assethub update [--check] [--dry-run] [--yes]\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 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] [--effort light|standard|thorough] [--max-rounds <n>] [--agent-model <provider:id|unambiguous-id>] [--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 refine --from-run <run-id> --skill-assembly [--reasoning low|medium|high] [--agent-model <agents-api model>] [--wait]\n assethub composer run --part <mesh-asset-id>[=<part-image-id>] [--part <mesh-asset-id>[=<part-image-id>]...] --reference <image-asset-id> [--model <id>] [--agent-model <provider:id|unambiguous-id>] [--mode quick|quality] [--optimize off|light|medium|heavy] [--transforms-json <json|@file>] [--canvas <id>] [--wait]\n assethub composer run --part <mesh-asset-id>=<part-image-id>... --reference <image-asset-id> --model V6 [--optimize off|light|medium|heavy] [--canvas <id>] [--wait]\n assethub composer run --part <mesh-asset-id>... --reference <image-asset-id> --model V5.1 [--reasoning low|medium|high] [--agent-model <agents-api model>] [--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 canvas graph-id <canvas-id>\n assethub runs list [--canvas <id>] [--cursor <cursor>] [--limit <n>]\n assethub runs get|watch|wait <run-id> [--interval-ms <ms>] [--timeout-ms <n>] [--summary] [--download --out-dir <dir>]\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 graph snapshot <graph-id> [--offset <n>] [--limit <n>]\n assethub graph node <graph-id> <node-id>\n assethub graph image <graph-id> <node-id> [--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>] [--base-body <mesh-asset-id>] [--skill-planner-model <model>] [--auto-repair true|false] [--skill-mode auto|manual|off] [--skill-id <id>...] [--context <canvas-id> --context-version <n>] [--wait] [--download --out-dir <dir>]\n Production graph options: --pipeline-depth parts|mesh|composition [--assembly-policy concept-to-character-v1] [--mesh-generation-json <json|@file>]\n assethub production batch (--file <path>... | --files-dir <dir> | --source-id <id>... | --source-url <url>...) --part-extractor <name> [--repeat <n>] [--yes] [--canvas <id>] [--operation-id <uuid>] [--wait [--concurrency <n>]] [--download --out-dir <dir>]\n One production analyze per image \u00D7 --repeat, on one canvas. Takes the production analyze options. Rerun with the printed --operation-id to resume; nothing is started twice.\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 run --image <file|asset-id> [--canvas <id>] [--part-extractor <name>] [--compose v6|none] [--mesh-model <id>] [--max-parts <n>] [--max-cost <credits>] [--estimate] [--wait] [--download --out-dir <dir>] [--json]\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 production resume <run-id|order-id> [--expected-resume-count <n>] [--wait] [--timeout-ms <ms>] [--download --out-dir <dir>] (after a fix, pick a stopped or stalled graph run back up; no new charge)\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>] [--base-body <mesh-asset-id>] [--skill-planner-model <model>] [--auto-repair true|false] [--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 assethub memory memorize --canvas <id> [--nodes <shape-id>,<shape-id>,...] [--wait] [--timeout <s>]\n assethub memory replay <memory-id> --source <asset-id> [--wait] [--timeout <s>]\n assethub skills list [--cursor <cursor>]\n assethub skills get <skill-id> [--revision <n>]\n assethub skills memory <skill-id> [--revision <n>] [--images <dir>]\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 skills validate --input-json <json|@file|@-> [--build <build-id>]\n assethub skills schema\n assethub skills build --goal <text> (--canvas <id>... | --memory <id>...) [--instructions <text>] [--operation-id <uuid>] [--wait] [--dry-run]\n assethub skills official list\n assethub skills official install <skill-id> --revision <n> --content-sha256 <sha256> [--expected-revision <n>] [--expected-grant-revision <n>]\n assethub skills official prepare <skill-id> --input-json <json|@file|@->\n assethub skills official customize <skill-id> --input-json <json|@file|@->\n assethub org search <query>\n assethub org canvases --org <orgId>\n assethub graph export-canvas --org <orgId> --canvas <id>[,<id>...] [--wait] [--timeout <s>] [--out-dir <dir>]\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 analyze --file ./concept.png --part-extractor v4 --wait --download --out-dir ./character\n assethub production batch --file ./harpy.png --file ./satyr.png --repeat 2 --part-extractor v4 --yes --wait --download --out-dir ./batch\n assethub production run --order-id ord_x --mission-id ms_x --run-mode full_auto --max-cost-credits 200 --wait\n assethub production run --image ./character.png --estimate\n assethub production run --image ./character.png --compose v6 --max-cost 500 --wait --download --out-dir ./out/asset\n assethub production watch ord_x\n assethub runs get run_x --summary\n assethub runs wait run_x --timeout-ms 3600000\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 production resume ord_x\n assethub production resume <run-id> --wait --download --out-dir ./character\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";
27
- export declare const commandSetup: (flags: Flags, installHooks?: InstallHooks) => Promise<void>;
27
+ 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 setup [--agent claude-code|codex|cursor...] [--project] [--only <step,...>] [--skip <step,...>] [--no-skills] [--no-auto-update | --auto-update] [--profile <name>] [--workspace <id>] [--api-key-stdin] [--base-url <url>] [--no-app-env] [--dry-run] [--yes] [--print-env] [--json]\n assethub env load [--profile <name>]\n assethub update [--check] [--dry-run] [--yes] (once a day a newer version installs itself in the background; turn off: setup --no-auto-update or ASSETHUB_NO_AUTO_UPDATE=1)\n assethub doctor [--mcp] [--setup [--agent <name>...] [--project]] [--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 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] [--effort light|standard|thorough] [--max-rounds <n>] [--agent-model <provider:id|unambiguous-id>] [--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 refine --from-run <run-id> --skill-assembly [--reasoning low|medium|high] [--agent-model <agents-api model>] [--wait]\n assethub composer run --part <mesh-asset-id>[=<part-image-id>] [--part <mesh-asset-id>[=<part-image-id>]...] --reference <image-asset-id> [--model <id>] [--agent-model <provider:id|unambiguous-id>] [--mode quick|quality] [--optimize off|light|medium|heavy] [--transforms-json <json|@file>] [--canvas <id>] [--wait]\n assethub composer run --part <mesh-asset-id>=<part-image-id>... --reference <image-asset-id> --model V6 [--optimize off|light|medium|heavy] [--canvas <id>] [--wait]\n assethub composer run --part <mesh-asset-id>... --reference <image-asset-id> --model V5.1 [--reasoning low|medium|high] [--agent-model <agents-api model>] [--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 canvas graph-id <canvas-id>\n assethub runs list [--canvas <id>] [--cursor <cursor>] [--limit <n>]\n assethub runs get|watch|wait <run-id> [--interval-ms <ms>] [--timeout-ms <n>] [--summary] [--download --out-dir <dir>]\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 graph snapshot <graph-id> [--offset <n>] [--limit <n>]\n assethub graph node <graph-id> <node-id>\n assethub graph image <graph-id> <node-id> [--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>] [--base-body <mesh-asset-id>] [--skill-planner-model <model>] [--auto-repair true|false] [--skill-mode auto|manual|off] [--skill-id <id>...] [--context <canvas-id> --context-version <n>] [--wait] [--download --out-dir <dir>]\n Production graph options: --pipeline-depth parts|mesh|composition [--assembly-policy concept-to-character-v1] [--mesh-generation-json <json|@file>]\n assethub production batch (--file <path>... | --files-dir <dir> | --source-id <id>... | --source-url <url>...) --part-extractor <name> [--repeat <n>] [--yes] [--canvas <id>] [--operation-id <uuid>] [--wait [--concurrency <n>]] [--download --out-dir <dir>]\n One production analyze per image \u00D7 --repeat, on one canvas. Takes the production analyze options. Rerun with the printed --operation-id to resume; nothing is started twice.\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 run --image <file|asset-id> [--canvas <id>] [--part-extractor <name>] [--compose v6|none] [--mesh-model <id>] [--max-parts <n>] [--max-cost <credits>] [--estimate] [--wait] [--download --out-dir <dir>] [--json]\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 production resume <run-id|order-id> [--expected-resume-count <n>] [--wait] [--timeout-ms <ms>] [--download --out-dir <dir>] (after a fix, pick a stopped or stalled graph run back up; no new charge)\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>] [--base-body <mesh-asset-id>] [--skill-planner-model <model>] [--auto-repair true|false] [--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 assethub memory memorize --canvas <id> [--nodes <shape-id>,<shape-id>,...] [--wait] [--timeout <s>]\n assethub memory replay <memory-id> --source <asset-id> [--wait] [--timeout <s>]\n assethub skills list [--cursor <cursor>]\n assethub skills get <skill-id> [--revision <n>]\n assethub skills memory <skill-id> [--revision <n>] [--images <dir>]\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 skills validate --input-json <json|@file|@-> [--build <build-id>]\n assethub skills schema\n assethub skills build --goal <text> (--canvas <id>... | --memory <id>...) [--instructions <text>] [--operation-id <uuid>] [--wait] [--dry-run]\n assethub skills official list\n assethub skills official install <skill-id> --revision <n> --content-sha256 <sha256> [--expected-revision <n>] [--expected-grant-revision <n>]\n assethub skills official prepare <skill-id> --input-json <json|@file|@->\n assethub skills official customize <skill-id> --input-json <json|@file|@->\n assethub org search <query>\n assethub org canvases --org <orgId>\n assethub graph export-canvas --org <orgId> --canvas <id>[,<id>...] [--wait] [--timeout <s>] [--out-dir <dir>]\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 setup --dry-run\n assethub setup --only skills --project\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 analyze --file ./concept.png --part-extractor v4 --wait --download --out-dir ./character\n assethub production batch --file ./harpy.png --file ./satyr.png --repeat 2 --part-extractor v4 --yes --wait --download --out-dir ./batch\n assethub production run --order-id ord_x --mission-id ms_x --run-mode full_auto --max-cost-credits 200 --wait\n assethub production run --image ./character.png --estimate\n assethub production run --image ./character.png --compose v6 --max-cost 500 --wait --download --out-dir ./out/asset\n assethub production watch ord_x\n assethub runs get run_x --summary\n assethub runs wait run_x --timeout-ms 3600000\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 production resume ord_x\n assethub production resume <run-id> --wait --download --out-dir ./character\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";
28
+ export declare const commandSetup: (flags: Flags, installHooks?: InstallHooks, overrides?: {
29
+ skip?: SetupStepName[];
30
+ }) => Promise<void>;
28
31
  /**
29
32
  * The `animate retarget` request, built from flags alone.
30
33
  *
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -2,12 +2,13 @@
2
2
  import { childOperationId, expandProductionBatch, planProductionNodeMeshes, callApiOperation, describeApiOperation, discoverApiOperations, searchApiOperations, TERMINAL_WORKSPACE_SKILL_BUILD_STATUSES, WORKSPACE_SKILL_ENHANCE_SECTIONS, } from '@assethub/api-client';
3
3
  import { setTimeout as delay } from 'node:timers/promises';
4
4
  import { cliVersion, diagnose, mcpConfig } from './setup.js';
5
- import { AGENT_IDS, initAgents, syncInstalledSkill } from './agentSetup.js';
6
- import { confirmNo, confirmYes, defaultFileDeps, formatSetupSummary, pickFromList, promptHidden, runProcess, runSetup, } from './setupCommand.js';
5
+ import { AGENT_IDS, parseAgentIds, syncInstalledSkill } from './agentSetup.js';
6
+ import { confirmNo, confirmYes, defaultFileDeps, formatSetupSummary, pickFromList, promptHidden, runProcess, runSetup, SETUP_STEPS, } from './setupCommand.js';
7
7
  import { launchAgentProgram, loadKeyIntoLaunchd } from './appEnv.js';
8
8
  import { defaultInstallHooks } from './setupHooksBridge.js';
9
9
  import { canUploadSessions, installHooks as installSessionHooks, runHooksCommand } from './hooks/index.js';
10
10
  import { createNodeUpdateDeps, runUpdate } from './update.js';
11
+ import { autoUpdateEnabled, claimRefreshAttempt, decideUpdateNotice, isInstalledPackage, patchUpdateCheck, readAutoUpdateSetting, readUpdateCheck, REFRESH_CHILD_ENV, refreshInBackground, refreshUpdateCheck, settingsPath, takeLock, updateCheckDisabled, updateCheckPath, writeAutoUpdateSetting, writeUpdateCheck, } from './updateNotice.js';
11
12
  import { ingestProjectSources } from './projectSources.js';
12
13
  import { downloadCanvas } from './canvasDownload.js';
13
14
  import { downloadCanvasGraphZip } from './canvasGraphDownload.js';
@@ -18,7 +19,7 @@ import { importCanvasAssetWithState } from './canvasAssetImport.js';
18
19
  import { execFile, spawn } from 'node:child_process';
19
20
  import { createHash, randomUUID } from 'node:crypto';
20
21
  import { realpathSync } from 'node:fs';
21
- import { chmod, mkdir, readdir, readFile, rename, unlink, writeFile, } from 'node:fs/promises';
22
+ import { chmod, mkdir, readdir, readFile, rename, rm, unlink, writeFile, } from 'node:fs/promises';
22
23
  import { homedir, tmpdir } from 'node:os';
23
24
  import { basename, dirname, extname, join, resolve } from 'node:path';
24
25
  import { argv, env, exit, stdin, stderr, stdout } from 'node:process';
@@ -222,11 +223,10 @@ CLI and MCP are available to all AssetHub users. Workspace permissions and featu
222
223
 
223
224
  Usage:
224
225
  assethub --version
225
- assethub setup [--client claude|codex|both] [--profile <name>] [--workspace <id>] [--api-key-stdin] [--base-url <url>] [--no-app-env] [--dry-run] [--yes] [--print-env] [--json]
226
+ assethub setup [--agent claude-code|codex|cursor...] [--project] [--only <step,...>] [--skip <step,...>] [--no-skills] [--no-auto-update | --auto-update] [--profile <name>] [--workspace <id>] [--api-key-stdin] [--base-url <url>] [--no-app-env] [--dry-run] [--yes] [--print-env] [--json]
226
227
  assethub env load [--profile <name>]
227
- assethub update [--check] [--dry-run] [--yes]
228
- assethub doctor [--mcp] [--profile <name>] [--timeout-ms <n>]
229
- assethub init [--agent claude-code|codex|cursor...] [--project] [--dry-run] [--base-url <url>] [--workspace <id>] [--profile <name>]
228
+ assethub update [--check] [--dry-run] [--yes] (once a day a newer version installs itself in the background; turn off: setup --no-auto-update or ASSETHUB_NO_AUTO_UPDATE=1)
229
+ assethub doctor [--mcp] [--setup [--agent <name>...] [--project]] [--profile <name>] [--timeout-ms <n>]
230
230
  assethub mcp tools [tool-name] [--account] [--profile <name>] [--timeout-ms <n>]
231
231
  assethub mcp config --client cursor|codex [--account] [--base-url <url>]
232
232
  assethub auth login --api-key <key> [--base-url <url>] [--profile <name>]
@@ -364,7 +364,8 @@ Global options:
364
364
  Examples:
365
365
  ASSETHUB_API_KEY=ah_live_xxx assethub models list
366
366
  assethub auth login --api-key-stdin
367
- assethub init --dry-run
367
+ assethub setup --dry-run
368
+ assethub setup --only skills --project
368
369
  assethub models list --ids-only
369
370
  assethub files upload ./input.png --media-type image
370
371
  assethub source create --file ./input.png --media-type image
@@ -1906,11 +1907,41 @@ const commandAuth = async (subcommand, flags) => {
1906
1907
  };
1907
1908
  // One-command onboarding. Login and workspace selection reuse commandAuth and
1908
1909
  // commandWorkspace (their JSON output is suppressed); setupCommand.ts owns the
1909
- // client configuration and the summary.
1910
- export const commandSetup = async (flags, installHooks = defaultInstallHooks) => {
1911
- const client = getFlag(flags, 'client') ?? 'both';
1912
- if (client !== 'claude' && client !== 'codex' && client !== 'both')
1913
- throw new Error('--client must be claude, codex or both');
1910
+ // steps, the agent configuration and the summary.
1911
+ const parseSetupSelection = (flags) => {
1912
+ const agentValues = getFlagValues(flags, 'agent').map(value => assertFlagHasValue(value, '--agent <name>'));
1913
+ let agents = agentValues.length > 0 ? parseAgentIds(agentValues) : undefined;
1914
+ if (!agents && hasFlag(flags, 'client')) {
1915
+ // Older spelling: --client claude|codex|both.
1916
+ const client = getFlag(flags, 'client');
1917
+ if (client !== 'claude' && client !== 'codex' && client !== 'both')
1918
+ throw new Error('--client must be claude, codex or both (use --agent claude-code|codex|cursor)');
1919
+ agents = client === 'both' ? ['claude-code', 'codex'] : parseAgentIds([client]);
1920
+ }
1921
+ const stepValues = (name) => getFlagValues(flags, name)
1922
+ .map(value => assertFlagHasValue(value, `--${name} <step>`))
1923
+ .flatMap(value => value.split(','))
1924
+ .map(value => value.trim())
1925
+ .filter(Boolean);
1926
+ const known = (name, values) => {
1927
+ const unknown = values.filter(value => !SETUP_STEPS.includes(value));
1928
+ if (unknown.length > 0)
1929
+ throw new Error(`Unknown setup step for --${name}: ${unknown.join(', ')}. Steps: login, workspace, mcp, skills, auto-update, app-env, doctor.`);
1930
+ return values;
1931
+ };
1932
+ const only = known('only', stepValues('only'));
1933
+ const skip = new Set(known('skip', stepValues('skip')));
1934
+ if (only.length > 0)
1935
+ for (const step of SETUP_STEPS)
1936
+ if (!only.includes(step))
1937
+ skip.add(step);
1938
+ if (hasFlag(flags, 'no-skills'))
1939
+ skip.add('skills');
1940
+ return { agents, skip: SETUP_STEPS.filter(step => skip.has(step)) };
1941
+ };
1942
+ /** The `runSetup` options and real dependencies for these flags; `setup`, `init` and `doctor --setup` share them. */
1943
+ const setupRun = async (flags, installHooks, overrides = {}) => {
1944
+ const selection = parseSetupSelection(flags);
1914
1945
  const config = await readAuthConfig(getConfigPath(flags));
1915
1946
  // Only name a profile the user chose or one that is saved: a synthetic profile
1916
1947
  // would make resolveAuth reject a fresh machine before its ASSETHUB_API_KEY fallback.
@@ -1933,26 +1964,32 @@ export const commandSetup = async (flags, installHooks = defaultInstallHooks) =>
1933
1964
  printSuppressed = false;
1934
1965
  }
1935
1966
  };
1936
- const result = await runSetup({
1937
- client,
1967
+ const options = {
1968
+ agents: selection.agents,
1969
+ project: hasFlag(flags, 'project'),
1970
+ skip: [...new Set([...selection.skip, ...(overrides.skip ?? [])])],
1938
1971
  workspace: getFlag(flags, 'workspace'),
1939
1972
  apiKeyStdin,
1940
1973
  apiKey: flagKey ?? envKey,
1941
1974
  apiKeySource: flagKey ? 'flag' : envKey ? 'env' : undefined,
1942
1975
  noHook: hasFlag(flags, 'no-hook'),
1943
1976
  noAppEnv: hasFlag(flags, 'no-app-env'),
1977
+ ...(hasFlag(flags, 'no-auto-update') ? { autoUpdate: false } : hasFlag(flags, 'auto-update') ? { autoUpdate: true } : {}),
1944
1978
  saveSessions: hasFlag(flags, 'save-sessions'),
1945
- dryRun: hasFlag(flags, 'dry-run'),
1979
+ dryRun: overrides.dryRun ?? hasFlag(flags, 'dry-run'),
1946
1980
  yes: hasFlag(flags, 'yes'),
1947
1981
  printEnv: hasFlag(flags, 'print-env'),
1948
- }, {
1982
+ };
1983
+ const deps = {
1949
1984
  ...defaultFileDeps(),
1950
1985
  launchAgentProgram: launchAgentProgram(process.execPath, realpathSync(argv[1] ?? fileURLToPath(import.meta.url)), ['env', 'load', ...(hasFlag(flags, 'profile') ? ['--profile', requireFlag(flags, 'profile')] : [])]),
1951
1986
  interactive: Boolean(stdin.isTTY && stderr.isTTY) && !apiKeyStdin,
1952
1987
  installHooks,
1953
- log: line => {
1954
- stderr.write(`${line}\n`);
1955
- },
1988
+ log: overrides.quietLog
1989
+ ? () => { }
1990
+ : line => {
1991
+ stderr.write(`${line}\n`);
1992
+ },
1956
1993
  hasWorkingKey: async () => {
1957
1994
  try {
1958
1995
  const auth = await resolveAuth(base);
@@ -1976,6 +2013,11 @@ export const commandSetup = async (flags, installHooks = defaultInstallHooks) =>
1976
2013
  }
1977
2014
  return commandAuth('login', loginFlags);
1978
2015
  }),
2016
+ resolveTarget: () => resolveMcpTarget(flags),
2017
+ readAutoUpdate: () => readAutoUpdateSetting(settingsPath(getConfigPath(flags))),
2018
+ writeAutoUpdate: on => writeAutoUpdateSetting(settingsPath(getConfigPath(flags)), on),
2019
+ canSelfUpdate: async () => isInstalledPackage(realpathSync(argv[1] ?? fileURLToPath(import.meta.url))),
2020
+ autoUpdateBlockedByEnv: !autoUpdateEnabled(undefined, env),
1979
2021
  resolveAuth: async () => {
1980
2022
  const auth = await resolveAuth(base);
1981
2023
  return { apiKey: auth.apiKey, baseUrl: auth.baseUrl, profile: auth.profile, workspaceId: auth.workspaceId };
@@ -2006,7 +2048,14 @@ export const commandSetup = async (flags, installHooks = defaultInstallHooks) =>
2006
2048
  includeMcp: true,
2007
2049
  timeoutMs: parsePositiveIntegerFlag(flags, 'timeout-ms', 15000),
2008
2050
  }),
2009
- });
2051
+ };
2052
+ return { options, deps };
2053
+ };
2054
+ export const commandSetup = async (flags, installHooks = defaultInstallHooks, overrides = {}) => {
2055
+ const { options, deps } = await setupRun(flags, installHooks, overrides);
2056
+ if (hasFlag(flags, 'client') && !hasFlag(flags, 'agent'))
2057
+ stderr.write('--client is deprecated; use --agent claude-code|codex|cursor.\n');
2058
+ const result = await runSetup(options, deps);
2010
2059
  if (hasFlag(flags, 'json'))
2011
2060
  print(result);
2012
2061
  else {
@@ -2017,6 +2066,29 @@ export const commandSetup = async (flags, installHooks = defaultInstallHooks) =>
2017
2066
  if (!result.ok)
2018
2067
  process.exitCode = 2;
2019
2068
  };
2069
+ /**
2070
+ * `doctor --setup`: the setup steps as a dry run that changes nothing, needs no
2071
+ * network, and fails when MCP config or the skill is missing or out of date.
2072
+ */
2073
+ const setupCheck = async (flags) => {
2074
+ const { options, deps } = await setupRun(flags, installSessionHooks, {
2075
+ skip: ['login', 'workspace', 'auto-update', 'app-env', 'hook', 'doctor'],
2076
+ dryRun: true,
2077
+ quietLog: true,
2078
+ });
2079
+ const result = await runSetup(options, deps);
2080
+ const outdated = result.steps.filter(step => step.status === 'fail' || step.change === 'would-update');
2081
+ return {
2082
+ name: 'setup',
2083
+ status: outdated.length === 0 ? 'pass' : 'fail',
2084
+ ...(outdated.length > 0
2085
+ ? {
2086
+ message: outdated.map(step => `${step.name}: ${step.detail.replace(/ \(dry run\)$/, '')}`).join('; '),
2087
+ hint: `Run \`assethub setup${options.project ? ' --project' : ''}\` to fix it.`,
2088
+ }
2089
+ : { message: `${result.agents.join(', ')}: MCP config and skill are up to date` }),
2090
+ };
2091
+ };
2020
2092
  // `env load` is what the macOS login agent installed by `setup` runs: it copies
2021
2093
  // the saved key into launchd's user environment so Claude and Codex, started
2022
2094
  // from the Dock, can expand ${ASSETHUB_API_KEY} in their MCP config.
@@ -5583,6 +5655,33 @@ const resolveMcpTarget = async (flags) => {
5583
5655
  (stored && new URL(baseUrl).origin === new URL(stored.baseUrl).origin ? stored.workspaceId : undefined);
5584
5656
  return { baseUrl, workspaceId };
5585
5657
  };
5658
+ // A stderr line when a newer CLI is known or was just installed, from a cache
5659
+ // refreshed (and, with auto-update on, acted on) at most once a day in the background.
5660
+ const noticeUpdate = async (flags) => {
5661
+ if (updateCheckDisabled(env) || env[REFRESH_CHILD_ENV])
5662
+ return;
5663
+ try {
5664
+ const cli = realpathSync(argv[1] ?? fileURLToPath(import.meta.url));
5665
+ if (!isInstalledPackage(cli))
5666
+ return;
5667
+ const cachePath = updateCheckPath(getConfigPath(flags));
5668
+ const cache = await readUpdateCheck(cachePath);
5669
+ const now = new Date();
5670
+ const decision = decideUpdateNotice(await cliVersion(), cache, now);
5671
+ for (const notice of decision.notices)
5672
+ stderr.write(`${notice}\n`);
5673
+ if (cache && (decision.markAnnounced || decision.markNoticed))
5674
+ await patchUpdateCheck(cachePath, cache, {
5675
+ ...(decision.markAnnounced && cache.autoUpdate ? { autoUpdate: { ...cache.autoUpdate, announced: true } } : {}),
5676
+ ...(decision.markNoticed ? { noticedAt: now.toISOString() } : {}),
5677
+ });
5678
+ if (decision.refresh && (await claimRefreshAttempt(cachePath, now)))
5679
+ refreshInBackground(process.execPath, cli, getConfigPath(flags));
5680
+ }
5681
+ catch {
5682
+ // best effort
5683
+ }
5684
+ };
5586
5685
  const run = async () => {
5587
5686
  const parsed = parseArgs(argv.slice(2));
5588
5687
  if (hasFlag(parsed.flags, 'version')) {
@@ -5596,16 +5695,16 @@ const run = async () => {
5596
5695
  const [command, subcommand] = parsed.positionals;
5597
5696
  if (command !== 'init')
5598
5697
  await syncInstalledSkill();
5698
+ if (!['update', 'hooks', 'env'].includes(command ?? ''))
5699
+ await noticeUpdate(parsed.flags);
5599
5700
  if (command === 'init') {
5600
5701
  if (subcommand)
5601
5702
  throw new Error(`Use init [--agent ${AGENT_IDS.join('|')}] [--project] [--dry-run]`);
5602
- const target = await resolveMcpTarget(parsed.flags);
5603
- print(await initAgents({
5604
- ...target,
5605
- agents: getFlagValues(parsed.flags, 'agent').map(value => assertFlagHasValue(value, '--agent <name>')),
5606
- project: hasFlag(parsed.flags, 'project'),
5607
- dryRun: hasFlag(parsed.flags, 'dry-run'),
5608
- }));
5703
+ // Kept for existing scripts: agent wiring only, as before, through setup's steps.
5704
+ stderr.write('`assethub init` is deprecated and will be removed in a later version; use `assethub setup` (or `assethub setup --only mcp,skills` for agent wiring only).\n');
5705
+ await commandSetup({ ...parsed.flags, json: true, yes: true }, installSessionHooks, {
5706
+ skip: ['login', 'workspace', 'auto-update', 'app-env', 'hook', 'doctor'],
5707
+ });
5609
5708
  return;
5610
5709
  }
5611
5710
  if (command === 'mcp' && subcommand === 'tools') {
@@ -5671,22 +5770,49 @@ const run = async () => {
5671
5770
  return;
5672
5771
  }
5673
5772
  if (command === 'update') {
5773
+ const cachePath = updateCheckPath(getConfigPath(parsed.flags));
5774
+ if (hasFlag(parsed.flags, 'refresh-check')) {
5775
+ // The detached daily check started by noticeUpdate: record the latest
5776
+ // version and, with auto-update on, install it. Prints nothing.
5777
+ const configPath = getConfigPath(parsed.flags);
5778
+ await refreshUpdateCheck({
5779
+ cachePath,
5780
+ lockPath: `${cachePath}.lock`,
5781
+ autoUpdate: autoUpdateEnabled(await readAutoUpdateSetting(settingsPath(configPath)), env),
5782
+ deps: createNodeUpdateDeps(['--config', configPath]),
5783
+ });
5784
+ return;
5785
+ }
5674
5786
  // The verifying doctor checks the same login this command was given.
5675
5787
  const forwardFlags = ['profile', 'config', 'base-url', 'workspace'].flatMap(name => {
5676
5788
  const value = getFlag(parsed.flags, name);
5677
5789
  return value ? [`--${name}`, value] : [];
5678
5790
  });
5679
5791
  const apiKey = getFlag(parsed.flags, 'api-key');
5680
- print(await runUpdate({ check: hasFlag(parsed.flags, 'check'), dryRun: hasFlag(parsed.flags, 'dry-run'), yes: hasFlag(parsed.flags, 'yes') }, createNodeUpdateDeps(forwardFlags, apiKey ? { ASSETHUB_API_KEY: apiKey } : {})));
5792
+ const installs = !hasFlag(parsed.flags, 'check') && !hasFlag(parsed.flags, 'dry-run');
5793
+ // Never install alongside a background auto-update.
5794
+ if (installs && !(await takeLock(`${cachePath}.lock`)))
5795
+ throw new Error('A background update of the CLI is running; try again in a minute.');
5796
+ const report = await runUpdate({ check: hasFlag(parsed.flags, 'check'), dryRun: hasFlag(parsed.flags, 'dry-run'), yes: hasFlag(parsed.flags, 'yes') }, createNodeUpdateDeps(forwardFlags, apiKey ? { ASSETHUB_API_KEY: apiKey } : {})).finally(async () => {
5797
+ if (installs)
5798
+ await rm(`${cachePath}.lock`, { force: true });
5799
+ });
5800
+ // Every answer from the registry refreshes the daily hint, so it never nags about an installed version.
5801
+ await writeUpdateCheck(cachePath, report.status === 'updated' ? report.to : report.latest).catch(() => undefined);
5802
+ print(report);
5681
5803
  return;
5682
5804
  }
5683
5805
  if (command === 'doctor') {
5684
5806
  stderr.write('Checking AssetHub connection…\n');
5685
- const report = await diagnose({
5807
+ const diagnosed = await diagnose({
5686
5808
  resolveAuth: () => resolveAuth(parsed.flags),
5687
5809
  includeMcp: hasFlag(parsed.flags, 'mcp'),
5688
5810
  timeoutMs: parsePositiveIntegerFlag(parsed.flags, 'timeout-ms', 15000),
5689
5811
  });
5812
+ const setup = hasFlag(parsed.flags, 'setup') ? await setupCheck(parsed.flags) : undefined;
5813
+ const report = setup
5814
+ ? { ...diagnosed, ok: diagnosed.ok && setup.status === 'pass', checks: [...diagnosed.checks, setup] }
5815
+ : diagnosed;
5690
5816
  print(report);
5691
5817
  if (!report.ok)
5692
5818
  process.exitCode = 2;