typebulb 0.10.2 → 0.10.3

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
@@ -123,7 +123,7 @@ typebulb skill Print this README as an Agent Skill on stdout
123
123
  typebulb check [file.bulb.md] Type-check a bulb without running it
124
124
  typebulb predict [file] Report the capability a bulb probably needs, without running it
125
125
  typebulb models List AI models for tb.ai, filtered by your .env API keys
126
- typebulb logs [file|pid] Print a running bulb's captured console (-f follow, -n N tail)
126
+ typebulb logs [file|pid] Print a running bulb's captured console (no arg: list running servers; -f follow, -n N tail)
127
127
  typebulb stop [file|pid] Stop a running bulb (no arg: list this project's running servers)
128
128
  typebulb trust [file] Remember a bulb as trusted (no arg: list trusted bulbs)
129
129
  typebulb untrust <file> Forget a bulb's trust (back to sandboxed)
@@ -2745,10 +2745,11 @@ a.server-port:hover { color: var(--accent); text-decoration: underline; }
2745
2745
  flex: 1;
2746
2746
  overflow-y: auto;
2747
2747
  /* Content runs under the overlaid statusbar rather than stopping above it.
2748
- Left padding is larger to clear the turn stripe in the left gutter; the
2749
- bottom is larger still to clear the overlaid statusbar pills (~2.1rem:
2748
+ Gutters are symmetric: the turn stripe is absolutely positioned, so it claims no layout
2749
+ width and the left gutter needs no extra room for it (see Invariants). The bottom is
2750
+ larger to clear the overlaid statusbar pills (~2.1rem:
2750
2751
  .4rem inset + 1.7rem pill) so the last line isn't hidden behind them. */
2751
- padding: 1.25rem 1.25rem 2.5rem 2.25rem;
2752
+ padding: 1.25rem 1.75rem 2.5rem 1.75rem;
2752
2753
  display: flex;
2753
2754
  flex-direction: column;
2754
2755
  gap: 1rem;
@@ -2800,10 +2801,15 @@ a.server-port:hover { color: var(--accent); text-decoration: underline; }
2800
2801
  /* Offsets subtract --border-w: absolute positioning anchors to the
2801
2802
  padding-edge (inside the border), so a user bubble's 1px border would
2802
2803
  otherwise shave 1px off each stripe edge. */
2804
+ /* Stripe hugs the column (1rem into the left gutter); absolute, so it consumes no layout width —
2805
+ which is why the gutters can be symmetric (no asymmetric padding needed to "make room"), and
2806
+ thus why breakouts need no nudge. - var(--border-w): a user bubble's 1px border pushes the
2807
+ padding edge (the abs-pos anchor) 1px right, so without it that stripe sits 1px right of the
2808
+ assistant bubbles' — compensate. */
2803
2809
  left: calc(-1rem - var(--border-w));
2804
2810
  top: calc(-.5rem - var(--border-w));
2805
2811
  bottom: calc(-.5rem - var(--border-w));
2806
- width: 2px;
2812
+ width: 1px;
2807
2813
  background: var(--turn-color, transparent);
2808
2814
  }
2809
2815
  /* Clip stripe at turn boundaries. A user bubble always starts a turn → no
@@ -2875,20 +2881,24 @@ a.server-port:hover { color: var(--accent); text-decoration: underline; }
2875
2881
  .md table { border-collapse: collapse; }
2876
2882
  .md th, .md td { border: 1px solid var(--border); padding: .3rem .55rem; }
2877
2883
 
2878
- /* Full-lane breakout a mermaid diagram (the whole element) and a SPREAD bulb's iframe step
2879
- out of the narrow prose column to the transcript width so wide content (a flowchart, a data
2880
- table) gets room instead of being squeezed. The bulb's *wrapper* never breaks outonly
2881
- its iframe does (see `.bulb-embed.spread > iframe` below), so the wrapper and the controls
2882
- anchored to it stay put in the prose column; the geometry here is the shared lane the iframe
2883
- reuses. Same lane width, same off-centre nudge (the messages gutter is 1rem wider on the left
2884
- for the turn stripe, so a plain centre would sit right-of-centre). position + z-index:0 lift
2885
- the box above the turn stripe (.bubble::before) the breakout crosses — it's later in tree order
2886
- but below later-in-tree pills; the mermaid SVG is transparent so a bg backs it, the bulb's
2887
- iframe is opaque so it occludes the stripe itself. */
2884
+ /* The full-lane breakout geometry, defined ONCE and shared by the two breakouts (the mermaid
2885
+ embed and a spread bulb). `100%` in --lane-ml resolves against each user's own containing block
2886
+ (prose width) at point of use, so both centre on the column axiswhich is the viewport centre,
2887
+ since the gutters are symmetric. One home so the geometry can't drift between the two (the bug
2888
+ that let an off-centre nudge survive in one rule after being removed from the other). */
2889
+ .md { --lane-w: calc(100vw - 2rem); --lane-ml: calc((100% - var(--lane-w)) / 2); }
2890
+
2891
+ /* Full-lane breakout the mermaid embed (whole element) and a SPREAD bulb's iframe step out of
2892
+ the prose column to the transcript width so wide content gets room. Both use --lane-w/--lane-ml
2893
+ and extend symmetrically from the column, which is viewport-centred (symmetric gutters), so
2894
+ neither needs an off-centre nudge (see Invariants in Specs-Bulbs/Claude-Bulb/Claude-Bulb.md). A
2895
+ bulb's *wrapper* never breaks out — only its inner surface does — so the wrapper and its controls
2896
+ stay at prose-right. position + z-index:0 lift the box over the turn stripe it crosses; the
2897
+ mermaid SVG is transparent so a bg backs it, the bulb iframe is opaque so it occludes the stripe. */
2888
2898
  .md .mermaid {
2889
- width: calc(100vw - 2rem);
2899
+ width: var(--lane-w);
2890
2900
  margin: .6rem 0;
2891
- margin-left: calc((100% - (100vw - 2rem)) / 2 - .5rem);
2901
+ margin-left: var(--lane-ml);
2892
2902
  margin-right: auto;
2893
2903
  position: relative;
2894
2904
  z-index: 0;
@@ -2956,17 +2966,16 @@ a.server-port:hover { color: var(--accent); text-decoration: underline; }
2956
2966
  code toggle hides it via .code-open rather than unmounting, so the bulb keeps its state. */
2957
2967
  .bulb-frame { display: contents; }
2958
2968
  .md .bulb-embed.code-open .bulb-frame { display: none; }
2959
- /* Spread: the inner surface — the live iframe OR the code view behind the toggle, whichever is
2960
- shown — breaks out to the full lane, while the wrapper stays in the prose column (so the
2961
- controls anchored to it hold at prose-right, not the lane's hard-right edge). Spread is an
2962
- embed-level state, so both surfaces honour it. Same lane geometry as `.mermaid` above; 100%
2963
- here resolves against the prose-width wrapper. `width !important` beats createBulbFrame's
2964
- inline `width:100%` on the iframe (harmless on the code view, which has no inline width); both
2965
- are opaque, so position/z-index:0 lift them over the turn stripe they now cross. */
2969
+ /* Spread: the inner surface (live iframe, or the code view behind the toggle) breaks out to the
2970
+ lane while the wrapper stays in the prose column, so the controls hold at prose-right. Shares the
2971
+ --lane-* geometry; centred on the column axis so toggling spread doesn't shift a column-fitting
2972
+ bulb sideways. `width !important` beats createBulbFrame's inline width:100% on the iframe
2973
+ (harmless on the code view, which has none); both opaque, so position/z-index:0 lift them over
2974
+ the turn stripe they now cross. */
2966
2975
  .md .bulb-embed.spread iframe,
2967
2976
  .md .bulb-embed.spread > .bulb-code {
2968
- width: calc(100vw - 2rem) !important;
2969
- margin-left: calc((100% - (100vw - 2rem)) / 2 - .5rem);
2977
+ width: var(--lane-w) !important;
2978
+ margin-left: var(--lane-ml);
2970
2979
  margin-right: auto;
2971
2980
  position: relative;
2972
2981
  z-index: 0;
@@ -3256,7 +3265,7 @@ a.server-port:hover { color: var(--accent); text-decoration: underline; }
3256
3265
  "beautiful-mermaid": "^1.1.3",
3257
3266
  "dompurify": "^3.2.6",
3258
3267
  "highlight.js": "^11.10.0",
3259
- "typebulb": "^0.10.2"
3268
+ "typebulb": "^0.10.3"
3260
3269
  }
3261
3270
  }
3262
3271
  ```
package/dist/index.js CHANGED
@@ -668,6 +668,6 @@ ${r.trim()}
668
668
  `)}catch(f){console.error("Compile error:",f)}}),F=vt({bulbPath:r,emitter:u}),n){let{name:f,serveDir:b}=n;L=Fn({dir:b,onChange:()=>{console.log(`Local package '${f}' changed. Browser reloading...
669
669
  `),a.emit("reload")}})}}e.open&&await it(g);let _=async()=>{console.log(`
670
670
  Shutting down...`),h.close(),F?.(),L?.(),i(),await qt(process.pid);let u=ve.join(ve.dirname(r),".typebulb","server.mjs");await Bn.rm(u,{force:!0}).catch(()=>{}),process.exit(0)};process.on("SIGINT",_),process.on("SIGTERM",_)}import*as Un from"path";import{EventEmitter as Mo}from"events";async function Wn(r,e,t,n,s){let o=ge(t),i=!1,a=async()=>{let{bulb:c,config:l}=await W(r);i||(mt(o,r,c.server),i=!0),await Nt(c.server,s,n,l.dependencies)};if(console.log(`Running ${Un.basename(r)}...`),await a(),e){console.log(`Watching for changes...
671
- `);let c=new Mo;c.on("reload",async()=>{try{console.log("Re-running..."),await a()}catch(l){console.error("Error:",l)}}),vt({bulbPath:r,emitter:c})}}var Jn="0.10.2";async function jo(){let r=ur(process.argv.slice(2));if(r.version&&(console.log(`typebulb ${Jn}`),process.exit(0)),r.help&&(pr(),process.exit(0)),r.subcommand==="logs"){await _n(r.file||void 0,{follow:r.follow,lines:r.lines});return}if(r.subcommand==="stop"){await Cn(r.file||void 0);return}if(r.subcommand==="skill"){await Pn(Jn);return}if(r.subcommand==="models"){await wn(r.mode);return}if(r.subcommand==="agent"){if(!r.agentTarget){await gn();return}me(r.agentTarget)||(console.error(`Unknown agent '${r.agentTarget}'. Known: ${Wt().join(", ")}.`),process.exit(1));let l=await zt(process.cwd(),r.agentTarget);if(l){console.log(`Viewer '${r.agentTarget}' is already running for this project:
671
+ `);let c=new Mo;c.on("reload",async()=>{try{console.log("Re-running..."),await a()}catch(l){console.error("Error:",l)}}),vt({bulbPath:r,emitter:c})}}var Jn="0.10.3";async function jo(){let r=ur(process.argv.slice(2));if(r.version&&(console.log(`typebulb ${Jn}`),process.exit(0)),r.help&&(pr(),process.exit(0)),r.subcommand==="logs"){await _n(r.file||void 0,{follow:r.follow,lines:r.lines});return}if(r.subcommand==="stop"){await Cn(r.file||void 0);return}if(r.subcommand==="skill"){await Pn(Jn);return}if(r.subcommand==="models"){await wn(r.mode);return}if(r.subcommand==="agent"){if(!r.agentTarget){await gn();return}me(r.agentTarget)||(console.error(`Unknown agent '${r.agentTarget}'. Known: ${Wt().join(", ")}.`),process.exit(1));let l=await zt(process.cwd(),r.agentTarget);if(l){console.log(`Viewer '${r.agentTarget}' is already running for this project:
672
672
  ${l.url}`),r.open&&await it(l.url);return}r.file=r.agentTarget,r.subcommand="run"}if(r.subcommand==="trust"||r.subcommand==="untrust"){await on(r.file||void 0,r.subcommand==="trust");return}let e,t=!1;if(!r.file||r.file==="."){let l=await Hr(process.cwd());l||(console.error("No .bulb.md file found in current directory"),process.exit(1)),e=l}else e=q.resolve(r.file);if(!await Vn.access(e).then(()=>!0,()=>!1)){let l=r.agentTarget?me(r.file):void 0;l?(e=l,t=!0):Wt().includes(r.file)?(console.error(`To open the ${r.file} agent viewer, 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 s=r.file&&r.file!=="."?r.file:q.relative(process.cwd(),e)||q.basename(e),o=`npx typebulb --trust ${s.includes(" ")?`"${s}"`:s}`;if(r.subcommand==="predict"){await sn(e,o);return}if(t)r.trust=!r.noTrust,r.trust&&console.log("trust: granted (built-in bulb)");else{let l=!r.noTrust&&ot(e);l&&!r.trust&&console.log("trust: granted from memory (run `typebulb untrust` to revoke)"),r.trust=r.noTrust?!1:r.trust||l}let i;try{i=await W(e)}catch{}let a;if(r.local){i&&!(r.local.name in(i.config.dependencies??{}))&&(console.error(`--replace: '${r.local.name}' is not a dependency in this bulb's config.json; nothing to replace.`),process.exit(1)),i&&(!i.bulb.code||r.server)&&console.warn("warning: --replace has no effect in server mode (the override is client-only).");try{a=await lr(r.local)}catch(l){console.error(l instanceof Error?l.message:String(l)),process.exit(1)}console.log(`replace: ${a.name} \u2192 ${q.relative(process.cwd(),a.dir)||"."}`)}if(r.subcommand==="check"){await nn(e,a);return}let c=t?process.cwd():q.dirname(e);if(i&&i.bulb.server&&(!i.bulb.code||r.server)){r.trust||(console.error(`This bulb runs server-side Node code (server.ts), which --trust must authorize:
673
673
  ${o}`),process.exit(1)),await Wn(e,r.watch,r.mode,a,c);return}await Ln(e,r,o,a,c)}jo().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.10.2",
3
+ "version": "0.10.3",
4
4
  "description": "Local bulb runner CLI for Typebulb",
5
5
  "license": "MIT",
6
6
  "engines": { "node": ">=18" },