typebulb 0.44.0 → 0.44.2
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 +0 -2
- package/SKILL.md +2 -4
- package/dist/agents/claude/styles.css +17 -13
- package/dist/agents/pi/matchu-patchu.ts +1 -1
- package/dist/agents/pi/styles.css +17 -13
- package/dist/index.js +1 -1
- package/package.json +14 -1
package/README.md
CHANGED
|
@@ -221,8 +221,6 @@ Start it yourself with `npx typebulb agent` (it auto-detects your harness) — d
|
|
|
221
221
|
|
|
222
222
|
One exception: if `TYPEBULB_MIRROR=1` is set in your environment, the user is prompting you from the mirror itself — it's already open in front of them, so skip `npx typebulb agent` and don't end with its link; just emit bulbs.
|
|
223
223
|
|
|
224
|
-
If the user asks to keep this document on hand across sessions, copy its packaged skill form — `SKILL.md`, at the path `npx typebulb agent` prints — into your skills folder (e.g. for Claude Code, `.claude/skills/typebulb/SKILL.md`).
|
|
225
|
-
|
|
226
224
|
### When agents should output local vs embedded bulbs
|
|
227
225
|
|
|
228
226
|
- **First, can it even embed?** A bulb needing `tb.ai`, `tb.infer`, `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.
|
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 (embedded, 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/embed 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.44.
|
|
4
|
+
version: 0.44.2
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
> Generated from typebulb v0.44.
|
|
7
|
+
> Generated from typebulb v0.44.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.
|
|
8
8
|
|
|
9
9
|
# typebulb
|
|
10
10
|
|
|
@@ -229,8 +229,6 @@ Start it yourself with `npx typebulb agent` (it auto-detects your harness) — d
|
|
|
229
229
|
|
|
230
230
|
One exception: if `TYPEBULB_MIRROR=1` is set in your environment, the user is prompting you from the mirror itself — it's already open in front of them, so skip `npx typebulb agent` and don't end with its link; just emit bulbs.
|
|
231
231
|
|
|
232
|
-
If the user asks to keep this document on hand across sessions, copy its packaged skill form — `SKILL.md`, at the path `npx typebulb agent` prints — into your skills folder (e.g. for Claude Code, `.claude/skills/typebulb/SKILL.md`).
|
|
233
|
-
|
|
234
232
|
### When agents should output local vs embedded bulbs
|
|
235
233
|
|
|
236
234
|
- **First, can it even embed?** A bulb needing `tb.ai`, `tb.infer`, `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.
|
|
@@ -229,24 +229,25 @@ body {
|
|
|
229
229
|
border-radius: 10px;
|
|
230
230
|
box-shadow: 0 8px 30px rgba(0, 0, 0, .45);
|
|
231
231
|
}
|
|
232
|
-
/*
|
|
233
|
-
|
|
234
|
-
|
|
232
|
+
/* Owned scrollbars: no arrow buttons, transparent track, a floating thumb only when the surface
|
|
233
|
+
actually overflows. On the menu lists the channel is ALWAYS reserved (overflow-y: scroll on the
|
|
234
|
+
three lists); the diff doc joins them so its thumb track matches the overview ruler (.diff-ruler).
|
|
235
|
+
Native auto scrollbars made a row band's right inset depend on list length: a
|
|
235
236
|
project with no bulbs of its own (one collapsed fold row) ran its band 15px nearer the popover
|
|
236
237
|
edge than the filter box under it, and bare overflow:scroll parked a vestigial arrow-stub beside
|
|
237
238
|
the short list. Width stays 15px, the native width .model-head's alignment padding hardcodes.
|
|
238
239
|
Chromium pseudos on purpose: setting the standard scrollbar-color would disable them. */
|
|
239
|
-
:is(.picker-list, .bulb-list, .gitdiff-list)::-webkit-scrollbar { width: 15px; }
|
|
240
|
-
:is(.picker-list, .bulb-list, .gitdiff-list)::-webkit-scrollbar-button { display: none; }
|
|
241
|
-
:is(.picker-list, .bulb-list, .gitdiff-list)::-webkit-scrollbar-track { background: transparent; }
|
|
242
|
-
:is(.picker-list, .bulb-list, .gitdiff-list)::-webkit-scrollbar-thumb {
|
|
240
|
+
:is(.picker-list, .bulb-list, .gitdiff-list, .diff-doc-body)::-webkit-scrollbar { width: 15px; }
|
|
241
|
+
:is(.picker-list, .bulb-list, .gitdiff-list, .diff-doc-body)::-webkit-scrollbar-button { display: none; }
|
|
242
|
+
:is(.picker-list, .bulb-list, .gitdiff-list, .diff-doc-body)::-webkit-scrollbar-track { background: transparent; }
|
|
243
|
+
:is(.picker-list, .bulb-list, .gitdiff-list, .diff-doc-body)::-webkit-scrollbar-thumb {
|
|
243
244
|
background-color: color-mix(in srgb, var(--fg) 28%, transparent);
|
|
244
245
|
border-radius: 8px;
|
|
245
246
|
/* Transparent border + padding-box clip floats a slim pill in the 15px channel. */
|
|
246
247
|
border: 4px solid transparent;
|
|
247
248
|
background-clip: padding-box;
|
|
248
249
|
}
|
|
249
|
-
:is(.picker-list, .bulb-list, .gitdiff-list)::-webkit-scrollbar-thumb:hover { background-color: color-mix(in srgb, var(--fg) 45%, transparent); }
|
|
250
|
+
:is(.picker-list, .bulb-list, .gitdiff-list, .diff-doc-body)::-webkit-scrollbar-thumb:hover { background-color: color-mix(in srgb, var(--fg) 45%, transparent); }
|
|
250
251
|
/* Popover alignment — which edge of the pill the menu aligns to (floating-UI's start/center/end
|
|
251
252
|
vocabulary; "end", right edges flush and growing left, is the unnamed default above). Tagged on
|
|
252
253
|
the pill's WRAP, not each popover root: a menu with several drilled-in views (the model pill's
|
|
@@ -1099,12 +1100,15 @@ a.server-port:hover { text-decoration: underline; }
|
|
|
1099
1100
|
.diff-doc-body .udiff-add { background: color-mix(in srgb, var(--diff-add) 15%, transparent); }
|
|
1100
1101
|
.diff-doc-body .udiff-del { background: color-mix(in srgb, var(--err) 18%, transparent); }
|
|
1101
1102
|
/* The overview ruler — VS Code's scrollbar change-marks, owned since the native scrollbar can't be
|
|
1102
|
-
painted: a thin track beside the scrollbar (
|
|
1103
|
-
|
|
1104
|
-
position, min-height so a one-line change stays visible.
|
|
1105
|
-
|
|
1103
|
+
painted: a thin track beside the scrollbar (15px = the owned channel's width — plain px on a
|
|
1104
|
+
desktop-only surface, the menus' own stance), red/green marks at each change run's fractional
|
|
1105
|
+
position, min-height so a one-line change stays visible. It spans the pane edge to edge, which is
|
|
1106
|
+
the thumb's track exactly once the arrow buttons are gone — that's why the doc's bar is owned.
|
|
1107
|
+
What drift is left on a tall doc is Chromium clamping the thumb to a minimum height, shortening
|
|
1108
|
+
its travel; a static ruler can't follow that. The wrapper keeps it overlaid rather than scrolling
|
|
1109
|
+
with the body. Marks are pointer-inert so a click anywhere on the track jumps. */
|
|
1106
1110
|
.diff-doc-scroll { position: relative; flex: 1; min-height: 0; display: flex; flex-direction: column; }
|
|
1107
|
-
.diff-ruler { position: absolute;
|
|
1111
|
+
.diff-ruler { position: absolute; inset-block: 0; right: 15px; width: 6px; cursor: pointer; z-index: 5; }
|
|
1108
1112
|
.diff-ruler-mark { position: absolute; left: 0; right: 0; min-height: 3px; border-radius: 1px; pointer-events: none; }
|
|
1109
1113
|
.diff-ruler-mark.add { background: var(--diff-add); opacity: .8; }
|
|
1110
1114
|
.diff-ruler-mark.del { background: var(--err); opacity: .8; }
|
|
@@ -2440,7 +2440,7 @@ var Patcher = class {
|
|
|
2440
2440
|
|
|
2441
2441
|
// cli/agents/pi/server/piPatcherExtension.ts
|
|
2442
2442
|
var DESCRIPTION = true ? "Apply unified diffs to files \u2014 tolerant of form, strict about intent. Repairs sloppy AI-generated diffs (mangled headers, whitespace drift, missing prefixes; line numbers can be wrong or absent \u2014 hunks anchor by fuzzy-matched context lines) and applies all hunks atomically when the intent is unambiguous; fails with a precise, typed error when it isn't. Use for multi-hunk edits in one step, or when exact string-replacement editing fails on whitespace or invisible characters." : "Apply unified diffs to files.";
|
|
2443
|
-
var BUILD_TAG = true ? "matchu-patchu-pi 0.3.5, built 2026-07-30
|
|
2443
|
+
var BUILD_TAG = true ? "matchu-patchu-pi 0.3.5, built 2026-07-30 15:13:29" : "matchu-patchu-pi dev";
|
|
2444
2444
|
var errorBlocks = (errors) => {
|
|
2445
2445
|
const parts = [`Patch failed with ${errors.length} error(s):`];
|
|
2446
2446
|
for (const e of errors) parts.push("", e.toString());
|
|
@@ -229,24 +229,25 @@ body {
|
|
|
229
229
|
border-radius: 10px;
|
|
230
230
|
box-shadow: 0 8px 30px rgba(0, 0, 0, .45);
|
|
231
231
|
}
|
|
232
|
-
/*
|
|
233
|
-
|
|
234
|
-
|
|
232
|
+
/* Owned scrollbars: no arrow buttons, transparent track, a floating thumb only when the surface
|
|
233
|
+
actually overflows. On the menu lists the channel is ALWAYS reserved (overflow-y: scroll on the
|
|
234
|
+
three lists); the diff doc joins them so its thumb track matches the overview ruler (.diff-ruler).
|
|
235
|
+
Native auto scrollbars made a row band's right inset depend on list length: a
|
|
235
236
|
project with no bulbs of its own (one collapsed fold row) ran its band 15px nearer the popover
|
|
236
237
|
edge than the filter box under it, and bare overflow:scroll parked a vestigial arrow-stub beside
|
|
237
238
|
the short list. Width stays 15px, the native width .model-head's alignment padding hardcodes.
|
|
238
239
|
Chromium pseudos on purpose: setting the standard scrollbar-color would disable them. */
|
|
239
|
-
:is(.picker-list, .bulb-list, .gitdiff-list)::-webkit-scrollbar { width: 15px; }
|
|
240
|
-
:is(.picker-list, .bulb-list, .gitdiff-list)::-webkit-scrollbar-button { display: none; }
|
|
241
|
-
:is(.picker-list, .bulb-list, .gitdiff-list)::-webkit-scrollbar-track { background: transparent; }
|
|
242
|
-
:is(.picker-list, .bulb-list, .gitdiff-list)::-webkit-scrollbar-thumb {
|
|
240
|
+
:is(.picker-list, .bulb-list, .gitdiff-list, .diff-doc-body)::-webkit-scrollbar { width: 15px; }
|
|
241
|
+
:is(.picker-list, .bulb-list, .gitdiff-list, .diff-doc-body)::-webkit-scrollbar-button { display: none; }
|
|
242
|
+
:is(.picker-list, .bulb-list, .gitdiff-list, .diff-doc-body)::-webkit-scrollbar-track { background: transparent; }
|
|
243
|
+
:is(.picker-list, .bulb-list, .gitdiff-list, .diff-doc-body)::-webkit-scrollbar-thumb {
|
|
243
244
|
background-color: color-mix(in srgb, var(--fg) 28%, transparent);
|
|
244
245
|
border-radius: 8px;
|
|
245
246
|
/* Transparent border + padding-box clip floats a slim pill in the 15px channel. */
|
|
246
247
|
border: 4px solid transparent;
|
|
247
248
|
background-clip: padding-box;
|
|
248
249
|
}
|
|
249
|
-
:is(.picker-list, .bulb-list, .gitdiff-list)::-webkit-scrollbar-thumb:hover { background-color: color-mix(in srgb, var(--fg) 45%, transparent); }
|
|
250
|
+
:is(.picker-list, .bulb-list, .gitdiff-list, .diff-doc-body)::-webkit-scrollbar-thumb:hover { background-color: color-mix(in srgb, var(--fg) 45%, transparent); }
|
|
250
251
|
/* Popover alignment — which edge of the pill the menu aligns to (floating-UI's start/center/end
|
|
251
252
|
vocabulary; "end", right edges flush and growing left, is the unnamed default above). Tagged on
|
|
252
253
|
the pill's WRAP, not each popover root: a menu with several drilled-in views (the model pill's
|
|
@@ -1099,12 +1100,15 @@ a.server-port:hover { text-decoration: underline; }
|
|
|
1099
1100
|
.diff-doc-body .udiff-add { background: color-mix(in srgb, var(--diff-add) 15%, transparent); }
|
|
1100
1101
|
.diff-doc-body .udiff-del { background: color-mix(in srgb, var(--err) 18%, transparent); }
|
|
1101
1102
|
/* The overview ruler — VS Code's scrollbar change-marks, owned since the native scrollbar can't be
|
|
1102
|
-
painted: a thin track beside the scrollbar (
|
|
1103
|
-
|
|
1104
|
-
position, min-height so a one-line change stays visible.
|
|
1105
|
-
|
|
1103
|
+
painted: a thin track beside the scrollbar (15px = the owned channel's width — plain px on a
|
|
1104
|
+
desktop-only surface, the menus' own stance), red/green marks at each change run's fractional
|
|
1105
|
+
position, min-height so a one-line change stays visible. It spans the pane edge to edge, which is
|
|
1106
|
+
the thumb's track exactly once the arrow buttons are gone — that's why the doc's bar is owned.
|
|
1107
|
+
What drift is left on a tall doc is Chromium clamping the thumb to a minimum height, shortening
|
|
1108
|
+
its travel; a static ruler can't follow that. The wrapper keeps it overlaid rather than scrolling
|
|
1109
|
+
with the body. Marks are pointer-inert so a click anywhere on the track jumps. */
|
|
1106
1110
|
.diff-doc-scroll { position: relative; flex: 1; min-height: 0; display: flex; flex-direction: column; }
|
|
1107
|
-
.diff-ruler { position: absolute;
|
|
1111
|
+
.diff-ruler { position: absolute; inset-block: 0; right: 15px; width: 6px; cursor: pointer; z-index: 5; }
|
|
1108
1112
|
.diff-ruler-mark { position: absolute; left: 0; right: 0; min-height: 3px; border-radius: 1px; pointer-events: none; }
|
|
1109
1113
|
.diff-ruler-mark.add { background: var(--diff-add); opacity: .8; }
|
|
1110
1114
|
.diff-ruler-mark.del { background: var(--err); opacity: .8; }
|
package/dist/index.js
CHANGED
|
@@ -2171,5 +2171,5 @@ ${AC}
|
|
|
2171
2171
|
`);let c=0,l=Promise.resolve();Nt({target:r,onChange:()=>{let d=++c;l=l.then(async()=>{if(d===c)try{console.log("Re-running..."),await a()}catch(u){console.error("Error:",u)}})}})}}Ot();Ke();import{Console as RC}from"node:console";Ie();async function rw(r,e,t,n,s){LC();try{let p=kr(await Q(),r)[0];p&&(Ni(p.pid,Je(p.pid).offset),console.error(`note: 'call' boots a fresh server.ts instance; the running server (${p.url}) is not contacted \u2014 state shared with it must live on disk.`))}catch{}let i=Ae(t),{bulb:o,config:a}=await De(r);o.server||ws("This bulb has no **server.ts** block; nothing to call."),Tt(i,r,o.server),s&&await Mr(r,s);let c;try{c=await es(o.server,r,n,a.dependencies,s)}catch(p){ws(p instanceof Error?p.message:String(p))}let l=ca(c,e.fn);if(!l){let p=[...Object.keys(c).filter(h=>typeof c[h]=="function"),...Object.keys(aa)];ws(`Function '${e.fn}' not found. Available: ${p.length?p.join(", "):"(none)"}.`)}let d=await _C(e);if(la(l)){try{for await(let p of l(...d))await tw(JSON.stringify(p,nw)+`
|
|
2172
2172
|
`)}catch(p){ws(p instanceof Error?p.stack??p.message:String(p))}return ew(0)}let u;try{u=await l(...d)}catch(p){ws(p instanceof Error?p.stack??p.message:String(p))}let f=$C(u);f!==void 0&&await tw(f+`
|
|
2173
2173
|
`),ew(0)}function ew(r){process.exitCode=r,setTimeout(()=>process.exit(r),2e3).unref?.()}async function _C(r){if(r.hasArgsFlag){let e=r.argsJson??"";return e==="-"&&(e=await MC()),IC(e)}return NC(r.positional)}function NC(r){return r.map(e=>{try{return JSON.parse(e)}catch{return e}})}function IC(r){let e;try{e=JSON.parse(r)}catch(t){throw new Error(`--args must be a JSON array: ${t instanceof Error?t.message:String(t)}`)}if(!Array.isArray(e))throw new Error(`--args must be a JSON array, got ${e===null?"null":typeof e}`);return e}function $C(r){if(r!==void 0)return JSON.stringify(r,nw,2)}function nw(r,e){return typeof e=="bigint"?e.toString():e}function ws(r){process.stderr.write(r+`
|
|
2174
|
-
`),process.exit(1)}function LC(){let r=new RC(process.stderr,process.stderr);console.log=r.log.bind(r),console.info=r.info.bind(r),console.debug=r.debug.bind(r),console.dir=r.dir.bind(r)}function tw(r){return new Promise((e,t)=>{process.stdout.write(r,n=>n?t(n):e())})}async function MC(){let r=[];for await(let e of process.stdin)r.push(e);return Buffer.concat(r).toString("utf-8")}var sw="0.44.
|
|
2174
|
+
`),process.exit(1)}function LC(){let r=new RC(process.stderr,process.stderr);console.log=r.log.bind(r),console.info=r.info.bind(r),console.debug=r.debug.bind(r),console.dir=r.dir.bind(r)}function tw(r){return new Promise((e,t)=>{process.stdout.write(r,n=>n?t(n):e())})}async function MC(){let r=[];for await(let e of process.stdin)r.push(e);return Buffer.concat(r).toString("utf-8")}var sw="0.44.2";for(let r of[process.stdout,process.stderr])r.on("error",e=>{if(e?.code!=="EPIPE")throw e});function iw(r,e){r||(console.error(`This bulb runs server-side Node code (server.ts), which --trust must authorize:
|
|
2175
2175
|
${e}`),process.exit(1))}async function BC(){let r=Zy(process.argv.slice(2));if(r.version&&(console.log(`typebulb ${sw}`),process.exit(0)),r.help&&(eb(),process.exit(0)),Xy(),r.subcommand==="logs"){await Pb(r.file||void 0,{follow:r.follow,clear:r.clear,run:r.run,lines:r.lines});return}if(r.subcommand==="wait"){await Cb(r.file||void 0,{match:r.match,timeoutSec:r.timeoutSec});return}if(r.subcommand==="stop"){r.stopScope?await _b(r.stopScope):await Rb(r.file||void 0);return}if(r.subcommand==="send"){await $b(r.file,r.sendMessage,r.sendWaitMs??0);return}if(r.subcommand==="models"){await Eb(r.mode);return}if(r.subcommand==="slug"){Ab(r.slugName);return}if(r.subcommand==="pull"){await kg(r.file||void 0,{force:r.force,mode:r.mode});return}if(r.subcommand==="push"){await Eg(r.file||void 0,{force:r.force,mode:r.mode});return}if(r.subcommand==="agent"){await(r.agentTarget?Xb(r):xb(sw));return}if(r.subcommand==="trust"||r.subcommand==="untrust"){await vb(r.file||void 0,r.subcommand==="trust");return}let e;if(!r.file||r.file==="."){let c=await eg(process.cwd());c||(console.error("No .bulb.md file found in current directory"),process.exit(1)),e=c}else e=ir.resolve(r.file);if(await ow.access(e).then(()=>!0,()=>!1)||(Vr().includes(r.file)&&(console.error(`To open the ${r.file} agent mirror, run: npx typebulb agent:${r.file}`),process.exit(1)),console.error(`File not found: ${e}`),process.exit(1)),e.endsWith(".bulb.md")||(console.error("File must have .bulb.md extension"),process.exit(1)),r.subcommand==="get"){await Mb(e,r.blockKind);return}if(r.subcommand==="put"){await jb(e,r.blockPairs);return}let n=r.file&&r.file!=="."?r.file:ir.relative(process.cwd(),e)||ir.basename(e),s=`npx typebulb --trust ${n.includes(" ")?`"${n}"`:n}`;if(r.subcommand==="predict"){await wb(e,s);return}let i=!r.noTrust&&Qt(e);i&&!r.trust&&console.error("trust: granted from memory (run `typebulb untrust` to revoke)"),r.trust=r.noTrust?!1:r.trust||i;let o;try{o=await De(e)}catch{}let a;if(r.local){o&&!(r.local.name in(o.config.dependencies??{}))&&(console.error(`--replace: '${r.local.name}' is not a dependency in this bulb's config.json; nothing to replace.`),process.exit(1)),o&&r.subcommand!=="call"&&(!o.bulb.code||r.server)&&console.warn("warning: --replace has no effect in server mode (the override is client-only).");try{a=await bd(r.local)}catch(c){console.error(c instanceof Error?c.message:String(c)),process.exit(1)}console.error(`replace: ${a.name} \u2192 ${ir.relative(process.cwd(),a.dir)||"."}`)}if(r.subcommand==="check"){await bb(e,a);return}if(r.subcommand==="call"){iw(r.trust,s),await rw(e,{fn:r.fn,positional:r.callArgs,argsJson:r.argsJson,hasArgsFlag:r.hasArgsFlag},r.mode,a,r.batch);return}if(o&&o.bulb.server&&(Li(o.bulb)||r.server)){iw(r.trust,s),await Zb(e,r.watch,r.mode,a,r.batch);return}await Yb(e,r,s,a)}BC().catch(r=>{console.error("Error:",r.message),process.exit(1)});
|
package/package.json
CHANGED
|
@@ -1,7 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "typebulb",
|
|
3
|
-
"version": "0.44.
|
|
3
|
+
"version": "0.44.2",
|
|
4
4
|
"description": "Typebulb CLI to run single-file markdown apps called bulbs, either as standalone web apps or embedded in agent responses.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"bulb",
|
|
7
|
+
"bulbs",
|
|
8
|
+
"markdown",
|
|
9
|
+
"single-file",
|
|
10
|
+
"tsx",
|
|
11
|
+
"cli",
|
|
12
|
+
"agent",
|
|
13
|
+
"coding-agent",
|
|
14
|
+
"agent-skill",
|
|
15
|
+
"claude-code",
|
|
16
|
+
"llm"
|
|
17
|
+
],
|
|
5
18
|
"license": "MIT",
|
|
6
19
|
"repository": {
|
|
7
20
|
"type": "git",
|