@wrongstack/tools 0.297.0 → 0.298.1
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/dist/_spawn-stream.d.ts +2 -0
- package/dist/_util.d.ts +29 -1
- package/dist/audit.js +113 -65
- package/dist/bash.js +5 -4
- package/dist/batch-tool-use.js +70 -7
- package/dist/browser/index.js +31 -1
- package/dist/builtin.js +908 -390
- package/dist/codebase-index/index.js +68 -16
- package/dist/codebase-index/project-server-protocol.d.ts +26 -0
- package/dist/codebase-index/project-server.js +60 -16
- package/dist/codebase-index/worker.js +36 -13
- package/dist/codebase-index/writer-search-helpers.d.ts +16 -0
- package/dist/codebase-index/writer.d.ts +13 -1
- package/dist/design.d.ts +1 -1
- package/dist/design.js +4 -3
- package/dist/diff.js +11 -1
- package/dist/e2e.js +9 -6
- package/dist/edit.js +9 -6
- package/dist/exec-allowlist.d.ts +15 -0
- package/dist/exec.js +627 -568
- package/dist/format.js +116 -65
- package/dist/git.js +22 -2
- package/dist/glob.js +11 -5
- package/dist/grep.js +160 -104
- package/dist/index.js +859 -329
- package/dist/install.js +120 -68
- package/dist/json.js +64 -18
- package/dist/kanban-board-inputs.d.ts +21 -4
- package/dist/kanban.js +20 -5
- package/dist/languages/index.js +128 -71
- package/dist/lint.js +113 -65
- package/dist/outdated.js +86 -26
- package/dist/pack.js +908 -390
- package/dist/patch.js +11 -1
- package/dist/plan.js +32 -10
- package/dist/read.js +77 -23
- package/dist/replace.js +11 -3
- package/dist/scaffold.js +9 -6
- package/dist/session-kanban.js +21 -5
- package/dist/task.js +3 -1
- package/dist/test.js +113 -65
- package/dist/todo.js +3 -1
- package/dist/tool-tier.js +908 -390
- package/dist/tool-use.d.ts +1 -1
- package/dist/tool-use.js +28 -4
- package/dist/tree.d.ts +1 -0
- package/dist/tree.js +44 -8
- package/dist/typecheck.js +113 -65
- package/dist/write.js +9 -6
- package/package.json +7 -6
- package/dist/_concurrency.d.ts.map +0 -1
- package/dist/_danger-detect.d.ts.map +0 -1
- package/dist/_edit-match.d.ts.map +0 -1
- package/dist/_env.d.ts.map +0 -1
- package/dist/_fetch-guard.d.ts.map +0 -1
- package/dist/_output-spool.d.ts.map +0 -1
- package/dist/_redact-command.d.ts.map +0 -1
- package/dist/_regex.d.ts.map +0 -1
- package/dist/_session-shell.d.ts.map +0 -1
- package/dist/_shell-pick.d.ts.map +0 -1
- package/dist/_spawn-stream.d.ts.map +0 -1
- package/dist/_syntax-check.d.ts.map +0 -1
- package/dist/_util.d.ts.map +0 -1
- package/dist/_win32-resolve.d.ts.map +0 -1
- package/dist/audit.d.ts.map +0 -1
- package/dist/audit.js.map +0 -7
- package/dist/auto-proceed-loop-guard.d.ts.map +0 -1
- package/dist/auto-proceed-loop-guard.js.map +0 -7
- package/dist/bash-kill-guard.d.ts.map +0 -1
- package/dist/bash.d.ts.map +0 -1
- package/dist/bash.js.map +0 -7
- package/dist/batch-tool-use.d.ts.map +0 -1
- package/dist/batch-tool-use.js.map +0 -7
- package/dist/browser/artifacts.d.ts.map +0 -1
- package/dist/browser/index.d.ts.map +0 -1
- package/dist/browser/index.js.map +0 -7
- package/dist/browser/manager.d.ts.map +0 -1
- package/dist/browser/network-guard-proxy.d.ts.map +0 -1
- package/dist/browser/security.d.ts.map +0 -1
- package/dist/browser/tools.d.ts.map +0 -1
- package/dist/browser/types.d.ts.map +0 -1
- package/dist/builtin.d.ts.map +0 -1
- package/dist/builtin.js.map +0 -7
- package/dist/circuit-breaker.d.ts.map +0 -1
- package/dist/circuit-breaker.js.map +0 -7
- package/dist/codebase-index/background-indexer.d.ts.map +0 -1
- package/dist/codebase-index/bm25.d.ts.map +0 -1
- package/dist/codebase-index/circuit-breaker.d.ts.map +0 -1
- package/dist/codebase-index/codebase-index-tool.d.ts.map +0 -1
- package/dist/codebase-index/codebase-search-tool.d.ts.map +0 -1
- package/dist/codebase-index/codebase-stats-tool.d.ts.map +0 -1
- package/dist/codebase-index/dead-code-scan.d.ts.map +0 -1
- package/dist/codebase-index/generic-parser.d.ts.map +0 -1
- package/dist/codebase-index/gitignore.d.ts.map +0 -1
- package/dist/codebase-index/go-parser.d.ts.map +0 -1
- package/dist/codebase-index/index-service.d.ts.map +0 -1
- package/dist/codebase-index/index.d.ts.map +0 -1
- package/dist/codebase-index/index.js.map +0 -7
- package/dist/codebase-index/indexer.d.ts.map +0 -1
- package/dist/codebase-index/json-parser.d.ts.map +0 -1
- package/dist/codebase-index/languages.d.ts.map +0 -1
- package/dist/codebase-index/lsp-kind.d.ts.map +0 -1
- package/dist/codebase-index/parser-dispatch.d.ts.map +0 -1
- package/dist/codebase-index/project-server-cache.d.ts.map +0 -1
- package/dist/codebase-index/project-server-client.d.ts.map +0 -1
- package/dist/codebase-index/project-server-endpoint.d.ts.map +0 -1
- package/dist/codebase-index/project-server-protocol.d.ts.map +0 -1
- package/dist/codebase-index/project-server.d.ts.map +0 -1
- package/dist/codebase-index/project-server.js.map +0 -7
- package/dist/codebase-index/py-parser.d.ts.map +0 -1
- package/dist/codebase-index/refs-extractor.d.ts.map +0 -1
- package/dist/codebase-index/rs-parser.d.ts.map +0 -1
- package/dist/codebase-index/schema.d.ts.map +0 -1
- package/dist/codebase-index/spawn-gate.d.ts.map +0 -1
- package/dist/codebase-index/sqlite-runtime.d.ts.map +0 -1
- package/dist/codebase-index/ts-parser.d.ts.map +0 -1
- package/dist/codebase-index/worker-protocol.d.ts.map +0 -1
- package/dist/codebase-index/worker.d.ts.map +0 -1
- package/dist/codebase-index/worker.js.map +0 -7
- package/dist/codebase-index/writer-admin.d.ts.map +0 -1
- package/dist/codebase-index/writer-bulk-insert.d.ts.map +0 -1
- package/dist/codebase-index/writer-graph-helpers.d.ts.map +0 -1
- package/dist/codebase-index/writer-graph-reader.d.ts.map +0 -1
- package/dist/codebase-index/writer-helpers.d.ts.map +0 -1
- package/dist/codebase-index/writer-pragmas.d.ts.map +0 -1
- package/dist/codebase-index/writer-ref-mapper.d.ts.map +0 -1
- package/dist/codebase-index/writer-schema.d.ts.map +0 -1
- package/dist/codebase-index/writer-search-helpers.d.ts.map +0 -1
- package/dist/codebase-index/writer-store-pool.d.ts.map +0 -1
- package/dist/codebase-index/writer.d.ts.map +0 -1
- package/dist/codebase-index/yaml-parser.d.ts.map +0 -1
- package/dist/design.d.ts.map +0 -1
- package/dist/design.js.map +0 -7
- package/dist/diff.d.ts.map +0 -1
- package/dist/diff.js.map +0 -7
- package/dist/document.d.ts.map +0 -1
- package/dist/document.js.map +0 -7
- package/dist/e2e.d.ts.map +0 -1
- package/dist/e2e.js.map +0 -7
- package/dist/edit.d.ts.map +0 -1
- package/dist/edit.js.map +0 -7
- package/dist/exec-kill-guard.d.ts.map +0 -1
- package/dist/exec.d.ts.map +0 -1
- package/dist/exec.js.map +0 -7
- package/dist/fetch.d.ts.map +0 -1
- package/dist/fetch.js.map +0 -7
- package/dist/format.d.ts.map +0 -1
- package/dist/format.js.map +0 -7
- package/dist/git.d.ts.map +0 -1
- package/dist/git.js.map +0 -7
- package/dist/glob.d.ts.map +0 -1
- package/dist/glob.js.map +0 -7
- package/dist/grep.d.ts.map +0 -1
- package/dist/grep.js.map +0 -7
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -7
- package/dist/install.d.ts.map +0 -1
- package/dist/install.js.map +0 -7
- package/dist/json.d.ts.map +0 -1
- package/dist/json.js.map +0 -7
- package/dist/kanban-board-inputs.d.ts.map +0 -1
- package/dist/kanban-decomposition-actions.d.ts.map +0 -1
- package/dist/kanban-detail-actions.d.ts.map +0 -1
- package/dist/kanban-evidence-bridge.d.ts.map +0 -1
- package/dist/kanban-presence.d.ts.map +0 -1
- package/dist/kanban-split-task-handler.d.ts.map +0 -1
- package/dist/kanban-task-inputs.d.ts.map +0 -1
- package/dist/kanban-tool-results.d.ts.map +0 -1
- package/dist/kanban-tool-schema.d.ts.map +0 -1
- package/dist/kanban-tool-types.d.ts.map +0 -1
- package/dist/kanban.d.ts.map +0 -1
- package/dist/kanban.js.map +0 -7
- package/dist/languages/detect.d.ts.map +0 -1
- package/dist/languages/diagnostics.d.ts.map +0 -1
- package/dist/languages/execute-tool.d.ts.map +0 -1
- package/dist/languages/execute.d.ts.map +0 -1
- package/dist/languages/index.d.ts.map +0 -1
- package/dist/languages/index.js.map +0 -7
- package/dist/languages/legacy-bridge.d.ts.map +0 -1
- package/dist/languages/package-tool.d.ts.map +0 -1
- package/dist/languages/plan.d.ts.map +0 -1
- package/dist/languages/profile-helpers.d.ts.map +0 -1
- package/dist/languages/profiles/additional.d.ts.map +0 -1
- package/dist/languages/profiles/primary.d.ts.map +0 -1
- package/dist/languages/registry.d.ts.map +0 -1
- package/dist/languages/tool.d.ts.map +0 -1
- package/dist/languages/types.d.ts.map +0 -1
- package/dist/lint.d.ts.map +0 -1
- package/dist/lint.js.map +0 -7
- package/dist/logs.d.ts.map +0 -1
- package/dist/logs.js.map +0 -7
- package/dist/memory.d.ts.map +0 -1
- package/dist/memory.js.map +0 -7
- package/dist/mode.d.ts.map +0 -1
- package/dist/mode.js.map +0 -7
- package/dist/next-steps.d.ts.map +0 -1
- package/dist/next-steps.js.map +0 -7
- package/dist/outdated.d.ts.map +0 -1
- package/dist/outdated.js.map +0 -7
- package/dist/pack.d.ts.map +0 -1
- package/dist/pack.js.map +0 -7
- package/dist/patch.d.ts.map +0 -1
- package/dist/patch.js.map +0 -7
- package/dist/plan.d.ts.map +0 -1
- package/dist/plan.js.map +0 -7
- package/dist/process-guardian.d.ts.map +0 -1
- package/dist/process-registry-persistent.d.ts.map +0 -1
- package/dist/process-registry.d.ts.map +0 -1
- package/dist/process-registry.js.map +0 -7
- package/dist/ps-slash.d.ts.map +0 -1
- package/dist/ps-slash.js.map +0 -7
- package/dist/read.d.ts.map +0 -1
- package/dist/read.js.map +0 -7
- package/dist/replace.d.ts.map +0 -1
- package/dist/replace.js.map +0 -7
- package/dist/scaffold.d.ts.map +0 -1
- package/dist/scaffold.js.map +0 -7
- package/dist/search.d.ts.map +0 -1
- package/dist/search.js.map +0 -7
- package/dist/session-kanban.d.ts.map +0 -1
- package/dist/session-kanban.js.map +0 -7
- package/dist/set-working-dir.d.ts.map +0 -1
- package/dist/skill.d.ts.map +0 -1
- package/dist/skill.js.map +0 -7
- package/dist/spawn-background.d.ts.map +0 -1
- package/dist/task.d.ts.map +0 -1
- package/dist/task.js.map +0 -7
- package/dist/test.d.ts.map +0 -1
- package/dist/test.js.map +0 -7
- package/dist/todo.d.ts.map +0 -1
- package/dist/todo.js.map +0 -7
- package/dist/tool-diff.d.ts.map +0 -1
- package/dist/tool-diff.js.map +0 -7
- package/dist/tool-help.d.ts.map +0 -1
- package/dist/tool-help.js.map +0 -7
- package/dist/tool-icon-map.d.ts.map +0 -1
- package/dist/tool-icons.d.ts.map +0 -1
- package/dist/tool-icons.js.map +0 -7
- package/dist/tool-search.d.ts.map +0 -1
- package/dist/tool-search.js.map +0 -7
- package/dist/tool-summary.d.ts.map +0 -1
- package/dist/tool-summary.js.map +0 -7
- package/dist/tool-tier.d.ts.map +0 -1
- package/dist/tool-tier.js.map +0 -7
- package/dist/tool-use.d.ts.map +0 -1
- package/dist/tool-use.js.map +0 -7
- package/dist/tree.d.ts.map +0 -1
- package/dist/tree.js.map +0 -7
- package/dist/typecheck.d.ts.map +0 -1
- package/dist/typecheck.js.map +0 -7
- package/dist/win32.d.ts.map +0 -1
- package/dist/win32.js.map +0 -7
- package/dist/write.d.ts.map +0 -1
- package/dist/write.js.map +0 -7
package/dist/languages/index.js
CHANGED
|
@@ -1465,8 +1465,8 @@ async function scanDirectory(directory, depth, profiles, limits, state, extraIgn
|
|
|
1465
1465
|
collectFileEvidence(directory, fullPath, entry.name, profiles, state);
|
|
1466
1466
|
}
|
|
1467
1467
|
}
|
|
1468
|
-
function collectFileEvidence(directory, fullPath,
|
|
1469
|
-
const lower =
|
|
1468
|
+
function collectFileEvidence(directory, fullPath, basename5, profiles, state) {
|
|
1469
|
+
const lower = basename5.toLowerCase();
|
|
1470
1470
|
const extension = path.extname(lower);
|
|
1471
1471
|
for (const profile of profiles) {
|
|
1472
1472
|
const detector = profile.detectors.find(
|
|
@@ -1477,7 +1477,7 @@ function collectFileEvidence(directory, fullPath, basename4, profiles, state) {
|
|
|
1477
1477
|
candidate.evidence.push({
|
|
1478
1478
|
kind: detector.kind,
|
|
1479
1479
|
path: fullPath,
|
|
1480
|
-
value:
|
|
1480
|
+
value: basename5,
|
|
1481
1481
|
weight: detector.weight
|
|
1482
1482
|
});
|
|
1483
1483
|
if (detector.kind === "manifest" || detector.kind === "config") {
|
|
@@ -2206,11 +2206,12 @@ function createOutputSpool(opts) {
|
|
|
2206
2206
|
return {
|
|
2207
2207
|
write(text) {
|
|
2208
2208
|
if (finalized || !text) return;
|
|
2209
|
-
|
|
2209
|
+
const textBytes = Buffer.byteLength(text, "utf8");
|
|
2210
|
+
totalBytes += textBytes;
|
|
2210
2211
|
if (!stream && !failed) {
|
|
2211
|
-
if (headBytes +
|
|
2212
|
+
if (headBytes + textBytes <= threshold) {
|
|
2212
2213
|
head += text;
|
|
2213
|
-
headBytes +=
|
|
2214
|
+
headBytes += textBytes;
|
|
2214
2215
|
return;
|
|
2215
2216
|
}
|
|
2216
2217
|
head += text;
|
|
@@ -2220,7 +2221,7 @@ function createOutputSpool(opts) {
|
|
|
2220
2221
|
}
|
|
2221
2222
|
if (stream) {
|
|
2222
2223
|
if (stream.writableLength > SPOOL_WRITE_HWM_BYTES) {
|
|
2223
|
-
droppedBytes +=
|
|
2224
|
+
droppedBytes += textBytes;
|
|
2224
2225
|
return;
|
|
2225
2226
|
}
|
|
2226
2227
|
stream.write(text);
|
|
@@ -2242,6 +2243,52 @@ function createOutputSpool(opts) {
|
|
|
2242
2243
|
};
|
|
2243
2244
|
}
|
|
2244
2245
|
|
|
2246
|
+
// src/_win32-resolve.ts
|
|
2247
|
+
import * as fs2 from "node:fs";
|
|
2248
|
+
import * as path4 from "node:path";
|
|
2249
|
+
function resolveWin32Command(cmd) {
|
|
2250
|
+
if (process.platform !== "win32") return cmd;
|
|
2251
|
+
if (cmd.includes("/") || cmd.includes("\\") || path4.extname(cmd.replace(/\//g, "\\"))) {
|
|
2252
|
+
return cmd;
|
|
2253
|
+
}
|
|
2254
|
+
const pathext = (process.env["PATHEXT"] ?? ".COM;.EXE;.BAT;.CMD;.VBS;.JS;.WS;.MSC").toLowerCase().split(";");
|
|
2255
|
+
const pathDirs = (process.env["PATH"] ?? "").split(path4.delimiter);
|
|
2256
|
+
for (const dir of pathDirs) {
|
|
2257
|
+
const base = path4.join(dir, cmd);
|
|
2258
|
+
for (const ext of pathext) {
|
|
2259
|
+
const full = `${base}${ext}`;
|
|
2260
|
+
try {
|
|
2261
|
+
fs2.accessSync(full, fs2.constants.X_OK);
|
|
2262
|
+
return full;
|
|
2263
|
+
} catch {
|
|
2264
|
+
}
|
|
2265
|
+
}
|
|
2266
|
+
}
|
|
2267
|
+
return cmd;
|
|
2268
|
+
}
|
|
2269
|
+
var WIN32_SHELL_META = /[&|<>"\r\n\0]/;
|
|
2270
|
+
function assertSafeWin32ShellArgs(args) {
|
|
2271
|
+
for (const arg of args) {
|
|
2272
|
+
if (typeof arg === "string" && WIN32_SHELL_META.test(arg)) {
|
|
2273
|
+
throw new Error(
|
|
2274
|
+
'win32 cmd shim spawn: argument contains a shell metacharacter (one of & | < > ", or a newline) that could enable command injection through the .cmd/.bat wrapper - refusing to run. Offending argument: ' + JSON.stringify(arg)
|
|
2275
|
+
);
|
|
2276
|
+
}
|
|
2277
|
+
}
|
|
2278
|
+
}
|
|
2279
|
+
function buildWin32CmdShimInvocation(command, args = []) {
|
|
2280
|
+
assertSafeWin32ShellArgs([command, ...args]);
|
|
2281
|
+
const line = ["call", quoteWin32CmdArg(command), ...args.map(quoteWin32CmdArg)].join(" ");
|
|
2282
|
+
return {
|
|
2283
|
+
command: process.env["COMSPEC"] ?? "cmd.exe",
|
|
2284
|
+
args: ["/d", "/c", line],
|
|
2285
|
+
windowsVerbatimArguments: true
|
|
2286
|
+
};
|
|
2287
|
+
}
|
|
2288
|
+
function quoteWin32CmdArg(arg) {
|
|
2289
|
+
return `"${arg}"`;
|
|
2290
|
+
}
|
|
2291
|
+
|
|
2245
2292
|
// src/process-registry.ts
|
|
2246
2293
|
import { spawn } from "node:child_process";
|
|
2247
2294
|
import * as os from "node:os";
|
|
@@ -2866,60 +2913,17 @@ function getProcessRegistry() {
|
|
|
2866
2913
|
return _registry;
|
|
2867
2914
|
}
|
|
2868
2915
|
|
|
2869
|
-
// src/_win32-resolve.ts
|
|
2870
|
-
import * as fs2 from "node:fs";
|
|
2871
|
-
import * as path4 from "node:path";
|
|
2872
|
-
function resolveWin32Command(cmd) {
|
|
2873
|
-
if (process.platform !== "win32") return cmd;
|
|
2874
|
-
if (cmd.includes("/") || cmd.includes("\\") || path4.extname(cmd.replace(/\//g, "\\"))) {
|
|
2875
|
-
return cmd;
|
|
2876
|
-
}
|
|
2877
|
-
const pathext = (process.env["PATHEXT"] ?? ".COM;.EXE;.BAT;.CMD;.VBS;.JS;.WS;.MSC").toLowerCase().split(";");
|
|
2878
|
-
const pathDirs = (process.env["PATH"] ?? "").split(path4.delimiter);
|
|
2879
|
-
for (const dir of pathDirs) {
|
|
2880
|
-
const base = path4.join(dir, cmd);
|
|
2881
|
-
for (const ext of pathext) {
|
|
2882
|
-
const full = `${base}${ext}`;
|
|
2883
|
-
try {
|
|
2884
|
-
fs2.accessSync(full, fs2.constants.X_OK);
|
|
2885
|
-
return full;
|
|
2886
|
-
} catch {
|
|
2887
|
-
}
|
|
2888
|
-
}
|
|
2889
|
-
}
|
|
2890
|
-
return cmd;
|
|
2891
|
-
}
|
|
2892
|
-
var WIN32_SHELL_META = /[&|<>"\r\n\0]/;
|
|
2893
|
-
function assertSafeWin32ShellArgs(args) {
|
|
2894
|
-
for (const arg of args) {
|
|
2895
|
-
if (typeof arg === "string" && WIN32_SHELL_META.test(arg)) {
|
|
2896
|
-
throw new Error(
|
|
2897
|
-
'win32 cmd shim spawn: argument contains a shell metacharacter (one of & | < > ", or a newline) that could enable command injection through the .cmd/.bat wrapper - refusing to run. Offending argument: ' + JSON.stringify(arg)
|
|
2898
|
-
);
|
|
2899
|
-
}
|
|
2900
|
-
}
|
|
2901
|
-
}
|
|
2902
|
-
function buildWin32CmdShimInvocation(command, args = []) {
|
|
2903
|
-
assertSafeWin32ShellArgs([command, ...args]);
|
|
2904
|
-
const line = ["call", quoteWin32CmdArg(command), ...args.map(quoteWin32CmdArg)].join(" ");
|
|
2905
|
-
return {
|
|
2906
|
-
command: process.env["COMSPEC"] ?? "cmd.exe",
|
|
2907
|
-
args: ["/d", "/c", line],
|
|
2908
|
-
windowsVerbatimArguments: true
|
|
2909
|
-
};
|
|
2910
|
-
}
|
|
2911
|
-
function quoteWin32CmdArg(arg) {
|
|
2912
|
-
return `"${arg}"`;
|
|
2913
|
-
}
|
|
2914
|
-
|
|
2915
2916
|
// src/_spawn-stream.ts
|
|
2916
2917
|
var isWin = process.platform === "win32";
|
|
2917
2918
|
async function* spawnStream(opts) {
|
|
2918
2919
|
const max = opts.maxBytes ?? 2e5;
|
|
2919
2920
|
const flushAt = opts.flushBytes ?? 4 * 1024;
|
|
2920
2921
|
const maxQueue = opts.maxQueueSize ?? 500;
|
|
2922
|
+
const maxQueueBytes = opts.maxQueueBytes ?? 1024 * 1024;
|
|
2921
2923
|
let stdout = "";
|
|
2922
2924
|
let stderr = "";
|
|
2925
|
+
let stdoutRetainedBytes = 0;
|
|
2926
|
+
let stderrRetainedBytes = 0;
|
|
2923
2927
|
let pending = "";
|
|
2924
2928
|
let error;
|
|
2925
2929
|
const spool = createOutputSpool({ tool: opts.cmd, thresholdBytes: max });
|
|
@@ -2961,6 +2965,7 @@ async function* spawnStream(opts) {
|
|
|
2961
2965
|
});
|
|
2962
2966
|
}
|
|
2963
2967
|
const queue = [];
|
|
2968
|
+
let queuedBytes = 0;
|
|
2964
2969
|
let waiter;
|
|
2965
2970
|
let paused = false;
|
|
2966
2971
|
const wake = () => {
|
|
@@ -2971,7 +2976,7 @@ async function* spawnStream(opts) {
|
|
|
2971
2976
|
}
|
|
2972
2977
|
};
|
|
2973
2978
|
const resume = () => {
|
|
2974
|
-
if (paused && queue.length
|
|
2979
|
+
if (paused && queue.length <= Math.floor(maxQueue / 2) && queuedBytes <= Math.floor(maxQueueBytes / 2)) {
|
|
2975
2980
|
paused = false;
|
|
2976
2981
|
child.stdout?.resume();
|
|
2977
2982
|
child.stderr?.resume();
|
|
@@ -2981,11 +2986,16 @@ async function* spawnStream(opts) {
|
|
|
2981
2986
|
const s = c.toString();
|
|
2982
2987
|
stdoutBytes += c.byteLength;
|
|
2983
2988
|
emitProcessOutput({ pid, stream: "stdout", chunk: c });
|
|
2984
|
-
if (
|
|
2989
|
+
if (stdoutRetainedBytes < max) {
|
|
2990
|
+
const retained = utf8Prefix(s, max - stdoutRetainedBytes);
|
|
2991
|
+
stdout += retained;
|
|
2992
|
+
stdoutRetainedBytes += Buffer.byteLength(retained, "utf8");
|
|
2993
|
+
}
|
|
2985
2994
|
spool.write(s);
|
|
2986
|
-
queue.push({ kind: "out", data: s });
|
|
2995
|
+
queue.push({ kind: "out", data: s, bytes: c.byteLength });
|
|
2996
|
+
queuedBytes += c.byteLength;
|
|
2987
2997
|
wake();
|
|
2988
|
-
if (!paused && queue.length >= maxQueue) {
|
|
2998
|
+
if (!paused && (queue.length >= maxQueue || queuedBytes >= maxQueueBytes)) {
|
|
2989
2999
|
paused = true;
|
|
2990
3000
|
child.stdout?.pause();
|
|
2991
3001
|
child.stderr?.pause();
|
|
@@ -2995,11 +3005,16 @@ async function* spawnStream(opts) {
|
|
|
2995
3005
|
const s = c.toString();
|
|
2996
3006
|
stderrBytes += c.byteLength;
|
|
2997
3007
|
emitProcessOutput({ pid, stream: "stderr", chunk: c });
|
|
2998
|
-
if (
|
|
3008
|
+
if (stderrRetainedBytes < max) {
|
|
3009
|
+
const retained = utf8Prefix(s, max - stderrRetainedBytes);
|
|
3010
|
+
stderr += retained;
|
|
3011
|
+
stderrRetainedBytes += Buffer.byteLength(retained, "utf8");
|
|
3012
|
+
}
|
|
2999
3013
|
spool.write(s);
|
|
3000
|
-
queue.push({ kind: "err", data: s });
|
|
3014
|
+
queue.push({ kind: "err", data: s, bytes: c.byteLength });
|
|
3015
|
+
queuedBytes += c.byteLength;
|
|
3001
3016
|
wake();
|
|
3002
|
-
if (!paused && queue.length >= maxQueue) {
|
|
3017
|
+
if (!paused && (queue.length >= maxQueue || queuedBytes >= maxQueueBytes)) {
|
|
3003
3018
|
paused = true;
|
|
3004
3019
|
child.stdout?.pause();
|
|
3005
3020
|
child.stderr?.pause();
|
|
@@ -3009,7 +3024,9 @@ async function* spawnStream(opts) {
|
|
|
3009
3024
|
child.stderr?.on("data", onErr);
|
|
3010
3025
|
child.on("error", (e) => {
|
|
3011
3026
|
error = e.message;
|
|
3012
|
-
|
|
3027
|
+
const bytes = Buffer.byteLength(e.message, "utf8");
|
|
3028
|
+
queue.push({ kind: "error", data: e.message, bytes });
|
|
3029
|
+
queuedBytes += bytes;
|
|
3013
3030
|
wake();
|
|
3014
3031
|
});
|
|
3015
3032
|
const completeTelemetry = (code, signal, timedOut = false) => {
|
|
@@ -3030,7 +3047,13 @@ async function* spawnStream(opts) {
|
|
|
3030
3047
|
if (typeof pid === "number") registry.unregister(pid);
|
|
3031
3048
|
const exitCode2 = code ?? (signal ? 1 : 0);
|
|
3032
3049
|
completeTelemetry(exitCode2, signal ?? void 0);
|
|
3033
|
-
queue.push({
|
|
3050
|
+
queue.push({
|
|
3051
|
+
kind: "close",
|
|
3052
|
+
data: "",
|
|
3053
|
+
bytes: 0,
|
|
3054
|
+
code: exitCode2,
|
|
3055
|
+
...signal ? { signal } : {}
|
|
3056
|
+
});
|
|
3034
3057
|
wake();
|
|
3035
3058
|
});
|
|
3036
3059
|
const onAbort = () => {
|
|
@@ -3042,7 +3065,7 @@ async function* spawnStream(opts) {
|
|
|
3042
3065
|
} catch {
|
|
3043
3066
|
}
|
|
3044
3067
|
}
|
|
3045
|
-
queue.push({ kind: "close", data: "", code: 124 });
|
|
3068
|
+
queue.push({ kind: "close", data: "", bytes: 0, code: 124 });
|
|
3046
3069
|
completeTelemetry(124, "SIGKILL", true);
|
|
3047
3070
|
wake();
|
|
3048
3071
|
};
|
|
@@ -3060,6 +3083,7 @@ async function* spawnStream(opts) {
|
|
|
3060
3083
|
});
|
|
3061
3084
|
}
|
|
3062
3085
|
const chunk = queue.shift();
|
|
3086
|
+
queuedBytes -= chunk.bytes;
|
|
3063
3087
|
resume();
|
|
3064
3088
|
if (chunk.kind === "close") {
|
|
3065
3089
|
if (!spawnFailed) exitCode = chunk.code ?? 0;
|
|
@@ -3086,7 +3110,7 @@ async function* spawnStream(opts) {
|
|
|
3086
3110
|
stdout: spooled ? stdout + spoolNote(spooled) : stdout,
|
|
3087
3111
|
stderr,
|
|
3088
3112
|
exitCode,
|
|
3089
|
-
truncated:
|
|
3113
|
+
truncated: stdoutBytes > stdoutRetainedBytes || stderrBytes > stderrRetainedBytes,
|
|
3090
3114
|
error,
|
|
3091
3115
|
spoolPath: spooled?.path,
|
|
3092
3116
|
spoolBytes: spooled?.bytes
|
|
@@ -3110,6 +3134,20 @@ async function* spawnStream(opts) {
|
|
|
3110
3134
|
}
|
|
3111
3135
|
}
|
|
3112
3136
|
}
|
|
3137
|
+
function utf8Prefix(text, maxBytes) {
|
|
3138
|
+
if (maxBytes <= 0) return "";
|
|
3139
|
+
if (Buffer.byteLength(text, "utf8") <= maxBytes) return text;
|
|
3140
|
+
let low = 0;
|
|
3141
|
+
let high = text.length;
|
|
3142
|
+
while (low < high) {
|
|
3143
|
+
const mid = Math.ceil((low + high) / 2);
|
|
3144
|
+
if (Buffer.byteLength(text.slice(0, mid), "utf8") <= maxBytes) low = mid;
|
|
3145
|
+
else high = mid - 1;
|
|
3146
|
+
}
|
|
3147
|
+
let end = low;
|
|
3148
|
+
if (end > 0 && /[\uD800-\uDBFF]/.test(text[end - 1])) end--;
|
|
3149
|
+
return text.slice(0, end);
|
|
3150
|
+
}
|
|
3113
3151
|
|
|
3114
3152
|
// src/_util.ts
|
|
3115
3153
|
import * as fsp2 from "node:fs/promises";
|
|
@@ -3136,12 +3174,13 @@ function ensureInsideRoot(absPath, ctx) {
|
|
|
3136
3174
|
function safeResolve(input, ctx) {
|
|
3137
3175
|
return ensureInsideRoot(resolvePath(input, ctx), ctx);
|
|
3138
3176
|
}
|
|
3139
|
-
async function
|
|
3140
|
-
if (ctx.allowOutsideProjectRoot) return;
|
|
3177
|
+
async function resolveRealInsideRoot(absPath, ctx) {
|
|
3178
|
+
if (ctx.allowOutsideProjectRoot) return absPath;
|
|
3141
3179
|
const realRoots = await Promise.all(
|
|
3142
3180
|
allowedRoots(ctx).map((r) => fsp2.realpath(r).catch(() => path5.resolve(r)))
|
|
3143
3181
|
);
|
|
3144
3182
|
let probe = absPath;
|
|
3183
|
+
const pendingTail = [];
|
|
3145
3184
|
for (; ; ) {
|
|
3146
3185
|
let real;
|
|
3147
3186
|
try {
|
|
@@ -3149,13 +3188,16 @@ async function assertRealInsideRoot(absPath, ctx) {
|
|
|
3149
3188
|
} catch (err) {
|
|
3150
3189
|
if (err.code === "ENOENT") {
|
|
3151
3190
|
const parent = path5.dirname(probe);
|
|
3152
|
-
if (parent === probe) return;
|
|
3191
|
+
if (parent === probe) return absPath;
|
|
3192
|
+
pendingTail.unshift(path5.basename(probe));
|
|
3153
3193
|
probe = parent;
|
|
3154
3194
|
continue;
|
|
3155
3195
|
}
|
|
3156
3196
|
throw err;
|
|
3157
3197
|
}
|
|
3158
|
-
if (isInsideAny(real, realRoots))
|
|
3198
|
+
if (isInsideAny(real, realRoots)) {
|
|
3199
|
+
return pendingTail.length > 0 ? path5.join(real, ...pendingTail) : real;
|
|
3200
|
+
}
|
|
3159
3201
|
throw new Error(
|
|
3160
3202
|
`Path "${absPath}" resolves through a symlink outside project root "${realRoots[0]}"`
|
|
3161
3203
|
);
|
|
@@ -3163,8 +3205,7 @@ async function assertRealInsideRoot(absPath, ctx) {
|
|
|
3163
3205
|
}
|
|
3164
3206
|
async function safeResolveReal(input, ctx) {
|
|
3165
3207
|
const abs = safeResolve(input, ctx);
|
|
3166
|
-
await
|
|
3167
|
-
return abs;
|
|
3208
|
+
return await resolveRealInsideRoot(abs, ctx);
|
|
3168
3209
|
}
|
|
3169
3210
|
var COMMAND_OUTPUT_MAX_BYTES = 32768;
|
|
3170
3211
|
var REPEAT_RUN_THRESHOLD = 3;
|
|
@@ -3244,10 +3285,11 @@ var MAX_ARGUMENTS = 128;
|
|
|
3244
3285
|
var MAX_ARGUMENT_LENGTH = 4096;
|
|
3245
3286
|
var PACKAGE_NAME_RE = /^(?:@[a-z0-9._-]+\/)?[a-z0-9._-]+(?:@[a-z0-9*+._~^<>=|-]+)?$/i;
|
|
3246
3287
|
var COMPOSER_PACKAGE_RE = /^[a-z0-9_.-]+\/[a-z0-9_.-]+(?::[a-z0-9*+._~^<>=|-]+)?$/i;
|
|
3247
|
-
var GO_MODULE_RE = /^(?:[a-z0-9
|
|
3288
|
+
var GO_MODULE_RE = /^(?:[a-z0-9-]+\.)+[a-z0-9-]+\/[a-z0-9._~+/@-]+$/i;
|
|
3248
3289
|
var PYTHON_PACKAGE_RE = /^[a-z0-9._-]+(?:\[[a-z0-9._,-]+\])?==[a-z0-9*+._!~-]+$/i;
|
|
3249
3290
|
async function planLanguageOperation(options) {
|
|
3250
3291
|
validateOperationOptions(options.operation, options.operationOptions?.packages);
|
|
3292
|
+
validateFilterOption(options.operationOptions?.filter);
|
|
3251
3293
|
const detection = await detectLanguageWorkspaces(options);
|
|
3252
3294
|
const candidates = detection.workspaces.filter(
|
|
3253
3295
|
(workspace) => workspace.capabilities.includes(options.operation)
|
|
@@ -3420,6 +3462,15 @@ function workspaceDepth(workspaceRoot, projectRoot) {
|
|
|
3420
3462
|
const relative5 = path6.relative(path6.resolve(projectRoot), path6.resolve(workspaceRoot));
|
|
3421
3463
|
return relative5 === "" ? 0 : relative5.split(path6.sep).length;
|
|
3422
3464
|
}
|
|
3465
|
+
function validateFilterOption(filter) {
|
|
3466
|
+
if (filter === void 0) return;
|
|
3467
|
+
if (filter.startsWith("-") || filter.includes(" --")) {
|
|
3468
|
+
throw new Error(`Invalid test filter (parsed as a runner option): "${filter}"`);
|
|
3469
|
+
}
|
|
3470
|
+
if (filter.length > MAX_ARGUMENT_LENGTH || /[\r\n\0]/.test(filter)) {
|
|
3471
|
+
throw new Error("Invalid test filter (oversized or contains a control character)");
|
|
3472
|
+
}
|
|
3473
|
+
}
|
|
3423
3474
|
function validateOperationOptions(operation, packages) {
|
|
3424
3475
|
if (!operation.startsWith("package-") || !packages) return;
|
|
3425
3476
|
for (const value of packages) {
|
|
@@ -3957,6 +4008,9 @@ var languageTool = {
|
|
|
3957
4008
|
useInstead: ["language_info", "install", "audit", "outdated"]
|
|
3958
4009
|
},
|
|
3959
4010
|
permission: "confirm",
|
|
4011
|
+
// WS-046: gives permission decisions something to key on.
|
|
4012
|
+
// The action performed (build/test/lint); the cwd is where, not what.
|
|
4013
|
+
subjectKey: "action",
|
|
3960
4014
|
mutating: true,
|
|
3961
4015
|
riskTier: "standard",
|
|
3962
4016
|
capabilities: ["shell.restricted", "fs.write"],
|
|
@@ -4214,6 +4268,9 @@ var languagePackageTool = {
|
|
|
4214
4268
|
useInstead: ["language_info", "language", "install", "audit", "outdated"]
|
|
4215
4269
|
},
|
|
4216
4270
|
permission: "confirm",
|
|
4271
|
+
// WS-046: gives permission decisions something to key on.
|
|
4272
|
+
// The package operation performed — install/remove are not interchangeable.
|
|
4273
|
+
subjectKey: "operation",
|
|
4217
4274
|
mutating: true,
|
|
4218
4275
|
riskTier: "destructive",
|
|
4219
4276
|
capabilities: ["shell.restricted", "fs.write", "net.outbound", "package.install"],
|
package/dist/lint.js
CHANGED
|
@@ -78,11 +78,12 @@ function createOutputSpool(opts) {
|
|
|
78
78
|
return {
|
|
79
79
|
write(text) {
|
|
80
80
|
if (finalized || !text) return;
|
|
81
|
-
|
|
81
|
+
const textBytes = Buffer.byteLength(text, "utf8");
|
|
82
|
+
totalBytes += textBytes;
|
|
82
83
|
if (!stream && !failed) {
|
|
83
|
-
if (headBytes +
|
|
84
|
+
if (headBytes + textBytes <= threshold) {
|
|
84
85
|
head += text;
|
|
85
|
-
headBytes +=
|
|
86
|
+
headBytes += textBytes;
|
|
86
87
|
return;
|
|
87
88
|
}
|
|
88
89
|
head += text;
|
|
@@ -92,7 +93,7 @@ function createOutputSpool(opts) {
|
|
|
92
93
|
}
|
|
93
94
|
if (stream) {
|
|
94
95
|
if (stream.writableLength > SPOOL_WRITE_HWM_BYTES) {
|
|
95
|
-
droppedBytes +=
|
|
96
|
+
droppedBytes += textBytes;
|
|
96
97
|
return;
|
|
97
98
|
}
|
|
98
99
|
stream.write(text);
|
|
@@ -114,6 +115,52 @@ function createOutputSpool(opts) {
|
|
|
114
115
|
};
|
|
115
116
|
}
|
|
116
117
|
|
|
118
|
+
// src/_win32-resolve.ts
|
|
119
|
+
import * as fs from "node:fs";
|
|
120
|
+
import * as path2 from "node:path";
|
|
121
|
+
function resolveWin32Command(cmd) {
|
|
122
|
+
if (process.platform !== "win32") return cmd;
|
|
123
|
+
if (cmd.includes("/") || cmd.includes("\\") || path2.extname(cmd.replace(/\//g, "\\"))) {
|
|
124
|
+
return cmd;
|
|
125
|
+
}
|
|
126
|
+
const pathext = (process.env["PATHEXT"] ?? ".COM;.EXE;.BAT;.CMD;.VBS;.JS;.WS;.MSC").toLowerCase().split(";");
|
|
127
|
+
const pathDirs = (process.env["PATH"] ?? "").split(path2.delimiter);
|
|
128
|
+
for (const dir of pathDirs) {
|
|
129
|
+
const base = path2.join(dir, cmd);
|
|
130
|
+
for (const ext of pathext) {
|
|
131
|
+
const full = `${base}${ext}`;
|
|
132
|
+
try {
|
|
133
|
+
fs.accessSync(full, fs.constants.X_OK);
|
|
134
|
+
return full;
|
|
135
|
+
} catch {
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return cmd;
|
|
140
|
+
}
|
|
141
|
+
var WIN32_SHELL_META = /[&|<>"\r\n\0]/;
|
|
142
|
+
function assertSafeWin32ShellArgs(args) {
|
|
143
|
+
for (const arg of args) {
|
|
144
|
+
if (typeof arg === "string" && WIN32_SHELL_META.test(arg)) {
|
|
145
|
+
throw new Error(
|
|
146
|
+
'win32 cmd shim spawn: argument contains a shell metacharacter (one of & | < > ", or a newline) that could enable command injection through the .cmd/.bat wrapper - refusing to run. Offending argument: ' + JSON.stringify(arg)
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
function buildWin32CmdShimInvocation(command, args = []) {
|
|
152
|
+
assertSafeWin32ShellArgs([command, ...args]);
|
|
153
|
+
const line = ["call", quoteWin32CmdArg(command), ...args.map(quoteWin32CmdArg)].join(" ");
|
|
154
|
+
return {
|
|
155
|
+
command: process.env["COMSPEC"] ?? "cmd.exe",
|
|
156
|
+
args: ["/d", "/c", line],
|
|
157
|
+
windowsVerbatimArguments: true
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
function quoteWin32CmdArg(arg) {
|
|
161
|
+
return `"${arg}"`;
|
|
162
|
+
}
|
|
163
|
+
|
|
117
164
|
// src/process-registry.ts
|
|
118
165
|
import { spawn } from "node:child_process";
|
|
119
166
|
import * as os from "node:os";
|
|
@@ -738,60 +785,17 @@ function getProcessRegistry() {
|
|
|
738
785
|
return _registry;
|
|
739
786
|
}
|
|
740
787
|
|
|
741
|
-
// src/_win32-resolve.ts
|
|
742
|
-
import * as fs from "node:fs";
|
|
743
|
-
import * as path2 from "node:path";
|
|
744
|
-
function resolveWin32Command(cmd) {
|
|
745
|
-
if (process.platform !== "win32") return cmd;
|
|
746
|
-
if (cmd.includes("/") || cmd.includes("\\") || path2.extname(cmd.replace(/\//g, "\\"))) {
|
|
747
|
-
return cmd;
|
|
748
|
-
}
|
|
749
|
-
const pathext = (process.env["PATHEXT"] ?? ".COM;.EXE;.BAT;.CMD;.VBS;.JS;.WS;.MSC").toLowerCase().split(";");
|
|
750
|
-
const pathDirs = (process.env["PATH"] ?? "").split(path2.delimiter);
|
|
751
|
-
for (const dir of pathDirs) {
|
|
752
|
-
const base = path2.join(dir, cmd);
|
|
753
|
-
for (const ext of pathext) {
|
|
754
|
-
const full = `${base}${ext}`;
|
|
755
|
-
try {
|
|
756
|
-
fs.accessSync(full, fs.constants.X_OK);
|
|
757
|
-
return full;
|
|
758
|
-
} catch {
|
|
759
|
-
}
|
|
760
|
-
}
|
|
761
|
-
}
|
|
762
|
-
return cmd;
|
|
763
|
-
}
|
|
764
|
-
var WIN32_SHELL_META = /[&|<>"\r\n\0]/;
|
|
765
|
-
function assertSafeWin32ShellArgs(args) {
|
|
766
|
-
for (const arg of args) {
|
|
767
|
-
if (typeof arg === "string" && WIN32_SHELL_META.test(arg)) {
|
|
768
|
-
throw new Error(
|
|
769
|
-
'win32 cmd shim spawn: argument contains a shell metacharacter (one of & | < > ", or a newline) that could enable command injection through the .cmd/.bat wrapper - refusing to run. Offending argument: ' + JSON.stringify(arg)
|
|
770
|
-
);
|
|
771
|
-
}
|
|
772
|
-
}
|
|
773
|
-
}
|
|
774
|
-
function buildWin32CmdShimInvocation(command, args = []) {
|
|
775
|
-
assertSafeWin32ShellArgs([command, ...args]);
|
|
776
|
-
const line = ["call", quoteWin32CmdArg(command), ...args.map(quoteWin32CmdArg)].join(" ");
|
|
777
|
-
return {
|
|
778
|
-
command: process.env["COMSPEC"] ?? "cmd.exe",
|
|
779
|
-
args: ["/d", "/c", line],
|
|
780
|
-
windowsVerbatimArguments: true
|
|
781
|
-
};
|
|
782
|
-
}
|
|
783
|
-
function quoteWin32CmdArg(arg) {
|
|
784
|
-
return `"${arg}"`;
|
|
785
|
-
}
|
|
786
|
-
|
|
787
788
|
// src/_spawn-stream.ts
|
|
788
789
|
var isWin = process.platform === "win32";
|
|
789
790
|
async function* spawnStream(opts) {
|
|
790
791
|
const max = opts.maxBytes ?? 2e5;
|
|
791
792
|
const flushAt = opts.flushBytes ?? 4 * 1024;
|
|
792
793
|
const maxQueue = opts.maxQueueSize ?? 500;
|
|
794
|
+
const maxQueueBytes = opts.maxQueueBytes ?? 1024 * 1024;
|
|
793
795
|
let stdout = "";
|
|
794
796
|
let stderr = "";
|
|
797
|
+
let stdoutRetainedBytes = 0;
|
|
798
|
+
let stderrRetainedBytes = 0;
|
|
795
799
|
let pending = "";
|
|
796
800
|
let error;
|
|
797
801
|
const spool = createOutputSpool({ tool: opts.cmd, thresholdBytes: max });
|
|
@@ -833,6 +837,7 @@ async function* spawnStream(opts) {
|
|
|
833
837
|
});
|
|
834
838
|
}
|
|
835
839
|
const queue = [];
|
|
840
|
+
let queuedBytes = 0;
|
|
836
841
|
let waiter;
|
|
837
842
|
let paused = false;
|
|
838
843
|
const wake = () => {
|
|
@@ -843,7 +848,7 @@ async function* spawnStream(opts) {
|
|
|
843
848
|
}
|
|
844
849
|
};
|
|
845
850
|
const resume = () => {
|
|
846
|
-
if (paused && queue.length
|
|
851
|
+
if (paused && queue.length <= Math.floor(maxQueue / 2) && queuedBytes <= Math.floor(maxQueueBytes / 2)) {
|
|
847
852
|
paused = false;
|
|
848
853
|
child.stdout?.resume();
|
|
849
854
|
child.stderr?.resume();
|
|
@@ -853,11 +858,16 @@ async function* spawnStream(opts) {
|
|
|
853
858
|
const s = c.toString();
|
|
854
859
|
stdoutBytes += c.byteLength;
|
|
855
860
|
emitProcessOutput({ pid, stream: "stdout", chunk: c });
|
|
856
|
-
if (
|
|
861
|
+
if (stdoutRetainedBytes < max) {
|
|
862
|
+
const retained = utf8Prefix(s, max - stdoutRetainedBytes);
|
|
863
|
+
stdout += retained;
|
|
864
|
+
stdoutRetainedBytes += Buffer.byteLength(retained, "utf8");
|
|
865
|
+
}
|
|
857
866
|
spool.write(s);
|
|
858
|
-
queue.push({ kind: "out", data: s });
|
|
867
|
+
queue.push({ kind: "out", data: s, bytes: c.byteLength });
|
|
868
|
+
queuedBytes += c.byteLength;
|
|
859
869
|
wake();
|
|
860
|
-
if (!paused && queue.length >= maxQueue) {
|
|
870
|
+
if (!paused && (queue.length >= maxQueue || queuedBytes >= maxQueueBytes)) {
|
|
861
871
|
paused = true;
|
|
862
872
|
child.stdout?.pause();
|
|
863
873
|
child.stderr?.pause();
|
|
@@ -867,11 +877,16 @@ async function* spawnStream(opts) {
|
|
|
867
877
|
const s = c.toString();
|
|
868
878
|
stderrBytes += c.byteLength;
|
|
869
879
|
emitProcessOutput({ pid, stream: "stderr", chunk: c });
|
|
870
|
-
if (
|
|
880
|
+
if (stderrRetainedBytes < max) {
|
|
881
|
+
const retained = utf8Prefix(s, max - stderrRetainedBytes);
|
|
882
|
+
stderr += retained;
|
|
883
|
+
stderrRetainedBytes += Buffer.byteLength(retained, "utf8");
|
|
884
|
+
}
|
|
871
885
|
spool.write(s);
|
|
872
|
-
queue.push({ kind: "err", data: s });
|
|
886
|
+
queue.push({ kind: "err", data: s, bytes: c.byteLength });
|
|
887
|
+
queuedBytes += c.byteLength;
|
|
873
888
|
wake();
|
|
874
|
-
if (!paused && queue.length >= maxQueue) {
|
|
889
|
+
if (!paused && (queue.length >= maxQueue || queuedBytes >= maxQueueBytes)) {
|
|
875
890
|
paused = true;
|
|
876
891
|
child.stdout?.pause();
|
|
877
892
|
child.stderr?.pause();
|
|
@@ -881,7 +896,9 @@ async function* spawnStream(opts) {
|
|
|
881
896
|
child.stderr?.on("data", onErr);
|
|
882
897
|
child.on("error", (e) => {
|
|
883
898
|
error = e.message;
|
|
884
|
-
|
|
899
|
+
const bytes = Buffer.byteLength(e.message, "utf8");
|
|
900
|
+
queue.push({ kind: "error", data: e.message, bytes });
|
|
901
|
+
queuedBytes += bytes;
|
|
885
902
|
wake();
|
|
886
903
|
});
|
|
887
904
|
const completeTelemetry = (code, signal, timedOut = false) => {
|
|
@@ -902,7 +919,13 @@ async function* spawnStream(opts) {
|
|
|
902
919
|
if (typeof pid === "number") registry.unregister(pid);
|
|
903
920
|
const exitCode2 = code ?? (signal ? 1 : 0);
|
|
904
921
|
completeTelemetry(exitCode2, signal ?? void 0);
|
|
905
|
-
queue.push({
|
|
922
|
+
queue.push({
|
|
923
|
+
kind: "close",
|
|
924
|
+
data: "",
|
|
925
|
+
bytes: 0,
|
|
926
|
+
code: exitCode2,
|
|
927
|
+
...signal ? { signal } : {}
|
|
928
|
+
});
|
|
906
929
|
wake();
|
|
907
930
|
});
|
|
908
931
|
const onAbort = () => {
|
|
@@ -914,7 +937,7 @@ async function* spawnStream(opts) {
|
|
|
914
937
|
} catch {
|
|
915
938
|
}
|
|
916
939
|
}
|
|
917
|
-
queue.push({ kind: "close", data: "", code: 124 });
|
|
940
|
+
queue.push({ kind: "close", data: "", bytes: 0, code: 124 });
|
|
918
941
|
completeTelemetry(124, "SIGKILL", true);
|
|
919
942
|
wake();
|
|
920
943
|
};
|
|
@@ -932,6 +955,7 @@ async function* spawnStream(opts) {
|
|
|
932
955
|
});
|
|
933
956
|
}
|
|
934
957
|
const chunk = queue.shift();
|
|
958
|
+
queuedBytes -= chunk.bytes;
|
|
935
959
|
resume();
|
|
936
960
|
if (chunk.kind === "close") {
|
|
937
961
|
if (!spawnFailed) exitCode = chunk.code ?? 0;
|
|
@@ -958,7 +982,7 @@ async function* spawnStream(opts) {
|
|
|
958
982
|
stdout: spooled ? stdout + spoolNote(spooled) : stdout,
|
|
959
983
|
stderr,
|
|
960
984
|
exitCode,
|
|
961
|
-
truncated:
|
|
985
|
+
truncated: stdoutBytes > stdoutRetainedBytes || stderrBytes > stderrRetainedBytes,
|
|
962
986
|
error,
|
|
963
987
|
spoolPath: spooled?.path,
|
|
964
988
|
spoolBytes: spooled?.bytes
|
|
@@ -982,6 +1006,20 @@ async function* spawnStream(opts) {
|
|
|
982
1006
|
}
|
|
983
1007
|
}
|
|
984
1008
|
}
|
|
1009
|
+
function utf8Prefix(text, maxBytes) {
|
|
1010
|
+
if (maxBytes <= 0) return "";
|
|
1011
|
+
if (Buffer.byteLength(text, "utf8") <= maxBytes) return text;
|
|
1012
|
+
let low = 0;
|
|
1013
|
+
let high = text.length;
|
|
1014
|
+
while (low < high) {
|
|
1015
|
+
const mid = Math.ceil((low + high) / 2);
|
|
1016
|
+
if (Buffer.byteLength(text.slice(0, mid), "utf8") <= maxBytes) low = mid;
|
|
1017
|
+
else high = mid - 1;
|
|
1018
|
+
}
|
|
1019
|
+
let end = low;
|
|
1020
|
+
if (end > 0 && /[\uD800-\uDBFF]/.test(text[end - 1])) end--;
|
|
1021
|
+
return text.slice(0, end);
|
|
1022
|
+
}
|
|
985
1023
|
|
|
986
1024
|
// src/_util.ts
|
|
987
1025
|
import * as path3 from "node:path";
|
|
@@ -2549,8 +2587,8 @@ async function scanDirectory(directory, depth, profiles, limits, state, extraIgn
|
|
|
2549
2587
|
collectFileEvidence(directory, fullPath, entry.name, profiles, state);
|
|
2550
2588
|
}
|
|
2551
2589
|
}
|
|
2552
|
-
function collectFileEvidence(directory, fullPath,
|
|
2553
|
-
const lower =
|
|
2590
|
+
function collectFileEvidence(directory, fullPath, basename5, profiles, state) {
|
|
2591
|
+
const lower = basename5.toLowerCase();
|
|
2554
2592
|
const extension = path4.extname(lower);
|
|
2555
2593
|
for (const profile of profiles) {
|
|
2556
2594
|
const detector = profile.detectors.find(
|
|
@@ -2561,7 +2599,7 @@ function collectFileEvidence(directory, fullPath, basename4, profiles, state) {
|
|
|
2561
2599
|
candidate.evidence.push({
|
|
2562
2600
|
kind: detector.kind,
|
|
2563
2601
|
path: fullPath,
|
|
2564
|
-
value:
|
|
2602
|
+
value: basename5,
|
|
2565
2603
|
weight: detector.weight
|
|
2566
2604
|
});
|
|
2567
2605
|
if (detector.kind === "manifest" || detector.kind === "config") {
|
|
@@ -2981,10 +3019,11 @@ var MAX_ARGUMENTS = 128;
|
|
|
2981
3019
|
var MAX_ARGUMENT_LENGTH = 4096;
|
|
2982
3020
|
var PACKAGE_NAME_RE = /^(?:@[a-z0-9._-]+\/)?[a-z0-9._-]+(?:@[a-z0-9*+._~^<>=|-]+)?$/i;
|
|
2983
3021
|
var COMPOSER_PACKAGE_RE = /^[a-z0-9_.-]+\/[a-z0-9_.-]+(?::[a-z0-9*+._~^<>=|-]+)?$/i;
|
|
2984
|
-
var GO_MODULE_RE = /^(?:[a-z0-9
|
|
3022
|
+
var GO_MODULE_RE = /^(?:[a-z0-9-]+\.)+[a-z0-9-]+\/[a-z0-9._~+/@-]+$/i;
|
|
2985
3023
|
var PYTHON_PACKAGE_RE = /^[a-z0-9._-]+(?:\[[a-z0-9._,-]+\])?==[a-z0-9*+._!~-]+$/i;
|
|
2986
3024
|
async function planLanguageOperation(options) {
|
|
2987
3025
|
validateOperationOptions(options.operation, options.operationOptions?.packages);
|
|
3026
|
+
validateFilterOption(options.operationOptions?.filter);
|
|
2988
3027
|
const detection = await detectLanguageWorkspaces(options);
|
|
2989
3028
|
const candidates = detection.workspaces.filter(
|
|
2990
3029
|
(workspace) => workspace.capabilities.includes(options.operation)
|
|
@@ -3157,6 +3196,15 @@ function workspaceDepth(workspaceRoot, projectRoot) {
|
|
|
3157
3196
|
const relative5 = path6.relative(path6.resolve(projectRoot), path6.resolve(workspaceRoot));
|
|
3158
3197
|
return relative5 === "" ? 0 : relative5.split(path6.sep).length;
|
|
3159
3198
|
}
|
|
3199
|
+
function validateFilterOption(filter) {
|
|
3200
|
+
if (filter === void 0) return;
|
|
3201
|
+
if (filter.startsWith("-") || filter.includes(" --")) {
|
|
3202
|
+
throw new Error(`Invalid test filter (parsed as a runner option): "${filter}"`);
|
|
3203
|
+
}
|
|
3204
|
+
if (filter.length > MAX_ARGUMENT_LENGTH || /[\r\n\0]/.test(filter)) {
|
|
3205
|
+
throw new Error("Invalid test filter (oversized or contains a control character)");
|
|
3206
|
+
}
|
|
3207
|
+
}
|
|
3160
3208
|
function validateOperationOptions(operation, packages) {
|
|
3161
3209
|
if (!operation.startsWith("package-") || !packages) return;
|
|
3162
3210
|
for (const value of packages) {
|