@bacnh85/pi-model-tools 0.3.0 → 0.3.1
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 +3 -0
- package/extensions/index.ts +2 -1
- package/extensions/lib/apply-patch.ts +29 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -92,6 +92,9 @@ Rules:
|
|
|
92
92
|
- Context+removed must match **uniquely** in the file (diverges from Codex's
|
|
93
93
|
first-match for safety, matching `edit`'s philosophy). Add more context lines
|
|
94
94
|
if a match is ambiguous.
|
|
95
|
+
- If the `@@` anchor text repeats as the immediately-following context or
|
|
96
|
+
removed line (common when models treat `@@` as a diff-style locator header),
|
|
97
|
+
the duplicate is auto-collapsed — only one occurrence is matched.
|
|
95
98
|
- Matching is progressive-fuzzy (exact → strip-trailing-ws → strip-both-ws →
|
|
96
99
|
Unicode-normalize), so minor whitespace/Unicode differences still apply.
|
|
97
100
|
|
package/extensions/index.ts
CHANGED
|
@@ -220,7 +220,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
220
220
|
name: "apply_patch",
|
|
221
221
|
label: "apply_patch",
|
|
222
222
|
description: [
|
|
223
|
-
"Apply a Codex-style V4D patch to edit one or more files. Emit only changed lines plus a little surrounding context (a small diff), which is easier to get right than reproducing a large verbatim block. Supported sections: `*** Add File: <path>` (only `+` lines), `*** Delete File: <path>` (no payload), `*** Update File: <path>` or `*** Update File: <old> → <new>` (rename). Inside an Update section, each hunk is preceded by a `@@` anchor line whose text is an unchanged context line, then `-` removed lines and `+` added lines. Leading-space context lines (` `) are also allowed. Context+removed must match UNIQUELY in the file. Wrap the whole patch in `*** Begin Patch` ... `*** End Patch`.",
|
|
223
|
+
"Apply a Codex-style V4D patch to edit one or more files. Emit only changed lines plus a little surrounding context (a small diff), which is easier to get right than reproducing a large verbatim block. Supported sections: `*** Add File: <path>` (only `+` lines), `*** Delete File: <path>` (no payload), `*** Update File: <path>` or `*** Update File: <old> → <new>` (rename). Inside an Update section, each hunk is preceded by a `@@` anchor line whose text is an unchanged context line, then `-` removed lines and `+` added lines. Leading-space context lines (` `) are also allowed. If the @@ anchor text is restated as the immediately-following context or removed line, the duplicate is auto-collapsed. Context+removed must match UNIQUELY in the file. Wrap the whole patch in `*** Begin Patch` ... `*** End Patch`.",
|
|
224
224
|
"",
|
|
225
225
|
"Example:",
|
|
226
226
|
"*** Begin Patch", "*** Update File: src/foo.ts", "@@ export function foo()", "- return 1", "+ return 2", "*** End Patch",
|
|
@@ -229,6 +229,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
229
229
|
promptGuidelines: [
|
|
230
230
|
"Use apply_patch for multi-line or multi-file edits: emit a small diff (context + -/+ lines) instead of reproducing large verbatim oldText blocks.",
|
|
231
231
|
"Each Update hunk needs a unique anchor: include enough unchanged context lines so the context+removed block matches exactly once in the file.",
|
|
232
|
+
"If the @@ anchor repeats on the very next line (as space-context or -removed), the duplicate is auto-collapsed.",
|
|
232
233
|
"For a single tiny one-line replacement, edit is fine; for anything larger or spanning multiple files, prefer apply_patch.",
|
|
233
234
|
],
|
|
234
235
|
parameters: Type.Object({ patch: Type.String({ description: "The V4D patch text, wrapped in *** Begin Patch ... *** End Patch." }) }),
|
|
@@ -21,6 +21,10 @@
|
|
|
21
21
|
* Divergence from Codex: context+removed blocks must match UNIQUELY (Codex
|
|
22
22
|
* takes the first match). Silent wrong-location edits are worse than a clear
|
|
23
23
|
* error, and this matches pi's own `edit` philosophy.
|
|
24
|
+
*
|
|
25
|
+
* Leniency: if the @@ anchor text repeats as the immediately-following context
|
|
26
|
+
* or removed line (common when models treat `@@` as a git-diff-style locator
|
|
27
|
+
* header), the duplicate is collapsed automatically.
|
|
24
28
|
*/
|
|
25
29
|
|
|
26
30
|
import { readFile, writeFile, unlink } from "node:fs/promises";
|
|
@@ -208,6 +212,17 @@ function eqRstrip(a: string, b: string) { return a.trimEnd() === b.trimEnd(); }
|
|
|
208
212
|
function eqTrim(a: string, b: string) { return a.trim() === b.trim(); }
|
|
209
213
|
function eqUnicode(a: string, b: string) { return normalizeAscii(a) === normalizeAscii(b); }
|
|
210
214
|
|
|
215
|
+
/**
|
|
216
|
+
* Loose equality matching seekSequence's 4-pass progression. Used for dedup
|
|
217
|
+
* so the collapse is consistent with the matcher's own fuzzy boundaries.
|
|
218
|
+
*/
|
|
219
|
+
function linesLooselyEqual(a: string, b: string): boolean {
|
|
220
|
+
return a === b
|
|
221
|
+
|| a.trimEnd() === b.trimEnd()
|
|
222
|
+
|| a.trim() === b.trim()
|
|
223
|
+
|| normalizeAscii(a) === normalizeAscii(b);
|
|
224
|
+
}
|
|
225
|
+
|
|
211
226
|
/**
|
|
212
227
|
* Count matches of `pattern` lines within `lines`, trying progressively
|
|
213
228
|
* lenient equality. Returns count and first start index under the strictest
|
|
@@ -325,12 +340,23 @@ export async function applyPatchToFiles(parsed: ParsedPatch, cwd: string): Promi
|
|
|
325
340
|
const newHunks: { start: number; removedLen: number; added: string[] }[] = [];
|
|
326
341
|
|
|
327
342
|
for (const h of hunks) {
|
|
328
|
-
|
|
329
|
-
|
|
343
|
+
// ponytail: collapse a redundant @@ anchor the model restated as
|
|
344
|
+
// the first payload line (context or removed). Models treat `@@` like
|
|
345
|
+
// a git-diff locator header and repeat it as context/removed, which
|
|
346
|
+
// would otherwise require the line to appear twice consecutively in
|
|
347
|
+
// the file. Real Codex makes @@ a pure cursor-advance locator; we keep
|
|
348
|
+
// it in the match block so unique-match disambiguation still works
|
|
349
|
+
// (@@ fn / -dup), but drop the duplicate. Upgrade to full cursor
|
|
350
|
+
// semantics if unique-match is ever relaxed.
|
|
351
|
+
let matchBlock = [...h.context, ...h.removed];
|
|
352
|
+
if (matchBlock.length >= 2 && linesLooselyEqual(matchBlock[0], matchBlock[1])) {
|
|
353
|
+
matchBlock = matchBlock.slice(1);
|
|
354
|
+
}
|
|
355
|
+
const { count, firstIndex, exact: hExact } = seekSequence(work, matchBlock);
|
|
330
356
|
if (!hExact) exact = false;
|
|
331
357
|
if (count === 0) throw new Error(`Hunk context not found in ${op.path}. Ensure context lines match the file.`);
|
|
332
358
|
if (count > 1) throw new Error(`Hunk context is ambiguous (${count} matches) in ${op.path}. Add more surrounding context lines to make it unique.`);
|
|
333
|
-
const removedStart = firstIndex + h.
|
|
359
|
+
const removedStart = firstIndex + (matchBlock.length - h.removed.length);
|
|
334
360
|
newHunks.push({ start: removedStart, removedLen: h.removed.length, added: h.added });
|
|
335
361
|
}
|
|
336
362
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bacnh85/pi-model-tools",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Unified tool-wrapping, argument repair, reasoning management, DeepSeek V4 guidance + Super Power Mode, defensive leak-cleaning, edit mismatch repair (read-notice stripping + trim-tolerant retry), and a Codex-style apply_patch diff tool for DeepSeek V4 and GLM model families from any provider.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|