Conversation
chore: sync main to develop
- Add is_system_default column to ai_models with migration - Resolve model access with fallback chain on chat API - Expose systemDefaultModelId from GET /api/ai/models - Admin UI to set system default model per tier - Client uses system default when user selection is unavailable
- Reject mixed PATCH fields with isSystemDefault=true - Clear system default flag when deactivating a model - Only map known no-model resolver errors to 503 - Return resolved modelId/didFallback in chat responses - Atomic validation in setSystemDefaultModel transaction - Serialize admin set-default requests; fix test fixtures
…eef9 feat(ai): add system default model with admin config and fallback
* feat(wiki-compose): auto-select backend from AI settings When opening Wiki Compose from the Wiki generate button, pre-select the execution backend that matches the provider chosen in Settings → AI. api_server maps to zedi_managed; user_api_key maps to the matching user_* backend when server BYOK credentials exist, otherwise falls back to zedi_managed. Co-authored-by: Akimasa Sugai <otomatty@users.noreply.github.com> * fix(wiki-compose): ignore stale AI settings sync responses Use a monotonic load generation counter so concurrent loadComposeBackendFromSettings calls cannot apply out-of-order results. 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>
* feat(wiki-compose): add Japanese UI and localized LLM output - Pass contentLocale from the client and resolve via Accept-Language on the API - Append locale instructions to Brief, research, structure, and draft prompts - Localize conflict-resolution copy and structure fallback outlines - Wire wikiCompose i18n keys through the Compose split-screen UI Co-authored-by: Akimasa Sugai <otomatty@users.noreply.github.com> * fix(wiki-compose): persist contentLocale and fix API typecheck - Store contentLocale in session metadata on first run; reuse on resume/GET - Parse Accept-Language with q-values via invitationService helper - Default getGraphContext fallback to ja; preserve null/undefined in strip helper - Add contentLocale to GraphContext test fixtures and ingest graph routes Co-authored-by: Akimasa Sugai <otomatty@users.noreply.github.com> * fix(wiki-compose): atomically persist contentLocale on session claim Combine running status and metadata locale into one update so a failed metadata write cannot strand the session in running without locale data. 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>
…986) * fix(wiki-compose): remove execution backend picker from compose flow Wiki Compose now resolves the execution backend from AI settings (same as Settings → AI) and starts automatically. The redundant backend selector and manual Start Compose step are removed. Co-authored-by: Akimasa Sugai <otomatty@users.noreply.github.com> * fix(wiki-compose): address auto-start race and add retry on failure - Always set isResolved after any successful backend load (fixes settings change during initial fetch leaving compose stuck) - Show Retry when session creation fails after removing manual start 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>
…#989) * feat(nav): replace mobile bottom-nav Account sheet with /account page The mobile bottom navigation's Account tab opened a side Sheet, which broke the back-button / deep-link consistency that the other primary tabs (My Note, Notes, AI) provide via plain page navigation. - Add a new `/account` route that reuses `SignedInMenuContent` and `SignedOutMenuContent` from the header avatar menu, so the account surface stays the single source of truth. - Convert the bottom-nav Account tab from a Sheet trigger into a `<Link to="/account">`, preserving the avatar visual and sync-status dot, and adding `aria-current="page"` when on the route. - Delete the now-unused `BottomNavMeContent` re-export shim. - Update / add tests for the new behavior. The mobile header avatar still opens its quick-access Sheet on purpose; collapsing it to navigate to /account as well can be a follow-up. * refactor(nav): simplify Account-tab active check and hoist noopClose Address review feedback from gemini-code-assist: - BottomNav: replace the single-pattern matchPath() loop with a direct pathname === "/account" comparison. The Account tab has no nested routes, so matchPath was just compiling a regex for one literal. - Account page: hoist the no-op onClose callback to module scope so we skip useCallback hook overhead for a function that never changes. --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com>
* fix(api): pin Wiki Compose LLM to google:gemini-3.5-flash Wiki Compose orchestrator, research, draft, and web_search now resolve a single fixed ai_models.id (google:gemini-3.5-flash) instead of provider-specific fallbacks. Ingest planner keeps resolveComposeModelId. Co-authored-by: Akimasa Sugai <otomatty@users.noreply.github.com> * fix(api): reject incompatible BYOK backends for fixed Gemini compose - assertComposeBackendReady: only zedi_managed or user_google for wiki-compose graphs - Export resolveActiveWikiComposeModelId; reuse in web_search resolver - Address review: bilingual JSDoc, BYOK preflight tests Co-authored-by: Akimasa Sugai <otomatty@users.noreply.github.com> * fix(api): restore tierClause in web search fallback path 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>
#992) * refactor(wiki-compose): apply thermo-nuclear review fixes - Align frontend backend resolution with Google-fixed Wiki Compose model - Extract session reducer module; slim useWikiComposeSession hook - Consolidate auto-start via startPolicy and canRetryStart - Deduplicate compose session locale prep on API routes - Remove duplicate props and dead outline preview ternary Co-authored-by: Akimasa Sugai <otomatty@users.noreply.github.com> * fix(wiki-compose): address PR review on auto-start and retry - Stop aborting SSE when session state updates after auto-start (Codex P1) - Allow canRetryStart for any fresh-compose auto-start failure - Guard outline mapping in resume reducer against invalid sections - Add bilingual JSDoc on ComposeRunLocalePrep 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>
* feat(notes): refresh my notes list with sections and pin Replace the flat card grid on /notes with a metadata-focused list: pinned (default + user pins), recent, and all sections with search and sort. Add localStorage-backed pin toggles and align NoteTitleSwitcher to show pinned + recent notes only. Co-authored-by: Akimasa Sugai <otomatty@users.noreply.github.com> * fix(notes): address PR review for list UI Use Link rows for middle-click support, null-safe titles, in-tab pin sync via custom event, aria-pressed on sort toggles, and restore switcher dropdown links with asChild. Co-authored-by: Akimasa Sugai <otomatty@users.noreply.github.com> * fix(notes): address remaining PR review on pins and docs Show pin controls on compact/mobile rows, strip default note id from persisted user pins when resolved, guard togglePin for default note, and add bilingual TSDoc for exported list types. Co-authored-by: Akimasa Sugai <otomatty@users.noreply.github.com> * fix(notes): keep togglePin side effects outside state updater Move localStorage writes and pin-changed events out of the setStoredPinnedIds functional updater so Strict Mode cannot double-apply side effects. 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>
* fix(editor): reserve bottom inset for mobile floating input bar Add dynamic padding-bottom on the Tiptap editor body so the last line stays above the fixed Wiki Link bar. When the virtual keyboard is visible, include the visualViewport offset so the bar lifted above the keyboard does not cover the document tail. * refactor(editor): compute floating bar inset in CSS Address review: pass keyboard offset as a CSS variable and include safe-area and bottom-nav when the keyboard is closed, matching the floating bar wrapper padding. --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com>
* fix(notes): make note settings layout responsive on mobile - Stack header and full-width back link on narrow viewports - Sticky horizontal section nav with hidden scrollbar below md - Responsive grids for invite/member/domain forms and list rows - Full-width primary actions on mobile in settings sections * fix(notes): restore desktop sticky sidebar and simplify save button rows Address review: drop md:static so aside stays sticky on md+, use flex sm:justify-end for single-button action rows instead of flex-col-reverse. --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com>
* perf(web): メモ化で不要な再レンダリング/再計算を削減 - WikiLinkSuggestion: getItems を useCallback+毎回呼び出しから useMemo へ 変更し、補完中のキーストロークごとの O(n) フィルタ走査を抑制 - AIChat/HeaderActions/GlobalSearch の各 Context value を useMemo 化し、 Provider 再レンダリングによる子孫の一律再レンダリングを回避 - McpServerSettings: ストア全体購読を個別セレクタ購読へ変更 https://claude.ai/code/session_01XgbeNj9c8fk6Tyg1JgioDU * perf(web): エディタの onChange を debounce してキーストローク毎の負荷を削減 入力ごとに document 全体を JSON.stringify し setEditorContent で親を 再レンダリングしていた処理を 300ms debounce にまとめる。本文の永続化は 協調編集 (Yjs/Hocuspocus) 経由で別途行われ、editorContent は AI 文脈や エクスポートなど派生用途のみに使われるため遅延の影響はない。既存の useDebouncedCallback を再利用。 https://claude.ai/code/session_01XgbeNj9c8fk6Tyg1JgioDU * perf(hocuspocus): グラフ同期 HTTP をページ単位でコアレッシング 保存ごとに triggerGraphSync を fire-and-forget していたため、連続保存で 同一ページのグラフ再構築 HTTP が重複起動しうる。coalescePerKey で in-flight 中の追加要求を 1 件の追走に集約し、1 ページあたり「実行中 1 + 待機 1」に 収束させる。汎用コアレッサは純粋関数として切り出し、単体テストを追加。 https://claude.ai/code/session_01XgbeNj9c8fk6Tyg1JgioDU * perf(api): 未解決 lint findings 取得に防御的 LIMIT を追加 getUnresolvedFindings / getFindingsForPage が LIMIT 無しで全件取得していた ため、バックログが膨大なユーザーで無制限の結果セットをメモリに読み込む 恐れがあった。ハードキャップ (DEFAULT_LINT_FINDINGS_LIMIT=500) を付与し、 適用を検証する単体テストを追加。 https://claude.ai/code/session_01XgbeNj9c8fk6Tyg1JgioDU * perf(api): getNoteRole のロール解決を 1 クエリに統合 ノートアクセス毎に最大 3 本(note → member → domain)の逐次クエリを 発行していたものを、note 列をフラットに select しつつ member/domain を 相関サブクエリで解決する 1 往復に統合。ドメインの最強ロール (editor > viewer) は SQL 側で集約し、優先順位 (#663) は従来どおり JS で 適用するため挙動は不変。 note 列をフラット展開することでモック DB の owner ケースは無改修で通り、 member/domain アクセスを明示シードしていたテストのみ combined 行形式へ 更新。getNoteRole が 1 往復であることを検証するテストも追加。 https://claude.ai/code/session_01XgbeNj9c8fk6Tyg1JgioDU * fix(api): getNoteRole で email 無しの呼び出しに member/domain ロールを付与しない レビュー指摘 (PR #997)。サブクエリ統合時、normalizedEmail が空でも `LOWER(member_email) = ''` が空メールの member 行に偶発一致し、匿名 ユーザーに private ノートへのアクセスを与えうるリグレッションがあった。 旧実装は email 無し時に member/domain チェックを丸ごとスキップしていた。 - email/domain が無ければ相関サブクエリを実行せず NULL を select(不要な サブクエリ実行も回避) - JS 側でも email/domain 不在時はロールを採用しない多層防御を追加 - email 無しで member ロールを付与しないことを検証する回帰テストを追加 https://claude.ai/code/session_01XgbeNj9c8fk6Tyg1JgioDU * ci(e2e): playwright インストールのハング対策(timeout + リトライ) E2E (web) ジョブで playwright install --with-deps chromium が CI の ネットワーク不調で停滞し、job timeout 未設定のため既定 6h ハングしていた。 - e2e-web ジョブに timeout-minutes: 20 を設定し早期に打ち切る - install を per-attempt timeout 300 + 既存 wretry.action で最大 3 回リトライ (停滞試行は timeout で非ゼロ終了させ、リトライを発火させる) コード変更ではなく CI 基盤の堅牢化。停滞ジョブの再実行も兼ねる。 https://claude.ai/code/session_01XgbeNj9c8fk6Tyg1JgioDU * ci(e2e): re-trigger run to retry transient playwright browser install E2E (web) が Install Playwright browsers のネットワーク取得失敗で落ちたため (直近 run は各試行 timeout 300 × 3 リトライを使い切り約16分で fail-fast)、 一時的な不調かを確認するために空コミットで CI を再実行する。コード変更なし。 https://claude.ai/code/session_01XgbeNj9c8fk6Tyg1JgioDU --------- Co-authored-by: Claude <noreply@anthropic.com>
* perf(api): バッチ化・並列化で逐次クエリ/逐次 await を解消 タイトルリネーム伝播 (`propagateTitleRename`) の参照元ページ書き換えを、 最大 8 件 (`SOURCE_REWRITE_CONCURRENCY`) の `Promise.allSettled` バッチで 並列化する。各 source は独立した `page_contents` 行をロックするため順序 非依存で、ロック競合・デッドロックは発生しない。失敗は従来どおりベスト エフォートでカウント・ログし、後続 source / ghost 昇格を止めない。 AI モデル同期 (`syncOneProvider`) の新規モデル投入を、行ごとの逐次 INSERT から単一マルチバリュー INSERT に変更 (N+1 → 1 クエリ)。sortOrder は max+1 から index で事前採番する。表示順 (orderBy) にしか使わないため、稀な onConflict スキップで生じるギャップは無害。 並列パスの回帰防止テストを追加 (順序非依存の意味ベース DB モック): ベストエフォート集計・同時実行数 8 のバウンド検証。 Refs #1001 * perf(api): リネーム伝播の並列度を 8→4 に引き下げ fire-and-forget な伝播では同時リネームで使用接続数が重畳する (N 件同時 → 最大 4N 接続)。DB プール上限 max:20 を枯渇させて 無関係な API を巻き込まないよう、保守的に 4 へ。バウンド検証テストも 4 ベース(チャンク 4/4/2)に更新。 レビュー指摘 (gemini-code-assist) への対応。 Refs #1001 --------- Co-authored-by: Claude <noreply@anthropic.com>
* perf(web): 検索結果の仮想化とメッセージ/Lint の描画コスト削減 issue #1000 の follow-up。調査の結果、Item 1 の PageGrid 仮想化と Item 3 (useWikiLinkStatusSync の署名生成) は既に対応済みだったため、 残る描画コストに対応する。 - 検索結果ドロップダウン (HeaderSearchDropdownContent) を @tanstack/react-virtual で仮想化。キーボードナビの active 行は scrollToIndex で描画ウィンドウ内へ寄せ、aria-activedescendant の 解決とスクロール追従を維持。親の querySelectorAll ベースの追従と 不要になった listRef を撤去。 - AIChatUserMessageBubble の renderUserContent を memo 化した UserMessageContent コンポーネントへ置換し、sort/map/RegExp/split の 構築を useMemo 化(Item 2)。 - LintSuggestions の formatDetail (fallback で JSON.stringify) を useMemo で事前計算し毎 render の serialize を回避(Item 4)。 各変更にテストを追加。既存テストは green、挙動・アクセシビリティに 回帰なし。 https://claude.ai/code/session_01XtKKGg3VZ5xdxVJpF9TFBC * fix(web): レビュー指摘対応(ホバー時のスクロールスナップ抑止・空タイトル除外) - HeaderSearchDropdownContent: マウスホバーによる activeIndex 変更時は scrollToIndex をスキップし、ホイールスクロール中のスナップ競合を防ぐ。 キーボード操作時のみ追従する(wasMouseChangeRef)。 - UserMessageContent: referencedPages から空タイトルを除外し、正規表現に 空の選択肢が入って `@` 単体へ誤マッチするのを防ぐ。全件空なら plain text。 - 各挙動のテストを追加。 https://claude.ai/code/session_01XtKKGg3VZ5xdxVJpF9TFBC --------- Co-authored-by: Claude <noreply@anthropic.com>
…tralize tests (#1016) * docs: ディレクトリ命名・配置・テスト配置の規約を AGENTS.md に明文化 既存コードベースで命名ケース(camelCase / kebab-case / PascalCase)と テスト配置(同居型 / 集中型)が混在しており、「既存の規則に合わせる」 だけでは判断できない状態だったため、優勢パターンを基準に明文化する。 https://claude.ai/code/session_013GVu22xu4k8gWrRG2dVZ9p * refactor: フックと非フックの配置違反を解消 - src/pages/useAIChatDetailLifecycle(.test) → src/hooks/(pages にフックを置かない) - src/hooks/aiChatEmptyTree, runAIChatAction(.test) → src/lib/aiChat/(フックでないヘルパー) - src/hooks/workflowRunOutcomeHandlers → src/lib/workflow/(同上) AGENTS.md の配置規則に従い、import は @/ エイリアスに更新。 https://claude.ai/code/session_013GVu22xu4k8gWrRG2dVZ9p * refactor: コンポーネント・ページディレクトリの命名を規約に統一 - src/components/{ai-chat→aiChat, pdf-reader→pdfReader, wiki-link→wikiLink} (機能ディレクトリは camelCase) - src/pages/{pdfKnowledge→PdfKnowledge}(ページディレクトリは PascalCase) - import パスを追従更新(CSS クラス名・storage key 等の文字列は対象外) 検証: ルート vitest 全 2652 テストがパス。 https://claude.ai/code/session_013GVu22xu4k8gWrRG2dVZ9p * refactor: src/lib 直下の aiChat 系モジュールを src/lib/aiChat/ へ集約 aiChatActionHelpers / aiChatActions / aiChatConversationTitle / aiChatDetailLandingPayload / aiChatPrompt / aiChatPromptActionFormat (およびテスト)を移動し、AGENTS.md の配置規則 「同一ドメイン 2 ファイル以上はサブディレクトリへ」に従う。 import は @/ エイリアスへ統一して更新。 検証: ルート vitest 全 2652 テストがパス。 https://claude.ai/code/session_013GVu22xu4k8gWrRG2dVZ9p * refactor(api): subscriptionManage の as any を unknown 経由の型アサーションに置換 Polar SDK の型解決問題の回避という意図は維持しつつ、 AGENTS.md の「any 禁止」に適合する形へ変更。eslint-disable を撤去。 https://claude.ai/code/session_013GVu22xu4k8gWrRG2dVZ9p * refactor(api): 同居型テスト 26 件を src/__tests__/ へ集約しテスト配置を統一 - AGENTS.md のテスト配置規約(server/api は集中型)に従い、 src/{lib,services,utils,agents,content} 直下の *.test.ts を src/__tests__/ のミラー位置へ移動。相対 import を追従更新。 - composeSessionRunLocale.test.ts の bun:test import を vitest に修正 (vitest 実行時に suite ごと失敗していた既存問題。CI は api の vitest を実行していないため未検出だった) 検証: server/api で tsc --noEmit クリーン、vitest 全 1424 テストがパス。 https://claude.ai/code/session_013GVu22xu4k8gWrRG2dVZ9p * refactor: レビュー指摘対応 — import type 化と再エクスポートの冗長解消 - aiChatPrompt.ts: 型のみ使用の PageContext / ReferencedPage を import type に変更 - aiChatActionHelpers.ts: 同一モジュールパスからの import と再 export を統合 https://claude.ai/code/session_013GVu22xu4k8gWrRG2dVZ9p * chore: e2e の Playwright インストールフレークにより CI を再実行 E2E (web) ジョブが Chromium ダウンロード後のインストールステップで exit code 124(タイムアウト)× 3 リトライで失敗。コード起因ではない インフラ系フレークのため空コミットで再トリガーする。 https://claude.ai/code/session_013GVu22xu4k8gWrRG2dVZ9p --------- Co-authored-by: Claude <noreply@anthropic.com>
… (#1018) * ci: cache Playwright browsers to fix E2E (web) install timeouts (#1017) E2E (web) ジョブが "Install Playwright browsers" でダウンロード完了後の 展開フェーズに 5 分間停滞し、timeout 300 の打ち切り(exit 124)× 3 試行で 恒常的に失敗していた。各リトライ冒頭で中途半端な chromium build を削除して 再ダウンロードするため、リトライが状況を改善しない構造だった。 - ~/.cache/ms-playwright を Playwright バージョンキーでキャッシュし、ヒット時は ダウンロード自体を回避(actions/cache の restore/save を分離) - save はブラウザ取得成功時のみ実行し、停滞して打ち切られた壊れた状態が キャッシュに焼き付くのを防ぐ - OS 依存 (apt) はキャッシュ対象外のため install-deps を別ステップで毎回実行 - ブラウザ取得は cache miss 時のみ、timeout を 600s に拡大し attempt_limit 2 に (ジョブ全体 20 分に収める) * ci: revert browser cache, add Playwright install diagnostics (#1017) 前回のブラウザキャッシュ対応は的外れだったため revert する。E2E (web) の 初回 run は必ず cache miss であり、ダウンロード自体が一度も完走しないため、 キャッシュは永遠に populate されず効果がなかった(run 27242439011 で確認: install ステップが 100% 到達後に無出力のまま 20 分の job 上限で cancelled)。 切り分けのための診断に差し替える: - apt OS 依存 (install-deps) を browser DL と別ステップに分離。直近 run で ~18s で成功しており、apt は原因ではないと確定済み。 - ブラウザ取得を DEBUG=pw:install 付き・単発(無リトライ)で実行し、100% 到達 後にどのフェーズ(zip 展開 / headless-shell / ffmpeg 取得)で停滞するかを ログに可視化する。証拠を得てから恒久対応を決める。 * ci: run Playwright install under Node to fix extraction hang (#1017) DEBUG=pw:install の切り分けログ(run 27243476723)で原因を特定した。chromium zip の DL は ~1.4s で完了しており、その直後の `pw:install extracting archive` (zip 展開)で停止し 5 分後に timeout(exit 124) で打ち切られていた。原因は ネットワークではなく zip 展開処理。 展開は extract-zip(yauzl + Node zlib stream) によるローカル処理で、これを bunx (Bun ランタイム)で実行していたため Bun の zlib/stream 実装でハングしていた。 ワークフロー未変更でも setup-bun の bun-version: "1.3" が実行時に最新 1.3.x を 引くため、5 月末の Bun 更新で静かに退行したと推測(5/28 以前は成功と整合)。 対応: - 展開を含む `playwright install` を bunx ではなく npx(Node)で実行する - apt 依存 (install-deps) は別ステップのまま据え置き(Bun でも正常) - timeout + wretry(最大2回) でネットワーク揺らぎに対応 - 前回の診断用 DEBUG=pw:install と単発実行は撤去 * ci: isolate Playwright extraction stall (env vs Playwright) (#1017) Node(npx) でも展開フェーズの停止が同一に再現し(run 27243906347: DL 100% 到達後に 無音 → timeout 124、bunx と同パターン)、ランタイム(Node/Bun)は原因ではないと確定。 前回の Node 切替仮説は棄却する。 環境(runner の FS/ディスク/CPU)と Playwright の JS 展開コードを切り分ける診断を追加: - df/free/nproc でディスク空き・メモリ・CPU を記録 - 同じ chromium zip を curl で取得(DL の健全性を再確認) - システムの unzip で $HOME 配下へ展開(Playwright を介さない展開) - 比較用に Playwright 本来の install も DEBUG 付き・単発・timeout 180 で再実行 システム unzip も停止すれば runner 環境が原因、成功すれば Playwright 1.57 の 展開コードが原因と切り分けられる。 * fix(ci): bump Playwright to 1.60 to fix yauzl extraction hang on Node 24 (#1017) E2E (web) の Playwright ブラウザインストールが恒常的に exit 124 で失敗していた 真因を特定した。Playwright < 1.60 は Node 24.16+ 上で zip 展開(yauzl)が無限 ハングする既知バグ(microsoft/playwright#40724)。GitHub ランナー画像の Node が 24.16+ に上がった 5 月末以降、本リポジトリの .nvmrc=24 と相まって install が `extracting archive` で停止し、timeout で打ち切られていた(ワークフローは不変)。 切り分けの根拠(run 27244855993 の診断ステップ): - ディスク 86GB 空き / メモリ 14GB / CPU 4core と環境は健全 - 同一 zip を curl 取得 2.4s・システム unzip 2.9s で正常展開(357MB) - 一方 Playwright 自身の `extracting archive` は Node でも Bun でも無限停止 → 環境・ネットワーク・zip は無実、Playwright の JS 展開コードのみが原因と確定 対応: - @playwright/test を ^1.57.0 → ^1.60.0 に更新(lock: 1.60.0)。yauzl 修正済み - install を展開修正が検証済みの Node(npx)で実行、apt 依存は別ステップに分離 これまでの試行(キャッシュ / timeout 拡大 / bunx→npx)はいずれも誤った前提 (ネットワーク・ランタイム起因)に基づくもので、切り分けにより棄却済み。 * ci: address review — retry apt deps, pin actions to SHA (#1018) レビュー対応(PR #1018): 1. P2 (chatgpt-codex): install-deps の retry 復活 apt 依存を別ステップに分離したことで一過性の apt/network 停滞時に retry が 効かなくなっていた。元の単一ステップ構成に戻し、--with-deps ごと timeout + wretry(最大3回) 配下に含めて apt も bounded retry の対象に戻す。 2. Major (coderabbitai): third-party アクションの SHA pin ci.yml 内の全 third-party アクションをタグ pin から commit SHA pin に統一し、 タグ retarget / supply-chain リスクを排除(既存の tauri-release.yml / terraform-cloudflare-prod.yml と同じ '@<sha> # vX.Y.Z' 形式に合わせる)。 - Wandalen/wretry.action @V3 -> e68c23e… - actions/checkout @v6.0.2 -> de0fac2… - actions/upload-artifact @v7 -> 043fb46… - gitleaks/gitleaks-action @v2 -> ff98106… * ci: clarify gitleaks pin comment to exact tag v2.3.9 (#1018) レビュー対応(coderabbit, line 450)。gitleaks/gitleaks-action の v2 は注釈付き タグで、タグオブジェクト SHA は dcedce43… だが、それが指すコミットは ff98106… (= v2.3.9)。GitHub Actions の SHA pin は『コミット SHA』を要求するため ff98106… が正しく、dcedce43…(タグオブジェクト)では動かない。SHA はそのままに、# v2 → # v2.3.9 とコメントを正確化して曖昧さを解消する。 --------- Co-authored-by: Claude <noreply@anthropic.com>
server/api's vitest suite (129 files / ~1,400 tests) was never run in CI — only api-typecheck (`bunx tsc --noEmit`) ran, so a broken suite could slip through unnoticed (e.g. the bun:test import in #992). server/hocuspocus had the same gap: its tests were only wired into the root `test:run` script, which CI does not execute (CI runs `test:coverage`). Add `api-test` and `hocuspocus-test` jobs mirroring the `mcp-test` setup (install deps inside the service dir, then `vitest run`), and align the misleading comment in the `test` job. Update AGENTS.md so the CI description matches reality, enumerating which job covers each service. Closes #1010 Co-authored-by: Claude <noreply@anthropic.com>
…ck in CI (#1021) Satisfies the #1011 acceptance criteria: - tsconfig.app.json: strict: true (+ ignoreDeprecations "6.0" for the TS 6.0 `baseUrl` TS5101 deprecation; drop the now-redundant noImplicitAny: false). - CI: the existing `type-check` job ran a bare `bunx tsc --noEmit`, which type-checks NONE of src/ — the root tsconfig.json is `files: []` + project references and is only processed with `-b`. Point it at `-p tsconfig.app.json` so frontend type errors are actually caught in PRs. Resolved 227 strict errors across 89 files (types only, behavior-preserving), notably: - Page/PageSummary.noteId: string -> string | null to match the storage layer (PageMetadata.noteId is string|null; pageStore and the repository emit null for personal pages). Interim type-honesty surfaced by strict; null handled at the search / linked-pages consumers. Eliminating null at the source and re-tightening to non-null is tracked by the personal-page removal epic. - markdownExport: typed nodeHandlers via Object.assign generics. - mermaid / storage / web-clipper / collaboration: null|undefined coalescing matching the target types. - tiptap: NodeViewContent<"code">, nested command module augmentation, ref widening (RefObject<T | null>). - Test fixtures typed (vi.fn<...> signatures, valid union literals, mock shapes). Behavior-affecting fix surfaced by strict: - useWikiSchema destructured `user` from useAuth(), but useAuth exposes no `user` (only userId), so `user` was always undefined and `enabled: !!user` kept the wiki-schema query permanently disabled. Switched to useUser(). Verified: tsc -p tsconfig.app.json = 0 errors, eslint 0 errors, prettier clean, 260 frontend test files / 2652 tests pass. https://claude.ai/code/session_015u86X91VM5DHsdsbjwEshC Co-authored-by: Claude <noreply@anthropic.com>
* refactor(front): src/hooks をドメイン別サブディレクトリに整理 (#1012) `src/hooks/` 直下に約 90 ファイルがフラットに堆積していた状態を解消し、 ドメイン別サブディレクトリ(aiChat/auth/media/notes/pages/search/settings/ tags/wiki/workflow)へ整理した。直下に残すのはドメインに属さない汎用フック (useCollaboration / useContainerColumns / useDebouncedCallback / useDebouncedValue / useKeyboardShortcuts / useVirtualKeyboardOffset)のみ。 - 55 個のフック本体 + 同居テストをドメイン別に git mv(直下 94 → 8 ファイル) - フック間・フックから他ディレクトリへの import を相対パスから @/ エイリアスに統一 (サブディレクトリ移動で壊れないようにするため) - AGENTS.md 配置規則に hooks のサブディレクトリ規約と @/ エイリアス方針を追記 巨大フック(useNoteQueries / usePageQueries)の分割は影響範囲が大きいため本 PR では見送り、ディレクトリ整理に集中した。 ルート vitest 全 2652 テストがパスすることを確認済み。 * docs(agents): フックへの import も @/ エイリアス必須であることを明記 コンポーネント・ページ等からフックを import する場合も `@/` エイリアスを 使うことを配置規則に明記した(PR #1022 レビュー反映)。 --------- Co-authored-by: Claude <noreply@anthropic.com>
…n-null 化 (#1020) (#1023) * refactor(front+server): 個人ページ(noteId === null)概念を根絶し Page.noteId を non-null 化 (#1020) - server: GET /api/sync/pages の各ページ行に note_id を追加し、トップレベルに default_note_id を返す(クライアントのレガシー null 行移行用) - front(sync): pull 適用前に reassignNullNotePages で既存の noteId:null 行を デフォルトノートへ付け替え。push はデフォルトノート配下のみに限定 - front(IndexedDB): PageMetadata.noteId を string に tighten。未移行の レガシー null 行は読み出しから除外し、同期時に自動移行 - front(types): Page.noteId / PageSummary.noteId を string(non-null)へ再 tighten し、#1011 で追加した消費側 null ガード・null 分岐を撤去 - ゲストのローカルページ作成を廃止(#889 以降 /notes/null/:pageId に遷移して 実質機能していなかった)。createPageLocal / pageStore を削除し、FAB は 未サインイン時に非表示 - WikiLink ホバープレビューを pageStore からリポジトリ(IndexedDB)ベースの usePageByTitle / useGhostLinkReferenced に置き換え - 検索結果の「共有」バッジは noteId の有無ではなく結果ソースで判定 - 呼び出し元のない importPersonalPageFromApi(note_id != null を拒否する ガード)を削除 [skip drizzle-check] サーバはルート実装のみの変更で、スキーマ変更なし Closes #1020 https://claude.ai/code/session_01FH8KekbbgxZxsw5LLknKCQ * fix: address PR #1023 review comments (gemini-code-assist) - NotePageView: isTitleEditable を canEdit に揃え、page 未ロード時の 編集可能判定を排除 - IndexedDBStorageAdapter.reassignNullNotePages: store.count() と by_note index の count 比較によるレガシー行ゼロ時の高速パスを追加し、毎同期の 全行カーソル走査を回避(localStorage フラグ案はユーザー間の漏れと ストレージ分裂があるため不採用) https://claude.ai/code/session_01FH8KekbbgxZxsw5LLknKCQ * fix: address PR #1023 review comments (coderabbitai) - FloatingActionButton: 未サインイン遷移時に FAB のローカル UI 状態 (メニュー / 画像ダイアログ)も畳む。initialClipUrl はサインイン往復 (#826 handoff)を壊すため破棄しない - NotePageView: isTitleEditable の prop ドキュメントを新権限モデル (access.canEdit ベース)に更新 - syncWithApi.test: reassign → upsert の呼び出し順アサーションを明示化 https://claude.ai/code/session_01FH8KekbbgxZxsw5LLknKCQ --------- Co-authored-by: Claude <noreply@anthropic.com>
`src/lib/aiChat/runAIChatAction.ts` has only ever been imported by its own test since its introduction in PR #862; it was never wired into production code. The live AI-chat action path is `useAIChatActions.handleExecuteAction`, which inlines the same logic via `aiChatActionHelpers`. Removing the unused module and its test. Also drop `getCreatePageOutline` from `aiChatActionHelpers` (plus its test block and the now-unused `CreatePageAction` import): it was only reachable through `runAIChatAction`, so it becomes dead once that module is removed. https://claude.ai/code/session_01ELTvLUUeXH92imBRCNvthK Co-authored-by: Claude <noreply@anthropic.com>
* refactor(api): move domain-logic helpers from lib to services Realign src/lib and src/services per AGENTS.md placement rules (domain logic lives in services/, generic helpers in lib/, *Service.ts files belong in services/). - welcomePageService.ts -> services/ (the only *Service.ts under lib/) - articleExtractor.ts -> services/ (URL→HTML→Readability→Tiptap pipeline) - youtubeExtractor.ts -> services/ (YouTube→Tiptap+AI summary pipeline) - Move mirrored tests to src/__tests__/services/ and follow all imports Generic helpers (clipServerFetch, clipUrlPolicy, cors, env, sentry, videoServerExtension, youtubeEmbedServerExtension, etc.) remain in lib/. tsc --noEmit and full vitest suite (1425 tests) pass. Refs #1013 https://claude.ai/code/session_01FemSKrxujx1CtF4iXaAY24 * refactor(api): move remaining domain-logic helpers from lib to services Continue the lib/services boundary cleanup per AGENTS.md placement rules. Move the domain-logic helpers that remained in lib/ to services/: - clipAndCreate.ts (URL→fetch→Readability→Tiptap→Y.Doc→DB pipeline) - userDelete.ts (soft-delete business logic) - auditLog.ts (admin audit-log domain helper) - extAuth.ts (Chrome extension auth flow: Redis/PKCE/JWT) - mcpAuth.ts (MCP auth flow: Redis/PKCE/JWT) - freeEmailDomains.ts (domain-invitation validation logic) - aiAccessHelpers.ts (AI model access checks; couples usage/aiProviders/subscription services) Mirrored tests moved to src/__tests__/services/ and all imports followed. src/lib/ now holds only generic helpers (clientIp, clipServerFetch, clipUrlPolicy, cors, env, extractPlainTextFromYXml, githubAppAuth, hocuspocusInvalidation, sentry, videoServerExtension, youtubeEmbedServerExtension). tsc --noEmit and full vitest suite (1425 tests) pass. Refs #1013 https://claude.ai/code/session_01FemSKrxujx1CtF4iXaAY24 * fix(api): follow lib→services move in cross-workspace references The lib→services move missed references outside server/api/src/, breaking three CI checks: - scripts/issue-mcp-token.ts imported ../src/lib/mcpAuth.js (Knip: unresolved import) → point to ../src/services/mcpAuth.js - Front-end drift test src/lib/freeEmailDomainsSync.test.ts readFileSync'd server/api/src/lib/freeEmailDomains.ts (Unit Tests: ENOENT) → update all path references to src/services/freeEmailDomains.ts - Prettier reflowed import lines in fetchArticle.ts/.test.ts and youtubeExtractor.ts (Lint: format:check) → apply prettier --write Also update doc-comment path references in src/lib/domainValidation.ts, src/lib/htmlToTiptap.ts, and packages/shared/src/freeEmailDomains.ts. https://claude.ai/code/session_01FemSKrxujx1CtF4iXaAY24 --------- Co-authored-by: Claude <noreply@anthropic.com>
… 化 (#1028) - lib/utils.ts の cn、hooks/use-toast.ts の reducer / toast / useToast に 日英併記の TSDoc を追加(sidebar 分割実装・use-mobile は対応済み) - packages/ui の自前実装スコープ(hooks / lib / components/sidebar)で jsdoc/require-jsdoc を error に昇格 - shadcn/ui 由来のベンダーコード(components/ 直下)は対象外とする旨を eslint.config.js のコメントと AGENTS.md に明記 Closes #1014 https://claude.ai/code/session_01Gj4667fp7NcqKWNsZAGjo1 Co-authored-by: Claude <noreply@anthropic.com>
* feat(editor): 動画のサニタイズ許可・D&D/ペーストアップロード・Markdown出力 (#364) Issue #364 のスコープ (a)(ブロッカー修正)。WebM 変換は後続 (b) で対応する。 - contentUtils: SUPPORTED_NODE_TYPES に "video" を追加。保存・再読込時の sanitizeTiptapContent で video ノードが落ちて再表示で消える問題を解消(真のブロッカー) - markdownExport: video ノードを HTML <video> タグで出力(未登録だと空出力になる) - lib/media/uploadMediaFile: presigned 2 段アップロードを共有ヘルパーへ抽出し、 MediaPlaceholderNodeView を置換(挙動不変・重複 MIME 定義を解消) - エディタ面の D&D / ペーストで動画を /api/media(S3 デフォルトストレージ)へ アップロードし、video ノードを挿入(filterVideoFiles / uploadVideoFilesAndInsert) - contentUtils / markdownExport / 各ヘルパーのユニットテストを追加 動画は provider 選択に依存せず常にデフォルトストレージを使うため Gyazo 競合は発生しない。 COOP/COEP は単一スレッド方式前提で本スコープでは不要。 https://claude.ai/code/session_01PBpAfnxPoqxX1fbTXuhod1 * fix(editor): 動画 Markdown 出力のエスケープ・ペースト/破棄ガード (review #1029) gemini-code-assist のレビュー指摘に対応: - markdownExport: video の src / alt を HTML エスケープし、属性ブレイクアウト経由の XSS/HTML インジェクションを防止(tiptapToHtml の escapeHtml を export して再利用) - usePasteImageHandler: getAsFile() が全て null のときは preventDefault せず、 ペーストをサイレントに握りつぶさないよう修正 - uploadVideoFilesAndInsert: アップロード完了後に editor.isDestroyed を確認し、 破棄済みインスタンスへのコマンド実行・不要なエラートーストを防止 - markdownExport: エスケープを担保するテストを追加 https://claude.ai/code/session_01PBpAfnxPoqxX1fbTXuhod1 * fix(editor): 動画 src のスキーム検証・TSDoc・MIME ドリフト検知 (review #1029) coderabbitai のレビュー指摘に対応(いずれも AGENTS.md のガイドラインに準拠): - markdownExport: video の src を tiptapToHtml の sanitizeUrl で検証し、javascript: 等の危険スキームを排除(export して再利用)。escapeHtml と併せ多層防御に - useImageUploadManagerHelpers: filterVideoFiles に日英併記の TSDoc を付与 - uploadMediaFile.test: 弱い membership チェックを廃し、server/api の ALLOWED_UPLOAD_TYPES を fs.readFileSync で読むドリフト検知に置換 (AGENTS.md §ドリフト検知 / cf. tagCharacterClassSync.test.ts) - escapeHtml の JSDoc を日英併記に、危険スキーム拒否のテストを追加 https://claude.ai/code/session_01PBpAfnxPoqxX1fbTXuhod1 --------- Co-authored-by: Claude <noreply@anthropic.com>
* fix(security): harden Tauri IPC/CSP, Mermaid XSS, secrets & deps Address findings from a repo-wide vulnerability review. Frontend / desktop (Tauri): - MermaidNodeView: switch securityLevel "loose" -> "strict" to keep DOMPurify sanitization on diagram labels. The rendered SVG is injected via dangerouslySetInnerHTML and the source is user-controlled (pasted/ imported markdown, shared/public pages), so "loose" allowed stored XSS reachable by unauthenticated public-page visitors. No interactivity used. - tauri.conf.json: add app.security.csp (and a relaxed devCsp for Vite HMR). Production CSP excludes 'unsafe-inline'/'unsafe-eval' from script-src (the primary XSS execution vector) while allowing wasm/workers/styles and configurable connect targets (API/realtime/Sentry/BYO AI providers). - Move ~/.claude config reading into a gated Rust command (read_claude_mcp_servers) that returns ONLY the mcpServers object, never the rest of the file (API keys / OAuth tokens). Remove the broad fs:allow-read-text-file ($HOME/.claude/**) capability, fs:default, the fs plugin registration, and the now-unused @tauri-apps/plugin-fs deps. Sidecar protocol (claude_query boundary): - Fully validate parseRequestLine: reject unknown types/malformed payloads, type-check every field, and validate mcpServers transports (stdio command spawning). Drop unknown fields. Add tests. Backend: - GET /api/users/me: project only client-needed fields instead of select(), no longer leaking internal moderation columns (status/suspended*). - internal.ts + hocuspocus: constant-time compare of the x-internal-secret shared secret (timingSafeEqual). Dependencies / infra: - Override dompurify to >=3.4.9 to clear transitive XSS advisories. - docker-compose.dev.yml: bind Postgres/Redis to 127.0.0.1 (weak/no auth). * fix(security): hash secrets before constant-time compare Address review feedback: compare fixed-length SHA-256 digests with timingSafeEqual instead of length-checking raw buffers, so neither the length nor the contents of the x-internal-secret leak via response timing. Applies to both the API internal route and the Hocuspocus internal endpoint. * test(security): cover http/sse MCP transport validation; tighten import type Address CodeRabbit review: - protocol.test.ts: add coverage for http/sse mcpServers validation, unknown transport rejection, and non-string url / bad headers — the prior tests only exercised the stdio path. - McpServerSettings: type read_claude_mcp_servers as Record<string, unknown> so each entry is unknown until validated, making the downstream cast meaningful. --------- Co-authored-by: Claude <noreply@anthropic.com>
実装を読まないエージェントに仕様だけを渡してテストを書かせることで、 実装の写し絵テスト(バグの固定化)を構造的に防ぐパイプライン。 - .claude/skills/spec-test: オーケストレーションとテスト観点リファレンス - .claude/agents/spec-extractor: 実装から仕様のみを抽出(コード非開示) - .claude/agents/test-designer: 仕様と観点からテストを設計・実装(実装の読み取り禁止) - .claude/agents/mutation-verifier: Stryker / アサーション強度レビューで検出力を検証 - .gitignore: .claude/ のうち skills / agents のみ追跡対象に変更 https://claude.ai/code/session_01VuNxv2TGSiBzKsEAn4U6di Co-authored-by: Claude <noreply@anthropic.com>
Bumps [gitleaks/gitleaks-action](https://github.com/gitleaks/gitleaks-action) from 2.3.9 to 3.0.0. - [Release notes](https://github.com/gitleaks/gitleaks-action/releases) - [Commits](gitleaks/gitleaks-action@ff98106...e0c47f4) --- updated-dependencies: - dependency-name: gitleaks/gitleaks-action dependency-version: '3' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…in the minor-and-patch group (#1008) * chore(deps): bump @polar-sh/sdk Bumps the minor-and-patch group in /server/api with 1 update: [@polar-sh/sdk](https://github.com/polarsource/polar-js). Updates `@polar-sh/sdk` from 0.47.1 to 0.48.0 - [Release notes](https://github.com/polarsource/polar-js/releases) - [Changelog](https://github.com/polarsource/polar-js/blob/main/RELEASES.md) - [Commits](polarsource/polar-js@v0.47.1...v0.48.0) --- updated-dependencies: - dependency-name: "@polar-sh/sdk" dependency-version: 0.48.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: minor-and-patch ... Signed-off-by: dependabot[bot] <support@github.com> * chore(deps): sync bun.lock with package.json changes --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* fix(sync): push local-only legacy pages after noteId migration (#1020) Initial sync skipped push when pre-pull localPageCount was zero, but legacy noteId:null rows are hidden from getAllPages until reassignNullNotePages runs in applyPull. That could leave offline-only pages never uploaded. Only skip push on initial sync when every page slated for push was just pulled from the server (redundant echo), not when local-only rows exist. * fix(sync): filter redundant initial push pages after legacy migration Address PR #1061 review: drop pulled rows whose local metadata is not newer than the server copy before POST, instead of uploading the full pull or misclassifying offline edits as redundant echoes. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com>
…1064) * fix(sync): push local-only legacy pages after noteId migration (#1020) Initial sync skipped push when pre-pull localPageCount was zero, but legacy noteId:null rows are hidden from getAllPages until reassignNullNotePages runs in applyPull. That could leave offline-only pages never uploaded. Only skip push on initial sync when every page slated for push was just pulled from the server (redundant echo), not when local-only rows exist. * fix(sync): push local-only pages on full pull regardless of lastSync getPagesForPush still filtered by updatedAt > lastSync when a full pull (since omitted) ran with an existing lastSync — e.g. forceFullSyncWhenLocalEmpty after a pre-#1061 skip left legacy pages stranded. On full/initial pulls, push every default-note row absent from the server response instead of relying on the onlyEchoingPulledPages workaround. --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: otomatty <saedgewell@gmail.com>
POST /api/sources/pdf/.../derive-page accepted an arbitrary noteId without checking membership, allowing authenticated users to inject pages into notes they cannot edit. Mirror POST /api/pages permission checks when noteId is set. Also correct zedi_remove_page_from_note MCP description: after issue #823 the endpoint soft-deletes the page; there is no unlink-only mode. Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: akimasa.sugai <akimasa.sugai@saedgewell.com>
…e runs (#1059) * fix(api): clear LangGraph checkpoint when retrying failed Wiki Compose runs POST /run on a failed session reused the same thread_id without deleting stale checkpoints, so LangGraph merged partial outline/draft state with fresh input and could produce incoherent completion markdown after LLM errors. Co-authored-by: akimasa.sugai <akimasa.sugai@saedgewell.com> * fix(api): resolve checkpoint test typing and format for CI Co-authored-by: Cursor <cursoragent@cursor.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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
概要
developブランチの変更(47 コミット、695 ファイル)をmainに取り込むリリース PR です。前回の main マージ(#972)以降の機能追加・リファクタリング・テスト強化・CI 改善を本番へ反映します。変更点
src//src/pages/server/api/services/移行、DB マイグレーション0033_add_ai_model_system_default.sqladmin/server/mcp//server/hocuspocus/src-tauri/src/components/editor/.github/workflows/.agents//scripts/bun run init)、/spec-testパイプライン追加変更の種類
テスト方法
deploy-prod.ymlにより DB マイグレーション(0033_add_ai_model_system_default.sql)が production に適用されることを確認するチェックリスト
.ja.mdペア)スクリーンショット(UI 変更がある場合)
Wiki Compose、ノート一覧、モバイルナビ、エディタ等に UI 変更あり。必要に応じてマージ前に develop 環境で確認。
関連 Issue
#982 以降の develop 取り込み分(#984–#1057 等)。破壊的変更: 個人ページ(
noteId === null)概念の廃止、Page.noteIdnon-null 化(#1020 / #1023)。マージ方法
Create a merge commit でマージしてください(AGENTS.md の release フローに従う)。
Made with Cursor