@wrongstack/tools 0.297.0 → 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 +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 +841 -351
- 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.js +560 -529
- 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 +792 -290
- 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 +841 -351
- 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 +841 -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 +113 -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/_spawn-stream.d.ts
CHANGED
|
@@ -20,6 +20,8 @@ export interface SpawnStreamOptions {
|
|
|
20
20
|
flushBytes?: number | undefined;
|
|
21
21
|
/** Maximum chunks to buffer before applying backpressure to the child. Default 500. */
|
|
22
22
|
maxQueueSize?: number | undefined;
|
|
23
|
+
/** Maximum UTF-8 bytes retained in the producer/consumer queue. Defaults to 1 MiB. */
|
|
24
|
+
maxQueueBytes?: number | undefined;
|
|
23
25
|
}
|
|
24
26
|
/**
|
|
25
27
|
* Spawn a child process and yield `partial_output` progress events as
|
package/dist/_util.d.ts
CHANGED
|
@@ -32,7 +32,35 @@ export declare function safeResolve(input: string, ctx: Context): string;
|
|
|
32
32
|
* the caller named exactly one file.
|
|
33
33
|
*/
|
|
34
34
|
export declare function assertRealInsideRoot(absPath: string, ctx: Context): Promise<void>;
|
|
35
|
-
/**
|
|
35
|
+
/**
|
|
36
|
+
* Containment check that RETURNS the canonical path it validated (WS-048).
|
|
37
|
+
*
|
|
38
|
+
* The check resolves symlinks and then confirms the resolved target is inside
|
|
39
|
+
* an allowed root. Handing the caller back the *unresolved* path throws that
|
|
40
|
+
* work away: the caller opens a path whose components are still symlinks, so
|
|
41
|
+
* whatever the check proved about the target is no longer what the caller
|
|
42
|
+
* touches. Swapping an intermediate component between the check and the open
|
|
43
|
+
* redirects the operation, and nothing downstream re-validates.
|
|
44
|
+
*
|
|
45
|
+
* Returning the resolved path removes that gap for every component that
|
|
46
|
+
* existed at check time — those are now literal directories, not links that can
|
|
47
|
+
* be re-pointed. It is not a total TOCTOU cure (only fd-relative operations
|
|
48
|
+
* would be), but the window it closes is the one this function's own contract
|
|
49
|
+
* claims to have closed.
|
|
50
|
+
*
|
|
51
|
+
* For a path that does not exist yet — a `write` to a new file — the deepest
|
|
52
|
+
* existing ancestor is resolved and the not-yet-created tail is re-joined onto
|
|
53
|
+
* it, so the canonical form is still returned rather than the raw input.
|
|
54
|
+
*/
|
|
55
|
+
export declare function resolveRealInsideRoot(absPath: string, ctx: Context): Promise<string>;
|
|
56
|
+
/**
|
|
57
|
+
* `safeResolve` + symlink realpath containment check, returning the CANONICAL
|
|
58
|
+
* path (WS-048).
|
|
59
|
+
*
|
|
60
|
+
* This used to return the unvalidated `abs` while validating `real`, so the
|
|
61
|
+
* header's promise of a "containment check" did not extend to the value the
|
|
62
|
+
* caller then opened.
|
|
63
|
+
*/
|
|
36
64
|
export declare function safeResolveReal(input: string, ctx: Context): Promise<string>;
|
|
37
65
|
export declare function truncateMiddle(s: string, max: number): string;
|
|
38
66
|
export declare function isBinaryBuffer(buf: Buffer): boolean;
|
package/dist/audit.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";
|
|
@@ -2563,8 +2601,8 @@ async function scanDirectory(directory, depth, profiles, limits, state, extraIgn
|
|
|
2563
2601
|
collectFileEvidence(directory, fullPath, entry.name, profiles, state);
|
|
2564
2602
|
}
|
|
2565
2603
|
}
|
|
2566
|
-
function collectFileEvidence(directory, fullPath,
|
|
2567
|
-
const lower =
|
|
2604
|
+
function collectFileEvidence(directory, fullPath, basename5, profiles, state) {
|
|
2605
|
+
const lower = basename5.toLowerCase();
|
|
2568
2606
|
const extension = path4.extname(lower);
|
|
2569
2607
|
for (const profile of profiles) {
|
|
2570
2608
|
const detector = profile.detectors.find(
|
|
@@ -2575,7 +2613,7 @@ function collectFileEvidence(directory, fullPath, basename4, profiles, state) {
|
|
|
2575
2613
|
candidate.evidence.push({
|
|
2576
2614
|
kind: detector.kind,
|
|
2577
2615
|
path: fullPath,
|
|
2578
|
-
value:
|
|
2616
|
+
value: basename5,
|
|
2579
2617
|
weight: detector.weight
|
|
2580
2618
|
});
|
|
2581
2619
|
if (detector.kind === "manifest" || detector.kind === "config") {
|
|
@@ -3194,10 +3232,11 @@ var MAX_ARGUMENTS = 128;
|
|
|
3194
3232
|
var MAX_ARGUMENT_LENGTH = 4096;
|
|
3195
3233
|
var PACKAGE_NAME_RE = /^(?:@[a-z0-9._-]+\/)?[a-z0-9._-]+(?:@[a-z0-9*+._~^<>=|-]+)?$/i;
|
|
3196
3234
|
var COMPOSER_PACKAGE_RE = /^[a-z0-9_.-]+\/[a-z0-9_.-]+(?::[a-z0-9*+._~^<>=|-]+)?$/i;
|
|
3197
|
-
var GO_MODULE_RE = /^(?:[a-z0-9
|
|
3235
|
+
var GO_MODULE_RE = /^(?:[a-z0-9-]+\.)+[a-z0-9-]+\/[a-z0-9._~+/@-]+$/i;
|
|
3198
3236
|
var PYTHON_PACKAGE_RE = /^[a-z0-9._-]+(?:\[[a-z0-9._,-]+\])?==[a-z0-9*+._!~-]+$/i;
|
|
3199
3237
|
async function planLanguageOperation(options) {
|
|
3200
3238
|
validateOperationOptions(options.operation, options.operationOptions?.packages);
|
|
3239
|
+
validateFilterOption(options.operationOptions?.filter);
|
|
3201
3240
|
const detection = await detectLanguageWorkspaces(options);
|
|
3202
3241
|
const candidates = detection.workspaces.filter(
|
|
3203
3242
|
(workspace) => workspace.capabilities.includes(options.operation)
|
|
@@ -3370,6 +3409,15 @@ function workspaceDepth(workspaceRoot, projectRoot) {
|
|
|
3370
3409
|
const relative5 = path6.relative(path6.resolve(projectRoot), path6.resolve(workspaceRoot));
|
|
3371
3410
|
return relative5 === "" ? 0 : relative5.split(path6.sep).length;
|
|
3372
3411
|
}
|
|
3412
|
+
function validateFilterOption(filter) {
|
|
3413
|
+
if (filter === void 0) return;
|
|
3414
|
+
if (filter.startsWith("-") || filter.includes(" --")) {
|
|
3415
|
+
throw new Error(`Invalid test filter (parsed as a runner option): "${filter}"`);
|
|
3416
|
+
}
|
|
3417
|
+
if (filter.length > MAX_ARGUMENT_LENGTH || /[\r\n\0]/.test(filter)) {
|
|
3418
|
+
throw new Error("Invalid test filter (oversized or contains a control character)");
|
|
3419
|
+
}
|
|
3420
|
+
}
|
|
3373
3421
|
function validateOperationOptions(operation, packages) {
|
|
3374
3422
|
if (!operation.startsWith("package-") || !packages) return;
|
|
3375
3423
|
for (const value of packages) {
|
package/dist/bash.js
CHANGED
|
@@ -81,11 +81,12 @@ function createOutputSpool(opts) {
|
|
|
81
81
|
return {
|
|
82
82
|
write(text) {
|
|
83
83
|
if (finalized || !text) return;
|
|
84
|
-
|
|
84
|
+
const textBytes = Buffer.byteLength(text, "utf8");
|
|
85
|
+
totalBytes += textBytes;
|
|
85
86
|
if (!stream && !failed) {
|
|
86
|
-
if (headBytes +
|
|
87
|
+
if (headBytes + textBytes <= threshold) {
|
|
87
88
|
head += text;
|
|
88
|
-
headBytes +=
|
|
89
|
+
headBytes += textBytes;
|
|
89
90
|
return;
|
|
90
91
|
}
|
|
91
92
|
head += text;
|
|
@@ -95,7 +96,7 @@ function createOutputSpool(opts) {
|
|
|
95
96
|
}
|
|
96
97
|
if (stream) {
|
|
97
98
|
if (stream.writableLength > SPOOL_WRITE_HWM_BYTES) {
|
|
98
|
-
droppedBytes +=
|
|
99
|
+
droppedBytes += textBytes;
|
|
99
100
|
return;
|
|
100
101
|
}
|
|
101
102
|
stream.write(text);
|
package/dist/batch-tool-use.js
CHANGED
|
@@ -2,30 +2,59 @@
|
|
|
2
2
|
import {
|
|
3
3
|
GOVERNED_TOOL_EXECUTOR_META_KEY
|
|
4
4
|
} from "@wrongstack/core/types";
|
|
5
|
+
var BATCHABLE_TOOL_NAMES = [
|
|
6
|
+
"read",
|
|
7
|
+
"glob",
|
|
8
|
+
"grep",
|
|
9
|
+
"tree",
|
|
10
|
+
"codebase-stats",
|
|
11
|
+
"codebase-search",
|
|
12
|
+
"language_info",
|
|
13
|
+
"tool_search",
|
|
14
|
+
"memory_for_file",
|
|
15
|
+
"memory_for_path",
|
|
16
|
+
"memory_search"
|
|
17
|
+
];
|
|
18
|
+
var BATCHABLE_TOOLS = new Set(BATCHABLE_TOOL_NAMES);
|
|
19
|
+
var MAX_BATCH_CALLS = 8;
|
|
20
|
+
var MAX_PARALLEL_BATCH_CALLS = 3;
|
|
5
21
|
var batchToolUseTool = {
|
|
6
22
|
name: "batch_tool_use",
|
|
7
23
|
category: "Meta",
|
|
8
|
-
description: "Execute a batch of
|
|
9
|
-
usageHint:
|
|
24
|
+
description: "Execute a small batch of independent, read-only discovery calls. Process, mutation, browser-action, MCP, delegation, and nested meta tools are not eligible.",
|
|
25
|
+
usageHint: `BOUNDED READ-ONLY BATCHING:
|
|
26
|
+
|
|
27
|
+
- Use only for a small set of independent reads or searches that are all needed now.
|
|
28
|
+
- Do not wrap normal sequential reasoning or every tool call in a batch.
|
|
29
|
+
- \`parallel: true\` (default) runs at most three eligible calls concurrently.
|
|
30
|
+
- \`stop_on_error: true\` makes it fail fast on the first error.
|
|
31
|
+
- Eligible tools: ${BATCHABLE_TOOL_NAMES.join(", ")}.`,
|
|
10
32
|
permission: "confirm",
|
|
33
|
+
// Scheduling barrier: keep the outer meta-call out of ToolExecutor's
|
|
34
|
+
// non-mutating fan-out even though every eligible inner tool is read-only.
|
|
11
35
|
mutating: true,
|
|
12
36
|
timeoutMs: 12e4,
|
|
13
|
-
capabilities: ["tool.
|
|
37
|
+
capabilities: ["tool.meta"],
|
|
14
38
|
icon: "meta",
|
|
15
39
|
inputSchema: {
|
|
16
40
|
type: "object",
|
|
17
41
|
properties: {
|
|
18
42
|
calls: {
|
|
19
43
|
type: "array",
|
|
44
|
+
maxItems: MAX_BATCH_CALLS,
|
|
20
45
|
items: {
|
|
21
46
|
type: "object",
|
|
22
47
|
properties: {
|
|
23
|
-
tool: {
|
|
48
|
+
tool: {
|
|
49
|
+
type: "string",
|
|
50
|
+
enum: [...BATCHABLE_TOOL_NAMES],
|
|
51
|
+
description: "An explicitly batch-safe, read-only discovery tool."
|
|
52
|
+
},
|
|
24
53
|
input: { type: "object" }
|
|
25
54
|
},
|
|
26
55
|
required: ["tool"]
|
|
27
56
|
},
|
|
28
|
-
description:
|
|
57
|
+
description: `Up to ${MAX_BATCH_CALLS} independent, batch-safe read calls.`
|
|
29
58
|
},
|
|
30
59
|
stop_on_error: {
|
|
31
60
|
type: "boolean",
|
|
@@ -48,6 +77,9 @@ var batchToolUseTool = {
|
|
|
48
77
|
stop_on_error: false
|
|
49
78
|
};
|
|
50
79
|
}
|
|
80
|
+
if (input.calls.length > MAX_BATCH_CALLS) {
|
|
81
|
+
throw new Error(`batch_tool_use: calls must contain at most ${MAX_BATCH_CALLS} items`);
|
|
82
|
+
}
|
|
51
83
|
const governedExecute = ctx.meta[GOVERNED_TOOL_EXECUTOR_META_KEY];
|
|
52
84
|
if (typeof governedExecute !== "function") {
|
|
53
85
|
return {
|
|
@@ -67,8 +99,11 @@ var batchToolUseTool = {
|
|
|
67
99
|
let succeeded = 0;
|
|
68
100
|
let failed = 0;
|
|
69
101
|
if (input.parallel !== false) {
|
|
70
|
-
const
|
|
71
|
-
|
|
102
|
+
const allResults = await mapWithConcurrency(
|
|
103
|
+
input.calls,
|
|
104
|
+
MAX_PARALLEL_BATCH_CALLS,
|
|
105
|
+
(call) => executeSingle(call, ctx, governedExecute)
|
|
106
|
+
);
|
|
72
107
|
results.push(...allResults);
|
|
73
108
|
succeeded = allResults.filter((r) => r.success).length;
|
|
74
109
|
failed = allResults.filter((r) => !r.success).length;
|
|
@@ -93,8 +128,28 @@ var batchToolUseTool = {
|
|
|
93
128
|
};
|
|
94
129
|
}
|
|
95
130
|
};
|
|
131
|
+
async function mapWithConcurrency(items, limit, run) {
|
|
132
|
+
const results = new Array(items.length);
|
|
133
|
+
let nextIndex = 0;
|
|
134
|
+
const worker = async () => {
|
|
135
|
+
while (nextIndex < items.length) {
|
|
136
|
+
const index = nextIndex++;
|
|
137
|
+
results[index] = await run(items[index]);
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
await Promise.all(Array.from({ length: Math.min(limit, items.length) }, () => worker()));
|
|
141
|
+
return results;
|
|
142
|
+
}
|
|
96
143
|
async function executeSingle(call, ctx, governedExecute) {
|
|
97
144
|
const start = Date.now();
|
|
145
|
+
if (call.tool === batchToolUseTool.name) {
|
|
146
|
+
return {
|
|
147
|
+
tool: call.tool,
|
|
148
|
+
success: false,
|
|
149
|
+
error: "recursive batch_tool_use execution is not allowed",
|
|
150
|
+
executionMs: Date.now() - start
|
|
151
|
+
};
|
|
152
|
+
}
|
|
98
153
|
const tool = ctx.tools.find((candidate) => candidate.name === call.tool);
|
|
99
154
|
if (!tool) {
|
|
100
155
|
return {
|
|
@@ -104,6 +159,14 @@ async function executeSingle(call, ctx, governedExecute) {
|
|
|
104
159
|
executionMs: Date.now() - start
|
|
105
160
|
};
|
|
106
161
|
}
|
|
162
|
+
if (!BATCHABLE_TOOLS.has(tool.name) || tool.mutating) {
|
|
163
|
+
return {
|
|
164
|
+
tool: call.tool,
|
|
165
|
+
success: false,
|
|
166
|
+
error: `tool "${call.tool}" is not eligible for batch execution; call it directly. Allowed: ${BATCHABLE_TOOL_NAMES.join(", ")}`,
|
|
167
|
+
executionMs: Date.now() - start
|
|
168
|
+
};
|
|
169
|
+
}
|
|
107
170
|
try {
|
|
108
171
|
const result = await governedExecute(call.tool, call.input);
|
|
109
172
|
return {
|
package/dist/browser/index.js
CHANGED
|
@@ -6,8 +6,14 @@ import * as path from "node:path";
|
|
|
6
6
|
import { atomicWrite, ulid } from "@wrongstack/core/utils";
|
|
7
7
|
var ARTIFACT_RETENTION_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
8
8
|
var sweptRoots = /* @__PURE__ */ new Set();
|
|
9
|
+
var MAX_SWEPT_ROOTS = 128;
|
|
9
10
|
function sweepOldArtifacts(root) {
|
|
10
11
|
if (sweptRoots.has(root)) return;
|
|
12
|
+
while (sweptRoots.size >= MAX_SWEPT_ROOTS) {
|
|
13
|
+
const oldest = sweptRoots.values().next().value;
|
|
14
|
+
if (oldest === void 0) break;
|
|
15
|
+
sweptRoots.delete(oldest);
|
|
16
|
+
}
|
|
11
17
|
sweptRoots.add(root);
|
|
12
18
|
void (async () => {
|
|
13
19
|
const cutoff = Date.now() - ARTIFACT_RETENTION_MS;
|
|
@@ -441,7 +447,7 @@ var BrowserSessionManager = class {
|
|
|
441
447
|
constructor(options, launcher = defaultLauncher) {
|
|
442
448
|
this.launcher = launcher;
|
|
443
449
|
this.artifacts = new BrowserArtifactStore(options.artifactRoot);
|
|
444
|
-
this.allowPrivateHosts = options.allowPrivateHosts ??
|
|
450
|
+
this.allowPrivateHosts = options.allowPrivateHosts ?? false;
|
|
445
451
|
this.allowedPrivateOrigins = options.allowedPrivateOrigins ?? [];
|
|
446
452
|
this.networkProxy = new BrowserNetworkGuardProxy({
|
|
447
453
|
allowPrivateHosts: this.allowPrivateHosts,
|
|
@@ -1017,6 +1023,9 @@ var browserScreenshotTool = {
|
|
|
1017
1023
|
description: "Capture a page or element PNG and return sensitive artifact metadata with integrity hash.",
|
|
1018
1024
|
usageHint: "browser_screenshot({ sessionId, fullPage?, selector? })",
|
|
1019
1025
|
permission: "confirm",
|
|
1026
|
+
// WS-046: the element/expression acted on, not the sessionId — a trust
|
|
1027
|
+
// rule must distinguish clicking one control from another.
|
|
1028
|
+
subjectKey: "selector",
|
|
1020
1029
|
mutating: true,
|
|
1021
1030
|
riskTier: "safe",
|
|
1022
1031
|
capabilities: [ToolCapabilities.NET_OUTBOUND],
|
|
@@ -1046,6 +1055,9 @@ function selectorTool(name, description, run) {
|
|
|
1046
1055
|
description,
|
|
1047
1056
|
usageHint: `${name}({ sessionId, selector })`,
|
|
1048
1057
|
permission: "confirm",
|
|
1058
|
+
// WS-046: the element/expression acted on, not the sessionId — a trust
|
|
1059
|
+
// rule must distinguish clicking one control from another.
|
|
1060
|
+
subjectKey: "selector",
|
|
1049
1061
|
mutating: true,
|
|
1050
1062
|
riskTier: "standard",
|
|
1051
1063
|
capabilities: [ToolCapabilities.NET_OUTBOUND],
|
|
@@ -1075,6 +1087,9 @@ var browserTypeTool = {
|
|
|
1075
1087
|
description: "Fill an input in an owned browser session. Use secretEnv instead of text for credentials so values stay out of tool arguments and session audit.",
|
|
1076
1088
|
usageHint: "browser_type({ sessionId, selector, text? | secretEnv? })",
|
|
1077
1089
|
permission: "confirm",
|
|
1090
|
+
// WS-046: the element/expression acted on, not the sessionId — a trust
|
|
1091
|
+
// rule must distinguish clicking one control from another.
|
|
1092
|
+
subjectKey: "selector",
|
|
1078
1093
|
mutating: true,
|
|
1079
1094
|
riskTier: "standard",
|
|
1080
1095
|
capabilities: [ToolCapabilities.NET_OUTBOUND],
|
|
@@ -1109,6 +1124,9 @@ var browserSelectTool = {
|
|
|
1109
1124
|
description: "Select an option in an owned browser session.",
|
|
1110
1125
|
usageHint: "browser_select({ sessionId, selector, value })",
|
|
1111
1126
|
permission: "confirm",
|
|
1127
|
+
// WS-046: the element/expression acted on, not the sessionId — a trust
|
|
1128
|
+
// rule must distinguish clicking one control from another.
|
|
1129
|
+
subjectKey: "selector",
|
|
1112
1130
|
mutating: true,
|
|
1113
1131
|
riskTier: "standard",
|
|
1114
1132
|
capabilities: [ToolCapabilities.NET_OUTBOUND],
|
|
@@ -1137,6 +1155,9 @@ var browserPressTool = {
|
|
|
1137
1155
|
description: "Press a keyboard key in an owned browser session.",
|
|
1138
1156
|
usageHint: "browser_press({ sessionId, key })",
|
|
1139
1157
|
permission: "confirm",
|
|
1158
|
+
// WS-046: the element/expression acted on, not the sessionId — a trust
|
|
1159
|
+
// rule must distinguish clicking one control from another.
|
|
1160
|
+
subjectKey: "key",
|
|
1140
1161
|
mutating: true,
|
|
1141
1162
|
riskTier: "standard",
|
|
1142
1163
|
capabilities: [ToolCapabilities.NET_OUTBOUND],
|
|
@@ -1155,6 +1176,9 @@ var browserDragTool = {
|
|
|
1155
1176
|
description: "Drag one element to another in an owned browser session.",
|
|
1156
1177
|
usageHint: "browser_drag({ sessionId, from, to })",
|
|
1157
1178
|
permission: "confirm",
|
|
1179
|
+
// WS-046: the element/expression acted on, not the sessionId — a trust
|
|
1180
|
+
// rule must distinguish clicking one control from another.
|
|
1181
|
+
subjectKey: "from",
|
|
1158
1182
|
mutating: true,
|
|
1159
1183
|
riskTier: "standard",
|
|
1160
1184
|
capabilities: [ToolCapabilities.NET_OUTBOUND],
|
|
@@ -1204,6 +1228,9 @@ var browserEvaluateTool = {
|
|
|
1204
1228
|
description: "Evaluate bounded JavaScript in the page. Requires confirmation because page code is arbitrary.",
|
|
1205
1229
|
usageHint: "browser_evaluate({ sessionId, expression })",
|
|
1206
1230
|
permission: "confirm",
|
|
1231
|
+
// WS-046: the element/expression acted on, not the sessionId — a trust
|
|
1232
|
+
// rule must distinguish clicking one control from another.
|
|
1233
|
+
subjectKey: "expression",
|
|
1207
1234
|
mutating: true,
|
|
1208
1235
|
riskTier: "destructive",
|
|
1209
1236
|
capabilities: [ToolCapabilities.NET_OUTBOUND, ToolCapabilities.TOOL_MUTATE_ANY],
|
|
@@ -1226,6 +1253,9 @@ var browserUploadTool = {
|
|
|
1226
1253
|
description: "Upload project-local files through a file input in an owned browser session.",
|
|
1227
1254
|
usageHint: "browser_upload({ sessionId, selector, files })",
|
|
1228
1255
|
permission: "confirm",
|
|
1256
|
+
// WS-046: the element/expression acted on, not the sessionId — a trust
|
|
1257
|
+
// rule must distinguish clicking one control from another.
|
|
1258
|
+
subjectKey: "selector",
|
|
1229
1259
|
mutating: true,
|
|
1230
1260
|
riskTier: "destructive",
|
|
1231
1261
|
capabilities: [ToolCapabilities.NET_OUTBOUND, ToolCapabilities.FS_READ],
|