@wrongstack/tools 0.296.4 → 0.298.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/dist/_spawn-stream.d.ts +2 -0
- package/dist/_util.d.ts +29 -1
- package/dist/audit.js +128 -65
- package/dist/bash.js +20 -4
- package/dist/batch-tool-use.js +70 -7
- package/dist/browser/index.js +31 -1
- package/dist/builtin.js +883 -351
- package/dist/codebase-index/index.js +95 -16
- package/dist/codebase-index/project-server-protocol.d.ts +26 -0
- package/dist/codebase-index/project-server.js +76 -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.js +562 -516
- package/dist/format.js +131 -65
- package/dist/git.js +22 -2
- package/dist/glob.js +11 -5
- package/dist/grep.js +160 -104
- package/dist/index.js +834 -290
- package/dist/install.js +135 -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 +143 -71
- package/dist/lint.js +128 -65
- package/dist/next-steps.d.ts +23 -0
- package/dist/next-steps.js +4 -0
- package/dist/outdated.js +101 -26
- package/dist/pack.js +883 -351
- package/dist/patch.js +11 -1
- package/dist/plan.js +32 -10
- package/dist/process-registry.d.ts +9 -0
- package/dist/process-registry.js +15 -0
- package/dist/ps-slash.js +15 -0
- package/dist/read.js +104 -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 +128 -65
- package/dist/todo.js +3 -1
- package/dist/tool-tier.js +883 -351
- 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 +128 -65
- package/dist/write.js +9 -6
- package/package.json +5 -4
- 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";
|
|
@@ -2573,6 +2620,7 @@ var ProcessRegistryImpl = class {
|
|
|
2573
2620
|
}
|
|
2574
2621
|
/** Get all tracked processes. */
|
|
2575
2622
|
list() {
|
|
2623
|
+
this._pruneAllStale();
|
|
2576
2624
|
return Array.from(this.processes.values());
|
|
2577
2625
|
}
|
|
2578
2626
|
/** Get processes filtered by name (e.g. 'bash', 'exec'). */
|
|
@@ -2603,6 +2651,7 @@ var ProcessRegistryImpl = class {
|
|
|
2603
2651
|
* Combined stats for observability — used by /ps and the TUI status bar.
|
|
2604
2652
|
*/
|
|
2605
2653
|
stats() {
|
|
2654
|
+
this._pruneAllStale();
|
|
2606
2655
|
return {
|
|
2607
2656
|
activeCount: this.activeCount,
|
|
2608
2657
|
backgroundCount: this.activeBackgroundCount,
|
|
@@ -2842,6 +2891,19 @@ var ProcessRegistryImpl = class {
|
|
|
2842
2891
|
this.processes.delete(pid);
|
|
2843
2892
|
}
|
|
2844
2893
|
}
|
|
2894
|
+
/**
|
|
2895
|
+
* Remove every stale entry, not just one PID. `list()`/`stats()` — the
|
|
2896
|
+
* surfaces the TUI status bar and `/ps` poll — must prune too: a child
|
|
2897
|
+
* whose 'close' event never fires (e.g. Windows grandchildren holding stdio
|
|
2898
|
+
* open) would otherwise linger in the registry until someone looks up its
|
|
2899
|
+
* exact PID, and PID reuse meanwhile makes `get()`/`kill()` target the
|
|
2900
|
+
* wrong process. RAM-leak audit 2026-07-31, MEDIUM.
|
|
2901
|
+
*/
|
|
2902
|
+
_pruneAllStale() {
|
|
2903
|
+
for (const [pid, entry] of this.processes) {
|
|
2904
|
+
if (this._isStaleEntry(entry)) this.processes.delete(pid);
|
|
2905
|
+
}
|
|
2906
|
+
}
|
|
2845
2907
|
};
|
|
2846
2908
|
var _registry;
|
|
2847
2909
|
function getProcessRegistry() {
|
|
@@ -2851,60 +2913,17 @@ function getProcessRegistry() {
|
|
|
2851
2913
|
return _registry;
|
|
2852
2914
|
}
|
|
2853
2915
|
|
|
2854
|
-
// src/_win32-resolve.ts
|
|
2855
|
-
import * as fs2 from "node:fs";
|
|
2856
|
-
import * as path4 from "node:path";
|
|
2857
|
-
function resolveWin32Command(cmd) {
|
|
2858
|
-
if (process.platform !== "win32") return cmd;
|
|
2859
|
-
if (cmd.includes("/") || cmd.includes("\\") || path4.extname(cmd.replace(/\//g, "\\"))) {
|
|
2860
|
-
return cmd;
|
|
2861
|
-
}
|
|
2862
|
-
const pathext = (process.env["PATHEXT"] ?? ".COM;.EXE;.BAT;.CMD;.VBS;.JS;.WS;.MSC").toLowerCase().split(";");
|
|
2863
|
-
const pathDirs = (process.env["PATH"] ?? "").split(path4.delimiter);
|
|
2864
|
-
for (const dir of pathDirs) {
|
|
2865
|
-
const base = path4.join(dir, cmd);
|
|
2866
|
-
for (const ext of pathext) {
|
|
2867
|
-
const full = `${base}${ext}`;
|
|
2868
|
-
try {
|
|
2869
|
-
fs2.accessSync(full, fs2.constants.X_OK);
|
|
2870
|
-
return full;
|
|
2871
|
-
} catch {
|
|
2872
|
-
}
|
|
2873
|
-
}
|
|
2874
|
-
}
|
|
2875
|
-
return cmd;
|
|
2876
|
-
}
|
|
2877
|
-
var WIN32_SHELL_META = /[&|<>"\r\n\0]/;
|
|
2878
|
-
function assertSafeWin32ShellArgs(args) {
|
|
2879
|
-
for (const arg of args) {
|
|
2880
|
-
if (typeof arg === "string" && WIN32_SHELL_META.test(arg)) {
|
|
2881
|
-
throw new Error(
|
|
2882
|
-
'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)
|
|
2883
|
-
);
|
|
2884
|
-
}
|
|
2885
|
-
}
|
|
2886
|
-
}
|
|
2887
|
-
function buildWin32CmdShimInvocation(command, args = []) {
|
|
2888
|
-
assertSafeWin32ShellArgs([command, ...args]);
|
|
2889
|
-
const line = ["call", quoteWin32CmdArg(command), ...args.map(quoteWin32CmdArg)].join(" ");
|
|
2890
|
-
return {
|
|
2891
|
-
command: process.env["COMSPEC"] ?? "cmd.exe",
|
|
2892
|
-
args: ["/d", "/c", line],
|
|
2893
|
-
windowsVerbatimArguments: true
|
|
2894
|
-
};
|
|
2895
|
-
}
|
|
2896
|
-
function quoteWin32CmdArg(arg) {
|
|
2897
|
-
return `"${arg}"`;
|
|
2898
|
-
}
|
|
2899
|
-
|
|
2900
2916
|
// src/_spawn-stream.ts
|
|
2901
2917
|
var isWin = process.platform === "win32";
|
|
2902
2918
|
async function* spawnStream(opts) {
|
|
2903
2919
|
const max = opts.maxBytes ?? 2e5;
|
|
2904
2920
|
const flushAt = opts.flushBytes ?? 4 * 1024;
|
|
2905
2921
|
const maxQueue = opts.maxQueueSize ?? 500;
|
|
2922
|
+
const maxQueueBytes = opts.maxQueueBytes ?? 1024 * 1024;
|
|
2906
2923
|
let stdout = "";
|
|
2907
2924
|
let stderr = "";
|
|
2925
|
+
let stdoutRetainedBytes = 0;
|
|
2926
|
+
let stderrRetainedBytes = 0;
|
|
2908
2927
|
let pending = "";
|
|
2909
2928
|
let error;
|
|
2910
2929
|
const spool = createOutputSpool({ tool: opts.cmd, thresholdBytes: max });
|
|
@@ -2946,6 +2965,7 @@ async function* spawnStream(opts) {
|
|
|
2946
2965
|
});
|
|
2947
2966
|
}
|
|
2948
2967
|
const queue = [];
|
|
2968
|
+
let queuedBytes = 0;
|
|
2949
2969
|
let waiter;
|
|
2950
2970
|
let paused = false;
|
|
2951
2971
|
const wake = () => {
|
|
@@ -2956,7 +2976,7 @@ async function* spawnStream(opts) {
|
|
|
2956
2976
|
}
|
|
2957
2977
|
};
|
|
2958
2978
|
const resume = () => {
|
|
2959
|
-
if (paused && queue.length
|
|
2979
|
+
if (paused && queue.length <= Math.floor(maxQueue / 2) && queuedBytes <= Math.floor(maxQueueBytes / 2)) {
|
|
2960
2980
|
paused = false;
|
|
2961
2981
|
child.stdout?.resume();
|
|
2962
2982
|
child.stderr?.resume();
|
|
@@ -2966,11 +2986,16 @@ async function* spawnStream(opts) {
|
|
|
2966
2986
|
const s = c.toString();
|
|
2967
2987
|
stdoutBytes += c.byteLength;
|
|
2968
2988
|
emitProcessOutput({ pid, stream: "stdout", chunk: c });
|
|
2969
|
-
if (
|
|
2989
|
+
if (stdoutRetainedBytes < max) {
|
|
2990
|
+
const retained = utf8Prefix(s, max - stdoutRetainedBytes);
|
|
2991
|
+
stdout += retained;
|
|
2992
|
+
stdoutRetainedBytes += Buffer.byteLength(retained, "utf8");
|
|
2993
|
+
}
|
|
2970
2994
|
spool.write(s);
|
|
2971
|
-
queue.push({ kind: "out", data: s });
|
|
2995
|
+
queue.push({ kind: "out", data: s, bytes: c.byteLength });
|
|
2996
|
+
queuedBytes += c.byteLength;
|
|
2972
2997
|
wake();
|
|
2973
|
-
if (!paused && queue.length >= maxQueue) {
|
|
2998
|
+
if (!paused && (queue.length >= maxQueue || queuedBytes >= maxQueueBytes)) {
|
|
2974
2999
|
paused = true;
|
|
2975
3000
|
child.stdout?.pause();
|
|
2976
3001
|
child.stderr?.pause();
|
|
@@ -2980,11 +3005,16 @@ async function* spawnStream(opts) {
|
|
|
2980
3005
|
const s = c.toString();
|
|
2981
3006
|
stderrBytes += c.byteLength;
|
|
2982
3007
|
emitProcessOutput({ pid, stream: "stderr", chunk: c });
|
|
2983
|
-
if (
|
|
3008
|
+
if (stderrRetainedBytes < max) {
|
|
3009
|
+
const retained = utf8Prefix(s, max - stderrRetainedBytes);
|
|
3010
|
+
stderr += retained;
|
|
3011
|
+
stderrRetainedBytes += Buffer.byteLength(retained, "utf8");
|
|
3012
|
+
}
|
|
2984
3013
|
spool.write(s);
|
|
2985
|
-
queue.push({ kind: "err", data: s });
|
|
3014
|
+
queue.push({ kind: "err", data: s, bytes: c.byteLength });
|
|
3015
|
+
queuedBytes += c.byteLength;
|
|
2986
3016
|
wake();
|
|
2987
|
-
if (!paused && queue.length >= maxQueue) {
|
|
3017
|
+
if (!paused && (queue.length >= maxQueue || queuedBytes >= maxQueueBytes)) {
|
|
2988
3018
|
paused = true;
|
|
2989
3019
|
child.stdout?.pause();
|
|
2990
3020
|
child.stderr?.pause();
|
|
@@ -2994,7 +3024,9 @@ async function* spawnStream(opts) {
|
|
|
2994
3024
|
child.stderr?.on("data", onErr);
|
|
2995
3025
|
child.on("error", (e) => {
|
|
2996
3026
|
error = e.message;
|
|
2997
|
-
|
|
3027
|
+
const bytes = Buffer.byteLength(e.message, "utf8");
|
|
3028
|
+
queue.push({ kind: "error", data: e.message, bytes });
|
|
3029
|
+
queuedBytes += bytes;
|
|
2998
3030
|
wake();
|
|
2999
3031
|
});
|
|
3000
3032
|
const completeTelemetry = (code, signal, timedOut = false) => {
|
|
@@ -3015,7 +3047,13 @@ async function* spawnStream(opts) {
|
|
|
3015
3047
|
if (typeof pid === "number") registry.unregister(pid);
|
|
3016
3048
|
const exitCode2 = code ?? (signal ? 1 : 0);
|
|
3017
3049
|
completeTelemetry(exitCode2, signal ?? void 0);
|
|
3018
|
-
queue.push({
|
|
3050
|
+
queue.push({
|
|
3051
|
+
kind: "close",
|
|
3052
|
+
data: "",
|
|
3053
|
+
bytes: 0,
|
|
3054
|
+
code: exitCode2,
|
|
3055
|
+
...signal ? { signal } : {}
|
|
3056
|
+
});
|
|
3019
3057
|
wake();
|
|
3020
3058
|
});
|
|
3021
3059
|
const onAbort = () => {
|
|
@@ -3027,7 +3065,7 @@ async function* spawnStream(opts) {
|
|
|
3027
3065
|
} catch {
|
|
3028
3066
|
}
|
|
3029
3067
|
}
|
|
3030
|
-
queue.push({ kind: "close", data: "", code: 124 });
|
|
3068
|
+
queue.push({ kind: "close", data: "", bytes: 0, code: 124 });
|
|
3031
3069
|
completeTelemetry(124, "SIGKILL", true);
|
|
3032
3070
|
wake();
|
|
3033
3071
|
};
|
|
@@ -3045,6 +3083,7 @@ async function* spawnStream(opts) {
|
|
|
3045
3083
|
});
|
|
3046
3084
|
}
|
|
3047
3085
|
const chunk = queue.shift();
|
|
3086
|
+
queuedBytes -= chunk.bytes;
|
|
3048
3087
|
resume();
|
|
3049
3088
|
if (chunk.kind === "close") {
|
|
3050
3089
|
if (!spawnFailed) exitCode = chunk.code ?? 0;
|
|
@@ -3071,7 +3110,7 @@ async function* spawnStream(opts) {
|
|
|
3071
3110
|
stdout: spooled ? stdout + spoolNote(spooled) : stdout,
|
|
3072
3111
|
stderr,
|
|
3073
3112
|
exitCode,
|
|
3074
|
-
truncated:
|
|
3113
|
+
truncated: stdoutBytes > stdoutRetainedBytes || stderrBytes > stderrRetainedBytes,
|
|
3075
3114
|
error,
|
|
3076
3115
|
spoolPath: spooled?.path,
|
|
3077
3116
|
spoolBytes: spooled?.bytes
|
|
@@ -3095,6 +3134,20 @@ async function* spawnStream(opts) {
|
|
|
3095
3134
|
}
|
|
3096
3135
|
}
|
|
3097
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
|
+
}
|
|
3098
3151
|
|
|
3099
3152
|
// src/_util.ts
|
|
3100
3153
|
import * as fsp2 from "node:fs/promises";
|
|
@@ -3121,12 +3174,13 @@ function ensureInsideRoot(absPath, ctx) {
|
|
|
3121
3174
|
function safeResolve(input, ctx) {
|
|
3122
3175
|
return ensureInsideRoot(resolvePath(input, ctx), ctx);
|
|
3123
3176
|
}
|
|
3124
|
-
async function
|
|
3125
|
-
if (ctx.allowOutsideProjectRoot) return;
|
|
3177
|
+
async function resolveRealInsideRoot(absPath, ctx) {
|
|
3178
|
+
if (ctx.allowOutsideProjectRoot) return absPath;
|
|
3126
3179
|
const realRoots = await Promise.all(
|
|
3127
3180
|
allowedRoots(ctx).map((r) => fsp2.realpath(r).catch(() => path5.resolve(r)))
|
|
3128
3181
|
);
|
|
3129
3182
|
let probe = absPath;
|
|
3183
|
+
const pendingTail = [];
|
|
3130
3184
|
for (; ; ) {
|
|
3131
3185
|
let real;
|
|
3132
3186
|
try {
|
|
@@ -3134,13 +3188,16 @@ async function assertRealInsideRoot(absPath, ctx) {
|
|
|
3134
3188
|
} catch (err) {
|
|
3135
3189
|
if (err.code === "ENOENT") {
|
|
3136
3190
|
const parent = path5.dirname(probe);
|
|
3137
|
-
if (parent === probe) return;
|
|
3191
|
+
if (parent === probe) return absPath;
|
|
3192
|
+
pendingTail.unshift(path5.basename(probe));
|
|
3138
3193
|
probe = parent;
|
|
3139
3194
|
continue;
|
|
3140
3195
|
}
|
|
3141
3196
|
throw err;
|
|
3142
3197
|
}
|
|
3143
|
-
if (isInsideAny(real, realRoots))
|
|
3198
|
+
if (isInsideAny(real, realRoots)) {
|
|
3199
|
+
return pendingTail.length > 0 ? path5.join(real, ...pendingTail) : real;
|
|
3200
|
+
}
|
|
3144
3201
|
throw new Error(
|
|
3145
3202
|
`Path "${absPath}" resolves through a symlink outside project root "${realRoots[0]}"`
|
|
3146
3203
|
);
|
|
@@ -3148,8 +3205,7 @@ async function assertRealInsideRoot(absPath, ctx) {
|
|
|
3148
3205
|
}
|
|
3149
3206
|
async function safeResolveReal(input, ctx) {
|
|
3150
3207
|
const abs = safeResolve(input, ctx);
|
|
3151
|
-
await
|
|
3152
|
-
return abs;
|
|
3208
|
+
return await resolveRealInsideRoot(abs, ctx);
|
|
3153
3209
|
}
|
|
3154
3210
|
var COMMAND_OUTPUT_MAX_BYTES = 32768;
|
|
3155
3211
|
var REPEAT_RUN_THRESHOLD = 3;
|
|
@@ -3229,10 +3285,11 @@ var MAX_ARGUMENTS = 128;
|
|
|
3229
3285
|
var MAX_ARGUMENT_LENGTH = 4096;
|
|
3230
3286
|
var PACKAGE_NAME_RE = /^(?:@[a-z0-9._-]+\/)?[a-z0-9._-]+(?:@[a-z0-9*+._~^<>=|-]+)?$/i;
|
|
3231
3287
|
var COMPOSER_PACKAGE_RE = /^[a-z0-9_.-]+\/[a-z0-9_.-]+(?::[a-z0-9*+._~^<>=|-]+)?$/i;
|
|
3232
|
-
var GO_MODULE_RE = /^(?:[a-z0-9
|
|
3288
|
+
var GO_MODULE_RE = /^(?:[a-z0-9-]+\.)+[a-z0-9-]+\/[a-z0-9._~+/@-]+$/i;
|
|
3233
3289
|
var PYTHON_PACKAGE_RE = /^[a-z0-9._-]+(?:\[[a-z0-9._,-]+\])?==[a-z0-9*+._!~-]+$/i;
|
|
3234
3290
|
async function planLanguageOperation(options) {
|
|
3235
3291
|
validateOperationOptions(options.operation, options.operationOptions?.packages);
|
|
3292
|
+
validateFilterOption(options.operationOptions?.filter);
|
|
3236
3293
|
const detection = await detectLanguageWorkspaces(options);
|
|
3237
3294
|
const candidates = detection.workspaces.filter(
|
|
3238
3295
|
(workspace) => workspace.capabilities.includes(options.operation)
|
|
@@ -3405,6 +3462,15 @@ function workspaceDepth(workspaceRoot, projectRoot) {
|
|
|
3405
3462
|
const relative5 = path6.relative(path6.resolve(projectRoot), path6.resolve(workspaceRoot));
|
|
3406
3463
|
return relative5 === "" ? 0 : relative5.split(path6.sep).length;
|
|
3407
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
|
+
}
|
|
3408
3474
|
function validateOperationOptions(operation, packages) {
|
|
3409
3475
|
if (!operation.startsWith("package-") || !packages) return;
|
|
3410
3476
|
for (const value of packages) {
|
|
@@ -3942,6 +4008,9 @@ var languageTool = {
|
|
|
3942
4008
|
useInstead: ["language_info", "install", "audit", "outdated"]
|
|
3943
4009
|
},
|
|
3944
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",
|
|
3945
4014
|
mutating: true,
|
|
3946
4015
|
riskTier: "standard",
|
|
3947
4016
|
capabilities: ["shell.restricted", "fs.write"],
|
|
@@ -4199,6 +4268,9 @@ var languagePackageTool = {
|
|
|
4199
4268
|
useInstead: ["language_info", "language", "install", "audit", "outdated"]
|
|
4200
4269
|
},
|
|
4201
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",
|
|
4202
4274
|
mutating: true,
|
|
4203
4275
|
riskTier: "destructive",
|
|
4204
4276
|
capabilities: ["shell.restricted", "fs.write", "net.outbound", "package.install"],
|