@d3ara1n/pi-hashline-edit 0.3.1 → 0.3.3
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/package.json +1 -1
- package/src/pi/edit-tool.ts +33 -16
- package/src/pi/replace-tool.ts +8 -2
package/package.json
CHANGED
package/src/pi/edit-tool.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Override edit: hashline ops via structured `edits` (LINE#HASH anchors).
|
|
3
3
|
*
|
|
4
|
-
* Each op in `edits` references line anchors copied from read
|
|
5
|
-
* prior edit's "Updated anchors"). The core verifies each anchor live against
|
|
4
|
+
* Each op in `edits` references line anchors copied from read / grep / replace output
|
|
5
|
+
* (or from a prior edit's "Updated anchors"). The core verifies each anchor live against
|
|
6
6
|
* the current file content — no snapshot, no global stale check: a cited line
|
|
7
7
|
* that changed (or was misremembered) fails its own anchor; unchanged lines
|
|
8
8
|
* elsewhere never block the edit. Legacy oldText/newText is not accepted — the
|
|
@@ -32,25 +32,41 @@ import { getState } from "./state.ts";
|
|
|
32
32
|
/** Cap on the number of updated anchors returned inline (bounds token cost for large inserts). */
|
|
33
33
|
const MAX_ANCHOR_LINES = 40;
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
35
|
+
/** `{line, hash}` anchor pair as an op field, described per use. */
|
|
36
|
+
function anchorRef(description: string) {
|
|
37
|
+
return Type.Optional(
|
|
38
|
+
Type.Object(
|
|
39
|
+
{
|
|
40
|
+
line: Type.Number({ description: "1-based line number" }),
|
|
41
|
+
hash: Type.String({ description: "Line content hash copied from read output (the #HASH after the line number)" }),
|
|
42
|
+
},
|
|
43
|
+
{ description },
|
|
44
|
+
),
|
|
45
|
+
);
|
|
46
|
+
}
|
|
39
47
|
|
|
40
48
|
const editOpSchema = Type.Object({
|
|
41
49
|
op: Type.Union(
|
|
42
50
|
[
|
|
43
|
-
Type.Literal("replace"),
|
|
44
|
-
Type.Literal("delete"),
|
|
45
|
-
Type.Literal("insert_after"
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
Type.Literal("
|
|
51
|
+
Type.Literal("replace", { description: "Replace the cited line(s) with `body`." }),
|
|
52
|
+
Type.Literal("delete", { description: "Delete the cited line(s)." }),
|
|
53
|
+
Type.Literal("insert_after", {
|
|
54
|
+
description: "Insert `body` immediately after the anchor line — the anchor line is kept as-is; do NOT copy it into `body`.",
|
|
55
|
+
}),
|
|
56
|
+
Type.Literal("insert_before", {
|
|
57
|
+
description: "Insert `body` immediately before the anchor line — the anchor line is kept as-is; do NOT copy it into `body`.",
|
|
58
|
+
}),
|
|
59
|
+
Type.Literal("append", { description: "Append `body` at the end of the file." }),
|
|
60
|
+
Type.Literal("prepend", { description: "Prepend `body` at the start of the file." }),
|
|
49
61
|
],
|
|
50
62
|
{ description: "Operation kind" },
|
|
51
63
|
),
|
|
52
|
-
anchor:
|
|
53
|
-
|
|
64
|
+
anchor: anchorRef(
|
|
65
|
+
"First line of the range (replace/delete) or the insertion point (insert_after/insert_before).",
|
|
66
|
+
),
|
|
67
|
+
end: anchorRef(
|
|
68
|
+
"Last line of the range to replace/delete, inclusive: the op touches exactly [anchor..end]. Omit only for a single-line change (end == anchor). A multi-line change that forgets `end` succeeds silently with the rest of the intended range left in the file — a corrupted file, not an error.",
|
|
69
|
+
),
|
|
54
70
|
body: Type.Optional(Type.Array(Type.String(), { description: "New content lines (required for replace/insert/append/prepend; omit for delete)" })),
|
|
55
71
|
});
|
|
56
72
|
|
|
@@ -180,12 +196,13 @@ export function makeEditOverride(cwd: string) {
|
|
|
180
196
|
name: "edit" as const,
|
|
181
197
|
label: "edit",
|
|
182
198
|
description:
|
|
183
|
-
|
|
199
|
+
"Edit a file via hashline ops (LINE#HASH anchors, content-verified). Each op in `edits` references line anchors from your latest read, grep, replace, or edit result.",
|
|
184
200
|
promptSnippet: "Edit files via hashline ops (edits[] with LINE#HASH anchors from read)",
|
|
185
201
|
promptGuidelines: [
|
|
186
202
|
"Pass `edits`: an array of ops. Each op = {op, anchor?, end?, body?}.",
|
|
203
|
+
"Prefer one `edit` with multiple ops for several changes to the same file, rather than several separate `edit` calls.",
|
|
187
204
|
"op ∈ replace | delete | insert_after | insert_before | append | prepend.",
|
|
188
|
-
|
|
205
|
+
"anchor & end = {line, hash} copied from your latest read, grep, replace, or edit result (the `#HASH` after each line number); grep's `-C` context lines are anchored and editable too. replace/delete take anchor (+ optional end for a range); insert_after/insert_before take anchor; append/prepend take neither.",
|
|
189
206
|
"body = string[] of new content lines (required for replace/insert/append/prepend; omit for delete).",
|
|
190
207
|
"A successful edit returns `Updated anchors` for the changed lines — use those (not stale line numbers) for the next edit to the same file; re-read only if you need lines outside that set.",
|
|
191
208
|
],
|
package/src/pi/replace-tool.ts
CHANGED
|
@@ -283,10 +283,16 @@ async function runReplace(
|
|
|
283
283
|
}
|
|
284
284
|
}
|
|
285
285
|
|
|
286
|
-
|
|
286
|
+
// generateDiffString / generateUnifiedPatch split on \n, so raw CRLF content would
|
|
287
|
+
// leave a trailing \r on every diff line — the TUI line-wrapper (wrapTextWithAnsi)
|
|
288
|
+
// then emits a spurious blank line per diff line. Normalize to LF for diff/patch
|
|
289
|
+
// only; the disk write above already preserved the original line endings.
|
|
290
|
+
const oldLf = currentText.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
291
|
+
const newLf = newText.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
292
|
+
const { diff, firstChangedLine } = generateDiffString(oldLf, newLf);
|
|
287
293
|
const details: EditToolDetails = {
|
|
288
294
|
diff,
|
|
289
|
-
patch: generateUnifiedPatch(displayPath,
|
|
295
|
+
patch: generateUnifiedPatch(displayPath, oldLf, newLf),
|
|
290
296
|
firstChangedLine,
|
|
291
297
|
};
|
|
292
298
|
|