| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
feat(docs): add Booklin banner and hand-made share card Booklin now opens the README as a full-width banner, and the same artwork — an open book scattering into sparkles that settle into an ordered grid, which is the pipeline in one picture — backs the share card. Drop the Material social plugin along with Cairo and the imaging extra. It rendered a flat-purple card headlined with the nav label, which on the most-shared URL of the site read, in enormous type, "Home". The og:/twitter: tags move into the template override, where one macro now feeds <title>, og:title and twitter:title so the three cannot drift. Build time falls from ~35s to under a second. No text is baked into the card: every client renders og:title and og:description beside it already, so words in the image would only repeat them, and repeat them at whatever size the client picks. Formats differ on purpose. The banner is WebP (57 KB against 1.1 MB as PNG) because it is an inline content image. The card is JPEG — several crawlers, LinkedIn and Slack among them, will not render WebP as an og:image and fall back to no preview at all. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> | 2 个月前 | |
fix(evals): ignore negative replay usage counts (#284) * fix(evals): ignore negative replay usage counts Update _count function to only accept non-negative integers. * test(evals): cover negative replay usage in CLI * test(evals): cover negative usage in replay scoring * docs(evals): record negative usage regression evidence | 12 天前 | |
feat(docs): make the site indexable and shareable The published site had no Open Graph or Twitter tags, so every share on Twitter, LinkedIn, Slack or Discord rendered as a bare link. All nine pages also shipped the same inherited meta description, and the homepage title was the bare site_name — thirteen characters saying nothing about what the project does. Enable the Material social plugin for per-page og:/twitter: tags and a generated preview card. MkDocs resolves a page title from its nav entry before the frontmatter, and Material renders the homepage title as site_name with no hook to change it, so a small template override adds a `seo_title:` frontmatter key and a homepage case. Nav labels stay short; SERP titles carry keywords. The Guide page (the README, published into docs/) linked to `docs/faq.md` and friends — correct on GitHub, a 404 on the site. Nine links and images were dead there. The assemble step now strips that prefix on the way in, and rewrites the `../README.md` backlinks the docs pages use, so both surfaces stay correct without duplicating prose. Docs pages move to lowercase kebab-case slugs, with mkdocs-redirects keeping the old SHOUTING_CASE URLs alive for existing inbound links. Also: robots.txt pointing at the sitemap, SoftwareApplication JSON-LD on the homepage, noindex on the 404 page, and a human-length description for the Skill Reference, whose SKILL.md description is written for host agents and ran 398 characters. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> | 2 个月前 | |
docs: set custom domain booktoskill.is-a.dev Add docs/CNAME so mkdocs gh-deploy preserves the custom domain on every publish (gh-deploy --force overwrites gh-pages otherwise). Point site_url at the new domain. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> | 4 个月前 | |
fix(sanitize): fold Kangxi radicals to their ideographs in extracted text (#277) A PDF whose embedded font subset carries no correct Unicode mapping emits a Kangxi radical where a character belongs, so a Chinese book extracts "判断⼒" for "判断力". Nothing looks wrong on the page and the run reports success, so the corruption reaches full_text.txt, every grep, the chapter-heading match and the topic index. Each code point in U+2F00-U+2FDF has a Unicode compatibility decomposition, so the mapping is NFKC restricted to that block rather than a hand-written table. Nothing is removed, so the fold is kept out of the invisible removal count the CLI reports as a security strip. CJK Radicals Supplement (U+2E80-U+2EF3) is deliberately left alone: Unicode defines no decomposition for it, and some entries are ordinary kanji (U+2EEB is 匀, not a radical form of 二). Fixes #274 | 11 天前 | |
docs: state that scanned PDFs need OCR first (#132) Nothing in the README, SKILL.md or docs/ mentioned scanned PDFs or OCR, so the one case that cannot work was the one case with no documentation. A user hit it in practice, waited through a full extraction pass, and had to guess what to do next. The extractor now stops on the first pages (#130), but the failure should not be where people learn the limit. Adds a note under the PDF extractor table and an FAQ entry, both pointing at ocrmypdf, and states that not running OCR is a deliberate choice rather than a gap. Co-authored-by: Claude Opus 5 <noreply@anthropic.com> | 2 个月前 | |
feat(hosts): add Opencode skill discovery and validation (#216) * feat(hosts): add Opencode skill discovery and validation Adds OpenCode (sst/opencode) as a supported skill host, following the same shape as the Hermes Agent host: a validator lens, discovery paths in the converter spec, and tests for both. Validation (`tools/validate_skill.py --lens opencode`): - name must match the official pattern `^[a-z0-9]+(-[a-z0-9]+)*$` (lowercase alphanumeric with single hyphen separators) — stricter than the general Agent Skills default, so dots and underscores are rejected - only the five documented frontmatter keys are recognized: name, description, license, compatibility, metadata - no `allowed-tools` enforcement: OpenCode grants access through `permission.skill` in opencode.json, not frontmatter - no description soft limit; only the 1024-char hard cap applies Discovery (SKILL.md): - personal roots: ~/.config/opencode/skills (OpenCode-managed), plus the ~/.agents/skills and ~/.claude/skills compatibility roots - project roots: .opencode/skills, .agents/skills, .claude/skills - no trust gate, unlike Hermes: OpenCode discovers skills by walking up from the working directory to the git worktree Tests: - 11 `test_opencode_lens_*` cases in tests/test_validate_skill.py - tests/test_opencode_host_support.py, symmetric to the Hermes suite minus its trust-gate cases (OpenCode has no such model); guarded by a real bash probe so it skips instead of failing on hosts where the WSL stub makes `bash` unusable Docs: install.md, architecture.md, how-it-works.md, index.md and the three READMEs list OpenCode alongside the existing hosts. The README repository map also listed only three lenses; it now lists all five. Refs: https://opencode.ai/docs/skills * test(opencode): probe project layout from the project root The `project-opencode` case failed on CI (Linux) while passing locally, because the new host suite is skipped on hosts without a working bash — so the guard hid a real bug until CI ran it. The spec's extractor probe lists project-local roots other than Hermes' as CWD-relative paths (`.opencode/skills/...`, alongside `.github/`, `.claude/`, `.agents/`); only the Hermes block rewrites candidates against `$PROJECT_ROOT`. The test ran the project layout from `project/src/nested`, where no `.opencode/` exists, so `SCRIPT_PATH` stayed empty and the assertion compared the CWD against the extractor. Run project layouts from the project root and keep the personal layouts at a nested CWD, which is what actually demonstrates that personal roots resolve as absolute `$HOME/...` paths independent of depth. Verified under a real bash: the project case now resolves, and the three personal cases (`.config/opencode`, `.agents`, `.claude`) still resolve from `project/src/nested`. * fix(hosts): resolve project-local skills from the git worktree Project-local candidates were listed as bare CWD-relative paths (`.opencode/skills/...`, `.github/...`, `.claude/...`, `.agents/...`), so the converter was only found when the agent happened to sit at the project root. From a nested directory such as `project/src/nested` the probe returned nothing and Step 2 failed with "Could not find scripts/extract.py". That contradicts how the hosts behave: OpenCode walks up from the working directory to the git worktree, so project skills are meant to be reachable from anywhere inside the project. Prepend the same four roots resolved against `$PROJECT_ROOT` (already computed by the probe) when it is non-empty, keeping the CWD-relative forms afterwards so behaviour outside a git repository is unchanged: ```bash if [ -n "$PROJECT_ROOT" ]; then CANDIDATES+=( "$PROJECT_ROOT/.github/skills/book-to-skill/scripts/extract.py" "$PROJECT_ROOT/.claude/skills/book-to-skill/scripts/extract.py" "$PROJECT_ROOT/.agents/skills/book-to-skill/scripts/extract.py" "$PROJECT_ROOT/.opencode/skills/book-to-skill/scripts/extract.py" ) fi ``` Tests: the nested-directory case is now asserted rather than worked around. `test_opencode_extractor_probe_discovers_supported_layouts` runs every layout from `project/src/nested`, and a new `test_opencode_project_probe_resolves_project_root_from_nested_cwd` covers `.opencode`, `.agents` and `.claude` from `project/src/nested/deeper`. The previous version ran the project layout from the project root, which hid the bug instead of catching it. Also fixes two test-infrastructure faults that made these tests skip on Windows and therefore unable to catch anything: * Bash detection invoked a bare `bash`, which CreateProcess resolves against the system directory before PATH, always picking the WSL stub (`C:\Windows\System32\bash.exe`) even though a working Git bash exists. Now tries absolute candidates — `$OPENCODE_GIT_BASH_PATH`, Git's `../bin/bash.exe`, `/usr/bin/bash` — and validates with `bash -c true`. * Paths returned by Git bash are in MSYS form (`/tmp/...` for `$HOME`) and never compared equal to `pathlib` paths. `_resolve()` now normalises through `cygpath -w` on Windows. Negative control: reverting the SKILL.md change fails exactly the four nested/project cases (4 failed, 12 passed); restoring it returns 16 passed. * fix(hosts): resolve review findings on the rebased selection policy - SKILL.md: remove the duplicated pre-#125 rule-6 orphan left by the conflict resolution; add OpenCode to the host prompt (rule 6) so the unknown-host question names every supported host; repair the frontmatter delimiter that the rebase glued to the description line. - tests/test_scope_selection_contract.py: stop freezing the selection list at exactly six rules and the pre-#209 prompt sentence; assert one contiguous 1..N list plus the required policy instead (review request, 2026-09-22). - tests/test_opencode_host_support.py: same de-freezing for the unknown-host prompt assertion (#209 legitimately grew that list). - tools/validate_skill.py: fix the lens table so the OpenClaw entry keeps its own keys and OpenCode no longer carries a duplicated enforces_allowed_tools/name_pattern pair. Windows-local gates: 695 passed, 16 skipped; the 17 test_hermes failures are the documented WSL-stub bash artifact (Linux CI green). ruff clean; validate_skill passes for claude and opencode lenses. --------- Co-authored-by: wgm66 <wgm66@users.noreply.github.com> | 24 天前 | |
docs: add Codex to host lists (#278) | 12 天前 | |
feat(hosts): add Opencode skill discovery and validation (#216) * feat(hosts): add Opencode skill discovery and validation Adds OpenCode (sst/opencode) as a supported skill host, following the same shape as the Hermes Agent host: a validator lens, discovery paths in the converter spec, and tests for both. Validation (`tools/validate_skill.py --lens opencode`): - name must match the official pattern `^[a-z0-9]+(-[a-z0-9]+)*$` (lowercase alphanumeric with single hyphen separators) — stricter than the general Agent Skills default, so dots and underscores are rejected - only the five documented frontmatter keys are recognized: name, description, license, compatibility, metadata - no `allowed-tools` enforcement: OpenCode grants access through `permission.skill` in opencode.json, not frontmatter - no description soft limit; only the 1024-char hard cap applies Discovery (SKILL.md): - personal roots: ~/.config/opencode/skills (OpenCode-managed), plus the ~/.agents/skills and ~/.claude/skills compatibility roots - project roots: .opencode/skills, .agents/skills, .claude/skills - no trust gate, unlike Hermes: OpenCode discovers skills by walking up from the working directory to the git worktree Tests: - 11 `test_opencode_lens_*` cases in tests/test_validate_skill.py - tests/test_opencode_host_support.py, symmetric to the Hermes suite minus its trust-gate cases (OpenCode has no such model); guarded by a real bash probe so it skips instead of failing on hosts where the WSL stub makes `bash` unusable Docs: install.md, architecture.md, how-it-works.md, index.md and the three READMEs list OpenCode alongside the existing hosts. The README repository map also listed only three lenses; it now lists all five. Refs: https://opencode.ai/docs/skills * test(opencode): probe project layout from the project root The `project-opencode` case failed on CI (Linux) while passing locally, because the new host suite is skipped on hosts without a working bash — so the guard hid a real bug until CI ran it. The spec's extractor probe lists project-local roots other than Hermes' as CWD-relative paths (`.opencode/skills/...`, alongside `.github/`, `.claude/`, `.agents/`); only the Hermes block rewrites candidates against `$PROJECT_ROOT`. The test ran the project layout from `project/src/nested`, where no `.opencode/` exists, so `SCRIPT_PATH` stayed empty and the assertion compared the CWD against the extractor. Run project layouts from the project root and keep the personal layouts at a nested CWD, which is what actually demonstrates that personal roots resolve as absolute `$HOME/...` paths independent of depth. Verified under a real bash: the project case now resolves, and the three personal cases (`.config/opencode`, `.agents`, `.claude`) still resolve from `project/src/nested`. * fix(hosts): resolve project-local skills from the git worktree Project-local candidates were listed as bare CWD-relative paths (`.opencode/skills/...`, `.github/...`, `.claude/...`, `.agents/...`), so the converter was only found when the agent happened to sit at the project root. From a nested directory such as `project/src/nested` the probe returned nothing and Step 2 failed with "Could not find scripts/extract.py". That contradicts how the hosts behave: OpenCode walks up from the working directory to the git worktree, so project skills are meant to be reachable from anywhere inside the project. Prepend the same four roots resolved against `$PROJECT_ROOT` (already computed by the probe) when it is non-empty, keeping the CWD-relative forms afterwards so behaviour outside a git repository is unchanged: ```bash if [ -n "$PROJECT_ROOT" ]; then CANDIDATES+=( "$PROJECT_ROOT/.github/skills/book-to-skill/scripts/extract.py" "$PROJECT_ROOT/.claude/skills/book-to-skill/scripts/extract.py" "$PROJECT_ROOT/.agents/skills/book-to-skill/scripts/extract.py" "$PROJECT_ROOT/.opencode/skills/book-to-skill/scripts/extract.py" ) fi ``` Tests: the nested-directory case is now asserted rather than worked around. `test_opencode_extractor_probe_discovers_supported_layouts` runs every layout from `project/src/nested`, and a new `test_opencode_project_probe_resolves_project_root_from_nested_cwd` covers `.opencode`, `.agents` and `.claude` from `project/src/nested/deeper`. The previous version ran the project layout from the project root, which hid the bug instead of catching it. Also fixes two test-infrastructure faults that made these tests skip on Windows and therefore unable to catch anything: * Bash detection invoked a bare `bash`, which CreateProcess resolves against the system directory before PATH, always picking the WSL stub (`C:\Windows\System32\bash.exe`) even though a working Git bash exists. Now tries absolute candidates — `$OPENCODE_GIT_BASH_PATH`, Git's `../bin/bash.exe`, `/usr/bin/bash` — and validates with `bash -c true`. * Paths returned by Git bash are in MSYS form (`/tmp/...` for `$HOME`) and never compared equal to `pathlib` paths. `_resolve()` now normalises through `cygpath -w` on Windows. Negative control: reverting the SKILL.md change fails exactly the four nested/project cases (4 failed, 12 passed); restoring it returns 16 passed. * fix(hosts): resolve review findings on the rebased selection policy - SKILL.md: remove the duplicated pre-#125 rule-6 orphan left by the conflict resolution; add OpenCode to the host prompt (rule 6) so the unknown-host question names every supported host; repair the frontmatter delimiter that the rebase glued to the description line. - tests/test_scope_selection_contract.py: stop freezing the selection list at exactly six rules and the pre-#209 prompt sentence; assert one contiguous 1..N list plus the required policy instead (review request, 2026-09-22). - tests/test_opencode_host_support.py: same de-freezing for the unknown-host prompt assertion (#209 legitimately grew that list). - tools/validate_skill.py: fix the lens table so the OpenClaw entry keeps its own keys and OpenCode no longer carries a duplicated enforces_allowed_tools/name_pattern pair. Windows-local gates: 695 passed, 16 skipped; the 17 test_hermes failures are the documented WSL-stub bash artifact (Linux CI green). ruff clean; validate_skill passes for claude and opencode lenses. --------- Co-authored-by: wgm66 <wgm66@users.noreply.github.com> | 24 天前 | |
feat(docs): make the site indexable and shareable The published site had no Open Graph or Twitter tags, so every share on Twitter, LinkedIn, Slack or Discord rendered as a bare link. All nine pages also shipped the same inherited meta description, and the homepage title was the bare site_name — thirteen characters saying nothing about what the project does. Enable the Material social plugin for per-page og:/twitter: tags and a generated preview card. MkDocs resolves a page title from its nav entry before the frontmatter, and Material renders the homepage title as site_name with no hook to change it, so a small template override adds a `seo_title:` frontmatter key and a homepage case. Nav labels stay short; SERP titles carry keywords. The Guide page (the README, published into docs/) linked to `docs/faq.md` and friends — correct on GitHub, a 404 on the site. Nine links and images were dead there. The assemble step now strips that prefix on the way in, and rewrites the `../README.md` backlinks the docs pages use, so both surfaces stay correct without duplicating prose. Docs pages move to lowercase kebab-case slugs, with mkdocs-redirects keeping the old SHOUTING_CASE URLs alive for existing inbound links. Also: robots.txt pointing at the sitemap, SoftwareApplication JSON-LD on the homepage, noindex on the 404 page, and a human-length description for the Skill Reference, whose SKILL.md description is written for host agents and ran 398 characters. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> | 2 个月前 | |
feat(docs): make the site indexable and shareable The published site had no Open Graph or Twitter tags, so every share on Twitter, LinkedIn, Slack or Discord rendered as a bare link. All nine pages also shipped the same inherited meta description, and the homepage title was the bare site_name — thirteen characters saying nothing about what the project does. Enable the Material social plugin for per-page og:/twitter: tags and a generated preview card. MkDocs resolves a page title from its nav entry before the frontmatter, and Material renders the homepage title as site_name with no hook to change it, so a small template override adds a `seo_title:` frontmatter key and a homepage case. Nav labels stay short; SERP titles carry keywords. The Guide page (the README, published into docs/) linked to `docs/faq.md` and friends — correct on GitHub, a 404 on the site. Nine links and images were dead there. The assemble step now strips that prefix on the way in, and rewrites the `../README.md` backlinks the docs pages use, so both surfaces stay correct without duplicating prose. Docs pages move to lowercase kebab-case slugs, with mkdocs-redirects keeping the old SHOUTING_CASE URLs alive for existing inbound links. Also: robots.txt pointing at the sitemap, SoftwareApplication JSON-LD on the homepage, noindex on the 404 page, and a human-length description for the Skill Reference, whose SKILL.md description is written for host agents and ran 398 characters. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> | 2 个月前 | |
feat(skill): optional GitHub publishing for generated skills (#102) Step 10 told people to share a generated skill with `gh skill publish`, which only reaches the Copilot ecosystem. Step 11 adds an opt-in path to a GitHub repo any Agent Skills host can install from, and nothing about it is automatic: the offer appears once, after the Step 9.5 scan passes, and a decline ends it. Visibility is a closed question of its own, asked separately from the offer, and the gate opens only when the answer is the word `public`. An earlier draft searched the reply for the substring, which "public domain", "publicly available" and the Step 10 trigger word "publish" would all have satisfied — in a project whose own benchmark books are public-domain titles. The copyright gate stacks on top: skills derived from third-party books stay private, and access to internal material is not permission to disclose it. Publishing from inside an existing repository is done from a scratch copy, because `git init` in place would record the skill as a gitlink with no `.gitmodules` and fresh clones of the outer project would silently omit it. The report says so, and says how to update later, rather than leaving that to be discovered at the next fold-in. The report's discoverability line is filled from the destination actually used, including the case where it must say a host will NOT see the skill. | 2 个月前 |
| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
| 2 个月前 | ||
| 12 天前 | ||
| 2 个月前 | ||
| 4 个月前 | ||
| 11 天前 | ||
| 2 个月前 | ||
| 24 天前 | ||
| 12 天前 | ||
| 24 天前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 2 个月前 |