typebulb 0.55.4 → 0.55.5

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
@@ -486,7 +486,7 @@ The user can proxy claude with the agent mirror's model switcher, to any model o
486
486
 
487
487
  ## Push & Pull (typebulb.com)
488
488
 
489
- One bulb per command, between typebulb.com and its conventional local file — the path IS the remote identity: `typebulbs/u/ben/birds.bulb.md` ↔ `typebulb.com/u/ben/birds`.
489
+ One bulb per command, between typebulb.com and its conventional local file — the path IS the remote identity: `typebulbs/u/ben/birds.bulb.md` ↔ `typebulb.com/u/ben/birds`. That bare URL opens the bulb in IDE mode; `typebulb.com/u/ben/birds/full` opens it in published mode — the canonical page, and the link to share.
490
490
 
491
491
  - **Pull**: `typebulb pull <bulb-url>` (or an existing local file, to refresh in place) — brings the bulb's `assets/` folder along. Unlisted and public bulbs need no login. A local file or asset with real changes is refused; `--force` overwrites it.
492
492
  - **Push**: `typebulb push <file>` uploads as you — set `TYPEBULB_TOKEN` in `.env` (minted on your typebulb.com settings page). A slug that doesn't exist yet is created, unlisted. If the site copy changed since your last pull/push, the push is refused; `--force` overwrites it. A `**server.ts**` block is stripped from the site copy (CLI-only); your local file is never modified.
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.4
4
+ version: 0.55.5
5
5
  ---
6
6
 
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.
7
+ > Generated from typebulb v0.55.5. `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
 
@@ -494,7 +494,7 @@ The user can proxy claude with the agent mirror's model switcher, to any model o
494
494
 
495
495
  ## Push & Pull (typebulb.com)
496
496
 
497
- One bulb per command, between typebulb.com and its conventional local file — the path IS the remote identity: `typebulbs/u/ben/birds.bulb.md` ↔ `typebulb.com/u/ben/birds`.
497
+ One bulb per command, between typebulb.com and its conventional local file — the path IS the remote identity: `typebulbs/u/ben/birds.bulb.md` ↔ `typebulb.com/u/ben/birds`. That bare URL opens the bulb in IDE mode; `typebulb.com/u/ben/birds/full` opens it in published mode — the canonical page, and the link to share.
498
498
 
499
499
  - **Pull**: `typebulb pull <bulb-url>` (or an existing local file, to refresh in place) — brings the bulb's `assets/` folder along. Unlisted and public bulbs need no login. A local file or asset with real changes is refused; `--force` overwrites it.
500
500
  - **Push**: `typebulb push <file>` uploads as you — set `TYPEBULB_TOKEN` in `.env` (minted on your typebulb.com settings page). A slug that doesn't exist yet is created, unlisted. If the site copy changed since your last pull/push, the push is refused; `--force` overwrites it. A `**server.ts**` block is stripped from the site copy (CLI-only); your local file is never modified.
package/dist/index.js CHANGED
@@ -248,7 +248,7 @@ ${t.comment}`:t.comment}this.doc.range[2]=t.offset;break}default:this.errors.pus
248
248
  `),c=i.filter(u=>u.type==="tool_use").map(u=>({id:u.id??"",name:u.name??"",input:u.input??{}}));if(o||a||c.length){let u=Date.parse(e.timestamp??""),d=!isNaN(u)&&u>=t;r.push({type:"assistant",text:o,thinking:a,tools:c,live:d})}let l=e.message?.usage??e.usage,f=l&&{in:l.input_tokens??0,out:l.output_tokens??0,cached:l.cache_read_input_tokens??0,cacheCreate:l.cache_creation_input_tokens??0};return{events:r,usage:f,model:e.message?.model}}return{events:r}}chainWorking(e){let t;for(let o of e)(o.type==="user"||o.type==="assistant")&&(t=o);if(!t)return!1;if(t.type==="user"){try{let o=t.message?.content,a=typeof o=="string"?o:Array.isArray(o)?o.filter(l=>l&&l.type==="text").map(l=>l.text??"").join(""):"";if(!(Array.isArray(o)&&o.some(l=>l&&l.type==="tool_result"))&&a.trim()&&xt(a)==="")return!1}catch{}return!0}let s=(Array.isArray(t.message?.content)?t.message.content:[]).filter(o=>o.type==="tool_use").map(o=>o.id);if(s.length===0)return!1;let i=new Set;for(let o of e){let a=o.message?.content;if(Array.isArray(a))for(let c of a)c.type==="tool_result"&&c.tool_use_id&&i.add(c.tool_use_id)}return s.some(o=>o&&!i.has(o))}sessionAlive(e){return zE(e)}readPreview(e){return VE(e)}searchText(e){if(!e||Hr(e)||e.type!=="user"&&e.type!=="assistant")return"";let t=e.message?.content,r="";if(typeof t=="string")r=xt(t);else if(Array.isArray(t)){let s=t;r=e.type==="user"?s.map(Ll).filter(Boolean).join(" "):s.filter(i=>i.type==="text"&&typeof i.text=="string").map(i=>i.text).join(" ")}return r.replace(/\s+/g," ").trim()}}});import{statSync as GE,readdirSync as XE,openSync as QE,readSync as ZE,closeSync as eA,existsSync as tA}from"fs";import{basename as nA,join as Dl,resolve as rA}from"path";import{homedir as qm}from"os";function iA(n){let e=n.trimStart();return sA.some(t=>e.startsWith(t))}function Vr(n,e){return Array.isArray(n)?n.map(t=>typeof t?.text=="string"?e&&iA(t.text)?"":be(t.text):t?.type==="input_image"&&typeof t.image_url=="string"&&t.image_url.startsWith("data:")?`![image](${t.image_url})`:"").filter(Boolean).join(`
249
249
  `):""}function oA(n){return typeof n=="string"?be(n):Vr(n,!1)}function aA(n){let e=n??"";for(let t of[/tools\.shell_command\((\{[\s\S]*?\})\)/,/tools\.shell_command\((\{[\s\S]*\})\)/]){let r=t.exec(e);if(r)try{return JSON.parse(r[1])}catch{}}return{script:e}}function cA(n){if(typeof n=="string"&&n)try{let e=JSON.parse(n);if(e&&typeof e=="object"&&!Array.isArray(e))return e}catch{}return{arguments:n??""}}function Km(n,e){let t;try{t=QE(n,"r")}catch{return}try{let r=Buffer.alloc(e),s=ZE(t,r,0,e,0);return{text:r.subarray(0,s).toString("utf8"),bytes:s}}finally{eA(t)}}function lA(n){let t=Km(n,65536);if(t===void 0)return;let r=t.text.indexOf(`
250
250
  `);if(r<0)return t.bytes>=65536?"":void 0;try{let s=JSON.parse(t.text.slice(0,r));return s?.type==="session_meta"&&typeof s.payload?.cwd=="string"?s.payload.cwd:""}catch{return""}}var sA,Jm,_n,jl=v(()=>{"use strict";Wr();Wi();sA=["<permissions instructions>","<apps_instructions>","<plugins_instructions>","<skills_instructions>","<recommended_plugins>","<environment_context>","<user_instructions>"];Jm=n=>{let e=rA(n);return process.platform==="win32"?e.toLowerCase():e},_n=class extends kt{constructor(t=Dl(qm(),".codex","sessions")){super();this.root=t}displayName="Codex Mirror";#e=0;#s;#t=new Map;detectsSelf(){return!!process.env.CODEX_THREAD_ID}detectsInstalled(){return tA(Dl(qm(),".codex"))}sessionsDir(t){return this.root}listSessionFiles(t){let r=Jm(t),s=[];for(let i of this.#r()){let o;try{let c=GE(i);if(!c.isFile())continue;o=c.mtimeMs}catch{continue}let a=this.#t.get(i);if(a===void 0){if(a=lA(i),a===void 0)continue;this.#t.set(i,a)}Jm(a)===r&&s.push({sessionId:nA(i,".jsonl"),file:i,mtime:o})}return s}#r(){let t=[],r=s=>{try{return XE(s).map(i=>Dl(s,i))}catch{return[]}};for(let s of r(this.root))for(let i of r(s))for(let o of r(i))for(let a of r(o))a.endsWith(".jsonl")&&t.push(a);return t}parseEntry(t){let r;try{r=JSON.parse(t)}catch{return null}return!r||typeof r.type!="string"?null:r}idOf(t){return t.ord===void 0&&(t.ord=String(this.#e++),t.parent=this.#s,this.#s=t.ord),t.ord}parentOf(t){return t.parent}timestampOf(t){return t.timestamp}isSidechain(t){return!1}isLeafType(t){return!0}isRecoveryNoise(t){return!1}apply(t,r){let s=[],i=t.payload;if(!i)return{events:s};let o=()=>{let a=Date.parse(t.timestamp??"");return!isNaN(a)&&a>=r};if(t.type==="response_item"){if(i.type==="message"){if(i.role==="user"){let a=Vr(i.content,!0).trim();a&&s.push({type:"user",text:a})}else if(i.role==="assistant"){let a=Vr(i.content,!1);a&&s.push({type:"assistant",text:a,thinking:"",tools:[],live:o()})}return{events:s}}if(i.type==="reasoning"){let a=Vr(i.summary,!1);return a&&s.push({type:"assistant",text:"",thinking:a,tools:[],live:o()}),{events:s}}if(i.type==="custom_tool_call"||i.type==="function_call"){let a=i.type==="custom_tool_call"?aA(i.input):cA(i.arguments);return s.push({type:"assistant",text:"",thinking:"",tools:[{id:i.call_id??"",name:i.name??"",input:a}],live:o()}),{events:s}}if(i.type==="custom_tool_call_output"||i.type==="function_call_output"){let a=oA(i.output);return s.push({type:"tool_result",id:i.call_id??"",content:a,isError:!1,digest:Le(a)}),{events:s}}return{events:s}}if(t.type==="event_msg"){if(i.type==="token_count"){let a=i.info?.last_token_usage;if(!a)return{events:s};let c={in:Math.max(0,(a.input_tokens??0)-(a.cached_input_tokens??0)),out:a.output_tokens??0,cached:a.cached_input_tokens??0,cacheCreate:a.cache_write_input_tokens??0};return{events:s,usage:c}}return{events:s}}return t.type==="turn_context"?{events:s,model:i.model}:{events:s}}chainWorking(t){let r=!1;for(let s of t){if(s.type!=="event_msg")continue;let i=s.payload?.type;i==="task_started"?r=!0:(i==="task_complete"||i==="turn_aborted")&&(r=!1)}return r}sessionAlive(){}readPreview(t){for(let r of(Km(t,256*1024)?.text??"").split(`
251
- `))if(r.includes('"user_message"'))try{let s=JSON.parse(r);if(s?.type==="event_msg"&&s.payload?.type==="user_message"&&typeof s.payload.message=="string"){let i=s.payload.message.replace(/\s+/g," ").trim();if(i)return i.slice(0,200)}}catch{}return""}searchText(t){if(t?.type!=="response_item"||t.payload?.type!=="message")return"";let r=t.payload.role;return r!=="user"&&r!=="assistant"?"":Vr(t.payload.content,r==="user").replace(/\s+/g," ").trim()}}});import{realpathSync as uA}from"fs";import{createHash as dA}from"crypto";import{join as Vi,resolve as fA}from"path";import{homedir as pA}from"os";function Et(){let n=process.env.TYPEBULB_SERVERS_DIR;return n?Vi(n,".."):Vi(pA(),".typebulb")}function et(){Wm||(Wm=!0,console.error(`${Et()} not writable \u2014 continuing stateless: ports won't stick, caches stay cold, and typebulb logs/wait/send/stop may not see this run`))}function tt(){return process.env.TYPEBULB_SERVERS_DIR||Vi(Et(),"servers")}function Hm(n){let e=X(n),t=dA("sha1").update(e).digest("hex").slice(0,8),r=e.slice(e.lastIndexOf("/")+1).replace(/\.bulb\.md$/,"");return Vi(Et(),"canvas",`${r}-${t}.png`)}function X(n){let e=fA(n),t=e;try{t=uA.native(e)}catch{}return(process.platform==="win32"?t.toLowerCase():t).replace(/\\/g,"/")}function Ym(n,e){let t=X(n),r=X(e);return t.startsWith(r.endsWith("/")?r:r+"/")?!t.includes("/node_modules/"):!1}var Wm,At=v(()=>{"use strict";Wm=!1});var Be,zi=v(()=>{"use strict";Be="0.55.4"});import{spawn as Vm}from"child_process";import{readdir as hA,readFile as Gm,writeFile as Xm,unlink as Fl,mkdir as mA}from"fs/promises";import{mkdirSync as Qm,writeFileSync as Gi,appendFileSync as gA,readFileSync as Ul}from"fs";import*as xe from"path";import{fileURLToPath as yA}from"url";function ql(n){return xe.join(tt(),`${n}.json`)}function Gr(n){return xe.join(tt(),`${n}.log`)}function Jl(n){return xe.join(tt(),`${n}.wait.json`)}function Zm(n){try{let e=JSON.parse(Ul(Jl(n),"utf8"));return e.cursors&&typeof e.cursors=="object"?e.cursors:{}}catch{return{}}}function Kl(n,e=""){let t=Zm(n)[e];return typeof t=="number"&&Number.isFinite(t)&&t>=0?t:void 0}function Xi(n,e,t=""){try{Qm(tt(),{recursive:!0});let r=Zm(n);r[t]=e,Gi(Jl(n),JSON.stringify({cursors:r}))}catch{}}function Qi(n){let e=Gr(n);try{Qm(tt(),{recursive:!0}),Gi(e,"")}catch{return()=>{}}let t=process.stdout.write.bind(process.stdout),r=process.stderr.write.bind(process.stderr),s=0,i=!1,o=a=>{if(!i)try{let c=typeof a=="string"?Buffer.from(a,"utf8"):Buffer.from(a);if(gA(e,c),s+=c.length,s>2*zm){let l=Ul(e),f=l.subarray(Math.max(0,l.length-zm));Gi(e,f),s=f.length}}catch{i=!0}};return process.stdout.write=((a,...c)=>(o(a),t(a,...c))),process.stderr.write=((a,...c)=>(o(a),r(a,...c))),()=>{process.stdout.write=t,process.stderr.write=r}}function eg(n){try{Gi(Gr(n),"")}catch{}}function He(n,e=0){try{let t=Ul(Gr(n)),r=e>=0&&e<=t.length?e:0;return{text:t.subarray(r).toString("utf8"),offset:t.length}}catch{return{text:"",offset:0}}}function Wl(n){return`\u2500\u2500 run ${n} \u2500\u2500 ${new Date().toTimeString().slice(0,8)}`}function wA(n){let e=bA.exec(n);return e?Number(e[1]):void 0}function tg(n,e){let t=n.split(`
251
+ `))if(r.includes('"user_message"'))try{let s=JSON.parse(r);if(s?.type==="event_msg"&&s.payload?.type==="user_message"&&typeof s.payload.message=="string"){let i=s.payload.message.replace(/\s+/g," ").trim();if(i)return i.slice(0,200)}}catch{}return""}searchText(t){if(t?.type!=="response_item"||t.payload?.type!=="message")return"";let r=t.payload.role;return r!=="user"&&r!=="assistant"?"":Vr(t.payload.content,r==="user").replace(/\s+/g," ").trim()}}});import{realpathSync as uA}from"fs";import{createHash as dA}from"crypto";import{join as Vi,resolve as fA}from"path";import{homedir as pA}from"os";function Et(){let n=process.env.TYPEBULB_SERVERS_DIR;return n?Vi(n,".."):Vi(pA(),".typebulb")}function et(){Wm||(Wm=!0,console.error(`${Et()} not writable \u2014 continuing stateless: ports won't stick, caches stay cold, and typebulb logs/wait/send/stop may not see this run`))}function tt(){return process.env.TYPEBULB_SERVERS_DIR||Vi(Et(),"servers")}function Hm(n){let e=X(n),t=dA("sha1").update(e).digest("hex").slice(0,8),r=e.slice(e.lastIndexOf("/")+1).replace(/\.bulb\.md$/,"");return Vi(Et(),"canvas",`${r}-${t}.png`)}function X(n){let e=fA(n),t=e;try{t=uA.native(e)}catch{}return(process.platform==="win32"?t.toLowerCase():t).replace(/\\/g,"/")}function Ym(n,e){let t=X(n),r=X(e);return t.startsWith(r.endsWith("/")?r:r+"/")?!t.includes("/node_modules/"):!1}var Wm,At=v(()=>{"use strict";Wm=!1});var Be,zi=v(()=>{"use strict";Be="0.55.5"});import{spawn as Vm}from"child_process";import{readdir as hA,readFile as Gm,writeFile as Xm,unlink as Fl,mkdir as mA}from"fs/promises";import{mkdirSync as Qm,writeFileSync as Gi,appendFileSync as gA,readFileSync as Ul}from"fs";import*as xe from"path";import{fileURLToPath as yA}from"url";function ql(n){return xe.join(tt(),`${n}.json`)}function Gr(n){return xe.join(tt(),`${n}.log`)}function Jl(n){return xe.join(tt(),`${n}.wait.json`)}function Zm(n){try{let e=JSON.parse(Ul(Jl(n),"utf8"));return e.cursors&&typeof e.cursors=="object"?e.cursors:{}}catch{return{}}}function Kl(n,e=""){let t=Zm(n)[e];return typeof t=="number"&&Number.isFinite(t)&&t>=0?t:void 0}function Xi(n,e,t=""){try{Qm(tt(),{recursive:!0});let r=Zm(n);r[t]=e,Gi(Jl(n),JSON.stringify({cursors:r}))}catch{}}function Qi(n){let e=Gr(n);try{Qm(tt(),{recursive:!0}),Gi(e,"")}catch{return()=>{}}let t=process.stdout.write.bind(process.stdout),r=process.stderr.write.bind(process.stderr),s=0,i=!1,o=a=>{if(!i)try{let c=typeof a=="string"?Buffer.from(a,"utf8"):Buffer.from(a);if(gA(e,c),s+=c.length,s>2*zm){let l=Ul(e),f=l.subarray(Math.max(0,l.length-zm));Gi(e,f),s=f.length}}catch{i=!0}};return process.stdout.write=((a,...c)=>(o(a),t(a,...c))),process.stderr.write=((a,...c)=>(o(a),r(a,...c))),()=>{process.stdout.write=t,process.stderr.write=r}}function eg(n){try{Gi(Gr(n),"")}catch{}}function He(n,e=0){try{let t=Ul(Gr(n)),r=e>=0&&e<=t.length?e:0;return{text:t.subarray(r).toString("utf8"),offset:t.length}}catch{return{text:"",offset:0}}}function Wl(n){return`\u2500\u2500 run ${n} \u2500\u2500 ${new Date().toTimeString().slice(0,8)}`}function wA(n){let e=bA.exec(n);return e?Number(e[1]):void 0}function tg(n,e){let t=n.split(`
252
252
  `),r=[];if(t.forEach((o,a)=>{let c=wA(o);c!==void 0&&r.push({id:c,idx:a})}),!r.length)return e==="latest"?n:"";let s=e==="latest"?r[r.length-1]:r.find(o=>o.id===e);if(!s)return"";let i=r.find(o=>o.idx>s.idx);return t.slice(s.idx,i?i.idx:t.length).join(`
253
253
  `)}function Hl(n){try{return process.kill(n,0),!0}catch(e){return e.code==="EPERM"}}async function ng(n){try{await mA(tt(),{recursive:!0}),await Xm(ql(n.pid),JSON.stringify({version:Be,...n}))}catch{et()}}async function rg(n,e){let t=ql(n);try{let r=JSON.parse(await Gm(t,"utf8"));if(r.denied===e)return;r.denied=e,await Xm(t,JSON.stringify(r))}catch{}}async function zr(n){await Fl(ql(n)).catch(()=>{}),await Fl(Gr(n)).catch(()=>{}),await Fl(Jl(n)).catch(()=>{})}async function Q(n){let e;try{e=await hA(tt())}catch{return[]}let t=[];return await Promise.all(e.map(async s=>{if(!/^\d+\.json$/.test(s))return;let i=parseInt(s,10),o;try{o=JSON.parse(await Gm(xe.join(tt(),s),"utf8"))}catch{await zr(i);return}o&&typeof o.pid=="number"&&Hl(o.pid)?t.push(o):await zr(i)})),(n?t.filter(s=>s.agent==null&&Ym(s.file,n)):t).sort((s,i)=>s.startedAt-i.startedAt)}async function Yl(n,e){let t=X(n);return(await Q()).find(r=>r.cwd!=null&&X(r.cwd)===t&&(e?r.agent===e:r.agent!=null))}async function Yt(n){try{process.kill(n,"SIGTERM")}catch{}await zr(n)}function Rn(n,e){let t=X(e);return n.filter(r=>r.agent==null&&r.pid!==process.pid&&X(r.file)===t)}async function Vl(n){let e=Rn(await Q(),n);for(let t of e)await Yt(t.pid);return e}function SA(n,e,t){(process.platform==="win32"?Vm("cmd",["/c","start","","/b",n,...e],{cwd:t,stdio:"ignore",windowsHide:!0}):Vm(n,e,{cwd:t,detached:!0,stdio:"ignore"})).unref()}function Xr(){return xe.join(xe.dirname(yA(import.meta.url)),"index.js")}function kA(n,e={}){return{command:process.execPath,args:[Xr(),...e.trust?["--trust"]:[],...e.batch?["--batch",e.batch]:[],...e.mode?["--mode",e.mode]:[],n,...e.open===!1?["--no-open"]:[]]}}function xA(n){return{command:process.execPath,args:[Xr(),`agent:${n}`,"--no-open"]}}async function sg(n,e,t,r){let s=await n();if(s)return s;SA(e.command,e.args,t);let i=Date.now()+2e4;for(;Date.now()<i;){await vA(150);let o=await n();if(o)return o}throw new Error(`Launched ${r} but it did not register within 20s.`)}async function Zi(n,e={}){let t=e.cwd??process.cwd(),r=xe.resolve(t,n),[s]=await Vl(r),i={...e,batch:e.batch??s?.batch,mode:e.mode??s?.mode};return sg(async()=>Rn(await Q(),r)[0],kA(n,i),t,xe.basename(n))}async function ig(n,e=process.cwd()){return sg(()=>Yl(e,n),xA(n),e,`the ${n} mirror`)}var zm,bA,vA,Ee=v(()=>{"use strict";At();zi();zm=1e6;bA=/^── run (\d+) ── /;vA=n=>new Promise(e=>setTimeout(e,n))});function In(n){return{...pf(n),server:n.files.get("server.ts")??""}}function eo(n){return!!n.server&&!n.code}var Qr=v(()=>{"use strict";Z();Z()});function to(n){let e=/^---[^\n]*\n([\s\S]*?)\n---/.exec(n),t=e?/^\s*name:\s*(.+?)\s*$/m.exec(e[1]):null;return t?t[1].replace(/^["']|["']$/g,""):void 0}function zl(n){return On(to(n)??"bulb")||"bulb"}var Gl=v(()=>{"use strict";Z()});import{transform as EA}from"sucrase";function Xl(n,e={}){let t=e.serverOnly?["typescript"]:["typescript","jsx"];try{let{code:r}=EA(n,{transforms:t,jsxRuntime:"automatic",jsxImportSource:e.jsxImportSource||"react",production:!0});return{code:r}}catch(r){return{code:"",error:String(r)}}}var og=v(()=>{});function Ql(n){let e=n.split(""),t=(i,o)=>{for(let a=i;a<o&&a<e.length;a++)e[a]!==`
254
254
  `&&(e[a]=" ")},r=0,s="";for(;r<n.length;){let i=n[r],o=n[r+1];if(i==="/"&&o==="/"){let a=r;for(;a<n.length&&n[a]!==`
@@ -1534,7 +1534,7 @@ Re-run with --force to overwrite the local file.`),process.exitCode=1;return;cas
1534
1534
  `+s.paths.map(o=>` assets/${o}`).join(`
1535
1535
  `)+`
1536
1536
  Re-run with --force to overwrite them.`),process.exitCode=1;return;case"http-error":s.status===404?console.error(`Bulb not found: ${r}`):s.status===401||s.status===403?console.error(`This bulb is private (${s.status}) \u2014 pulling it needs a TYPEBULB_TOKEN for its owner.`):console.error(`Pull failed: ${t.origin} responded ${s.status}`),process.exitCode=1;return;case"not-markdown":console.error(`${r}.md did not return bulb markdown (got ${s.contentType??"no content-type"}) \u2014 is ${t.origin} a typebulb host?`),process.exitCode=1}}function Sy(n){if(!(!n||!n.downloaded&&!n.errors.length)){console.log(`assets: ${n.downloaded} downloaded${n.unchanged?`, ${n.unchanged} unchanged`:""}`);for(let e of n.errors)console.error(` asset failed \u2014 ${e} (a re-pull retries just the missing ones)`);n.errors.length&&(process.exitCode=1)}}var aO,Uo,Uu,qo,ws,Ju,Wo=v(()=>{"use strict";it();Z();ze();aO="https://typebulb.com",Uo=(n,e)=>Oe.join("typebulbs","u",n,`${e}.bulb.md`),Uu=n=>`${n.origin}/u/${encodeURIComponent(n.userSlug)}/${encodeURIComponent(n.slug)}.md`,qo=n=>n.split("/").map(encodeURIComponent).join("/"),ws=n=>`${n.origin}/u/${encodeURIComponent(n.userSlug)}/${encodeURIComponent(n.slug)}/assets`;Ju=n=>oO("md5").update(n).digest("hex")});import*as Ge from"fs/promises";import*as vs from"path";async function xy(n,e=""){let t=await Ge.readdir(n,{withFileTypes:!0}).catch(()=>[]),r=[];for(let s of t)s.isDirectory()?r.push(...await xy(vs.join(n,s.name),`${e}${s.name}/`)):s.isFile()&&r.push(e+s.name);return r}async function dO(n,e){let t=e.timeoutMs??3e4,r=ws(n),s={Authorization:`Bearer ${e.token}`},i=$t(n.dest);if(!await Ge.stat(i).then(m=>m.isDirectory()).catch(()=>!1))return{kind:"skipped"};let o=await xy(i),a=await Ku(n,{token:e.token,timeoutMs:t});if("error"in a)return{kind:"sync-error",message:a.error};let c=a.entries;if(!o.length&&!c.length)return{kind:"skipped"};let l=new Map(c.map(m=>[m.path,m.md5])),f=new Set(o),u=c.map(m=>m.path).filter(m=>!f.has(m)),d=0,p=0;try{await qu(o,4,async m=>{let h=await Ge.readFile(vs.join(i,...m.split("/")));if(l.get(m)===Ju(h)){p++;return}let y=await fetch(`${r}/${qo(m)}`,{method:"PUT",body:new Uint8Array(h),headers:s,signal:AbortSignal.timeout(t)});if(!y.ok)throw new Error(`upload of '${m}' refused (${y.status}): ${Xn(await y.text())}`);d++})}catch(m){return{kind:"sync-error",message:m instanceof Error?m.message:String(m)}}return{kind:"synced",uploaded:d,unchanged:p,toDelete:u,base:qs(n.userSlug,n.slug)}}async function fO(n,e,t){let r=t.timeoutMs??3e4,s=ws(n),i=[];for(let o of e)try{let a=await fetch(`${s}/${qo(o)}`,{method:"DELETE",headers:{Authorization:`Bearer ${t.token}`},signal:AbortSignal.timeout(r)});if(!a.ok)return{deleted:i,error:`delete of '${o}' refused (${a.status}): ${Xn(await a.text())}`};i.push(o)}catch(a){return{deleted:i,error:a instanceof Error?a.message:String(a)}}return{deleted:i}}async function Ho(n,e){let t=await Ge.readFile(n.dest,"utf-8"),{mtime:r}=await Ge.stat(n.dest),s=await dO(n,{token:e.token,timeoutMs:e.timeoutMs});if(s.kind==="sync-error")return{kind:"asset-error",message:s.message};let i=s.kind==="synced"?{uploaded:s.uploaded,unchanged:s.unchanged,deleted:[],base:s.base}:void 0,o={Authorization:`Bearer ${e.token}`,"Content-Type":"text/markdown; charset=utf-8"};e.force||(o["If-Unmodified-Since"]=r.toUTCString());let a=await fetch(Uu(n),{method:"PUT",body:t,headers:o,signal:e.timeoutMs?AbortSignal.timeout(e.timeoutMs):void 0}),c=await a.text();if(a.status===409)return{kind:"conflict",message:Xn(c),assets:i};if(!a.ok)return{kind:"http-error",status:a.status,message:Xn(c),assets:i};let l=JSON.parse(c);if(await Ge.utimes(n.dest,new Date,new Date(l.updatedAt)),i&&s.kind==="synced"&&s.toDelete.length){let f=await fO(n,s.toDelete,{token:e.token,timeoutMs:e.timeoutMs});i.deleted=f.deleted,f.error&&(i.pruneError=f.error)}return{kind:"pushed",created:l.created,serverStripped:l.serverStripped,updatedAt:l.updatedAt,assets:i}}async function Ey(n,e){n||(console.error("Usage: typebulb push <typebulbs/u/<user>/<slug>.bulb.md>"),process.exit(1)),/^https?:\/\//i.test(n)&&(console.error("push takes a local .bulb.md file, not a URL (the path is its remote identity)"),process.exit(1));let t=Wu(n,e.mode),r=process.env.TYPEBULB_TOKEN;r||(console.error("push needs TYPEBULB_TOKEN in your .env \u2014 create one on your typebulb.com settings page."),process.exit(1));let s=`${t.origin}/u/${t.userSlug}/${t.slug}`,i=vs.relative(process.cwd(),t.dest)||t.dest,o;try{o=await Ho(t,{token:r,force:e.force})}catch(a){let c=a instanceof Error?a.message:String(a);console.error(a?.code==="ENOENT"?`File not found: ${i}`:`Could not push to ${t.origin}: ${c}`),process.exitCode=1;return}switch(o.kind!=="asset-error"&&o.assets&&console.log(`assets: ${o.assets.uploaded} uploaded, ${o.assets.unchanged} unchanged \u2192 ${o.assets.base}`),o.kind){case"asset-error":console.error(`assets sync failed: ${o.message}
1537
- push refused: the bulb text was not pushed.`),process.exitCode=1;return;case"pushed":{console.log(`pushed ${i} \u2192 ${s}`),o.created&&(console.log(" created a new bulb, unlisted \u2014 nothing existed at this URL before"),console.log(" if you renamed this file, its previous bulb is still live at the old URL")),o.serverStripped&&console.log("note: the server.ts block was stripped on the server copy (CLI-only); your local file is untouched.");for(let a of o.assets?.deleted??[])console.log(` deleted ${a} (no longer in assets/)`);o.assets?.pruneError&&console.log(`note: asset cleanup incomplete \u2014 ${o.assets.pruneError}; the next push will retry.`);return}case"conflict":console.error(`${o.message}
1537
+ push refused: the bulb text was not pushed.`),process.exitCode=1;return;case"pushed":{console.log(`pushed ${i} \u2192 ${s}/full`),o.created&&(console.log(" created a new bulb, unlisted \u2014 nothing existed at this URL before"),console.log(" if you renamed this file, its previous bulb is still live at the old URL")),o.serverStripped&&console.log("note: the server.ts block was stripped on the server copy (CLI-only); your local file is untouched.");for(let a of o.assets?.deleted??[])console.log(` deleted ${a} (no longer in assets/)`);o.assets?.pruneError&&console.log(`note: asset cleanup incomplete \u2014 ${o.assets.pruneError}; the next push will retry.`);return}case"conflict":console.error(`${o.message}
1538
1538
  pull to see the remote: typebulb pull ${i}
1539
1539
  or overwrite it: typebulb push ${i} --force`),process.exitCode=1;return;case"http-error":o.status===401?console.error("The server rejected TYPEBULB_TOKEN (401) \u2014 it may be revoked; mint a new one on the settings page."):console.error(`Push failed: ${t.origin} responded ${o.status}${o.message?` \u2014 ${o.message}`:""}`),process.exitCode=1}}var Hu=v(()=>{"use strict";Z();Wo();ze()});var Qn=v(()=>{"use strict";Ee();cy();Yn();yy();Gl();by();vy();ys();rn();rn();_o();Fu();Ee();Wo();Hu();it()});import{existsSync as pO,mkdirSync as hO,readFileSync as mO,rmSync as gO,writeFileSync as yO}from"fs";import{homedir as bO}from"os";import*as Zn from"path";function kO(){return SO.replace('"__TB_SKILL_PATH__"',JSON.stringify(bs())).replace('"__TB_BIN_PATH__"',JSON.stringify(Xr()))}function Ay(){try{if(!pO(Yu()))return}catch{return}try{let n=wO(),e=kO(),t;try{t=mO(n,"utf8")}catch{}t!==e&&(hO(Zn.dirname(n),{recursive:!0}),yO(n,e))}catch{}for(let n of vO())try{gO(n,{force:!0})}catch{}}var Yu,wO,vO,SO,Ty=v(()=>{"use strict";Qn();Yu=()=>Zn.join(bO(),".pi","agent"),wO=()=>Zn.join(Yu(),"extensions","typebulb.ts"),vO=()=>["typebulb-wait.ts","matchu-patchu.ts"].map(n=>Zn.join(Yu(),"extensions",n)),SO=String.raw`// Generated by typebulb — do not edit; overwritten on each run.
1540
1540
  import { spawn } from "node:child_process";
@@ -2257,7 +2257,7 @@ declare const tb: {${i_}${Zb}${nw}${rw}${ew}${tw}
2257
2257
  `)&&process.stdout.write(`
2258
2258
  `),e.follow&&e.run===void 0){let i=r.offset,o=setInterval(()=>{let c=He(t.pid,i);i=c.offset,c.text&&process.stdout.write(c.text)},500),a=()=>{clearInterval(o),process.exit(0)};process.on("SIGINT",a),process.on("SIGTERM",a),await new Promise(()=>{})}}var D_=n=>new Promise(e=>setTimeout(e,n));async function Ow(n,e){if(!n){Ud(await Q(process.cwd()),"Run `typebulb wait <file|pid>` to block until one logs a new line.");return}let t=qd(await Q(),n,"wait",process.cwd(),pn()),r=t.agent!=null,s=process.env.TYPEBULB_WAIT_SHIM==="1",i=process.env.TYPEBULB_WAIT_FOLLOW==="1",o=s||i,a=e.timeoutSec??1800,c=e.match??"",l=He(t.pid).offset,f=i?void 0:Kl(t.pid,c)??(c?Kl(t.pid):void 0),u=i?l:f!==void 0&&f<=l?f:c?0:l,d=Date.now()+a*1e3,p=r?1e4:1e3,m=2e3,h,y="",A=0;for(;;){let S=He(t.pid,u);if(u=S.offset,S.text){y+=S.text;let P=y.split(`
2259
2259
  `);y=P.pop()??"";for(let C of P)C.trim()&&(e.match&&!C.includes(e.match)||(console.log(C),!i&&(h??=Date.now()+p,r&&(C.includes("] compile error")||C.includes("] runtime error"))&&(h=Math.min(h,Date.now()+m)))))}if(h&&Date.now()>=h)break;if(!o&&!h&&Date.now()>=d){console.error(`timeout: no ${e.match?`line matching '${e.match}'`:"new output"} from ${Rs(t)} within ${a}s`),A=2;break}if(!Hl(t.pid)){h||(console.error(`server ${Rs(t)} (pid ${t.pid}) exited while waiting`),process.exit(3));break}await D_(400)}i||Xi(t.pid,u,c),process.exit(A)}async function Pw(n){if(!n){Ud(await Q(process.cwd()),"Run `typebulb stop <file|pid>` to stop one.");return}let e=qd(await Q(),n,"stop",process.cwd(),pn());await Yt(e.pid),console.log(`Stopped ${Rs(e)} (pid ${e.pid}, ${e.url}).`)}async function Cw(n){let e=process.cwd(),t=n==="agent"?pn():void 0,r=n==="global"?await Q():n==="bulbs"?await Q(e):(await Q()).filter(i=>i.agent!=null&&i.cwd!=null&&X(i.cwd)===X(e)&&(!t||i.agent===t)),s=n==="global"?"server":n==="agent"?"mirror":"bulb";if(!r.length){console.log(n==="global"?"No running bulb servers.":`No running ${s}s for this project.`);return}await Promise.all(r.map(i=>Yt(i.pid))),console.log(`Stopped ${r.length} ${s}${r.length===1?"":"s"}:`);for(let i of r)console.log(` ${i.url} pid ${i.pid} ${Rs(i)}`)}Ee();At();Yn();import*as Ea from"path";import*as _w from"http";import{mkdir as j_,writeFile as F_}from"fs/promises";async function ar(){let n=[];for await(let e of process.stdin)n.push(e);return Buffer.concat(n).toString("utf-8")}function Is(n){return(n.charCodeAt(0)===65279?n.slice(1):n).replace(/\r\n/g,`
2260
- `).trimEnd()}function U_(n,e){return new Promise((t,r)=>{let s=new URL(n),i=_w.request({hostname:s.hostname,port:s.port,path:s.pathname+s.search,method:"POST",headers:{"Content-Type":"text/plain","Content-Length":Buffer.byteLength(e)}},o=>{let a="";o.setEncoding("utf8"),o.on("data",c=>{a+=c}),o.on("end",()=>t({status:o.statusCode??0,text:a}))});i.setTimeout(0),i.on("error",r),i.end(e)})}var q_=n=>{let e=Math.round((Date.now()-n)/6e4);return e<1?"moments ago":e<60?`${e}m ago`:`${Math.round(e/60)}h ago`};async function Rw(n,e,t=0){e==="-"&&(e=Is(await ar()));let r=e!==void 0&&e.startsWith("tb:");r&&t<=0&&(t=Rd);let s=e!==void 0&&/^tb:(click|set)( |$)/.test(e),i=Ea.resolve(n),o=Rn(await Q(),i)[0];if(!o){let p=(await ms(process.cwd()))(i);console.error(p?`No running server for '${n}' \u2014 it last ran ${q_(p)}. Relaunching reuses the same URL (a stale tab is one reload from live): npx typebulb ${n}`:`No running server for '${n}'. Start it first: npx typebulb ${n}`),process.exit(1)}let a=async p=>{let m=[p>0?`reply=${p}`:"",s?"solo=1":""].filter(Boolean).join("&"),h=await U_(`${o.url}/__send${m?`?${m}`:""}`,e??"");(h.status<200||h.status>=300)&&(console.error(`send failed: HTTP ${h.status} from ${o.url}/__send`),process.exit(1));try{return JSON.parse(h.text)}catch{return{}}},c={};try{let p=Date.now()+t;do{if(c=await a(t>0?Math.max(p-Date.now(),1e3):0),(c.clients??0)>0||Date.now()>=p)break;await new Promise(m=>setTimeout(m,150))}while(!0)}catch(p){console.error(`send failed: ${p instanceof Error?p.message:String(p)}`),process.exit(1)}let l=c.clients??0,f=`${l} page${l===1?"":"s"}`;if(c.refused&&(console.error(`Actuation needs exactly one connected page; ${f} are open on ${o.url} \u2014 close the extras and retry.`),process.exit(1)),l===0){let p=c.droppedMsAgo,m=p!==void 0?` \u2014 a page disconnected ${Math.round(p/1e3)}s ago and hasn't reconnected; reload it, or open ${o.url}`:` \u2014 no page has ever connected; share ${o.url} and arm: typebulb wait ${n} --match "[page] connected"`;t>0?console.error(`No page connected after ${t/1e3}s${m}`):console.error(`Sent, but no page is connected${m}`),r&&process.exit(1);return}console.error(`Sent to ${f}.`);let u=c.results??[],d=c.errors??[];for(let p of d)console.error(`handler error: ${p}`);if(d.length&&process.exit(1),u.length>1&&(console.error(`${u.length} replies from ${f} \u2014 one reply owns stdout: at most one tb.onMessage handler, in one page, may return a value.`),process.exit(1)),u.length===1){if(e!==void 0&&/^tb:png( |$)/.test(e)){let m={};try{m=JSON.parse(u[0])}catch{}typeof m.png!="string"&&(console.error("tb:png replied with an unexpected shape \u2014 an older runtime? (`typebulb logs` lists server versions)"),process.exit(1));let h=Hm(i);await j_(Ea.dirname(h),{recursive:!0}),await F_(h,Buffer.from(m.png,"base64"));let y=[m.via?`inside "${m.via}"`:"",m.backdrop?`backdrop ${m.backdrop}`:""].filter(Boolean);console.error(`canvas ${m.width}\xD7${m.height} \u2192 PNG${y.length?` (${y.join("; ")})`:""}`),console.log(h);return}let p;try{p=JSON.parse(u[0])}catch{p=void 0}console.log(typeof p=="string"?p:u[0])}else c.timedOut&&(r&&(console.error(`No reply to '${e}' within ${t/1e3}s \u2014 reload the page and retry.`),process.exit(1)),console.error(`(no reply within ${t/1e3}s \u2014 slow work needs a larger --wait=ms; a reply that NEVER comes is a done-promise that missed an exit)`))}Wo();Hu();Z();import*as Iw from"fs/promises";async function Nw(n,e){let t=await Iw.readFile(n,"utf-8"),r=mn(t),s=ce[e].path,i=r.files.get(s);i||(console.error(i===void 0?`No **${s}** block in ${n}`:`The **${s}** block in ${n} is empty`),process.exit(2)),process.stdout.write(i.endsWith(`
2260
+ `).trimEnd()}function U_(n,e){return new Promise((t,r)=>{let s=new URL(n),i=_w.request({hostname:s.hostname,port:s.port,path:s.pathname+s.search,method:"POST",headers:{"Content-Type":"text/plain","Content-Length":Buffer.byteLength(e)}},o=>{let a="";o.setEncoding("utf8"),o.on("data",c=>{a+=c}),o.on("end",()=>t({status:o.statusCode??0,text:a}))});i.setTimeout(0),i.on("error",r),i.end(e)})}var q_=n=>{let e=Math.round((Date.now()-n)/6e4);return e<1?"moments ago":e<60?`${e}m ago`:`${Math.round(e/60)}h ago`};async function Rw(n,e,t=0){e==="-"&&(e=Is(await ar()));let r=e!==void 0&&e.startsWith("tb:");r&&t<=0&&(t=Rd);let s=e!==void 0&&/^tb:(click|set)( |$)/.test(e),i=Ea.resolve(n),o=Rn(await Q(),i)[0];if(!o){let p=(await ms(process.cwd()))(i);console.error(p?`No running server for '${n}' \u2014 it last ran ${q_(p)}. Relaunching reuses the same URL (a stale tab is one reload from live): npx typebulb ${n}`:`No running server for '${n}'. Start it first: npx typebulb ${n}`),process.exit(1)}let a=async p=>{let m=[p>0?`reply=${p}`:"",s?"solo=1":""].filter(Boolean).join("&"),h=await U_(`${o.url}/__send${m?`?${m}`:""}`,e??"");(h.status<200||h.status>=300)&&(console.error(`send failed: HTTP ${h.status} from ${o.url}/__send`),process.exit(1));try{return JSON.parse(h.text)}catch{return{}}},c={};try{let p=Date.now()+t;do{if(c=await a(t>0?Math.max(p-Date.now(),1e3):0),(c.clients??0)>0||Date.now()>=p)break;await new Promise(m=>setTimeout(m,150))}while(!0)}catch(p){console.error(`send failed: ${p instanceof Error?p.message:String(p)}`),process.exit(1)}let l=c.clients??0,f=`${l} page${l===1?"":"s"}`;if(c.refused&&(console.error(`Actuation needs exactly one connected page; ${f} are open on ${o.url} \u2014 close the extras and retry.`),process.exit(1)),l===0){let p=c.droppedMsAgo,m=p!==void 0?` \u2014 a page disconnected ${Math.round(p/1e3)}s ago and hasn't reconnected; reload it, or open ${o.url}`:` \u2014 no page has ever connected; share ${o.url} and arm: typebulb wait ${n} --match "[page] connected"`;t>0?console.error(`No page connected after ${t/1e3}s${m}`):console.error(`Sent, but no page is connected${m}`),r&&process.exit(1);return}console.error(`Sent to ${f}.`);let u=c.results??[],d=c.errors??[];for(let p of d)console.error(`handler error: ${p}`);if(d.length&&process.exit(1),u.length>1&&(console.error(`${u.length} replies from ${f} \u2014 one reply owns stdout: at most one tb.onMessage handler, in one page, may return a value.`),process.exit(1)),u.length===1){if(e!==void 0&&/^tb:png( |$)/.test(e)){let m={};try{m=JSON.parse(u[0])}catch{}typeof m.png!="string"&&(console.error("tb:png replied with an unexpected shape \u2014 an older runtime? (`typebulb logs` lists server versions)"),process.exit(1));let h=Hm(i);await j_(Ea.dirname(h),{recursive:!0}),await F_(h,Buffer.from(m.png,"base64"));let y=[m.via?`inside "${m.via}"`:"",m.backdrop?`backdrop ${m.backdrop}`:""].filter(Boolean);console.error(`canvas ${m.width}\xD7${m.height} \u2192 PNG${y.length?` (${y.join("; ")})`:""}`),console.log(h);return}let p;try{p=JSON.parse(u[0])}catch{p=void 0}console.log(typeof p=="string"?p:u[0])}else c.timedOut&&(r&&(console.error(`No reply to '${e}' within ${t/1e3}s \u2014 reload the page and retry.`),process.exit(1)),console.error(`(no reply within ${t/1e3}s \u2014 slow work needs a larger --wait=ms; a reply that NEVER comes is a done-promise that missed an exit, or a blocked main thread: tb:snapshot runs no page code, so its silence too means blocked)`))}Wo();Hu();Z();import*as Iw from"fs/promises";async function Nw(n,e){let t=await Iw.readFile(n,"utf-8"),r=mn(t),s=ce[e].path,i=r.files.get(s);i||(console.error(i===void 0?`No **${s}** block in ${n}`:`The **${s}** block in ${n} is empty`),process.exit(2)),process.stdout.write(i.endsWith(`
2261
2261
  `)?i:i+`
2262
2262
  `)}Z();import*as Ns from"fs/promises";async function Mw(n,e){let t=await Ns.readFile(n,"utf-8"),r=[];for(let{kind:i,source:o}of e){let a;try{a=o==="-"?await ar():await Ns.readFile(o,"utf-8")}catch(c){Lw(`Cannot read ${i}'s source: ${c instanceof Error?c.message:String(c)}`)}r.push({kind:i,content:Is(a),label:o==="-"?"stdin":o})}let s;try{s=J_(t,r)}catch(i){Lw(`${n}: ${i instanceof Error?i.message:String(i)}`)}for(let i of s.upToDate)console.log(`${ce[i].path}: already up to date`);if(s.written.length){await Ns.writeFile(n,s.text);for(let i of s.written)console.log(i.action==="removed"?`${ce[i.kind].path}: removed (${i.label} is empty)`:`${ce[i.kind].path}: ${i.action} from ${i.label} (${i.chars.toLocaleString()} chars)`)}}function J_(n,e){let t=mn(n),r=n,s=[],i=[];for(let{kind:o,content:a,label:c}of e){let l=ce[o].path,f=t.files.get(l);if(!a){if(f===void 0){i.push(o);continue}r=$w(bf(r,o),r,l),s.push({kind:o,action:"removed",chars:0,label:c});continue}if(f!==void 0&&Is(f)===a){i.push(o);continue}r=$w(lr(r,o,a),r,l),s.push({kind:o,action:f===void 0?"created":"replaced",chars:a.length,label:c})}return{text:r,written:s,upToDate:i}}function $w(n,e,t){if(n===e)throw new Error(`the **${t}** block's fence is unterminated; refusing to rewrite inside it`);return n}function Lw(n){console.error(n),process.exit(1)}it();ze();Z();Fo();import*as Ft from"fs/promises";import*as Ra from"path";import{EventEmitter as qw}from"events";import oR from"open";nn();Z();import{Hono as z_}from"hono";import{serve as G_}from"@hono/node-server";import{streamSSE as X_}from"hono/streaming";import*as Hd from"fs/promises";Mn();ls();Ln();import*as Jd from"fs/promises";import*as $s from"path";var Aa=class{async get(e){let t=De(e),r=$s.join(cs,t+".bin"),s=$s.join(cs,t+".json");try{let[i,o]=await Promise.all([Jd.readFile(r),Jd.readFile(s,"utf8")]),a=JSON.parse(o);return{body:i,contentType:a.contentType,cacheControl:a.cacheControl}}catch{return}}async set(e,t){await ee();let r=De(e),s=$s.join(cs,r+".bin"),i=$s.join(cs,r+".json"),o={url:e,contentType:t.contentType,cacheControl:t.cacheControl};await Promise.all([Ae(s,t.body),Ae(i,JSON.stringify(o))])}};var Bw=`
2263
2263
  const CSS = '\\n' +
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "typebulb",
3
- "version": "0.55.4",
3
+ "version": "0.55.5",
4
4
  "description": "Typebulb CLI to run single-file markdown apps called bulbs, either as standalone web apps or embedded in agent responses.",
5
5
  "keywords": [
6
6
  "bulb",