pi-agent-flow 2.0.0 → 2.0.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/README.md +126 -489
- package/agents/audit.md +7 -2
- package/agents/build.md +6 -2
- package/agents/craft.md +6 -3
- package/agents/debug.md +7 -3
- package/agents/ideas.md +8 -4
- package/agents/scout.md +8 -1
- package/dist/batch/apply-patch.d.ts +60 -0
- package/dist/batch/apply-patch.d.ts.map +1 -0
- package/dist/batch/apply-patch.js +477 -0
- package/dist/batch/apply-patch.js.map +1 -0
- package/dist/batch/batch-bash.d.ts +0 -6
- package/dist/batch/batch-bash.d.ts.map +1 -1
- package/dist/batch/batch-bash.js +52 -14
- package/dist/batch/batch-bash.js.map +1 -1
- package/dist/batch/constants.d.ts +45 -4
- package/dist/batch/constants.d.ts.map +1 -1
- package/dist/batch/constants.js +72 -4
- package/dist/batch/constants.js.map +1 -1
- package/dist/batch/execute.d.ts +8 -2
- package/dist/batch/execute.d.ts.map +1 -1
- package/dist/batch/execute.js +338 -70
- package/dist/batch/execute.js.map +1 -1
- package/dist/batch/fuzzy-edit.d.ts +4 -1
- package/dist/batch/fuzzy-edit.d.ts.map +1 -1
- package/dist/batch/fuzzy-edit.js +7 -2
- package/dist/batch/fuzzy-edit.js.map +1 -1
- package/dist/batch/index.d.ts +3 -15
- package/dist/batch/index.d.ts.map +1 -1
- package/dist/batch/index.js +48 -78
- package/dist/batch/index.js.map +1 -1
- package/dist/batch/render.d.ts.map +1 -1
- package/dist/batch/render.js +30 -7
- package/dist/batch/render.js.map +1 -1
- package/dist/batch/shell-compress.d.ts +25 -0
- package/dist/batch/shell-compress.d.ts.map +1 -0
- package/dist/batch/shell-compress.js +602 -0
- package/dist/batch/shell-compress.js.map +1 -0
- package/dist/batch/summary.d.ts.map +1 -1
- package/dist/batch/summary.js +4 -0
- package/dist/batch/summary.js.map +1 -1
- package/dist/batch/symbols.d.ts.map +1 -1
- package/dist/batch/symbols.js +12 -7
- package/dist/batch/symbols.js.map +1 -1
- package/dist/config/config.d.ts +5 -0
- package/dist/config/config.d.ts.map +1 -1
- package/dist/config/config.js +63 -0
- package/dist/config/config.js.map +1 -1
- package/dist/config/models.d.ts +2 -0
- package/dist/config/models.d.ts.map +1 -0
- package/dist/config/models.js +49 -0
- package/dist/config/models.js.map +1 -0
- package/dist/config/settings-resolver.js +2 -2
- package/dist/config/settings-resolver.js.map +1 -1
- package/dist/core/agents.js +2 -2
- package/dist/core/agents.js.map +1 -1
- package/dist/core/depth.d.ts +3 -3
- package/dist/core/depth.d.ts.map +1 -1
- package/dist/core/depth.js +5 -5
- package/dist/core/depth.js.map +1 -1
- package/dist/core/executor.d.ts +10 -3
- package/dist/core/executor.d.ts.map +1 -1
- package/dist/core/executor.js +7 -3
- package/dist/core/executor.js.map +1 -1
- package/dist/core/flow.d.ts +19 -3
- package/dist/core/flow.d.ts.map +1 -1
- package/dist/core/flow.js +97 -58
- package/dist/core/flow.js.map +1 -1
- package/dist/core/session-mode.d.ts +1 -1
- package/dist/core/session-mode.d.ts.map +1 -1
- package/dist/core/session-mode.js +2 -1
- package/dist/core/session-mode.js.map +1 -1
- package/dist/core/{delegation.d.ts → transition.d.ts} +9 -9
- package/dist/core/transition.d.ts.map +1 -0
- package/dist/core/{delegation.js → transition.js} +17 -24
- package/dist/core/transition.js.map +1 -0
- package/dist/flow/auto-warp.d.ts +12 -0
- package/dist/flow/auto-warp.d.ts.map +1 -0
- package/dist/flow/auto-warp.js +29 -0
- package/dist/flow/auto-warp.js.map +1 -0
- package/dist/flow/command.d.ts.map +1 -1
- package/dist/flow/command.js +7 -2
- package/dist/flow/command.js.map +1 -1
- package/dist/flow/continuation.d.ts.map +1 -1
- package/dist/flow/continuation.js +52 -15
- package/dist/flow/continuation.js.map +1 -1
- package/dist/flow/index.d.ts +5 -2
- package/dist/flow/index.d.ts.map +1 -1
- package/dist/flow/index.js +6 -3
- package/dist/flow/index.js.map +1 -1
- package/dist/flow/loop-command.d.ts +8 -0
- package/dist/flow/loop-command.d.ts.map +1 -0
- package/dist/flow/loop-command.js +102 -0
- package/dist/flow/loop-command.js.map +1 -0
- package/dist/flow/loop-templates.d.ts +7 -0
- package/dist/flow/loop-templates.d.ts.map +1 -0
- package/dist/flow/loop-templates.js +38 -0
- package/dist/flow/loop-templates.js.map +1 -0
- package/dist/flow/loop.d.ts +19 -0
- package/dist/flow/loop.d.ts.map +1 -0
- package/dist/flow/loop.js +95 -0
- package/dist/flow/loop.js.map +1 -0
- package/dist/flow/settings-command.d.ts.map +1 -1
- package/dist/flow/settings-command.js +93 -4
- package/dist/flow/settings-command.js.map +1 -1
- package/dist/flow/store.d.ts +3 -3
- package/dist/flow/store.d.ts.map +1 -1
- package/dist/flow/store.js +24 -16
- package/dist/flow/store.js.map +1 -1
- package/dist/flow/template-shared.d.ts +9 -0
- package/dist/flow/template-shared.d.ts.map +1 -0
- package/dist/flow/template-shared.js +13 -0
- package/dist/flow/template-shared.js.map +1 -0
- package/dist/flow/template-strings.d.ts.map +1 -1
- package/dist/flow/template-strings.js +2 -5
- package/dist/flow/template-strings.js.map +1 -1
- package/dist/flow/types.d.ts +15 -9
- package/dist/flow/types.d.ts.map +1 -1
- package/dist/flow/warp.d.ts +15 -0
- package/dist/flow/warp.d.ts.map +1 -0
- package/dist/flow/warp.js +207 -0
- package/dist/flow/warp.js.map +1 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +185 -28
- package/dist/index.js.map +1 -1
- package/dist/snapshot/cli-args.d.ts +1 -0
- package/dist/snapshot/cli-args.d.ts.map +1 -1
- package/dist/snapshot/cli-args.js +12 -0
- package/dist/snapshot/cli-args.js.map +1 -1
- package/dist/snapshot/runner-events.d.ts +5 -0
- package/dist/snapshot/runner-events.d.ts.map +1 -1
- package/dist/snapshot/runner-events.js +89 -15
- package/dist/snapshot/runner-events.js.map +1 -1
- package/dist/snapshot/snapshot.d.ts +22 -19
- package/dist/snapshot/snapshot.d.ts.map +1 -1
- package/dist/snapshot/snapshot.js +1063 -167
- package/dist/snapshot/snapshot.js.map +1 -1
- package/dist/steering/flow-prompt.d.ts +2 -2
- package/dist/steering/flow-prompt.d.ts.map +1 -1
- package/dist/steering/flow-prompt.js +4 -4
- package/dist/steering/flow-prompt.js.map +1 -1
- package/dist/steering/sliding-prompt.d.ts.map +1 -1
- package/dist/steering/sliding-prompt.js +9 -6
- package/dist/steering/sliding-prompt.js.map +1 -1
- package/dist/steering/tool-utils.d.ts +31 -8
- package/dist/steering/tool-utils.d.ts.map +1 -1
- package/dist/steering/tool-utils.js +63 -30
- package/dist/steering/tool-utils.js.map +1 -1
- package/dist/tools/ask-user.d.ts +0 -17
- package/dist/tools/ask-user.d.ts.map +1 -1
- package/dist/tools/ask-user.js +13 -37
- package/dist/tools/ask-user.js.map +1 -1
- package/dist/tools/timed-bash.d.ts +1 -1
- package/dist/tools/timed-bash.d.ts.map +1 -1
- package/dist/tools/timed-bash.js +19 -8
- package/dist/tools/timed-bash.js.map +1 -1
- package/dist/tools/web-tool.d.ts.map +1 -1
- package/dist/tools/web-tool.js +11 -13
- package/dist/tools/web-tool.js.map +1 -1
- package/dist/tui/render-utils.d.ts +5 -1
- package/dist/tui/render-utils.d.ts.map +1 -1
- package/dist/tui/render-utils.js +36 -10
- package/dist/tui/render-utils.js.map +1 -1
- package/dist/tui/render.d.ts +9 -0
- package/dist/tui/render.d.ts.map +1 -1
- package/dist/tui/render.js +112 -100
- package/dist/tui/render.js.map +1 -1
- package/dist/tui/scramble/constants.d.ts +8 -8
- package/dist/tui/scramble/constants.d.ts.map +1 -1
- package/dist/tui/scramble/constants.js +7 -7
- package/dist/tui/scramble/constants.js.map +1 -1
- package/dist/tui/scramble/index.d.ts +1 -1
- package/dist/tui/scramble/index.d.ts.map +1 -1
- package/dist/tui/scramble/index.js +1 -1
- package/dist/tui/scramble/index.js.map +1 -1
- package/dist/tui/scramble/manager.d.ts +1 -5
- package/dist/tui/scramble/manager.d.ts.map +1 -1
- package/dist/tui/scramble/manager.js +16 -64
- package/dist/tui/scramble/manager.js.map +1 -1
- package/dist/tui/scramble/utils.js +1 -1
- package/dist/tui/scramble/utils.js.map +1 -1
- package/dist/types/flow.d.ts +2 -0
- package/dist/types/flow.d.ts.map +1 -1
- package/dist/types/flow.js +11 -2
- package/dist/types/flow.js.map +1 -1
- package/dist/types/output.d.ts +6 -0
- package/dist/types/output.d.ts.map +1 -1
- package/package.json +2 -2
- package/dist/core/delegation.d.ts.map +0 -1
- package/dist/core/delegation.js.map +0 -1
- package/dist/flow/warp-command.d.ts +0 -9
- package/dist/flow/warp-command.d.ts.map +0 -1
- package/dist/flow/warp-command.js +0 -405
- package/dist/flow/warp-command.js.map +0 -1
|
@@ -0,0 +1,477 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* apply-patch — 1:1 port of OpenAI Codex CLI apply_patch tool.
|
|
3
|
+
*
|
|
4
|
+
* Parses patch text into hunks, locates context via 4-stage fuzzy matching,
|
|
5
|
+
* computes replacements, and applies them to the filesystem.
|
|
6
|
+
*/
|
|
7
|
+
import * as fs from "node:fs/promises";
|
|
8
|
+
import * as path from "node:path";
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
// Parser constants
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
const BEGIN_PATCH_MARKER = "*** Begin Patch";
|
|
13
|
+
const END_PATCH_MARKER = "*** End Patch";
|
|
14
|
+
const ENVIRONMENT_ID_MARKER = "*** Environment ID: ";
|
|
15
|
+
const ADD_FILE_MARKER = "*** Add File: ";
|
|
16
|
+
const DELETE_FILE_MARKER = "*** Delete File: ";
|
|
17
|
+
const UPDATE_FILE_MARKER = "*** Update File: ";
|
|
18
|
+
const MOVE_TO_MARKER = "*** Move to: ";
|
|
19
|
+
const EOF_MARKER = "*** End of File";
|
|
20
|
+
const CHANGE_CONTEXT_MARKER = "@@ ";
|
|
21
|
+
const EMPTY_CHANGE_CONTEXT_MARKER = "@@";
|
|
22
|
+
export class ParseError extends Error {
|
|
23
|
+
kind;
|
|
24
|
+
lineNumber;
|
|
25
|
+
constructor(kind, message, lineNumber) {
|
|
26
|
+
super(message);
|
|
27
|
+
this.kind = kind;
|
|
28
|
+
this.lineNumber = lineNumber;
|
|
29
|
+
this.name = "ParseError";
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export class ComputeReplacementsError extends Error {
|
|
33
|
+
constructor(message) {
|
|
34
|
+
super(message);
|
|
35
|
+
this.name = "ComputeReplacementsError";
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
// Patch parser
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
function checkPatchBoundariesStrict(lines) {
|
|
42
|
+
if (lines.length === 0) {
|
|
43
|
+
throw new ParseError("invalid-patch", "The first line of the patch must be '*** Begin Patch'");
|
|
44
|
+
}
|
|
45
|
+
const first = lines[0].trim();
|
|
46
|
+
const last = lines[lines.length - 1].trim();
|
|
47
|
+
if (first !== BEGIN_PATCH_MARKER) {
|
|
48
|
+
throw new ParseError("invalid-patch", "The first line of the patch must be '*** Begin Patch'");
|
|
49
|
+
}
|
|
50
|
+
if (last !== END_PATCH_MARKER) {
|
|
51
|
+
throw new ParseError("invalid-patch", "The last line of the patch must be '*** End Patch'");
|
|
52
|
+
}
|
|
53
|
+
return { patchLines: lines, hunkLines: lines.slice(1, -1) };
|
|
54
|
+
}
|
|
55
|
+
function checkPatchBoundariesLenient(lines) {
|
|
56
|
+
try {
|
|
57
|
+
return checkPatchBoundariesStrict(lines);
|
|
58
|
+
}
|
|
59
|
+
catch (strictErr) {
|
|
60
|
+
if (lines.length >= 4) {
|
|
61
|
+
const first = lines[0].trim();
|
|
62
|
+
const last = lines[lines.length - 1].trim();
|
|
63
|
+
if ((first === "<<EOF" || first === "<<'EOF'" || first === '<<"EOF"') &&
|
|
64
|
+
last.endsWith("EOF")) {
|
|
65
|
+
const inner = lines.slice(1, -1);
|
|
66
|
+
try {
|
|
67
|
+
return checkPatchBoundariesStrict(inner);
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
/* fall through to return original error */
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
throw strictErr;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function parseEnvironmentIdPreamble(lines) {
|
|
78
|
+
if (lines.length === 0) {
|
|
79
|
+
return { remaining: lines, lineNumber: 2 };
|
|
80
|
+
}
|
|
81
|
+
const first = lines[0].trimStart();
|
|
82
|
+
if (first.startsWith(ENVIRONMENT_ID_MARKER)) {
|
|
83
|
+
const id = first.slice(ENVIRONMENT_ID_MARKER.length).trim();
|
|
84
|
+
if (id === "") {
|
|
85
|
+
throw new ParseError("invalid-patch", "apply_patch environment_id cannot be empty");
|
|
86
|
+
}
|
|
87
|
+
return { environmentId: id, remaining: lines.slice(1), lineNumber: 3 };
|
|
88
|
+
}
|
|
89
|
+
return { remaining: lines, lineNumber: 2 };
|
|
90
|
+
}
|
|
91
|
+
function parseUpdateFileChunk(lines, lineNumber, allowMissingContext) {
|
|
92
|
+
if (lines.length === 0) {
|
|
93
|
+
throw new ParseError("invalid-hunk", "Update hunk does not contain any lines", lineNumber);
|
|
94
|
+
}
|
|
95
|
+
let changeContext;
|
|
96
|
+
let startIndex = 0;
|
|
97
|
+
if (lines[0] === EMPTY_CHANGE_CONTEXT_MARKER) {
|
|
98
|
+
changeContext = undefined;
|
|
99
|
+
startIndex = 1;
|
|
100
|
+
}
|
|
101
|
+
else if (lines[0].startsWith(CHANGE_CONTEXT_MARKER)) {
|
|
102
|
+
changeContext = lines[0].slice(CHANGE_CONTEXT_MARKER.length);
|
|
103
|
+
startIndex = 1;
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
if (!allowMissingContext) {
|
|
107
|
+
throw new ParseError("invalid-hunk", `Expected update hunk to start with a @@ context marker, got: '${lines[0]}'`, lineNumber);
|
|
108
|
+
}
|
|
109
|
+
changeContext = undefined;
|
|
110
|
+
startIndex = 0;
|
|
111
|
+
}
|
|
112
|
+
if (startIndex >= lines.length) {
|
|
113
|
+
throw new ParseError("invalid-hunk", "Update hunk does not contain any lines", lineNumber + 1);
|
|
114
|
+
}
|
|
115
|
+
const oldLines = [];
|
|
116
|
+
const newLines = [];
|
|
117
|
+
let isEndOfFile = false;
|
|
118
|
+
let parsedLines = 0;
|
|
119
|
+
for (let i = startIndex; i < lines.length; i++) {
|
|
120
|
+
const line = lines[i];
|
|
121
|
+
if (line === EOF_MARKER) {
|
|
122
|
+
if (parsedLines === 0) {
|
|
123
|
+
throw new ParseError("invalid-hunk", "Update hunk does not contain any lines", lineNumber + 1);
|
|
124
|
+
}
|
|
125
|
+
isEndOfFile = true;
|
|
126
|
+
parsedLines += 1;
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
const firstChar = line.charAt(0);
|
|
130
|
+
if (firstChar === "") {
|
|
131
|
+
oldLines.push("");
|
|
132
|
+
newLines.push("");
|
|
133
|
+
}
|
|
134
|
+
else if (firstChar === " ") {
|
|
135
|
+
oldLines.push(line.slice(1));
|
|
136
|
+
newLines.push(line.slice(1));
|
|
137
|
+
}
|
|
138
|
+
else if (firstChar === "+") {
|
|
139
|
+
newLines.push(line.slice(1));
|
|
140
|
+
}
|
|
141
|
+
else if (firstChar === "-") {
|
|
142
|
+
oldLines.push(line.slice(1));
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
if (parsedLines === 0) {
|
|
146
|
+
throw new ParseError("invalid-hunk", `Unexpected line found in update hunk: '${line}'. Every line should start with ' ' (context line), '+' (added line), or '-' (removed line)`, lineNumber + 1);
|
|
147
|
+
}
|
|
148
|
+
// Assume start of next hunk.
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
parsedLines += 1;
|
|
152
|
+
}
|
|
153
|
+
return {
|
|
154
|
+
chunk: { changeContext, oldLines, newLines, isEndOfFile },
|
|
155
|
+
parsedLines: parsedLines + startIndex,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
function parseOneHunk(lines, lineNumber) {
|
|
159
|
+
const firstLine = lines[0].trim();
|
|
160
|
+
if (firstLine.startsWith(ADD_FILE_MARKER)) {
|
|
161
|
+
const filePath = firstLine.slice(ADD_FILE_MARKER.length);
|
|
162
|
+
let contents = "";
|
|
163
|
+
let parsedLines = 1;
|
|
164
|
+
for (let i = 1; i < lines.length; i++) {
|
|
165
|
+
const line = lines[i];
|
|
166
|
+
if (line.startsWith("+")) {
|
|
167
|
+
contents += line.slice(1) + "\n";
|
|
168
|
+
parsedLines += 1;
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return { hunk: { type: "add", path: filePath, contents }, parsedLines };
|
|
175
|
+
}
|
|
176
|
+
if (firstLine.startsWith(DELETE_FILE_MARKER)) {
|
|
177
|
+
const filePath = firstLine.slice(DELETE_FILE_MARKER.length);
|
|
178
|
+
return { hunk: { type: "delete", path: filePath }, parsedLines: 1 };
|
|
179
|
+
}
|
|
180
|
+
if (firstLine.startsWith(UPDATE_FILE_MARKER)) {
|
|
181
|
+
const filePath = firstLine.slice(UPDATE_FILE_MARKER.length);
|
|
182
|
+
let remaining = lines.slice(1);
|
|
183
|
+
let parsedLines = 1;
|
|
184
|
+
let movePath;
|
|
185
|
+
if (remaining.length > 0 && remaining[0].startsWith(MOVE_TO_MARKER)) {
|
|
186
|
+
movePath = remaining[0].slice(MOVE_TO_MARKER.length);
|
|
187
|
+
remaining = remaining.slice(1);
|
|
188
|
+
parsedLines += 1;
|
|
189
|
+
}
|
|
190
|
+
const chunks = [];
|
|
191
|
+
while (remaining.length > 0) {
|
|
192
|
+
if (remaining[0].trim() === "") {
|
|
193
|
+
parsedLines += 1;
|
|
194
|
+
remaining = remaining.slice(1);
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
if (remaining[0].startsWith("*")) {
|
|
198
|
+
break;
|
|
199
|
+
}
|
|
200
|
+
const { chunk, parsedLines: chunkLines } = parseUpdateFileChunk(remaining, lineNumber + parsedLines, chunks.length === 0);
|
|
201
|
+
chunks.push(chunk);
|
|
202
|
+
parsedLines += chunkLines;
|
|
203
|
+
remaining = remaining.slice(chunkLines);
|
|
204
|
+
}
|
|
205
|
+
if (chunks.length === 0) {
|
|
206
|
+
throw new ParseError("invalid-hunk", `Update file hunk for path '${filePath}' is empty`, lineNumber);
|
|
207
|
+
}
|
|
208
|
+
return { hunk: { type: "update", path: filePath, movePath, chunks }, parsedLines };
|
|
209
|
+
}
|
|
210
|
+
throw new ParseError("invalid-hunk", `'${firstLine}' is not a valid hunk header. Valid hunk headers: '*** Add File: {path}', '*** Delete File: {path}', '*** Update File: {path}'`, lineNumber);
|
|
211
|
+
}
|
|
212
|
+
export function parsePatch(patch) {
|
|
213
|
+
const trimmed = patch.trim();
|
|
214
|
+
const lines = trimmed.split("\n");
|
|
215
|
+
const { patchLines, hunkLines } = checkPatchBoundariesLenient(lines);
|
|
216
|
+
const { environmentId, remaining, lineNumber } = parseEnvironmentIdPreamble(hunkLines);
|
|
217
|
+
let remainingLines = remaining;
|
|
218
|
+
let currentLine = lineNumber;
|
|
219
|
+
const hunks = [];
|
|
220
|
+
while (remainingLines.length > 0) {
|
|
221
|
+
const { hunk, parsedLines } = parseOneHunk(remainingLines, currentLine);
|
|
222
|
+
hunks.push(hunk);
|
|
223
|
+
currentLine += parsedLines;
|
|
224
|
+
remainingLines = remainingLines.slice(parsedLines);
|
|
225
|
+
}
|
|
226
|
+
return {
|
|
227
|
+
patch: patchLines.join("\n"),
|
|
228
|
+
hunks,
|
|
229
|
+
environmentId,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
// ---------------------------------------------------------------------------
|
|
233
|
+
// seek_sequence — 4-stage fuzzy matching
|
|
234
|
+
// ---------------------------------------------------------------------------
|
|
235
|
+
export function seekSequence(lines, pattern, start, eof) {
|
|
236
|
+
if (pattern.length === 0) {
|
|
237
|
+
return start;
|
|
238
|
+
}
|
|
239
|
+
if (pattern.length > lines.length) {
|
|
240
|
+
return undefined;
|
|
241
|
+
}
|
|
242
|
+
const searchStart = eof && lines.length >= pattern.length ? lines.length - pattern.length : start;
|
|
243
|
+
// Stage 1: exact match
|
|
244
|
+
for (let i = searchStart; i <= lines.length - pattern.length; i++) {
|
|
245
|
+
let ok = true;
|
|
246
|
+
for (let j = 0; j < pattern.length; j++) {
|
|
247
|
+
if (lines[i + j] !== pattern[j]) {
|
|
248
|
+
ok = false;
|
|
249
|
+
break;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
if (ok)
|
|
253
|
+
return i;
|
|
254
|
+
}
|
|
255
|
+
// Stage 2: rstrip match (ignore trailing whitespace)
|
|
256
|
+
for (let i = searchStart; i <= lines.length - pattern.length; i++) {
|
|
257
|
+
let ok = true;
|
|
258
|
+
for (let j = 0; j < pattern.length; j++) {
|
|
259
|
+
if (lines[i + j].trimEnd() !== pattern[j].trimEnd()) {
|
|
260
|
+
ok = false;
|
|
261
|
+
break;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
if (ok)
|
|
265
|
+
return i;
|
|
266
|
+
}
|
|
267
|
+
// Stage 3: trim match (ignore leading and trailing whitespace)
|
|
268
|
+
for (let i = searchStart; i <= lines.length - pattern.length; i++) {
|
|
269
|
+
let ok = true;
|
|
270
|
+
for (let j = 0; j < pattern.length; j++) {
|
|
271
|
+
if (lines[i + j].trim() !== pattern[j].trim()) {
|
|
272
|
+
ok = false;
|
|
273
|
+
break;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
if (ok)
|
|
277
|
+
return i;
|
|
278
|
+
}
|
|
279
|
+
// Stage 4: Unicode normalisation
|
|
280
|
+
function normalise(s) {
|
|
281
|
+
return s
|
|
282
|
+
.trim()
|
|
283
|
+
.split("")
|
|
284
|
+
.map((c) => {
|
|
285
|
+
switch (c) {
|
|
286
|
+
// Dashes / hyphens → ASCII '-'
|
|
287
|
+
case "\u2010":
|
|
288
|
+
case "\u2011":
|
|
289
|
+
case "\u2012":
|
|
290
|
+
case "\u2013":
|
|
291
|
+
case "\u2014":
|
|
292
|
+
case "\u2015":
|
|
293
|
+
case "\u2212":
|
|
294
|
+
return "-";
|
|
295
|
+
// Fancy single quotes → '\''
|
|
296
|
+
case "\u2018":
|
|
297
|
+
case "\u2019":
|
|
298
|
+
case "\u201A":
|
|
299
|
+
case "\u201B":
|
|
300
|
+
return "'";
|
|
301
|
+
// Fancy double quotes → '"'
|
|
302
|
+
case "\u201C":
|
|
303
|
+
case "\u201D":
|
|
304
|
+
case "\u201E":
|
|
305
|
+
case "\u201F":
|
|
306
|
+
return '"';
|
|
307
|
+
// Odd spaces → normal space
|
|
308
|
+
case "\u00A0":
|
|
309
|
+
case "\u2002":
|
|
310
|
+
case "\u2003":
|
|
311
|
+
case "\u2004":
|
|
312
|
+
case "\u2005":
|
|
313
|
+
case "\u2006":
|
|
314
|
+
case "\u2007":
|
|
315
|
+
case "\u2008":
|
|
316
|
+
case "\u2009":
|
|
317
|
+
case "\u200A":
|
|
318
|
+
case "\u202F":
|
|
319
|
+
case "\u205F":
|
|
320
|
+
case "\u3000":
|
|
321
|
+
return " ";
|
|
322
|
+
default:
|
|
323
|
+
return c;
|
|
324
|
+
}
|
|
325
|
+
})
|
|
326
|
+
.join("");
|
|
327
|
+
}
|
|
328
|
+
for (let i = searchStart; i <= lines.length - pattern.length; i++) {
|
|
329
|
+
let ok = true;
|
|
330
|
+
for (let j = 0; j < pattern.length; j++) {
|
|
331
|
+
if (normalise(lines[i + j]) !== normalise(pattern[j])) {
|
|
332
|
+
ok = false;
|
|
333
|
+
break;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
if (ok)
|
|
337
|
+
return i;
|
|
338
|
+
}
|
|
339
|
+
return undefined;
|
|
340
|
+
}
|
|
341
|
+
// ---------------------------------------------------------------------------
|
|
342
|
+
// compute_replacements + apply_replacements
|
|
343
|
+
// ---------------------------------------------------------------------------
|
|
344
|
+
export function computeReplacements(originalLines, filePath, chunks) {
|
|
345
|
+
const replacements = [];
|
|
346
|
+
let lineIndex = 0;
|
|
347
|
+
for (const chunk of chunks) {
|
|
348
|
+
if (chunk.changeContext) {
|
|
349
|
+
const idx = seekSequence(originalLines, [chunk.changeContext], lineIndex, false);
|
|
350
|
+
if (idx === undefined) {
|
|
351
|
+
throw new ComputeReplacementsError(`Failed to find context '${chunk.changeContext}' in ${filePath}`);
|
|
352
|
+
}
|
|
353
|
+
lineIndex = idx + 1;
|
|
354
|
+
}
|
|
355
|
+
if (chunk.oldLines.length === 0) {
|
|
356
|
+
// Pure addition — insert at end (or just before the trailing empty line).
|
|
357
|
+
const insertionIdx = originalLines.length > 0 && originalLines[originalLines.length - 1] === ""
|
|
358
|
+
? originalLines.length - 1
|
|
359
|
+
: originalLines.length;
|
|
360
|
+
replacements.push({ startIdx: insertionIdx, oldLen: 0, newLines: chunk.newLines });
|
|
361
|
+
continue;
|
|
362
|
+
}
|
|
363
|
+
let pattern = chunk.oldLines;
|
|
364
|
+
let found = seekSequence(originalLines, pattern, lineIndex, chunk.isEndOfFile);
|
|
365
|
+
let newSlice = chunk.newLines;
|
|
366
|
+
if (found === undefined && pattern.length > 0 && pattern[pattern.length - 1] === "") {
|
|
367
|
+
// Retry without the trailing empty sentinel.
|
|
368
|
+
pattern = pattern.slice(0, -1);
|
|
369
|
+
if (newSlice.length > 0 && newSlice[newSlice.length - 1] === "") {
|
|
370
|
+
newSlice = newSlice.slice(0, -1);
|
|
371
|
+
}
|
|
372
|
+
found = seekSequence(originalLines, pattern, lineIndex, chunk.isEndOfFile);
|
|
373
|
+
}
|
|
374
|
+
if (found === undefined) {
|
|
375
|
+
throw new ComputeReplacementsError(`Failed to find expected lines in ${filePath}:\n${chunk.oldLines.join("\n")}`);
|
|
376
|
+
}
|
|
377
|
+
replacements.push({ startIdx: found, oldLen: pattern.length, newLines: newSlice });
|
|
378
|
+
lineIndex = found + pattern.length;
|
|
379
|
+
}
|
|
380
|
+
replacements.sort((a, b) => a.startIdx - b.startIdx);
|
|
381
|
+
return replacements;
|
|
382
|
+
}
|
|
383
|
+
export function applyReplacements(lines, replacements) {
|
|
384
|
+
const result = [...lines];
|
|
385
|
+
for (let i = replacements.length - 1; i >= 0; i--) {
|
|
386
|
+
const { startIdx, oldLen, newLines } = replacements[i];
|
|
387
|
+
result.splice(startIdx, oldLen, ...newLines);
|
|
388
|
+
}
|
|
389
|
+
return result;
|
|
390
|
+
}
|
|
391
|
+
function deriveNewContentsFromChunks(originalContent, chunks, filePath) {
|
|
392
|
+
let originalLines = originalContent.split("\n").map((l) => l);
|
|
393
|
+
// Drop the trailing empty element that results from the final newline
|
|
394
|
+
// so that line counts match the behaviour of standard diff.
|
|
395
|
+
if (originalLines.length > 0 && originalLines[originalLines.length - 1] === "") {
|
|
396
|
+
originalLines.pop();
|
|
397
|
+
}
|
|
398
|
+
const replacements = computeReplacements(originalLines, filePath, chunks);
|
|
399
|
+
let newLines = applyReplacements(originalLines, replacements);
|
|
400
|
+
// Ensure file terminates with a newline.
|
|
401
|
+
if (newLines.length === 0 || newLines[newLines.length - 1] !== "") {
|
|
402
|
+
newLines.push("");
|
|
403
|
+
}
|
|
404
|
+
return newLines.join("\n");
|
|
405
|
+
}
|
|
406
|
+
export async function applyPatch(patchText, cwd) {
|
|
407
|
+
const args = parsePatch(patchText);
|
|
408
|
+
const added = [];
|
|
409
|
+
const modified = [];
|
|
410
|
+
const deleted = [];
|
|
411
|
+
let exact = true;
|
|
412
|
+
for (const hunk of args.hunks) {
|
|
413
|
+
switch (hunk.type) {
|
|
414
|
+
case "add": {
|
|
415
|
+
const targetPath = path.resolve(cwd, hunk.path);
|
|
416
|
+
await fs.mkdir(path.dirname(targetPath), { recursive: true });
|
|
417
|
+
await fs.writeFile(targetPath, hunk.contents, "utf-8");
|
|
418
|
+
added.push(hunk.path);
|
|
419
|
+
break;
|
|
420
|
+
}
|
|
421
|
+
case "delete": {
|
|
422
|
+
const targetPath = path.resolve(cwd, hunk.path);
|
|
423
|
+
try {
|
|
424
|
+
await fs.unlink(targetPath);
|
|
425
|
+
}
|
|
426
|
+
catch (err) {
|
|
427
|
+
if (err.code === "ENOENT") {
|
|
428
|
+
exact = false;
|
|
429
|
+
}
|
|
430
|
+
else {
|
|
431
|
+
throw err;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
deleted.push(hunk.path);
|
|
435
|
+
break;
|
|
436
|
+
}
|
|
437
|
+
case "update": {
|
|
438
|
+
const targetPath = path.resolve(cwd, hunk.path);
|
|
439
|
+
let originalContent;
|
|
440
|
+
try {
|
|
441
|
+
originalContent = await fs.readFile(targetPath, "utf-8");
|
|
442
|
+
}
|
|
443
|
+
catch (err) {
|
|
444
|
+
if (err.code === "ENOENT") {
|
|
445
|
+
throw new Error(`File not found: ${hunk.path}`);
|
|
446
|
+
}
|
|
447
|
+
throw err;
|
|
448
|
+
}
|
|
449
|
+
const newContent = deriveNewContentsFromChunks(originalContent, hunk.chunks, hunk.path);
|
|
450
|
+
if (hunk.movePath) {
|
|
451
|
+
const destPath = path.resolve(cwd, hunk.movePath);
|
|
452
|
+
await fs.mkdir(path.dirname(destPath), { recursive: true });
|
|
453
|
+
await fs.writeFile(destPath, newContent, "utf-8");
|
|
454
|
+
try {
|
|
455
|
+
await fs.unlink(targetPath);
|
|
456
|
+
}
|
|
457
|
+
catch (err) {
|
|
458
|
+
if (err.code === "ENOENT") {
|
|
459
|
+
exact = false;
|
|
460
|
+
}
|
|
461
|
+
else {
|
|
462
|
+
throw err;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
modified.push(hunk.movePath);
|
|
466
|
+
}
|
|
467
|
+
else {
|
|
468
|
+
await fs.writeFile(targetPath, newContent, "utf-8");
|
|
469
|
+
modified.push(hunk.path);
|
|
470
|
+
}
|
|
471
|
+
break;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
return { affected: { added, modified, deleted }, exact };
|
|
476
|
+
}
|
|
477
|
+
//# sourceMappingURL=apply-patch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply-patch.js","sourceRoot":"","sources":["../../src/batch/apply-patch.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"batch-bash.d.ts","sourceRoot":"","sources":["../../src/batch/batch-bash.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"batch-bash.d.ts","sourceRoot":"","sources":["../../src/batch/batch-bash.ts"],"names":[],"mappings":"AAyBA,OAAO,EACN,KAAK,YAAY,EACjB,KAAK,iBAAiB,EAKtB,MAAM,gBAAgB,CAAC;AAgBxB,UAAU,iBAAiB;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,IAAI,GAAG,OAAO,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACnB;AAED;;;;GAIG;AACH,qBAAa,kBAAkB;IAC9B,OAAO,CAAC,OAAO,CAAqC;IACpD,OAAO,CAAC,SAAS,CAAwC;IAEzD,sFAAsF;IACtF,MAAM,CACL,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE,WAAW,GAClB,IAAI;IAwGP,2CAA2C;IAC3C,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAI9B,0DAA0D;IAC1D,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM;IAOlC,4CAA4C;IAC5C,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAIjD,iFAAiF;IACjF,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS;IAIxD,mFAAmF;IACnF,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS;IAMvD,+CAA+C;IAC/C,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAI5C,wCAAwC;IACxC,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAIjC,qCAAqC;IACrC,OAAO,CAAC,SAAS;IAWjB,6CAA6C;IAC7C,QAAQ,IAAI,IAAI;CAKhB;AAWD,sEAAsE;AACtE,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CACjC,IAAI,EAAE,MAAM,EACZ,QAAQ,GAAE,MAA8B,EACxC,QAAQ,GAAE,MAA8B,GACtC,MAAM,CA0CR;AAED,uEAAuE;AACvE,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CASrF;AAED;;;;;;;;GAQG;AACH,wBAAsB,gBAAgB,CACrC,GAAG,EAAE,KAAK,CAAC;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,EAC5D,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,kBAAkB,EAC3B,MAAM,CAAC,EAAE,WAAW,EACpB,aAAa,GAAE,MAA6B,GAC1C,OAAO,CAAC,YAAY,EAAE,CAAC,CAqDzB;AAoCD,uCAAuC;AACvC,wBAAgB,oBAAoB,CACnC,GAAG,EAAE,MAAM,EAAE,EACb,OAAO,EAAE,kBAAkB,GACzB,iBAAiB,EAAE,CAgCrB;AAaD,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,kBAAkB;;;;;;;4BAgBzC,OAAO,GAAG,OAAO;yBAS3B,MAAM,SACZ,OAAO,YACJ,WAAW,cACT,OAAO;;;;;;;;;EAkCrB"}
|
package/dist/batch/batch-bash.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { appendDirectiveOnce } from "../steering/tool-utils.js";
|
|
2
|
+
import { compressOutput } from "./shell-compress.js";
|
|
2
3
|
/**
|
|
3
4
|
* batch bash -- parallel bash execution and polling.
|
|
4
5
|
*
|
|
@@ -10,6 +11,13 @@ import { appendStrategicHintOnce } from "../steering/tool-utils.js";
|
|
|
10
11
|
* wait time before the batch tool returns partial results. Commands that
|
|
11
12
|
* haven't finished continue running in the background and can be polled
|
|
12
13
|
* via the `batch_bash_poll` tool.
|
|
14
|
+
*
|
|
15
|
+
* Why not `createLocalBashOperations` from `@mariozechner/pi-coding-agent`?
|
|
16
|
+
* That helper is a simple exec wrapper (returns a promise when the process exits).
|
|
17
|
+
* Our tracker needs background execution + polling: processes must outlive the
|
|
18
|
+
* soft timeout and be queried later via `batch_bash_poll`. We therefore use raw
|
|
19
|
+
* `node:child_process.spawn` directly to retain full control over detached mode,
|
|
20
|
+
* per-process AbortControllers, and background lifecycle.
|
|
13
21
|
*/
|
|
14
22
|
import { spawn } from "node:child_process";
|
|
15
23
|
import { Type } from "@sinclair/typebox";
|
|
@@ -62,8 +70,19 @@ export class BashProcessTracker {
|
|
|
62
70
|
}
|
|
63
71
|
child.on("close", (code) => {
|
|
64
72
|
this.running.delete(id);
|
|
65
|
-
|
|
66
|
-
|
|
73
|
+
let stdout;
|
|
74
|
+
let stderr;
|
|
75
|
+
try {
|
|
76
|
+
const rawStdout = rp.stdoutChunks.join("");
|
|
77
|
+
const rawStderr = rp.stderrChunks.join("");
|
|
78
|
+
const { stdout: compressedStdout, stderr: compressedStderr } = compressOutput(rp.command, rawStdout, rawStderr);
|
|
79
|
+
stdout = truncateBashOutput(compressedStdout);
|
|
80
|
+
stderr = truncateBashOutput(compressedStderr);
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
stdout = truncateBashOutput(rp.stdoutChunks.join(""));
|
|
84
|
+
stderr = truncateBashOutput(rp.stderrChunks.join(""));
|
|
85
|
+
}
|
|
67
86
|
const duration = Date.now() - rp.startedAt;
|
|
68
87
|
const report = classifyDuration(duration);
|
|
69
88
|
this.completed.set(id, {
|
|
@@ -81,8 +100,19 @@ export class BashProcessTracker {
|
|
|
81
100
|
this.running.delete(id);
|
|
82
101
|
const duration = Date.now() - rp.startedAt;
|
|
83
102
|
const report = classifyDuration(duration);
|
|
84
|
-
|
|
85
|
-
|
|
103
|
+
let stdout;
|
|
104
|
+
let stderr;
|
|
105
|
+
try {
|
|
106
|
+
const rawStdout = rp.stdoutChunks.join("");
|
|
107
|
+
const rawStderr = rp.stderrChunks.join("");
|
|
108
|
+
const { stdout: compressedStdout, stderr: compressedStderr } = compressOutput(rp.command, rawStdout, rawStderr);
|
|
109
|
+
stdout = truncateBashOutput(compressedStdout);
|
|
110
|
+
stderr = truncateBashOutput(compressedStderr) || err.message;
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
stdout = truncateBashOutput(rp.stdoutChunks.join(""));
|
|
114
|
+
stderr = truncateBashOutput(rp.stderrChunks.join("")) || err.message;
|
|
115
|
+
}
|
|
86
116
|
this.completed.set(id, {
|
|
87
117
|
id,
|
|
88
118
|
command,
|
|
@@ -182,14 +212,25 @@ export function truncateBashOutput(text, maxBytes = MAX_BASH_OUTPUT_BYTES, maxLi
|
|
|
182
212
|
const resultBytes = Buffer.byteLength(result, "utf-8");
|
|
183
213
|
if (resultBytes > maxBytes) {
|
|
184
214
|
const buf = Buffer.from(result, "utf-8");
|
|
185
|
-
// Find last newline before maxBytes
|
|
215
|
+
// Find last newline before maxBytes, never cutting inside a multi-byte UTF-8 character
|
|
186
216
|
let cutAt = maxBytes;
|
|
187
|
-
while (cutAt > 0
|
|
217
|
+
while (cutAt > 0) {
|
|
218
|
+
// Skip UTF-8 continuation bytes so we land on a character boundary
|
|
219
|
+
while (cutAt > 0 && (buf[cutAt] & 0xc0) === 0x80) {
|
|
220
|
+
cutAt--;
|
|
221
|
+
}
|
|
222
|
+
if (cutAt <= 0)
|
|
223
|
+
break;
|
|
224
|
+
if (buf[cutAt] === 0x0a)
|
|
225
|
+
break;
|
|
188
226
|
cutAt--;
|
|
189
227
|
}
|
|
190
228
|
if (cutAt <= 0) {
|
|
191
|
-
// No newline found within safe range; force cut at maxBytes
|
|
229
|
+
// No newline found within safe range; force cut at maxBytes aligned to char boundary
|
|
192
230
|
cutAt = maxBytes;
|
|
231
|
+
while (cutAt > 0 && (buf[cutAt] & 0xc0) === 0x80) {
|
|
232
|
+
cutAt--;
|
|
233
|
+
}
|
|
193
234
|
}
|
|
194
235
|
result = buf.slice(0, cutAt).toString("utf-8");
|
|
195
236
|
result += `\n[... truncated at ${(maxBytes / 1024).toFixed(0)} KB, ${totalBytes} total ...]`;
|
|
@@ -349,7 +390,7 @@ export function createBatchBashPollTool(tracker) {
|
|
|
349
390
|
].join("\n"),
|
|
350
391
|
promptSnippet: "Poll pending bash commands for results",
|
|
351
392
|
promptGuidelines: [
|
|
352
|
-
"Use batch_bash_poll to check on bash commands that returned pending from a batch call.",
|
|
393
|
+
"Use `batch_bash_poll` to check on bash commands that returned pending from a batch call.",
|
|
353
394
|
"Pass the `i` (id) values from the pending results.",
|
|
354
395
|
],
|
|
355
396
|
parameters: BatchBashPollParams,
|
|
@@ -366,10 +407,7 @@ export function createBatchBashPollTool(tracker) {
|
|
|
366
407
|
const args = (input ?? {});
|
|
367
408
|
const ids = Array.isArray(args.i) ? args.i : Array.isArray(args.ids) ? args.ids : [];
|
|
368
409
|
if (ids.length === 0) {
|
|
369
|
-
|
|
370
|
-
content: [{ type: "text", text: "Error: i (ids) array is required and must not be empty." }],
|
|
371
|
-
isError: true,
|
|
372
|
-
};
|
|
410
|
+
throw new Error("Error: i (ids) array is required and must not be empty.");
|
|
373
411
|
}
|
|
374
412
|
const results = pollBatchBashResults(ids, tracker);
|
|
375
413
|
const lines = [];
|
|
@@ -395,7 +433,7 @@ export function createBatchBashPollTool(tracker) {
|
|
|
395
433
|
content: [{ type: "text", text: lines.join("\n").trimEnd() }],
|
|
396
434
|
details: { results },
|
|
397
435
|
};
|
|
398
|
-
|
|
436
|
+
appendDirectiveOnce(pollResult);
|
|
399
437
|
return pollResult;
|
|
400
438
|
},
|
|
401
439
|
};
|