refactor: codebase audit cleanup — dead code, dedup, module splits

Multi-agent audit + aggressive cleanup across server/web/coder/booterm,
delivered behind a DEFER discipline so none of the in-flight files were
touched. Removes dead code/deps/columns, dedups server + coder helpers,
and splits the oversized modules (tools.ts, opencode-server.ts,
sentinel-summaries, turn.ts, TerminalPane.tsx) behind stable contracts.
Adds 78 parity/unit tests (server 587, coder 323); fixes two latent bugs
(ChatPane queue keys, FileViewerOverlay blank-line parity).

Intended tag: v2.7.12-audit-cleanup.
This commit is contained in:
2026-06-02 21:10:06 +00:00
parent 6560398285
commit abe1a311d0
143 changed files with 6729 additions and 6087 deletions

View File

@@ -1,11 +0,0 @@
/** User messages are inserted atomically — never stream-append like assistant deltas. */
export function applyMessageDelta(
role: 'user' | 'assistant' | 'system' | 'tool',
existingContent: string,
chunk: string,
): string {
if (role === 'user') {
return chunk || existingContent;
}
return existingContent + chunk;
}

View File

@@ -7,12 +7,3 @@ export function isCoderSessionName(name: string | null | undefined): boolean {
return false;
}
/** Optimistic coder pane shell before scoped chat id arrives from the server. */
export function defaultCoderWorkspacePane(id: string = crypto.randomUUID()) {
return {
id,
kind: 'coder' as const,
chatIds: [] as string[],
activeChatIdx: -1,
};
}

View File

@@ -63,6 +63,3 @@ export function mergeWireToolCall(
return [...list, entry];
}
export function wireToolCallsToRuns(wires: CoderToolCallWire[] | undefined): ToolRun[] {
return (wires ?? []).map(wireToolCallToRun);
}

View File

@@ -1,5 +1,44 @@
export function formatTokens(n: number | null | undefined): string | null {
if (n === null || n === undefined) return null;
if (n < 1000) return `${n} tok`;
return `${(n / 1000).toFixed(1)}k tok`;
// Short "Xs/m/h/d/mo/y" relative time without "ago" suffix (ProjectSidebar).
export function relTime(iso: string): string {
const now = Date.now();
const t = Date.parse(iso);
if (Number.isNaN(t)) return '';
const sec = Math.max(0, Math.floor((now - t) / 1000));
if (sec < 60) return `${sec}s`;
const min = Math.floor(sec / 60);
if (min < 60) return `${min}m`;
const hr = Math.floor(min / 60);
if (hr < 24) return `${hr}h`;
const day = Math.floor(hr / 24);
if (day < 30) return `${day}d`;
const mo = Math.floor(day / 30);
if (mo < 12) return `${mo}mo`;
return `${Math.floor(mo / 12)}y`;
}
// "just now / Xm ago / Xh ago / Xd ago" with locale-date fallback for >7d
// (SessionLandingPage).
export function formatRelative(iso: string): string {
const then = new Date(iso).getTime();
if (Number.isNaN(then)) return '';
const s = Math.max(0, Math.round((Date.now() - then) / 1000));
if (s < 60) return 'just now';
const m = Math.round(s / 60);
if (m < 60) return `${m}m ago`;
const h = Math.round(m / 60);
if (h < 24) return `${h}h ago`;
const d = Math.round(h / 24);
if (d < 7) return `${d}d ago`;
return new Date(iso).toLocaleDateString();
}
// "just now / Xm ago / Xh ago / Xd ago" with no full-date fallback (AgentPicker).
export function formatAgo(iso: string): string {
const then = new Date(iso).getTime();
if (Number.isNaN(then)) return '—';
const diff = Date.now() - then;
if (diff < 60_000) return 'just now';
if (diff < 3_600_000) return `${Math.round(diff / 60_000)}m ago`;
if (diff < 86_400_000) return `${Math.round(diff / 3_600_000)}h ago`;
return `${Math.round(diff / 86_400_000)}d ago`;
}

View File

@@ -0,0 +1,34 @@
import type { ReactNode } from 'react';
import { sessionEvents } from '@/hooks/sessionEvents';
// Match path-shaped substrings ending in `.ext`. Requires a `/` in the match
// to reduce false positives in prose (e.g. plain `foo.ts` won't match but
// `src/foo.ts` will). False positives at the edges are accepted (2026-05-14).
const PATH_REGEX = /([a-zA-Z0-9._/-]+\.[a-zA-Z0-9]+)/g;
export function linkifyPaths(text: string, keyPrefix = 'p'): ReactNode {
const out: ReactNode[] = [];
let lastIdx = 0;
let idx = 0;
for (const match of text.matchAll(PATH_REGEX)) {
const matchedText = match[0];
const start = match.index ?? 0;
if (!matchedText.includes('/')) continue;
if (start > lastIdx) out.push(text.slice(lastIdx, start));
out.push(
<button
key={`${keyPrefix}-${idx}`}
type="button"
onClick={() => sessionEvents.emit({ type: 'open_file_in_browser', path: matchedText })}
className="text-primary underline cursor-pointer hover:text-primary/80"
>
{matchedText}
</button>
);
lastIdx = start + matchedText.length;
idx += 1;
}
if (out.length === 0) return text;
if (lastIdx < text.length) out.push(text.slice(lastIdx));
return out;
}

View File

@@ -0,0 +1,46 @@
// Terminal WebSocket wire protocol (centralized; v2 Phase 9 extraction).
//
// The booterm WS multiplexes two directions on one socket with a binary/text
// discriminator (mirrored server-side in apps/booterm):
// - PTY input (keystrokes, paste, hotkey bytes) is sent as a BINARY frame.
// - Control frames are JSON text: outbound {type:'resize',cols,rows};
// inbound {type:'init'} and {type:'exit',code}.
// This module is the single source of that encoding so a server-side protocol
// change is mirrored in one place. Behavior is byte-identical to the prior
// inline encoding scattered across TerminalPane.
// TextEncoder is stateless; a single shared instance is equivalent to the
// per-call `new TextEncoder()` the inline sites used.
const textEncoder = new TextEncoder();
// Keystrokes / paste / hotkey bytes go out as a BINARY frame so the server can
// disambiguate them from JSON control frames. TextEncoder is in every modern
// browser.
export function encodeInput(text: string): Uint8Array {
return textEncoder.encode(text);
}
// Resize is in-band on the WebSocket as a JSON text frame. The HTTP /resize
// endpoint had a race with PTY-map registration; WS frames don't.
export function encodeResize(cols: number, rows: number): string {
return JSON.stringify({ type: 'resize', cols, rows });
}
export type ServerControlFrame =
| { type: 'init' }
| { type: 'exit'; code: number };
// Parse an inbound text frame. Returns a recognized control frame, or `null`
// when the text is not JSON or not a known control type — in which case the
// caller writes it to the terminal as raw text. Preserves the original
// try/catch fall-through: a parse error or an unknown `type` both yield null.
export function parseServerFrame(data: string): ServerControlFrame | null {
try {
const parsed = JSON.parse(data) as { type?: string; code?: number };
if (parsed.type === 'init') return { type: 'init' };
if (parsed.type === 'exit') return { type: 'exit', code: parsed.code ?? 0 };
} catch {
/* not JSON — caller writes as text */
}
return null;
}