@assethub/cli 0.1.35 → 0.1.37
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 +23 -0
- package/dist/agentSetup.d.ts +1 -1
- package/dist/agentSetup.d.ts.map +1 -1
- package/dist/agentSetup.js +8 -3
- package/dist/hooks/save.d.ts +8 -0
- package/dist/hooks/save.d.ts.map +1 -1
- package/dist/hooks/save.js +32 -6
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +65 -7
- package/dist/setupCommand.d.ts +10 -1
- package/dist/setupCommand.d.ts.map +1 -1
- package/dist/setupCommand.js +33 -2
- package/dist/updateNotice.d.ts +71 -0
- package/dist/updateNotice.d.ts.map +1 -0
- package/dist/updateNotice.js +189 -0
- package/package.json +1 -1
- package/skills/assethub/SKILL.md +17 -0
package/README.md
CHANGED
|
@@ -62,6 +62,29 @@ print the `export ASSETHUB_API_KEY=...` line, and export it in the shell that
|
|
|
62
62
|
starts Claude Code or Codex. The key is redacted
|
|
63
63
|
(`ah_…last4`) everywhere else.
|
|
64
64
|
|
|
65
|
+
## Staying up to date
|
|
66
|
+
|
|
67
|
+
```sh
|
|
68
|
+
assethub update --check # JSON: up_to_date or update_available
|
|
69
|
+
assethub update # upgrade a global install now; the saved login is kept
|
|
70
|
+
assethub setup --no-auto-update # turn background updates off (--auto-update turns them on)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Auto-update is on by default. Once a day, a detached background process checks
|
|
74
|
+
for a newer release and installs it with the package manager that installed the
|
|
75
|
+
CLI, the same way `assethub update --yes` does, keeping the saved login. No
|
|
76
|
+
command waits for it, and an install never happens inside a running command; the
|
|
77
|
+
next command prints one line on stderr (`updated itself from 0.1.36 to 0.1.37`).
|
|
78
|
+
stdout stays one JSON object. If the install fails, the CLI keeps the current
|
|
79
|
+
version and says so, then keeps announcing the newer release.
|
|
80
|
+
|
|
81
|
+
It applies only to a global install (not `npx`, a project dependency or a source
|
|
82
|
+
checkout) and is off in CI, with `ASSETHUB_NO_AUTO_UPDATE=1` (no install, notice
|
|
83
|
+
only) or with `ASSETHUB_NO_UPDATE_CHECK=1` (no check at all). The choice is saved
|
|
84
|
+
in `~/.assethub/settings.json`, and `assethub setup` shows it as its `auto-update`
|
|
85
|
+
step. The bundled agent skill also asks agents to run `assethub update --check`
|
|
86
|
+
at the start of each session.
|
|
87
|
+
|
|
65
88
|
## API discovery and Workspace Skills
|
|
66
89
|
|
|
67
90
|
Use `api search [query]` to discover the authenticated server catalog and
|
package/dist/agentSetup.d.ts
CHANGED
|
@@ -27,7 +27,7 @@ export declare const readJsonServer: (text: string | undefined) => unknown;
|
|
|
27
27
|
* Returns the new text, or the input unchanged when the entry already matches.
|
|
28
28
|
*/
|
|
29
29
|
export declare const mergeJsonServer: (path: string, text: string | undefined, entry: Record<string, unknown>) => string;
|
|
30
|
-
export type SkillStatus = 'installed' | 'updated' | 'unchanged' | 'kept-existing';
|
|
30
|
+
export type SkillStatus = 'installed' | 'updated' | 'unchanged' | 'kept-existing' | 'kept-newer';
|
|
31
31
|
export declare const installSkill: ({ root, version, dryRun, }: {
|
|
32
32
|
/** The home folder, or the project folder for a project install. */
|
|
33
33
|
root: string;
|
package/dist/agentSetup.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agentSetup.d.ts","sourceRoot":"","sources":["../src/agentSetup.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"agentSetup.d.ts","sourceRoot":"","sources":["../src/agentSetup.ts"],"names":[],"mappings":"AAkCA,eAAO,MAAM,SAAS,6CAA8C,CAAA;AACpE,MAAM,MAAM,OAAO,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,CAAC,CAAA;AAEhD,MAAM,MAAM,SAAS,GAAG;IACtB,EAAE,EAAE,OAAO,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,gGAAgG;IAChG,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAA;CACtC,CAAA;AAED,eAAO,MAAM,WAAW,EAAE,SAAS,SAAS,EAyB3C,CAAA;AAED,eAAO,MAAM,SAAS,GAAI,IAAI,OAAO,KAAG,SACiB,CAAA;AAEzD,sHAAsH;AACtH,eAAO,MAAM,aAAa,GAAI,QAAQ,MAAM,EAAE,KAAG,OAAO,EAOvD,CAAA;AAED,qHAAqH;AACrH,eAAO,MAAM,YAAY,GACvB,MAAM,MAAM,EACZ,YAAY,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,EACzD,YAAY,MAAM,KACjB,OAAO,CAAC,OAAO,EAAE,CAUnB,CAAA;AAMD,+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,+GAA+G;AAC/G,eAAO,MAAM,cAAc,GAAI,MAAM,MAAM,GAAG,SAAS,KAAG,OAQzD,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe,GAC1B,MAAM,MAAM,EACZ,MAAM,MAAM,GAAG,SAAS,EACxB,OAAO,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC7B,MA2BF,CAAA;AAID,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG,SAAS,GAAG,WAAW,GAAG,eAAe,GAAG,YAAY,CAAA;AAmChG,eAAO,MAAM,YAAY,GAAU,4BAIhC;IACD,oEAAoE;IACpE,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,CA2BhE,CAAA;AAED,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,UAAU,GAAG,WAAW,GAAG,eAAe,CAAA;AAkC9E;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,QAAa,OAAO,CAAC,IAAI,CAgBvD,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,WAAW,CAAA;IACnB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE;QAAC,KAAK,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,UAAU,CAAA;KAAC,EAAE,CAAA;CAC5D,CAAA;AAED,+GAA+G;AAC/G,eAAO,MAAM,kBAAkB,GAAU,2BAItC;IACD,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,OAAO,EAAE,CAAA;IACjB,MAAM,EAAE,OAAO,CAAA;CAChB,KAAG,OAAO,CAAC,YAAY,CAMvB,CAAA"}
|
package/dist/agentSetup.js
CHANGED
|
@@ -19,6 +19,7 @@ import { dirname, join, relative, resolve } from 'node:path';
|
|
|
19
19
|
import { env, pid } from 'node:process';
|
|
20
20
|
import { fileURLToPath } from 'node:url';
|
|
21
21
|
import { cliVersion, validatedBaseUrl } from './setup.js';
|
|
22
|
+
import { compareVersions } from './update.js';
|
|
22
23
|
export const AGENT_IDS = ['claude-code', 'codex', 'cursor'];
|
|
23
24
|
export const AGENT_SPECS = [
|
|
24
25
|
{
|
|
@@ -191,13 +192,16 @@ export const installSkill = async ({ root, version, dryRun, }) => {
|
|
|
191
192
|
: 'installed'
|
|
192
193
|
: marker === version
|
|
193
194
|
? 'unchanged'
|
|
194
|
-
:
|
|
195
|
+
: // An older CLI (or a stale monorepo build) never replaces a newer skill.
|
|
196
|
+
compareVersions(version, marker) < 0
|
|
197
|
+
? 'kept-newer'
|
|
198
|
+
: 'updated';
|
|
195
199
|
if (!dryRun && (status === 'installed' || status === 'updated'))
|
|
196
200
|
await replaceSkillDir(source, target, version);
|
|
197
201
|
return {
|
|
198
202
|
path: target,
|
|
199
203
|
status,
|
|
200
|
-
...(status === 'kept-existing' ? {} : { version }),
|
|
204
|
+
...(status === 'kept-existing' ? {} : { version: status === 'kept-newer' ? marker : version }),
|
|
201
205
|
};
|
|
202
206
|
};
|
|
203
207
|
const linkSkill = async (agentSkillsDir, canonical, dryRun) => {
|
|
@@ -244,7 +248,8 @@ export const syncInstalledSkill = async () => {
|
|
|
244
248
|
if (installed === undefined)
|
|
245
249
|
return;
|
|
246
250
|
const version = await cliVersion();
|
|
247
|
-
|
|
251
|
+
// Only an upgrade refreshes it: an older CLI never overwrites a newer skill.
|
|
252
|
+
if (installed === version || compareVersions(version, installed) < 0)
|
|
248
253
|
return;
|
|
249
254
|
const source = packagedSkillDir();
|
|
250
255
|
if (!(await isDirectory(source)))
|
package/dist/hooks/save.d.ts
CHANGED
|
@@ -56,6 +56,14 @@ export declare const SWEEP_LIMIT = 3;
|
|
|
56
56
|
* only be uploaded once abandoned (ABANDONED_AFTER_MS quiet, then a new session).
|
|
57
57
|
*/
|
|
58
58
|
export declare const WORKING_UPLOAD_INTERVAL_MS: number;
|
|
59
|
+
/** The shortest interval ASSETHUB_SESSION_UPLOAD_INTERVAL_MIN may set. */
|
|
60
|
+
export declare const MIN_WORKING_UPLOAD_INTERVAL_MS: number;
|
|
61
|
+
/**
|
|
62
|
+
* ASSETHUB_SESSION_UPLOAD_INTERVAL_MIN, in minutes, else WORKING_UPLOAD_INTERVAL_MS.
|
|
63
|
+
* Each upload sends a new snapshot of the whole transcript, so it is never
|
|
64
|
+
* shorter than a minute; a value that is not a positive number is ignored.
|
|
65
|
+
*/
|
|
66
|
+
export declare const workingUploadIntervalMs: (env: NodeJS.ProcessEnv) => number;
|
|
59
67
|
/**
|
|
60
68
|
* Copy + redact the transcript Claude Code keeps at `meta.transcriptPath`, and
|
|
61
69
|
* collect its images. Runs once per SessionEnd and before an upload, never per
|
package/dist/hooks/save.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"save.d.ts","sourceRoot":"","sources":["../../src/hooks/save.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAC,UAAU,EAAE,SAAS,EAAgB,WAAW,EAAC,MAAM,YAAY,CAAA;AAChF,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,aAAa,CAAA;AAE9C,eAAO,MAAM,UAAU,KAAK,CAAA;AAC5B,eAAO,MAAM,eAAe,QAAmB,CAAA;AAC/C,eAAO,MAAM,sBAAsB,KAAK,CAAA;AASxC,MAAM,MAAM,kBAAkB,GAAG;IAC/B,wCAAwC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,oCAAoC;IACpC,KAAK,CAAC,EAAE,SAAS,CAAA;IACjB,+EAA+E;IAC/E,MAAM,CAAC,EAAE,UAAU,CAAA;IACnB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,GAAG,CAAC,EAAE,MAAM,IAAI,CAAA;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAA;IACvB,MAAM,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE,SAAS,CAAC,CAAA;IACvC;;;;OAIG;IACH,WAAW,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;IAC5D,uEAAuE;IACvE,UAAU,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;IACvC;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;CACpE,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,UAAU,EAAE,MAAM,CAAA;IAClB,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,SAAS,GAAG,UAAU,CAAA;CACjC,CAAA;AAYD,wFAAwF;AACxF,eAAO,MAAM,mBAAmB,GAAI,YAAY,MAAM,EAAE,UAAU,MAAM,KAAG,IACgC,CAAA;AAE3G,qEAAqE;AACrE,eAAO,MAAM,0BAA0B,GAAI,YAAY,MAAM,EAAE,UAAU,MAAM,KAAG,IACP,CAAA;AAE3E,8DAA8D;AAC9D,eAAO,MAAM,kBAAkB,GAAI,UAAU,MAAM,KAAG,IAC+B,CAAA;AAErF,eAAO,MAAM,aAAa,GAAI,KAAK,MAAM,CAAC,UAAU,KAAG,MAAM,GAAG,IAM/D,CAAA;AAED,4FAA4F;AAC5F,eAAO,MAAM,aAAa,GACxB,MAAM,MAAM,EACZ,KAAK,IAAI,EACT,MAAM,MAAM,EACZ,MAAM,MAAM,KACX,OAAO,CAAC,MAAM,CAwBhB,CAAA;AAgFD,qGAAqG;AACrG,eAAO,MAAM,kBAAkB,QAAqB,CAAA;AACpD,wEAAwE;AACxE,eAAO,MAAM,WAAW,IAAI,CAAA;AAE5B;;;;GAIG;AACH,eAAO,MAAM,0BAA0B,
|
|
1
|
+
{"version":3,"file":"save.d.ts","sourceRoot":"","sources":["../../src/hooks/save.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAC,UAAU,EAAE,SAAS,EAAgB,WAAW,EAAC,MAAM,YAAY,CAAA;AAChF,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,aAAa,CAAA;AAE9C,eAAO,MAAM,UAAU,KAAK,CAAA;AAC5B,eAAO,MAAM,eAAe,QAAmB,CAAA;AAC/C,eAAO,MAAM,sBAAsB,KAAK,CAAA;AASxC,MAAM,MAAM,kBAAkB,GAAG;IAC/B,wCAAwC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,oCAAoC;IACpC,KAAK,CAAC,EAAE,SAAS,CAAA;IACjB,+EAA+E;IAC/E,MAAM,CAAC,EAAE,UAAU,CAAA;IACnB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,GAAG,CAAC,EAAE,MAAM,IAAI,CAAA;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAA;IACvB,MAAM,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE,SAAS,CAAC,CAAA;IACvC;;;;OAIG;IACH,WAAW,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;IAC5D,uEAAuE;IACvE,UAAU,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;IACvC;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;CACpE,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,UAAU,EAAE,MAAM,CAAA;IAClB,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,SAAS,GAAG,UAAU,CAAA;CACjC,CAAA;AAYD,wFAAwF;AACxF,eAAO,MAAM,mBAAmB,GAAI,YAAY,MAAM,EAAE,UAAU,MAAM,KAAG,IACgC,CAAA;AAE3G,qEAAqE;AACrE,eAAO,MAAM,0BAA0B,GAAI,YAAY,MAAM,EAAE,UAAU,MAAM,KAAG,IACP,CAAA;AAE3E,8DAA8D;AAC9D,eAAO,MAAM,kBAAkB,GAAI,UAAU,MAAM,KAAG,IAC+B,CAAA;AAErF,eAAO,MAAM,aAAa,GAAI,KAAK,MAAM,CAAC,UAAU,KAAG,MAAM,GAAG,IAM/D,CAAA;AAED,4FAA4F;AAC5F,eAAO,MAAM,aAAa,GACxB,MAAM,MAAM,EACZ,KAAK,IAAI,EACT,MAAM,MAAM,EACZ,MAAM,MAAM,KACX,OAAO,CAAC,MAAM,CAwBhB,CAAA;AAgFD,qGAAqG;AACrG,eAAO,MAAM,kBAAkB,QAAqB,CAAA;AACpD,wEAAwE;AACxE,eAAO,MAAM,WAAW,IAAI,CAAA;AAE5B;;;;GAIG;AACH,eAAO,MAAM,0BAA0B,QAAgB,CAAA;AACvD,0EAA0E;AAC1E,eAAO,MAAM,8BAA8B,QAAY,CAAA;AAEvD;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,GAAI,KAAK,MAAM,CAAC,UAAU,KAAG,MAOhE,CAAA;AAMD;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,GAC7B,YAAY,MAAM,EAClB,UAAS;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAA;CAAM,KAC/D,OAAO,CAAC,WAAW,GAAG,IAAI,CA6C5B,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,GAChC,MAAM,MAAM,EACZ,KAAK,IAAI,EACT,mBAAmB,MAAM,KACxB,OAAO,CAAC,MAAM,CAmBhB,CAAA;AAED,eAAO,MAAM,WAAW,GAAU,UAAS,kBAAuB,KAAG,OAAO,CAAC,iBAAiB,CAwG7F,CAAA"}
|
package/dist/hooks/save.js
CHANGED
|
@@ -162,7 +162,24 @@ export const SWEEP_LIMIT = 3;
|
|
|
162
162
|
* stay open for days and rarely reach SessionEnd, so without this they would
|
|
163
163
|
* only be uploaded once abandoned (ABANDONED_AFTER_MS quiet, then a new session).
|
|
164
164
|
*/
|
|
165
|
-
export const WORKING_UPLOAD_INTERVAL_MS =
|
|
165
|
+
export const WORKING_UPLOAD_INTERVAL_MS = 8 * 60 * 1000;
|
|
166
|
+
/** The shortest interval ASSETHUB_SESSION_UPLOAD_INTERVAL_MIN may set. */
|
|
167
|
+
export const MIN_WORKING_UPLOAD_INTERVAL_MS = 60 * 1000;
|
|
168
|
+
/**
|
|
169
|
+
* ASSETHUB_SESSION_UPLOAD_INTERVAL_MIN, in minutes, else WORKING_UPLOAD_INTERVAL_MS.
|
|
170
|
+
* Each upload sends a new snapshot of the whole transcript, so it is never
|
|
171
|
+
* shorter than a minute; a value that is not a positive number is ignored.
|
|
172
|
+
*/
|
|
173
|
+
export const workingUploadIntervalMs = (env) => {
|
|
174
|
+
const raw = env.ASSETHUB_SESSION_UPLOAD_INTERVAL_MIN?.trim();
|
|
175
|
+
if (!raw)
|
|
176
|
+
return WORKING_UPLOAD_INTERVAL_MS;
|
|
177
|
+
const ms = Number(raw) * 60 * 1000;
|
|
178
|
+
// Finite after scaling too: a huge value would otherwise stop uploads for good.
|
|
179
|
+
if (!Number.isFinite(ms) || ms <= 0)
|
|
180
|
+
return WORKING_UPLOAD_INTERVAL_MS;
|
|
181
|
+
return Math.max(ms, MIN_WORKING_UPLOAD_INTERVAL_MS);
|
|
182
|
+
};
|
|
166
183
|
const WORKING_UPLOAD_EVENTS = new Set(['Stop', 'PreCompact']);
|
|
167
184
|
/** Events that copy and redact the transcript now; the rest only mark it changed. */
|
|
168
185
|
const FULL_SAVE_EVENTS = new Set(['SessionEnd', 'Manual']);
|
|
@@ -323,11 +340,20 @@ export const saveSession = async (options = {}) => {
|
|
|
323
340
|
const result = { sessionDir, event };
|
|
324
341
|
if (uploadOn && options.startWorkingUpload && WORKING_UPLOAD_EVENTS.has(event)) {
|
|
325
342
|
const latest = await readMeta(sessionDir);
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
343
|
+
const interval = workingUploadIntervalMs(env);
|
|
344
|
+
let claimed = false;
|
|
345
|
+
// Checked and stamped under the meta lock, before spawning, so neither the
|
|
346
|
+
// next few turns nor a hook running beside this one start another.
|
|
347
|
+
if (latest)
|
|
348
|
+
await updateMeta(sessionDir, latest, current => {
|
|
349
|
+
// Counts uploads any path started (an earlier Stop, SessionEnd, a sweep).
|
|
350
|
+
const lastStart = Math.max(Date.parse(current.lastWorkingUploadAt ?? '') || 0, Date.parse(current.lastUploadAttemptAt ?? '') || 0);
|
|
351
|
+
if (now.getTime() - lastStart < interval)
|
|
352
|
+
return current;
|
|
353
|
+
claimed = true;
|
|
354
|
+
return { ...current, lastWorkingUploadAt: now.toISOString() };
|
|
355
|
+
});
|
|
356
|
+
if (claimed) {
|
|
331
357
|
options.startWorkingUpload(sessionDir, options.upload?.profile);
|
|
332
358
|
result.uploadStarted = true;
|
|
333
359
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -24,7 +24,7 @@ type CommandContext = {
|
|
|
24
24
|
*/
|
|
25
25
|
args: string[];
|
|
26
26
|
};
|
|
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] [--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] [--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";
|
|
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
28
|
export declare const commandSetup: (flags: Flags, installHooks?: InstallHooks, overrides?: {
|
|
29
29
|
skip?: SetupStepName[];
|
|
30
30
|
}) => Promise<void>;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAgBA,OAAO,EAYL,KAAK,aAAa,EACnB,MAAM,mBAAmB,CAAA;AAE1B,OAAO,EAAsB,KAAK,YAAY,EAAC,MAAM,uBAAuB,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -8,6 +8,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,9 +223,9 @@ 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 [--agent claude-code|codex|cursor...] [--project] [--only <step,...>] [--skip <step,...>] [--no-skills] [--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 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)
|
|
228
229
|
assethub doctor [--mcp] [--setup [--agent <name>...] [--project]] [--profile <name>] [--timeout-ms <n>]
|
|
229
230
|
assethub mcp tools [tool-name] [--account] [--profile <name>] [--timeout-ms <n>]
|
|
230
231
|
assethub mcp config --client cursor|codex [--account] [--base-url <url>]
|
|
@@ -1925,7 +1926,7 @@ const parseSetupSelection = (flags) => {
|
|
|
1925
1926
|
const known = (name, values) => {
|
|
1926
1927
|
const unknown = values.filter(value => !SETUP_STEPS.includes(value));
|
|
1927
1928
|
if (unknown.length > 0)
|
|
1928
|
-
throw new Error(`Unknown setup step for --${name}: ${unknown.join(', ')}. Steps: login, workspace, mcp, skills, app-env, doctor.`);
|
|
1929
|
+
throw new Error(`Unknown setup step for --${name}: ${unknown.join(', ')}. Steps: login, workspace, mcp, skills, auto-update, app-env, doctor.`);
|
|
1929
1930
|
return values;
|
|
1930
1931
|
};
|
|
1931
1932
|
const only = known('only', stepValues('only'));
|
|
@@ -1973,6 +1974,7 @@ const setupRun = async (flags, installHooks, overrides = {}) => {
|
|
|
1973
1974
|
apiKeySource: flagKey ? 'flag' : envKey ? 'env' : undefined,
|
|
1974
1975
|
noHook: hasFlag(flags, 'no-hook'),
|
|
1975
1976
|
noAppEnv: hasFlag(flags, 'no-app-env'),
|
|
1977
|
+
...(hasFlag(flags, 'no-auto-update') ? { autoUpdate: false } : hasFlag(flags, 'auto-update') ? { autoUpdate: true } : {}),
|
|
1976
1978
|
saveSessions: hasFlag(flags, 'save-sessions'),
|
|
1977
1979
|
dryRun: overrides.dryRun ?? hasFlag(flags, 'dry-run'),
|
|
1978
1980
|
yes: hasFlag(flags, 'yes'),
|
|
@@ -2012,6 +2014,10 @@ const setupRun = async (flags, installHooks, overrides = {}) => {
|
|
|
2012
2014
|
return commandAuth('login', loginFlags);
|
|
2013
2015
|
}),
|
|
2014
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),
|
|
2015
2021
|
resolveAuth: async () => {
|
|
2016
2022
|
const auth = await resolveAuth(base);
|
|
2017
2023
|
return { apiKey: auth.apiKey, baseUrl: auth.baseUrl, profile: auth.profile, workspaceId: auth.workspaceId };
|
|
@@ -2066,7 +2072,7 @@ export const commandSetup = async (flags, installHooks = defaultInstallHooks, ov
|
|
|
2066
2072
|
*/
|
|
2067
2073
|
const setupCheck = async (flags) => {
|
|
2068
2074
|
const { options, deps } = await setupRun(flags, installSessionHooks, {
|
|
2069
|
-
skip: ['login', 'workspace', 'app-env', 'hook', 'doctor'],
|
|
2075
|
+
skip: ['login', 'workspace', 'auto-update', 'app-env', 'hook', 'doctor'],
|
|
2070
2076
|
dryRun: true,
|
|
2071
2077
|
quietLog: true,
|
|
2072
2078
|
});
|
|
@@ -5649,6 +5655,33 @@ const resolveMcpTarget = async (flags) => {
|
|
|
5649
5655
|
(stored && new URL(baseUrl).origin === new URL(stored.baseUrl).origin ? stored.workspaceId : undefined);
|
|
5650
5656
|
return { baseUrl, workspaceId };
|
|
5651
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
|
+
};
|
|
5652
5685
|
const run = async () => {
|
|
5653
5686
|
const parsed = parseArgs(argv.slice(2));
|
|
5654
5687
|
if (hasFlag(parsed.flags, 'version')) {
|
|
@@ -5662,13 +5695,15 @@ const run = async () => {
|
|
|
5662
5695
|
const [command, subcommand] = parsed.positionals;
|
|
5663
5696
|
if (command !== 'init')
|
|
5664
5697
|
await syncInstalledSkill();
|
|
5698
|
+
if (!['update', 'hooks', 'env'].includes(command ?? ''))
|
|
5699
|
+
await noticeUpdate(parsed.flags);
|
|
5665
5700
|
if (command === 'init') {
|
|
5666
5701
|
if (subcommand)
|
|
5667
5702
|
throw new Error(`Use init [--agent ${AGENT_IDS.join('|')}] [--project] [--dry-run]`);
|
|
5668
5703
|
// Kept for existing scripts: agent wiring only, as before, through setup's steps.
|
|
5669
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');
|
|
5670
5705
|
await commandSetup({ ...parsed.flags, json: true, yes: true }, installSessionHooks, {
|
|
5671
|
-
skip: ['login', 'workspace', 'app-env', 'hook', 'doctor'],
|
|
5706
|
+
skip: ['login', 'workspace', 'auto-update', 'app-env', 'hook', 'doctor'],
|
|
5672
5707
|
});
|
|
5673
5708
|
return;
|
|
5674
5709
|
}
|
|
@@ -5735,13 +5770,36 @@ const run = async () => {
|
|
|
5735
5770
|
return;
|
|
5736
5771
|
}
|
|
5737
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
|
+
}
|
|
5738
5786
|
// The verifying doctor checks the same login this command was given.
|
|
5739
5787
|
const forwardFlags = ['profile', 'config', 'base-url', 'workspace'].flatMap(name => {
|
|
5740
5788
|
const value = getFlag(parsed.flags, name);
|
|
5741
5789
|
return value ? [`--${name}`, value] : [];
|
|
5742
5790
|
});
|
|
5743
5791
|
const apiKey = getFlag(parsed.flags, 'api-key');
|
|
5744
|
-
|
|
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);
|
|
5745
5803
|
return;
|
|
5746
5804
|
}
|
|
5747
5805
|
if (command === 'doctor') {
|
package/dist/setupCommand.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ export type SetupStep = {
|
|
|
12
12
|
/** The config file or folder the step reads and writes. */
|
|
13
13
|
path?: string;
|
|
14
14
|
};
|
|
15
|
-
export declare const SETUP_STEPS: readonly ["login", "workspace", "mcp", "skills", "app-env", "hook", "doctor"];
|
|
15
|
+
export declare const SETUP_STEPS: readonly ["login", "workspace", "mcp", "skills", "auto-update", "app-env", "hook", "doctor"];
|
|
16
16
|
export type SetupStepName = (typeof SETUP_STEPS)[number];
|
|
17
17
|
export type SetupResult = {
|
|
18
18
|
ok: boolean;
|
|
@@ -47,6 +47,8 @@ export type SetupOptions = {
|
|
|
47
47
|
noHook: boolean;
|
|
48
48
|
/** `--no-app-env`: leave launchd alone even on macOS. */
|
|
49
49
|
noAppEnv?: boolean;
|
|
50
|
+
/** `--auto-update` / `--no-auto-update`: save that choice; undefined keeps the saved one (default on). */
|
|
51
|
+
autoUpdate?: boolean;
|
|
50
52
|
/** Explicit consent to record and upload agent sessions (`--save-sessions`). */
|
|
51
53
|
saveSessions: boolean;
|
|
52
54
|
dryRun: boolean;
|
|
@@ -121,6 +123,13 @@ export type SetupDeps = {
|
|
|
121
123
|
home: string;
|
|
122
124
|
/** argv the macOS LaunchAgent runs at login: node, this CLI, `env load --profile <name>`. */
|
|
123
125
|
launchAgentProgram: string[];
|
|
126
|
+
/** The saved auto-update choice (undefined: never set, which means on). */
|
|
127
|
+
readAutoUpdate: () => Promise<boolean | undefined>;
|
|
128
|
+
writeAutoUpdate: (on: boolean) => Promise<void>;
|
|
129
|
+
/** Whether this CLI is an installed package `assethub update` can upgrade (not npx or a source checkout). */
|
|
130
|
+
canSelfUpdate: () => Promise<boolean>;
|
|
131
|
+
/** ASSETHUB_NO_AUTO_UPDATE, ASSETHUB_NO_UPDATE_CHECK or CI turn it off for this environment. */
|
|
132
|
+
autoUpdateBlockedByEnv: boolean;
|
|
124
133
|
};
|
|
125
134
|
export declare const redactKey: (key: string) => string;
|
|
126
135
|
export declare const mergeCodexSection: (existing: string, section: string) => string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setupCommand.d.ts","sourceRoot":"","sources":["../src/setupCommand.ts"],"names":[],"mappings":"AAIA,OAAO,EAAC,WAAW,EAAwE,MAAM,aAAa,CAAA;AAE9G,OAAO,EAQL,KAAK,OAAO,EACZ,KAAK,YAAY,EAClB,MAAM,iBAAiB,CAAA;AAGxB,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,uBAAuB,CAAA;AAEvD,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,CAAA;AAC/C,4FAA4F;AAC5F,MAAM,MAAM,UAAU,GAAG,WAAW,GAAG,SAAS,GAAG,cAAc,CAAA;AACjE,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,UAAU,CAAA;IAClB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,UAAU,CAAA;IACnB,2DAA2D;IAC3D,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,CAAA;AAID,eAAO,MAAM,WAAW
|
|
1
|
+
{"version":3,"file":"setupCommand.d.ts","sourceRoot":"","sources":["../src/setupCommand.ts"],"names":[],"mappings":"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"}
|
package/dist/setupCommand.js
CHANGED
|
@@ -8,7 +8,7 @@ import { agentSpec, cliHome, detectAgents, installAgentSkills, mcpServerEntry, m
|
|
|
8
8
|
import { cliVersion, mcpConfig, validatedBaseUrl } from './setup.js';
|
|
9
9
|
// The steps `--only` and `--skip` name, in the order setup runs them. `agents`
|
|
10
10
|
// is not one: the mcp and skills steps need it.
|
|
11
|
-
export const SETUP_STEPS = ['login', 'workspace', 'mcp', 'skills', 'app-env', 'hook', 'doctor'];
|
|
11
|
+
export const SETUP_STEPS = ['login', 'workspace', 'mcp', 'skills', 'auto-update', 'app-env', 'hook', 'doctor'];
|
|
12
12
|
export const redactKey = (key) => `ah_…${key.slice(-4)}`;
|
|
13
13
|
const scrub = (text, key) => key ? text.split(key).join(redactKey(key)) : text;
|
|
14
14
|
const TOML_HEADER = /^\s*\[\[?\s*([^\]]+?)\s*\]\]?\s*(#.*)?$/;
|
|
@@ -441,6 +441,15 @@ export const runSetup = async (options, deps) => {
|
|
|
441
441
|
steps.push({ name: 'skills', status: 'fail', detail: error instanceof Error ? error.message : String(error) });
|
|
442
442
|
}
|
|
443
443
|
}
|
|
444
|
+
// 4b. Auto-update: on by default; shown so nobody is surprised by it.
|
|
445
|
+
if (!skipped('auto-update')) {
|
|
446
|
+
try {
|
|
447
|
+
steps.push(await autoUpdateStep(options, deps));
|
|
448
|
+
}
|
|
449
|
+
catch (error) {
|
|
450
|
+
steps.push({ name: 'auto-update', status: 'fail', detail: error instanceof Error ? error.message : String(error) });
|
|
451
|
+
}
|
|
452
|
+
}
|
|
444
453
|
// 5. Make the key visible to apps started outside a shell (macOS).
|
|
445
454
|
const appEnv = skipped('app-env') ? undefined : await ensureAppEnv(options, deps, key);
|
|
446
455
|
if (appEnv)
|
|
@@ -567,6 +576,26 @@ export const runSetup = async (options, deps) => {
|
|
|
567
576
|
...(exportLine ? { exportLine } : {}),
|
|
568
577
|
};
|
|
569
578
|
};
|
|
579
|
+
const autoUpdateStep = async (options, deps) => {
|
|
580
|
+
const name = 'auto-update';
|
|
581
|
+
const saved = await deps.readAutoUpdate();
|
|
582
|
+
const wanted = options.autoUpdate ?? saved ?? true;
|
|
583
|
+
const changes = options.autoUpdate !== undefined && options.autoUpdate !== (saved ?? true);
|
|
584
|
+
const onText = 'on: once a day a newer CLI installs itself in the background, keeping your login (turn off: `assethub setup --no-auto-update`)';
|
|
585
|
+
const offText = 'off: run `assethub update` yourself (turn on: `assethub setup --auto-update`)';
|
|
586
|
+
if (changes && options.dryRun)
|
|
587
|
+
return { name, status: 'skip', detail: `would turn auto-update ${wanted ? 'on' : 'off'} (dry run)`, change: 'would-update' };
|
|
588
|
+
if (options.autoUpdate !== undefined && options.autoUpdate !== saved)
|
|
589
|
+
await deps.writeAutoUpdate(options.autoUpdate);
|
|
590
|
+
const change = changes ? 'updated' : 'unchanged';
|
|
591
|
+
if (!wanted)
|
|
592
|
+
return { name, status: 'ok', detail: offText, change };
|
|
593
|
+
if (!(await deps.canSelfUpdate()))
|
|
594
|
+
return { name, status: 'skip', detail: 'this CLI is not a global install (npx or a source checkout), so it cannot update itself', change };
|
|
595
|
+
if (deps.autoUpdateBlockedByEnv)
|
|
596
|
+
return { name, status: 'skip', detail: 'on, but ASSETHUB_NO_AUTO_UPDATE, ASSETHUB_NO_UPDATE_CHECK or CI turns it off in this environment', change };
|
|
597
|
+
return { name, status: 'ok', detail: onText, change };
|
|
598
|
+
};
|
|
570
599
|
const skillsStep = (report, dryRun) => {
|
|
571
600
|
const changedLinks = report.links.filter(link => link.status === 'linked' || link.status === 'relinked');
|
|
572
601
|
const keptLinks = report.links.filter(link => link.status === 'kept-existing');
|
|
@@ -575,7 +604,9 @@ const skillsStep = (report, dryRun) => {
|
|
|
575
604
|
const parts = [
|
|
576
605
|
report.status === 'kept-existing'
|
|
577
606
|
? `kept ${report.path} (not created by AssetHub)`
|
|
578
|
-
:
|
|
607
|
+
: report.status === 'kept-newer'
|
|
608
|
+
? `kept ${report.path} (${report.version}, newer than this CLI)`
|
|
609
|
+
: `${dryRun && copyChanged ? `would ${report.status === 'installed' ? 'install' : 'update'}` : report.status} ${report.path}${report.version ? ` (${report.version})` : ''}`,
|
|
579
610
|
...(changedLinks.length > 0
|
|
580
611
|
? [`${dryRun ? 'would link' : 'linked'} into ${listJoin(changedLinks.map(link => agentSpec(link.agent).name))}`]
|
|
581
612
|
: []),
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { type UpdateDeps } from './update.js';
|
|
2
|
+
export declare const CHECK_INTERVAL_MS: number;
|
|
3
|
+
export declare const REFRESH_CHILD_ENV = "ASSETHUB_UPDATE_REFRESH_CHILD";
|
|
4
|
+
/** What the last background install did; announced once, then marked. */
|
|
5
|
+
export type AutoUpdateResult = {
|
|
6
|
+
from: string;
|
|
7
|
+
to: string;
|
|
8
|
+
at: string;
|
|
9
|
+
announced?: boolean;
|
|
10
|
+
} | {
|
|
11
|
+
from: string;
|
|
12
|
+
error: string;
|
|
13
|
+
at: string;
|
|
14
|
+
announced?: boolean;
|
|
15
|
+
};
|
|
16
|
+
export type UpdateCheckCache = {
|
|
17
|
+
checkedAt: string;
|
|
18
|
+
latest: string;
|
|
19
|
+
autoUpdate?: AutoUpdateResult;
|
|
20
|
+
/** When the `is available` line was last shown: at most once a day. */
|
|
21
|
+
noticedAt?: string;
|
|
22
|
+
};
|
|
23
|
+
export declare const updateCheckPath: (configPath: string) => string;
|
|
24
|
+
export declare const readUpdateCheck: (path: string) => Promise<UpdateCheckCache | undefined>;
|
|
25
|
+
export declare const writeUpdateCheck: (path: string, latest: string, now?: Date, autoUpdate?: AutoUpdateResult) => Promise<void>;
|
|
26
|
+
/** Rewrites the cache with some fields changed (announcement bookkeeping by the foreground command). */
|
|
27
|
+
export declare const patchUpdateCheck: (path: string, cache: UpdateCheckCache, patch: Partial<UpdateCheckCache>) => Promise<void>;
|
|
28
|
+
export declare const ATTEMPT_INTERVAL_MS: number;
|
|
29
|
+
export declare const attemptPath: (cachePath: string) => string;
|
|
30
|
+
/** Whether a refresh was started recently enough not to start another; records this attempt when not. */
|
|
31
|
+
export declare const claimRefreshAttempt: (cachePath: string, now?: Date) => Promise<boolean>;
|
|
32
|
+
export declare const settingsPath: (configPath: string) => string;
|
|
33
|
+
/** The saved choice: true or false, or undefined when never set (which means on). */
|
|
34
|
+
export declare const readAutoUpdateSetting: (path: string) => Promise<boolean | undefined>;
|
|
35
|
+
export declare const writeAutoUpdateSetting: (path: string, autoUpdate: boolean) => Promise<void>;
|
|
36
|
+
/** Auto-update is on by default; the saved setting or ASSETHUB_NO_AUTO_UPDATE turns it off. */
|
|
37
|
+
export declare const autoUpdateEnabled: (setting: boolean | undefined, env: NodeJS.ProcessEnv) => boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Only a global install can be upgraded by `assethub update`: a project
|
|
40
|
+
* dependency, an npx run or a source checkout has nothing to announce. Same
|
|
41
|
+
* layouts as update.ts's detectInstall, without running `npm root --global`
|
|
42
|
+
* on every command.
|
|
43
|
+
*/
|
|
44
|
+
export declare const isInstalledPackage: (cliPath: string) => boolean;
|
|
45
|
+
/** Opted out, or running somewhere nobody reads a hint (CI). */
|
|
46
|
+
export declare const updateCheckDisabled: (env: NodeJS.ProcessEnv) => boolean;
|
|
47
|
+
export type NoticeDecision = {
|
|
48
|
+
notices: string[];
|
|
49
|
+
refresh: boolean;
|
|
50
|
+
markAnnounced: boolean;
|
|
51
|
+
markNoticed: boolean;
|
|
52
|
+
};
|
|
53
|
+
/** What to print now, whether to mark a background install as announced, and whether to refresh. */
|
|
54
|
+
export declare const decideUpdateNotice: (current: string, cache: UpdateCheckCache | undefined, now: Date) => NoticeDecision;
|
|
55
|
+
/** One install at a time, background or `assethub update`: a second one leaves it alone. */
|
|
56
|
+
export declare const takeLock: (path: string) => Promise<boolean>;
|
|
57
|
+
/**
|
|
58
|
+
* Reads the latest version and, when auto-update is on and it is newer,
|
|
59
|
+
* installs it through `runUpdate` (same installer, same login check as
|
|
60
|
+
* `assethub update --yes`). Records the outcome for the next command to announce.
|
|
61
|
+
*/
|
|
62
|
+
export declare const refreshUpdateCheck: (input: {
|
|
63
|
+
cachePath: string;
|
|
64
|
+
lockPath: string;
|
|
65
|
+
autoUpdate: boolean;
|
|
66
|
+
deps: UpdateDeps;
|
|
67
|
+
now?: () => Date;
|
|
68
|
+
}) => Promise<UpdateCheckCache | undefined>;
|
|
69
|
+
/** Starts the background refresh and returns at once; the child outlives this process. */
|
|
70
|
+
export declare const refreshInBackground: (node: string, cli: string, configPath: string) => void;
|
|
71
|
+
//# sourceMappingURL=updateNotice.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"updateNotice.d.ts","sourceRoot":"","sources":["../src/updateNotice.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
// Keeping the CLI current. Once a day a detached `assethub update --refresh-check`
|
|
2
|
+
// process reads the latest version and, with auto-update on (the default),
|
|
3
|
+
// installs it the way `assethub update` would. No command ever waits on the
|
|
4
|
+
// network or the install: each one only reads the small cache file the
|
|
5
|
+
// background process leaves behind, announces what happened once, and moves on.
|
|
6
|
+
import { spawn } from 'node:child_process';
|
|
7
|
+
import { mkdir, open, readFile, rm, stat, writeFile } from 'node:fs/promises';
|
|
8
|
+
import { dirname, join } from 'node:path';
|
|
9
|
+
import { compareVersions, PACKAGE_NAME, runUpdate } from './update.js';
|
|
10
|
+
export const CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
11
|
+
export const REFRESH_CHILD_ENV = 'ASSETHUB_UPDATE_REFRESH_CHILD';
|
|
12
|
+
export const updateCheckPath = (configPath) => join(dirname(configPath), 'update-check.json');
|
|
13
|
+
export const readUpdateCheck = async (path) => {
|
|
14
|
+
try {
|
|
15
|
+
const cache = JSON.parse(await readFile(path, 'utf8'));
|
|
16
|
+
return typeof cache.checkedAt === 'string' && typeof cache.latest === 'string'
|
|
17
|
+
? {
|
|
18
|
+
checkedAt: cache.checkedAt,
|
|
19
|
+
latest: cache.latest,
|
|
20
|
+
...(cache.autoUpdate && typeof cache.autoUpdate === 'object' ? { autoUpdate: cache.autoUpdate } : {}),
|
|
21
|
+
...(typeof cache.noticedAt === 'string' ? { noticedAt: cache.noticedAt } : {}),
|
|
22
|
+
}
|
|
23
|
+
: undefined;
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
export const writeUpdateCheck = async (path, latest, now = new Date(), autoUpdate) => {
|
|
30
|
+
await mkdir(dirname(path), { recursive: true });
|
|
31
|
+
const cache = { checkedAt: now.toISOString(), latest, ...(autoUpdate ? { autoUpdate } : {}) };
|
|
32
|
+
await writeFile(path, `${JSON.stringify(cache)}\n`);
|
|
33
|
+
};
|
|
34
|
+
/** Rewrites the cache with some fields changed (announcement bookkeeping by the foreground command). */
|
|
35
|
+
export const patchUpdateCheck = async (path, cache, patch) => {
|
|
36
|
+
await writeFile(path, `${JSON.stringify({ ...cache, ...patch })}\n`);
|
|
37
|
+
};
|
|
38
|
+
// A failed or slow refresh leaves the cache stale; this marker keeps every
|
|
39
|
+
// command from starting another one. Retried at most once an hour.
|
|
40
|
+
export const ATTEMPT_INTERVAL_MS = 60 * 60 * 1000;
|
|
41
|
+
export const attemptPath = (cachePath) => `${cachePath}.attempt`;
|
|
42
|
+
/** Whether a refresh was started recently enough not to start another; records this attempt when not. */
|
|
43
|
+
export const claimRefreshAttempt = async (cachePath, now = new Date()) => {
|
|
44
|
+
const path = attemptPath(cachePath);
|
|
45
|
+
const last = await readFile(path, 'utf8').then(text => Date.parse(text.trim()), () => Number.NaN);
|
|
46
|
+
if (Number.isFinite(last) && now.getTime() - last < ATTEMPT_INTERVAL_MS && last <= now.getTime())
|
|
47
|
+
return false;
|
|
48
|
+
await mkdir(dirname(path), { recursive: true });
|
|
49
|
+
await writeFile(path, `${now.toISOString()}\n`);
|
|
50
|
+
return true;
|
|
51
|
+
};
|
|
52
|
+
// ---- the auto-update setting (on unless turned off) ----
|
|
53
|
+
export const settingsPath = (configPath) => join(dirname(configPath), 'settings.json');
|
|
54
|
+
/** The saved choice: true or false, or undefined when never set (which means on). */
|
|
55
|
+
export const readAutoUpdateSetting = async (path) => {
|
|
56
|
+
try {
|
|
57
|
+
const value = JSON.parse(await readFile(path, 'utf8')).autoUpdate;
|
|
58
|
+
return typeof value === 'boolean' ? value : undefined;
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
export const writeAutoUpdateSetting = async (path, autoUpdate) => {
|
|
65
|
+
let settings = {};
|
|
66
|
+
try {
|
|
67
|
+
const parsed = JSON.parse(await readFile(path, 'utf8'));
|
|
68
|
+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed))
|
|
69
|
+
settings = parsed;
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
// missing or unreadable: start fresh
|
|
73
|
+
}
|
|
74
|
+
await mkdir(dirname(path), { recursive: true });
|
|
75
|
+
await writeFile(path, `${JSON.stringify({ ...settings, autoUpdate }, null, 2)}\n`);
|
|
76
|
+
};
|
|
77
|
+
const truthy = (value) => ['1', 'true', 'yes'].includes((value ?? '').toLowerCase());
|
|
78
|
+
/** Auto-update is on by default; the saved setting or ASSETHUB_NO_AUTO_UPDATE turns it off. */
|
|
79
|
+
export const autoUpdateEnabled = (setting, env) => setting !== false && !truthy(env.ASSETHUB_NO_AUTO_UPDATE) && !updateCheckDisabled(env);
|
|
80
|
+
/**
|
|
81
|
+
* Only a global install can be upgraded by `assethub update`: a project
|
|
82
|
+
* dependency, an npx run or a source checkout has nothing to announce. Same
|
|
83
|
+
* layouts as update.ts's detectInstall, without running `npm root --global`
|
|
84
|
+
* on every command.
|
|
85
|
+
*/
|
|
86
|
+
export const isInstalledPackage = (cliPath) => {
|
|
87
|
+
const path = cliPath.replaceAll('\\', '/');
|
|
88
|
+
if (!path.includes(`/node_modules/${PACKAGE_NAME}/`) || path.includes('/_npx/'))
|
|
89
|
+
return false;
|
|
90
|
+
return [
|
|
91
|
+
`/lib/node_modules/${PACKAGE_NAME}/`, // npm, nvm, Homebrew node, a custom npm prefix
|
|
92
|
+
`/npm/node_modules/${PACKAGE_NAME}/`, // npm on Windows (%AppData%/npm)
|
|
93
|
+
'/.volta/',
|
|
94
|
+
'/.bun/install/global/',
|
|
95
|
+
'/pnpm/global/',
|
|
96
|
+
'/yarn/global/',
|
|
97
|
+
].some(segment => path.includes(segment));
|
|
98
|
+
};
|
|
99
|
+
/** Opted out, or running somewhere nobody reads a hint (CI). */
|
|
100
|
+
export const updateCheckDisabled = (env) => truthy(env.ASSETHUB_NO_UPDATE_CHECK) || Boolean(env.CI);
|
|
101
|
+
const TURN_OFF = 'turn off with `assethub setup --no-auto-update`';
|
|
102
|
+
/** What to print now, whether to mark a background install as announced, and whether to refresh. */
|
|
103
|
+
export const decideUpdateNotice = (current, cache, now) => {
|
|
104
|
+
const checked = cache ? Date.parse(cache.checkedAt) : Number.NaN;
|
|
105
|
+
const refresh = !Number.isFinite(checked) || now.getTime() - checked >= CHECK_INTERVAL_MS || checked > now.getTime();
|
|
106
|
+
const notices = [];
|
|
107
|
+
const result = cache?.autoUpdate;
|
|
108
|
+
const announce = result !== undefined && !result.announced;
|
|
109
|
+
if (announce && 'to' in result && result.to === current)
|
|
110
|
+
notices.push(`${PACKAGE_NAME} updated itself from ${result.from} to ${result.to} (auto-update; ${TURN_OFF}).`);
|
|
111
|
+
if (announce && 'error' in result)
|
|
112
|
+
notices.push(`${PACKAGE_NAME} could not update itself to ${cache?.latest}: ${result.error}`);
|
|
113
|
+
const noticed = cache?.noticedAt ? Date.parse(cache.noticedAt) : Number.NaN;
|
|
114
|
+
const noticeDue = !Number.isFinite(noticed) || now.getTime() - noticed >= CHECK_INTERVAL_MS || noticed > now.getTime();
|
|
115
|
+
// A failed install is reported together with the release it could not install.
|
|
116
|
+
const available = cache !== undefined && compareVersions(cache.latest, current) > 0 && (noticeDue || (announce && 'error' in result));
|
|
117
|
+
if (available)
|
|
118
|
+
notices.push(`${PACKAGE_NAME} ${cache.latest} is available (you have ${current}). Run \`assethub update\` to upgrade; your login is kept.`);
|
|
119
|
+
return { notices, refresh, markAnnounced: announce, markNoticed: available };
|
|
120
|
+
};
|
|
121
|
+
// ---- the background refresh ----
|
|
122
|
+
const LOCK_STALE_MS = 15 * 60 * 1000;
|
|
123
|
+
/** One install at a time, background or `assethub update`: a second one leaves it alone. */
|
|
124
|
+
export const takeLock = async (path) => {
|
|
125
|
+
await mkdir(dirname(path), { recursive: true });
|
|
126
|
+
try {
|
|
127
|
+
await (await open(path, 'wx')).close();
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
const age = await stat(path).then(info => Date.now() - info.mtimeMs, () => 0);
|
|
132
|
+
if (age < LOCK_STALE_MS)
|
|
133
|
+
return false;
|
|
134
|
+
await rm(path, { force: true });
|
|
135
|
+
try {
|
|
136
|
+
await (await open(path, 'wx')).close();
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
/**
|
|
145
|
+
* Reads the latest version and, when auto-update is on and it is newer,
|
|
146
|
+
* installs it through `runUpdate` (same installer, same login check as
|
|
147
|
+
* `assethub update --yes`). Records the outcome for the next command to announce.
|
|
148
|
+
*/
|
|
149
|
+
export const refreshUpdateCheck = async (input) => {
|
|
150
|
+
const now = input.now ?? (() => new Date());
|
|
151
|
+
if (!(await takeLock(input.lockPath)))
|
|
152
|
+
return undefined;
|
|
153
|
+
try {
|
|
154
|
+
const [current, latest] = await Promise.all([input.deps.currentVersion(), input.deps.latestVersion()]);
|
|
155
|
+
let autoUpdate;
|
|
156
|
+
if (input.autoUpdate && compareVersions(latest, current) > 0) {
|
|
157
|
+
try {
|
|
158
|
+
const report = await runUpdate({ yes: true }, { ...input.deps, latestVersion: async () => latest, interactive: false });
|
|
159
|
+
if (report.status === 'updated')
|
|
160
|
+
autoUpdate = { from: report.from, to: report.to, at: now().toISOString() };
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
163
|
+
autoUpdate = { from: current, error: error instanceof Error ? error.message : String(error), at: now().toISOString() };
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
await writeUpdateCheck(input.cachePath, latest, now(), autoUpdate);
|
|
167
|
+
return { checkedAt: now().toISOString(), latest, ...(autoUpdate ? { autoUpdate } : {}) };
|
|
168
|
+
}
|
|
169
|
+
finally {
|
|
170
|
+
await rm(input.lockPath, { force: true });
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
/** Starts the background refresh and returns at once; the child outlives this process. */
|
|
174
|
+
export const refreshInBackground = (node, cli, configPath) => {
|
|
175
|
+
try {
|
|
176
|
+
const child = spawn(node, [cli, 'update', '--refresh-check', '--config', configPath], {
|
|
177
|
+
detached: true,
|
|
178
|
+
stdio: 'ignore',
|
|
179
|
+
// Marks the child (and the `assethub doctor` it runs to verify an install) so it
|
|
180
|
+
// neither prints notices nor starts another refresh.
|
|
181
|
+
env: { ...process.env, [REFRESH_CHILD_ENV]: '1' },
|
|
182
|
+
});
|
|
183
|
+
child.on('error', () => { });
|
|
184
|
+
child.unref();
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
// best effort: a missing hint must never fail the user's command
|
|
188
|
+
}
|
|
189
|
+
};
|
package/package.json
CHANGED
package/skills/assethub/SKILL.md
CHANGED
|
@@ -31,6 +31,23 @@ description: |
|
|
|
31
31
|
|
|
32
32
|
Always in this order. Skipping a step is how credits get wasted.
|
|
33
33
|
|
|
34
|
+
### 0. Make sure the CLI is current (once per session)
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
assethub update --check
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Operations, models and these rules change between releases, and an old CLI can reject flags the server now expects or miss a safety fix. Run this once at the start of a session, before the first paid call. It is free.
|
|
41
|
+
|
|
42
|
+
Auto-update is on by default: once a day the CLI installs a newer release by itself in the background, and the next command says so on stderr (`updated itself from … to …`). So this check usually reports `up_to_date`. It is still needed: auto-update may be off (`assethub setup --no-auto-update`, `ASSETHUB_NO_AUTO_UPDATE=1`, CI), may have failed, or may not have run yet today.
|
|
43
|
+
|
|
44
|
+
- `"status": "up_to_date"`: carry on.
|
|
45
|
+
- `"status": "update_available"`: run `assethub update --yes`. It upgrades the global install with the package manager that installed it and keeps the saved login. Tell the user which version you moved from and to (`from`, `to`). The next `assethub` command refreshes this skill automatically, so re-read it after that command; its rules may have changed.
|
|
46
|
+
- `update` refuses (an `npx` or project-local install, or a source checkout) or fails (no network): continue on the current version and tell the user once. Do not retry it in a loop.
|
|
47
|
+
- Do not update while another `assethub` command is still running (a `--wait` in another terminal). Runs on the server are not affected by an update; resume them afterwards with their `runId`.
|
|
48
|
+
|
|
49
|
+
The CLI also prints a one-line `is available` or `could not update itself` notice on stderr. Treat it the same way. When you see `updated itself`, re-read this skill after that command, as above. Never turn auto-update off for the user.
|
|
50
|
+
|
|
34
51
|
### 1. Check what this key can do
|
|
35
52
|
|
|
36
53
|
```bash
|