Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,24 @@ function ClaudePasteDetection({ sessionId, runtime, kind }: DevDebugModuleProps)
</div>

<div className="p-3 flex flex-col gap-3">
{/* Pane 0 — live screen copy. Reads runtime.screen every render, so it
stays in lock-step with the headless TUI: paste, and you watch the
composer fill (placeholder or inlined text) right here. This is the
exact snapshot the content-match submit detector keys on. */}
<section>
<div className="mb-1 flex items-center justify-between">
<span className="text-[9px] text-muted uppercase tracking-[0.12em]">
screen copy (live)
</span>
<span className="text-[10px] text-muted tabular-nums">
{plain.length} chars · {(plain.match(/\[Pasted text #\d+/g) ?? []).length} placeholders
</span>
</div>
<pre className="max-h-[140px] overflow-auto whitespace-pre-wrap break-words border border-[#222] bg-[#0b0b0b] px-2 py-1 text-[10px] leading-[1.45] text-ink-dim">
{plain.slice(-600) || '(screen empty)'}
</pre>
</section>

{/* Pane 1 — live detection */}
<section>
<div className="mb-1 text-[9px] text-muted uppercase tracking-[0.12em]">live detection</div>
Expand Down Expand Up @@ -134,14 +152,15 @@ function ClaudePasteDetection({ sessionId, runtime, kind }: DevDebugModuleProps)
<th className="text-right px-2 py-1 font-normal">issued→det</th>
<th className="text-right px-2 py-1 font-normal">det→cr</th>
<th className="text-left px-2 py-1 font-normal">outcome</th>
<th className="text-left px-2 py-1 font-normal">via</th>
<th className="text-right px-2 py-1 font-normal">len</th>
<th className="text-left px-2 py-1 font-normal">strategy</th>
</tr>
</thead>
<tbody className="text-ink-dim">
{rows.length === 0 ? (
<tr>
<td colSpan={6} className="px-2 py-3 text-center text-muted">
<td colSpan={7} className="px-2 py-3 text-center text-muted">
no submits recorded yet
</td>
</tr>
Expand All @@ -162,6 +181,17 @@ function ClaudePasteDetection({ sessionId, runtime, kind }: DevDebugModuleProps)
>
{row.outcome}
</td>
<td
className={`px-2 py-0.5 ${
row.via === 'inline'
? 'text-amber-400'
: row.via === 'placeholder'
? 'text-green-400'
: 'text-muted'
}`}
>
{row.via ?? '—'}
</td>
<td className="px-2 py-0.5 text-right">{row.composerLen ?? '—'}</td>
<td className="px-2 py-0.5 truncate">{row.strategy ?? '—'}</td>
</tr>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ export type SubmitLifecycle = {
outcome: SubmitOutcome
composerLen: number | null
strategy: string | null
/** Which absorption signal fired: 'placeholder' (collapsed paste) or
* 'inline' (medium paste, the #279 case) — null if it timed out. */
via: string | null
}

function find(events: PasteDebugEvent[], layer: string, event: string): PasteDebugEvent | undefined {
Expand All @@ -49,9 +52,14 @@ export function buildLifecycle(session: PasteDebugSession): SubmitLifecycle {
const ev = session.events

const enter = find(ev, 'RENDER', 'keydown:enter')
const appeared = find(ev, 'SCREEN', 'placeholder:appeared')
// Content-match events (#279 fix) with back-compat to the older
// placeholder-only event names so historical journals still read.
const appeared =
find(ev, 'SCREEN', 'paste:absorbed') ?? find(ev, 'SCREEN', 'placeholder:appeared')
const timedOut =
find(ev, 'SCREEN', 'placeholder:timeout') ?? find(ev, 'SCREEN', 'placeholder:no-session')
find(ev, 'SCREEN', 'paste:absorb-timeout') ??
find(ev, 'SCREEN', 'placeholder:timeout') ??
find(ev, 'SCREEN', 'placeholder:no-session')
const submitCr = find(ev, 'IPC', 'write:submit-cr')
const singleWrite = find(ev, 'IPC', 'write:paste-and-submit-single')
const threw = ev.find(e => e.layer === 'ERROR')
Expand Down Expand Up @@ -82,6 +90,7 @@ export function buildLifecycle(session: PasteDebugSession): SubmitLifecycle {
outcome,
composerLen: num(enter?.data, 'composerLen'),
strategy,
via: typeof appeared?.data?.via === 'string' ? appeared.data.via : null,
}
}

Expand Down
Loading