@assethub/cli 0.1.30 → 0.1.31

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.
Files changed (70) hide show
  1. package/README.md +282 -8
  2. package/dist/appEnv.d.ts +20 -0
  3. package/dist/appEnv.d.ts.map +1 -0
  4. package/dist/appEnv.js +62 -0
  5. package/dist/canvasGraphDownload.d.ts +11 -0
  6. package/dist/canvasGraphDownload.d.ts.map +1 -0
  7. package/dist/canvasGraphDownload.js +108 -0
  8. package/dist/execution.d.ts +5 -2
  9. package/dist/execution.d.ts.map +1 -1
  10. package/dist/execution.js +11 -12
  11. package/dist/hooks/command.d.ts +14 -0
  12. package/dist/hooks/command.d.ts.map +1 -0
  13. package/dist/hooks/command.js +178 -0
  14. package/dist/hooks/graph.d.ts +40 -0
  15. package/dist/hooks/graph.d.ts.map +1 -0
  16. package/dist/hooks/graph.js +267 -0
  17. package/dist/hooks/index.d.ts +7 -0
  18. package/dist/hooks/index.d.ts.map +1 -0
  19. package/dist/hooks/index.js +6 -0
  20. package/dist/hooks/install.d.ts +43 -0
  21. package/dist/hooks/install.d.ts.map +1 -0
  22. package/dist/hooks/install.js +174 -0
  23. package/dist/hooks/paths.d.ts +31 -0
  24. package/dist/hooks/paths.d.ts.map +1 -0
  25. package/dist/hooks/paths.js +101 -0
  26. package/dist/hooks/redact.d.ts +5 -0
  27. package/dist/hooks/redact.d.ts.map +1 -0
  28. package/dist/hooks/redact.js +67 -0
  29. package/dist/hooks/save.d.ts +60 -0
  30. package/dist/hooks/save.d.ts.map +1 -0
  31. package/dist/hooks/save.js +330 -0
  32. package/dist/hooks/transcript.d.ts +23 -0
  33. package/dist/hooks/transcript.d.ts.map +1 -0
  34. package/dist/hooks/transcript.js +74 -0
  35. package/dist/hooks/trim.d.ts +15 -0
  36. package/dist/hooks/trim.d.ts.map +1 -0
  37. package/dist/hooks/trim.js +108 -0
  38. package/dist/hooks/types.d.ts +56 -0
  39. package/dist/hooks/types.d.ts.map +1 -0
  40. package/dist/hooks/types.js +0 -0
  41. package/dist/hooks/upload.d.ts +52 -0
  42. package/dist/hooks/upload.d.ts.map +1 -0
  43. package/dist/hooks/upload.js +252 -0
  44. package/dist/index.d.ts +12 -2
  45. package/dist/index.d.ts.map +1 -1
  46. package/dist/index.js +1569 -165
  47. package/dist/nodeMeshBatch.d.ts.map +1 -1
  48. package/dist/nodeMeshBatch.js +5 -4
  49. package/dist/productionBatch.d.ts +77 -0
  50. package/dist/productionBatch.d.ts.map +1 -0
  51. package/dist/productionBatch.js +204 -0
  52. package/dist/runProgress.d.ts +4 -0
  53. package/dist/runProgress.d.ts.map +1 -0
  54. package/dist/runProgress.js +16 -0
  55. package/dist/runsUpload/controlEndpoints.d.ts +1 -1
  56. package/dist/runsUpload/controlEndpoints.d.ts.map +1 -1
  57. package/dist/runsUpload/controlEndpoints.js +4 -2
  58. package/dist/runsUpload/uploadRun.d.ts +7 -1
  59. package/dist/runsUpload/uploadRun.d.ts.map +1 -1
  60. package/dist/runsUpload/uploadRun.js +7 -4
  61. package/dist/setupCommand.d.ts +127 -0
  62. package/dist/setupCommand.d.ts.map +1 -0
  63. package/dist/setupCommand.js +534 -0
  64. package/dist/setupHooksBridge.d.ts +8 -0
  65. package/dist/setupHooksBridge.d.ts.map +1 -0
  66. package/dist/setupHooksBridge.js +4 -0
  67. package/dist/update.d.ts +74 -0
  68. package/dist/update.d.ts.map +1 -0
  69. package/dist/update.js +205 -0
  70. package/package.json +2 -2
package/dist/update.js ADDED
@@ -0,0 +1,205 @@
1
+ // `assethub update`: move a global install to the latest published version.
2
+ // It only runs the package manager that installed the CLI; the saved login in
3
+ // ~/.assethub/config.json lives outside the package, so it survives untouched.
4
+ import { execFile, spawn } from 'node:child_process';
5
+ import { realpath } from 'node:fs/promises';
6
+ import { argv, env, platform, stderr, stdin } from 'node:process';
7
+ import { createInterface } from 'node:readline/promises';
8
+ import { promisify } from 'node:util';
9
+ import { cliVersion } from './setup.js';
10
+ const execFileAsync = promisify(execFile);
11
+ export const PACKAGE_NAME = '@assethub/cli';
12
+ const parseVersion = (version) => {
13
+ const [core, prerelease] = version.split('-', 2);
14
+ return { core: core.split('.').map(Number), prerelease };
15
+ };
16
+ /** Semver precedence for plain `x.y.z[-pre]` versions (build metadata unused). */
17
+ export const compareVersions = (a, b) => {
18
+ const left = parseVersion(a);
19
+ const right = parseVersion(b);
20
+ for (let i = 0; i < 3; i++) {
21
+ const diff = (left.core[i] ?? 0) - (right.core[i] ?? 0);
22
+ if (diff !== 0)
23
+ return diff;
24
+ }
25
+ if (left.prerelease === right.prerelease)
26
+ return 0;
27
+ if (left.prerelease === undefined)
28
+ return 1;
29
+ if (right.prerelease === undefined)
30
+ return -1;
31
+ return left.prerelease.localeCompare(right.prerelease, 'en', { numeric: true });
32
+ };
33
+ const packageSegment = `/node_modules/${PACKAGE_NAME}/`;
34
+ export const detectInstall = (binPath, npmGlobalRoot) => {
35
+ const path = binPath.replaceAll('\\', '/');
36
+ if (!path.includes(packageSegment))
37
+ return { kind: 'source' };
38
+ if (path.includes('/_npx/'))
39
+ return { kind: 'npx' };
40
+ if (path.includes('/.volta/'))
41
+ return { kind: 'global', installer: 'volta' };
42
+ if (path.includes('/.bun/install/global/'))
43
+ return { kind: 'global', installer: 'bun' };
44
+ if (path.includes('/pnpm/global/'))
45
+ return { kind: 'global', installer: 'pnpm' };
46
+ if (path.includes('/yarn/global/'))
47
+ return { kind: 'global', installer: 'yarn' };
48
+ const root = npmGlobalRoot?.replaceAll('\\', '/').replace(/\/+$/, '');
49
+ if (root && path.startsWith(`${root}/`))
50
+ return { kind: 'global', installer: 'npm' };
51
+ return { kind: 'project' };
52
+ };
53
+ export const installCommand = (installer, version) => {
54
+ const spec = `${PACKAGE_NAME}@${version}`;
55
+ switch (installer) {
56
+ case 'npm':
57
+ return ['npm', ['install', '--global', spec]];
58
+ case 'pnpm':
59
+ return ['pnpm', ['add', '--global', spec]];
60
+ case 'yarn':
61
+ return ['yarn', ['global', 'add', spec]];
62
+ case 'bun':
63
+ return ['bun', ['add', '--global', spec]];
64
+ case 'volta':
65
+ return ['volta', ['install', spec]];
66
+ }
67
+ };
68
+ const refusal = (install, latest) => {
69
+ switch (install.kind) {
70
+ case 'npx':
71
+ return `This CLI is running from the npx cache; run \`npx ${PACKAGE_NAME}@latest\` to use ${latest}.`;
72
+ case 'project':
73
+ return `This CLI is installed as a project dependency; update ${PACKAGE_NAME} to ${latest} in that project's package.json.`;
74
+ case 'source':
75
+ return 'This CLI is running from a source checkout; pull and rebuild it instead.';
76
+ }
77
+ };
78
+ export const runUpdate = async (options, deps) => {
79
+ const [from, latest] = await Promise.all([deps.currentVersion(), deps.latestVersion()]);
80
+ if (compareVersions(latest, from) <= 0)
81
+ return { status: 'up_to_date', from, latest };
82
+ if (options.check)
83
+ return { status: 'update_available', from, latest };
84
+ const install = detectInstall(await deps.binPath(), await deps.npmGlobalRoot());
85
+ if (install.kind !== 'global')
86
+ throw new Error(refusal(install, latest));
87
+ const [command, args] = installCommand(install.installer, latest);
88
+ const shown = [command, ...args].join(' ');
89
+ if (options.dryRun)
90
+ return { status: 'dry_run', from, latest, installer: install.installer, command: shown };
91
+ if (deps.interactive && !options.yes && !(await deps.confirm(`Update ${PACKAGE_NAME} ${from} -> ${latest} with \`${shown}\`?`)))
92
+ throw new Error('Update cancelled; nothing was changed.');
93
+ deps.say(`Running ${shown}`);
94
+ const { code } = await deps.run(command, args);
95
+ if (code !== 0)
96
+ throw new Error(`\`${shown}\` exited with code ${code}; ${PACKAGE_NAME} is still ${from}.`);
97
+ const installed = await deps.verify();
98
+ if (installed.version !== latest)
99
+ throw new Error(`\`${shown}\` succeeded but \`assethub --version\` still reports ${installed.version}; another ${PACKAGE_NAME} earlier on PATH may be shadowing this install.`);
100
+ if (installed.auth === 'fail')
101
+ deps.say('Updated, but the saved login did not pass its check. Run `assethub doctor` to see why; the update did not change your login.');
102
+ return { status: 'updated', from, to: installed.version, installer: install.installer, auth: installed.auth };
103
+ };
104
+ // Windows installs expose `npm.cmd` / `assethub.cmd`, which need a shell.
105
+ const shell = platform === 'win32';
106
+ const VERSION_PATTERN = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/;
107
+ const validVersion = (version, source) => {
108
+ if (typeof version !== 'string' || !VERSION_PATTERN.test(version))
109
+ throw new Error(`${source} returned an unexpected version: ${JSON.stringify(version)}`);
110
+ return version;
111
+ };
112
+ /**
113
+ * Prefers the package manager, which applies the user's .npmrc registry,
114
+ * auth token and proxy exactly as the install will; falls back to a direct
115
+ * registry read only when that lookup cannot run (e.g. no npm on PATH).
116
+ */
117
+ export const resolveLatestVersion = async (viaPackageManager, viaRegistry) => {
118
+ try {
119
+ return await viaPackageManager();
120
+ }
121
+ catch (npmError) {
122
+ try {
123
+ return await viaRegistry();
124
+ }
125
+ catch (registryError) {
126
+ throw new Error(`Could not read the latest ${PACKAGE_NAME} version. npm view: ${npmError.message}. Registry: ${registryError.message}`);
127
+ }
128
+ }
129
+ };
130
+ const latestViaNpm = async () => {
131
+ const { stdout } = await execFileAsync('npm', ['view', `${PACKAGE_NAME}@latest`, 'version', '--json'], {
132
+ shell,
133
+ timeout: 30_000,
134
+ });
135
+ return validVersion(JSON.parse(stdout), 'npm view');
136
+ };
137
+ const latestViaRegistry = async () => {
138
+ const registry = (env.npm_config_registry || 'https://registry.npmjs.org').replace(/\/+$/, '');
139
+ const url = `${registry}/${PACKAGE_NAME.replace('/', '%2f')}/latest`;
140
+ const response = await fetch(url, { headers: { accept: 'application/json' }, signal: AbortSignal.timeout(15_000) });
141
+ if (!response.ok)
142
+ throw new Error(`${url} answered HTTP ${response.status}`);
143
+ return validVersion((await response.json()).version, url);
144
+ };
145
+ /** Wires runUpdate to the real registry, package manager and freshly installed binary. */
146
+ /**
147
+ * `forwardFlags` reach the verifying `assethub doctor` on its command line;
148
+ * `forwardEnv` carries what must not appear there, such as an explicit API key.
149
+ */
150
+ export const createNodeUpdateDeps = (forwardFlags, forwardEnv = {}) => ({
151
+ currentVersion: cliVersion,
152
+ latestVersion: () => resolveLatestVersion(latestViaNpm, latestViaRegistry),
153
+ binPath: () => realpath(argv[1]),
154
+ npmGlobalRoot: async () => {
155
+ try {
156
+ return (await execFileAsync('npm', ['root', '--global'], { shell })).stdout.trim() || undefined;
157
+ }
158
+ catch {
159
+ return undefined;
160
+ }
161
+ },
162
+ // The installer's output goes to stderr so stdout stays one JSON report.
163
+ run: (command, args) => new Promise(resolve => {
164
+ const child = spawn(command, args, { stdio: ['inherit', 2, 'inherit'], shell });
165
+ child.on('error', () => resolve({ code: 127 }));
166
+ child.on('close', code => resolve({ code: code ?? 1 }));
167
+ }),
168
+ // Run whatever `assethub` the user's PATH now resolves, so a shadowing older
169
+ // install is caught. Doctor reads the same saved profile the old version used.
170
+ verify: async () => {
171
+ let raw;
172
+ try {
173
+ raw = (await execFileAsync('assethub', ['doctor', ...forwardFlags], {
174
+ shell,
175
+ timeout: 60_000,
176
+ env: { ...env, ...forwardEnv },
177
+ })).stdout;
178
+ }
179
+ catch (error) {
180
+ // doctor exits 2 when a check fails but still prints its report.
181
+ raw = error.stdout ?? '';
182
+ if (!raw)
183
+ throw new Error(`Could not run the updated \`assethub doctor\`: ${error.message}`);
184
+ }
185
+ const report = JSON.parse(raw);
186
+ const unconfigured = report.checks?.some(check => check.code === 'AUTH_CONFIGURATION');
187
+ return {
188
+ version: report.version ?? 'unknown',
189
+ auth: unconfigured ? 'not_configured' : report.ok ? 'pass' : 'fail',
190
+ };
191
+ },
192
+ interactive: Boolean(stdin.isTTY && stderr.isTTY),
193
+ confirm: async (question) => {
194
+ const rl = createInterface({ input: stdin, output: stderr });
195
+ try {
196
+ return /^y(es)?$/i.test((await rl.question(`${question} [y/N] `)).trim());
197
+ }
198
+ finally {
199
+ rl.close();
200
+ }
201
+ },
202
+ say: message => {
203
+ stderr.write(`${message}\n`);
204
+ },
205
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@assethub/cli",
3
- "version": "0.1.30",
3
+ "version": "0.1.31",
4
4
  "description": "Command line interface for AssetHub.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -31,7 +31,7 @@
31
31
  "access": "public"
32
32
  },
33
33
  "dependencies": {
34
- "@assethub/api-client": "^0.1.16",
34
+ "@assethub/api-client": "^0.1.17",
35
35
  "@modelcontextprotocol/sdk": "^1.30.0"
36
36
  },
37
37
  "repository": {