@youdie006/prodex 0.40.16 → 0.40.18
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 +4 -2
- package/SECURITY.md +45 -0
- package/dist/bridge-gitignore.js +47 -0
- package/dist/browser-handoff.js +29 -16
- package/dist/browser-process.js +196 -0
- package/dist/chatgpt-browser.js +51 -63
- package/dist/cli-args.js +8 -2
- package/dist/cli-pro.js +34 -4
- package/dist/cli.js +2 -4
- package/dist/config.js +13 -25
- package/dist/repo.js +9 -2
- package/dist/safe-file.js +57 -13
- package/dist/store-writer.js +20 -5
- package/dist/store.js +19 -26
- package/dist/tui-run.js +1 -1
- package/docs/cli-reference.md +3 -1
- package/docs/platform-verification.md +164 -0
- package/package.json +7 -2
- package/prodex.mjs +11 -0
- package/scripts/npm-command.mjs +71 -0
- package/scripts/release-check.mjs +18 -11
- package/scripts/release-pack.mjs +13 -4
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# Platform Verification
|
|
2
|
+
|
|
3
|
+
Open source does not mean every operating system, architecture, filesystem, or
|
|
4
|
+
browser version has been tested. This record distinguishes configured CI jobs,
|
|
5
|
+
completed checks, installed versions, and live account-dependent behavior.
|
|
6
|
+
|
|
7
|
+
## 0.40.18 verification
|
|
8
|
+
|
|
9
|
+
Branch: `fix/cross-platform-verification`.
|
|
10
|
+
Tracking PR: <https://github.com/youdie006/prodex/pull/6>.
|
|
11
|
+
Verified runtime commit: `ba9551be75586b7ab603964a6cbf117483578766`.
|
|
12
|
+
Completed six-job CI: <https://github.com/youdie006/prodex/actions/runs/34980308069>.
|
|
13
|
+
Final release/publication and machine installation records are kept in the
|
|
14
|
+
version-specific GitHub Release; this source verification is not an installation
|
|
15
|
+
or an existing-client reconnection claim.
|
|
16
|
+
|
|
17
|
+
| Environment | Completed result at verified runtime commit | Scope |
|
|
18
|
+
| --- | --- | --- |
|
|
19
|
+
| Ubuntu 24.04 x64, Node 20/22/24 | PASS | Each job: 1,614 passed, 0 failed, 3 platform exclusions; full release verification and headless smoke |
|
|
20
|
+
| macOS 15 ARM, Node 22 | PASS | 1,613 passed, 0 failed, 4 platform exclusions; full release verification and headless smoke |
|
|
21
|
+
| macOS 15 Intel, Node 22 | PASS | 1,613 passed, 0 failed, 4 platform exclusions; full release verification and headless smoke |
|
|
22
|
+
| Windows Server 2025 x64, Node 22 | PASS | 1,615 passed, 0 failed, 4 platform exclusions; metadata, installed-package verification and headless smoke |
|
|
23
|
+
| Windows 11 x64, Node 22.22.0 | Partial native verification | Actual installed command and fresh MCP passed; 42 CLI/product checks and 7 service-error checks passed. Local full security fixtures require file-symlink privileges and are not claimed as passed |
|
|
24
|
+
| WSL Linux x64, Node 22.22.0 | PASS | Full release verification: 1,614 passed, 0 failed, 3 platform exclusions; earlier real headless browser smoke also passed |
|
|
25
|
+
| Physical M3 macOS ARM, Node 22.22.3 | PASS | Full release verification: 1,613 passed, 0 failed, 4 platform exclusions; earlier real headless browser smoke also passed |
|
|
26
|
+
|
|
27
|
+
## Earlier attempts
|
|
28
|
+
|
|
29
|
+
Initial matrix commit: `37b1684795271f69afdca492562d99aa9c203e6d`.
|
|
30
|
+
CI run: <https://github.com/youdie006/prodex/actions/runs/34964947086>.
|
|
31
|
+
Integrated compatibility commit: `8569391d525e15e16e67665dbc19e04da53ee042`.
|
|
32
|
+
Integrated CI run: <https://github.com/youdie006/prodex/actions/runs/34970055803>.
|
|
33
|
+
Candidate commit: `33646bd4cdffca376f332f103f3c5a00932cf767`.
|
|
34
|
+
Candidate CI run: <https://github.com/youdie006/prodex/actions/runs/34974010179>.
|
|
35
|
+
Follow-up commit: `afec42d3e7f9f4e82601db6fe553dd742664f54d`.
|
|
36
|
+
Follow-up CI run: <https://github.com/youdie006/prodex/actions/runs/34976162000>.
|
|
37
|
+
|
|
38
|
+
The Windows initialization and junction regressions failed before correction and
|
|
39
|
+
passed afterward. Additional native checks reproduced file replacement and
|
|
40
|
+
concurrent initialization failures; their six focused regressions now pass.
|
|
41
|
+
The additional concurrent gitignore replacement regression passed on native
|
|
42
|
+
Windows after both initializers adopted the same verified, idempotent write path.
|
|
43
|
+
The later 48-test Windows run also passed the original concurrent follow-up
|
|
44
|
+
reservation test, npm credential-isolated dry runs, and anchored writer checks.
|
|
45
|
+
M3's first integrated command incorrectly exported `PRODEX_NO_AUTO_LOGIN=1`,
|
|
46
|
+
which disabled five mocked recovery tests. The complete release-verification
|
|
47
|
+
command passed after removing that conflicting harness override. No account
|
|
48
|
+
browser or login profile was used by those mocked tests.
|
|
49
|
+
The initial Windows suite also lacks file-symlink creation privileges on this
|
|
50
|
+
machine. This is recorded separately from product failures; no security test is
|
|
51
|
+
declared passed by ignoring an `EPERM` error. Directory-junction checks can run
|
|
52
|
+
without granting administrator privileges or changing Windows Developer Mode.
|
|
53
|
+
|
|
54
|
+
Candidate 0.40.18 uses the unique root bin `prodex.mjs`: native npm produced
|
|
55
|
+
archive modes 0755 for that bin and 0644 for `dist/cli.js` and `LICENSE`.
|
|
56
|
+
The native metadata check and independent tar-header inspection passed. An
|
|
57
|
+
initial root name `cli.js` was rejected because npm also marked the same-named
|
|
58
|
+
nested compiled file executable. Strict release checks were not relaxed.
|
|
59
|
+
WSL's installed-package smoke passed for the corrected 0.40.18 candidate.
|
|
60
|
+
At that point, final candidate CI and installation checks were still pending.
|
|
61
|
+
Native Windows focused reruns passed the 11 CLI regressions, two browser-send
|
|
62
|
+
and profile cases, and all 21 release-pack tests. The candidate package smoke
|
|
63
|
+
passed its formerly failing archive-mode check, then stopped at a real file
|
|
64
|
+
symlink creation `EPERM`; that run is partial, not a package-smoke pass.
|
|
65
|
+
The three link-swap regressions now assert their fixture was actually installed,
|
|
66
|
+
so an unsupported symlink operation cannot masquerade as a rejected attack.
|
|
67
|
+
|
|
68
|
+
One local staging attempt began before its source archive finished writing and
|
|
69
|
+
failed with a truncated TypeScript file. That invalid snapshot was discarded;
|
|
70
|
+
the complete archive was extracted and source hashes checked before rerunning.
|
|
71
|
+
This was a verification setup failure, not accepted product evidence.
|
|
72
|
+
|
|
73
|
+
The candidate Windows CI failure was reproduced locally by inheriting uppercase
|
|
74
|
+
`NPM_EXECPATH`. It silently displaced explicit lowercase overrides, causing real
|
|
75
|
+
npm to run instead of the intended fixture. After normalizing environment names
|
|
76
|
+
before subprocess creation, the native npm/release suites passed 54 tests with
|
|
77
|
+
one POSIX-only exclusion; their two file-symlink cases still failed with `EPERM`.
|
|
78
|
+
The matching WSL checks passed 91 tests with one Windows-only exclusion.
|
|
79
|
+
Follow-up changes also canonicalize Windows temporary paths, retain private-mode
|
|
80
|
+
assertions only where POSIX modes apply, bound Windows file concurrency to four,
|
|
81
|
+
and give the four-consult approval-renewal test a separate 60-second deadline.
|
|
82
|
+
Those corrections required the subsequent complete matrix before publication.
|
|
83
|
+
|
|
84
|
+
Follow-up commit `afec42d3e7f9f4e82601db6fe553dd742664f54d` was tested in
|
|
85
|
+
<https://github.com/youdie006/prodex/actions/runs/34976162000>. Ubuntu Node
|
|
86
|
+
20/22/24 and macOS ARM passed. Windows passed 1,597 tests with 8 failures and
|
|
87
|
+
4 platform exclusions: every failure was an unhandled process-inspection error
|
|
88
|
+
in product diagnostics. The strict Windows identity parser correctly refused
|
|
89
|
+
incomplete process records, but diagnostics incorrectly aborted the rest of the
|
|
90
|
+
report. The new regression reproduced that crash before correction. The fix
|
|
91
|
+
reports an unknown-identity blocker without login/reset guidance, keeps shutdown
|
|
92
|
+
ownership checks strict, and isolates refused-connection fixtures from the host's
|
|
93
|
+
real process table. Focused checks passed on native Windows (42 tests) and WSL
|
|
94
|
+
(49 tests); typecheck and the npm-helper declaration type probe also passed.
|
|
95
|
+
macOS Intel passed 1,600 tests with 4 exclusions and three 30-second timeouts:
|
|
96
|
+
the paired project-warning cases, paired terminal-state cases, and eight-task
|
|
97
|
+
concurrent creation. The independent cases are now separate tests, and the
|
|
98
|
+
concurrent case retains all eight tasks with a dedicated 60-second deadline.
|
|
99
|
+
All five affected cases passed on WSL after this test-only correction. The
|
|
100
|
+
subsequent complete matrix passed; no global or production timeout was raised.
|
|
101
|
+
The two affected storage/send files also passed all 178 tests on physical M3.
|
|
102
|
+
|
|
103
|
+
The user subsequently reported a rendered Cloudflare 502 page. Seven focused
|
|
104
|
+
regressions verify service-error classification, exclusion of ordinary chat
|
|
105
|
+
content, genuine authentication/protection precedence, and no automatic resend
|
|
106
|
+
after submission on both WSL and native Windows. The full affected browser,
|
|
107
|
+
process and product-check files passed 173 tests on WSL; typecheck passed.
|
|
108
|
+
The page error itself is upstream; these
|
|
109
|
+
simulated checks do not establish restored ChatGPT availability or a new live
|
|
110
|
+
Pro answer, and no visible login window or account profile reset was attempted.
|
|
111
|
+
|
|
112
|
+
The same `afec42d` snapshot passed full `CI=1 npm run release:verify` on WSL
|
|
113
|
+
(1,604 tests, 3 platform exclusions) and physical M3 (1,603 tests, 4 exclusions),
|
|
114
|
+
including installed-package checks. Native Windows installed the candidate into
|
|
115
|
+
a temporary consumer path containing spaces; its actual `prodex.cmd` launched a
|
|
116
|
+
fresh non-tmux MCP, reported 0.40.18 and 20 tools, and read the intended explicit
|
|
117
|
+
working-directory fixture. The transport exited and left no matching child
|
|
118
|
+
process. These are isolated candidate installs, not global deployment or public
|
|
119
|
+
publication. Existing account browsers and the attached MCP were not restarted.
|
|
120
|
+
|
|
121
|
+
## What each check proves
|
|
122
|
+
|
|
123
|
+
- Unit/integration tests: local ledger, routing, path policy, and simulated UI.
|
|
124
|
+
- Package smoke: installed CLI and MCP transports against disposable local data.
|
|
125
|
+
- Browser launch smoke: a fresh headless profile with `about:blank`, CDP readiness,
|
|
126
|
+
script evaluation, owned-process shutdown, and cleanup. No ChatGPT login.
|
|
127
|
+
- Live Pro verification: a separate, manually triggered account test with request
|
|
128
|
+
identity, model evidence, and saved result validation. None of the checks above
|
|
129
|
+
substitutes for this test.
|
|
130
|
+
|
|
131
|
+
## Limits and prerequisites
|
|
132
|
+
|
|
133
|
+
- Node 20+, Git, ripgrep, and a supported Chromium-family browser are prerequisites.
|
|
134
|
+
- Virtual display requires Linux/WSL, Xvfb and xauth. Native macOS and Windows do
|
|
135
|
+
not support this mode; they must report that limitation without opening a window.
|
|
136
|
+
- WSL uses a Linux browser/profile. Native Windows browser discovery is not WSL
|
|
137
|
+
cross-host browser support.
|
|
138
|
+
- Native Windows storage inherits Windows ACLs. See [SECURITY.md](../SECURITY.md#local-storage-permissions).
|
|
139
|
+
- Generated native Windows commands target PowerShell, not `cmd.exe`; compound
|
|
140
|
+
examples with `&&` require PowerShell 7. Internal subprocesses use literal argv.
|
|
141
|
+
- Authentication, CAPTCHA, Cloudflare, permissions, and usage limits remain
|
|
142
|
+
explicit blockers. No automatic visible fallback or protection bypass is tested.
|
|
143
|
+
- ARM Windows, Linux ARM, BSD, containers without browser dependencies, and every
|
|
144
|
+
historical OS/browser version are not covered by this matrix.
|
|
145
|
+
|
|
146
|
+
## Installation and running processes
|
|
147
|
+
|
|
148
|
+
At the start of this work WSL and M3 had CLI 0.40.17 installed. The MCP attached to
|
|
149
|
+
the existing Codex client still had 0.40.16 loaded. Updating a package on disk does
|
|
150
|
+
not reconnect that MCP or change an already-running browser's mode. No client
|
|
151
|
+
restart has been performed in this verification task.
|
|
152
|
+
|
|
153
|
+
The previously verified WSL no-desktop-window session uses ordinary headed Chrome
|
|
154
|
+
on a private virtual display. It is not pure headless Chrome. M3's prior pure
|
|
155
|
+
headless ChatGPT check stopped at Cloudflare. Neither installing this branch nor
|
|
156
|
+
passing a no-account browser launch test removes that account-dependent blocker.
|
|
157
|
+
|
|
158
|
+
After the reported 502, bounded read-only probes on 2026-09-15 at approximately
|
|
159
|
+
14:38 UTC used the tested candidate adapter against the existing dedicated
|
|
160
|
+
browsers. WSL was reachable with saved-login signals and a composer, with no
|
|
161
|
+
blocker. M3 was reachable but returned `cloudflare_check`, not a 502. Neither
|
|
162
|
+
probe opened a browser, changed profiles, reloaded a page, logged in, or sent a
|
|
163
|
+
prompt. WSL readiness does not prove the upstream error's cause or a new Pro
|
|
164
|
+
answer; M3 authenticated pure-headless access remains blocked.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@youdie006/prodex",
|
|
3
|
-
"version": "0.40.
|
|
3
|
+
"version": "0.40.18",
|
|
4
4
|
"description": "Local receipt bus for coordinating Codex execution with ChatGPT Pro/Projects consultation.",
|
|
5
5
|
"author": "youdie006",
|
|
6
6
|
"license": "MIT",
|
|
@@ -26,18 +26,22 @@
|
|
|
26
26
|
],
|
|
27
27
|
"type": "module",
|
|
28
28
|
"bin": {
|
|
29
|
-
"prodex": "
|
|
29
|
+
"prodex": "prodex.mjs"
|
|
30
30
|
},
|
|
31
31
|
"exports": {},
|
|
32
32
|
"files": [
|
|
33
|
+
"prodex.mjs",
|
|
33
34
|
"dist",
|
|
34
35
|
"LICENSE",
|
|
35
36
|
"README.md",
|
|
37
|
+
"SECURITY.md",
|
|
36
38
|
"docs/claude.md",
|
|
37
39
|
"docs/clients.md",
|
|
38
40
|
"docs/http-mcp.md",
|
|
39
41
|
"docs/releasing.md",
|
|
40
42
|
"docs/cli-reference.md",
|
|
43
|
+
"docs/platform-verification.md",
|
|
44
|
+
"scripts/npm-command.mjs",
|
|
41
45
|
"scripts/release-check.mjs",
|
|
42
46
|
"scripts/release-pack.mjs"
|
|
43
47
|
],
|
|
@@ -49,6 +53,7 @@
|
|
|
49
53
|
"release:pack": "node scripts/release-pack.mjs",
|
|
50
54
|
"release:verify": "node scripts/release-check.mjs --verification-only",
|
|
51
55
|
"smoke:package": "node scripts/package-smoke.mjs",
|
|
56
|
+
"smoke:browser": "node scripts/browser-launch-smoke.mjs",
|
|
52
57
|
"test": "vitest run",
|
|
53
58
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
54
59
|
"prepack": "npm run build",
|
package/prodex.mjs
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { runCli } from "./dist/cli.js";
|
|
3
|
+
|
|
4
|
+
runCli(process.argv.slice(2))
|
|
5
|
+
.then((code) => {
|
|
6
|
+
if (code !== 0) process.exitCode = code;
|
|
7
|
+
})
|
|
8
|
+
.catch((error) => {
|
|
9
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
10
|
+
process.exitCode = 1;
|
|
11
|
+
});
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { realpathSync, statSync } from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { promisify } from "node:util";
|
|
5
|
+
|
|
6
|
+
const execFileAsync = promisify(execFile);
|
|
7
|
+
|
|
8
|
+
export function resolveNpmCliPath(options = {}) {
|
|
9
|
+
const env = normalizeNpmEnvironment(options.env ?? process.env);
|
|
10
|
+
const execPath = options.execPath ?? process.execPath;
|
|
11
|
+
const cwd = options.cwd ?? process.cwd();
|
|
12
|
+
const candidates = [];
|
|
13
|
+
const npmExecPath = envValue(env, "npm_execpath");
|
|
14
|
+
if (npmExecPath && !isCompetingPackageManagerCli(npmExecPath)) candidates.push(path.resolve(cwd, npmExecPath));
|
|
15
|
+
|
|
16
|
+
const pathValue = envValue(env, "PATH");
|
|
17
|
+
for (const entry of pathValue?.split(path.delimiter) ?? []) {
|
|
18
|
+
if (!entry) continue;
|
|
19
|
+
for (const commandName of process.platform === "win32" ? ["npm.cmd", "npm.exe", "npm"] : ["npm"]) {
|
|
20
|
+
const commandPath = path.join(entry, commandName);
|
|
21
|
+
const resolvedCommand = existingJavaScriptFile(commandPath);
|
|
22
|
+
if (resolvedCommand) candidates.push(resolvedCommand);
|
|
23
|
+
}
|
|
24
|
+
candidates.push(path.join(entry, "node_modules", "npm", "bin", "npm-cli.js"));
|
|
25
|
+
candidates.push(path.resolve(entry, "..", "lib", "node_modules", "npm", "bin", "npm-cli.js"));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const nodeDir = path.dirname(execPath);
|
|
29
|
+
candidates.push(path.join(nodeDir, "node_modules", "npm", "bin", "npm-cli.js"));
|
|
30
|
+
candidates.push(path.resolve(nodeDir, "..", "lib", "node_modules", "npm", "bin", "npm-cli.js"));
|
|
31
|
+
|
|
32
|
+
for (const candidate of candidates) {
|
|
33
|
+
const resolved = existingJavaScriptFile(candidate);
|
|
34
|
+
if (resolved) return resolved;
|
|
35
|
+
}
|
|
36
|
+
throw new Error(`Could not locate npm's JavaScript CLI for ${execPath}`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function execNpm(args, options = {}) {
|
|
40
|
+
const env = normalizeNpmEnvironment(options.env ?? process.env);
|
|
41
|
+
const npmCliPath = resolveNpmCliPath({ cwd: options.cwd, env, execPath: process.execPath });
|
|
42
|
+
return execFileAsync(process.execPath, [npmCliPath, ...args], { ...options, env, encoding: "utf8" });
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function normalizeNpmEnvironment(env, platform = process.platform) {
|
|
46
|
+
if (platform !== "win32") return env;
|
|
47
|
+
// Node otherwise sorts duplicate Windows names and can keep the inherited
|
|
48
|
+
// spelling instead of an explicit override appended by the caller.
|
|
49
|
+
const entries = new Map();
|
|
50
|
+
for (const [name, value] of Object.entries(env)) entries.set(name.toLowerCase(), [name, value]);
|
|
51
|
+
return Object.fromEntries(entries.values());
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function envValue(env, name) {
|
|
55
|
+
if (typeof env[name] === "string") return env[name];
|
|
56
|
+
const entry = Object.entries(env).find(([key, value]) => key.toLowerCase() === name.toLowerCase() && typeof value === "string");
|
|
57
|
+
return entry?.[1];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function isCompetingPackageManagerCli(candidate) {
|
|
61
|
+
return /^(?:pnpm|pnpx|yarn|yarnpkg)(?:\.(?:cjs|mjs|js))?$/i.test(path.basename(candidate));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function existingJavaScriptFile(candidate) {
|
|
65
|
+
try {
|
|
66
|
+
const resolved = realpathSync(candidate);
|
|
67
|
+
return /\.(?:cjs|mjs|js)$/i.test(resolved) && statSync(resolved).isFile() ? resolved : undefined;
|
|
68
|
+
} catch {
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -4,6 +4,7 @@ import { lstat, readFile } from "node:fs/promises";
|
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
import { promisify } from "node:util";
|
|
7
|
+
import { execNpm } from "./npm-command.mjs";
|
|
7
8
|
|
|
8
9
|
const execFileAsync = promisify(execFile);
|
|
9
10
|
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
@@ -159,7 +160,7 @@ async function runFullReleaseVerification(rootDir) {
|
|
|
159
160
|
];
|
|
160
161
|
for (const [command, commandArgs] of checks) {
|
|
161
162
|
const key = [command, ...commandArgs].join(" ");
|
|
162
|
-
await run(
|
|
163
|
+
await run(command, commandArgs, rootDir, CHECK_TIMEOUT_MS[key] ?? CHECK_TIMEOUT_MS.default);
|
|
163
164
|
}
|
|
164
165
|
}
|
|
165
166
|
|
|
@@ -205,7 +206,7 @@ async function assertPackedFileModes(rootDir, packageJson) {
|
|
|
205
206
|
async function readPackedFiles(rootDir) {
|
|
206
207
|
let stdout;
|
|
207
208
|
try {
|
|
208
|
-
({ stdout } = await
|
|
209
|
+
({ stdout } = await execNpm(["pack", "--json", "--dry-run", "--ignore-scripts"], {
|
|
209
210
|
cwd: rootDir,
|
|
210
211
|
timeout: 120_000,
|
|
211
212
|
maxBuffer: 20 * 1024 * 1024
|
|
@@ -282,6 +283,9 @@ function findNonExecutableBinPackedFiles(files, packageJson) {
|
|
|
282
283
|
}
|
|
283
284
|
|
|
284
285
|
async function findNonExecutableBinSourceFiles(rootDir, packageJson) {
|
|
286
|
+
// Windows ACLs do not map to POSIX execute bits. npm still reports package
|
|
287
|
+
// bin entries with canonical executable modes in the packed file metadata.
|
|
288
|
+
if (process.platform === "win32") return [];
|
|
285
289
|
const invalid = [];
|
|
286
290
|
for (const packagePath of packageBinPaths(packageJson)) {
|
|
287
291
|
const filePath = path.join(rootDir, packagePath);
|
|
@@ -349,11 +353,18 @@ async function run(command, commandArgs, cwd, timeoutMs = 300_000) {
|
|
|
349
353
|
const commandLine = [command, ...commandArgs].join(" ");
|
|
350
354
|
console.log(`release_check: ${commandLine}`);
|
|
351
355
|
try {
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
356
|
+
const execute = command === "npm"
|
|
357
|
+
? execNpm(commandArgs, {
|
|
358
|
+
cwd,
|
|
359
|
+
timeout: timeoutMs,
|
|
360
|
+
maxBuffer: 20 * 1024 * 1024
|
|
361
|
+
})
|
|
362
|
+
: execFileAsync(command === "node" ? process.execPath : command, commandArgs, {
|
|
363
|
+
cwd,
|
|
364
|
+
timeout: timeoutMs,
|
|
365
|
+
maxBuffer: 20 * 1024 * 1024
|
|
366
|
+
});
|
|
367
|
+
await execute;
|
|
357
368
|
} catch (error) {
|
|
358
369
|
// Surface the real failure: the one-line detail used to show the FIRST
|
|
359
370
|
// stderr line, which npm noise ("npm warn ...") could occupy while the
|
|
@@ -376,10 +387,6 @@ function printCapturedOutputTail(error, commandLine) {
|
|
|
376
387
|
}
|
|
377
388
|
}
|
|
378
389
|
|
|
379
|
-
function commandForPlatform(command) {
|
|
380
|
-
return process.platform === "win32" && command === "npm" ? "npm.cmd" : command;
|
|
381
|
-
}
|
|
382
|
-
|
|
383
390
|
function parseArgs(values) {
|
|
384
391
|
const parsed = {
|
|
385
392
|
root: undefined,
|
package/scripts/release-pack.mjs
CHANGED
|
@@ -5,10 +5,10 @@ import { tmpdir } from "node:os";
|
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
7
7
|
import { promisify } from "node:util";
|
|
8
|
+
import { execNpm } from "./npm-command.mjs";
|
|
8
9
|
|
|
9
10
|
const execFileAsync = promisify(execFile);
|
|
10
11
|
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
11
|
-
const npmCommand = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
12
12
|
|
|
13
13
|
try {
|
|
14
14
|
const args = parseArgs(process.argv.slice(2));
|
|
@@ -71,7 +71,7 @@ async function ensureDistBuiltForSource(root) {
|
|
|
71
71
|
const tsconfigPath = path.join(root, "tsconfig.json");
|
|
72
72
|
const srcDir = path.join(root, "src");
|
|
73
73
|
if (!(await pathExists(tsconfigPath)) || !(await pathExists(srcDir))) return false;
|
|
74
|
-
await
|
|
74
|
+
await execNpm(["run", "build"], { cwd: root, maxBuffer: 20 * 1024 * 1024 });
|
|
75
75
|
return true;
|
|
76
76
|
}
|
|
77
77
|
|
|
@@ -211,7 +211,11 @@ async function run(command, commandArgs, cwd) {
|
|
|
211
211
|
|
|
212
212
|
async function runNpmPack(commandArgs, cwd, label) {
|
|
213
213
|
try {
|
|
214
|
-
return await
|
|
214
|
+
return await execNpm(commandArgs, {
|
|
215
|
+
cwd,
|
|
216
|
+
timeout: 120_000,
|
|
217
|
+
maxBuffer: 20 * 1024 * 1024
|
|
218
|
+
});
|
|
215
219
|
} catch (error) {
|
|
216
220
|
throw new Error(`${label} failed: ${commandFailureDetail(error)}`);
|
|
217
221
|
}
|
|
@@ -340,7 +344,12 @@ function errorMessage(error) {
|
|
|
340
344
|
}
|
|
341
345
|
|
|
342
346
|
function shellQuote(value) {
|
|
343
|
-
|
|
347
|
+
const shellSafe = /^[A-Za-z0-9_./:@=-]+$/.test(value);
|
|
348
|
+
if (shellSafe && (process.platform !== "win32" || !value.startsWith("@"))) return value;
|
|
349
|
+
const escaped = process.platform === "win32"
|
|
350
|
+
? value.replaceAll("'", "''")
|
|
351
|
+
: value.replaceAll("'", "'\\''");
|
|
352
|
+
return `'${escaped}'`;
|
|
344
353
|
}
|
|
345
354
|
|
|
346
355
|
async function readReleaseGitStatus(root) {
|