typebulb 0.14.1 → 0.14.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.
- package/README.md +99 -94
- package/dist/agents/claude/client.js +161 -161
- package/dist/agents/claude/styles.css +36 -22
- package/dist/index.js +128 -128
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -25,14 +25,60 @@ A `.bulb.md` file bundles code, styles, data, and config in one file.
|
|
|
25
25
|
- **Package resolution** — Client dependencies are automatically resolved by generating import maps (same resolver as typebulb.com). Server dependencies are automatically installed via npm.
|
|
26
26
|
- **Replace dependency** — `--replace <name>=<path>` replaces a declared dependency with a local *built* package folder (browser-ready ESM, no external bare imports) instead of a CDN, for testing an unpublished build. Supplies both runtime bytes and types; applies to `run` and `check`. Under `--watch` the folder is watched and the browser reloads on rebuild (`--no-watch` freezes it). Dev-only; nothing is written to the bulb.
|
|
27
27
|
- **Local caching** — Resolver metadata and CDN package bytes are cached under `~/.typebulb/cache/`, so repeat runs don't re-hit the network and warm runs work offline.
|
|
28
|
-
-
|
|
28
|
+
- **`tb.ai()`** — a bulb's own code calling AI providers at runtime (chatbots, agents, experiments). `tb.models()` lists available models. Set API keys in `.env` (see below). Requires `--trust`.
|
|
29
29
|
- **Restricted 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 a Restricted run.
|
|
30
30
|
- **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.
|
|
31
31
|
- **Agent mirror** — a browser view of your project's Claude Code sessions that renders embedded bulbs, KaTeX, and mermaid live inline, plus runs/stops local bulbs (see [Claude](#claude)). `typebulb agent:claude` opens it. `typebulb agent` (no target) is the first command an agent runs: it brings up the mirror without opening a browser, prints its link, and points at the authoring skill. `typebulb skill` prints this whole README as an Agent Skill the agent can read and save.
|
|
32
32
|
|
|
33
|
-
##
|
|
33
|
+
## Usage
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
typebulb [file.bulb.md] Run a bulb (defaults to .bulb.md in cwd)
|
|
37
|
+
typebulb agent:claude Open the agent mirror of your project's Claude Code sessions
|
|
38
|
+
typebulb agent An agent's first command — brings up the agent mirror,
|
|
39
|
+
prints its URL + the authoring-skill paths; always exits 0
|
|
40
|
+
typebulb skill Print this README as an Agent Skill on stdout
|
|
41
|
+
typebulb call <file> <fn> […] Invoke one server.ts export headlessly: prints its return as JSON to stdout, logs/errors to stderr (needs --trust)
|
|
42
|
+
typebulb check [file.bulb.md] Type-check a bulb without running it
|
|
43
|
+
typebulb predict [file] Report the capability a bulb probably needs, without running it
|
|
44
|
+
typebulb models List AI models for tb.ai, filtered by your .env API keys
|
|
45
|
+
typebulb logs [file|pid] Print a running bulb's captured console (no arg: list running servers; -f follow, -n N tail)
|
|
46
|
+
typebulb wait [file|agent] Block until the target server logs a new line, print it, exit — an agent's wake-up
|
|
47
|
+
(--match <substr> filters; --timeout <sec>, default 1800, exit 2)
|
|
48
|
+
typebulb stop [file|pid] Stop a running bulb (no arg: list this project's running servers)
|
|
49
|
+
typebulb stop --bulbs Stop this project's bulbs; the agent mirror keeps running
|
|
50
|
+
typebulb stop --agent Stop this project's agent mirror; its bulbs keep running
|
|
51
|
+
typebulb stop --global Stop every running bulb and mirror, all projects (housekeeping)
|
|
52
|
+
typebulb trust [file] Remember a bulb as trusted (no arg: list trusted bulbs)
|
|
53
|
+
typebulb untrust <file> Forget a bulb's trust (back to Restricted)
|
|
54
|
+
typebulb --no-watch <file> Disable hot reload
|
|
55
|
+
typebulb --port 3333 <file> Custom port
|
|
56
|
+
typebulb --no-open <file> Don't auto-open browser
|
|
57
|
+
typebulb --mode <name> <file> Also load .env.<name> on top of .env / .env.local
|
|
58
|
+
typebulb --trust <file> Grant filesystem + AI + server.ts for this run (default: Restricted)
|
|
59
|
+
typebulb --no-trust <file> Force Restricted even if the bulb is remembered-trusted
|
|
60
|
+
typebulb --server <file> Run server.ts only, no web server (needs --trust)
|
|
61
|
+
typebulb --replace <name>=<path> Replace a dependency with a local build
|
|
62
|
+
typebulb --help Show help
|
|
63
|
+
typebulb --version Show version
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Bulb Format
|
|
67
|
+
|
|
68
|
+
A bulb is a single **markdown** file — the minimum viable structure for a small app. Its named **blocks** hold the code, plus optional styles, data, and config. Every block except `code.tsx` is optional. Mechanically, each block is a `**name**` header on its own line followed by a fenced code block, and the file opens with YAML frontmatter (`format: typebulb/v1`, `name:`).
|
|
69
|
+
|
|
70
|
+
| Block | Purpose |
|
|
71
|
+
|-------|---------|
|
|
72
|
+
| `**code.tsx**` | **Required.** App logic and UI (TypeScript/TSX). |
|
|
73
|
+
| `**index.html**` | The mount container. Include it — nearly every bulb does (e.g. `<div id="root"></div>`). Only pure console apps omit it. |
|
|
74
|
+
| `**styles.css**` | CSS. |
|
|
75
|
+
| `**config.json**` | `dependencies` and a `description`. |
|
|
76
|
+
| `**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**. |
|
|
77
|
+
| `**infer.md**` / `**insight.json**` | Runtime one-shot LLM call via `tb.infer()` — a typebulb.com feature; not supported locally. |
|
|
78
|
+
| `**notes.md**` | Persistent context for the AI assistant, carried across conversations and clones. Not run. |
|
|
79
|
+
| `**server.ts**` | Node.js code; its exports become `tb.server.<name>()` in the browser. Plain Node — no `tb`; log with `console.log`. **Local only.** |
|
|
34
80
|
|
|
35
|
-
|
|
81
|
+
### Example
|
|
36
82
|
|
|
37
83
|
````markdown
|
|
38
84
|
---
|
|
@@ -114,96 +160,6 @@ Or install globally:
|
|
|
114
160
|
npm install -g typebulb
|
|
115
161
|
```
|
|
116
162
|
|
|
117
|
-
## Usage
|
|
118
|
-
|
|
119
|
-
```
|
|
120
|
-
typebulb [file.bulb.md] Run a bulb (defaults to .bulb.md in cwd)
|
|
121
|
-
typebulb agent:claude Open the agent mirror of your project's Claude Code sessions
|
|
122
|
-
typebulb agent An agent's first command — brings up the agent mirror,
|
|
123
|
-
prints its URL + the authoring-skill paths; always exits 0
|
|
124
|
-
typebulb skill Print this README as an Agent Skill on stdout
|
|
125
|
-
typebulb call <file> <fn> […] Invoke one server.ts export headlessly: prints its return as JSON to stdout, logs/errors to stderr (needs --trust)
|
|
126
|
-
typebulb check [file.bulb.md] Type-check a bulb without running it
|
|
127
|
-
typebulb predict [file] Report the capability a bulb probably needs, without running it
|
|
128
|
-
typebulb models List AI models for tb.ai, filtered by your .env API keys
|
|
129
|
-
typebulb logs [file|pid] Print a running bulb's captured console (no arg: list running servers; -f follow, -n N tail)
|
|
130
|
-
typebulb wait [file|agent] Block until the target server logs a new line, print it, exit — an agent's wake-up
|
|
131
|
-
(--match <substr> filters; --timeout <sec>, default 1800, exit 2)
|
|
132
|
-
typebulb stop [file|pid] Stop a running bulb (no arg: list this project's running servers)
|
|
133
|
-
typebulb stop --bulbs Stop this project's bulbs; the agent mirror keeps running
|
|
134
|
-
typebulb stop --agent Stop this project's agent mirror; its bulbs keep running
|
|
135
|
-
typebulb stop --global Stop every running bulb and mirror, all projects (housekeeping)
|
|
136
|
-
typebulb trust [file] Remember a bulb as trusted (no arg: list trusted bulbs)
|
|
137
|
-
typebulb untrust <file> Forget a bulb's trust (back to Restricted)
|
|
138
|
-
typebulb --no-watch <file> Disable hot reload
|
|
139
|
-
typebulb --port 3333 <file> Custom port
|
|
140
|
-
typebulb --no-open <file> Don't auto-open browser
|
|
141
|
-
typebulb --mode <name> <file> Also load .env.<name> on top of .env / .env.local
|
|
142
|
-
typebulb --trust <file> Grant filesystem + AI + server.ts for this run (default: Restricted)
|
|
143
|
-
typebulb --no-trust <file> Force Restricted even if the bulb is remembered-trusted
|
|
144
|
-
typebulb --server <file> Run server.ts only, no web server (needs --trust)
|
|
145
|
-
typebulb --replace <name>=<path> Replace a dependency with a local build
|
|
146
|
-
typebulb --help Show help
|
|
147
|
-
typebulb --version Show version
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
## AI API Setup
|
|
151
|
-
|
|
152
|
-
Bulbs can call AI providers via `tb.ai()`. Add API keys to your `.env` file:
|
|
153
|
-
|
|
154
|
-
| Provider name | API key env var |
|
|
155
|
-
|---------------|-----------------|
|
|
156
|
-
| `anthropic` | `ANTHROPIC_API_KEY` |
|
|
157
|
-
| `openai` | `OPENAI_API_KEY` |
|
|
158
|
-
| `gemini` | `GOOGLE_API_KEY` |
|
|
159
|
-
| `openrouter` | `OPENROUTER_API_KEY` |
|
|
160
|
-
|
|
161
|
-
Set your default provider and model:
|
|
162
|
-
|
|
163
|
-
```
|
|
164
|
-
TB_AI_PROVIDER=anthropic
|
|
165
|
-
TB_AI_MODEL=claude-haiku-4-5-20251001
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
Both can be overridden per-call: `tb.ai({ provider: "gemini", model: "gemini-3.1-flash-lite", ... })`.
|
|
169
|
-
|
|
170
|
-
Run `typebulb models` to list the available model ids instead of guessing one.
|
|
171
|
-
|
|
172
|
-
### Reasoning
|
|
173
|
-
|
|
174
|
-
`tb.ai()` accepts an optional `reasoning` parameter (0–3) that hints at how much extended thinking the model should use:
|
|
175
|
-
|
|
176
|
-
| Level | Label | Effect |
|
|
177
|
-
|-------|-------|--------|
|
|
178
|
-
| 0 | Min | No extended reasoning (default) |
|
|
179
|
-
| 1 | Low | Light reasoning |
|
|
180
|
-
| 2 | Med | Moderate reasoning |
|
|
181
|
-
| 3 | Max | Maximum reasoning |
|
|
182
|
-
|
|
183
|
-
```typescript
|
|
184
|
-
const { text } = await tb.ai({
|
|
185
|
-
messages: [{ role: "user", content: "Explain quantum tunneling" }],
|
|
186
|
-
reasoning: 2,
|
|
187
|
-
});
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
Provider support varies — the level is mapped to provider-specific parameters (e.g. Anthropic's adaptive thinking, OpenAI's reasoning effort).
|
|
191
|
-
|
|
192
|
-
## Blocks
|
|
193
|
-
|
|
194
|
-
A bulb is a single **markdown** file — the minimum viable structure for a small app. Its named **blocks** hold the code, plus optional styles, data, and config. Every block except `code.tsx` is optional. Mechanically, each block is a `**name**` header on its own line followed by a fenced code block, and the file opens with YAML frontmatter (`format: typebulb/v1`, `name:`).
|
|
195
|
-
|
|
196
|
-
| Block | Purpose |
|
|
197
|
-
|-------|---------|
|
|
198
|
-
| `**code.tsx**` | **Required.** App logic and UI (TypeScript/TSX). |
|
|
199
|
-
| `**index.html**` | The mount container. Include it — nearly every bulb does (e.g. `<div id="root"></div>`). Only pure console apps omit it. |
|
|
200
|
-
| `**styles.css**` | CSS. |
|
|
201
|
-
| `**config.json**` | `dependencies` and a `description`. |
|
|
202
|
-
| `**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**. |
|
|
203
|
-
| `**infer.md**` / `**insight.json**` | Runtime one-shot LLM call via `tb.infer()` — a typebulb.com feature; not supported locally. |
|
|
204
|
-
| `**notes.md**` | Persistent context for the AI assistant, carried across conversations and clones. Not run. |
|
|
205
|
-
| `**server.ts**` | Node.js code; its exports become `tb.server.<name>()` in the browser. Plain Node — no `tb`; log with `console.log`. **Local only.** |
|
|
206
|
-
|
|
207
163
|
## The `tb.*` API, by target
|
|
208
164
|
|
|
209
165
|
`tb` is a pre-declared global your code can use without importing. What each call does, and where it works:
|
|
@@ -273,6 +229,14 @@ The host owns a bulb's **width**; you own its **height**.
|
|
|
273
229
|
.wrap { margin: 0 auto; padding: 24px 16px; } /* not: margin: 24px auto */
|
|
274
230
|
```
|
|
275
231
|
|
|
232
|
+
## Wake-on-event
|
|
233
|
+
|
|
234
|
+
`typebulb wait` turns a background task into a subscription. It blocks until the target server logs a new line (`--match <substr>` filters), prints it, and exits — and since an agent harness re-invokes the agent when a background task finishes, the exit *is* the wake-up. It resumes where your last `wait` or `call` on that target left off, so an event that lands while you're acting — or before the wait attaches — still fires it immediately; arm order doesn't matter. Exit `2` is the timeout (default 30 min): nothing happened, re-arm or stand down. Exit `3` means the server died.
|
|
235
|
+
|
|
236
|
+
**The turn-based loop** (a game, an approval flow): a bulb whose `server.ts` does `console.log` on each user action is the event channel. Per turn — act via `typebulb call`, arm `wait <file> --match <tag>` in the background, end your turn; on wake, read state with `typebulb call <file> <getState>` (never parse it from the log line) and repeat. A bulb's uncaught browser errors land in the same log as `[runtime error] …`, so the wake channel also catches your bulb breaking. For embeds, the same subscription is `typebulb wait claude` on the mirror — see [Emitting an embedded bulb](#emitting-an-embedded-bulb).
|
|
237
|
+
|
|
238
|
+
**Keep every loop command argument-stable.** A harness that permission-matches exact command strings prompts the user on *every* event if varying data (a move, a payload) rides the command line. Keep it off: write the args to a fixed file and pipe them — `cat <bulb-folder>/args.json | typebulb call <file> <fn> --args -` — so each of the loop's commands is one constant string, approved once. `wait` and a `getState` call are constant already.
|
|
239
|
+
|
|
276
240
|
## Tips for Agents
|
|
277
241
|
|
|
278
242
|
- **`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.
|
|
@@ -280,7 +244,6 @@ The host owns a bulb's **width**; you own its **height**.
|
|
|
280
244
|
- **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 Restricted 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.
|
|
281
245
|
- **A bulb's working files live in a folder named after the bulb.** Whether written by `server.ts` or `tb.fs.write`, favor a sibling folder matching the bulb's slug.
|
|
282
246
|
- **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`.
|
|
283
|
-
- **Waking on a user's action** — a bulb whose `server.ts` does `console.log` on an event (a chess move, a form submit) is a wake-up channel: `typebulb wait <file> --match <tag>` exits when the line lands. `wait` resumes where your last `wait` or `call` on that target left off, so an event that lands while you're acting (or before the wait attaches) still fires it immediately — arm order doesn't matter. On wake, read state with `typebulb call <file> <getState>` (never parse it from the log line), act, re-arm. Uncaught browser errors land in the same log as `[runtime error] …`.
|
|
284
247
|
- **Mount to the container your `index.html` declares.** The corpus convention is `<div id="root"></div>` with `createRoot(document.getElementById("root")!)`.
|
|
285
248
|
- **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.
|
|
286
249
|
- **Theme-aware styling.** Style off CSS variables / `currentColor` so the bulb reads correctly in both light and dark; the host sets the theme.
|
|
@@ -345,6 +308,48 @@ Which must be declared in the dependencies section:
|
|
|
345
308
|
|
|
346
309
|
Typebulb has a package resolver that will load and cache these packages from `esm.sh` when the bulb runs.
|
|
347
310
|
|
|
311
|
+
## `tb.ai()`
|
|
312
|
+
|
|
313
|
+
Trusted bulbs can call AI providers **from their own code** at runtime, billed to your API keys. Don't confuse this with the agent loop ([Wake-on-event](#wake-on-event)): there Claude drives a bulb from the chat session and *is* the intelligence — no provider, no key, and the bulb stays plain. `tb.ai()` is for bulbs that are themselves AI apps (chatbots, agents, experiments). Add API keys to your `.env` file:
|
|
314
|
+
|
|
315
|
+
| Provider name | API key env var |
|
|
316
|
+
|---------------|-----------------|
|
|
317
|
+
| `anthropic` | `ANTHROPIC_API_KEY` |
|
|
318
|
+
| `openai` | `OPENAI_API_KEY` |
|
|
319
|
+
| `gemini` | `GOOGLE_API_KEY` |
|
|
320
|
+
| `openrouter` | `OPENROUTER_API_KEY` |
|
|
321
|
+
|
|
322
|
+
Set your default provider and model:
|
|
323
|
+
|
|
324
|
+
```
|
|
325
|
+
TB_AI_PROVIDER=anthropic
|
|
326
|
+
TB_AI_MODEL=claude-haiku-4-5-20251001
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
Both can be overridden per-call: `tb.ai({ provider: "gemini", model: "gemini-3.1-flash-lite", ... })`.
|
|
330
|
+
|
|
331
|
+
Run `typebulb models` to list the available model ids instead of guessing one.
|
|
332
|
+
|
|
333
|
+
### Reasoning
|
|
334
|
+
|
|
335
|
+
`tb.ai()` accepts an optional `reasoning` parameter (0–3) that hints at how much extended thinking the model should use:
|
|
336
|
+
|
|
337
|
+
| Level | Label | Effect |
|
|
338
|
+
|-------|-------|--------|
|
|
339
|
+
| 0 | Min | No extended reasoning (default) |
|
|
340
|
+
| 1 | Low | Light reasoning |
|
|
341
|
+
| 2 | Med | Moderate reasoning |
|
|
342
|
+
| 3 | High | Heavy reasoning |
|
|
343
|
+
|
|
344
|
+
```typescript
|
|
345
|
+
const { text } = await tb.ai({
|
|
346
|
+
messages: [{ role: "user", content: "Explain quantum tunneling" }],
|
|
347
|
+
reasoning: 2,
|
|
348
|
+
});
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
Provider support varies — the level is mapped to provider-specific parameters (e.g. Anthropic's adaptive thinking, OpenAI's reasoning effort).
|
|
352
|
+
|
|
348
353
|
## License
|
|
349
354
|
|
|
350
355
|
MIT
|