Skip to content

v0.39.0

Choose a tag to compare

@Kewton Kewton released this 18 Sep 16:14
· 24 commits to main since this release
9231557

[0.39.0] - 2026-09-19

Highlight: ナビゲーションの作り直しと画面遷移の刷新が中心のリリース。Home 画面と Assistant Chat を廃止し、サイドバー上端をリポジトリ/セッション/レビューの画面移動ナビに置き換えた。あわせて AppShell を root layout へ引き上げたことで、ナビを押してもシェルが作り直されなくなった(サイドバーのスクロール位置・ホバー中の並び・ローカル state が保たれる)。遷移中のスピナーもメイン領域の中央に収まり、フルリロードのような見え方が解消している。更新まわりでは、PC の右上に「Update v{版}」ボタンが出て、更新後に「新機能と改善」を日英で表示するようになった。

Added

  • test(e2e): 画面遷移中フォールバックの高さを実寸で固定する E2E テストを追加 (#2693): ルート共通のローディング表示(RouteLoading)がメイン領域を満たし縦中心に配置されること、スマホで下部ナビに重ならず利用可能領域の中央に来ること、および高さ auto の親でも 192px 以上の高さを維持することを、page.route による RSC 遅延と getBoundingClientRect の実寸測定で固定する E2E テストを追加。

  • feat(ui): サイドバーにエージェント(インスタンス)1 つ=1 行の「セッション」表示を追加 (#2656): サイドバーの「表示」セレクトに 3 つ目の選択肢「セッション」を追加し、ブランチ単位ではなくエージェント(インスタンス)単位で 1 行ずつ並べるようにした。行は buildSessionRows() がブランチの cliStatus(roster 全員+roster 外で稼働中のインスタンス)から作り、ドットはブランチの集約ではなくそのインスタンス自身の状態を出す(終了済みは「アイドル (終了)」)。並びは sortSessionRows() が状態(STATUS_PRIORITY 昇順=承認待ちが先)を常に先にし、次に選んだ並び順を使う(並び順が「ステータス」のときだけ、状態の段が向きに従う)。エージェントごとの最終活動時刻は API に無いので「更新日時」はブランチの updatedAt。行を押すと /worktrees/<id>?instance=<instanceId> へ移動し、詳細画面が roster 到着後に 1 回だけそのインスタンスを選ぶ(PC はヘッダーのインスタンス選択と同じ経路でトークン付きに分割へ配り、スマホは先に表示中へ加えてから選ぶ)。処理後は router.replace で instance だけを URL から外す(他のクエリは保持)。ViewMode は VIEW_MODES から導出する形に変え、保存値の検証は isValidViewMode に一本化した。grouped / flat の中身・保存キー・ブランチ行のクリック・既存 testid は変更なし。

  • feat(release): リリース手順に release-notes/<X.Y.Z>.json の作成と検査を追加 (#2652): アプリ内の「新機能と改善」ダイアログ(#2651)が読む日英の要約ファイルの作成手順、除外規則、形式検査テストを /release スキルとリリースガイドに追加した。CHANGELOG の節を書いたあとに、利用者が画面や CLI で気づく項目だけを平易な日本語と英語のプレーンテキストで 1 文にし、#2646 の形式(release-notes/<X.Y.Z>.json)で保存して tests/unit/release-notes/release-notes-files.test.ts で検査する手順を 2-2b として新設した。また、2-4 の git add と変更ファイル数の説明を 5 ファイルに更新し、手順の順序や規則を検証する tests/unit/docs/release-notes-skill.test.ts を追加した。

  • feat(ui): 更新後に「新機能と改善」ダイアログで変更点を出す (#2651): 画面を開いたとき、localStorage の commandmate.lastSeenAppVersion と bundle の NEXT_PUBLIC_APP_VERSION を比べ、上がっていれば GET /api/app/release-notes?from=&to=(#2646)のノートを Modal で表示する新規 src/components/common/WhatsNewDialog.tsx を追加し、AppShell の PC・スマホ両分岐で <VersionMismatchBanner /> の直後にマウントした。文言は UI の言語(ja / en)に追従し、ノートはプレーンテキストとして描く(Markdown / HTML として解釈しない)。閉じたときに現在の版を保存し、初回・版の下がり・壊れた保存値は保存だけして何も出さず、取得に失敗したときは保存せず次回に再試行する。あわせて appApi.getReleaseNotes(from, to) と ReleaseNotesResponse 型を src/lib/api-client.ts に、common.whatsNew.* の 8 キーを locales/{ja,en}/common.json に追加した。VersionMismatchBanner の位置・文言と appApi の既存関数は変更なし。

  • feat(app-update): 同梱リリースノート release-notes/<X.Y.Z>.json と GET /api/app/release-notes を追加 (#2646): 更新直後に出す「新機能と改善」(#2651)を UI の言語(ja / en)で出せるように、版ごとの利用者向け要約を日英のプレーンテキストで持つファイルをパッケージに同梱し(package.json の files へ release-notes/ を追加。日本語のみの CHANGELOG.md はこれまでどおり同梱しない)、「ある版からある版までに入った変更」を返す API を足した。src/lib/app-update/release-notes.ts の parseReleaseNote(raw, expectedVersion) は版・日付・{ ja, en }・件数(各 30)・文字数(500)の規則を 1 か所で判定し、1 つでも反すればそのファイルごと捨てる(知らないキーは返り値に含めない)。readReleaseNotesBetween(from, to, rootDir = process.cwd()) は readdir の結果のうち ^\d+\.\d+\.\d+\.json$ に合う通常ファイル(512 KiB 以下)だけを開き、from < v <= to を新しい順に最大 20 件返す(クエリの値でパスを組み立てないので traversal が届かない。ディレクトリとシンボリックリンクは lstat で除外)。「ノートが無い」と「読めなかった」は区別し、パスが無い(ENOENT / ENOTDIR)は []、それ以外の I/O 例外(EACCES / EIO)は throw して route が 500 を返す。GET /api/app/release-notes?from=&to= はどちらかが X.Y.Z でなければ 400、from >= to はファイルを読まずに { notes: [] }、全応答に Cache-Control: no-store を付け、認証は従来どおり middleware に任せる(AUTH_EXCLUDED_PATHS には入れない)。実際のノートファイルは #2652 の手順で次のリリースから作るため、release-notes/ が無い間 API は常に { notes: [] } を返す。同梱ファイルが実行時に黙って飛ばされることがないよう、名前・JSON・規則・版・シンボリックリンク・大きさの 6 種の陰性対照つきの検査(tests/unit/release-notes/release-notes-files.test.ts)を追加した。

  • feat(worktree): アクティビティバー最下部に設定メニューを追加し /more の見出しを辞書化 (#2645): PC のブランチ画面のアクティビティバー最下部に歯車ボタン(ActivityBarSettingsMenu)を配置し、設定(/more)・スキル(/skills)・テーマ・言語・GitHub・ログアウトをまとめたメニューを追加。あわせて /more の見出しを common.nav.more、説明文を common.settings.pageDescription から取得するように辞書化。

  • feat(sidebar): サイドバー上端を画面移動ナビにし要対応件数をレビュー行に集約 (#2644): サイドバーヘッダーにリポジトリ(同期ボタン含む)、セッション、レビュー(要対応件数チップ付き)のナビゲーションリスト(sidebar-nav)を追加し、表示切替と並び替えを独立したコントロール行(sidebar-list-controls)へ移動、「ブランチ」見出しと独立した要対応ピルを削除。

  • feat(release): CHANGELOG 断片(changelog.d/)の検証・集約スクリプトを追加 (#2640): 並列 PR での CHANGELOG.md 競合を防ぐため、Issue ごとの断片ファイル(changelog.d/<Issue番号>.md)を扱う scripts/changelog-fragments.mjs(check / preview / apply)と仕様ドキュメント changelog.d/README.md を追加。

  • feat(orchestrate): 契約検証にunit-relatedゲートを追加 (#2639): /orchestrate の検証(wait --verify)で、変更に関係するテストとリポジトリのファイルを読むテストだけを実行する unit-related ゲート(scripts/run-related-unit-tests.mjs)を既定に追加。テスト全体の実行をCIに任せることで、委任完了待ちの時間を短縮。

Changed

  • refactor(navigation): 画面ナビの遷移手段を TransitionLink と useViewTransitionRouter に統一 (#2684): サイドバーのナビ行を素の next/link から TransitionLink へ置き換え、コマンドパレットのルータを useRouter から useViewTransitionRouter へ変更することで、ヘッダーや設定画面と同様に View Transitions によるクロスフェード遷移に統一。

  • feat(worktree): PC の入力欄を手動リサイズ時も内容に応じて自動伸縮させ、保存値は拡大方向の下限として扱うよう変更 (#2681): PC の composer において、手動リサイズで保存された高さを固定高さではなく「下限(floor)」として扱うように変更。内容が下限より短ければ下限まで縮み、長ければ COMPOSER_AUTO_MAX_HEIGHT_PX(160px)まで内容に追従して自動伸長する。呼び出し側の maxHeight 上限を描画と CSS の両方に適用し、上限変化時も追従するよう修正。

  • refactor(assistant): Assistant Chat のサーバー側を削除 (#2655): #2649 で画面を消したあと呼び出し元が無くなっていた API 7 本(src/app/api/assistant/{conversation,current-output,messages,session,start,terminal,tools}/route.ts)、src/lib/assistant/ の 10 モジュール、src/lib/polling/assistant-conversation-poller.ts、src/lib/db/assistant-conversation-db.ts を削除し、@/lib/db からその関数・型の再 export を外した。tmux 直参照の allowlist は恒久除外 12 → 7・段階解消 16 → 15(合計 28 → 22)に、sanitizeEnvForChildProcess の呼び出し元は 6 → 5 に縮み、それぞれ .eslintrc.json と件数を固定するガードテストを実態へ合わせた。DB テーブル(assistant_conversations / assistant_messages / assistant_session_states / assistant_executions)とマイグレーション v28〜v30 は v1.0 まで残す(削除は #2657)ため CURRENT_SCHEMA_VERSION は 61 のまま、既存 DB はそのまま起動できる。削除した API へのリクエストは Next の既定どおり 404 になる。返答の保存経路(src/lib/assistant-response-saver.ts)と __global__ のセッション管理は別モジュールなので影響しない。

  • feat(ui): アップデートの状態をアプリ全体で持ち、PC の右上に「Update v{版}」ボタンを出す (#2654): 更新確認・更新の状態遷移(idle / confirming / starting / updating / no-restart / timeout / error)・再起動待ちを新しい AppUpdateProvider(AppProviders の ConfirmProvider の内側)へ移した。確認は起動時と 60 分ごと(idle のときだけ)に走り、失敗や degraded では前回の結果を保つ。PC のブランチ画面ヘッダーと上部ナビに「Update v{版}」ボタンが出て、情報モーダルを開かずに更新を始められる(global / npx は確認ダイアログ、それ以外はリリースページ。更新中は「更新中…」、no-restart / timeout / error は押すと従来のバナーをモーダルで出す)。スマホは info タブのバッジとバナーのまま変わらない。あわせて、情報モーダルで「今すぐアップデート」を押した直後にモーダルを閉じると再起動待ちが止まり、更新が終わってもページが再読み込みされない不具合を修正(Modal が閉じると子を unmount するため、バナーの中にあった ping ループごと消えていた)。src/hooks/useUpdateCheck.ts は廃止し、VersionSection / UpdateNotificationBanner / useWorktreeDetailController は useAppUpdate() を読む。

  • feat(ui): スマホのブランチ画面で、左上をサイドバー開閉にし、Home ボタンを削除する (#2653): Home 画面の廃止(#2658)に伴い、モバイルヘッダー(MobileHeader)の左上にあった Home ボタンを削除してサイドバー(ブランチ一覧)ドロワーを開くメニューボタンに置き換え、右上は検索ボタンのみにしてタイトルが中央に来るようレイアウトを調整した。コントローラーおよび MobileHeaderProps から不要になった onBackClick / handleBackClick および useRouter を削除。

  • feat(sidebar): サイドバーの表示切替と並び替えを文字で表示 (#2648): 表示切替をアイコンからセレクト(リポジトリ/ブランチ)へ、並び順を文字トリガーへ、並び替えの向きを矢印から文字(新しい順/A→Z/要対応が先など)へ変更し、2列のグリッド(sidebar-list-controls)に配置した。

  • feat(ui): PCブランチ画面ヘッダーからホームボタンと区切り線を削除する (#2647): Home 画面の廃止(#2658)に伴い、PC のブランチ画面ヘッダー(DesktopHeader)左端にあった「ホーム」ボタンと区切り線を削除し、状態ドットから始まるように変更した。

  • feat(ui): /(Home)のダッシュボードを廃止し、最後に開いたブランチへ移動するようにした (#2643): / はダッシュボード(概要見出し・セッション概要・最近のセッション・ToDo・クイックアクション)を描かず、共有キャッシュ(useWorktreesCacheContext)の読込完了後に router.replace で行き先を決める。移動先は localStorage['commandmate.lastOpenedWorktreeId'](ブランチ画面を開いたときに端末ごとに記録。サーバーには送らない)が非表示リポジトリを除いた一覧にあればそのブランチ、無ければ /sessions。ポーリングで一覧が更新されても移動は 1 回だけ。初回読込中はスピナー、取得失敗で一覧が空ならエラーと再試行ボタン、取得に成功して一覧が空なら初回ガイド(OnboardingChecklist)・「ブランチがありません」・「リポジトリを追加」リンクを出して移動しない(空状態の判定は repositories ではなく一覧で行う。repositories は getRepositories による worktrees の集計なので「未登録」と「登録済み・worktree 0 件」を区別できない)。あわせて useWorktreesCache の成功時の setIsLoading(false) を一覧と同じ startTransition に入れ、「isLoading=false かつ一覧が空」のコミットが挟まって / がリポジトリ 0 件の画面を一瞬出すのをなくし(失敗時は catch で即時)、失敗後に一覧が空のまま再取得している間は isLoading を true に戻す。ログイン後の移動先・PWA の start_url・ヘッダーのロゴはいずれも / のままで、この振り分けで行き先が決まる。Home 専用の HomeHeading / HomeQuickActions / HomeSessionSummary / RecentSessionsList / SessionOverviewTile / TodoWidget と、それらだけが使っていた home.json のキー(title / running / waiting / sessionOverview.* / sessionSummary.* / recentSessions.* / todo.*)を削除した。

  • feat(ui): ナビから「ホーム」「チャット」を外し、/more を「設定」に改名。スマホ下部ナビに「ブランチ」ボタンを追加 (#2642): Home 画面と Assistant Chat の廃止(#2658)に向けて、PC 上部ナビ(Header.tsx)を「セッション / リポジトリ / レビュー・レポート / 設定」の 4 項目に、スマホ下部ナビ(GlobalMobileNav.tsx)を「ブランチ / セッション / レビュー / 設定 / 検索」の 5 枠に変更し、コマンドパレットのナビ候補から home / chat を削除した(保存済みの Recent に残っていても NAV_ITEMS.find が外すため表示されない)。ロゴは / へのリンクのまま。スマホではブランチ画面(/worktrees/*)以外にブランチ一覧を開く手段が無かったため、下部ナビの左端に mobile-nav-open-sidebar(ラベル common.sidebar.branches)を置き、useOptionalSidebarContext() でドロワーを開く(Provider が無いときはボタンのみ非表示。ドロワーとバーは同じ fixed z-50 でバーが後勝ちするため、ドロワーが開いている間はバーを描画せず、言語・テーマ・ログアウトの行を隠さない)。辞書は nav.home を削除し nav.more を「設定」/"Settings" に変更、nav.more を借りていたリポジトリタブ帯の「…」ボタンには repoTabBar.overflow(ほかのリポジトリ / More repositories)を新設した。nav.chat キーと /chat 本体は #2649 で削除する。

  • feat(release): CHANGELOG のエントリを changelog.d/ へ移行し、/orchestrate と /release の手順を切り替える (#2641): 並列の PR が CHANGELOG.md の ## [Unreleased] で衝突していた(2026-09-17〜18 の run で計 7 回、手で解消)ため、## [Unreleased] にあった 16 エントリを文面を変えずに changelog.d/<N>.md へ移し、## [Unreleased] に空行以外の行があると落ちるガード(陰性対照つき)を tests/unit/scripts/changelog-fragments.test.ts に追加した。/orchestrate は、ワーカーに changelog.d/<N>.md を実装と同じコミットに含めさせ、マージ前の書き写しとエントリ数の diff(6-4)を「PR ブランチで node scripts/changelog-fragments.mjs check が exit 0 で、changelog.d/<N>.md がコミットに含まれていること」の確認に置き換えた(module-reference の断片は従来どおりオーケストレーターが一本化する)。/release(SKILL.md・templates/changelog-entry.md・docs/release-guide.md・英語版)は、check / preview で内容を確かめてから apply --version <X.Y.Z> --date <JST の日付> で節を生成し、見出しの直後に > **Highlight**: を書き足す手順に変え、apply が消した断片を git add changelog.d でリリースのコミットに含める。

  • ci: Unit Testsジョブを4本に分割してCIを短縮 (#2638): ci-pr.yml の Unit Tests ジョブを 4 本の matrix shards (1/4〜4/4) に分割して並列実行し、集約ジョブ test-unit-result (ubuntu-latest) で結果を束ねることで CI 実行時間を短縮。cancel-pr-runs-on-close.yml のジョブ数コメントおよび orchestrate.md の並列オーケストレーション記述を更新。

  • feat(ui): ファイルツリーのアイコンを2枚重ねにする (#2616): PC の Activity Bar(スマホ横向き・タブレットも同じコンポーネント)で、ファイルツリーのアイコン(lucide File)がメモ(StickyNote)と 20px で見分けられなかったため、ファイルが2枚重なった lucide Files に変更。スマホ縦向きの下部タブの Files も Folder から Files に揃えた。これまで Files を使っていたターミナル上部の「Open Files」トグルは、ファイルツリーと同じアイコンにならないよう PanelRight に変更。ラベル・Tooltip・件数バッジ・aria 属性・キーボード操作・Activity の並び順は変更なし。Activity Bar の10項目でアイコンが重複しないこと、各ボタンが描く svg(lucide-files / lucide-sticky-note / lucide-panel-right)をテストで固定した。

Removed

  • refactor(todo): Home ToDo(リポジトリ単位)の API・DB モジュール・API クライアントを削除 (#2650): #2643 で画面から外れて呼び出し元が無くなったため、/api/todos・/api/repositories/[id]/todos/** と todo-db.ts・todoApi・MAX_TODOS_PER_REPOSITORY を削除した。ブランチ ToDo(TodoPane / worktree_todos)と repository_todos テーブル・マイグレーション v34 は変更なし。

  • feat(ui): Assistant Chat(/chat)の画面側を削除 (#2649): ページ(src/app/chat/)・部品(AssistantChatPanel / AssistantMessageInput / AssistantMessageList)・API クライアント(src/lib/api/assistant-api.ts)・クライアント専用の型(src/types/assistant.ts)と、home.assistant.*・common.nav.chat(ja / en)を削除した。/chat は Next の既定どおり 404 になる(リダイレクトは足さない)。History の会話カードが使う .assistant-md の CSS 規則は残し、.chat-md のコメントだけ現状に合わせた。サーバー側(/api/assistant/**、src/lib/assistant/**、poller、DB モジュール)は #2655 で削除する。

Fixed

  • fix(ui): スマホで下部ナビとセーフエリアが重なってページ下端が隠れる問題を修正 (#2695): スマホで <main> が下部ナビのために空けていた余白(pb-14 = 56px)がホームインジケータなどのセーフエリア(env(safe-area-inset-bottom))を勘定に入れておらず、inset が非ゼロの端末(iOS 等)でページ内容の下端がナビに隠れる不具合を解消。ユーティリティクラス .pb-nav-safe(padding-bottom: calc(3.5rem + env(safe-area-inset-bottom, 0px)))を src/app/globals.css に新設し、AppShell のモバイル <main> のパディングを pb-14 から置き換えた。

  • fix(ui): 画面遷移中のスピナーがメイン領域の上端に寄る問題を修正 (#2692): ルート共通のローディング表示(RouteLoading)の flex-1 を h-full に変更。親の <main data-view-transition="content"> が display: block であり flex-1 が不活性だったためメイン領域の上端 192px(min-h-[12rem])に寄って表示されていた問題を解消し、メイン領域全体の中央に配置されるよう修正。

  • fix(ui): 画面遷移中のスピナーを画面全体からメイン領域だけに収める (#2683): ルート共通のローディング表示(RouteLoading)の min-h-screen を flex-1 min-h-[12rem] に変更。シェルが root layout に引き上げられたことでローディングがシェルの内側(<main>)に描画されるようになり、全画面高さを保持したままではレイアウトが跳ねる問題を解消。シェルの外で使われるルートでも高さが auto の親で潰れないよう絶対値の下限(min-h-[12rem])を設け、ビューポート基準および百分率に依存しない構成にした。

  • fix(ui): 画面を移ってもサイドバーとヘッダーが作り直されないようにした (#2682): サイドバーのナビ(リポジトリ/セッション/レビュー)や歯車の設定を押すと画面全体が作り直され、フルリロードのように見えていた問題を修正。リンクの実装は正しく、原因はシェル(Sidebar / Header / main)を 9 つの page.tsx が各自で描いていたこと——page は layout より下にあるため、ルートが変わるたびにシェルごと作り直され、サイドバーのスクロール位置・ホバー中の並び固定・シェルのローカル state が失われていた。新しい src/components/layout/AppShellGate.tsx を root layout(src/app/layout.tsx の AppProviders の内側)に置き、9 つの page から <AppShell> を外した。これでシェルは一度だけ mount され、遷移で入れ替わるのは <main> の中身だけになる。/login・/offline・/proxy・/worktrees/<id>/terminal・/worktrees/<id>/files/... は従来どおりシェルなしで、判定は純関数 shouldRenderShell(pathname) が持つ(前方一致はセグメント境界で見るため /loginx はシェルあり)。ファイルの移動・URL・AppShell の中身と props・useLayoutConfig の判定・各 page の中身の JSX は変更なし。シェルが root layout の内側に入るのに合わせて src/app/error.tsx の min-h-screen を min-h-full にした(高さの二重取り対策)。シェル自身が投げた例外は、これまでの page 側 error boundary ではなく root の error.tsx が拾うようになる。

  • fix(ui): 検索欄の狭い幅での折り返しを修正 (#2635): ファイルツリーのパネル幅が狭いときにパネル上部の検索欄(SearchBar)で文字やボタンが折り返されて崩れる問題を修正。モード切り替え行に flex-wrap、ラベルに whitespace-nowrap、モードボタン(mode-name/mode-content)に whitespace-nowrap flex-shrink-0 を追加し、検索語が空かつ非検索時は読み込み/クリアボタン枠(w-6)を描画しないようにして入力欄の幅を確保。

  • fix(ui): ファイルツリーの最小幅で名前が消える問題を修正 (#2634): ファイルツリーのパネルを最小(10%、ツリー幅約117px)まで狭めて深い階層を展開したとき、インデントと非伸縮要素(60px)の合計がツリー幅を超えてファイル名・ディレクトリ名の表示幅が0pxになる問題を修正。インデントの指定をインラインのpaddingLeftからCSS変数--tree-indentに変え、行のクラスでpl-[min(var(--tree-indent),max(0.5rem,calc(100%_-_7rem)))]を適用することで、インデントの上限をツリー幅から7rem(縮まない要素60px+名前の最低幅52px)を引いた値に制限した。

  • fix(ui): ファイルツリーのツールバーの文字折り返しを修正 (#2631): PC レイアウトのファイルツリー(既定の幅 18% で約 210px、スマホ横向きで約 100px)で、ツールバーの「新規ファイル」「新規ディレクトリ」が 1 文字ずつ折り返され、アイコンも点のように潰れていた。ボタンに whitespace-nowrap / flex-shrink-0 が無く、右端のボタン群と幅を取り合っていたのが原因。ツリー(file-tree-view)をコンテナクエリの基準(@container)にし、ボタン・アイコン・Tooltip のラッパーを縮まないようにした。ラベルはツリーの幅が 360px 以上(ja でラベル 2 つと右端のボタン群が 1 行に収まる幅。FILE_TREE_TOOLBAR_LABEL_MIN_CONTAINER_PX)のときだけ表示し、それより狭いとアイコンだけになる。アイコンだけのときも aria-label と Tooltip(ホバー・キーボードフォーカス)でボタンの意味が分かる。ツールバーと右端のボタン群は flex-wrap にし、収まらないときは縮めずに次の行へ送る。ファイル行は、名前が 1 文字まで切れていた(README.md の横に 81 B)問題も直した。各行をコンテナクエリの基準にし、インデント後に行に残る幅でメタデータ列を出し分ける(サイズ列は 176px 以上、作成日時・更新日時は 296px 以上、両方表示するときの更新日時は 416px 以上)。列が出ている間は名前に最小幅 4rem を持たせ、列の方を truncate で縮める。値はホバーの Tooltip で確認できる。シェブロンとファイル/フォルダのアイコンも縮まないようにした。ラベルの文言、ボタンの並び、data-testid は変えていない。

  • fix(session): 作業中の copilot へ --model 付きで送ると、直後の wait が前のターンの終了で完了し、前のターンの返答が履歴に残らない問題を修正 (#2630): #2623 で /model の前に copilot が待機状態になるまで待つ(最大 30 秒)ようになったため、その間に前のターンが終わると 2 つの不具合が起きていた。(1) 履歴のユーザー行の時刻が送信要求を受けた時刻のままで、前のターンの Stop より古くなり、wait --instance copilot がその Stop を見て、本文が copilot に届く前に Completed (basis=hook_stop) を返していた。(2) copilot の返答を履歴に書くのはレスポンスポーラーだけ(savePendingAssistantResponse は代替画面のツールでは何もしない)なのに、前のターンを見ているポーラーが終わった画面を読む前に本文が入力され、前のターンの返答が保存されなかった。sendUserMessage の順序を「/model → 前のターンのポーラーが返答を記録して止まるのを待つ(最大 5 秒)→ ユーザー行の時刻を決める → savePendingAssistantResponse → 同文再送の検出 → 本文を入力」に変更した。--model なしの送信と、待機中の copilot への --model 付き送信の挙動は変わらない。単体テストは UAT の時刻を偽の時計で再現し、書いた行を実際の wait のループ(pollWorktree)で判定する

  • fix(cli-tools): copilot を --model 付きで起動すると依頼本文が実行されない問題を修正 (#2623): commandmate send <wt> "<本文>" --agent copilot --model <モデル> で copilot 1.0.85 を起動すると、/model の後に送った本文が実行されず、wait --instance copilot は #1975 の 60 秒保留の後に basis=scraper_ready で完了していた。原因は、copilot が起動直後にフック・スキル・MCP サーバを読み込んでいる間(入力欄の下の行が ● Loading: … の間。約 3〜4.5 秒)も入力欄を表示していたこと。sendModelCommand は入力欄の有無だけで切替完了と判断して 22ms で戻っていた。読み込み中に送った /model は読み込みが終わってから実行されるが、その後ろに送った本文は入力欄に残るか消え、UserPromptSubmit / Stop フックも発火しなかった。修正後の sendModelCommand は、ステータスバーが待機表示(/ commands · ? help)になってから /model を送り、copilot の応答行(● Model changed from … to <id> / ● Switched model to: <id>)が新しく出るまで待つ。✗ Model "<id>" is unsupported. / is unavailable. が出た場合や 30 秒以内に応答が無い場合は、本文を送らずに copilot の文言を含めて送信失敗(stage: 'model')として返す。実行中のターンに /model を送ると応答行を出さずに切り替わるため、ターンが終わるまで待ってから送る。--model なしの送信も、読み込み中は読み込みが終わるまで待つ(実行中のターンへの送信は従来どおりすぐ送る)。Issue で疑っていた MCP Servers reloaded は起動ごとに 1 回出る表示で、/model とは関係なかった。1.0.85 の実画面 19 枚を tests/fixtures/copilot-model-switch-2623.ts に追加した。

  • fix(test): agent-launch-plan-secrets-1933.test.ts の HOME 漏れを止める (#2622): planFor() が全 CLI の prepareLaunch() を呼ぶ際に HOME や worktreePath が隔離されておらず、agy の ~/.gemini/config/hooks.json や claude の ~/.commandmate/hooks/claude-wt-1933-*.json が実環境に書き込まれ /tmp/cm-1933-worktree にゴミが残っていた問題を、private HOME / CODEX_HOME の stub 化と一時 worktreePath の利用、afterEach でのディレクトリ削除、および afterAll での実環境 mtime / エントリ不変ガードを追加して解消。

  • fix(cli): エージェントの自己再開でターンが閉じても wait が完了と読まないようにする (#2614): Antigravity が schedule のタイマーやバックグラウンドのコマンドを残したままターンを閉じたとき、wait(--verify と ask を含む)がその Stop を完了と読んでいた問題を修正。agy の Stop hook が payload の fullyIdle: false(agy 自身の「バックグラウンドタスクが残っている」宣言)を --detail self_resume_pending として relay に渡すようになり、新しい宣言 stopReportsSelfResume(antigravity のみ true)を持つソースでは、wait がその Stop を保留し、エージェントが自分で起き直してから閉じた最後の Stop で完了する。完了行は basis=hook_stop のまま、保留したときだけ heldForSelfResume=<秒> を付ける。起き直さない場合は Stop から 30 分で注記つきで完了し、--timeout / --stall-timeout はそれより短ければ優先される。

  • fix(detection): Codex の Browser use 承認画面で状態表示と送信判定が食い違う問題を修正 (#2609): フッタが enter to submit | esc to cancel の Codex ツール呼び出し承認フォーム(Field 1/1 / 1. Allow / 2. Always allow / 3. Cancel)を、状態 API は waiting / prompt_detected と表示する一方、detectCodexDialog の入口ゲートが press enter to confirm/select しか認めず null を返していたため、respond が prompt_no_longer_active(exit 99)で拒否され、Auto-Yes も unclassified-frame で抑止されていた。実測したフッタ行そのものだけに一致する CODEX_FORM_SUBMIT_FOOTER_PATTERN(行全体アンカー)を追加して detectCodexDialog の入口ゲートで OR 判定し、CODEX_SELECTION_LIST_PATTERN(detect.ts の選択リスト分岐でも使う)は広げていない。esc to cancel だけ・文中への引用・回答済みブロックの scrollback は引き続き null。

  • docs(orchestrate): Phase 2.5 の copilot 指定と wait/capture の送り先表記を修正 (#2608): .claude/commands/orchestrate.md の Phase 2.5(バグ根本原因分析)で copilot 1.0.85 が受け付けない claude-opus-4.6 が指定されていた記述を claude-sonnet-5 に更新し、send 直後に capture で画面のモデル表記を確認する手順を追加。あわせて wait での --instance copilot 抜けおよび capture での --agent 表記を --instance copilot に統一。

  • fix(api): current-output の thinkingMessage をエージェント名固定から直す (#2607): GET /api/worktrees/:id/current-output(commandmate capture --json)の thinkingMessage が文言固定だったため、Antigravity などどのエージェントのセッションでも "Claude is thinking..." を返していた(2026-09-17 に antigravity セッションで実測)。buildCurrentOutput が既存の getCliToolDisplayName(cliToolId) で表示名を引いて "<表示名> is thinking..."(例: "Antigravity is thinking..." / "OpenCode is thinking...")を返すように修正。claude では従来どおり "Claude is thinking..."、thinking が false のときも従来どおり null。リポジトリ内にこの文字列を照合している呼び出し元は無く(型定義とドキュメントの claude の出力例のみ)、UI 表示にも影響しない。

  • fix(skills): orchestrate-monitor の画面判定を Antigravity のペインでも効かせる (#2606): classify-state.sh が capture の cliToolId で目印を選び、Antigravity では monitor-lib.sh に追加した agy 用判定(生成中 = ステータス行の esc to cancel・点字スピナー、プロンプト = ↑/↓ Navigate フッター+番号つき選択肢、待機中 = 入力欄の枠)を使うよう変更。↑/↓ Navigate のある画面では esc to cancel を生成中と読まない。上端寄せの agy ペインでは realtimeSnippet が空行ばかりになるため、realtimeSnippet と content の長い方から空行を除いた末尾を読む。Claude / Codex の判定は変更なし。

  • fix(test): db-migration-path のテストが、本番 DB の完全なコピーを HOME に残さないようにした (#2605): tests/unit/db-migration-path.test.ts の 2 本は cwd と HOME を隔離せずに migrateDbIfNeeded を呼んでいた。そのため本番 DB(data/db.sqlite)がある作業ディレクトリ(/release が unit を回す main など)で実行するたびに、次の 2 つが起きていた。(1) 本番 DB がレガシー DB と誤認されて ~/.commandmate-test-<ms>/data/cm.db へ丸ごとコピーされる、(2) data/db.sqlite.bak が上書きされる。テストを追加した 2026-02-03 から、残骸は 1,568 個・185 GiB に達していた(既存分は手動で削除済み)。修正では、2 本を「レガシー DB が見つからない」状態(空の一時ディレクトリへの process.cwd() の spy、HOME の stub、DATABASE_PATH を空にする)で呼び、migrated === false であること、ディレクトリ作成もコピーも起きないことを assert する。あわせて、隔離した変数を関数が実際に読んでいることを示す陽性対照を tests/unit/db-migration-path-isolation.test.ts に追加した(isSystemDirectory を sandbox の配下だけ部分 mock する。os.tmpdir() はシステムディレクトリとして拒否されるため)。両ファイルには、実際の HOME 直下の .commandmate-test-* が増えていないことを確かめるガードも入れた。src/ の変更はない。

  • fix(test): Catalog から install した Skill を sync-map の分類対象から外す (#2595): .claude/skills および .agents/skills 内の .commandmate-receipt.json を持つディレクトリを未分類ガードから除外し、receipt 保持ディレクトリが sync-map.json に宣言されている場合は別エラーとして検出。