cli-jaw 2.17.4 → 2.17.5

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 (56) hide show
  1. package/dist/bin/commands/serve.js +6 -8
  2. package/dist/bin/commands/serve.js.map +1 -1
  3. package/dist/bin/commands/service.js +49 -2
  4. package/dist/bin/commands/service.js.map +1 -1
  5. package/dist/server.js +7 -1
  6. package/dist/server.js.map +1 -1
  7. package/dist/src/agent/agy-capabilities.js +4 -6
  8. package/dist/src/agent/agy-capabilities.js.map +1 -1
  9. package/dist/src/agent/codex-app-client.js +6 -2
  10. package/dist/src/agent/codex-app-client.js.map +1 -1
  11. package/dist/src/agent/pi-runtime.js +18 -7
  12. package/dist/src/agent/pi-runtime.js.map +1 -1
  13. package/dist/src/agent/spawn/process-kill.js +31 -3
  14. package/dist/src/agent/spawn/process-kill.js.map +1 -1
  15. package/dist/src/agent/spawn-env.js +21 -0
  16. package/dist/src/agent/spawn-env.js.map +1 -1
  17. package/dist/src/agent/spawn.js +2 -2
  18. package/dist/src/agent/spawn.js.map +1 -1
  19. package/dist/src/cli/acp-client.js +3 -1
  20. package/dist/src/cli/acp-client.js.map +1 -1
  21. package/dist/src/cli/capability-probe-worker.js +8 -2
  22. package/dist/src/cli/capability-probe-worker.js.map +1 -1
  23. package/dist/src/cli/cli-status-worker.js +2 -1
  24. package/dist/src/cli/cli-status-worker.js.map +1 -1
  25. package/dist/src/cli/readiness.js +10 -34
  26. package/dist/src/cli/readiness.js.map +1 -1
  27. package/dist/src/core/browser-open.js +12 -2
  28. package/dist/src/core/browser-open.js.map +1 -1
  29. package/dist/src/core/cli-detection.js +3 -12
  30. package/dist/src/core/cli-detection.js.map +1 -1
  31. package/dist/src/core/instance-lifecycle.js +39 -5
  32. package/dist/src/core/instance-lifecycle.js.map +1 -1
  33. package/dist/src/core/probe-exec.js +72 -0
  34. package/dist/src/core/probe-exec.js.map +1 -0
  35. package/dist/src/core/tsx-spawn.js +32 -0
  36. package/dist/src/core/tsx-spawn.js.map +1 -0
  37. package/dist/src/lib/tui/bun-shim.mjs +5 -1
  38. package/dist/src/manager/server.js +7 -1
  39. package/dist/src/manager/server.js.map +1 -1
  40. package/dist/src/manager/windows-service.js +50 -17
  41. package/dist/src/manager/windows-service.js.map +1 -1
  42. package/dist/src/routes/messaging.js +12 -7
  43. package/dist/src/routes/messaging.js.map +1 -1
  44. package/dist/src/routes/quota.js +5 -10
  45. package/dist/src/routes/quota.js.map +1 -1
  46. package/package.json +3 -3
  47. package/scripts/check-native-load.cjs +21 -3
  48. package/scripts/generate-channel-capability-table.mts +9 -2
  49. package/scripts/install.ps1 +10 -2
  50. package/scripts/postinstall-guard.cjs +10 -12
  51. package/scripts/promote-to-main.sh +54 -1
  52. package/scripts/release-gates.mjs +54 -16
  53. package/scripts/require-release-evidence.mjs +14 -2
  54. package/scripts/run-with-env.mjs +30 -0
  55. package/scripts/sync-electron-version.cjs +35 -4
  56. package/scripts/verify-release-evidence.mjs +20 -0
@@ -390,6 +390,10 @@ if (!changed.length) {
390
390
 
391
391
  const macosEvidence = process.env.CLI_JAW_MACOS_EVIDENCE_DIR || process.env.MACOS_EVIDENCE_DIR || '';
392
392
  const wslEvidence = process.env.CLI_JAW_WSL_EVIDENCE_DIR || process.env.WSL_EVIDENCE_DIR || '';
393
+ // Optional third lane (#384): native Windows evidence. WSL is a Linux
394
+ // userland, so WSL evidence proves nothing about win32. The lane is optional
395
+ // until the ps1 collector and auditor target support land.
396
+ const windowsEvidence = process.env.CLI_JAW_WINDOWS_EVIDENCE_DIR || process.env.WINDOWS_EVIDENCE_DIR || '';
393
397
 
394
398
  console.error(`[release-evidence-required] installer-sensitive changes detected since ${ref || '(initial release)'} (${changed.length}, ${shortHash(changed)})`);
395
399
  for (const file of changed.slice(0, 30)) {
@@ -408,12 +412,18 @@ if (!macosEvidence || !wslEvidence) {
408
412
  'run', 'list',
409
413
  '--workflow', 'postinstall-platform.yml',
410
414
  '--commit', headSha,
411
- '--event', 'push',
412
415
  '--status', 'success',
413
416
  '--limit', '1',
414
417
  '--json', 'url',
415
418
  '--jq', '.[0].url // ""',
416
419
  ], { cwd: repoRoot, encoding: 'utf8', shell: false });
420
+ // No --event filter, mirroring bc7c19ba which already made publish.yml
421
+ // accept any-event Postinstall Platform Checks. A merge commit whose diff
422
+ // is empty (e.g. main merged back into preview after a promotion) never
423
+ // produces a push run for its own SHA, so requiring the push event made
424
+ // this gate unpassable for exactly the SHA a promotion certifies. Any
425
+ // successful run of the pinned workflow on this commit is the same
426
+ // evidence regardless of the event that started it.
417
427
  const ciUrl = (ciCheck.stdout || '').trim();
418
428
  if (ciUrl) {
419
429
  console.log(`[release-evidence-required] PASS CI postinstall-platform evidence: ${ciUrl}`);
@@ -433,7 +443,9 @@ if (!macosEvidence || !wslEvidence) {
433
443
  }
434
444
 
435
445
  const gate = path.join(__dirname, 'verify-release-evidence.mjs');
436
- const result = spawnSync(process.execPath, [gate, '--macos', macosEvidence, '--wsl', wslEvidence], {
446
+ const gateArgs = [gate, '--macos', macosEvidence, '--wsl', wslEvidence];
447
+ if (windowsEvidence) gateArgs.push('--windows', windowsEvidence);
448
+ const result = spawnSync(process.execPath, gateArgs, {
437
449
  cwd: repoRoot,
438
450
  env: process.env,
439
451
  encoding: 'utf8',
@@ -0,0 +1,30 @@
1
+ // Cross-platform env-prefixed script runner (#383). npm scripts on Windows run
2
+ // under cmd.exe, where the POSIX `VAR=value cmd` prefix is not syntax - it
3
+ // fails with "'VAR' is not recognized". Usage:
4
+ // node scripts/run-with-env.mjs VAR=value [VAR2=value2 ...] -- <cmd> [args...]
5
+ // The command runs through the current Node when it is a .mjs/.cjs/.js/.ts
6
+ // entry resolved via node_modules, else spawned directly.
7
+ import { spawn } from 'node:child_process';
8
+ import { createRequire } from 'node:module';
9
+
10
+ const argv = process.argv.slice(2);
11
+ const sep = argv.indexOf('--');
12
+ if (sep === -1) {
13
+ console.error('usage: node scripts/run-with-env.mjs VAR=value ... -- <cmd> [args...]');
14
+ process.exit(2);
15
+ }
16
+ const env = { ...process.env };
17
+ for (const pair of argv.slice(0, sep)) {
18
+ const eq = pair.indexOf('=');
19
+ if (eq === -1) { console.error(`not a VAR=value pair: ${pair}`); process.exit(2); }
20
+ env[pair.slice(0, eq)] = pair.slice(eq + 1);
21
+ }
22
+ const [cmd, ...args] = argv.slice(sep + 1);
23
+ const require = createRequire(import.meta.url);
24
+ // tsx runs through its JS entry so no .cmd shim is involved (#381/#382).
25
+ const spec = cmd === 'tsx'
26
+ ? { file: process.execPath, args: [require.resolve('tsx/cli'), ...args] }
27
+ : { file: cmd, args };
28
+ const child = spawn(spec.file, spec.args, { stdio: 'inherit', env });
29
+ child.on('exit', (code, signal) => process.exit(signal ? 1 : (code ?? 1)));
30
+ child.on('error', (err) => { console.error(err.message); process.exit(1); });
@@ -19,7 +19,9 @@
19
19
  * wrote something else.
20
20
  */
21
21
  const { readFileSync } = require('node:fs');
22
+ const { existsSync } = require('node:fs');
22
23
  const { join } = require('node:path');
24
+ const { dirname } = require('node:path');
23
25
  const { spawnSync } = require('node:child_process');
24
26
 
25
27
  const repoRoot = join(__dirname, '..');
@@ -41,6 +43,28 @@ function readVersion(dir) {
41
43
  }
42
44
  }
43
45
 
46
+ /**
47
+ * Resolve npm as [bin, ...baseArgs] runnable via spawnSync WITHOUT a shell.
48
+ * On Windows the bare name 'npm' is npm.cmd, and Node's spawnSync refuses to
49
+ * run .cmd/.bat files without shell:true (EINVAL since the CVE-2024-27980
50
+ * hardening) -- so the sync silently failed on every native-Windows release.
51
+ * Running npm-cli.js under the current node binary sidesteps both the shim
52
+ * and the shell. Same resolution ladder as scripts/ensure-native-modules.cjs.
53
+ */
54
+ function resolveNpmCommand() {
55
+ const nodeBinDir = dirname(process.execPath);
56
+ const candidates = [
57
+ process.env.npm_execpath,
58
+ join(nodeBinDir, 'node_modules', 'npm', 'bin', 'npm-cli.js'),
59
+ join(nodeBinDir, 'lib', 'node_modules', 'npm', 'bin', 'npm-cli.js'),
60
+ join(dirname(nodeBinDir), 'lib', 'node_modules', 'npm', 'bin', 'npm-cli.js'),
61
+ ].filter(Boolean);
62
+ for (const candidate of candidates) {
63
+ if (existsSync(candidate)) return [process.execPath, candidate];
64
+ }
65
+ return [process.platform === 'win32' ? 'npm.cmd' : 'npm'];
66
+ }
67
+
44
68
  function main() {
45
69
  let rootVersion;
46
70
  let electronVersion;
@@ -75,13 +99,20 @@ function main() {
75
99
  // both files directly means reimplementing the lockfile's shape, and
76
100
  // getting it subtly wrong surfaces later as unexplained churn in someone
77
101
  // else's dependency diff.
102
+ const [npmBin, ...npmBaseArgs] = resolveNpmCommand();
78
103
  const result = spawnSync(
79
- 'npm',
80
- ['version', rootVersion, '--no-git-tag-version', '--allow-same-version'],
81
- { cwd: electronDir, encoding: 'utf8', timeout: 60_000 },
104
+ npmBin,
105
+ [...npmBaseArgs, 'version', rootVersion, '--no-git-tag-version', '--allow-same-version'],
106
+ {
107
+ cwd: electronDir,
108
+ encoding: 'utf8',
109
+ timeout: 60_000,
110
+ // .cmd shims need a shell; the npm-cli.js path never takes this branch.
111
+ shell: npmBin.endsWith('.cmd'),
112
+ },
82
113
  );
83
114
  if (result.status !== 0) {
84
- const detail = (result.stderr || result.stdout || '').trim();
115
+ const detail = (result.stderr || result.stdout || (result.error && result.error.message) || '').trim();
85
116
  console.error(`ERROR: npm version failed in electron/: ${detail}`);
86
117
  return 1;
87
118
  }
@@ -13,6 +13,10 @@ function usage() {
13
13
  Options:
14
14
  --macos DIR Strict macOS fresh-machine evidence directory.
15
15
  --wsl DIR Strict Windows-via-WSL fresh-machine evidence directory.
16
+ --windows DIR Optional native-Windows evidence directory (plumbing lane,
17
+ #384). Validates the directory and the archived install.ps1
18
+ hash; the full native audit lands with the ps1 collector
19
+ (auditor targets are macos|wsl|linux today).
16
20
  --auditor FILE Auditor script path. Defaults to sibling audit-fresh-install-evidence.mjs.
17
21
  -h, --help Show this help.
18
22
 
@@ -24,12 +28,14 @@ flags to the per-target auditor.
24
28
  const args = process.argv.slice(2);
25
29
  let macosDir = '';
26
30
  let wslDir = '';
31
+ let windowsDir = '';
27
32
  let auditor = path.join(__dirname, 'audit-fresh-install-evidence.mjs');
28
33
  const currentScripts = {
29
34
  collector: path.join(__dirname, 'collect-fresh-install-evidence.sh'),
30
35
  verifier: path.join(__dirname, 'verify-fresh-install.sh'),
31
36
  macosInstaller: path.join(__dirname, 'install.sh'),
32
37
  wslInstaller: path.join(__dirname, 'install-wsl.sh'),
38
+ windowsInstaller: path.join(__dirname, 'install.ps1'),
33
39
  };
34
40
 
35
41
  for (let i = 0; i < args.length; i += 1) {
@@ -46,6 +52,10 @@ for (let i = 0; i < args.length; i += 1) {
46
52
  wslDir = args[++i] || '';
47
53
  continue;
48
54
  }
55
+ if (arg === '--windows') {
56
+ windowsDir = args[++i] || '';
57
+ continue;
58
+ }
49
59
  if (arg === '--auditor') {
50
60
  auditor = args[++i] || '';
51
61
  continue;
@@ -85,6 +95,10 @@ function requireFile(label, file) {
85
95
 
86
96
  requireDirectory('macOS', macosDir);
87
97
  requireDirectory('Windows-via-WSL', wslDir);
98
+ // Optional lane (#384): mandatory would break the package.json script, the
99
+ // README examples, and the literal-string tests. require-release-evidence
100
+ // passes it only when CLI_JAW_WINDOWS_EVIDENCE_DIR is set.
101
+ if (windowsDir) requireDirectory('Windows-native', windowsDir);
88
102
  requireFile('auditor', auditor);
89
103
  requireFile('current collector', currentScripts.collector);
90
104
  requireFile('current verifier', currentScripts.verifier);
@@ -145,6 +159,12 @@ if (!failures.length) {
145
159
  requireEvidenceScriptMatches('Windows-via-WSL', wslDir, '00-collector-script.sh', currentScripts.collector);
146
160
  requireEvidenceScriptMatches('Windows-via-WSL', wslDir, '02-installer-script.sh', currentScripts.wslInstaller);
147
161
  requireEvidenceScriptMatches('Windows-via-WSL', wslDir, '21-verifier-script.sh', currentScripts.verifier);
162
+ // Native-Windows plumbing lane (#384): hash-pin the archived installer to
163
+ // the shipped install.ps1. The full per-file audit needs a ps1 collector and
164
+ // auditor target support - recorded as its own unit, not silently skipped.
165
+ if (windowsDir) {
166
+ requireEvidenceScriptMatches('Windows-native', windowsDir, '02-installer-script.ps1', currentScripts.windowsInstaller);
167
+ }
148
168
  }
149
169
 
150
170
  if (failures.length) {