From f22a3b33c870a694b7a512d6e8f9b885b9674a06 Mon Sep 17 00:00:00 2001 From: Markus Fritsche Date: Sun, 10 May 2026 14:42:56 +0000 Subject: [PATCH] renderer: assistant text, exec output frame, status line MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 0 minimal output formatting per PHASE0.md skeleton. M.assistant(text) — line-by-line; `CMD: ` lines bold+cyan M.exec_output(output, code) — top/bottom rules; exit code on closing rule (red on non-zero) M.status(line) — dim "[aish] ..." single-liner ANSI table is local to the module (no external dep). Trailing-sentinel pattern ((text..\"\\n\"):gmatch(\"([^\\n]*)\\n\")) preserves blank lines in assistant output rather than squashing them, at the cost of one extra trailing newline — acceptable for Phase 0. Real syntax-aware formatting (tree-sitter) lands in Phase 6. Smoke verifies escape codes are emitted (od -c shows \\033[1m\\033[36m around CMD: line) and the visual layout looks right. Co-Authored-By: Claude Opus 4.7 (1M context) --- renderer.lua | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/renderer.lua b/renderer.lua index 2456fd4..1e1ff67 100644 --- a/renderer.lua +++ b/renderer.lua @@ -1,19 +1,51 @@ -- renderer.lua — output formatting and ANSI sequences. --- Phase 0: minimal — assistant text plain-printed; CMD: lines highlighted; --- exec output framed. Syntax highlighting hooks land in Phase 5. +-- Phase 0: assistant text plain-printed with `CMD: ` lines highlighted; +-- exec output framed with the exit code on the closing rule. Syntax +-- highlighting hooks land in Phase 6 (was Phase 5 pre-MCP renumber). local M = {} +local A = { + reset = "\27[0m", + bold = "\27[1m", + dim = "\27[2m", + cyan = "\27[36m", + red = "\27[31m", +} + +local function emit(...) io.write(...); io.flush() end + +-- Print assistant response text. Lines beginning with `CMD: ` (per the §3 +-- substrate-locked extraction marker) are emitted bold+cyan so the user +-- can spot the suggestion without scanning prose. function M.assistant(text) - error("renderer.assistant: not implemented (Phase 0 pending)") + for line in ((text or "") .. "\n"):gmatch("([^\n]*)\n") do + if line:sub(1, 5) == "CMD: " then + emit(A.bold, A.cyan, line, A.reset, "\n") + else + emit(line, "\n") + end + end end +-- Frame captured shell-exec output with a top rule + the body + a closing +-- rule that carries the exit code (red on non-zero). function M.exec_output(output, exit_code) - error("renderer.exec_output: not implemented (Phase 0 pending)") + output = (output or ""):gsub("\n$", "") + emit(A.dim, "─── exec output ───", A.reset, "\n") + if output ~= "" then emit(output, "\n") end + if exit_code and exit_code ~= 0 then + emit(A.dim, "─── exit ", A.reset, + A.red, tostring(exit_code), A.reset, + A.dim, " ───", A.reset, "\n") + else + emit(A.dim, "─── exit 0 ───", A.reset, "\n") + end end +-- Single-line dim status (e.g. §8 eviction notice, model switch confirms). function M.status(line) - error("renderer.status: not implemented (Phase 0 pending)") + emit(A.dim, "[aish] ", tostring(line), A.reset, "\n") end return M