@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/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";
|
|
@@ -445,6 +492,7 @@ var ProcessRegistryImpl = class {
|
|
|
445
492
|
}
|
|
446
493
|
/** Get all tracked processes. */
|
|
447
494
|
list() {
|
|
495
|
+
this._pruneAllStale();
|
|
448
496
|
return Array.from(this.processes.values());
|
|
449
497
|
}
|
|
450
498
|
/** Get processes filtered by name (e.g. 'bash', 'exec'). */
|
|
@@ -475,6 +523,7 @@ var ProcessRegistryImpl = class {
|
|
|
475
523
|
* Combined stats for observability — used by /ps and the TUI status bar.
|
|
476
524
|
*/
|
|
477
525
|
stats() {
|
|
526
|
+
this._pruneAllStale();
|
|
478
527
|
return {
|
|
479
528
|
activeCount: this.activeCount,
|
|
480
529
|
backgroundCount: this.activeBackgroundCount,
|
|
@@ -714,6 +763,19 @@ var ProcessRegistryImpl = class {
|
|
|
714
763
|
this.processes.delete(pid);
|
|
715
764
|
}
|
|
716
765
|
}
|
|
766
|
+
/**
|
|
767
|
+
* Remove every stale entry, not just one PID. `list()`/`stats()` — the
|
|
768
|
+
* surfaces the TUI status bar and `/ps` poll — must prune too: a child
|
|
769
|
+
* whose 'close' event never fires (e.g. Windows grandchildren holding stdio
|
|
770
|
+
* open) would otherwise linger in the registry until someone looks up its
|
|
771
|
+
* exact PID, and PID reuse meanwhile makes `get()`/`kill()` target the
|
|
772
|
+
* wrong process. RAM-leak audit 2026-07-31, MEDIUM.
|
|
773
|
+
*/
|
|
774
|
+
_pruneAllStale() {
|
|
775
|
+
for (const [pid, entry] of this.processes) {
|
|
776
|
+
if (this._isStaleEntry(entry)) this.processes.delete(pid);
|
|
777
|
+
}
|
|
778
|
+
}
|
|
717
779
|
};
|
|
718
780
|
var _registry;
|
|
719
781
|
function getProcessRegistry() {
|
|
@@ -723,60 +785,17 @@ function getProcessRegistry() {
|
|
|
723
785
|
return _registry;
|
|
724
786
|
}
|
|
725
787
|
|
|
726
|
-
// src/_win32-resolve.ts
|
|
727
|
-
import * as fs from "node:fs";
|
|
728
|
-
import * as path2 from "node:path";
|
|
729
|
-
function resolveWin32Command(cmd) {
|
|
730
|
-
if (process.platform !== "win32") return cmd;
|
|
731
|
-
if (cmd.includes("/") || cmd.includes("\\") || path2.extname(cmd.replace(/\//g, "\\"))) {
|
|
732
|
-
return cmd;
|
|
733
|
-
}
|
|
734
|
-
const pathext = (process.env["PATHEXT"] ?? ".COM;.EXE;.BAT;.CMD;.VBS;.JS;.WS;.MSC").toLowerCase().split(";");
|
|
735
|
-
const pathDirs = (process.env["PATH"] ?? "").split(path2.delimiter);
|
|
736
|
-
for (const dir of pathDirs) {
|
|
737
|
-
const base = path2.join(dir, cmd);
|
|
738
|
-
for (const ext of pathext) {
|
|
739
|
-
const full = `${base}${ext}`;
|
|
740
|
-
try {
|
|
741
|
-
fs.accessSync(full, fs.constants.X_OK);
|
|
742
|
-
return full;
|
|
743
|
-
} catch {
|
|
744
|
-
}
|
|
745
|
-
}
|
|
746
|
-
}
|
|
747
|
-
return cmd;
|
|
748
|
-
}
|
|
749
|
-
var WIN32_SHELL_META = /[&|<>"\r\n\0]/;
|
|
750
|
-
function assertSafeWin32ShellArgs(args) {
|
|
751
|
-
for (const arg of args) {
|
|
752
|
-
if (typeof arg === "string" && WIN32_SHELL_META.test(arg)) {
|
|
753
|
-
throw new Error(
|
|
754
|
-
'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)
|
|
755
|
-
);
|
|
756
|
-
}
|
|
757
|
-
}
|
|
758
|
-
}
|
|
759
|
-
function buildWin32CmdShimInvocation(command, args = []) {
|
|
760
|
-
assertSafeWin32ShellArgs([command, ...args]);
|
|
761
|
-
const line = ["call", quoteWin32CmdArg(command), ...args.map(quoteWin32CmdArg)].join(" ");
|
|
762
|
-
return {
|
|
763
|
-
command: process.env["COMSPEC"] ?? "cmd.exe",
|
|
764
|
-
args: ["/d", "/c", line],
|
|
765
|
-
windowsVerbatimArguments: true
|
|
766
|
-
};
|
|
767
|
-
}
|
|
768
|
-
function quoteWin32CmdArg(arg) {
|
|
769
|
-
return `"${arg}"`;
|
|
770
|
-
}
|
|
771
|
-
|
|
772
788
|
// src/_spawn-stream.ts
|
|
773
789
|
var isWin = process.platform === "win32";
|
|
774
790
|
async function* spawnStream(opts) {
|
|
775
791
|
const max = opts.maxBytes ?? 2e5;
|
|
776
792
|
const flushAt = opts.flushBytes ?? 4 * 1024;
|
|
777
793
|
const maxQueue = opts.maxQueueSize ?? 500;
|
|
794
|
+
const maxQueueBytes = opts.maxQueueBytes ?? 1024 * 1024;
|
|
778
795
|
let stdout = "";
|
|
779
796
|
let stderr = "";
|
|
797
|
+
let stdoutRetainedBytes = 0;
|
|
798
|
+
let stderrRetainedBytes = 0;
|
|
780
799
|
let pending = "";
|
|
781
800
|
let error;
|
|
782
801
|
const spool = createOutputSpool({ tool: opts.cmd, thresholdBytes: max });
|
|
@@ -818,6 +837,7 @@ async function* spawnStream(opts) {
|
|
|
818
837
|
});
|
|
819
838
|
}
|
|
820
839
|
const queue = [];
|
|
840
|
+
let queuedBytes = 0;
|
|
821
841
|
let waiter;
|
|
822
842
|
let paused = false;
|
|
823
843
|
const wake = () => {
|
|
@@ -828,7 +848,7 @@ async function* spawnStream(opts) {
|
|
|
828
848
|
}
|
|
829
849
|
};
|
|
830
850
|
const resume = () => {
|
|
831
|
-
if (paused && queue.length
|
|
851
|
+
if (paused && queue.length <= Math.floor(maxQueue / 2) && queuedBytes <= Math.floor(maxQueueBytes / 2)) {
|
|
832
852
|
paused = false;
|
|
833
853
|
child.stdout?.resume();
|
|
834
854
|
child.stderr?.resume();
|
|
@@ -838,11 +858,16 @@ async function* spawnStream(opts) {
|
|
|
838
858
|
const s = c.toString();
|
|
839
859
|
stdoutBytes += c.byteLength;
|
|
840
860
|
emitProcessOutput({ pid, stream: "stdout", chunk: c });
|
|
841
|
-
if (
|
|
861
|
+
if (stdoutRetainedBytes < max) {
|
|
862
|
+
const retained = utf8Prefix(s, max - stdoutRetainedBytes);
|
|
863
|
+
stdout += retained;
|
|
864
|
+
stdoutRetainedBytes += Buffer.byteLength(retained, "utf8");
|
|
865
|
+
}
|
|
842
866
|
spool.write(s);
|
|
843
|
-
queue.push({ kind: "out", data: s });
|
|
867
|
+
queue.push({ kind: "out", data: s, bytes: c.byteLength });
|
|
868
|
+
queuedBytes += c.byteLength;
|
|
844
869
|
wake();
|
|
845
|
-
if (!paused && queue.length >= maxQueue) {
|
|
870
|
+
if (!paused && (queue.length >= maxQueue || queuedBytes >= maxQueueBytes)) {
|
|
846
871
|
paused = true;
|
|
847
872
|
child.stdout?.pause();
|
|
848
873
|
child.stderr?.pause();
|
|
@@ -852,11 +877,16 @@ async function* spawnStream(opts) {
|
|
|
852
877
|
const s = c.toString();
|
|
853
878
|
stderrBytes += c.byteLength;
|
|
854
879
|
emitProcessOutput({ pid, stream: "stderr", chunk: c });
|
|
855
|
-
if (
|
|
880
|
+
if (stderrRetainedBytes < max) {
|
|
881
|
+
const retained = utf8Prefix(s, max - stderrRetainedBytes);
|
|
882
|
+
stderr += retained;
|
|
883
|
+
stderrRetainedBytes += Buffer.byteLength(retained, "utf8");
|
|
884
|
+
}
|
|
856
885
|
spool.write(s);
|
|
857
|
-
queue.push({ kind: "err", data: s });
|
|
886
|
+
queue.push({ kind: "err", data: s, bytes: c.byteLength });
|
|
887
|
+
queuedBytes += c.byteLength;
|
|
858
888
|
wake();
|
|
859
|
-
if (!paused && queue.length >= maxQueue) {
|
|
889
|
+
if (!paused && (queue.length >= maxQueue || queuedBytes >= maxQueueBytes)) {
|
|
860
890
|
paused = true;
|
|
861
891
|
child.stdout?.pause();
|
|
862
892
|
child.stderr?.pause();
|
|
@@ -866,7 +896,9 @@ async function* spawnStream(opts) {
|
|
|
866
896
|
child.stderr?.on("data", onErr);
|
|
867
897
|
child.on("error", (e) => {
|
|
868
898
|
error = e.message;
|
|
869
|
-
|
|
899
|
+
const bytes = Buffer.byteLength(e.message, "utf8");
|
|
900
|
+
queue.push({ kind: "error", data: e.message, bytes });
|
|
901
|
+
queuedBytes += bytes;
|
|
870
902
|
wake();
|
|
871
903
|
});
|
|
872
904
|
const completeTelemetry = (code, signal, timedOut = false) => {
|
|
@@ -887,7 +919,13 @@ async function* spawnStream(opts) {
|
|
|
887
919
|
if (typeof pid === "number") registry.unregister(pid);
|
|
888
920
|
const exitCode2 = code ?? (signal ? 1 : 0);
|
|
889
921
|
completeTelemetry(exitCode2, signal ?? void 0);
|
|
890
|
-
queue.push({
|
|
922
|
+
queue.push({
|
|
923
|
+
kind: "close",
|
|
924
|
+
data: "",
|
|
925
|
+
bytes: 0,
|
|
926
|
+
code: exitCode2,
|
|
927
|
+
...signal ? { signal } : {}
|
|
928
|
+
});
|
|
891
929
|
wake();
|
|
892
930
|
});
|
|
893
931
|
const onAbort = () => {
|
|
@@ -899,7 +937,7 @@ async function* spawnStream(opts) {
|
|
|
899
937
|
} catch {
|
|
900
938
|
}
|
|
901
939
|
}
|
|
902
|
-
queue.push({ kind: "close", data: "", code: 124 });
|
|
940
|
+
queue.push({ kind: "close", data: "", bytes: 0, code: 124 });
|
|
903
941
|
completeTelemetry(124, "SIGKILL", true);
|
|
904
942
|
wake();
|
|
905
943
|
};
|
|
@@ -917,6 +955,7 @@ async function* spawnStream(opts) {
|
|
|
917
955
|
});
|
|
918
956
|
}
|
|
919
957
|
const chunk = queue.shift();
|
|
958
|
+
queuedBytes -= chunk.bytes;
|
|
920
959
|
resume();
|
|
921
960
|
if (chunk.kind === "close") {
|
|
922
961
|
if (!spawnFailed) exitCode = chunk.code ?? 0;
|
|
@@ -943,7 +982,7 @@ async function* spawnStream(opts) {
|
|
|
943
982
|
stdout: spooled ? stdout + spoolNote(spooled) : stdout,
|
|
944
983
|
stderr,
|
|
945
984
|
exitCode,
|
|
946
|
-
truncated:
|
|
985
|
+
truncated: stdoutBytes > stdoutRetainedBytes || stderrBytes > stderrRetainedBytes,
|
|
947
986
|
error,
|
|
948
987
|
spoolPath: spooled?.path,
|
|
949
988
|
spoolBytes: spooled?.bytes
|
|
@@ -967,6 +1006,20 @@ async function* spawnStream(opts) {
|
|
|
967
1006
|
}
|
|
968
1007
|
}
|
|
969
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
|
+
}
|
|
970
1023
|
|
|
971
1024
|
// src/_util.ts
|
|
972
1025
|
import * as path3 from "node:path";
|
|
@@ -2534,8 +2587,8 @@ async function scanDirectory(directory, depth, profiles, limits, state, extraIgn
|
|
|
2534
2587
|
collectFileEvidence(directory, fullPath, entry.name, profiles, state);
|
|
2535
2588
|
}
|
|
2536
2589
|
}
|
|
2537
|
-
function collectFileEvidence(directory, fullPath,
|
|
2538
|
-
const lower =
|
|
2590
|
+
function collectFileEvidence(directory, fullPath, basename5, profiles, state) {
|
|
2591
|
+
const lower = basename5.toLowerCase();
|
|
2539
2592
|
const extension = path4.extname(lower);
|
|
2540
2593
|
for (const profile of profiles) {
|
|
2541
2594
|
const detector = profile.detectors.find(
|
|
@@ -2546,7 +2599,7 @@ function collectFileEvidence(directory, fullPath, basename4, profiles, state) {
|
|
|
2546
2599
|
candidate.evidence.push({
|
|
2547
2600
|
kind: detector.kind,
|
|
2548
2601
|
path: fullPath,
|
|
2549
|
-
value:
|
|
2602
|
+
value: basename5,
|
|
2550
2603
|
weight: detector.weight
|
|
2551
2604
|
});
|
|
2552
2605
|
if (detector.kind === "manifest" || detector.kind === "config") {
|
|
@@ -2966,10 +3019,11 @@ var MAX_ARGUMENTS = 128;
|
|
|
2966
3019
|
var MAX_ARGUMENT_LENGTH = 4096;
|
|
2967
3020
|
var PACKAGE_NAME_RE = /^(?:@[a-z0-9._-]+\/)?[a-z0-9._-]+(?:@[a-z0-9*+._~^<>=|-]+)?$/i;
|
|
2968
3021
|
var COMPOSER_PACKAGE_RE = /^[a-z0-9_.-]+\/[a-z0-9_.-]+(?::[a-z0-9*+._~^<>=|-]+)?$/i;
|
|
2969
|
-
var GO_MODULE_RE = /^(?:[a-z0-9
|
|
3022
|
+
var GO_MODULE_RE = /^(?:[a-z0-9-]+\.)+[a-z0-9-]+\/[a-z0-9._~+/@-]+$/i;
|
|
2970
3023
|
var PYTHON_PACKAGE_RE = /^[a-z0-9._-]+(?:\[[a-z0-9._,-]+\])?==[a-z0-9*+._!~-]+$/i;
|
|
2971
3024
|
async function planLanguageOperation(options) {
|
|
2972
3025
|
validateOperationOptions(options.operation, options.operationOptions?.packages);
|
|
3026
|
+
validateFilterOption(options.operationOptions?.filter);
|
|
2973
3027
|
const detection = await detectLanguageWorkspaces(options);
|
|
2974
3028
|
const candidates = detection.workspaces.filter(
|
|
2975
3029
|
(workspace) => workspace.capabilities.includes(options.operation)
|
|
@@ -3142,6 +3196,15 @@ function workspaceDepth(workspaceRoot, projectRoot) {
|
|
|
3142
3196
|
const relative5 = path6.relative(path6.resolve(projectRoot), path6.resolve(workspaceRoot));
|
|
3143
3197
|
return relative5 === "" ? 0 : relative5.split(path6.sep).length;
|
|
3144
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
|
+
}
|
|
3145
3208
|
function validateOperationOptions(operation, packages) {
|
|
3146
3209
|
if (!operation.startsWith("package-") || !packages) return;
|
|
3147
3210
|
for (const value of packages) {
|
package/dist/next-steps.d.ts
CHANGED
|
@@ -46,6 +46,29 @@ export interface ParseNextStepsResult {
|
|
|
46
46
|
/** The first item's text when it has auto="true"; otherwise empty. */
|
|
47
47
|
autoTexts: string[];
|
|
48
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* Whether an LLM response's stop reason means the message is the FINAL one of
|
|
51
|
+
* a turn.
|
|
52
|
+
*
|
|
53
|
+
* The agent loop calls the provider once per iteration, so a multi-step turn
|
|
54
|
+
* emits several assistant messages. Only the last one — the response that
|
|
55
|
+
* stopped without asking for another tool — is the model's actual answer;
|
|
56
|
+
* everything before it is mid-turn prose the model wrote on its way to a tool
|
|
57
|
+
* call. A `<nextsteps>` block in mid-turn text is noise: surfacing it would
|
|
58
|
+
* offer the user suggestions while the work is still in flight, and would let
|
|
59
|
+
* `/next` and auto-submit pick up a suggestion the model has already moved on
|
|
60
|
+
* from.
|
|
61
|
+
*
|
|
62
|
+
* Every surface that renders suggestions gates on this so the three of them
|
|
63
|
+
* cannot disagree about where a turn ends. Callers still strip the block from
|
|
64
|
+
* the message body regardless — the raw XML must never reach the user.
|
|
65
|
+
*
|
|
66
|
+
* `tool_call` is the spelling some providers put on the WebUI wire (typed
|
|
67
|
+
* loosely as `stopReason: string`); the canonical `StopReason` union uses
|
|
68
|
+
* `tool_use`. An absent stop reason counts as final so legacy paths that never
|
|
69
|
+
* carried one keep their suggestions.
|
|
70
|
+
*/
|
|
71
|
+
export declare function isFinalTurnStopReason(stopReason: string | undefined): boolean;
|
|
49
72
|
/**
|
|
50
73
|
* Parse canonical "<nextsteps>" blocks from assistant output (or raw numbered lines).
|
|
51
74
|
*
|
package/dist/next-steps.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
// src/next-steps.ts
|
|
2
|
+
function isFinalTurnStopReason(stopReason) {
|
|
3
|
+
return stopReason !== "tool_use" && stopReason !== "tool_call";
|
|
4
|
+
}
|
|
2
5
|
var NEXT_STEPS_TAG_RE = /<nextsteps\b[^>]*>\s*\n+/i;
|
|
3
6
|
var ITEM_RE = /^(?:(\d+)[.)]\s*|[-*•]\s*)(.+?)(\s+auto="true")?$/;
|
|
4
7
|
var MAX_STEPS = 6;
|
|
@@ -111,6 +114,7 @@ function stripNextStepsBlock(text) {
|
|
|
111
114
|
return text.replace(/<next_?steps\b[^>]*>[\s\S]*?<\/next_?steps>/gi, "").replace(/<next_?steps\b[^>]*\/?>/gi, "").replace(/\n{3,}/g, "\n\n").trim();
|
|
112
115
|
}
|
|
113
116
|
export {
|
|
117
|
+
isFinalTurnStopReason,
|
|
114
118
|
parseNextSteps,
|
|
115
119
|
stripNextStepsBlock
|
|
116
120
|
};
|