Skip to content

Release: develop を main にマージ#972

Merged
otomatty merged 60 commits into
mainfrom
develop
May 25, 2026
Merged

Release: develop を main にマージ#972
otomatty merged 60 commits into
mainfrom
develop

Conversation

@otomatty

@otomatty otomatty commented May 25, 2026

Copy link
Copy Markdown
Owner

概要

develop ブランチに蓄積された変更を main へマージします。develop の HEAD (71e2b627) を main に取り込むためのリリース PR です(56 コミット、271 ファイル)。

変更点

領域 主な変更
server/api/ Wiki Compose P0–P5 — LangGraph 基盤、research subgraph、BYOK 実行バックエンド、Ingest 連携、動的ルーティング、メンテナンス graph。composeSessions API、Postgres checkpointer、SSE マッピング
src/ Wiki Compose 分割画面 UI、PageActionHub(PDF 出力・サムネイル・Compose 入口)、ゴーストリンク補完、モバイル選択シート・キーボード追従、mermaid ノード正規化、Wiki リンク Cmd/Ctrl+click
server/api/drizzle/ 0031_add_wiki_compose_sessions.sql0032_add_user_ai_credentials.sql
server/api/.env.example USER_AI_CREDENTIALS_ENCRYPTION_KEY(BYOK 資格情報の at-rest 暗号化)
.github/ setup-toolchain composite action、CI / deploy ワークフロー更新
ドキュメント 英語正本 + .ja.md ペア(README / CONTRIBUTING / SECURITY / DOCUMENTATION 等)、check-doc-pairs.mjs
e2e/ Wiki Compose、Wiki リンクゴースト補完の E2E 追加

変更の種類

  • 🐛 バグ修正 (Bug fix)
  • ✨ 新機能 (New feature)
  • 💥 破壊的変更 (Breaking change)
  • 📝 ドキュメント (Documentation)
  • 🎨 スタイル/リファクタリング (Style/Refactor)
  • 🧪 テスト (Tests)
  • 🔧 ビルド/CI (Build/CI)

テスト方法

  1. CI(lint / format:check / vitest / playwright / drizzle-migration-check / api-typecheck)が green であること
  2. 本番デプロイ前に USER_AI_CREDENTIALS_ENCRYPTION_KEY を API サービスに設定すること(Wiki Compose BYOK 利用時)
  3. DB マイグレーション 0031 / 0032deploy-prod.yml で適用されること
  4. Wiki Compose フロー(brief → research → outline → draft)が develop 環境で動作すること
  5. エディタの PageActionHub・ゴーストリンク補完・PDF 出力が期待通り動作すること

チェックリスト

  • テストがすべてパスする(CI 待ち)
  • Lint エラーがない(CI 待ち)
  • 必要に応じてドキュメントを更新した(英語正本 + .ja.md ペア)
  • コミットメッセージが Conventional Commits に従っている

マージ方法

Create a merge commit でマージしてください(developmain のリリース PR 標準)。

デプロイ時の注意

  • DB マイグレーション: 0031_add_wiki_compose_sessions.sql0032_add_user_ai_credentials.sql
  • 新規環境変数: USER_AI_CREDENTIALS_ENCRYPTION_KEY(32 バイト、Base64 または 64 文字 hex)

関連 Issue

Related to #920, #921, #922, #923, #927#944, #946, #948#971

Made with Cursor

Summary by CodeRabbit

Release Notes

  • New Features

    • Added Wiki Compose: AI-powered multi-phase workflow for creating wiki articles with research, outline generation, and human-in-the-loop review steps.
    • Introduced bring-your-own-key (BYOK) support for Anthropic, OpenAI, and Google AI models.
    • Added compose session persistence and management.
    • Integrated web and wiki search capabilities into compose workflow.
  • Documentation

    • Expanded contribution guides with English and Japanese translations.
    • Added comprehensive security and documentation policies.
    • Updated admin and extension READMEs with setup and deployment guidance.
  • Infrastructure

    • Consolidated CI/CD toolchain setup via shared GitHub Action.
    • Updated GitHub workflows for improved reliability with retry logic.

Review Change Stack

otomatty and others added 30 commits May 20, 2026 12:22
chore: sync main to develop
`PageEditorHeader` のアクションメニューに、Markdown エクスポートと同じ UX で
PDF を直接ダウンロードする項目を追加する。クライアント側で Tiptap JSON を
HTML 化し、html2pdf.js (html2canvas + jsPDF) で書き出すことで、新規サーバー
エンドポイントを追加せずに済むようにした。

- `src/lib/tiptapToHtml.ts`: Tiptap JSON → 印刷向け HTML 変換と `downloadPdf`
- `src/components/editor/PageEditor/usePdfExport.ts`: トースト付きハンドラ
- `NotePageView` の編集可/読み取り専用ビュー両方にメニュー項目を統合
- ja/en の i18n キー (`editor.pageMenu.exportPdf`, `editor.pdfExport.*`)
- 単体テスト (tiptapToHtml: 13, usePdfExport: 3, NotePageView: 30 件)

Add an "Export as PDF" action to the page editor's overflow menu, mirroring
the Markdown export UX with a direct download. Client-side conversion via
`html2pdf.js` keeps the new feature off the server. Wired into both editable
and read-only views; the read-only path disables the item until
`usePagePublicContent` resolves, matching the Markdown export gating.
- プレーンテキスト fallback で `\n` を `<p>`/`<br />` に展開
  (codex P1: 読み取り専用 `content_text` が 1 行に潰れていた)
- `sanitizeUrl` 正規表現に `.` を追加し `image.png` 等の相対画像を許可
  (gemini-code-assist high)
- heading コメントを h2-h5 → h2-h6 に修正 (gemini-code-assist medium)
- 上記 3 点に対応する単体テストを追加 (CRLF 正規化・空白のみ入力含む)

Read-only PDF export now preserves paragraph breaks for the plain-text
content fed from `usePagePublicContent.content_text` (Y.Doc-extracted text
with `\n` between blocks). Dotted relative image paths render correctly.
Heading dispatch comment matches the actual h2-h6 range.
feat: Add client-side PDF export via html2pdf.js
…Bar (#922) (#923)

* feat(editor): introduce PageActionHub and retire EditorRecommendationBar (#922)

Replace the bottom-fixed EditorRecommendationBar on /notes/:noteId/:pageId
with a registry-based PageActionHub (Dialog on desktop, Drawer on mobile)
opened by a new single-button FAB. Phase 1 migrates the two existing
thumbnail actions ("画像を検索" / "AI で画像生成") into the hub and removes
the old bar plus its tests; later phases will add WebClipper / Mermaid /
AI / templates as additional registry entries.

- Add PageActionHub container, list/detail navigation, registry, and a
  dedicated PageActionHubFab gated on canEdit && isSignedIn.
- Thread a pageActionHubRef through TiptapEditor →
  useTiptapEditorController → PageActionHub, mirroring the existing
  insertAtCursorRef pattern so the FAB in NotePageView can call open().
- Reuse the existing useThumbnailImageSearch / useThumbnailImageGenerate /
  useThumbnailController hooks; move shared ThumbnailCandidate type to
  thumbnailTypes.ts before deleting EditorRecommendationBarTypes.
- Replace editor.recommendation.* i18n keys with editor.pageActionHub.*
  (ja/en).

* fix(editor): address PageActionHub review feedback (PR #923)

- PageActionHub: return null instead of an empty wrapper div in the
  header slot while the list view is active to avoid stray spacing
  inside DrawerHeader / DialogHeader.
- ThumbnailGenerateAction: guard the post-await setState / onClose
  with an isMountedRef so closing the hub mid-flight no longer
  updates an unmounted component.

---------

Co-authored-by: Claude <noreply@anthropic.com>
* refactor(editor): make WikiLinkSuggestion mount-agnostic for shared reuse (#925)

入力バー (#924 §2) と本文中 `[[` サジェスト両方から再利用できるよう、
`WikiLinkSuggestion` の props から Editor / range など呼び出し元
コンテキストへの依存を除去し、純粋なプレゼンテーションコンポーネントに
整理する。マウント位置 (fixed / absolute) は呼び出し側に委ねる。

- Drop unused `editor` and `range` props; the component had declared them
  but never read them inside the render path.
- Update `WikiLinkSuggestionLayer` (sole caller) to omit those props.
- Add Vitest coverage for rendering, scope filtering, the "create new"
  entry, click-to-select, keyboard navigation (↑↓Enter/Escape), and the
  mount-agnostic positioning guarantee.
- `wikiLinkSuggestionPlugin.ts` is untouched; in-body `[[` behavior is
  preserved.

* refactor(editor): address review feedback on WikiLinkSuggestion (#933)

- Export `WikiLinkSuggestionProps` so the upcoming input bar (#924 §2)
  can type its host wrapper without re-declaring the shape (gemini).
- Add `type="button"` to suggestion rows so reusing the component inside
  a `<form>` (the planned FAB input bar) does not accidentally submit
  the form on click / Enter (CodeRabbit quick win).
- Replace the explicit `act(() => Promise.resolve())` microtask flush in
  the cycling-keyboard test with `waitFor` against the highlight class,
  decoupling the test from the component's `queueMicrotask` internals
  (gemini / CodeRabbit).

---------

Co-authored-by: Claude <noreply@anthropic.com>
* feat(editor): add FAB-adjacent WikiLink input bar (#926)

Adds an always-on pill input bar to the left of the FAB on the editor
screen. The bar doubles as ghost-link creation and existing-link
insertion: focusing the bar snapshots the editor cursor, Enter falls
back to an existing page on exact-match (otherwise inserts a ghost
link), and clicking a candidate inserts the resolved Wiki Link. After
confirming, focus returns to the editor.

Reuses the shared WikiLinkSuggestion popup decoupled in #925 and
delegates state / async confirm logic to a new useWikiLinkInputBar hook
to keep the rendering component small. Hidden on read-only views.

* fix(editor): forward note-scope candidates to WikiLink exists checker

Reviewer (Codex P1) flagged that `useWikiLinkInputBar` was calling
`useWikiLinkExistsChecker({ pageNoteId })` without `notePages`. In note
scope the checker intentionally returns empty sets when note candidates
are absent, so the bar's Enter exact-match fallback could never resolve
an existing same-note page and would always insert a ghost link — the
exact case the fallback is meant to cover.

Reuse the candidate pages already fetched by `useWikiLinkCandidates` as
the `notePages` source (mirrors the `useWikiLinkStatusSync` pattern).
Personal scope is unchanged.

Also add CodeRabbit's aria-label assertion to the placeholder test and
two regression tests pinning the scope-aware checker options.

---------

Co-authored-by: Claude <noreply@anthropic.com>
`FloatingWikiLinkInputBar` を入力欄フォーカス時のみ `visualViewport`
を購読し、キーボードが覆う高さ分だけ `bottom` を持ち上げるように変更。
入力バー自体と候補リストの両方が常にキーボード上に見える状態を保つ。
focus が外れたタイミングでリスナーは解除し通常配置に戻す。

- `useVirtualKeyboardOffset` フックを `useSyncExternalStore` で実装し、
  iOS Safari と Android Chrome の挙動差(layout vs visual viewport)を
  `innerHeight - vv.height - vv.offsetTop` で吸収。
- `FloatingWikiLinkInputBar` は `onFocusCapture`/`onBlurCapture` でバー
  内の focus 状態を追い、`relatedTarget` を見てサジェストとの行き来では
  解除しないようにする。
- キーボード表示中は `safe-area-inset-bottom` と `--app-bottom-nav-height`
  を加味した padding を 0.5rem に縮め、キーボード上端へ視覚的に貼り付ける。

Co-authored-by: Claude <noreply@anthropic.com>
… (#936)

* feat(editor): デスクトップ Cmd/Ctrl+K と Cmd/Ctrl+Shift+L ショートカット (#928)

エディタフォーカス時に動作する 2 つのデスクトップショートカットを追加。

- `Cmd/Ctrl+K`: Wiki Link 入力バーへフォーカスを移す。入力バー側の
  `handleFocus` が選択位置を退避するため、確定時に元の位置へ挿入される
  既存パスをそのまま活用する。
- `Cmd/Ctrl+Shift+L`: 選択中テキストを即 `[[Title]]` Wiki Link 化する。
  空選択時は no-op。実体は `useBubbleMenuWikiLink.convertToWikiLink` を
  再利用してバブルメニューと挙動を一致させる。

既存のグローバル検索 (`useGlobalSearchShortcut` の `Cmd/Ctrl+K`) および
Tiptap `@tiptap/extension-link` の `Mod-k` と衝突するため、新フックは
document の capture phase で keydown を捕捉し、`preventDefault()` +
`stopPropagation()` で他リスナーをバイパスする。`useGlobalSearchShortcut`
側にも `defaultPrevented` ガードを追加し、登録順に依存しない契約とする。

WikiLinkInputBar には `focusInputBarRef`(`MutableRefObject<(() => void) | null>`、
`focusContentRef` と同じ規約)を新設して、外部からの imperative focus を
許可する。`useBubbleMenuWikiLink` は `Editor | null` を受け入れるように
シグネチャを拡張し、`TiptapEditor` から editor 初期化前でも安全に呼べる
ようにした。

Vitest テストは `src/hooks/useEditorWikiLinkShortcuts.test.ts`(17 ケース)
と `src/hooks/useGlobalSearchShortcut.test.ts`(5 ケース)に追加。
`WikiLinkInputBar.test.tsx` には ref 経由フォーカスのテストも追加。

Add desktop Cmd/Ctrl+K and Cmd/Ctrl+Shift+L shortcuts that operate while
the editor is focused. Cmd/Ctrl+K focuses the WikiLinkInputBar (reusing
its built-in selection-save on focus); Cmd/Ctrl+Shift+L converts the
current selection into a `[[Title]]` link via the existing
`useBubbleMenuWikiLink` conversion, with empty-selection as a no-op.

The new hook listens in document capture phase and calls preventDefault +
stopPropagation when consumed, preempting both `useGlobalSearchShortcut`
and the Tiptap Link extension's Mod-k binding. `useGlobalSearchShortcut`
now also bails out on `event.defaultPrevented` so the contract is robust
to listener registration order.

https://claude.ai/code/session_018SWqs6vMEyXzW6cm75q8Fp

* fix(editor): caps lock 中の cmd+k 取りこぼしと変換 reject の握り潰し対応 (#928)

PR レビュー指摘 (#936) 対応。

- Caps Lock オン時に `event.key === "K"` で `Cmd+K` ハンドラが発火しない問題を
  修正。`toLowerCase()` で正規化し、Shift 無し時の `"k"` / `"K"` 両方を捕捉
  する (Codex P2)。`Cmd+Shift+L` も同様に正規化して `"l"` / `"L"` を一律に扱う。
- `void convertSelectionToWikiLink()` の reject が document keydown ハンドラ
  経由で unhandled rejection になる可能性に対し、`.catch(console.error)` で
  ログだけ取って握り潰すよう変更 (CodeRabbit / Gemini)。

Vitest テストに以下を追加:
- Caps Lock 相当の大文字 `K` で Cmd+K が動くこと。
- `convertSelectionToWikiLink` が reject しても `console.error` が呼ばれるだけで
  unhandled rejection にならないこと。

Gemini のプラットフォーム別 modifier (`metaKey` for Mac / `ctrlKey` otherwise) は
issue #928 の "macOS / Windows / Linux でキーバインドを統一" 要件および既存
`useGlobalSearchShortcut` の挙動と整合しないため不採用。理由は PR コメントで返信。

Address PR review feedback on #936.

- Cmd+K previously skipped events when Caps Lock was on (`event.key === "K"`).
  Normalize via `toLowerCase()` so both `"k"` and `"K"` match without Shift,
  and likewise for Cmd+Shift+L (Codex P2 feedback).
- `void convertSelectionToWikiLink()` could surface unhandled promise
  rejections out of the document keydown handler. Wrap with
  `.catch(console.error)` to log and swallow (CodeRabbit / Gemini feedback).

The platform-split modifier suggestion (metaKey for Mac, ctrlKey for others)
is deliberately not adopted: issue #928 requires uniform behavior across
macOS / Windows / Linux, matching the existing `useGlobalSearchShortcut`.
Reasoning posted as inline PR reply.

https://claude.ai/code/session_018SWqs6vMEyXzW6cm75q8Fp

---------

Co-authored-by: Claude <noreply@anthropic.com>
* ci: add setup-toolchain composite action with retry on transient failures

Introduces .github/actions/setup-toolchain to deduplicate the common
"Node + Bun + bun install" setup and wrap it with retry semantics, so
intermittent GitHub API 401 / 5xx responses (e.g. setup-bun hitting
api.github.com/repos/oven-sh/bun/git/refs/tags) no longer fail PR checks.

- Node / Bun setup are wrapped with Wandalen/wretry.action@v3
  (attempt_limit: 3, attempt_delay: 5000ms).
- bun install retries inline in shell with linear 5s / 10s backoff.
- Callers continue to invoke actions/checkout themselves (necessary
  because a local composite action cannot bootstrap its own checkout)
  and now wrap it with Wandalen/wretry.action@v3 too, since checkout
  itself has been observed to flake.
- ci.yml, deploy-dev.yml, deploy-prod.yml, nightly-mutation.yml all
  switched to the new pattern. setup-bun / install-deps inputs let
  Node-only and workspace-only jobs opt out cleanly.

Closes #937

* ci(setup-toolchain): forward github.token to setup-bun explicitly

Initial run on this branch failed in every Bun-using job with a
persistent "Bad credentials" 401 from api.github.com/repos/oven-sh/bun.
Drizzle jobs (setup-bun: false) passed, confirming the failure is
specific to `setup-bun` invoked through `Wandalen/wretry.action`.

`setup-bun`'s action.yml resolves its `token` input from
`${{ github.token }}` via a default expression — but that expression
isn't evaluated for the nested context when wretry wraps the action,
so setup-bun ends up calling the GitHub API with an empty token.

Forward `token: ${{ github.token }}` explicitly through wretry's
`with:` block so the nested setup-bun actually authenticates. Checkout
and setup-node continue to work without explicit token forwarding
(proven by the Drizzle jobs that already passed on the first run).

---------

Co-authored-by: Claude <noreply@anthropic.com>
BubbleMenu は仮想キーボードと干渉するためモバイルでは非表示にし、
代わりにキーボード直上に固定表示するシートで Wiki Link 化 /
Bold / Italic / Code / Strike を提供する。シートの表示判定は
EditorBubbleMenu の shouldShow と同条件、位置は visualViewport
追従(既存 useVirtualKeyboardOffset を再利用)。

Co-authored-by: Claude <noreply@anthropic.com>
Make GitHub entry documentation English-first with full Japanese pairs,
add DOCUMENTATION.md policy, CI pair verification, and PR checklist updates.

Co-authored-by: Cursor <cursoragent@cursor.com>
* feat(editor): インラインゴースト補完を追加 (#930)

タイピング中、既存ページ名の接頭辞に一致する単語があれば残り部分を
カーソル右に薄色のゴーストとして表示し、Tab(デスクトップ)または
チップタップ(モバイル)で WikiLink マークに確定する ProseMirror
プラグインを追加(親 issue #924 §4)。

- `wikiLinkGhostCompletionPlugin.ts`: `Extension.create` + `Plugin`
  構成で `wikiLinkSuggestionPlugin` / `tagSuggestionPlugin` と
  ライフサイクルを揃える。`useWikiLinkCandidates` の結果は ref 経由の
  getter で受け取り、候補更新でエディタ再生成を避ける
- 抑止条件: 範囲選択中・他サジェスト系 active・コードブロック・
  インラインコード・title / caption 等本文外・既存 WikiLink マーク内・
  ≥2 文字未満・先頭 `[` `]` `#` `@` `/`・候補なし or 完全一致
- 確定パスはタブとタップで共用(`handleKeyDown` + `mousedown` /
  `touchstart` の DOM event delegation)
- IME 中は `compositionstart` で即時クローズ、`view.composing` で
  Tab を奪わない
- Vitest 30 ケース(最小スキーマで状態遷移を網羅)、Playwright 7 ケース
  (ハッピー / Esc / 1 文字 / コードブロック / `[[` 競合 / Tab 素通し)

* fix(editor): suppress ghost completion while slash menu is active, harden DOM guards

PR #940 のレビュー指摘に対応する 3 件の修正と、コメントの日英併記化:

- `findContextSuppression` に `slashSuggestionPluginKey` の active チェックを
  追加。`SlashSuggestionPlugin` は空白を含むクエリでも active を維持するため
  ( `/(^|\\s)\\/([^\\n]*)$/` )、「`/cmd Ghost`」のような入力でゴースト widget が
  二重に出たり Tab を奪ったりするのを防ぐ (Codex P1)
- `handleDOMEvents.mousedown` / `touchstart` で `event.target instanceof Element`
  ガードを追加。テキストノードに対して `closest` を呼んだ際の TypeError を
  回避する (CodeRabbit Major)
- E2E にインラインコード抑止テストを追加。受け入れ条件「コードブロック /
  インラインコードでは発火しない」の E2E カバレッジを補完 (CodeRabbit Major)
- `seedCandidatePage` の JSDoc から実体と矛盾する "Returns the title" を削除
- 英語のみのコメント数件に日本語を併記 (CLAUDE.md のコメント方針)
- 新規追加のスラッシュ抑止契約を vitest でカバー

---------

Co-authored-by: Claude <noreply@anthropic.com>
)

* feat(editor): wiki link の Cmd+クリック / 中クリックで新タブ遷移 (#931)

- `useWikiLinkNavigation.handleLinkClick` に `{ newTab }` オプションを追加し、
  既存ページ解決時とゴーストリンク Dialog 確定時の両方で
  `window.open(url, "_blank", "noopener,noreferrer")` ⇔ `navigate(url)` を切替。
- `WikiLinkExtension` の ProseMirror plugin で `event.metaKey || event.ctrlKey`
  と `auxclick` (button === 1) を検出して新タブ意図を伝搬。
- `AIChatWikiLink` のゴーストボタンで `onClick` の修飾キーと `onAuxClick` を
  処理(既存ページは `<Link>` のブラウザ既定挙動でカバー済み)。
- ナビゲーション pipeline (`useEditorSetup` / `editorConfig`) の型署名に
  `options?: { newTab?: boolean }` を追加して可読性を改善。
- `useWikiLinkNavigation` と `WikiLinkExtension` のテストに修飾キー /
  中クリック / Dialog 経由の新タブ遷移ケースを追加。

* fix(editor): wiki link 新タブ遷移を about:blank プレ確保方式に変更 (#931)

PR レビュー(gemini-code-assist / coderabbitai)の指摘に対応。
`useEffect` 内や `await mutateAsync` 後の `window.open` はユーザー
アクティベーションが切れており、Safari / Firefox を中心にポップアップ
ブロッカで遮断される。

対応として、`handleLinkClick` の同期スタック内で
`window.open("about:blank", "_blank", "noopener,noreferrer")` を呼んで
タブを確保し、ページ解決後 / ダイアログ確定後にそのタブの
`location.href` を最終 URL に差し替える方式に変更。

- 既存ページ解決時: useEffect で `pendingNewTabWindowRef.current.location.href`
  を上書き。
- ゴーストリンク Dialog 確定時: 確保済みタブの `location.href` を上書き。
  ノートスコープ no-op / ミューテーション失敗 / Cancel 時はタブを `close()`
  して空白タブが残らないようにする。
- ポップアップがブロックされて `window.open` が `null` を返した場合は
  silent no-op(既存挙動を悪化させない)。
- テストを `mockReturnValue(mockWindow)` / `mockWindow.location.href`
  / `mockWindow.close` 検証に書き換え、失敗時クローズの新規ケースを追加。

---------

Co-authored-by: Claude <noreply@anthropic.com>
* style(#932): unify ghost/referenced wiki link appearance to faint orange only

破線下線・[+] アイコン等の追加装飾を削除し、`.wiki-link-referenced` /
`.wiki-link-ghost` を「薄いオレンジ系の濃淡だけで区別する」設計に統一
(親 #924 §5)。共有 CSS 変数 `--link-referenced` / `--link-ghost` を
オレンジ系へ更新し、`.tag-referenced` / `.tag-ghost` も #725 の整合性
維持のため同設計に揃える。ライト/ダーク両モードで WCAG AA
(4.5:1) を満たす値を選定。`:focus-visible` のキーボードフォーカスを
明示的に追加。

Removes dashed underline and `[+]` icon decorations from ghost links;
`.wiki-link-referenced` and `.wiki-link-ghost` are now distinguished by
lightness alone within a warm-orange family (parent #924 §5). The shared
`--link-referenced` / `--link-ghost` CSS variables are repointed to
orange-based hues; `.tag-referenced` / `.tag-ghost` follow the same
design to keep the parity introduced in #725. Both modes meet WCAG AA
(≥4.5:1) against their backgrounds. Explicit `:focus-visible` outlines
are added for keyboard accessibility.

https://claude.ai/code/session_01Jr2tWRzoWJdxeDmgqawLQo

* fix(#932): tighten ghost link contrast & drop unreachable focus-visible

レビューフィードバックの反映:

- chatgpt-codex の指摘通り、ライトモード ghost の `28 50% 40%` は 10%
  の tinted chip 背景上で約 4.18:1 となり WCAG AA を満たしていなかった。
  チップ背景込みで AA を満たす値に再調整:
  - `--link-referenced` (light): `24 80% 35%` → `24 80% 32%` (~5.5:1)
  - `--link-ghost`      (light): `28 50% 40%` → `28 50% 38%` (~4.5:1)
  referenced > ghost の濃淡階層は維持。

- CodeRabbit の指摘通り、WikiLinkExtension / TagExtension は `<span>` を
  `tabindex` 無しでレンダリングするため `:focus-visible` ルールは到達
  不能のデッド CSS。4 箇所(wiki-link-referenced/ghost,
  tag-referenced/ghost)から削除し、将来 span を tabbable 化する際の
  メモをコメントで残した。

Addresses review feedback from PR #943:

- chatgpt-codex flagged that the light ghost token at `28 50% 40%`
  resolved to ~4.18:1 against the 10%-tinted chip background, below WCAG
  AA. Retuned both light tokens against the chip-composited background
  while preserving the `referenced > ghost` lightness hierarchy.

- CodeRabbit flagged that `:focus-visible` cannot fire on the
  non-tabbable `<span>` elements rendered by WikiLink/Tag extensions.
  Removed the four dead rules; left a code comment noting the gap so a
  future a11y pass can restore them once the extensions emit focusable
  semantics.

https://claude.ai/code/session_01Jr2tWRzoWJdxeDmgqawLQo

---------

Co-authored-by: Claude <noreply@anthropic.com>
* feat(editor): redesign note page bottom input bar and action FAB

Align the wiki link bar with the editor Container, pair it with a menu-style
FAB in one fixed row, improve desktop spacing and mobile keyboard tracking,
and update the placeholder to 「メモを書く」.

Co-authored-by: Cursor <cursoragent@cursor.com>

* docs: update CLAUDE.md with coding guidelines for LLM implementation

Added detailed guidelines to reduce common mistakes in LLM coding, emphasizing clarity, simplicity, and minimal changes. Sections include pre-implementation considerations, prioritizing simplicity, minimizing changes, and defining success criteria for tasks. Updated project-specific notes and TDD connections to align with existing documentation.

* fix(editor): use CSS variables for floating bar bottom padding

Wire padding constants through custom properties instead of duplicating
calc() strings in Tailwind classes, per review feedback on PR #944.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
* feat(editor): render markdown mermaid code blocks as diagrams (#945)

```mermaid``` フェンス由来の codeBlock を専用 `mermaid` ノードに変換して
`MermaidNodeView` で SVG 描画する経路を整備。

- `transformMermaidCodeBlocksInContent` を追加し、ProseMirror JSON 中の
  `codeBlock(language="mermaid")` を `mermaid` ノードへ置換
- `MarkdownPasteExtension` で WikiLink 後処理と同様に上記変換を実行
- 既存ドキュメント向けに `MermaidCodeBlockNormalize` 拡張を追加し、
  ロード時 / 言語属性変更時に lazy migration を実施
- `markdownExport` に `mermaid` ハンドラを追加し ` ```mermaid ` フェンスへ
  逆変換(往復対称性を担保)
- `tiptapToHtml` に同期描画用プレースホルダー(`<pre><code language-mermaid>`)
  を追加し、PDF 出力で図のソースが落ちないようにする

Convert ```mermaid``` fenced code blocks (represented as `codeBlock` +
`language: "mermaid"`) into dedicated `mermaid` nodes so they render via
the existing `MermaidNodeView`. Mirrors the WikiLink post-parse transform
pattern and adds a lazy migration extension for already-saved pages.

* fix(editor): address review feedback on mermaid normalization (#946)

PR #946 のレビュー指摘を反映する。

- `transformMermaidCodeBlocksInContent` の事前ディープクローンを廃止し、
  構造共有方式に変更。変更が無いノードは同一参照を返すため、Mermaid を
  含まない大きな貼り付け/取り込みではゼロコピーで処理される
  (gemini-code-assist 高優先 ×2)
- `MermaidCodeBlockNormalize` の正規化トランザクションに
  `setMeta("addToHistory", false)` を付与し、undo 履歴への混入を防ぐ。
  Cmd+Z で `mermaid` → `codeBlock` に戻り、次の編集で再変換される
  undo/redo bounce を回避 (CodeRabbit major)
- 構造共有および undo 履歴除外の回帰テストを追加

Apply structural sharing to the post-parse transform and exclude lazy
migration transactions from undo history, addressing the high-priority
gemini-code-assist comments and the CodeRabbit major finding on PR #946.

---------

Co-authored-by: Claude <noreply@anthropic.com>
* feat(api): wiki compose P0 — LangGraph エージェント基盤 (#948)

Wiki Compose の P0 基盤として、`server/api/src/agents/` 配下に LangGraph
実行基盤を構築する。後続フェーズ (#949〜) が依存する共通レイヤ。

## 追加

- 依存パッケージ: `@langchain/core`, `@langchain/langgraph`,
  `@langchain/langgraph-checkpoint-postgres`, `@langchain/openai`,
  `@langchain/anthropic`, `@langchain/google-genai`, `zod`
- `agents/core/llm/`:
  - `ZediChatModel` — `BaseChatModel` を継承し、全 LLM 呼び出しを既存
    `callProvider` / `streamProvider` 経由に統一する。`validateModelAccess`
    + `recordUsage` を 1 呼び出しあたり 1 回ずつ通し、`/api/ai/chat` と
    課金経路を共通化する。P0 は backend=`zedi_managed` のみ。
  - `modelFactory` — backend ガード (`assertSupportedBackendP0`) +
    provider API キー解決をまとめる。
  - `usageCallback` — `recordZediUsage` と LangChain `BaseMessage` →
    既存 `AIMessage` への変換ユーティリティ。
- `agents/core/checkpoint/postgresCheckpointer.ts` — `PostgresSaver` の
  プロセスローカルシングルトン。checkpoint テーブルは `setup()` で別管理。
- `agents/core/state/baseState.ts` — 全 subgraph 共通の `BaseState`
  (messages / phase / pageId / userId)。
- `agents/core/tools/` — `web_search` / `wiki_search` / `fetch_article` /
  `image_search` を zod schema + LangGraph tool として登録。P0 は本体スタブ。
- `agents/core/types/` — `ExecutionBackend`, `GraphContext`, `SseEvent`
  の discriminated union。
- `agents/registry/graphRegistry.ts` — `graphId` → factory のマップ。
  P0 動作確認用に `wiki-compose-stub` を登録。
- `agents/runner/`:
  - `GraphRunner` — invoke / streamEvents / resume を一括で受け持つ。
    `thread_id` と `GraphContext` を `configurable` に注入する。
  - `sseMapper` — LangGraph 生イベント → `SseEvent` の純粋関数変換。
- Drizzle: `wiki_compose_sessions` テーブル + migration
  `0031_add_wiki_compose_sessions.sql`。
- Routes `/api/pages/:pageId/compose-sessions`:
  - `POST /` — 行作成 (graphId / backend 検証)
  - `GET /:id` — 取得
  - `POST /:id/run` — SSE 実行
  - `PATCH /:id/resume` — interrupt 再開
  - `DELETE /:id` — キャンセル

## テスト

- `agents/` 配下 5 ファイル (42 件): ZediChatModel の usage 記録経路、
  GraphRunner の registry 解決と Command 渡し、sseMapper の event 変換、
  tools の zod schema と名前安定性、backend ホワイトリスト。
- `routes/composeSessions.test.ts` (10 件): 認可・CRUD・backend ガード。
- 全体: 1306 件 (既存 + 新規)。

* chore(api): wire postgres checkpointer + knip hygiene for #948

Knip flagged 3 unused files and 4 unused deps. Address each in line with
the issue's acceptance criteria rather than just suppressing.

- `agents/core/checkpoint/index.ts` — new barrel exposing `resolveCheckpointerForRun()`.
  Returns the `PostgresSaver` singleton when `DATABASE_URL` / `POSTGRES_URL` is
  set (production), and `false` otherwise (tests / CI / smoke runs). Calls
  `ensurePostgresCheckpointerSetup()` once on first production use.
- `routes/composeSessions.ts` — run + resume routes now feed the resolved
  checkpointer to `GraphRunner` instead of hard-coded `false`. Satisfies the
  P0 acceptance criterion: "`PostgresSaver` で thread_id 単位の checkpoint
  保存・再開ができる".
- `agents/index.ts` — re-export `resolveCheckpointerForRun` and register
  `src/agents/index.ts` as a knip entry so the public agent barrel and the
  `core/types/index.ts` re-exports stop being flagged as unreachable.
- `knip.json` — ignore `@langchain/openai` / `@langchain/anthropic` /
  `@langchain/google-genai`. Issue #948 lists them as P0 deps; #949+
  subgraphs will consume them directly.

Verified: knip clean (no unused files / deps), typecheck ✓, 1306 tests ✓.

---------

Co-authored-by: Claude <noreply@anthropic.com>
* feat(api): wiki compose P0 — LangGraph エージェント基盤 (#948)

Wiki Compose の P0 基盤として、`server/api/src/agents/` 配下に LangGraph
実行基盤を構築する。後続フェーズ (#949〜) が依存する共通レイヤ。

## 追加

- 依存パッケージ: `@langchain/core`, `@langchain/langgraph`,
  `@langchain/langgraph-checkpoint-postgres`, `@langchain/openai`,
  `@langchain/anthropic`, `@langchain/google-genai`, `zod`
- `agents/core/llm/`:
  - `ZediChatModel` — `BaseChatModel` を継承し、全 LLM 呼び出しを既存
    `callProvider` / `streamProvider` 経由に統一する。`validateModelAccess`
    + `recordUsage` を 1 呼び出しあたり 1 回ずつ通し、`/api/ai/chat` と
    課金経路を共通化する。P0 は backend=`zedi_managed` のみ。
  - `modelFactory` — backend ガード (`assertSupportedBackendP0`) +
    provider API キー解決をまとめる。
  - `usageCallback` — `recordZediUsage` と LangChain `BaseMessage` →
    既存 `AIMessage` への変換ユーティリティ。
- `agents/core/checkpoint/postgresCheckpointer.ts` — `PostgresSaver` の
  プロセスローカルシングルトン。checkpoint テーブルは `setup()` で別管理。
- `agents/core/state/baseState.ts` — 全 subgraph 共通の `BaseState`
  (messages / phase / pageId / userId)。
- `agents/core/tools/` — `web_search` / `wiki_search` / `fetch_article` /
  `image_search` を zod schema + LangGraph tool として登録。P0 は本体スタブ。
- `agents/core/types/` — `ExecutionBackend`, `GraphContext`, `SseEvent`
  の discriminated union。
- `agents/registry/graphRegistry.ts` — `graphId` → factory のマップ。
  P0 動作確認用に `wiki-compose-stub` を登録。
- `agents/runner/`:
  - `GraphRunner` — invoke / streamEvents / resume を一括で受け持つ。
    `thread_id` と `GraphContext` を `configurable` に注入する。
  - `sseMapper` — LangGraph 生イベント → `SseEvent` の純粋関数変換。
- Drizzle: `wiki_compose_sessions` テーブル + migration
  `0031_add_wiki_compose_sessions.sql`。
- Routes `/api/pages/:pageId/compose-sessions`:
  - `POST /` — 行作成 (graphId / backend 検証)
  - `GET /:id` — 取得
  - `POST /:id/run` — SSE 実行
  - `PATCH /:id/resume` — interrupt 再開
  - `DELETE /:id` — キャンセル

## テスト

- `agents/` 配下 5 ファイル (42 件): ZediChatModel の usage 記録経路、
  GraphRunner の registry 解決と Command 渡し、sseMapper の event 変換、
  tools の zod schema と名前安定性、backend ホワイトリスト。
- `routes/composeSessions.test.ts` (10 件): 認可・CRUD・backend ガード。
- 全体: 1306 件 (既存 + 新規)。

* fix(api): prevent compose sessions stuck in running state

Use atomic status claims for run/resume, persist terminal status on SSE
abort, and mark sessions failed when resume throws before completion.

Co-authored-by: akimasa.sugai <akimasa.sugai@saedgewell.com>

* fix(api): return 400 for unsupported backend on compose resume

Validate session backend before claiming an interrupted session and
map UnsupportedBackendError to HTTP 400, matching POST /run behavior.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: akimasa.sugai <akimasa.sugai@saedgewell.com>
Co-authored-by: otomatty <saedgewell@gmail.com>
* feat(api): Wiki Compose P1 — researchLoopSubgraph (#949)

Implements the autonomous research-loop subgraph for Wiki Compose on top
of the P0 LangGraph scaffold (#948). Backend only — frontend
ResearchSection / ActivitySection are deferred to P2 (#950).

## researchLoopSubgraph

`plan_queries → (web_search ∥ wiki_search) → fetch_articles →
evaluate_sufficiency → [refine_queries → loop] × N → compile_batch →
human_review_research (interrupt) → END`

Exit when `score >= 0.75` OR `iteration >= maxIterations` (default 3,
clamped 1..5). HITL via LangGraph 1.x `interrupt()`; resume payload
`{ approvedSourceIds, rejectedSourceIds?, note? }` validated by
`researchResumeSchema` and projected into `approvedResearch` /
`rejectedResearch`. Additional research re-runs the graph on a fresh
session with `{ kind: "additional_research", instruction,
carryOverApprovedIds }` input (no new route).

## Tools (replaces stubs)

- `wikiSearchTool` — reads `db`/`userId`/`userEmail` from `GraphContext`
  and calls new `searchUserWikiPages` service (extracted from
  `routes/search.ts` preserving the `scope=shared` SQL exactly).
- `fetchArticleTool` — wraps `extractArticleFromUrl` with the same
  `isClipUrlAllowedAfterDns` SSRF guard `clipServerFetch` uses; per-URL
  errors return `{ ok:false, error }` so one bad URL never aborts the
  loop.
- `webSearchTool` — resolves cheapest OpenAI/Google model via
  `resolveWebSearchModelId` (env override + `ai_models` query), then
  builds `ZediChatModel` with `useWebSearch` / `useGoogleSearch` for
  structured output. Documented fallback: no managed search model →
  `{ ok:true, results:[], note:"web_search_unavailable" }`.

## P0 surface additions (additive, non-breaking)

- `ZediChatModel.extraProviderOptions` pass-through for provider knobs
  (used by `webSearchTool`).
- `GraphContext.userEmail` for `wikiSearchService`'s domain predicate.
- 3 new SSE events: `research_iteration`, `research_evaluation`,
  `research_batch` dispatched via `dispatchCustomEvent`, surfaced by a
  new `on_custom_event` branch in `sseMapper.mapLangGraphEvent`.

## P0 bug fix (interrupt detection)

LangGraph ≥ 1.x surfaces interrupts on the result state as a
`__interrupt__: Interrupt[]` array, NOT as a thrown error.
`GraphRunner.invoke` now detects this; `sseMapper.mapChainEnd` converts
it to a wire `SseInterruptEvent`; the route flips `finalStatus` to
`"interrupted"` on any emitted interrupt event. Legacy throw path is
kept for forward-compat / version skew.

## Composition

- `recursionLimit: 60` for `wiki-compose-research` (≈5 iterations ×
  ~6 nodes); other graphs keep the default 25.
- `registerResearchLoopGraph()` called from `app.ts` alongside
  `registerStubGraph()`.

## Tests (24 new)

- `researchGraph.{conditional,loop,interrupt,resume,modelGuard}` cover
  all #949 acceptance criteria (autonomous loop to maxIterations,
  conditional edge, interrupt position, resume → approvedResearch,
  re-run input shape, every LLM via `createZediChatModel`).
- `tools/{wikiSearch,webSearch,fetchArticle}` for per-tool envelopes,
  SSRF guard, Anthropic fallback.
- `nodes/compileBatch` for exit-reason derivation.
- `services/wikiSearchService` for the extracted page-search service.

`pnpm vitest run` — 1333 passed (109 files). `bunx tsc --noEmit` clean.

Closes #949.

* refactor(api/agents): inline web-search model resolver next to its caller

Cleanup follow-up to the initial #949 commit, no behaviour change.

- Replace lazy `await import()` inside `detectProviderForModelId` with
  top-level imports from `drizzle-orm` + the `aiModels` schema; the
  schema layer is leaf-level so there's no circular-dep risk.
- Move `resolveWebSearchModelId` from
  `agents/subgraphs/research/nodes/shared/` to `agents/core/tools/`
  next to its only consumer (`webSearch.ts`). Removes the backward
  directional dependency from `core` → `subgraphs`.

`bunx tsc --noEmit` clean; 24 research-loop tests + 65 agents tests
still pass.

* fix(api/agents): address PR #956 review feedback

Two substantive bugs surfaced by the automated PR review:

## codex P1 — additional-research input contract was broken

The documented `body.input = { kind: "additional_research", ... }` shape
never reached `plan_queries`: LangGraph's strict state schema drops top-
level input keys that have no annotation, so `kind` / `instruction` /
`carryOverApprovedIds` silently vanished and re-runs behaved like a
normal initial run.

Fix:

- Add `additionalRequest: AdditionalResearchRequest | null` to
  `ResearchLoopState` (and `types.ts`); reducer is `(prev, next) =>
   next ?? prev`, default `null`.
- The route now translates `{ kind: "additional_research", ... }` into
  `{ additionalRequest: {...} }` before passing to the graph
  (`translateGraphInput` in `composeSessions.ts`); other graph ids pass
  through unchanged. Public client contract is unchanged.
- `plan_queries` reads `state.additionalRequest` (not `messages[0]`)
  and clears it to `null` after consumption so a defensive re-plan in
  the same session doesn't loop on the same instruction.

## codex P2 + gemini #1/#2/#4 — web↔fetched dedup was bogus

The JSDoc claimed "in-place upgrade from `kind:web` to `kind:fetched`",
but `web:<sha(url)>` and `fetched:<sha(finalUrl)>` were distinct ids so
the id-keyed reducer kept both rows. After a redirect (trailing slash /
canonical host change), they wouldn't even agree on URL, splitting the
same article into two state rows and re-fetching across iterations.

Fix:

- Unified id scheme `src:<sha256(originalUrl)>` for web AND fetched.
  Fetched rows carry the source row's id over instead of minting a new
  one, so the reducer (`mergeSourcesById`) overwrites the web row in
  place — matching the JSDoc contract.
- New optional `Source.finalUrl` carries the redirect-resolved URL for
  display / citation; `Source.url` stays equal to the original so the
  id stays stable across iterations.
- `fetchArticles` no longer maintains a separate `fetchedUrls` set; the
  reducer-level dedup is sufficient now that ids match.

## gemini #3 — evaluateSufficiency maxTokens 512 → 1024

512 was tight for a structured `{ score, rationale, missingAspects[] }`
response when the LLM verbose-explained low-score iterations; bumped to
1024 to keep JSON from truncating mid-array.

## Tests

- New: `nodes/planQueries.test.ts` (3 tests) — exercises the
  `additionalRequest` consumption and `maxIterations` clamping.
- Updated existing tests' Source ids from `web:` to `src:`.
- All 1336 tests pass (110 files); `tsc --noEmit` and `biome` clean.

* style: prettier --write on Wiki Compose P1 files

CI Lint job ran prettier --check across the repo and flagged 20 files
introduced by #949 / the merge of develop's #955 fix. Re-formatted with
prettier; no behaviour change.

Format-check, lint, and docs:check-pairs all pass locally; agents +
services + routes tests still pass (860/860).

* fix(api/agents): address PR #956 review feedback (round 3)

## Critical (coderabbit)

composeSessions.ts:357 unconditionally set finalStatus = "completed"
after the SSE stream drained, silently overwriting the "interrupted"
state set inside the for-await loop. Interrupted sessions were therefore
persisted as completed (closedAt set), breaking the resume path. The
bug was a regression from the merge of develop's #955 fix, which moved
the default initialiser without updating this branch.

Fix: guard the completion promotion with `finalStatus !== "interrupted"`.

## Major (coderabbit) — resolveWebSearchModel tier filter

The resolver could pick a tier-inaccessible model (or an env override
that the caller's tier could not use), which then exploded inside
`createZediChatModel` and surfaced as an error envelope instead of the
documented graceful "web_search_unavailable" path.

Fix: add a `UserTier` parameter and apply `tierRequired = "free"` for
free users. Validate env overrides through the same DB filter before
returning — if the override is inactive or tier-blocked, fall through
to the standard lookup.

## Major (coderabbit) — TSDoc on exported node functions

Added function-level TSDoc to all 7 exported research-loop node
functions per repo guidelines: `compileBatch`, `evaluateSufficiency`,
`fetchArticles`, `humanReviewResearch`, `refineQueries`, `webSearch`,
`wikiSearch`. Each documents its purpose, params, return shape, and
notable side-effects / thrown errors.

## Minor (coderabbit) — getGraphContext field check

Added a minimal field-presence check (`userId`, `db`, `feature`) so a
malformed context fails loudly at the call site rather than deep inside
`recordUsage`. Avoided pulling in Zod for a single-producer contract.

## Skipped with reason

- gemini #2 (evaluateSufficiency dedup web/fetched in prompt): already
  resolved by the unified `src:<sha>` id scheme — the state reducer
  dedupes upstream, so evaluate_sufficiency never sees both kinds for
  the same URL.
- gemini #4 (state.ts JSDoc claim about in-place upgrade): already
  resolved by the same id refactor in this round of fixes.

## Verification

- `bunx tsc --noEmit` clean.
- Agents + services + composeSessions tests: 84/84 pass.
- `bun run format:check` / `bun run lint` (0 errors) / `docs:check-pairs` all green.

---------

Co-authored-by: Claude <noreply@anthropic.com>
…) (#959)

Backend (server/api/src/agents/graphs/wikiCompose/):
- wikiComposeGraph orchestrator that walks Brief → Research → Structure
  → Draft → Completed in one LangGraph. State extends ResearchLoopState as a
  strict superset so the P1 research loop composes inline; interrupts at the
  three HITL points (brief / research / outline) halt the same thread_id.
- new nodes: briefDialogue (0..7 structured questions), humanReviewBrief,
  structureDialogue (3..10 section outline), humanReviewOutline, draftSections
  (sequential per-section LLM streaming via model.stream), completed
  (markdown assembly + citation collation).
- resume payload validators (briefResumeSchema, outlineResumeSchema) reject
  malformed payloads at the node boundary.
- new SSE events compose_phase / compose_section so the frontend can drive
  the phase stepper + per-section streaming without inspecting state.
- composeSessions route bumps recursion limit to 120 for the orchestrator
  (Brief + Research up to 5x6 nodes + Structure + up to 10 draft sections).

Frontend (src/):
- /notes/:noteId/:pageId/compose and /compose/:sessionId routes mount the new
  WikiComposePage (split-screen: left EditorPane with live section preview,
  right ComposePanel with PhaseStepper + Brief/Research/Outline sections +
  Activity timeline). Mobile uses vertical split.
- useWikiComposeSession hook owns the SSE wiring and state machine.
- composeService provides REST + SSE clients with a spec-compliant SSE parser
  (handles multi-chunk records, comments, multi-line data, aborts).
- WikiGeneratorButton gains a composeHref mode that navigates to /compose and
  stays visible on pages that already have content (Compose supports append).
  Legacy inline-generation path unchanged when composeHref is absent.

Tests:
- vitest: orchestrator wiring + 3 interrupt points pinned with MemorySaver;
  SSE custom-event mapper extensions; SSE parser edge cases; hook state
  reductions for Brief / Draft / submitBrief flows; PhaseStepper a11y.
- playwright (e2e/wiki-compose.spec.ts): full happy-path with mocked SSE
  routes — Compose entry → Brief submit → research approval → outline
  approval → completed Draft → back to /notes.

Issue: #950

Co-authored-by: Claude <noreply@anthropic.com>
…#958)

* fix(api): do not overwrite cancelled Wiki Compose sessions on run end

When DELETE cancels a running session, persist terminal status only if the
row is still `running` so graph completion cannot clobber `cancelled`.

Co-authored-by: akimasa.sugai <akimasa.sugai@saedgewell.com>

* style(api): format composeSessionPersistence for Prettier

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: akimasa.sugai <akimasa.sugai@saedgewell.com>
Outline approval runs draft synchronously on PATCH /resume and returns
completion in JSON, but the hook ignored output and skipped SSE when status
was completed, leaving the editor empty. Apply __interrupt__ and completion
from resume output, avoid invalid POST /run on interrupted checkpoints, and
persist sessionId in the compose URL after create.

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
- Register PageActionHub wiki.compose action with compose navigation
- Replace pendingChatPageGeneration with navigateToWikiCompose from AI chat
- Pass chat seed through session metadata and graph chatSeed state
- Wire wikiComposeHref into PageActionHub context from the page editor
…t run

Two sibling routes remounted WikiComposePage when persisting the session id
in the URL, aborting the first SSE stream and dropping chat seed from
location state. Use a single route with optional :sessionId and restore
chatSeed from session metadata when retrying a failed row.
Bumps the minor-and-patch group with 2 updates: [@anthropic-ai/sdk](https://github.com/anthropics/anthropic-sdk-typescript) and [katex](https://github.com/KaTeX/KaTeX).


Updates `@anthropic-ai/sdk` from 0.96.0 to 0.98.0
- [Release notes](https://github.com/anthropics/anthropic-sdk-typescript/releases)
- [Changelog](https://github.com/anthropics/anthropic-sdk-typescript/blob/main/CHANGELOG.md)
- [Commits](anthropics/anthropic-sdk-typescript@sdk-v0.96.0...sdk-v0.98.0)

Updates `katex` from 0.16.47 to 0.17.0
- [Release notes](https://github.com/KaTeX/KaTeX/releases)
- [Changelog](https://github.com/KaTeX/KaTeX/blob/main/CHANGELOG.md)
- [Commits](KaTeX/KaTeX@v0.16.47...v0.17.0)

---
updated-dependencies:
- dependency-name: "@anthropic-ai/sdk"
  dependency-version: 0.98.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
- dependency-name: katex
  dependency-version: 0.17.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [eslint-plugin-jsdoc](https://github.com/gajus/eslint-plugin-jsdoc) from 62.9.0 to 63.0.0.
- [Release notes](https://github.com/gajus/eslint-plugin-jsdoc/releases)
- [Commits](gajus/eslint-plugin-jsdoc@v62.9.0...v63.0.0)

---
updated-dependencies:
- dependency-name: eslint-plugin-jsdoc
  dependency-version: 63.0.0
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
DELETE could overwrite a session that finished as completed while cancel
was in flight. Use a status-guarded update like persistOutcomeIfStillRunning
and return the latest row status when the cancel update matches nothing.

Co-authored-by: akimasa.sugai <akimasa.sugai@saedgewell.com>
cursoragent and others added 4 commits May 25, 2026 08:08
- Return no compose model ids for wiki-maintenance so BYOK session create
  does not require orchestrator credentials for a lint-only graph.
- Project conflict_resolution interrupts on GET compose-sessions reload.
- Handle conflict_resolution in the compose hook and UI so research approval
  can pause for acknowledgement instead of leaving the session stuck.
… (#970)

* feat(api): wiki compose P5 dynamic routing and maintenance graph (#953)

- Add routeAfterBrief and routeAfterResearch conditional edges to wikiComposeGraph
- Add skip_research and conflict_resolution nodes with Vitest coverage
- Register wiki-maintenance graph (broken links + stub page scan)
- Bump wiki-compose graph version to 1.1.0

Co-authored-by: Akimasa Sugai <otomatty@users.noreply.github.com>

* fix(api,ui): address P5 PR review — conflict UI, brief degraded routing (#953)

- Add briefDegraded flag so LLM fallback still runs research
- Wire conflict_resolution through projection, hook, and ComposePanel UI
- Stabilize stub scan query with orderBy; bilingual maintenance strings

Co-authored-by: Akimasa Sugai <otomatty@users.noreply.github.com>

* fix(ui): conflict resume preserves approvals and align phase types (#953)

- Seed interrupt context from checkpoint approvedResearch on resume
- Add conflict to compose_phase SSE unions (client + server)
- Bilingual TSDoc for review nits

Co-authored-by: Akimasa Sugai <otomatty@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Akimasa Sugai <otomatty@users.noreply.github.com>
- Align conflict_resolution UI with develop (conflict phase, ConflictResolutionSection)
- Keep briefDegraded routing from develop
- Update hook test to expect conflict phase after research approval
…s-a450

fix(api): wiki-maintenance BYOK and conflict-resolution HITL stuck sessions
@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@coderabbitai

coderabbitai Bot commented May 25, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@otomatty, we couldn't start this review because you've used your available PR reviews for now.

Your plan includes 5 reviews of capacity. Refill in 5 minutes and 34 seconds.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more review capacity refills, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than trial, open-source, and free plans. In all cases, review capacity refills continuously over time.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 2f7e445e-60aa-4ebb-989e-1b0f656dbdf9

📥 Commits

Reviewing files that changed from the base of the PR and between 71e2b62 and c671d17.

📒 Files selected for processing (21)
  • server/api/drizzle/0031_add_wiki_compose_sessions.sql
  • server/api/drizzle/0032_add_user_ai_credentials.sql
  • server/api/src/__tests__/agents/core/composeBackendValidation.test.ts
  • server/api/src/__tests__/agents/core/llm/zediChatModel.test.ts
  • server/api/src/__tests__/agents/graphs/ingest/planIngestModel.test.ts
  • server/api/src/__tests__/agents/runner/sseMapper.test.ts
  • server/api/src/__tests__/routes/composeSessionProjection.test.ts
  • server/api/src/agents/core/checkpoint/postgresCheckpointer.ts
  • server/api/src/agents/core/composeBackendValidation.ts
  • server/api/src/agents/core/llm/zediChatModel.ts
  • server/api/src/agents/core/tools/resolveWebSearchModel.ts
  • server/api/src/agents/core/types/index.ts
  • server/api/src/agents/graphs/ingest/nodes/planIngest.ts
  • server/api/src/agents/runner/sseMapper.ts
  • server/api/src/agents/subgraphs/research/resumeSchema.ts
  • server/api/src/routes/composeSessionProjection.ts
  • server/api/src/routes/composeSessions.ts
  • server/api/src/routes/ingest.ts
  • server/api/src/services/wikiSearchService.ts
  • src/hooks/useWikiComposeSession.ts
  • src/lib/wikiCompose/composeService.ts
📝 Walkthrough

Walkthrough

Adds Wiki Compose graphs and routes, BYOK credential storage/validation, shared tools and LLM model factory, Postgres checkpointing, SSE mapping, ingest-planner integration, docs pairing checks, CI composite action, frontend compose route/UI, and extensive unit/E2E tests with necessary DB schema/migrations.

Changes

Compose Orchestration + BYOK Integration

Layer / File(s) Summary
Graph registry, runner, SSE mapping
server/api/src/agents/registry/*, server/api/src/agents/runner/*, server/api/src/agents/index.ts
Graph registration/lookup, Postgres checkpointer, GraphRunner (invoke/stream/resume), and SSE event mapper added.
Compose graphs and state
server/api/src/agents/graphs/wikiCompose/*, .../research/*, .../ingest/*, .../wikiMaintenance/*
Implements Wiki Compose orchestrator, research subgraph, ingest planner, and maintenance graphs with state, nodes, routing, resume schemas, and tests.
LLM model, factory, tools
server/api/src/agents/core/llm/*, .../tools/*, .../types/*
Adds ZediChatModel, modelFactory with backend checks, web/wiki/fetch tools, SSE/event types, execution backend utilities, and usage recording.
Routes and projection
server/api/src/routes/composeSessions.ts, .../composeSessionProjection.ts, .../ingest.ts, .../userAiCredentials.ts, .../search.ts
Compose sessions API (create/run/resume/cancel), UI projection from checkpoints, ingest graph run/resume, BYOK credential routes, and search delegates to service.
Schema/migrations
server/api/drizzle/*, server/api/src/schema/*, .env.example
Adds wiki_compose_sessions, user_ai_credentials, and corresponding Drizzle schemas with examples and journal updates.
Services and crypto
server/api/src/services/*
Implements wiki search service, BYOK credential CRUD with AES-256-GCM, ingest plan parsing.
CI and docs policy
.github/actions/setup-toolchain/*, .github/workflows/*, scripts/check-doc-pairs.mjs, package.json
Adds composite setup-toolchain action; updates workflows to use it with retries; adds doc pair checker and script.
Frontend/UI & E2E
src/App.tsx, editor/PageActionHub*, FloatingWikiLink*, e2e/*
Adds compose route, PageActionHub components/tests, new-tab ghost link behavior, and E2E for compose and ghost completion.
Documentation updates
README*.md, DOCUMENTATION*.md, SECURITY*.md, CONTRIBUTING*.md, AGENTS.md, CLAUDE.md, extension/*, admin/*, server/mcp/*
Switches to English-first with .ja.md pairs, adds policies/guides, and updates extension/admin/MCP docs.

Sequence Diagram(s)

sequenceDiagram
  rect rgba(0, 128, 255, 0.5)
  participant Web as Frontend
  participant API as Hono API
  participant DB as Postgres
  participant LG as LangGraph
  end
  Web->>API: POST /compose-sessions
  API->>DB: insert session (pending)
  Web->>API: POST /compose-sessions/:id/run (SSE)
  API->>LG: streamEvents(context, checkpointer)
  LG-->>Web: SSE started/status/token/interrupt
  Web->>API: PATCH /compose-sessions/:id/resume {resume}
  API->>LG: resume(thread, resume)
  LG->>API: result (completed/interrupted/failed)
  API->>DB: persistOutcomeIfStillRunning
  API-->>Web: { status, output }
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

  • otomatty/zedi#966 — Implements BYOK execution backend and credential wiring overlapping with this PR’s user_ai_credentials and backend validation.
  • otomatty/zedi#959 — Adds Wiki Compose orchestrator/state/routes similar to the compose graphs and API introduced here.
  • otomatty/zedi#968 — Ingest planner graph integration and tests align with this PR’s ingest-planner graph and run/resume endpoints.

Suggested labels

enhancement

Poem

A rabbit taps keys with gleeful might,
Weave graphs of thought that stream in light—
BYOK tucked safe at rest,
Compose hums on, resumes its quest.
CI hops thrice, retried and true—
Docs in pairs, in English too.
Ship it! 🐇✨

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch develop

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the "Wiki Compose" feature, utilizing LangGraph to manage AI-driven workflows including research, ingestion, and maintenance. Key components include the ZediChatModel for consistent usage tracking and a secure BYOK credential system with encryption. The submission is supported by comprehensive tests, database migrations, and synchronized English and Japanese documentation. Feedback focuses on improving the reliability of usage recording in ZediChatModel to handle aborted streams and addressing potential HTTP timeout issues when executing long-running graphs synchronously.

Comment thread server/api/src/agents/core/llm/zediChatModel.ts
Comment thread server/api/src/routes/ingest.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 71e2b627d8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread server/api/src/agents/core/composeBackendValidation.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 19

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

🟡 Minor comments (26)
README.ja.md-88-90 (1)

88-90: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Remove spaces inside inline code spans in shortcut examples.

The spans like `# ` / `- ` / `> ` trigger markdownlint MD038; format them without inner edge spaces (or escape visible spaces explicitly).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.ja.md` around lines 88 - 90, Inline code examples currently show
backtick spans with trailing spaces like `# `, `- `, and `> ` which trigger
markdownlint MD038; update those spans to remove the inner edge spaces (use `#`,
`-`, `>` instead) or explicitly escape the visible space if you need to show it,
ensuring the README.ja.md examples use `#`, `-`, `>` (or escaped-space
equivalents) rather than `# `, `- `, `> `.
CONTRIBUTING.ja.md-236-246 (1)

236-246: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Specify languages for unlabeled fenced blocks.

The fences at Line 236 and Line 262 should declare a language (e.g., text) to satisfy markdownlint.

Also applies to: 262-268

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CONTRIBUTING.ja.md` around lines 236 - 246, The markdown fenced blocks
showing the project tree (the block starting with "src/" and containing
"components/", "FeatureComponent.tsx", "hooks/", "useFeature.ts", "lib/",
"featureUtils.ts") must declare a language to satisfy markdownlint; update each
triple-backtick fence around those unlabeled blocks to include a language token
such as ```text (or ```bash) so the two documented blocks (the src/ tree blocks)
are changed from ``` to ```text.
README.md-88-90 (1)

88-90: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix inline code span spacing in Markdown shortcut list.

Spans with inner trailing spaces (e.g., `# `) violate MD038 and can fail markdown lint checks.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` around lines 88 - 90, The inline code spans in the Markdown
shortcut list use trailing spaces inside the backticks (e.g., `# `, `- `, `> `)
which triggers MD038; update each span to remove the trailing space so they read
`#`, `-`, and `>` respectively (ensure the text in the README.md list entries
uses those corrected inline code spans and re-run markdown lint to confirm MD038
is resolved).
README.md-308-344 (1)

308-344: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Set a language for the fenced project-structure block.

Use a language label like text on the fence at Line 308 to satisfy MD040.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` around lines 308 - 344, Add a language label to the fenced
project-structure block so the Markdown linter MD040 is satisfied: change the
opening triple-backtick that precedes the tree diagram (the fenced
project-structure block in README.md starting with "src/                     #
Frontend (React + Vite)") to use a language tag such as ```text (e.g., replace
``` with ```text) and keep the rest of the block unchanged.
CONTRIBUTING.ja.md-7-40 (1)

7-40: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix TOC anchor fragments to match Japanese headings.

Several TOC links point to English anchors while the actual headings are Japanese, so intra-doc navigation breaks (e.g., #contributing-to-zedi, #getting-started).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CONTRIBUTING.ja.md` around lines 7 - 40, The Table of Contents uses English
anchor fragments (e.g., `#contributing-to-zedi`, `#getting-started`) that don't
match the actual Japanese section headings, breaking intra-doc links; update
each TOC link target to the correct fragment that matches the Japanese heading
text (convert the Japanese heading to the same slug used by Markdown: lowercase,
spaces to hyphens, and percent-encode any non-ASCII characters if your renderer
requires it) for entries such as "Contributing to Zedi", "Getting Started",
"Development Workflow", "Pull Request Process", "Coding Standards", "Commit
Message Guidelines", "Reporting Bugs", "Suggesting Features" and "Questions?" so
the anchors reference the exact Japanese headings in the document.
README.ja.md-311-347 (1)

311-347: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add a language tag to the project-structure fenced block.

The fence starting at Line 311 is unlabeled; use text to satisfy markdownlint MD040.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.ja.md` around lines 311 - 347, The fenced code block showing the
project directory tree (starting with the line "src/                     #
フロントエンド本体(React + Vite)") is unlabeled; update its opening fence from ``` to
```text so the block is explicitly marked as plain text (this satisfies
markdownlint MD040) in README.ja.md.
CLAUDE.md-63-67 (1)

63-67: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add a language to the fenced code block.

The snippet at Line 63 uses an unlabeled fence; add a language (e.g., text) to satisfy markdownlint and keep docs checks stable.

Proposed fix
-```
+```text
 1. [ステップ] → 検証: [確認方法]
 2. [ステップ] → 検証: [確認方法]
 3. [ステップ] → 検証: [確認方法]
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @CLAUDE.md around lines 63 - 67, Update the unlabeled fenced code block in
CLAUDE.md (the triple-backtick block containing the three numbered steps) to
include a language identifier (e.g., change totext) so markdownlint and
docs checks pass; locate the block shown in the diff and replace the opening
fence with ```text while leaving the block contents unchanged.


</details>

</blockquote></details>
<details>
<summary>SECURITY.md-19-20 (1)</summary><blockquote>

`19-20`: _⚠️ Potential issue_ | _🟡 Minor_ | _⚡ Quick win_

**Replace placeholder vulnerability contact before release.**

`security@example.com` is a placeholder, so reports may never reach maintainers. Please replace it with the actual monitored security address (or remove email and keep only private advisory flow until it exists).

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@SECURITY.md` around lines 19 - 20, The SECURITY.md currently lists a
placeholder contact "security@example.com" which should be replaced before
release; update the SECURITY.md content to either replace "security@example.com"
with the real monitored security contact email or remove the email line and rely
solely on the "GitHub Security Advisories" private reporting flow, ensuring the
file clearly directs reporters to the actual mechanism and monitored address.
```

</details>

</blockquote></details>
<details>
<summary>scripts/check-doc-pairs.mjs-38-39 (1)</summary><blockquote>

`38-39`: _⚠️ Potential issue_ | _🟡 Minor_ | _⚡ Quick win_

**Fix JSDoc signature drift on `main`.**

The docblock declares an argument that `main()` does not accept, so the in-code specification is inaccurate.



<details>
<summary>✏️ Proposed fix</summary>

```diff
-/** `@param` {string[]} errors */
+/** Runs documentation pair checks and exits non-zero on failure. */
 function main() {
```
</details>

Based on learnings: Source of truth for specifications is TSDoc/JSDoc in code and tests; long-form prose should not be tracked in Git; see SPECIFICATION_POLICY.md.

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/check-doc-pairs.mjs` around lines 38 - 39, The JSDoc for main()
wrongly declares a parameter (string[] errors) while the function signature
takes no arguments; update the docblock in scripts/check-doc-pairs.mjs to
reflect the actual signature by removing the parameter from the /** ... */
comment for function main (or, if main should accept errors, change the function
to accept that parameter and use it consistently) and ensure the JSDoc tags
(param descriptions) match the function name main and its real parameters.
```

</details>

</blockquote></details>
<details>
<summary>server/api/src/__tests__/agents/graphs/wikiMaintenance/wikiMaintenanceGraph.test.ts-1-3 (1)</summary><blockquote>

`1-3`: _⚠️ Potential issue_ | _🟡 Minor_ | _⚡ Quick win_

**Add Japanese translation to file header.**

The coding guidelines require TSDoc/JSDoc comments to include both Japanese and English text. Other test files in this PR include bilingual headers (e.g., `ingestPlannerGraph.test.ts` has "Ingest planner graph (`#952`) — research subgraph wiring + routing tests. / ingest プランナーグラフ — 調査 subgraph 配線とルーティングのテスト。").




<details>
<summary>Suggested fix</summary>

```diff
 /**
- * Wiki maintenance graph (`#953`) — wiring + scan node tests.
+ * Wiki maintenance graph (`#953`) — wiring + scan node tests.
+ * Wiki メンテナンスグラフ (`#953`) — 配線とスキャンノードのテスト。
  */
```

</details>

As per coding guidelines: `**/*.{ts,tsx,js,jsx}`: TSDoc/JSDoc comments and code comments should include both Japanese and English language text to align with project tone

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@server/api/src/__tests__/agents/graphs/wikiMaintenance/wikiMaintenanceGraph.test.ts`
around lines 1 - 3, Add a Japanese translation to the file header comment that
currently reads "Wiki maintenance graph (`#953`) — wiring + scan node tests." —
update the TSDoc/JSDoc comment to include a Japanese equivalent (e.g., "Wiki
メンテナンスグラフ — 配線 + スキャンノードのテスト。") directly under or alongside the English line so
the header contains both English and Japanese as required by the coding
guidelines.
```

</details>

</blockquote></details>
<details>
<summary>server/api/src/__tests__/services/userAiCredentialCrypto.test.ts-8-8 (1)</summary><blockquote>

`8-8`: _⚠️ Potential issue_ | _🟡 Minor_ | _⚡ Quick win_

**Make this JSDoc line bilingual (JA/EN).**

The added comment is English-only; please add Japanese text as well to match repository comment policy.


As per coding guidelines `**/*.{ts,tsx,js,jsx}`: TSDoc/JSDoc comments and code comments should include both Japanese and English language text to align with project tone.

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/api/src/__tests__/services/userAiCredentialCrypto.test.ts` at line 8,
The JSDoc comment "/** 32-byte test key (hex). */" is English-only; update it to
include Japanese and English on the same comment (e.g., add "32バイトのテストキー(16進)"
before or after the English text) so the JSDoc above the test key constant in
userAiCredentialCrypto.test.ts is bilingual per repo policy.
```

</details>

</blockquote></details>
<details>
<summary>server/api/src/__tests__/routes/composeSessionPersistence.test.ts-1-3 (1)</summary><blockquote>

`1-3`: _⚠️ Potential issue_ | _🟡 Minor_ | _⚡ Quick win_

**Make the file-level JSDoc bilingual (JA/EN).**

The new header comment is English-only; project policy asks for both Japanese and English in TSDoc/JSDoc and code comments.


As per coding guidelines `**/*.{ts,tsx,js,jsx}`: TSDoc/JSDoc comments and code comments should include both Japanese and English language text to align with project tone.

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/api/src/__tests__/routes/composeSessionPersistence.test.ts` around
lines 1 - 3, The file-level JSDoc at the top of
composeSessionPersistence.test.ts is English-only; update that header comment to
include both Japanese and English lines (bilingual TSDoc/JSDoc) per project
policy. Edit the existing comment block (the top-of-file /** ... */) to add a
concise Japanese translation of the English description (e.g., Japanese
sentence(s) above or below the English text) so the file header contains both
languages while preserving the original meaning and format.
```

</details>

</blockquote></details>
<details>
<summary>server/api/src/__tests__/services/wikiSearchService.test.ts-1-7 (1)</summary><blockquote>

`1-7`: _⚠️ Potential issue_ | _🟡 Minor_ | _⚡ Quick win_

**Add Japanese text to the top-level test description comment.**

This new block comment is English-only; add a Japanese counterpart to satisfy the bilingual comment rule.


As per coding guidelines `**/*.{ts,tsx,js,jsx}`: TSDoc/JSDoc comments and code comments should include both Japanese and English language text to align with project tone.

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/api/src/__tests__/services/wikiSearchService.test.ts` around lines 1 -
7, The top-level block comment above the tests is English-only; add a concise
Japanese translation alongside the existing English text so the comment is
bilingual. Update the comment that documents searchUserWikiPages unit tests (the
block referencing searchUserWikiPages, getDefaultNoteOrNull, WikiSearchHit, and
limit clamping) by adding equivalent Japanese sentences for each bullet point
and the leading sentence to satisfy the bilingual comment rule.
```

</details>

</blockquote></details>
<details>
<summary>server/api/src/__tests__/routes/composeSessions.test.ts-116-117 (1)</summary><blockquote>

`116-117`: _⚠️ Potential issue_ | _🟡 Minor_ | _⚡ Quick win_

**Keep inline comments bilingual (JA/EN) for consistency.**

This newly added inline comment is English-only; please add the Japanese pair per repository tone policy.


As per coding guidelines `**/*.{ts,tsx,js,jsx}`: TSDoc/JSDoc comments and code comments should include both Japanese and English language text to align with project tone.

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/api/src/__tests__/routes/composeSessions.test.ts` around lines 116 -
117, The inline comment above the registerGraph call in the
composeSessions.test.ts test is English-only; update that comment to include the
Japanese translation alongside the existing English text to follow the
repository's bilingual comment policy. Locate the comment immediately above the
registerGraph({...}) invocation in
server/api/src/__tests__/routes/composeSessions.test.ts and replace or extend it
so it contains both English and Japanese (e.g., "Register a graph the routes can
resolve. Body is irrelevant for CRUD tests. /
ルートが解決できるグラフを登録します。ボディはCRUDテストでは重要ではありません。"), ensuring the text appears directly
next to the registerGraph reference and preserves the original meaning.
```

</details>

</blockquote></details>
<details>
<summary>server/api/src/agents/core/checkpoint/postgresCheckpointer.ts-45-49 (1)</summary><blockquote>

`45-49`: _⚠️ Potential issue_ | _🟡 Minor_ | _⚡ Quick win_

**`schema` is accepted but effectively ignored after first initialization.**

The current singleton cache returns the first saver forever, even if later calls pass a different schema.


<details>
<summary>💡 Suggested fix (fail fast on mixed-schema usage)</summary>

```diff
 let cached: PostgresSaver | null = null;
+let cachedSchema: string | null = null;
 let setupOnce: Promise<void> | null = null;
@@
 export function getPostgresCheckpointer(schema: string = "public"): PostgresSaver {
-  if (cached) return cached;
+  if (cached) {
+    if (cachedSchema !== schema) {
+      throw new Error(
+        `PostgresSaver already initialized with schema="${cachedSchema}", cannot switch to "${schema}"`,
+      );
+    }
+    return cached;
+  }
   cached = PostgresSaver.fromConnString(readConnectionString(), { schema });
+  cachedSchema = schema;
   return cached;
 }
@@
 export function __resetPostgresCheckpointerForTests(): void {
   cached = null;
+  cachedSchema = null;
   setupOnce = null;
 }
```
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/api/src/agents/core/checkpoint/postgresCheckpointer.ts` around lines
45 - 49, getPostgresCheckpointer currently returns a singleton PostgresSaver
(cached) and ignores subsequent schema arguments; change it to fail fast on
mixed-schema usage by checking the existing cached saver’s schema before
returning it—if cached exists and its schema (e.g., cached.schema or
cached.options.schema) does not equal the requested schema argument, throw an
error indicating mixed-schema calls are unsupported; otherwise create the saver
with PostgresSaver.fromConnString(readConnectionString(), { schema }) and set
cached as before.
```

</details>

</blockquote></details>
<details>
<summary>server/api/src/agents/graphs/wikiCompose/nodes/shared/loadPageSnapshot.ts-19-24 (1)</summary><blockquote>

`19-24`: _⚠️ Potential issue_ | _🟡 Minor_ | _⚡ Quick win_

**Make TSDoc bilingual for exported function.**

The TSDoc for the exported function `loadPageSnapshot` should include both Japanese and English text per coding guidelines.

As per coding guidelines, TSDoc/JSDoc comments should include both Japanese and English language text.




<details>
<summary>📝 Proposed bilingual TSDoc</summary>

```diff
 /**
+ * ページスナップショットを取得する。
+ *
  * Fetch a page snapshot. The function is intentionally narrow — it only reads
  * the fields the orchestrator nodes need, so it doesn't drag the full page
  * accessor service into the agent runtime.
+ *
+ * `@param` db - Database instance
+ * `@param` pageId - Target page UUID
+ * `@returns` Page snapshot with title, body, and content flag
  */
 export async function loadPageSnapshot(db: Database, pageId: string): Promise<PageSnapshot> {
```
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/api/src/agents/graphs/wikiCompose/nodes/shared/loadPageSnapshot.ts`
around lines 19 - 24, Add a bilingual (Japanese + English) TSDoc comment for the
exported function loadPageSnapshot so the documentation complies with project
guidelines; update the existing comment block above export async function
loadPageSnapshot(db: Database, pageId: string): Promise<PageSnapshot> to include
a short English description and a corresponding Japanese translation, and ensure
param and return descriptions are present in both languages referencing the db
and pageId parameters and the PageSnapshot return value.
```

</details>

</blockquote></details>
<details>
<summary>server/api/src/agents/graphs/wikiCompose/routing.ts-22-26 (1)</summary><blockquote>

`22-26`: _⚠️ Potential issue_ | _🟡 Minor_ | _⚡ Quick win_

**Add bilingual TSDoc for exported types.**

The exported type aliases `BriefRoute` and `ResearchRoute` should include bilingual TSDoc/JSDoc per coding guidelines.

As per coding guidelines, export types must include TSDoc/JSDoc documentation with both Japanese and English text.




<details>
<summary>📝 Proposed bilingual TSDoc</summary>

```diff
-/** Edge label after `human_review_brief`. */
+/**
+ * `human_review_brief` 後の遷移先ラベル。
+ *
+ * Edge label after `human_review_brief`.
+ */
 export type BriefRoute = "research" | "skip_research";

-/** Edge label after `human_review_research`. */
+/**
+ * `human_review_research` 後の遷移先ラベル。
+ *
+ * Edge label after `human_review_research`.
+ */
 export type ResearchRoute = "structure" | "conflict_resolution";
```
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/api/src/agents/graphs/wikiCompose/routing.ts` around lines 22 - 26,
Add bilingual TSDoc/JSDoc comments (English + Japanese) immediately above the
exported type aliases BriefRoute and ResearchRoute; each comment should be a
short description in both languages and use TSDoc format (/** ... */) so tooling
picks it up. Ensure the comments describe the purpose of the type (edge label
after human_review_brief and human_review_research) in English and Japanese and
remain concise.
```

</details>

</blockquote></details>
<details>
<summary>server/api/src/agents/graphs/wikiCompose/nodes/structureDialogue.ts-24-39 (1)</summary><blockquote>

`24-39`: _⚠️ Potential issue_ | _🟡 Minor_ | _⚡ Quick win_

**Add bilingual TSDoc for exported schema.**

The exported `outlineProposalSchema` should include proper TSDoc/JSDoc documentation with both Japanese and English text per coding guidelines.

As per coding guidelines, export types and interfaces (including Zod schemas used as types) must include TSDoc/JSDoc documentation with both Japanese and English text.




<details>
<summary>📝 Proposed TSDoc</summary>

```diff
-/**
- * Structured output schema. 3..10 sections, depth 1..3, each with a short
- * intent so the user can spot redundant or off-topic items at a glance.
- */
+/**
+ * アウトライン提案の structured output スキーマ。
+ *
+ * Structured output schema for outline proposal. Requires 3–10 sections,
+ * depth 1–3, each with a short intent so the user can spot redundant or
+ * off-topic items at a glance.
+ */
 export const outlineProposalSchema = z.object({
```
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/api/src/agents/graphs/wikiCompose/nodes/structureDialogue.ts` around
lines 24 - 39, Add bilingual (Japanese/English) TSDoc/JSDoc comments for the
exported Zod schema outlineProposalSchema: locate the exported symbol
outlineProposalSchema in structureDialogue.ts and add a JSDoc block immediately
above it that documents the purpose, structure (sections array, heading, depth,
intent), constraints (3..10 sections, depth 1..3, string length limits) and
usage in both Japanese and English per coding guidelines; ensure the comment is
attached to the exported const so the docs are picked up for generated types and
linters.
```

</details>

</blockquote></details>
<details>
<summary>server/api/src/agents/graphs/wikiCompose/nodes/skipResearch.ts-10-14 (1)</summary><blockquote>

`10-14`: _⚠️ Potential issue_ | _🟡 Minor_ | _⚡ Quick win_

**Make TSDoc bilingual for exported function.**

The TSDoc for the exported function `skipResearch` should include both Japanese and English text per coding guidelines.

As per coding guidelines, TSDoc/JSDoc comments should include both Japanese and English language text.




<details>
<summary>📝 Proposed bilingual TSDoc</summary>

```diff
 /**
+ * 調査をスキップして空の research outcome を返す。
+ *
  * Project a no-op research outcome so downstream Structure can run without
  * an extra HITL at `human_review_research`.
+ *
+ * `@returns` State update bypassing research with empty arrays
  */
 export async function skipResearch(): Promise<WikiComposeStateUpdate> {
```
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/api/src/agents/graphs/wikiCompose/nodes/skipResearch.ts` around lines
10 - 14, Update the TSDoc for the exported function skipResearch so it contains
both Japanese and English descriptions per guidelines: add a concise Japanese
sentence describing the same purpose as the existing English line ("Project a
no-op research outcome so downstream Structure can run without an extra HITL at
`human_review_research`") and keep the original English text; ensure the
bilingual comment sits immediately above the export async function
skipResearch() declaration and follows TSDoc/JSDoc formatting conventions.
```

</details>

</blockquote></details>
<details>
<summary>server/api/src/agents/graphs/wikiCompose/nodes/structureDialogue.ts-73-77 (1)</summary><blockquote>

`73-77`: _⚠️ Potential issue_ | _🟡 Minor_ | _⚡ Quick win_

**Add bilingual TSDoc for exported function.**

The exported function `structureDialogue` should include proper TSDoc/JSDoc documentation with both Japanese and English text per coding guidelines.

As per coding guidelines, export functions must include TSDoc/JSDoc documentation with both Japanese and English text.




<details>
<summary>📝 Proposed TSDoc</summary>

```diff
-/** `structure_dialogue` node — proposes the outline. */
+/**
+ * `structure_dialogue` ノード — アウトライン提案を生成する。
+ *
+ * Generates an outline proposal based on the brief answers and approved
+ * research sources. The LLM produces 3–10 sections optimized for the
+ * Draft phase's single-pass writing constraint.
+ *
+ * `@param` state - Current Wiki Compose orchestrator state
+ * `@param` config - LangGraph runnable config
+ * `@returns` State update with outline proposal and phase transition
+ */
 export async function structureDialogue(
```
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/api/src/agents/graphs/wikiCompose/nodes/structureDialogue.ts` around
lines 73 - 77, Add a bilingual (English + Japanese) TSDoc/JSDoc comment block
immediately above the exported function structureDialogue that describes the
function purpose, documents parameters (state: WikiComposeStateType, config:
LangGraphRunnableConfig) and the Promise<WikiComposeStateUpdate> return value,
and includes short summaries in both languages; follow existing project TSDoc
style (summary lines for EN/JP, `@param` for each arg, and `@returns`) so the export
meets the coding guidelines.
```

</details>

</blockquote></details>
<details>
<summary>server/api/src/agents/graphs/wikiCompose/nodes/humanReviewOutline.ts-20-23 (1)</summary><blockquote>

`20-23`: _⚠️ Potential issue_ | _🟡 Minor_ | _⚡ Quick win_

**Add TSDoc/JSDoc documentation for exported function.**

The exported function `humanReviewOutline` must include TSDoc/JSDoc documentation per coding guidelines. The inline comment at line 19 is insufficient—exported functions require proper documentation blocks.

As per coding guidelines, export functions must include TSDoc/JSDoc documentation, and these comments should include both Japanese and English text.




<details>
<summary>📝 Proposed TSDoc addition</summary>

```diff
-/** `human_review_outline` node — interrupt + resume projection. */
+/**
+ * `human_review_outline` ノード — アウトライン承認 HITL 処理。
+ *
+ * Halts execution at the outline interrupt, allows the user to edit the
+ * proposed outline (reorder, rename, adjust depth, add/remove sections),
+ * then validates and projects the edited outline back into state.
+ *
+ * `human_review_outline` node — outline approval HITL.
+ *
+ * `@param` state - Current Wiki Compose orchestrator state
+ * `@param` _config - LangGraph runnable config (unused)
+ * `@returns` State update with approved outline and phase transition
+ */
 export async function humanReviewOutline(
```
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/api/src/agents/graphs/wikiCompose/nodes/humanReviewOutline.ts` around
lines 20 - 23, The exported function humanReviewOutline lacks a proper
TSDoc/JSDoc block; add a documentation comment above its declaration that
describes the function in both English and Japanese, documents parameters
(state: WikiComposeStateType, _config: LangGraphRunnableConfig) and the return
type (Promise<WikiComposeStateUpdate>), and includes brief notes about behavior
and side effects per project guidelines so the exported symbol is fully
documented.
```

</details>

</blockquote></details>
<details>
<summary>server/api/src/agents/graphs/wikiCompose/nodes/shared/dispatch.ts-12-25 (1)</summary><blockquote>

`12-25`: _⚠️ Potential issue_ | _🟡 Minor_ | _⚡ Quick win_

**Add bilingual TSDoc/JSDoc for exported interfaces.**

The exported interfaces `ComposePhasePayload` and `ComposeSectionPayload` must include proper TSDoc/JSDoc documentation with both Japanese and English text per coding guidelines.

As per coding guidelines, export types and interfaces must include TSDoc/JSDoc documentation, and these comments should include both Japanese and English text.




<details>
<summary>📝 Proposed documentation</summary>

```diff
-/** Payload shape for `compose_phase` custom events. */
+/**
+ * `compose_phase` カスタムイベントのペイロード shape。
+ *
+ * Payload shape for `compose_phase` custom events.
+ */
 export interface ComposePhasePayload {
   phase: "brief" | "research" | "structure" | "draft" | "completed";
   status: "entered" | "completed";
 }

-/** Payload shape for `compose_section` custom events. */
+/**
+ * `compose_section` カスタムイベントのペイロード shape。
+ *
+ * Payload shape for `compose_section` custom events.
+ */
 export interface ComposeSectionPayload {
```
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/api/src/agents/graphs/wikiCompose/nodes/shared/dispatch.ts` around
lines 12 - 25, Add TSDoc/JSDoc comments for the exported interfaces
ComposePhasePayload and ComposeSectionPayload that include both English and
Japanese descriptions; place the bilingual comment block immediately above each
interface declaration, briefly describing the interface purpose and each field
(phase/status for ComposePhasePayload; sectionId/heading/status/index/total for
ComposeSectionPayload) in both languages and include `@remarks` or `@example` only
if needed by conventions.
```

</details>

</blockquote></details>
<details>
<summary>server/api/src/agents/graphs/wikiCompose/nodes/shared/dispatch.ts-27-41 (1)</summary><blockquote>

`27-41`: _⚠️ Potential issue_ | _🟡 Minor_ | _⚡ Quick win_

**Add bilingual TSDoc/JSDoc for exported functions.**

The exported functions `dispatchComposePhase` and `dispatchComposeSection` must include proper TSDoc/JSDoc documentation with both Japanese and English text per coding guidelines.

As per coding guidelines, export functions must include TSDoc/JSDoc documentation, and these comments should include both Japanese and English text.




<details>
<summary>📝 Proposed documentation</summary>

```diff
-/** Dispatch a `compose_phase` SSE custom event. */
+/**
+ * `compose_phase` SSE カスタムイベントを発火する。
+ *
+ * Dispatch a `compose_phase` SSE custom event.
+ *
+ * `@param` payload - Phase transition payload
+ * `@param` config - LangGraph runnable config
+ */
 export async function dispatchComposePhase(
   payload: ComposePhasePayload,
   config: LangGraphRunnableConfig,
 ): Promise<void> {
   await dispatchCustomEvent("compose_phase", payload, config);
 }

-/** Dispatch a `compose_section` SSE custom event. */
+/**
+ * `compose_section` SSE カスタムイベントを発火する。
+ *
+ * Dispatch a `compose_section` SSE custom event.
+ *
+ * `@param` payload - Section progress payload
+ * `@param` config - LangGraph runnable config
+ */
 export async function dispatchComposeSection(
```
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/api/src/agents/graphs/wikiCompose/nodes/shared/dispatch.ts` around
lines 27 - 41, Add bilingual TSDoc/JSDoc comments for the exported functions
dispatchComposePhase and dispatchComposeSection: for each exported function
(dispatchComposePhase, dispatchComposeSection) add a TSDoc block immediately
above the function that includes a short English description, a short Japanese
description, parameter descriptions for payload and config in both languages,
and the Promise<void> return description in both languages, following the
project's comment style and tag usage (e.g., `@param`, `@returns`) so the functions
comply with the export documentation guideline.
```

</details>

</blockquote></details>
<details>
<summary>server/api/src/agents/subgraphs/research/nodes/compileBatch.ts-34-39 (1)</summary><blockquote>

`34-39`: _⚠️ Potential issue_ | _🟡 Minor_ | _⚡ Quick win_

**Freeze batch payload values instead of keeping live state references.**

`ResearchBatch` is documented as a compile-time snapshot, but `queries`, `sources`, and `evaluation` currently retain references to mutable state objects.

 

<details>
<summary>💡 Proposed fix</summary>

```diff
   const batch: ResearchBatch = {
     id: randomUUID(),
     iteration: state.iteration,
-    queries: state.queries,
-    sources: state.pendingSources,
-    evaluation: state.lastEvaluation,
+    queries: state.queries.map((q) => ({ ...q, channels: [...q.channels] })),
+    sources: state.pendingSources.map((s) => ({ ...s })),
+    evaluation: state.lastEvaluation
+      ? {
+          ...state.lastEvaluation,
+          missingAspects: [...state.lastEvaluation.missingAspects],
+        }
+      : null,
     createdAt: new Date().toISOString(),
   };
```
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/api/src/agents/subgraphs/research/nodes/compileBatch.ts` around lines
34 - 39, The batch currently holds live references to mutable state
(state.queries, state.pendingSources, state.lastEvaluation) instead of a
snapshot; update the ResearchBatch construction in compileBatch.ts to freeze
those values by deep-copying them (e.g., use structuredClone or an equivalent
deep-clone) for the queries, sources and evaluation fields so the batch object
is an immutable compile-time snapshot rather than referencing the mutable state
objects. Ensure you replace direct references in the batch literal (fields
queries, sources, evaluation) with the cloned values so subsequent mutations to
state do not affect the stored ResearchBatch.
```

</details>

</blockquote></details>
<details>
<summary>server/mcp/README.ja.md-140-142 (1)</summary><blockquote>

`140-142`: _⚠️ Potential issue_ | _🟡 Minor_ | _⚡ Quick win_

**Add a language identifier to the fenced code block.**

This block is currently unlabeled and triggers markdownlint MD040.

 

<details>
<summary>💡 Suggested fix</summary>

```diff
-```
+```text
 > zedi_get_current_user を呼び出してみて
 ```
```
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @server/mcp/README.ja.md around lines 140 - 142, The fenced code block
containing the line "> zedi_get_current_user を呼び出してみて" lacks a language
identifier and triggers markdownlint MD040; fix it by adding a language tag
(e.g., "text" or "bash") after the opening backticks of that fenced block so it
becomes "text" (or "bash") to properly label the block and satisfy the
linter.


</details>

</blockquote></details>
<details>
<summary>server/mcp/README.md-140-142 (1)</summary><blockquote>

`140-142`: _⚠️ Potential issue_ | _🟡 Minor_ | _⚡ Quick win_

**Add a language to the fenced code block (MD040).**

Line 140 uses an unlabeled fenced block, which triggers markdownlint MD040.

<details>
<summary>🔧 Suggested fix</summary>

```diff
-```
+```text
 > Call zedi_get_current_user
 ```
```
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @server/mcp/README.md around lines 140 - 142, The fenced code block
containing "> Call zedi_get_current_user" is unlabeled and triggers MD040;
update that block in README.md by adding a language identifier (for example
"text" or "bash") to the opening fence so it becomes text (or bash)
followed by the existing line and the closing ```, ensuring the fenced block is
properly labeled.


</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>🧹 Nitpick comments (9)</summary><blockquote>

<details>
<summary>e2e/wiki-link-ghost-completion.spec.ts (1)</summary><blockquote>

`41-43`: _⚡ Quick win_

**Add an explicit return type to `editorLocator`.**

`editorLocator(page: Page)` should declare its return type explicitly to match the strict TypeScript guideline used in this repo.  
 

As per coding guidelines: “TypeScript must be strict; prohibit `any` type and require explicit type annotations”.

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@e2e/wiki-link-ghost-completion.spec.ts` around lines 41 - 43, The helper
function editorLocator(page: Page) lacks an explicit return type; add an
explicit Playwright Locator return type to its signature (e.g., change
editorLocator(page: Page): Locator) and ensure Locator is imported from
Playwright if not already present so the function conforms to the repo's strict
TypeScript rules; update the signature where editorLocator is defined and adjust
imports accordingly.
```

</details>

</blockquote></details>
<details>
<summary>server/api/src/agents/graphs/ingest/nodes/prepareIngest.ts (1)</summary><blockquote>

`18-23`: _⚡ Quick win_

**Add Japanese text to the exported function JSDoc.**

This TSDoc block is English-only; please include the Japanese counterpart to match repo policy.




As per coding guidelines `**/*.{ts,tsx,js,jsx}`: TSDoc/JSDoc comments and code comments should include both Japanese and English language text.

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/api/src/agents/graphs/ingest/nodes/prepareIngest.ts` around lines 18 -
23, Update the exported function's JSDoc in prepareIngest.ts to include a
Japanese translation alongside the existing English text: locate the JSDoc for
the exported function (prepareIngest) and add equivalent Japanese sentences for
the summary and any param/return descriptions so the comment contains both
English and Japanese per repo policy; preserve existing wording and formatting,
and ensure any tags (e.g., `@param`, `@returns`) also include Japanese descriptions
matching their English counterparts.
```

</details>

</blockquote></details>
<details>
<summary>server/api/src/agents/graphs/ingest/nodes/index.ts (1)</summary><blockquote>

`1-2`: _⚡ Quick win_

**Document this public nodes barrel with JA/EN TSDoc.**

Please add a brief bilingual module comment for this exported entrypoint.




As per coding guidelines `**/*.{ts,tsx,js,jsx}`: Export functions, types, and interfaces must include TSDoc/JSDoc documentation, and TSDoc/JSDoc comments and code comments should include both Japanese and English language text.

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/api/src/agents/graphs/ingest/nodes/index.ts` around lines 1 - 2, Add a
bilingual (Japanese/English) TSDoc module comment at the top of this public
barrel file that documents the exported entrypoint and purpose; reference the
exports prepareIngest and planIngest in the comment and describe in both
languages that this module re-exports those functions for ingest node
orchestration. Ensure the comment uses TSDoc/JSDoc syntax (/** ... */) and
briefly states the module responsibility in JA and EN so it satisfies the
export/documentation guideline.
```

</details>

</blockquote></details>
<details>
<summary>server/api/src/agents/graphs/ingest/nodes/planIngest.ts (1)</summary><blockquote>

`36-38`: _⚡ Quick win_

**Make the exported function JSDoc bilingual (JA/EN).**

The function TSDoc is currently English-only; please add a Japanese counterpart line.




As per coding guidelines `**/*.{ts,tsx,js,jsx}`: TSDoc/JSDoc comments and code comments should include both Japanese and English language text.

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/api/src/agents/graphs/ingest/nodes/planIngest.ts` around lines 36 -
38, The JSDoc above the exported function that produces an IngestPlan via
ZediChatModel is English-only; add a Japanese equivalent sentence to the comment
block so the TSDoc is bilingual. Locate the JSDoc that references IngestPlan and
ZediChatModel in planIngest.ts (the comment immediately above the exported
function that produces the plan) and add a Japanese line mirroring the English
description (for example: "研究完了後にZediChatModelを使用してIngestPlanを生成します。"), and
likewise add Japanese lines for any `@param/`@returns descriptions if present so
all doc lines include both JA and EN.
```

</details>

</blockquote></details>
<details>
<summary>server/api/src/agents/graphs/ingest/index.ts (1)</summary><blockquote>

`1-17`: _⚡ Quick win_

**Add a bilingual module JSDoc for this public barrel.**

This file exports public graph API but currently has no TSDoc/JSDoc header. Please add a short JA/EN module comment.




As per coding guidelines `**/*.{ts,tsx,js,jsx}`: Export functions, types, and interfaces must include TSDoc/JSDoc documentation, and TSDoc/JSDoc comments and code comments should include both Japanese and English language text.

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/api/src/agents/graphs/ingest/index.ts` around lines 1 - 17, Add a
bilingual (Japanese/English) module JSDoc header to this public barrel file
describing its purpose and the public exports (e.g., INGEST_PLANNER_GRAPH_ID,
INGEST_PLANNER_GRAPH_VERSION, registerIngestPlannerGraph, IngestPlannerState,
IngestPlannerStateType, IngestPlannerStateUpdate, and the exported types
IngestAction, IngestPlan, IngestConflict, CandidatePage, IngestArticleSummary).
The comment should be a short two-language summary (JA then EN) stating that
this module re-exports the ingest planner graph API and its state/types, and
follow project TSDoc/JSDoc format (/** ... */) so linters and docs pick it up.
```

</details>

</blockquote></details>
<details>
<summary>server/api/src/agents/graphs/wikiMaintenance/nodes/planMaintenance.ts (1)</summary><blockquote>

`7-9`: _⚡ Quick win_

**Add symbol-level bilingual JSDoc for exported `planMaintenance`.**

Line 7 exports a public function, but documentation is only file-level. Please add a direct JA/EN TSDoc block above the function.

 

<details>
<summary>📝 Proposed fix</summary>

```diff
+/**
+ * Aggregate scan findings into a single maintenance plan and advance phase.
+ * スキャン結果を 1 つのメンテナンス計画に集約し、フェーズを進める。
+ */
 export async function planMaintenance(
   state: WikiMaintenanceStateType,
 ): Promise<WikiMaintenanceStateUpdate> {
```
</details>

As per coding guidelines `**/*.{ts,tsx,js,jsx}`: Export functions, types, and interfaces must include TSDoc/JSDoc documentation, and TSDoc/JSDoc comments should include both Japanese and English language text.

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/api/src/agents/graphs/wikiMaintenance/nodes/planMaintenance.ts` around
lines 7 - 9, Add a symbol-level bilingual (JA/EN) TSDoc/JSDoc block directly
above the exported function planMaintenance that documents its purpose,
parameters and return type; mention the parameter type WikiMaintenanceStateType
and the return type Promise<WikiMaintenanceStateUpdate> in both Japanese and
English, include short descriptions for what the function does and what the
caller can expect, and ensure the comment follows existing TSDoc style used
elsewhere in the repo.
```

</details>

</blockquote></details>
<details>
<summary>server/api/src/agents/subgraphs/research/nodes/humanReviewResearch.ts (1)</summary><blockquote>

`20-26`: _⚡ Quick win_

**Make the exported payload TSDoc bilingual (EN/JA) for policy consistency.**

This block is currently English-only while nearby node docs are bilingual.

 

As per coding guidelines `**/*.{ts,tsx,js,jsx}`: TSDoc/JSDoc comments and code comments should include both Japanese and English language text to align with project tone.

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/api/src/agents/subgraphs/research/nodes/humanReviewResearch.ts` around
lines 20 - 26, Update the TSDoc block for the exported payload (the comment
above the payload passed to interrupt() and referenced as
SseInterruptEvent.payload) to include a Japanese translation alongside the
existing English text; keep the same technical details and safety note but add a
concise Japanese equivalent for each sentence so the comment is bilingual
(EN/JA) and matches nearby node docs and project guidelines.
```

</details>

</blockquote></details>
<details>
<summary>server/api/src/agents/subgraphs/research/nodes/shared/dispatchSseCustom.ts (1)</summary><blockquote>

`11-58`: _⚡ Quick win_

**Add per-export bilingual TSDoc for public wrappers and payload types.**

Several exported declarations are documented only in one language or only via a shared block; please add explicit JP/EN TSDoc on each exported interface/function for consistent API-level specs.



As per coding guidelines `**/*.{ts,tsx,js,jsx}`: Export functions, types, and interfaces must include TSDoc/JSDoc documentation and `**/*.{ts,tsx,js,jsx}`: TSDoc/JSDoc comments and code comments should include both Japanese and English language text.

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/api/src/agents/subgraphs/research/nodes/shared/dispatchSseCustom.ts`
around lines 11 - 58, Add explicit bilingual (Japanese + English) TSDoc comments
for each exported symbol so every public type and function has its own JP/EN
documentation block: add comments above ResearchIterationPayload,
ResearchEvaluationPayload, ResearchBatchPayload, dispatchResearchIteration,
dispatchResearchEvaluation, and dispatchResearchBatch describing purpose,
fields/parameters, and return value in both languages. Keep the content concise,
mirror existing style used elsewhere in the repo (short JP sentence then short
EN sentence), and ensure each exported interface documents each field and each
exported function documents its payload and config parameters and Promise<void>
return.
```

</details>

</blockquote></details>
<details>
<summary>server/api/src/agents/subgraphs/research/shouldRefine.ts (1)</summary><blockquote>

`6-13`: _⚡ Quick win_

**Add English text to the exported predicate’s TSDoc.**

Please make this function-level TSDoc bilingual (JP/EN) to match the project documentation tone for public exports.



As per coding guidelines `**/*.{ts,tsx,js,jsx}`: Export functions, types, and interfaces must include TSDoc/JSDoc documentation and `**/*.{ts,tsx,js,jsx}`: TSDoc/JSDoc comments and code comments should include both Japanese and English language text.

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/api/src/agents/subgraphs/research/shouldRefine.ts` around lines 6 -
13, The TSDoc for the exported function shouldRefine currently exists only in
Japanese; update it to include both Japanese and English descriptions — mention
what the function does (termination check called immediately after
evaluate_sufficiency), explain the return values ("compile" when score >= 0.75
or iteration >= maxIterations, otherwise "refine"), and document the parameter
type ResearchLoopStateType and return union type ("refine" | "compile") in both
languages so the exported predicate has bilingual documentation consistent with
project guidelines.
```

</details>

</blockquote></details>

</blockquote></details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

Comment thread .github/actions/setup-toolchain/action.yml
Comment thread .github/workflows/ci.yml
Comment on lines +26 to +30
uses: Wandalen/wretry.action@v3
with:
bun-version: "1.3"
action: actions/checkout@v6.0.2
attempt_limit: 3
attempt_delay: 5000

@coderabbitai coderabbitai Bot May 25, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# List workflow files
echo "=== Workflow files ==="
ls -1 .github/workflows 2>/dev/null || true

echo
echo "=== Wandalen/wretry.action uses across workflows ==="
rg -n --hidden --no-ignore -S "Wandalen/wretry\.action@"
  .github/workflows || true

echo
echo "=== .github/workflows/ci.yml excerpt around lines 20-120 ==="
if [ -f .github/workflows/ci.yml ]; then
  sed -n '1,140p' .github/workflows/ci.yml | nl -ba | sed -n '1,140p'
fi

echo
echo "=== .github/workflows/ci.yml excerpt around lines 120-460 ==="
if [ -f .github/workflows/ci.yml ]; then
  sed -n '120,520p' .github/workflows/ci.yml | nl -ba | sed -n '1,520p'
fi

echo
echo "=== Check whether any action ref for Wandalen/wretry.action is pinned to a SHA ==="
# If ref looks like full SHA (40-hex) consider pinned; otherwise report.
rg -n --hidden --no-ignore -S "Wandalen/wretry\.action@([0-9a-f]{40}|[0-9a-f]{7,40})" .github/workflows || true

Repository: otomatty/zedi

Length of output: 3541


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Unique Wandalen/wretry.action refs in .github/workflows/ci.yml ==="
rg -n --hidden --no-ignore -S "uses:\s*Wandalen/wretry\.action@" .github/workflows/ci.yml \
  | sed -E 's/.*uses:\s*(Wandalen\/wretry\.action@[^[:space:]]+).*/\1/' \
  | sort -u || true

echo
echo "=== Exact uses in .github/workflows/ci.yml (line-numbered) ==="
rg -n --hidden --no-ignore -S "uses:\s*Wandalen/wretry\.action@" .github/workflows/ci.yml || true

echo
echo "=== Snippets for the originally cited ranges in .github/workflows/ci.yml ==="
for r in "1-40" "41-80" "81-120" "121-170" "171-220" "221-280" "281-340" "341-420" "401-430"; do
  start=${r%-*}; end=${r#*-}
  echo "--- ci.yml $start-$end ---"
  sed -n "${start},${end}p" .github/workflows/ci.yml | cat -n
  echo
done

echo "=== Any SHA-pinned Wandalen/wretry.action usage in the whole repo? ==="
# report any ref that looks like a full 40-hex commit
rg -n --hidden --no-ignore -S "uses:\s*Wandalen/wretry\.action@([0-9a-f]{40})" .github/workflows .github/actions || true

Repository: otomatty/zedi

Length of output: 20044


SHA-pin Wandalen/wretry.action in .github/workflows/ci.yml

All uses: Wandalen/wretry.action@v3 entries in this workflow use a mutable tag (not an immutable commit SHA), including at lines: 26, 49, 66, 94, 138, 197, 227, 261, 298, 322, 360, 400. Pin each to the specific commit SHA to prevent supply-chain drift.

🧰 Tools
🪛 zizmor (1.25.2)

[error] 26-26: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci.yml around lines 26 - 30, Replace every mutable tag
reference to Wandalen/wretry.action@v3 with the action pinned to its immutable
commit SHA (e.g., Wandalen/wretry.action@<commit-sha>) for each occurrence of
"uses: Wandalen/wretry.action@v3" so the workflow cannot drift; update all
instances (the repeated "uses: Wandalen/wretry.action@v3" entries) to the same
verified commit SHA, committing the updated workflow once you have looked up the
correct SHA for the v3 release.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

同上(#974 スコープ外)。ci.ymlWandalen/wretry.action SHA pin は別 PR で対応予定です。

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@otomatty 了解しました。別 PR での対応で問題ありません。フォローアップ用に GitHub Issue を作成しましょうか?


🧠 Learnings used
Learnt from: otomatty
Repo: otomatty/zedi PR: 785
File: .github/workflows/dependabot-bun-lock.yml:101-109
Timestamp: 2026-04-27T05:29:23.690Z
Learning: For CI GitHub Actions workflows that run Bun (Bun v1.3.11+), prefer `bun install --no-summary` over `bun install --silent` when you still need error and warning visibility. `--silent` suppresses all logging (including errors and warnings), while `--no-summary` only removes the install summary and keeps progress output plus errors and warnings.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

お願いします。

Comment on lines +34 to +35
await page.waitForTimeout(1500);
}

@coderabbitai coderabbitai Bot May 25, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Replace fixed sleeps with state-based waits to reduce E2E flakiness.

Repeated waitForTimeout(...) calls make this suite timing-sensitive under CI variance. Prefer waiting on concrete UI/network states (e.g., candidate presence, save completion signal, or specific locator assertions) instead of fixed delays.

Also applies to: 62-63, 79-80, 100-101, 121-122, 138-139, 161-162, 184-185, 205-206

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@e2e/wiki-link-ghost-completion.spec.ts` around lines 34 - 35, Replace the
fixed sleep calls (page.waitForTimeout(...)) with deterministic, state-based
waits: identify the UI or network event the test is waiting for (e.g.,
suggestion list population, save completion, specific element visibility) and
use page.waitForSelector / locator.waitFor / page.waitForResponse or Playwright
expect assertions against the relevant locators instead of page.waitForTimeout;
update each occurrence of page.waitForTimeout in this spec (including the listed
lines) to wait for the concrete signal (candidate presence, a "saved" indicator,
response URL/status, or locator count/text) so tests await the actual state
change rather than a fixed delay.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

今回の #974 スコープ外です。E2E の waitForTimeout 置換は大規模 refactor のため、現状 CI green を維持しつつ別途対応します。

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@otomatty、了解しました。waitForTimeout の置換はスコープ外として対応を保留していただきます。

フォローアップとして、このリファクタリングを追跡するための GitHub Issue を作成しましょうか?

(ง •̀_•́)ง


🧠 Learnings used
Learnt from: otomatty
Repo: otomatty/zedi PR: 465
File: packages/claude-sidecar/src/handlers/query.ts:109-123
Timestamp: 2026-04-02T06:02:33.826Z
Learning: `anthropic-ai/claude-agent-sdk` の `query()` で使う `Options` 型には、`cwd`, `maxTurns`, `includePartialMessages`, `permissionMode`, `resume`, `abortController`, `allowedTools`, `settingSources` が含まれます。コードレビュー時に、これらのフィールドを「SDK 非互換(存在しない/無効なオプション)」として誤検知しないでください。実際に `Options` と整合していれば、その前提で判定してください。

Learnt from: otomatty
Repo: otomatty/zedi PR: 604
File: src/pages/IndexPage.tsx:58-74
Timestamp: 2026-04-17T07:12:27.068Z
Learning: In otomatty/zedi, ESLint’s findings may differ between the review sandbox and the repository’s pinned `eslint-plugin-react-hooks7.0.1`. Before flagging an issue from `eslint-plugin-react-hooks` (notably `react-hooks/set-state-in-effect`), confirm the violation matches the behavior of the project’s actual pinned plugin version. If the sandbox is running a newer plugin (e.g., v7.1.0) that detects indirect setState via intermediate `useCallback` references, treat sandbox-only differences as potential false positives and verify against the pinned dependency before raising the review concern.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

お願いします。

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@otomatty、イシューを作成しました 🎉

#977refactor(e2e): Replace waitForTimeout with state-based waits in wiki-link-ghost-completion.spec.ts

対象の waitForTimeout 箇所(Lines 34–35, 62–63, 79–80, 100–101, 121–122, 138–139, 161–162, 184–185, 205–206)をすべて記載し、@otomatty さんにアサインしました。タイミングが合ったときに対応いただければ幸いです!


🧠 Learnings used
Learnt from: otomatty
Repo: otomatty/zedi PR: 465
File: packages/claude-sidecar/src/handlers/query.ts:109-123
Timestamp: 2026-04-02T06:02:33.826Z
Learning: `anthropic-ai/claude-agent-sdk` の `query()` で使う `Options` 型には、`cwd`, `maxTurns`, `includePartialMessages`, `permissionMode`, `resume`, `abortController`, `allowedTools`, `settingSources` が含まれます。コードレビュー時に、これらのフィールドを「SDK 非互換(存在しない/無効なオプション)」として誤検知しないでください。実際に `Options` と整合していれば、その前提で判定してください。

Learnt from: otomatty
Repo: otomatty/zedi PR: 604
File: src/pages/IndexPage.tsx:58-74
Timestamp: 2026-04-17T07:12:27.068Z
Learning: In otomatty/zedi, ESLint’s findings may differ between the review sandbox and the repository’s pinned `eslint-plugin-react-hooks7.0.1`. Before flagging an issue from `eslint-plugin-react-hooks` (notably `react-hooks/set-state-in-effect`), confirm the violation matches the behavior of the project’s actual pinned plugin version. If the sandbox is running a newer plugin (e.g., v7.1.0) that detects indirect setState via intermediate `useCallback` references, treat sandbox-only differences as potential false positives and verify against the pinned dependency before raising the review concern.

Comment on lines +2 to +3
# 後方互換ラッパー。実体はグローバル Skill に移行済み。
exec "${DELETE_MERGED_BRANCHES_SCRIPT:-$HOME/.cursor/skills/delete-merged-branches/scripts/delete-merged-branches.sh}" "$@"

@coderabbitai coderabbitai Bot May 25, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Keep the wrapper runnable when the global Skill path is missing.

Direct exec to a user-local path can hard-fail on fresh dev/CI environments. Add an executable check and clear error before exec.

🛠️ Proposed fix
 #!/usr/bin/env bash
 # 後方互換ラッパー。実体はグローバル Skill に移行済み。
-exec "${DELETE_MERGED_BRANCHES_SCRIPT:-$HOME/.cursor/skills/delete-merged-branches/scripts/delete-merged-branches.sh}" "$@"
+TARGET="${DELETE_MERGED_BRANCHES_SCRIPT:-$HOME/.cursor/skills/delete-merged-branches/scripts/delete-merged-branches.sh}"
+if [[ ! -x "$TARGET" ]]; then
+  echo "delete-merged-branches: target script not found or not executable: $TARGET" >&2
+  echo "Set DELETE_MERGED_BRANCHES_SCRIPT to a valid path." >&2
+  exit 1
+fi
+exec "$TARGET" "$@"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# 後方互換ラッパー。実体はグローバル Skill に移行済み。
exec "${DELETE_MERGED_BRANCHES_SCRIPT:-$HOME/.cursor/skills/delete-merged-branches/scripts/delete-merged-branches.sh}" "$@"
#!/usr/bin/env bash
# 後方互換ラッパー。実体はグローバル Skill に移行済み。
TARGET="${DELETE_MERGED_BRANCHES_SCRIPT:-$HOME/.cursor/skills/delete-merged-branches/scripts/delete-merged-branches.sh}"
if [[ ! -x "$TARGET" ]]; then
echo "delete-merged-branches: target script not found or not executable: $TARGET" >&2
echo "Set DELETE_MERGED_BRANCHES_SCRIPT to a valid path." >&2
exit 1
fi
exec "$TARGET" "$@"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/delete-merged-branches.sh` around lines 2 - 3, The wrapper currently
does a hard exec of
"${DELETE_MERGED_BRANCHES_SCRIPT:-$HOME/.cursor/skills/delete-merged-branches/scripts/delete-merged-branches.sh}"
which will fail on fresh environments; modify the script to first test that the
resolved script path exists and is executable (use the same expansion of
DELETE_MERGED_BRANCHES_SCRIPT and the fallback "$HOME/.cursor/skills/..." to
resolve the target), and if not executable print a clear, non-cryptic message to
stderr (e.g., "delete-merged-branches script not found or not executable;
skipping") and exit cleanly (non-error) so CI/dev runs aren’t hard-failed; only
call exec if the test passes.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

今回の #974 スコープ外です。グローバル Skill パス向けラッパー改善は dev ツール系のため、リリース blocker とは切り分けています。

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@otomatty、了解しました。今回のリリーススコープからは外していただいて問題ありません。

フォローアップとして、このラッパー改善を追跡するための GitHub Issue を作成しましょうか?

(ˆ·ω·ˆ)

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

お願いします。

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@otomatty、Issue を作成しました!

👉 #978 – scripts/delete-merged-branches.sh: add existence/executable guard before exec
#978

あなたにアサインしてあります。このリリースが落ち着いたタイミングで対応いただければ大丈夫です。

(ˆ·ω·ˆ)

Comment thread SECURITY.ja.md
Comment on lines +19 to +21
1. **メールで報告**: security@example.com(プロジェクトのセキュリティ連絡先に置き換えてください)
2. **GitHub Security Advisories**: リポジトリの Security タブから Private vulnerability reporting を使用

@coderabbitai coderabbitai Bot May 25, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Replace placeholder security contact before release.

security@example.com is a placeholder and leaves vulnerability reporters without a real channel. Publish a real monitored address (or remove email and rely on GitHub private reporting only).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@SECURITY.ja.md` around lines 19 - 21, The SECURITY contact currently uses the
placeholder address "security@example.com"; replace that placeholder with a
real, monitored security reporting email (or remove the email line and
explicitly state reliance on GitHub Private vulnerability reporting) and ensure
the Japanese text and numbering remain consistent; update any related mention in
the file (the line containing "security@example.com") so the release contains a
valid, monitored reporting channel.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

今回の #974 スコープ外です。security@example.com は運用判断(実メール vs GitHub Private Reporting のみ)が必要なため、別途対応します。

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@otomatty、了解です。運用方針が決まり次第対応いただければ問題ありません。追跡用にフォローアップ Issue を作成しましょうか?

( ˘•ω•˘ ).。oO

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

お願いします。

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@otomatty、フォローアップ Issue を作成しました 🎉

#979#979

Issue には以下の内容を記載しています:

  • 実メールアドレスへの置き換え または メール行を削除して GitHub Private Vulnerability Reporting のみを案内する、の2択
  • 更新対象ファイル(SECURITY.md / SECURITY.ja.md
  • 英日ペアの同期を忘れないよう注記

ご都合の良いタイミングで対応いただければ大丈夫です 🐇

Comment thread server/api/src/agents/subgraphs/research/resumeSchema.ts Outdated
Comment thread server/api/src/routes/composeSessionProjection.ts
Comment thread server/api/src/services/wikiSearchService.ts Outdated
Comment thread server/api/src/services/wikiSearchService.ts
* fix(api): address PR #972 review findings for release readiness

Correct migration FK targets (`user` not `users`), unblock BYOK session
creation, and harden compose projection, SSE mapping, and resume validation.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(api): address PR #974 review comments on streaming billing

Bill streaming usage only on successful done chunks, skip DB writes on
provider errors and incomplete streams, and sync bilingual TSDoc.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(api): restore rows[0] guard for strict TypeScript narrowing

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
cursoragent and others added 3 commits May 26, 2026 01:12
…dels

- plan_ingest used getOrchestratorModelId(), breaking user_* backends after
  research nodes already resolved models via resolveComposeModelId.
- Reject POST /graph/run on interrupted ingest threads; require /graph/resume.
- Reject POST /compose-sessions/:id/run on interrupted rows; stop client
  needsStream fallback that replayed fresh input on a suspended checkpoint.
Align test fixture with IngestPlannerState after rebase onto develop.

Co-authored-by: Cursor <cursoragent@cursor.com>
…dels (#973)

fix(api): guard HITL checkpoints and align ingest plan_ingest BYOK models
@railway-app railway-app Bot temporarily deployed to Zedi / development May 25, 2026 16:23 Inactive
@otomatty otomatty merged commit a75d699 into main May 25, 2026
24 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants