Skip to content

fix(cli): clear Sidekick Message on Control+C and preserve newline keys - #1124

Merged
taras merged 3 commits into
mainfrom
codex/sidekick-composer-1115
Nov 5, 2026
Merged

taras merged 3 commits into
mainfrom
codex/sidekick-composer-1115

Conversation

@taras

@taras taras commented Nov 5, 2026 •

Copy link
Copy Markdown
Owner

Why

Terminal.app’s captured Shift+Return sequence is dropped by input normalization. Control+C also exits while the focused Sidekick Message contains an unsent draft.

Closes #1115.

What changes

Before: Shift+Return can do nothing, and Control+C exits instead of clearing Message.

After: observed Escape+Return and distinct shifted Enter insert a newline. Control+C clears a nonempty focused Message, resets its caret and keeps focus. An empty Message retains joined exit or attached-UI detach. Interrupts received before the first frame is presented still leave, including on attachment and reattachment.

How it works

The existing decoder supplies the key fields. Normalization maps the supported newline forms to text, while ordinary Return submits. The focused Message claims Interrupt through the existing action/reducer path and decides clear versus exit from the current value. The command retains the exact pre-presentation leaving decision and uses its existing exit/detach owner.

What must stay true

  • Clearing preserves Draft/takeover, question answers, queued messages, admitted entries and Sidekick work.
  • A covered or unfocused Message does not intercept Control+C.
  • Empty-field leaving joins cleanup. Detachment keeps the headless child usable.
  • Same-burst input after leaving cannot submit; key releases insert nothing.

Verification

Final signed commit: 271cd7b730849f09aac4de986849d3c6c1169e99, based on main 2f0ddfd0c7c8352d1d61b0100f85ff541623356e.

Final correction evidence passes:

  • deno task test packages/cli/tests/repl-headless-attach.test.ts — 5 tests/12 steps; attached first-write detach, normal clear/empty-detach, usable child and terminal ownership.
  • deno task test packages/cli/tests/repl-sidekick-lifecycle.test.ts — 10/40; standalone first-write leaving, current-state clearing, caret/revision, work/drawer preservation and exact submitted text.
  • deno task test packages/cli/tests/repl-sidekick-acp.test.ts — 9/54; bootstrap, cleanup and retained ACP behavior.
  • The independent attached first-write witness now joins with no prompt, one reset and zero readers. Its regression fails on the earlier source.

Earlier terminal normalization, recovery/journey and production-source PTY evidence is retained for unchanged paths; it is not represented as rerun on the final commit. Those checks cover exact captured bytes, split reads, press/repeat/release, multiline paste and ordinary Return. Negative controls detect removal of both fixes.

Performance

Controlled mounted-REPL input-to-correct-screen measurements at 160×36, 15 measured samples per case:

Interaction Message length Median p95
Newline plus identifying token 16 8.62 ms 9.93 ms
Newline plus identifying token 4,096 15.76 ms 17.82 ms
Clear 16 8.32 ms 11.22 ms
Clear 4,096 7.41 ms 8.02 ms

Each measured interaction completed one content presentation. A 64-character burst took 16.75 ms and two content presentations. CPU/delegation costs and input-specific predicates were recorded and reviewed. These are controlled observations including the emulator, with no before/after baseline, physical GUI refresh or history-scaling claim. The auxiliary counter measures clock waits begun, not confirmed published ticks.

Review and delivery

The original Planner and independent Codex Astra both pass the final commit, with the startup findings integrated. Astra replaces the explicit Fable quota failure under AGENTS.md. Its nonblocking measurement wording qualification is incorporated above; no product blocker remains.

Required CI2458 passes on the final head, including the required green job. The typed delivery gate verifies the matching independent receipt, clean source/PR head and exact-current-main CI2453. Earlier CI2457 at 5f84413f failed an existing Node wheel-permission assertion tracked in #1125; its unchanged-source local pass used a slightly different platform/Node patch version. That issue remains open after this green run; no check is waived.

Risks and limitations

The original physical Control+J failure remains unreproduced. Captured bytes work in focused source and installed-0.14.0 PTY replays; this makes no universal fallback or physical GUI success claim. Terminal preferences are unchanged. The requested patch release follows this separate fix.

Scope confirmation

  • Every changed file supports the keyboard fix and verification.
  • Unrelated cleanup and formatting changes are excluded.
  • No generated files or dependencies change.
  • The description matches the final diff and evidence provenance.

…ift+Return newlines

Control-C in a focused Message that holds text clears it, puts its caret at
the start and keeps focus; on an empty Message, and anywhere else, Control-C
still leaves (or detaches an attached UI). The root decides clear versus leave
from its current message, so a burst cannot act on a stale description.

Terminal.app sends Shift+Return as ESC CR, which the decoder reports as Enter
with Alt and Control. That signature, and Enter carrying only Shift, now
normalize to a newline on press and repeat; plain Enter still submits.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found 1 redundant comment. Inline suggestions to remove them below.

Comment thread packages/cli/src/repl/program.ts Outdated
// Control-C through the tree, where only the focused message box
// handles it. Anything else leaves, and so does a screen too small to
// draw that box or one the reader already chose to end before it was
// presented.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant comment — restates what the code does.

Suggested change
// presented.

@github-actions

github-actions Bot commented Nov 5, 2026 •

Copy link
Copy Markdown

PR #1124: fix(cli): clear Sidekick Message on Control+C and preserve newline keys

10 files, +566 / -40

Scope

🟡 606 lines changed. PRs under 400 receive more thorough review.

Structural

Oxlint structural signals:

  • no-unused-vars ×15: packages/cli/src/repl/program.ts, packages/cli/src/repl/application.ts
  • no-unnecessary-boolean-literal-compare ×1: packages/cli/src/repl/application.ts

Slop

  • packages/cli/src/repl/program.ts:2407 (removed)
  • packages/cli/src/repl/program.ts:2409 (removed)

Static Analysis

Oxlint: 140 diagnostics across 3 files (11 rules)
Density: 0.247 violations/added-line

no-shadow (81): packages/cli/src/repl/description.ts, packages/cli/src/repl/program.ts, packages/cli/src/repl/application.ts
no-unused-vars (15): packages/cli/src/repl/program.ts, packages/cli/src/repl/application.ts
no-floating-promises (15): packages/cli/src/repl/program.ts
consistent-function-scoping (8): packages/cli/src/repl/description.ts, packages/cli/src/repl/application.ts
unbound-method (7): packages/cli/src/repl/description.ts, packages/cli/src/repl/program.ts
consistent-return (5): packages/cli/src/repl/application.ts, packages/cli/src/repl/program.ts
no-useless-default-assignment (3): packages/cli/src/repl/application.ts, packages/cli/src/repl/program.ts
no-duplicate-type-constituents (3): packages/cli/src/repl/application.ts
no-useless-fallback-in-spread (1): packages/cli/src/repl/description.ts
no-array-sort (1): packages/cli/src/repl/application.ts
no-unnecessary-boolean-literal-compare (1): packages/cli/src/repl/application.ts

Correctness

No extraneous code patterns detected.

The reader's eager Interrupt shutdown stayed active only until the first draw
began, so keys queued while that frame was still being written could reach
and clear the Message instead of leaving. Presentation is now marked only
after a draw returns a presented frame.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found 1 redundant comment. Inline suggestions to remove them below.

Comment thread packages/cli/src/repl/program.ts Outdated
// Control-C through the tree, where only the focused message box
// handles it. Anything else leaves, and so does a screen too small to
// draw that box or one the reader already chose to end before it was
// presented.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant comment — restates what the code does.

Suggested change
// presented.

@taras

taras commented Nov 5, 2026

Copy link
Copy Markdown
Owner Author

Independent review by Codex Astra, replacing the unavailable Fable review under AGENTS.md. Reviewed commit: 5f84413f165df4d65694a8ee062af3d7366c6160. Verdict: changes required.

One confirmed product finding concerns packages/cli/src/repl/program.ts:1070 and the attached UI’s first presentation. The reader records pre-presentation leaving only when liveScreen is absent. In an attached UI, hold the first content write while the screen is blank, feed Tab/Tab/Tab, first, Control+C, then release the write. The queued interrupt clears the newly focused Message instead of detaching. The local witness reached this path with no provider prompt; the UI remained editable and needed explicit cleanup. Cleanup joined with one terminal reset and no remaining reader.

Preserve the pre-presentation leaving choice through the existing attached detach owner, retain the headless child’s usability, and add this held-write regression. Keep the already accepted presented-Message clear/empty-detach behavior and standalone startup regression. The same original implementor is integrating this bounded finding.

All nine recorded clauses were examined and the required architecture reading is complete. The normal clearing, current-state burst handling, captured newline forms and retained terminal evidence support their accepted paths. No new parser, focus store or provider behavior is needed.

Performance evidence is still incomplete. Two scratch probes failed because their next-write wait did not establish that the measured input had completed. Those failures establish no product or performance regression, and no latency/frame-rate numbers are claimed. Valid input-specific completion and frame observation are being prepared for the affected closeout.

The independent review did not use CI as a verdict. Separately, CI2457’s existing Node wheel-permission assertion is tracked in #1125 with its first failure and qualified unchanged-source local pass. Required exact-head CI remains a delivery gate.

The reader latched a pre-presentation Control-C only for a standalone
terminal. An attached UI queued it as an ordinary key, so Tab and typing
queued ahead of it focused and filled the Message once the held first frame
arrived, and Control-C cleared it instead of detaching. Presentation is now
tracked per screen generation, and each Control-C read before its screen was
presented makes the loop leave on that exact event, detaching through the
existing owner while the child keeps running.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@taras

taras commented Nov 5, 2026

Copy link
Copy Markdown
Owner Author

Independent Astra affected closeout: PASS on 271cd7b730849f09aac4de986849d3c6c1169e99. The attached pre-presentation finding is fixed, the regression distinguishes the earlier failure, and detachment preserves child usability. All nine original clauses retain their final dispositions; no blocking product finding remains. The original Planner also passes this exact commit.

The supplied input-specific measurement method supports the controlled latency, CPU and completed content-frame observations now summarized in the PR description. Its auxiliary metric counts clock waits begun, not confirmed published ticks; the qualified report preserves that distinction. The short burst ratio is neither sustained nor physical terminal refresh, and no before/after baseline is claimed. Prior invalid probes and earlier review records remain preserved.

Final-head CI2458 is queued separately. A review pass does not waive required CI or current-main health; #1125 remains open for the earlier wheel-permission failure.

@taras
taras marked this pull request as ready for review November 5, 2026 12:35
@taras
taras merged commit 8095903 into main Nov 5, 2026
58 checks passed
@taras
taras deleted the codex/sidekick-composer-1115 branch November 5, 2026 12:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Clear Sidekick message text with Ctrl+C and support newline shortcuts

1 participant