@oh-my-pi/pi-coding-agent 15.5.9 → 15.5.11

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.
@@ -2,13 +2,15 @@ import { Database } from "bun:sqlite";
2
2
  import * as fs from "node:fs/promises";
3
3
  import * as path from "node:path";
4
4
 
5
- import { stripHashlinePrefixes } from "@oh-my-pi/hashline";
5
+ import { formatHashlineHeader, stripHashlinePrefixes } from "@oh-my-pi/hashline";
6
6
  import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
7
7
  import type { Component } from "@oh-my-pi/pi-tui";
8
8
  import { Text } from "@oh-my-pi/pi-tui";
9
9
  import { isEnoent, isRecord, prompt, untilAborted } from "@oh-my-pi/pi-utils";
10
10
  import * as z from "zod/v4";
11
11
 
12
+ import { getFileSnapshotStore } from "../edit/file-snapshot-store";
13
+ import { normalizeToLF } from "../edit/normalize";
12
14
  import type { RenderResultOptions } from "../extensibility/custom-tools/types";
13
15
  import { InternalUrlRouter } from "../internal-urls";
14
16
  import { parseInternalUrl } from "../internal-urls/parse";
@@ -116,6 +118,24 @@ function stripWriteContent(session: ToolSession, content: string): { text: strin
116
118
  return stripWriteContentWithPotentialLooseHeader(content.split("\n"));
117
119
  }
118
120
 
121
+ /**
122
+ * Record a snapshot of the freshly-written `content` for `absolutePath`
123
+ * so subsequent hashline edits address the new file with a current tag,
124
+ * and return the matching `¶displayPath#TAG` header. Returns `undefined`
125
+ * when the session is not in hashline mode so callers can no-op cheaply.
126
+ *
127
+ * Mirrors the post-commit snapshot recording the hashline patcher performs
128
+ * after a successful edit: the model gets a tag without an extra `read`.
129
+ */
130
+ function maybeWriteSnapshotHeader(session: ToolSession, absolutePath: string, content: string): string | undefined {
131
+ if (!resolveFileDisplayMode(session).hashLines) return undefined;
132
+ const normalized = normalizeToLF(content);
133
+ const tag = getFileSnapshotStore(session).recordContiguous(absolutePath, 1, normalized.split("\n"), {
134
+ fullText: normalized,
135
+ });
136
+ return formatHashlineHeader(formatPathRelativeToCwd(absolutePath, session.cwd), tag);
137
+ }
138
+
119
139
  /**
120
140
  * Append a trailing note line to the first text block of a tool result.
121
141
  * Mutates `result` in place (the result object is owned by this call).
@@ -540,11 +560,13 @@ export class WriteTool implements AgentTool<typeof writeSchema, WriteToolDetails
540
560
  this.session.fileSnapshotStore?.invalidate(absolutePath);
541
561
  this.session.conflictHistory?.invalidate(entry.id);
542
562
 
563
+ const header = maybeWriteSnapshotHeader(this.session, absolutePath, newContent);
543
564
  const range =
544
565
  entry.startLine === entry.endLine
545
566
  ? `line ${entry.startLine}`
546
567
  : `lines ${entry.startLine}\u2013${entry.endLine}`;
547
- let resultText = `Resolved conflict #${entry.id} at ${range} in ${entry.displayPath}.`;
568
+ const summary = `Resolved conflict #${entry.id} at ${range} in ${entry.displayPath}.`;
569
+ let resultText = header ? `${header}\n${summary}` : summary;
548
570
  if (stripped) {
549
571
  resultText += `\nNote: auto-stripped hashline display prefixes from content before writing.`;
550
572
  }
@@ -624,7 +646,7 @@ export class WriteTool implements AgentTool<typeof writeSchema, WriteToolDetails
624
646
 
625
647
  const batchRequest = getLspBatchRequest(context?.toolCall);
626
648
  const allDiagnostics: FileDiagnosticsResult[] = [];
627
- const succeededFiles: { displayPath: string; count: number }[] = [];
649
+ const succeededFiles: { displayPath: string; count: number; header?: string }[] = [];
628
650
  const failedFiles: { displayPath: string; count: number; error: string }[] = [];
629
651
  let totalResolvedIds = 0;
630
652
 
@@ -661,7 +683,8 @@ export class WriteTool implements AgentTool<typeof writeSchema, WriteToolDetails
661
683
  invalidateFsScanAfterWrite(absolutePath);
662
684
  this.session.fileSnapshotStore?.invalidate(absolutePath);
663
685
  for (const entry of fileEntries) history.invalidate(entry.id);
664
- succeededFiles.push({ displayPath: sample.displayPath, count: fileEntries.length });
686
+ const header = maybeWriteSnapshotHeader(this.session, absolutePath, text);
687
+ succeededFiles.push({ displayPath: sample.displayPath, count: fileEntries.length, header });
665
688
  totalResolvedIds += fileEntries.length;
666
689
  if (diagnostics) allDiagnostics.push(diagnostics);
667
690
  }
@@ -685,6 +708,13 @@ export class WriteTool implements AgentTool<typeof writeSchema, WriteToolDetails
685
708
  summaryLines.push(` ${file.displayPath}: ${file.count} ${conflictWord(file.count)} (${file.error})`);
686
709
  }
687
710
  }
711
+ const headerLines = succeededFiles
712
+ .map(file => file.header)
713
+ .filter((header): header is string => header !== undefined);
714
+ if (headerLines.length > 0) {
715
+ summaryLines.push("Snapshots:");
716
+ for (const header of headerLines) summaryLines.push(` ${header}`);
717
+ }
688
718
  if (stripped) {
689
719
  summaryLines.push("Note: auto-stripped hashline display prefixes from content before writing.");
690
720
  }
@@ -813,7 +843,9 @@ export class WriteTool implements AgentTool<typeof writeSchema, WriteToolDetails
813
843
  }
814
844
  invalidateFsScanAfterWrite(absolutePath);
815
845
  const displayPath = formatPathRelativeToCwd(absolutePath, this.session.cwd);
816
- let resultText = `Successfully wrote ${cleanContent.length} bytes to ${displayPath}`;
846
+ const header = maybeWriteSnapshotHeader(this.session, absolutePath, cleanContent);
847
+ const writeLine = `Successfully wrote ${cleanContent.length} bytes to ${displayPath}`;
848
+ let resultText = header ? `${header}\n${writeLine}` : writeLine;
817
849
  if (stripped) {
818
850
  resultText += `\nNote: auto-stripped hashline display prefixes from content before writing.`;
819
851
  }
@@ -825,7 +857,9 @@ export class WriteTool implements AgentTool<typeof writeSchema, WriteToolDetails
825
857
  const madeExecutable = await maybeMarkExecutableForShebang(absolutePath, cleanContent);
826
858
 
827
859
  const displayPath = formatPathRelativeToCwd(absolutePath, this.session.cwd);
828
- let resultText = `Successfully wrote ${cleanContent.length} bytes to ${displayPath}`;
860
+ const header = maybeWriteSnapshotHeader(this.session, absolutePath, cleanContent);
861
+ const writeLine = `Successfully wrote ${cleanContent.length} bytes to ${displayPath}`;
862
+ let resultText = header ? `${header}\n${writeLine}` : writeLine;
829
863
  if (stripped) {
830
864
  resultText += `\nNote: auto-stripped hashline display prefixes from content before writing.`;
831
865
  }