Conversation
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>
- 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 reviews are paused for this user.Troubleshooting steps vary by plan Learn more → On a Teams plan? Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center? |
|
Warning Review limit reached
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 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 configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (21)
📝 WalkthroughWalkthroughAdds 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. ChangesCompose Orchestration + BYOK Integration
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 }
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Possibly related PRs
Suggested labels
Poem
✨ Finishing Touches🧪 Generate unit tests (beta)
|
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
💡 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".
There was a problem hiding this comment.
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 winRemove 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 winSpecify 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 winFix 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 winSet a language for the fenced project-structure block.
Use a language label like
texton 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 winFix 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 winAdd a language tag to the project-structure fenced block.
The fence starting at Line 311 is unlabeled; use
textto 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 winAdd 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.mdaround 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., changetotext) 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.mdaround 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.mdaround 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 becomestext (orbash)
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 -->
| uses: Wandalen/wretry.action@v3 | ||
| with: | ||
| bun-version: "1.3" | ||
| action: actions/checkout@v6.0.2 | ||
| attempt_limit: 3 | ||
| attempt_delay: 5000 |
There was a problem hiding this comment.
🧩 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 || trueRepository: 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 || trueRepository: 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.
There was a problem hiding this comment.
同上(#974 スコープ外)。ci.yml の Wandalen/wretry.action SHA pin は別 PR で対応予定です。
There was a problem hiding this comment.
@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.
| await page.waitForTimeout(1500); | ||
| } |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
今回の #974 スコープ外です。E2E の waitForTimeout 置換は大規模 refactor のため、現状 CI green を維持しつつ別途対応します。
There was a problem hiding this comment.
@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.
There was a problem hiding this comment.
@otomatty、イシューを作成しました 🎉
#977 — refactor(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.
| # 後方互換ラッパー。実体はグローバル Skill に移行済み。 | ||
| exec "${DELETE_MERGED_BRANCHES_SCRIPT:-$HOME/.cursor/skills/delete-merged-branches/scripts/delete-merged-branches.sh}" "$@" |
There was a problem hiding this comment.
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.
| # 後方互換ラッパー。実体はグローバル 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.
There was a problem hiding this comment.
今回の #974 スコープ外です。グローバル Skill パス向けラッパー改善は dev ツール系のため、リリース blocker とは切り分けています。
There was a problem hiding this comment.
@otomatty、了解しました。今回のリリーススコープからは外していただいて問題ありません。
フォローアップとして、このラッパー改善を追跡するための GitHub Issue を作成しましょうか?
(ˆ·ω·ˆ)
There was a problem hiding this comment.
@otomatty、Issue を作成しました!
👉 #978 – scripts/delete-merged-branches.sh: add existence/executable guard before exec
#978
あなたにアサインしてあります。このリリースが落ち着いたタイミングで対応いただければ大丈夫です。
(ˆ·ω·ˆ)
| 1. **メールで報告**: security@example.com(プロジェクトのセキュリティ連絡先に置き換えてください) | ||
| 2. **GitHub Security Advisories**: リポジトリの Security タブから Private vulnerability reporting を使用 | ||
|
|
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
今回の #974 スコープ外です。security@example.com は運用判断(実メール vs GitHub Private Reporting のみ)が必要なため、別途対応します。
There was a problem hiding this comment.
@otomatty、了解です。運用方針が決まり次第対応いただければ問題ありません。追跡用にフォローアップ Issue を作成しましょうか?
( ˘•ω•˘ ).。oO
There was a problem hiding this comment.
@otomatty、フォローアップ Issue を作成しました 🎉
#979 → #979
Issue には以下の内容を記載しています:
- 実メールアドレスへの置き換え または メール行を削除して GitHub Private Vulnerability Reporting のみを案内する、の2択
- 更新対象ファイル(
SECURITY.md/SECURITY.ja.md) - 英日ペアの同期を忘れないよう注記
ご都合の良いタイミングで対応いただければ大丈夫です 🐇
* 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>
…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
概要
developブランチに蓄積された変更をmainへマージします。develop の HEAD (71e2b627) をmainに取り込むためのリリース PR です(56 コミット、271 ファイル)。変更点
server/api/composeSessionsAPI、Postgres checkpointer、SSE マッピングsrc/server/api/drizzle/0031_add_wiki_compose_sessions.sql、0032_add_user_ai_credentials.sqlserver/api/.env.exampleUSER_AI_CREDENTIALS_ENCRYPTION_KEY(BYOK 資格情報の at-rest 暗号化).github/setup-toolchaincomposite action、CI / deploy ワークフロー更新.ja.mdペア(README / CONTRIBUTING / SECURITY / DOCUMENTATION 等)、check-doc-pairs.mjse2e/変更の種類
テスト方法
USER_AI_CREDENTIALS_ENCRYPTION_KEYを API サービスに設定すること(Wiki Compose BYOK 利用時)0031/0032がdeploy-prod.ymlで適用されることチェックリスト
.ja.mdペア)マージ方法
Create a merge commit でマージしてください(
develop→mainのリリース PR 標準)。デプロイ時の注意
0031_add_wiki_compose_sessions.sql、0032_add_user_ai_credentials.sqlUSER_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
Documentation
Infrastructure