v0.4.0 — The Living Grimoire: self-updating engine + Editorial Constellation frontend#10
Open
vedantggwp wants to merge 13 commits into
Open
v0.4.0 — The Living Grimoire: self-updating engine + Editorial Constellation frontend#10vedantggwp wants to merge 13 commits into
vedantggwp wants to merge 13 commits into
Conversation
…helper - lib/present/css.ts (1,462 lines) -> 13 focused css/ partials assembled in fixed order by css/index.ts; output verified byte-identical on sample-wiki and examples/mcp fixtures - css-modes.ts absorbed into read/graph/search partials (overrides still emitted last to preserve byte order) - 8 duplicate esc() definitions -> lib/present/esc.ts - theme-toggle script -> lib/present/js/runtime.ts - 193/193 tests green, dist bundles regenerated
- #1: derive slugs like papyr-core (basename + slugify lower/strict); nested-taxonomy wikis now render all articles instead of 0; new article.category field; collision warning for duplicate basenames; slugify promoted to an explicit dependency - #6: strip leading h2 that slug-matches the title, drop it from headings so TOC stays consistent - #7: hub lead strips terminal periods, caps at 120 chars on a word boundary, phrases level audiences as 'a/an {level} audience' - #8: rewrite legacy /client-config/{slug} hrefs alongside #/note/, warn on survivors - #5: treemap labels full-contrast --color-text on every tier; tier conveyed by tint/stroke/dot; .gap-card explicit text color - new nested-wiki fixture; 19 new tests; 212/212 green
Deterministic half of the self-updating engine, following the v0.3.1 hybrid-enforcement pattern (lib emits evidence, skills apply judgment): - lib/update-policy.ts: _config/update.md parser (zod frontmatter + watchlist/exclusion body sections) with conservative defaults when absent — the policy file replaces interactive checkpoints for headless runs - lib/source-ledger.ts: cross-run dedup ledger (normalizeUrl, approved-sources.md any-shape URL extraction, raw/ frontmatter, lastUpdate derived from collected dates + log headers) - lib/freshness.ts: per-article staleness tiers; checked beats updated; dateless articles are unknown, never stale - lib/connections.ts: unlinked-pair candidates (shared tags/sources/ component), exclusion-filtered, scored, capped at 20 - lib/compile.ts Step 12: emits freshness.json + update-context.json always, connection-candidates.json conditionally; stale conditional artifacts now removed (incl. taxonomy-proposal.json); notes.json gains updated/checked/evergreen; frontmatter extraction resolves nested-taxonomy files via wiki walk (compile-side issue #1) - lib/serve.ts: loads freshness.json null-safely, appends Stale Articles to grimoire_coverage_gaps, version 0.4.0 - lib/slug.ts: shared slug derivation (papyr-core lockstep) - gray-matter promoted to explicit dependency - 53 new tests, 265/265 green
…apter The judgment half of the self-updating engine (Phase 2): - skills/update/SKILL.md: headless scheduled editorial pass — never asks, policy file + PR review replace the two taste checkpoints; 12 steps with explicit degradation ladder (pr -> branch -> digest-only), no-op runs produce no empty PRs, same-day reruns reuse the open PR - skills/update/references: digest + PR body templates (below-threshold sources stay visible so reviewers can promote them) - skills/update/assets/github-workflow.yml: weekly cron + manual trigger via claude-code-action@v1 automation mode (inputs verified against current docs), allowedTools allowlist, recursion-guard note - skills/scout: Delta Mode — temporal/open-questions/gaps/watchlist angles, hard cross-run dedup against update-context.json knownUrls - skills/init scaffolds _config/update.md (template round-trips through lib/update-policy.ts); skills/run suggests update --setup - docs/self-updating.md: full setup guide incl. org PR-permission toggle, GITHUB_TOKEN recursion guard, serve restart after merge - 265/265 tests green
Phase 3a of the Editorial Constellation frontend: - lib/present/color.ts: OKLCH math (Ottosson), categorical ramp from the palette accent (achromatic-safe), sRGB mixing, WCAG contrast — pure - css/tokens.ts: motion tokens (--dur-1..4 scaled by motion level, 0.01ms for none), --ease-out/in-out/spring (linear() behind @supports), strict 4px spacing grid --space-1..10 (#4) + density-swapped semantic tokens (--pad-card/--pad-card-lg/--pad-section/--gap-grid/--gap-stack), z-layer scale, --cat-0..7 light+dark from the accent hue - config.ts: motion/density validated unions (warn + default on unknown), individual font-heading/font-body/font-mono overrides with font-display alias (#3), modes: list with read forced on (#9) - html.ts: <html class="motion-* density-*">, nav filtered by enabled modes; index.ts gates generators + hub cards + recommended badge (#9) - fonts now load only via <link> (removed the double-fetching CSS @import) - bento/cards consume semantic spacing tokens - 34 new tests incl. AA contrast matrix across all 8 palettes x 2 themes (issue #5 regression); 299/299 green
… issue #2 Phase 3b: - site/read/{slug}/index.html per article: 3-col shell at depth 2, real prev/next links (centrality order), sidebar links with aria-current, per-article TOC with scroll spy, accurate per-page reading progress - read/index.html is now a reading index: centrality-ordered rows with summaries, continue-reading pickup (localStorage), and a redirect shim keeping legacy read/index.html#slug deep links working on file:// - known wikilinks rewritten to real ../{slug}/index.html routes at build time; unresolved ones stay marked new and inert (aria-disabled) - cross-document View Transitions: @view-transition navigation auto, page cross-fade + 8px slide, title morphs via vta-{slug} names, nav brand morph — all inside prefers-reduced-motion: no-preference, fully omitted for motion: none - shared .reveal utility with the JS-presence safety gate (html.js) so no-JS readers always see content; motion runtime script in every shell - pageShell/navBar/htmlHead gain depth param; search results navigate to per-article routes; site/ cleared before generation (no stale pages) - 13 new route tests incl. disabled-modes workspace; 307/307 green
… tilt Phase 3c: - lib/present/layout.ts: deterministic force layout (FNV-seeded, no randomness — identical inputs produce identical sites) capped at 80 nodes + squarified treemap (Bruls et al) for the d3-free gaps mode - js/constellation.ts: ambient canvas behind the hero drawing the wiki's REAL knowledge graph — seeded sine drift, faint edges, accent glow on the top-3 nodes, pointer attraction with label surfacing; delta-clamped rAF, pauses on hidden tab, single static frame when motion is off, dpr-aware, theme-toggle repaint, aria-hidden - js/runtime.ts: count-up stats (IO-triggered, 600ms ease-out cubic) and rAF-throttled card tilt + specular glow (hover:hover + pointer:fine + motion gates); runtime script moved to top of <body> so inline page scripts can rely on GRIMOIRE_MOTION_OK and reveals never flash - css/hub.ts: hero entrance choreography (staggered rise), scroll-driven parallax behind @supports (animation-timeline: scroll()) — static fallback everywhere else, tilt transforms driven by --tilt-max token - bento cards join the shared .reveal stagger - 14 new tests (layout determinism/bounds, treemap area/overlap/ proportionality, hub markup); 320/320 green
…shness Phase 3d: - js/popover.ts: Wikipedia-style wikilink hover previews from page-local window.LINK_PREVIEWS (only the slugs each page references, <2KB); native Popover API with fixed-div fallback, 250ms hover intent, focus/Escape keyboard support, skipped on touch - article pages gain a 'Linked from' backlinks panel (title + teaser), a numbered Sources section with domain chips, source-count chip links to #sources, confidence badges explain themselves via title text - freshness badges (aging/stale) on article meta, driven by the update engine's freshness.json via a zod-tolerant loader (lib/present/ freshness.ts) — pre-v0.4 workspaces degrade silently; SiteData gains freshness - TOC scroll-spy upgraded to a sliding accent marker (translateY + height transitions) instead of class flips - reading progress takes the pure-CSS scroll-timeline path where supported, scroll-listener fallback elsewhere - typography polish: text-wrap pretty, ::selection, scroll-margin-top on [id], hanging punctuation on quotes, mobile hyphenation - 325/325 green
Phase 3e: - graph: nodes colored from the palette's --cat-* OKLCH ramp (theme toggle recolors instantly, no more hardcoded schemeTableau10); deterministic warm-start positions from layout.ts (no spawn explosion); click = 1-hop focus mode (Esc/background clears), dblclick opens the article; cluster-hull toggle (top-5 tags, 3+ members, 6% fill); panel gains the summary and an Open in Read link - gaps: d3 dropped entirely — build-time squarified treemap rendered as absolutely-positioned percent-geometry DOM cells (page ~290KB -> 21KB); cells are keyboard-focusable with descriptive aria-labels; Coverage | Freshness lens recolors by per-tag staleness from the update engine; CSS-only staggered pop-in - quiz: real 3D flip (grid-stacked faces, preserve-3d, spring easing, instant under reduced motion), card slide-in, streak chip at 3+, and a CSS-only 12-particle confetti burst at 3/5/10 in --cat-* colors - feed: update-run digest entries (the SKILL.md Step 9 log contract) render as accent-bordered stat-chip cards; newest dot pulses briefly - search: arrow-key result navigation (aria-activedescendant), Enter to open, result rows finally navigate on click, staggered entrance, empty state offers top-tag recovery pills, kbd hint row - examples/mcp full-site weight: 628KB total (was ~800KB) - 334/334 green
- version 0.4.0 in package.json + plugin.json - roadmap Phase 8 (The Living Grimoire), decisions.md entry with rejected alternatives, changelog entry, SOUL principle 5 clause (control relocates to policy + PR review in scheduled mode) - architecture.md: update stage row + new workspace artifacts - design-config template: real motion/density semantics, modes: key, individual font overrides documented - README + CLAUDE.md skill tables gain update - visual QA pass on examples/mcp over http: hub constellation, article freshness badge, gaps treemap verified by screenshot; fixed the double-legend bug (.gaps-legend[hidden]), full-width Recommended badge, and the favicon 404 (inline SVG favicon) - 334/334 green, bundles rebuilt
The plugin itself never needs an API key — locally (interactive or cron) /grimoire:update runs on the user's existing Claude Code login like every other skill. The one place a credential is needed is the GitHub Actions runner (fresh VM, no Claude login), and the right default there for a Claude Code plugin audience is the subscription OAuth token from `claude setup-token` (CLAUDE_CODE_OAUTH_TOKEN). API key demoted to the metered-billing alternative across the workflow template, --setup instructions, and docs; local cron called out as the zero-credential path.
README rebuilt against a documentation-quality rubric (value clarity, time-to-first-success, information architecture, audience fit, evidence freshness, completeness, scannability, honesty): - stale v0.3.0 badges and 183-test count corrected (v0.4.0, 334) - self-updating loop promoted to a first-class section with both schedulers and the subscription-auth story (no API key narrative) - 'Why Grimoire' positioning vs notes apps / chatbots / RAG pipelines - frontend + MCP sections re-grounded in shipped v0.4 behavior (per-article routes, view transitions, constellation, freshness lens) - 8-skill table with corrected heading; duplicate install removed; CONTRIBUTING/SECURITY/docs linked PII sweep: .mcp.json (machine-specific absolute paths) untracked and gitignored; no emails, names, or local paths remain in tracked docs.
Pre-landing adversarial review findings (all fixed): - [P1] JSON.stringify does not escape '<' — frontmatter-derived strings (title/summary/tags from scouted web sources) embedded via inline <script> globals (HUB_GRAPH, SEARCH_ARTICLES, LINK_PREVIEWS, QUIZ_CARDS, GRAPH_DATA) could carry '</script>' and execute attacker script in the reader's browser. New jsonForScript() escapes < to \u003c (+ U+2028/2029) at every embed site; round-trips losslessly - [P1] graph detail panel joined raw frontmatter tags into innerHTML — now filled via textContent like the summary; panel slug URL-encoded - [P2] update policy now rejects inverted staleness windows (aging < fresh), which previously made the aging tier unreachable - GitHub Actions template hardened: id-token grant dropped (OAuth-token auth needs no OIDC), gh narrowed to pr/auth subcommands, blast-radius note added for the untrusted-web-ingestion surface +4 regression tests (script-breakout neutralization, separator escapes, policy ordering); 338/338 green; bundles rebuilt
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.
Summary
Grimoire learns the maintain half of the LLM-maintained-wiki pattern, and the frontend gets the overhaul to match. 13 commits, version 0.3.1 → 0.4.0, tests 193 → 338.
Self-updating engine
/grimoire:update— headless scheduled editorial pass: delta scout (angles from the wiki's own open questions, coverage gaps, and a user watchlist; cross-run URL dedup) → policy-gated batch ingest → connection mining with persistent exclusions → staleness verification → digest → PR-gated shipping (never touches the default branch; no-op runs create no PRs)lib/update-policy.ts,lib/source-ledger.ts,lib/freshness.ts,lib/connections.ts; compile now emitsfreshness.json,connection-candidates.json,update-context.jsongrimoire_coverage_gaps--setup) authenticates with a subscription token (claude setup-token) — no API key requiredEditorial Constellation frontend
lib/present/color.ts)read/{slug}/) with cross-document View Transitions and title morphs; legacy hash links redirectprefers-reduced-motionand themotion:config; WCAG AA contrast verified per palette in testsQuality & housekeeping
esc()/slug helpers.mcp.jsonuntracked, local paths genericized)Pre-Landing Review
Adversarial review (fresh-context subagent) found 4 issues — all fixed in
fix(present): harden inline script embeds:</script>breakout XSS via inline JSON embeds carrying frontmatter from scouted sources → newjsonForScript()at all 5 embed sitesinnerHTML→textContentid-tokengrant dropped,ghnarrowed, blast-radius note addedCleared by review: serve slug traversal (regex-blocked),
rmSync(site/)(gated on workspace checks), layout NaN/div-zero guards, feed$1injection.Test Coverage
338 tests across 20 suites (was 193). New suites cover the update substrate (policy parsing, URL normalization, freshness tier boundaries with injected clocks, connection candidates), the token layer (4px-grid lint, motion scaling, AA contrast matrix across all 8 palettes × 2 themes), routes (per-article files, disabled modes), deterministic layouts (force + treemap), and XSS regression (
</script>neutralization). Visual QA by screenshot over http: hub constellation, article freshness badges, gaps lens.Verification on first real run
Three things only a live run can confirm (designed fallbacks for each, see docs/self-updating.md):
/grimoire:update --dry-runend-to-end, plugin auto-load in headless CI, WebSearch availability under the Actions runner (watchlist URLs are the fallback).Issues
Closes #1
Closes #2
Closes #3
Closes #4
Closes #5
Closes #6
Closes #7
Closes #8
Closes #9
🤖 Generated with Claude Code