typebulb 0.50.0 → 0.51.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 CHANGED
@@ -47,6 +47,7 @@ typebulb send <file> tb:rect … Print a named control's rect ('tb:rect butto
47
47
  typebulb send <file> tb:click … Click a control by role+name ('tb:click button "Pass"'); the reply is a fresh snapshot
48
48
  typebulb send <file> tb:set … Set a form control ('tb:set combobox "level" = hard'), firing input+change
49
49
  typebulb send <file> tb:png … Save the live canvas as PNG, print its path (sole canvas needs no name; 'tb:png "<name>"' among several)
50
+ typebulb send <file> tb:theme … Flip the page's theme for a probe ('tb:theme dark'; bare clears) — transient, never saved
50
51
  typebulb get <file> <kind> Print one block's content (data, insight, code, …) to stdout
51
52
  typebulb put <file> <k>=<src> Write a file's (or stdin's) content into a block, surgically
52
53
  typebulb pull <url|file> Fetch a bulb from typebulb.com into typebulbs/u/<user>/<slug>.bulb.md
@@ -301,6 +302,18 @@ The host owns a bulb's **width**; you own its **height**.
301
302
  .wrap { margin: 0 auto; padding: 24px 16px; } /* not: margin: 24px auto */
302
303
  ```
303
304
 
305
+ ## Theming
306
+
307
+ The host owns light/dark; you style for both.
308
+
309
+ **Style off `html[data-theme]`.** The host sets that attribute — key your CSS off it (`html[data-theme="dark"] { … }`), off CSS variables, or off `currentColor`; don't read `tb.theme` to branch your rendering. `color-scheme` is set for you: the host always maps `html[data-theme="dark"] { color-scheme: dark }` (and light) on top of your `styles.css`.
310
+
311
+ **Native dropdowns need system colors.** Style `select, option { background: Canvas; color: CanvasText }` — those track the host's `color-scheme`, and a `transparent` `<select>` otherwise opens an unthemed popup, white-on-white in dark mode.
312
+
313
+ **A bulb with one correct look pins it with two rules, not one.** A daytime scene that would be nonsense in dark overrides the host's own selectors from `styles.css`: your colours **and** `html[data-theme="dark"] { color-scheme: light }`. Miss the second and the flip still swaps its scrollbars and form controls.
314
+
315
+ **Check both themes without leaving the terminal.** `typebulb send <file> tb:theme dark`, then `tb:png` or `tb:snapshot`. The flip is transient — nothing is saved, and a reload restores what the user was looking at.
316
+
304
317
  ## Tips for Agents
305
318
 
306
319
  - **A bulb's working files land beside it automatically** — relative `tb.fs` paths resolve to the bulb's folder, in `code.tsx` and `server.ts` alike: `tb.fs.write('run.json')`, no path prefix, no mkdir.
@@ -314,16 +327,9 @@ The host owns a bulb's **width**; you own its **height**.
314
327
  - **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`.
315
328
  - **Mount to the container your `index.html` declares.** The corpus convention is `<div id="root"></div>` with `createRoot(document.getElementById("root")!)`.
316
329
  - **All imports at the top of `code.tsx`, and every bare import declared in `config.json` `dependencies`.** Bare imports (`react`, `d3`, `three`, …) resolve from a CDN — no install step — but declaring them is **required, not optional**: an import missing from `dependencies` is a lint error that fails `npx typebulb check` *and* refuses to run. Declaring is also what pins versions and lets `check` fetch type defs (without it you get errors like `TS2875: react/jsx-runtime`). So a bulb with imports must carry a `config.json` with a matching `dependencies` entry for each.
317
- - **Theme-aware styling.** Style off CSS variables / `currentColor` so the bulb reads correctly in both light and dark; the host sets the theme.
318
- - **Native dropdowns.** Style `select, option { background: Canvas; color: CanvasText }` (system colors track the host's `color-scheme`) — a `transparent` `<select>` otherwise opens an unthemed popup, white-on-white in dark mode.
319
- - **`tb.ai()` takes more than the basics** — the full shape is `tb.ai({ messages, system?, effort?, provider?, model?, webSearch? })` → `Promise<{ text }>`. `webSearch` defaults **on** in the CLI (you supply your own key); pass `webSearch: false` to turn it off. For token-by-token output use `tb.ai.stream(...)` (see [`tb.ai()` § Streaming](#streaming)).
320
- - **Gate AI-heavy bulbs on `tb.aiAccess()`** — `'own'` / `'courtesy'` / `'none'`, never re-derived from `tb.mode` or the model list (see [AI access](#ai-access)).
321
- - **`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.
322
- - **`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`.
323
330
  - **Math (KaTeX) renders in your replies** — write inline `$…$` / display `$$…$$` (prefer `$y = x^2$` over inline-code or a Unicode `y = x²`). The mirror's KaTeX renders only in prose and doesn't reach inside a fenced block (bulb, mermaid, svg, code).
324
331
  - **Charts: prefer a bulb over mermaid's `xychart`** unless a static, unlabeled bar or line is enough — start from the [Charts](#charts) skeleton.
325
332
  - **`tb.json<T>(n)` is generic** — `tb.json<Album[]>(0)` returns typed parsed JSON; `tb.data(n)` returns the raw string.
326
- - **`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.
327
333
  - **Prefer an `index.html` fragment** over a full HTML document — usually just the mount stub (`<div id="root"></div>`).
328
334
  - **`config.json` → `ts.jsxImportSource`** — the one supported `ts` option; defaults to `react`. Set it to use a different JSX runtime (e.g. `preact`).
329
335
  - **Never invent a connection string or API key** — a `server.ts` that needs a database or API reads it from `.env` (loaded from the directory you run in). Ask the user for the value; don't fabricate one or commit it.
@@ -413,9 +419,11 @@ Run `typebulb models` to list the models available for the providers specified.
413
419
 
414
420
  Trusted bulbs can call AI providers **from their own code** at runtime, billed to your API keys.
415
421
 
416
- You can call the provider and model explicitly like this: `tb.ai({ provider: "gemini", model: "gemini-3.1-flash-lite", ... })`.
422
+ ```ts
423
+ tb.ai({ messages, system?, effort?, provider?, model?, webSearch? }) // → Promise<{ text }>
424
+ ```
417
425
 
418
- Or you can rely on the default provider and model if you set them in `.env`.
426
+ Name the provider and model explicitly — `tb.ai({ provider: "openai", model: "gpt-5.6-luna", … })` — or rely on the defaults you set in `.env`. `webSearch` defaults **off**; pass `webSearch: true` to give the model a web-search tool (searches bill to your key).
419
427
 
420
428
  ### Reasoning effort
421
429
 
@@ -451,7 +459,7 @@ Breaking the loop stops the stream; same options as `tb.ai()`. **`kind: "reasoni
451
459
 
452
460
  ### AI access
453
461
 
454
- `tb.aiAccess()` reports what backs `tb.ai`, typed as the ambient `AiAccess`.
462
+ `tb.aiAccess()` reports what backs `tb.ai`, typed as the ambient `AiAccess`. Gate an AI-heavy bulb on it, never on `tb.mode` or the model list.
455
463
 
456
464
  | Value | What it means | What a bulb does |
457
465
  |-------|---------------|------------------|
package/SKILL.md CHANGED
@@ -1,10 +1,10 @@
1
1
  ---
2
2
  name: typebulb
3
3
  description: "Author and run Typebulb bulbs — single-file markdown apps (TypeScript/TSX) that run locally via `npx typebulb` (full power: filesystem, database, `server.ts`, `tb.ai`) or render live inline in your coding agent's session through Typebulb's agent mirror (sandboxed, client-only). A bulb can be a visual widget (chart, simulation, diagram, calculator, UI), a full-stack tool with a Node backend, or an AI app that calls models at runtime. Covers the bulb format, the `tb.*` API, trust, and the local run/inline workflow. Use when the user wants a bulb, a quick local tool (visual, backend-backed, or AI-powered), or something visual rendered inline in the conversation."
4
- version: 0.50.0
4
+ version: 0.51.1
5
5
  ---
6
6
 
7
- > Generated from typebulb v0.50.0. `npx typebulb agent` prints the running version alongside the path to its packaged SKILL.md: if that version is newer than this one, replace this file with that one.
7
+ > Generated from typebulb v0.51.1. `npx typebulb agent` prints the running version alongside the path to its packaged SKILL.md: if that version is newer than this one, replace this file with that one.
8
8
 
9
9
  # typebulb
10
10
 
@@ -55,6 +55,7 @@ typebulb send <file> tb:rect … Print a named control's rect ('tb:rect butto
55
55
  typebulb send <file> tb:click … Click a control by role+name ('tb:click button "Pass"'); the reply is a fresh snapshot
56
56
  typebulb send <file> tb:set … Set a form control ('tb:set combobox "level" = hard'), firing input+change
57
57
  typebulb send <file> tb:png … Save the live canvas as PNG, print its path (sole canvas needs no name; 'tb:png "<name>"' among several)
58
+ typebulb send <file> tb:theme … Flip the page's theme for a probe ('tb:theme dark'; bare clears) — transient, never saved
58
59
  typebulb get <file> <kind> Print one block's content (data, insight, code, …) to stdout
59
60
  typebulb put <file> <k>=<src> Write a file's (or stdin's) content into a block, surgically
60
61
  typebulb pull <url|file> Fetch a bulb from typebulb.com into typebulbs/u/<user>/<slug>.bulb.md
@@ -309,6 +310,18 @@ The host owns a bulb's **width**; you own its **height**.
309
310
  .wrap { margin: 0 auto; padding: 24px 16px; } /* not: margin: 24px auto */
310
311
  ```
311
312
 
313
+ ## Theming
314
+
315
+ The host owns light/dark; you style for both.
316
+
317
+ **Style off `html[data-theme]`.** The host sets that attribute — key your CSS off it (`html[data-theme="dark"] { … }`), off CSS variables, or off `currentColor`; don't read `tb.theme` to branch your rendering. `color-scheme` is set for you: the host always maps `html[data-theme="dark"] { color-scheme: dark }` (and light) on top of your `styles.css`.
318
+
319
+ **Native dropdowns need system colors.** Style `select, option { background: Canvas; color: CanvasText }` — those track the host's `color-scheme`, and a `transparent` `<select>` otherwise opens an unthemed popup, white-on-white in dark mode.
320
+
321
+ **A bulb with one correct look pins it with two rules, not one.** A daytime scene that would be nonsense in dark overrides the host's own selectors from `styles.css`: your colours **and** `html[data-theme="dark"] { color-scheme: light }`. Miss the second and the flip still swaps its scrollbars and form controls.
322
+
323
+ **Check both themes without leaving the terminal.** `typebulb send <file> tb:theme dark`, then `tb:png` or `tb:snapshot`. The flip is transient — nothing is saved, and a reload restores what the user was looking at.
324
+
312
325
  ## Tips for Agents
313
326
 
314
327
  - **A bulb's working files land beside it automatically** — relative `tb.fs` paths resolve to the bulb's folder, in `code.tsx` and `server.ts` alike: `tb.fs.write('run.json')`, no path prefix, no mkdir.
@@ -322,16 +335,9 @@ The host owns a bulb's **width**; you own its **height**.
322
335
  - **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`.
323
336
  - **Mount to the container your `index.html` declares.** The corpus convention is `<div id="root"></div>` with `createRoot(document.getElementById("root")!)`.
324
337
  - **All imports at the top of `code.tsx`, and every bare import declared in `config.json` `dependencies`.** Bare imports (`react`, `d3`, `three`, …) resolve from a CDN — no install step — but declaring them is **required, not optional**: an import missing from `dependencies` is a lint error that fails `npx typebulb check` *and* refuses to run. Declaring is also what pins versions and lets `check` fetch type defs (without it you get errors like `TS2875: react/jsx-runtime`). So a bulb with imports must carry a `config.json` with a matching `dependencies` entry for each.
325
- - **Theme-aware styling.** Style off CSS variables / `currentColor` so the bulb reads correctly in both light and dark; the host sets the theme.
326
- - **Native dropdowns.** Style `select, option { background: Canvas; color: CanvasText }` (system colors track the host's `color-scheme`) — a `transparent` `<select>` otherwise opens an unthemed popup, white-on-white in dark mode.
327
- - **`tb.ai()` takes more than the basics** — the full shape is `tb.ai({ messages, system?, effort?, provider?, model?, webSearch? })` → `Promise<{ text }>`. `webSearch` defaults **on** in the CLI (you supply your own key); pass `webSearch: false` to turn it off. For token-by-token output use `tb.ai.stream(...)` (see [`tb.ai()` § Streaming](#streaming)).
328
- - **Gate AI-heavy bulbs on `tb.aiAccess()`** — `'own'` / `'courtesy'` / `'none'`, never re-derived from `tb.mode` or the model list (see [AI access](#ai-access)).
329
- - **`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.
330
- - **`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`.
331
338
  - **Math (KaTeX) renders in your replies** — write inline `$…$` / display `$$…$$` (prefer `$y = x^2$` over inline-code or a Unicode `y = x²`). The mirror's KaTeX renders only in prose and doesn't reach inside a fenced block (bulb, mermaid, svg, code).
332
339
  - **Charts: prefer a bulb over mermaid's `xychart`** unless a static, unlabeled bar or line is enough — start from the [Charts](#charts) skeleton.
333
340
  - **`tb.json<T>(n)` is generic** — `tb.json<Album[]>(0)` returns typed parsed JSON; `tb.data(n)` returns the raw string.
334
- - **`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.
335
341
  - **Prefer an `index.html` fragment** over a full HTML document — usually just the mount stub (`<div id="root"></div>`).
336
342
  - **`config.json` → `ts.jsxImportSource`** — the one supported `ts` option; defaults to `react`. Set it to use a different JSX runtime (e.g. `preact`).
337
343
  - **Never invent a connection string or API key** — a `server.ts` that needs a database or API reads it from `.env` (loaded from the directory you run in). Ask the user for the value; don't fabricate one or commit it.
@@ -421,9 +427,11 @@ Run `typebulb models` to list the models available for the providers specified.
421
427
 
422
428
  Trusted bulbs can call AI providers **from their own code** at runtime, billed to your API keys.
423
429
 
424
- You can call the provider and model explicitly like this: `tb.ai({ provider: "gemini", model: "gemini-3.1-flash-lite", ... })`.
430
+ ```ts
431
+ tb.ai({ messages, system?, effort?, provider?, model?, webSearch? }) // → Promise<{ text }>
432
+ ```
425
433
 
426
- Or you can rely on the default provider and model if you set them in `.env`.
434
+ Name the provider and model explicitly — `tb.ai({ provider: "openai", model: "gpt-5.6-luna", … })` — or rely on the defaults you set in `.env`. `webSearch` defaults **off**; pass `webSearch: true` to give the model a web-search tool (searches bill to your key).
427
435
 
428
436
  ### Reasoning effort
429
437
 
@@ -459,7 +467,7 @@ Breaking the loop stops the stream; same options as `tb.ai()`. **`kind: "reasoni
459
467
 
460
468
  ### AI access
461
469
 
462
- `tb.aiAccess()` reports what backs `tb.ai`, typed as the ambient `AiAccess`.
470
+ `tb.aiAccess()` reports what backs `tb.ai`, typed as the ambient `AiAccess`. Gate an AI-heavy bulb on it, never on `tb.mode` or the model list.
463
471
 
464
472
  | Value | What it means | What a bulb does |
465
473
  |-------|---------------|------------------|