@cydm/pie 1.0.5 → 1.0.6
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/README.md +11 -0
- package/dist/builtin/extensions/ask-user/index.js +11 -2911
- package/dist/builtin/extensions/changelog/index.js +3 -8
- package/dist/builtin/extensions/deploy/index.js +1 -1
- package/dist/builtin/extensions/document-attachments/index.js +1 -0
- package/dist/builtin/extensions/files/index.js +1 -1
- package/dist/builtin/extensions/init/index.js +1 -3
- package/dist/builtin/extensions/kimi-attachments/index.js +1 -0
- package/dist/builtin/extensions/plan-mode/index.js +30 -97
- package/dist/builtin/extensions/subagent/index.js +26 -10994
- package/dist/builtin/extensions/todo/index.js +11 -2719
- package/dist/chunks/capabilities-FENCOHVA.js +9 -0
- package/dist/chunks/chunk-JYBXCEJJ.js +315 -0
- package/dist/chunks/chunk-MWFBYJOI.js +7334 -0
- package/dist/{builtin/extensions/questionnaire/index.js → chunks/chunk-RID3574D.js} +1453 -1488
- package/dist/chunks/chunk-TBJ25UWB.js +3657 -0
- package/dist/chunks/chunk-TG2EQLX2.js +43 -0
- package/dist/chunks/chunk-XZXLO7YB.js +322 -0
- package/dist/chunks/file-logger-AL5VVZHH.js +22 -0
- package/dist/chunks/src-EGWRDMLB.js +13 -0
- package/dist/chunks/src-WRUACRN2.js +132 -0
- package/dist/cli.js +1108 -15659
- package/package.json +4 -5
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
createCliHostCapabilities
|
|
4
|
+
} from "./chunk-JYBXCEJJ.js";
|
|
5
|
+
import "./chunk-RID3574D.js";
|
|
6
|
+
import "./chunk-TG2EQLX2.js";
|
|
7
|
+
export {
|
|
8
|
+
createCliHostCapabilities
|
|
9
|
+
};
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
Type
|
|
4
|
+
} from "./chunk-RID3574D.js";
|
|
5
|
+
|
|
6
|
+
// src/capabilities/bash/index.ts
|
|
7
|
+
import { spawn } from "child_process";
|
|
8
|
+
import { createWriteStream } from "fs";
|
|
9
|
+
import { tmpdir } from "os";
|
|
10
|
+
import { join } from "path";
|
|
11
|
+
import { randomBytes } from "crypto";
|
|
12
|
+
|
|
13
|
+
// src/capabilities/bash/truncate.ts
|
|
14
|
+
var DEFAULT_MAX_LINES = 2e3;
|
|
15
|
+
var DEFAULT_MAX_BYTES = 50 * 1024;
|
|
16
|
+
function formatSize(bytes) {
|
|
17
|
+
if (bytes < 1024) {
|
|
18
|
+
return `${bytes}B`;
|
|
19
|
+
} else if (bytes < 1024 * 1024) {
|
|
20
|
+
return `${(bytes / 1024).toFixed(1)}KB`;
|
|
21
|
+
} else {
|
|
22
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function truncateTail(content, options = {}) {
|
|
26
|
+
const maxLines = options.maxLines ?? DEFAULT_MAX_LINES;
|
|
27
|
+
const maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;
|
|
28
|
+
const totalBytes = Buffer.byteLength(content, "utf-8");
|
|
29
|
+
const lines = content.split("\n");
|
|
30
|
+
const totalLines = lines.length;
|
|
31
|
+
if (totalLines <= maxLines && totalBytes <= maxBytes) {
|
|
32
|
+
return {
|
|
33
|
+
content,
|
|
34
|
+
truncated: false,
|
|
35
|
+
truncatedBy: null,
|
|
36
|
+
totalLines,
|
|
37
|
+
totalBytes,
|
|
38
|
+
outputLines: totalLines,
|
|
39
|
+
outputBytes: totalBytes,
|
|
40
|
+
lastLinePartial: false,
|
|
41
|
+
maxLines,
|
|
42
|
+
maxBytes
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
const outputLinesArr = [];
|
|
46
|
+
let outputBytesCount = 0;
|
|
47
|
+
let truncatedBy = "lines";
|
|
48
|
+
let lastLinePartial = false;
|
|
49
|
+
for (let i = lines.length - 1; i >= 0 && outputLinesArr.length < maxLines; i--) {
|
|
50
|
+
const line = lines[i];
|
|
51
|
+
const lineBytes = Buffer.byteLength(line, "utf-8") + (outputLinesArr.length > 0 ? 1 : 0);
|
|
52
|
+
if (outputBytesCount + lineBytes > maxBytes) {
|
|
53
|
+
truncatedBy = "bytes";
|
|
54
|
+
if (outputLinesArr.length === 0) {
|
|
55
|
+
const truncatedLine = truncateStringToBytesFromEnd(line, maxBytes);
|
|
56
|
+
outputLinesArr.unshift(truncatedLine);
|
|
57
|
+
outputBytesCount = Buffer.byteLength(truncatedLine, "utf-8");
|
|
58
|
+
lastLinePartial = true;
|
|
59
|
+
}
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
outputLinesArr.unshift(line);
|
|
63
|
+
outputBytesCount += lineBytes;
|
|
64
|
+
}
|
|
65
|
+
if (outputLinesArr.length >= maxLines && outputBytesCount <= maxBytes) {
|
|
66
|
+
truncatedBy = "lines";
|
|
67
|
+
}
|
|
68
|
+
const outputContent = outputLinesArr.join("\n");
|
|
69
|
+
const finalOutputBytes = Buffer.byteLength(outputContent, "utf-8");
|
|
70
|
+
return {
|
|
71
|
+
content: outputContent,
|
|
72
|
+
truncated: true,
|
|
73
|
+
truncatedBy,
|
|
74
|
+
totalLines,
|
|
75
|
+
totalBytes,
|
|
76
|
+
outputLines: outputLinesArr.length,
|
|
77
|
+
outputBytes: finalOutputBytes,
|
|
78
|
+
lastLinePartial,
|
|
79
|
+
maxLines,
|
|
80
|
+
maxBytes
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function truncateStringToBytesFromEnd(str, maxBytes) {
|
|
84
|
+
const buf = Buffer.from(str, "utf-8");
|
|
85
|
+
if (buf.length <= maxBytes) {
|
|
86
|
+
return str;
|
|
87
|
+
}
|
|
88
|
+
let start = buf.length - maxBytes;
|
|
89
|
+
while (start < buf.length && (buf[start] & 192) === 128) {
|
|
90
|
+
start++;
|
|
91
|
+
}
|
|
92
|
+
return buf.slice(start).toString("utf-8");
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// src/capabilities/bash/index.ts
|
|
96
|
+
var bashSchema = Type.Object({
|
|
97
|
+
command: Type.String({ description: "The bash command to execute" }),
|
|
98
|
+
timeout: Type.Optional(
|
|
99
|
+
Type.Number({
|
|
100
|
+
description: "Timeout in seconds. Default: 120s (2 minutes). For longer tasks, explicitly set a higher value: { timeout: 600 } for npm install, { timeout: 600 } for cargo build, etc."
|
|
101
|
+
})
|
|
102
|
+
),
|
|
103
|
+
cwd: Type.Optional(Type.String({ description: "Working directory for the command" }))
|
|
104
|
+
});
|
|
105
|
+
var DEFAULT_TIMEOUT_SECONDS = 120;
|
|
106
|
+
function getTempFilePath() {
|
|
107
|
+
const id = randomBytes(8).toString("hex");
|
|
108
|
+
return join(tmpdir(), `pie-bash-${id}.log`);
|
|
109
|
+
}
|
|
110
|
+
function killProcessTree(pid) {
|
|
111
|
+
if (process.platform === "win32") {
|
|
112
|
+
try {
|
|
113
|
+
spawn("taskkill", ["/F", "/T", "/PID", String(pid)], {
|
|
114
|
+
stdio: "ignore",
|
|
115
|
+
detached: true
|
|
116
|
+
});
|
|
117
|
+
} catch {
|
|
118
|
+
}
|
|
119
|
+
} else {
|
|
120
|
+
try {
|
|
121
|
+
process.kill(-pid, "SIGKILL");
|
|
122
|
+
} catch {
|
|
123
|
+
try {
|
|
124
|
+
process.kill(pid, "SIGKILL");
|
|
125
|
+
} catch {
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
function createBashTool(defaultCwd) {
|
|
131
|
+
return {
|
|
132
|
+
name: "bash",
|
|
133
|
+
label: "bash",
|
|
134
|
+
description: `Execute a bash command in the current working directory. Returns stdout and stderr. Output is truncated to last ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). If truncated, full output is saved to a temp file. Default timeout: 120s. Use timeout parameter for longer tasks (e.g., npm install -> 600).`,
|
|
135
|
+
parameters: bashSchema,
|
|
136
|
+
execute: async (_toolCallId, { command, timeout, cwd }, signal, onUpdate) => {
|
|
137
|
+
const workingDir = cwd ?? defaultCwd ?? process.cwd();
|
|
138
|
+
const timeoutMs = (timeout ?? DEFAULT_TIMEOUT_SECONDS) * 1e3;
|
|
139
|
+
return new Promise((resolve, reject) => {
|
|
140
|
+
if (signal?.aborted) {
|
|
141
|
+
reject(new Error("Operation aborted"));
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
let tempFilePath;
|
|
145
|
+
let tempFileStream;
|
|
146
|
+
let totalBytes = 0;
|
|
147
|
+
const chunks = [];
|
|
148
|
+
let chunksBytes = 0;
|
|
149
|
+
const maxChunksBytes = DEFAULT_MAX_BYTES * 2;
|
|
150
|
+
let timedOut = false;
|
|
151
|
+
const child = spawn(command, [], {
|
|
152
|
+
shell: true,
|
|
153
|
+
cwd: workingDir,
|
|
154
|
+
env: process.env,
|
|
155
|
+
detached: true
|
|
156
|
+
// Allows killing entire process tree
|
|
157
|
+
});
|
|
158
|
+
const timeoutId = setTimeout(() => {
|
|
159
|
+
timedOut = true;
|
|
160
|
+
if (child.pid) {
|
|
161
|
+
killProcessTree(child.pid);
|
|
162
|
+
}
|
|
163
|
+
}, timeoutMs);
|
|
164
|
+
const onAbort = () => {
|
|
165
|
+
clearTimeout(timeoutId);
|
|
166
|
+
if (child.pid) {
|
|
167
|
+
killProcessTree(child.pid);
|
|
168
|
+
}
|
|
169
|
+
reject(new Error("Operation aborted"));
|
|
170
|
+
};
|
|
171
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
172
|
+
child.stdout?.on("data", (data) => {
|
|
173
|
+
totalBytes += data.length;
|
|
174
|
+
if (totalBytes > DEFAULT_MAX_BYTES && !tempFilePath) {
|
|
175
|
+
tempFilePath = getTempFilePath();
|
|
176
|
+
tempFileStream = createWriteStream(tempFilePath);
|
|
177
|
+
for (const chunk of chunks) {
|
|
178
|
+
tempFileStream.write(chunk);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
if (tempFileStream) {
|
|
182
|
+
tempFileStream.write(data);
|
|
183
|
+
}
|
|
184
|
+
chunks.push(data);
|
|
185
|
+
chunksBytes += data.length;
|
|
186
|
+
while (chunksBytes > maxChunksBytes && chunks.length > 1) {
|
|
187
|
+
const removed = chunks.shift();
|
|
188
|
+
chunksBytes -= removed.length;
|
|
189
|
+
}
|
|
190
|
+
if (onUpdate) {
|
|
191
|
+
const fullBuffer = Buffer.concat(chunks);
|
|
192
|
+
const fullText = fullBuffer.toString("utf-8");
|
|
193
|
+
const truncation = truncateTail(fullText);
|
|
194
|
+
onUpdate({
|
|
195
|
+
content: [{ type: "text", text: truncation.content || "" }],
|
|
196
|
+
details: {
|
|
197
|
+
exitCode: null,
|
|
198
|
+
signal: null,
|
|
199
|
+
timedOut: false,
|
|
200
|
+
truncation: truncation.truncated ? {
|
|
201
|
+
truncated: true,
|
|
202
|
+
truncatedBy: truncation.truncatedBy,
|
|
203
|
+
totalLines: truncation.totalLines,
|
|
204
|
+
outputLines: truncation.outputLines
|
|
205
|
+
} : void 0,
|
|
206
|
+
fullOutputPath: tempFilePath
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
child.stderr?.on("data", (data) => {
|
|
212
|
+
totalBytes += data.length;
|
|
213
|
+
if (totalBytes > DEFAULT_MAX_BYTES && !tempFilePath) {
|
|
214
|
+
tempFilePath = getTempFilePath();
|
|
215
|
+
tempFileStream = createWriteStream(tempFilePath);
|
|
216
|
+
for (const chunk of chunks) {
|
|
217
|
+
tempFileStream.write(chunk);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
if (tempFileStream) {
|
|
221
|
+
tempFileStream.write(data);
|
|
222
|
+
}
|
|
223
|
+
chunks.push(data);
|
|
224
|
+
chunksBytes += data.length;
|
|
225
|
+
while (chunksBytes > maxChunksBytes && chunks.length > 1) {
|
|
226
|
+
const removed = chunks.shift();
|
|
227
|
+
chunksBytes -= removed.length;
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
child.on("close", (code, sig) => {
|
|
231
|
+
clearTimeout(timeoutId);
|
|
232
|
+
signal?.removeEventListener("abort", onAbort);
|
|
233
|
+
if (tempFileStream) {
|
|
234
|
+
tempFileStream.end();
|
|
235
|
+
}
|
|
236
|
+
const fullBuffer = Buffer.concat(chunks);
|
|
237
|
+
let fullOutput = fullBuffer.toString("utf-8");
|
|
238
|
+
const truncation = truncateTail(fullOutput);
|
|
239
|
+
let outputText = truncation.content || "(no output)";
|
|
240
|
+
const details = {
|
|
241
|
+
exitCode: code,
|
|
242
|
+
signal: sig?.toString() ?? null,
|
|
243
|
+
timedOut
|
|
244
|
+
};
|
|
245
|
+
if (truncation.truncated) {
|
|
246
|
+
details.truncation = {
|
|
247
|
+
truncated: true,
|
|
248
|
+
truncatedBy: truncation.truncatedBy,
|
|
249
|
+
totalLines: truncation.totalLines,
|
|
250
|
+
outputLines: truncation.outputLines
|
|
251
|
+
};
|
|
252
|
+
details.fullOutputPath = tempFilePath;
|
|
253
|
+
const startLine = truncation.totalLines - truncation.outputLines + 1;
|
|
254
|
+
const endLine = truncation.totalLines;
|
|
255
|
+
if (truncation.lastLinePartial) {
|
|
256
|
+
const lastLineSize = formatSize(
|
|
257
|
+
Buffer.byteLength(fullOutput.split("\n").pop() || "", "utf-8")
|
|
258
|
+
);
|
|
259
|
+
outputText += `
|
|
260
|
+
|
|
261
|
+
[Showing last ${formatSize(truncation.outputBytes)} of line ${endLine} (line is ${lastLineSize}). Full output: ${tempFilePath}]`;
|
|
262
|
+
} else if (truncation.truncatedBy === "lines") {
|
|
263
|
+
outputText += `
|
|
264
|
+
|
|
265
|
+
[Showing lines ${startLine}-${endLine} of ${truncation.totalLines}. Full output: ${tempFilePath}]`;
|
|
266
|
+
} else {
|
|
267
|
+
outputText += `
|
|
268
|
+
|
|
269
|
+
[Showing lines ${startLine}-${endLine} of ${truncation.totalLines} (${formatSize(DEFAULT_MAX_BYTES)} limit). Full output: ${tempFilePath}]`;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
if (timedOut) {
|
|
273
|
+
outputText += `
|
|
274
|
+
|
|
275
|
+
[Command timed out after ${timeout ?? DEFAULT_TIMEOUT_SECONDS} seconds]`;
|
|
276
|
+
}
|
|
277
|
+
const content = [{ type: "text", text: outputText }];
|
|
278
|
+
if (code !== 0 && code !== null) {
|
|
279
|
+
reject(new Error(outputText));
|
|
280
|
+
} else {
|
|
281
|
+
resolve({ content, details });
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
child.on("error", (err) => {
|
|
285
|
+
clearTimeout(timeoutId);
|
|
286
|
+
signal?.removeEventListener("abort", onAbort);
|
|
287
|
+
if (tempFileStream) {
|
|
288
|
+
tempFileStream.end();
|
|
289
|
+
}
|
|
290
|
+
reject(err);
|
|
291
|
+
});
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// src/capabilities/index.ts
|
|
298
|
+
function createCliHostCapabilities(cwd) {
|
|
299
|
+
const bashTool = createBashTool(cwd);
|
|
300
|
+
const capabilities = [
|
|
301
|
+
{
|
|
302
|
+
id: "bash",
|
|
303
|
+
description: "Node/TUI host capability for executing shell commands in the local workspace.",
|
|
304
|
+
tools: [bashTool]
|
|
305
|
+
}
|
|
306
|
+
];
|
|
307
|
+
return {
|
|
308
|
+
capabilities,
|
|
309
|
+
tools: capabilities.flatMap((capability) => capability.tools)
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
export {
|
|
314
|
+
createCliHostCapabilities
|
|
315
|
+
};
|