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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-hashline-edit-pro",
3
- "version": "4.0.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",
@@ -1,4 +1,5 @@
1
- import { appendFile, mkdir, readFile, readdir, rm, stat } from "fs/promises";
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
- await appendFile(currentSidecar, JSON.stringify({ kind: "session", sessionFile } satisfies RegistryEvent) + "\n", "utf-8");
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
- appendFile(currentSidecar!, JSON.stringify(event) + "\n", "utf-8").catch((error) => {
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
- if (currentSidecar) {
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 && currentSidecar) {
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 && currentSidecar) appendEvent(event);
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 && currentSidecar) appendEvent(event);
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 && currentSidecar) {
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 (currentSidecar && entries.size > 0) {
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
- if (errCode(error) !== "ENOENT") {
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
  }