Skip to content

fix(tui): keep a held Up key from crossing into prompt history - #3044

Open
bj456736 wants to merge 6 commits into
MoonshotAI:mainfrom
bj456736:fix/held-up-key-history-guard
Open

fix(tui): keep a held Up key from crossing into prompt history#3044
bj456736 wants to merge 6 commits into
MoonshotAI:mainfrom
bj456736:fix/held-up-key-history-guard

Conversation

@bj456736

Copy link
Copy Markdown
Contributor

Problem

Holding to reach the top of a long unsent draft fires key-repeat events. The repeats walk the cursor to the first line, then keep going — crossing into prompt history without any deliberate keypress. One stray edit on a recalled entry (e.g. a space) then silently drops the unsent draft.

Fix

Detect held-key repeats and bar them from crossing from the draft into history:

  • Kitty keyboard protocol (already negotiated with flags=7): use the reported press/repeat event type — exact.
  • Other terminals: a held key repeats every ~25–40ms while humans rarely re-press faster than ~100ms, so two ↑ events <100ms apart are treated as a repeat stream.

Semantics after the change:

  • Hold ↑ in a multi-line draft → cursor climbs to the top and stops there.
  • Release and press ↑ again (discrete press) → enters history, same as before.
  • Once history is entered by a discrete press, held ↑ keeps browsing (harmless; the draft snapshot is already captured).
  • ↓ behavior unchanged.

The companion fix (preserving the draft when a recalled history entry is edited) is intentionally not in this PR and will follow separately.

Tests

  • 3 new tests: repeat stream stops at the top of the draft and a later discrete press enters history; repeats keep browsing once history was entered discretely; Kitty repeat events are barred from entering history.
  • 5 existing history tests updated to advance a mocked clock so their keypresses read as discrete presses.
  • pi-tui suite: 977/977 pass; tsc --noEmit clean; oxlint 0 errors; app-side custom-editor/editor-keyboard suites pass.

A held Up key fires key-repeat events that walk the cursor to the top of
a multi-line draft and then, without any deliberate keypress, carry the
editor into prompt history — where a single stray edit silently drops
the unsent draft. Detect held-key repeats (Kitty keyboard protocol event
types where available, a 100ms inter-press heuristic elsewhere) and bar
them from crossing from the draft into history; discrete presses keep
the existing behavior, and once history is entered deliberately, repeats
may keep browsing.
@changeset-bot

changeset-bot Bot commented Aug 18, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 95f5505

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@moonshot-ai/kimi-code Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@bj456736

Copy link
Copy Markdown
Contributor Author

@codex review

@pkg-pr-new

pkg-pr-new Bot commented Aug 18, 2026

Copy link
Copy Markdown
pnpm dlx https://pkg.pr.new/@moonshot-ai/kimi-code@087fb7f
npx https://pkg.pr.new/@moonshot-ai/kimi-code@087fb7f

commit: 087fb7f

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 31c757600a

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/pi-tui/src/components/editor.ts Outdated
Comment thread packages/pi-tui/src/components/editor.ts
… the guard

On legacy terminals the first autorepeat arrives only after the
keyboard's initial repeat delay (X11 defaults to 660ms, macOS/Windows up
to ~1s), so it outruns the 100ms inter-press heuristic and still crosses
from the draft into history. Arm a snap-back on such crossings: a
repeat-classified Up arriving within the initial-delay window proves the
hold and navigates back out to the draft. Crossings followed by
deliberate navigation past the first entry are disarmed.

Also register the held-Up guard as divergence MoonshotAI#9 in the pi-tui
AGENTS.md local-divergence list so re-vendoring preserves it.
@bj456736

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 72049b60cc

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/pi-tui/src/components/editor.ts
@bj456736

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a2c8686d3c

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/pi-tui/src/components/editor.ts
A non-Up key between two Up presses proves the stream was interrupted,
so the next Up must read as a fresh press rather than an autorepeat of
the earlier one. Without the reset, Up → Down → quick Up failed to
re-enter history. The multiple-browse-session test now exercises the
reset path instead of masking it with a clock advance, and a dedicated
regression test covers the interrupted-stream case.
@bj456736

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ec2c3e613c

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/pi-tui/src/components/editor.ts Outdated
…nput

The chain reset lived in the base Editor's handleInput, but hosts also
break the stream outside it: programmatic setText ('') clears (e.g. the
Ctrl+C clear-draft path) and CustomEditor consumes shortcuts like Ctrl+C
before they ever reach super.handleInput. Expose resetUpArrowRepeatChain(),
call it from setText, and reset in CustomEditor for intercepted non-Up
keys. The setText history test now exercises the reset instead of
masking the stale timestamp with a clock advance; a new CustomEditor
test covers the intercepted-shortcut path.
@bj456736
bj456736 force-pushed the fix/held-up-key-history-guard branch from 8ccedd0 to 95f5505 Compare August 18, 2026 11:33
@bj456736

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 95f5505065

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/pi-tui/src/components/editor.ts Outdated
With the Kitty protocol the crossing event's press/repeat type is
exact, so a press crossing is deliberate — arming the timing-based
snap-back anyway made the first repeat of that same held key yank the
editor back to the draft instead of continuing through history. Only
arm when the Kitty protocol is inactive.
@chengluyu

Copy link
Copy Markdown
Collaborator

@codex review

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 087fb7f08f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +522 to +524
const repeat = isKittyProtocolActive()
? isKeyRepeat(data)
: gap < UP_ARROW_REPEAT_THRESHOLD_MS;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Fall back unless Kitty reports event types

When a terminal negotiates only a subset of the Kitty protocol flags, such as flag 1 without flag 2, terminal.ts still marks Kitty active for any nonzero flag set, while isKeyRepeat() is meaningful only with the report-event-types flag. In that environment every autorepeat arrives without :2 and is classified as a discrete press here, completely bypassing the held-Up history guard. Track whether negotiated flag 2 is enabled and use the timing heuristic when it is not.

AGENTS.md reference: packages/pi-tui/AGENTS.md:L17-L17

Useful? React with 👍 / 👎.

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.

2 participants