@agimon-ai/po-runner 0.0.0-alpha.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/LICENSE +21 -0
- package/README.md +257 -0
- package/dist/ansiScrub-CsqTSaVT.mjs +71 -0
- package/dist/ansiScrub-CsqTSaVT.mjs.map +1 -0
- package/dist/ansiScrub-D5gpHDch.cjs +100 -0
- package/dist/ansiScrub-D5gpHDch.cjs.map +1 -0
- package/dist/ansiScrub.cjs +7 -0
- package/dist/ansiScrub.d.mts +26 -0
- package/dist/ansiScrub.d.mts.map +1 -0
- package/dist/ansiScrub.mjs +2 -0
- package/dist/apiContracts.cjs +162 -0
- package/dist/apiContracts.cjs.map +1 -0
- package/dist/apiContracts.d.mts +53 -0
- package/dist/apiContracts.d.mts.map +1 -0
- package/dist/apiContracts.mjs +157 -0
- package/dist/apiContracts.mjs.map +1 -0
- package/dist/bashResult-DNgtahGR.cjs +629 -0
- package/dist/bashResult-DNgtahGR.cjs.map +1 -0
- package/dist/bashResult-DcrRaBLv.d.mts +49 -0
- package/dist/bashResult-DcrRaBLv.d.mts.map +1 -0
- package/dist/bashResult-bIVSzoj-.mjs +546 -0
- package/dist/bashResult-bIVSzoj-.mjs.map +1 -0
- package/dist/bashRunService-CJ02XaAq.mjs +440 -0
- package/dist/bashRunService-CJ02XaAq.mjs.map +1 -0
- package/dist/bashRunService-Ci0cGdYO.d.mts +71 -0
- package/dist/bashRunService-Ci0cGdYO.d.mts.map +1 -0
- package/dist/bashRunService-DyqxOSlx.cjs +445 -0
- package/dist/bashRunService-DyqxOSlx.cjs.map +1 -0
- package/dist/bashRunService.cjs +3 -0
- package/dist/bashRunService.d.mts +36 -0
- package/dist/bashRunService.d.mts.map +1 -0
- package/dist/bashRunService.mjs +2 -0
- package/dist/bashSchema.cjs +5 -0
- package/dist/bashSchema.d.mts +7 -0
- package/dist/bashSchema.d.mts.map +1 -0
- package/dist/bashSchema.mjs +2 -0
- package/dist/bashTool-B1EwZLo_.d.mts +20 -0
- package/dist/bashTool-B1EwZLo_.d.mts.map +1 -0
- package/dist/bashTool-C-k7fmyh.mjs +24 -0
- package/dist/bashTool-C-k7fmyh.mjs.map +1 -0
- package/dist/bashTool-CdgtqVFD.cjs +41 -0
- package/dist/bashTool-CdgtqVFD.cjs.map +1 -0
- package/dist/bashTool.cjs +13 -0
- package/dist/bashTool.cjs.map +1 -0
- package/dist/bashTool.d.mts +8 -0
- package/dist/bashTool.d.mts.map +1 -0
- package/dist/bashTool.mjs +11 -0
- package/dist/bashTool.mjs.map +1 -0
- package/dist/bin/cli.cjs +78 -0
- package/dist/bin/cli.cjs.map +1 -0
- package/dist/bin/cli.d.mts +4 -0
- package/dist/bin/cli.d.mts.map +1 -0
- package/dist/bin/cli.mjs +77 -0
- package/dist/bin/cli.mjs.map +1 -0
- package/dist/bin/logSink.cjs +102 -0
- package/dist/bin/logSink.cjs.map +1 -0
- package/dist/bin/logSink.d.mts +4 -0
- package/dist/bin/logSink.d.mts.map +1 -0
- package/dist/bin/logSink.mjs +99 -0
- package/dist/bin/logSink.mjs.map +1 -0
- package/dist/bin/runnerHost.cjs +131 -0
- package/dist/bin/runnerHost.cjs.map +1 -0
- package/dist/bin/runnerHost.d.mts +4 -0
- package/dist/bin/runnerHost.d.mts.map +1 -0
- package/dist/bin/runnerHost.mjs +127 -0
- package/dist/bin/runnerHost.mjs.map +1 -0
- package/dist/cliApp-Dj9nwaOv.cjs +244 -0
- package/dist/cliApp-Dj9nwaOv.cjs.map +1 -0
- package/dist/cliApp-v8Z3rMCi.mjs +237 -0
- package/dist/cliApp-v8Z3rMCi.mjs.map +1 -0
- package/dist/cliApp.cjs +3 -0
- package/dist/cliApp.d.mts +18 -0
- package/dist/cliApp.d.mts.map +1 -0
- package/dist/cliApp.mjs +2 -0
- package/dist/clock-Cv2pddgo.mjs +16 -0
- package/dist/clock-Cv2pddgo.mjs.map +1 -0
- package/dist/clock-euJkweLq.d.mts +11 -0
- package/dist/clock-euJkweLq.d.mts.map +1 -0
- package/dist/clock-jqnLWziT.cjs +21 -0
- package/dist/clock-jqnLWziT.cjs.map +1 -0
- package/dist/clock.cjs +3 -0
- package/dist/clock.d.mts +10 -0
- package/dist/clock.d.mts.map +1 -0
- package/dist/clock.mjs +2 -0
- package/dist/compaction-4QSUsBxq.cjs +40 -0
- package/dist/compaction-4QSUsBxq.cjs.map +1 -0
- package/dist/compaction-DCw80VZj.mjs +29 -0
- package/dist/compaction-DCw80VZj.mjs.map +1 -0
- package/dist/compaction.cjs +4 -0
- package/dist/compaction.d.mts +10 -0
- package/dist/compaction.d.mts.map +1 -0
- package/dist/compaction.mjs +2 -0
- package/dist/config.cjs +41 -0
- package/dist/config.d.mts +2 -0
- package/dist/config.mjs +2 -0
- package/dist/extensions/mcp-ui.mjs +23 -0
- package/dist/extensions/mcp-ui.mjs.map +1 -0
- package/dist/extensions/mcp.cjs +142 -0
- package/dist/extensions/mcp.cjs.map +1 -0
- package/dist/extensions/mcp.d.mts +5 -0
- package/dist/extensions/mcp.d.mts.map +1 -0
- package/dist/extensions/mcp.mjs +114 -0
- package/dist/extensions/mcp.mjs.map +1 -0
- package/dist/extensions/server.cjs +1156 -0
- package/dist/extensions/server.cjs.map +1 -0
- package/dist/extensions/server.d.mts +5 -0
- package/dist/extensions/server.d.mts.map +1 -0
- package/dist/extensions/server.mjs +1146 -0
- package/dist/extensions/server.mjs.map +1 -0
- package/dist/extensions/web.mjs +1785 -0
- package/dist/extensions/web.mjs.map +1 -0
- package/dist/headless-BGYfIlNk.mjs +169 -0
- package/dist/headless-BGYfIlNk.mjs.map +1 -0
- package/dist/headless-CHUsBGhg.cjs +180 -0
- package/dist/headless-CHUsBGhg.cjs.map +1 -0
- package/dist/index-BZL7keVW.d.mts +31 -0
- package/dist/index-BZL7keVW.d.mts.map +1 -0
- package/dist/index-BwB_jTI9.d.mts +12 -0
- package/dist/index-BwB_jTI9.d.mts.map +1 -0
- package/dist/index-D9-IXax4.d.mts +43 -0
- package/dist/index-D9-IXax4.d.mts.map +1 -0
- package/dist/index-DBz0DxnL.d.mts +39 -0
- package/dist/index-DBz0DxnL.d.mts.map +1 -0
- package/dist/index-DM7yJpMs.d.mts +25 -0
- package/dist/index-DM7yJpMs.d.mts.map +1 -0
- package/dist/index-Dhi8asLH.d.mts +22 -0
- package/dist/index-Dhi8asLH.d.mts.map +1 -0
- package/dist/index.cjs +19 -0
- package/dist/index.d.mts +7 -0
- package/dist/index.mjs +6 -0
- package/dist/launcher-BDm6-DiQ.mjs +150 -0
- package/dist/launcher-BDm6-DiQ.mjs.map +1 -0
- package/dist/launcher-BG5t9nvG.d.mts +39 -0
- package/dist/launcher-BG5t9nvG.d.mts.map +1 -0
- package/dist/launcher-SlyE8R3b.cjs +157 -0
- package/dist/launcher-SlyE8R3b.cjs.map +1 -0
- package/dist/launcher.cjs +3 -0
- package/dist/launcher.d.mts +33 -0
- package/dist/launcher.d.mts.map +1 -0
- package/dist/launcher.mjs +2 -0
- package/dist/lifeline-BZaQA0rm.mjs +88 -0
- package/dist/lifeline-BZaQA0rm.mjs.map +1 -0
- package/dist/lifeline-BuV_erib.cjs +98 -0
- package/dist/lifeline-BuV_erib.cjs.map +1 -0
- package/dist/lifeline-eJdZV0nN.d.mts +19 -0
- package/dist/lifeline-eJdZV0nN.d.mts.map +1 -0
- package/dist/lifeline.cjs +6 -0
- package/dist/lifeline.d.mts +21 -0
- package/dist/lifeline.d.mts.map +1 -0
- package/dist/lifeline.mjs +3 -0
- package/dist/logFile-C7oQ_v-g.d.mts +16 -0
- package/dist/logFile-C7oQ_v-g.d.mts.map +1 -0
- package/dist/logFile-CNvepZh0.cjs +67 -0
- package/dist/logFile-CNvepZh0.cjs.map +1 -0
- package/dist/logFile-KKPbkC-a.mjs +60 -0
- package/dist/logFile-KKPbkC-a.mjs.map +1 -0
- package/dist/logFile.cjs +3 -0
- package/dist/logFile.d.mts +11 -0
- package/dist/logFile.d.mts.map +1 -0
- package/dist/logFile.mjs +2 -0
- package/dist/logReader-B6J7L7Ua.cjs +282 -0
- package/dist/logReader-B6J7L7Ua.cjs.map +1 -0
- package/dist/logReader-MdW9ffvV.d.mts +43 -0
- package/dist/logReader-MdW9ffvV.d.mts.map +1 -0
- package/dist/logReader-UfbDbwQl.mjs +257 -0
- package/dist/logReader-UfbDbwQl.mjs.map +1 -0
- package/dist/logReader.cjs +4 -0
- package/dist/logReader.d.mts +3 -0
- package/dist/logReader.mjs +2 -0
- package/dist/processControl-BAOa3oo_.d.mts +14 -0
- package/dist/processControl-BAOa3oo_.d.mts.map +1 -0
- package/dist/processControl-DApTpV16.mjs +26 -0
- package/dist/processControl-DApTpV16.mjs.map +1 -0
- package/dist/processControl-DNJ1WZ9N.cjs +31 -0
- package/dist/processControl-DNJ1WZ9N.cjs.map +1 -0
- package/dist/processControl.cjs +3 -0
- package/dist/processControl.d.mts +10 -0
- package/dist/processControl.d.mts.map +1 -0
- package/dist/processControl.mjs +2 -0
- package/dist/ptyHost-DWWtRrGn.d.mts +38 -0
- package/dist/ptyHost-DWWtRrGn.d.mts.map +1 -0
- package/dist/ptyHost-DlQtTB8F.mjs +150 -0
- package/dist/ptyHost-DlQtTB8F.mjs.map +1 -0
- package/dist/ptyHost-MI2Z6WTG.cjs +157 -0
- package/dist/ptyHost-MI2Z6WTG.cjs.map +1 -0
- package/dist/ptyHost.cjs +3 -0
- package/dist/ptyHost.d.mts +26 -0
- package/dist/ptyHost.d.mts.map +1 -0
- package/dist/ptyHost.mjs +2 -0
- package/dist/ptySpawner-B6GsueZd.d.mts +28 -0
- package/dist/ptySpawner-B6GsueZd.d.mts.map +1 -0
- package/dist/ptySpawner-DEi1KOnd.mjs +17 -0
- package/dist/ptySpawner-DEi1KOnd.mjs.map +1 -0
- package/dist/ptySpawner-ijw0g5_T.cjs +22 -0
- package/dist/ptySpawner-ijw0g5_T.cjs.map +1 -0
- package/dist/ptySpawner.cjs +3 -0
- package/dist/ptySpawner.d.mts +14 -0
- package/dist/ptySpawner.d.mts.map +1 -0
- package/dist/ptySpawner.mjs +2 -0
- package/dist/reconcile-BugwYFbV.cjs +133 -0
- package/dist/reconcile-BugwYFbV.cjs.map +1 -0
- package/dist/reconcile-DMeNSxwn.mjs +114 -0
- package/dist/reconcile-DMeNSxwn.mjs.map +1 -0
- package/dist/reconcile.cjs +5 -0
- package/dist/reconcile.d.mts +36 -0
- package/dist/reconcile.d.mts.map +1 -0
- package/dist/reconcile.mjs +2 -0
- package/dist/responseEnvelope.cjs +19 -0
- package/dist/responseEnvelope.d.mts +50 -0
- package/dist/responseEnvelope.d.mts.map +1 -0
- package/dist/responseEnvelope.mjs +3 -0
- package/dist/rmuxBackend-CaEWooWn.d.mts +36 -0
- package/dist/rmuxBackend-CaEWooWn.d.mts.map +1 -0
- package/dist/rmuxBackend-DfyQwJrc.mjs +509 -0
- package/dist/rmuxBackend-DfyQwJrc.mjs.map +1 -0
- package/dist/rmuxBackend-DlxgqRZ1.cjs +523 -0
- package/dist/rmuxBackend-DlxgqRZ1.cjs.map +1 -0
- package/dist/rmuxBackend.cjs +4 -0
- package/dist/rmuxBackend.d.mts +3 -0
- package/dist/rmuxBackend.mjs +2 -0
- package/dist/rolldown-runtime-VH7oDXx4.cjs +28 -0
- package/dist/rtkProcessor-B4_urXQr.mjs +10 -0
- package/dist/rtkProcessor-B4_urXQr.mjs.map +1 -0
- package/dist/rtkProcessor-B9KPdyzr.mjs +309 -0
- package/dist/rtkProcessor-B9KPdyzr.mjs.map +1 -0
- package/dist/rtkProcessor-Bc4L4o_8.cjs +335 -0
- package/dist/rtkProcessor-Bc4L4o_8.cjs.map +1 -0
- package/dist/rtkProcessor-CVZvNhkJ.d.mts +35 -0
- package/dist/rtkProcessor-CVZvNhkJ.d.mts.map +1 -0
- package/dist/rtkProcessor-CsrCPyTQ.cjs +33 -0
- package/dist/rtkProcessor-CsrCPyTQ.cjs.map +1 -0
- package/dist/rtkProcessor.cjs +11 -0
- package/dist/rtkProcessor.d.mts +7 -0
- package/dist/rtkProcessor.d.mts.map +1 -0
- package/dist/rtkProcessor.mjs +3 -0
- package/dist/runnerConfig-BQBlVAXn.mjs +134 -0
- package/dist/runnerConfig-BQBlVAXn.mjs.map +1 -0
- package/dist/runnerConfig-BjtulXBI.d.mts +57 -0
- package/dist/runnerConfig-BjtulXBI.d.mts.map +1 -0
- package/dist/runnerConfig-D2tGq5ZM.cjs +367 -0
- package/dist/runnerConfig-D2tGq5ZM.cjs.map +1 -0
- package/dist/runnerDependencies-DruByBGS.mjs +647 -0
- package/dist/runnerDependencies-DruByBGS.mjs.map +1 -0
- package/dist/runnerDependencies-KMZigIxB.cjs +667 -0
- package/dist/runnerDependencies-KMZigIxB.cjs.map +1 -0
- package/dist/runnerDependencies.cjs +3 -0
- package/dist/runnerDependencies.d.mts +2 -0
- package/dist/runnerDependencies.mjs +2 -0
- package/dist/runnerNamer-B8FH7n2v.mjs +44 -0
- package/dist/runnerNamer-B8FH7n2v.mjs.map +1 -0
- package/dist/runnerNamer-we1XVYfM.cjs +49 -0
- package/dist/runnerNamer-we1XVYfM.cjs.map +1 -0
- package/dist/runnerNamer.cjs +3 -0
- package/dist/runnerNamer.d.mts +11 -0
- package/dist/runnerNamer.d.mts.map +1 -0
- package/dist/runnerNamer.mjs +2 -0
- package/dist/runnerPaths-BTEuzxw0.cjs +471 -0
- package/dist/runnerPaths-BTEuzxw0.cjs.map +1 -0
- package/dist/runnerPaths-B_dAAeco.mjs +451 -0
- package/dist/runnerPaths-B_dAAeco.mjs.map +1 -0
- package/dist/runnerPaths.cjs +3 -0
- package/dist/runnerPaths.d.mts +50 -0
- package/dist/runnerPaths.d.mts.map +1 -0
- package/dist/runnerPaths.mjs +2 -0
- package/dist/runnerRegistry-BmkZTJHi.cjs +371 -0
- package/dist/runnerRegistry-BmkZTJHi.cjs.map +1 -0
- package/dist/runnerRegistry-CeOHEjBv.mjs +339 -0
- package/dist/runnerRegistry-CeOHEjBv.mjs.map +1 -0
- package/dist/runnerRegistry-CtJiD02R.d.mts +88 -0
- package/dist/runnerRegistry-CtJiD02R.d.mts.map +1 -0
- package/dist/runnerRegistry.cjs +4 -0
- package/dist/runnerRegistry.d.mts +3 -0
- package/dist/runnerRegistry.mjs +2 -0
- package/dist/runnerSettings-DiV1lvzx.d.mts +34 -0
- package/dist/runnerSettings-DiV1lvzx.d.mts.map +1 -0
- package/dist/services/lifeline/client.cjs +52 -0
- package/dist/services/lifeline/client.cjs.map +1 -0
- package/dist/services/lifeline/client.d.mts +22 -0
- package/dist/services/lifeline/client.d.mts.map +1 -0
- package/dist/services/lifeline/client.mjs +48 -0
- package/dist/services/lifeline/client.mjs.map +1 -0
- package/dist/services/runnerSupervisor/index.cjs +207 -0
- package/dist/services/runnerSupervisor/index.cjs.map +1 -0
- package/dist/services/runnerSupervisor/index.d.mts +71 -0
- package/dist/services/runnerSupervisor/index.d.mts.map +1 -0
- package/dist/services/runnerSupervisor/index.mjs +195 -0
- package/dist/services/runnerSupervisor/index.mjs.map +1 -0
- package/dist/session-BC43uEyG.cjs +29 -0
- package/dist/session-BC43uEyG.cjs.map +1 -0
- package/dist/session-Chsb_Nh2.mjs +18 -0
- package/dist/session-Chsb_Nh2.mjs.map +1 -0
- package/dist/session-DE2Acesp.mjs +6 -0
- package/dist/session-DE2Acesp.mjs.map +1 -0
- package/dist/session-SfIPtdZO.cjs +11 -0
- package/dist/session-SfIPtdZO.cjs.map +1 -0
- package/dist/session.cjs +6 -0
- package/dist/session.d.mts +11 -0
- package/dist/session.d.mts.map +1 -0
- package/dist/session.mjs +3 -0
- package/dist/spawner-BxFsINXP.cjs +68 -0
- package/dist/spawner-BxFsINXP.cjs.map +1 -0
- package/dist/spawner-CdrN_HNk.d.mts +35 -0
- package/dist/spawner-CdrN_HNk.d.mts.map +1 -0
- package/dist/spawner-LoVsn55-.mjs +63 -0
- package/dist/spawner-LoVsn55-.mjs.map +1 -0
- package/dist/spawner.cjs +3 -0
- package/dist/spawner.d.mts +9 -0
- package/dist/spawner.d.mts.map +1 -0
- package/dist/spawner.mjs +2 -0
- package/dist/type-BXM03qSw.d.mts +44 -0
- package/dist/type-BXM03qSw.d.mts.map +1 -0
- package/dist/type-C31e1gla.d.mts +43 -0
- package/dist/type-C31e1gla.d.mts.map +1 -0
- package/dist/type-vWQNTahw.d.mts +12 -0
- package/dist/type-vWQNTahw.d.mts.map +1 -0
- package/dist/types.cjs +0 -0
- package/dist/types.d.mts +3 -0
- package/dist/types.mjs +1 -0
- package/llms.txt +9 -0
- package/package.json +303 -0
- package/skills/doom-runner/SKILL.md +78 -0
- package/src/prompts/po-use-runner/SKILL.md +47 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { s as getLogMaxBytes } from "./runnerConfig-BQBlVAXn.mjs";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
//#region src/services/logFile/index.ts
|
|
4
|
+
var LogFile = class {
|
|
5
|
+
paths;
|
|
6
|
+
constructor(paths) {
|
|
7
|
+
this.paths = paths;
|
|
8
|
+
}
|
|
9
|
+
open(id) {
|
|
10
|
+
this.paths.ensureDirectories();
|
|
11
|
+
const logPath = this.paths.logPathFor(id);
|
|
12
|
+
const rotatedPath = this.paths.rotatedLogPathFor(id);
|
|
13
|
+
const maxBytes = getLogMaxBytes();
|
|
14
|
+
let handle = fs.openSync(logPath, "w");
|
|
15
|
+
let written = 0;
|
|
16
|
+
let closed = false;
|
|
17
|
+
/**
|
|
18
|
+
* A run that keeps producing output for hours would otherwise grow one file
|
|
19
|
+
* without limit. Rotating keeps the newest window at the advertised path
|
|
20
|
+
* and the window before it alongside, so on-disk cost is bounded at roughly
|
|
21
|
+
* twice the ceiling, the path a result advertises stays valid, and the line
|
|
22
|
+
* counts a reader reports still describe the file it actually read.
|
|
23
|
+
*/
|
|
24
|
+
const rotate = () => {
|
|
25
|
+
fs.closeSync(handle);
|
|
26
|
+
try {
|
|
27
|
+
fs.renameSync(logPath, rotatedPath);
|
|
28
|
+
} catch (error) {
|
|
29
|
+
process.emitWarning(`Could not rotate runner log ${logPath}: ${String(error)}`);
|
|
30
|
+
}
|
|
31
|
+
handle = fs.openSync(logPath, "w");
|
|
32
|
+
written = 0;
|
|
33
|
+
};
|
|
34
|
+
return {
|
|
35
|
+
path: logPath,
|
|
36
|
+
append(text) {
|
|
37
|
+
const chunk = Buffer.from(text, "utf8");
|
|
38
|
+
if (written > 0 && written + chunk.byteLength > maxBytes) rotate();
|
|
39
|
+
fs.writeSync(handle, chunk);
|
|
40
|
+
written += chunk.byteLength;
|
|
41
|
+
},
|
|
42
|
+
size() {
|
|
43
|
+
return written;
|
|
44
|
+
},
|
|
45
|
+
close() {
|
|
46
|
+
if (closed) return;
|
|
47
|
+
closed = true;
|
|
48
|
+
try {
|
|
49
|
+
fs.closeSync(handle);
|
|
50
|
+
} catch (error) {
|
|
51
|
+
process.emitWarning(`Could not close runner log ${logPath}: ${String(error)}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
//#endregion
|
|
58
|
+
export { LogFile as t };
|
|
59
|
+
|
|
60
|
+
//# sourceMappingURL=logFile-KKPbkC-a.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logFile-KKPbkC-a.mjs","names":[],"sources":["../src/services/logFile/index.ts"],"sourcesContent":["import fs from 'node:fs';\n\nimport type { ILogFile, LogWriter } from '../../types/logFile';\nimport { getLogMaxBytes } from '../runnerConfig';\nimport type { IRunnerPaths } from '../runnerPaths/type';\n\nexport class LogFile implements ILogFile {\n constructor(private readonly paths: IRunnerPaths) {}\n\n open(id: string): LogWriter {\n this.paths.ensureDirectories();\n const logPath = this.paths.logPathFor(id);\n const rotatedPath = this.paths.rotatedLogPathFor(id);\n const maxBytes = getLogMaxBytes();\n\n // A reused name starts clean: the previous runner's output is already\n // available to whoever wanted it, and mixing two runs in one file makes\n // both unreadable.\n let handle = fs.openSync(logPath, 'w');\n let written = 0;\n let closed = false;\n\n /**\n * A run that keeps producing output for hours would otherwise grow one file\n * without limit. Rotating keeps the newest window at the advertised path\n * and the window before it alongside, so on-disk cost is bounded at roughly\n * twice the ceiling, the path a result advertises stays valid, and the line\n * counts a reader reports still describe the file it actually read.\n */\n const rotate = (): void => {\n fs.closeSync(handle);\n try {\n fs.renameSync(logPath, rotatedPath);\n } catch (error) {\n // Holding the ceiling matters more than keeping the previous window,\n // so the new file is opened either way and the loss is reported.\n process.emitWarning(`Could not rotate runner log ${logPath}: ${String(error)}`);\n }\n handle = fs.openSync(logPath, 'w');\n written = 0;\n };\n\n return {\n path: logPath,\n append(text: string): void {\n const chunk = Buffer.from(text, 'utf8');\n // An empty file always takes the chunk, so a single write larger than\n // the ceiling is stored rather than rotated away into nothing.\n if (written > 0 && written + chunk.byteLength > maxBytes) rotate();\n fs.writeSync(handle, chunk);\n written += chunk.byteLength;\n },\n size(): number {\n return written;\n },\n close(): void {\n // Closing twice is normal: a launch that fails closes the log before\n // the exit handler does. Only a first close that fails is news.\n if (closed) return;\n closed = true;\n try {\n fs.closeSync(handle);\n } catch (error) {\n process.emitWarning(`Could not close runner log ${logPath}: ${String(error)}`);\n }\n },\n };\n }\n}\n"],"mappings":";;;AAMA,IAAa,UAAb,MAAyC;CACV;CAA7B,YAAY,OAAsC;EAArB,KAAA,QAAA;CAAsB;CAEnD,KAAK,IAAuB;EAC1B,KAAK,MAAM,kBAAkB;EAC7B,MAAM,UAAU,KAAK,MAAM,WAAW,EAAE;EACxC,MAAM,cAAc,KAAK,MAAM,kBAAkB,EAAE;EACnD,MAAM,WAAW,eAAe;EAKhC,IAAI,SAAS,GAAG,SAAS,SAAS,GAAG;EACrC,IAAI,UAAU;EACd,IAAI,SAAS;;;;;;;;EASb,MAAM,eAAqB;GACzB,GAAG,UAAU,MAAM;GACnB,IAAI;IACF,GAAG,WAAW,SAAS,WAAW;GACpC,SAAS,OAAO;IAGd,QAAQ,YAAY,+BAA+B,QAAQ,IAAI,OAAO,KAAK,GAAG;GAChF;GACA,SAAS,GAAG,SAAS,SAAS,GAAG;GACjC,UAAU;EACZ;EAEA,OAAO;GACL,MAAM;GACN,OAAO,MAAoB;IACzB,MAAM,QAAQ,OAAO,KAAK,MAAM,MAAM;IAGtC,IAAI,UAAU,KAAK,UAAU,MAAM,aAAa,UAAU,OAAO;IACjE,GAAG,UAAU,QAAQ,KAAK;IAC1B,WAAW,MAAM;GACnB;GACA,OAAe;IACb,OAAO;GACT;GACA,QAAc;IAGZ,IAAI,QAAQ;IACZ,SAAS;IACT,IAAI;KACF,GAAG,UAAU,MAAM;IACrB,SAAS,OAAO;KACd,QAAQ,YAAY,8BAA8B,QAAQ,IAAI,OAAO,KAAK,GAAG;IAC/E;GACF;EACF;CACF;AACF"}
|
package/dist/logFile.cjs
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { n as LogWriter, t as ILogFile } from "./logFile-C7oQ_v-g.mjs";
|
|
2
|
+
import { t as IRunnerPaths } from "./type-BXM03qSw.mjs";
|
|
3
|
+
//#region src/services/logFile/index.d.ts
|
|
4
|
+
export declare class LogFile implements ILogFile {
|
|
5
|
+
private readonly paths;
|
|
6
|
+
constructor(paths: IRunnerPaths);
|
|
7
|
+
open(id: string): LogWriter;
|
|
8
|
+
}
|
|
9
|
+
//#endregion
|
|
10
|
+
export type { ILogFile, LogWriter };
|
|
11
|
+
//# sourceMappingURL=logFile.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logFile.d.mts","names":[],"sources":["../src/services/logFile/index.ts"],"mappings":";;;qBAMa,mBAAmB;mBACD;EAA7B,YAA6B,OAAO;EAEpC,KAAK,aAAa"}
|
package/dist/logFile.mjs
ADDED
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
const require_rolldown_runtime = require("./rolldown-runtime-VH7oDXx4.cjs");
|
|
2
|
+
const require_runnerConfig = require("./runnerConfig-D2tGq5ZM.cjs");
|
|
3
|
+
const require_bashResult = require("./bashResult-DNgtahGR.cjs");
|
|
4
|
+
let node_fs = require("node:fs");
|
|
5
|
+
node_fs = require_rolldown_runtime.__toESM(node_fs, 1);
|
|
6
|
+
let node_string_decoder = require("node:string_decoder");
|
|
7
|
+
//#region src/constants/logReader.ts
|
|
8
|
+
const READ_CHUNK_BYTES = 65536;
|
|
9
|
+
//#endregion
|
|
10
|
+
//#region src/services/logReader/index.ts
|
|
11
|
+
var LogReader = class {
|
|
12
|
+
read(logPath, query = {}) {
|
|
13
|
+
let handle;
|
|
14
|
+
try {
|
|
15
|
+
handle = node_fs.default.openSync(logPath, "r");
|
|
16
|
+
return {
|
|
17
|
+
...scanLog(handle, query),
|
|
18
|
+
fileSize: node_fs.default.fstatSync(handle).size,
|
|
19
|
+
path: logPath,
|
|
20
|
+
exists: true
|
|
21
|
+
};
|
|
22
|
+
} catch (error) {
|
|
23
|
+
if (error.code !== "ENOENT") throw error;
|
|
24
|
+
return {
|
|
25
|
+
text: "",
|
|
26
|
+
lineCount: 0,
|
|
27
|
+
totalLines: 0,
|
|
28
|
+
fileSize: 0,
|
|
29
|
+
completeBytes: 0,
|
|
30
|
+
path: logPath,
|
|
31
|
+
exists: false
|
|
32
|
+
};
|
|
33
|
+
} finally {
|
|
34
|
+
if (handle !== void 0) node_fs.default.closeSync(handle);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
function scanLog(handle, query) {
|
|
39
|
+
const limit = Math.max(0, Math.floor(query.lines ?? 200));
|
|
40
|
+
const needle = query.grep ? query.ignoreCase ? query.grep.toLowerCase() : query.grep : void 0;
|
|
41
|
+
const contextLines = Math.max(0, Math.floor(query.contextLines ?? 0));
|
|
42
|
+
const decoder = new node_string_decoder.StringDecoder("utf8");
|
|
43
|
+
const buffer = Buffer.alloc(READ_CHUNK_BYTES);
|
|
44
|
+
const before = [];
|
|
45
|
+
const output = [];
|
|
46
|
+
let pending = "";
|
|
47
|
+
let totalLines = 0;
|
|
48
|
+
let afterThrough = -1;
|
|
49
|
+
let lastEmitted = -1;
|
|
50
|
+
let lastByte;
|
|
51
|
+
let bytesSeen = 0;
|
|
52
|
+
let completeBytes = 0;
|
|
53
|
+
const retain = (line) => {
|
|
54
|
+
if (limit === 0) return;
|
|
55
|
+
output.push(line);
|
|
56
|
+
if (output.length > limit) output.shift();
|
|
57
|
+
};
|
|
58
|
+
const emit = (line) => {
|
|
59
|
+
if (line.index <= lastEmitted) return;
|
|
60
|
+
lastEmitted = line.index;
|
|
61
|
+
retain(line);
|
|
62
|
+
};
|
|
63
|
+
const consume = (text) => {
|
|
64
|
+
const line = {
|
|
65
|
+
index: totalLines,
|
|
66
|
+
text
|
|
67
|
+
};
|
|
68
|
+
totalLines += 1;
|
|
69
|
+
if (!needle) {
|
|
70
|
+
retain(line);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if ((query.ignoreCase ? text.toLowerCase() : text).includes(needle)) {
|
|
74
|
+
for (const previous of before) emit(previous);
|
|
75
|
+
emit(line);
|
|
76
|
+
afterThrough = Math.max(afterThrough, line.index + contextLines);
|
|
77
|
+
} else if (line.index <= afterThrough) emit(line);
|
|
78
|
+
before.push(line);
|
|
79
|
+
if (before.length > contextLines) before.shift();
|
|
80
|
+
};
|
|
81
|
+
for (;;) {
|
|
82
|
+
const bytesRead = node_fs.default.readSync(handle, buffer, 0, buffer.byteLength, null);
|
|
83
|
+
if (bytesRead === 0) break;
|
|
84
|
+
lastByte = buffer[bytesRead - 1];
|
|
85
|
+
const lastNewline = buffer.subarray(0, bytesRead).lastIndexOf(10);
|
|
86
|
+
if (lastNewline >= 0) completeBytes = bytesSeen + lastNewline + 1;
|
|
87
|
+
bytesSeen += bytesRead;
|
|
88
|
+
pending += decoder.write(buffer.subarray(0, bytesRead));
|
|
89
|
+
let newline = pending.indexOf("\n");
|
|
90
|
+
while (newline >= 0) {
|
|
91
|
+
consume(pending.slice(0, newline));
|
|
92
|
+
pending = pending.slice(newline + 1);
|
|
93
|
+
newline = pending.indexOf("\n");
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
pending += decoder.end();
|
|
97
|
+
if (pending.length > 0) consume(pending);
|
|
98
|
+
const trailingNewline = lastByte === 10;
|
|
99
|
+
const scanned = {
|
|
100
|
+
text: `${output.map((line) => line.text).join("\n")}${!needle && trailingNewline && output.length > 0 ? "\n" : ""}`,
|
|
101
|
+
lineCount: output.length,
|
|
102
|
+
totalLines,
|
|
103
|
+
completeBytes
|
|
104
|
+
};
|
|
105
|
+
if (!needle) return scanned;
|
|
106
|
+
return {
|
|
107
|
+
...scanned,
|
|
108
|
+
lineNumbers: output.map((line) => line.index + 1)
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Grep with context, matching the `product-stack logs` semantics so the two
|
|
113
|
+
* surfaces behave the same. Overlapping and adjacent context windows merge.
|
|
114
|
+
*/
|
|
115
|
+
function filterLogText(text, query) {
|
|
116
|
+
if (!query.grep) return text;
|
|
117
|
+
const lines = text.split("\n");
|
|
118
|
+
const needle = query.ignoreCase ? query.grep.toLowerCase() : query.grep;
|
|
119
|
+
const contextLines = Math.max(0, query.contextLines ?? 0);
|
|
120
|
+
const ranges = [];
|
|
121
|
+
lines.forEach((line, index) => {
|
|
122
|
+
if (!(query.ignoreCase ? line.toLowerCase() : line).includes(needle)) return;
|
|
123
|
+
ranges.push({
|
|
124
|
+
start: Math.max(0, index - contextLines),
|
|
125
|
+
end: Math.min(lines.length - 1, index + contextLines)
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
if (ranges.length === 0) return "";
|
|
129
|
+
const merged = [];
|
|
130
|
+
for (const range of ranges) {
|
|
131
|
+
const previous = merged.at(-1);
|
|
132
|
+
if (previous && range.start <= previous.end + 1) previous.end = Math.max(previous.end, range.end);
|
|
133
|
+
else merged.push({ ...range });
|
|
134
|
+
}
|
|
135
|
+
return merged.flatMap((range) => lines.slice(range.start, range.end + 1)).join("\n");
|
|
136
|
+
}
|
|
137
|
+
/** Reads a bounded head and tail plus exact metadata after the writer has flushed. */
|
|
138
|
+
function summarizeLog(path, maxLines = require_runnerConfig.getResultMaxLines(), maxBytes = require_runnerConfig.getResultMaxBytes(), maxTokens = require_runnerConfig.getResultMaxTokens(), settings) {
|
|
139
|
+
let handle;
|
|
140
|
+
try {
|
|
141
|
+
const size = node_fs.default.statSync(path).size;
|
|
142
|
+
handle = node_fs.default.openSync(path, "r");
|
|
143
|
+
const readBuffer = Buffer.alloc(READ_CHUNK_BYTES);
|
|
144
|
+
const endLimit = Math.max(1, maxBytes + 1);
|
|
145
|
+
let headBuffer = Buffer.alloc(0);
|
|
146
|
+
let tailBuffer = Buffer.alloc(0);
|
|
147
|
+
let newlineCount = 0;
|
|
148
|
+
let lastByte;
|
|
149
|
+
const decoder = new node_string_decoder.StringDecoder("utf8");
|
|
150
|
+
const scanned = require_bashResult.createErrorScanner(require_runnerConfig.getErrorMaxEntries(settings), settings);
|
|
151
|
+
let pending = "";
|
|
152
|
+
for (;;) {
|
|
153
|
+
const bytesRead = node_fs.default.readSync(handle, readBuffer, 0, readBuffer.byteLength, null);
|
|
154
|
+
if (bytesRead === 0) break;
|
|
155
|
+
const chunk = readBuffer.subarray(0, bytesRead);
|
|
156
|
+
for (const byte of chunk) if (byte === 10) newlineCount += 1;
|
|
157
|
+
lastByte = chunk.at(-1);
|
|
158
|
+
if (headBuffer.byteLength < endLimit) headBuffer = Buffer.concat([headBuffer, chunk.subarray(0, endLimit - headBuffer.byteLength)]);
|
|
159
|
+
tailBuffer = appendBufferTail(tailBuffer, chunk, endLimit);
|
|
160
|
+
pending += decoder.write(chunk);
|
|
161
|
+
let newline = pending.indexOf("\n");
|
|
162
|
+
while (newline >= 0) {
|
|
163
|
+
scanned.push(pending.slice(0, newline));
|
|
164
|
+
pending = pending.slice(newline + 1);
|
|
165
|
+
newline = pending.indexOf("\n");
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
pending += decoder.end();
|
|
169
|
+
if (pending.length > 0) scanned.push(pending);
|
|
170
|
+
const lines = newlineCount + (size > 0 && lastByte !== 10 ? 1 : 0);
|
|
171
|
+
const excerpt = size <= tailBuffer.byteLength ? require_bashResult.boundExcerpt(utf8Tail(tailBuffer, tailBuffer.byteLength), maxLines, maxBytes, maxTokens, settings) : require_bashResult.composeExcerpt(headBuffer.toString("utf8"), utf8Tail(tailBuffer, tailBuffer.byteLength), lines, maxLines, maxBytes, scanned.entries(), maxTokens, settings);
|
|
172
|
+
return {
|
|
173
|
+
tail: excerpt.text,
|
|
174
|
+
bytes: size,
|
|
175
|
+
lines,
|
|
176
|
+
tailLines: excerpt.lines
|
|
177
|
+
};
|
|
178
|
+
} catch {
|
|
179
|
+
return {
|
|
180
|
+
tail: "",
|
|
181
|
+
bytes: 0,
|
|
182
|
+
lines: 0,
|
|
183
|
+
tailLines: 0
|
|
184
|
+
};
|
|
185
|
+
} finally {
|
|
186
|
+
if (handle !== void 0) node_fs.default.closeSync(handle);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Keeps both ends of an oversized result and points at the file holding the rest.
|
|
191
|
+
*
|
|
192
|
+
* The notice states the file's real size and line count so the model does not
|
|
193
|
+
* guess at offsets when it goes on to read the file, which is the failure this
|
|
194
|
+
* whole policy exists to prevent.
|
|
195
|
+
*/
|
|
196
|
+
function truncateForResult(text, fullOutputPath, maxBytes = require_runnerConfig.getResultMaxBytes(), maxLines = require_runnerConfig.getResultMaxLines()) {
|
|
197
|
+
const excerpt = require_bashResult.boundExcerpt(text, maxLines, maxBytes);
|
|
198
|
+
if (!excerpt.truncated) return {
|
|
199
|
+
text,
|
|
200
|
+
truncated: false,
|
|
201
|
+
outputLines: excerpt.lines
|
|
202
|
+
};
|
|
203
|
+
return {
|
|
204
|
+
text: `${excerpt.text}\n${truncationNotice(excerpt, fullOutputPath, text)}`,
|
|
205
|
+
truncated: true,
|
|
206
|
+
outputLines: excerpt.lines
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
function truncationNotice(excerpt, fullOutputPath, text) {
|
|
210
|
+
const file = measureFile(fullOutputPath);
|
|
211
|
+
const totalLines = file?.lines ?? require_bashResult.countLines(text);
|
|
212
|
+
const fileSize = file?.bytes ?? Buffer.byteLength(text, "utf8");
|
|
213
|
+
return [
|
|
214
|
+
`[output truncated: showing ${excerpt.lines.toLocaleString("en-US")} of ${totalLines.toLocaleString("en-US")} lines,`,
|
|
215
|
+
`${excerpt.elidedLines.toLocaleString("en-US")} elided from the middle.`,
|
|
216
|
+
`Full output is at ${fullOutputPath} (${require_bashResult.formatSize(fileSize)}, ${totalLines.toLocaleString("en-US")} lines).`,
|
|
217
|
+
`Inspect it with doom-runner logs, or read the file with an offset near line ${totalLines.toLocaleString("en-US")}.]`
|
|
218
|
+
].join(" ");
|
|
219
|
+
}
|
|
220
|
+
/** Real size and line count of the file the notice points at. */
|
|
221
|
+
function measureFile(path) {
|
|
222
|
+
let handle;
|
|
223
|
+
try {
|
|
224
|
+
const bytes = node_fs.default.statSync(path).size;
|
|
225
|
+
handle = node_fs.default.openSync(path, "r");
|
|
226
|
+
const buffer = Buffer.alloc(READ_CHUNK_BYTES);
|
|
227
|
+
let newlineCount = 0;
|
|
228
|
+
let lastByte;
|
|
229
|
+
for (;;) {
|
|
230
|
+
const bytesRead = node_fs.default.readSync(handle, buffer, 0, buffer.byteLength, null);
|
|
231
|
+
if (bytesRead === 0) break;
|
|
232
|
+
const chunk = buffer.subarray(0, bytesRead);
|
|
233
|
+
for (const byte of chunk) if (byte === 10) newlineCount += 1;
|
|
234
|
+
lastByte = chunk.at(-1);
|
|
235
|
+
}
|
|
236
|
+
return {
|
|
237
|
+
bytes,
|
|
238
|
+
lines: newlineCount + (bytes > 0 && lastByte !== 10 ? 1 : 0)
|
|
239
|
+
};
|
|
240
|
+
} catch {
|
|
241
|
+
return;
|
|
242
|
+
} finally {
|
|
243
|
+
if (handle !== void 0) node_fs.default.closeSync(handle);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
function utf8Tail(encoded, maxBytes) {
|
|
247
|
+
let start = Math.max(0, encoded.byteLength - maxBytes);
|
|
248
|
+
while (start < encoded.byteLength && (encoded[start] & 192) === 128) start += 1;
|
|
249
|
+
return encoded.subarray(start).toString("utf8");
|
|
250
|
+
}
|
|
251
|
+
function appendBufferTail(current, chunk, limit) {
|
|
252
|
+
if (chunk.byteLength >= limit) return Buffer.from(chunk.subarray(chunk.byteLength - limit));
|
|
253
|
+
const combined = Buffer.concat([current, chunk]);
|
|
254
|
+
return combined.byteLength > limit ? Buffer.from(combined.subarray(combined.byteLength - limit)) : combined;
|
|
255
|
+
}
|
|
256
|
+
//#endregion
|
|
257
|
+
Object.defineProperty(exports, "LogReader", {
|
|
258
|
+
enumerable: true,
|
|
259
|
+
get: function() {
|
|
260
|
+
return LogReader;
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
Object.defineProperty(exports, "filterLogText", {
|
|
264
|
+
enumerable: true,
|
|
265
|
+
get: function() {
|
|
266
|
+
return filterLogText;
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
Object.defineProperty(exports, "summarizeLog", {
|
|
270
|
+
enumerable: true,
|
|
271
|
+
get: function() {
|
|
272
|
+
return summarizeLog;
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
Object.defineProperty(exports, "truncateForResult", {
|
|
276
|
+
enumerable: true,
|
|
277
|
+
get: function() {
|
|
278
|
+
return truncateForResult;
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
//# sourceMappingURL=logReader-B6J7L7Ua.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logReader-B6J7L7Ua.cjs","names":["fs","StringDecoder","getResultMaxLines","getResultMaxBytes","getResultMaxTokens","createErrorScanner","getErrorMaxEntries","boundExcerpt","composeExcerpt","countLines","formatSize"],"sources":["../src/constants/logReader.ts","../src/services/logReader/index.ts"],"sourcesContent":["export const DEFAULT_LINES = 200;\nexport const READ_CHUNK_BYTES = 65_536;\n","import fs from 'node:fs';\nimport { StringDecoder } from 'node:string_decoder';\n\nimport { DEFAULT_LINES, READ_CHUNK_BYTES } from '../../constants/logReader';\nimport { type Excerpt, type LogSummary, type TruncatedOutput } from '../../types/bashResult';\nimport type { ILogReader, LogQuery, LogSlice } from '../../types/logReader';\nimport type { RunnerSettings } from '../../types/runnerSettings';\nimport { boundExcerpt, composeExcerpt, countLines, createErrorScanner, formatSize } from '../bashResult';\nimport { getErrorMaxEntries, getResultMaxBytes, getResultMaxLines, getResultMaxTokens } from '../runnerConfig';\n\ninterface IndexedLine {\n readonly index: number;\n readonly text: string;\n}\n\ninterface ScannedLog {\n readonly text: string;\n readonly lineCount: number;\n readonly totalLines: number;\n readonly completeBytes: number;\n readonly lineNumbers?: number[];\n}\n\nexport class LogReader implements ILogReader {\n read(logPath: string, query: LogQuery = {}): LogSlice {\n let handle: number | undefined;\n try {\n handle = fs.openSync(logPath, 'r');\n const scanned = scanLog(handle, query);\n return {\n ...scanned,\n fileSize: fs.fstatSync(handle).size,\n path: logPath,\n exists: true,\n };\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;\n return {\n text: '',\n lineCount: 0,\n totalLines: 0,\n fileSize: 0,\n completeBytes: 0,\n path: logPath,\n exists: false,\n };\n } finally {\n if (handle !== undefined) fs.closeSync(handle);\n }\n }\n}\n\nfunction scanLog(handle: number, query: LogQuery): ScannedLog {\n const limit = Math.max(0, Math.floor(query.lines ?? DEFAULT_LINES));\n const needle = query.grep ? (query.ignoreCase ? query.grep.toLowerCase() : query.grep) : undefined;\n const contextLines = Math.max(0, Math.floor(query.contextLines ?? 0));\n const decoder = new StringDecoder('utf8');\n const buffer = Buffer.alloc(READ_CHUNK_BYTES);\n const before: IndexedLine[] = [];\n const output: IndexedLine[] = [];\n let pending = '';\n let totalLines = 0;\n let afterThrough = -1;\n let lastEmitted = -1;\n let lastByte: number | undefined;\n let bytesSeen = 0;\n let completeBytes = 0;\n\n const retain = (line: IndexedLine): void => {\n if (limit === 0) return;\n output.push(line);\n if (output.length > limit) output.shift();\n };\n const emit = (line: IndexedLine): void => {\n if (line.index <= lastEmitted) return;\n lastEmitted = line.index;\n retain(line);\n };\n const consume = (text: string): void => {\n const line = { index: totalLines, text };\n totalLines += 1;\n if (!needle) {\n retain(line);\n return;\n }\n\n const haystack = query.ignoreCase ? text.toLowerCase() : text;\n if (haystack.includes(needle)) {\n for (const previous of before) emit(previous);\n emit(line);\n afterThrough = Math.max(afterThrough, line.index + contextLines);\n } else if (line.index <= afterThrough) {\n emit(line);\n }\n before.push(line);\n if (before.length > contextLines) before.shift();\n };\n\n for (;;) {\n const bytesRead = fs.readSync(handle, buffer, 0, buffer.byteLength, null);\n if (bytesRead === 0) break;\n lastByte = buffer[bytesRead - 1];\n // A newline is a single byte in UTF-8 and never a continuation byte, so the\n // last one in this chunk ends the last complete line seen so far.\n const lastNewline = buffer.subarray(0, bytesRead).lastIndexOf(0x0a);\n if (lastNewline >= 0) completeBytes = bytesSeen + lastNewline + 1;\n bytesSeen += bytesRead;\n pending += decoder.write(buffer.subarray(0, bytesRead));\n let newline = pending.indexOf('\\n');\n while (newline >= 0) {\n consume(pending.slice(0, newline));\n pending = pending.slice(newline + 1);\n newline = pending.indexOf('\\n');\n }\n }\n pending += decoder.end();\n if (pending.length > 0) consume(pending);\n\n const trailingNewline = lastByte === 0x0a;\n const body = output.map((line) => line.text).join('\\n');\n const text = `${body}${!needle && trailingNewline && output.length > 0 ? '\\n' : ''}`;\n const scanned: ScannedLog = { text, lineCount: output.length, totalLines, completeBytes };\n if (!needle) return scanned;\n return { ...scanned, lineNumbers: output.map((line) => line.index + 1) };\n}\n\n/**\n * Grep with context, matching the `product-stack logs` semantics so the two\n * surfaces behave the same. Overlapping and adjacent context windows merge.\n */\nexport function filterLogText(text: string, query: Pick<LogQuery, 'grep' | 'ignoreCase' | 'contextLines'>): string {\n if (!query.grep) return text;\n const lines = text.split('\\n');\n const needle = query.ignoreCase ? query.grep.toLowerCase() : query.grep;\n const contextLines = Math.max(0, query.contextLines ?? 0);\n const ranges: Array<{ start: number; end: number }> = [];\n\n lines.forEach((line, index) => {\n const haystack = query.ignoreCase ? line.toLowerCase() : line;\n if (!haystack.includes(needle)) return;\n ranges.push({\n start: Math.max(0, index - contextLines),\n end: Math.min(lines.length - 1, index + contextLines),\n });\n });\n\n if (ranges.length === 0) return '';\n const merged: Array<{ start: number; end: number }> = [];\n for (const range of ranges) {\n const previous = merged.at(-1);\n if (previous && range.start <= previous.end + 1) {\n previous.end = Math.max(previous.end, range.end);\n } else {\n merged.push({ ...range });\n }\n }\n return merged.flatMap((range) => lines.slice(range.start, range.end + 1)).join('\\n');\n}\n\n/** Reads a bounded head and tail plus exact metadata after the writer has flushed. */\nexport function summarizeLog(\n path: string,\n maxLines = getResultMaxLines(),\n maxBytes = getResultMaxBytes(),\n maxTokens = getResultMaxTokens(),\n settings?: RunnerSettings,\n): LogSummary {\n let handle: number | undefined;\n try {\n const size = fs.statSync(path).size;\n handle = fs.openSync(path, 'r');\n const readBuffer = Buffer.alloc(READ_CHUNK_BYTES);\n // Both ends are captured at the full budget; the line trim decides the split.\n const endLimit = Math.max(1, maxBytes + 1);\n let headBuffer: Buffer<ArrayBufferLike> = Buffer.alloc(0);\n let tailBuffer: Buffer<ArrayBufferLike> = Buffer.alloc(0);\n let newlineCount = 0;\n let lastByte: number | undefined;\n const decoder = new StringDecoder('utf8');\n const scanned = createErrorScanner(getErrorMaxEntries(settings), settings);\n let pending = '';\n for (;;) {\n const bytesRead = fs.readSync(handle, readBuffer, 0, readBuffer.byteLength, null);\n if (bytesRead === 0) break;\n const chunk = readBuffer.subarray(0, bytesRead);\n for (const byte of chunk) if (byte === 0x0a) newlineCount += 1;\n lastByte = chunk.at(-1);\n if (headBuffer.byteLength < endLimit) {\n headBuffer = Buffer.concat([headBuffer, chunk.subarray(0, endLimit - headBuffer.byteLength)]);\n }\n tailBuffer = appendBufferTail(tailBuffer, chunk, endLimit);\n pending += decoder.write(chunk);\n let newline = pending.indexOf('\\n');\n while (newline >= 0) {\n scanned.push(pending.slice(0, newline));\n pending = pending.slice(newline + 1);\n newline = pending.indexOf('\\n');\n }\n }\n pending += decoder.end();\n if (pending.length > 0) scanned.push(pending);\n const lines = newlineCount + (size > 0 && lastByte !== 0x0a ? 1 : 0);\n // The tail capture holds the whole file only while the file fits inside one\n // buffer. Past that the start is already gone from it, so the two ends have\n // to be composed instead.\n const excerpt =\n size <= tailBuffer.byteLength\n ? boundExcerpt(utf8Tail(tailBuffer, tailBuffer.byteLength), maxLines, maxBytes, maxTokens, settings)\n : composeExcerpt(\n headBuffer.toString('utf8'),\n utf8Tail(tailBuffer, tailBuffer.byteLength),\n lines,\n maxLines,\n maxBytes,\n scanned.entries(),\n maxTokens,\n settings,\n );\n return { tail: excerpt.text, bytes: size, lines, tailLines: excerpt.lines };\n } catch {\n return { tail: '', bytes: 0, lines: 0, tailLines: 0 };\n } finally {\n if (handle !== undefined) fs.closeSync(handle);\n }\n}\n\n/**\n * Keeps both ends of an oversized result and points at the file holding the rest.\n *\n * The notice states the file's real size and line count so the model does not\n * guess at offsets when it goes on to read the file, which is the failure this\n * whole policy exists to prevent.\n */\nexport function truncateForResult(\n text: string,\n fullOutputPath: string,\n maxBytes = getResultMaxBytes(),\n maxLines = getResultMaxLines(),\n): TruncatedOutput {\n const excerpt = boundExcerpt(text, maxLines, maxBytes);\n if (!excerpt.truncated) return { text, truncated: false, outputLines: excerpt.lines };\n\n return {\n text: `${excerpt.text}\\n${truncationNotice(excerpt, fullOutputPath, text)}`,\n truncated: true,\n outputLines: excerpt.lines,\n };\n}\n\nfunction truncationNotice(excerpt: Excerpt, fullOutputPath: string, text: string): string {\n // Counted from the file, never from `text`. What the caller holds in memory\n // is itself capped, so using it here would understate the file by orders of\n // magnitude and send the reader looking past the end of a much longer file.\n const file = measureFile(fullOutputPath);\n const totalLines = file?.lines ?? countLines(text);\n const fileSize = file?.bytes ?? Buffer.byteLength(text, 'utf8');\n\n return [\n `[output truncated: showing ${excerpt.lines.toLocaleString('en-US')} of ${totalLines.toLocaleString('en-US')} lines,`,\n `${excerpt.elidedLines.toLocaleString('en-US')} elided from the middle.`,\n `Full output is at ${fullOutputPath} (${formatSize(fileSize)}, ${totalLines.toLocaleString('en-US')} lines).`,\n `Inspect it with doom-runner logs, or read the file with an offset near line ${totalLines.toLocaleString('en-US')}.]`,\n ].join(' ');\n}\n\n/** Real size and line count of the file the notice points at. */\nfunction measureFile(path: string): { bytes: number; lines: number } | undefined {\n let handle: number | undefined;\n try {\n const bytes = fs.statSync(path).size;\n handle = fs.openSync(path, 'r');\n const buffer = Buffer.alloc(READ_CHUNK_BYTES);\n let newlineCount = 0;\n let lastByte: number | undefined;\n for (;;) {\n const bytesRead = fs.readSync(handle, buffer, 0, buffer.byteLength, null);\n if (bytesRead === 0) break;\n const chunk = buffer.subarray(0, bytesRead);\n for (const byte of chunk) if (byte === 0x0a) newlineCount += 1;\n lastByte = chunk.at(-1);\n }\n return { bytes, lines: newlineCount + (bytes > 0 && lastByte !== 0x0a ? 1 : 0) };\n } catch {\n return undefined;\n } finally {\n if (handle !== undefined) fs.closeSync(handle);\n }\n}\n\nfunction utf8Tail(encoded: Buffer<ArrayBufferLike>, maxBytes: number): string {\n let start = Math.max(0, encoded.byteLength - maxBytes);\n while (start < encoded.byteLength && (encoded[start]! & 0xc0) === 0x80) start += 1;\n return encoded.subarray(start).toString('utf8');\n}\n\nfunction appendBufferTail(\n current: Buffer<ArrayBufferLike>,\n chunk: Buffer<ArrayBufferLike>,\n limit: number,\n): Buffer<ArrayBufferLike> {\n if (chunk.byteLength >= limit) return Buffer.from(chunk.subarray(chunk.byteLength - limit));\n const combined = Buffer.concat([current, chunk]);\n return combined.byteLength > limit ? Buffer.from(combined.subarray(combined.byteLength - limit)) : combined;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
//#region src/types/logReader.d.ts
|
|
2
|
+
interface LogQuery {
|
|
3
|
+
/** Trailing lines to return before filtering. Defaults to 200. */
|
|
4
|
+
lines?: number;
|
|
5
|
+
grep?: string;
|
|
6
|
+
ignoreCase?: boolean;
|
|
7
|
+
contextLines?: number;
|
|
8
|
+
}
|
|
9
|
+
interface LogSlice {
|
|
10
|
+
text: string;
|
|
11
|
+
/** Lines in the returned slice. */
|
|
12
|
+
lineCount: number;
|
|
13
|
+
/** Lines in the whole file, so a truncated view says what it left out. */
|
|
14
|
+
totalLines: number;
|
|
15
|
+
/** Size of the log file on disk, in bytes. */
|
|
16
|
+
fileSize: number;
|
|
17
|
+
/**
|
|
18
|
+
* Bytes through the end of the last complete line.
|
|
19
|
+
*
|
|
20
|
+
* A runner caught mid-line leaves the file ending without a newline. That
|
|
21
|
+
* partial line is still returned in `text`, because a finished run whose
|
|
22
|
+
* last line never got a newline would otherwise lose it. A follower starts
|
|
23
|
+
* from here instead of `fileSize` so the line arrives whole from the stream
|
|
24
|
+
* rather than split across the slice and the first appended chunk.
|
|
25
|
+
*/
|
|
26
|
+
completeBytes: number;
|
|
27
|
+
path: string;
|
|
28
|
+
/** False when the runner has produced no log file yet. */
|
|
29
|
+
exists: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* 1-based numbers of the returned lines, for a grep whose results are not
|
|
32
|
+
* contiguous. Absent for a plain tail, where the numbers run unbroken to
|
|
33
|
+
* `totalLines` and the reader can count them itself.
|
|
34
|
+
*/
|
|
35
|
+
lineNumbers?: number[];
|
|
36
|
+
}
|
|
37
|
+
/** Scans complete logs with bounded memory, then returns a tail or grep context. */
|
|
38
|
+
interface ILogReader {
|
|
39
|
+
read(logPath: string, query?: LogQuery): LogSlice;
|
|
40
|
+
}
|
|
41
|
+
//#endregion
|
|
42
|
+
export { LogQuery as n, LogSlice as r, ILogReader as t };
|
|
43
|
+
//# sourceMappingURL=logReader-MdW9ffvV.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logReader-MdW9ffvV.d.mts","names":[],"sources":["../src/types/logReader.ts"],"mappings":";UAAiB;;EAEf;EACA;EACA;EACA;;UAGe;EACf;;EAEA;;EAEA;;EAEA;;;;;;;;;;EAUA;EACA;;EAEA;;;;;;EAMA;;;UAIe;EACf,KAAK,iBAAiB,QAAQ,WAAW"}
|