fix(headless): suppress notification spam, categorize messages, distinguish phase vs status
Three small UX fixes for headless / autopilot logs: 1. Add `zz-notifications` to TUI_FOOTER_STATUS_KEYS — these are sticky notification dots from the interactive TUI footer; they have no meaning in headless and were spamming the log. 2. Categorize notification messages by prefix so headless output is scannable: [mcp] for MCP-client-ready, [search] for web search status, [parallel] for slice-parallel/subagent dispatch. Falls through to the existing important/non-important formatting for everything else. 3. Distinguish phase transitions from generic status updates: phase:/ milestone:/slice:/task: prefixed keys get [phase]; everything else gets [status]. Previously both used [phase], which was misleading. Patterns based on bunker commits 14ec4d97f / c15afb45f (which were the research source) but written fresh against our existing TUI_FOOTER_STATUS_KEYS structure rather than cherry-picked. The assistant-text-preview commit (cf0274c63) is a separate, larger refactor in headless.ts and is deferred to v3.1. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
c41912ff55
commit
dff0df5fdc
1 changed files with 39 additions and 2 deletions
|
|
@ -90,8 +90,39 @@ const TUI_FOOTER_STATUS_KEYS = new Set([
|
|||
"ollama",
|
||||
"sf-fast",
|
||||
"sf-auto",
|
||||
"zz-notifications",
|
||||
]);
|
||||
|
||||
/**
|
||||
* Categorize notification messages so headless logs are scannable —
|
||||
* `[mcp]` for MCP-client ready lines, `[search]` for search status,
|
||||
* `[parallel]` for slice-parallel/subagent dispatch. Returns null to
|
||||
* fall through to the default formatting.
|
||||
*/
|
||||
function formatCategorizedNotification(message: string): string | null {
|
||||
if (message.startsWith("MCP client ready")) return `[mcp] ${message}`;
|
||||
if (message.startsWith("Web search:")) return `[search] ${message}`;
|
||||
if (message.startsWith("Native Anthropic web search")) return `[search] ${message}`;
|
||||
if (message.includes("dispatching") && message.includes("subagents"))
|
||||
return `[parallel] ${message}`;
|
||||
if (message.startsWith("Slice-parallel:")) return `[parallel] ${message}`;
|
||||
if (message.startsWith("sf-reactive:")) return `[parallel] ${message}`;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* True when statusKey indicates a real phase/milestone/slice/task transition
|
||||
* (rather than a generic status update). Drives [phase] vs [status] tagging.
|
||||
*/
|
||||
function isPhaseStatusKey(statusKey: string): boolean {
|
||||
return (
|
||||
statusKey.startsWith("phase:") ||
|
||||
statusKey.startsWith("milestone:") ||
|
||||
statusKey.startsWith("slice:") ||
|
||||
statusKey.startsWith("task:")
|
||||
);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Tool-Arg Summarizer
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
@ -351,6 +382,9 @@ export function formatProgress(
|
|||
if (method === "notify") {
|
||||
const msg = String(event.message ?? "");
|
||||
if (!msg) return null;
|
||||
// Categorise known prefixes so headless logs are scannable.
|
||||
const categorised = formatCategorizedNotification(msg);
|
||||
if (categorised) return categorised;
|
||||
// Bold important notifications
|
||||
const isImportant =
|
||||
/^(committed:|verification gate:|milestone|blocked:)/i.test(msg);
|
||||
|
|
@ -368,10 +402,13 @@ export function formatProgress(
|
|||
// Show meaningful phase transitions.
|
||||
if (statusKey) {
|
||||
const label = parsePhaseLabel(statusKey, msg);
|
||||
if (label) return `${c.cyan}${tag("phase")}${label}${c.reset}`;
|
||||
if (label) {
|
||||
const labelTag = isPhaseStatusKey(statusKey) ? tag("phase") : tag("status");
|
||||
return `${c.cyan}${labelTag}${label}${c.reset}`;
|
||||
}
|
||||
}
|
||||
// Fallback: show message if non-empty.
|
||||
if (msg) return `${c.cyan}${tag("phase")}${msg}${c.reset}`;
|
||||
if (msg) return `${c.cyan}${tag("status")}${msg}${c.reset}`;
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue