Repository navigation
v0.33.3
[0.33.3] - 2026-09-09
Highlight: チャット面が「終わったセッションの会話」を現行のものとして見せ続ける問題を、サーバ側とUI側の両方から塞ぎました。CommandMate の外でセッションが終わった場合(tmux 消滅・CLI が shell に落ちる・再起動)、これまで行を archive する経路は kill-session だけで、本番 DB では archived=0 の 327 行すべてが既に死んだセッションのものでした(#2444)。新しいエージェントプロセスが始まる時点で前セッションの行を退避し、UI 側では非稼働の間だけ旧行を「前回のセッション」に畳んで終了バナーを出します(#2445)。あわせて chat 表示にも History 列を並べられるようにして、過去の会話を読む導線を回復しました(#2446)。antigravity の中間ナレーションを「ターン終了」と誤判定して暫定本文のまま完了配送していた件も、保存と完了を分離して修正しています(#2443)。さらに socket 未指定の tmux 破壊コマンドを生成 deny 規則・静的ガード・env-clean の 3 層で塞ぎました — 2026-08-02 と 2026-09-08 の 2 度、既定サーバの全 mcbd-* セッションが消えた事故を受けた対応です(#2442)。
Added
- feat(hooks,verify): socket 未指定の tmux 破壊コマンドを機構で塞ぎ、env-clean を契約から選べるようにする (#2442): Claude セッションへ注入する
permissions.denyに socket 無指定のtmux kill-server/kill-session/set-option -g(aliasset -g)/bind-key(bind)/unbind-key(unbind)を追加(-L/-Sつきの隔離 probe は従来どおり通る。claude 2.1.266 で実測、記録はdocs/design/agent-hooks-permission-deny-verification.md§6)。静的ガードの走査対象をtests/からscripts//docs//.claude//.agents// ルートAGENTS.md・CLAUDE.mdの実行コードブロックまで広げ、判定を近傍 120 文字の窓から呼び出し単位へ変更。契約にsuccess.requireEnvCleanとverify.gates: [env-clean]を追加し(repository option と OR)、本リポジトリの.commandmate/verify.yamlでoptions.requireEnvClean: trueを有効化。 - feat(chat): セッションが終了している間、チャット面の前セッションの行を「前回のセッション」に折りたたみ終了バナーを出す (#2445):
attaching === false && isRunning === false(ChatSurface.isChatSessionEnded、PC/スマホ両方からterminal.attachingを配線)で観測された非稼働の間だけ、既に画面にあった保存済み行を既定閉の折りたたみ(前回のセッション(N 件)、開くとopacity-60)へ入れ、その下にterminal.sessionEnded(TerminalDisplayの #842 placeholder と同一キー)+履歴への案内を出す。分類は非稼働を最初に観測した時点の message ID スナップショットなので、死んだペインへ送った行はサーバ echo に置き換わっても折りたたみの外に残る。閉じている間は検索対象からも外れ、開くと戻る。あわせてarchived行はチャット面に描かなくなり(History 列と共有するincludeArchivedの fetch から表示側だけ除外)、非稼働中は生成中/保持中バブルを描かず、復帰しても前 turn の保持バブルを復活させない。TerminalDisplayのハードコード 2 文は ja/en に移した。サーバ側 archive(#2444)と PC chat の History 列(#2446)は別変更のため、単独導入では復帰後に旧行が通常表示へ戻る。 - feat(worktree): PC のチャット表示でも History 列を横に並べられるようにした (#2446): chat 面(#2193)は
ChatSurface単体で split の出力半分を占め、アクションバーの[履歴]は全 split が chat のとき無効化されていた(#2259)ため、チャット面から過去セッションの行を外す #2445 が入るとチャット表示には過去の会話を読む場所が無くなる。chatSurfaceSlotをターミナル面と同じ[History列 | PaneResizer | 出力]の骨格(chatSlot/共通化したhistoryColumnSlot)で包み、historyVisible/historyWidth/toggleHistory/handleHistoryResizeはuseHistoryPaneState(commandmate.worktree.historyVisible/historyWidth)をターミナル面と共有するので、モード切替で列が出たり消えたり幅が変わったりしない。列を閉じたときは出力側にwidth:100%を明示する(#2259 と同じ)。あわせてTerminalSplitContainerのhistoryUnavailable判定・terminal.historyChatOnlyHint(ja/en)と、その唯一の読み手だったsrc/hooks/useSplitSurfaceModes.ts(emitSurfaceModeChangeを含む)を削除し、[履歴]トグルは常に有効になった。History 列とChatTranscriptの検索ハイライトはhistory-search-<splitIndex>/chat-search-<splitIndex>と別名前空間なので同時表示でも衝突しない。
Fixed
- fix(session): CommandMate の外で終わったセッションの行が、次のプロセス開始時に archive されるようにした (#2444): tmux が消えた・CLI が
/exitで shell に落ちた・マシンが再起動した、のどれで終わってもchat_messages.archivedを書く経路がPOST /api/worktrees/:id/kill-sessionの 1 つしかなく、しかも生きたセッションが 1 つも無いと同 route は archive の手前で 404 を返すため、死んだセッションの行がarchived = 0のままチャット面に「現行の会話」として残り続けていた。beginAgentSession()(8 ツールの生成経路と codex / opencode の同一 pane 再起動経路が呼ぶ、opencode の live-reuse では呼ばれない seam)から新モジュールsrc/lib/session/session-generation-archive.tsを try/catch つきで呼び、当該(worktreeId, instanceId)の active 行だけをdeleteMessagesByInstanceで archive してrecomputeLastUserMessageでサイドバーを追従させ、messages_invalidated(reason: 'session_generation'、受信側は理由で分岐しない契約なので互換)を(worktreeId, cliToolId, instanceId)scope で配信する。死を観測した瞬間(isRunning=false)ではなく新プロセスを作る事実を境界にしたのは、has-session のタイムアウトや状態判定の揺れで一瞬falseになっただけの生きた会話を消さないため。schema は変えず(#168 が却下したsession_id方式は採らない)、archive 失敗はログのみでセッション起動は止めない。あわせて唯一beginAgentSessionを呼んでいなかったvibe-localの生成経路に同じ 1 行を追加した。既知の制約として、archive 後に転写リーダーが前セッションの行を新規 INSERT した場合はその 1 行が新セッション側に混ざる(既存行の UPDATE はarchivedを触らないため影響しない)。 - fix(history): antigravity の中間ナレーションを「ターン終了」と誤判定し、暫定本文のまま relay へ完了配送する問題を修正 (#2443): 保存(History への行)と完了(配送してよい)を分離し、agy 自身の
Stopが turn の最新レコード以降に届いたときだけ確定として扱う。暫定の行は保存・更新を続けつつ配送せず、暫定で書いた行は通常の直近 3 件の窓を外れても結論へ追随する。