pi-readseek 0.9.1 → 0.9.2

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.
Files changed (2) hide show
  1. package/dist/index.ts +124 -174
  2. package/package.json +2 -2
package/dist/index.ts CHANGED
@@ -3386,159 +3386,6 @@ function resolveSyntaxValidateMode(opts) {
3386
3386
  return opts.syntaxValidate ?? resolveReadSeekSyntaxValidation() ?? DEFAULT;
3387
3387
  }
3388
3388
 
3389
- // src/pending-diff-preview.ts
3390
- import { existsSync as existsSync2, readFileSync as readFileSync4, realpathSync, statSync as statSync3 } from "node:fs";
3391
- import { dirname, isAbsolute as isAbsolute2, relative as relative2, resolve, sep } from "node:path";
3392
- var PENDING_DIFF_MAX_BYTES = 1024 * 1024;
3393
- function skip(reason) {
3394
- return { type: "skip", reason };
3395
- }
3396
- function isInsidePath(parent, child) {
3397
- const rel = relative2(parent, child);
3398
- return rel === "" || rel !== "" && !rel.startsWith("..") && !rel.startsWith(sep) && !resolve(rel).startsWith(".." + sep);
3399
- }
3400
- function resolveWorkspacePreviewPath(rawPath, cwd, allowMissing) {
3401
- if (typeof rawPath !== "string" || rawPath.trim() === "")
3402
- return { type: "skip", reason: "missing path" };
3403
- const workspace = realpathSync(cwd);
3404
- const normalizedPath = rawPath.replace(/^@/, "");
3405
- const explicitAbsolute = isAbsolute2(normalizedPath);
3406
- const requested = resolve(workspace, normalizedPath);
3407
- if (existsSync2(requested)) {
3408
- const realTarget = realpathSync(requested);
3409
- if (!explicitAbsolute && !isInsidePath(workspace, realTarget))
3410
- return { type: "skip", reason: "path outside workspace" };
3411
- return { type: "ok", path: realTarget, existed: true };
3412
- }
3413
- if (!explicitAbsolute && !isInsidePath(workspace, requested))
3414
- return { type: "skip", reason: "path outside workspace" };
3415
- if (!allowMissing)
3416
- return { type: "skip", reason: "file not found" };
3417
- const parent = dirname(requested);
3418
- if (!existsSync2(parent))
3419
- return { type: "skip", reason: "parent directory not found" };
3420
- return { type: "ok", path: requested, existed: false };
3421
- }
3422
- function readUtf8File(filePath) {
3423
- const stat2 = statSync3(filePath);
3424
- if (!stat2.isFile())
3425
- return { type: "skip", reason: "not a file" };
3426
- if (stat2.size > PENDING_DIFF_MAX_BYTES)
3427
- return { type: "skip", reason: "file too large" };
3428
- const content = readFileSync4(filePath, "utf-8");
3429
- if (content.includes("\x00"))
3430
- return { type: "skip", reason: "binary file" };
3431
- return { type: "ok", content };
3432
- }
3433
- function buildData(filePath, previousContent, nextContent, existed, headerLabel) {
3434
- const diff = generateDiffString(normalizeToLF(previousContent), normalizeToLF(nextContent)).diff;
3435
- return {
3436
- type: "ok",
3437
- data: {
3438
- filePath,
3439
- previousContent,
3440
- nextContent,
3441
- fileExistedBeforeWrite: existed,
3442
- headerLabel,
3443
- diff
3444
- }
3445
- };
3446
- }
3447
- function getEdits(input) {
3448
- return Array.isArray(input.edits) ? input.edits : [];
3449
- }
3450
- function buildPendingWritePreviewData(input, cwd) {
3451
- if (typeof input.content !== "string")
3452
- return skip("missing content");
3453
- if (Buffer.byteLength(input.content, "utf8") > PENDING_DIFF_MAX_BYTES)
3454
- return skip("content too large");
3455
- const resolved = resolveWorkspacePreviewPath(input.path, cwd, true);
3456
- if (resolved.type === "skip")
3457
- return resolved;
3458
- const previous = resolved.existed ? readUtf8File(resolved.path) : { type: "ok", content: "" };
3459
- if (previous.type === "skip")
3460
- return previous;
3461
- return buildData(resolved.path, previous.content, input.content, resolved.existed, resolved.existed ? "pending overwrite" : "pending create");
3462
- }
3463
- async function buildPendingEditPreviewData(input, cwd) {
3464
- const edits = getEdits(input);
3465
- if (edits.length === 0)
3466
- return skip("missing edits");
3467
- const resolved = resolveWorkspacePreviewPath(input.path, cwd, false);
3468
- if (resolved.type === "skip")
3469
- return resolved;
3470
- const previous = readUtf8File(resolved.path);
3471
- if (previous.type === "skip")
3472
- return previous;
3473
- try {
3474
- const plan = await readSeekEdit(resolved.path, edits, {
3475
- language: typeof input.language === "string" ? input.language : undefined
3476
- });
3477
- if (typeof plan.content !== "string")
3478
- return skip("edit plan did not include content");
3479
- return buildData(resolved.path, previous.content, plan.content, true, "pending edit");
3480
- } catch (err) {
3481
- return skip(`edit projection failed: ${err?.message ?? String(err)}`);
3482
- }
3483
- }
3484
- function buildEditPreviewKey(input) {
3485
- if (typeof input.path !== "string")
3486
- return;
3487
- const edits = getEdits(input);
3488
- if (edits.length === 0)
3489
- return;
3490
- return JSON.stringify({ path: input.path, edits, language: input.language });
3491
- }
3492
- function buildWritePreviewKey(input) {
3493
- if (typeof input.path !== "string" || typeof input.content !== "string")
3494
- return;
3495
- return JSON.stringify({ path: input.path, content: input.content });
3496
- }
3497
- function resolvePendingDiffPreview(context, stateKey, previewKey, compute) {
3498
- if (!previewKey)
3499
- return;
3500
- const root = context?.state;
3501
- if (!root)
3502
- return;
3503
- const slot = root[stateKey] ??= {};
3504
- if (slot.key !== previewKey) {
3505
- slot.key = previewKey;
3506
- slot.data = undefined;
3507
- slot.pending = false;
3508
- }
3509
- if (slot.data !== undefined)
3510
- return slot.data;
3511
- if (slot.pending)
3512
- return;
3513
- let value;
3514
- try {
3515
- value = compute();
3516
- } catch (err) {
3517
- const skipped = { type: "skip", reason: `projection failed: ${err?.message ?? String(err)}` };
3518
- slot.data = skipped;
3519
- return skipped;
3520
- }
3521
- if (value && typeof value.then === "function") {
3522
- slot.pending = true;
3523
- value.then((resolved) => {
3524
- if (slot.key !== previewKey)
3525
- return;
3526
- slot.data = resolved;
3527
- slot.pending = false;
3528
- context?.invalidate?.();
3529
- }).catch((err) => {
3530
- if (slot.key !== previewKey)
3531
- return;
3532
- slot.data = { type: "skip", reason: `projection failed: ${err?.message ?? String(err)}` };
3533
- slot.pending = false;
3534
- context?.invalidate?.();
3535
- });
3536
- return;
3537
- }
3538
- slot.data = value;
3539
- return slot.data;
3540
- }
3541
-
3542
3389
  // src/diff-data.ts
3543
3390
  var MAX_INLINE_DIFF_LINE_LENGTH = 4096;
3544
3391
  var MAX_INLINE_DIFF_TOKENS = 512;
@@ -3957,15 +3804,6 @@ function upsertTextComponent(lastComponent, text) {
3957
3804
  }
3958
3805
 
3959
3806
  // src/edit.ts
3960
- var EDIT_PENDING_PREVIEW_STATE_KEY = "hashline-edit-pending-preview";
3961
- function pendingPreviewLines(summary, preview, expanded) {
3962
- if (!preview || preview.type !== "ok")
3963
- return { lines: summary.split(`
3964
- `) };
3965
- const diffData = buildDiffData({ path: preview.data.filePath, oldContent: preview.data.previousContent, newContent: preview.data.nextContent, diff: preview.data.diff });
3966
- const headerLine = summaryLine(preview.data.headerLabel, { hidden: !expanded });
3967
- return { lines: [summary, headerLine], diffData: expanded ? diffData : undefined, headerLabel: preview.data.headerLabel };
3968
- }
3969
3807
  var hashlineEditItemSchema = Type3.Object({
3970
3808
  set_line: Type3.Optional(Type3.Object({
3971
3809
  anchor: Type3.String({ description: "Fresh LINE:HASH anchor for the line to replace" }),
@@ -4201,18 +4039,7 @@ function registerEditTool(pi, options = {}) {
4201
4039
  text += ` ${theme.fg("dim", suffix)}`;
4202
4040
  }
4203
4041
  text = clampLineToWidth(text, context.width);
4204
- if (context.executionStarted) {
4205
- return upsertTextComponent(context.lastComponent, text);
4206
- }
4207
- const previewKey = buildEditPreviewKey(args ?? {});
4208
- const preview = resolvePendingDiffPreview(context, EDIT_PENDING_PREVIEW_STATE_KEY, previewKey, () => buildPendingEditPreviewData(args ?? {}, context.cwd ?? process.cwd()));
4209
- const expanded = !!context.expanded;
4210
- const preview2 = pendingPreviewLines(text, preview, expanded);
4211
- if (preview2.diffData) {
4212
- return upsertDiffComponent(context.lastComponent, { prefixLines: preview2.lines, diffData: preview2.diffData, theme, expanded: true });
4213
- }
4214
- return upsertTextComponent(context.lastComponent, clampLinesToWidth(preview2.lines, context.width).join(`
4215
- `));
4042
+ return upsertTextComponent(context.lastComponent, text);
4216
4043
  },
4217
4044
  renderResult(result, options2, theme, ...rest) {
4218
4045
  const { isPartial, isError, expanded, width, context } = resolveRenderResultContext(options2, rest, resolveReadSeekToolDisplayMode("edit") === "expanded");
@@ -5566,6 +5393,129 @@ import { dirname as dirname2, relative as relative3 } from "node:path";
5566
5393
  import { withFileMutationQueue as withFileMutationQueue2, truncateHead as truncateHead4 } from "@earendil-works/pi-coding-agent";
5567
5394
  import { Text as Text7 } from "@earendil-works/pi-tui";
5568
5395
  import { Type as Type9 } from "@sinclair/typebox";
5396
+
5397
+ // src/pending-diff-preview.ts
5398
+ import { existsSync as existsSync2, readFileSync as readFileSync4, realpathSync, statSync as statSync3 } from "node:fs";
5399
+ import { dirname, isAbsolute as isAbsolute2, relative as relative2, resolve, sep } from "node:path";
5400
+ var PENDING_DIFF_MAX_BYTES = 1024 * 1024;
5401
+ function skip(reason) {
5402
+ return { type: "skip", reason };
5403
+ }
5404
+ function isInsidePath(parent, child) {
5405
+ const rel = relative2(parent, child);
5406
+ return rel === "" || rel !== "" && !rel.startsWith("..") && !rel.startsWith(sep) && !resolve(rel).startsWith(".." + sep);
5407
+ }
5408
+ function resolveWorkspacePreviewPath(rawPath, cwd, allowMissing) {
5409
+ if (typeof rawPath !== "string" || rawPath.trim() === "")
5410
+ return { type: "skip", reason: "missing path" };
5411
+ const workspace = realpathSync(cwd);
5412
+ const normalizedPath = rawPath.replace(/^@/, "");
5413
+ const explicitAbsolute = isAbsolute2(normalizedPath);
5414
+ const requested = resolve(workspace, normalizedPath);
5415
+ if (existsSync2(requested)) {
5416
+ const realTarget = realpathSync(requested);
5417
+ if (!explicitAbsolute && !isInsidePath(workspace, realTarget))
5418
+ return { type: "skip", reason: "path outside workspace" };
5419
+ return { type: "ok", path: realTarget, existed: true };
5420
+ }
5421
+ if (!explicitAbsolute && !isInsidePath(workspace, requested))
5422
+ return { type: "skip", reason: "path outside workspace" };
5423
+ if (!allowMissing)
5424
+ return { type: "skip", reason: "file not found" };
5425
+ const parent = dirname(requested);
5426
+ if (!existsSync2(parent))
5427
+ return { type: "skip", reason: "parent directory not found" };
5428
+ return { type: "ok", path: requested, existed: false };
5429
+ }
5430
+ function readUtf8File(filePath) {
5431
+ const stat2 = statSync3(filePath);
5432
+ if (!stat2.isFile())
5433
+ return { type: "skip", reason: "not a file" };
5434
+ if (stat2.size > PENDING_DIFF_MAX_BYTES)
5435
+ return { type: "skip", reason: "file too large" };
5436
+ const content = readFileSync4(filePath, "utf-8");
5437
+ if (content.includes("\x00"))
5438
+ return { type: "skip", reason: "binary file" };
5439
+ return { type: "ok", content };
5440
+ }
5441
+ function buildData(filePath, previousContent, nextContent, existed, headerLabel) {
5442
+ const diff = generateDiffString(normalizeToLF(previousContent), normalizeToLF(nextContent)).diff;
5443
+ return {
5444
+ type: "ok",
5445
+ data: {
5446
+ filePath,
5447
+ previousContent,
5448
+ nextContent,
5449
+ fileExistedBeforeWrite: existed,
5450
+ headerLabel,
5451
+ diff
5452
+ }
5453
+ };
5454
+ }
5455
+ function buildPendingWritePreviewData(input, cwd) {
5456
+ if (typeof input.content !== "string")
5457
+ return skip("missing content");
5458
+ if (Buffer.byteLength(input.content, "utf8") > PENDING_DIFF_MAX_BYTES)
5459
+ return skip("content too large");
5460
+ const resolved = resolveWorkspacePreviewPath(input.path, cwd, true);
5461
+ if (resolved.type === "skip")
5462
+ return resolved;
5463
+ const previous = resolved.existed ? readUtf8File(resolved.path) : { type: "ok", content: "" };
5464
+ if (previous.type === "skip")
5465
+ return previous;
5466
+ return buildData(resolved.path, previous.content, input.content, resolved.existed, resolved.existed ? "pending overwrite" : "pending create");
5467
+ }
5468
+ function buildWritePreviewKey(input) {
5469
+ if (typeof input.path !== "string" || typeof input.content !== "string")
5470
+ return;
5471
+ return JSON.stringify({ path: input.path, content: input.content });
5472
+ }
5473
+ function resolvePendingDiffPreview(context, stateKey, previewKey, compute) {
5474
+ if (!previewKey)
5475
+ return;
5476
+ const root = context?.state;
5477
+ if (!root)
5478
+ return;
5479
+ const slot = root[stateKey] ??= {};
5480
+ if (slot.key !== previewKey) {
5481
+ slot.key = previewKey;
5482
+ slot.data = undefined;
5483
+ slot.pending = false;
5484
+ }
5485
+ if (slot.data !== undefined)
5486
+ return slot.data;
5487
+ if (slot.pending)
5488
+ return;
5489
+ let value;
5490
+ try {
5491
+ value = compute();
5492
+ } catch (err) {
5493
+ const skipped = { type: "skip", reason: `projection failed: ${err?.message ?? String(err)}` };
5494
+ slot.data = skipped;
5495
+ return skipped;
5496
+ }
5497
+ if (value && typeof value.then === "function") {
5498
+ slot.pending = true;
5499
+ value.then((resolved) => {
5500
+ if (slot.key !== previewKey)
5501
+ return;
5502
+ slot.data = resolved;
5503
+ slot.pending = false;
5504
+ context?.invalidate?.();
5505
+ }).catch((err) => {
5506
+ if (slot.key !== previewKey)
5507
+ return;
5508
+ slot.data = { type: "skip", reason: `projection failed: ${err?.message ?? String(err)}` };
5509
+ slot.pending = false;
5510
+ context?.invalidate?.();
5511
+ });
5512
+ return;
5513
+ }
5514
+ slot.data = value;
5515
+ return slot.data;
5516
+ }
5517
+
5518
+ // src/write.ts
5569
5519
  var WRITE_PENDING_PREVIEW_STATE_KEY = "hashline-write-pending-preview";
5570
5520
  var CONTENT_PREVIEW_MAX_LINES = 200;
5571
5521
  function formatContentPreviewLines(content, theme) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-readseek",
3
- "version": "0.9.1",
3
+ "version": "0.9.2",
4
4
  "description": "Pi extension for LINE:HASH-anchored file operations and structural code navigation",
5
5
  "type": "module",
6
6
  "exports": {
@@ -40,7 +40,7 @@
40
40
  "node": ">=20.0.0"
41
41
  },
42
42
  "dependencies": {
43
- "@jarkkojs/readseek": "^0.9.1",
43
+ "@jarkkojs/readseek": "^0.9.2",
44
44
  "diff": "^9.0.0",
45
45
  "xxhash-wasm": "^1.1.0"
46
46
  },