pi-hashline-edit-pro 4.0.0 → 4.0.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/package.json +1 -1
- package/src/anchor-registry.ts +14 -13
- package/src/hash-store.ts +2 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-hashline-edit-pro",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Hash-anchored read/replace/insert/grep tools for pi-coding-agent. Every line gets a unique 4-char tokenizer-friendly anchor that stays stable across edits; stale or ambiguous anchors are rejected, never fuzzy-matched. Undo persists across restarts.",
|
|
6
6
|
"main": "index.ts",
|
package/src/anchor-registry.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { mkdir, readFile, readdir, rm, stat } from "fs/promises";
|
|
2
|
+
import { appendFileSync } from "fs";
|
|
2
3
|
import { join } from "path";
|
|
3
4
|
import { createHash } from "crypto";
|
|
4
5
|
import { sessionClaimsDir } from "./paths";
|
|
@@ -130,7 +131,7 @@ export async function initRegistry(sessionFile: string | undefined): Promise<voi
|
|
|
130
131
|
registries.set(key, folded);
|
|
131
132
|
try {
|
|
132
133
|
await mkdir(sessionClaimsDir(), { recursive: true });
|
|
133
|
-
|
|
134
|
+
appendEvent({ kind: "session", sessionFile } satisfies RegistryEvent);
|
|
134
135
|
} catch (error) {
|
|
135
136
|
console.error("Failed to initialize anchor registry sidecar:", error);
|
|
136
137
|
}
|
|
@@ -142,9 +143,12 @@ function current(): SessionState | undefined {
|
|
|
142
143
|
}
|
|
143
144
|
|
|
144
145
|
function appendEvent(event: RegistryEvent): void {
|
|
145
|
-
|
|
146
|
+
if (!currentSidecar) return;
|
|
147
|
+
try {
|
|
148
|
+
appendFileSync(currentSidecar, JSON.stringify(event) + "\n", "utf-8");
|
|
149
|
+
} catch (error) {
|
|
146
150
|
console.error("Failed to append registry event:", error);
|
|
147
|
-
}
|
|
151
|
+
}
|
|
148
152
|
}
|
|
149
153
|
|
|
150
154
|
function fingerprintIndex(state: SessionState, path: string): Map<string, string[]> {
|
|
@@ -188,9 +192,7 @@ export function allocateAnchor(path: string, checksum: string): string {
|
|
|
188
192
|
const anchor = mintAnchor(state);
|
|
189
193
|
state.everMinted.add(anchor);
|
|
190
194
|
state.owned.set(anchor, { path, checksum });
|
|
191
|
-
|
|
192
|
-
appendEvent({ kind: "allocate", path, rows: [[anchor, checksum]] });
|
|
193
|
-
}
|
|
195
|
+
appendEvent({ kind: "allocate", path, rows: [[anchor, checksum]] });
|
|
194
196
|
return anchor;
|
|
195
197
|
}
|
|
196
198
|
|
|
@@ -217,7 +219,7 @@ export function freeAnchors(path: string, anchors?: string[]): void {
|
|
|
217
219
|
}
|
|
218
220
|
state.served.delete(path);
|
|
219
221
|
}
|
|
220
|
-
if (freed.length > 0
|
|
222
|
+
if (freed.length > 0) {
|
|
221
223
|
appendEvent({ kind: "free", path, anchors: anchors ?? undefined });
|
|
222
224
|
}
|
|
223
225
|
}
|
|
@@ -227,7 +229,6 @@ export function clearRegistry(): void {
|
|
|
227
229
|
if (!state) return;
|
|
228
230
|
state.owned.clear();
|
|
229
231
|
state.served.clear();
|
|
230
|
-
if (!currentSidecar) return;
|
|
231
232
|
appendEvent({ kind: "clear" });
|
|
232
233
|
}
|
|
233
234
|
|
|
@@ -362,7 +363,7 @@ export function alignOwnershipWithSpans(
|
|
|
362
363
|
const freed: { anchor: string; checksum: string }[] = [];
|
|
363
364
|
const minted: MintedAt[] = [];
|
|
364
365
|
const log = (event: RegistryEvent): void => {
|
|
365
|
-
if (!options?.shadow
|
|
366
|
+
if (!options?.shadow) appendEvent(event);
|
|
366
367
|
};
|
|
367
368
|
|
|
368
369
|
const sorted = [...spans].sort((a, b) => a.start - b.start);
|
|
@@ -432,7 +433,7 @@ export function alignOwnership(
|
|
|
432
433
|
const freed: { anchor: string; checksum: string }[] = [];
|
|
433
434
|
const minted: MintedAt[] = [];
|
|
434
435
|
const log = (event: RegistryEvent): void => {
|
|
435
|
-
if (!options?.shadow
|
|
436
|
+
if (!options?.shadow) appendEvent(event);
|
|
436
437
|
};
|
|
437
438
|
if (prevAnchors) {
|
|
438
439
|
for (const anchor of prevAnchors) state.everMinted.add(anchor);
|
|
@@ -544,7 +545,7 @@ export async function allocateFileAnchors(
|
|
|
544
545
|
state.owned.set(anchor, { path, checksum });
|
|
545
546
|
return anchor;
|
|
546
547
|
});
|
|
547
|
-
if (!shadow
|
|
548
|
+
if (!shadow) {
|
|
548
549
|
appendEvent({ kind: "allocate", path, rows: anchors.map((a, i) => [a, checksums[i]!]) });
|
|
549
550
|
}
|
|
550
551
|
return { anchors, freed: [], minted: anchors };
|
|
@@ -567,7 +568,7 @@ export function adoptAnchors(path: string, entries: Map<string, string>): void {
|
|
|
567
568
|
state.owned.set(anchor, { path, checksum });
|
|
568
569
|
served.set(anchor, checksum);
|
|
569
570
|
}
|
|
570
|
-
if (
|
|
571
|
+
if (entries.size > 0) {
|
|
571
572
|
appendEvent({ kind: "allocate", path, rows: [...entries] });
|
|
572
573
|
}
|
|
573
574
|
}
|
package/src/hash-store.ts
CHANGED
|
@@ -535,7 +535,8 @@ async function statMissing(rows: { path: string }[]): Promise<string[]> {
|
|
|
535
535
|
await stat(row.path);
|
|
536
536
|
return undefined;
|
|
537
537
|
} catch (error: unknown) {
|
|
538
|
-
|
|
538
|
+
const code = errCode(error);
|
|
539
|
+
if (code !== "ENOENT" && code !== "ENOTDIR") {
|
|
539
540
|
console.error("Failed to stat hash store path:", row.path, error);
|
|
540
541
|
return undefined;
|
|
541
542
|
}
|