@agimon-ai/po-runner 0.0.0-alpha.2 → 0.0.0-alpha.21
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 +149 -21
- package/README.md +17 -17
- package/dist/ansiScrub.mjs +1 -2
- package/dist/apiContracts.cjs +1 -1
- package/dist/apiContracts.cjs.map +1 -1
- package/dist/apiContracts.mjs +1 -1
- package/dist/apiContracts.mjs.map +1 -1
- package/dist/{bashResult-bIVSzoj-.mjs → bashResult-BqDa7sbC.mjs} +10 -9
- package/dist/bashResult-BqDa7sbC.mjs.map +1 -0
- package/dist/{bashResult-DNgtahGR.cjs → bashResult-C2iKhHpD.cjs} +10 -9
- package/dist/bashResult-C2iKhHpD.cjs.map +1 -0
- package/dist/{bashRunService-CJ02XaAq.mjs → bashRunService-Cl3pYccr.mjs} +2 -2
- package/dist/bashRunService-Cl3pYccr.mjs.map +1 -0
- package/dist/{bashRunService-DyqxOSlx.cjs → bashRunService-DjOH5kye.cjs} +2 -2
- package/dist/bashRunService-DjOH5kye.cjs.map +1 -0
- package/dist/bashRunService.cjs +1 -1
- package/dist/bashRunService.d.mts +3 -3
- package/dist/bashRunService.mjs +1 -2
- package/dist/bashSchema.cjs +1 -1
- package/dist/bashSchema.mjs +1 -2
- package/dist/{bashTool-C-k7fmyh.mjs → bashTool-BvC3YOgG.mjs} +2 -2
- package/dist/{bashTool-C-k7fmyh.mjs.map → bashTool-BvC3YOgG.mjs.map} +1 -1
- package/dist/{bashTool-CdgtqVFD.cjs → bashTool-euL6zMDl.cjs} +2 -2
- package/dist/{bashTool-CdgtqVFD.cjs.map → bashTool-euL6zMDl.cjs.map} +1 -1
- package/dist/bashTool.cjs +3 -3
- package/dist/bashTool.d.mts +1 -1
- package/dist/bashTool.mjs +3 -3
- package/dist/bin/cli.cjs +6 -6
- package/dist/bin/cli.cjs.map +1 -1
- package/dist/bin/cli.mjs +7 -7
- package/dist/bin/cli.mjs.map +1 -1
- package/dist/bin/logSink.cjs +6 -6
- package/dist/bin/logSink.cjs.map +1 -1
- package/dist/bin/logSink.mjs +7 -7
- package/dist/bin/logSink.mjs.map +1 -1
- package/dist/bin/runnerHost.cjs +4 -4
- package/dist/bin/runnerHost.cjs.map +1 -1
- package/dist/bin/runnerHost.mjs +5 -5
- package/dist/bin/runnerHost.mjs.map +1 -1
- package/dist/{cliApp-Dj9nwaOv.cjs → cliApp-T8Fx_-1j.cjs} +6 -6
- package/dist/cliApp-T8Fx_-1j.cjs.map +1 -0
- package/dist/{cliApp-v8Z3rMCi.mjs → cliApp-q97eVh4E.mjs} +6 -6
- package/dist/cliApp-q97eVh4E.mjs.map +1 -0
- package/dist/cliApp.cjs +1 -1
- package/dist/cliApp.d.mts +1 -1
- package/dist/cliApp.mjs +1 -2
- package/dist/clock.mjs +1 -2
- package/dist/{compaction-4QSUsBxq.cjs → compaction-Cduebib_.cjs} +3 -3
- package/dist/compaction-Cduebib_.cjs.map +1 -0
- package/dist/{compaction-DCw80VZj.mjs → compaction-nNlE6e5I.mjs} +3 -3
- package/dist/compaction-nNlE6e5I.mjs.map +1 -0
- package/dist/compaction.cjs +1 -1
- package/dist/compaction.d.mts +1 -1
- package/dist/compaction.mjs +1 -2
- package/dist/config.cjs +1 -1
- package/dist/config.d.mts +1 -1
- package/dist/config.mjs +1 -2
- package/dist/extensions/mcp-ui.mjs.map +1 -1
- package/dist/extensions/mcp.cjs +8 -7
- package/dist/extensions/mcp.cjs.map +1 -1
- package/dist/extensions/mcp.d.mts +1 -1
- package/dist/extensions/mcp.mjs +7 -6
- package/dist/extensions/mcp.mjs.map +1 -1
- package/dist/extensions/native.mjs +1 -1
- package/dist/extensions/native.mjs.map +1 -1
- package/dist/extensions/server.cjs +233 -119
- package/dist/extensions/server.cjs.map +1 -1
- package/dist/extensions/server.d.mts +2 -2
- package/dist/extensions/server.d.mts.map +1 -1
- package/dist/extensions/server.mjs +233 -119
- package/dist/extensions/server.mjs.map +1 -1
- package/dist/extensions/web.mjs +88 -62
- package/dist/extensions/web.mjs.map +1 -1
- package/dist/{headless-BGYfIlNk.mjs → headless-DOlCixyf.mjs} +5 -5
- package/dist/headless-DOlCixyf.mjs.map +1 -0
- package/dist/{headless-CHUsBGhg.cjs → headless-Dko_yBiy.cjs} +5 -5
- package/dist/headless-Dko_yBiy.cjs.map +1 -0
- package/dist/{index-Dhi8asLH.d.mts → index--xF7DvsE.d.mts} +4 -4
- package/dist/{index-Dhi8asLH.d.mts.map → index--xF7DvsE.d.mts.map} +1 -1
- package/dist/{index-BZL7keVW.d.mts → index-BCCF1sGD.d.mts} +2 -2
- package/dist/{index-BZL7keVW.d.mts.map → index-BCCF1sGD.d.mts.map} +1 -1
- package/dist/{index-BwB_jTI9.d.mts → index-BzeXJk6V.d.mts} +5 -5
- package/dist/index-BzeXJk6V.d.mts.map +1 -0
- package/dist/{index-D9-IXax4.d.mts → index-C-IC35d9.d.mts} +2 -2
- package/dist/{index-D9-IXax4.d.mts.map → index-C-IC35d9.d.mts.map} +1 -1
- package/dist/{index-DBz0DxnL.d.mts → index-CzCF_OP9.d.mts} +3 -4
- package/dist/index-CzCF_OP9.d.mts.map +1 -0
- package/dist/index.cjs +5 -5
- package/dist/index.d.mts +5 -5
- package/dist/index.mjs +5 -5
- package/dist/{launcher-BDm6-DiQ.mjs → launcher-CCYsFBM9.mjs} +3 -3
- package/dist/{launcher-BDm6-DiQ.mjs.map → launcher-CCYsFBM9.mjs.map} +1 -1
- package/dist/{launcher-SlyE8R3b.cjs → launcher-ZgDdyXpq.cjs} +8 -2
- package/dist/{launcher-SlyE8R3b.cjs.map → launcher-ZgDdyXpq.cjs.map} +1 -1
- package/dist/launcher.cjs +1 -1
- package/dist/launcher.d.mts +1 -1
- package/dist/launcher.mjs +1 -2
- package/dist/{lifeline-BZaQA0rm.mjs → lifeline-Bm-bHIjS.mjs} +6 -6
- package/dist/lifeline-Bm-bHIjS.mjs.map +1 -0
- package/dist/{lifeline-BuV_erib.cjs → lifeline-m7laIzIP.cjs} +6 -6
- package/dist/lifeline-m7laIzIP.cjs.map +1 -0
- package/dist/lifeline.cjs +1 -1
- package/dist/lifeline.d.mts +1 -1
- package/dist/lifeline.mjs +1 -1
- package/dist/{logFile-CNvepZh0.cjs → logFile-CnPKtxPy.cjs} +2 -2
- package/dist/{logFile-CNvepZh0.cjs.map → logFile-CnPKtxPy.cjs.map} +1 -1
- package/dist/{logFile-KKPbkC-a.mjs → logFile-XcDHBwu1.mjs} +2 -2
- package/dist/{logFile-KKPbkC-a.mjs.map → logFile-XcDHBwu1.mjs.map} +1 -1
- package/dist/logFile.cjs +1 -1
- package/dist/logFile.d.mts +1 -1
- package/dist/logFile.mjs +1 -2
- package/dist/{logReader-B6J7L7Ua.cjs → logReader-DHCK2BEr.cjs} +4 -4
- package/dist/{logReader-B6J7L7Ua.cjs.map → logReader-DHCK2BEr.cjs.map} +1 -1
- package/dist/{logReader-UfbDbwQl.mjs → logReader-mq9uVurh.mjs} +4 -4
- package/dist/{logReader-UfbDbwQl.mjs.map → logReader-mq9uVurh.mjs.map} +1 -1
- package/dist/logReader.cjs +1 -1
- package/dist/logReader.mjs +1 -2
- package/dist/processControl.mjs +1 -2
- package/dist/{ptyHost-DlQtTB8F.mjs → ptyHost-CwbLLr90.mjs} +2 -2
- package/dist/{ptyHost-DlQtTB8F.mjs.map → ptyHost-CwbLLr90.mjs.map} +1 -1
- package/dist/{ptyHost-MI2Z6WTG.cjs → ptyHost-D35hNmtd.cjs} +2 -2
- package/dist/{ptyHost-MI2Z6WTG.cjs.map → ptyHost-D35hNmtd.cjs.map} +1 -1
- package/dist/ptyHost.cjs +1 -1
- package/dist/ptyHost.mjs +1 -2
- package/dist/{ptySpawner-DEi1KOnd.mjs → ptySpawner-C375NJnj.mjs} +2 -2
- package/dist/ptySpawner-C375NJnj.mjs.map +1 -0
- package/dist/{ptySpawner-ijw0g5_T.cjs → ptySpawner-C39IzbRo.cjs} +2 -2
- package/dist/ptySpawner-C39IzbRo.cjs.map +1 -0
- package/dist/ptySpawner.cjs +1 -1
- package/dist/ptySpawner.d.mts +1 -1
- package/dist/ptySpawner.mjs +1 -2
- package/dist/{reconcile-DMeNSxwn.mjs → reconcile-5cZ11jSD.cjs} +12 -42
- package/dist/reconcile-5cZ11jSD.cjs.map +1 -0
- package/dist/{reconcile-BugwYFbV.cjs → reconcile-wNYQJZF-.mjs} +2 -62
- package/dist/reconcile-wNYQJZF-.mjs.map +1 -0
- package/dist/reconcile.cjs +1 -2
- package/dist/reconcile.d.mts +2 -9
- package/dist/reconcile.d.mts.map +1 -1
- package/dist/reconcile.mjs +1 -2
- package/dist/responseEnvelope.cjs +2 -2
- package/dist/responseEnvelope.d.mts +3 -3
- package/dist/responseEnvelope.mjs +2 -2
- package/dist/{rmuxBackend-DlxgqRZ1.cjs → rmuxBackend-Dh0CYVAL.cjs} +5 -5
- package/dist/rmuxBackend-Dh0CYVAL.cjs.map +1 -0
- package/dist/{rmuxBackend-DfyQwJrc.mjs → rmuxBackend-rjrVTG6K.mjs} +4 -4
- package/dist/rmuxBackend-rjrVTG6K.mjs.map +1 -0
- package/dist/rmuxBackend.cjs +1 -1
- package/dist/rmuxBackend.d.mts +1 -1
- package/dist/rmuxBackend.mjs +1 -2
- package/dist/{rtkProcessor-Bc4L4o_8.cjs → rtkProcessor-DSGbM-Cm.cjs} +4 -4
- package/dist/rtkProcessor-DSGbM-Cm.cjs.map +1 -0
- package/dist/{rtkProcessor-B9KPdyzr.mjs → rtkProcessor-Iw9gP5Xp.mjs} +3 -3
- package/dist/rtkProcessor-Iw9gP5Xp.mjs.map +1 -0
- package/dist/rtkProcessor.cjs +1 -1
- package/dist/rtkProcessor.d.mts +1 -1
- package/dist/rtkProcessor.mjs +1 -1
- package/dist/{runnerConfig-D2tGq5ZM.cjs → runnerConfig-BoLMinlx.cjs} +11 -11
- package/dist/runnerConfig-BoLMinlx.cjs.map +1 -0
- package/dist/{runnerConfig-BjtulXBI.d.mts → runnerConfig-DuWL6TJx.d.mts} +10 -10
- package/dist/{runnerConfig-BjtulXBI.d.mts.map → runnerConfig-DuWL6TJx.d.mts.map} +1 -1
- package/dist/{runnerConfig-BQBlVAXn.mjs → runnerConfig-XXMq4VQA.mjs} +11 -11
- package/dist/runnerConfig-XXMq4VQA.mjs.map +1 -0
- package/dist/{runnerDependencies-DruByBGS.mjs → runnerDependencies-7h_cxOva.mjs} +17 -17
- package/dist/runnerDependencies-7h_cxOva.mjs.map +1 -0
- package/dist/{runnerDependencies-KMZigIxB.cjs → runnerDependencies-DSun3xO-.cjs} +17 -17
- package/dist/runnerDependencies-DSun3xO-.cjs.map +1 -0
- package/dist/runnerDependencies.cjs +1 -1
- package/dist/runnerDependencies.d.mts +1 -1
- package/dist/runnerDependencies.mjs +1 -2
- package/dist/runnerNamer.d.mts +1 -1
- package/dist/runnerNamer.mjs +1 -2
- package/dist/{runnerPaths-BTEuzxw0.cjs → runnerPaths-B41rMOY6.cjs} +20 -38
- package/dist/runnerPaths-B41rMOY6.cjs.map +1 -0
- package/dist/{runnerPaths-B_dAAeco.mjs → runnerPaths-Dibbvyx_.mjs} +20 -38
- package/dist/runnerPaths-Dibbvyx_.mjs.map +1 -0
- package/dist/runnerPaths.cjs +1 -1
- package/dist/runnerPaths.d.mts +5 -7
- package/dist/runnerPaths.d.mts.map +1 -1
- package/dist/runnerPaths.mjs +1 -2
- package/dist/{runnerRegistry-CeOHEjBv.mjs → runnerRegistry-BgaR5O86.mjs} +12 -11
- package/dist/runnerRegistry-BgaR5O86.mjs.map +1 -0
- package/dist/{runnerRegistry-CtJiD02R.d.mts → runnerRegistry-V-Ocaf4N.d.mts} +1 -3
- package/dist/{runnerRegistry-CtJiD02R.d.mts.map → runnerRegistry-V-Ocaf4N.d.mts.map} +1 -1
- package/dist/{runnerRegistry-BmkZTJHi.cjs → runnerRegistry-dQYlMSpQ.cjs} +23 -10
- package/dist/runnerRegistry-dQYlMSpQ.cjs.map +1 -0
- package/dist/runnerRegistry.cjs +1 -1
- package/dist/runnerRegistry.d.mts +2 -2
- package/dist/runnerRegistry.mjs +1 -2
- package/dist/services/lifeline/client.cjs +2 -2
- package/dist/services/lifeline/client.cjs.map +1 -1
- package/dist/services/lifeline/client.d.mts +1 -1
- package/dist/services/lifeline/client.mjs +2 -2
- package/dist/services/lifeline/client.mjs.map +1 -1
- package/dist/{session-Chsb_Nh2.mjs → session-BKYnH4R6.mjs} +2 -2
- package/dist/{session-Chsb_Nh2.mjs.map → session-BKYnH4R6.mjs.map} +1 -1
- package/dist/{session-BC43uEyG.cjs → session-BvqzhXZY.cjs} +2 -2
- package/dist/{session-BC43uEyG.cjs.map → session-BvqzhXZY.cjs.map} +1 -1
- package/dist/session.cjs +1 -1
- package/dist/session.mjs +1 -1
- package/dist/spawner.mjs +1 -2
- package/dist/{type-C31e1gla.d.mts → type-Do0YxwVQ.d.mts} +4 -4
- package/dist/{type-C31e1gla.d.mts.map → type-Do0YxwVQ.d.mts.map} +1 -1
- package/dist/{type-BXM03qSw.d.mts → type-DwMZoINK.d.mts} +8 -8
- package/dist/{type-BXM03qSw.d.mts.map → type-DwMZoINK.d.mts.map} +1 -1
- package/dist/types.d.mts +1 -1
- package/package.json +31 -34
- package/skills/{doom-runner → po-runner}/SKILL.md +15 -15
- package/src/prompts/po-use-runner/SKILL.md +11 -11
- package/dist/bashResult-DNgtahGR.cjs.map +0 -1
- package/dist/bashResult-bIVSzoj-.mjs.map +0 -1
- package/dist/bashRunService-CJ02XaAq.mjs.map +0 -1
- package/dist/bashRunService-DyqxOSlx.cjs.map +0 -1
- package/dist/cliApp-Dj9nwaOv.cjs.map +0 -1
- package/dist/cliApp-v8Z3rMCi.mjs.map +0 -1
- package/dist/compaction-4QSUsBxq.cjs.map +0 -1
- package/dist/compaction-DCw80VZj.mjs.map +0 -1
- package/dist/headless-BGYfIlNk.mjs.map +0 -1
- package/dist/headless-CHUsBGhg.cjs.map +0 -1
- package/dist/index-BwB_jTI9.d.mts.map +0 -1
- package/dist/index-DBz0DxnL.d.mts.map +0 -1
- package/dist/lifeline-BZaQA0rm.mjs.map +0 -1
- package/dist/lifeline-BuV_erib.cjs.map +0 -1
- package/dist/ptySpawner-DEi1KOnd.mjs.map +0 -1
- package/dist/ptySpawner-ijw0g5_T.cjs.map +0 -1
- package/dist/reconcile-BugwYFbV.cjs.map +0 -1
- package/dist/reconcile-DMeNSxwn.mjs.map +0 -1
- package/dist/rmuxBackend-DfyQwJrc.mjs.map +0 -1
- package/dist/rmuxBackend-DlxgqRZ1.cjs.map +0 -1
- package/dist/rtkProcessor-B9KPdyzr.mjs.map +0 -1
- package/dist/rtkProcessor-Bc4L4o_8.cjs.map +0 -1
- package/dist/runnerConfig-BQBlVAXn.mjs.map +0 -1
- package/dist/runnerConfig-D2tGq5ZM.cjs.map +0 -1
- package/dist/runnerDependencies-DruByBGS.mjs.map +0 -1
- package/dist/runnerDependencies-KMZigIxB.cjs.map +0 -1
- package/dist/runnerPaths-BTEuzxw0.cjs.map +0 -1
- package/dist/runnerPaths-B_dAAeco.mjs.map +0 -1
- package/dist/runnerRegistry-BmkZTJHi.cjs.map +0 -1
- package/dist/runnerRegistry-CeOHEjBv.mjs.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_rolldown_runtime = require("./rolldown-runtime-VH7oDXx4.cjs");
|
|
2
|
-
const require_runnerConfig = require("./runnerConfig-
|
|
2
|
+
const require_runnerConfig = require("./runnerConfig-BoLMinlx.cjs");
|
|
3
3
|
let node_fs = require("node:fs");
|
|
4
4
|
node_fs = require_rolldown_runtime.__toESM(node_fs, 1);
|
|
5
5
|
//#region src/services/logFile/index.ts
|
|
@@ -64,4 +64,4 @@ Object.defineProperty(exports, "LogFile", {
|
|
|
64
64
|
}
|
|
65
65
|
});
|
|
66
66
|
|
|
67
|
-
//# sourceMappingURL=logFile-
|
|
67
|
+
//# sourceMappingURL=logFile-CnPKtxPy.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logFile-
|
|
1
|
+
{"version":3,"file":"logFile-CnPKtxPy.cjs","names":["getLogMaxBytes","fs"],"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,WAAWA,qBAAAA,eAAe;EAKhC,IAAI,SAASC,QAAAA,QAAG,SAAS,SAAS,GAAG;EACrC,IAAI,UAAU;EACd,IAAI,SAAS;;;;;;;;EASb,MAAM,eAAqB;GACzB,QAAA,QAAG,UAAU,MAAM;GACnB,IAAI;IACF,QAAA,QAAG,WAAW,SAAS,WAAW;GACpC,SAAS,OAAO;IAGd,QAAQ,YAAY,+BAA+B,QAAQ,IAAI,OAAO,KAAK,GAAG;GAChF;GACA,SAASA,QAAAA,QAAG,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,QAAA,QAAG,UAAU,QAAQ,KAAK;IAC1B,WAAW,MAAM;GACnB;GACA,OAAe;IACb,OAAO;GACT;GACA,QAAc;IAGZ,IAAI,QAAQ;IACZ,SAAS;IACT,IAAI;KACF,QAAA,QAAG,UAAU,MAAM;IACrB,SAAS,OAAO;KACd,QAAQ,YAAY,8BAA8B,QAAQ,IAAI,OAAO,KAAK,GAAG;IAC/E;GACF;EACF;CACF;AACF"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { s as getLogMaxBytes } from "./runnerConfig-
|
|
1
|
+
import { s as getLogMaxBytes } from "./runnerConfig-XXMq4VQA.mjs";
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
//#region src/services/logFile/index.ts
|
|
4
4
|
var LogFile = class {
|
|
@@ -57,4 +57,4 @@ var LogFile = class {
|
|
|
57
57
|
//#endregion
|
|
58
58
|
export { LogFile as t };
|
|
59
59
|
|
|
60
|
-
//# sourceMappingURL=logFile-
|
|
60
|
+
//# sourceMappingURL=logFile-XcDHBwu1.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logFile-
|
|
1
|
+
{"version":3,"file":"logFile-XcDHBwu1.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
CHANGED
package/dist/logFile.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as LogWriter, t as ILogFile } from "./logFile-C7oQ_v-g.mjs";
|
|
2
|
-
import { t as IRunnerPaths } from "./type-
|
|
2
|
+
import { t as IRunnerPaths } from "./type-DwMZoINK.mjs";
|
|
3
3
|
//#region src/services/logFile/index.d.ts
|
|
4
4
|
export declare class LogFile implements ILogFile {
|
|
5
5
|
private readonly paths;
|
package/dist/logFile.mjs
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export { LogFile };
|
|
1
|
+
export { t as LogFile } from "./logFile-XcDHBwu1.mjs";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const require_rolldown_runtime = require("./rolldown-runtime-VH7oDXx4.cjs");
|
|
2
|
-
const require_runnerConfig = require("./runnerConfig-
|
|
3
|
-
const require_bashResult = require("./bashResult-
|
|
2
|
+
const require_runnerConfig = require("./runnerConfig-BoLMinlx.cjs");
|
|
3
|
+
const require_bashResult = require("./bashResult-C2iKhHpD.cjs");
|
|
4
4
|
let node_fs = require("node:fs");
|
|
5
5
|
node_fs = require_rolldown_runtime.__toESM(node_fs, 1);
|
|
6
6
|
let node_string_decoder = require("node:string_decoder");
|
|
@@ -214,7 +214,7 @@ function truncationNotice(excerpt, fullOutputPath, text) {
|
|
|
214
214
|
`[output truncated: showing ${excerpt.lines.toLocaleString("en-US")} of ${totalLines.toLocaleString("en-US")} lines,`,
|
|
215
215
|
`${excerpt.elidedLines.toLocaleString("en-US")} elided from the middle.`,
|
|
216
216
|
`Full output is at ${fullOutputPath} (${require_bashResult.formatSize(fileSize)}, ${totalLines.toLocaleString("en-US")} lines).`,
|
|
217
|
-
`Inspect it with
|
|
217
|
+
`Inspect it with po-runner logs, or read the file with an offset near line ${totalLines.toLocaleString("en-US")}.]`
|
|
218
218
|
].join(" ");
|
|
219
219
|
}
|
|
220
220
|
/** Real size and line count of the file the notice points at. */
|
|
@@ -279,4 +279,4 @@ Object.defineProperty(exports, "truncateForResult", {
|
|
|
279
279
|
}
|
|
280
280
|
});
|
|
281
281
|
|
|
282
|
-
//# sourceMappingURL=logReader-
|
|
282
|
+
//# sourceMappingURL=logReader-DHCK2BEr.cjs.map
|
|
@@ -1 +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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"}
|
|
1
|
+
{"version":3,"file":"logReader-DHCK2BEr.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 po-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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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { d as getResultMaxLines, f as getResultMaxTokens, r as getErrorMaxEntries, u as getResultMaxBytes } from "./runnerConfig-
|
|
2
|
-
import { a as countLines, i as composeExcerpt, o as createErrorScanner, t as boundExcerpt, u as formatSize } from "./bashResult-
|
|
1
|
+
import { d as getResultMaxLines, f as getResultMaxTokens, r as getErrorMaxEntries, u as getResultMaxBytes } from "./runnerConfig-XXMq4VQA.mjs";
|
|
2
|
+
import { a as countLines, i as composeExcerpt, o as createErrorScanner, t as boundExcerpt, u as formatSize } from "./bashResult-BqDa7sbC.mjs";
|
|
3
3
|
import fs from "node:fs";
|
|
4
4
|
import { StringDecoder } from "node:string_decoder";
|
|
5
5
|
//#region src/constants/logReader.ts
|
|
@@ -212,7 +212,7 @@ function truncationNotice(excerpt, fullOutputPath, text) {
|
|
|
212
212
|
`[output truncated: showing ${excerpt.lines.toLocaleString("en-US")} of ${totalLines.toLocaleString("en-US")} lines,`,
|
|
213
213
|
`${excerpt.elidedLines.toLocaleString("en-US")} elided from the middle.`,
|
|
214
214
|
`Full output is at ${fullOutputPath} (${formatSize(fileSize)}, ${totalLines.toLocaleString("en-US")} lines).`,
|
|
215
|
-
`Inspect it with
|
|
215
|
+
`Inspect it with po-runner logs, or read the file with an offset near line ${totalLines.toLocaleString("en-US")}.]`
|
|
216
216
|
].join(" ");
|
|
217
217
|
}
|
|
218
218
|
/** Real size and line count of the file the notice points at. */
|
|
@@ -254,4 +254,4 @@ function appendBufferTail(current, chunk, limit) {
|
|
|
254
254
|
//#endregion
|
|
255
255
|
export { truncateForResult as i, filterLogText as n, summarizeLog as r, LogReader as t };
|
|
256
256
|
|
|
257
|
-
//# sourceMappingURL=logReader-
|
|
257
|
+
//# sourceMappingURL=logReader-mq9uVurh.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logReader-UfbDbwQl.mjs","names":[],"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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"}
|
|
1
|
+
{"version":3,"file":"logReader-mq9uVurh.mjs","names":[],"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 po-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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"}
|
package/dist/logReader.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_logReader = require("./logReader-
|
|
2
|
+
const require_logReader = require("./logReader-DHCK2BEr.cjs");
|
|
3
3
|
exports.LogReader = require_logReader.LogReader;
|
|
4
4
|
exports.filterLogText = require_logReader.filterLogText;
|
package/dist/logReader.mjs
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export { LogReader, filterLogText };
|
|
1
|
+
export { t as LogReader, n as filterLogText } from "./logReader-mq9uVurh.mjs";
|
package/dist/processControl.mjs
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export { NodeProcessControl };
|
|
1
|
+
export { t as NodeProcessControl } from "./processControl-DApTpV16.mjs";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as scrubTerminalOutput } from "./ansiScrub-CsqTSaVT.mjs";
|
|
2
|
-
import { u as getResultMaxBytes } from "./runnerConfig-
|
|
2
|
+
import { u as getResultMaxBytes } from "./runnerConfig-XXMq4VQA.mjs";
|
|
3
3
|
import { t as PI_SESSION_ID_ENV } from "./session-DE2Acesp.mjs";
|
|
4
4
|
import { NO_TERMINAL_INPUT_ENV } from "./services/runnerSupervisor/index.mjs";
|
|
5
5
|
import headless from "@xterm/headless";
|
|
@@ -147,4 +147,4 @@ function renderScreen(terminal) {
|
|
|
147
147
|
//#endregion
|
|
148
148
|
export { PtyHost as t };
|
|
149
149
|
|
|
150
|
-
//# sourceMappingURL=ptyHost-
|
|
150
|
+
//# sourceMappingURL=ptyHost-CwbLLr90.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ptyHost-
|
|
1
|
+
{"version":3,"file":"ptyHost-CwbLLr90.mjs","names":[],"sources":["../src/constants/ptyHost.ts","../src/services/ptyHost/index.ts"],"sourcesContent":["export const DEFAULT_COLS = 120;\nexport const DEFAULT_ROWS = 30;\nexport const SCROLLBACK = 2_000;\nexport const MEMORY_BUFFER_FACTOR = 2;\nexport const TERM_GRACE_MS = 2_000;\nexport const LIVENESS_POLL_MS = 100;\nexport const NEWLINE = '\\n';\n","import headless, { type Terminal } from '@xterm/headless';\n\nimport {\n DEFAULT_COLS,\n DEFAULT_ROWS,\n LIVENESS_POLL_MS,\n MEMORY_BUFFER_FACTOR,\n NEWLINE,\n SCROLLBACK,\n TERM_GRACE_MS,\n} from '../../constants/ptyHost';\nimport { PI_SESSION_ID_ENV } from '../../constants/session';\nimport type { IClock } from '../../types/clock';\nimport type { ILogFile } from '../../types/logFile';\nimport type { IProcessControl } from '../../types/processControl';\nimport type { IPtyHost, PtyLaunchRequest, PtyRun } from '../../types/ptyHost';\nimport type { IPtySpawner, PtyProcess } from '../../types/ptySpawner';\nimport type { RunnerSettings } from '../../types/runnerSettings';\nimport type { ExitResult } from '../../types/spawner';\nimport { scrubTerminalOutput } from '../ansiScrub';\nimport { getResultMaxBytes } from '../runnerConfig';\nimport { NO_TERMINAL_INPUT_ENV } from '../runnerSupervisor';\n\n/** Enough history for the overlay to scroll without holding a whole build. */\n\n// Use the CommonJS default export: Node cannot detect this package's named exports.\n// A static import also lets server bundles include it without a live node_modules lookup.\nconst { Terminal: HeadlessTerminal } = headless;\n\nexport class PtyHost implements IPtyHost {\n private readonly runs = new Map<string, PtyRun>();\n\n constructor(\n private readonly spawner: IPtySpawner,\n private readonly logFile: ILogFile,\n private readonly processControl: IProcessControl,\n private readonly clock: IClock,\n private readonly environment: Readonly<Record<string, string | undefined>> = process.env,\n private readonly settings?: RunnerSettings,\n ) {}\n\n async launch(request: PtyLaunchRequest): Promise<PtyRun> {\n const cols = request.cols ?? DEFAULT_COLS;\n const rows = request.rows ?? DEFAULT_ROWS;\n const writer = this.logFile.open(request.id);\n const terminal = new HeadlessTerminal({ cols, rows, scrollback: SCROLLBACK, allowProposedApi: true });\n const memoryLimit = getResultMaxBytes(this.environment, this.settings) * MEMORY_BUFFER_FACTOR;\n\n const child = await this.spawner.spawn({\n command: request.command,\n cwd: request.cwd,\n env: { ...this.environment, ...NO_TERMINAL_INPUT_ENV, [PI_SESSION_ID_ENV]: request.sessionId },\n cols,\n rows,\n });\n\n let buffer = '';\n let buffering = true;\n let settled = false;\n let resolveCompletion: (result: ExitResult) => void = () => undefined;\n const completion = new Promise<ExitResult>((resolve) => {\n resolveCompletion = resolve;\n });\n const dataHandlers = new Set<(data: string) => void>();\n\n child.onData((data) => {\n // The terminal keeps the screen; the log keeps text worth grepping.\n terminal.write(data);\n const scrubbed = scrubTerminalOutput(data);\n writer.append(scrubbed);\n if (buffering) {\n buffer += scrubbed;\n if (buffer.length > memoryLimit) buffer = buffer.slice(-memoryLimit);\n }\n for (const handler of dataHandlers) handler(data);\n });\n\n child.onExit((result) => {\n if (settled) return;\n settled = true;\n this.runs.delete(request.name);\n writer.close();\n resolveCompletion({ code: result.exitCode, signal: null });\n });\n\n const run: PtyRun = {\n id: request.id,\n name: request.name,\n pid: child.pid,\n logPath: writer.path,\n backend: 'native',\n output: () => buffer,\n completion: () => completion,\n detach: () => {\n buffering = false;\n buffer = '';\n },\n stop: () => this.stopChild(child, request.name),\n write: (text) => child.write(text),\n screen: () => renderScreen(terminal),\n onData: (handler) => {\n dataHandlers.add(handler);\n return () => dataHandlers.delete(handler);\n },\n resize: (nextCols, nextRows) => {\n child.resize(nextCols, nextRows);\n terminal.resize(nextCols, nextRows);\n },\n };\n\n this.runs.set(request.name, run);\n return run;\n }\n\n get(name: string): PtyRun | undefined {\n return this.runs.get(name);\n }\n\n write(name: string, text: string): boolean {\n const run = this.runs.get(name);\n if (!run) return false;\n run.write(text.endsWith(NEWLINE) ? text : `${text}${NEWLINE}`);\n return true;\n }\n\n list(): PtyRun[] {\n return [...this.runs.values()];\n }\n\n async disposeAll(): Promise<void> {\n const runs = [...this.runs.values()];\n this.runs.clear();\n for (const run of runs) await run.stop();\n }\n\n private async stopChild(child: PtyProcess, name: string): Promise<boolean> {\n this.runs.delete(name);\n if (!this.processControl.isAlive(child.pid)) return false;\n\n child.kill('SIGTERM');\n const deadline = this.clock.now() + TERM_GRACE_MS;\n while (this.clock.now() < deadline) {\n if (!this.processControl.isAlive(child.pid)) return true;\n await new Promise<void>((resolve) => {\n this.clock.after(LIVENESS_POLL_MS, resolve);\n });\n }\n child.kill('SIGKILL');\n return true;\n }\n}\n\n/** The visible rows, trimmed of trailing blanks, as plain text. */\nfunction renderScreen(terminal: Terminal): string {\n const buffer = terminal.buffer.active;\n const lines: string[] = [];\n for (let row = buffer.baseY; row < buffer.baseY + terminal.rows; row += 1) {\n lines.push(buffer.getLine(row)?.translateToString(true) ?? '');\n }\n while (lines.length > 0 && lines.at(-1) === '') lines.pop();\n return lines.join(NEWLINE);\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const require_rolldown_runtime = require("./rolldown-runtime-VH7oDXx4.cjs");
|
|
2
2
|
const require_ansiScrub = require("./ansiScrub-D5gpHDch.cjs");
|
|
3
|
-
const require_runnerConfig = require("./runnerConfig-
|
|
3
|
+
const require_runnerConfig = require("./runnerConfig-BoLMinlx.cjs");
|
|
4
4
|
const require_session = require("./session-SfIPtdZO.cjs");
|
|
5
5
|
const require_services_runnerSupervisor_index = require("./services/runnerSupervisor/index.cjs");
|
|
6
6
|
let _xterm_headless = require("@xterm/headless");
|
|
@@ -154,4 +154,4 @@ Object.defineProperty(exports, "PtyHost", {
|
|
|
154
154
|
}
|
|
155
155
|
});
|
|
156
156
|
|
|
157
|
-
//# sourceMappingURL=ptyHost-
|
|
157
|
+
//# sourceMappingURL=ptyHost-D35hNmtd.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ptyHost-
|
|
1
|
+
{"version":3,"file":"ptyHost-D35hNmtd.cjs","names":["headless","getResultMaxBytes","NO_TERMINAL_INPUT_ENV","PI_SESSION_ID_ENV","scrubTerminalOutput"],"sources":["../src/constants/ptyHost.ts","../src/services/ptyHost/index.ts"],"sourcesContent":["export const DEFAULT_COLS = 120;\nexport const DEFAULT_ROWS = 30;\nexport const SCROLLBACK = 2_000;\nexport const MEMORY_BUFFER_FACTOR = 2;\nexport const TERM_GRACE_MS = 2_000;\nexport const LIVENESS_POLL_MS = 100;\nexport const NEWLINE = '\\n';\n","import headless, { type Terminal } from '@xterm/headless';\n\nimport {\n DEFAULT_COLS,\n DEFAULT_ROWS,\n LIVENESS_POLL_MS,\n MEMORY_BUFFER_FACTOR,\n NEWLINE,\n SCROLLBACK,\n TERM_GRACE_MS,\n} from '../../constants/ptyHost';\nimport { PI_SESSION_ID_ENV } from '../../constants/session';\nimport type { IClock } from '../../types/clock';\nimport type { ILogFile } from '../../types/logFile';\nimport type { IProcessControl } from '../../types/processControl';\nimport type { IPtyHost, PtyLaunchRequest, PtyRun } from '../../types/ptyHost';\nimport type { IPtySpawner, PtyProcess } from '../../types/ptySpawner';\nimport type { RunnerSettings } from '../../types/runnerSettings';\nimport type { ExitResult } from '../../types/spawner';\nimport { scrubTerminalOutput } from '../ansiScrub';\nimport { getResultMaxBytes } from '../runnerConfig';\nimport { NO_TERMINAL_INPUT_ENV } from '../runnerSupervisor';\n\n/** Enough history for the overlay to scroll without holding a whole build. */\n\n// Use the CommonJS default export: Node cannot detect this package's named exports.\n// A static import also lets server bundles include it without a live node_modules lookup.\nconst { Terminal: HeadlessTerminal } = headless;\n\nexport class PtyHost implements IPtyHost {\n private readonly runs = new Map<string, PtyRun>();\n\n constructor(\n private readonly spawner: IPtySpawner,\n private readonly logFile: ILogFile,\n private readonly processControl: IProcessControl,\n private readonly clock: IClock,\n private readonly environment: Readonly<Record<string, string | undefined>> = process.env,\n private readonly settings?: RunnerSettings,\n ) {}\n\n async launch(request: PtyLaunchRequest): Promise<PtyRun> {\n const cols = request.cols ?? DEFAULT_COLS;\n const rows = request.rows ?? DEFAULT_ROWS;\n const writer = this.logFile.open(request.id);\n const terminal = new HeadlessTerminal({ cols, rows, scrollback: SCROLLBACK, allowProposedApi: true });\n const memoryLimit = getResultMaxBytes(this.environment, this.settings) * MEMORY_BUFFER_FACTOR;\n\n const child = await this.spawner.spawn({\n command: request.command,\n cwd: request.cwd,\n env: { ...this.environment, ...NO_TERMINAL_INPUT_ENV, [PI_SESSION_ID_ENV]: request.sessionId },\n cols,\n rows,\n });\n\n let buffer = '';\n let buffering = true;\n let settled = false;\n let resolveCompletion: (result: ExitResult) => void = () => undefined;\n const completion = new Promise<ExitResult>((resolve) => {\n resolveCompletion = resolve;\n });\n const dataHandlers = new Set<(data: string) => void>();\n\n child.onData((data) => {\n // The terminal keeps the screen; the log keeps text worth grepping.\n terminal.write(data);\n const scrubbed = scrubTerminalOutput(data);\n writer.append(scrubbed);\n if (buffering) {\n buffer += scrubbed;\n if (buffer.length > memoryLimit) buffer = buffer.slice(-memoryLimit);\n }\n for (const handler of dataHandlers) handler(data);\n });\n\n child.onExit((result) => {\n if (settled) return;\n settled = true;\n this.runs.delete(request.name);\n writer.close();\n resolveCompletion({ code: result.exitCode, signal: null });\n });\n\n const run: PtyRun = {\n id: request.id,\n name: request.name,\n pid: child.pid,\n logPath: writer.path,\n backend: 'native',\n output: () => buffer,\n completion: () => completion,\n detach: () => {\n buffering = false;\n buffer = '';\n },\n stop: () => this.stopChild(child, request.name),\n write: (text) => child.write(text),\n screen: () => renderScreen(terminal),\n onData: (handler) => {\n dataHandlers.add(handler);\n return () => dataHandlers.delete(handler);\n },\n resize: (nextCols, nextRows) => {\n child.resize(nextCols, nextRows);\n terminal.resize(nextCols, nextRows);\n },\n };\n\n this.runs.set(request.name, run);\n return run;\n }\n\n get(name: string): PtyRun | undefined {\n return this.runs.get(name);\n }\n\n write(name: string, text: string): boolean {\n const run = this.runs.get(name);\n if (!run) return false;\n run.write(text.endsWith(NEWLINE) ? text : `${text}${NEWLINE}`);\n return true;\n }\n\n list(): PtyRun[] {\n return [...this.runs.values()];\n }\n\n async disposeAll(): Promise<void> {\n const runs = [...this.runs.values()];\n this.runs.clear();\n for (const run of runs) await run.stop();\n }\n\n private async stopChild(child: PtyProcess, name: string): Promise<boolean> {\n this.runs.delete(name);\n if (!this.processControl.isAlive(child.pid)) return false;\n\n child.kill('SIGTERM');\n const deadline = this.clock.now() + TERM_GRACE_MS;\n while (this.clock.now() < deadline) {\n if (!this.processControl.isAlive(child.pid)) return true;\n await new Promise<void>((resolve) => {\n this.clock.after(LIVENESS_POLL_MS, resolve);\n });\n }\n child.kill('SIGKILL');\n return true;\n }\n}\n\n/** The visible rows, trimmed of trailing blanks, as plain text. */\nfunction renderScreen(terminal: Terminal): string {\n const buffer = terminal.buffer.active;\n const lines: string[] = [];\n for (let row = buffer.baseY; row < buffer.baseY + terminal.rows; row += 1) {\n lines.push(buffer.getLine(row)?.translateToString(true) ?? '');\n }\n while (lines.length > 0 && lines.at(-1) === '') lines.pop();\n return lines.join(NEWLINE);\n}\n"],"mappings":"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"}
|
package/dist/ptyHost.cjs
CHANGED
package/dist/ptyHost.mjs
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export { PtyHost };
|
|
1
|
+
export { t as PtyHost } from "./ptyHost-CwbLLr90.mjs";
|
|
@@ -3,7 +3,7 @@ const RMUX_REQUIRED_ERROR = "The node-pty fallback has been removed. Interactive
|
|
|
3
3
|
/**
|
|
4
4
|
* Compatibility stub for the published NodePtySpawner subpath.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
6
|
+
* Po Runner no longer starts interactive commands through node-pty. The class
|
|
7
7
|
* remains exportable so existing imports fail at launch with an actionable error.
|
|
8
8
|
*/
|
|
9
9
|
var NodePtySpawner = class {
|
|
@@ -14,4 +14,4 @@ var NodePtySpawner = class {
|
|
|
14
14
|
//#endregion
|
|
15
15
|
export { NodePtySpawner as t };
|
|
16
16
|
|
|
17
|
-
//# sourceMappingURL=ptySpawner-
|
|
17
|
+
//# sourceMappingURL=ptySpawner-C375NJnj.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ptySpawner-C375NJnj.mjs","names":[],"sources":["../src/services/ptySpawner/index.ts"],"sourcesContent":["import type { IPtySpawner, PtyProcess, PtySpawnRequest } from '../../types/ptySpawner';\n\nconst RMUX_REQUIRED_ERROR =\n 'The node-pty fallback has been removed. Interactive commands require a supported RMUX runtime.';\n\n/**\n * Compatibility stub for the published NodePtySpawner subpath.\n *\n * Po Runner no longer starts interactive commands through node-pty. The class\n * remains exportable so existing imports fail at launch with an actionable error.\n */\nexport class NodePtySpawner implements IPtySpawner {\n async spawn(_request: PtySpawnRequest): Promise<PtyProcess> {\n throw new Error(RMUX_REQUIRED_ERROR);\n }\n}\n"],"mappings":";AAEA,MAAM,sBACJ;;;;;;;AAQF,IAAa,iBAAb,MAAmD;CACjD,MAAM,MAAM,UAAgD;EAC1D,MAAM,IAAI,MAAM,mBAAmB;CACrC;AACF"}
|
|
@@ -3,7 +3,7 @@ const RMUX_REQUIRED_ERROR = "The node-pty fallback has been removed. Interactive
|
|
|
3
3
|
/**
|
|
4
4
|
* Compatibility stub for the published NodePtySpawner subpath.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
6
|
+
* Po Runner no longer starts interactive commands through node-pty. The class
|
|
7
7
|
* remains exportable so existing imports fail at launch with an actionable error.
|
|
8
8
|
*/
|
|
9
9
|
var NodePtySpawner = class {
|
|
@@ -19,4 +19,4 @@ Object.defineProperty(exports, "NodePtySpawner", {
|
|
|
19
19
|
}
|
|
20
20
|
});
|
|
21
21
|
|
|
22
|
-
//# sourceMappingURL=ptySpawner-
|
|
22
|
+
//# sourceMappingURL=ptySpawner-C39IzbRo.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ptySpawner-C39IzbRo.cjs","names":[],"sources":["../src/services/ptySpawner/index.ts"],"sourcesContent":["import type { IPtySpawner, PtyProcess, PtySpawnRequest } from '../../types/ptySpawner';\n\nconst RMUX_REQUIRED_ERROR =\n 'The node-pty fallback has been removed. Interactive commands require a supported RMUX runtime.';\n\n/**\n * Compatibility stub for the published NodePtySpawner subpath.\n *\n * Po Runner no longer starts interactive commands through node-pty. The class\n * remains exportable so existing imports fail at launch with an actionable error.\n */\nexport class NodePtySpawner implements IPtySpawner {\n async spawn(_request: PtySpawnRequest): Promise<PtyProcess> {\n throw new Error(RMUX_REQUIRED_ERROR);\n }\n}\n"],"mappings":";AAEA,MAAM,sBACJ;;;;;;;AAQF,IAAa,iBAAb,MAAmD;CACjD,MAAM,MAAM,UAAgD;EAC1D,MAAM,IAAI,MAAM,mBAAmB;CACrC;AACF"}
|
package/dist/ptySpawner.cjs
CHANGED
package/dist/ptySpawner.d.mts
CHANGED
|
@@ -3,7 +3,7 @@ import { i as PtySpawnRequest, n as PtyExitResult, r as PtyProcess, t as IPtySpa
|
|
|
3
3
|
/**
|
|
4
4
|
* Compatibility stub for the published NodePtySpawner subpath.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
6
|
+
* Po Runner no longer starts interactive commands through node-pty. The class
|
|
7
7
|
* remains exportable so existing imports fail at launch with an actionable error.
|
|
8
8
|
*/
|
|
9
9
|
export declare class NodePtySpawner implements IPtySpawner {
|
package/dist/ptySpawner.mjs
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export { NodePtySpawner };
|
|
1
|
+
export { t as NodePtySpawner } from "./ptySpawner-C375NJnj.mjs";
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
1
|
//#endregion
|
|
3
2
|
//#region src/services/reconcile/index.ts
|
|
4
3
|
const MULTIPLEXER_BACKENDS = /* @__PURE__ */ new Set(["rmux", "tmux"]);
|
|
@@ -68,47 +67,18 @@ async function reconcileActiveRunners(dependencies) {
|
|
|
68
67
|
}
|
|
69
68
|
return result;
|
|
70
69
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
async function cleanupLegacyRunnerStore(dependencies) {
|
|
77
|
-
const result = {
|
|
78
|
-
reclaimed: [],
|
|
79
|
-
errors: []
|
|
80
|
-
};
|
|
81
|
-
const legacyDirectory = dependencies.paths.legacyDirectory();
|
|
82
|
-
if (!legacyDirectory) return result;
|
|
83
|
-
const legacyRecords = (await dependencies.registry.list()).filter((record) => isWithin(legacyDirectory, record.logPath));
|
|
84
|
-
for (const record of legacyRecords) {
|
|
85
|
-
const childAlive = dependencies.processControl.isAlive(record.pid);
|
|
86
|
-
const ownerAlive = dependencies.processControl.isAlive(record.hostPid);
|
|
87
|
-
if (childAlive && ownerAlive) continue;
|
|
88
|
-
try {
|
|
89
|
-
if (childAlive) {
|
|
90
|
-
if (!await stopRunnerProcess(record, dependencies.launcher, dependencies.rmuxBackend) && dependencies.processControl.isAlive(record.pid)) {
|
|
91
|
-
result.errors.push(`Could not stop legacy runner ${record.id}`);
|
|
92
|
-
continue;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
await dependencies.registry.release(record.id, record.sessionId);
|
|
96
|
-
result.reclaimed.push(record.id);
|
|
97
|
-
} catch (error) {
|
|
98
|
-
result.errors.push(`Could not reclaim legacy runner ${record.id}: ${String(error)}`);
|
|
99
|
-
}
|
|
70
|
+
//#endregion
|
|
71
|
+
Object.defineProperty(exports, "reconcileActiveRunners", {
|
|
72
|
+
enumerable: true,
|
|
73
|
+
get: function() {
|
|
74
|
+
return reconcileActiveRunners;
|
|
100
75
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
return result;
|
|
76
|
+
});
|
|
77
|
+
Object.defineProperty(exports, "stopRunnerProcess", {
|
|
78
|
+
enumerable: true,
|
|
79
|
+
get: function() {
|
|
80
|
+
return stopRunnerProcess;
|
|
107
81
|
}
|
|
108
|
-
|
|
109
|
-
return result;
|
|
110
|
-
}
|
|
111
|
-
//#endregion
|
|
112
|
-
export { reconcileActiveRunners as n, stopRunnerProcess as r, cleanupLegacyRunnerStore as t };
|
|
82
|
+
});
|
|
113
83
|
|
|
114
|
-
//# sourceMappingURL=reconcile-
|
|
84
|
+
//# sourceMappingURL=reconcile-5cZ11jSD.cjs.map
|