typebulb 0.55.2 → 0.55.4

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
@@ -229,7 +229,7 @@ One exception: if `TYPEBULB_MIRROR=1` is set in your environment, the user is pr
229
229
 
230
230
  - **First, can it even run inline?** A bulb needing `tb.ai`, `tb.infer`, `tb.fs`, or `server.ts` must be **local** — inline bulbs are client-only, so those calls fail there. The choice below is only for client-only bulbs.
231
231
  - **Is anyone watching?** An inline bulb only renders live when the agent mirror is open; with none it shows as raw text. `npx typebulb agent` starts the mirror if needed and prints its link — share it with the user; don't make the user start anything.
232
- - **Something to see right now, in the flow of the conversation** — a chart of some numbers, a quick simulation, an illustrative widget. → **inline**: emit it in a `bulb` block so it renders live in the conversation.
232
+ - **Something to see right now, in the flow of the conversation** — a chart of some numbers, a quick simulation, an illustrative widget. → **inline**: emit it in a `bulb` block, straight into the reply. Don't draft it as a `.bulb.md` and test it first: a broken one reports its own error back to you (below), and the user expects a snappy response with an inline bulb.
233
233
  - **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 inline block is throwaway and can't be edited in place, so it's the wrong fit for anything iterative.
234
234
 
235
235
  ### Emitting an inline bulb
@@ -279,7 +279,7 @@ That one launch *is* the loop: the server watches the file, so every save recomp
279
279
  - **Slow work settles in the handler** — a handler may be async, and the reply waits for its promise: keep a done-promise, `await` it, and return the finished state, with `--wait=<ms>` sized to the work (instead of polling flags in a sleep loop, or snapshot-polling from outside). The sharp edge: settle the promise on *every* exit of the run — success, failure, supersession, in a `finally` — and start idle with an already-resolved one, or the handler hangs and reads as a broken bulb. One case stays two-step: a `tb:*` gesture that kicks off slow work replies with the immediate frame (runtime-answered), so follow it with this settle probe.
280
280
  - **Rendered truth** — `typebulb send <file> tb:snapshot` prints the page's accessibility outline (roles, names, visible text) without disturbing its state. Use it when logs say ok but the screen might not, and as the first probe on a live page in a state you can't reproduce — a save would hot-reload and destroy it. (`tb:` messages are answered by the runtime, never your handlers, and imply `--wait`.) Its first line is the page's geometry — viewport, content size, and a fits-or-overflows verdict — so an unwanted scrollbar shows up in the first read.
281
281
  - **Measuring layout** — `typebulb send <file> 'tb:rect button "Pass"'` prints that control's viewport-relative rect as JSON (`{x, y, width, height, viewport}`, integers): how big something ended up, whether two things align, whether one is offscreen — arithmetic on rects, no probe handler. Only what the outline names is measurable; give a structural container a `role` **and** an `aria-label` (`<div role="group" aria-label="board">`) to measure it — a label alone leaves it invisible.
282
- - **Acting on the page** — `typebulb send <file> 'tb:click button "Pass"'` clicks the one control matching that role and name (exact, else a unique case-insensitive substring) and replies with a fresh snapshot; `tb:set combobox "strength" = hard` is the same for form controls (checkboxes and radios take `tb:click`). A disabled, readonly, or covered target is an error naming it — that silence is the bug class these verbs catch. Needs exactly one page open, and the reply is the immediate frame (slow work: follow up with `tb:snapshot`). Only what the outline names is targetable: real `<button>`s and labeled controls, not an `onClick` `<div>`.
282
+ - **Acting on the page** — `typebulb send <file> 'tb:click button "Pass"'` clicks the one control matching that role and name (exact, else a unique case-insensitive substring) and replies with a fresh snapshot; `tb:set combobox "strength" = hard` is the same for form controls (checkboxes and radios take `tb:click`). A disabled, readonly, or covered target is an error naming it — that silence is the bug class these verbs catch. The click is synthetic, so a handler needing user activation (a clipboard write, fullscreen) does nothing and reports nothing. Needs exactly one page open, and the reply is the immediate frame (slow work: follow up with `tb:snapshot`). Only what the outline names is targetable: real `<button>`s and labeled controls, not an `onClick` `<div>`.
283
283
  - **Poking state** — for state beyond what a form control expresses (`tb:set` covers those), author a set-handler up front: a `tb.onMessage` branch that takes a data payload (JSON arrives parsed), applies it to your state — committing the change if your framework needs an explicit step — and returns the new state: `typebulb send <file> '{"set":"speed","value":2}' --wait` prints it. In React, register it in an effect so it closes over the setters (the returned unsubscribe is the cleanup).
284
284
  - **A page must be open** — the CLI runs no browser of its own, so every client-side check waits on a real window (and `--no-open` means there isn't one). `send` says which case it is: nobody has ever connected (share the link), or a page dropped and hasn't returned (it's stale — reload it). Never open a window at the user: the server logs `[page] connected` when a page attaches, so end your turn with the link, arming `typebulb wait <file> --match "[page] connected"` in the background first — the user opening the page is your wake-up.
285
285
  - **Reading a canvas** — `typebulb send <file> tb:png` writes the page's canvas to a PNG (a stable per-bulb path under `~/.typebulb/`, overwritten each read) and prints the path — rendered truth for a bulb whose output is drawn, with no probe handler and nothing disturbed. One canvas needs no name; several take `tb:png "<name>"` — an `aria-label` on the canvas, or `role="img" aria-label="…"` on the container when a chart library owns the canvas. A WebGL/WebGPU canvas without `preserveDrawingBuffer` reads back blank outside its own frame — capture during the draw instead.
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.55.2
4
+ version: 0.55.4
5
5
  ---
6
6
 
7
- > Generated from typebulb v0.55.2. `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.55.4. `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
 
@@ -237,7 +237,7 @@ One exception: if `TYPEBULB_MIRROR=1` is set in your environment, the user is pr
237
237
 
238
238
  - **First, can it even run inline?** A bulb needing `tb.ai`, `tb.infer`, `tb.fs`, or `server.ts` must be **local** — inline bulbs are client-only, so those calls fail there. The choice below is only for client-only bulbs.
239
239
  - **Is anyone watching?** An inline bulb only renders live when the agent mirror is open; with none it shows as raw text. `npx typebulb agent` starts the mirror if needed and prints its link — share it with the user; don't make the user start anything.
240
- - **Something to see right now, in the flow of the conversation** — a chart of some numbers, a quick simulation, an illustrative widget. → **inline**: emit it in a `bulb` block so it renders live in the conversation.
240
+ - **Something to see right now, in the flow of the conversation** — a chart of some numbers, a quick simulation, an illustrative widget. → **inline**: emit it in a `bulb` block, straight into the reply. Don't draft it as a `.bulb.md` and test it first: a broken one reports its own error back to you (below), and the user expects a snappy response with an inline bulb.
241
241
  - **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 inline block is throwaway and can't be edited in place, so it's the wrong fit for anything iterative.
242
242
 
243
243
  ### Emitting an inline bulb
@@ -287,7 +287,7 @@ That one launch *is* the loop: the server watches the file, so every save recomp
287
287
  - **Slow work settles in the handler** — a handler may be async, and the reply waits for its promise: keep a done-promise, `await` it, and return the finished state, with `--wait=<ms>` sized to the work (instead of polling flags in a sleep loop, or snapshot-polling from outside). The sharp edge: settle the promise on *every* exit of the run — success, failure, supersession, in a `finally` — and start idle with an already-resolved one, or the handler hangs and reads as a broken bulb. One case stays two-step: a `tb:*` gesture that kicks off slow work replies with the immediate frame (runtime-answered), so follow it with this settle probe.
288
288
  - **Rendered truth** — `typebulb send <file> tb:snapshot` prints the page's accessibility outline (roles, names, visible text) without disturbing its state. Use it when logs say ok but the screen might not, and as the first probe on a live page in a state you can't reproduce — a save would hot-reload and destroy it. (`tb:` messages are answered by the runtime, never your handlers, and imply `--wait`.) Its first line is the page's geometry — viewport, content size, and a fits-or-overflows verdict — so an unwanted scrollbar shows up in the first read.
289
289
  - **Measuring layout** — `typebulb send <file> 'tb:rect button "Pass"'` prints that control's viewport-relative rect as JSON (`{x, y, width, height, viewport}`, integers): how big something ended up, whether two things align, whether one is offscreen — arithmetic on rects, no probe handler. Only what the outline names is measurable; give a structural container a `role` **and** an `aria-label` (`<div role="group" aria-label="board">`) to measure it — a label alone leaves it invisible.
290
- - **Acting on the page** — `typebulb send <file> 'tb:click button "Pass"'` clicks the one control matching that role and name (exact, else a unique case-insensitive substring) and replies with a fresh snapshot; `tb:set combobox "strength" = hard` is the same for form controls (checkboxes and radios take `tb:click`). A disabled, readonly, or covered target is an error naming it — that silence is the bug class these verbs catch. Needs exactly one page open, and the reply is the immediate frame (slow work: follow up with `tb:snapshot`). Only what the outline names is targetable: real `<button>`s and labeled controls, not an `onClick` `<div>`.
290
+ - **Acting on the page** — `typebulb send <file> 'tb:click button "Pass"'` clicks the one control matching that role and name (exact, else a unique case-insensitive substring) and replies with a fresh snapshot; `tb:set combobox "strength" = hard` is the same for form controls (checkboxes and radios take `tb:click`). A disabled, readonly, or covered target is an error naming it — that silence is the bug class these verbs catch. The click is synthetic, so a handler needing user activation (a clipboard write, fullscreen) does nothing and reports nothing. Needs exactly one page open, and the reply is the immediate frame (slow work: follow up with `tb:snapshot`). Only what the outline names is targetable: real `<button>`s and labeled controls, not an `onClick` `<div>`.
291
291
  - **Poking state** — for state beyond what a form control expresses (`tb:set` covers those), author a set-handler up front: a `tb.onMessage` branch that takes a data payload (JSON arrives parsed), applies it to your state — committing the change if your framework needs an explicit step — and returns the new state: `typebulb send <file> '{"set":"speed","value":2}' --wait` prints it. In React, register it in an effect so it closes over the setters (the returned unsubscribe is the cleanup).
292
292
  - **A page must be open** — the CLI runs no browser of its own, so every client-side check waits on a real window (and `--no-open` means there isn't one). `send` says which case it is: nobody has ever connected (share the link), or a page dropped and hasn't returned (it's stale — reload it). Never open a window at the user: the server logs `[page] connected` when a page attaches, so end your turn with the link, arming `typebulb wait <file> --match "[page] connected"` in the background first — the user opening the page is your wake-up.
293
293
  - **Reading a canvas** — `typebulb send <file> tb:png` writes the page's canvas to a PNG (a stable per-bulb path under `~/.typebulb/`, overwritten each read) and prints the path — rendered truth for a bulb whose output is drawn, with no probe handler and nothing disturbed. One canvas needs no name; several take `tb:png "<name>"` — an `aria-label` on the canvas, or `role="img" aria-label="…"` on the container when a chart library owns the canvas. A WebGL/WebGPU canvas without `preserveDrawingBuffer` reads back blank outside its own frame — capture during the draw instead.