typebulb 0.13.0 → 0.13.1
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.
- package/README.md +19 -17
- package/description.md +1 -1
- package/dist/agents/claude/client.js +2 -1
- package/dist/index.js +184 -173
- package/dist/render.js +2 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ A `.bulb.md` file bundles code, styles, data, and config in one file.
|
|
|
18
18
|
- **CLI logging** — `tb.server.log(...)` prints to the CLI's stdout
|
|
19
19
|
- **Env files** — `.env` / `.env.local` load from cwd, `.env.local` overriding `.env` (an exported shell var wins over both). `--mode <name>` adds `.env.<name>` to switch environments (local/staging/prod); a startup line reports which keys loaded from where.
|
|
20
20
|
- **Server mode** — `--server` runs only the `**server.ts**` section in Node, skipping the web server. Bulbs with only `**server.ts**` (no `**code.tsx**`) use this mode automatically.
|
|
21
|
-
- **Type-check without running** — `typebulb check <file>` runs `tsc --noEmit` against the bulb
|
|
21
|
+
- **Type-check without running** — `typebulb check <file>` runs `tsc --noEmit` against the bulb: non-zero exit with diagnostics on errors, a one-line all-clear on stderr on success.
|
|
22
22
|
- **Filesystem access** — `tb.fs.read()` (UTF-8 text), `tb.fs.readBytes()` (raw `Uint8Array`), and `tb.fs.write()` (text or bytes) for local files. Requires `--trust`.
|
|
23
23
|
- **Hot reload** — Recompiles on save and refreshes the browser (on by default; disable with `--no-watch`)
|
|
24
24
|
- **Package resolution** — Client dependencies are automatically resolved by generating import maps (same resolver as typebulb.com). Server dependencies are automatically installed via npm.
|
|
@@ -27,7 +27,7 @@ A `.bulb.md` file bundles code, styles, data, and config in one file.
|
|
|
27
27
|
- **AI calls** — `tb.ai()` for general-purpose AI (chatbots, agents, experiments). `tb.models()` lists available models. Set API keys in `.env` (see below). Requires `--trust`.
|
|
28
28
|
- **Sandboxed by default** — A plain `npx typebulb my-app.bulb.md` runs with no filesystem or `server.ts` (like typebulb.com); `--trust` grants those for a run. Trust is **remembered**: `typebulb trust <file>` elevates a bulb once so later plain runs are trusted, `untrust` revokes it, and `--no-trust` forces sandboxed for a single run.
|
|
29
29
|
- **Predict trust** — `typebulb predict <file>` reports the capability a bulb will likely need (fs / AI / `server.ts`) without running it, so you can decide on `--trust` up front rather than after a mid-run permission failure.
|
|
30
|
-
- **Agent
|
|
30
|
+
- **Agent mirror** — `typebulb agent:claude` opens the agent mirror, a browser view over a Claude Code session that renders embedded bulbs, KaTeX, and mermaid live inline, plus runs/stops local bulbs (see [Claude](#claude)). `typebulb agent` (no target) is the first command an agent runs: it tells the agent how to show a bulb inline or build one locally. `typebulb skill` prints this whole README as an Agent Skill the agent can read and save.
|
|
31
31
|
|
|
32
32
|
## Quick Start
|
|
33
33
|
|
|
@@ -117,18 +117,19 @@ npm install -g typebulb
|
|
|
117
117
|
|
|
118
118
|
```
|
|
119
119
|
typebulb [file.bulb.md] Run a bulb (defaults to .bulb.md in cwd)
|
|
120
|
-
typebulb agent:claude Open the agent
|
|
120
|
+
typebulb agent:claude Open the agent mirror (a Claude Code session)
|
|
121
121
|
typebulb agent Start here — how to show a bulb inline or build one locally
|
|
122
|
-
(prints the
|
|
122
|
+
(prints the mirror URL when one is up); always exits 0
|
|
123
123
|
typebulb skill Print this README as an Agent Skill on stdout
|
|
124
|
+
typebulb call <file> <fn> […] Invoke one server.ts export headlessly: prints its return as JSON to stdout, logs/errors to stderr (needs --trust)
|
|
124
125
|
typebulb check [file.bulb.md] Type-check a bulb without running it
|
|
125
126
|
typebulb predict [file] Report the capability a bulb probably needs, without running it
|
|
126
127
|
typebulb models List AI models for tb.ai, filtered by your .env API keys
|
|
127
128
|
typebulb logs [file|pid] Print a running bulb's captured console (no arg: list running servers; -f follow, -n N tail)
|
|
128
129
|
typebulb stop [file|pid] Stop a running bulb (no arg: list this project's running servers)
|
|
129
|
-
typebulb stop --bulbs Stop this project's bulbs; the agent
|
|
130
|
-
typebulb stop --agent Stop this project's agent
|
|
131
|
-
typebulb stop --global Stop every running bulb and
|
|
130
|
+
typebulb stop --bulbs Stop this project's bulbs; the agent mirror keeps running
|
|
131
|
+
typebulb stop --agent Stop this project's agent mirror; its bulbs keep running
|
|
132
|
+
typebulb stop --global Stop every running bulb and mirror, all projects (housekeeping)
|
|
132
133
|
typebulb trust [file] Remember a bulb as trusted (no arg: list trusted bulbs)
|
|
133
134
|
typebulb untrust <file> Forget a bulb's trust (back to sandboxed)
|
|
134
135
|
typebulb --no-watch <file> Disable hot reload
|
|
@@ -198,7 +199,7 @@ A bulb is a single **markdown** file — the minimum viable structure for a smal
|
|
|
198
199
|
| `**data.txt**` | Read-only data your code processes via `tb.data(n)` (raw string) / `tb.json(n)` (parsed) — JSON, CSV, XML, YAML, or plain text. Multiple chunks are separated by **two blank lines**. |
|
|
199
200
|
| `**infer.md**` / `**insight.json**` | Runtime one-shot LLM call via `tb.infer()` — a typebulb.com feature; not supported locally. |
|
|
200
201
|
| `**notes.md**` | Persistent context for the AI assistant, carried across conversations and clones. Not run. |
|
|
201
|
-
| `**server.ts**` | Node.js code; its exports become `tb.server.<name>()` in the browser. **Local only.** |
|
|
202
|
+
| `**server.ts**` | Node.js code; its exports become `tb.server.<name>()` in the browser. Plain Node — no `tb`; log with `console.log`. **Local only.** |
|
|
202
203
|
|
|
203
204
|
## The `tb.*` API, by target
|
|
204
205
|
|
|
@@ -228,7 +229,7 @@ A local `.bulb.md` can be re-imported into typebulb.com. If it has a `**server.t
|
|
|
228
229
|
|
|
229
230
|
## Claude
|
|
230
231
|
|
|
231
|
-
The agent
|
|
232
|
+
The agent mirror currently supports Claude Code only. `npx typebulb agent:claude` gives the user a great scratchpad experience:
|
|
232
233
|
|
|
233
234
|
* a view over the Claude Code session, where assistant messages containing bulbs render as sandboxed embedded bulbs inline in the conversation, alongside KaTeX math, mermaid diagrams and svg.
|
|
234
235
|
* run and stop any bulb in their project.
|
|
@@ -241,7 +242,7 @@ To keep this skill on hand across sessions, run `npx typebulb skill` and copy it
|
|
|
241
242
|
### When Claude should output local vs embedded bulbs
|
|
242
243
|
|
|
243
244
|
- **First, can it even embed?** A bulb needing `tb.ai`, `tb.fs`, or `server.ts` must be **local** — embeds are client-only, so those calls fail there. The choice below is only for client-only bulbs.
|
|
244
|
-
- **Is anyone watching?** An embed only renders live when the agent
|
|
245
|
+
- **Is anyone watching?** An embed only renders live when the agent mirror is open; with none it shows as raw text. `typebulb agent` tells you which case you're in. If no mirror is up and you want to show something inline, start it yourself — `npx typebulb agent:claude --no-open` — and share the link; don't make the user do it.
|
|
245
246
|
- **Something to see right now, in the flow of the conversation** — a chart of some numbers, a quick simulation, an illustrative widget. → **embedded**: emit it in a `bulb` block so it renders live inline.
|
|
246
247
|
- **A tool worth keeping** — something to reuse, run on its own, or refine over several turns. → **local**: write a `.bulb.md` file run with `npx typebulb`. An embedded block is throwaway and can't be edited in place, so it's the wrong fit for anything iterative.
|
|
247
248
|
|
|
@@ -249,21 +250,21 @@ To keep this skill on hand across sessions, run `npx typebulb skill` and copy it
|
|
|
249
250
|
|
|
250
251
|
To render a bulb live inline, wrap the **entire** bulb — frontmatter and all blocks — in a fenced code block whose opening line is **four backticks immediately followed by `bulb`**, and whose closing line is four backticks. Four, not three, so the bulb's own triple-backtick code fences nest inside without prematurely closing the outer block.
|
|
251
252
|
|
|
252
|
-
The agent
|
|
253
|
+
The agent mirror turns that block into a live, sandboxed app, with a *breakout ↗* control that saves it as a `.bulb.md` in the `typebulbs/` folder — editable with hot reload, and sandboxed unless you trust it. Embedded bulbs are client-only — no `server.ts`, no `tb.fs`/`tb.ai`, no storage.
|
|
253
254
|
|
|
254
|
-
**Fixing a broken embed?** Re-emit it under the *same* `name:` — the
|
|
255
|
+
**Fixing a broken embed?** Re-emit it under the *same* `name:` — the mirror folds the old version into a stub and keeps your fix as the live one. (A rename is treated as a new bulb.)
|
|
255
256
|
|
|
256
|
-
**A broken embed reads back.** Emit it and move on; embeds usually just work. If the user says one broke, the
|
|
257
|
+
**A broken embed reads back.** Emit it and move on; embeds usually just work. If the user says one broke, the mirror has already forwarded its compile/runtime error to `typebulb logs claude`, name-tagged (`[embed <name>]`) — pull it from there and fix, instead of asking the user to copy-paste.
|
|
257
258
|
|
|
258
259
|
## Sizing
|
|
259
260
|
|
|
260
261
|
The host owns a bulb's **width**; you own its **height**.
|
|
261
262
|
|
|
262
|
-
**Width is the host's.** Standalone, a bulb fills its browser window; in the agent
|
|
263
|
+
**Width is the host's.** Standalone, a bulb fills its browser window; in the agent mirror, an embed fits the conversation column by default, with a per-embed *spread* toggle to the full transcript width — and a cap so a tall embed doesn't run away down the transcript. Don't set a width or guess how much room you'll get.
|
|
263
264
|
|
|
264
|
-
**Height follows your content.** Prose, a form, a chart flow to their natural height — set none. A full-bleed canvas has no natural height: give its root `height: 100dvh` **and** a pixel floor like `min-height: 420px`. Both are needed — `100dvh` fills its own window if the bulb is broken out, and the floor holds a definite band when embedded. Without the floor a bare `100dvh` collapses to zero embedded, because the
|
|
265
|
+
**Height follows your content.** Prose, a form, a chart flow to their natural height — set none. A full-bleed canvas has no natural height: give its root `height: 100dvh` **and** a pixel floor like `min-height: 420px`. Both are needed — `100dvh` fills its own window if the bulb is broken out, and the floor holds a definite band when embedded. Without the floor a bare `100dvh` collapses to zero embedded, because the mirror sizes an embed to its content height and `100dvh` gives it nothing to measure against.
|
|
265
266
|
|
|
266
|
-
**When embedded, keep vertical space on the root in `padding`, not `margin`.** The
|
|
267
|
+
**When embedded, keep vertical space on the root in `padding`, not `margin`.** The mirror measures an embed by `document.body.scrollHeight`, and the runtime makes `body` a block formatting context so a root child's vertical margin (yours, or a UA default like `<h1>`'s) is contained rather than escaping the measurement — so you no longer have to get this exactly right. It's still cleaner to keep the horizontal `auto` for centering and move the vertical space to padding:
|
|
267
268
|
|
|
268
269
|
```css
|
|
269
270
|
.wrap { margin: 0 auto; padding: 24px 16px; } /* not: margin: 24px auto */
|
|
@@ -274,13 +275,14 @@ The host owns a bulb's **width**; you own its **height**.
|
|
|
274
275
|
- **`config.json` `description`** is the bulb's SEO meta description — keep it to one or two plain sentences (~150–160 chars), or it gets truncated.
|
|
275
276
|
- **The frontmatter `name:` is the bulb's title** — a few words, not a sentence — and the filename should be its slug (`name: Counter` → `counter.bulb.md`).
|
|
276
277
|
- **Self-testing a local bulb** — To confirm a bulb works, run it, instrument with `tb.server.log(...)` (prints to the server's stdout, captured in the log — and works **even on a sandboxed bulb**), and read it back with `typebulb logs`. That's the loop to verify behaviour without asking the user to copy-paste console output. `tb.fs.write(...)` is handy for dumping large outputs.
|
|
278
|
+
- **Testing a `server.ts` export directly** — `typebulb call <file> <fn> [arg…]` boots `server.ts`, invokes one export, and prints its return as JSON to stdout (logs/errors to stderr, so `… | jq` works). Args after `<fn>` are JSON-or-string; `--args '<json-array>'` (or `--args -` for stdin) escapes tricky quoting. Needs `--trust`.
|
|
277
279
|
- **Mount to the container your `index.html` declares.** The corpus convention is `<div id="root"></div>` with `createRoot(document.getElementById("root")!)`.
|
|
278
280
|
- **All imports at the top of `code.tsx`.** Bare imports (`react`, `d3`, `three`, …) auto-resolve from a CDN — no install step. Declare them in `config.json` `dependencies` anyway: that's what lets `npx typebulb check` fetch type defs (without it you get errors like `TS2875: react/jsx-runtime`) and pins versions.
|
|
279
281
|
- **Theme-aware styling.** Style off CSS variables / `currentColor` so the bulb reads correctly in both light and dark; the host sets the theme.
|
|
280
282
|
- **`tb.ai()` takes more than the basics** — the full shape is `tb.ai({ messages, system?, reasoning?, provider?, model?, webSearch? })` → `Promise<{ text }>` (non-streaming). `webSearch` defaults **on** in the CLI (you supply your own key); pass `webSearch: false` to turn it off.
|
|
281
283
|
- **`tb.theme` drives the `html[data-theme]` attribute** — style off that selector (`html[data-theme="dark"] { … }`); don't read `tb.theme` to branch your rendering.
|
|
282
284
|
- **`color-scheme` is set for you** — the host always applies `html[data-theme="dark"] { color-scheme: dark }` / `html[data-theme="light"] { color-scheme: light }` on top of your `styles.css`.
|
|
283
|
-
- **Math renders live in the
|
|
285
|
+
- **Math renders live in the mirror** — write inline math as `$…$` and display math as `$$…$$` (the mirror renders KaTeX; a plain terminal chat doesn't, so reach for real math here). Prefer `$y = x^2$` over inline-code or a Unicode superscript (`y = x²`).
|
|
284
286
|
- **`tb.json<T>(n)` is generic** — `tb.json<Album[]>(0)` returns typed parsed JSON; `tb.data(n)` returns the raw string.
|
|
285
287
|
- **`tb.proxy()` is for same-origin Web Worker / WASM loads** — e.g. ffmpeg or tesseract: `tb.proxy("https://unpkg.com/...")` routes the CDN URL through the local server's origin.
|
|
286
288
|
- **Prefer an `index.html` fragment** over a full HTML document — usually just the mount stub (`<div id="root"></div>`).
|
package/description.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Author and run Typebulb bulbs — single-file markdown apps (TypeScript/TSX) that run
|
|
2
2
|
locally via `npx typebulb` (full power: filesystem, database, `server.ts`, `tb.ai`) or
|
|
3
|
-
render live inline in a Claude Code session through Typebulb's agent
|
|
3
|
+
render live inline in a Claude Code session through Typebulb's agent mirror (sandboxed,
|
|
4
4
|
client-only). A bulb can be a visual widget (chart, simulation, diagram, calculator, UI),
|
|
5
5
|
a full-stack tool with a Node backend, or an AI app that calls models at runtime. Covers
|
|
6
6
|
the bulb format, the `tb.*` API, trust, and the local run/embed workflow. Use when the
|
|
@@ -693,7 +693,7 @@ ${a.map(({variableName:d,uniqueLocalName:g})=>` reactHotLoader.register(${d}, "
|
|
|
693
693
|
// otherwise fail with cryptic CORS/CSP errors. Detect it and fail clearly.
|
|
694
694
|
//
|
|
695
695
|
// The same sandboxed-iframe path also backs the CLI's default (untrusted) launch
|
|
696
|
-
// (
|
|
696
|
+
// (TB-Trust.md), where the right message names \`--trust\` rather
|
|
697
697
|
// than "no host bridge". The host injects window.__TB_EMBED_ERR__ to override the
|
|
698
698
|
// text; absent it, the nested-bulb wording applies.
|
|
699
699
|
const isEmbedded = window.parent !== window;
|
|
@@ -897,6 +897,7 @@ ${a.map(({variableName:d,uniqueLocalName:g})=>` reactHotLoader.register(${d}, "
|
|
|
897
897
|
}
|
|
898
898
|
})();
|
|
899
899
|
`;function REt(s){return s.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}var PEt=` *, *::before, *::after { box-sizing: border-box; }
|
|
900
|
+
canvas { max-width: 100%; }
|
|
900
901
|
body { margin: 0; display: flow-root; font-family: system-ui, -apple-system, sans-serif; }
|
|
901
902
|
html[data-theme="dark"] { color-scheme: dark; }
|
|
902
903
|
html[data-theme="light"] { color-scheme: light; }`;function FEt(s,o){let a=d=>d.replace(/<\/script/gi,"<\\/script");return` <script>
|