edge-pi-cli 0.1.4 → 0.1.5

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.
@@ -133,33 +133,39 @@ export async function executeBashCommand(command, options = {}) {
133
133
  child.on("close", (code, sig) => {
134
134
  if (options.signal)
135
135
  options.signal.removeEventListener("abort", onAbort);
136
- if (tempFileStream)
137
- tempFileStream.end();
138
- const fullOutput = Buffer.concat(chunks).toString("utf-8");
139
- const truncation = truncateTail(fullOutput, { maxBytes, maxLines });
140
- let outputText = truncation.content;
141
- if (cancelled || sig) {
136
+ const resolveResult = () => {
137
+ const fullOutput = Buffer.concat(chunks).toString("utf-8");
138
+ const truncation = truncateTail(fullOutput, { maxBytes, maxLines });
139
+ let outputText = truncation.content;
140
+ if (cancelled || sig) {
141
+ resolve({
142
+ output: outputText,
143
+ exitCode: code === null ? undefined : code,
144
+ cancelled: true,
145
+ truncated: truncation.truncated,
146
+ fullOutputPath: tempFilePath,
147
+ });
148
+ return;
149
+ }
150
+ if (truncation.truncated) {
151
+ const startLine = truncation.totalLines - truncation.outputLines + 1;
152
+ const endLine = truncation.totalLines;
153
+ outputText += `\n\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines} (${formatSize(maxBytes)} limit). Full output: ${tempFilePath}]`;
154
+ }
142
155
  resolve({
143
156
  output: outputText,
144
157
  exitCode: code === null ? undefined : code,
145
- cancelled: true,
158
+ cancelled: false,
146
159
  truncated: truncation.truncated,
147
160
  fullOutputPath: tempFilePath,
148
161
  });
149
- return;
162
+ };
163
+ if (tempFileStream) {
164
+ tempFileStream.end(resolveResult);
150
165
  }
151
- if (truncation.truncated) {
152
- const startLine = truncation.totalLines - truncation.outputLines + 1;
153
- const endLine = truncation.totalLines;
154
- outputText += `\n\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines} (${formatSize(maxBytes)} limit). Full output: ${tempFilePath}]`;
166
+ else {
167
+ resolveResult();
155
168
  }
156
- resolve({
157
- output: outputText,
158
- exitCode: code === null ? undefined : code,
159
- cancelled: false,
160
- truncated: truncation.truncated,
161
- fullOutputPath: tempFilePath,
162
- });
163
169
  });
164
170
  });
165
171
  }
@@ -1 +1 @@
1
- {"version":3,"file":"bash-executor.js","sourceRoot":"","sources":["../../src/utils/bash-executor.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn } from \"node:child_process\";\nimport { randomBytes } from \"node:crypto\";\nimport { createWriteStream } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\n\nconst DEFAULT_MAX_LINES = 2000;\nconst DEFAULT_MAX_BYTES = 50 * 1024;\n\nexport function formatSize(bytes: number): string {\n\tif (bytes < 1024) return `${bytes}B`;\n\tif (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;\n\treturn `${(bytes / (1024 * 1024)).toFixed(1)}MB`;\n}\n\nexport function truncateTail(\n\tcontent: string,\n\toptions: { maxLines?: number; maxBytes?: number } = {},\n): {\n\tcontent: string;\n\ttruncated: boolean;\n\ttruncatedBy: \"lines\" | \"bytes\" | null;\n\ttotalLines: number;\n\ttotalBytes: number;\n\toutputLines: number;\n\toutputBytes: number;\n} {\n\tconst maxLines = options.maxLines ?? DEFAULT_MAX_LINES;\n\tconst maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;\n\n\tconst totalBytes = Buffer.byteLength(content, \"utf-8\");\n\tconst lines = content.split(\"\\n\");\n\tconst totalLines = lines.length;\n\n\tif (totalLines <= maxLines && totalBytes <= maxBytes) {\n\t\treturn {\n\t\t\tcontent,\n\t\t\ttruncated: false,\n\t\t\ttruncatedBy: null,\n\t\t\ttotalLines,\n\t\t\ttotalBytes,\n\t\t\toutputLines: totalLines,\n\t\t\toutputBytes: totalBytes,\n\t\t};\n\t}\n\n\tconst outLines: string[] = [];\n\tlet outBytes = 0;\n\tlet truncatedBy: \"lines\" | \"bytes\" = \"lines\";\n\n\tfor (let i = lines.length - 1; i >= 0 && outLines.length < maxLines; i--) {\n\t\tconst line = lines[i];\n\t\tconst lineBytes = Buffer.byteLength(line, \"utf-8\") + (outLines.length > 0 ? 1 : 0);\n\t\tif (outBytes + lineBytes > maxBytes) {\n\t\t\ttruncatedBy = \"bytes\";\n\t\t\tbreak;\n\t\t}\n\t\toutLines.unshift(line);\n\t\toutBytes += lineBytes;\n\t}\n\n\tconst out = outLines.join(\"\\n\");\n\treturn {\n\t\tcontent: out,\n\t\ttruncated: true,\n\t\ttruncatedBy,\n\t\ttotalLines,\n\t\ttotalBytes,\n\t\toutputLines: outLines.length,\n\t\toutputBytes: Buffer.byteLength(out, \"utf-8\"),\n\t};\n}\n\nexport interface BashExecutionResult {\n\toutput: string;\n\texitCode: number | undefined;\n\tcancelled: boolean;\n\ttruncated: boolean;\n\tfullOutputPath?: string;\n}\n\nexport interface ExecuteBashCommandOptions {\n\tcwd?: string;\n\t/** Kill the process tree on abort. */\n\tsignal?: AbortSignal;\n\t/** Called for each raw output chunk (stdout and stderr). */\n\tonChunk?: (chunk: string) => void;\n\t/** Max captured output. Defaults to edge-pi tool limits. */\n\tmaxLines?: number;\n\tmaxBytes?: number;\n}\n\nfunction getTempFilePath(): string {\n\tconst id = randomBytes(8).toString(\"hex\");\n\treturn join(tmpdir(), `edge-pi-cli-inline-bash-${id}.log`);\n}\n\nfunction killProcessTree(pid: number): void {\n\ttry {\n\t\tprocess.kill(-pid, \"SIGTERM\");\n\t} catch {\n\t\ttry {\n\t\t\tprocess.kill(pid, \"SIGTERM\");\n\t\t} catch {\n\t\t\t// ignore\n\t\t}\n\t}\n}\n\nexport async function executeBashCommand(\n\tcommand: string,\n\toptions: ExecuteBashCommandOptions = {},\n): Promise<BashExecutionResult> {\n\tconst cwd = options.cwd ?? process.cwd();\n\tconst maxLines = options.maxLines ?? DEFAULT_MAX_LINES;\n\tconst maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;\n\n\treturn new Promise<BashExecutionResult>((resolve, reject) => {\n\t\tconst child = spawn(\"bash\", [\"-c\", command], {\n\t\t\tcwd,\n\t\t\tdetached: true,\n\t\t\tenv: { ...process.env },\n\t\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t\t});\n\n\t\tlet cancelled = false;\n\n\t\tlet tempFilePath: string | undefined;\n\t\tlet tempFileStream: ReturnType<typeof createWriteStream> | undefined;\n\t\tlet totalBytes = 0;\n\n\t\tconst chunks: Buffer[] = [];\n\t\tlet chunksBytes = 0;\n\t\tconst maxChunksBytes = maxBytes * 2;\n\n\t\tconst handleData = (data: Buffer) => {\n\t\t\toptions.onChunk?.(data.toString(\"utf-8\"));\n\n\t\t\ttotalBytes += data.length;\n\n\t\t\tif (totalBytes > maxBytes && !tempFilePath) {\n\t\t\t\ttempFilePath = getTempFilePath();\n\t\t\t\ttempFileStream = createWriteStream(tempFilePath);\n\t\t\t\tfor (const chunk of chunks) {\n\t\t\t\t\ttempFileStream.write(chunk);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (tempFileStream) {\n\t\t\t\ttempFileStream.write(data);\n\t\t\t}\n\n\t\t\tchunks.push(data);\n\t\t\tchunksBytes += data.length;\n\n\t\t\twhile (chunksBytes > maxChunksBytes && chunks.length > 1) {\n\t\t\t\tconst removed = chunks.shift();\n\t\t\t\tif (removed) chunksBytes -= removed.length;\n\t\t\t}\n\t\t};\n\n\t\tchild.stdout?.on(\"data\", handleData);\n\t\tchild.stderr?.on(\"data\", handleData);\n\n\t\tconst onAbort = () => {\n\t\t\tcancelled = true;\n\t\t\tif (child.pid) {\n\t\t\t\tkillProcessTree(child.pid);\n\t\t\t}\n\t\t};\n\n\t\tif (options.signal) {\n\t\t\tif (options.signal.aborted) {\n\t\t\t\tonAbort();\n\t\t\t} else {\n\t\t\t\toptions.signal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t}\n\t\t}\n\n\t\tchild.on(\"error\", (err) => {\n\t\t\tif (options.signal) options.signal.removeEventListener(\"abort\", onAbort);\n\t\t\treject(err);\n\t\t});\n\n\t\tchild.on(\"close\", (code, sig) => {\n\t\t\tif (options.signal) options.signal.removeEventListener(\"abort\", onAbort);\n\t\t\tif (tempFileStream) tempFileStream.end();\n\n\t\t\tconst fullOutput = Buffer.concat(chunks).toString(\"utf-8\");\n\t\t\tconst truncation = truncateTail(fullOutput, { maxBytes, maxLines });\n\n\t\t\tlet outputText = truncation.content;\n\t\t\tif (cancelled || sig) {\n\t\t\t\tresolve({\n\t\t\t\t\toutput: outputText,\n\t\t\t\t\texitCode: code === null ? undefined : code,\n\t\t\t\t\tcancelled: true,\n\t\t\t\t\ttruncated: truncation.truncated,\n\t\t\t\t\tfullOutputPath: tempFilePath,\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (truncation.truncated) {\n\t\t\t\tconst startLine = truncation.totalLines - truncation.outputLines + 1;\n\t\t\t\tconst endLine = truncation.totalLines;\n\t\t\t\toutputText += `\\n\\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines} (${formatSize(maxBytes)} limit). Full output: ${tempFilePath}]`;\n\t\t\t}\n\n\t\t\tresolve({\n\t\t\t\toutput: outputText,\n\t\t\t\texitCode: code === null ? undefined : code,\n\t\t\t\tcancelled: false,\n\t\t\t\ttruncated: truncation.truncated,\n\t\t\t\tfullOutputPath: tempFilePath,\n\t\t\t});\n\t\t});\n\t});\n}\n"]}
1
+ {"version":3,"file":"bash-executor.js","sourceRoot":"","sources":["../../src/utils/bash-executor.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn } from \"node:child_process\";\nimport { randomBytes } from \"node:crypto\";\nimport { createWriteStream } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\n\nconst DEFAULT_MAX_LINES = 2000;\nconst DEFAULT_MAX_BYTES = 50 * 1024;\n\nexport function formatSize(bytes: number): string {\n\tif (bytes < 1024) return `${bytes}B`;\n\tif (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;\n\treturn `${(bytes / (1024 * 1024)).toFixed(1)}MB`;\n}\n\nexport function truncateTail(\n\tcontent: string,\n\toptions: { maxLines?: number; maxBytes?: number } = {},\n): {\n\tcontent: string;\n\ttruncated: boolean;\n\ttruncatedBy: \"lines\" | \"bytes\" | null;\n\ttotalLines: number;\n\ttotalBytes: number;\n\toutputLines: number;\n\toutputBytes: number;\n} {\n\tconst maxLines = options.maxLines ?? DEFAULT_MAX_LINES;\n\tconst maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;\n\n\tconst totalBytes = Buffer.byteLength(content, \"utf-8\");\n\tconst lines = content.split(\"\\n\");\n\tconst totalLines = lines.length;\n\n\tif (totalLines <= maxLines && totalBytes <= maxBytes) {\n\t\treturn {\n\t\t\tcontent,\n\t\t\ttruncated: false,\n\t\t\ttruncatedBy: null,\n\t\t\ttotalLines,\n\t\t\ttotalBytes,\n\t\t\toutputLines: totalLines,\n\t\t\toutputBytes: totalBytes,\n\t\t};\n\t}\n\n\tconst outLines: string[] = [];\n\tlet outBytes = 0;\n\tlet truncatedBy: \"lines\" | \"bytes\" = \"lines\";\n\n\tfor (let i = lines.length - 1; i >= 0 && outLines.length < maxLines; i--) {\n\t\tconst line = lines[i];\n\t\tconst lineBytes = Buffer.byteLength(line, \"utf-8\") + (outLines.length > 0 ? 1 : 0);\n\t\tif (outBytes + lineBytes > maxBytes) {\n\t\t\ttruncatedBy = \"bytes\";\n\t\t\tbreak;\n\t\t}\n\t\toutLines.unshift(line);\n\t\toutBytes += lineBytes;\n\t}\n\n\tconst out = outLines.join(\"\\n\");\n\treturn {\n\t\tcontent: out,\n\t\ttruncated: true,\n\t\ttruncatedBy,\n\t\ttotalLines,\n\t\ttotalBytes,\n\t\toutputLines: outLines.length,\n\t\toutputBytes: Buffer.byteLength(out, \"utf-8\"),\n\t};\n}\n\nexport interface BashExecutionResult {\n\toutput: string;\n\texitCode: number | undefined;\n\tcancelled: boolean;\n\ttruncated: boolean;\n\tfullOutputPath?: string;\n}\n\nexport interface ExecuteBashCommandOptions {\n\tcwd?: string;\n\t/** Kill the process tree on abort. */\n\tsignal?: AbortSignal;\n\t/** Called for each raw output chunk (stdout and stderr). */\n\tonChunk?: (chunk: string) => void;\n\t/** Max captured output. Defaults to edge-pi tool limits. */\n\tmaxLines?: number;\n\tmaxBytes?: number;\n}\n\nfunction getTempFilePath(): string {\n\tconst id = randomBytes(8).toString(\"hex\");\n\treturn join(tmpdir(), `edge-pi-cli-inline-bash-${id}.log`);\n}\n\nfunction killProcessTree(pid: number): void {\n\ttry {\n\t\tprocess.kill(-pid, \"SIGTERM\");\n\t} catch {\n\t\ttry {\n\t\t\tprocess.kill(pid, \"SIGTERM\");\n\t\t} catch {\n\t\t\t// ignore\n\t\t}\n\t}\n}\n\nexport async function executeBashCommand(\n\tcommand: string,\n\toptions: ExecuteBashCommandOptions = {},\n): Promise<BashExecutionResult> {\n\tconst cwd = options.cwd ?? process.cwd();\n\tconst maxLines = options.maxLines ?? DEFAULT_MAX_LINES;\n\tconst maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;\n\n\treturn new Promise<BashExecutionResult>((resolve, reject) => {\n\t\tconst child = spawn(\"bash\", [\"-c\", command], {\n\t\t\tcwd,\n\t\t\tdetached: true,\n\t\t\tenv: { ...process.env },\n\t\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t\t});\n\n\t\tlet cancelled = false;\n\n\t\tlet tempFilePath: string | undefined;\n\t\tlet tempFileStream: ReturnType<typeof createWriteStream> | undefined;\n\t\tlet totalBytes = 0;\n\n\t\tconst chunks: Buffer[] = [];\n\t\tlet chunksBytes = 0;\n\t\tconst maxChunksBytes = maxBytes * 2;\n\n\t\tconst handleData = (data: Buffer) => {\n\t\t\toptions.onChunk?.(data.toString(\"utf-8\"));\n\n\t\t\ttotalBytes += data.length;\n\n\t\t\tif (totalBytes > maxBytes && !tempFilePath) {\n\t\t\t\ttempFilePath = getTempFilePath();\n\t\t\t\ttempFileStream = createWriteStream(tempFilePath);\n\t\t\t\tfor (const chunk of chunks) {\n\t\t\t\t\ttempFileStream.write(chunk);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (tempFileStream) {\n\t\t\t\ttempFileStream.write(data);\n\t\t\t}\n\n\t\t\tchunks.push(data);\n\t\t\tchunksBytes += data.length;\n\n\t\t\twhile (chunksBytes > maxChunksBytes && chunks.length > 1) {\n\t\t\t\tconst removed = chunks.shift();\n\t\t\t\tif (removed) chunksBytes -= removed.length;\n\t\t\t}\n\t\t};\n\n\t\tchild.stdout?.on(\"data\", handleData);\n\t\tchild.stderr?.on(\"data\", handleData);\n\n\t\tconst onAbort = () => {\n\t\t\tcancelled = true;\n\t\t\tif (child.pid) {\n\t\t\t\tkillProcessTree(child.pid);\n\t\t\t}\n\t\t};\n\n\t\tif (options.signal) {\n\t\t\tif (options.signal.aborted) {\n\t\t\t\tonAbort();\n\t\t\t} else {\n\t\t\t\toptions.signal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t}\n\t\t}\n\n\t\tchild.on(\"error\", (err) => {\n\t\t\tif (options.signal) options.signal.removeEventListener(\"abort\", onAbort);\n\t\t\treject(err);\n\t\t});\n\n\t\tchild.on(\"close\", (code, sig) => {\n\t\t\tif (options.signal) options.signal.removeEventListener(\"abort\", onAbort);\n\t\t\tconst resolveResult = () => {\n\t\t\t\tconst fullOutput = Buffer.concat(chunks).toString(\"utf-8\");\n\t\t\t\tconst truncation = truncateTail(fullOutput, { maxBytes, maxLines });\n\n\t\t\t\tlet outputText = truncation.content;\n\t\t\t\tif (cancelled || sig) {\n\t\t\t\t\tresolve({\n\t\t\t\t\t\toutput: outputText,\n\t\t\t\t\t\texitCode: code === null ? undefined : code,\n\t\t\t\t\t\tcancelled: true,\n\t\t\t\t\t\ttruncated: truncation.truncated,\n\t\t\t\t\t\tfullOutputPath: tempFilePath,\n\t\t\t\t\t});\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (truncation.truncated) {\n\t\t\t\t\tconst startLine = truncation.totalLines - truncation.outputLines + 1;\n\t\t\t\t\tconst endLine = truncation.totalLines;\n\t\t\t\t\toutputText += `\\n\\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines} (${formatSize(maxBytes)} limit). Full output: ${tempFilePath}]`;\n\t\t\t\t}\n\n\t\t\t\tresolve({\n\t\t\t\t\toutput: outputText,\n\t\t\t\t\texitCode: code === null ? undefined : code,\n\t\t\t\t\tcancelled: false,\n\t\t\t\t\ttruncated: truncation.truncated,\n\t\t\t\t\tfullOutputPath: tempFilePath,\n\t\t\t\t});\n\t\t\t};\n\n\t\t\tif (tempFileStream) {\n\t\t\t\ttempFileStream.end(resolveResult);\n\t\t\t} else {\n\t\t\t\tresolveResult();\n\t\t\t}\n\t\t});\n\t});\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "edge-pi-cli",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "CLI for the edge-pi coding agent SDK",
5
5
  "type": "module",
6
6
  "bin": {
@@ -27,7 +27,7 @@
27
27
  "@ai-sdk/openai": "^3.0.26",
28
28
  "@mariozechner/pi-tui": "^0.50.9",
29
29
  "chalk": "^5.5.0",
30
- "edge-pi": "^0.1.4",
30
+ "edge-pi": "^0.1.5",
31
31
  "proper-lockfile": "^4.1.2",
32
32
  "yaml": "^2.7.1"
33
33
  },