gsd-pi 2.8.0 → 2.8.2
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/dist/loader.js +5 -0
- package/node_modules/@gsd/pi-coding-agent/dist/config.d.ts +2 -0
- package/node_modules/@gsd/pi-coding-agent/dist/config.d.ts.map +1 -1
- package/node_modules/@gsd/pi-coding-agent/dist/config.js +4 -0
- package/node_modules/@gsd/pi-coding-agent/dist/config.js.map +1 -1
- package/node_modules/@gsd/pi-coding-agent/dist/core/artifact-manager.d.ts +52 -0
- package/node_modules/@gsd/pi-coding-agent/dist/core/artifact-manager.d.ts.map +1 -0
- package/node_modules/@gsd/pi-coding-agent/dist/core/artifact-manager.js +117 -0
- package/node_modules/@gsd/pi-coding-agent/dist/core/artifact-manager.js.map +1 -0
- package/node_modules/@gsd/pi-coding-agent/dist/core/bash-executor.js +2 -2
- package/node_modules/@gsd/pi-coding-agent/dist/core/bash-executor.js.map +1 -1
- package/node_modules/@gsd/pi-coding-agent/dist/core/blob-store.d.ts +31 -0
- package/node_modules/@gsd/pi-coding-agent/dist/core/blob-store.d.ts.map +1 -0
- package/node_modules/@gsd/pi-coding-agent/dist/core/blob-store.js +97 -0
- package/node_modules/@gsd/pi-coding-agent/dist/core/blob-store.js.map +1 -0
- package/node_modules/@gsd/pi-coding-agent/dist/core/session-manager.d.ts +1 -0
- package/node_modules/@gsd/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
- package/node_modules/@gsd/pi-coding-agent/dist/core/session-manager.js +112 -3
- package/node_modules/@gsd/pi-coding-agent/dist/core/session-manager.js.map +1 -1
- package/node_modules/@gsd/pi-coding-agent/dist/core/tools/bash.d.ts +4 -0
- package/node_modules/@gsd/pi-coding-agent/dist/core/tools/bash.d.ts.map +1 -1
- package/node_modules/@gsd/pi-coding-agent/dist/core/tools/bash.js +32 -22
- package/node_modules/@gsd/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
- package/node_modules/@gsd/pi-coding-agent/dist/core/tools/path-utils.d.ts +1 -1
- package/node_modules/@gsd/pi-coding-agent/dist/core/tools/path-utils.d.ts.map +1 -1
- package/node_modules/@gsd/pi-coding-agent/dist/core/tools/path-utils.js +13 -2
- package/node_modules/@gsd/pi-coding-agent/dist/core/tools/path-utils.js.map +1 -1
- package/node_modules/@gsd/pi-coding-agent/dist/core/tools/path-utils.test.d.ts +2 -0
- package/node_modules/@gsd/pi-coding-agent/dist/core/tools/path-utils.test.d.ts.map +1 -0
- package/node_modules/@gsd/pi-coding-agent/dist/core/tools/path-utils.test.js +57 -0
- package/node_modules/@gsd/pi-coding-agent/dist/core/tools/path-utils.test.js.map +1 -0
- package/node_modules/@gsd/pi-coding-agent/dist/index.d.ts +3 -1
- package/node_modules/@gsd/pi-coding-agent/dist/index.d.ts.map +1 -1
- package/node_modules/@gsd/pi-coding-agent/dist/index.js +4 -1
- package/node_modules/@gsd/pi-coding-agent/dist/index.js.map +1 -1
- package/node_modules/@gsd/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/node_modules/@gsd/pi-coding-agent/dist/modes/interactive/interactive-mode.js +7 -5
- package/node_modules/@gsd/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/node_modules/@gsd/pi-coding-agent/dist/utils/shell.d.ts +7 -0
- package/node_modules/@gsd/pi-coding-agent/dist/utils/shell.d.ts.map +1 -1
- package/node_modules/@gsd/pi-coding-agent/dist/utils/shell.js +11 -0
- package/node_modules/@gsd/pi-coding-agent/dist/utils/shell.js.map +1 -1
- package/node_modules/@gsd/pi-coding-agent/src/config.ts +5 -0
- package/node_modules/@gsd/pi-coding-agent/src/core/artifact-manager.ts +125 -0
- package/node_modules/@gsd/pi-coding-agent/src/core/bash-executor.ts +2 -2
- package/node_modules/@gsd/pi-coding-agent/src/core/blob-store.ts +106 -0
- package/node_modules/@gsd/pi-coding-agent/src/core/session-manager.ts +119 -3
- package/node_modules/@gsd/pi-coding-agent/src/core/tools/bash.ts +35 -22
- package/node_modules/@gsd/pi-coding-agent/src/core/tools/path-utils.test.ts +66 -0
- package/node_modules/@gsd/pi-coding-agent/src/core/tools/path-utils.ts +14 -2
- package/node_modules/@gsd/pi-coding-agent/src/index.ts +4 -1
- package/node_modules/@gsd/pi-coding-agent/src/modes/interactive/interactive-mode.ts +6 -4
- package/node_modules/@gsd/pi-coding-agent/src/utils/shell.ts +11 -0
- package/package.json +6 -1
- package/packages/pi-coding-agent/dist/config.d.ts +2 -0
- package/packages/pi-coding-agent/dist/config.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/config.js +4 -0
- package/packages/pi-coding-agent/dist/config.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/artifact-manager.d.ts +52 -0
- package/packages/pi-coding-agent/dist/core/artifact-manager.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/artifact-manager.js +117 -0
- package/packages/pi-coding-agent/dist/core/artifact-manager.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/bash-executor.js +2 -2
- package/packages/pi-coding-agent/dist/core/bash-executor.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/blob-store.d.ts +31 -0
- package/packages/pi-coding-agent/dist/core/blob-store.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/blob-store.js +97 -0
- package/packages/pi-coding-agent/dist/core/blob-store.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager.d.ts +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager.js +112 -3
- package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/bash.d.ts +4 -0
- package/packages/pi-coding-agent/dist/core/tools/bash.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/bash.js +32 -22
- package/packages/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/path-utils.d.ts +1 -1
- package/packages/pi-coding-agent/dist/core/tools/path-utils.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/path-utils.js +13 -2
- package/packages/pi-coding-agent/dist/core/tools/path-utils.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/path-utils.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/tools/path-utils.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/tools/path-utils.test.js +57 -0
- package/packages/pi-coding-agent/dist/core/tools/path-utils.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/index.d.ts +3 -1
- package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/index.js +4 -1
- package/packages/pi-coding-agent/dist/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +7 -5
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/utils/shell.d.ts +7 -0
- package/packages/pi-coding-agent/dist/utils/shell.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/utils/shell.js +11 -0
- package/packages/pi-coding-agent/dist/utils/shell.js.map +1 -1
- package/packages/pi-coding-agent/src/config.ts +5 -0
- package/packages/pi-coding-agent/src/core/artifact-manager.ts +125 -0
- package/packages/pi-coding-agent/src/core/bash-executor.ts +2 -2
- package/packages/pi-coding-agent/src/core/blob-store.ts +106 -0
- package/packages/pi-coding-agent/src/core/session-manager.ts +119 -3
- package/packages/pi-coding-agent/src/core/tools/bash.ts +35 -22
- package/packages/pi-coding-agent/src/core/tools/path-utils.test.ts +66 -0
- package/packages/pi-coding-agent/src/core/tools/path-utils.ts +14 -2
- package/packages/pi-coding-agent/src/index.ts +4 -1
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +6 -4
- package/packages/pi-coding-agent/src/utils/shell.ts +11 -0
- package/src/resources/extensions/bg-shell/index.ts +2 -1
- package/src/resources/extensions/browser-tools/lifecycle.ts +6 -1
- package/src/resources/extensions/gsd/auto.ts +92 -49
- package/src/resources/extensions/gsd/dispatch-guard.ts +65 -0
- package/src/resources/extensions/gsd/docs/preferences-reference.md +76 -0
- package/src/resources/extensions/gsd/exit-command.ts +18 -0
- package/src/resources/extensions/gsd/files.ts +9 -40
- package/src/resources/extensions/gsd/git-service.ts +62 -17
- package/src/resources/extensions/gsd/gitignore.ts +28 -0
- package/src/resources/extensions/gsd/guided-flow.ts +49 -11
- package/src/resources/extensions/gsd/index.ts +111 -16
- package/src/resources/extensions/gsd/preferences.ts +8 -0
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +2 -2
- package/src/resources/extensions/gsd/prompts/complete-slice.md +3 -3
- package/src/resources/extensions/gsd/prompts/discuss.md +27 -2
- package/src/resources/extensions/gsd/prompts/execute-task.md +2 -2
- package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +3 -3
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +2 -2
- package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +3 -3
- package/src/resources/extensions/gsd/prompts/replan-slice.md +2 -2
- package/src/resources/extensions/gsd/prompts/research-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/research-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/run-uat.md +4 -4
- package/src/resources/extensions/gsd/roadmap-slices.ts +50 -0
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +102 -0
- package/src/resources/extensions/gsd/tests/exit-command.test.ts +50 -0
- package/src/resources/extensions/gsd/tests/git-service.test.ts +116 -39
- package/src/resources/extensions/gsd/tests/reassess-prompt.test.ts +5 -5
- package/src/resources/extensions/gsd/tests/replan-slice.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/roadmap-slices.test.ts +59 -0
- package/src/resources/extensions/gsd/tests/run-uat.test.ts +2 -4
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +122 -0
- package/src/resources/extensions/ttsr/index.ts +163 -0
- package/src/resources/extensions/ttsr/rule-loader.ts +121 -0
- package/src/resources/extensions/ttsr/ttsr-interrupt.md +6 -0
- package/src/resources/extensions/ttsr/ttsr-manager.ts +344 -0
|
@@ -6,8 +6,9 @@ import { join } from "node:path";
|
|
|
6
6
|
import type { AgentTool } from "@gsd/pi-agent-core";
|
|
7
7
|
import { type Static, Type } from "@sinclair/typebox";
|
|
8
8
|
import { spawn } from "child_process";
|
|
9
|
-
import { getShellConfig, getShellEnv, killProcessTree } from "../../utils/shell.js";
|
|
9
|
+
import { getShellConfig, getShellEnv, killProcessTree, sanitizeCommand } from "../../utils/shell.js";
|
|
10
10
|
import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize, type TruncationResult, truncateTail } from "./truncate.js";
|
|
11
|
+
import type { ArtifactManager } from "../artifact-manager.js";
|
|
11
12
|
|
|
12
13
|
// Cached Win32 FFI handles for restoring VT input after child processes
|
|
13
14
|
let _vtHandles: { GetConsoleMode: any; SetConsoleMode: any; handle: any } | null = null;
|
|
@@ -51,6 +52,7 @@ export type BashToolInput = Static<typeof bashSchema>;
|
|
|
51
52
|
export interface BashToolDetails {
|
|
52
53
|
truncation?: TruncationResult;
|
|
53
54
|
fullOutputPath?: string;
|
|
55
|
+
artifactId?: string;
|
|
54
56
|
}
|
|
55
57
|
|
|
56
58
|
/**
|
|
@@ -187,12 +189,15 @@ export interface BashToolOptions {
|
|
|
187
189
|
commandPrefix?: string;
|
|
188
190
|
/** Hook to adjust command, cwd, or env before execution */
|
|
189
191
|
spawnHook?: BashSpawnHook;
|
|
192
|
+
/** Session-scoped artifact storage. When provided, spills to artifact files instead of temp files. */
|
|
193
|
+
artifactManager?: ArtifactManager;
|
|
190
194
|
}
|
|
191
195
|
|
|
192
196
|
export function createBashTool(cwd: string, options?: BashToolOptions): AgentTool<typeof bashSchema> {
|
|
193
197
|
const ops = options?.operations ?? defaultBashOperations;
|
|
194
198
|
const commandPrefix = options?.commandPrefix;
|
|
195
199
|
const spawnHook = options?.spawnHook;
|
|
200
|
+
const artifactManager = options?.artifactManager;
|
|
196
201
|
|
|
197
202
|
return {
|
|
198
203
|
name: "bash",
|
|
@@ -206,13 +211,14 @@ export function createBashTool(cwd: string, options?: BashToolOptions): AgentToo
|
|
|
206
211
|
onUpdate?,
|
|
207
212
|
) => {
|
|
208
213
|
// Apply command prefix if configured (e.g., "shopt -s expand_aliases" for alias support)
|
|
209
|
-
const resolvedCommand = commandPrefix ? `${commandPrefix}\n${command}` : command;
|
|
214
|
+
const resolvedCommand = sanitizeCommand(commandPrefix ? `${commandPrefix}\n${command}` : command);
|
|
210
215
|
const spawnContext = resolveSpawnContext(resolvedCommand, cwd, spawnHook);
|
|
211
216
|
|
|
212
217
|
return new Promise((resolve, reject) => {
|
|
213
|
-
// We'll stream to a
|
|
214
|
-
let
|
|
215
|
-
let
|
|
218
|
+
// We'll stream to a file if output gets large
|
|
219
|
+
let spillFilePath: string | undefined;
|
|
220
|
+
let spillArtifactId: string | undefined;
|
|
221
|
+
let spillFileStream: ReturnType<typeof createWriteStream> | undefined;
|
|
216
222
|
let totalBytes = 0;
|
|
217
223
|
|
|
218
224
|
// Keep a rolling buffer of the last chunk for tail truncation
|
|
@@ -224,19 +230,25 @@ export function createBashTool(cwd: string, options?: BashToolOptions): AgentToo
|
|
|
224
230
|
const handleData = (data: Buffer) => {
|
|
225
231
|
totalBytes += data.length;
|
|
226
232
|
|
|
227
|
-
// Start writing to
|
|
228
|
-
if (totalBytes > DEFAULT_MAX_BYTES && !
|
|
229
|
-
|
|
230
|
-
|
|
233
|
+
// Start writing to file once we exceed the threshold
|
|
234
|
+
if (totalBytes > DEFAULT_MAX_BYTES && !spillFilePath) {
|
|
235
|
+
if (artifactManager) {
|
|
236
|
+
const allocated = artifactManager.allocatePath("bash");
|
|
237
|
+
spillFilePath = allocated.path;
|
|
238
|
+
spillArtifactId = allocated.id;
|
|
239
|
+
} else {
|
|
240
|
+
spillFilePath = getTempFilePath();
|
|
241
|
+
}
|
|
242
|
+
spillFileStream = createWriteStream(spillFilePath);
|
|
231
243
|
// Write all buffered chunks to the file
|
|
232
244
|
for (const chunk of chunks) {
|
|
233
|
-
|
|
245
|
+
spillFileStream.write(chunk);
|
|
234
246
|
}
|
|
235
247
|
}
|
|
236
248
|
|
|
237
249
|
// Write to temp file if we have one
|
|
238
|
-
if (
|
|
239
|
-
|
|
250
|
+
if (spillFileStream) {
|
|
251
|
+
spillFileStream.write(data);
|
|
240
252
|
}
|
|
241
253
|
|
|
242
254
|
// Keep rolling buffer of recent data
|
|
@@ -258,7 +270,7 @@ export function createBashTool(cwd: string, options?: BashToolOptions): AgentToo
|
|
|
258
270
|
content: [{ type: "text", text: truncation.content || "" }],
|
|
259
271
|
details: {
|
|
260
272
|
truncation: truncation.truncated ? truncation : undefined,
|
|
261
|
-
fullOutputPath:
|
|
273
|
+
fullOutputPath: spillFilePath,
|
|
262
274
|
},
|
|
263
275
|
});
|
|
264
276
|
}
|
|
@@ -272,8 +284,8 @@ export function createBashTool(cwd: string, options?: BashToolOptions): AgentToo
|
|
|
272
284
|
})
|
|
273
285
|
.then(({ exitCode }) => {
|
|
274
286
|
// Close temp file stream
|
|
275
|
-
if (
|
|
276
|
-
|
|
287
|
+
if (spillFileStream) {
|
|
288
|
+
spillFileStream.end();
|
|
277
289
|
}
|
|
278
290
|
|
|
279
291
|
// Combine all buffered chunks
|
|
@@ -290,21 +302,22 @@ export function createBashTool(cwd: string, options?: BashToolOptions): AgentToo
|
|
|
290
302
|
if (truncation.truncated) {
|
|
291
303
|
details = {
|
|
292
304
|
truncation,
|
|
293
|
-
fullOutputPath:
|
|
305
|
+
fullOutputPath: spillFilePath,
|
|
306
|
+
...(spillArtifactId ? { artifactId: spillArtifactId } : {}),
|
|
294
307
|
};
|
|
295
308
|
|
|
296
309
|
// Build actionable notice
|
|
297
310
|
const startLine = truncation.totalLines - truncation.outputLines + 1;
|
|
298
311
|
const endLine = truncation.totalLines;
|
|
312
|
+
const outputRef = spillArtifactId ? `artifact://${spillArtifactId}` : spillFilePath;
|
|
299
313
|
|
|
300
314
|
if (truncation.lastLinePartial) {
|
|
301
|
-
// Edge case: last line alone > 30KB
|
|
302
315
|
const lastLineSize = formatSize(Buffer.byteLength(fullOutput.split("\n").pop() || "", "utf-8"));
|
|
303
|
-
outputText += `\n\n[Showing last ${formatSize(truncation.outputBytes)} of line ${endLine} (line is ${lastLineSize}). Full output: ${
|
|
316
|
+
outputText += `\n\n[Showing last ${formatSize(truncation.outputBytes)} of line ${endLine} (line is ${lastLineSize}). Full output: ${outputRef}]`;
|
|
304
317
|
} else if (truncation.truncatedBy === "lines") {
|
|
305
|
-
outputText += `\n\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines}. Full output: ${
|
|
318
|
+
outputText += `\n\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines}. Full output: ${outputRef}]`;
|
|
306
319
|
} else {
|
|
307
|
-
outputText += `\n\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines} (${formatSize(DEFAULT_MAX_BYTES)} limit). Full output: ${
|
|
320
|
+
outputText += `\n\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines} (${formatSize(DEFAULT_MAX_BYTES)} limit). Full output: ${outputRef}]`;
|
|
308
321
|
}
|
|
309
322
|
}
|
|
310
323
|
|
|
@@ -317,8 +330,8 @@ export function createBashTool(cwd: string, options?: BashToolOptions): AgentToo
|
|
|
317
330
|
})
|
|
318
331
|
.catch((err: Error) => {
|
|
319
332
|
// Close temp file stream
|
|
320
|
-
if (
|
|
321
|
-
|
|
333
|
+
if (spillFileStream) {
|
|
334
|
+
spillFileStream.end();
|
|
322
335
|
}
|
|
323
336
|
|
|
324
337
|
// Combine all buffered chunks for error output
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { describe, it, mock, afterEach } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { resolveToCwd, expandPath } from "./path-utils.js";
|
|
4
|
+
|
|
5
|
+
describe("resolveToCwd", () => {
|
|
6
|
+
it("resolves relative paths against cwd", () => {
|
|
7
|
+
const result = resolveToCwd("foo/bar.txt", "/home/user/project");
|
|
8
|
+
assert.equal(result, "/home/user/project/foo/bar.txt");
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it("returns absolute paths unchanged", () => {
|
|
12
|
+
const result = resolveToCwd("/absolute/path.txt", "/home/user/project");
|
|
13
|
+
assert.equal(result, "/absolute/path.txt");
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("expands ~ to home directory", () => {
|
|
17
|
+
const result = resolveToCwd("~/file.txt", "/home/user/project");
|
|
18
|
+
assert.ok(result.endsWith("/file.txt"));
|
|
19
|
+
assert.ok(!result.includes("~"));
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
describe("normalizeMsysPath (via resolveToCwd on win32)", () => {
|
|
24
|
+
const originalPlatform = process.platform;
|
|
25
|
+
|
|
26
|
+
afterEach(() => {
|
|
27
|
+
Object.defineProperty(process, "platform", { value: originalPlatform });
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("converts /c/Users/... to C:\\Users\\... on win32", () => {
|
|
31
|
+
Object.defineProperty(process, "platform", { value: "win32" });
|
|
32
|
+
// Re-import to pick up platform change — but since normalizeMsysPath
|
|
33
|
+
// reads process.platform at call time, we can test directly.
|
|
34
|
+
// On non-Windows, resolveToCwd treats /c/Users as absolute, so we
|
|
35
|
+
// test the normalization logic by checking the MSYS regex behavior.
|
|
36
|
+
const msysPath = "/c/Users/test/project";
|
|
37
|
+
const msysRegex = /^\/[a-zA-Z]\//;
|
|
38
|
+
assert.ok(msysRegex.test(msysPath), "MSYS path pattern matches");
|
|
39
|
+
|
|
40
|
+
// Simulate the conversion
|
|
41
|
+
const converted = `${msysPath[1].toUpperCase()}:\\${msysPath.slice(3).replace(/\//g, "\\")}`;
|
|
42
|
+
assert.equal(converted, "C:\\Users\\test\\project");
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("converts /f/Projects to F:\\Projects on win32", () => {
|
|
46
|
+
const msysPath = "/f/Projects";
|
|
47
|
+
const converted = `${msysPath[1].toUpperCase()}:\\${msysPath.slice(3).replace(/\//g, "\\")}`;
|
|
48
|
+
assert.equal(converted, "F:\\Projects");
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("does not convert regular Unix paths", () => {
|
|
52
|
+
const regularPath = "/usr/local/bin";
|
|
53
|
+
const msysRegex = /^\/[a-zA-Z]\//;
|
|
54
|
+
// /u/local/bin would match, but /usr/local/bin has 3+ chars before /
|
|
55
|
+
// Actually /u/ would match — but /usr/ won't because 'us' is 2 chars.
|
|
56
|
+
// The regex checks single letter after leading slash.
|
|
57
|
+
assert.ok(!msysRegex.test("/usr/local/bin"), "/usr/... is not an MSYS path");
|
|
58
|
+
assert.ok(msysRegex.test("/u/local/bin"), "/u/... would match (single letter)");
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("does not convert paths without leading slash", () => {
|
|
62
|
+
const msysRegex = /^\/[a-zA-Z]\//;
|
|
63
|
+
assert.ok(!msysRegex.test("c/Users/test"), "no leading slash — not MSYS");
|
|
64
|
+
assert.ok(!msysRegex.test("relative/path"), "relative path — not MSYS");
|
|
65
|
+
});
|
|
66
|
+
});
|
|
@@ -47,12 +47,24 @@ export function expandPath(filePath: string): string {
|
|
|
47
47
|
return normalized;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
/**
|
|
51
|
+
* On Windows, convert MSYS/MinGW-style paths (/c/Users/...) to native
|
|
52
|
+
* drive letter paths (C:\Users\...). LLMs often produce these when given
|
|
53
|
+
* Windows paths in prompts.
|
|
54
|
+
*/
|
|
55
|
+
function normalizeMsysPath(p: string): string {
|
|
56
|
+
if (process.platform === "win32" && /^\/[a-zA-Z]\//.test(p)) {
|
|
57
|
+
return `${p[1]!.toUpperCase()}:\\${p.slice(3).replace(/\//g, "\\")}`;
|
|
58
|
+
}
|
|
59
|
+
return p;
|
|
60
|
+
}
|
|
61
|
+
|
|
50
62
|
/**
|
|
51
63
|
* Resolve a path relative to the given cwd.
|
|
52
|
-
* Handles ~ expansion and absolute paths.
|
|
64
|
+
* Handles ~ expansion, MSYS-style paths on Windows, and absolute paths.
|
|
53
65
|
*/
|
|
54
66
|
export function resolveToCwd(filePath: string, cwd: string): string {
|
|
55
|
-
const expanded = expandPath(filePath);
|
|
67
|
+
const expanded = normalizeMsysPath(expandPath(filePath));
|
|
56
68
|
if (isAbsolute(expanded)) {
|
|
57
69
|
return expanded;
|
|
58
70
|
}
|
|
@@ -198,6 +198,9 @@ export {
|
|
|
198
198
|
type SessionMessageEntry,
|
|
199
199
|
type ThinkingLevelChangeEntry,
|
|
200
200
|
} from "./core/session-manager.js";
|
|
201
|
+
// Blob and artifact storage
|
|
202
|
+
export { BlobStore, isBlobRef, parseBlobRef, externalizeImageData, resolveImageData } from "./core/blob-store.js";
|
|
203
|
+
export { ArtifactManager } from "./core/artifact-manager.js";
|
|
201
204
|
export {
|
|
202
205
|
type CompactionSettings,
|
|
203
206
|
type ImageSettings,
|
|
@@ -330,4 +333,4 @@ export {
|
|
|
330
333
|
export { copyToClipboard } from "./utils/clipboard.js";
|
|
331
334
|
export { parseFrontmatter, stripFrontmatter } from "./utils/frontmatter.js";
|
|
332
335
|
// Shell utilities
|
|
333
|
-
export { getShellConfig } from "./utils/shell.js";
|
|
336
|
+
export { getShellConfig, sanitizeCommand } from "./utils/shell.js";
|
|
@@ -824,10 +824,12 @@ export class InteractiveMode {
|
|
|
824
824
|
|
|
825
825
|
// Try parent directories (package manager stores directory paths)
|
|
826
826
|
let current = p;
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
const
|
|
830
|
-
if (
|
|
827
|
+
let parent = path.dirname(current);
|
|
828
|
+
while (parent !== current) {
|
|
829
|
+
const meta = metadata.get(parent);
|
|
830
|
+
if (meta) return meta;
|
|
831
|
+
current = parent;
|
|
832
|
+
parent = path.dirname(current);
|
|
831
833
|
}
|
|
832
834
|
|
|
833
835
|
return undefined;
|
|
@@ -118,6 +118,17 @@ export function getShellConfig(): { shell: string; args: string[] } {
|
|
|
118
118
|
return cachedShellConfig;
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
+
/**
|
|
122
|
+
* On Windows + Git Bash, rewrite Windows-style NUL redirects to /dev/null.
|
|
123
|
+
* Git Bash doesn't recognize NUL as a device name and creates a literal file
|
|
124
|
+
* that is undeletable due to NUL being a reserved Windows device name.
|
|
125
|
+
* No-op on non-Windows platforms.
|
|
126
|
+
*/
|
|
127
|
+
export function sanitizeCommand(command: string): string {
|
|
128
|
+
if (process.platform !== "win32") return command;
|
|
129
|
+
return command.replace(/(\d*>>?) *\bNUL\b(?=\s|;|\||&|\)|$)/gi, "$1 /dev/null");
|
|
130
|
+
}
|
|
131
|
+
|
|
121
132
|
export function getShellEnv(): NodeJS.ProcessEnv {
|
|
122
133
|
const binDir = getBinDir();
|
|
123
134
|
const pathKey = Object.keys(process.env).find((key) => key.toLowerCase() === "path") ?? "PATH";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gsd-pi",
|
|
3
|
-
"version": "2.8.
|
|
3
|
+
"version": "2.8.2",
|
|
4
4
|
"description": "GSD — Get Shit Done coding agent",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -59,6 +59,7 @@
|
|
|
59
59
|
"@gsd/pi-coding-agent": "*",
|
|
60
60
|
"@gsd/pi-tui": "*",
|
|
61
61
|
"picocolors": "^1.1.1",
|
|
62
|
+
"picomatch": "^4.0.3",
|
|
62
63
|
"playwright": "^1.58.2",
|
|
63
64
|
"sharp": "^0.34.5"
|
|
64
65
|
},
|
|
@@ -70,9 +71,13 @@
|
|
|
70
71
|
],
|
|
71
72
|
"devDependencies": {
|
|
72
73
|
"@types/node": "^22.0.0",
|
|
74
|
+
"@types/picomatch": "^4.0.2",
|
|
73
75
|
"jiti": "^2.6.1",
|
|
74
76
|
"typescript": "^5.4.0"
|
|
75
77
|
},
|
|
78
|
+
"optionalDependencies": {
|
|
79
|
+
"fsevents": "~2.3.3"
|
|
80
|
+
},
|
|
76
81
|
"overrides": {
|
|
77
82
|
"gaxios": "7.1.4"
|
|
78
83
|
}
|
|
@@ -63,6 +63,8 @@ export declare function getBinDir(): string;
|
|
|
63
63
|
export declare function getPromptsDir(): string;
|
|
64
64
|
/** Get path to sessions directory */
|
|
65
65
|
export declare function getSessionsDir(): string;
|
|
66
|
+
/** Get path to content-addressed blob store directory */
|
|
67
|
+
export declare function getBlobsDir(): string;
|
|
66
68
|
/** Get path to debug log file */
|
|
67
69
|
export declare function getDebugLogPath(): string;
|
|
68
70
|
//# sourceMappingURL=config.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAYA;;;GAGG;AACH,eAAO,MAAM,WAAW,SACqF,CAAC;AAE9G,gEAAgE;AAChE,eAAO,MAAM,YAAY,SAAyB,CAAC;AAMnD,MAAM,MAAM,aAAa,GAAG,YAAY,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,SAAS,CAAC;AAEvF,wBAAgB,mBAAmB,IAAI,aAAa,CAqBnD;AAED,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAgBhE;AAMD;;;;;GAKG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAuBtC;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAQrC;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAO7C;AAED,+BAA+B;AAC/B,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED,4BAA4B;AAC5B,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,iCAAiC;AACjC,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,qCAAqC;AACrC,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED,+BAA+B;AAC/B,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAQD,eAAO,MAAM,QAAQ,EAAE,MAAmC,CAAC;AAC3D,eAAO,MAAM,eAAe,EAAE,MAAyC,CAAC;AACxE,eAAO,MAAM,OAAO,EAAE,MAAoB,CAAC;AAG3C,eAAO,MAAM,aAAa,QAA+C,CAAC;AAI1E,6CAA6C;AAC7C,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAGxD;AAMD,0DAA0D;AAC1D,wBAAgB,WAAW,IAAI,MAAM,CASpC;AAED,iDAAiD;AACjD,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED,8BAA8B;AAC9B,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,4BAA4B;AAC5B,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,gCAAgC;AAChC,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED,kCAAkC;AAClC,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,sDAAsD;AACtD,wBAAgB,SAAS,IAAI,MAAM,CAElC;AAED,6CAA6C;AAC7C,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,qCAAqC;AACrC,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED,iCAAiC;AACjC,wBAAgB,eAAe,IAAI,MAAM,CAExC"}
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAYA;;;GAGG;AACH,eAAO,MAAM,WAAW,SACqF,CAAC;AAE9G,gEAAgE;AAChE,eAAO,MAAM,YAAY,SAAyB,CAAC;AAMnD,MAAM,MAAM,aAAa,GAAG,YAAY,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,SAAS,CAAC;AAEvF,wBAAgB,mBAAmB,IAAI,aAAa,CAqBnD;AAED,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAgBhE;AAMD;;;;;GAKG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAuBtC;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAQrC;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAO7C;AAED,+BAA+B;AAC/B,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED,4BAA4B;AAC5B,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,iCAAiC;AACjC,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,qCAAqC;AACrC,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED,+BAA+B;AAC/B,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAQD,eAAO,MAAM,QAAQ,EAAE,MAAmC,CAAC;AAC3D,eAAO,MAAM,eAAe,EAAE,MAAyC,CAAC;AACxE,eAAO,MAAM,OAAO,EAAE,MAAoB,CAAC;AAG3C,eAAO,MAAM,aAAa,QAA+C,CAAC;AAI1E,6CAA6C;AAC7C,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAGxD;AAMD,0DAA0D;AAC1D,wBAAgB,WAAW,IAAI,MAAM,CASpC;AAED,iDAAiD;AACjD,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED,8BAA8B;AAC9B,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,4BAA4B;AAC5B,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,gCAAgC;AAChC,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED,kCAAkC;AAClC,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,sDAAsD;AACtD,wBAAgB,SAAS,IAAI,MAAM,CAElC;AAED,6CAA6C;AAC7C,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,qCAAqC;AACrC,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED,yDAAyD;AACzD,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,iCAAiC;AACjC,wBAAgB,eAAe,IAAI,MAAM,CAExC"}
|
|
@@ -196,6 +196,10 @@ export function getPromptsDir() {
|
|
|
196
196
|
export function getSessionsDir() {
|
|
197
197
|
return join(getAgentDir(), "sessions");
|
|
198
198
|
}
|
|
199
|
+
/** Get path to content-addressed blob store directory */
|
|
200
|
+
export function getBlobsDir() {
|
|
201
|
+
return join(getAgentDir(), "blobs");
|
|
202
|
+
}
|
|
199
203
|
/** Get path to debug log file */
|
|
200
204
|
export function getDebugLogPath() {
|
|
201
205
|
return join(getAgentDir(), `${APP_NAME}-debug.log`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readFileSync } from \"fs\";\nimport { homedir } from \"os\";\nimport { dirname, join, resolve } from \"path\";\nimport { fileURLToPath } from \"url\";\n\n// =============================================================================\n// Package Detection\n// =============================================================================\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n/**\n * Detect if we're running as a Bun compiled binary.\n * Bun binaries have import.meta.url containing \"$bunfs\", \"~BUN\", or \"%7EBUN\" (Bun's virtual filesystem path)\n */\nexport const isBunBinary =\n\timport.meta.url.includes(\"$bunfs\") || import.meta.url.includes(\"~BUN\") || import.meta.url.includes(\"%7EBUN\");\n\n/** Detect if Bun is the runtime (compiled binary or bun run) */\nexport const isBunRuntime = !!process.versions.bun;\n\n// =============================================================================\n// Install Method Detection\n// =============================================================================\n\nexport type InstallMethod = \"bun-binary\" | \"npm\" | \"pnpm\" | \"yarn\" | \"bun\" | \"unknown\";\n\nexport function detectInstallMethod(): InstallMethod {\n\tif (isBunBinary) {\n\t\treturn \"bun-binary\";\n\t}\n\n\tconst resolvedPath = `${__dirname}\\0${process.execPath || \"\"}`.toLowerCase();\n\n\tif (resolvedPath.includes(\"/pnpm/\") || resolvedPath.includes(\"/.pnpm/\") || resolvedPath.includes(\"\\\\pnpm\\\\\")) {\n\t\treturn \"pnpm\";\n\t}\n\tif (resolvedPath.includes(\"/yarn/\") || resolvedPath.includes(\"/.yarn/\") || resolvedPath.includes(\"\\\\yarn\\\\\")) {\n\t\treturn \"yarn\";\n\t}\n\tif (isBunRuntime) {\n\t\treturn \"bun\";\n\t}\n\tif (resolvedPath.includes(\"/npm/\") || resolvedPath.includes(\"/node_modules/\") || resolvedPath.includes(\"\\\\npm\\\\\")) {\n\t\treturn \"npm\";\n\t}\n\n\treturn \"unknown\";\n}\n\nexport function getUpdateInstruction(packageName: string): string {\n\tconst method = detectInstallMethod();\n\tswitch (method) {\n\t\tcase \"bun-binary\":\n\t\t\treturn `Download from: https://github.com/badlogic/pi-mono/releases/latest`;\n\t\tcase \"pnpm\":\n\t\t\treturn `Run: pnpm install -g ${packageName}`;\n\t\tcase \"yarn\":\n\t\t\treturn `Run: yarn global add ${packageName}`;\n\t\tcase \"bun\":\n\t\t\treturn `Run: bun install -g ${packageName}`;\n\t\tcase \"npm\":\n\t\t\treturn `Run: npm install -g ${packageName}`;\n\t\tdefault:\n\t\t\treturn `Run: npm install -g ${packageName}`;\n\t}\n}\n\n// =============================================================================\n// Package Asset Paths (shipped with executable)\n// =============================================================================\n\n/**\n * Get the base directory for resolving package assets (themes, package.json, README.md, CHANGELOG.md).\n * - For Bun binary: returns the directory containing the executable\n * - For Node.js (dist/): returns __dirname (the dist/ directory)\n * - For tsx (src/): returns parent directory (the package root)\n */\nexport function getPackageDir(): string {\n\t// Allow override via environment variable (useful for Nix/Guix where store paths tokenize poorly)\n\tconst envDir = process.env.PI_PACKAGE_DIR;\n\tif (envDir) {\n\t\tif (envDir === \"~\") return homedir();\n\t\tif (envDir.startsWith(\"~/\")) return homedir() + envDir.slice(1);\n\t\treturn envDir;\n\t}\n\n\tif (isBunBinary) {\n\t\t// Bun binary: process.execPath points to the compiled executable\n\t\treturn dirname(process.execPath);\n\t}\n\t// Node.js: walk up from __dirname until we find package.json\n\tlet dir = __dirname;\n\twhile (dir !== dirname(dir)) {\n\t\tif (existsSync(join(dir, \"package.json\"))) {\n\t\t\treturn dir;\n\t\t}\n\t\tdir = dirname(dir);\n\t}\n\t// Fallback (shouldn't happen)\n\treturn __dirname;\n}\n\n/**\n * Get path to built-in themes directory (shipped with package)\n * - For Bun binary: theme/ next to executable\n * - For Node.js (dist/): dist/modes/interactive/theme/\n * - For tsx (src/): src/modes/interactive/theme/\n */\nexport function getThemesDir(): string {\n\tif (isBunBinary) {\n\t\treturn join(dirname(process.execPath), \"theme\");\n\t}\n\t// Theme is in modes/interactive/theme/ relative to src/ or dist/\n\tconst packageDir = getPackageDir();\n\tconst srcOrDist = existsSync(join(packageDir, \"src\")) ? \"src\" : \"dist\";\n\treturn join(packageDir, srcOrDist, \"modes\", \"interactive\", \"theme\");\n}\n\n/**\n * Get path to HTML export template directory (shipped with package)\n * - For Bun binary: export-html/ next to executable\n * - For Node.js (dist/): dist/core/export-html/\n * - For tsx (src/): src/core/export-html/\n */\nexport function getExportTemplateDir(): string {\n\tif (isBunBinary) {\n\t\treturn join(dirname(process.execPath), \"export-html\");\n\t}\n\tconst packageDir = getPackageDir();\n\tconst srcOrDist = existsSync(join(packageDir, \"src\")) ? \"src\" : \"dist\";\n\treturn join(packageDir, srcOrDist, \"core\", \"export-html\");\n}\n\n/** Get path to package.json */\nexport function getPackageJsonPath(): string {\n\treturn join(getPackageDir(), \"package.json\");\n}\n\n/** Get path to README.md */\nexport function getReadmePath(): string {\n\treturn resolve(join(getPackageDir(), \"README.md\"));\n}\n\n/** Get path to docs directory */\nexport function getDocsPath(): string {\n\treturn resolve(join(getPackageDir(), \"docs\"));\n}\n\n/** Get path to examples directory */\nexport function getExamplesPath(): string {\n\treturn resolve(join(getPackageDir(), \"examples\"));\n}\n\n/** Get path to CHANGELOG.md */\nexport function getChangelogPath(): string {\n\treturn resolve(join(getPackageDir(), \"CHANGELOG.md\"));\n}\n\n// =============================================================================\n// App Config (from package.json piConfig)\n// =============================================================================\n\nconst pkg = JSON.parse(readFileSync(getPackageJsonPath(), \"utf-8\"));\n\nexport const APP_NAME: string = pkg.piConfig?.name || \"pi\";\nexport const CONFIG_DIR_NAME: string = pkg.piConfig?.configDir || \".pi\";\nexport const VERSION: string = pkg.version;\n\n// e.g., PI_CODING_AGENT_DIR or TAU_CODING_AGENT_DIR\nexport const ENV_AGENT_DIR = `${APP_NAME.toUpperCase()}_CODING_AGENT_DIR`;\n\nconst DEFAULT_SHARE_VIEWER_URL = \"https://pi.dev/session/\";\n\n/** Get the share viewer URL for a gist ID */\nexport function getShareViewerUrl(gistId: string): string {\n\tconst baseUrl = process.env.PI_SHARE_VIEWER_URL || DEFAULT_SHARE_VIEWER_URL;\n\treturn `${baseUrl}#${gistId}`;\n}\n\n// =============================================================================\n// User Config Paths (~/.pi/agent/*)\n// =============================================================================\n\n/** Get the agent config directory (e.g., ~/.pi/agent/) */\nexport function getAgentDir(): string {\n\tconst envDir = process.env[ENV_AGENT_DIR];\n\tif (envDir) {\n\t\t// Expand tilde to home directory\n\t\tif (envDir === \"~\") return homedir();\n\t\tif (envDir.startsWith(\"~/\")) return homedir() + envDir.slice(1);\n\t\treturn envDir;\n\t}\n\treturn join(homedir(), CONFIG_DIR_NAME, \"agent\");\n}\n\n/** Get path to user's custom themes directory */\nexport function getCustomThemesDir(): string {\n\treturn join(getAgentDir(), \"themes\");\n}\n\n/** Get path to models.json */\nexport function getModelsPath(): string {\n\treturn join(getAgentDir(), \"models.json\");\n}\n\n/** Get path to auth.json */\nexport function getAuthPath(): string {\n\treturn join(getAgentDir(), \"auth.json\");\n}\n\n/** Get path to settings.json */\nexport function getSettingsPath(): string {\n\treturn join(getAgentDir(), \"settings.json\");\n}\n\n/** Get path to tools directory */\nexport function getToolsDir(): string {\n\treturn join(getAgentDir(), \"tools\");\n}\n\n/** Get path to managed binaries directory (fd, rg) */\nexport function getBinDir(): string {\n\treturn join(getAgentDir(), \"bin\");\n}\n\n/** Get path to prompt templates directory */\nexport function getPromptsDir(): string {\n\treturn join(getAgentDir(), \"prompts\");\n}\n\n/** Get path to sessions directory */\nexport function getSessionsDir(): string {\n\treturn join(getAgentDir(), \"sessions\");\n}\n\n/** Get path to debug log file */\nexport function getDebugLogPath(): string {\n\treturn join(getAgentDir(), `${APP_NAME}-debug.log`);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readFileSync } from \"fs\";\nimport { homedir } from \"os\";\nimport { dirname, join, resolve } from \"path\";\nimport { fileURLToPath } from \"url\";\n\n// =============================================================================\n// Package Detection\n// =============================================================================\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n/**\n * Detect if we're running as a Bun compiled binary.\n * Bun binaries have import.meta.url containing \"$bunfs\", \"~BUN\", or \"%7EBUN\" (Bun's virtual filesystem path)\n */\nexport const isBunBinary =\n\timport.meta.url.includes(\"$bunfs\") || import.meta.url.includes(\"~BUN\") || import.meta.url.includes(\"%7EBUN\");\n\n/** Detect if Bun is the runtime (compiled binary or bun run) */\nexport const isBunRuntime = !!process.versions.bun;\n\n// =============================================================================\n// Install Method Detection\n// =============================================================================\n\nexport type InstallMethod = \"bun-binary\" | \"npm\" | \"pnpm\" | \"yarn\" | \"bun\" | \"unknown\";\n\nexport function detectInstallMethod(): InstallMethod {\n\tif (isBunBinary) {\n\t\treturn \"bun-binary\";\n\t}\n\n\tconst resolvedPath = `${__dirname}\\0${process.execPath || \"\"}`.toLowerCase();\n\n\tif (resolvedPath.includes(\"/pnpm/\") || resolvedPath.includes(\"/.pnpm/\") || resolvedPath.includes(\"\\\\pnpm\\\\\")) {\n\t\treturn \"pnpm\";\n\t}\n\tif (resolvedPath.includes(\"/yarn/\") || resolvedPath.includes(\"/.yarn/\") || resolvedPath.includes(\"\\\\yarn\\\\\")) {\n\t\treturn \"yarn\";\n\t}\n\tif (isBunRuntime) {\n\t\treturn \"bun\";\n\t}\n\tif (resolvedPath.includes(\"/npm/\") || resolvedPath.includes(\"/node_modules/\") || resolvedPath.includes(\"\\\\npm\\\\\")) {\n\t\treturn \"npm\";\n\t}\n\n\treturn \"unknown\";\n}\n\nexport function getUpdateInstruction(packageName: string): string {\n\tconst method = detectInstallMethod();\n\tswitch (method) {\n\t\tcase \"bun-binary\":\n\t\t\treturn `Download from: https://github.com/badlogic/pi-mono/releases/latest`;\n\t\tcase \"pnpm\":\n\t\t\treturn `Run: pnpm install -g ${packageName}`;\n\t\tcase \"yarn\":\n\t\t\treturn `Run: yarn global add ${packageName}`;\n\t\tcase \"bun\":\n\t\t\treturn `Run: bun install -g ${packageName}`;\n\t\tcase \"npm\":\n\t\t\treturn `Run: npm install -g ${packageName}`;\n\t\tdefault:\n\t\t\treturn `Run: npm install -g ${packageName}`;\n\t}\n}\n\n// =============================================================================\n// Package Asset Paths (shipped with executable)\n// =============================================================================\n\n/**\n * Get the base directory for resolving package assets (themes, package.json, README.md, CHANGELOG.md).\n * - For Bun binary: returns the directory containing the executable\n * - For Node.js (dist/): returns __dirname (the dist/ directory)\n * - For tsx (src/): returns parent directory (the package root)\n */\nexport function getPackageDir(): string {\n\t// Allow override via environment variable (useful for Nix/Guix where store paths tokenize poorly)\n\tconst envDir = process.env.PI_PACKAGE_DIR;\n\tif (envDir) {\n\t\tif (envDir === \"~\") return homedir();\n\t\tif (envDir.startsWith(\"~/\")) return homedir() + envDir.slice(1);\n\t\treturn envDir;\n\t}\n\n\tif (isBunBinary) {\n\t\t// Bun binary: process.execPath points to the compiled executable\n\t\treturn dirname(process.execPath);\n\t}\n\t// Node.js: walk up from __dirname until we find package.json\n\tlet dir = __dirname;\n\twhile (dir !== dirname(dir)) {\n\t\tif (existsSync(join(dir, \"package.json\"))) {\n\t\t\treturn dir;\n\t\t}\n\t\tdir = dirname(dir);\n\t}\n\t// Fallback (shouldn't happen)\n\treturn __dirname;\n}\n\n/**\n * Get path to built-in themes directory (shipped with package)\n * - For Bun binary: theme/ next to executable\n * - For Node.js (dist/): dist/modes/interactive/theme/\n * - For tsx (src/): src/modes/interactive/theme/\n */\nexport function getThemesDir(): string {\n\tif (isBunBinary) {\n\t\treturn join(dirname(process.execPath), \"theme\");\n\t}\n\t// Theme is in modes/interactive/theme/ relative to src/ or dist/\n\tconst packageDir = getPackageDir();\n\tconst srcOrDist = existsSync(join(packageDir, \"src\")) ? \"src\" : \"dist\";\n\treturn join(packageDir, srcOrDist, \"modes\", \"interactive\", \"theme\");\n}\n\n/**\n * Get path to HTML export template directory (shipped with package)\n * - For Bun binary: export-html/ next to executable\n * - For Node.js (dist/): dist/core/export-html/\n * - For tsx (src/): src/core/export-html/\n */\nexport function getExportTemplateDir(): string {\n\tif (isBunBinary) {\n\t\treturn join(dirname(process.execPath), \"export-html\");\n\t}\n\tconst packageDir = getPackageDir();\n\tconst srcOrDist = existsSync(join(packageDir, \"src\")) ? \"src\" : \"dist\";\n\treturn join(packageDir, srcOrDist, \"core\", \"export-html\");\n}\n\n/** Get path to package.json */\nexport function getPackageJsonPath(): string {\n\treturn join(getPackageDir(), \"package.json\");\n}\n\n/** Get path to README.md */\nexport function getReadmePath(): string {\n\treturn resolve(join(getPackageDir(), \"README.md\"));\n}\n\n/** Get path to docs directory */\nexport function getDocsPath(): string {\n\treturn resolve(join(getPackageDir(), \"docs\"));\n}\n\n/** Get path to examples directory */\nexport function getExamplesPath(): string {\n\treturn resolve(join(getPackageDir(), \"examples\"));\n}\n\n/** Get path to CHANGELOG.md */\nexport function getChangelogPath(): string {\n\treturn resolve(join(getPackageDir(), \"CHANGELOG.md\"));\n}\n\n// =============================================================================\n// App Config (from package.json piConfig)\n// =============================================================================\n\nconst pkg = JSON.parse(readFileSync(getPackageJsonPath(), \"utf-8\"));\n\nexport const APP_NAME: string = pkg.piConfig?.name || \"pi\";\nexport const CONFIG_DIR_NAME: string = pkg.piConfig?.configDir || \".pi\";\nexport const VERSION: string = pkg.version;\n\n// e.g., PI_CODING_AGENT_DIR or TAU_CODING_AGENT_DIR\nexport const ENV_AGENT_DIR = `${APP_NAME.toUpperCase()}_CODING_AGENT_DIR`;\n\nconst DEFAULT_SHARE_VIEWER_URL = \"https://pi.dev/session/\";\n\n/** Get the share viewer URL for a gist ID */\nexport function getShareViewerUrl(gistId: string): string {\n\tconst baseUrl = process.env.PI_SHARE_VIEWER_URL || DEFAULT_SHARE_VIEWER_URL;\n\treturn `${baseUrl}#${gistId}`;\n}\n\n// =============================================================================\n// User Config Paths (~/.pi/agent/*)\n// =============================================================================\n\n/** Get the agent config directory (e.g., ~/.pi/agent/) */\nexport function getAgentDir(): string {\n\tconst envDir = process.env[ENV_AGENT_DIR];\n\tif (envDir) {\n\t\t// Expand tilde to home directory\n\t\tif (envDir === \"~\") return homedir();\n\t\tif (envDir.startsWith(\"~/\")) return homedir() + envDir.slice(1);\n\t\treturn envDir;\n\t}\n\treturn join(homedir(), CONFIG_DIR_NAME, \"agent\");\n}\n\n/** Get path to user's custom themes directory */\nexport function getCustomThemesDir(): string {\n\treturn join(getAgentDir(), \"themes\");\n}\n\n/** Get path to models.json */\nexport function getModelsPath(): string {\n\treturn join(getAgentDir(), \"models.json\");\n}\n\n/** Get path to auth.json */\nexport function getAuthPath(): string {\n\treturn join(getAgentDir(), \"auth.json\");\n}\n\n/** Get path to settings.json */\nexport function getSettingsPath(): string {\n\treturn join(getAgentDir(), \"settings.json\");\n}\n\n/** Get path to tools directory */\nexport function getToolsDir(): string {\n\treturn join(getAgentDir(), \"tools\");\n}\n\n/** Get path to managed binaries directory (fd, rg) */\nexport function getBinDir(): string {\n\treturn join(getAgentDir(), \"bin\");\n}\n\n/** Get path to prompt templates directory */\nexport function getPromptsDir(): string {\n\treturn join(getAgentDir(), \"prompts\");\n}\n\n/** Get path to sessions directory */\nexport function getSessionsDir(): string {\n\treturn join(getAgentDir(), \"sessions\");\n}\n\n/** Get path to content-addressed blob store directory */\nexport function getBlobsDir(): string {\n\treturn join(getAgentDir(), \"blobs\");\n}\n\n/** Get path to debug log file */\nexport function getDebugLogPath(): string {\n\treturn join(getAgentDir(), `${APP_NAME}-debug.log`);\n}\n"]}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manages artifact storage for a session.
|
|
3
|
+
*
|
|
4
|
+
* Artifacts are stored with sequential IDs in the session's artifact directory.
|
|
5
|
+
* The directory is created lazily on first write.
|
|
6
|
+
*/
|
|
7
|
+
export declare class ArtifactManager {
|
|
8
|
+
#private;
|
|
9
|
+
/**
|
|
10
|
+
* @param sessionFile Path to the session .jsonl file
|
|
11
|
+
*/
|
|
12
|
+
constructor(sessionFile: string);
|
|
13
|
+
/**
|
|
14
|
+
* Artifact directory path.
|
|
15
|
+
* Directory may not exist until first artifact is saved.
|
|
16
|
+
*/
|
|
17
|
+
get dir(): string;
|
|
18
|
+
/** Atomically allocate next artifact ID. */
|
|
19
|
+
allocateId(): number;
|
|
20
|
+
/**
|
|
21
|
+
* Allocate a new artifact path and ID without writing content.
|
|
22
|
+
* @param toolType Tool name for file extension (e.g., "bash", "fetch")
|
|
23
|
+
*/
|
|
24
|
+
allocatePath(toolType: string): {
|
|
25
|
+
id: string;
|
|
26
|
+
path: string;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Save content as an artifact and return the artifact ID.
|
|
30
|
+
* @param content Full content to save
|
|
31
|
+
* @param toolType Tool name for file extension (e.g., "bash", "fetch")
|
|
32
|
+
* @returns Artifact ID (numeric string)
|
|
33
|
+
*/
|
|
34
|
+
save(content: string, toolType: string): string;
|
|
35
|
+
/**
|
|
36
|
+
* Check if an artifact exists.
|
|
37
|
+
* @param id Artifact ID (numeric string)
|
|
38
|
+
*/
|
|
39
|
+
exists(id: string): boolean;
|
|
40
|
+
/**
|
|
41
|
+
* List all artifact files in the directory.
|
|
42
|
+
* Returns empty array if directory doesn't exist.
|
|
43
|
+
*/
|
|
44
|
+
listFiles(): string[];
|
|
45
|
+
/**
|
|
46
|
+
* Get the full path to an artifact file.
|
|
47
|
+
* Returns null if artifact doesn't exist.
|
|
48
|
+
* @param id Artifact ID (numeric string)
|
|
49
|
+
*/
|
|
50
|
+
getPath(id: string): string | null;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=artifact-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifact-manager.d.ts","sourceRoot":"","sources":["../../src/core/artifact-manager.ts"],"names":[],"mappings":"AASA;;;;;GAKG;AACH,qBAAa,eAAe;;IAM3B;;OAEG;gBACS,WAAW,EAAE,MAAM;IAK/B;;;OAGG;IACH,IAAI,GAAG,IAAI,MAAM,CAEhB;IA8BD,4CAA4C;IAC5C,UAAU,IAAI,MAAM;IAIpB;;;OAGG;IACH,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE;IAO5D;;;;;OAKG;IACH,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM;IAM/C;;;OAGG;IACH,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAK3B;;;OAGG;IACH,SAAS,IAAI,MAAM,EAAE;IAQrB;;;;OAIG;IACH,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;CAKlC"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session-scoped artifact storage for truncated tool outputs.
|
|
3
|
+
*
|
|
4
|
+
* Artifacts are stored in a directory alongside the session file,
|
|
5
|
+
* accessible via artifact:// URLs.
|
|
6
|
+
*/
|
|
7
|
+
import { mkdirSync, readdirSync, writeFileSync } from "node:fs";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
/**
|
|
10
|
+
* Manages artifact storage for a session.
|
|
11
|
+
*
|
|
12
|
+
* Artifacts are stored with sequential IDs in the session's artifact directory.
|
|
13
|
+
* The directory is created lazily on first write.
|
|
14
|
+
*/
|
|
15
|
+
export class ArtifactManager {
|
|
16
|
+
#nextId = 0;
|
|
17
|
+
#dir;
|
|
18
|
+
#dirCreated = false;
|
|
19
|
+
#initialized = false;
|
|
20
|
+
/**
|
|
21
|
+
* @param sessionFile Path to the session .jsonl file
|
|
22
|
+
*/
|
|
23
|
+
constructor(sessionFile) {
|
|
24
|
+
// Artifact directory is session file path without .jsonl extension
|
|
25
|
+
this.#dir = sessionFile.slice(0, -6);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Artifact directory path.
|
|
29
|
+
* Directory may not exist until first artifact is saved.
|
|
30
|
+
*/
|
|
31
|
+
get dir() {
|
|
32
|
+
return this.#dir;
|
|
33
|
+
}
|
|
34
|
+
#ensureDir() {
|
|
35
|
+
if (!this.#dirCreated) {
|
|
36
|
+
mkdirSync(this.#dir, { recursive: true });
|
|
37
|
+
this.#dirCreated = true;
|
|
38
|
+
}
|
|
39
|
+
if (!this.#initialized) {
|
|
40
|
+
this.#scanExistingIds();
|
|
41
|
+
this.#initialized = true;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Scan existing artifact files to find the next available ID.
|
|
46
|
+
* Ensures we don't overwrite artifacts when resuming a session.
|
|
47
|
+
*/
|
|
48
|
+
#scanExistingIds() {
|
|
49
|
+
const files = this.listFiles();
|
|
50
|
+
let maxId = -1;
|
|
51
|
+
for (const file of files) {
|
|
52
|
+
const match = file.match(/^(\d+)\..*\.log$/);
|
|
53
|
+
if (match) {
|
|
54
|
+
const id = parseInt(match[1], 10);
|
|
55
|
+
if (id > maxId)
|
|
56
|
+
maxId = id;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
this.#nextId = maxId + 1;
|
|
60
|
+
}
|
|
61
|
+
/** Atomically allocate next artifact ID. */
|
|
62
|
+
allocateId() {
|
|
63
|
+
return this.#nextId++;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Allocate a new artifact path and ID without writing content.
|
|
67
|
+
* @param toolType Tool name for file extension (e.g., "bash", "fetch")
|
|
68
|
+
*/
|
|
69
|
+
allocatePath(toolType) {
|
|
70
|
+
this.#ensureDir();
|
|
71
|
+
const id = String(this.allocateId());
|
|
72
|
+
const filename = `${id}.${toolType}.log`;
|
|
73
|
+
return { id, path: join(this.#dir, filename) };
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Save content as an artifact and return the artifact ID.
|
|
77
|
+
* @param content Full content to save
|
|
78
|
+
* @param toolType Tool name for file extension (e.g., "bash", "fetch")
|
|
79
|
+
* @returns Artifact ID (numeric string)
|
|
80
|
+
*/
|
|
81
|
+
save(content, toolType) {
|
|
82
|
+
const { id, path } = this.allocatePath(toolType);
|
|
83
|
+
writeFileSync(path, content);
|
|
84
|
+
return id;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Check if an artifact exists.
|
|
88
|
+
* @param id Artifact ID (numeric string)
|
|
89
|
+
*/
|
|
90
|
+
exists(id) {
|
|
91
|
+
const files = this.listFiles();
|
|
92
|
+
return files.some((f) => f.startsWith(`${id}.`));
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* List all artifact files in the directory.
|
|
96
|
+
* Returns empty array if directory doesn't exist.
|
|
97
|
+
*/
|
|
98
|
+
listFiles() {
|
|
99
|
+
try {
|
|
100
|
+
return readdirSync(this.#dir);
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return [];
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Get the full path to an artifact file.
|
|
108
|
+
* Returns null if artifact doesn't exist.
|
|
109
|
+
* @param id Artifact ID (numeric string)
|
|
110
|
+
*/
|
|
111
|
+
getPath(id) {
|
|
112
|
+
const files = this.listFiles();
|
|
113
|
+
const match = files.find((f) => f.startsWith(`${id}.`));
|
|
114
|
+
return match ? join(this.#dir, match) : null;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=artifact-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifact-manager.js","sourceRoot":"","sources":["../../src/core/artifact-manager.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Session-scoped artifact storage for truncated tool outputs.\n *\n * Artifacts are stored in a directory alongside the session file,\n * accessible via artifact:// URLs.\n */\nimport { mkdirSync, readdirSync, writeFileSync, existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\n/**\n * Manages artifact storage for a session.\n *\n * Artifacts are stored with sequential IDs in the session's artifact directory.\n * The directory is created lazily on first write.\n */\nexport class ArtifactManager {\n\t#nextId = 0;\n\treadonly #dir: string;\n\t#dirCreated = false;\n\t#initialized = false;\n\n\t/**\n\t * @param sessionFile Path to the session .jsonl file\n\t */\n\tconstructor(sessionFile: string) {\n\t\t// Artifact directory is session file path without .jsonl extension\n\t\tthis.#dir = sessionFile.slice(0, -6);\n\t}\n\n\t/**\n\t * Artifact directory path.\n\t * Directory may not exist until first artifact is saved.\n\t */\n\tget dir(): string {\n\t\treturn this.#dir;\n\t}\n\n\t#ensureDir(): void {\n\t\tif (!this.#dirCreated) {\n\t\t\tmkdirSync(this.#dir, { recursive: true });\n\t\t\tthis.#dirCreated = true;\n\t\t}\n\t\tif (!this.#initialized) {\n\t\t\tthis.#scanExistingIds();\n\t\t\tthis.#initialized = true;\n\t\t}\n\t}\n\n\t/**\n\t * Scan existing artifact files to find the next available ID.\n\t * Ensures we don't overwrite artifacts when resuming a session.\n\t */\n\t#scanExistingIds(): void {\n\t\tconst files = this.listFiles();\n\t\tlet maxId = -1;\n\t\tfor (const file of files) {\n\t\t\tconst match = file.match(/^(\\d+)\\..*\\.log$/);\n\t\t\tif (match) {\n\t\t\t\tconst id = parseInt(match[1], 10);\n\t\t\t\tif (id > maxId) maxId = id;\n\t\t\t}\n\t\t}\n\t\tthis.#nextId = maxId + 1;\n\t}\n\n\t/** Atomically allocate next artifact ID. */\n\tallocateId(): number {\n\t\treturn this.#nextId++;\n\t}\n\n\t/**\n\t * Allocate a new artifact path and ID without writing content.\n\t * @param toolType Tool name for file extension (e.g., \"bash\", \"fetch\")\n\t */\n\tallocatePath(toolType: string): { id: string; path: string } {\n\t\tthis.#ensureDir();\n\t\tconst id = String(this.allocateId());\n\t\tconst filename = `${id}.${toolType}.log`;\n\t\treturn { id, path: join(this.#dir, filename) };\n\t}\n\n\t/**\n\t * Save content as an artifact and return the artifact ID.\n\t * @param content Full content to save\n\t * @param toolType Tool name for file extension (e.g., \"bash\", \"fetch\")\n\t * @returns Artifact ID (numeric string)\n\t */\n\tsave(content: string, toolType: string): string {\n\t\tconst { id, path } = this.allocatePath(toolType);\n\t\twriteFileSync(path, content);\n\t\treturn id;\n\t}\n\n\t/**\n\t * Check if an artifact exists.\n\t * @param id Artifact ID (numeric string)\n\t */\n\texists(id: string): boolean {\n\t\tconst files = this.listFiles();\n\t\treturn files.some((f) => f.startsWith(`${id}.`));\n\t}\n\n\t/**\n\t * List all artifact files in the directory.\n\t * Returns empty array if directory doesn't exist.\n\t */\n\tlistFiles(): string[] {\n\t\ttry {\n\t\t\treturn readdirSync(this.#dir);\n\t\t} catch {\n\t\t\treturn [];\n\t\t}\n\t}\n\n\t/**\n\t * Get the full path to an artifact file.\n\t * Returns null if artifact doesn't exist.\n\t * @param id Artifact ID (numeric string)\n\t */\n\tgetPath(id: string): string | null {\n\t\tconst files = this.listFiles();\n\t\tconst match = files.find((f) => f.startsWith(`${id}.`));\n\t\treturn match ? join(this.#dir, match) : null;\n\t}\n}\n"]}
|
|
@@ -11,7 +11,7 @@ import { tmpdir } from "node:os";
|
|
|
11
11
|
import { join } from "node:path";
|
|
12
12
|
import { spawn } from "child_process";
|
|
13
13
|
import stripAnsi from "strip-ansi";
|
|
14
|
-
import { getShellConfig, getShellEnv, killProcessTree, sanitizeBinaryOutput } from "../utils/shell.js";
|
|
14
|
+
import { getShellConfig, getShellEnv, killProcessTree, sanitizeBinaryOutput, sanitizeCommand } from "../utils/shell.js";
|
|
15
15
|
import { DEFAULT_MAX_BYTES, truncateTail } from "./tools/truncate.js";
|
|
16
16
|
// ============================================================================
|
|
17
17
|
// Implementation
|
|
@@ -33,7 +33,7 @@ import { DEFAULT_MAX_BYTES, truncateTail } from "./tools/truncate.js";
|
|
|
33
33
|
export function executeBash(command, options) {
|
|
34
34
|
return new Promise((resolve, reject) => {
|
|
35
35
|
const { shell, args } = getShellConfig();
|
|
36
|
-
const child = spawn(shell, [...args, command], {
|
|
36
|
+
const child = spawn(shell, [...args, sanitizeCommand(command)], {
|
|
37
37
|
detached: true,
|
|
38
38
|
env: getShellEnv(),
|
|
39
39
|
stdio: ["ignore", "pipe", "pipe"],
|