Skip to content

v0.33.3

Choose a tag to compare

@Kewton Kewton released this 09 Sep 04:49
· 25 commits to main since this release
304b263

[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(alias set -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 件の窓を外れても結論へ追随する。