@immediately-run/grove 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/README.md +43 -115
  2. package/llms.txt +6 -2
  3. package/package.json +20 -8
  4. package/src/App.tsx +11 -7
  5. package/src/GroveApp.css +485 -85
  6. package/src/GroveWiki.tsx +176 -54
  7. package/src/components/AssetImage.tsx +1 -12
  8. package/src/components/Backlinks.tsx +2 -2
  9. package/src/components/Catalogue.test.tsx +157 -0
  10. package/src/components/ContentTheme.test.tsx +146 -0
  11. package/src/components/ContentTheme.tsx +111 -0
  12. package/src/components/DocList.infinite.test.tsx +177 -0
  13. package/src/components/DocList.tsx +82 -9
  14. package/src/components/Drawer.tsx +14 -2
  15. package/src/components/EntryHeader.tsx +24 -15
  16. package/src/components/EntryImage.test.tsx +210 -0
  17. package/src/components/EntryImage.tsx +47 -0
  18. package/src/components/Galleries.test.tsx +98 -0
  19. package/src/components/GroveAgent.test.tsx +330 -0
  20. package/src/components/GroveAgent.tsx +269 -149
  21. package/src/components/GroveNav.test.tsx +229 -0
  22. package/src/components/GroveNav.tsx +69 -20
  23. package/src/components/Icon.tsx +0 -1
  24. package/src/components/InlineProse.tsx +37 -0
  25. package/src/components/LayoutGallery.tsx +65 -0
  26. package/src/components/PageView.tsx +19 -4
  27. package/src/components/Search.test.tsx +113 -0
  28. package/src/components/Search.tsx +53 -18
  29. package/src/components/Sidebar.test.tsx +135 -0
  30. package/src/components/Sidebar.tsx +114 -12
  31. package/src/components/TableOfContents.test.tsx +27 -16
  32. package/src/components/ThemeAssets.test.tsx +109 -0
  33. package/src/components/ThemeAssets.tsx +63 -0
  34. package/src/components/ThemeGallery.tsx +31 -0
  35. package/src/components/Timeline.tsx +5 -2
  36. package/src/components/WikiLink.tsx +2 -2
  37. package/src/data/catalogue.ts +54 -0
  38. package/src/data/themeFonts.ts +58 -0
  39. package/src/data/themes.ts +44 -4
  40. package/src/devfs.d.ts +5 -4
  41. package/src/hooks/{useCorpusMetadata.ts → useBundleMetadata.ts} +6 -6
  42. package/src/hooks/useContentComponents.ts +1 -1
  43. package/src/hooks/useEditAffordance.ts +99 -0
  44. package/src/hooks/useOpenWikiBoot.ts +1 -1
  45. package/src/hooks/useOverlayFocusDismiss.test.tsx +139 -0
  46. package/src/hooks/useOverlayFocusDismiss.ts +118 -0
  47. package/src/hooks/useScrollReset.test.tsx +132 -0
  48. package/src/hooks/useScrollReset.ts +52 -0
  49. package/src/index.css +9 -2
  50. package/src/lib/agentPrompt.test.ts +96 -0
  51. package/src/lib/agentPrompt.ts +86 -0
  52. package/src/lib/agentTools.test.ts +115 -0
  53. package/src/lib/agentTools.ts +132 -0
  54. package/src/lib/agentTranscript.ts +50 -0
  55. package/src/lib/assetPath.test.ts +36 -0
  56. package/src/lib/assetPath.ts +42 -0
  57. package/src/lib/collectionCalls.test.ts +69 -0
  58. package/src/lib/content.test.ts +10 -2
  59. package/src/lib/content.ts +7 -0
  60. package/src/lib/contentRoot.ts +16 -1
  61. package/src/lib/contentStylesheet.test.ts +80 -0
  62. package/src/lib/contentStylesheet.ts +103 -0
  63. package/src/lib/corpusScan.test.ts +37 -3
  64. package/src/lib/corpusScan.ts +17 -2
  65. package/src/lib/editTarget.test.ts +108 -0
  66. package/src/lib/editTarget.ts +93 -0
  67. package/src/lib/inlineProse.parity.test.ts +52 -0
  68. package/src/lib/layout.ts +29 -0
  69. package/src/lib/openWiki.test.ts +46 -5
  70. package/src/lib/openWiki.ts +18 -3
  71. package/src/lib/pageVariants.test.tsx +87 -0
  72. package/src/lib/queries.test.ts +33 -1
  73. package/src/lib/queries.ts +33 -1
  74. package/src/lib/reachCard.test.ts +94 -0
  75. package/src/lib/reachCard.ts +112 -0
  76. package/src/lib/shell.ts +17 -0
  77. package/src/lib/starterSweep.test.tsx +160 -0
  78. package/src/lib/starterSweep.ts +97 -0
  79. package/src/lib/themeAssets.test.ts +135 -0
  80. package/src/lib/themeAssets.ts +143 -0
  81. package/src/lib/themeSelection.test.ts +52 -0
  82. package/src/lib/themeSelection.ts +59 -0
  83. package/src/mdxComponents.ts +4 -0
  84. package/viewer-manifest.schema.json +37 -0
  85. package/viewer.manifest.json +133 -6
package/README.md CHANGED
@@ -1,122 +1,50 @@
1
- # immediately.run — starter template
1
+ # Grove — the wiki viewer for [immediately.run](https://immediately.run)
2
+
3
+ Grove renders an MDX corpus as a wiki: plain interlinked entries with frontmatter,
4
+ a sidebar, search, backlinks, tags, timelines — transpiled in the browser, no
5
+ server, no build step at runtime. It ships three ways:
6
+
7
+ 1. **As a fork** — copy this repo, replace `content/` with your entries, push,
8
+ open it on immediately.run. Your corpus, your code, one repo.
9
+ 2. **As the dispatched viewer** — a corpus mounted into a running Grove via the
10
+ `open-wiki` task; the wiki is somebody else's directory and Grove reads it
11
+ through the mount (the engine never assumes it owns the corpus).
12
+ 3. **As a pinned library** — `@immediately-run/grove` as an ordinary npm
13
+ dependency: compose `src/lib.ts`'s helpers and the component vocabulary into
14
+ your own viewer.
15
+
16
+ The composition surface — every component, its tier and overridability, the
17
+ frontmatter keys the engine reads — is declared in
18
+ [`viewer.manifest.json`](./viewer.manifest.json) and summarized in [`llms.txt`](./llms.txt).
19
+ The themes and layouts are compared live by the `Themes` and `Layouts` entries of
20
+ the sample corpus; the theming contract (token-only themes, declared faces,
21
+ checked contrast) is stated in [`THEMING.md`](./THEMING.md). What the engine owns
22
+ versus what content may reach is [`docs/ENGINE_BOUNDARY.md`](./docs/ENGINE_BOUNDARY.md).
23
+
24
+ ## Running locally
2
25
 
3
- A ready-to-run starter for building apps on
4
- [immediately.run](https://immediately.run): React + TypeScript + Vite, wired to
5
- the brand design system, with the project layout immediately.run expects.
6
-
7
- ## Try it instantly
8
-
9
- Try this template on [immediately.run](https://immediately.run/present/github/immediately-run/new-project-template/main/files/src/App.tsx)
10
-
11
- > Using this as a starting point for your own app? After you push to your repo,
12
- > update the link above to
13
- > `https://immediately.run/present/github/<owner>/<repo>/<ref>/files/src/App.tsx`.
14
-
15
- ## Use this template
16
-
17
- 1. Create a new repo from this template (or copy the files).
18
- 2. `npm install`
19
- 3. `npm run dev` and start editing `src/App.tsx`.
20
- 4. Push to GitHub and open it on immediately.run with the link above.
21
-
22
- ## Fast loading on immediately.run (auto-cache)
23
-
24
- immediately.run normally reads your sources from the GitHub API, which is slow
25
- and rate-limited for anonymous visitors. This template ships a GitHub Action
26
- ([`.github/workflows/cache.yml`](./.github/workflows/cache.yml)) that, on every
27
- push to `main`, builds a pre-cached zip of your repo and publishes it to your
28
- repo's **own GitHub Pages**. immediately.run finds it automatically at
29
- `https://<owner>.github.io/<repo>/cached_repositories/main.zip` and loads from
30
- there — falling back to the API if it's missing.
31
-
32
- The cache also embeds a manifest sidecar, so visitors can push edits back to
33
- GitHub even when the app was loaded from the zip.
34
-
35
- **Setup:** push to `main` and the workflow does the rest. When the immediately-run
36
- org's **deploy GitHub App** has **Pages: write** + **Administration: write** and its
37
- `DEPLOY_APP_ID` / `DEPLOY_APP_PRIVATE_KEY` are org secrets, the workflow **enables
38
- Pages for you** on the first run — no manual step. Otherwise, do it once:
39
- **Settings → Pages → Build and deployment → Source: GitHub Actions**. (The cache may
40
- lag a push by up to ~10 minutes of GitHub Pages CDN caching.)
41
-
42
- ### Always run the newest commit
43
-
44
- By default the cached version is served even if it's a few minutes behind
45
- `main`. If your app must always reflect the very latest commit, add this to
46
- `package.json`:
47
-
48
- ```jsonc
49
- {
50
- "immediately.run": {
51
- "requireLatest": true
52
- }
53
- }
54
- ```
55
-
56
- immediately.run still boots instantly from the cache, then checks in the
57
- background (one API request) whether the cache is current and, if not, reloads
58
- from GitHub.
59
-
60
- ## How it's organized
61
-
62
- immediately.run renders the **default export of `src/App.tsx`** — that's the
63
- entry point, not `main.tsx`.
64
-
65
- ```
66
- src/
67
- main.tsx # local vite dev/build entry only — immediately.run IGNORES this
68
- App.tsx # ROOT: default export + imports the global CSS
69
- index.css # fonts, design tokens (dark + light), resets
70
- App.css # layout + component styles
71
- mdx.d.ts # type shim so `import X from './x.mdx'` works
72
- components/ # one default-exported React component per file
73
- data/ # typed data arrays (NO components/JSX here)
74
- hooks/ # custom hooks (NO components here)
75
- assets/ # images you import, e.g. import logo from './assets/logo.png'
76
- ```
77
-
78
- The included page shows the core patterns: a data array mapped to cards
79
- (`data/features.ts` → `components/Features.tsx`), a custom hook
80
- (`hooks/useTheme.ts` → `components/ThemeSwitch.tsx`), and local React state
81
- (`components/Counter.tsx`).
82
-
83
- ## Filesystem access (`fs`)
84
-
85
- immediately.run apps can read and write a filesystem by importing `fs` (async
86
- only — `fs.promises.*` and callback style). This template has local-dev support
87
- for it built in via [`@immediately-run/dev-fs`](https://github.com/immediately-run/dev-fs),
88
- a Vite plugin (already wired into `vite.config.ts`) that bridges the same
89
- filesystem to your real local disk during `vite dev`. See that repo for the
90
- supported API and details.
91
-
92
- ```ts
93
- import fs from 'fs'
94
-
95
- await fs.promises.writeFile('/data/notes.txt', 'hello', 'utf8')
96
- const text = await fs.promises.readFile('/data/notes.txt', 'utf8')
26
+ ```bash
27
+ npm install
28
+ npm run dev # vite dev server — the sample handbook
29
+ npm run verify # lint + build + tests + the manifest/contrast/token gates
97
30
  ```
98
31
 
99
- `main.tsx` runs a one-off round-trip smoke test in dev — check the browser
100
- console for the `[dev-fs]` group, and delete it freely.
101
-
102
- ## The rules that keep it working on immediately.run
103
-
104
- See [`CLAUDE.md`](./CLAUDE.md) for the full list. The essentials:
32
+ On immediately.run, open
33
+ `https://immediately.run/present/github/<owner>/grove/main/files/content/home.mdx`
34
+ (fork) — or dispatch it at any wiki directory with the platform's file picker.
35
+ A GitHub Action (`.github/workflows/cache.yml`) publishes a pre-cached zip to
36
+ this repo's own Pages on every push to `main`, so anonymous loads are fast.
105
37
 
106
- - **Global CSS is imported from `App.tsx`, never only from `main.tsx`.**
107
- - **A file that exports a component exports *only* components** — data, consts,
108
- and helpers go in `data/`, `hooks/`, or `lib/`. `npm run lint` enforces this.
109
- - **Pull colors, fonts, radii, and shadows from the tokens in `index.css`**
110
- rather than hard-coding values.
38
+ ## Authoring entries
111
39
 
112
- ## Develop
40
+ Entries are `.mdx` files under `content/` with YAML frontmatter (`title`, `tags`,
41
+ `date`, `nav`, `order`, plus the engine keys in the manifest: `site`, `theme`,
42
+ `layout`, `view`, `frame`, `render`, `cover`, …). Interlink with wiki links;
43
+ declare a picture per entry with `cover:`; group a folder with a
44
+ `content/<dir>/_layout.mdx` starter. The built-in agent answers questions about
45
+ the corpus over the host's chat slot — ask it where things are before editing.
113
46
 
114
- Requires Node.js 20.19+ or 22.12+.
47
+ ## License
115
48
 
116
- ```bash
117
- npm install
118
- npm run dev # local dev server
119
- npm run build # tsc -b && vite build — must pass with no type errors
120
- npm run lint # eslint — enforces the React Fast Refresh / HMR rule
121
- npm run preview # serve the production build
122
- ```
49
+ Apache-2.0. Bundled fonts in `assets/fonts/` carry their own notices
50
+ (OFL / USWDS) alongside.
package/llms.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  # @immediately-run/grove — the viewer kit for directory-as-content wikis
2
2
 
3
- > The Grove viewer: a kit of React components, layouts and themes for building immediately.run wikis. Composable as a fork, a dispatch target, or a pinned library. (v0.1.1)
3
+ > The Grove viewer: a kit of React components, layouts and themes for building immediately.run wikis. Composable as a fork, a dispatch target, or a pinned library. (v0.1.3)
4
4
 
5
5
  Grove is NOT a wiki engine: routing, MDX compilation, the frontmatter index, link
6
6
  spaces and heading anchors live in the sandbox + `@immediately-run/sdk`. What this
@@ -69,7 +69,7 @@ is one corpus's conventions (declared by that corpus, not this repo).
69
69
  - `ChildPages` (engine, overridable) — The entries nested under this one.
70
70
  - `Directory` (engine, overridable) — The entries under one corpus directory. Props: path: string?.
71
71
  - `DirectoryList` (engine, overridable) — A folder listing as a table, with metadata columns chosen by `columns` and narrowed to those the rows actually carry. Props: path: string?, title: string?, columns: string?, sort: string?, hidden: boolean?.
72
- - `DocList` (engine, overridable) — A queried list of entries — the generic index primitive. Props: tag: string?, limit: number?.
72
+ - `DocList` (engine, overridable) — A queried list of entries — the generic index primitive. paginate="infinite" windows it with a sentinel and a stated end (R3-314); the attribute must be a literal. Props: tag: string?, limit: number?, paginate: 'infinite'?, batch: number?.
73
73
  - `DocsByTag` (engine, overridable) — Entries grouped under one tag. Props: tag: string?.
74
74
  - `FamilyTree` (engine, overridable) — A relationship graph rendered from frontmatter links. Props: children: node?.
75
75
  - `GroveFooter` (chrome, overridable) — The site footer.
@@ -79,6 +79,7 @@ is one corpus's conventions (declared by that corpus, not this repo).
79
79
  - `Infobox` (engine, overridable) — The boxed summary panel a wiki entry carries beside its lede. Props: title: string?, children: node?.
80
80
  - `Kbd` (engine, overridable) — A keyboard key. Props: children: node?.
81
81
  - `KeyValue` (engine, overridable) — A definition-list row for infobox-style facts. Props: children: node?.
82
+ - `LayoutGallery` (engine, overridable) — The layouts gallery: the starters, page variants and collection shapes grouped by their three mechanisms, enumerated from this manifest.
82
83
  - `Lede` (engine, overridable) — The opening paragraph, set apart typographically. Props: children: node?.
83
84
  - `More` (engine, overridable) — A 'read more' pointer to a related entry. Props: href: string?, children: node?.
84
85
  - `Outlet` (engine, LOCKED) — The layout chain's inward slot. NOT overridable — the chain's nesting is engine mechanics, and replacing it detaches every layer from the page it wraps.
@@ -88,12 +89,14 @@ is one corpus's conventions (declared by that corpus, not this repo).
88
89
  - `TableOfContents` (engine, overridable) — The on-this-page heading list, which keeps the active entry in view as the reader scrolls. Props: entryKey: string?, title: string?, className: string?.
89
90
  - `TagCloud` (engine, overridable) — Every tag in the corpus, weighted by use. Props: limit: number?.
90
91
  - `TagList` (engine, overridable) — The tags of one entry, as links to their indexes. Props: tags: string[]?.
92
+ - `ThemeGallery` (engine, overridable) — The themes gallery: one row per shipped theme, enumerated from this manifest — adding a theme adds a row with no edit to the entry.
91
93
  - `Timeline` (engine, overridable) — A dated sequence of entries or events. Props: children: node?.
92
94
  - `Toc` (engine, overridable) — The table of contents derived from the entry's heading anchors. Props: depth: number?.
93
95
 
94
96
  ## Frontmatter keys the engine reads
95
97
 
96
98
  - `site`
99
+ - `theme`
97
100
  - `layout`
98
101
  - `view`
99
102
  - `frame`
@@ -101,6 +104,7 @@ is one corpus's conventions (declared by that corpus, not this repo).
101
104
  - `nav`
102
105
  - `order`
103
106
  - `tags`
107
+ - `cover`
104
108
 
105
109
  Unknown keys pass through (carried, unread) — a corpus may keep its own vocabulary.
106
110
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@immediately-run/grove",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "type": "module",
5
5
  "main": "src/main.tsx",
6
6
  "immediately.run": {
@@ -10,7 +10,17 @@
10
10
  "task": "open-wiki",
11
11
  "version": "1.0"
12
12
  }
13
- ]
13
+ ],
14
+ "invokes": [
15
+ {
16
+ "task": "edit-file",
17
+ "version": "^1"
18
+ }
19
+ ],
20
+ "requests": {
21
+ "task:invoke": {},
22
+ "llm:chat": {}
23
+ }
14
24
  },
15
25
  "scripts": {
16
26
  "dev": "vite",
@@ -18,17 +28,20 @@
18
28
  "lint": "eslint .",
19
29
  "test": "vitest run",
20
30
  "preview": "vite preview",
21
- "verify": "npm run check:llms && npm run check:engine-api:selftest && npm run check:engine-api && npm run check:manifest && npm run check:deps && npm run lint && npm run build && npm run test",
31
+ "verify": "npm run check:llms && npm run check:engine-api:selftest && npm run check:engine-api && npm run check:manifest && npm run check:deps && npm run check:published && npm run check:theme-contrast && npm run check:theme-token-only && npm run lint && npm run build && npm run test",
32
+ "check:theme-contrast": "node scripts/check-theme-contrast.mjs --self-test && node scripts/check-theme-contrast.mjs",
33
+ "check:theme-token-only": "node scripts/check-theme-token-only.mjs --self-test && node scripts/check-theme-token-only.mjs",
22
34
  "check:manifest": "node scripts/check-manifest.mjs",
23
35
  "check:deps": "node scripts/check-app-dependencies.mjs --self-test && node scripts/check-app-dependencies.mjs",
36
+ "check:published": "node scripts/check-published-parity.mjs --self-test && node scripts/check-published-parity.mjs --offline-ok",
24
37
  "check:engine-api": "node scripts/check-engine-api.mjs",
25
38
  "check:engine-api:selftest": "node scripts/check-engine-api.mjs --self-test",
26
39
  "gen:llms": "node scripts/gen-llms.mjs",
27
40
  "check:llms": "node scripts/gen-llms.mjs --check"
28
41
  },
29
42
  "dependencies": {
30
- "@immediately-run/mdx-plugins": "0.4.0",
31
- "@immediately-run/sdk": "^0.52.0",
43
+ "@immediately-run/mdx-plugins": "0.7.1",
44
+ "@immediately-run/sdk": "^0.67.0",
32
45
  "react": "^19.2.5",
33
46
  "react-dom": "^19.2.5"
34
47
  },
@@ -48,8 +61,7 @@
48
61
  "typescript": "~6.0.2",
49
62
  "typescript-eslint": "^8.58.2",
50
63
  "vite": "^8.0.9",
51
- "vitest": "^4.1.9",
52
- "@immediately-run/mdx-plugins": "0.4.0"
64
+ "vitest": "^4.1.9"
53
65
  },
54
66
  "description": "The Grove viewer: a kit of React components, layouts and themes for building immediately.run wikis. Composable as a fork, a dispatch target, or a pinned library.",
55
67
  "license": "Apache-2.0",
@@ -75,7 +87,7 @@
75
87
  "llms.txt"
76
88
  ],
77
89
  "peerDependencies": {
78
- "@immediately-run/sdk": "^0.52.0",
90
+ "@immediately-run/sdk": "^0.67.0",
79
91
  "react": "^19.2.5",
80
92
  "react-dom": "^19.2.5"
81
93
  }
package/src/App.tsx CHANGED
@@ -24,7 +24,7 @@ import { MetadataSource } from '@immediately-run/sdk';
24
24
  import { TinkerableContext } from '@immediately-run/sdk/TinkerableContext';
25
25
  import { MDXProvider } from '@immediately-run/sdk/MDXProvider';
26
26
  import { useOpenWikiBoot } from './hooks/useOpenWikiBoot';
27
- import { useCorpusMetadata } from './hooks/useCorpusMetadata';
27
+ import { useBundleMetadata } from './hooks/useBundleMetadata';
28
28
  import { useContentComponents } from './hooks/useContentComponents';
29
29
  import { getContentRoot } from './lib/contentRoot';
30
30
  import { viewedDocumentForTarget } from './lib/content';
@@ -69,7 +69,7 @@ export default function App() {
69
69
  }
70
70
  }, [boot.status, outerHref]);
71
71
  // Only a dispatched viewer scans; a fork's index is already in the context.
72
- const corpus = useCorpusMetadata(boot.status === 'ready' ? getContentRoot() : null);
72
+ const bundle = useBundleMetadata(boot.status === 'ready' ? getContentRoot() : null);
73
73
  // BOTH packagings, deliberately (R3-174). A corpus's own component vocabulary must not
74
74
  // depend on how it was composed — `PLATFORM_LAYERING_SPEC` §1.1's mode-invariance rule —
75
75
  // so a fork reads its marker too; that is one cheap open of a file already in `/app`.
@@ -93,8 +93,8 @@ export default function App() {
93
93
  // invariant): rendering into a half-composed map would flash a missing-component error
94
94
  // for `<RoadmapBoard>` until registration landed — the very error content components
95
95
  // exist to remove — and a nested provider patched in afterwards would do the same.
96
- // Holding here costs nothing, because the gate already exists for the corpus scan.
97
- if (boot.status === 'waiting' || corpus.status === 'scanning' || contentComponents.status === 'loading') {
96
+ // Holding here costs nothing, because the gate already exists for the bundle scan.
97
+ if (boot.status === 'waiting' || bundle.status === 'scanning' || contentComponents.status === 'loading') {
98
98
  return (
99
99
  <div className="grove-boot">
100
100
  <p className="grove-boot__msg">Opening…</p>
@@ -116,14 +116,18 @@ export default function App() {
116
116
  wiki
117
117
  );
118
118
 
119
- if (corpus.status === 'ready' && corpus.metadata) {
120
- // Provide the scanned corpus as the metadata SOURCE through the supported
119
+ // R3-315/R3-310 — the declared face set mounts INSIDE GroveWiki now, keyed to
120
+ // the resolved theme (the catalogue looks change the reading face); nothing
121
+ // font-shaped waits on the scan from here.
122
+
123
+ if (bundle.status === 'ready' && bundle.metadata) {
124
+ // Provide the scanned bundle as the metadata SOURCE through the supported
121
125
  // surface (R3-276), not a wholesale TinkerableContext re-provision: the
122
126
  // platform stays free to grow its own state, and the hooks read the nearest
123
127
  // MetadataSource — so every consumer works unchanged, and nothing re-states
124
128
  // host fields it does not own.
125
129
  return (
126
- <MetadataSource value={corpus.metadata}>{withComponents}</MetadataSource>
130
+ <MetadataSource value={bundle.metadata}>{withComponents}</MetadataSource>
127
131
  );
128
132
  }
129
133