Repository navigation
feat(paste): event-driven submit + per-paste debug dump + headless quirks docs - #71
Merged
Merged
Conversation
…irks docs
Bundles three coordinated changes addressing the long-standing
"first Enter on a multi-line paste does nothing; second Enter
submits" intermittent in Claude composers.
Track A — documentation in claude-code-headless submodule:
- Thick WHY comment above HeadlessTerminal.scheduleFlush explaining
that the 'screen' event silently stops firing under Claude's
synchronized-output protocol (pendingWrites stays > 0 with
@xterm/headless under sync-out pressure). Consumers needing
correctness should poll snapshotPlain() directly.
- Stronger warning on the activity-event debouncer that the
SPINNER_VERB_RE walk produces false negatives during
tool-result rows and transient headers, and the 'activity'
event must NOT be used as a binary "did this submit?" verdict.
The paste-submit harness lost 2/10 iterations on a spurious
spinner read before we figured this out.
Track B — per-paste debug dump:
Mirror of the dictation-debug subsystem from PR #68. Every Enter
in a Claude composer mints a pasteId and emits
RENDER/IPC/PTY/SCREEN/OUTCOME events into
<userData>/paste-debug/<pasteId>.paste.jsonl. Renderer and main
both write into the same file keyed by pasteId; payloads are
sha8-fingerprinted so the IPC and PTY events can be paired across
the renderer↔main boundary. 100 ms batched, 14-day prune.
This is the diagnostic that will finally answer "why does the
PTY-isolated harness pass 10/10 with the production 125 ms timer
but the user still hits the bug live?" Hypotheses include IPC
variance shrinking the effective gap, a double-fire on Enter
where a second \r races the first paste's payload, or a React
state mutation between paste and submit — the dump shape lets us
pick the right one from a real failing session.
Track C — event-driven paste-submit:
Replaces the unconditional 125 ms wall-clock wait between
bracketed paste and \r with a poll for Claude's `[Pasted text #N]`
placeholder. The PTY-isolated harness shows event-driven is
10/10 reliable with an average wait of ~58 ms vs. the timer's
125 ms unconditional floor. Falls back to the timer after a 2 s
safety bound if the placeholder never materializes (future-Claude
rename insurance). Gated by settings.eventDrivenPasteSubmit,
default ON. Setting also exposed in Settings → Workspace.
Submodule bump:
packages/claude-code-headless → feat/paste-submit-headless-fix
e59235a — adds ClaudeCodeHeadless.awaitPastePlaceholder and the
two doc comments above. Will need to be merged to submodule main
before this cc-shell PR can merge.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced May 11, 2026
Juliusolsson05
added a commit
that referenced
this pull request
Sep 27, 2026
workflow-mcp#71 merged after #63: one shared pollUntil and run waits that end on every terminal status replace the 0.5 s counted polls that failed package CI. Test-only (six test files), so the lockfile still needs no resync (npm ci --dry-run accepts it). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Sep 27, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Three coordinated changes addressing the long-standing "first Enter on a multi-line paste does nothing; second Enter submits" intermittent in Claude composers. Built on top of the PTY-isolated reproduction harness at `vendor/in_progress/paste-submit-repro/` and the per-session debug-dump pattern from PR #68.
Track A —
claude-code-headlessdocumentationBoth comment-only changes land in the submodule (#7). Captures two findings the harness surfaced:
HeadlessTerminal.scheduleFlushstall under synchronized output —\\x1b[?2026h…\\x1b[?2026lsequences leave `pendingWrites` > 0 indefinitely; `'screen'` event silently stops firing even when the xterm buffer is being updated correctly. Recommend `snapshotPlain()` polling for correctness-critical consumers.Track B — per-paste debug dump
Mirror of the dictation-debug subsystem (PR #68). Every Enter in a Claude composer mints a `pasteId` and writes append-only JSONL at `/paste-debug/.paste.jsonl` with RENDER / IPC / PTY / SCREEN / OUTCOME / ERROR events:
100 ms batched writes, 14-day startup prune, 0o600 file mode, no raw PTY bytes ever (sha8 fingerprints only). New files: `src/main/pasteDebugJournal.ts`, `src/main/ipc/pasteDebug.ts`, `src/preload/api/pasteDebug.ts`.
This is the diagnostic that will answer "why does the PTY-isolated harness pass 10/10 but the user still hits the bug live?" Hypotheses include IPC variance shrinking the effective gap, a double-fire on Enter where a second `\r` races the first paste's payload, or a React state mutation between paste and submit. The dump shape lets us pick the right one from a real failing session.
Track C — event-driven paste-submit
Replaces the unconditional 125 ms wall-clock wait in `claudePaste.ts:43` with a poll for Claude's `[Pasted text #N]` placeholder via the new `ClaudeCodeHeadless.awaitPastePlaceholder()`. The PTY-isolated harness shows event-driven is 10/10 reliable with an average wait of ~58 ms vs. the timer's 125 ms unconditional floor (which the harness shows races even at 1000 ms under load — there's no T that's reliably long enough).
Gated by `settings.eventDrivenPasteSubmit` (default ON). Falls back to the existing 125 ms timer after a 2 s safety bound if the placeholder never materializes (future-Claude rename insurance). Settings entry at Settings → Workspace → Event-Driven Paste Submit.
Test plan
Plan / context
`docs/superpowers/plans/2026-05-11-paste-submit-harness-findings-and-fix.md` has the full session log, hypothesis space, and 10-task breakdown. Harness at `vendor/in_progress/paste-submit-repro/` (untracked scratch, not committed).
🤖 Generated with Claude Code