Skip to content

harness: str_replace L2 — TEAL/EMBER side backgrounds #687

Description

@btipling

Summary

Follow-up to #684 / plan #665 (source #368).

L1 path + expandable L2 audit is on main. L2 still paints the whole detail as one teal_text mono block. This issue is paint, not a new emit shape: old side on an EMBER background, new side on a TEAL background. No per-line - / + prefixes (that was the previous ask; dropped).

Do not revive #685’s other choices (cap-before-redact, JS .length as “bytes”, untested execute path, delete-has_detail for all tools).

Current behavior (baseline on main)

Layer What happens now
Emit appendStrReplaceDiff in lib/agent/tools.ts — redact then cap 4096 UTF-8 bytes/side, structural -old_string / +new_string headers. Content lines that equal a header get a leading space.
L2 preview buildStrReplacePreview in lib/agent/agentStream.ts — positional header parse + per-side window 20/6.
L1 itemLabel hides host name · running… / name · ok / name · failed; error briefs with a path still show.
Paint paintToolRun dumps it.detail in one textLayout with palette.teal_text (native/harness/src/ui/toolrun.zig). No side boxes.

Desired UX

Expanded str_replace L2 is two stacked bands under the status line:

Side Background Text
old (removed) palette.ember_surface (or ember_bg) palette.ember_text
new (added) palette.teal_surface (or teal_bg) palette.teal_text
  • Status line stays uncolored chrome (path + replacements + bytes) — still the L1 brief source. salientToolBits ignores the body.
  • No - / + line prefixes and no need to change the emit to unified-diff. Keep -old_string / +new_string as parse sentinels (do not paint those header lines, or paint them as muted labels).
  • Empty new_string (delete): old band still shows; new band is an empty TEAL strip so the operator sees “nothing added.”
  • replace_all still one pair.
  • Other tools’ L2 unchanged (still one teal_text block).

EMBER is danger-only in the palette contract. Removal is the destructive side — use surface/bg + text, not ember_accent (that stays the ✗ glyph). No freehand hex.

Implementation sketch (not locked)

  1. Wasm (native/harness/src/ui/toolrun.zig, maybe a pure split in rich/toolrun.zig): when name == str_replace and detail has the two headers, split status / old / new. Paint old in an EMBER-filled box, new in a TEAL-filled box. Mono face stays.
  2. Emit / preview: leave tools.ts + buildStrReplacePreview as shipped in feat(agent): show str_replace path + expandable old→new diff #684 unless paint needs a tighter sentinel. Do not switch to per-line -/+.
  3. Tests: Zig unit test on the splitter (old vs new, escaped content line +new_string, empty new). zig build test-rich on the runner. No protocol bump.
  4. Docs: docs/harness-limits.md Two-level expand row — L2 str_replace is two palette bands, not a unified-diff dump.

Non-goals

  • Per-line - / + prefixes (explicitly not this issue)
  • Revert / apply buttons
  • write_file diffs
  • Changing str_replace match semantics
  • Colorizing exec / read_file / other tools
  • Forbidden: dual DOM chat · secrets in Wasm · cap-before-redact · treating JS .length as bytes · painting host status fallbacks on L1 · freehand hex / non-palette colors

Acceptance

  • Successful str_replace L2 paints old on EMBER surface, new on TEAL surface
  • No per-line - / + prefixes added
  • Header sentinels are not shown as raw -old_string / +new_string dump (hidden or muted labels)
  • Redact-then-cap 4096 UTF-8 bytes/side + per-side 20/6 window unchanged
  • L1 path + Goal 3 unchanged
  • docs/harness-limits.md matches
  • No protocol bump

Related

  • Landed: #684 merge c9f4684, plan #665
  • Display source (closed, prefixes only): #685 / #663
  • Parent product ask: #368

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions