@the-open-engine/zeroshot 6.11.0 ā 6.12.0
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/commands/providers.js +13 -13
- package/cli/index.js +77 -35
- package/cli/lib/first-run.js +12 -11
- package/cli/lib/update-checker.js +517 -132
- package/lib/agent-cli-provider/adapters/opencode.d.ts.map +1 -1
- package/lib/agent-cli-provider/adapters/opencode.js +3 -0
- package/lib/agent-cli-provider/adapters/opencode.js.map +1 -1
- package/lib/agent-cli-provider/types.d.ts +1 -0
- package/lib/agent-cli-provider/types.d.ts.map +1 -1
- package/lib/agent-cli-provider/types.js.map +1 -1
- package/lib/cluster/client.cjs +146 -0
- package/lib/cluster/client.d.ts +44 -0
- package/lib/cluster/client.mjs +141 -0
- package/lib/cluster/connection.cjs +382 -0
- package/lib/cluster/connection.d.ts +41 -0
- package/lib/cluster/connection.mjs +378 -0
- package/lib/cluster/errors.cjs +44 -0
- package/lib/cluster/errors.d.ts +23 -0
- package/lib/cluster/errors.mjs +32 -0
- package/lib/cluster/frames.cjs +49 -0
- package/lib/cluster/frames.d.ts +12 -0
- package/lib/cluster/frames.mjs +45 -0
- package/lib/cluster/generated/protocol-schema.cjs +5 -0
- package/lib/cluster/generated/protocol-schema.d.ts +1 -0
- package/lib/cluster/generated/protocol-schema.mjs +2 -0
- package/lib/cluster/generated/protocol.cjs +22 -0
- package/lib/cluster/generated/protocol.d.ts +781 -0
- package/lib/cluster/generated/protocol.mjs +19 -0
- package/lib/cluster/index.cjs +40 -0
- package/lib/cluster/index.d.ts +10 -0
- package/lib/cluster/index.mjs +6 -0
- package/lib/cluster/queue.cjs +71 -0
- package/lib/cluster/queue.d.ts +15 -0
- package/lib/cluster/queue.mjs +67 -0
- package/lib/cluster/socket.cjs +15 -0
- package/lib/cluster/socket.d.ts +11 -0
- package/lib/cluster/socket.mjs +12 -0
- package/lib/cluster/subscriptions.cjs +270 -0
- package/lib/cluster/subscriptions.d.ts +69 -0
- package/lib/cluster/subscriptions.mjs +264 -0
- package/lib/cluster/validators.cjs +46 -0
- package/lib/cluster/validators.d.ts +3 -0
- package/lib/cluster/validators.mjs +42 -0
- package/lib/settings.js +195 -23
- package/lib/setup-apply.js +45 -32
- package/lib/setup-undo.js +25 -16
- package/package.json +25 -3
- package/scripts/build-cluster.js +43 -0
- package/scripts/generate-cluster-types.js +203 -0
- package/scripts/release-dry-run.js +6 -6
- package/scripts/rust-distribution.js +933 -0
- package/src/agent/agent-hook-executor.js +14 -6
- package/src/agent/agent-lifecycle.js +25 -8
- package/src/agent/agent-task-executor.js +711 -139
- package/src/agent/output-reformatter.js +54 -41
- package/src/agent/pr-verification.js +11 -3
- package/src/agent/task-execution-handle.js +373 -0
- package/src/agent-cli-provider/adapters/opencode.ts +3 -0
- package/src/agent-cli-provider/types.ts +1 -0
- package/src/agent-wrapper.js +5 -2
- package/src/cluster/client.ts +199 -0
- package/src/cluster/connection.ts +300 -0
- package/src/cluster/errors.ts +32 -0
- package/src/cluster/frames.ts +44 -0
- package/src/cluster/generated/protocol-schema.ts +2 -0
- package/src/cluster/generated/protocol.ts +183 -0
- package/src/cluster/index.ts +38 -0
- package/src/cluster/queue.ts +84 -0
- package/src/cluster/socket.ts +31 -0
- package/src/cluster/subscriptions.ts +256 -0
- package/src/cluster/validators.ts +56 -0
- package/src/cluster/ws.d.ts +7 -0
- package/src/isolation-manager.js +16 -0
- package/src/issue-providers/jira-provider.js +1 -1
- package/src/issue-providers/linear-provider.js +4 -4
- package/task-lib/runner.js +3 -0
|
@@ -1,19 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Update Checker -
|
|
2
|
+
* Update Checker - cached startup notices and the explicit npm updater.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* - 5-second timeout (non-blocking if offline)
|
|
7
|
-
* - Interactive prompt for manual update
|
|
8
|
-
* - Respects quiet mode (no prompts in CI/scripts)
|
|
4
|
+
* Automatic startup work is notification-only and stale-while-revalidate.
|
|
5
|
+
* Installation remains exclusive to the explicit `zeroshot update` command.
|
|
9
6
|
*/
|
|
10
7
|
|
|
11
8
|
const https = require('https');
|
|
12
9
|
const childProcess = require('child_process');
|
|
10
|
+
const crypto = require('crypto');
|
|
13
11
|
const fs = require('fs');
|
|
14
12
|
const path = require('path');
|
|
15
|
-
const
|
|
16
|
-
const { loadSettings, saveSettings } = require('../../lib/settings');
|
|
13
|
+
const { loadSettings, mutateSettings } = require('../../lib/settings');
|
|
17
14
|
|
|
18
15
|
const NEW_PACKAGE_NAME = '@the-open-engine/zeroshot';
|
|
19
16
|
const LEGACY_PACKAGE_NAME = '@covibes/zeroshot';
|
|
@@ -28,6 +25,13 @@ const FETCH_TIMEOUT_MS = 5000;
|
|
|
28
25
|
// npm registry URL
|
|
29
26
|
const REGISTRY_URL = `https://registry.npmjs.org/${NEW_PACKAGE_NAME}/latest`;
|
|
30
27
|
|
|
28
|
+
const MAX_RESPONSE_BYTES = 64 * 1024;
|
|
29
|
+
const STABLE_CORE_VERSION_PATTERN = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/;
|
|
30
|
+
const BUILD_IDENTIFIER_PATTERN = /^[0-9A-Za-z-]+$/;
|
|
31
|
+
const MAX_VERSION_LENGTH = 256;
|
|
32
|
+
|
|
33
|
+
let inFlightRefresh = null;
|
|
34
|
+
|
|
31
35
|
function getPackageMetadata() {
|
|
32
36
|
return require('../../package.json');
|
|
33
37
|
}
|
|
@@ -48,6 +52,10 @@ function isLegacyDistro(packageName = getCurrentPackageName()) {
|
|
|
48
52
|
return packageName === LEGACY_PACKAGE_NAME;
|
|
49
53
|
}
|
|
50
54
|
|
|
55
|
+
function shouldForceLegacyUpdate(argv, packageName = getCurrentPackageName()) {
|
|
56
|
+
return isLegacyDistro(packageName) && Array.isArray(argv) && argv[0] === 'update';
|
|
57
|
+
}
|
|
58
|
+
|
|
51
59
|
function printLegacyDistroNotice(packageName = getCurrentPackageName()) {
|
|
52
60
|
if (!isLegacyDistro(packageName)) {
|
|
53
61
|
return false;
|
|
@@ -199,89 +207,142 @@ function buildInstallArgs(updateTarget) {
|
|
|
199
207
|
return args;
|
|
200
208
|
}
|
|
201
209
|
|
|
210
|
+
function parseStableVersion(version) {
|
|
211
|
+
if (typeof version !== 'string' || version.length > MAX_VERSION_LENGTH) return null;
|
|
212
|
+
const plusIndex = version.indexOf('+');
|
|
213
|
+
const core = plusIndex === -1 ? version : version.slice(0, plusIndex);
|
|
214
|
+
if (plusIndex !== -1) {
|
|
215
|
+
const build = version.slice(plusIndex + 1);
|
|
216
|
+
if (!build || build.split('.').some((part) => !BUILD_IDENTIFIER_PATTERN.test(part))) {
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
const match = STABLE_CORE_VERSION_PATTERN.exec(core);
|
|
221
|
+
if (!match) return null;
|
|
222
|
+
const parts = [Number(match[1]), Number(match[2]), Number(match[3])];
|
|
223
|
+
return parts.every(Number.isSafeInteger) ? parts : null;
|
|
224
|
+
}
|
|
225
|
+
|
|
202
226
|
/**
|
|
203
|
-
* Compare
|
|
204
|
-
*
|
|
205
|
-
*
|
|
206
|
-
* @
|
|
227
|
+
* Compare a running version with a validated stable registry release.
|
|
228
|
+
* Non-release source versions are older for the explicit update command;
|
|
229
|
+
* automatic eligibility independently rejects them before checker work.
|
|
230
|
+
* @param {string} current
|
|
231
|
+
* @param {string} latest
|
|
232
|
+
* @returns {boolean}
|
|
207
233
|
*/
|
|
208
234
|
function isNewerVersion(current, latest) {
|
|
209
|
-
const
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
if (
|
|
216
|
-
if (
|
|
235
|
+
const latestParts = parseStableVersion(latest);
|
|
236
|
+
if (!latestParts) return false;
|
|
237
|
+
const currentParts = parseStableVersion(current);
|
|
238
|
+
if (!currentParts) return true;
|
|
239
|
+
|
|
240
|
+
for (let index = 0; index < 3; index += 1) {
|
|
241
|
+
if (latestParts[index] > currentParts[index]) return true;
|
|
242
|
+
if (latestParts[index] < currentParts[index]) return false;
|
|
217
243
|
}
|
|
218
244
|
return false;
|
|
219
245
|
}
|
|
220
246
|
|
|
247
|
+
function validatedManifestVersion(manifest) {
|
|
248
|
+
if (
|
|
249
|
+
!manifest ||
|
|
250
|
+
typeof manifest !== 'object' ||
|
|
251
|
+
manifest.name !== NEW_PACKAGE_NAME ||
|
|
252
|
+
!parseStableVersion(manifest.version) ||
|
|
253
|
+
!manifest.dist ||
|
|
254
|
+
typeof manifest.dist !== 'object' ||
|
|
255
|
+
typeof manifest.dist.tarball !== 'string' ||
|
|
256
|
+
!manifest.dist.tarball.trim().startsWith('https://') ||
|
|
257
|
+
typeof manifest.dist.integrity !== 'string' ||
|
|
258
|
+
manifest.dist.integrity.trim().length === 0
|
|
259
|
+
) {
|
|
260
|
+
return null;
|
|
261
|
+
}
|
|
262
|
+
return manifest.version;
|
|
263
|
+
}
|
|
264
|
+
|
|
221
265
|
/**
|
|
222
|
-
* Fetch
|
|
223
|
-
* @
|
|
266
|
+
* Fetch and validate the installable npm latest manifest.
|
|
267
|
+
* @param {object} options
|
|
268
|
+
* @returns {Promise<string|null>}
|
|
224
269
|
*/
|
|
225
|
-
function fetchLatestVersion() {
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
}
|
|
270
|
+
function fetchLatestVersion(options = {}) {
|
|
271
|
+
const httpsModule = options.httpsModule || https;
|
|
272
|
+
const timeoutMs = options.timeoutMs ?? FETCH_TIMEOUT_MS;
|
|
273
|
+
const maxResponseBytes = options.maxResponseBytes ?? MAX_RESPONSE_BYTES;
|
|
274
|
+
const scheduleTimeout = options.setTimeout || setTimeout;
|
|
275
|
+
const cancelTimeout = options.clearTimeout || clearTimeout;
|
|
232
276
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
277
|
+
return new Promise((resolve) => {
|
|
278
|
+
let request;
|
|
279
|
+
let safetyTimer;
|
|
280
|
+
let settled = false;
|
|
281
|
+
|
|
282
|
+
const finish = (value) => {
|
|
283
|
+
if (settled) return;
|
|
284
|
+
settled = true;
|
|
285
|
+
if (safetyTimer) cancelTimeout(safetyTimer);
|
|
286
|
+
request?.setTimeout?.(0);
|
|
287
|
+
resolve(value);
|
|
288
|
+
};
|
|
237
289
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
290
|
+
try {
|
|
291
|
+
request = httpsModule.get(REGISTRY_URL, { timeout: timeoutMs }, (response) => {
|
|
292
|
+
if (response.statusCode !== 200) {
|
|
293
|
+
response.destroy?.();
|
|
294
|
+
request.destroy?.();
|
|
295
|
+
finish(null);
|
|
296
|
+
return;
|
|
244
297
|
}
|
|
245
|
-
});
|
|
246
|
-
});
|
|
247
298
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
299
|
+
const chunks = [];
|
|
300
|
+
let size = 0;
|
|
301
|
+
response.on('data', (chunk) => {
|
|
302
|
+
if (settled) return;
|
|
303
|
+
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
304
|
+
size += buffer.length;
|
|
305
|
+
if (size > maxResponseBytes) {
|
|
306
|
+
response.destroy?.();
|
|
307
|
+
request.destroy?.();
|
|
308
|
+
finish(null);
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
chunks.push(buffer);
|
|
312
|
+
});
|
|
313
|
+
response.on('error', () => finish(null));
|
|
314
|
+
response.on('end', () => {
|
|
315
|
+
if (settled) return;
|
|
316
|
+
try {
|
|
317
|
+
const manifest = JSON.parse(Buffer.concat(chunks, size).toString('utf8'));
|
|
318
|
+
finish(validatedManifestVersion(manifest));
|
|
319
|
+
} catch {
|
|
320
|
+
finish(null);
|
|
321
|
+
}
|
|
322
|
+
});
|
|
323
|
+
});
|
|
324
|
+
} catch {
|
|
325
|
+
finish(null);
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
251
328
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
329
|
+
request.on('error', () => finish(null));
|
|
330
|
+
request.on('timeout', () => {
|
|
331
|
+
request.destroy();
|
|
332
|
+
finish(null);
|
|
255
333
|
});
|
|
334
|
+
if (options.unref) {
|
|
335
|
+
request.on('socket', (socket) => socket.unref?.());
|
|
336
|
+
}
|
|
256
337
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
338
|
+
safetyTimer = scheduleTimeout(() => {
|
|
339
|
+
request.destroy();
|
|
340
|
+
finish(null);
|
|
341
|
+
}, timeoutMs + 1000);
|
|
342
|
+
safetyTimer.unref?.();
|
|
262
343
|
});
|
|
263
344
|
}
|
|
264
345
|
|
|
265
|
-
/**
|
|
266
|
-
* Prompt user for update confirmation
|
|
267
|
-
* @param {string} currentVersion
|
|
268
|
-
* @param {string} latestVersion
|
|
269
|
-
* @returns {Promise<boolean>} True if user wants to update
|
|
270
|
-
*/
|
|
271
|
-
function promptForUpdate(currentVersion, latestVersion) {
|
|
272
|
-
return new Promise((resolve) => {
|
|
273
|
-
const rl = readline.createInterface({
|
|
274
|
-
input: process.stdin,
|
|
275
|
-
output: process.stdout,
|
|
276
|
-
});
|
|
277
|
-
|
|
278
|
-
console.log(`\nš¦ Update available: ${currentVersion} ā ${latestVersion}`);
|
|
279
|
-
rl.question(' Install now? [y/N] ', (answer) => {
|
|
280
|
-
rl.close();
|
|
281
|
-
resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');
|
|
282
|
-
});
|
|
283
|
-
});
|
|
284
|
-
}
|
|
285
346
|
|
|
286
347
|
/**
|
|
287
348
|
* Check if we have write permission to npm global directory
|
|
@@ -349,98 +410,419 @@ function runUpdate(options = {}) {
|
|
|
349
410
|
});
|
|
350
411
|
}
|
|
351
412
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
413
|
+
function runLegacyUpdateIfRequested(argv, options = {}) {
|
|
414
|
+
const packageName = options.packageName || getCurrentPackageName();
|
|
415
|
+
if (!shouldForceLegacyUpdate(argv, packageName)) return null;
|
|
416
|
+
const installer = options.runUpdate || runUpdate;
|
|
417
|
+
return Promise.resolve(installer());
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
const GROUPABLE_GLOBAL_SHORT_FLAGS = new Set(['q', 'h', 'V']);
|
|
421
|
+
|
|
422
|
+
function hasGroupedGlobalShortFlag(argv) {
|
|
423
|
+
const end = argv.indexOf('--');
|
|
424
|
+
const limit = end === -1 ? argv.length : end;
|
|
425
|
+
for (let index = 0; index < limit; index += 1) {
|
|
426
|
+
const token = argv[index];
|
|
427
|
+
if (
|
|
428
|
+
token.length > 2 &&
|
|
429
|
+
token.startsWith('-') &&
|
|
430
|
+
!token.startsWith('--') &&
|
|
431
|
+
[...token.slice(1)].every((flag) => GROUPABLE_GLOBAL_SHORT_FLAGS.has(flag))
|
|
432
|
+
) {
|
|
433
|
+
return true;
|
|
434
|
+
}
|
|
361
435
|
}
|
|
436
|
+
return false;
|
|
437
|
+
}
|
|
362
438
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
return
|
|
439
|
+
function findSubcommand(command, name) {
|
|
440
|
+
return (command.commands || []).find((candidate) => {
|
|
441
|
+
return candidate.name() === name || candidate.aliases().includes(name);
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
function optionMaps(commandHierarchy) {
|
|
446
|
+
const short = new Map();
|
|
447
|
+
const long = new Map();
|
|
448
|
+
for (const command of commandHierarchy) {
|
|
449
|
+
const helpOption = command._getHelpOption?.();
|
|
450
|
+
for (const option of [helpOption, ...(command.options || [])]) {
|
|
451
|
+
if (!option) continue;
|
|
452
|
+
if (option.short) short.set(option.short, option);
|
|
453
|
+
if (option.long) long.set(option.long, option);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
return { short, long };
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
function optionOccurrence(option, value = null) {
|
|
460
|
+
return { short: option.short || null, long: option.long || null, value };
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
function matchLongOption(token, maps) {
|
|
464
|
+
const equalsIndex = token.indexOf('=');
|
|
465
|
+
const name = equalsIndex === -1 ? token : token.slice(0, equalsIndex);
|
|
466
|
+
const option = maps.long.get(name);
|
|
467
|
+
if (!option) return null;
|
|
468
|
+
if (equalsIndex !== -1 && !option.required && !option.optional) return null;
|
|
469
|
+
const value = equalsIndex === -1 ? null : token.slice(equalsIndex + 1);
|
|
470
|
+
return {
|
|
471
|
+
occurrences: [optionOccurrence(option, value)],
|
|
472
|
+
needsValue: equalsIndex === -1 && (option.required || option.optional),
|
|
473
|
+
optionalValue: option.optional,
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
function matchShortOptions(token, maps) {
|
|
478
|
+
const exact = maps.short.get(token);
|
|
479
|
+
if (exact) {
|
|
480
|
+
return {
|
|
481
|
+
occurrences: [optionOccurrence(exact)],
|
|
482
|
+
needsValue: exact.required || exact.optional,
|
|
483
|
+
optionalValue: exact.optional,
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
if (token.length < 3 || !token.startsWith('-') || token.startsWith('--')) return null;
|
|
487
|
+
|
|
488
|
+
const occurrences = [];
|
|
489
|
+
for (let index = 1; index < token.length; index += 1) {
|
|
490
|
+
const option = maps.short.get(`-${token[index]}`);
|
|
491
|
+
if (!option) return null;
|
|
492
|
+
if (option.required || option.optional) {
|
|
493
|
+
occurrences.push(optionOccurrence(option, token.slice(index + 1) || null));
|
|
494
|
+
return {
|
|
495
|
+
occurrences,
|
|
496
|
+
needsValue: index === token.length - 1,
|
|
497
|
+
optionalValue: option.optional,
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
occurrences.push(optionOccurrence(option));
|
|
501
|
+
}
|
|
502
|
+
return { occurrences, needsValue: false, optionalValue: false };
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
function consumeOptionValue(match, argv, index, limit) {
|
|
506
|
+
if (!match.needsValue || index + 1 >= limit) return 0;
|
|
507
|
+
const value = argv[index + 1];
|
|
508
|
+
if (match.optionalValue && value.startsWith('-')) return 0;
|
|
509
|
+
match.occurrences[match.occurrences.length - 1].value = value;
|
|
510
|
+
return 1;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
function classifyCommanderArguments(program, argv, defaultCommandName) {
|
|
514
|
+
const selectedCommandPath = [];
|
|
515
|
+
const occurrences = [];
|
|
516
|
+
const hierarchy = [program];
|
|
517
|
+
let consumedValueIndex = -1;
|
|
518
|
+
let command = program;
|
|
519
|
+
let positionalSeen = false;
|
|
520
|
+
|
|
521
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
522
|
+
if (index === consumedValueIndex) continue;
|
|
523
|
+
const token = argv[index];
|
|
524
|
+
if (token === '--') break;
|
|
525
|
+
const maps = optionMaps(hierarchy);
|
|
526
|
+
const match = token.startsWith('--')
|
|
527
|
+
? matchLongOption(token, maps)
|
|
528
|
+
: matchShortOptions(token, maps);
|
|
529
|
+
if (match) {
|
|
530
|
+
if (consumeOptionValue(match, argv, index, argv.length) === 1) {
|
|
531
|
+
consumedValueIndex = index + 1;
|
|
532
|
+
}
|
|
533
|
+
occurrences.push(...match.occurrences);
|
|
534
|
+
continue;
|
|
535
|
+
}
|
|
536
|
+
if (token.startsWith('-')) continue;
|
|
537
|
+
|
|
538
|
+
const child = positionalSeen ? null : findSubcommand(command, token);
|
|
539
|
+
if (child) {
|
|
540
|
+
command = child;
|
|
541
|
+
hierarchy.push(child);
|
|
542
|
+
selectedCommandPath.push(child.name());
|
|
543
|
+
positionalSeen = false;
|
|
544
|
+
continue;
|
|
545
|
+
}
|
|
546
|
+
if (command === program && selectedCommandPath.length === 0 && defaultCommandName) {
|
|
547
|
+
const defaultCommand = findSubcommand(program, defaultCommandName);
|
|
548
|
+
if (defaultCommand) {
|
|
549
|
+
command = defaultCommand;
|
|
550
|
+
hierarchy.push(defaultCommand);
|
|
551
|
+
selectedCommandPath.push(defaultCommand.name());
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
positionalSeen = true;
|
|
555
|
+
}
|
|
556
|
+
return { selectedCommandPath, occurrences };
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
function parsedOptionPresent(metadata, argv, longName, shortName = null) {
|
|
560
|
+
if (!metadata) return optionIndex(argv, longName, shortName) !== -1;
|
|
561
|
+
return metadata.occurrences.some((entry) => {
|
|
562
|
+
return entry.long === longName || (shortName && entry.short === shortName);
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
function parsedOptionValue(metadata, argv, longName, shortName = null) {
|
|
567
|
+
if (!metadata) return optionValue(argv, longName, shortName);
|
|
568
|
+
for (let index = metadata.occurrences.length - 1; index >= 0; index -= 1) {
|
|
569
|
+
const entry = metadata.occurrences[index];
|
|
570
|
+
if (entry.long === longName || (shortName && entry.short === shortName)) {
|
|
571
|
+
return entry.value;
|
|
572
|
+
}
|
|
366
573
|
}
|
|
574
|
+
return null;
|
|
575
|
+
}
|
|
367
576
|
|
|
368
|
-
|
|
369
|
-
const
|
|
370
|
-
|
|
577
|
+
function optionIndex(argv, longName, shortName = null) {
|
|
578
|
+
const end = argv.indexOf('--');
|
|
579
|
+
const limit = end === -1 ? argv.length : end;
|
|
580
|
+
for (let index = 0; index < limit; index += 1) {
|
|
581
|
+
const token = argv[index];
|
|
582
|
+
if (token === longName || (shortName && token === shortName)) return index;
|
|
583
|
+
if (token.startsWith(`${longName}=`)) return index;
|
|
584
|
+
}
|
|
585
|
+
return -1;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
function optionValue(argv, longName, shortName = null) {
|
|
589
|
+
const end = argv.indexOf('--');
|
|
590
|
+
const limit = end === -1 ? argv.length : end;
|
|
591
|
+
for (let index = 0; index < limit; index += 1) {
|
|
592
|
+
const token = argv[index];
|
|
593
|
+
if (token === longName || (shortName && token === shortName)) {
|
|
594
|
+
return argv[index + 1] ?? null;
|
|
595
|
+
}
|
|
596
|
+
if (token.startsWith(`${longName}=`)) return token.slice(longName.length + 1);
|
|
597
|
+
if (shortName && token.startsWith(shortName) && token.length > shortName.length) {
|
|
598
|
+
return token.slice(shortName.length);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
return null;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
function commandPath(argv) {
|
|
605
|
+
const positional = [];
|
|
606
|
+
const optionsWithValues = new Set([
|
|
607
|
+
'--format',
|
|
608
|
+
'-f',
|
|
609
|
+
'--output-format',
|
|
610
|
+
'--json-schema',
|
|
611
|
+
'--mcp-config',
|
|
612
|
+
]);
|
|
613
|
+
const end = argv.indexOf('--');
|
|
614
|
+
const limit = end === -1 ? argv.length : end;
|
|
615
|
+
let skipNext = false;
|
|
616
|
+
|
|
617
|
+
for (let index = 0; index < limit; index += 1) {
|
|
618
|
+
const token = argv[index];
|
|
619
|
+
if (skipNext) {
|
|
620
|
+
skipNext = false;
|
|
621
|
+
continue;
|
|
622
|
+
}
|
|
623
|
+
if (optionsWithValues.has(token)) {
|
|
624
|
+
skipNext = true;
|
|
625
|
+
continue;
|
|
626
|
+
}
|
|
627
|
+
if (!token.startsWith('-')) positional.push(token);
|
|
628
|
+
}
|
|
629
|
+
return positional;
|
|
371
630
|
}
|
|
372
631
|
|
|
373
632
|
/**
|
|
374
|
-
*
|
|
375
|
-
* @param {object} options
|
|
376
|
-
* @param {boolean} options.quiet - Skip interactive prompts
|
|
377
|
-
* @returns {Promise<void>}
|
|
633
|
+
* Pure classification for optional automatic update work.
|
|
378
634
|
*/
|
|
379
|
-
|
|
380
|
-
const
|
|
635
|
+
function isAutomaticUpdateEligible(options = {}) {
|
|
636
|
+
const argv = options.argv || process.argv.slice(2);
|
|
637
|
+
const env = options.env || process.env;
|
|
638
|
+
const stdin = options.stdin || process.stdin;
|
|
639
|
+
const stdout = options.stdout || process.stdout;
|
|
640
|
+
const stderr = options.stderr || process.stderr;
|
|
641
|
+
const currentVersion = options.currentVersion || getCurrentVersion();
|
|
642
|
+
const packageName = options.packageName || getCurrentPackageName();
|
|
381
643
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
644
|
+
if (
|
|
645
|
+
packageName !== NEW_PACKAGE_NAME ||
|
|
646
|
+
!parseStableVersion(currentVersion) ||
|
|
647
|
+
argv.length === 0 ||
|
|
648
|
+
stdin.isTTY !== true ||
|
|
649
|
+
stdout.isTTY !== true ||
|
|
650
|
+
stderr.isTTY !== true ||
|
|
651
|
+
(env.CI !== undefined && env.CI !== null && String(env.CI).length > 0) ||
|
|
652
|
+
env.ZEROSHOT_DAEMON === '1'
|
|
653
|
+
) {
|
|
654
|
+
return false;
|
|
385
655
|
}
|
|
386
656
|
|
|
387
|
-
|
|
388
|
-
|
|
657
|
+
let metadata = null;
|
|
658
|
+
if (options.commanderProgram) {
|
|
659
|
+
try {
|
|
660
|
+
metadata = classifyCommanderArguments(
|
|
661
|
+
options.commanderProgram,
|
|
662
|
+
argv,
|
|
663
|
+
options.defaultCommandName
|
|
664
|
+
);
|
|
665
|
+
} catch {
|
|
666
|
+
return false;
|
|
667
|
+
}
|
|
668
|
+
}
|
|
389
669
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
670
|
+
if (
|
|
671
|
+
parsedOptionPresent(metadata, argv, '--quiet', '-q') ||
|
|
672
|
+
parsedOptionPresent(metadata, argv, '--help', '-h') ||
|
|
673
|
+
parsedOptionPresent(metadata, argv, '--version', '-V') ||
|
|
674
|
+
(!metadata && hasGroupedGlobalShortFlag(argv)) ||
|
|
675
|
+
optionIndex(argv, '--completion') !== -1
|
|
676
|
+
) {
|
|
677
|
+
return false;
|
|
678
|
+
}
|
|
393
679
|
|
|
394
|
-
|
|
395
|
-
if (!
|
|
396
|
-
|
|
680
|
+
const [command, subcommand] = metadata ? metadata.selectedCommandPath : commandPath(argv);
|
|
681
|
+
if (!command) return false;
|
|
682
|
+
if (
|
|
683
|
+
command === 'update' ||
|
|
684
|
+
command === 'get-log-path' ||
|
|
685
|
+
(command === 'task' && subcommand === 'run') ||
|
|
686
|
+
(command === 'setup' && ['plan', 'apply', 'undo'].includes(subcommand)) ||
|
|
687
|
+
(command === 'cmdproof' && ['prove', 'verify', 'check'].includes(subcommand))
|
|
688
|
+
) {
|
|
689
|
+
return false;
|
|
397
690
|
}
|
|
398
691
|
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
692
|
+
if (
|
|
693
|
+
parsedOptionPresent(metadata, argv, '--json') ||
|
|
694
|
+
parsedOptionPresent(metadata, argv, '--silent-json-output') ||
|
|
695
|
+
parsedOptionPresent(metadata, argv, '--json-schema')
|
|
696
|
+
) {
|
|
697
|
+
return false;
|
|
402
698
|
}
|
|
403
699
|
|
|
404
|
-
|
|
405
|
-
if (
|
|
406
|
-
|
|
700
|
+
const outputFormat = parsedOptionValue(metadata, argv, '--output-format');
|
|
701
|
+
if (outputFormat === 'json' || outputFormat === 'stream-json') return false;
|
|
702
|
+
if (command === 'export' && parsedOptionValue(metadata, argv, '--format', '-f') === 'json') {
|
|
703
|
+
return false;
|
|
407
704
|
}
|
|
408
705
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
saveSettings(settings);
|
|
706
|
+
return true;
|
|
707
|
+
}
|
|
412
708
|
|
|
413
|
-
|
|
414
|
-
|
|
709
|
+
function shouldCheckForUpdates(settings, now = Date.now()) {
|
|
710
|
+
if (settings.autoCheckUpdates !== true) return false;
|
|
711
|
+
const timestamp = settings.lastUpdateCheckAt;
|
|
712
|
+
if (!Number.isFinite(timestamp) || timestamp < 0 || timestamp > now) return true;
|
|
713
|
+
return now - timestamp >= CHECK_INTERVAL_MS;
|
|
714
|
+
}
|
|
415
715
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
716
|
+
async function refreshUpdateCache(options) {
|
|
717
|
+
const now = options.now || Date.now;
|
|
718
|
+
const transaction = options.mutateSettings || mutateSettings;
|
|
719
|
+
const fetcher = options.fetchLatestVersion || fetchLatestVersion;
|
|
720
|
+
const generateClaimId = options.generateClaimId || (() => crypto.randomUUID());
|
|
721
|
+
const attemptAt = now();
|
|
722
|
+
const claimId = generateClaimId();
|
|
723
|
+
let claim;
|
|
724
|
+
|
|
725
|
+
try {
|
|
726
|
+
claim = transaction(
|
|
727
|
+
(settings) => {
|
|
728
|
+
if (!shouldCheckForUpdates(settings, attemptAt)) return null;
|
|
729
|
+
settings.lastUpdateCheckAt = attemptAt;
|
|
730
|
+
settings.lastUpdateCheckClaim = claimId;
|
|
731
|
+
return { attemptAt, claimId };
|
|
732
|
+
},
|
|
733
|
+
{ lockTimeoutMs: 0 }
|
|
734
|
+
);
|
|
735
|
+
} catch {
|
|
424
736
|
return;
|
|
425
737
|
}
|
|
738
|
+
if (!claim) return;
|
|
426
739
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
console.log(` Run: ${buildManualInstallCommand(getInstallPrefix(), true)}\n`);
|
|
740
|
+
let latestVersion;
|
|
741
|
+
try {
|
|
742
|
+
latestVersion = await fetcher({ unref: true });
|
|
743
|
+
} catch {
|
|
432
744
|
return;
|
|
433
745
|
}
|
|
746
|
+
if (!parseStableVersion(latestVersion)) return;
|
|
747
|
+
|
|
748
|
+
try {
|
|
749
|
+
transaction(
|
|
750
|
+
(settings) => {
|
|
751
|
+
if (
|
|
752
|
+
settings.autoCheckUpdates !== true ||
|
|
753
|
+
settings.lastUpdateCheckAt !== attemptAt ||
|
|
754
|
+
settings.lastUpdateCheckClaim !== claimId
|
|
755
|
+
) {
|
|
756
|
+
return false;
|
|
757
|
+
}
|
|
758
|
+
settings.lastSeenVersion = latestVersion;
|
|
759
|
+
settings.lastUpdateCheckClaim = null;
|
|
760
|
+
return true;
|
|
761
|
+
},
|
|
762
|
+
{ lockTimeoutMs: 0 }
|
|
763
|
+
);
|
|
764
|
+
} catch {
|
|
765
|
+
// Optional cache persistence must never affect command dispatch or output.
|
|
766
|
+
}
|
|
767
|
+
}
|
|
434
768
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
769
|
+
/**
|
|
770
|
+
* Synchronously render the startup cache and begin a due refresh without awaiting it.
|
|
771
|
+
* @returns {Promise<void>|null} the shared refresh, exposed for deterministic tests
|
|
772
|
+
*/
|
|
773
|
+
function checkForUpdates(options = {}) {
|
|
774
|
+
if (!options.eligibilityChecked && !isAutomaticUpdateEligible(options)) return null;
|
|
775
|
+
|
|
776
|
+
const currentVersion = options.currentVersion || getCurrentVersion();
|
|
777
|
+
if (!parseStableVersion(currentVersion)) return null;
|
|
778
|
+
const readSettings = options.loadSettings || loadSettings;
|
|
779
|
+
let settings;
|
|
780
|
+
try {
|
|
781
|
+
settings = readSettings({ silent: true });
|
|
782
|
+
} catch {
|
|
783
|
+
return null;
|
|
439
784
|
}
|
|
785
|
+
if (settings.autoCheckUpdates !== true) return null;
|
|
786
|
+
|
|
787
|
+
if (
|
|
788
|
+
parseStableVersion(settings.lastSeenVersion) &&
|
|
789
|
+
isNewerVersion(currentVersion, settings.lastSeenVersion)
|
|
790
|
+
) {
|
|
791
|
+
try {
|
|
792
|
+
const stderr = options.stderr || process.stderr;
|
|
793
|
+
stderr.write(
|
|
794
|
+
`Update available: ${currentVersion} ā ${settings.lastSeenVersion}. Run \`zeroshot update\`.\n`
|
|
795
|
+
);
|
|
796
|
+
} catch {
|
|
797
|
+
// Optional notification output failures are contained.
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
const now = options.now || Date.now;
|
|
802
|
+
if (!shouldCheckForUpdates(settings, now())) return null;
|
|
803
|
+
if (inFlightRefresh) return inFlightRefresh;
|
|
804
|
+
|
|
805
|
+
const refresh = new Promise((resolve) => {
|
|
806
|
+
const schedule = options.scheduleRefresh || setImmediate;
|
|
807
|
+
const handle = schedule(() => {
|
|
808
|
+
Promise.resolve(refreshUpdateCache(options))
|
|
809
|
+
.catch(() => {})
|
|
810
|
+
.then(resolve);
|
|
811
|
+
});
|
|
812
|
+
handle?.unref?.();
|
|
813
|
+
});
|
|
814
|
+
inFlightRefresh = refresh;
|
|
815
|
+
refresh.then(() => {
|
|
816
|
+
if (inFlightRefresh === refresh) inFlightRefresh = null;
|
|
817
|
+
});
|
|
818
|
+
return refresh;
|
|
440
819
|
}
|
|
441
820
|
|
|
442
821
|
module.exports = {
|
|
443
822
|
checkForUpdates,
|
|
823
|
+
isAutomaticUpdateEligible,
|
|
824
|
+
parseStableVersion,
|
|
825
|
+
validatedManifestVersion,
|
|
444
826
|
// Exported for testing and CLI update command
|
|
445
827
|
NEW_PACKAGE_NAME,
|
|
446
828
|
LEGACY_PACKAGE_NAME,
|
|
@@ -448,6 +830,7 @@ module.exports = {
|
|
|
448
830
|
getCurrentPackageName,
|
|
449
831
|
isLegacyDistro,
|
|
450
832
|
printLegacyDistroNotice,
|
|
833
|
+
shouldForceLegacyUpdate,
|
|
451
834
|
deriveInstallPrefixFromPackageRoot,
|
|
452
835
|
getInstallPrefix,
|
|
453
836
|
resolveNpmCommand,
|
|
@@ -456,7 +839,9 @@ module.exports = {
|
|
|
456
839
|
isNewerVersion,
|
|
457
840
|
fetchLatestVersion,
|
|
458
841
|
runUpdate,
|
|
842
|
+
runLegacyUpdateIfRequested,
|
|
459
843
|
shouldCheckForUpdates,
|
|
460
844
|
canWriteToNpmGlobal,
|
|
461
845
|
CHECK_INTERVAL_MS,
|
|
846
|
+
MAX_RESPONSE_BYTES,
|
|
462
847
|
};
|