Skip to content

v0.49.0

Latest

Choose a tag to compare

@Kewton Kewton released this 27 Oct 03:05
808668c

[0.49.0] - 2026-10-27

Highlight: Auto-Yes の有効時間を 1〜24 時間から選べるようになり、チャットのコードブロックにコピーボタンが付きました。codex まわりでは、入力欄に残った貼り付けの印([Pasted Content N chars])を消せず送信を断り続ける問題と、容量超過(Selected model is at capacity)を検出できず 40 分待つ問題を直しました。並列の検証が mutex 待ちで裁定不能(exit 99)になった回は、自動で並び直すようになりました。

Added

  • feat(auto-yes): Auto-Yes の有効時間を 1〜24 時間から選べるようにする(1h / 3h / 8h はプリセットとして残す) (#3913): 有効時間を 1〜24 時間の整数時間に広げた。定義は依存の無い新モジュール src/config/auto-yes-duration.ts にまとめ(全部の候補 AUTO_YES_DURATIONS=24 値の literal union の型 AutoYesDuration、プリセット PRESET_AUTO_YES_DURATIONS=1h / 3h / 8h、CLI の書式 ^(?:[1-9]|1[0-9]|2[0-4])h$)、auto-yes-config.ts と CLI の duration-constants.ts は再 export する(CLI の 1h|3h|8h の写しと旧名 ALLOWED_DURATIONS / DURATION_MAP / DURATION_LABELS は廃止)。API POST /api/worktrees/:id/auto-yes は有効化のときだけ 1〜24 時間(3600000 の倍数)を受け付け、範囲外・端数・型違いは 400 で状態も poller も変えない(省略時 1h、無効化は duration を見ないのは従来どおり)。setAutoYesEnabled も有効化時に検査し、不正な値は RangeError で状態を書き換えない。CLI の auto-yes --enable --duration と send --duration は 1h〜24h(0h・25h・1.5h・90m・01h・+1h・1H などは従来どおり exit 2)、scripts/orchestrate/launch-worker.mjs も同じ書式。確認ダイアログは 1h / 3h / 8h のボタンに「その他」(1〜24 時間の select)を足し、開くたびに 1h に戻す(ダイアログは常にマウントされていて前回の選択が次の初期値になっていた)。タスク作成ダイアログの select も 1〜24 時間。表示名は ICU(ja {hours}時間、en {hours, plural, one {# hour} other {# hours}})。長くすると慎重のモードでも自動で答える許可の確認が増える旨の注記を追加。期限切れ・停止条件・再起動での解除・答え方のモードの安全装置は変えていない。

  • feat(chat): チャットのコードブロックにコピーボタンを付ける (#3912): ChatMarkdownBody を通る画面(保存済み・実行中・確定待ちの吹き出し。PC の分割・スマホ・Sessions のタイルも ChatSurface 経由で同じ)で、回答・思考・ツールログの各コードブロックに、ファイルのプレビューと同じ CodeBlockWithCopy のコピーボタンを付けた。押すとそのブロックの文字列だけ(色付けの span を除いたもの)をコピーし、空・空白だけのブロックにはボタンを出さない。components の pre は 1 つにまとめ、renderDiagrams && isMermaidPreChild(children) のときだけ図の枠を素通しにする(MERMAID_MARKDOWN_COMPONENTS からは code だけを使うので、mermaid の pre が新しい pre を上書きしない。renderDiagrams=false の mermaid の fence はコードとしてボタンが付く)。インラインコード・ユーザー本文・端末の平文・History(ConversationPairCard)には付けない。共通の部品も直した(ファイルのプレビュー・ファイルのページ・TodoPane にも効く): CopyButton に data-search-skip と select-none を付け、検索の強調の対応づけと範囲選択の Cmd/Ctrl+C に Copy / Copied が混ざらないようにした(コードを包む要素には付けない)。@media (hover: none) の端末では幅にかかわらずボタンを常に表示し(.code-copy-button)、<pre> の右に余白を取って 1 行のコードにボタンが重ならないようにした(.code-block-with-copy > pre。ボタンは <pre> の外なので横スクロールでも動かない)。チャットの最初・最後のコードブロックの上下の余白は従来どおり 0。

  • feat(verification): 検証の待ちと実行を人向けの表示と run の記録にも出す (#3909): #3884 でゲートの log_tail 末尾に入った [timing] queue= mutex= run= を、commandmate verify / wait --verify の GATE 行(GATE unit PASS (exit=0, 600.0s, queue=30.0s, mutex=120.0s, run=600.0s)。waited= の代わりに出す)と verify history の人向けの行(行末の timing: unit(queue=… mutex=… run=…))に出す。行の無いゲート(何も待たなかったもの・#3884 より前のサーバの run)と mutex 待ちの SKIP は今までの表示のまま。/orchestrate の wait-verify.mjs は最後の verify の GATE 行を合計して verify の記録の queueSec / mutexSec / runSec に渡し、run-log.mjs status --json の stages.verify で読める(どのゲートも出さなかった run には書かない)。あわせて、run の最初の実行枠の待ちも取り消せるようにした: 2 枠が長いゲートを実行している間に取り消した run は、そのどちらかが終わるまで running のまま取消し API が requested(202)を返していたが、すぐ cancelled で閉じる(ゲートの行は作らない。空いた枠は次に待つ run へ渡る)。standalone の cmate-verify の verify-run.sh は commandmate-skills と byte-identical の pin があるため waited= の形式のままとし、理由と揃え方を docs/design/verification-config.md §9.3.1 に書いた(§9.2.1 のロックを取る場所も precheck の追加後に合わせて直した)。

Changed

  • refactor(prompt-response): 手動回答の送信エラーを分類する manualOutcomeOfSendError を 1 か所にまとめた (#3926): /respond にあった写しを消し、prompt-response/answer-delivery.ts から export した関数を 2 つの route が import する。判定(既知の拒否 → not-sent、keysSent / answerDelivery の優先順位、null を返す場合)は変えていない。

  • refactor(detection): Claude の画面の枠(タスクパネル・セッション差分 HUD・プレビュー枠)を読む処理を prompt-detect-multiple-choice-chrome.ts へ分割 (#3924): findClaudeTaskPanelLines / findClaudeChrome / maskClaudeChrome / ClaudeChrome と CLAUDE_TASK_PANEL_*・CLAUDE_SESSION_DIFF_HUD_PATTERN、それらが使う SUMMARY_LINE_PATTERN をコメントごと挙動不変で新モジュールへ移し、元の prompt-detect-multiple-choice.ts は移した公開名を再 export する(公開 API・import 元は不変、新モジュールは元を import しない)。元のファイルは 1,561 行 → 1,350 行(1,500 行の閾値と前回の 1,442 行を下回る)。新モジュールの単体テスト prompt-detect-multiple-choice-chrome.test.ts を追加。

  • feat(orchestrate): precheck の保留(exit 3)を案内し、merge-pr で不合格と分ける (#3908): orchestrate.md の precheck / merge-pr の exit 表に 3(保留。再実行・再指示しない)を追加。merge-pr は取り込み後の precheck が exit 3 のとき did not pass ではなく「保留」と表示し exit 3 で返す(不合格は従来どおり exit 1)。switching.md の担当切替・格上げ後の待機は wait-verify.mjs を通す形に変更し、設計書の修正指示(4-3)と根本原因分析の依頼は launch-worker.mjs を通さない理由を明記。3-3 に合格行の HEAD 確認を 1 行追加。

  • refactor(session): waiting-episode-state.ts を型・状態表・episode の書き込みに分割(682 行 → 203 行) (#3865): 型とインターフェースを waiting-episode-state-types.ts、globalThis の状態表・listener の登録と通知・読み取り・テスト seam を waiting-episode-state-store.ts、open / close / replace / rebind / updateKind を waiting-episode-state-ops.ts へ移し、waiting-episode-state.ts は declare global・observeWaitingEdge・binding resolver の登録を持ち、これまでの export をすべて再 export する入口にした。import 元は変更なし、振る舞いの変更なし。

Fixed

  • fix(orchestrate): wait-verify.mjs が mutex 待ちだけの exit 99 を受けたら検証を自動で並び直す (#3938): 並列の検証で cpu.heavy が timeoutSec(5400 秒)の間ずっと埋まり、ゲートが reason=mutex-wait の SKIP になって裁定不能(exit 99)になった回を、人が --after-reinstruct で直列に回し直していた(2026-10-25〜26 の run で verify 23 回中 6 回)。verify show <run> --json のゲートの logTail の 1 行目で、SKIP がすべて reason=mutex-wait かつ FAIL・TIMEOUT・ほかの SKIP が無い run だけを --mutex-retries <n>(既定 2)回まで始め直す。通常の検証・--after-reinstruct・3-3 の確認が始める再検証の 3 経路で同じ。始め直す前に新しい task(exit 3)と HEAD(動いたら mutex-requeue-stopped=head-moved で 99 のまま)を確かめ直し、環境の manifest を取り直す。各試行のログは wait-<N>.verify.try<k>.log に残り、記録の要約に mutex-requeue=<n> mutex-runs=<id,…> mutexSec-total=<秒>、記録の queueSec/mutexSec/runSec は全試行の合計になる。run が読めない・理由が読めない・run が cancelled など passed/failed/error 以外で終わったときは今までどおり exit 99。裁定に至らなかった検証(3-3 の確認が始める再検証の 99 も)は Auto-Yes を切らない。製品の commandmate verify と .commandmate/verify.yaml は変えていない。

  • fix(cli-tools): codex の入力欄に残った貼り付けの印 [Pasted Content N chars] を消せず、送信前のクリアが送信を断り続ける問題を修正 (#3937): clearComposer は毎回 C-e+C-u だけを送っており、codex 0.164.0 で印が 12 回とも残って cleared=false になっていた(2026-10-25 実機。手で BSpace を 1 回送ると消えた)。codex の入力欄が 印 1 つだけ(前後に手入力なし) のときに限り、その 1 回を新設の clearComposerPasteToken(C-e+BSpace)にする。印+手入力・印 2 つ・本文が印の文字列を引用する場合は従来の C-e+C-u のままで、送るたびに読み直して判定する作りも変えない(claude と印のない codex は送るキー不変)。遅れて描かれて入力欄に残った印も、次の送信の前のクリアと未送信バーの Clear がこの 1 回で消せるようになる(送信中に遅れて届く印を待って取り下げる仕組みは、同じ instance への送信の直列化が要るため別 Issue)。実機の codex 0.164.0 で BSpace が印を丸ごと消すことと、印+手入力での動きは未確認。

  • fix(detection): codex の「Selected model is at capacity」を上流障害として検出し、整合性レビューが 40 分待たないようにする (#3936): UPSTREAM_FAULTS に codex の容量超過の規則 model-capacity(selfRetrying: false)を追加。錨は codex 自身のエラー行の形(列 0 の ■ Selected model is at capacity)で、返答の本文が文言を引用しただけの行(• /字下げ)・入力のエコー(› )・claude の 529 行の The API is at capacity には当たらない。これで codex でも ask / wait --fail-on-upstream-fault が exit 11、capture --json が upstreamFault、失敗の push 通知が働く(以前は規則が無く、入力欄に戻った後もターン終了の報告待ちのまま ask --timeout 2400 まで待って 124 になっていた)。push の判定(response-checker)は生の末尾 100 行ではなく capture の realtimeSnippet と同じ切り出し(buildRealtimeSnippet)を使うようにし、inline の codex の画面で capture には出るのに通知が鳴らない食い違いを解消。scripts/orchestrate/consistency-review.mjs は ask の exit 11 を他の失敗と分け、run の記録の note に upstream fault id=<id> を載せる(model-capacity は switch --instance、ほかは id に応じて。別 instance への自動切り替えはしない)。また、最初の capture --json が isRunning: false/session_not_running で startingSince の無い instance には、作業を頼まない短い起動の文を send で 1 回だけ送ってから ready を待つ(起動後の上限は 30 回。起動の send が失敗したら依頼を送らず review=fail。起動中の instance には送らず待つ)。以前は止まっている instance が ready にならず 180 回・30 分待って not ready で止まっていた。上流障害の id の説明(CLI の型・サーバーの型・CLI 操作ガイド ja/en)に context-limit と model-capacity を追加。capacity の画面は実機で採れておらず、fixture は summary の引用から作った合成(tests/fixtures/upstream-faults/README.md)。

  • fix(demo-video): env-up.sh の背景起動で bash の child setpgid … Operation not permitted が stderr に出る問題を修正 (#3935): set -m のジョブ制御下では bash が親と子の両方で setpgid(子, 子) を呼び、親が先に成功すると子の側が EPERM になって、子がサブシェルのリダイレクトより前に継承した stderr へ 1 行書いていた(macOS の負荷下で約 0.3〜0.7%。PGID は親の呼び出しで正しく、実害はメッセージだけ)。これが env-up-listener-owner.test.ts / env-scripts.test.ts の expect(result.stderr).toBe('') を検証の重い負荷の中でだけときどき落としていた。set -m 〜 set +m を { … } 2>>"$LOG_FILE" で囲んでその間の bash の出力をサーバーログへ送り、サブシェルは事前に切り詰めたログへ追記(>>)するのでその行は診断用にログに残る。サーバーの PGID=PID・SERVER_PGID の読み直し・pid_is_ours・cleanup_failed_boot・env-down.sh は不変。.claude/ と .agents/ の両方に適用。負荷下の再現(tests/scripts/demo-video-bg-setpgid-load.sh、8 並列×1,500 回)は旧形 41 回・新形 0 回。

  • fix(verification): wait-verify の note のゲート一覧を保存済みの run から作り、取消し API の JSDoc を直す (#3928): summarizeVerdict がログ全体の GATE 行を拾うため、落ちたゲートの本文に GATE 行があると同じゲートが passed=unit,unit と二重に数えられていた。note は timing と同じ保存済みの run(verify show --json)のゲートから作り、run が読めないときだけログ本文から読み、その場合も 1 つの id は 1 回に限る。verify/runs/[runId]/cancel/route.ts の JSDoc も、最初の枠を待つ run も取消しで待ちを抜ける実際の動き(#3909)に合わせた。

  • fix(terminal): ダイアログの下に隠れた codex の古い入力欄を未送信バーに出さない (#3927): codex の画面で、古い複数行の入力欄の下にダイアログ(承認など)の選択肢が出ているとき、PC とスマホの未送信バーが古い本文を出し続け、「消去」は効かず(クリアは #3906 から no_composer で何もしない)、「実行」の Enter はダイアログの選択肢を確定しうる状態だった。「下段にダイアログがあれば入力欄は無いものとする」規則(codexDialogBelow / findCodexLiveComposerRow)を src/lib/session/composer-clear.ts からブラウザーも読める src/lib/detection/composer-text.ts へ移し(logger を引く tools/codex/cli-patterns.ts の行の読み取りは同じモジュールの SGR 走査で書き直し、全 codex fixture の全行で移す前と同じ判定になることをテストで固定)、新しい extractLiveComposerText() に載せた。サーバーの公開値(current-output-builder の composerText / composerState、capture --json も同じ)、ブラウザーでの抽出(useTerminalPanePolling)、クリアの 3 つがこれを読むので、その画面では composerText: null / composerState: 'no_composer' になり未送信バーは出ない。extractComposerText() 自体の読み方、送信側(submit-verified-sender)の absent の判定、Auto-Yes の Enter フォールバックは変えていない。入力欄だけの codex 画面と codex 以外のツールの画面は従来どおり。

  • fix(respond): 構造化回答(decisionId 指定・id 無し)が Auto-Yes に手動回答を知らせない問題を修正 (#3925): POST /api/worktrees/[id]/respond の構造化の経路(PC・スマホの入力欄の PromptPanel が使う { decisionId, answer } と、commandmate respond が使う { answer })は、承認・質問の回答を agent の API で届ける前に noteManualAnswerStarted を呼んでいなかったため、進行中の Auto-Yes の tick が失効せず、送った直後の短い手動保持も掛からず、同じ確認画面に tick が重ねて答える余地があった。messageId の経路(#3907)と同じ順序で、所有範囲の確認・404・409・不正回答の拒否を先に済ませてから開始を通知し、送る直前の画面を取得して noteManualSendStarting で登録し、送信の結果を通知する。結果は source の受領で読み、届いた(delivered: true)は answered、届かなかった(delivered: false)は not-sent、受領が無いときは結果不明として abandonManualSend のみ、例外は manualOutcomeOfSendError で分類してから従来どおり 500 にする。拒否では開始通知を呼ばない。送る直前の画面は tmux の所有を確かめてから読み、別サーバーの同名セッション・所有を確認できないときは読まずに(#2885)「画面なし」で送信を登録する(API での配送と結果の通知は従来どおり)。/prompt-response の構造化段も同じ分類で結果を通知するので、同じ承認にどちらの URL で答えても、以前の結果不明の送信の保持が同じように解除・維持される(answerStructuredDecision の結果に source の受領そのもの receipt(受領なしは null)を足し、/prompt-response の構造化段はそれで分類する。従来の delivered は受領なしを false に畳むので、受領なしでも not-sent として以前の保持を解除していた。delivered と他の呼び出しの振る舞いは不変)。送る直前の画面の読み取り(screenAtSend)は route.ts から respond/screen-at-send.ts へ移し、両経路で共有する(構造化側が route.ts を import する循環を避けるため)。

  • fix(orchestrate): plan-check routes の検査抜けと precheck の重さ見積りの精度を修正 (#3910): plan-check routes が check と同じ違反で止まり(不正な plan は一覧を出さず exit 1)、状態名を NFKC・内部空白の畳み込み・大文字小文字無視で照合し、precheck は解析に失敗したファイルの参照を全部残し、型の位置の import('…').T・typeof import('…')・import type x = require() を実行時の辺から外す。

  • fix(cli): capture --prompts --json が確認画面の reading と承認対象の完全性を落とす問題と、respond の messageId 経路が手動回答の結果を Auto-Yes に伝えない問題を修正 (#3907): capture --prompts --json の各 prompt に、保存された行の approvalTargetCompleteness と reading(#3881)を wait と同じ値で出す(無い行では null。CLI の型 CapturePromptEntry を追加)。テキスト表示は変えない。POST /api/worktrees/:id/respond の { messageId, answer } 経路は、今の PC・スマホ・CLI からは呼ばれていないが既存テストが公開の形として固定しているため廃止せず、/prompt-response と同じく手動回答の ticket(#3821 / #3880)を通す: 最初のキーの前に noteManualAnswerStarted(進行中の tick を止め、しばらく画面を人に任せる)、送信は送る直前に取り直した画面(/prompt-response と同じ読み方 assessPromptAnswerability)で登録し、保存行の画面では固定しない(読めなければ識別できない画面として保持)。取り直した同じフレームを sendPromptAnswer の frame に渡し、数字の回答の検査が画面を読み直して登録と送り先がずれないようにする、送信の終わり方で settleManualAnswer(通った・キー前に拒否=保持を解放、キーが画面に残った可能性/結果不明=その確認画面を保持)。これまでは、この経路の送信が結果不明で終わると保持の期限後に Auto-Yes が同じ確認へ再び打鍵し、送信が通っても Auto-Yes 自身の結果不明の保持が残っていた。

  • fix(cli-tools): codex の入力欄が読み取り窓の外にあるときの到着確認と送信後の判定の食い違いを修正 (#3906): codex への送信の確認(#3880)は入力欄の本文を全量比較するが、入力欄を探す窓(末尾 12 行・末尾 4 ブロック)は土台のままだった。1 行の段落+空行+20 行の段落のように › 行が末尾 12 行の外に出ると、同じ画面を到着確認は unseen(本文があるのに引き戻して失敗)、送信後の判定は submitted と読んでいた。また段落が多く入力欄が末尾 4 ブロックに入らないと、marker reader の 1 行目の先頭一致だけで landed になりえた。extractComposerText が見つけた入力欄は窓の外でもそのまま読み、4 ブロックの外では最下段の本物の入力欄行から footer までを全量比較の対象として引き継ぐ。その行は findCodexBottomGlyphRow と同じく下から読み、承認ダイアログの選択肢(›)が先に出たら入力欄は無いとみなす(ダイアログの上に残った古い入力欄が本文の先頭と一致しても pending にせず、ダイアログへ Enter を再送しない)。この規則は extractComposerText が末尾 4 ブロックの中で複数行の入力欄を見つけた枝にも、クリア側にも同じく効く。ANSI の属性が無い › 行(ダイアログの選択肢と見分けられない)はこの探索で入力欄とみなさない。codex 0.153〜0.160 が履歴エコーを dim でなく太字だけで描く行(ESC[1m› ESC[0m、空白が太字の中)も入力欄とみなさない。窓の外の本物の入力欄(空行を挟まない 20 行の入力欄のように抽出器が複数行で読む枝も含む)が本文と一致しないときは、別の /… なら窓の中と同じく replaced、それ以外の文字なら新しい indeterminate(Enter を再送せず読み直し、解消しなければ submit could not be confirmed で失敗=送信状態は indeterminate)にして、成功扱いにしない。awaitTypedBody の短い本文(512 bytes 以下)は codex では入力欄の全量一致だけを到着とする(5 段落のうち第 1 段落だけ描画された画面で Enter を押さない)。clearComposer も codex で抽出器が入力欄を見つけないとき同じ規則で入力欄を探して読むので、送信側が pasting と読んで取り下げる多段落の本文を消し、消せなければ content のまま返して次の本文を入力しない。実機の codex は動かさず、静的な画面の対照と既存の codex fixture 全件の判定(修正前と同じ)で確かめた。