模板總整修:技能與腳本重構、多來源章節切分、安全強化、中文搜尋層 - #6
Merged
Merged
Conversation
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01US3TEe1Pu3mFHCjjwzq8Fg
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01US3TEe1Pu3mFHCjjwzq8Fg
Remove the PostToolUse permission-check hook registration and script: it was wired to the wrong event (PostToolUse cannot block anything), had an infinite-loop bug on Windows drive roots, and duplicates Claude Code's built-in permission system. Raise pytest hook timeout to 60s. Commit the pending .python-version fix (3.10.12 violated requires-python >=3.11). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01US3TEe1Pu3mFHCjjwzq8Fg
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01US3TEe1Pu3mFHCjjwzq8Fg
…wed status Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01US3TEe1Pu3mFHCjjwzq8Fg
…rg check Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01US3TEe1Pu3mFHCjjwzq8Fg
Add reset_chapters, reset_style_decisions, remove_progress_files, reset_astro_config, write_placeholder_index, and remove_plans_dir so clean_sample_data.py fully resets a project back to template state (chapters.json, style-decisions.json, translation-progress*.json, docs/astro.config.mjs, docs index.mdx, plans/). main() now runs these after clean_glossary in order. Also narrow clean_glossary's except Exception to except (json.JSONDecodeError, OSError). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01US3TEe1Pu3mFHCjjwzq8Fg
…laceholder index) - Run scripts/clean_sample_data.py to strip Cairn/Year Zero Engine sample content: blank chapters.json/glossary.json/style-decisions.json, remove translation-progress.json, reset docs/astro.config.mjs title+sidebar, write placeholder docs/src/content/docs/index.mdx. - Manually finish the docs reset: drop dead og:image/twitter:image meta tags from astro.config.mjs head, delete unused custom-light.css and the fake hero.jpg, drop the unused @astrojs/vercel dependency (no adapter configured) and refresh docs/bun.lock, drop the /fonts headers block from vercel.json (no such directory), and rewrite docs/README.md for the template pipeline. - Add data/pdfs/.gitkeep and data/markdown/.gitkeep placeholders. - Fix a real idempotence bug found while re-verifying the clean script: reset_astro_config's sidebar regex, when run a second time against an already-empty `sidebar: [],`, had no newline to anchor on and over-consumed past plugins/customCss/closing brackets, corrupting the file. Guard against the already-empty case and add a regression test. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01US3TEe1Pu3mFHCjjwzq8Fg
…om template Deletes internal agent-system analysis, plans, superpowers specs, and the completed-but-archived openspec opendataloader-engine change. These artifacts were for project development and are not part of the template distribution. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01US3TEe1Pu3mFHCjjwzq8Fg
Add mandatory cleanup step to new-project/SKILL.md right after repository creation, and sync README.md / scripts/README.md docs with the script's full reset/delete behavior list so child projects never inherit sample data. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01US3TEe1Pu3mFHCjjwzq8Fg
…perseded per design spec) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01US3TEe1Pu3mFHCjjwzq8Fg
…fs to rules - Remove disable-model-invocation from md-review, term-decision, check-consistency (these skills are invoked by other skills' workflows, so model must be able to call them) - Add disable-model-invocation to final-proofread (entry-point skill kept restricted for consistency) - Replace all AGENTS.md references with .claude/rules/docs-conventions.md across md-review, md-review/reviewer-prompt, and super-translate skills Verification: - git grep "AGENTS.md" -- .claude/skills: no output ✓ - git grep -l "disable-model-invocation" -- .claude/skills: 7 files ✓ Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01US3TEe1Pu3mFHCjjwzq8Fg
…g rule, unify iteration cap at 2 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01US3TEe1Pu3mFHCjjwzq8Fg
…k to md-review Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01US3TEe1Pu3mFHCjjwzq8Fg
Replace English placeholder with brief-mandated Traditional Chinese text: 「刪節號必須使用 \`……\`,不得使用 \`...\`」 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01US3TEe1Pu3mFHCjjwzq8Fg
…ft paths Resolve translation_mode.mode before Step 1 preconditions so the progress file, scope, and progress_read.py invocation are mode-aware (bilingual vs. default), and route the Gate 2 broken-link check through the resolved content root. Move chapter-split's topology draft path under .state/chapter-split/ to match chapters.draft.json. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01US3TEe1Pu3mFHCjjwzq8Fg
Review finding: the Gate 1a homepage path was a bare literal indistinguishable from a missed bilingual-mode conversion. Annotate it explicitly as the fixed, mode-independent site root. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01US3TEe1Pu3mFHCjjwzq8Fg
Delete .agents/ (physical copy of .claude/skills that diverged; .codex/ and .gemini/skills remain as symlinks and cannot drift). Add the four missing .gemini/commands TOMLs (md-review, bilingual-translate, fix-ref, final-proofread) mirroring the existing translate.toml format. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01US3TEe1Pu3mFHCjjwzq8Fg
…s, and engines Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01US3TEe1Pu3mFHCjjwzq8Fg
…scripts README Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01US3TEe1Pu3mFHCjjwzq8Fg
- init_handoff_gate.run_cmd now decodes child stdout/stderr as utf-8 instead of the cp950 default on win32, and check_bun_available() turns a missing `bun` into a clear gate failure entry instead of a FileNotFoundError traceback. - _ocr_lib.py (tesseract --list-langs, tesseract OCR run) and _opendataloader_lib.py (java -version) subprocess.run calls also pin encoding="utf-8" so Traditional Chinese CLI output doesn't crash or mojibake. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01US3TEe1Pu3mFHCjjwzq8Fg
…resolve() roots, opendataloader engine choice Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01US3TEe1Pu3mFHCjjwzq8Fg
…split_pages_content Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01US3TEe1Pu3mFHCjjwzq8Fg
…ts, drop stale duplicates 根目錄 tests/(4 檔、~63 測、3 月起未被 pytest testpaths 收集)已整批處理: - PORT 為 pytest 風格(tmp_path/monkeypatch/plain assert,移除 sys.path 自插): draft、style_decisions/validate_style_decisions、term_generate/term_edit/ term_read、_term_lib、validate_glossary、init_create_progress、 bilingual_prep、clean_sample_data 舊三函式、init_handoff_gate 三測 - 三個 bilingual 測試檔改寫為直接函式呼叫,消除硬編 macOS cwd 與 無 encoding 的 subprocess/read_text - DISCARD:TestExtractPdf 與 TestSplitChapters 中已由 test_layout_lib、 test_epub_lib、test_image_analysis、test_split_chapters 覆蓋的重複測試 - 補回兩處實際未被覆蓋的邏輯:extract_pdf 的 load_document_extraction_settings/resolve_page_text_strategy, split_chapters 的 group_images_by_page - term_edit.mutate_term 的 auto-cal 行為已演進(自動跑 cal 後照常套用), 測試改寫對齊現行行為,未動生產程式碼 280 -> 341 tests passing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01US3TEe1Pu3mFHCjjwzq8Fg
…n-version Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01US3TEe1Pu3mFHCjjwzq8Fg
…t, shared verification logic Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01US3TEe1Pu3mFHCjjwzq8Fg
…ion + origin re-validation sanitizeRedirect now strips ASCII C0 control chars (tab/CR/LF/etc.) before the prefix checks, since new URL() silently drops them and a payload like "/\t/evil.com" previously passed the raw-string checks but resolved cross-origin. api/site-auth.ts adds a second, independent origin check on both the success and error redirect branches as defense in depth. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01US3TEe1Pu3mFHCjjwzq8Fg
C1 generate_nav.generate_index() unconditionally emitted a hero `image.file: ../../assets/hero.jpg` block, but the blank-template reset deletes that asset. Starlight binds hero.image.file to Astro's image() helper, so `bun run build` died with [ImageNotFound]. The block is now emitted only when HERO_IMAGE exists on disk. C2 update_astro_sidebar's pattern required a newline after `sidebar: [`, so it never matched the reset config's collapsed `sidebar: [],` — it printed a warning, returned the input unchanged and still exited 0, shipping a site with no navigation. The pattern now matches both the collapsed and populated forms while anchoring the closing `],` to its own line (so it cannot over-consume plugins/customCss/the starlight() close), and a no-match now raises SidebarPatchError -> exit 1 instead of failing silently. I2 md-review SKILL.md still demanded `sidebar.order` on pages, which contradicts docs-conventions.md (its own stated source) after this branch moved ordering to _meta.yml. I3 clean_sample_data.clean_docs_content filtered on .md/.mdx only, so _meta.yml files survived the "complete reset", kept section dirs non-empty and left starlight-auto-sidebar loading stale metadata. M4 session-start.sh was missing progress_read.py and draft.py from the script list required by design 3.2. M5 add the missing .gemini/commands/terminology-management.toml so the Gemini command set (13) matches .claude/skills/. I1 document the social-crawler auth bypass in README as an accepted risk. middleware.ts is deliberately unchanged: the OG-preview tradeoff is the user's call, but the password gate must not be sold as a security boundary. Tests: 341 -> 349 (hero-image presence/absence, sidebar patching across both config shapes plus the shipped config, loud-failure case, and _meta.yml removal). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01US3TEe1Pu3mFHCjjwzq8Fg
模板預設 body 的 background-image 是註解掉的(純色背景), 但 --overlay-opacity 仍為 0.7,body::before 與 .main-pane 兩層遮罩 只是把 6% 亮度的背景再壓成近乎純黑,沒有作用對象。 - --overlay-opacity 0.7 -> 0,並註明僅在放入 /public/bg.jpg 後才調回 - 新增 --bg-chrome(+3%)、--bg-panel(+6%)、--bg-raised(+14%) 三個相對 --bg-l 的層級變數 - 導覽列/側欄、分隔線、行內程式碼底、搜尋 UI、hero 漸層、 LinkCard hover 原本寫死 8%/12%/20%/25%,--bg-l 一旦調高就會 比背景暗而層級反轉,全部改為相對推導 - header.header 與 .sidebar 各重複宣告兩次且同為 !important, 後者勝出導致遮罩設 0 時導覽列全透明;刪除「背景設定」區的重複 規則,統一由「導航列」「側邊欄」兩節設定 --bg-l 維持 6% 時各層級算出 9%/12%/20%,與原本寫死值一致, 預設外觀不變;唯一差異為導覽列由 ~5.3%(比內文底暗)改為 9%。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QjAPKNvmSWFd3tdJJ8xixx
灰階原本全部鎖在 hue 224 與絕對亮度,但檔頭宣稱「只需修改 H 值即可 換色」。gray-5/gray-6 又被 Starlight 內部引用約 48 處(表格框線、引言 左框線、摺疊區塊邊框、Header 分隔線、Pagination、行動選單、TOC 上框線、 expressive-code 邊框),所以先前把模板自身用法相對化後,這些內建元件 仍停在寫死的值。 - gray-1~4(文字色)色相改為 var(--bg-h),飽和度由 20/10/8/10% 降為 12/8/6/8%,避免換色相後內文被染色 - gray-5 / gray-6(表面色)改為沿用 --bg-raised / --bg-panel - 補上註解:層級採加法模型,僅適用深色模式 實測(astro build + astro preview,Playwright 讀取計算值): --bg-h 330 時表格框線由 rgb(44,48,58) 藍灰轉為 rgb(64,38,51) 粉, 與底色色相一致;--bg-l 16% 時框線/底色對比由 1.17(幾乎沒入背景) 回到 1.60。預設值下對比 1.46 -> 1.41,亮度相同、飽和度略增, 外觀無實質變化。三種情境下各層級皆亮於底色,無反轉。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QjAPKNvmSWFd3tdJJ8xixx
…faults theme 區塊先前只能靠 merge-json 手寫,且 init-doc 仍會把 overlay 問成 0.7 —— 那會把剛改成相對層級的預設值又蓋回純色背景下多餘的遮罩。 - style_decisions.py 新增 set-theme,欄位為 mode / overlay / palette / bg-h / bg-l,對應 custom.css 目前實際暴露的旋鈕 - 新增 parse_overlay(0-1)、parse_hue(0-360)、parse_lightness(0-100, 正規化為百分比字串,可填 6 或 6%)三個驗證器 - schema theme 區塊補上 bg_h / bg_l(optional string,向後相容) - init-doc SKILL.md Step 6:改為詢問 --bg-h / --bg-l 兩個旋鈕,明確要求 overlay 維持 0 除非真的放了 docs/public/bg.jpg,並補上 set-theme 指令 測試:新增 10 個案例涵蓋成功寫入、多次合併不覆蓋既有欄位、缺欄位報錯、 三個驗證器的邊界與非法值。全套 365 passed,schema 驗證通過。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QjAPKNvmSWFd3tdJJ8xixx
Step 6 的編號從 7 直接跳到 9,第 8 項不存在。將 9-12 重新編為 8-11, 使該節維持連續的 1-11。其他 Step 的編號經檢查皆無跳號。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QjAPKNvmSWFd3tdJJ8xixx
原樣搬移 docs/search/(斷詞、展開、摘要清理、HTML 鏡像改寫、 shim、驗收腳本)與 package.json 的 build/test/verify-search 腳本。 Pagefind 內建 jieba 為簡體詞庫,正體內容退化為逐字切分;改以 forceLanguage:en 重建索引,由 glossary 最長匹配 + Intl.Segmenter 自行斷詞。模板情境的調整(零術語降級、驗收設定化)於後續 commit。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0179yzJfRj89SWDjSwydoAAu
模板新專案的 glossary 只有 _meta,原版在此直接讓建置失敗; 改為合法檔案零術語時警告並退回純 Intl.Segmenter 斷詞(仍優於 簡體 jieba),檔案缺失或 JSON 損壞維持失敗。同時只納入 status=approved 的詞條,讓斷詞字典與正文用詞一致(Law 7)。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0179yzJfRj89SWDjSwydoAAu
stormlight 版 verify.mjs 的查詢集、展開詞與 ICU 片語都綁定該書 語料,健康句更依賴人工核對 1277 個術語確認無重疊。模板化改為: 語料查詢集移入 docs/search/verify-cases.json(附範例檔),設定 缺失時僅跑通用檢查並提示;健康句於執行期以 healthTerms 剔除 與 glossary 重疊的詞條;成詞率在零術語時略過;術語抽取改用 load-terms 共用模組,消除與建置端的重複實作。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0179yzJfRj89SWDjSwydoAAu
docs/search/README.md 收錄語料中立版的設計說明與 verify-cases 撰寫指引;final-proofread 由三關改四關,最後一關跑建置後的 verify-search;CLAUDE.md 補上搜尋層的技術棧與路徑;.gitignore 忽略 .superpowers/ 工作區。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0179yzJfRj89SWDjSwydoAAu
|
|
Correctness fixes: - middleware.ts: replace unanchored string-splice error-param removal with URLSearchParams.delete(), which was corrupting redirect targets - generate_nav.py: normalize flat slash-path keys before nav/sidebar generation so it matches the tree split_chapters.py actually writes - split_chapters.py: normalize_files() now raises on flat-leaf/nested key collisions instead of crashing with KeyError or silently losing data - merge_multi.py: merge_configs() no longer crashes on a missing optional "order" field; missing required fields now raise a clear error - init_create_progress.py: malformed chapter entries now raise instead of being silently dropped from translation-progress.json - docs/search/client/shim.mjs: fix a race in ensureBasePath() where concurrent search()/preload() calls could bypass basePath application - progress_read.py: --source filter now recomputes the total count instead of reporting against the unfiltered chapter count - api/site-auth.ts: wrap formData() parsing in try/catch to keep the old graceful-redirect behavior on unexpected content types - clean_sample_data.py: broaden except clauses to also catch UnicodeDecodeError; reuse generate_nav's line-anchored SIDEBAR_PATTERN to avoid over-consuming past the sidebar array's own closing bracket - .claude/hooks/pytest-check.py: raise the pytest timeout from 45s to 90s (measured cold-cache runs leave too little margin) Cleanup: - lib/site-auth-shared.ts: extract pinToOrigin() to remove the duplicated same-origin redirect check in api/site-auth.ts - scripts/_markdown_utils.py: add a shared iter_leaves() walker, used by init_create_progress.py where its stricter "must have pages" contract matches split_chapters.py's; generate_nav.py's own leaf walkers keep their existing, deliberately more lenient contract - merge_multi.py: add missing type hints Also fixes a uv deprecation warning by moving dev-dependencies from [tool.uv] to the standard [dependency-groups] table in pyproject.toml.
Owner
|
辛苦了,這個 PR 內容很扎實!審查後發現 15 個問題,已經全部處理並合併,這邊做個總結給你參考。 已修正的正確性問題
順手做的簡化
沒動的部分
另外中途發現 所有修正都補了對應的 pytest 測試(含錯誤情境),372 個 Python 測試 + 63 個 JS 測試全數通過,CI(terminology、GitGuardian)也是綠燈,已 squash merge 進 main。 |
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.
摘要
本 PR 合併兩條工作線:
fix/project-review的模板總整修(技能整併、腳本測試化、範本重置、安全強化),以及在其上的
feat/chinese-search中文搜尋強化層。主要變更
中文搜尋強化層(
docs/search/,新增)Pagefind 內建 jieba 為簡體詞庫,正體內容退化為逐字切分(來源專案實測:術語成詞率僅 9%,
高雜訊查詢命中全站 94% 頁面)。改以
forceLanguage: 'en'重建索引,由 glossary 最長匹配Intl.Segmenter自行斷詞,建置後注入隱藏鏡像,查詢端以 shim 包裝斷詞、子字串展開與摘要清理。來源專案實測成詞率 9% → 90%,索引縮小 0.5 MB。
模板化調整(相對 stormlight 原版):
不再讓建置失敗;檔案缺失或 JSON 損壞維持失敗
status: "approved"詞條,斷詞字典與正文用詞一致(Law 7)docs/search/verify-cases.json(附範例檔),健康句檢查於執行期自動剔除與 glossary 重疊的術語
/final-proofread由三關改四關,Gate 4 執行建置後的verify-searchdocs/search/README.md專案總整修
clean_sample_data全面重置、空 sidebar、placeholder 首頁;new-projectclone 後自動執行;移除維護者工作文件與已完成的 openspec changeoptimized-translating、pdf-translation(設計規格取代);模型路由寫進技能派遣步驟;review 迭代上限統一為 2;新增
md-review技能與docs-conventions/python rules;移除漂移的
.agents/副本、補齊.gemini/commandsscripts/、移除壞掉的permission-check hook;Python 版本由
.python-version追蹤多來源章節切分
split_chapters()重構為多來源遞迴結構,新增merge_multi.py合併各 PDF 章節設定write_meta_yml()),保留巢狀 sidebar 群組source欄位,progress_read.py --source過濾安全強化(預覽站 site-auth)
lib/site-auth-shared.ts共用sanitizeRedirect先剝除 C0 控制字元(/\t/evil.com類 payload原可繞過前綴檢查);成功/失敗兩條 redirect 分支各加獨立 origin 複驗
測試與 CI
tests/遷移為scripts/tests/(16 個測試檔),移除過時重複node:test撰寫 63 個單元測試(TDD)主題
--bg-h/--bg-l,移除純色背景下多餘遮罩style_decisions.py新增set-theme子命令,與 init-doc 預設對齊驗證
scripts/tests/pytest 全數通過(CI 同步執行)docs/:bun run test63 個測試全綠bun run build:零術語降級警告正確、404.html 正確跳過、索引重建完成bun run verify-search:通用檢查通過(斷詞健康 11 個多字詞),exit 0注意事項
docs/search/README.md建立自己的verify-cases.json