pi-hashline-edit-pro 2.8.4 → 3.0.0
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 +24 -24
- package/package.json +2 -2
- package/prompts/grep-guidelines.md +3 -3
- package/prompts/grep.md +1 -1
- package/prompts/insert-guidelines.md +1 -3
- package/prompts/insert-snippet.md +1 -1
- package/prompts/insert.md +1 -1
- package/prompts/read-guidelines.md +2 -2
- package/prompts/read.md +1 -1
- package/prompts/replace-guidelines.md +4 -5
- package/prompts/replace-snippet.md +1 -1
- package/prompts/replace.md +1 -1
- package/prompts/undo-last-change-guidelines.md +1 -2
- package/prompts/undo-last-change.md +1 -1
- package/src/commit.ts +1 -1
- package/src/config.ts +1 -1
- package/src/constants.ts +1 -1
- package/src/grep.ts +5 -5
- package/src/hashline/alphabet.ts +30 -7
- package/src/hashline/anchor-table.json +1 -0
- package/src/hashline/hash.ts +6 -28
- package/src/hashline/parse.ts +8 -8
- package/src/hashline/resolve.ts +3 -3
- package/src/insert.ts +6 -6
- package/src/payload-contract.ts +5 -5
- package/src/utils.ts +1 -1
package/src/hashline/hash.ts
CHANGED
|
@@ -7,36 +7,20 @@ import {
|
|
|
7
7
|
persistSnapshot,
|
|
8
8
|
} from "../hash-store";
|
|
9
9
|
import { xxh32, initHasher } from "./hasher";
|
|
10
|
-
import { HASH_LEN,
|
|
11
|
-
export { initHasher, HASH_LEN,
|
|
10
|
+
import { HASH_LEN, ANCHOR_COUNT, anchorAt, anchorIndex, HASH_CLASS, HASH_RUN } from "./alphabet";
|
|
11
|
+
export { initHasher, HASH_LEN, HASH_CLASS, HASH_RUN };
|
|
12
12
|
|
|
13
13
|
export const ANCHOR_LEN = HASH_LEN;
|
|
14
14
|
|
|
15
15
|
export const HASH_SEP = "│";
|
|
16
16
|
|
|
17
|
-
export const HASH_SPACE =
|
|
17
|
+
export const HASH_SPACE = ANCHOR_COUNT;
|
|
18
18
|
export const MAX_HASH_LINES = HASH_SPACE;
|
|
19
19
|
|
|
20
|
-
export const HASH_PROBE_STRIDE =
|
|
21
|
-
|
|
22
|
-
function idxToHash(idx: number): string {
|
|
23
|
-
let out = "";
|
|
24
|
-
for (let j = 0; j < HASH_LEN; j++) {
|
|
25
|
-
out = ALPH[idx % ALPH.length]! + out;
|
|
26
|
-
idx = Math.floor(idx / ALPH.length);
|
|
27
|
-
}
|
|
28
|
-
return out;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const hashCache = new Map<number, string>();
|
|
20
|
+
export const HASH_PROBE_STRIDE = 571;
|
|
32
21
|
|
|
33
22
|
function hashAt(idx: number): string {
|
|
34
|
-
|
|
35
|
-
if (hash === undefined) {
|
|
36
|
-
hash = idxToHash(idx);
|
|
37
|
-
hashCache.set(idx, hash);
|
|
38
|
-
}
|
|
39
|
-
return hash;
|
|
23
|
+
return anchorAt(idx);
|
|
40
24
|
}
|
|
41
25
|
|
|
42
26
|
export const HL_PREFIX_PLUS_RE = new RegExp(
|
|
@@ -182,13 +166,7 @@ export async function lineHashes(
|
|
|
182
166
|
}
|
|
183
167
|
|
|
184
168
|
function hashToIndex(hash: string): number {
|
|
185
|
-
|
|
186
|
-
for (let j = 0; j < HASH_LEN; j++) {
|
|
187
|
-
const charIdx = ALPH.indexOf(hash[j]!);
|
|
188
|
-
if (charIdx < 0) return -1;
|
|
189
|
-
idx = idx * ALPH.length + charIdx;
|
|
190
|
-
}
|
|
191
|
-
return idx;
|
|
169
|
+
return anchorIndex(hash);
|
|
192
170
|
}
|
|
193
171
|
|
|
194
172
|
function nearestNew(
|
package/src/hashline/parse.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ANCHOR_LEN,
|
|
3
|
-
ALPH_RE,
|
|
4
3
|
HASH_CLASS,
|
|
5
4
|
} from "./hash";
|
|
5
|
+
import { ALPH_RE } from "./alphabet";
|
|
6
6
|
import { NEW_CONTENT_NOT_ARRAY_MSG } from "../constants";
|
|
7
7
|
|
|
8
8
|
const HASH_EXTRACT_RE = new RegExp(HASH_CLASS);
|
|
@@ -13,11 +13,11 @@ function diagRef(ref: string): string {
|
|
|
13
13
|
const trimmed = ref.trim();
|
|
14
14
|
|
|
15
15
|
if (!trimmed.length) {
|
|
16
|
-
return `[E_BAD_REF] Invalid anchor. Expected a
|
|
16
|
+
return `[E_BAD_REF] Invalid anchor. Expected a 4-char alphanumeric anchor (e.g. "Hasu").`;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
if (/^\d+/.test(trimmed)) {
|
|
20
|
-
return `[E_BAD_REF] Invalid anchor. Use the anchor alone (e.g. "
|
|
20
|
+
return `[E_BAD_REF] Invalid anchor. Use the anchor alone (e.g. "Hasu"): no line numbers or trailing content.`;
|
|
21
21
|
}
|
|
22
22
|
if (trimmed.includes("│") && trimmed.includes("\n")) {
|
|
23
23
|
const lines = trimmed.split(/\r?\n/);
|
|
@@ -26,16 +26,16 @@ function diagRef(ref: string): string {
|
|
|
26
26
|
const hashRe = HASH_EXTRACT_RE;
|
|
27
27
|
const firstMatch = first.match(hashRe);
|
|
28
28
|
const lastMatch = last.match(hashRe);
|
|
29
|
-
const firstHash = firstMatch?.[0] ?? "
|
|
30
|
-
const lastHash = lastMatch?.[0] ?? "
|
|
29
|
+
const firstHash = firstMatch?.[0] ?? "Hasu";
|
|
30
|
+
const lastHash = lastMatch?.[0] ?? "Hasu";
|
|
31
31
|
const preview = first.slice(0, 60);
|
|
32
|
-
return `[E_BAD_REF] Invalid anchor — remove_from and remove_to must each be a single bare
|
|
32
|
+
return `[E_BAD_REF] Invalid anchor — remove_from and remove_to must each be a single bare 4-char hash (e.g. "Hasu"), not a block with HASH│content. Received ${lines.length} lines starting "${preview}…" — use only the first hash "${firstHash}" as remove_from and "${lastHash}" as remove_to, and put the new content (without HASH│) in replacement_lines.`;
|
|
33
33
|
}
|
|
34
34
|
if (trimmed.includes("│")) {
|
|
35
|
-
return `[E_BAD_REF] Invalid anchor "${trimmed}": use only the
|
|
35
|
+
return `[E_BAD_REF] Invalid anchor "${trimmed}": use only the 4-char anchor, drop everything from "│" onward.`;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
return `[E_BAD_REF] Invalid anchor "${trimmed}". Expected a
|
|
38
|
+
return `[E_BAD_REF] Invalid anchor "${trimmed}". Expected a 4-char alphanumeric anchor (e.g. "Hasu").`;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
function parseRef(ref: string): Anchor {
|
package/src/hashline/resolve.ts
CHANGED
|
@@ -159,12 +159,12 @@ function assertItem(edit: Record<string, unknown>): void {
|
|
|
159
159
|
|
|
160
160
|
if ("remove_from" in edit && typeof edit.remove_from !== "string") {
|
|
161
161
|
throw new Error(
|
|
162
|
-
`[E_BAD_SHAPE] Field "remove_from" must be an anchor string (
|
|
162
|
+
`[E_BAD_SHAPE] Field "remove_from" must be an anchor string (4-char anchor).`,
|
|
163
163
|
);
|
|
164
164
|
}
|
|
165
165
|
if ("remove_to" in edit && typeof edit.remove_to !== "string") {
|
|
166
166
|
throw new Error(
|
|
167
|
-
`[E_BAD_SHAPE] Field "remove_to" must be an anchor string (
|
|
167
|
+
`[E_BAD_SHAPE] Field "remove_to" must be an anchor string (4-char anchor).`,
|
|
168
168
|
);
|
|
169
169
|
}
|
|
170
170
|
if (!("replacement_lines" in edit)) {
|
|
@@ -175,7 +175,7 @@ function assertItem(edit: Record<string, unknown>): void {
|
|
|
175
175
|
}
|
|
176
176
|
if (typeof edit.remove_from !== "string" || typeof edit.remove_to !== "string") {
|
|
177
177
|
throw new Error(
|
|
178
|
-
`[E_BAD_SHAPE] The edit requires "remove_from" and "remove_to" anchor strings (
|
|
178
|
+
`[E_BAD_SHAPE] The edit requires "remove_from" and "remove_to" anchor strings (4-char anchors from read output).`,
|
|
179
179
|
);
|
|
180
180
|
}
|
|
181
181
|
}
|
package/src/insert.ts
CHANGED
|
@@ -31,7 +31,7 @@ export function assertInsertReq(request: unknown): asserts request is InsertReq
|
|
|
31
31
|
throw new Error('[E_BAD_SHAPE] Insert request requires a non-empty "path" string.');
|
|
32
32
|
}
|
|
33
33
|
if (typeof request.anchor !== "string" || request.anchor.length === 0) {
|
|
34
|
-
throw new Error('[E_BAD_SHAPE] Insert request requires an "anchor" string (
|
|
34
|
+
throw new Error('[E_BAD_SHAPE] Insert request requires an "anchor" string (4-char anchor from read output).');
|
|
35
35
|
}
|
|
36
36
|
if (request.direction !== "before" && request.direction !== "after") {
|
|
37
37
|
throw new Error('[E_BAD_SHAPE] Insert request "direction" must be "before" or "after".');
|
|
@@ -49,23 +49,23 @@ const insertToolSchema = Type.Object(
|
|
|
49
49
|
}),
|
|
50
50
|
anchor: Type.String({
|
|
51
51
|
description:
|
|
52
|
-
'Bare
|
|
52
|
+
'Bare 4-char anchor from a read row like `Hasu│content`, never the content. A pasted `+Hasu│x` diff row or `anchor│` prefix is stripped with a warning. The anchor line is preserved; lines go after or before it.',
|
|
53
53
|
}),
|
|
54
54
|
direction: Type.Union(
|
|
55
55
|
[
|
|
56
|
-
Type.Literal("after"
|
|
57
|
-
Type.Literal("before"
|
|
56
|
+
Type.Literal("after"),
|
|
57
|
+
Type.Literal("before"),
|
|
58
58
|
],
|
|
59
59
|
{ description: '"after" or "before"' },
|
|
60
60
|
),
|
|
61
61
|
lines: Type.Array(
|
|
62
62
|
Type.String({
|
|
63
63
|
description:
|
|
64
|
-
"One line to insert
|
|
64
|
+
"One line to insert; never embed \\n inside an element.",
|
|
65
65
|
}),
|
|
66
66
|
{
|
|
67
67
|
description:
|
|
68
|
-
'
|
|
68
|
+
'One string per line; [""] is a blank line; never include the anchor line.',
|
|
69
69
|
}
|
|
70
70
|
),
|
|
71
71
|
},
|
package/src/payload-contract.ts
CHANGED
|
@@ -4,22 +4,22 @@ import { isRec, normalizeFilePath, rejectUnknownFields } from "./utils";
|
|
|
4
4
|
const replacementLinesSchema = Type.Array(
|
|
5
5
|
Type.String({
|
|
6
6
|
description:
|
|
7
|
-
"One replacement line
|
|
7
|
+
"One replacement line; never embed \\n inside an element.",
|
|
8
8
|
}),
|
|
9
9
|
{
|
|
10
10
|
description:
|
|
11
|
-
"
|
|
11
|
+
"One string per line. Use [] to delete the range.",
|
|
12
12
|
},
|
|
13
13
|
);
|
|
14
14
|
|
|
15
15
|
const removeFromSchema = Type.String({
|
|
16
16
|
description:
|
|
17
|
-
"Bare
|
|
17
|
+
"Bare 4-char anchor from a read row like `Hasu│content` (the leftmost column), never the row content. Marks the FIRST line to remove (inclusive)",
|
|
18
18
|
});
|
|
19
19
|
|
|
20
20
|
const removeToSchema = Type.String({
|
|
21
21
|
description:
|
|
22
|
-
"Bare
|
|
22
|
+
"Bare 4-char anchor from a read row like `Hasu│content` (the leftmost column), never the row content. Marks the LAST line to remove (inclusive)",
|
|
23
23
|
});
|
|
24
24
|
|
|
25
25
|
export const editToolSchema = Type.Object(
|
|
@@ -27,7 +27,7 @@ export const editToolSchema = Type.Object(
|
|
|
27
27
|
path: Type.Optional(
|
|
28
28
|
Type.String({
|
|
29
29
|
description:
|
|
30
|
-
"Path to edit
|
|
30
|
+
"Path to edit; always provide it explicitly — it is only auto-resolved from the anchors as a fallback.",
|
|
31
31
|
}),
|
|
32
32
|
),
|
|
33
33
|
remove_from: removeFromSchema,
|
package/src/utils.ts
CHANGED
|
@@ -114,7 +114,7 @@ export function getCached<K, V>(map: Map<K, V>, key: K, compute: (key: K) => V):
|
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
export function isHashRow(line: string): boolean {
|
|
117
|
-
return /^[A-Za-z0-9]{
|
|
117
|
+
return /^[A-Za-z0-9]{4}│/.test(line);
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
function gutterWidth(max: number, fallback: number): number {
|