typebulb 0.28.0 → 0.28.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.
@@ -2217,7 +2217,7 @@ var Patcher = class _Patcher {
2217
2217
 
2218
2218
  // cli/agents/pi/server/piPatcherExtension.ts
2219
2219
  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.";
2220
- var BUILD_TAG = true ? "matchu-patchu-pi 0.2.0, built 2026-07-15 23:58:22" : "matchu-patchu-pi dev";
2220
+ var BUILD_TAG = true ? "matchu-patchu-pi 0.2.0, built 2026-07-16 09:47:20" : "matchu-patchu-pi dev";
2221
2221
  var errorBlocks = (errors) => {
2222
2222
  const parts = [`Patch failed with ${errors.length} error(s):`];
2223
2223
  for (const e of errors) parts.push("", e.toString());
@@ -817,16 +817,27 @@ a.server-port:hover { text-decoration: underline; }
817
817
  the logs-link register — marks the category and opens the bulb's published page. A remote
818
818
  (not-yet-downloaded) row's name is additionally muted and inert (no file to open), and its
819
819
  time column stays empty (no mtime to show). */
820
- .server-name.remote { color: var(--muted); cursor: default; }
820
+ .server-name.remote { cursor: default; }
821
821
  .server-name.remote:hover { text-decoration: none; }
822
822
  .sample-link { color: var(--muted); font-size: .76rem; text-decoration: none; cursor: pointer; flex: none; }
823
823
  .sample-link:hover { color: var(--accent); text-decoration: underline; }
824
- /* The samples-catalog fold header (bulbsPill.ts groupRow): caret in the button column, muted label
825
- spanning the remaining tracks. Pitch, hover, and the keyboard highlight inherit from .server-row. */
824
+ /* The remote fold (bulbsPill.ts groupRow / fold-row): the header and the remote rows within share
825
+ one veil step over the menu's panel bg (the picker-peek shade) as ONE contiguous band — each
826
+ row's ::before bridges the grid row-gap up to the row above, junction corners square off, and
827
+ only the band's outer corners round (the header's top; the last row's bottom, via :has). The
828
+ accent label marks the header. Single-class selectors on purpose: .server-row:hover/.active
829
+ outrank them, so the highlight tints still win. */
826
830
  .sample-group { cursor: pointer; color: var(--muted); }
827
- .sample-group:hover, .sample-group.active { color: var(--fg); }
831
+ .sample-group, .fold-row { background: linear-gradient(var(--veil), var(--veil)), var(--panel); }
832
+ .sample-group.open { border-radius: 6px 6px 0 0; }
833
+ .fold-row { position: relative; border-radius: 0; }
834
+ .fold-row::before {
835
+ content: ''; position: absolute; left: 0; right: 0; top: -.15rem; height: .15rem;
836
+ background: linear-gradient(var(--veil), var(--veil)), var(--panel);
837
+ }
838
+ .fold-row:not(:has(+ .fold-row)) { border-radius: 0 0 6px 6px; }
828
839
  .sample-group .caret-tri { justify-self: center; }
829
- .sample-group-label { grid-column: 2 / -1; }
840
+ .sample-group-label { grid-column: 2 / -1; color: var(--accent); }
830
841
  /* The 1fr name column: name + (in full-text mode) its hit count read together, the badge
831
842
  right-aligned at the column's end by the name's flex:1 — the session row's preview/hits layout. */
832
843
  .bulb-name-cell { display: flex; align-items: baseline; gap: .6rem; min-width: 0; }
package/dist/index.js CHANGED
@@ -558,7 +558,7 @@ ${r.slice(0,TE)}`}],effort:0,webSearch:!1,signal:e});if(!i.ok)continue;let o=OE(
558
558
  `)){if(!B.trim())continue;let $=r.parseEntry(B);if(!$)continue;let J=r.searchText($);J&&_.push({text:J,lower:J.toLowerCase()})}return eu.set(g,{mtime:v,turns:_}),_}async function Ty(g){let v=g.toLowerCase(),w=[];for(let{sessionId:_,file:M,mtime:B}of r.listSessionFiles(e.cwd).sort(($,J)=>J.mtime-$.mtime)){let{hitCount:$,snippet:J}=Gi(Ay(M,B),v);if($&&(w.push({sessionId:_,mtime:B,preview:r.readPreview(M),hitCount:$,snippet:J}),w.length>=HE))break}return w}let tu=800,ru=new Map;function Py(g,v){let w=ru.get(g);if(w&&w.mtime===v)return w.text;let _="";try{_=Zi(g,"utf8")}catch{return""}let M="";for(let $ of _.split(`
559
559
  `)){if(!$.trim())continue;let J=r.parseEntry($);if(J)for(let q of r.apply(J,e.sessionStartMs).events)q.type==="assistant"&&q.text.trim()&&(M=q.text.trim())}let B=M.length>tu?M.slice(0,tu).trimEnd()+"\u2026":M;return ru.set(g,{mtime:v,text:B}),B}async function Oy(g){let v=r.listSessionFiles(e.cwd).find(w=>w.sessionId===g);return{text:v?Py(v.file,v.mtime):""}}async function Cy(g){let v=e,w=r.listSessionFiles(v.cwd).find(_=>_.sessionId===g);return w?w.file===v.file?{ok:!0}:(C(w),c(),a(),{ok:!0}):{ok:!1,error:"session not found"}}return p(e.cwd),y(e.cwd),b(),{info:N,poll:Ve,logEmbedStatus:vt,listSessions:Ey,searchSessions:Ty,sessionPeek:Oy,attach:Cy,composerSend:hy,composerStop:by,composerNew:wy,composerFiles:vy,composerUiRespond:gy,composerRpc:yy,composerPaste:ky,composerPasteRead:xy,shutdownComposer:Sy}}var qE,UE,wh,JE,HE,vl=A(()=>{ht();ih();Vi();wl();mh();qE=".typebulb",UE=`${qE}/locks`,wh=5e3,JE=6e4;HE=50});import{existsSync as El,mkdirSync as WE,readFileSync as vh,writeFileSync as YE}from"fs";import{join as Kt,isAbsolute as VE}from"path";async function Sh(r,e){let t=VE(r)?r:Kt(K,r);return El(t)?(dl(t,e),{ok:!0}):{ok:!1,error:"file not found"}}async function kh(r){let e=K,t=fl(r),n=Kt(e,"typebulbs");WE(n,{recursive:!0});let s=cl(t),i=`${s}.bulb.md`;for(let l=2;El(Kt(n,i))&&vh(Kt(n,i),"utf8")!==t;l++)i=`${s}-${l}.bulb.md`;let o=Kt(n,i);El(o)||YE(o,t);let a=Kt("typebulbs",i),c=await Ni(a,{cwd:e,open:!1});return{ok:!0,file:a,pid:c.pid,url:c.url}}async function xh(){return Y(K)}async function Eh(r){return await jt(r),{ok:!0}}async function Ah(){return $i(K).filter(r=>!r.serverOnly).map(r=>({...r,trusted:Bt(r.path)}))}async function Th(r){let e=r.toLowerCase(),t=[];for(let n of $i(K).filter(s=>!s.serverOnly).sort((s,i)=>i.mtime-s.mtime)){let s="";try{s=vh(n.path,"utf8")}catch{continue}let i=[];for(let c of s.split(`
560
560
  `)){let l=c.replace(/\s+/g," ").trim();l&&i.push({text:l,lower:l.toLowerCase()})}let{hitCount:o,snippet:a}=Gi(i,e);o&&t.push({path:n.path,hitCount:o,snippet:a})}return t}async function Ph(r,e){let t=K;e!=null&&br(r,e);let n=await Ni(r,{cwd:t,open:!1,trust:e});return{ok:!0,file:n.file,pid:n.pid,url:n.url,trust:!!n.trust}}async function Oh(r){return{cap:await ul(r)}}async function Ch(r,e){return br(r,e),{ok:!0}}async function _h(r,e){return Re(r,e)}async function $h(){return $n&&Date.now()-$n.fetchedAt<=zE?$n.samples:(Sl??=QE().finally(()=>{Sl=null}),Sl)}async function QE(){try{let r=await fetch(`${GE}/api/scripts/u/samples?stubs`,{signal:AbortSignal.timeout(Nh)});if(!r.ok)throw new Error(`HTTP ${r.status}`);let e=await r.json(),t=i=>i.order??Number.MAX_SAFE_INTEGER,n=i=>Date.parse(i.createdAt??"")||0,s=e.filter(i=>i.slug!=="welcome").sort((i,o)=>t(i)-t(o)||n(o)-n(i)).map(i=>({slug:i.slug,name:i.name,description:$o(i.config)}));return $n={samples:s,fetchedAt:Date.now()},s}catch{return $n?.samples??[]}}async function Lh(r){return Al.test(r)?Bh(Rh,"samples",r,!0):{ok:!1,error:"bad slug"}}async function Mh(){let r=Tl();if(!r)return{bulbs:[]};let e=`${to()}
561
- ${r}`;return gt?.key===e&&Date.now()-gt.fetchedAt<=XE?{user:gt.user,bulbs:gt.bulbs}:(kl??=ZE(e,r).finally(()=>{kl=null}),kl)}async function xl(r,e,t){let n=await fetch(`${r}${e}`,{headers:t,signal:AbortSignal.timeout(Nh)});if(!n.ok)throw new Error(`HTTP ${n.status}`);if(!n.headers.get("content-type")?.includes("json"))throw new Error("not json");return n.json()}async function ZE(r,e){let t={Authorization:`Bearer ${e}`};try{let n=to(),s;try{s=await xl(n,"/api/me",t)}catch{let a=new URL(n);n=`${a.protocol}//api.${a.host}`,s=await xl(n,"/api/me",t)}let o=(await xl(n,"/api/scripts/list",t)).map(a=>({slug:a.slug,name:a.name,description:$o(a.config)}));return gt={key:r,user:s.slug,bulbs:o,fetchedAt:Date.now()},{user:s.slug,bulbs:o}}catch{return gt?.key===r?{user:gt.user,bulbs:gt.bulbs}:{bulbs:[]}}}async function Dh(r,e,t=!1){return!Al.test(e)||!Al.test(r)?{ok:!1,error:"bad slug"}:Bh(to(),r,e,t)}async function Bh(r,e,t,n){let s=Bi(e,t);try{let i=await Fi({origin:r,userSlug:e,slug:t,dest:Kt(K,s)},{force:n,token:Tl(),timeoutMs:Ih});return i.kind==="conflict"?{ok:!1,conflict:!0,error:"local file differs from the site copy"}:i.kind==="http-error"?{ok:!1,error:`HTTP ${i.status}`}:i.kind==="not-markdown"?{ok:!1,error:`not a bulb (${i.contentType??"no content-type"})`}:{ok:!0,file:s,upToDate:i.kind==="up-to-date"}}catch(i){return{ok:!1,error:i?.message??String(i)}}}async function jh(r,e=!1){let t=Tl();if(!t)return{ok:!1,error:"no TYPEBULB_TOKEN in .env"};try{let n=ji(r,K,to()),s=await Ui(n,{token:t,force:e,timeoutMs:Ih});return s.kind==="conflict"?{ok:!1,conflict:!0,error:s.message}:s.kind==="http-error"?{ok:!1,error:`HTTP ${s.status}: ${s.message}`}:{ok:!0,created:s.created,serverStripped:s.serverStripped}}catch(n){return{ok:!1,error:n?.message??String(n)}}}var GE,Rh,zE,Nh,Ih,$n,Sl,Al,XE,gt,kl,to,Tl,Pl=A(()=>{Ar();ht();wl();je();GE="https://api.typebulb.com",Rh="https://typebulb.com",zE=3600*1e3,Nh=5e3,Ih=15e3,$n=null,Sl=null;Al=/^[a-z0-9][a-z0-9-]*$/,XE=300*1e3,gt=null,kl=null,to=()=>Di("TYPEBULB_ORIGIN",K)||Rh,Tl=()=>Di("TYPEBULB_TOKEN",K)});import{readFileSync as _l,writeFileSync as qh,mkdirSync as eA,appendFileSync as Uh,rmSync as Fh}from"fs";import{join as so,dirname as tA}from"path";import{createServer as rA}from"http";function yt(r){try{return JSON.parse(_l(r,"utf8"))}catch{return null}}function no(r,e){eA(tA(r),{recursive:!0}),qh(r,JSON.stringify(e,null,2)+`
561
+ ${r}`;return gt?.key===e&&Date.now()-gt.fetchedAt<=XE?{user:gt.user,bulbs:gt.bulbs}:(kl??=ZE(e,r).finally(()=>{kl=null}),kl)}async function xl(r,e,t){let n=await fetch(`${r}${e}`,{headers:t,signal:AbortSignal.timeout(Nh)});if(!n.ok)throw new Error(`HTTP ${n.status}`);if(!n.headers.get("content-type")?.includes("json"))throw new Error("not json");return n.json()}async function ZE(r,e){let t={Authorization:`Bearer ${e}`};try{let n=to(),s;try{s=await xl(n,"/api/me",t)}catch{let a=new URL(n);n=`${a.protocol}//api.${a.host}`,s=await xl(n,"/api/me",t)}let o=(await xl(n,"/api/scripts/list",t)).filter(a=>a.userSlug===s.slug&&!a.isTemplate).map(a=>({slug:a.slug,name:a.name,description:$o(a.config)}));return gt={key:r,user:s.slug,bulbs:o,fetchedAt:Date.now()},{user:s.slug,bulbs:o}}catch{return gt?.key===r?{user:gt.user,bulbs:gt.bulbs}:{bulbs:[]}}}async function Dh(r,e,t=!1){return!Al.test(e)||!Al.test(r)?{ok:!1,error:"bad slug"}:Bh(to(),r,e,t)}async function Bh(r,e,t,n){let s=Bi(e,t);try{let i=await Fi({origin:r,userSlug:e,slug:t,dest:Kt(K,s)},{force:n,token:Tl(),timeoutMs:Ih});return i.kind==="conflict"?{ok:!1,conflict:!0,error:"local file differs from the site copy"}:i.kind==="http-error"?{ok:!1,error:`HTTP ${i.status}`}:i.kind==="not-markdown"?{ok:!1,error:`not a bulb (${i.contentType??"no content-type"})`}:{ok:!0,file:s,upToDate:i.kind==="up-to-date"}}catch(i){return{ok:!1,error:i?.message??String(i)}}}async function jh(r,e=!1){let t=Tl();if(!t)return{ok:!1,error:"no TYPEBULB_TOKEN in .env"};try{let n=ji(r,K,to()),s=await Ui(n,{token:t,force:e,timeoutMs:Ih});return s.kind==="conflict"?{ok:!1,conflict:!0,error:s.message}:s.kind==="http-error"?{ok:!1,error:`HTTP ${s.status}: ${s.message}`}:{ok:!0,created:s.created,serverStripped:s.serverStripped}}catch(n){return{ok:!1,error:n?.message??String(n)}}}var GE,Rh,zE,Nh,Ih,$n,Sl,Al,XE,gt,kl,to,Tl,Pl=A(()=>{Ar();ht();wl();je();GE="https://api.typebulb.com",Rh="https://typebulb.com",zE=3600*1e3,Nh=5e3,Ih=15e3,$n=null,Sl=null;Al=/^[a-z0-9][a-z0-9-]*$/,XE=300*1e3,gt=null,kl=null,to=()=>Di("TYPEBULB_ORIGIN",K)||Rh,Tl=()=>Di("TYPEBULB_TOKEN",K)});import{readFileSync as _l,writeFileSync as qh,mkdirSync as eA,appendFileSync as Uh,rmSync as Fh}from"fs";import{join as so,dirname as tA}from"path";import{createServer as rA}from"http";function yt(r){try{return JSON.parse(_l(r,"utf8"))}catch{return null}}function no(r,e){eA(tA(r),{recursive:!0}),qh(r,JSON.stringify(e,null,2)+`
562
562
  `)}function Kh(r,e,t){let n=so(r,".gitignore"),s="";try{s=_l(n,"utf8")}catch{}let i=new Set(s.split(/\r?\n/).map(c=>c.trim())),o=e.filter(c=>!i.has(c));if(!o.length)return;let a=s&&!s.endsWith(`
563
563
  `)?`
564
564
  `:"";try{Uh(n,a+t+`
@@ -1915,5 +1915,5 @@ ${oP}
1915
1915
  `);let a=0,c=Promise.resolve();Vt({target:r,onChange:()=>{let l=++a;c=c.then(async()=>{if(l===a)try{console.log("Re-running..."),await o()}catch(d){console.error("Error:",d)}})}})}}mt();import{Console as fP}from"node:console";Ne();async function fy(r,e,t,n){gP();try{let f=Sr(await Y(),r)[0];f&&(_i(f.pid,Re(f.pid).offset),console.error(`note: 'call' boots a fresh server.ts instance; the running server (${f.url}) is not contacted \u2014 state shared with it must live on disk.`))}catch{}let s=ge(t),{bulb:i,config:o}=await xe(r);i.server||Yn("This bulb has no **server.ts** block; nothing to call."),pt(s,r,i.server);let a;try{a=await On(i.server,r,n,o.dependencies)}catch(f){Yn(f instanceof Error?f.message:String(f))}let c=ko(a,e.fn);if(!c){let f=[...Object.keys(a).filter(p=>typeof a[p]=="function"),...Object.keys(So)];Yn(`Function '${e.fn}' not found. Available: ${f.length?f.join(", "):"(none)"}.`)}let l=await dP(e);if(xo(c)){try{for await(let f of c(...l))await uy(JSON.stringify(f,dy)+`
1916
1916
  `)}catch(f){Yn(f instanceof Error?f.stack??f.message:String(f))}return ly(0)}let d;try{d=await c(...l)}catch(f){Yn(f instanceof Error?f.stack??f.message:String(f))}let u=hP(d);u!==void 0&&await uy(u+`
1917
1917
  `),ly(0)}function ly(r){process.exitCode=r,setTimeout(()=>process.exit(r),2e3).unref?.()}async function dP(r){if(r.hasArgsFlag){let e=r.argsJson??"";return e==="-"&&(e=await yP()),mP(e)}return pP(r.positional)}function pP(r){return r.map(e=>{try{return JSON.parse(e)}catch{return e}})}function mP(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 hP(r){if(r!==void 0)return JSON.stringify(r,dy,2)}function dy(r,e){return typeof e=="bigint"?e.toString():e}function Yn(r){process.stderr.write(r+`
1918
- `),process.exit(1)}function gP(){let r=new fP(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 uy(r){return new Promise((e,t)=>{process.stdout.write(r,n=>n?t(n):e())})}async function yP(){let r=[];for await(let e of process.stdin)r.push(e);return Buffer.concat(r).toString("utf-8")}var Xl="0.28.0";function py(r,e){r||(console.error(`This bulb runs server-side Node code (server.ts), which --trust must authorize:
1918
+ `),process.exit(1)}function gP(){let r=new fP(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 uy(r){return new Promise((e,t)=>{process.stdout.write(r,n=>n?t(n):e())})}async function yP(){let r=[];for await(let e of process.stdin)r.push(e);return Buffer.concat(r).toString("utf-8")}var Xl="0.28.2";function py(r,e){r||(console.error(`This bulb runs server-side Node code (server.ts), which --trust must authorize:
1919
1919
  ${e}`),process.exit(1))}async function bP(){let r=pu(process.argv.slice(2));if(r.version&&(console.log(`typebulb ${Xl}`),process.exit(0)),r.help&&(mu(),process.exit(0)),Ig(),r.subcommand==="logs"){await Jg(r.file||void 0,{follow:r.follow,clear:r.clear,run:r.run,lines:r.lines});return}if(r.subcommand==="wait"){await Kg(r.file||void 0,{match:r.match,timeoutSec:r.timeoutSec});return}if(r.subcommand==="stop"){r.stopScope?await Wg(r.stopScope):await Hg(r.file||void 0);return}if(r.subcommand==="send"){await Vg(r.file,r.sendMessage,r.sendWaitMs??0);return}if(r.subcommand==="skill"){await Fg(Xl);return}if(r.subcommand==="models"){await Bg(r.mode);return}if(r.subcommand==="pull"){await Bm(r.file||void 0,{force:r.force,mode:r.mode});return}if(r.subcommand==="push"){await qm(r.file||void 0,{force:r.force,mode:r.mode});return}if(r.subcommand==="agent"){await(r.agentTarget?oy(r):Dg(Xl));return}if(r.subcommand==="trust"||r.subcommand==="untrust"){await Ng(r.file||void 0,r.subcommand==="trust");return}let e;if(!r.file||r.file==="."){let c=await om(process.cwd());c||(console.error("No .bulb.md file found in current directory"),process.exit(1)),e=c}else e=Gt.resolve(r.file);await my.access(e).then(()=>!0,()=>!1)||(Rr().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));let n=r.file&&r.file!=="."?r.file:Gt.relative(process.cwd(),e)||Gt.basename(e),s=`npx typebulb --trust ${n.includes(" ")?`"${n}"`:n}`;if(r.subcommand==="predict"){await Rg(e,s);return}let i=!r.noTrust&&Bt(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 xe(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 fu(r.local)}catch(c){console.error(c instanceof Error?c.message:String(c)),process.exit(1)}console.error(`replace: ${a.name} \u2192 ${Gt.relative(process.cwd(),a.dir)||"."}`)}if(r.subcommand==="check"){await _g(e,a);return}if(r.subcommand==="call"){py(r.trust,s),await fy(e,{fn:r.fn,positional:r.callArgs,argsJson:r.argsJson,hasArgsFlag:r.hasArgsFlag},r.mode,a);return}if(o&&o.bulb.server&&(zs(o.bulb)||r.server)){py(r.trust,s),await cy(e,r.watch,r.mode,a);return}await ry(e,r,s,a)}bP().catch(r=>{console.error("Error:",r.message),process.exit(1)});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "typebulb",
3
- "version": "0.28.0",
3
+ "version": "0.28.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
5
  "license": "MIT",
6
6
  "repository": {