@chiwanpark/pi-squared-agent 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. package/README.md +13 -0
  2. package/dist/cli.d.ts +3 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +144 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/index.d.ts +11 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +11 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/runtime/auth-store.d.ts +36 -0
  11. package/dist/runtime/auth-store.d.ts.map +1 -0
  12. package/dist/runtime/auth-store.js +131 -0
  13. package/dist/runtime/auth-store.js.map +1 -0
  14. package/dist/runtime/config-store.d.ts +44 -0
  15. package/dist/runtime/config-store.d.ts.map +1 -0
  16. package/dist/runtime/config-store.js +138 -0
  17. package/dist/runtime/config-store.js.map +1 -0
  18. package/dist/runtime/messages.d.ts +12 -0
  19. package/dist/runtime/messages.d.ts.map +1 -0
  20. package/dist/runtime/messages.js +101 -0
  21. package/dist/runtime/messages.js.map +1 -0
  22. package/dist/runtime/model-resolver.d.ts +52 -0
  23. package/dist/runtime/model-resolver.d.ts.map +1 -0
  24. package/dist/runtime/model-resolver.js +175 -0
  25. package/dist/runtime/model-resolver.js.map +1 -0
  26. package/dist/runtime/pi-agent.d.ts +83 -0
  27. package/dist/runtime/pi-agent.d.ts.map +1 -0
  28. package/dist/runtime/pi-agent.js +405 -0
  29. package/dist/runtime/pi-agent.js.map +1 -0
  30. package/dist/runtime/status-store.d.ts +50 -0
  31. package/dist/runtime/status-store.d.ts.map +1 -0
  32. package/dist/runtime/status-store.js +65 -0
  33. package/dist/runtime/status-store.js.map +1 -0
  34. package/dist/runtime/system-prompt.d.ts +11 -0
  35. package/dist/runtime/system-prompt.d.ts.map +1 -0
  36. package/dist/runtime/system-prompt.js +43 -0
  37. package/dist/runtime/system-prompt.js.map +1 -0
  38. package/dist/runtime/tools/bash.d.ts +23 -0
  39. package/dist/runtime/tools/bash.d.ts.map +1 -0
  40. package/dist/runtime/tools/bash.js +206 -0
  41. package/dist/runtime/tools/bash.js.map +1 -0
  42. package/dist/runtime/tools/child-process.d.ts +13 -0
  43. package/dist/runtime/tools/child-process.d.ts.map +1 -0
  44. package/dist/runtime/tools/child-process.js +75 -0
  45. package/dist/runtime/tools/child-process.js.map +1 -0
  46. package/dist/runtime/tools/output-accumulator.d.ts +52 -0
  47. package/dist/runtime/tools/output-accumulator.d.ts.map +1 -0
  48. package/dist/runtime/tools/output-accumulator.js +160 -0
  49. package/dist/runtime/tools/output-accumulator.js.map +1 -0
  50. package/dist/runtime/tools/shell.d.ts +26 -0
  51. package/dist/runtime/tools/shell.d.ts.map +1 -0
  52. package/dist/runtime/tools/shell.js +116 -0
  53. package/dist/runtime/tools/shell.js.map +1 -0
  54. package/dist/runtime/tools/truncate.d.ts +38 -0
  55. package/dist/runtime/tools/truncate.d.ts.map +1 -0
  56. package/dist/runtime/tools/truncate.js +98 -0
  57. package/dist/runtime/tools/truncate.js.map +1 -0
  58. package/dist/tools/bash/child-process.d.ts +13 -0
  59. package/dist/tools/bash/child-process.d.ts.map +1 -0
  60. package/dist/tools/bash/child-process.js +79 -0
  61. package/dist/tools/bash/child-process.js.map +1 -0
  62. package/dist/tools/bash/output-accumulator.d.ts +54 -0
  63. package/dist/tools/bash/output-accumulator.d.ts.map +1 -0
  64. package/dist/tools/bash/output-accumulator.js +171 -0
  65. package/dist/tools/bash/output-accumulator.js.map +1 -0
  66. package/dist/tools/bash/shell.d.ts +26 -0
  67. package/dist/tools/bash/shell.d.ts.map +1 -0
  68. package/dist/tools/bash/shell.js +129 -0
  69. package/dist/tools/bash/shell.js.map +1 -0
  70. package/dist/tools/bash/tool.d.ts +23 -0
  71. package/dist/tools/bash/tool.d.ts.map +1 -0
  72. package/dist/tools/bash/tool.js +219 -0
  73. package/dist/tools/bash/tool.js.map +1 -0
  74. package/dist/tools/bash/truncate.d.ts +50 -0
  75. package/dist/tools/bash/truncate.d.ts.map +1 -0
  76. package/dist/tools/bash/truncate.js +184 -0
  77. package/dist/tools/bash/truncate.js.map +1 -0
  78. package/dist/tools/external-tool.d.ts +2 -0
  79. package/dist/tools/external-tool.d.ts.map +1 -0
  80. package/dist/tools/external-tool.js +15 -0
  81. package/dist/tools/external-tool.js.map +1 -0
  82. package/dist/tools/file/edit-diff.d.ts +27 -0
  83. package/dist/tools/file/edit-diff.d.ts.map +1 -0
  84. package/dist/tools/file/edit-diff.js +196 -0
  85. package/dist/tools/file/edit-diff.js.map +1 -0
  86. package/dist/tools/file/edit.d.ts +26 -0
  87. package/dist/tools/file/edit.d.ts.map +1 -0
  88. package/dist/tools/file/edit.js +106 -0
  89. package/dist/tools/file/edit.js.map +1 -0
  90. package/dist/tools/file/find.d.ts +27 -0
  91. package/dist/tools/file/find.d.ts.map +1 -0
  92. package/dist/tools/file/find.js +150 -0
  93. package/dist/tools/file/find.js.map +1 -0
  94. package/dist/tools/file/glob.d.ts +6 -0
  95. package/dist/tools/file/glob.d.ts.map +1 -0
  96. package/dist/tools/file/glob.js +50 -0
  97. package/dist/tools/file/glob.js.map +1 -0
  98. package/dist/tools/file/grep.d.ts +29 -0
  99. package/dist/tools/file/grep.d.ts.map +1 -0
  100. package/dist/tools/file/grep.js +220 -0
  101. package/dist/tools/file/grep.js.map +1 -0
  102. package/dist/tools/file/index.d.ts +7 -0
  103. package/dist/tools/file/index.d.ts.map +1 -0
  104. package/dist/tools/file/index.js +7 -0
  105. package/dist/tools/file/index.js.map +1 -0
  106. package/dist/tools/file/ls.d.ts +27 -0
  107. package/dist/tools/file/ls.d.ts.map +1 -0
  108. package/dist/tools/file/ls.js +82 -0
  109. package/dist/tools/file/ls.js.map +1 -0
  110. package/dist/tools/file/read.d.ts +23 -0
  111. package/dist/tools/file/read.d.ts.map +1 -0
  112. package/dist/tools/file/read.js +98 -0
  113. package/dist/tools/file/read.js.map +1 -0
  114. package/dist/tools/file/write.d.ts +17 -0
  115. package/dist/tools/file/write.d.ts.map +1 -0
  116. package/dist/tools/file/write.js +45 -0
  117. package/dist/tools/file/write.js.map +1 -0
  118. package/dist/tools/file-mutation-queue.d.ts +3 -0
  119. package/dist/tools/file-mutation-queue.d.ts.map +1 -0
  120. package/dist/tools/file-mutation-queue.js +47 -0
  121. package/dist/tools/file-mutation-queue.js.map +1 -0
  122. package/dist/tools/path-utils.d.ts +5 -0
  123. package/dist/tools/path-utils.d.ts.map +1 -0
  124. package/dist/tools/path-utils.js +79 -0
  125. package/dist/tools/path-utils.js.map +1 -0
  126. package/dist/tools/web/index.d.ts +2 -0
  127. package/dist/tools/web/index.d.ts.map +1 -0
  128. package/dist/tools/web/index.js +2 -0
  129. package/dist/tools/web/index.js.map +1 -0
  130. package/dist/tools/web/search.d.ts +44 -0
  131. package/dist/tools/web/search.d.ts.map +1 -0
  132. package/dist/tools/web/search.js +209 -0
  133. package/dist/tools/web/search.js.map +1 -0
  134. package/dist/tui/box.d.ts +11 -0
  135. package/dist/tui/box.d.ts.map +1 -0
  136. package/dist/tui/box.js +24 -0
  137. package/dist/tui/box.js.map +1 -0
  138. package/dist/tui/chat-screen.d.ts +29 -0
  139. package/dist/tui/chat-screen.d.ts.map +1 -0
  140. package/dist/tui/chat-screen.js +475 -0
  141. package/dist/tui/chat-screen.js.map +1 -0
  142. package/dist/tui/commands.d.ts +34 -0
  143. package/dist/tui/commands.d.ts.map +1 -0
  144. package/dist/tui/commands.js +691 -0
  145. package/dist/tui/commands.js.map +1 -0
  146. package/dist/tui/interactive.d.ts +9 -0
  147. package/dist/tui/interactive.d.ts.map +1 -0
  148. package/dist/tui/interactive.js +88 -0
  149. package/dist/tui/interactive.js.map +1 -0
  150. package/dist/tui/overlays.d.ts +39 -0
  151. package/dist/tui/overlays.d.ts.map +1 -0
  152. package/dist/tui/overlays.js +157 -0
  153. package/dist/tui/overlays.js.map +1 -0
  154. package/dist/tui/theme.d.ts +40 -0
  155. package/dist/tui/theme.d.ts.map +1 -0
  156. package/dist/tui/theme.js +120 -0
  157. package/dist/tui/theme.js.map +1 -0
  158. package/dist/tui/welcome.d.ts +3 -0
  159. package/dist/tui/welcome.d.ts.map +1 -0
  160. package/dist/tui/welcome.js +37 -0
  161. package/dist/tui/welcome.js.map +1 -0
  162. package/package.json +54 -0
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Shell configuration, environment helpers, and process-kill utilities.
3
+ *
4
+ * Ported from @earendil-works/pi-coding-agent.
5
+ * Simplification: getShellEnv() returns process.env as-is without prepending a
6
+ * pi-specific bin directory.
7
+ */
8
+ import { existsSync } from "node:fs";
9
+ import { spawn, spawnSync } from "child_process";
10
+ /** Find bash executable on PATH (cross-platform). */
11
+ function findBashOnPath() {
12
+ if (process.platform === "win32") {
13
+ try {
14
+ const result = spawnSync("where", ["bash.exe"], {
15
+ encoding: "utf-8",
16
+ timeout: 5000,
17
+ windowsHide: true,
18
+ });
19
+ if (result.status === 0 && result.stdout) {
20
+ const firstMatch = result.stdout.trim().split(/\r?\n/)[0];
21
+ if (firstMatch && existsSync(firstMatch)) return firstMatch;
22
+ }
23
+ } catch {
24
+ // ignore
25
+ }
26
+ return null;
27
+ }
28
+ try {
29
+ const result = spawnSync("which", ["bash"], { encoding: "utf-8", timeout: 5000 });
30
+ if (result.status === 0 && result.stdout) {
31
+ const firstMatch = result.stdout.trim().split(/\r?\n/)[0];
32
+ if (firstMatch) return firstMatch;
33
+ }
34
+ } catch {
35
+ // ignore
36
+ }
37
+ return null;
38
+ }
39
+ /**
40
+ * Resolve shell configuration based on platform and an optional explicit shell path.
41
+ *
42
+ * Resolution order:
43
+ * 1. User-specified shellPath
44
+ * 2. On Windows: Git Bash in known locations, then bash on PATH
45
+ * 3. On Unix: /bin/bash, then bash on PATH, then fallback to sh
46
+ */
47
+ export function getShellConfig(customShellPath) {
48
+ if (customShellPath) {
49
+ if (existsSync(customShellPath)) return { shell: customShellPath, args: ["-c"] };
50
+ throw new Error(`Custom shell path not found: ${customShellPath}`);
51
+ }
52
+ if (process.platform === "win32") {
53
+ const paths = [];
54
+ const programFiles = process.env["ProgramFiles"];
55
+ if (programFiles) paths.push(`${programFiles}\\Git\\bin\\bash.exe`);
56
+ const programFilesX86 = process.env["ProgramFiles(x86)"];
57
+ if (programFilesX86) paths.push(`${programFilesX86}\\Git\\bin\\bash.exe`);
58
+ for (const p of paths) {
59
+ if (existsSync(p)) return { shell: p, args: ["-c"] };
60
+ }
61
+ const bashOnPath = findBashOnPath();
62
+ if (bashOnPath) return { shell: bashOnPath, args: ["-c"] };
63
+ throw new Error(
64
+ `No bash shell found. Options:\n` +
65
+ ` 1. Install Git for Windows: https://git-scm.com/download/win\n` +
66
+ ` 2. Add your bash to PATH (Cygwin, MSYS2, etc.)\n` +
67
+ ` 3. Set shellPath in settings.json\n\n` +
68
+ `Searched Git Bash in:\n${paths.map((p) => ` ${p}`).join("\n")}`,
69
+ );
70
+ }
71
+ // Unix: /bin/bash → bash on PATH → sh
72
+ if (existsSync("/bin/bash")) return { shell: "/bin/bash", args: ["-c"] };
73
+ const bashOnPath = findBashOnPath();
74
+ if (bashOnPath) return { shell: bashOnPath, args: ["-c"] };
75
+ return { shell: "sh", args: ["-c"] };
76
+ }
77
+ /** Return the current process environment for spawned commands. */
78
+ export function getShellEnv() {
79
+ return { ...process.env };
80
+ }
81
+ /**
82
+ * Detached child processes are tracked so they can be cleaned up when the
83
+ * parent receives SIGHUP/SIGTERM.
84
+ */
85
+ const trackedDetachedChildPids = new Set();
86
+ export function trackDetachedChildPid(pid) {
87
+ trackedDetachedChildPids.add(pid);
88
+ }
89
+ export function untrackDetachedChildPid(pid) {
90
+ trackedDetachedChildPids.delete(pid);
91
+ }
92
+ /** Kill a process and its entire process group (cross-platform). */
93
+ export function killProcessTree(pid) {
94
+ if (process.platform === "win32") {
95
+ try {
96
+ spawn("taskkill", ["/F", "/T", "/PID", String(pid)], {
97
+ stdio: "ignore",
98
+ detached: true,
99
+ windowsHide: true,
100
+ });
101
+ } catch {
102
+ // ignore
103
+ }
104
+ } else {
105
+ try {
106
+ process.kill(-pid, "SIGKILL");
107
+ } catch {
108
+ try {
109
+ process.kill(pid, "SIGKILL");
110
+ } catch {
111
+ // process already dead
112
+ }
113
+ }
114
+ }
115
+ }
116
+ //# sourceMappingURL=shell.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shell.js","sourceRoot":"","sources":["../../../src/runtime/tools/shell.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Shared truncation utilities for tool outputs.
3
+ *
4
+ * Truncation is based on two independent limits — whichever is hit first wins:
5
+ * - Line limit (default: 2000 lines)
6
+ * - Byte limit (default: 50 KB)
7
+ *
8
+ * Ported from @earendil-works/pi-coding-agent.
9
+ */
10
+ export declare const DEFAULT_MAX_LINES = 2000;
11
+ export declare const DEFAULT_MAX_BYTES: number;
12
+ export interface TruncationResult {
13
+ content: string;
14
+ truncated: boolean;
15
+ truncatedBy: "lines" | "bytes" | null;
16
+ totalLines: number;
17
+ totalBytes: number;
18
+ outputLines: number;
19
+ outputBytes: number;
20
+ lastLinePartial: boolean;
21
+ firstLineExceedsLimit: boolean;
22
+ maxLines: number;
23
+ maxBytes: number;
24
+ }
25
+ export interface TruncationOptions {
26
+ maxLines?: number;
27
+ maxBytes?: number;
28
+ }
29
+ /** Format bytes as human-readable size. */
30
+ export declare function formatSize(bytes: number): string;
31
+ /**
32
+ * Truncate content from the tail (keep last N lines/bytes).
33
+ * Suitable for bash output where you want to see the end (errors, final results).
34
+ *
35
+ * May return a partial first line if the last line alone exceeds the byte limit.
36
+ */
37
+ export declare function truncateTail(content: string, options?: TruncationOptions): TruncationResult;
38
+ //# sourceMappingURL=truncate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"truncate.d.ts","sourceRoot":"","sources":["../../../src/runtime/tools/truncate.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,eAAO,MAAM,iBAAiB,OAAO,CAAC;AACtC,eAAO,MAAM,iBAAiB,QAAY,CAAC;AAE3C,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,OAAO,GAAG,OAAO,GAAG,IAAI,CAAC;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,OAAO,CAAC;IACzB,qBAAqB,EAAE,OAAO,CAAC;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,2CAA2C;AAC3C,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIhD;AASD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB,GAAG,gBAAgB,CAiE/F"}
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Shared truncation utilities for tool outputs.
3
+ *
4
+ * Truncation is based on two independent limits — whichever is hit first wins:
5
+ * - Line limit (default: 2000 lines)
6
+ * - Byte limit (default: 50 KB)
7
+ *
8
+ * Ported from @earendil-works/pi-coding-agent.
9
+ */
10
+ export const DEFAULT_MAX_LINES = 2000;
11
+ export const DEFAULT_MAX_BYTES = 50 * 1024; // 50 KB
12
+ /** Format bytes as human-readable size. */
13
+ export function formatSize(bytes) {
14
+ if (bytes < 1024) return `${bytes}B`;
15
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;
16
+ return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
17
+ }
18
+ function splitLinesForCounting(content) {
19
+ if (content.length === 0) return [];
20
+ const lines = content.split("\n");
21
+ if (content.endsWith("\n")) lines.pop();
22
+ return lines;
23
+ }
24
+ /**
25
+ * Truncate content from the tail (keep last N lines/bytes).
26
+ * Suitable for bash output where you want to see the end (errors, final results).
27
+ *
28
+ * May return a partial first line if the last line alone exceeds the byte limit.
29
+ */
30
+ export function truncateTail(content, options = {}) {
31
+ const maxLines = options.maxLines ?? DEFAULT_MAX_LINES;
32
+ const maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;
33
+ const totalBytes = Buffer.byteLength(content, "utf-8");
34
+ const lines = splitLinesForCounting(content);
35
+ const totalLines = lines.length;
36
+ if (totalLines <= maxLines && totalBytes <= maxBytes) {
37
+ return {
38
+ content,
39
+ truncated: false,
40
+ truncatedBy: null,
41
+ totalLines,
42
+ totalBytes,
43
+ outputLines: totalLines,
44
+ outputBytes: totalBytes,
45
+ lastLinePartial: false,
46
+ firstLineExceedsLimit: false,
47
+ maxLines,
48
+ maxBytes,
49
+ };
50
+ }
51
+ const outputLinesArr = [];
52
+ let outputBytesCount = 0;
53
+ let truncatedBy = "lines";
54
+ let lastLinePartial = false;
55
+ for (let i = lines.length - 1; i >= 0 && outputLinesArr.length < maxLines; i--) {
56
+ const line = lines[i] ?? "";
57
+ const lineBytes = Buffer.byteLength(line, "utf-8") + (outputLinesArr.length > 0 ? 1 : 0);
58
+ if (outputBytesCount + lineBytes > maxBytes) {
59
+ truncatedBy = "bytes";
60
+ // Edge case: first line alone exceeds the limit — take the tail of that line.
61
+ if (outputLinesArr.length === 0) {
62
+ const truncatedLine = truncateStringToBytesFromEnd(line, maxBytes);
63
+ outputLinesArr.unshift(truncatedLine);
64
+ outputBytesCount = Buffer.byteLength(truncatedLine, "utf-8");
65
+ lastLinePartial = true;
66
+ }
67
+ break;
68
+ }
69
+ outputLinesArr.unshift(line);
70
+ outputBytesCount += lineBytes;
71
+ }
72
+ if (outputLinesArr.length >= maxLines && outputBytesCount <= maxBytes) {
73
+ truncatedBy = "lines";
74
+ }
75
+ const outputContent = outputLinesArr.join("\n");
76
+ return {
77
+ content: outputContent,
78
+ truncated: true,
79
+ truncatedBy,
80
+ totalLines,
81
+ totalBytes,
82
+ outputLines: outputLinesArr.length,
83
+ outputBytes: Buffer.byteLength(outputContent, "utf-8"),
84
+ lastLinePartial,
85
+ firstLineExceedsLimit: false,
86
+ maxLines,
87
+ maxBytes,
88
+ };
89
+ }
90
+ function truncateStringToBytesFromEnd(str, maxBytes) {
91
+ const buf = Buffer.from(str, "utf-8");
92
+ if (buf.length <= maxBytes) return str;
93
+ let start = buf.length - maxBytes;
94
+ // Advance to the next valid UTF-8 character boundary.
95
+ while (start < buf.length && ((buf[start] ?? 0) & 0xc0) === 0x80) start++;
96
+ return buf.subarray(start).toString("utf-8");
97
+ }
98
+ //# sourceMappingURL=truncate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"truncate.js","sourceRoot":"","sources":["../../../src/runtime/tools/truncate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Wait for a child process to terminate without hanging on inherited stdio handles.
3
+ *
4
+ * On Windows, daemonized descendants can inherit the child's stdout/stderr pipe
5
+ * handles. In that case the child emits `exit`, but `close` can hang forever even
6
+ * though the original process is already gone. We wait briefly for stdio to end,
7
+ * then forcibly stop tracking the inherited handles.
8
+ *
9
+ * Ported from @earendil-works/pi-coding-agent.
10
+ */
11
+ import type { ChildProcess } from "node:child_process";
12
+ export declare function waitForChildProcess(child: ChildProcess): Promise<number | null>;
13
+ //# sourceMappingURL=child-process.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"child-process.d.ts","sourceRoot":"","sources":["../../../src/tools/bash/child-process.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAIvD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAuE/E"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Wait for a child process to terminate without hanging on inherited stdio handles.
3
+ *
4
+ * On Windows, daemonized descendants can inherit the child's stdout/stderr pipe
5
+ * handles. In that case the child emits `exit`, but `close` can hang forever even
6
+ * though the original process is already gone. We wait briefly for stdio to end,
7
+ * then forcibly stop tracking the inherited handles.
8
+ *
9
+ * Ported from @earendil-works/pi-coding-agent.
10
+ */
11
+ const EXIT_STDIO_GRACE_MS = 100;
12
+ export function waitForChildProcess(child) {
13
+ return new Promise((resolve, reject) => {
14
+ let settled = false;
15
+ let exited = false;
16
+ let exitCode = null;
17
+ let postExitTimer;
18
+ let stdoutEnded = child.stdout === null;
19
+ let stderrEnded = child.stderr === null;
20
+ const cleanup = () => {
21
+ if (postExitTimer) {
22
+ clearTimeout(postExitTimer);
23
+ postExitTimer = undefined;
24
+ }
25
+ child.removeListener("error", onError);
26
+ child.removeListener("exit", onExit);
27
+ child.removeListener("close", onClose);
28
+ child.stdout?.removeListener("end", onStdoutEnd);
29
+ child.stderr?.removeListener("end", onStderrEnd);
30
+ };
31
+ const finalize = (code) => {
32
+ if (settled)
33
+ return;
34
+ settled = true;
35
+ cleanup();
36
+ child.stdout?.destroy();
37
+ child.stderr?.destroy();
38
+ resolve(code);
39
+ };
40
+ const maybeFinalizeAfterExit = () => {
41
+ if (!exited || settled)
42
+ return;
43
+ if (stdoutEnded && stderrEnded)
44
+ finalize(exitCode);
45
+ };
46
+ const onStdoutEnd = () => {
47
+ stdoutEnded = true;
48
+ maybeFinalizeAfterExit();
49
+ };
50
+ const onStderrEnd = () => {
51
+ stderrEnded = true;
52
+ maybeFinalizeAfterExit();
53
+ };
54
+ const onError = (err) => {
55
+ if (settled)
56
+ return;
57
+ settled = true;
58
+ cleanup();
59
+ reject(err);
60
+ };
61
+ const onExit = (code) => {
62
+ exited = true;
63
+ exitCode = code;
64
+ maybeFinalizeAfterExit();
65
+ if (!settled) {
66
+ postExitTimer = setTimeout(() => finalize(code), EXIT_STDIO_GRACE_MS);
67
+ }
68
+ };
69
+ const onClose = (code) => {
70
+ finalize(code);
71
+ };
72
+ child.stdout?.once("end", onStdoutEnd);
73
+ child.stderr?.once("end", onStderrEnd);
74
+ child.once("error", onError);
75
+ child.once("exit", onExit);
76
+ child.once("close", onClose);
77
+ });
78
+ }
79
+ //# sourceMappingURL=child-process.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"child-process.js","sourceRoot":"","sources":["../../../src/tools/bash/child-process.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Incrementally tracks streaming bash output with bounded memory.
3
+ *
4
+ * Decodes incoming Buffer chunks with a streaming UTF-8 decoder, keeps only a
5
+ * rolling tail in memory, and spills the full raw output to a temp file when
6
+ * the output exceeds the display limits.
7
+ *
8
+ * Ported from @earendil-works/pi-coding-agent.
9
+ */
10
+ import { type TruncationResult } from "./truncate.js";
11
+ export interface OutputSnapshot {
12
+ content: string;
13
+ truncation: TruncationResult;
14
+ fullOutputPath: string | undefined;
15
+ }
16
+ export interface OutputAccumulatorOptions {
17
+ maxLines?: number;
18
+ maxBytes?: number;
19
+ tempFilePrefix?: string;
20
+ }
21
+ export declare class OutputAccumulator {
22
+ private readonly maxLines;
23
+ private readonly maxBytes;
24
+ private readonly maxRollingBytes;
25
+ private readonly tempFilePrefix;
26
+ private decoder;
27
+ private rawChunks;
28
+ private tailText;
29
+ private tailBytes;
30
+ private tailStartsAtLineBoundary;
31
+ private totalRawBytes;
32
+ private totalDecodedBytes;
33
+ private completedLines;
34
+ private totalLines;
35
+ private currentLineBytes;
36
+ private hasOpenLine;
37
+ private finished;
38
+ private tempFilePath;
39
+ private tempFileStream;
40
+ constructor(options?: OutputAccumulatorOptions);
41
+ append(data: Buffer): void;
42
+ finish(): void;
43
+ snapshot(options?: {
44
+ persistIfTruncated?: boolean;
45
+ }): OutputSnapshot;
46
+ closeTempFile(): Promise<void>;
47
+ getLastLineBytes(): number;
48
+ private appendDecodedText;
49
+ private trimTail;
50
+ private getSnapshotText;
51
+ private shouldUseTempFile;
52
+ private ensureTempFile;
53
+ }
54
+ //# sourceMappingURL=output-accumulator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output-accumulator.d.ts","sourceRoot":"","sources":["../../../src/tools/bash/output-accumulator.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH,OAAO,EAAsD,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAW1G,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,gBAAgB,CAAC;IAC7B,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;CACpC;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IAExC,OAAO,CAAC,OAAO,CAAqB;IACpC,OAAO,CAAC,SAAS,CAAgB;IACjC,OAAO,CAAC,QAAQ,CAAM;IACtB,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,wBAAwB,CAAQ;IACxC,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAAS;IAEzB,OAAO,CAAC,YAAY,CAAqB;IACzC,OAAO,CAAC,cAAc,CAA0B;gBAEpC,OAAO,GAAE,wBAA6B;IAOlD,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAY1B,MAAM,IAAI,IAAI;IAOd,QAAQ,CAAC,OAAO,GAAE;QAAE,kBAAkB,CAAC,EAAE,OAAO,CAAA;KAAO,GAAG,cAAc;IAsBlE,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAmBpC,gBAAgB,IAAI,MAAM;IAI1B,OAAO,CAAC,iBAAiB;IA0BzB,OAAO,CAAC,QAAQ;IAahB,OAAO,CAAC,eAAe;IAMvB,OAAO,CAAC,iBAAiB;IAMzB,OAAO,CAAC,cAAc;CAOvB"}
@@ -0,0 +1,171 @@
1
+ /**
2
+ * Incrementally tracks streaming bash output with bounded memory.
3
+ *
4
+ * Decodes incoming Buffer chunks with a streaming UTF-8 decoder, keeps only a
5
+ * rolling tail in memory, and spills the full raw output to a temp file when
6
+ * the output exceeds the display limits.
7
+ *
8
+ * Ported from @earendil-works/pi-coding-agent.
9
+ */
10
+ import { randomBytes } from "node:crypto";
11
+ import { createWriteStream } from "node:fs";
12
+ import { tmpdir } from "node:os";
13
+ import { join } from "node:path";
14
+ import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, truncateTail } from "./truncate.js";
15
+ function defaultTempFilePath(prefix) {
16
+ const id = randomBytes(8).toString("hex");
17
+ return join(tmpdir(), `${prefix}-${id}.log`);
18
+ }
19
+ function byteLength(text) {
20
+ return Buffer.byteLength(text, "utf-8");
21
+ }
22
+ export class OutputAccumulator {
23
+ maxLines;
24
+ maxBytes;
25
+ maxRollingBytes;
26
+ tempFilePrefix;
27
+ decoder = new TextDecoder();
28
+ rawChunks = [];
29
+ tailText = "";
30
+ tailBytes = 0;
31
+ tailStartsAtLineBoundary = true;
32
+ totalRawBytes = 0;
33
+ totalDecodedBytes = 0;
34
+ completedLines = 0;
35
+ totalLines = 0;
36
+ currentLineBytes = 0;
37
+ hasOpenLine = false;
38
+ finished = false;
39
+ tempFilePath;
40
+ tempFileStream;
41
+ constructor(options = {}) {
42
+ this.maxLines = options.maxLines ?? DEFAULT_MAX_LINES;
43
+ this.maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;
44
+ this.maxRollingBytes = Math.max(this.maxBytes * 2, 1);
45
+ this.tempFilePrefix = options.tempFilePrefix ?? "pi-output";
46
+ }
47
+ append(data) {
48
+ if (this.finished)
49
+ throw new Error("Cannot append to a finished output accumulator");
50
+ this.totalRawBytes += data.length;
51
+ this.appendDecodedText(this.decoder.decode(data, { stream: true }));
52
+ if (this.tempFileStream ?? this.shouldUseTempFile()) {
53
+ this.ensureTempFile();
54
+ this.tempFileStream?.write(data);
55
+ }
56
+ else if (data.length > 0) {
57
+ this.rawChunks.push(data);
58
+ }
59
+ }
60
+ finish() {
61
+ if (this.finished)
62
+ return;
63
+ this.finished = true;
64
+ this.appendDecodedText(this.decoder.decode());
65
+ if (this.shouldUseTempFile())
66
+ this.ensureTempFile();
67
+ }
68
+ snapshot(options = {}) {
69
+ const tailTruncation = truncateTail(this.getSnapshotText(), {
70
+ maxLines: this.maxLines,
71
+ maxBytes: this.maxBytes,
72
+ });
73
+ const truncated = this.totalLines > this.maxLines || this.totalDecodedBytes > this.maxBytes;
74
+ const truncatedBy = truncated
75
+ ? (tailTruncation.truncatedBy ?? (this.totalDecodedBytes > this.maxBytes ? "bytes" : "lines"))
76
+ : null;
77
+ const truncation = {
78
+ ...tailTruncation,
79
+ truncated,
80
+ truncatedBy,
81
+ totalLines: this.totalLines,
82
+ totalBytes: this.totalDecodedBytes,
83
+ maxLines: this.maxLines,
84
+ maxBytes: this.maxBytes,
85
+ };
86
+ if (options.persistIfTruncated === true && truncation.truncated)
87
+ this.ensureTempFile();
88
+ return { content: truncation.content, truncation, fullOutputPath: this.tempFilePath };
89
+ }
90
+ async closeTempFile() {
91
+ if (!this.tempFileStream)
92
+ return;
93
+ const stream = this.tempFileStream;
94
+ this.tempFileStream = undefined;
95
+ await new Promise((resolve, reject) => {
96
+ const onError = (error) => {
97
+ stream.off("finish", onFinish);
98
+ reject(error);
99
+ };
100
+ const onFinish = () => {
101
+ stream.off("error", onError);
102
+ resolve();
103
+ };
104
+ stream.once("error", onError);
105
+ stream.once("finish", onFinish);
106
+ stream.end();
107
+ });
108
+ }
109
+ getLastLineBytes() {
110
+ return this.currentLineBytes;
111
+ }
112
+ appendDecodedText(text) {
113
+ if (text.length === 0)
114
+ return;
115
+ const bytes = byteLength(text);
116
+ this.totalDecodedBytes += bytes;
117
+ this.tailText += text;
118
+ this.tailBytes += bytes;
119
+ if (this.tailBytes > this.maxRollingBytes * 2)
120
+ this.trimTail();
121
+ let newlines = 0;
122
+ let lastNewline = -1;
123
+ for (let i = text.indexOf("\n"); i !== -1; i = text.indexOf("\n", i + 1)) {
124
+ newlines++;
125
+ lastNewline = i;
126
+ }
127
+ if (newlines === 0) {
128
+ this.currentLineBytes += bytes;
129
+ this.hasOpenLine = true;
130
+ }
131
+ else {
132
+ this.completedLines += newlines;
133
+ const tail = text.slice(lastNewline + 1);
134
+ this.currentLineBytes = byteLength(tail);
135
+ this.hasOpenLine = tail.length > 0;
136
+ }
137
+ this.totalLines = this.completedLines + (this.hasOpenLine ? 1 : 0);
138
+ }
139
+ trimTail() {
140
+ const buffer = Buffer.from(this.tailText, "utf-8");
141
+ if (buffer.length <= this.maxRollingBytes) {
142
+ this.tailBytes = buffer.length;
143
+ return;
144
+ }
145
+ let start = buffer.length - this.maxRollingBytes;
146
+ while (start < buffer.length && ((buffer[start] ?? 0) & 0xc0) === 0x80)
147
+ start++;
148
+ this.tailStartsAtLineBoundary = start === 0 ? this.tailStartsAtLineBoundary : (buffer[start - 1] ?? 0) === 0x0a;
149
+ this.tailText = buffer.subarray(start).toString("utf-8");
150
+ this.tailBytes = byteLength(this.tailText);
151
+ }
152
+ getSnapshotText() {
153
+ if (this.tailStartsAtLineBoundary)
154
+ return this.tailText;
155
+ const firstNewline = this.tailText.indexOf("\n");
156
+ return firstNewline === -1 ? this.tailText : this.tailText.slice(firstNewline + 1);
157
+ }
158
+ shouldUseTempFile() {
159
+ return (this.totalRawBytes > this.maxBytes || this.totalDecodedBytes > this.maxBytes || this.totalLines > this.maxLines);
160
+ }
161
+ ensureTempFile() {
162
+ if (this.tempFilePath)
163
+ return;
164
+ this.tempFilePath = defaultTempFilePath(this.tempFilePrefix);
165
+ this.tempFileStream = createWriteStream(this.tempFilePath);
166
+ for (const chunk of this.rawChunks)
167
+ this.tempFileStream.write(chunk);
168
+ this.rawChunks = [];
169
+ }
170
+ }
171
+ //# sourceMappingURL=output-accumulator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output-accumulator.js","sourceRoot":"","sources":["../../../src/tools/bash/output-accumulator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Shell configuration, environment helpers, and process-kill utilities.
3
+ *
4
+ * Ported from @earendil-works/pi-coding-agent.
5
+ * Simplification: getShellEnv() returns process.env as-is without prepending a
6
+ * pi-specific bin directory.
7
+ */
8
+ /**
9
+ * Resolve shell configuration based on platform and an optional explicit shell path.
10
+ *
11
+ * Resolution order:
12
+ * 1. User-specified shellPath
13
+ * 2. On Windows: Git Bash in known locations, then bash on PATH
14
+ * 3. On Unix: /bin/bash, then bash on PATH, then fallback to sh
15
+ */
16
+ export declare function getShellConfig(customShellPath?: string): {
17
+ shell: string;
18
+ args: string[];
19
+ };
20
+ /** Return the current process environment for spawned commands. */
21
+ export declare function getShellEnv(): NodeJS.ProcessEnv;
22
+ export declare function trackDetachedChildPid(pid: number): void;
23
+ export declare function untrackDetachedChildPid(pid: number): void;
24
+ /** Kill a process and its entire process group (cross-platform). */
25
+ export declare function killProcessTree(pid: number): void;
26
+ //# sourceMappingURL=shell.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shell.d.ts","sourceRoot":"","sources":["../../../src/tools/bash/shell.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAmCH;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CA+B1F;AAED,mEAAmE;AACnE,wBAAgB,WAAW,IAAI,MAAM,CAAC,UAAU,CAE/C;AAQD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAEvD;AAED,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAEzD;AAED,oEAAoE;AACpE,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAsBjD"}