@cfbender/cesium 0.3.5

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 (44) hide show
  1. package/ARCHITECTURE.md +304 -0
  2. package/CHANGELOG.md +335 -0
  3. package/LICENSE +21 -0
  4. package/README.md +479 -0
  5. package/agents/cesium.md +39 -0
  6. package/assets/styleguide.html +857 -0
  7. package/package.json +61 -0
  8. package/src/cli/commands/ls.ts +186 -0
  9. package/src/cli/commands/open.ts +208 -0
  10. package/src/cli/commands/prune.ts +348 -0
  11. package/src/cli/commands/restart.ts +38 -0
  12. package/src/cli/commands/serve.ts +214 -0
  13. package/src/cli/commands/stop.ts +130 -0
  14. package/src/cli/commands/theme.ts +333 -0
  15. package/src/cli/index.ts +78 -0
  16. package/src/config.ts +94 -0
  17. package/src/index.ts +35 -0
  18. package/src/prompt/system-fragment.md +97 -0
  19. package/src/render/client-js.ts +316 -0
  20. package/src/render/controls.ts +302 -0
  21. package/src/render/critique.ts +360 -0
  22. package/src/render/extract.ts +83 -0
  23. package/src/render/scrub.ts +141 -0
  24. package/src/render/theme.ts +712 -0
  25. package/src/render/validate.ts +524 -0
  26. package/src/render/wrap.ts +165 -0
  27. package/src/server/api.ts +166 -0
  28. package/src/server/http.ts +195 -0
  29. package/src/server/lifecycle.ts +331 -0
  30. package/src/server/stop.ts +124 -0
  31. package/src/storage/index-cache.ts +71 -0
  32. package/src/storage/index-gen.ts +447 -0
  33. package/src/storage/lock.ts +108 -0
  34. package/src/storage/mutate.ts +396 -0
  35. package/src/storage/paths.ts +159 -0
  36. package/src/storage/project-summaries.ts +19 -0
  37. package/src/storage/theme-write.ts +19 -0
  38. package/src/storage/write.ts +75 -0
  39. package/src/tools/ask.ts +353 -0
  40. package/src/tools/critique.ts +66 -0
  41. package/src/tools/publish.ts +404 -0
  42. package/src/tools/stop.ts +53 -0
  43. package/src/tools/styleguide.ts +23 -0
  44. package/src/tools/wait.ts +192 -0
@@ -0,0 +1,304 @@
1
+ # Architecture
2
+
3
+ Cesium is an opencode plugin that converts substantive agent responses into self-contained
4
+ HTML artifacts stored on disk and served locally. This document describes the architectural
5
+ decisions made for v1.
6
+
7
+ **Status: v0.3.0 shipped.** See [`CHANGELOG.md`](CHANGELOG.md) for release notes.
8
+
9
+ ---
10
+
11
+ ## Vision
12
+
13
+ When the agent produces something worth keeping — a plan, comparison, code review, audit,
14
+ explainer, or RFC — it generates a beautiful `.html` file instead of printing markdown to
15
+ the terminal. The artifact lives in `~/.local/state/cesium/` and can be opened in a browser,
16
+ shared over SSH, or archived as-is. The terminal remains the control surface. Each artifact
17
+ is 100% self-contained: no external stylesheets, no CDN scripts, no network required to view.
18
+
19
+ ---
20
+
21
+ ## Trigger model
22
+
23
+ Cesium is **agent-decided via tool call**, not automatic on every response. The plugin
24
+ injects a ~40-line system-prompt fragment (~600 tokens) into every agent session that
25
+ describes when to publish vs. stay in the terminal.
26
+
27
+ **Publish heuristics (baked into the injected prompt):**
28
+
29
+ - Response would be >= ~400 words, OR
30
+ - Contains a comparison, decision matrix, or multi-section plan/PRD/RFC, OR
31
+ - A code review with more than 3 findings, OR
32
+ - Anything the user is likely to revisit or share.
33
+
34
+ **Stay in terminal:**
35
+
36
+ - Direct factual question, short status update, mid-tool-loop chatter.
37
+
38
+ **User override always wins:** `/cesium`, "publish this", "make me an HTML report" force
39
+ publish; "just tell me", "in terminal" suppress it.
40
+
41
+ **Tie-breaker:** when uncertain, publish and emit a 2-3 line terminal summary.
42
+
43
+ ---
44
+
45
+ ## Tool surface
46
+
47
+ Two tools are registered by the plugin:
48
+
49
+ ### `cesium_publish` (primary)
50
+
51
+ Accepts the body HTML and metadata for one artifact. The plugin owns the full HTML shell:
52
+ `<!doctype html>`, `<head>`, the inlined CSS framework, embedded metadata, and the footer
53
+ with revision links. The agent writes only the `<body>` inner HTML.
54
+
55
+ Input fields:
56
+
57
+ - `title` (string, required)
58
+ - `kind` — `"plan" | "review" | "comparison" | "report" | "explainer" | "design" | "audit" | "rfc" | "other"`
59
+ - `html` — body inner HTML
60
+ - `summary` — optional 1-2 line terminal blurb
61
+ - `tags` — optional string array
62
+ - `supersedes` — optional id of artifact this revises
63
+
64
+ Returns: `{ id, filePath, fileUrl, httpUrl, indexUrl }`
65
+
66
+ ### `cesium_styleguide` (on-demand reference)
67
+
68
+ Returns the full CSS reference page as a string. Called by the agent before starting a
69
+ complex artifact. Kept separate to avoid bloating every tool call.
70
+
71
+ ---
72
+
73
+ ## HTML generation strategy
74
+
75
+ **Approach:** shared inline CSS framework + agent-written semantic HTML.
76
+
77
+ The plugin injects a known-good `<style>` block (~3kb) into every artifact. The agent
78
+ composes content using a named class vocabulary (documented in the tool description and
79
+ retrievable via `cesium_styleguide`). The agent may also use inline `style="..."` and
80
+ inline `<svg>` for bespoke diagrams.
81
+
82
+ **Strict portability rule:** no external resources. The scrub pass strips or rewrites:
83
+
84
+ - `<link rel="stylesheet" href="...">` — removed, comment left
85
+ - `<script src="...">` — removed, comment left
86
+ - `url(https://...)` in style — removed
87
+ - `<img src="http...">` — removed, comment left
88
+
89
+ Broken or unparseable HTML is tolerated: the file is written anyway with a warning banner
90
+ prepended. Validation errors (missing title, empty html, invalid kind) are caught before
91
+ write and returned as tool errors.
92
+
93
+ **Color tokens (default theme):**
94
+
95
+ | Token | Value | Role |
96
+ | ------------- | --------- | --------------------- |
97
+ | `--bg` | `#FAF9F5` | ivory page background |
98
+ | `--surface` | `#FFFFFF` | card/panel surface |
99
+ | `--surface-2` | `#F0EEE6` | secondary surface |
100
+ | `--oat` | `#E3DACC` | muted border fill |
101
+ | `--rule` | `#D1CFC5` | rule / divider |
102
+ | `--ink` | `#141413` | primary text |
103
+ | `--ink-soft` | `#3D3D3A` | secondary text |
104
+ | `--muted` | `#87867F` | placeholder / caption |
105
+ | `--accent` | `#D97757` | clay — callout/link |
106
+ | `--olive` | `#788C5D` | sage — success |
107
+ | `--code-bg` | `#141413` | code panel bg |
108
+ | `--code-fg` | `#E8E6DE` | code panel fg |
109
+
110
+ User theme overrides: `~/.config/opencode/cesium.json` → `theme` field (per-token overrides
111
+ stack on top of the active preset). Four named presets are shipped (`warm`, `cool`, `mono`,
112
+ `paper`) selectable via `themePreset` — see README for the full preset reference.
113
+
114
+ **Type stack:** system fonts only (`ui-serif`, `system-ui`, `ui-monospace`) — strict
115
+ portability requires no remote font loads.
116
+
117
+ **Named component classes the agent uses:**
118
+ `.eyebrow`, `.h-display`, `.h-section`, `.section-num`, `.card`, `.tldr`, `.callout`,
119
+ `.code`, `.timeline`, `.diagram`, `.compare-table`, `.risk-table`, `.kbd`, `.pill`,
120
+ `.tag`, `.byline`
121
+
122
+ ---
123
+
124
+ ## Storage layout
125
+
126
+ ```
127
+ ~/.local/state/cesium/
128
+ ├── index.html # global cross-project index
129
+ ├── index.json # global cache (rebuilt on every publish)
130
+ └── projects/
131
+ └── <project-slug>/
132
+ ├── index.html # per-project index
133
+ ├── index.json # per-project cache
134
+ └── artifacts/
135
+ ├── 2026-05-11T14-22-09Z__plan-auth-rewrite__a7K9pQ.html
136
+ └── ...
137
+ ```
138
+
139
+ **Project slug derivation (priority order):**
140
+
141
+ 1. Git remote `origin`, normalized: `github-com-cfb-cesium`
142
+ 2. `<cwd-basename>-<6char-hash-of-absolute-path>` — prevents collisions when multiple repos
143
+ share the same basename
144
+
145
+ **Worktrees** of one repo merge into one project directory. Branch is captured in artifact
146
+ metadata, not in the path.
147
+
148
+ **Filename:** `<iso-utc-timestamp>__<title-slug>__<6char-nanoid>.html`
149
+ Sortable, greppable, human-readable, collision-resistant.
150
+
151
+ **Metadata: dual-source.**
152
+ Each artifact embeds a `<script type="application/json" id="cesium-meta">` block — the
153
+ source of truth. The artifact is 100% self-contained; metadata travels with the file.
154
+ `index.json` is a derived cache rebuilt on every publish (not the authoritative store).
155
+
156
+ **Metadata fields:** `id`, `title`, `kind`, `summary`, `tags`, `createdAt`, `model`,
157
+ `sessionId`, `projectSlug`, `projectName`, `cwd`, `worktree`, `gitBranch`, `gitCommit`,
158
+ `supersedes?`, `supersededBy?`, `contentSha256`
159
+
160
+ ---
161
+
162
+ ## Index & serving
163
+
164
+ **Index:** per-project and global `index.html` regenerated atomically on every publish.
165
+ Lists artifacts grouped by week, with kind filter chips, inline title search (tiny inline
166
+ JS), and revision-chain collapsing (latest version visible by default). Pre-rendered — works
167
+ without the server (archivable, rsync-friendly).
168
+
169
+ **Server:** lazy auto-start, single global process, port 3030 (increments to 3031..3050 if
170
+ busy).
171
+
172
+ - Bun HTTP server bound to `127.0.0.1:3030`, rooted at `~/.local/state/cesium/`.
173
+ - Starts on first publish in an opencode session.
174
+ - Idle-shuts after 30 minutes of no requests (configurable via `cesium.json`).
175
+ - PID file at `~/.local/state/cesium/.server.pid`. Stale PID detected and cleared on startup.
176
+ - SIGTERM handler for clean shutdown.
177
+ - SSH detection: if `$SSH_CONNECTION` is set, publish output reminds the user to forward
178
+ the port. Server does NOT bind to `0.0.0.0` by default.
179
+
180
+ **Terminal output after publish:**
181
+
182
+ ```
183
+ Cesium · Auth design (plan)
184
+ http://localhost:3030/projects/github-com-cfb-cesium/artifacts/...
185
+ file:///Users/cfb/.local/state/cesium/...
186
+ ```
187
+
188
+ ---
189
+
190
+ ## Revision chains
191
+
192
+ When `cesium_publish` receives a `supersedes` id:
193
+
194
+ 1. New artifact is written with `supersedes` populated.
195
+ 2. Previous artifact's embedded metadata is patched in-place: `supersededBy` field added.
196
+ Visual content is untouched.
197
+ 3. Index renders the chain: "v3 of auth design (revises v2, v1)".
198
+
199
+ ---
200
+
201
+ ## Interactive artifacts (v0.3.0)
202
+
203
+ ### The artifact-as-UI insight
204
+
205
+ In v0.3.0, `ask`-kind artifacts collapse the "publish" and "interactive UI" pipelines
206
+ into one. The artifact file IS the form. Inline JS POSTs individual answers to the
207
+ cesium HTTP server; the server mutates the file on disk atomically; once all required
208
+ questions are answered the status transitions to `"complete"` and the controls freeze
209
+ into a static answered record. The same `.html` file is the form, the live conversation,
210
+ and the permanent record — no separate UI, no database, no websocket.
211
+
212
+ ### Storage
213
+
214
+ `ask`-kind artifacts carry an `interactive` field in the embedded
215
+ `<script type="application/json" id="cesium-meta">` block. Shape:
216
+
217
+ ```ts
218
+ type InteractiveData = {
219
+ status: "open" | "complete" | "expired" | "cancelled";
220
+ requireAll: boolean;
221
+ expiresAt: string; // ISO-8601
222
+ questions: Question[];
223
+ answers: Record<string, { value: AnswerValue; answeredAt: string }>;
224
+ completedAt?: string;
225
+ };
226
+ ```
227
+
228
+ The same atomic-write + `index.json` cache pattern as publish artifacts applies.
229
+ `src/storage/mutate.ts` owns the read-mutate-write cycle for interactive artifacts.
230
+
231
+ ### Transport
232
+
233
+ Answer submission:
234
+
235
+ ```
236
+ POST /api/sessions/<projectSlug>/<filename>/answers/<questionId>
237
+ Body: { "value": <AnswerValue> }
238
+ ```
239
+
240
+ State query:
241
+
242
+ ```
243
+ GET /api/sessions/<projectSlug>/<filename>/state
244
+ Response: { status, remaining, answers }
245
+ ```
246
+
247
+ The server uses `withLock` on `<artifactPath>.lock` for all read-mutate-write
248
+ operations — the same lock primitive used by the index.
249
+
250
+ ### Tools
251
+
252
+ - **`cesium_ask`** — validates input, builds the interactive artifact, writes it to
253
+ disk, starts the server, and returns `{ id, filePath, fileUrl, httpUrl }`.
254
+ - **`cesium_wait`** — polls disk every 500 ms, reading the artifact's embedded
255
+ `interactive.status`. Returns the full `answers` map once status is non-`"open"`.
256
+ No subagents, no WebSockets — pure polling, pure HTTP.
257
+
258
+ ### Question types (v0.3.0)
259
+
260
+ Six types ship in v0.3.0: `pick_one`, `pick_many`, `confirm`, `ask_text`, `slider`,
261
+ `react`. Branching logic, ranking, and file/image inputs are deferred.
262
+
263
+ Each type has a corresponding control renderer in `src/render/controls.ts` that
264
+ produces the interactive HTML, and an answered renderer (`renderAnswered`) that
265
+ produces the frozen read-only record once an answer is recorded.
266
+
267
+ ### Lifecycle
268
+
269
+ Status transitions: `open` → `complete` (all required answers received) or
270
+ `open` → `expired` (server-side check on `expiresAt`) or `open` → `cancelled`
271
+ (explicit cancellation via API).
272
+
273
+ Once status is non-`"open"`, `wrapDocument` omits the inline
274
+ `<script data-cesium-client>` tag entirely, so the file loads without any interactive
275
+ overhead. Controls render as `.cs-answered` read-only markup.
276
+
277
+ ### CSS additions
278
+
279
+ `src/render/theme.ts` → `frameworkRulesCss()` gained ~210 lines of `.cs-*` rules:
280
+
281
+ - `.cs-questions` — container
282
+ - `.cs-question` — individual question block
283
+ - `.cs-control` — wraps each input widget
284
+ - `.cs-answered` — frozen answer display
285
+ - `.cs-banner` / `.cs-banner-offline` / `.cs-banner-ended` — status banners
286
+ - Per-type modifiers: `.cs-pick`, `.cs-confirm`, `.cs-slider`, `.cs-text`, `.cs-react`
287
+
288
+ ---
289
+
290
+ ## v1 build phases
291
+
292
+ | Phase | Scope | Status |
293
+ | ----- | ---------------------------------------------------------------------------------- | ------- |
294
+ | 0 | Scaffolding, configs, docs, empty stubs | shipped |
295
+ | 1 | Storage + render core (paths, write, theme, wrap, scrub, validate) | shipped |
296
+ | 2 | `cesium_publish` + `cesium_styleguide` tools, plugin entry, system prompt fragment | shipped |
297
+ | 3 | Per-project + global `index.html` generation, file lock, revision chains | shipped |
298
+ | 4 | Lazy auto-server, port-scan, idle shutdown, SSH detection | shipped |
299
+ | 5 | Reference examples, dedicated agent definition, release polish | shipped |
300
+ | A | Interactive artifact types + `cesium_ask` tool | shipped |
301
+ | B | Answer submission API (`/api/sessions/…/answers/:qid`) + per-artifact file lock | shipped |
302
+ | C | `cesium_wait` polling tool + client JS answer submission | shipped |
303
+ | D | Interactive lifecycle (status transitions, expiry, freeze) | shipped |
304
+ | E | `buildProjectSummaries` refactor, `examples/ask.html`, docs, v0.3.0 release | shipped |
package/CHANGELOG.md ADDED
@@ -0,0 +1,335 @@
1
+ # Changelog
2
+
3
+ ## v0.3.5 — 2026-05-11
4
+
5
+ Fixes the `Publish to npm` GitHub Action.
6
+
7
+ - **fix:** Workflow now uses Node 24 (which ships with npm 11+, required for
8
+ the OIDC trusted-publisher flow). The previous attempt used Node 22 plus an
9
+ explicit `npm install -g npm@latest` step, which hit a `MODULE_NOT_FOUND`
10
+ on `promise-retry` in the runner's pre-cached npm. Bundled npm 11 from
11
+ Node 24 sidesteps the upgrade step entirely.
12
+
13
+ ## v0.3.4 — 2026-05-11
14
+
15
+ Smoke test for the npm publish GitHub Action (OIDC trusted-publisher flow).
16
+ First release published from CI.
17
+
18
+ - **fix:** Removed `publishConfig.provenance: true` from `package.json`. The
19
+ field forces `--provenance` even on local publishes, where it fails with
20
+ `Automatic provenance generation not supported for provider: null`. The
21
+ GitHub Action passes `--provenance` explicitly, so CI publishes still
22
+ ship with an npm provenance attestation.
23
+ - **docs:** Bootstrap step in README "Releasing" no longer passes
24
+ `--provenance` (it can't work locally).
25
+
26
+ ## v0.3.3 — 2026-05-11
27
+
28
+ First release published to npm as **`@cfbender/cesium`**. No runtime behavior
29
+ changes; only packaging and release infrastructure.
30
+
31
+ - **packaging:** Renamed package from `cesium` to `@cfbender/cesium` (scoped,
32
+ public). Install with `bun install -g @cfbender/cesium`. Old git-URL installs
33
+ still work but will fall behind.
34
+ - **packaging:** Added explicit `files` allowlist to package.json — the
35
+ published tarball ships `src/`, `assets/styleguide.html`, `agents/`, and
36
+ `ARCHITECTURE.md` only. Tests, examples, scripts, design specs, and the
37
+ README demo video are excluded.
38
+ - **packaging:** `engines.bun >= 1.0.0` declared (cesium runs TS directly via
39
+ Bun; the CLI's `#!/usr/bin/env bun` shebang requires Bun on `PATH`).
40
+ - **packaging:** `prepublishOnly` runs `typecheck` + `test` before publish.
41
+ - **packaging:** `publishConfig.access = "public"` and
42
+ `publishConfig.provenance = true` so scoped publishes work and ship with
43
+ npm provenance attestations.
44
+ - **ci:** New `.github/workflows/publish.yml`. Triggers on `v*` tag push,
45
+ runs typecheck + tests, verifies tag-vs-package-version match, then
46
+ `npm publish --access public --provenance` via npm's **Trusted Publisher
47
+ OIDC flow** — no `NPM_TOKEN` secret required. The first release is
48
+ published manually so the package exists on the registry; subsequent
49
+ releases are tag-triggered. See README "Releasing" for the bootstrap.
50
+ - **docs:** README install section rewritten around the npm package; mise /
51
+ `bun update -g` upgrade flows documented; trusted-publisher bootstrap +
52
+ release-via-tag flow documented.
53
+
54
+ ## v0.3.2 — 2026-05-11
55
+
56
+ Quality-of-life patch focused on `cesium serve` reliability and README polish.
57
+
58
+ - **fix:** `cesium serve` no longer auto-shuts-down on idle. The configured
59
+ `idleTimeoutMs` exists for the plugin's lazy-started server and was being
60
+ unintentionally applied to foreground `cesium serve`, killing the process
61
+ unexpectedly. Foreground serve now runs until SIGINT/SIGTERM by default.
62
+ - **new:** `cesium serve --idle-timeout DUR` opts back into auto-shutdown.
63
+ Accepts plain milliseconds or a suffixed duration (`90s`, `30m`, `2h`).
64
+ Use `0`, `never`, or `off` to disable explicitly.
65
+ - **internal:** `lifecycle.startIdleTimer` now treats `idleTimeoutMs <= 0` as
66
+ "never time out" and skips creating the interval.
67
+ - **docs:** README demo asset (`assets/cesium.mp4`, ~600 KB, 720px wide)
68
+ embedded near the top via a `<video>` tag.
69
+ - **docs:** New "Common workflows" section in the README covering forced
70
+ publish, finding/opening artifacts, sharing, pruning, theme changes,
71
+ server restart, and Q&A loops.
72
+ - **docs:** Acknowledgements section added.
73
+ - **tests:** 889 → 906 (+9 serve-arg parser tests, +2 lifecycle tests for
74
+ the `idleTimeoutMs <= 0` path; the previously-skipped flaky idle-timer
75
+ test was preserved).
76
+
77
+ ## v0.3.1 — 2026-05-11
78
+
79
+ Small quality-of-life patch. The only user-visible change is the Skip button on
80
+ optional `ask_text` questions; all other v0.3.0 behavior is unchanged.
81
+
82
+ - **new:** `optional?: boolean` field on `ask_text` questions (default `false`).
83
+ When `true`, the server accepts an empty-string answer (skipped), and the
84
+ answered section renders a muted "(skipped)" placeholder instead of a blockquote.
85
+ - **new:** Skip button rendered alongside Submit for optional ask_text controls
86
+ (`class="cs-skip"`), wrapped in a `class="cs-button-row"` flex container.
87
+ - **new:** Client JS `cs-skip` click handler — POSTs `{ type: "ask_text", text: "" }`
88
+ via the same `submitAnswer` path as Submit.
89
+ - **examples:** `ask.html` "constraints" question is now `optional: true` — showcases
90
+ the Skip button.
91
+ - **tests:** 870 → 889 (+19 new tests across validate, mutate, controls, client-js,
92
+ theme, system-fragment).
93
+
94
+ ## v0.3.0 — 2026-05-11
95
+
96
+ ### Added
97
+
98
+ - **`cesium_ask`** — publish an interactive Q&A artifact and return its URL. The
99
+ agent calls this when it needs structured input before producing a final artifact:
100
+ design tradeoffs, plan choices, confirmation gates. Returns `{ id, filePath, fileUrl, httpUrl }`.
101
+
102
+ - **`cesium_wait`** — block until the user finishes answering all required questions.
103
+ Polls disk every 500 ms reading the artifact's embedded `interactive.status`. Returns
104
+ the full `answers` map once complete, expired, or cancelled.
105
+
106
+ - **New artifact kind: `"ask"`** — interactive Q&A artifacts. A single self-contained
107
+ `.html` file that embeds the question form, client JS, and answers. Server-mutated
108
+ atomically on each answer; crystallizes into a permanent static record once complete.
109
+ The same file is the form, the live session, and the archive.
110
+
111
+ - **Six question types:** `pick_one` (radio group + recommended), `pick_many`
112
+ (checkbox group + min/max), `confirm` (yes/no with custom labels), `ask_text`
113
+ (free-text, optional multiline), `slider` (numeric range), `react` (thumbs reaction
114
+ with optional comment).
115
+
116
+ - **Server: new `/api/*` routes** — `POST /api/sessions/<slug>/<file>/answers/<qid>`
117
+ submits an individual answer; `GET /api/sessions/<slug>/<file>/state` returns current
118
+ status and remaining question ids. Per-artifact file lock (`<artifactPath>.lock`).
119
+
120
+ - **`examples/ask.html`** — baked demo artifact demonstrating all six question types
121
+ in `status: "open"` state. Open in browser to see the controls.
122
+
123
+ ### Changed
124
+
125
+ - **Storage:** new `src/storage/mutate.ts` — atomic read-mutate-write for interactive
126
+ artifacts. New `src/storage/project-summaries.ts` — `buildProjectSummaries` extracted
127
+ from `publish.ts` and `ask.ts` into a shared module (no behavior change).
128
+
129
+ - **Render:** new `src/render/controls.ts` (question control + answered renderers) and
130
+ `src/render/client-js.ts` (~309-line inline JS bundle for answer POSTing and UI state).
131
+ ~210 new `.cs-*` CSS rules in `frameworkRulesCss()`.
132
+
133
+ - **Tests:** 863 → 870 (commit 1 refactor: +7 project-summaries tests). Full suite: 870
134
+ pass (+281 new tests since v0.2.4).
135
+
136
+ ## v0.2.4 — 2026-05-11
137
+
138
+ ### Added
139
+
140
+ - `cesium --version` / `cesium -v` / `cesium version` — print the installed
141
+ version. Useful for confirming what's actually running after an upgrade.
142
+
143
+ ### Changed
144
+
145
+ - `claret-dark` code panels now render at `surface2` (`#2B1F22`) instead of
146
+ recessed `#0F0509`. The recessed value gave only ~9 luminance points of
147
+ contrast against the page bg; the elevated value reads cleanly.
148
+
149
+ ## v0.2.3 — 2026-05-11
150
+
151
+ ### Added
152
+
153
+ - `cesium_stop` tool. The agent can now stop the running cesium HTTP server
154
+ from inside an opencode session via a tool call. Useful for cycling the
155
+ server after a config change, or cleaning up at session end. Idempotent.
156
+ - `claret-dark` theme preset — dark wine background with bright rose and sage
157
+ accents, sourced from `claret.nvim`'s dark palette.
158
+ - `claret-light` theme preset — the previous `claret` palette, renamed.
159
+
160
+ ### Changed
161
+
162
+ - **Default theme is now `claret-dark`.** If you have `themePreset: "claret"`
163
+ in `~/.config/opencode/cesium.json`, you'll now see the dark variant. Set
164
+ `themePreset: "claret-light"` to keep the old look. The bare `"claret"` name
165
+ is preserved as an alias for `"claret-dark"`.
166
+ - Refactored cross-process server-stop logic into `src/server/stop.ts` so the
167
+ CLI's `cesium stop` and the new `cesium_stop` tool share the same code path.
168
+
169
+ ## v0.2.2 — 2026-05-11
170
+
171
+ ### Added
172
+
173
+ - `cesium stop` — kills the running cesium server cross-process via its PID
174
+ file. Sends SIGTERM with a configurable grace period (`--timeout`, default
175
+ 3000 ms), then SIGKILL. `--force` skips the grace. Idempotent: safe when no
176
+ server is running.
177
+ - `cesium restart` — stops then re-starts the server. Replaces the calling
178
+ terminal with the new server (foreground, like `cesium serve`). Inherits
179
+ serve's `--port` / `--hostname` flags.
180
+
181
+ ## v0.2.1 — 2026-05-11
182
+
183
+ ### Changed
184
+
185
+ - **Default theme is now `claret`** — a deep-rose-on-warm-cream palette derived
186
+ from the claret.nvim color scheme. The previous default (`warm`) is still
187
+ available as a preset; set `themePreset: "warm"` in `cesium.json` to keep the
188
+ old look.
189
+
190
+ ### Added
191
+
192
+ - Dynamic theme via `<stateDir>/theme.css`. Each artifact (and index page) now
193
+ references this file via a relative `<link rel="stylesheet">`. Changing the
194
+ configured theme and running `cesium theme apply` re-skins all linked
195
+ artifacts on disk — file://-served artifacts fall back to their original
196
+ inline tokens, preserving offline portability.
197
+ - `claret` theme preset.
198
+ - `cesium theme show` — print resolved theme tokens, indicate when on-disk
199
+ theme.css is out of date.
200
+ - `cesium theme apply` — write theme.css from current config.
201
+ - `cesium theme apply --rewrite-artifacts` — retrofit existing artifacts and
202
+ index pages on disk to reference theme.css. Adds the `<link>` tag idempotently
203
+ to files that don't already have one.
204
+
205
+ ### Architectural notes
206
+
207
+ - Inline `<style>` blocks now contain framework rules + a _fallback_ token set
208
+ baked at publish time. The external `theme.css` overrides the fallback when
209
+ present (CSS cascade). Standalone `.html` files still render correctly when
210
+ opened via `file://` without the surrounding state dir.
211
+
212
+ ## v0.2.0 — 2026-05-11
213
+
214
+ This is the v0.2.0 polish release. Three smaller features shipped as 0.1.3–0.1.5
215
+ (theme presets, cesium_critique, full-text search) and the standalone CLI lands
216
+ here. Use `cesium <subcommand>` from any shell.
217
+
218
+ ### Added
219
+
220
+ - Standalone `cesium` CLI with subcommands:
221
+ - `cesium ls [--all] [--json] [--limit N]` — list artifacts
222
+ - `cesium open <id-prefix> [--print]` — open an artifact in the browser
223
+ - `cesium serve [--port N] [--hostname H]` — run the local server in foreground
224
+ - `cesium prune --older-than <duration> [--yes]` — delete old artifacts
225
+ - `package.json` `bin` field exposes the CLI when the plugin is installed via
226
+ bun/opencode (linked into `node_modules/.bin/cesium`).
227
+
228
+ ## v0.1.5 — 2026-05-11
229
+
230
+ ### Added
231
+
232
+ - Index search now matches body text in addition to titles. Each artifact's
233
+ rendered card carries a `data-body-text` attribute (capped at 5000 chars,
234
+ lowercased) and the inline filter checks both fields.
235
+ - Body text is extracted at publish time via parse5 and stored on the
236
+ `IndexEntry` shape.
237
+
238
+ ### Changed
239
+
240
+ - `IndexEntry` gained a `bodyText: string` field. Existing `index.json` files
241
+ without this field are loaded with an empty string; republishing populates it.
242
+ - Search input placeholder updated from "Filter by title…" to
243
+ "Filter by title or content…".
244
+
245
+ ## v0.1.4 — 2026-05-11
246
+
247
+ ### Added
248
+
249
+ - `cesium_critique` tool. Agent can call this before publishing to get a 0-100
250
+ score and structured findings (warn/suggest/info) about how well the body
251
+ adheres to the design system. The system-prompt fragment now instructs
252
+ agents to self-check on complex artifacts.
253
+
254
+ ## v0.1.3 — 2026-05-11
255
+
256
+ ### Added
257
+
258
+ - Four theme presets (`warm`, `cool`, `mono`, `paper`) selectable via `themePreset`
259
+ in `~/.config/opencode/cesium.json`. `CESIUM_THEME_PRESET` env honored.
260
+ - Per-token `theme: {...}` overrides now stack on top of the chosen preset.
261
+
262
+ ## v0.1.2 — 2026-05-11
263
+
264
+ ### Added
265
+
266
+ - Each artifact now renders a small back-nav at the top of the body linking to
267
+ its project's `index.html` and to the global `index.html`. Uses relative
268
+ paths so it works the same over `http://` and `file://`.
269
+
270
+ ## v0.1.1 — 2026-05-11
271
+
272
+ ### Added
273
+
274
+ - `hostname` config field (default `127.0.0.1`) lets the local HTTP server bind
275
+ to any address, including `0.0.0.0` for LAN access. `CESIUM_HOSTNAME` env var
276
+ is honored as an override.
277
+ - Display URLs in `terminalSummary` now resolve sensibly: `127.0.0.1` becomes
278
+ `localhost`, `0.0.0.0` becomes the first non-loopback IPv4 interface address,
279
+ named hosts pass through verbatim. Generated http URLs are always reachable.
280
+
281
+ ### Changed
282
+
283
+ - `terminalSummary` URLs now show `http://localhost:3030/...` by default
284
+ (previously `http://127.0.0.1:3030/...`). Functionally equivalent on a single
285
+ machine; consistent with how URLs are rendered when binding to other hosts.
286
+
287
+ ## v0.1.0 — 2026-05-11
288
+
289
+ Initial release.
290
+
291
+ ### Tools
292
+
293
+ - `cesium_publish` — agent-decided HTML artifact publishing with strict portability
294
+ (no external resources), input validation, embedded JSON metadata, atomic writes,
295
+ and revision chains via `supersedes`.
296
+ - `cesium_styleguide` — on-demand design system reference for the agent.
297
+
298
+ ### Storage
299
+
300
+ - Artifacts written to `~/.local/state/cesium/projects/<project-slug>/artifacts/`.
301
+ - Project slug derived from git remote when available, else `<basename>-<6char hash>`.
302
+ - Embedded `<script type="application/json" id="cesium-meta">` is the source of truth;
303
+ `index.json` per-project + global is a regenerated cache.
304
+ - Revision chains: `supersedes` field links a new artifact to its predecessor; the
305
+ predecessor's metadata is patched in-place with `supersededBy`.
306
+
307
+ ### Index pages
308
+
309
+ - Per-project and global `index.html` regenerated atomically on every publish.
310
+ - Inline JS for kind-filter chips, title search, and revision-chain collapsing.
311
+ - File lock at `<stateDir>/.index.lock` serializes concurrent publishes.
312
+
313
+ ### Server
314
+
315
+ - Lazy-start Bun HTTP server on port 3030 (configurable). Scans 3030–3050 on conflict.
316
+ - Static file serving with proper MIME types and path-traversal defense in depth.
317
+ - Idle shutdown after 30 minutes of no requests.
318
+ - SSH detection (`$SSH_CONNECTION`) emits a `ssh -L` port-forward hint in the publish
319
+ output.
320
+ - PID file at `<stateDir>/.server.pid` with stale-process detection.
321
+
322
+ ### Design system
323
+
324
+ - Warm ivory / clay / oat palette inspired by the html-effectiveness reference.
325
+ - 16 named component classes covering typography, cards, callouts, code panels,
326
+ timelines, diagrams, comparison and risk tables, and inline chips.
327
+ - System fonts only — no remote resources. Files are fully self-contained.
328
+
329
+ ### Agent steering
330
+
331
+ - `experimental.chat.system.transform` hook injects a ~600-token system fragment
332
+ describing the trigger heuristic (≥ 400 word threshold) and the component-class
333
+ cheatsheet.
334
+ - Optional dedicated `@cesium` agent definition shipped at `agents/cesium.md` —
335
+ copy into `~/.config/opencode/agents/` to invoke explicit-publish sessions.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 cfb
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.