@caupulican/pi-adaptative 0.93.5 → 0.93.8
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/CHANGELOG.md +31 -0
- package/dist/bundled-resources/skills/n-plus-2-architecture/SKILL.md +13 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +5 -20
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/autonomy/envelope-enforcement.d.ts +3 -1
- package/dist/core/autonomy/envelope-enforcement.d.ts.map +1 -1
- package/dist/core/autonomy/envelope-enforcement.js +23 -12
- package/dist/core/autonomy/envelope-enforcement.js.map +1 -1
- package/dist/core/autonomy/gates.d.ts.map +1 -1
- package/dist/core/autonomy/gates.js +24 -26
- package/dist/core/autonomy/gates.js.map +1 -1
- package/dist/core/context-gc.d.ts.map +1 -1
- package/dist/core/context-gc.js +128 -3
- package/dist/core/context-gc.js.map +1 -1
- package/dist/core/session-shutdown.d.ts +9 -0
- package/dist/core/session-shutdown.d.ts.map +1 -0
- package/dist/core/session-shutdown.js +44 -0
- package/dist/core/session-shutdown.js.map +1 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/skill-vault.d.ts +6 -2
- package/dist/core/skill-vault.d.ts.map +1 -1
- package/dist/core/skill-vault.js +30 -12
- package/dist/core/skill-vault.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +7 -18
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/bash.d.ts +1 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +6 -5
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +86 -33
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/file-mutation-intent.d.ts +16 -0
- package/dist/core/tools/file-mutation-intent.d.ts.map +1 -1
- package/dist/core/tools/file-mutation-intent.js +51 -2
- package/dist/core/tools/file-mutation-intent.js.map +1 -1
- package/dist/core/tools/output-accumulator.d.ts +3 -0
- package/dist/core/tools/output-accumulator.d.ts.map +1 -1
- package/dist/core/tools/output-accumulator.js +10 -1
- package/dist/core/tools/output-accumulator.js.map +1 -1
- package/dist/core/tools/persistent-process-coordinator.d.ts +8 -2
- package/dist/core/tools/persistent-process-coordinator.d.ts.map +1 -1
- package/dist/core/tools/persistent-process-coordinator.js +52 -4
- package/dist/core/tools/persistent-process-coordinator.js.map +1 -1
- package/dist/core/tools/shell-execution-session.d.ts +8 -1
- package/dist/core/tools/shell-execution-session.d.ts.map +1 -1
- package/dist/core/tools/shell-execution-session.js +54 -3
- package/dist/core/tools/shell-execution-session.js.map +1 -1
- package/dist/core/tools/shell-session.d.ts +2 -1
- package/dist/core/tools/shell-session.d.ts.map +1 -1
- package/dist/core/tools/shell-session.js +22 -2
- package/dist/core/tools/shell-session.js.map +1 -1
- package/dist/core/tools/skill.d.ts +1 -0
- package/dist/core/tools/skill.d.ts.map +1 -1
- package/dist/core/tools/skill.js +11 -6
- package/dist/core/tools/skill.js.map +1 -1
- package/dist/core/tools/windows-shell-engine.d.ts +1 -1
- package/dist/core/tools/windows-shell-engine.d.ts.map +1 -1
- package/dist/core/tools/windows-shell-engine.js +6 -2
- package/dist/core/tools/windows-shell-engine.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +2 -2
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/utils/shell.d.ts +3 -5
- package/dist/utils/shell.d.ts.map +1 -1
- package/dist/utils/shell.js +4 -7
- package/dist/utils/shell.js.map +1 -1
- package/docs/settings.md +7 -7
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +12 -12
- package/package.json +4 -4
|
@@ -39,6 +39,7 @@ export declare class OutputAccumulator {
|
|
|
39
39
|
private readonly persistAllOutput;
|
|
40
40
|
private readonly maxPersistedBytes;
|
|
41
41
|
private readonly decoder;
|
|
42
|
+
private readonly outputHash;
|
|
42
43
|
private rawChunks;
|
|
43
44
|
private headLines;
|
|
44
45
|
private headStoredBytes;
|
|
@@ -57,6 +58,7 @@ export declare class OutputAccumulator {
|
|
|
57
58
|
private totalLines;
|
|
58
59
|
private hasOpenLine;
|
|
59
60
|
private finished;
|
|
61
|
+
private outputSignature;
|
|
60
62
|
private tempFilePath;
|
|
61
63
|
private tempFileFd;
|
|
62
64
|
private tempFileError;
|
|
@@ -76,6 +78,7 @@ export declare class OutputAccumulator {
|
|
|
76
78
|
private withPersistenceState;
|
|
77
79
|
closeTempFile(): Promise<void>;
|
|
78
80
|
getLastLineBytes(): number;
|
|
81
|
+
getOutputSignature(): string;
|
|
79
82
|
private appendBlock;
|
|
80
83
|
private appendDecodedText;
|
|
81
84
|
private appendToCurrentLine;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"output-accumulator.d.ts","sourceRoot":"","sources":["../../../src/core/tools/output-accumulator.ts"],"names":[],"mappings":"AAGA,OAAO,EAGN,KAAK,gBAAgB,EAErB,MAAM,oCAAoC,CAAC;AAK5C,MAAM,WAAW,wBAAwB;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gGAAgG;IAChG,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,6FAA6F;IAC7F,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,wFAAwF;IACxF,yBAAyB,CAAC,EAAE,OAAO,CAAC;CACpC;AAED,MAAM,WAAW,cAAc;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,gBAAgB,CAAC;IAC7B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,aAAa;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;CACrB;AAwCD;;;;;;;GAOG;AACH,qBAAa,iBAAiB;IAC7B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAU;IAC3C,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAS;IAC3C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;
|
|
1
|
+
{"version":3,"file":"output-accumulator.d.ts","sourceRoot":"","sources":["../../../src/core/tools/output-accumulator.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { randomBytes } from "node:crypto";
|
|
1
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
2
2
|
import { closeSync, openSync, writeSync } from "node:fs";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, truncateKnownHeadTail, } from "@caupulican/pi-agent-core/truncate";
|
|
@@ -45,6 +45,7 @@ function tailUtf8String(text, maxBytes) {
|
|
|
45
45
|
*/
|
|
46
46
|
export class OutputAccumulator {
|
|
47
47
|
constructor(options = {}) {
|
|
48
|
+
this.outputHash = createHash("sha256");
|
|
48
49
|
this.rawChunks = [];
|
|
49
50
|
this.headLines = [];
|
|
50
51
|
this.headStoredBytes = 0;
|
|
@@ -77,6 +78,7 @@ export class OutputAccumulator {
|
|
|
77
78
|
if (this.finished) {
|
|
78
79
|
throw new Error("Cannot append to a finished output accumulator");
|
|
79
80
|
}
|
|
81
|
+
this.outputHash.update(data);
|
|
80
82
|
for (let offset = 0; offset < data.length; offset += MAX_APPEND_CHUNK_BYTES) {
|
|
81
83
|
this.appendBlock(data.subarray(offset, offset + MAX_APPEND_CHUNK_BYTES));
|
|
82
84
|
}
|
|
@@ -86,6 +88,7 @@ export class OutputAccumulator {
|
|
|
86
88
|
return;
|
|
87
89
|
}
|
|
88
90
|
this.finished = true;
|
|
91
|
+
this.outputSignature = this.outputHash.digest("base64url");
|
|
89
92
|
this.appendDecodedText(this.decoder.decode());
|
|
90
93
|
if (this.shouldUseTempFile()) {
|
|
91
94
|
this.tryEnsureTempFile();
|
|
@@ -137,6 +140,12 @@ export class OutputAccumulator {
|
|
|
137
140
|
getLastLineBytes() {
|
|
138
141
|
return this.hasOpenLine ? this.currentLineBytes : this.lastCompletedLineBytes;
|
|
139
142
|
}
|
|
143
|
+
getOutputSignature() {
|
|
144
|
+
if (!this.finished || this.outputSignature === undefined) {
|
|
145
|
+
throw new Error("Output signature is unavailable before finish");
|
|
146
|
+
}
|
|
147
|
+
return this.outputSignature;
|
|
148
|
+
}
|
|
140
149
|
appendBlock(data) {
|
|
141
150
|
this.totalRawBytes += data.length;
|
|
142
151
|
this.appendDecodedText(this.decoder.decode(data, { stream: true }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"output-accumulator.js","sourceRoot":"","sources":["../../../src/core/tools/output-accumulator.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport { closeSync, openSync, writeSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport {\n\tDEFAULT_MAX_BYTES,\n\tDEFAULT_MAX_LINES,\n\ttype TruncationResult,\n\ttruncateKnownHeadTail,\n} from \"@caupulican/pi-agent-core/truncate\";\nimport { getAgentDir } from \"../../config.ts\";\nimport { getProcessWorkRun } from \"../../utils/work-directory.ts\";\nimport { createShellOutputDecoder, type ShellOutputDecoder } from \"./shell-output-decoder.ts\";\n\nexport interface OutputAccumulatorOptions {\n\tmaxLines?: number;\n\tmaxBytes?: number;\n\ttempFilePrefix?: string;\n\ttempDirectory?: string;\n\t/** Stream the complete output to disk even when the bounded in-memory view is not truncated. */\n\tpersistAllOutput?: boolean;\n\t/** Maximum raw bytes persisted to the managed output file. Defaults to no additional cap. */\n\tmaxPersistedBytes?: number;\n\t/** Decode valid UTF-8 plus isolated Windows-1252 bytes from native Windows programs. */\n\twindowsCompatibleEncoding?: boolean;\n}\n\nexport interface OutputSnapshot {\n\tcontent: string;\n\ttruncation: TruncationResult;\n\tfullOutputPath?: string;\n\tfullOutputError?: string;\n\tpersistedOutputTruncated?: boolean;\n\tpersistedOutputBytes?: number;\n}\n\nexport interface OutputPreview {\n\tcontent: string;\n\tskippedLines: number;\n}\n\nfunction defaultTempFilePath(directory: string, prefix: string): string {\n\tconst id = randomBytes(8).toString(\"hex\");\n\treturn join(directory, `${prefix}-${id}.log`);\n}\n\nconst MAX_APPEND_CHUNK_BYTES = 64 * 1024;\n\nfunction byteLength(text: string): number {\n\treturn Buffer.byteLength(text, \"utf-8\");\n}\n\nfunction formatIoError(error: unknown): string {\n\tif (error instanceof Error) {\n\t\tconst code = (error as NodeJS.ErrnoException).code;\n\t\treturn code ? `${code}: ${error.message}` : error.message;\n\t}\n\treturn String(error);\n}\n\nfunction tailUtf8String(text: string, maxBytes: number): { text: string; bytes: number } {\n\tif (maxBytes <= 0 || text.length === 0) {\n\t\treturn { text: \"\", bytes: 0 };\n\t}\n\n\tconst buffer = Buffer.from(text, \"utf-8\");\n\tif (buffer.length <= maxBytes) {\n\t\treturn { text, bytes: buffer.length };\n\t}\n\n\tlet start = buffer.length - maxBytes;\n\twhile (start < buffer.length && (buffer[start] & 0xc0) === 0x80) {\n\t\tstart++;\n\t}\n\n\tconst result = buffer.subarray(start).toString(\"utf-8\");\n\treturn { text: result, bytes: byteLength(result) };\n}\n\n/**\n * Incrementally tracks streaming output with bounded memory.\n *\n * Appends decode chunks with a streaming UTF-8 decoder, keeps a bounded tail of\n * logical lines, and opens a temp file when the full output needs preserving.\n * Snapshot and preview work is bounded by configured output limits, never by\n * total command history.\n */\nexport class OutputAccumulator {\n\tprivate readonly maxLines: number;\n\tprivate readonly maxBytes: number;\n\tprivate readonly tempFilePrefix: string;\n\tprivate readonly tempDirectory: string;\n\tprivate readonly persistAllOutput: boolean;\n\tprivate readonly maxPersistedBytes: number;\n\tprivate readonly decoder: ShellOutputDecoder;\n\n\tprivate rawChunks: Buffer[] = [];\n\tprivate headLines: string[] = [];\n\tprivate headStoredBytes = 0;\n\tprivate tailLines: string[] = [];\n\tprivate tailLineBytes: number[] = [];\n\tprivate tailLineStoredBytes: number[] = [];\n\tprivate tailStart = 0;\n\tprivate tailStoredBytes = 0;\n\tprivate currentLineText = \"\";\n\tprivate currentLineBytes = 0;\n\tprivate currentLineStoredBytes = 0;\n\tprivate lastCompletedLineBytes = 0;\n\tprivate totalRawBytes = 0;\n\tprivate totalDecodedBytes = 0;\n\tprivate completedLines = 0;\n\tprivate totalLines = 0;\n\tprivate hasOpenLine = false;\n\tprivate finished = false;\n\n\tprivate tempFilePath: string | undefined;\n\tprivate tempFileFd: number | undefined;\n\tprivate tempFileError: string | undefined;\n\tprivate persistedOutputBytes = 0;\n\tprivate persistedOutputTruncated = false;\n\n\tconstructor(options: OutputAccumulatorOptions = {}) {\n\t\tthis.maxLines = options.maxLines ?? DEFAULT_MAX_LINES;\n\t\tthis.maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;\n\t\tthis.tempFilePrefix = options.tempFilePrefix ?? \"pi-output\";\n\t\tthis.tempDirectory = options.tempDirectory ?? getProcessWorkRun(getAgentDir(), \"outputs\", \"tool-streams\").path;\n\t\tthis.persistAllOutput = options.persistAllOutput ?? false;\n\t\tthis.maxPersistedBytes = options.maxPersistedBytes ?? Number.POSITIVE_INFINITY;\n\t\tthis.decoder = createShellOutputDecoder(options.windowsCompatibleEncoding);\n\t}\n\n\tappend(data: Buffer): void {\n\t\tif (this.finished) {\n\t\t\tthrow new Error(\"Cannot append to a finished output accumulator\");\n\t\t}\n\n\t\tfor (let offset = 0; offset < data.length; offset += MAX_APPEND_CHUNK_BYTES) {\n\t\t\tthis.appendBlock(data.subarray(offset, offset + MAX_APPEND_CHUNK_BYTES));\n\t\t}\n\t}\n\n\tfinish(): void {\n\t\tif (this.finished) {\n\t\t\treturn;\n\t\t}\n\t\tthis.finished = true;\n\t\tthis.appendDecodedText(this.decoder.decode());\n\t\tif (this.shouldUseTempFile()) {\n\t\t\tthis.tryEnsureTempFile();\n\t\t}\n\t}\n\n\tsnapshot(options: { persistIfTruncated?: boolean; persistAlways?: boolean } = {}): OutputSnapshot {\n\t\tconst snapshot = this.buildModelSnapshot(this.maxLines, this.maxBytes);\n\n\t\tif (options.persistAlways || (options.persistIfTruncated && snapshot.truncation.truncated)) {\n\t\t\tthis.tryEnsureTempFile();\n\t\t}\n\n\t\treturn this.withPersistenceState(snapshot);\n\t}\n\n\tpreview(maxLines: number, maxBytes = this.maxBytes): OutputPreview {\n\t\tconst snapshot = this.previewSnapshot(maxLines, maxBytes);\n\t\treturn {\n\t\t\tcontent: snapshot.content,\n\t\t\tskippedLines: Math.max(0, this.totalLines - snapshot.truncation.outputLines),\n\t\t};\n\t}\n\n\tpreviewSnapshot(\n\t\tmaxLines: number,\n\t\tmaxBytes = this.maxBytes,\n\t\toptions: { persistIfFullTruncated?: boolean } = {},\n\t): OutputSnapshot {\n\t\tconst snapshot = this.buildSnapshot(maxLines, maxBytes);\n\t\tif (options.persistIfFullTruncated && this.shouldUseTempFile()) {\n\t\t\tthis.tryEnsureTempFile();\n\t\t}\n\t\treturn this.withPersistenceState(snapshot);\n\t}\n\n\tprivate withPersistenceState(snapshot: OutputSnapshot): OutputSnapshot {\n\t\treturn {\n\t\t\t...snapshot,\n\t\t\tfullOutputPath: this.fullOutputPath(),\n\t\t\tfullOutputError: this.tempFileError,\n\t\t\tpersistedOutputTruncated: this.persistedOutputTruncated || undefined,\n\t\t\tpersistedOutputBytes: this.persistedOutputTruncated ? this.persistedOutputBytes : undefined,\n\t\t};\n\t}\n\n\tasync closeTempFile(): Promise<void> {\n\t\tconst fd = this.tempFileFd;\n\t\tif (fd === undefined) {\n\t\t\treturn;\n\t\t}\n\t\tthis.tempFileFd = undefined;\n\t\ttry {\n\t\t\tcloseSync(fd);\n\t\t} catch (error) {\n\t\t\tthis.tempFileError ??= formatIoError(error);\n\t\t}\n\t}\n\n\tgetLastLineBytes(): number {\n\t\treturn this.hasOpenLine ? this.currentLineBytes : this.lastCompletedLineBytes;\n\t}\n\n\tprivate appendBlock(data: Buffer): void {\n\t\tthis.totalRawBytes += data.length;\n\t\tthis.appendDecodedText(this.decoder.decode(data, { stream: true }));\n\n\t\tif (this.tempFileFd !== undefined || this.shouldUseTempFile()) {\n\t\t\tif (this.tryEnsureTempFile() && this.tempFileFd !== undefined) {\n\t\t\t\ttry {\n\t\t\t\t\tthis.writePersisted(data);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthis.recordTempFileError(error);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (data.length > 0) {\n\t\t\t// Copy retained chunks: Buffer.subarray would pin a large caller buffer in memory.\n\t\t\tthis.rawChunks.push(Buffer.from(data));\n\t\t}\n\t}\n\n\tprivate appendDecodedText(text: string): void {\n\t\tif (text.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.totalDecodedBytes += byteLength(text);\n\n\t\tlet segmentStart = 0;\n\t\tfor (\n\t\t\tlet newlineIndex = text.indexOf(\"\\n\");\n\t\t\tnewlineIndex !== -1;\n\t\t\tnewlineIndex = text.indexOf(\"\\n\", segmentStart)\n\t\t) {\n\t\t\tthis.appendToCurrentLine(text.slice(segmentStart, newlineIndex));\n\t\t\tthis.pushCompletedCurrentLine();\n\t\t\tsegmentStart = newlineIndex + 1;\n\t\t}\n\n\t\tif (segmentStart < text.length) {\n\t\t\tthis.appendToCurrentLine(text.slice(segmentStart));\n\t\t}\n\n\t\tthis.totalLines = this.completedLines + (this.hasOpenLine ? 1 : 0);\n\t}\n\n\tprivate appendToCurrentLine(segment: string): void {\n\t\tif (segment.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst segmentBytes = byteLength(segment);\n\t\tthis.currentLineBytes += segmentBytes;\n\t\tthis.hasOpenLine = true;\n\n\t\tif (segmentBytes >= this.maxBytes) {\n\t\t\tconst tail = tailUtf8String(segment, this.maxBytes);\n\t\t\tthis.currentLineText = tail.text;\n\t\t\tthis.currentLineStoredBytes = tail.bytes;\n\t\t\treturn;\n\t\t}\n\n\t\tthis.currentLineText += segment;\n\t\tthis.currentLineStoredBytes += segmentBytes;\n\t\tif (this.currentLineStoredBytes > this.maxBytes) {\n\t\t\tconst tail = tailUtf8String(this.currentLineText, this.maxBytes);\n\t\t\tthis.currentLineText = tail.text;\n\t\t\tthis.currentLineStoredBytes = tail.bytes;\n\t\t}\n\t}\n\n\tprivate pushCompletedCurrentLine(): void {\n\t\tthis.completedLines++;\n\t\tthis.lastCompletedLineBytes = this.currentLineBytes;\n\t\tthis.recordHeadLine(this.currentLineText, this.currentLineStoredBytes);\n\t\tthis.tailLines.push(this.currentLineText);\n\t\tthis.tailLineBytes.push(this.currentLineBytes);\n\t\tthis.tailLineStoredBytes.push(this.currentLineStoredBytes);\n\t\tthis.tailStoredBytes += this.currentLineStoredBytes;\n\t\tthis.currentLineText = \"\";\n\t\tthis.currentLineBytes = 0;\n\t\tthis.currentLineStoredBytes = 0;\n\t\tthis.hasOpenLine = false;\n\t\tthis.trimStoredTail();\n\t}\n\n\tprivate recordHeadLine(text: string, storedBytes: number): void {\n\t\tif (this.headLines.length >= this.maxLines) return;\n\t\tconst separatorBytes = this.headLines.length > 0 ? 1 : 0;\n\t\tif (this.headStoredBytes + storedBytes + separatorBytes > this.maxBytes) return;\n\t\tthis.headLines.push(text);\n\t\tthis.headStoredBytes += storedBytes + separatorBytes;\n\t}\n\n\tprivate trimStoredTail(): void {\n\t\twhile (this.completedTailLineCount() > this.maxLines || this.tailStoredBytes > this.maxBytes) {\n\t\t\tthis.tailStoredBytes -= this.tailLineStoredBytes[this.tailStart] ?? 0;\n\t\t\tthis.tailStart++;\n\t\t}\n\n\t\tif (this.tailStart > 1024 && this.tailStart * 2 > this.tailLines.length) {\n\t\t\tthis.tailLines = this.tailLines.slice(this.tailStart);\n\t\t\tthis.tailLineBytes = this.tailLineBytes.slice(this.tailStart);\n\t\t\tthis.tailLineStoredBytes = this.tailLineStoredBytes.slice(this.tailStart);\n\t\t\tthis.tailStart = 0;\n\t\t}\n\t}\n\n\tprivate completedTailLineCount(): number {\n\t\treturn this.tailLines.length - this.tailStart;\n\t}\n\n\tprivate retainedTailLines(): string[] {\n\t\tconst lines = this.tailLines.slice(this.tailStart);\n\t\tif (this.hasOpenLine) lines.push(this.currentLineText);\n\t\treturn lines;\n\t}\n\n\tprivate buildModelSnapshot(maxLines: number, maxBytes: number): OutputSnapshot {\n\t\tconst tailSnapshot = this.buildSnapshot(maxLines, maxBytes);\n\t\tif (!tailSnapshot.truncation.truncated || this.headLines.length === 0) {\n\t\t\treturn tailSnapshot;\n\t\t}\n\n\t\tconst truncation = truncateKnownHeadTail(\n\t\t\tthis.headLines,\n\t\t\tthis.retainedTailLines(),\n\t\t\t{ totalLines: this.totalLines, totalBytes: this.totalDecodedBytes },\n\t\t\t{ maxLines, maxBytes },\n\t\t);\n\t\treturn {\n\t\t\tcontent: truncation.content,\n\t\t\ttruncation,\n\t\t\tfullOutputPath: this.fullOutputPath(),\n\t\t\tfullOutputError: this.tempFileError,\n\t\t};\n\t}\n\n\tprivate buildSnapshot(maxLines: number, maxBytes: number): OutputSnapshot {\n\t\tconst truncated = this.totalLines > maxLines || this.totalDecodedBytes > maxBytes;\n\t\tconst outputLines: string[] = [];\n\t\tlet outputBytes = 0;\n\t\tlet outputLineCount = 0;\n\t\tlet truncatedBy: \"lines\" | \"bytes\" = this.totalLines > maxLines ? \"lines\" : \"bytes\";\n\t\tlet lastLinePartial = false;\n\t\tlet readCurrent = this.hasOpenLine;\n\t\tlet completedIndex = this.tailLines.length - 1;\n\n\t\twhile (outputLineCount < maxLines) {\n\t\t\tlet line: string;\n\t\t\tlet lineBytes: number;\n\t\t\tlet storedBytes: number;\n\t\t\tif (readCurrent) {\n\t\t\t\tline = this.currentLineText;\n\t\t\t\tlineBytes = this.currentLineBytes;\n\t\t\t\tstoredBytes = this.currentLineStoredBytes;\n\t\t\t\treadCurrent = false;\n\t\t\t} else {\n\t\t\t\tif (completedIndex < this.tailStart) break;\n\t\t\t\tline = this.tailLines[completedIndex] ?? \"\";\n\t\t\t\tlineBytes = this.tailLineBytes[completedIndex] ?? 0;\n\t\t\t\tstoredBytes = this.tailLineStoredBytes[completedIndex] ?? 0;\n\t\t\t\tcompletedIndex--;\n\t\t\t}\n\n\t\t\tconst separatorBytes = outputLineCount > 0 ? 1 : 0;\n\t\t\tconst fullLineBytes = lineBytes + separatorBytes;\n\t\t\tif (outputBytes + fullLineBytes > maxBytes) {\n\t\t\t\ttruncatedBy = \"bytes\";\n\t\t\t\tif (outputLineCount === 0) {\n\t\t\t\t\tconst partial =\n\t\t\t\t\t\tlineBytes > maxBytes ? tailUtf8String(line, maxBytes) : { text: line, bytes: storedBytes };\n\t\t\t\t\toutputLines.unshift(partial.text);\n\t\t\t\t\toutputBytes = partial.bytes;\n\t\t\t\t\toutputLineCount = 1;\n\t\t\t\t\tlastLinePartial = lineBytes > partial.bytes;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\toutputLines.unshift(line);\n\t\t\toutputBytes += storedBytes + separatorBytes;\n\t\t\toutputLineCount++;\n\t\t}\n\n\t\tlet content = outputLines.join(\"\\n\");\n\t\tif (!truncated && !this.hasOpenLine && this.totalLines > 0) {\n\t\t\tcontent += \"\\n\";\n\t\t\toutputBytes += 1;\n\t\t}\n\n\t\tconst effectiveTruncatedBy = truncated ? truncatedBy : null;\n\t\tconst truncation: TruncationResult = {\n\t\t\tcontent,\n\t\t\ttruncated,\n\t\t\ttruncatedBy: effectiveTruncatedBy,\n\t\t\ttotalLines: this.totalLines,\n\t\t\ttotalBytes: this.totalDecodedBytes,\n\t\t\toutputLines: outputLineCount,\n\t\t\toutputBytes,\n\t\t\tlastLinePartial,\n\t\t\tfirstLineExceedsLimit: false,\n\t\t\tmaxLines,\n\t\t\tmaxBytes,\n\t\t};\n\n\t\treturn {\n\t\t\tcontent,\n\t\t\ttruncation,\n\t\t\tfullOutputPath: this.fullOutputPath(),\n\t\t\tfullOutputError: this.tempFileError,\n\t\t};\n\t}\n\n\tprivate shouldUseTempFile(): boolean {\n\t\treturn (\n\t\t\tthis.persistAllOutput ||\n\t\t\tthis.totalRawBytes > this.maxBytes ||\n\t\t\tthis.totalDecodedBytes > this.maxBytes ||\n\t\t\tthis.totalLines > this.maxLines\n\t\t);\n\t}\n\n\tprivate fullOutputPath(): string | undefined {\n\t\treturn this.tempFileError === undefined ? this.tempFilePath : undefined;\n\t}\n\n\tprivate tryEnsureTempFile(): boolean {\n\t\tif (this.tempFileError !== undefined) {\n\t\t\treturn false;\n\t\t}\n\t\tif (this.tempFileFd !== undefined) {\n\t\t\treturn true;\n\t\t}\n\t\ttry {\n\t\t\tthis.tempFilePath ??= defaultTempFilePath(this.tempDirectory, this.tempFilePrefix);\n\t\t\tthis.tempFileFd = openSync(this.tempFilePath, \"w\");\n\t\t\tfor (const chunk of this.rawChunks) {\n\t\t\t\tthis.writePersisted(chunk);\n\t\t\t}\n\t\t\tthis.rawChunks = [];\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\tthis.recordTempFileError(error);\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tprivate writePersisted(data: Buffer): void {\n\t\tif (this.tempFileFd === undefined || data.length === 0) return;\n\t\tconst remaining = Math.max(0, this.maxPersistedBytes - this.persistedOutputBytes);\n\t\tif (remaining === 0) {\n\t\t\tthis.persistedOutputTruncated = true;\n\t\t\treturn;\n\t\t}\n\t\tconst bounded = data.length > remaining ? data.subarray(0, remaining) : data;\n\t\tlet offset = 0;\n\t\twhile (offset < bounded.length) {\n\t\t\tconst written = writeSync(this.tempFileFd, bounded, offset, bounded.length - offset);\n\t\t\tif (written <= 0) throw new Error(\"Managed output write made no progress\");\n\t\t\toffset += written;\n\t\t\tthis.persistedOutputBytes += written;\n\t\t}\n\t\tif (bounded.length < data.length) this.persistedOutputTruncated = true;\n\t}\n\n\tprivate recordTempFileError(error: unknown): void {\n\t\tthis.tempFileError ??= formatIoError(error);\n\t\tconst fd = this.tempFileFd;\n\t\tthis.tempFileFd = undefined;\n\t\tif (fd !== undefined) {\n\t\t\ttry {\n\t\t\t\tcloseSync(fd);\n\t\t\t} catch (closeError) {\n\t\t\t\tthis.tempFileError += `; close failed: ${formatIoError(closeError)}`;\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"output-accumulator.js","sourceRoot":"","sources":["../../../src/core/tools/output-accumulator.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash, randomBytes } from \"node:crypto\";\nimport { closeSync, openSync, writeSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport {\n\tDEFAULT_MAX_BYTES,\n\tDEFAULT_MAX_LINES,\n\ttype TruncationResult,\n\ttruncateKnownHeadTail,\n} from \"@caupulican/pi-agent-core/truncate\";\nimport { getAgentDir } from \"../../config.ts\";\nimport { getProcessWorkRun } from \"../../utils/work-directory.ts\";\nimport { createShellOutputDecoder, type ShellOutputDecoder } from \"./shell-output-decoder.ts\";\n\nexport interface OutputAccumulatorOptions {\n\tmaxLines?: number;\n\tmaxBytes?: number;\n\ttempFilePrefix?: string;\n\ttempDirectory?: string;\n\t/** Stream the complete output to disk even when the bounded in-memory view is not truncated. */\n\tpersistAllOutput?: boolean;\n\t/** Maximum raw bytes persisted to the managed output file. Defaults to no additional cap. */\n\tmaxPersistedBytes?: number;\n\t/** Decode valid UTF-8 plus isolated Windows-1252 bytes from native Windows programs. */\n\twindowsCompatibleEncoding?: boolean;\n}\n\nexport interface OutputSnapshot {\n\tcontent: string;\n\ttruncation: TruncationResult;\n\tfullOutputPath?: string;\n\tfullOutputError?: string;\n\tpersistedOutputTruncated?: boolean;\n\tpersistedOutputBytes?: number;\n}\n\nexport interface OutputPreview {\n\tcontent: string;\n\tskippedLines: number;\n}\n\nfunction defaultTempFilePath(directory: string, prefix: string): string {\n\tconst id = randomBytes(8).toString(\"hex\");\n\treturn join(directory, `${prefix}-${id}.log`);\n}\n\nconst MAX_APPEND_CHUNK_BYTES = 64 * 1024;\n\nfunction byteLength(text: string): number {\n\treturn Buffer.byteLength(text, \"utf-8\");\n}\n\nfunction formatIoError(error: unknown): string {\n\tif (error instanceof Error) {\n\t\tconst code = (error as NodeJS.ErrnoException).code;\n\t\treturn code ? `${code}: ${error.message}` : error.message;\n\t}\n\treturn String(error);\n}\n\nfunction tailUtf8String(text: string, maxBytes: number): { text: string; bytes: number } {\n\tif (maxBytes <= 0 || text.length === 0) {\n\t\treturn { text: \"\", bytes: 0 };\n\t}\n\n\tconst buffer = Buffer.from(text, \"utf-8\");\n\tif (buffer.length <= maxBytes) {\n\t\treturn { text, bytes: buffer.length };\n\t}\n\n\tlet start = buffer.length - maxBytes;\n\twhile (start < buffer.length && (buffer[start] & 0xc0) === 0x80) {\n\t\tstart++;\n\t}\n\n\tconst result = buffer.subarray(start).toString(\"utf-8\");\n\treturn { text: result, bytes: byteLength(result) };\n}\n\n/**\n * Incrementally tracks streaming output with bounded memory.\n *\n * Appends decode chunks with a streaming UTF-8 decoder, keeps a bounded tail of\n * logical lines, and opens a temp file when the full output needs preserving.\n * Snapshot and preview work is bounded by configured output limits, never by\n * total command history.\n */\nexport class OutputAccumulator {\n\tprivate readonly maxLines: number;\n\tprivate readonly maxBytes: number;\n\tprivate readonly tempFilePrefix: string;\n\tprivate readonly tempDirectory: string;\n\tprivate readonly persistAllOutput: boolean;\n\tprivate readonly maxPersistedBytes: number;\n\tprivate readonly decoder: ShellOutputDecoder;\n\tprivate readonly outputHash = createHash(\"sha256\");\n\n\tprivate rawChunks: Buffer[] = [];\n\tprivate headLines: string[] = [];\n\tprivate headStoredBytes = 0;\n\tprivate tailLines: string[] = [];\n\tprivate tailLineBytes: number[] = [];\n\tprivate tailLineStoredBytes: number[] = [];\n\tprivate tailStart = 0;\n\tprivate tailStoredBytes = 0;\n\tprivate currentLineText = \"\";\n\tprivate currentLineBytes = 0;\n\tprivate currentLineStoredBytes = 0;\n\tprivate lastCompletedLineBytes = 0;\n\tprivate totalRawBytes = 0;\n\tprivate totalDecodedBytes = 0;\n\tprivate completedLines = 0;\n\tprivate totalLines = 0;\n\tprivate hasOpenLine = false;\n\tprivate finished = false;\n\tprivate outputSignature: string | undefined;\n\n\tprivate tempFilePath: string | undefined;\n\tprivate tempFileFd: number | undefined;\n\tprivate tempFileError: string | undefined;\n\tprivate persistedOutputBytes = 0;\n\tprivate persistedOutputTruncated = false;\n\n\tconstructor(options: OutputAccumulatorOptions = {}) {\n\t\tthis.maxLines = options.maxLines ?? DEFAULT_MAX_LINES;\n\t\tthis.maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;\n\t\tthis.tempFilePrefix = options.tempFilePrefix ?? \"pi-output\";\n\t\tthis.tempDirectory = options.tempDirectory ?? getProcessWorkRun(getAgentDir(), \"outputs\", \"tool-streams\").path;\n\t\tthis.persistAllOutput = options.persistAllOutput ?? false;\n\t\tthis.maxPersistedBytes = options.maxPersistedBytes ?? Number.POSITIVE_INFINITY;\n\t\tthis.decoder = createShellOutputDecoder(options.windowsCompatibleEncoding);\n\t}\n\n\tappend(data: Buffer): void {\n\t\tif (this.finished) {\n\t\t\tthrow new Error(\"Cannot append to a finished output accumulator\");\n\t\t}\n\t\tthis.outputHash.update(data);\n\n\t\tfor (let offset = 0; offset < data.length; offset += MAX_APPEND_CHUNK_BYTES) {\n\t\t\tthis.appendBlock(data.subarray(offset, offset + MAX_APPEND_CHUNK_BYTES));\n\t\t}\n\t}\n\n\tfinish(): void {\n\t\tif (this.finished) {\n\t\t\treturn;\n\t\t}\n\t\tthis.finished = true;\n\t\tthis.outputSignature = this.outputHash.digest(\"base64url\");\n\t\tthis.appendDecodedText(this.decoder.decode());\n\t\tif (this.shouldUseTempFile()) {\n\t\t\tthis.tryEnsureTempFile();\n\t\t}\n\t}\n\n\tsnapshot(options: { persistIfTruncated?: boolean; persistAlways?: boolean } = {}): OutputSnapshot {\n\t\tconst snapshot = this.buildModelSnapshot(this.maxLines, this.maxBytes);\n\n\t\tif (options.persistAlways || (options.persistIfTruncated && snapshot.truncation.truncated)) {\n\t\t\tthis.tryEnsureTempFile();\n\t\t}\n\n\t\treturn this.withPersistenceState(snapshot);\n\t}\n\n\tpreview(maxLines: number, maxBytes = this.maxBytes): OutputPreview {\n\t\tconst snapshot = this.previewSnapshot(maxLines, maxBytes);\n\t\treturn {\n\t\t\tcontent: snapshot.content,\n\t\t\tskippedLines: Math.max(0, this.totalLines - snapshot.truncation.outputLines),\n\t\t};\n\t}\n\n\tpreviewSnapshot(\n\t\tmaxLines: number,\n\t\tmaxBytes = this.maxBytes,\n\t\toptions: { persistIfFullTruncated?: boolean } = {},\n\t): OutputSnapshot {\n\t\tconst snapshot = this.buildSnapshot(maxLines, maxBytes);\n\t\tif (options.persistIfFullTruncated && this.shouldUseTempFile()) {\n\t\t\tthis.tryEnsureTempFile();\n\t\t}\n\t\treturn this.withPersistenceState(snapshot);\n\t}\n\n\tprivate withPersistenceState(snapshot: OutputSnapshot): OutputSnapshot {\n\t\treturn {\n\t\t\t...snapshot,\n\t\t\tfullOutputPath: this.fullOutputPath(),\n\t\t\tfullOutputError: this.tempFileError,\n\t\t\tpersistedOutputTruncated: this.persistedOutputTruncated || undefined,\n\t\t\tpersistedOutputBytes: this.persistedOutputTruncated ? this.persistedOutputBytes : undefined,\n\t\t};\n\t}\n\n\tasync closeTempFile(): Promise<void> {\n\t\tconst fd = this.tempFileFd;\n\t\tif (fd === undefined) {\n\t\t\treturn;\n\t\t}\n\t\tthis.tempFileFd = undefined;\n\t\ttry {\n\t\t\tcloseSync(fd);\n\t\t} catch (error) {\n\t\t\tthis.tempFileError ??= formatIoError(error);\n\t\t}\n\t}\n\n\tgetLastLineBytes(): number {\n\t\treturn this.hasOpenLine ? this.currentLineBytes : this.lastCompletedLineBytes;\n\t}\n\n\tgetOutputSignature(): string {\n\t\tif (!this.finished || this.outputSignature === undefined) {\n\t\t\tthrow new Error(\"Output signature is unavailable before finish\");\n\t\t}\n\t\treturn this.outputSignature;\n\t}\n\n\tprivate appendBlock(data: Buffer): void {\n\t\tthis.totalRawBytes += data.length;\n\t\tthis.appendDecodedText(this.decoder.decode(data, { stream: true }));\n\n\t\tif (this.tempFileFd !== undefined || this.shouldUseTempFile()) {\n\t\t\tif (this.tryEnsureTempFile() && this.tempFileFd !== undefined) {\n\t\t\t\ttry {\n\t\t\t\t\tthis.writePersisted(data);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthis.recordTempFileError(error);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (data.length > 0) {\n\t\t\t// Copy retained chunks: Buffer.subarray would pin a large caller buffer in memory.\n\t\t\tthis.rawChunks.push(Buffer.from(data));\n\t\t}\n\t}\n\n\tprivate appendDecodedText(text: string): void {\n\t\tif (text.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.totalDecodedBytes += byteLength(text);\n\n\t\tlet segmentStart = 0;\n\t\tfor (\n\t\t\tlet newlineIndex = text.indexOf(\"\\n\");\n\t\t\tnewlineIndex !== -1;\n\t\t\tnewlineIndex = text.indexOf(\"\\n\", segmentStart)\n\t\t) {\n\t\t\tthis.appendToCurrentLine(text.slice(segmentStart, newlineIndex));\n\t\t\tthis.pushCompletedCurrentLine();\n\t\t\tsegmentStart = newlineIndex + 1;\n\t\t}\n\n\t\tif (segmentStart < text.length) {\n\t\t\tthis.appendToCurrentLine(text.slice(segmentStart));\n\t\t}\n\n\t\tthis.totalLines = this.completedLines + (this.hasOpenLine ? 1 : 0);\n\t}\n\n\tprivate appendToCurrentLine(segment: string): void {\n\t\tif (segment.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst segmentBytes = byteLength(segment);\n\t\tthis.currentLineBytes += segmentBytes;\n\t\tthis.hasOpenLine = true;\n\n\t\tif (segmentBytes >= this.maxBytes) {\n\t\t\tconst tail = tailUtf8String(segment, this.maxBytes);\n\t\t\tthis.currentLineText = tail.text;\n\t\t\tthis.currentLineStoredBytes = tail.bytes;\n\t\t\treturn;\n\t\t}\n\n\t\tthis.currentLineText += segment;\n\t\tthis.currentLineStoredBytes += segmentBytes;\n\t\tif (this.currentLineStoredBytes > this.maxBytes) {\n\t\t\tconst tail = tailUtf8String(this.currentLineText, this.maxBytes);\n\t\t\tthis.currentLineText = tail.text;\n\t\t\tthis.currentLineStoredBytes = tail.bytes;\n\t\t}\n\t}\n\n\tprivate pushCompletedCurrentLine(): void {\n\t\tthis.completedLines++;\n\t\tthis.lastCompletedLineBytes = this.currentLineBytes;\n\t\tthis.recordHeadLine(this.currentLineText, this.currentLineStoredBytes);\n\t\tthis.tailLines.push(this.currentLineText);\n\t\tthis.tailLineBytes.push(this.currentLineBytes);\n\t\tthis.tailLineStoredBytes.push(this.currentLineStoredBytes);\n\t\tthis.tailStoredBytes += this.currentLineStoredBytes;\n\t\tthis.currentLineText = \"\";\n\t\tthis.currentLineBytes = 0;\n\t\tthis.currentLineStoredBytes = 0;\n\t\tthis.hasOpenLine = false;\n\t\tthis.trimStoredTail();\n\t}\n\n\tprivate recordHeadLine(text: string, storedBytes: number): void {\n\t\tif (this.headLines.length >= this.maxLines) return;\n\t\tconst separatorBytes = this.headLines.length > 0 ? 1 : 0;\n\t\tif (this.headStoredBytes + storedBytes + separatorBytes > this.maxBytes) return;\n\t\tthis.headLines.push(text);\n\t\tthis.headStoredBytes += storedBytes + separatorBytes;\n\t}\n\n\tprivate trimStoredTail(): void {\n\t\twhile (this.completedTailLineCount() > this.maxLines || this.tailStoredBytes > this.maxBytes) {\n\t\t\tthis.tailStoredBytes -= this.tailLineStoredBytes[this.tailStart] ?? 0;\n\t\t\tthis.tailStart++;\n\t\t}\n\n\t\tif (this.tailStart > 1024 && this.tailStart * 2 > this.tailLines.length) {\n\t\t\tthis.tailLines = this.tailLines.slice(this.tailStart);\n\t\t\tthis.tailLineBytes = this.tailLineBytes.slice(this.tailStart);\n\t\t\tthis.tailLineStoredBytes = this.tailLineStoredBytes.slice(this.tailStart);\n\t\t\tthis.tailStart = 0;\n\t\t}\n\t}\n\n\tprivate completedTailLineCount(): number {\n\t\treturn this.tailLines.length - this.tailStart;\n\t}\n\n\tprivate retainedTailLines(): string[] {\n\t\tconst lines = this.tailLines.slice(this.tailStart);\n\t\tif (this.hasOpenLine) lines.push(this.currentLineText);\n\t\treturn lines;\n\t}\n\n\tprivate buildModelSnapshot(maxLines: number, maxBytes: number): OutputSnapshot {\n\t\tconst tailSnapshot = this.buildSnapshot(maxLines, maxBytes);\n\t\tif (!tailSnapshot.truncation.truncated || this.headLines.length === 0) {\n\t\t\treturn tailSnapshot;\n\t\t}\n\n\t\tconst truncation = truncateKnownHeadTail(\n\t\t\tthis.headLines,\n\t\t\tthis.retainedTailLines(),\n\t\t\t{ totalLines: this.totalLines, totalBytes: this.totalDecodedBytes },\n\t\t\t{ maxLines, maxBytes },\n\t\t);\n\t\treturn {\n\t\t\tcontent: truncation.content,\n\t\t\ttruncation,\n\t\t\tfullOutputPath: this.fullOutputPath(),\n\t\t\tfullOutputError: this.tempFileError,\n\t\t};\n\t}\n\n\tprivate buildSnapshot(maxLines: number, maxBytes: number): OutputSnapshot {\n\t\tconst truncated = this.totalLines > maxLines || this.totalDecodedBytes > maxBytes;\n\t\tconst outputLines: string[] = [];\n\t\tlet outputBytes = 0;\n\t\tlet outputLineCount = 0;\n\t\tlet truncatedBy: \"lines\" | \"bytes\" = this.totalLines > maxLines ? \"lines\" : \"bytes\";\n\t\tlet lastLinePartial = false;\n\t\tlet readCurrent = this.hasOpenLine;\n\t\tlet completedIndex = this.tailLines.length - 1;\n\n\t\twhile (outputLineCount < maxLines) {\n\t\t\tlet line: string;\n\t\t\tlet lineBytes: number;\n\t\t\tlet storedBytes: number;\n\t\t\tif (readCurrent) {\n\t\t\t\tline = this.currentLineText;\n\t\t\t\tlineBytes = this.currentLineBytes;\n\t\t\t\tstoredBytes = this.currentLineStoredBytes;\n\t\t\t\treadCurrent = false;\n\t\t\t} else {\n\t\t\t\tif (completedIndex < this.tailStart) break;\n\t\t\t\tline = this.tailLines[completedIndex] ?? \"\";\n\t\t\t\tlineBytes = this.tailLineBytes[completedIndex] ?? 0;\n\t\t\t\tstoredBytes = this.tailLineStoredBytes[completedIndex] ?? 0;\n\t\t\t\tcompletedIndex--;\n\t\t\t}\n\n\t\t\tconst separatorBytes = outputLineCount > 0 ? 1 : 0;\n\t\t\tconst fullLineBytes = lineBytes + separatorBytes;\n\t\t\tif (outputBytes + fullLineBytes > maxBytes) {\n\t\t\t\ttruncatedBy = \"bytes\";\n\t\t\t\tif (outputLineCount === 0) {\n\t\t\t\t\tconst partial =\n\t\t\t\t\t\tlineBytes > maxBytes ? tailUtf8String(line, maxBytes) : { text: line, bytes: storedBytes };\n\t\t\t\t\toutputLines.unshift(partial.text);\n\t\t\t\t\toutputBytes = partial.bytes;\n\t\t\t\t\toutputLineCount = 1;\n\t\t\t\t\tlastLinePartial = lineBytes > partial.bytes;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\toutputLines.unshift(line);\n\t\t\toutputBytes += storedBytes + separatorBytes;\n\t\t\toutputLineCount++;\n\t\t}\n\n\t\tlet content = outputLines.join(\"\\n\");\n\t\tif (!truncated && !this.hasOpenLine && this.totalLines > 0) {\n\t\t\tcontent += \"\\n\";\n\t\t\toutputBytes += 1;\n\t\t}\n\n\t\tconst effectiveTruncatedBy = truncated ? truncatedBy : null;\n\t\tconst truncation: TruncationResult = {\n\t\t\tcontent,\n\t\t\ttruncated,\n\t\t\ttruncatedBy: effectiveTruncatedBy,\n\t\t\ttotalLines: this.totalLines,\n\t\t\ttotalBytes: this.totalDecodedBytes,\n\t\t\toutputLines: outputLineCount,\n\t\t\toutputBytes,\n\t\t\tlastLinePartial,\n\t\t\tfirstLineExceedsLimit: false,\n\t\t\tmaxLines,\n\t\t\tmaxBytes,\n\t\t};\n\n\t\treturn {\n\t\t\tcontent,\n\t\t\ttruncation,\n\t\t\tfullOutputPath: this.fullOutputPath(),\n\t\t\tfullOutputError: this.tempFileError,\n\t\t};\n\t}\n\n\tprivate shouldUseTempFile(): boolean {\n\t\treturn (\n\t\t\tthis.persistAllOutput ||\n\t\t\tthis.totalRawBytes > this.maxBytes ||\n\t\t\tthis.totalDecodedBytes > this.maxBytes ||\n\t\t\tthis.totalLines > this.maxLines\n\t\t);\n\t}\n\n\tprivate fullOutputPath(): string | undefined {\n\t\treturn this.tempFileError === undefined ? this.tempFilePath : undefined;\n\t}\n\n\tprivate tryEnsureTempFile(): boolean {\n\t\tif (this.tempFileError !== undefined) {\n\t\t\treturn false;\n\t\t}\n\t\tif (this.tempFileFd !== undefined) {\n\t\t\treturn true;\n\t\t}\n\t\ttry {\n\t\t\tthis.tempFilePath ??= defaultTempFilePath(this.tempDirectory, this.tempFilePrefix);\n\t\t\tthis.tempFileFd = openSync(this.tempFilePath, \"w\");\n\t\t\tfor (const chunk of this.rawChunks) {\n\t\t\t\tthis.writePersisted(chunk);\n\t\t\t}\n\t\t\tthis.rawChunks = [];\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\tthis.recordTempFileError(error);\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tprivate writePersisted(data: Buffer): void {\n\t\tif (this.tempFileFd === undefined || data.length === 0) return;\n\t\tconst remaining = Math.max(0, this.maxPersistedBytes - this.persistedOutputBytes);\n\t\tif (remaining === 0) {\n\t\t\tthis.persistedOutputTruncated = true;\n\t\t\treturn;\n\t\t}\n\t\tconst bounded = data.length > remaining ? data.subarray(0, remaining) : data;\n\t\tlet offset = 0;\n\t\twhile (offset < bounded.length) {\n\t\t\tconst written = writeSync(this.tempFileFd, bounded, offset, bounded.length - offset);\n\t\t\tif (written <= 0) throw new Error(\"Managed output write made no progress\");\n\t\t\toffset += written;\n\t\t\tthis.persistedOutputBytes += written;\n\t\t}\n\t\tif (bounded.length < data.length) this.persistedOutputTruncated = true;\n\t}\n\n\tprivate recordTempFileError(error: unknown): void {\n\t\tthis.tempFileError ??= formatIoError(error);\n\t\tconst fd = this.tempFileFd;\n\t\tthis.tempFileFd = undefined;\n\t\tif (fd !== undefined) {\n\t\t\ttry {\n\t\t\t\tcloseSync(fd);\n\t\t\t} catch (closeError) {\n\t\t\t\tthis.tempFileError += `; close failed: ${formatIoError(closeError)}`;\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
* Shared lifecycle owner for one serialized, persistent child process.
|
|
3
3
|
*
|
|
4
4
|
* Wire protocols, state projection, and respawn policy stay with their concrete shell adapters.
|
|
5
|
-
* This boundary owns only the invariant OS mechanics: one active task, one
|
|
6
|
-
* event rejection, exit/close arbitration, whole-tree kill,
|
|
5
|
+
* This boundary owns only the invariant OS mechanics: one active task, one current child, every
|
|
6
|
+
* outstanding child terminal, stale event rejection, exit/close arbitration, whole-tree kill,
|
|
7
|
+
* loop references, and parent exit.
|
|
7
8
|
*/
|
|
8
9
|
import type { ChildProcess } from "node:child_process";
|
|
9
10
|
export interface PersistentChildHandlers {
|
|
@@ -14,18 +15,23 @@ export interface PersistentChildHandlers {
|
|
|
14
15
|
}
|
|
15
16
|
export declare class PersistentProcessCoordinator {
|
|
16
17
|
private currentChild;
|
|
18
|
+
private readonly pendingChildTerminals;
|
|
17
19
|
private queue;
|
|
18
20
|
private disposed;
|
|
19
21
|
constructor();
|
|
20
22
|
get child(): ChildProcess | null;
|
|
23
|
+
get terminalPromise(): Promise<void>;
|
|
21
24
|
runSerialized<T>(task: () => Promise<T>): Promise<T>;
|
|
22
25
|
attach(child: ChildProcess, handlers: PersistentChildHandlers): void;
|
|
23
26
|
kill(): void;
|
|
27
|
+
private terminateChild;
|
|
24
28
|
dispose(): void;
|
|
25
29
|
/** Synchronous best-effort tree kill for the process exit hook. */
|
|
26
30
|
killForProcessExit(): void;
|
|
27
31
|
/** Idle coordinators must not keep one-shot Node modes alive; active commands must. */
|
|
28
32
|
setLoopRef(active: boolean): void;
|
|
33
|
+
private waitForTerminalRelease;
|
|
34
|
+
private trackTerminal;
|
|
29
35
|
private clear;
|
|
30
36
|
}
|
|
31
37
|
//# sourceMappingURL=persistent-process-coordinator.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"persistent-process-coordinator.d.ts","sourceRoot":"","sources":["../../../src/core/tools/persistent-process-coordinator.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"persistent-process-coordinator.d.ts","sourceRoot":"","sources":["../../../src/core/tools/persistent-process-coordinator.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAIvD,MAAM,WAAW,uBAAuB;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,OAAO,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IAC5B,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;CACnC;AAaD,qBAAa,4BAA4B;IACxC,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAA4B;IAClE,OAAO,CAAC,KAAK,CAAoC;IACjD,OAAO,CAAC,QAAQ,CAAS;IAEzB,cAGC;IAED,IAAI,KAAK,IAAI,YAAY,GAAG,IAAI,CAE/B;IAED,IAAI,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAEnC;IAED,aAAa,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAOnD;IAED,MAAM,CAAC,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,uBAAuB,GAAG,IAAI,CAyCnE;IAED,IAAI,IAAI,IAAI,CAKX;IAED,OAAO,CAAC,cAAc;IAatB,OAAO,IAAI,IAAI,CAKd;IAED,mEAAmE;IACnE,kBAAkB,IAAI,IAAI,CAEzB;IAED,uFAAuF;IACvF,UAAU,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAIhC;YAEa,sBAAsB;IAOpC,OAAO,CAAC,aAAa;IAuBrB,OAAO,CAAC,KAAK;CAMb"}
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
* Shared lifecycle owner for one serialized, persistent child process.
|
|
3
3
|
*
|
|
4
4
|
* Wire protocols, state projection, and respawn policy stay with their concrete shell adapters.
|
|
5
|
-
* This boundary owns only the invariant OS mechanics: one active task, one
|
|
6
|
-
* event rejection, exit/close arbitration, whole-tree kill,
|
|
5
|
+
* This boundary owns only the invariant OS mechanics: one active task, one current child, every
|
|
6
|
+
* outstanding child terminal, stale event rejection, exit/close arbitration, whole-tree kill,
|
|
7
|
+
* loop references, and parent exit.
|
|
7
8
|
*/
|
|
8
9
|
import { setChildProcessLoopRef } from "../../utils/child-process-ref.js";
|
|
9
10
|
import { killProcessTree, trackDetachedChildPid, untrackDetachedChildPid } from "../../utils/shell.js";
|
|
@@ -21,6 +22,7 @@ function installExitHook() {
|
|
|
21
22
|
export class PersistentProcessCoordinator {
|
|
22
23
|
constructor() {
|
|
23
24
|
this.currentChild = null;
|
|
25
|
+
this.pendingChildTerminals = new Set();
|
|
24
26
|
this.queue = Promise.resolve();
|
|
25
27
|
this.disposed = false;
|
|
26
28
|
installExitHook();
|
|
@@ -29,6 +31,9 @@ export class PersistentProcessCoordinator {
|
|
|
29
31
|
get child() {
|
|
30
32
|
return this.currentChild;
|
|
31
33
|
}
|
|
34
|
+
get terminalPromise() {
|
|
35
|
+
return this.waitForTerminalRelease();
|
|
36
|
+
}
|
|
32
37
|
runSerialized(task) {
|
|
33
38
|
const run = this.queue.then(task);
|
|
34
39
|
this.queue = run.then(() => undefined, () => undefined);
|
|
@@ -36,8 +41,8 @@ export class PersistentProcessCoordinator {
|
|
|
36
41
|
}
|
|
37
42
|
attach(child, handlers) {
|
|
38
43
|
if (this.disposed) {
|
|
39
|
-
|
|
40
|
-
|
|
44
|
+
this.trackTerminal(child);
|
|
45
|
+
this.terminateChild(child);
|
|
41
46
|
throw new Error("Persistent process coordinator is disposed");
|
|
42
47
|
}
|
|
43
48
|
if (this.currentChild)
|
|
@@ -45,6 +50,7 @@ export class PersistentProcessCoordinator {
|
|
|
45
50
|
this.currentChild = child;
|
|
46
51
|
if (child.pid)
|
|
47
52
|
trackDetachedChildPid(child.pid);
|
|
53
|
+
this.trackTerminal(child);
|
|
48
54
|
child.stdout?.on("data", (data) => {
|
|
49
55
|
if (this.currentChild === child)
|
|
50
56
|
handlers.onStdout(data);
|
|
@@ -86,8 +92,21 @@ export class PersistentProcessCoordinator {
|
|
|
86
92
|
if (!child)
|
|
87
93
|
return;
|
|
88
94
|
this.clear(child);
|
|
95
|
+
this.terminateChild(child);
|
|
96
|
+
}
|
|
97
|
+
terminateChild(child) {
|
|
98
|
+
// Bun's Windows child-process bridge can stop publishing terminal events after every
|
|
99
|
+
// handle has been unref'd. Re-arm the already-installed close observer before killing so
|
|
100
|
+
// strict teardown can distinguish physical handle release from process exit.
|
|
101
|
+
setChildProcessLoopRef(child, true);
|
|
89
102
|
if (child.pid)
|
|
90
103
|
killProcessTree(child.pid);
|
|
104
|
+
try {
|
|
105
|
+
child.kill();
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
// Process already dead
|
|
109
|
+
}
|
|
91
110
|
}
|
|
92
111
|
dispose() {
|
|
93
112
|
if (this.disposed)
|
|
@@ -107,6 +126,35 @@ export class PersistentProcessCoordinator {
|
|
|
107
126
|
return;
|
|
108
127
|
setChildProcessLoopRef(child, active);
|
|
109
128
|
}
|
|
129
|
+
async waitForTerminalRelease() {
|
|
130
|
+
await this.queue;
|
|
131
|
+
while (this.pendingChildTerminals.size > 0) {
|
|
132
|
+
await Promise.all(Array.from(this.pendingChildTerminals));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
trackTerminal(child) {
|
|
136
|
+
let settled = false;
|
|
137
|
+
let resolveTerminal;
|
|
138
|
+
const terminalPromise = new Promise((resolve) => {
|
|
139
|
+
resolveTerminal = resolve;
|
|
140
|
+
});
|
|
141
|
+
const settleTerminal = () => {
|
|
142
|
+
if (settled)
|
|
143
|
+
return;
|
|
144
|
+
settled = true;
|
|
145
|
+
child.off("error", handleTerminalError);
|
|
146
|
+
child.off("close", settleTerminal);
|
|
147
|
+
this.pendingChildTerminals.delete(terminalPromise);
|
|
148
|
+
resolveTerminal();
|
|
149
|
+
};
|
|
150
|
+
const handleTerminalError = () => {
|
|
151
|
+
if (!child.pid)
|
|
152
|
+
settleTerminal();
|
|
153
|
+
};
|
|
154
|
+
this.pendingChildTerminals.add(terminalPromise);
|
|
155
|
+
child.on("error", handleTerminalError);
|
|
156
|
+
child.once("close", settleTerminal);
|
|
157
|
+
}
|
|
110
158
|
clear(child) {
|
|
111
159
|
if (this.currentChild !== child)
|
|
112
160
|
return false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"persistent-process-coordinator.js","sourceRoot":"","sources":["../../../src/core/tools/persistent-process-coordinator.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared lifecycle owner for one serialized, persistent child process.\n *\n * Wire protocols, state projection, and respawn policy stay with their concrete shell adapters.\n * This boundary owns only the invariant OS mechanics: one active task, one tracked child, stale\n * event rejection, exit/close arbitration, whole-tree kill, loop references, and parent exit.\n */\n\nimport type { ChildProcess } from \"node:child_process\";\nimport { setChildProcessLoopRef } from \"../../utils/child-process-ref.ts\";\nimport { killProcessTree, trackDetachedChildPid, untrackDetachedChildPid } from \"../../utils/shell.ts\";\n\nexport interface PersistentChildHandlers {\n\tonStdout(data: Buffer): void;\n\tonStderr(data: Buffer): void;\n\tonError(error: Error): void;\n\tonClose(code: number | null): void;\n}\n\nconst liveCoordinators = new Set<PersistentProcessCoordinator>();\nlet exitHookInstalled = false;\n\nfunction installExitHook(): void {\n\tif (exitHookInstalled) return;\n\texitHookInstalled = true;\n\tprocess.on(\"exit\", () => {\n\t\tfor (const coordinator of liveCoordinators) coordinator.killForProcessExit();\n\t});\n}\n\nexport class PersistentProcessCoordinator {\n\tprivate currentChild: ChildProcess | null = null;\n\tprivate queue: Promise<void> = Promise.resolve();\n\tprivate disposed = false;\n\n\tconstructor() {\n\t\tinstallExitHook();\n\t\tliveCoordinators.add(this);\n\t}\n\n\tget child(): ChildProcess | null {\n\t\treturn this.currentChild;\n\t}\n\n\trunSerialized<T>(task: () => Promise<T>): Promise<T> {\n\t\tconst run = this.queue.then(task);\n\t\tthis.queue = run.then(\n\t\t\t() => undefined,\n\t\t\t() => undefined,\n\t\t);\n\t\treturn run;\n\t}\n\n\tattach(child: ChildProcess, handlers: PersistentChildHandlers): void {\n\t\tif (this.disposed) {\n\t\t\tif (child.pid) killProcessTree(child.pid);\n\t\t\tthrow new Error(\"Persistent process coordinator is disposed\");\n\t\t}\n\t\tif (this.currentChild) throw new Error(\"Persistent process coordinator already owns a child\");\n\t\tthis.currentChild = child;\n\t\tif (child.pid) trackDetachedChildPid(child.pid);\n\n\t\tchild.stdout?.on(\"data\", (data: Buffer) => {\n\t\t\tif (this.currentChild === child) handlers.onStdout(data);\n\t\t});\n\t\tchild.stderr?.on(\"data\", (data: Buffer) => {\n\t\t\tif (this.currentChild === child) handlers.onStderr(data);\n\t\t});\n\t\tchild.on(\"error\", (error) => {\n\t\t\tif (!this.clear(child)) return;\n\t\t\thandlers.onError(error instanceof Error ? error : new Error(String(error)));\n\t\t});\n\t\tlet exitCode: number | null = null;\n\t\tlet fallbackTimer: ReturnType<typeof setTimeout> | undefined;\n\n\t\tchild.on(\"exit\", (code) => {\n\t\t\tif (this.currentChild !== child) return;\n\t\t\texitCode = code;\n\t\t\tfallbackTimer = setTimeout(() => {\n\t\t\t\tif (!this.clear(child)) return;\n\t\t\t\thandlers.onClose(exitCode);\n\t\t\t}, 2_000);\n\t\t\tif (typeof fallbackTimer === \"object\" && fallbackTimer && \"unref\" in fallbackTimer) {\n\t\t\t\tfallbackTimer.unref();\n\t\t\t}\n\t\t});\n\n\t\tchild.on(\"close\", (code) => {\n\t\t\tif (fallbackTimer) clearTimeout(fallbackTimer);\n\t\t\tif (!this.clear(child)) return;\n\t\t\thandlers.onClose(code ?? exitCode);\n\t\t});\n\t}\n\n\tkill(): void {\n\t\tconst child = this.currentChild;\n\t\tif (!child) return;\n\t\tthis.clear(child);\n\t\tif (child.pid) killProcessTree(child.pid);\n\t}\n\n\tdispose(): void {\n\t\tif (this.disposed) return;\n\t\tthis.disposed = true;\n\t\tliveCoordinators.delete(this);\n\t\tthis.kill();\n\t}\n\n\t/** Synchronous best-effort tree kill for the process exit hook. */\n\tkillForProcessExit(): void {\n\t\tthis.kill();\n\t}\n\n\t/** Idle coordinators must not keep one-shot Node modes alive; active commands must. */\n\tsetLoopRef(active: boolean): void {\n\t\tconst child = this.currentChild;\n\t\tif (!child) return;\n\t\tsetChildProcessLoopRef(child, active);\n\t}\n\n\tprivate clear(child: ChildProcess): boolean {\n\t\tif (this.currentChild !== child) return false;\n\t\tif (child.pid) untrackDetachedChildPid(child.pid);\n\t\tthis.currentChild = null;\n\t\treturn true;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"persistent-process-coordinator.js","sourceRoot":"","sources":["../../../src/core/tools/persistent-process-coordinator.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared lifecycle owner for one serialized, persistent child process.\n *\n * Wire protocols, state projection, and respawn policy stay with their concrete shell adapters.\n * This boundary owns only the invariant OS mechanics: one active task, one current child, every\n * outstanding child terminal, stale event rejection, exit/close arbitration, whole-tree kill,\n * loop references, and parent exit.\n */\n\nimport type { ChildProcess } from \"node:child_process\";\nimport { setChildProcessLoopRef } from \"../../utils/child-process-ref.ts\";\nimport { killProcessTree, trackDetachedChildPid, untrackDetachedChildPid } from \"../../utils/shell.ts\";\n\nexport interface PersistentChildHandlers {\n\tonStdout(data: Buffer): void;\n\tonStderr(data: Buffer): void;\n\tonError(error: Error): void;\n\tonClose(code: number | null): void;\n}\n\nconst liveCoordinators = new Set<PersistentProcessCoordinator>();\nlet exitHookInstalled = false;\n\nfunction installExitHook(): void {\n\tif (exitHookInstalled) return;\n\texitHookInstalled = true;\n\tprocess.on(\"exit\", () => {\n\t\tfor (const coordinator of liveCoordinators) coordinator.killForProcessExit();\n\t});\n}\n\nexport class PersistentProcessCoordinator {\n\tprivate currentChild: ChildProcess | null = null;\n\tprivate readonly pendingChildTerminals = new Set<Promise<void>>();\n\tprivate queue: Promise<void> = Promise.resolve();\n\tprivate disposed = false;\n\n\tconstructor() {\n\t\tinstallExitHook();\n\t\tliveCoordinators.add(this);\n\t}\n\n\tget child(): ChildProcess | null {\n\t\treturn this.currentChild;\n\t}\n\n\tget terminalPromise(): Promise<void> {\n\t\treturn this.waitForTerminalRelease();\n\t}\n\n\trunSerialized<T>(task: () => Promise<T>): Promise<T> {\n\t\tconst run = this.queue.then(task);\n\t\tthis.queue = run.then(\n\t\t\t() => undefined,\n\t\t\t() => undefined,\n\t\t);\n\t\treturn run;\n\t}\n\n\tattach(child: ChildProcess, handlers: PersistentChildHandlers): void {\n\t\tif (this.disposed) {\n\t\t\tthis.trackTerminal(child);\n\t\t\tthis.terminateChild(child);\n\t\t\tthrow new Error(\"Persistent process coordinator is disposed\");\n\t\t}\n\t\tif (this.currentChild) throw new Error(\"Persistent process coordinator already owns a child\");\n\t\tthis.currentChild = child;\n\t\tif (child.pid) trackDetachedChildPid(child.pid);\n\t\tthis.trackTerminal(child);\n\n\t\tchild.stdout?.on(\"data\", (data: Buffer) => {\n\t\t\tif (this.currentChild === child) handlers.onStdout(data);\n\t\t});\n\t\tchild.stderr?.on(\"data\", (data: Buffer) => {\n\t\t\tif (this.currentChild === child) handlers.onStderr(data);\n\t\t});\n\t\tchild.on(\"error\", (error) => {\n\t\t\tif (!this.clear(child)) return;\n\t\t\thandlers.onError(error instanceof Error ? error : new Error(String(error)));\n\t\t});\n\t\tlet exitCode: number | null = null;\n\t\tlet fallbackTimer: ReturnType<typeof setTimeout> | undefined;\n\n\t\tchild.on(\"exit\", (code) => {\n\t\t\tif (this.currentChild !== child) return;\n\t\t\texitCode = code;\n\t\t\tfallbackTimer = setTimeout(() => {\n\t\t\t\tif (!this.clear(child)) return;\n\t\t\t\thandlers.onClose(exitCode);\n\t\t\t}, 2_000);\n\t\t\tif (typeof fallbackTimer === \"object\" && fallbackTimer && \"unref\" in fallbackTimer) {\n\t\t\t\tfallbackTimer.unref();\n\t\t\t}\n\t\t});\n\n\t\tchild.on(\"close\", (code) => {\n\t\t\tif (fallbackTimer) clearTimeout(fallbackTimer);\n\t\t\tif (!this.clear(child)) return;\n\t\t\thandlers.onClose(code ?? exitCode);\n\t\t});\n\t}\n\n\tkill(): void {\n\t\tconst child = this.currentChild;\n\t\tif (!child) return;\n\t\tthis.clear(child);\n\t\tthis.terminateChild(child);\n\t}\n\n\tprivate terminateChild(child: ChildProcess): void {\n\t\t// Bun's Windows child-process bridge can stop publishing terminal events after every\n\t\t// handle has been unref'd. Re-arm the already-installed close observer before killing so\n\t\t// strict teardown can distinguish physical handle release from process exit.\n\t\tsetChildProcessLoopRef(child, true);\n\t\tif (child.pid) killProcessTree(child.pid);\n\t\ttry {\n\t\t\tchild.kill();\n\t\t} catch {\n\t\t\t// Process already dead\n\t\t}\n\t}\n\n\tdispose(): void {\n\t\tif (this.disposed) return;\n\t\tthis.disposed = true;\n\t\tliveCoordinators.delete(this);\n\t\tthis.kill();\n\t}\n\n\t/** Synchronous best-effort tree kill for the process exit hook. */\n\tkillForProcessExit(): void {\n\t\tthis.kill();\n\t}\n\n\t/** Idle coordinators must not keep one-shot Node modes alive; active commands must. */\n\tsetLoopRef(active: boolean): void {\n\t\tconst child = this.currentChild;\n\t\tif (!child) return;\n\t\tsetChildProcessLoopRef(child, active);\n\t}\n\n\tprivate async waitForTerminalRelease(): Promise<void> {\n\t\tawait this.queue;\n\t\twhile (this.pendingChildTerminals.size > 0) {\n\t\t\tawait Promise.all(Array.from(this.pendingChildTerminals));\n\t\t}\n\t}\n\n\tprivate trackTerminal(child: ChildProcess): void {\n\t\tlet settled = false;\n\t\tlet resolveTerminal: () => void;\n\t\tconst terminalPromise = new Promise<void>((resolve) => {\n\t\t\tresolveTerminal = resolve;\n\t\t});\n\t\tconst settleTerminal = () => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tchild.off(\"error\", handleTerminalError);\n\t\t\tchild.off(\"close\", settleTerminal);\n\t\t\tthis.pendingChildTerminals.delete(terminalPromise);\n\t\t\tresolveTerminal();\n\t\t};\n\t\tconst handleTerminalError = () => {\n\t\t\tif (!child.pid) settleTerminal();\n\t\t};\n\n\t\tthis.pendingChildTerminals.add(terminalPromise);\n\t\tchild.on(\"error\", handleTerminalError);\n\t\tchild.once(\"close\", settleTerminal);\n\t}\n\n\tprivate clear(child: ChildProcess): boolean {\n\t\tif (this.currentChild !== child) return false;\n\t\tif (child.pid) untrackDetachedChildPid(child.pid);\n\t\tthis.currentChild = null;\n\t\treturn true;\n\t}\n}\n"]}
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
/** One production lifecycle boundary for every process/state resource owned by a shell session. */
|
|
2
|
-
|
|
2
|
+
export declare const SHELL_EXECUTION_DISPOSAL_WATCHDOG_MS = 5000;
|
|
3
|
+
/** Synchronously dispose both execution tiers and their shared authoritative Windows state. */
|
|
3
4
|
export declare function disposeShellExecutionSession(sessionKey: string): void;
|
|
5
|
+
/**
|
|
6
|
+
* Awaitable disposal that guarantees child processes in both execution tiers have reached
|
|
7
|
+
* physical terminal close before resolving. Concurrent callers for the same sessionKey share
|
|
8
|
+
* the identical pending wait promise.
|
|
9
|
+
*/
|
|
10
|
+
export declare function disposeShellExecutionSessionAndWait(sessionKey: string, timeoutMs?: number): Promise<void>;
|
|
4
11
|
//# sourceMappingURL=shell-execution-session.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shell-execution-session.d.ts","sourceRoot":"","sources":["../../../src/core/tools/shell-execution-session.ts"],"names":[],"mappings":"AAAA,mGAAmG;
|
|
1
|
+
{"version":3,"file":"shell-execution-session.d.ts","sourceRoot":"","sources":["../../../src/core/tools/shell-execution-session.ts"],"names":[],"mappings":"AAAA,mGAAmG;AASnG,eAAO,MAAM,oCAAoC,OAAQ,CAAC;AAE1D,+FAA+F;AAC/F,wBAAgB,4BAA4B,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAerE;AAUD;;;;GAIG;AACH,wBAAgB,mCAAmC,CAClD,UAAU,EAAE,MAAM,EAClB,SAAS,GAAE,MAA6C,GACtD,OAAO,CAAC,IAAI,CAAC,CA8Bf"}
|
|
@@ -2,10 +2,61 @@
|
|
|
2
2
|
import { disposePersistentShellSession } from "./shell-session.js";
|
|
3
3
|
import { disposeWindowsShellEngineSession } from "./windows-shell-engine.js";
|
|
4
4
|
import { disposeWindowsShellState } from "./windows-shell-state.js";
|
|
5
|
-
|
|
5
|
+
const inFlightTerminalPromises = new Map();
|
|
6
|
+
const inFlightDisposalWaits = new Map();
|
|
7
|
+
export const SHELL_EXECUTION_DISPOSAL_WATCHDOG_MS = 5_000;
|
|
8
|
+
/** Synchronously dispose both execution tiers and their shared authoritative Windows state. */
|
|
6
9
|
export function disposeShellExecutionSession(sessionKey) {
|
|
7
|
-
disposeWindowsShellEngineSession(sessionKey);
|
|
8
|
-
disposePersistentShellSession(sessionKey);
|
|
9
10
|
disposeWindowsShellState(sessionKey);
|
|
11
|
+
const p1 = disposeWindowsShellEngineSession(sessionKey);
|
|
12
|
+
const p2 = disposePersistentShellSession(sessionKey);
|
|
13
|
+
const previous = inFlightTerminalPromises.get(sessionKey);
|
|
14
|
+
const combined = Promise.all([previous ?? Promise.resolve(), p1, p2])
|
|
15
|
+
.then(() => undefined)
|
|
16
|
+
.finally(() => {
|
|
17
|
+
if (inFlightTerminalPromises.get(sessionKey) === combined) {
|
|
18
|
+
inFlightTerminalPromises.delete(sessionKey);
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
inFlightTerminalPromises.set(sessionKey, combined);
|
|
22
|
+
}
|
|
23
|
+
async function drainTerminalPromises(sessionKey) {
|
|
24
|
+
while (true) {
|
|
25
|
+
const terminalPromise = inFlightTerminalPromises.get(sessionKey);
|
|
26
|
+
if (!terminalPromise)
|
|
27
|
+
return;
|
|
28
|
+
await terminalPromise;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Awaitable disposal that guarantees child processes in both execution tiers have reached
|
|
33
|
+
* physical terminal close before resolving. Concurrent callers for the same sessionKey share
|
|
34
|
+
* the identical pending wait promise.
|
|
35
|
+
*/
|
|
36
|
+
export function disposeShellExecutionSessionAndWait(sessionKey, timeoutMs = SHELL_EXECUTION_DISPOSAL_WATCHDOG_MS) {
|
|
37
|
+
disposeShellExecutionSession(sessionKey);
|
|
38
|
+
const existing = inFlightDisposalWaits.get(sessionKey);
|
|
39
|
+
if (existing)
|
|
40
|
+
return existing;
|
|
41
|
+
let watchdogTimer;
|
|
42
|
+
const watchdogPromise = new Promise((_, reject) => {
|
|
43
|
+
watchdogTimer = setTimeout(() => {
|
|
44
|
+
reject(new Error(`Shell execution session terminal release timed out after ${timeoutMs}ms before child close event`));
|
|
45
|
+
}, timeoutMs);
|
|
46
|
+
if (typeof watchdogTimer === "object" && watchdogTimer && "unref" in watchdogTimer) {
|
|
47
|
+
watchdogTimer.unref();
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
const waitPromise = Promise.race([drainTerminalPromises(sessionKey), watchdogPromise])
|
|
51
|
+
.then(() => undefined)
|
|
52
|
+
.finally(() => {
|
|
53
|
+
if (watchdogTimer)
|
|
54
|
+
clearTimeout(watchdogTimer);
|
|
55
|
+
if (inFlightDisposalWaits.get(sessionKey) === waitPromise) {
|
|
56
|
+
inFlightDisposalWaits.delete(sessionKey);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
inFlightDisposalWaits.set(sessionKey, waitPromise);
|
|
60
|
+
return waitPromise;
|
|
10
61
|
}
|
|
11
62
|
//# sourceMappingURL=shell-execution-session.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shell-execution-session.js","sourceRoot":"","sources":["../../../src/core/tools/shell-execution-session.ts"],"names":[],"mappings":"AAAA,mGAAmG;AAEnG,OAAO,EAAE,6BAA6B,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,EAAE,gCAAgC,EAAE,MAAM,2BAA2B,CAAC;AAC7E,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAEpE,
|
|
1
|
+
{"version":3,"file":"shell-execution-session.js","sourceRoot":"","sources":["../../../src/core/tools/shell-execution-session.ts"],"names":[],"mappings":"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","sourcesContent":["/** One production lifecycle boundary for every process/state resource owned by a shell session. */\n\nimport { disposePersistentShellSession } from \"./shell-session.ts\";\nimport { disposeWindowsShellEngineSession } from \"./windows-shell-engine.ts\";\nimport { disposeWindowsShellState } from \"./windows-shell-state.ts\";\n\nconst inFlightTerminalPromises = new Map<string, Promise<void>>();\nconst inFlightDisposalWaits = new Map<string, Promise<void>>();\n\nexport const SHELL_EXECUTION_DISPOSAL_WATCHDOG_MS = 5_000;\n\n/** Synchronously dispose both execution tiers and their shared authoritative Windows state. */\nexport function disposeShellExecutionSession(sessionKey: string): void {\n\tdisposeWindowsShellState(sessionKey);\n\tconst p1 = disposeWindowsShellEngineSession(sessionKey);\n\tconst p2 = disposePersistentShellSession(sessionKey);\n\n\tconst previous = inFlightTerminalPromises.get(sessionKey);\n\tconst combined = Promise.all([previous ?? Promise.resolve(), p1, p2])\n\t\t.then(() => undefined)\n\t\t.finally(() => {\n\t\t\tif (inFlightTerminalPromises.get(sessionKey) === combined) {\n\t\t\t\tinFlightTerminalPromises.delete(sessionKey);\n\t\t\t}\n\t\t});\n\n\tinFlightTerminalPromises.set(sessionKey, combined);\n}\n\nasync function drainTerminalPromises(sessionKey: string): Promise<void> {\n\twhile (true) {\n\t\tconst terminalPromise = inFlightTerminalPromises.get(sessionKey);\n\t\tif (!terminalPromise) return;\n\t\tawait terminalPromise;\n\t}\n}\n\n/**\n * Awaitable disposal that guarantees child processes in both execution tiers have reached\n * physical terminal close before resolving. Concurrent callers for the same sessionKey share\n * the identical pending wait promise.\n */\nexport function disposeShellExecutionSessionAndWait(\n\tsessionKey: string,\n\ttimeoutMs: number = SHELL_EXECUTION_DISPOSAL_WATCHDOG_MS,\n): Promise<void> {\n\tdisposeShellExecutionSession(sessionKey);\n\tconst existing = inFlightDisposalWaits.get(sessionKey);\n\tif (existing) return existing;\n\n\tlet watchdogTimer: ReturnType<typeof setTimeout> | undefined;\n\tconst watchdogPromise = new Promise<void>((_, reject) => {\n\t\twatchdogTimer = setTimeout(() => {\n\t\t\treject(\n\t\t\t\tnew Error(\n\t\t\t\t\t`Shell execution session terminal release timed out after ${timeoutMs}ms before child close event`,\n\t\t\t\t),\n\t\t\t);\n\t\t}, timeoutMs);\n\t\tif (typeof watchdogTimer === \"object\" && watchdogTimer && \"unref\" in watchdogTimer) {\n\t\t\twatchdogTimer.unref();\n\t\t}\n\t});\n\n\tconst waitPromise = Promise.race([drainTerminalPromises(sessionKey), watchdogPromise])\n\t\t.then(() => undefined)\n\t\t.finally(() => {\n\t\t\tif (watchdogTimer) clearTimeout(watchdogTimer);\n\t\t\tif (inFlightDisposalWaits.get(sessionKey) === waitPromise) {\n\t\t\t\tinFlightDisposalWaits.delete(sessionKey);\n\t\t\t}\n\t\t});\n\n\tinFlightDisposalWaits.set(sessionKey, waitPromise);\n\treturn waitPromise;\n}\n"]}
|
|
@@ -81,6 +81,7 @@ export declare class PersistentShellSession {
|
|
|
81
81
|
}>;
|
|
82
82
|
/** Start and validate the long-lived shell before the first user command. Idempotent per session. */
|
|
83
83
|
prewarm(cwd: string, env?: NodeJS.ProcessEnv): Promise<void>;
|
|
84
|
+
get terminalPromise(): Promise<void>;
|
|
84
85
|
dispose(): void;
|
|
85
86
|
private execNow;
|
|
86
87
|
private spawnChild;
|
|
@@ -93,5 +94,5 @@ export declare class PersistentShellSession {
|
|
|
93
94
|
/** Get or lazily create the persistent session for a key. A kind change replaces the session. */
|
|
94
95
|
export declare function acquirePersistentShellSession(key: string, kind: PlatformShellToolName): PersistentShellSession;
|
|
95
96
|
/** Kill and forget a session (agent teardown). Safe to call for keys that never spawned. */
|
|
96
|
-
export declare function disposePersistentShellSession(key: string): void
|
|
97
|
+
export declare function disposePersistentShellSession(key: string): Promise<void>;
|
|
97
98
|
//# sourceMappingURL=shell-session.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shell-session.d.ts","sourceRoot":"","sources":["../../../src/core/tools/shell-session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAKH,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,YAAY,EAAS,MAAM,eAAe,CAAC;AAS5E,OAAO,EAIN,KAAK,qBAAqB,EAE1B,KAAK,WAAW,EAChB,MAAM,sBAAsB,CAAC;AAI9B,OAAO,EACN,+BAA+B,EAC/B,sCAAsC,GACtC,MAAM,4CAA4C,CAAC;AAQpD,MAAM,WAAW,uBAAuB;IACvC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,kGAAkG;IAClG,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gGAAgG;IAChG,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACxB;AAED,MAAM,WAAW,6BAA6B;IAC7C,2BAA2B,CAAC,EAAE,MAAM,WAAW,EAAE,CAAC;IAClD,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,YAAY,KAAK,YAAY,CAAC;IACjF,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC1B;AAUD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAazF;AA6ED,iHAAiH;AACjH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAK/F;AA8CD,qBAAa,sBAAsB;IAClC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAwB;IAC7C,OAAO,CAAC,QAAQ,CAAC,2BAA2B,CAAsB;IAClE,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA2E;IACxG,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAsC;IAClE,OAAO,CAAC,QAAQ,CAAkC;IAClD,OAAO,CAAC,gBAAgB,CAAuB;IAC/C,OAAO,CAAC,UAAU,CAA2B;IAC7C,OAAO,CAAC,aAAa,CAAyC;IAC9D,OAAO,CAAC,QAAQ,CAAS;IAEzB,YAAY,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,qBAAqB,EAAE,OAAO,GAAE,6BAAkC,EAMhG;IAED,IAAI,WAAW,IAAI,qBAAqB,CAEvC;IAED,4FAA4F;IAC5F,IAAI,CACH,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,uBAAuB,GAC9B,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAEpD;IAED,qGAAqG;IACrG,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,CAAC,UAA0B,GAAG,OAAO,CAAC,IAAI,CAAC,CA0B1E;IAED,OAAO,IAAI,IAAI,CAOd;YAEa,OAAO;YAqMP,UAAU;YAqBV,oBAAoB;IA2BlC,OAAO,CAAC,wBAAwB;IA2FhC,OAAO,CAAC,gBAAgB;IAexB,OAAO,CAAC,eAAe;IAKvB,OAAO,CAAC,SAAS;CAIjB;
|
|
1
|
+
{"version":3,"file":"shell-session.d.ts","sourceRoot":"","sources":["../../../src/core/tools/shell-session.ts"],"names":[],"mappings":"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"}
|
|
@@ -215,6 +215,9 @@ export class PersistentShellSession {
|
|
|
215
215
|
this.coordinator.setLoopRef(false);
|
|
216
216
|
});
|
|
217
217
|
}
|
|
218
|
+
get terminalPromise() {
|
|
219
|
+
return this.coordinator.terminalPromise;
|
|
220
|
+
}
|
|
218
221
|
dispose() {
|
|
219
222
|
if (this.disposed)
|
|
220
223
|
return;
|
|
@@ -580,12 +583,28 @@ export class PersistentShellSession {
|
|
|
580
583
|
}
|
|
581
584
|
}
|
|
582
585
|
const shellSessions = new Map();
|
|
586
|
+
const retiredShellSessionTerminals = new Map();
|
|
587
|
+
function retainShellSessionTerminal(key, terminalPromise) {
|
|
588
|
+
const previous = retiredShellSessionTerminals.get(key);
|
|
589
|
+
const combined = Promise.all([previous ?? Promise.resolve(), terminalPromise])
|
|
590
|
+
.then(() => undefined)
|
|
591
|
+
.finally(() => {
|
|
592
|
+
if (retiredShellSessionTerminals.get(key) === combined) {
|
|
593
|
+
retiredShellSessionTerminals.delete(key);
|
|
594
|
+
}
|
|
595
|
+
});
|
|
596
|
+
retiredShellSessionTerminals.set(key, combined);
|
|
597
|
+
return combined;
|
|
598
|
+
}
|
|
583
599
|
/** Get or lazily create the persistent session for a key. A kind change replaces the session. */
|
|
584
600
|
export function acquirePersistentShellSession(key, kind) {
|
|
585
601
|
const existing = shellSessions.get(key);
|
|
586
602
|
if (existing && existing.sessionKind === kind)
|
|
587
603
|
return existing;
|
|
588
|
-
existing
|
|
604
|
+
if (existing) {
|
|
605
|
+
existing.dispose();
|
|
606
|
+
retainShellSessionTerminal(key, existing.terminalPromise);
|
|
607
|
+
}
|
|
589
608
|
const session = new PersistentShellSession(key, kind);
|
|
590
609
|
shellSessions.set(key, session);
|
|
591
610
|
return session;
|
|
@@ -594,8 +613,9 @@ export function acquirePersistentShellSession(key, kind) {
|
|
|
594
613
|
export function disposePersistentShellSession(key) {
|
|
595
614
|
const session = shellSessions.get(key);
|
|
596
615
|
if (!session)
|
|
597
|
-
return;
|
|
616
|
+
return retiredShellSessionTerminals.get(key) ?? Promise.resolve();
|
|
598
617
|
shellSessions.delete(key);
|
|
599
618
|
session.dispose();
|
|
619
|
+
return retainShellSessionTerminal(key, session.terminalPromise);
|
|
600
620
|
}
|
|
601
621
|
//# sourceMappingURL=shell-session.js.map
|