Skip to content

fix: Shift+Enter が改行にならず [27;2;13~ と挿入される問題を修正 - #14

Merged
takecchi merged 1 commit into
mainfrom
codiva/shift-enter-27-2-13-pr-2
Jul 19, 2026
Merged

fix: Shift+Enter が改行にならず [27;2;13~ と挿入される問題を修正#14
takecchi merged 1 commit into
mainfrom
codiva/shift-enter-27-2-13-pr-2

Conversation

@takecchi

Copy link
Copy Markdown
Owner

概要

Shift+Enter で改行しようとすると、入力欄に [27;2;13~ という文字列がそのまま挿入されてしまう問題を修正しました。

原因

Ghostty / xterm 系の端末は Shift+Enter を modifyOtherKeys / CSI-u エスケープESC [27;2;13~)として送信します。Ink のキーパーサはこの形式を解釈できず、ESC を剥がした生テキスト [27;2;13~useInput に渡すため、composer にそのまま挿入されていました。

変更点

  • src/core/key-sequence.ts(新規): 純粋な decodeKeySequence() を追加。parseSgrMouse と同様の境界パーサで、

    • modifyOtherKeys 形式 CSI 27 ; mod ; code ~
    • CSI-u 形式 CSI code ; mod u

    の両方を復号し、Enter / Tab / Esc / Backspace / 印字文字 + Shift / Ctrl / Meta 修飾に正規化します。修飾値は 1 + bitmask(bit0=Shift, bit1=Alt, bit2=Ctrl)。

  • src/ui/session-list.tsx: useInput でマウス解釈の直後にエスケープを復号し、実キー chord に変換してから resolveEnter / editText に渡すように変更。これで Shift+Enter が改行として扱われます(既存の「末尾バックスラッシュ + Enter」フォールバックも維持)。

  • アーキテクチャ規約に従い、解析ロジックは純粋関数として core/ に配置し、I/O(Ink useInput)は view 側に閉じ込めています。

テスト計画

  • src/core/key-sequence.spec.ts: Shift/Ctrl/Alt+Enter、Tab/Esc/Backspace/印字文字、CSI-u 形式、非該当入力(テキスト・マウスレポート・未終端)をテーブルドリブンで検証
  • tests/app.test.tsx: ESC [27;2;13~ を実際に stdin へ流し、改行が入って submit されない → プレーン Enter で 2 行プロンプトが送信される、を end-to-end で検証
  • npm test(365 passed / coverage: key-sequence.ts 100% lines)
  • npm run typecheck / npm run lint(新規エラー・警告なし)
  • 実機(Ghostty + 日本語 IME)で Shift+Enter が改行になることを手動確認

Ghostty/xterm 系端末は Shift+Enter を modifyOtherKeys / CSI-u エスケープ
(`ESC [27;2;13~`)で送るが、Ink はこれを解釈できず生テキストとして渡すため、
入力欄に `[27;2;13~` がそのまま挿入されていた。

- core/key-sequence.ts に純粋な decodeKeySequence() を追加(parseSgrMouse と同様の
  境界パーサ)。modifyOtherKeys(`[27;mod;code~`)と CSI-u(`[code;mod u`)の両形式を
  復号し、Enter/Tab/Esc/Backspace/印字文字+Shift/Ctrl/Meta 修飾に正規化する。
- session-list の useInput でマウス解釈の直後に復号し、実キー chord へ変換してから
  resolveEnter / editText に渡す。これで Shift+Enter が改行として扱われる。
- 単体テスト(key-sequence.spec.ts)と統合テスト(app.test.tsx)を追加。
@takecchi
takecchi merged commit 7678cc7 into main Jul 19, 2026
1 check passed
@takecchi
takecchi deleted the codiva/shift-enter-27-2-13-pr-2 branch July 19, 2026 07:46
takecchi added a commit that referenced this pull request Aug 6, 2026
## 背景

セッションが自分で別ブランチを切って `gh pr create` すると、1 セッションに複数の PR が紐づきます。しかし一覧の PR
セルは**セッションブランチ(`codiva/<slug>`)の PR しか出せず**、2 本目以降はどこにも表示されませんでした。

## 変更内容

### 検知(`core/pr-detect.ts` 新規・純粋)

- `gh pr create` を実行した **tool_use の結果**に出る PR URL を拾う(`sdk-parse` が
tool_use id を控えて tool_result と突き合わせる)。
- ログ全体から URL を拾わないのは誤検出を避けるため — `gh pr list` の出力や、`gh pr view` /
WebFetch で覗いただけの他人の PR まで「このセッションの PR」になってしまう。
- MCP の `create_pull_request` 系ツールもツール名で拾う。
- 参照の追加・除去は**変化が無ければ同じ配列参照を返す**(`state.json` を無駄に書き直さない / 再描画を増やさない)。

### 状態・永続化

- `SessionState.extraPrs`(識別のみ・**永続**)と
`prCreateToolIds`(結果待ちの対応付け・transient)を追加。
- `state.json` に保存・復元(壊れた要素は 1 件ずつ落とす)。reducer はブランチの PR と重複したら畳む。

### 表示

| 画面 | 表記 |
|---|---|
| 一覧 | `✓ #12 +2`(代表 + 残り件数)。PR 列は複数 PR の行があるときだけ 10 → 14 桁に広げる |
| 詳細 | `PR 3 件: ✓ #12 · #13 · #14`(複数 PR のときだけ 1 行。1 本ならログの縦幅を 1 行も譲らない)
|

- **代表はセッションブランチの PR**。`prStatus`(グリフ)を持つ唯一の PR で、クリック / `p`
で開く先でもあるため、見えている番号と開く先とグリフの意味を一致させた。
- セッションが自分で作った PR は codiva が追跡・操作しない(別ブランチのものを勝手に ready
化・マージしない)ので**番号のみ・グリフなし**。状態を知らないのに緑や赤で嘘をつかない。
- **`gh` の追加呼び出しはゼロ**(API クォータを増やさない)。
- 描画とクリック当たり判定は必ず同じ列幅(`core/list-hit.ts` の `prCellWidth`)を使う。
- `PrCell` / `prStatusBadge` は `ui/pr-cell.tsx` に共通化(一覧と詳細で同じグリフ・同じ色)。

### ドキュメント

`README.md`(利用者向けの表記説明)/ `docs/ARCHITECTURE.md`(状態フィールド・設計判断)/
`docs/TASKS.md`(Phase 27)/ `CLAUDE.md`(コードの地図)。

## テスト

- `src/core/pr-detect.spec.ts`(新規・テーブルドリブン): コマンド判定 / URL 抽出(GHE
ホスト・サブパス・重複・issues リンク)/ 参照同一性 / 上限 / 表示ヘルパ。
- `src/core/sdk-parse.spec.ts`: 実フィクスチャと同じメッセージ形で tool_use → tool_result
の対応、`gh pr list` を数えないこと、ブランチ PR と判明したら畳むこと。
- `src/core/persistence.spec.ts`: 往復と壊れた JSON の扱い。
- `src/core/list-hit.spec.ts`: 列幅の切替。
- `tests/app.test.tsx`: 一覧に `✓ #42 +2` が出て `#43` は出ないこと、詳細に全件が並ぶこと、1
本のときは詳細に PR 行を出さないこと。

### 動作確認

- [x] `npm run lint` / `npm run typecheck` / `npm test`(2,232 件)/ `npm
run build`
- [ ] 実 TTY + Claude 認証での手動確認(非対話セッションでは実行できないため未実施)。確認観点: 複数 PR
を出したセッションの行が `#12 +2` になり、PR セルのクリックで代表の PR が開く / 詳細ビューに全件が並ぶ / 再起動しても
`+n` が残る。

🤖 Generated with [Claude Code](https://claude.com/claude-code)
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.

1 participant