@the-open-engine/zeroshot 6.0.1 → 6.0.2
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/cli/index.js +8 -6
- package/cli/lib/update-checker.js +205 -24
- package/package.json +1 -1
package/cli/index.js
CHANGED
|
@@ -67,7 +67,7 @@ const {
|
|
|
67
67
|
registerDetachedSetupCluster,
|
|
68
68
|
} = require('../lib/detached-startup');
|
|
69
69
|
// Setup wizard removed - use: zeroshot settings set <key> <value>
|
|
70
|
-
const { checkForUpdates } = require('./lib/update-checker');
|
|
70
|
+
const { checkForUpdates, printLegacyDistroNotice } = require('./lib/update-checker');
|
|
71
71
|
const { StatusFooter, AGENT_STATE, ACTIVE_STATES } = require('../src/status-footer');
|
|
72
72
|
|
|
73
73
|
// =============================================================================
|
|
@@ -5387,13 +5387,15 @@ function printMessage(msg, showClusterId = false, watchMode = false, isActive =
|
|
|
5387
5387
|
|
|
5388
5388
|
// Main async entry point
|
|
5389
5389
|
async function main() {
|
|
5390
|
-
const
|
|
5391
|
-
|
|
5392
|
-
|
|
5393
|
-
|
|
5390
|
+
const isTest = process.env.NODE_ENV === 'test';
|
|
5391
|
+
const isQuiet = process.argv.includes('-q') || process.argv.includes('--quiet') || isTest;
|
|
5392
|
+
|
|
5393
|
+
printLegacyDistroNotice();
|
|
5394
5394
|
|
|
5395
5395
|
// Check for updates (non-blocking if offline)
|
|
5396
|
-
|
|
5396
|
+
if (!isTest) {
|
|
5397
|
+
await checkForUpdates({ quiet: isQuiet });
|
|
5398
|
+
}
|
|
5397
5399
|
|
|
5398
5400
|
let args = process.argv.slice(2);
|
|
5399
5401
|
|
|
@@ -9,10 +9,16 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
const https = require('https');
|
|
12
|
-
const
|
|
12
|
+
const childProcess = require('child_process');
|
|
13
|
+
const fs = require('fs');
|
|
14
|
+
const path = require('path');
|
|
13
15
|
const readline = require('readline');
|
|
14
16
|
const { loadSettings, saveSettings } = require('../../lib/settings');
|
|
15
17
|
|
|
18
|
+
const NEW_PACKAGE_NAME = '@the-open-engine/zeroshot';
|
|
19
|
+
const LEGACY_PACKAGE_NAME = '@covibes/zeroshot';
|
|
20
|
+
const NEW_PACKAGE_SPEC = `${NEW_PACKAGE_NAME}@latest`;
|
|
21
|
+
|
|
16
22
|
// 24 hours in milliseconds
|
|
17
23
|
const CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
18
24
|
|
|
@@ -20,15 +26,177 @@ const CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
|
20
26
|
const FETCH_TIMEOUT_MS = 5000;
|
|
21
27
|
|
|
22
28
|
// npm registry URL
|
|
23
|
-
const REGISTRY_URL =
|
|
29
|
+
const REGISTRY_URL = `https://registry.npmjs.org/${NEW_PACKAGE_NAME}/latest`;
|
|
30
|
+
|
|
31
|
+
function getPackageMetadata() {
|
|
32
|
+
return require('../../package.json');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function getCurrentPackageName() {
|
|
36
|
+
return getPackageMetadata().name || NEW_PACKAGE_NAME;
|
|
37
|
+
}
|
|
24
38
|
|
|
25
39
|
/**
|
|
26
40
|
* Get current package version
|
|
27
41
|
* @returns {string}
|
|
28
42
|
*/
|
|
29
43
|
function getCurrentVersion() {
|
|
30
|
-
|
|
31
|
-
|
|
44
|
+
return getPackageMetadata().version;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function isLegacyDistro(packageName = getCurrentPackageName()) {
|
|
48
|
+
return packageName === LEGACY_PACKAGE_NAME;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function printLegacyDistroNotice(packageName = getCurrentPackageName()) {
|
|
52
|
+
if (!isLegacyDistro(packageName)) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
console.error(
|
|
57
|
+
`\n⚠️ ${LEGACY_PACKAGE_NAME} has moved to ${NEW_PACKAGE_NAME}. ` +
|
|
58
|
+
'Run `zeroshot update` to switch this installation.\n'
|
|
59
|
+
);
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function getPackageRoot() {
|
|
64
|
+
return path.dirname(require.resolve('../../package.json'));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function hasPathSuffix(parts, suffix) {
|
|
68
|
+
if (suffix.length > parts.length) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const start = parts.length - suffix.length;
|
|
73
|
+
return suffix.every((part, index) => parts[start + index] === part);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function joinPathParts(parts) {
|
|
77
|
+
const joined = parts.join(path.sep);
|
|
78
|
+
return joined === '' ? path.parse(process.cwd()).root : joined;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function deriveInstallPrefixFromPackageRoot(packageRoot, packageName) {
|
|
82
|
+
const parts = path.resolve(packageRoot).split(path.sep);
|
|
83
|
+
const packageParts = packageName.split('/');
|
|
84
|
+
|
|
85
|
+
if (!hasPathSuffix(parts, packageParts)) {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const nodeModulesIndex = parts.length - packageParts.length - 1;
|
|
90
|
+
if (nodeModulesIndex < 0 || parts[nodeModulesIndex] !== 'node_modules') {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (parts[nodeModulesIndex - 1] === 'lib') {
|
|
95
|
+
return joinPathParts(parts.slice(0, nodeModulesIndex - 1));
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return joinPathParts(parts.slice(0, nodeModulesIndex));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function resolveNpmCommand(installPrefix = null) {
|
|
102
|
+
const npmName = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
103
|
+
const candidates = [];
|
|
104
|
+
|
|
105
|
+
if (installPrefix) {
|
|
106
|
+
candidates.push(path.join(installPrefix, 'bin', npmName));
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
candidates.push(path.join(path.dirname(process.execPath), npmName));
|
|
110
|
+
|
|
111
|
+
for (const candidate of candidates) {
|
|
112
|
+
if (fs.existsSync(candidate)) {
|
|
113
|
+
return candidate;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return npmName;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function getNpmConfiguredPrefix(npmCommand = resolveNpmCommand()) {
|
|
121
|
+
return childProcess
|
|
122
|
+
.execFileSync(npmCommand, ['config', 'get', 'prefix'], {
|
|
123
|
+
encoding: 'utf8',
|
|
124
|
+
})
|
|
125
|
+
.trim();
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function getInstallPrefix(options = {}) {
|
|
129
|
+
if (options.installPrefix) {
|
|
130
|
+
return options.installPrefix;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const packageName = options.packageName || getCurrentPackageName();
|
|
134
|
+
const packageRoot = options.packageRoot || getPackageRoot();
|
|
135
|
+
const derivedPrefix = deriveInstallPrefixFromPackageRoot(packageRoot, packageName);
|
|
136
|
+
|
|
137
|
+
if (derivedPrefix) {
|
|
138
|
+
return derivedPrefix;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return getNpmConfiguredPrefix(options.npmCommand);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function getGlobalModulesDir(installPrefix) {
|
|
145
|
+
const unixGlobalModulesDir = path.join(installPrefix, 'lib', 'node_modules');
|
|
146
|
+
if (fs.existsSync(unixGlobalModulesDir)) {
|
|
147
|
+
return unixGlobalModulesDir;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return path.join(installPrefix, 'node_modules');
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function shellQuote(value) {
|
|
154
|
+
if (/^[A-Za-z0-9_./:@+-]+$/.test(value)) {
|
|
155
|
+
return value;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function buildManualInstallCommand(installPrefix = null, useSudo = false) {
|
|
162
|
+
const command = [
|
|
163
|
+
useSudo ? 'sudo' : null,
|
|
164
|
+
'npm',
|
|
165
|
+
'install',
|
|
166
|
+
'-g',
|
|
167
|
+
installPrefix ? '--prefix' : null,
|
|
168
|
+
installPrefix ? shellQuote(installPrefix) : null,
|
|
169
|
+
NEW_PACKAGE_SPEC,
|
|
170
|
+
].filter(Boolean);
|
|
171
|
+
|
|
172
|
+
return command.join(' ');
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function getUpdateTarget(options = {}) {
|
|
176
|
+
const packageName = options.packageName || getCurrentPackageName();
|
|
177
|
+
const legacy = isLegacyDistro(packageName);
|
|
178
|
+
const installPrefix = getInstallPrefix(options);
|
|
179
|
+
const npmCommand = options.npmCommand || resolveNpmCommand(installPrefix);
|
|
180
|
+
|
|
181
|
+
return {
|
|
182
|
+
packageName,
|
|
183
|
+
legacy,
|
|
184
|
+
installPrefix,
|
|
185
|
+
npmCommand,
|
|
186
|
+
globalModulesDir: getGlobalModulesDir(installPrefix),
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function buildInstallArgs(updateTarget) {
|
|
191
|
+
const args = ['install', '-g', '--prefix', updateTarget.installPrefix];
|
|
192
|
+
|
|
193
|
+
if (updateTarget.legacy) {
|
|
194
|
+
// npm refuses to replace the legacy package's `zeroshot` bin without this.
|
|
195
|
+
args.push('--force');
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
args.push(NEW_PACKAGE_SPEC);
|
|
199
|
+
return args;
|
|
32
200
|
}
|
|
33
201
|
|
|
34
202
|
/**
|
|
@@ -119,17 +287,10 @@ function promptForUpdate(currentVersion, latestVersion) {
|
|
|
119
287
|
* Check if we have write permission to npm global directory
|
|
120
288
|
* @returns {boolean} True if we can write to npm global prefix
|
|
121
289
|
*/
|
|
122
|
-
function canWriteToNpmGlobal() {
|
|
123
|
-
const { execSync } = require('child_process');
|
|
124
|
-
const fs = require('fs');
|
|
125
|
-
|
|
290
|
+
function canWriteToNpmGlobal(options = {}) {
|
|
126
291
|
try {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
const globalModulesDir = require('path').join(prefix, 'lib', 'node_modules');
|
|
130
|
-
|
|
131
|
-
// Check if directory exists and is writable
|
|
132
|
-
fs.accessSync(globalModulesDir, fs.constants.W_OK);
|
|
292
|
+
const updateTarget = getUpdateTarget(options);
|
|
293
|
+
fs.accessSync(updateTarget.globalModulesDir, fs.constants.W_OK);
|
|
133
294
|
return true;
|
|
134
295
|
} catch {
|
|
135
296
|
return false;
|
|
@@ -140,22 +301,32 @@ function canWriteToNpmGlobal() {
|
|
|
140
301
|
* Run npm install to update the package
|
|
141
302
|
* @returns {Promise<boolean>} True if update succeeded
|
|
142
303
|
*/
|
|
143
|
-
function runUpdate() {
|
|
304
|
+
function runUpdate(options = {}) {
|
|
144
305
|
return new Promise((resolve) => {
|
|
306
|
+
let updateTarget;
|
|
307
|
+
try {
|
|
308
|
+
updateTarget = getUpdateTarget(options);
|
|
309
|
+
} catch {
|
|
310
|
+
console.log('❌ Update failed. Try manually:');
|
|
311
|
+
console.log(` ${buildManualInstallCommand()}\n`);
|
|
312
|
+
resolve(false);
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
|
|
145
316
|
// Check permissions BEFORE attempting update
|
|
146
|
-
if (!canWriteToNpmGlobal()) {
|
|
317
|
+
if (!canWriteToNpmGlobal(options)) {
|
|
147
318
|
console.log('\n⚠️ Cannot auto-update: no write permission to npm global directory.');
|
|
148
319
|
console.log(' Run manually with sudo:');
|
|
149
|
-
console.log(
|
|
320
|
+
console.log(` ${buildManualInstallCommand(updateTarget.installPrefix, true)}\n`);
|
|
150
321
|
resolve(false);
|
|
151
322
|
return;
|
|
152
323
|
}
|
|
153
324
|
|
|
154
325
|
console.log('\n📥 Installing update...');
|
|
155
326
|
|
|
156
|
-
const proc = spawn(
|
|
327
|
+
const proc = childProcess.spawn(updateTarget.npmCommand, buildInstallArgs(updateTarget), {
|
|
157
328
|
stdio: 'inherit',
|
|
158
|
-
shell:
|
|
329
|
+
shell: false,
|
|
159
330
|
});
|
|
160
331
|
|
|
161
332
|
proc.on('close', (code) => {
|
|
@@ -165,14 +336,14 @@ function runUpdate() {
|
|
|
165
336
|
resolve(true);
|
|
166
337
|
} else {
|
|
167
338
|
console.log('❌ Update failed. Try manually:');
|
|
168
|
-
console.log(
|
|
339
|
+
console.log(` ${buildManualInstallCommand(updateTarget.installPrefix, true)}\n`);
|
|
169
340
|
resolve(false);
|
|
170
341
|
}
|
|
171
342
|
});
|
|
172
343
|
|
|
173
344
|
proc.on('error', () => {
|
|
174
345
|
console.log('❌ Update failed. Try manually:');
|
|
175
|
-
console.log(
|
|
346
|
+
console.log(` ${buildManualInstallCommand(updateTarget.installPrefix, true)}\n`);
|
|
176
347
|
resolve(false);
|
|
177
348
|
});
|
|
178
349
|
});
|
|
@@ -246,9 +417,9 @@ async function checkForUpdates(options = {}) {
|
|
|
246
417
|
if (options.quiet) {
|
|
247
418
|
console.log(`📦 Update available: ${currentVersion} → ${latestVersion}`);
|
|
248
419
|
if (hasWriteAccess) {
|
|
249
|
-
console.log(
|
|
420
|
+
console.log(` Run: ${buildManualInstallCommand(getInstallPrefix(), false)}\n`);
|
|
250
421
|
} else {
|
|
251
|
-
console.log(
|
|
422
|
+
console.log(` Run: ${buildManualInstallCommand(getInstallPrefix(), true)}\n`);
|
|
252
423
|
}
|
|
253
424
|
return;
|
|
254
425
|
}
|
|
@@ -257,7 +428,7 @@ async function checkForUpdates(options = {}) {
|
|
|
257
428
|
// (they'd say yes then get an error, which is frustrating UX)
|
|
258
429
|
if (!hasWriteAccess) {
|
|
259
430
|
console.log(`\n📦 Update available: ${currentVersion} → ${latestVersion}`);
|
|
260
|
-
console.log(
|
|
431
|
+
console.log(` Run: ${buildManualInstallCommand(getInstallPrefix(), true)}\n`);
|
|
261
432
|
return;
|
|
262
433
|
}
|
|
263
434
|
|
|
@@ -271,7 +442,17 @@ async function checkForUpdates(options = {}) {
|
|
|
271
442
|
module.exports = {
|
|
272
443
|
checkForUpdates,
|
|
273
444
|
// Exported for testing and CLI update command
|
|
445
|
+
NEW_PACKAGE_NAME,
|
|
446
|
+
LEGACY_PACKAGE_NAME,
|
|
274
447
|
getCurrentVersion,
|
|
448
|
+
getCurrentPackageName,
|
|
449
|
+
isLegacyDistro,
|
|
450
|
+
printLegacyDistroNotice,
|
|
451
|
+
deriveInstallPrefixFromPackageRoot,
|
|
452
|
+
getInstallPrefix,
|
|
453
|
+
resolveNpmCommand,
|
|
454
|
+
getUpdateTarget,
|
|
455
|
+
buildInstallArgs,
|
|
275
456
|
isNewerVersion,
|
|
276
457
|
fetchLatestVersion,
|
|
277
458
|
runUpdate,
|