Skip to content

v0.45.1

Choose a tag to compare

@Kewton Kewton released this 10 Oct 13:34
· 8 commits to main since this release
a0eaa2e

[0.45.1] - 2026-10-10

Highlight: チャットと History の Markdown 表示で ```mermaid が図として描かれるようになり(ダークテーマ対応、#3503)、単独のファイル表示ページでも図になりました(#3522)。履歴検索の強調が Markdown の記法の文字数だけずれる問題を、原文の位置で当てる形に直し(#3523)、mermaid 図の照合も Markdown の構造で行うようにしました(#3525・#3544)。サーバログの 8 割を占めていた duplicate-response-skipped(1 日 51,933 行)と、同じ形の `duplicate-prompt-skipped` を「連続の最初と約 1 分に 1 回」に間引きました(#3519・#3538)。

Added

  • feat(orchestrate): 5-2b の整合性レビュー(Codex への依頼)を scripts/orchestrate/consistency-review.mjs にする (#3528): run ごとに手で写していた review-<N>.sh を 1 本のスクリプトにした。--run-dir --issues --issue --head --brief [--rereview --previous <前回の review md>] で、worktree の HEAD が --head と同じかを確かめ、Codex のロック(workspace/proposals/<date>/.lock)を取り、capture --instance codex --json が ready を 3 回続けて読むまで待ってから ask … --instance codex --timeout 2400 --json を送る。返答の本文は行頭の > **Thinking ( より前だけを取り出す(手作りの版は > **Thinking で切っていたため、本文が > **Thinking** を引用した所で指摘と DONE: 行を失った)。依頼文は雛形 scripts/orchestrate/templates/consistency-review.md(初回)と consistency-review-rereview.md(前回の指摘ごとの判定を先に書かせる)から作り、置換の漏れはエラーにする。DONE: 行があれば consistency-review.md に 1 行を足して run の記録に review=ok、依頼の失敗・DONE: 行なしは review=fail(exit 1)、引数の誤りは exit 2。docs/orchestrate/trials.md の 5-2b の手順をこの呼び出しに書き換えた。

  • feat(files): 単独のファイル表示ページで ```mermaid を図として描画 (#3522): src/app/worktrees/[id]/files/[...path]/page.tsx の `ReactMarkdown` に `MermaidCodeBlock` を接続し、`code` は `isMermaidLanguage` で mermaid だけ `MermaidCodeBlock` へ、`pre` は `isMermaidPreChild` で mermaid の子を素通しにした(図の枠が自分でブロックを持つ)。ダークテーマ・閉じたソース・エラー表示は `MermaidCodeBlock` の既定のまま。mermaid 以外のコードブロック(コピーボタン)とインラインコードの表示は不変。

  • **feat(chat): チャットと History の Markdown 表示で mermaid を図にする(ダークテーマ対応)** (#3503): 確定済みのチャットの回答・思考・ツールログ(`ChatMarkdownBody` の新しい `renderDiagrams`、渡すのは保存済みの行の `ChatMessageBubble` だけ)と History の会話カード(`AssistantMarkdown`)で、ファイルプレビュー(#100)と同じ `MermaidCodeBlock` を使って mermaid のコードブロックを図にする。判定と図の枠は 1 つ(`mermaid-block-utils` の `isMermaidPreChild` と `mermaid-markdown` の `MERMAID_MARKDOWN_COMPONENTS`)で、mermaid 以外のコード・インラインコードの描画は react-markdown の既定のまま。生成中(`ChatLiveTurnBubble`)と保留中の吹き出しは図にせずソースのまま出す。図の下には既定で閉じた「ソース」の折り畳みを置き、元のソースを文字として出す(構文エラーのときはエラー文と開いたソース。プレビューも同じ)。図は `<pre>` で包まず、コード用の暗い背景ではない図専用の背景(`.mermaid-figure`、ライト/ダークで切替)に置く。テーマはアプリのテーマ(next-themes の `resolvedTheme`)から `default` / `dark` を選び、mermaid の `secure` に `theme` / `themeVariables` / `themeCSS` / `darkMode` を足して、ソースの frontmatter や `%%{init}%%` のテーマ指定よりアプリのテーマを優先する(テーマ以外のソース側の設定は残る)。`initialize` と `render` は 1 本の順番待ちで直列にし、テーマが変わったときだけ `initialize` し直してから全部の図を描き直す(描き直し中も前の図を出したまま。持ち主が外れた待ちは列を塞がない)。`securityLevel: 'strict'` は維持し、`suppressErrorRendering: true` で構文エラー時に `document.body` へ一時 SVG を残さない。同じ内容の図が 2 つあってもノード・エッジの ID が衝突しないよう、描画後の SVG の ID を図ごとの接頭辞つきに付け替える(参照も追従)。履歴検索(チャット・History)は、図の SVG・読み込み中/エラーの文・「ソース」の見出しを数えず(`data-search-skip`)、原文の位置を畳んだソースの本文(`data-mermaid-source`)と、図の前後の本文の同じ出現位置へ対応させ、ヒットのあるソースを開いて強調する(`applyHistoryHighlights` の新しい `sourceText`)。引用の中の mermaid(先頭の > **Thinking** の節など)と、1〜3 個の空白で字下げしたフェンス・リストの項目を開くフェンス(Markdown の描画と同じく字下げ分を除いた本文で比べる)もフェンスとして扱い、チャットでは思考・ツールログの節を別の区画(chatSearchSections と data-search-section)として照合するので、引用の中の図と同じ本文の通常の図があっても、それぞれのヒットはそれぞれの図のソースを開いて強調する(対応が決まらないヒットは別の図に当てない)。図の描画が終わったとき・テーマ切替で描き直したときは強調を掛け直す。回答のコピーは今までどおり原文。画像を含む図・端末画面をそのまま写した行・印刷は対象外。

Changed

  • docs(orchestrate): 5-2b に consistency-review.mjs の呼び出しを書く (#3540): .claude/commands/orchestrate.md の 5-2b が、#3528 で入れた scripts/orchestrate/consistency-review.mjs の名前を出していなかったため、6-1・6-2 の publish-pr.mjs / merge-pr.mjs と同じ書き方で呼び出し(--run-dir・--issues・--issue・--head・--brief、再レビューは --rereview --previous)と終了コード(0 / 1 / 2)を 1 行足した。本文は上限内(check-orchestrate-size 通過)で、他の節は変えていない。

  • docs(auto-yes): 分割後の実態と合わなくなった 3 か所のコメントを修正 (#3521): auto-yes-enter-fallback-state.ts の promptFrameKey が auto-yes-poller-state.ts にあると明記、auto-yes-poller.ts ヘッダの Dependencies を実際の import に合わせ、auto-yes-poller-state.ts の promptFrameKey / warnOncePerFrame の JSDoc をそれぞれの関数の直前へ並べ替え。コード(コメント以外)は不変。

  • refactor(chat): ChatMessageBubble.tsx を 1,254 行に分割(承認グループとツール活動の共有部品を別ファイルへ) (#3518): ChatToolApprovalGroup とその定数を ChatToolApprovalGroup.tsx へ、ChatToolActivityContext・useChatToolActivityDisclosure・CHAT_TOOL_ACTIVITY_*・CHAT_BUBBLE_ROW_CLASS を循環回避のため chat-bubble-tool-activity.tsx へ移し、ChatMessageBubble.tsx から同名で再 export。振る舞い・公開面は不変。

  • refactor(terminal-highlight): #3503 の mermaid 対応を 3 つの分割先へ移し terminal-highlight.ts を 772 行から 316 行に戻す (#3517): テキストノード収集と Range 生成(collectTextNodes / buildRange、MatchPosition・SEARCH_SKIP_ATTR・MERMAID_SOURCE_ATTR・MERMAID_BLOCK_SETTLED_EVENT・TextNodeEntry)を src/lib/terminal-highlight-dom.ts、```mermaid フェンスの解析(findMermaidFences / `MermaidFence`)を `src/lib/terminal-highlight-fences.ts`、原文位置から DOM 位置への対応付け(`mapRawPositionsToDom` / `openFoldedSource`、Span 演算、`HighlightSection`・`SEARCH_SECTION_ATTR`)を `src/lib/terminal-highlight-mermaid.ts` に、本体とコメントを書き換えずに移した。依存は terminal-highlight → mermaid → dom・fences の一方向(dom と fences は何も import しない)で循環なし。移した公開名は `terminal-highlight.ts` から再 export するので `@/lib/terminal-highlight` の import 元は無変更、振る舞いも不変。

  • chore(agent-health): 自動依頼の 1 日の上限を改善 4 件・合計 8 件に上げる (#3505): 改善の起票ペース(1 日 4 件)に消化を合わせる。カタログのずれは 1 件のまま。

  • refactor(auto-yes): auto-yes-poller.ts を 1,543 行から 1,273 行へ分割 (#3411): poller の状態型 AutoYesPollerState と once-per-frame の WARN(promptFrameKey / warnOncePerFrame)を src/lib/polling/auto-yes-poller-state.ts へ、#3214 の抑止の出口(JudgedPrompt / suppressAndWarnOnce / suppressIfNotOursToAnswer / suppressUnclassifiedFrame)を src/lib/polling/auto-yes-prompt-suppression.ts へ、本体とコメントを書き換えずに移した。auto-yes-poller.ts は AutoYesPollerState を再 export し、既存の import 元は変えていない。新しい 2 ファイルは poller も tmux/tmux も import しない(循環と tmux の import 許可リストを増やさない)。#3406 の Enter フォールバック(tryEnterFallback / isStillEnterFallbackScreen)は tmux への送信と response-checker 経由の再判定を持つため poller に残した。Auto-Yes の判定順・ログ名・記録値は不変。

  • refactor(agent-health): decideReadiness を判定の節ごとの関数に分けて複雑度を 25 未満に (#3410): release-readiness.ts の decideReadiness(ESLint complexity 39)を、develop CI・本日マージされた PR・npm audit・dispatch したバグの再現・製品の経路の fail/要判断・未完了の dispatch と持ち越しの節ごとの非 export 関数に分け、累積先 ReadinessAccumulator を引数で渡す形にした。reasons / notes / nextSteps の中身と順序、節を呼ぶ順序は不変。

Fixed

  • fix(search): 検索の予備の照合で、段落の字下げ継続の後の 2. ```mermaid をフェンスと読まない (#3544): mermaid ソースが原文の範囲を名乗れない領域の予備の経路 findMermaidFences が、行の正規表現(直前の行が字下げならリスト項目の続き)で 段落\n 字下げした続き\n2. ```mermaid を項目の中のフェンスと読み、同じ本文の本物の図のソースをその偽フェンスに対応付けて、本物の図のヒットが強調されなかった。フェンスを開く行かどうかは描画と同じ remark(SHARED_REMARK_PLUGINS)で原文を構文解析した code ノードの位置で決めるようにし、interruptsParagraph の近似を削除。予備の経路はチャットで実際に通る(思考の節や道具の記録を畳んだ答えの最終行の末尾空白・CRLF は分割の trim() で消えて写像が null、思考の節が 2 つ以上だと思考側の写像が null)。History(恒等の写像)は従来どおり構造で照合する。

  • fix(orchestrate): 整合性レビューの保存本文に Tool calls の節が混ざる問題を修正 (#3539): consistency-review.mjs の extractReplyBody が返答を > **Thinking ( の行でしか切らず、思考の節が無く > **Tool calls (N)** の節だけが付いた返答ではその節が review-<N>.md に残っていた。区切りを Thinking ( と Tool calls ( の早い方(行頭一致・最初の 1 か所)にし、本文中の > **Tool calls** の引用では切れないままにした。DONE: 行の判定は引用行を数えないので裁定は変わらない。

  • fix(polling): duplicate-prompt-skipped を連続の最初と 30 tick に 1 回へ間引く (#3538): full-screen TUI(copilot / opencode)が未回答のプロンプトに止まっている間、duplicate-prompt-skipped が重複 tick ごと(2 秒ごと)に info で出ていたのを、#3519 の duplicate-response-skipped と同じ形にした。連続の 1 tick 目は従来どおりの payload(worktreeId / cliToolId)で出し、以降は DUPLICATE_PROMPT_SKIP_LOG_TICK_INTERVAL(=#3519 と共有の 30)tick に 1 回、consecutive / suppressed を添えて出す。数え上げは prompt-dedup.ts がプロンプトのハッシュと同じ寿命で持ち(新しいプロンプト・clearPromptHashCache(stopPolling / session cleanup)で消え、worktree の rename では一緒に移り、移送先の別ハッシュの回数は残さない。プロンプトの無い tick では、ハッシュは残したまま連続の数え上げだけを resetDuplicatePromptSkipStreak で戻すので、同じプロンプトが戻ったときの最初の重複も出る)、response-poller-core は変更なし。capture --json の promptDedup に出る recordPromptDedupSkip(#1695)の数え上げは間引かず、従来どおり重複 tick ごとに数える。

  • fix(orchestrate): merge-pr.mjs の取り込み後 precheck が整理の --kind refactor を引き継がない問題を修正 (#3527): 引き継ぎ元を作業の HEAD の precheck だけに限っていたため、一本化のコミットを重ねて公開する HEAD にだけ precheck がある場合に --base だけで走り、suppressions 段が skip になっていた。作業の HEAD に無ければ、その Issue の直近の precheck=ok(どの HEAD でも)の opts を引き継ぎ、どちらも無いときは推測せず exit 1 で止めて push しない。

  • fix(orchestrate): module-reference の一本化を重ねてから出した PR の題名が一本化の題名になる問題を修正 (#3526): publish-pr.mjs が PR の題名の既定を公開する HEAD の最後のコミットから取っていたため、6-4 の一本化コミットを重ねた HEAD では PR と squash 後の develop のコミットの題名が docs(module-reference): … 一本化 になっていた。既定を作業の HEAD(workHeadOf=ワーカーの最後のコミット)の題名にし、--title は従来どおり優先する。merge-pr.mjs は作業の HEAD が公開 HEAD と異なるとき、squash に --subject "<作業の HEAD の題名> (#<PR 番号>)" を渡して、すでに一本化の題名で開いた PR でもワーカーの題名で squash する。

  • fix(search): 履歴検索の mermaid 図の照合を行の正規表現から Markdown の構造(node.position)に変更 (#3525): #3503 の照合は原文の mermaid フェンスを行の正規表現(`findMermaidFences`)で切り出して画面のソースと本文で対応させていたため、描画(micromark)と食い違う形があった — 段落の直後の `2. mermaid(CommonMark では段落の文字)をリストの中のフェンスとして読み、後ろの同じ本文の図のヒットが強調されず段落のヒットが図に当たる/4 個以上の字下げ(入れ子のリスト)・タブの字下げ・ツールログのリストの中の図はヒットが強調されない。MermaidCodeBlockが react-markdown のnode.positionを原文の offset に直して『ソース』の要素にdata-mermaid-raw-start/data-mermaid-raw-end として載せ、mapRawPositionsToDom はその範囲で原文のフェンスと画面のソースを直接結ぶ(fenceFromRawRange が範囲をフェンスとして読み戻せたときだけ。読み戻せない・属性が無い領域は従来の本文一致の照合に落とす)。チャットは本文を前処理してから描くので、答え・思考・ツールログの各部分を原文の行に揃えて offset を戻す(alignDerivedText。揃わない部分は属性を付けず従来の照合)。History は本文そのものを描くので恒等。フォールバックの findMermaidFences` も、段落の直後の 1 以外で始まる番号付きリストをフェンスとして扱わないよう直した。ファイルのプレビューは属性が増えるだけで表示は不変。

  • fix(search): 履歴検索の強調が Markdown の記法の文字数だけ後ろへずれる問題を修正 (#3523): チャット(ChatTranscript)と History(HistoryPane)で、ヒットは原文(message.content)で数え、強調は描画後の DOM のテキストで数えていたため、描画で消える **・`・リンクの [..](url)・見出しの #・リストの - ・段落間の空行の 2 文字目の分だけ強調が後ろへずれていた(描画テストで再現: 太字・インラインコード・リンク・見出し・リスト・コードブロック・引用・表・段落 2 つ目のすべてで別の文字に当たる)。新設の rehype プラグイン rehypeSearchRawText(src/lib/terminal-highlight-markdown.ts)が各要素に「原文のどこにあるか」(react-markdown の node.position、チャットの部品は #3525 の写像で原文へ戻す)を data-search-raw として載せ、applyHistoryHighlights は mapMarkdownPositionsToDom でヒットを原文の位置から DOM の位置へ写す。位置は UTF-16 単位(絵文字を含む行でもずれない)。チャットでローカル動画・画像に置き換わるリンク / 画像(ChatVideo / ChatImage)は元の要素の印を引き継ぎ、動画の下のリンクの文字は写し、画像の代わりに描く代替文字は写像から外して、周りの段落は History と同じ位置に当たる。写せないヒット(印の無い行・要素の文字数が印と合わない行)は従来どおりの当て方のまま。mermaid のある行(#3503 / #3525 の対応付け)と端末の行(applyTerminalHighlights)は挙動不変。

  • fix(slash-commands): SKILL.md が無いスキルディレクトリで ERROR を出さない (#3520): parseSkillFile が SKILL.md の無いディレクトリ(~/.codex/skills/codex-primary-runtime・~/.claude/skills/synced など正常系)で fs.statSync の ENOENT を logger.error('error-parsing-skill-file-skillpath:') に流し、1 日 約 180 行の ERROR になっていた。ENOENT は logger.debug を出して null を返す正常系にし、権限・壊れた内容などそれ以外のエラーは従来どおり ERROR で出す。

  • fix(polling): duplicate-response-skipped のログを重複 tick ごとから「連続の最初+約 1 分に 1 回」へ間引く (#3519): 画面が止まったままの間、ポーラ(2 秒周期・1 サイクル最大 900 tick)が重複 tick のたびに同じ行を出し、24 時間で 51,933 行(サーバログ全体の 80%)になっていた。response-dedup に pollerKey ごとの連続重複 tick の数え上げ(claimDuplicateResponseSkipLog)を足し、連続の 1 tick 目は従来と同じ形で、以降は DUPLICATE_RESPONSE_SKIP_LOG_TICK_INTERVAL=30 tick(約 60 秒)に 1 回だけ consecutive(何 tick 目か)と suppressed(前の行から出さなかった tick 数)を添えて出す。1 サイクル 899 行が 30 行になる。#1695 の痕跡(返答が History に載らなかったとき grep で見つかる)は連続ごとに必ず残る。レベルは info のまま。数え上げは応答ハッシュと同じ寿命で、新しい返答で 0 に戻り、stopPolling(clearResponseHashCache)で消え、resume ではハッシュと一緒に残り、worktree の rename ではハッシュと一緒に移る(response-poller-core は変更なし)。