/** * @fileoverview Per-task tool-call detail layer (v2.0.0). * * This module is the SSR-side companion to the client-side * `public/tool-call-detail.js`. It owns: * * 1. **`computeDiff(oldStr, newStr)`** — LCS-based line diff that * replaces the v1.2.0 naive split-and-filter `renderDiffPanel()` * (`src/server.ts:1109`). The naive version mis-tagged context * lines as +/- whenever a duplicate line existed elsewhere in the * file. v2.0.0 uses a proper LCS table to identify the longest * common subsequence and only flags lines that actually leave or * enter the file. * * 2. **`renderToolCallDetail(call, opts)`** — the SSR HTML for the * right-hand detail panel. Replaces the inline `renderDiffPanel` * call inside the tool-row renderer. The HTML carries: * - `
` with tool name + status, * - `
` for the * Monaco editor (only when a path is known), * - `
    ` with LCS-marked lines. * * 3. **`extractToolCallFiles(call)`** — the canonical "what file is * this tool call touching?" helper. Mirrors `extractArgPath()` in * `src/server.ts` but returns the *first* match (used by the * detail renderer; the file-tree uses `extractAffectedPaths()` * from `src/file-tree.ts` for the *set*). * * 4. **`summarizeToolCalls(toolCalls)`** — produces a per-tool * aggregate used by the stats chip strip at the top of the * detail page. Previously this lived inline inside `renderTaskPage`; * v2.0.0 extracts it for unit testing. * * Design doc: §4 (data flow) and §5.1 (component breakdown). The HTML * output is XSS-safe: every user-supplied string is run through * `escapeHtml()` before injection. */ import type { ToolCallRecord } from "./types.js"; /** * A single diff line. `oldLine` and `newLine` are 1-indexed line numbers, * matching how editors display them. For `kind: "added"` lines, * `oldLine` is null; for `kind: "removed"` lines, `newLine` is null. */ export interface DiffLine { kind: "context" | "added" | "removed"; text: string; oldLine: number | null; newLine: number | null; } /** * Stats summary for a tool-call list. Counts + per-tool breakdown. */ export interface StatsSummary { total: number; success: number; fail: number; totalMs: number; byTool: Record; } /** * Options for `renderToolCallDetail()`. */ export interface RenderToolCallDetailOptions { /** The `data-tool-id` of the row this detail panel is rendering for. */ currentCallId: string; } /** * v2.0.7 (Task #2706): tools that mutate a file on disk and therefore * benefit from a Monaco + diff view. `read_file` is intentionally * excluded — a task with 20+ read_file calls would otherwise mount * 20+ Monaco placeholders, ballooning memory and causing the right-hand * "View file" detail panel to overlap the inline editors below. * * Anything NOT in this set falls through to `renderSimpleHeader()`, * which omits the monaco-editor / diff-body blocks entirely. * * Keep the set conservative: prefer false negatives (a write-style * tool falls through to simple header) over false positives (a * read-style tool mounts a Monaco editor we don't need). */ export declare const VIEW_TOOLS: ReadonlySet; /** * v2.5.12 (Task #2952): tools that write a whole-file content payload. * * For these tools the right-hand detail panel renders the FULL content * of the file the tool just wrote (line-numbered, no truncation) rather * than mounting a Monaco editor that loads the file from disk. The * Monaco path was causing two user-reported issues: * * 1. The /api/file-content endpoint truncates very large files; the * user saw only the first ~15 lines in the right panel. * 2. Even when not truncated, Monaco never reflected what the tool * call actually wrote — only what was on disk afterwards (which * can differ if a later edit_file rewrote the same path). * * Anything else in {@link VIEW_TOOLS} (edit_file, multi_edit_file, * apply_patch, etc.) keeps the existing diff/Monaco behavior. */ export declare const WRITE_FILE_TOOLS: ReadonlySet; /** * v2.5.22 (Task #3063): tools that perform targeted line-level edits * (vs whole-file writes). For these tools the right-hand detail panel * MUST show a git-style diff (LCS +/-) of the change set, NOT the * post-edit full file contents. * * Background: prior to this fix, the view body for edit_file calls * mounted BOTH a `
    ` (the diff) AND * a `
    ` placeholder that loaded the entire * file from disk via /api/file-content. When the user clicked "View * file" they saw Monaco rendering the whole file (often 669+ lines), * which buried the actual change set the tool made. * * The fix: for tools in this set we render ONLY the diff block and * rename the toggle label from "View file" → "View diff" so users * know what they're about to expand. * * Anything else in {@link VIEW_TOOLS} keeps the existing Monaco + diff * behavior (e.g. unknown tool variants fall back gracefully). */ export declare const EDIT_FILE_TOOLS: ReadonlySet; /** * Compute an LCS-based line diff between `oldStr` and `newStr`. * * Algorithm: classic O(N*M) dynamic-programming LCS table, then a * single backtrack to produce the diff. N+M ≤ ~400 lines in practice * (an edit_file call rarely touches more than that); for the very * rare larger inputs the renderer falls back to "context only" mode * (no +/- markers) to keep memory bounded. We expose the size * decision to the caller via the returned array length — callers can * cap the render. * * Empty inputs return `[]`. Identical inputs return N context lines * with no +/- markers. Replaced lines surface as `removed` followed * by `added` (the LCS picks which half of the diff to emit; the other * half is the same shape). */ export declare function computeDiff(oldStr: string, newStr: string): DiffLine[]; /** * Return the first path-like field found on a tool call's `args`, or * `null` if none of the canonical aliases are present. * * Lookup order matches `extractArgPath()` in `src/server.ts` so SSR * + CSR stay in sync. */ export declare function extractToolCallFiles(call: { args?: Record; }): string | null; /** * Render the right-hand detail panel for a single tool call. * * The output is a self-contained `
    ` * block. The block can appear: * - inside the existing tool-row `` (replacing * the current inline `
    `), or * - in a new "current call" panel that lives below the toolcalls * table (preferred when a mermaid node is clicked — the table row * expands AND the dedicated panel scrolls into view). * * The HTML always carries `data-current-call=""` so the * client can locate it from a mermaid `__toolClick(N)` callback. * * v2.0.7 (Task #2706): conditional view rendering. Tools NOT in * {@link VIEW_TOOLS} (most importantly `read_file`) skip the * Monaco / diff block entirely — they only emit the header. Tools * IN {@link VIEW_TOOLS} (write/edit variants) wrap their Monaco + * diff block inside a `data-view-body` container that is collapsed * by default (`hidden` attribute) and exposes a `data-view-toggle` * button the user must click to expand. This eliminates the * "20 read_files × full Monaco" memory pressure the user reported * on Feishu (2026-08-03) and removes the layout overlap between * the right-hand detail panel and the inline editors below. */ export declare function renderToolCallDetail(call: ToolCallRecord, opts: RenderToolCallDetailOptions): string; /** * Aggregate counts + per-tool stats for a list of tool calls. * * Used by the per-task stats chip strip. The v1.2.0 implementation * inlined this in `renderTaskPage`; v2.0.0 extracts it for unit * testing and to share with the client-side `tool-call-detail.js` * (which renders the same chips on hydration for live updates). */ export declare function summarizeToolCalls(toolCalls: ReadonlyArray): StatsSummary; //# sourceMappingURL=tool-call-detail.d.ts.map