@oh-my-pi/pi-coding-agent 13.7.5 → 13.7.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/CHANGELOG.md +10 -0
- package/package.json +7 -7
- package/src/tools/ast-edit.ts +9 -6
- package/src/tools/ast-grep.ts +11 -5
- package/src/tools/render-utils.ts +18 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [13.7.6] - 2026-03-04
|
|
6
|
+
### Added
|
|
7
|
+
|
|
8
|
+
- Exported `dedupeParseErrors` utility function to deduplicate parse error messages while preserving order
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- Reduced duplicate parse error messages when multiple patterns fail on the same file
|
|
13
|
+
- Normalized parse error output in ast-grep to remove pattern-specific prefixes and show only file-level errors
|
|
14
|
+
|
|
5
15
|
## [13.7.4] - 2026-03-04
|
|
6
16
|
### Added
|
|
7
17
|
- Added `fetch.useKagiSummarizer` setting to toggle Kagi Universal Summarizer usage in the fetch tool.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/pi-coding-agent",
|
|
4
|
-
"version": "13.7.
|
|
4
|
+
"version": "13.7.6",
|
|
5
5
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
6
6
|
"homepage": "https://github.com/can1357/oh-my-pi",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -41,12 +41,12 @@
|
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"@mozilla/readability": "^0.6",
|
|
44
|
-
"@oh-my-pi/omp-stats": "13.7.
|
|
45
|
-
"@oh-my-pi/pi-agent-core": "13.7.
|
|
46
|
-
"@oh-my-pi/pi-ai": "13.7.
|
|
47
|
-
"@oh-my-pi/pi-natives": "13.7.
|
|
48
|
-
"@oh-my-pi/pi-tui": "13.7.
|
|
49
|
-
"@oh-my-pi/pi-utils": "13.7.
|
|
44
|
+
"@oh-my-pi/omp-stats": "13.7.6",
|
|
45
|
+
"@oh-my-pi/pi-agent-core": "13.7.6",
|
|
46
|
+
"@oh-my-pi/pi-ai": "13.7.6",
|
|
47
|
+
"@oh-my-pi/pi-natives": "13.7.6",
|
|
48
|
+
"@oh-my-pi/pi-tui": "13.7.6",
|
|
49
|
+
"@oh-my-pi/pi-utils": "13.7.6",
|
|
50
50
|
"@sinclair/typebox": "^0.34",
|
|
51
51
|
"@xterm/headless": "^6.0",
|
|
52
52
|
"ajv": "^8.18",
|
package/src/tools/ast-edit.ts
CHANGED
|
@@ -16,6 +16,7 @@ import type { ToolSession } from ".";
|
|
|
16
16
|
import type { OutputMeta } from "./output-meta";
|
|
17
17
|
import { hasGlobPathChars, parseSearchPath, resolveToCwd } from "./path-utils";
|
|
18
18
|
import {
|
|
19
|
+
dedupeParseErrors,
|
|
19
20
|
formatCount,
|
|
20
21
|
formatEmptyMessage,
|
|
21
22
|
formatErrorMessage,
|
|
@@ -140,6 +141,7 @@ export class AstEditTool implements AgentTool<typeof astEditSchema, AstEditToolD
|
|
|
140
141
|
signal,
|
|
141
142
|
});
|
|
142
143
|
|
|
144
|
+
const dedupedParseErrors = dedupeParseErrors(result.parseErrors);
|
|
143
145
|
const formatPath = (filePath: string): string => {
|
|
144
146
|
const cleanPath = filePath.startsWith("/") ? filePath.slice(1) : filePath;
|
|
145
147
|
if (isDirectory) {
|
|
@@ -178,15 +180,15 @@ export class AstEditTool implements AgentTool<typeof astEditSchema, AstEditToolD
|
|
|
178
180
|
filesSearched: result.filesSearched,
|
|
179
181
|
applied: result.applied,
|
|
180
182
|
limitReached: result.limitReached,
|
|
181
|
-
parseErrors:
|
|
183
|
+
parseErrors: dedupedParseErrors,
|
|
182
184
|
scopePath,
|
|
183
185
|
files: fileList,
|
|
184
186
|
fileReplacements: [],
|
|
185
187
|
};
|
|
186
188
|
|
|
187
189
|
if (result.totalReplacements === 0) {
|
|
188
|
-
const parseMessage =
|
|
189
|
-
? `\n${formatParseErrors(
|
|
190
|
+
const parseMessage = dedupedParseErrors.length
|
|
191
|
+
? `\n${formatParseErrors(dedupedParseErrors).join("\n")}`
|
|
190
192
|
: "";
|
|
191
193
|
return toolResult(baseDetails).text(`No replacements made${parseMessage}`).done();
|
|
192
194
|
}
|
|
@@ -258,8 +260,8 @@ export class AstEditTool implements AgentTool<typeof astEditSchema, AstEditToolD
|
|
|
258
260
|
if (result.limitReached) {
|
|
259
261
|
outputLines.push("", "Limit reached; narrow path or increase limit.");
|
|
260
262
|
}
|
|
261
|
-
if (
|
|
262
|
-
outputLines.push("", ...formatParseErrors(
|
|
263
|
+
if (dedupedParseErrors.length) {
|
|
264
|
+
outputLines.push("", ...formatParseErrors(dedupedParseErrors));
|
|
263
265
|
}
|
|
264
266
|
|
|
265
267
|
// Register pending action so `resolve` can apply or discard these previewed changes
|
|
@@ -281,13 +283,14 @@ export class AstEditTool implements AgentTool<typeof astEditSchema, AstEditToolD
|
|
|
281
283
|
maxFiles,
|
|
282
284
|
failOnParseError: false,
|
|
283
285
|
});
|
|
286
|
+
const dedupedApplyParseErrors = dedupeParseErrors(applyResult.parseErrors);
|
|
284
287
|
const appliedDetails: AstEditToolDetails = {
|
|
285
288
|
totalReplacements: applyResult.totalReplacements,
|
|
286
289
|
filesTouched: applyResult.filesTouched,
|
|
287
290
|
filesSearched: applyResult.filesSearched,
|
|
288
291
|
applied: applyResult.applied,
|
|
289
292
|
limitReached: applyResult.limitReached,
|
|
290
|
-
parseErrors:
|
|
293
|
+
parseErrors: dedupedApplyParseErrors,
|
|
291
294
|
scopePath,
|
|
292
295
|
files: fileList,
|
|
293
296
|
fileReplacements,
|
package/src/tools/ast-grep.ts
CHANGED
|
@@ -16,6 +16,7 @@ import type { ToolSession } from ".";
|
|
|
16
16
|
import type { OutputMeta } from "./output-meta";
|
|
17
17
|
import { hasGlobPathChars, parseSearchPath, resolveToCwd } from "./path-utils";
|
|
18
18
|
import {
|
|
19
|
+
dedupeParseErrors,
|
|
19
20
|
formatCount,
|
|
20
21
|
formatEmptyMessage,
|
|
21
22
|
formatErrorMessage,
|
|
@@ -133,6 +134,11 @@ export class AstGrepTool implements AgentTool<typeof astGrepSchema, AstGrepToolD
|
|
|
133
134
|
signal,
|
|
134
135
|
});
|
|
135
136
|
|
|
137
|
+
const normalizedParseErrors = (result.parseErrors ?? []).map(error => {
|
|
138
|
+
const parseError = error.match(/^.+: (.+: parse error \(syntax tree contains error nodes\))$/);
|
|
139
|
+
return parseError?.[1] ?? error;
|
|
140
|
+
});
|
|
141
|
+
const dedupedParseErrors = dedupeParseErrors(normalizedParseErrors);
|
|
136
142
|
const formatPath = (filePath: string): string => {
|
|
137
143
|
const cleanPath = filePath.startsWith("/") ? filePath.slice(1) : filePath;
|
|
138
144
|
if (isDirectory) {
|
|
@@ -165,15 +171,15 @@ export class AstGrepTool implements AgentTool<typeof astGrepSchema, AstGrepToolD
|
|
|
165
171
|
fileCount: result.filesWithMatches,
|
|
166
172
|
filesSearched: result.filesSearched,
|
|
167
173
|
limitReached: result.limitReached,
|
|
168
|
-
parseErrors:
|
|
174
|
+
parseErrors: dedupedParseErrors,
|
|
169
175
|
scopePath,
|
|
170
176
|
files: fileList,
|
|
171
177
|
fileMatches: [],
|
|
172
178
|
};
|
|
173
179
|
|
|
174
180
|
if (result.matches.length === 0) {
|
|
175
|
-
const parseMessage =
|
|
176
|
-
? `\n${formatParseErrors(
|
|
181
|
+
const parseMessage = dedupedParseErrors.length
|
|
182
|
+
? `\n${formatParseErrors(dedupedParseErrors).join("\n")}`
|
|
177
183
|
: "";
|
|
178
184
|
return toolResult(baseDetails).text(`No matches found${parseMessage}`).done();
|
|
179
185
|
}
|
|
@@ -253,8 +259,8 @@ export class AstGrepTool implements AgentTool<typeof astGrepSchema, AstGrepToolD
|
|
|
253
259
|
if (result.limitReached) {
|
|
254
260
|
outputLines.push("", "Result limit reached; narrow path pattern or increase limit.");
|
|
255
261
|
}
|
|
256
|
-
if (
|
|
257
|
-
outputLines.push("", ...formatParseErrors(
|
|
262
|
+
if (dedupedParseErrors.length) {
|
|
263
|
+
outputLines.push("", ...formatParseErrors(dedupedParseErrors));
|
|
258
264
|
}
|
|
259
265
|
|
|
260
266
|
return toolResult(details).text(outputLines.join("\n")).done();
|
|
@@ -533,10 +533,25 @@ export function wrapBrackets(text: string, theme: Theme): string {
|
|
|
533
533
|
|
|
534
534
|
export const PARSE_ERRORS_LIMIT = 20;
|
|
535
535
|
|
|
536
|
+
export function dedupeParseErrors(errors: string[] | undefined): string[] {
|
|
537
|
+
if (!errors || errors.length === 0) return [];
|
|
538
|
+
const seen = new Set<string>();
|
|
539
|
+
const deduped: string[] = [];
|
|
540
|
+
for (const error of errors) {
|
|
541
|
+
if (seen.has(error)) continue;
|
|
542
|
+
seen.add(error);
|
|
543
|
+
deduped.push(error);
|
|
544
|
+
}
|
|
545
|
+
return deduped;
|
|
546
|
+
}
|
|
547
|
+
|
|
536
548
|
export function formatParseErrors(errors: string[]): string[] {
|
|
537
|
-
|
|
538
|
-
|
|
549
|
+
const deduped = dedupeParseErrors(errors);
|
|
550
|
+
if (deduped.length === 0) return [];
|
|
551
|
+
const capped = deduped.slice(0, PARSE_ERRORS_LIMIT);
|
|
539
552
|
const header =
|
|
540
|
-
|
|
553
|
+
deduped.length > PARSE_ERRORS_LIMIT
|
|
554
|
+
? `Parse issues (${PARSE_ERRORS_LIMIT} / ${deduped.length}):`
|
|
555
|
+
: "Parse issues:";
|
|
541
556
|
return [header, ...capped.map(err => `- ${err}`)];
|
|
542
557
|
}
|