@wrongstack/tools 0.313.0 → 0.316.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_edit-match.d.ts +3 -2
- package/dist/_output-spool.d.ts +4 -3
- package/dist/_shell-pick.d.ts +2 -1
- package/dist/_spawn-stream.d.ts +2 -1
- package/dist/_syntax-check.d.ts +2 -1
- package/dist/audit.js +10 -4055
- package/dist/bash-kill-guard.d.ts +3 -6
- package/dist/bash.js +9 -2308
- package/dist/batch-tool-use.js +2 -187
- package/dist/browser/index.js +25 -1339
- package/dist/browser/network-guard-proxy.d.ts +2 -1
- package/dist/builtin.js +69 -33949
- package/dist/chunk-22B7GE5T.js +260 -0
- package/dist/chunk-2VSZC6QM.js +113 -0
- package/dist/chunk-3PVYQFRQ.js +472 -0
- package/dist/chunk-42BHI7TN.js +337 -0
- package/dist/chunk-4BHUSMNL.js +104 -0
- package/dist/chunk-4I4LWFOO.js +431 -0
- package/dist/chunk-4UESMQDP.js +122 -0
- package/dist/chunk-553IQUMO.js +478 -0
- package/dist/chunk-5H4GSJAI.js +223 -0
- package/dist/chunk-6RNIFLG4.js +305 -0
- package/dist/chunk-7EY5DCRO.js +434 -0
- package/dist/chunk-A6BRWIXN.js +317 -0
- package/dist/chunk-AHHDWNXC.js +200 -0
- package/dist/chunk-BSLVR56S.js +199 -0
- package/dist/chunk-BTSFTGIL.js +7 -0
- package/dist/chunk-D33S4RQG.js +222 -0
- package/dist/chunk-DA4KNE2H.js +4412 -0
- package/dist/chunk-DR7JOQTC.js +520 -0
- package/dist/chunk-EEOFQDT6.js +898 -0
- package/dist/chunk-EJWSCQ6D.js +137 -0
- package/dist/chunk-EMRGN4KM.js +170 -0
- package/dist/chunk-FQZOHLG3.js +89 -0
- package/dist/chunk-GOIZNNOA.js +221 -0
- package/dist/chunk-HFXSNKCV.js +196 -0
- package/dist/chunk-HYX2TZ7O.js +1272 -0
- package/dist/chunk-I64BS3VC.js +15 -0
- package/dist/chunk-IVWV2UM6.js +955 -0
- package/dist/chunk-IXMNTNW5.js +238 -0
- package/dist/chunk-IYK7XGDZ.js +892 -0
- package/dist/chunk-J5SKD6LN.js +235 -0
- package/dist/chunk-JNNVRHMV.js +2111 -0
- package/dist/chunk-JOHXDF3D.js +295 -0
- package/dist/chunk-JRJJX3L5.js +424 -0
- package/dist/chunk-K3WNSHUF.js +1371 -0
- package/dist/chunk-L25CVUVR.js +2830 -0
- package/dist/chunk-LIJQMYYX.js +59 -0
- package/dist/chunk-LWKUTMD5.js +197 -0
- package/dist/chunk-MQX2KXVW.js +54 -0
- package/dist/chunk-MZZN7VCD.js +359 -0
- package/dist/chunk-NBDZMMG2.js +169 -0
- package/dist/chunk-NKJW5GFO.js +366 -0
- package/dist/chunk-NKNOBUBU.js +522 -0
- package/dist/chunk-O4MBV4AX.js +134 -0
- package/dist/chunk-OUBDL3WH.js +3515 -0
- package/dist/chunk-PQKK5JH7.js +101 -0
- package/dist/chunk-PY2IOS7C.js +1000 -0
- package/dist/chunk-Q5JPPCZC.js +12 -0
- package/dist/chunk-QBV725YG.js +128 -0
- package/dist/chunk-QZQSPUBF.js +315 -0
- package/dist/chunk-RGISBZBD.js +231 -0
- package/dist/chunk-RJZQWEMS.js +84 -0
- package/dist/chunk-RXISBFR5.js +315 -0
- package/dist/chunk-S5CCLZL3.js +99 -0
- package/dist/chunk-SDLVH5RZ.js +178 -0
- package/dist/chunk-T2F4S7U4.js +1723 -0
- package/dist/chunk-TEBQ4VPZ.js +163 -0
- package/dist/chunk-U4D5S3VQ.js +21 -0
- package/dist/chunk-U4VAATKP.js +193 -0
- package/dist/chunk-UCYQTZ7F.js +113 -0
- package/dist/chunk-UKU2ZX4C.js +203 -0
- package/dist/chunk-UNSKG6DC.js +159 -0
- package/dist/chunk-V43EQ6VR.js +68 -0
- package/dist/chunk-VB3MJGCV.js +610 -0
- package/dist/chunk-VFKPWSOX.js +154 -0
- package/dist/chunk-VJNHFZ7J.js +190 -0
- package/dist/chunk-VXECAJJ7.js +1091 -0
- package/dist/chunk-WHIIIREL.js +223 -0
- package/dist/chunk-Z6DAKQ3U.js +1 -0
- package/dist/chunk-ZJQ4IGXK.js +474 -0
- package/dist/chunk-ZLTFLC25.js +385 -0
- package/dist/circuit-breaker.js +3 -191
- package/dist/codebase-index/ast-invariant-engine.d.ts +5 -4
- package/dist/codebase-index/binary-frame.d.ts +0 -2
- package/dist/codebase-index/bm25.d.ts +1 -1
- package/dist/codebase-index/circuit-breaker.d.ts +2 -1
- package/dist/codebase-index/codebase-ast-replace-tool.d.ts +3 -2
- package/dist/codebase-index/codebase-impact-analysis-tool.d.ts +4 -3
- package/dist/codebase-index/codebase-invariant-check-tool.d.ts +3 -2
- package/dist/codebase-index/codebase-repo-map-tool.d.ts +3 -2
- package/dist/codebase-index/codebase-skeleton-tool.d.ts +3 -2
- package/dist/codebase-index/codebase-targeted-test-tool.d.ts +3 -2
- package/dist/codebase-index/content-hash.d.ts +0 -2
- package/dist/codebase-index/import-extractor.d.ts +0 -13
- package/dist/codebase-index/index-service.d.ts +1 -1
- package/dist/codebase-index/index.js +84 -13688
- package/dist/codebase-index/languages.d.ts +2 -1
- package/dist/codebase-index/module-roots.d.ts +3 -2
- package/dist/codebase-index/parser-batch.d.ts +0 -5
- package/dist/codebase-index/parser-dispatch.d.ts +2 -1
- package/dist/codebase-index/parser-output.d.ts +4 -3
- package/dist/codebase-index/parser-worker-pool.d.ts +0 -2
- package/dist/codebase-index/parser-worker-script.d.ts +1 -16
- package/dist/codebase-index/parser-worker-script.js +8 -3995
- package/dist/codebase-index/project-server-client-state.d.ts +2 -2
- package/dist/codebase-index/project-server-endpoint.d.ts +0 -15
- package/dist/codebase-index/project-server.js +60 -8548
- package/dist/codebase-index/tree-sitter/visitor.d.ts +2 -1
- package/dist/codebase-index/tree-sitter-parser.d.ts +0 -2
- package/dist/codebase-index/ts-parser.d.ts +1 -1
- package/dist/codebase-index/vector-search.d.ts +2 -1
- package/dist/codebase-index/wal-maintenance.d.ts +3 -2
- package/dist/codebase-index/worker.js +20 -8416
- package/dist/codebase-index/writer-admin.d.ts +0 -1
- package/dist/codebase-index/writer-search.d.ts +0 -9
- package/dist/design.js +2 -299
- package/dist/diff.js +4 -256
- package/dist/document.js +4 -222
- package/dist/e2e.js +5 -476
- package/dist/edit.js +14 -10200
- package/dist/exec.js +16 -3131
- package/dist/fetch.js +8 -398
- package/dist/format.js +10 -3750
- package/dist/generic-parser-VUXDIAOZ.js +13 -0
- package/dist/git.js +4 -380
- package/dist/glob.js +6 -280
- package/dist/go-parser-JXYKJHRC.js +469 -0
- package/dist/grep.js +7 -604
- package/dist/index.js +318 -35387
- package/dist/install.js +10 -4091
- package/dist/json-parser-IBHZ4BZC.js +213 -0
- package/dist/json.js +4 -665
- package/dist/kanban-contract-actions.d.ts +1 -1
- package/dist/kanban-detail-actions.d.ts +2 -1
- package/dist/kanban-presence.d.ts +2 -1
- package/dist/kanban-serializer.d.ts +0 -8
- package/dist/kanban-split-task-handler.d.ts +2 -2
- package/dist/kanban-tool-types.d.ts +2 -1
- package/dist/kanban.js +3 -2096
- package/dist/languages/diagnostics.d.ts +2 -1
- package/dist/languages/index.js +23 -4664
- package/dist/languages/legacy-bridge.d.ts +3 -2
- package/dist/languages/types.d.ts +2 -1
- package/dist/legacy-bridge-7M6QLUQN.js +18 -0
- package/dist/lint.js +10 -3706
- package/dist/logs.js +4 -287
- package/dist/memory.js +6 -215
- package/dist/mode.js +3 -99
- package/dist/outdated.js +4 -5170
- package/dist/pack.js +65 -33897
- package/dist/parser-dispatch-QH4XPGG6.js +14 -0
- package/dist/patch.js +13 -9935
- package/dist/plan.js +5 -3286
- package/dist/process-registry.js +8 -651
- package/dist/ps-slash.js +12 -1439
- package/dist/pwsh.d.ts +0 -1
- package/dist/py-parser-IS4HKYMF.js +16 -0
- package/dist/read.js +13 -9816
- package/dist/replace.js +15 -10014
- package/dist/rs-parser-XHUUO2KZ.js +81 -0
- package/dist/scaffold.js +4 -253
- package/dist/search.js +5 -585
- package/dist/session-kanban-sync.d.ts +0 -6
- package/dist/session-kanban.js +30 -972
- package/dist/skill.js +2 -215
- package/dist/spawn-background.d.ts +1 -1
- package/dist/task.js +5 -3410
- package/dist/test.js +10 -3773
- package/dist/todo.js +4 -2891
- package/dist/tool-help.js +3 -123
- package/dist/tool-search.js +3 -79
- package/dist/tool-tier.js +68 -33984
- package/dist/tool-use.js +2 -93
- package/dist/tree-sitter-parser-AIERW3YI.js +15 -0
- package/dist/tree.js +4 -288
- package/dist/ts-parser-RCTYKSVI.js +232 -0
- package/dist/typecheck.js +10 -3753
- package/dist/win32.js +6 -60
- package/dist/write.js +14 -9882
- package/dist/yaml-parser-4SAXV3PL.js +157 -0
- package/package.json +5 -5
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createOutputSpool,
|
|
3
|
+
spoolNote
|
|
4
|
+
} from "./chunk-2VSZC6QM.js";
|
|
5
|
+
import {
|
|
6
|
+
getProcessRegistry,
|
|
7
|
+
redactCommand
|
|
8
|
+
} from "./chunk-3PVYQFRQ.js";
|
|
9
|
+
import {
|
|
10
|
+
buildWin32CmdShimInvocation,
|
|
11
|
+
resolveWin32Command
|
|
12
|
+
} from "./chunk-V43EQ6VR.js";
|
|
13
|
+
|
|
14
|
+
// src/_spawn-stream.ts
|
|
15
|
+
import { spawn } from "node:child_process";
|
|
16
|
+
import {
|
|
17
|
+
emitProcessCompleted,
|
|
18
|
+
emitProcessOutput,
|
|
19
|
+
emitProcessStarted
|
|
20
|
+
} from "@wrongstack/core/observability";
|
|
21
|
+
import { buildChildEnv } from "@wrongstack/core/utils";
|
|
22
|
+
var isWin = process.platform === "win32";
|
|
23
|
+
async function* spawnStream(opts) {
|
|
24
|
+
const max = opts.maxBytes ?? 999999999;
|
|
25
|
+
const flushAt = opts.flushBytes ?? 4 * 1024;
|
|
26
|
+
const maxQueue = opts.maxQueueSize ?? 500;
|
|
27
|
+
const maxQueueBytes = opts.maxQueueBytes ?? 1024 * 1024;
|
|
28
|
+
let stdout = "";
|
|
29
|
+
let stderr = "";
|
|
30
|
+
let stdoutRetainedBytes = 0;
|
|
31
|
+
let stderrRetainedBytes = 0;
|
|
32
|
+
let pending = "";
|
|
33
|
+
let error;
|
|
34
|
+
const spool = createOutputSpool({ tool: opts.cmd, thresholdBytes: max });
|
|
35
|
+
const resolved = resolveWin32Command(opts.cmd);
|
|
36
|
+
const needsShell = isWin && (resolved.endsWith(".cmd") || resolved.endsWith(".bat"));
|
|
37
|
+
const shim = needsShell ? buildWin32CmdShimInvocation(resolved, opts.args) : null;
|
|
38
|
+
const cmd = shim?.command ?? resolved;
|
|
39
|
+
const args = shim?.args ?? opts.args;
|
|
40
|
+
const child = spawn(cmd, args, {
|
|
41
|
+
cwd: opts.cwd,
|
|
42
|
+
env: buildChildEnv(),
|
|
43
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
44
|
+
windowsHide: true,
|
|
45
|
+
...isWin ? {} : { signal: opts.signal },
|
|
46
|
+
...shim ? { windowsVerbatimArguments: shim.windowsVerbatimArguments } : {}
|
|
47
|
+
});
|
|
48
|
+
const registry = getProcessRegistry();
|
|
49
|
+
const pid = child.pid;
|
|
50
|
+
const processStartedAt = Date.now();
|
|
51
|
+
let stdoutBytes = 0;
|
|
52
|
+
let stderrBytes = 0;
|
|
53
|
+
let telemetryCompleted = false;
|
|
54
|
+
emitProcessStarted({
|
|
55
|
+
...pid !== void 0 ? { pid } : {},
|
|
56
|
+
parentPid: process.pid,
|
|
57
|
+
command: redactCommand(`${opts.cmd} ${opts.args.join(" ")}`),
|
|
58
|
+
args: redactCommand(opts.args.join(" ")).split(" ").filter(Boolean),
|
|
59
|
+
cwd: opts.cwd,
|
|
60
|
+
background: false,
|
|
61
|
+
startedAt: new Date(processStartedAt).toISOString()
|
|
62
|
+
});
|
|
63
|
+
if (typeof pid === "number") {
|
|
64
|
+
registry.register({
|
|
65
|
+
pid,
|
|
66
|
+
name: opts.cmd,
|
|
67
|
+
command: redactCommand(`${opts.cmd} ${opts.args.join(" ")}`),
|
|
68
|
+
startedAt: Date.now(),
|
|
69
|
+
child
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
const queue = [];
|
|
73
|
+
let queuedBytes = 0;
|
|
74
|
+
let waiter;
|
|
75
|
+
let paused = false;
|
|
76
|
+
const wake = () => {
|
|
77
|
+
if (waiter) {
|
|
78
|
+
const w = waiter;
|
|
79
|
+
waiter = void 0;
|
|
80
|
+
w();
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
const resume = () => {
|
|
84
|
+
if (paused && queue.length <= Math.floor(maxQueue / 2) && queuedBytes <= Math.floor(maxQueueBytes / 2)) {
|
|
85
|
+
paused = false;
|
|
86
|
+
child.stdout?.resume();
|
|
87
|
+
child.stderr?.resume();
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
const onOut = (c) => {
|
|
91
|
+
const s = c.toString();
|
|
92
|
+
stdoutBytes += c.byteLength;
|
|
93
|
+
emitProcessOutput({ pid, stream: "stdout", chunk: c });
|
|
94
|
+
if (stdoutRetainedBytes < max) {
|
|
95
|
+
const retained = utf8Prefix(s, max - stdoutRetainedBytes);
|
|
96
|
+
stdout += retained;
|
|
97
|
+
stdoutRetainedBytes += Buffer.byteLength(retained, "utf8");
|
|
98
|
+
}
|
|
99
|
+
spool.write(s);
|
|
100
|
+
queue.push({ kind: "out", data: s, bytes: c.byteLength });
|
|
101
|
+
queuedBytes += c.byteLength;
|
|
102
|
+
wake();
|
|
103
|
+
if (!paused && (queue.length >= maxQueue || queuedBytes >= maxQueueBytes)) {
|
|
104
|
+
paused = true;
|
|
105
|
+
child.stdout?.pause();
|
|
106
|
+
child.stderr?.pause();
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
const onErr = (c) => {
|
|
110
|
+
const s = c.toString();
|
|
111
|
+
stderrBytes += c.byteLength;
|
|
112
|
+
emitProcessOutput({ pid, stream: "stderr", chunk: c });
|
|
113
|
+
if (stderrRetainedBytes < max) {
|
|
114
|
+
const retained = utf8Prefix(s, max - stderrRetainedBytes);
|
|
115
|
+
stderr += retained;
|
|
116
|
+
stderrRetainedBytes += Buffer.byteLength(retained, "utf8");
|
|
117
|
+
}
|
|
118
|
+
spool.write(s);
|
|
119
|
+
queue.push({ kind: "err", data: s, bytes: c.byteLength });
|
|
120
|
+
queuedBytes += c.byteLength;
|
|
121
|
+
wake();
|
|
122
|
+
if (!paused && (queue.length >= maxQueue || queuedBytes >= maxQueueBytes)) {
|
|
123
|
+
paused = true;
|
|
124
|
+
child.stdout?.pause();
|
|
125
|
+
child.stderr?.pause();
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
child.stdout?.on("data", onOut);
|
|
129
|
+
child.stderr?.on("data", onErr);
|
|
130
|
+
child.on("error", (e) => {
|
|
131
|
+
error = e.message;
|
|
132
|
+
const bytes = Buffer.byteLength(e.message, "utf8");
|
|
133
|
+
queue.push({ kind: "error", data: e.message, bytes });
|
|
134
|
+
queuedBytes += bytes;
|
|
135
|
+
wake();
|
|
136
|
+
});
|
|
137
|
+
const completeTelemetry = (code, signal, timedOut = false) => {
|
|
138
|
+
if (telemetryCompleted) return;
|
|
139
|
+
telemetryCompleted = true;
|
|
140
|
+
emitProcessCompleted({
|
|
141
|
+
...pid !== void 0 ? { pid } : {},
|
|
142
|
+
exitCode: code,
|
|
143
|
+
...signal ? { signal } : {},
|
|
144
|
+
durationMs: Date.now() - processStartedAt,
|
|
145
|
+
stdoutBytes,
|
|
146
|
+
stderrBytes,
|
|
147
|
+
timedOut,
|
|
148
|
+
endedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
149
|
+
});
|
|
150
|
+
};
|
|
151
|
+
child.on("close", (code, signal) => {
|
|
152
|
+
if (typeof pid === "number") registry.unregister(pid);
|
|
153
|
+
const exitCode2 = code ?? (signal ? 1 : 0);
|
|
154
|
+
completeTelemetry(exitCode2, signal ?? void 0);
|
|
155
|
+
queue.push({
|
|
156
|
+
kind: "close",
|
|
157
|
+
data: "",
|
|
158
|
+
bytes: 0,
|
|
159
|
+
code: exitCode2,
|
|
160
|
+
...signal ? { signal } : {}
|
|
161
|
+
});
|
|
162
|
+
wake();
|
|
163
|
+
});
|
|
164
|
+
const onAbort = () => {
|
|
165
|
+
if (typeof pid === "number") {
|
|
166
|
+
registry.kill(pid, { force: true });
|
|
167
|
+
} else {
|
|
168
|
+
try {
|
|
169
|
+
child.kill("SIGKILL");
|
|
170
|
+
} catch {
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
queue.push({ kind: "close", data: "", bytes: 0, code: 124 });
|
|
174
|
+
completeTelemetry(124, "SIGKILL", true);
|
|
175
|
+
wake();
|
|
176
|
+
};
|
|
177
|
+
if (isWin) {
|
|
178
|
+
if (opts.signal.aborted) onAbort();
|
|
179
|
+
else opts.signal.addEventListener("abort", onAbort, { once: true });
|
|
180
|
+
}
|
|
181
|
+
let exitCode = 0;
|
|
182
|
+
let spawnFailed = false;
|
|
183
|
+
try {
|
|
184
|
+
for (; ; ) {
|
|
185
|
+
while (queue.length === 0) {
|
|
186
|
+
await new Promise((resolve) => {
|
|
187
|
+
waiter = resolve;
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
const chunk = queue.shift();
|
|
191
|
+
queuedBytes -= chunk.bytes;
|
|
192
|
+
resume();
|
|
193
|
+
if (chunk.kind === "close") {
|
|
194
|
+
if (!spawnFailed) exitCode = chunk.code ?? 0;
|
|
195
|
+
break;
|
|
196
|
+
}
|
|
197
|
+
if (chunk.kind === "error") {
|
|
198
|
+
spawnFailed = true;
|
|
199
|
+
exitCode = 1;
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
pending += chunk.data;
|
|
203
|
+
if (pending.length >= flushAt) {
|
|
204
|
+
yield { type: "partial_output", text: pending };
|
|
205
|
+
pending = "";
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
if (pending.length > 0) {
|
|
209
|
+
yield { type: "partial_output", text: pending };
|
|
210
|
+
}
|
|
211
|
+
const spooled = spool.finalize();
|
|
212
|
+
return {
|
|
213
|
+
// The marker rides on stdout's tail so every consumer's head+tail
|
|
214
|
+
// normalization keeps it without per-tool changes.
|
|
215
|
+
stdout: spooled ? stdout + spoolNote(spooled) : stdout,
|
|
216
|
+
stderr,
|
|
217
|
+
exitCode,
|
|
218
|
+
truncated: stdoutBytes > stdoutRetainedBytes || stderrBytes > stderrRetainedBytes,
|
|
219
|
+
error,
|
|
220
|
+
spoolPath: spooled?.path,
|
|
221
|
+
spoolBytes: spooled?.bytes
|
|
222
|
+
};
|
|
223
|
+
} finally {
|
|
224
|
+
spool.finalize();
|
|
225
|
+
if (isWin) opts.signal.removeEventListener("abort", onAbort);
|
|
226
|
+
child.stdout?.off("data", onOut);
|
|
227
|
+
child.stderr?.off("data", onErr);
|
|
228
|
+
child.stdout?.destroy();
|
|
229
|
+
child.stderr?.destroy();
|
|
230
|
+
if (child.exitCode === null && !child.killed) {
|
|
231
|
+
if (typeof pid === "number") {
|
|
232
|
+
registry.kill(pid, { force: true });
|
|
233
|
+
} else {
|
|
234
|
+
try {
|
|
235
|
+
child.kill("SIGKILL");
|
|
236
|
+
} catch {
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
function utf8Prefix(text, maxBytes) {
|
|
243
|
+
if (maxBytes <= 0) return "";
|
|
244
|
+
if (Buffer.byteLength(text, "utf8") <= maxBytes) return text;
|
|
245
|
+
let low = 0;
|
|
246
|
+
let high = text.length;
|
|
247
|
+
while (low < high) {
|
|
248
|
+
const mid = Math.ceil((low + high) / 2);
|
|
249
|
+
if (Buffer.byteLength(text.slice(0, mid), "utf8") <= maxBytes) low = mid;
|
|
250
|
+
else high = mid - 1;
|
|
251
|
+
}
|
|
252
|
+
let end = low;
|
|
253
|
+
if (end > 0 && /[\uD800-\uDBFF]/.test(text[end - 1])) end--;
|
|
254
|
+
return text.slice(0, end);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
export {
|
|
258
|
+
spawnStream
|
|
259
|
+
};
|
|
260
|
+
//# sourceMappingURL=chunk-22B7GE5T.js.map
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// src/_output-spool.ts
|
|
2
|
+
import { createWriteStream, mkdirSync } from "node:fs";
|
|
3
|
+
import * as fsp from "node:fs/promises";
|
|
4
|
+
import * as path from "node:path";
|
|
5
|
+
import { wstackGlobalRoot } from "@wrongstack/core/utils";
|
|
6
|
+
var SPOOL_RETENTION_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
7
|
+
var SPOOL_WRITE_HWM_BYTES = 4 * 1024 * 1024;
|
|
8
|
+
var sweepStarted = false;
|
|
9
|
+
function toolOutputDir() {
|
|
10
|
+
return path.join(wstackGlobalRoot(), "tool-output");
|
|
11
|
+
}
|
|
12
|
+
function sweepOldSpoolFiles(dir) {
|
|
13
|
+
if (sweepStarted) return;
|
|
14
|
+
sweepStarted = true;
|
|
15
|
+
void (async () => {
|
|
16
|
+
try {
|
|
17
|
+
const now = Date.now();
|
|
18
|
+
for (const name of await fsp.readdir(dir)) {
|
|
19
|
+
if (!name.endsWith(".log")) continue;
|
|
20
|
+
const p = path.join(dir, name);
|
|
21
|
+
try {
|
|
22
|
+
const st = await fsp.stat(p);
|
|
23
|
+
if (now - st.mtimeMs > SPOOL_RETENTION_MS) await fsp.unlink(p);
|
|
24
|
+
} catch {
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
} catch {
|
|
28
|
+
}
|
|
29
|
+
})();
|
|
30
|
+
}
|
|
31
|
+
function spoolNote(info) {
|
|
32
|
+
const dropped = info.droppedBytes > 0 ? `, ~${info.droppedBytes} bytes dropped under backpressure` : "";
|
|
33
|
+
return `
|
|
34
|
+
[output truncated \u2014 full ${info.bytes} bytes at ${info.path}${dropped}; read/grep that file selectively instead of re-running with more output]`;
|
|
35
|
+
}
|
|
36
|
+
function createOutputSpool(opts) {
|
|
37
|
+
const threshold = opts.thresholdBytes ?? 32768;
|
|
38
|
+
const safeTool = opts.tool.replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 40) || "tool";
|
|
39
|
+
let head = "";
|
|
40
|
+
let headBytes = 0;
|
|
41
|
+
let totalBytes = 0;
|
|
42
|
+
let droppedBytes = 0;
|
|
43
|
+
let stream = null;
|
|
44
|
+
let filePath = null;
|
|
45
|
+
let failed = false;
|
|
46
|
+
let finalized = false;
|
|
47
|
+
const open = () => {
|
|
48
|
+
if (stream || failed) return;
|
|
49
|
+
try {
|
|
50
|
+
const dir = toolOutputDir();
|
|
51
|
+
mkdirSync(dir, { recursive: true });
|
|
52
|
+
sweepOldSpoolFiles(dir);
|
|
53
|
+
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
54
|
+
const rand = Math.random().toString(36).slice(2, 6);
|
|
55
|
+
filePath = path.join(dir, `${stamp}-${safeTool}-${rand}.log`);
|
|
56
|
+
stream = createWriteStream(filePath, { flags: "w", encoding: "utf8" });
|
|
57
|
+
stream.on("error", () => {
|
|
58
|
+
failed = true;
|
|
59
|
+
stream = null;
|
|
60
|
+
filePath = null;
|
|
61
|
+
});
|
|
62
|
+
stream.write(head);
|
|
63
|
+
} catch {
|
|
64
|
+
failed = true;
|
|
65
|
+
stream = null;
|
|
66
|
+
filePath = null;
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
return {
|
|
70
|
+
write(text) {
|
|
71
|
+
if (finalized || !text) return;
|
|
72
|
+
const textBytes = Buffer.byteLength(text, "utf8");
|
|
73
|
+
totalBytes += textBytes;
|
|
74
|
+
if (!stream && !failed) {
|
|
75
|
+
if (headBytes + textBytes <= threshold) {
|
|
76
|
+
head += text;
|
|
77
|
+
headBytes += textBytes;
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
head += text;
|
|
81
|
+
open();
|
|
82
|
+
head = "";
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (stream) {
|
|
86
|
+
if (stream.writableLength > SPOOL_WRITE_HWM_BYTES) {
|
|
87
|
+
droppedBytes += textBytes;
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
stream.write(text);
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
finalize() {
|
|
94
|
+
if (finalized) {
|
|
95
|
+
return filePath ? { path: filePath, bytes: totalBytes, droppedBytes } : null;
|
|
96
|
+
}
|
|
97
|
+
finalized = true;
|
|
98
|
+
head = "";
|
|
99
|
+
if (!stream || !filePath) return null;
|
|
100
|
+
try {
|
|
101
|
+
stream.end();
|
|
102
|
+
} catch {
|
|
103
|
+
}
|
|
104
|
+
return { path: filePath, bytes: totalBytes, droppedBytes };
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export {
|
|
110
|
+
spoolNote,
|
|
111
|
+
createOutputSpool
|
|
112
|
+
};
|
|
113
|
+
//# sourceMappingURL=chunk-2VSZC6QM.js.map
|