Bläddra i källkod

docs: finish the whole-file-diff sweep across comments and RFCs

Codex's stale-prose pass found seven more spots still describing the
result diff as ALWAYS an applied contextual hunk, or a create/binary
overwrite as rendering "only the call-time card": the DiffCallView JSDoc
and the acp bridge diff-arm comment, the FsWriteOutcome.before and
readTextForDiff JSDoc, and three RFC lines. All now say: the result diff
is the applied change — a contextual hunk when there is a before-image,
else a whole-file diff (create / undiffable binary) — and a successful
mutation always returns the result diff so the model-facing text can't
clobber it. Regenerate the cordis catalog (source line shift).
Tianyi Cui 2 månader sedan
förälder
incheckning
e07886599c

+ 1 - 1
docs/cordis-catalog/events-and-services.md

@@ -547,7 +547,7 @@ async execute(exec: ToolExecution): Promise<ToolExecutionResult>
 
 Types: [ToolDefinition](../core-data-structures/tools.md) · [ToolExecution](../core-data-structures/tools.md) · [ToolExecutionResult](../core-data-structures/tools.md)
 
-Source: [`packages/core/tools/src/index.ts:365`](../../packages/core/tools/src/index.ts)
+Source: [`packages/core/tools/src/index.ts:366`](../../packages/core/tools/src/index.ts)
 
 ## Inherited tier (cordis core + loader/hmr/timer)
 

+ 2 - 2
docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.md

@@ -35,7 +35,7 @@ Per the [capability-seam split](2026-06-13-capability-seams.md), the storage bac
 
 ### 3. The bridge renders a `diff` result card
 
-`ToolResultView` gains a `DiffResultView { card:'diff'; title?; diffs: FileDiff[] }`; the bridge's result-side `switch (view.card)` gets a `diff` arm emitting the `{type:'diff'}` `ToolCallContent` blocks (mirroring the call-side arm). An ACP `tool_call_update.content` REPLACES the call's content in an editor, so the result-time contextual hunk **supersedes** the call-time snippet — the two-update sequence (call snippet, then result hunk) matches `claude-agent-acp` exactly.
+`ToolResultView` gains a `DiffResultView { card:'diff'; title?; diffs: FileDiff[] }`; the bridge's result-side `switch (view.card)` gets a `diff` arm emitting the `{type:'diff'}` `ToolCallContent` blocks (mirroring the call-side arm). An ACP `tool_call_update.content` REPLACES the call's content in an editor, so the result diff **supersedes** the call-time snippet (and keeps the model-facing result text from clobbering it) — the two-update sequence (call snippet, then result diff) matches `claude-agent-acp` exactly.
 
 ### The diff algorithm — a third-party runtime dependency over vendoring
 
@@ -44,7 +44,7 @@ Computing hunks-with-context is a solved problem with sharp edge cases (grouping
 ## Non-goals
 
 - **Live incremental diff streaming.** The hunk is computed once, after the mutation completes; there is no per-keystroke diff.
-- **Diffing a binary/non-UTF-8 overwrite.** `before` is `null` for such a file (it has no text diff basis); the write still succeeds and renders the call-time card only.
+- **Diffing a binary/non-UTF-8 overwrite.** `before` is `null` for such a file (it has no text diff basis); the write still succeeds and the result renders a whole-file diff (`oldText: null`) rather than a contextual hunk.
 - **Rename/move diffs.** Only content diffs of a single resolved path.
 
 ## Related

+ 1 - 1
docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.md

@@ -65,6 +65,6 @@ interface TerminalResultView { card: 'terminal'; title?: string; output?: string
 ## Related
 
 - Supersedes the deferral in [Collapse tool-owned UI presentation](../../rejected/simplification/2026-06-20-generic-tool-rendering.md) (rejected — "wait for two real tools and two real consumers, then a tagged render-intent union"). That bar is now met; this is that union.
-- Extended by [Result-time applied-hunk diffs](2026-07-02-result-time-applied-hunk-diffs.md), which adds a persisted `meta` channel so write/edit emit a result-time contextual-hunk `DiffResultView` (context lines + one hunk per `replace_all` site) on top of this union's call-time diff card.
+- Extended by [Result-time applied-hunk diffs](2026-07-02-result-time-applied-hunk-diffs.md), which adds a persisted `meta` channel so write/edit emit a result-time `DiffResultView` — the applied change (a contextual hunk with context lines / one per `replace_all` site, or a whole-file diff for a create) — on top of this union's call-time diff card.
 - Folds `ToolTerminal` into the `terminal` views described by [ACP terminal and tool-call rendering](../feature/2026-06-18-acp-terminal-and-tool-rendering.md) (the `_meta` terminal-card convention and capability gate are unchanged; only the harness-side presentation type changes).
 - The ACP SDK's `Diff` / `ToolCallContent` types back the new `diff` card.

+ 3 - 2
packages/core/tools/src/index.ts

@@ -159,8 +159,9 @@ export interface TerminalCallView {
  * A call that creates or modifies files, rendered as an inline diff card by a
  * capable UI. Set by a tool whose call writes/edits a file (e.g. `write`,
  * `edit`). The diffs are derived from the call ARGUMENTS (a create's `oldText` is
- * `null`); the result-time applied-hunk diff (with context) is a separate
- * {@link DiffResultView} the tool emits after `execute`.
+ * `null`); the tool emits a separate {@link DiffResultView} after `execute` — the
+ * applied change (an edit/overwrite hunk with context, or a whole-file diff for a
+ * create).
  */
 export interface DiffCallView {
   card: 'diff'

+ 3 - 2
packages/fs/fs-local/src/fsio.ts

@@ -386,8 +386,9 @@ export async function readForEdit(
  * Best-effort read of a file's current text for a before/after diff basis, used
  * by an overwrite. Returns the LF-normalized decoded content, or `null` when the
  * file is binary or not valid UTF-8 — a write must succeed regardless of the
- * prior bytes, so an undiffable prior file simply yields no contextual diff
- * (the caller treats `null` the same as an absent file: call-time card only).
+ * prior bytes, so an undiffable prior file simply yields no contextual-hunk basis
+ * (the caller treats `null` the same as an absent file: the result renders a
+ * whole-file diff rather than an applied hunk).
  */
 export async function readTextForDiff(absolutePath: string, signal?: AbortSignal): Promise<string | null> {
   const buffer = await readFileAbortable(absolutePath, 'read', signal)

+ 4 - 2
packages/fs/fs/src/types.ts

@@ -103,8 +103,10 @@ export interface FsWriteOutcome {
   version: FsVersion
   /**
    * The file's content BEFORE the write, or `null` when the file did not exist
-   * (a create). LF-normalized storage text (the diff basis), never a diff — a
-   * consumer computes the result-time contextual diff from `before`/`after`.
+   * (a create) or was undiffable (binary/non-UTF-8). LF-normalized storage text
+   * (the diff basis), never a diff — a consumer computes the result-time
+   * contextual diff from `before`/`after` when `before` is present, else falls
+   * back to a whole-file diff.
    */
   before: string | null
   /** The file's content AFTER the write, LF-normalized to share `before`'s diff basis. */

+ 6 - 4
packages/ui/acp/src/index.ts

@@ -1170,10 +1170,12 @@ function toolResultUpdate(callId: CallId, view: ToolResultView, isError: boolean
         ...view.title !== undefined ? { title: view.title } : {},
       }
     case 'diff': {
-      // A result-time applied-hunk diff: emit one `{ type: 'diff' }` content block
-      // per hunk (mirroring the call-side diff arm). `tool_call_update.content`
-      // REPLACES the call's content in an editor, so these hunks supersede the
-      // call-time whole-file snippet the pending card installed.
+      // A result-time diff: emit one `{ type: 'diff' }` content block per entry
+      // (an applied hunk for an edit/overwrite, or a whole-file diff for a
+      // create), mirroring the call-side diff arm. `tool_call_update.content`
+      // REPLACES the call's content in an editor, so this result diff supersedes
+      // the diff the pending card installed (and keeps the model-facing result
+      // text from clobbering it).
       const content: AcpToolCallContent[] = view.diffs.map(d => ({ type: 'diff', path: d.path, oldText: d.oldText, newText: d.newText }))
       return {
         sessionUpdate: 'tool_call_update',