typebulb 0.11.1 → 0.11.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.
@@ -549,6 +549,11 @@ a.server-port:hover { color: var(--accent); text-decoration: underline; }
549
549
  }
550
550
  .md table { border-collapse: collapse; }
551
551
  .md th, .md td { border: 1px solid var(--border); padding: .3rem .55rem; }
552
+ /* A faint header band breaks the grid's monotony and gives the table a head/body structure — tonal
553
+ (`--panel`, the same neutral the pills use), never a hue, so it reads as structure not opinion and
554
+ follows the host light/dark theme. The header text stays `--fg`: weight + the fill carry it, a tint
555
+ would be the opinionated bit. Left-align headers to sit with the body cells. */
556
+ .md th { background: var(--panel); font-weight: 600; text-align: left; }
552
557
 
553
558
  /* The full-lane breakout geometry, defined ONCE and shared by the two breakouts (the mermaid
554
559
  embed and a spread bulb). `100%` in --lane-ml resolves against each user's own containing block
@@ -599,15 +604,52 @@ a.server-port:hover { color: var(--accent); text-decoration: underline; }
599
604
  .md .svg-embed { justify-content: center; }
600
605
  .md .svg-embed svg { max-width: 100%; height: auto; }
601
606
 
607
+ /* Markdown tables: chop in-column (the `.embed` rule below) and `safe center` — a table that fits its
608
+ box centres, and one that overflows falls back to left so it scrolls from its first column rather than
609
+ clipping. Centring holds in both modes: a small in-column table sits centred in the prose column, a
610
+ spread one centred in the lane. The scroll lives on the inner `.table-scroll`, not the `.embed`
611
+ wrapper, so a horizontal scrollbar rides above the chop's bottom padding instead of flush against the
612
+ next line (a scrollbar sits at its own container's bottom edge). It's the centred flex child, capped at
613
+ the box so it shrinks-to-fit and scrolls only what overflows; `max-width:100%` + the overflow-induced
614
+ 0 min-width let it shrink below the table's natural width. `spread` widens the wrapper to the lane (the
615
+ mermaid geometry) for a table fitTableEmbeds found too wide for the column. The opaque `.embed`
616
+ padding/z-index still occludes the turn stripe the spread crosses — no box-shadow needed. */
617
+ .md .table-embed { justify-content: safe center; }
618
+ .md .table-embed .table-scroll { overflow-x: auto; max-width: 100%; }
619
+ /* max-content keeps the table at its natural (unwrapped) width so it overflows `.table-scroll` and earns
620
+ a scrollbar, rather than wrapping its cells to fit — the bar is the point, and it now rides inside the
621
+ chop padding. */
622
+ /* Two ceilings work together so a prose-heavy table neither scrolls forever nor squashes to mush:
623
+ - per-column (the cell `max-width` — in an auto-layout table every cell in a column shares one width,
624
+ so a cell cap *is* a column cap): no single column hogs; long text wraps at a readable measure.
625
+ - whole-table (`max-width: var(--lane-w)`): the table never grows past the lane, so when columns don't
626
+ all fit, the browser's auto-layout *shares* the lane among them — wrapping each to its slice rather
627
+ than scrolling. It only scrolls once even longest-word-only columns can't fit the lane (genuinely too
628
+ many columns). `width: max-content` is still the *preferred* width, so a small table stays natural
629
+ and a wide one spreads; the lane cap just bounds the worst case. The floor lever (a per-cell
630
+ `min-width`) — turn squash into scroll past some readable minimum — is deliberately left off until a
631
+ real table needs it. `word-break: normal` resets the global `.md { word-break: break-word }` (which
632
+ behaves like overflow-wrap:anywhere): left inherited, that global lets the lane cap squeeze a column
633
+ below its longest word and snap it mid-character ("status" → "statu·s"). Reset to word-boundary
634
+ wrapping so each column floors at its longest whole word and a too-tight table scrolls instead of
635
+ shattering text; a pathological no-space token (a long URL) then scrolls rather than breaking. */
636
+ .md .table-embed table { margin: 0; width: max-content; max-width: var(--lane-w); }
637
+ .md .table-embed th, .md .table-embed td { max-width: 40ch; word-break: normal; }
638
+ .md .table-embed.spread {
639
+ width: var(--lane-w);
640
+ margin-left: var(--lane-ml);
641
+ margin-right: auto;
642
+ }
643
+
602
644
  /* ````bulb```` embeds: a sandboxed nested app. createBulbFrame owns the iframe (auto-height,
603
645
  borderless). No frame of our own — like the mermaid/svg embeds, it sits in the flow rather
604
646
  than in a box, so it reads as part of the transcript; the rounded clip just tidies the corners
605
- of a bulb that paints its own background. `inline` (default) keeps it in the prose column and
647
+ of a bulb that paints its own background. `fit` (default) keeps it in the prose column and
606
648
  caps its height (below); `spread` adds full-lane breakout + spacing from the shared rule above.
607
649
  position:relative anchors the controls overlay in BOTH modes (spread re-declares it for the
608
650
  z-index lift). .err is the compile-failure fallback; .bulb-err-strip is a runtime-error strip
609
651
  under a live embed (both monospace, muted red). */
610
- /* The stripe-chop, shared by every opaque in-column visual artifact (the inline bulb and a raw
652
+ /* The stripe-chop, shared by every opaque in-column visual artifact (the fit bulb and a raw
611
653
  `svg` — each opts in by carrying `.embed`). An opaque bg over position:relative + z-index:0
612
654
  paints above .bubble::before; a -1rem left extension reaches the stripe in the gutter without a
613
655
  full breakout (padding-left:1rem keeps the content in the prose column, and the box's right edge
@@ -631,7 +673,7 @@ a.server-port:hover { color: var(--accent); text-decoration: underline; }
631
673
  /* Inline (default): cap the embed's height so a tall bulb doesn't run away down the transcript.
632
674
  Past the cap the embed scrolls internally (its own overflow, set by the host↔embed protocol —
633
675
  the iframe element can't scroll its srcdoc from out here). spread removes the cap. */
634
- .md .bulb-embed.inline iframe { max-height: 80dvh; }
676
+ .md .bulb-embed.fit iframe { max-height: 80dvh; }
635
677
  /* The frame host is a layout-less wrapper (domeleon owns the node; we parent the live iframe into
636
678
  it once) — display:contents lifts the iframe to be a flex child of .bulb-embed, so the sizing and
637
679
  spread-breakout rules target it directly, exactly as when it was appended as a direct child. The
package/dist/index.js CHANGED
@@ -481,7 +481,7 @@ declare const tb: {${en}${tn}${rn}${on}${wo}${nn}${sn}
481
481
  }
482
482
  })();
483
483
  `;function wt(r){return r.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}var vt=` *, *::before, *::after { box-sizing: border-box; }
484
- body { margin: 0; font-family: system-ui, -apple-system, sans-serif; }
484
+ body { margin: 0; display: flow-root; font-family: system-ui, -apple-system, sans-serif; }
485
485
  html[data-theme="dark"] { color-scheme: dark; }
486
486
  html[data-theme="light"] { color-scheme: light; }`;function xt(r,e){let t=n=>n.replace(/<\/script/gi,"<\\/script");return` <script>
487
487
  (function() {
@@ -731,6 +731,6 @@ ${Ji}
731
731
  `);async function v(){await(await import("esbuild")).build({entryPoints:[I.join(c,"client","index.ts")],bundle:!0,platform:"browser",format:"esm",outfile:I.join(a,"client.js")});for(let T of["styles.css","index.html"])Ba(I.join(c,T),I.join(a,T))}let $;if(r.watch&&n){let E=Ma(c),T=!1;$=Ut({dir:E?c:a,onChange:async()=>{if(!T){T=!0;try{E&&await v(),console.log(`Viewer rebuilt. Browser reloading...
732
732
  `),n.emit("reload")}catch(p){console.error("Viewer rebuild failed:",p instanceof Error?p.message:p)}finally{T=!1}}}})}r.open&&await Pe(g);let O=async()=>{console.log(`
733
733
  Shutting down...`),m.close(),$?.(),t(),await Ze(process.pid),process.exit(0)};process.on("SIGINT",O),process.on("SIGTERM",O)}import*as Vs from"path";import{EventEmitter as Na}from"events";async function zs(r,e,t,n,s){let o=ne(t),i=!1,a=async()=>{let{bulb:c,config:l}=await G(r);i||(_e(o,r,c.server),i=!0),await dr(c.server,s,n,l.dependencies)};if(console.log(`Running ${Vs.basename(r)}...`),await a(),e){console.log(`Watching for changes...
734
- `);let c=new Na;c.on("reload",async()=>{try{console.log("Re-running..."),await a()}catch(l){console.error("Error:",l)}}),Lt({bulbPath:r,emitter:c})}}var qs="0.11.1";async function La(){let r=Vr(process.argv.slice(2));if(r.version&&(console.log(`typebulb ${qs}`),process.exit(0)),r.help&&(zr(),process.exit(0)),r.subcommand==="logs"){await rs(r.file||void 0,{follow:r.follow,lines:r.lines});return}if(r.subcommand==="stop"){r.all?await ss():await ns(r.file||void 0);return}if(r.subcommand==="skill"){await Qn(qs);return}if(r.subcommand==="models"){await Kn(r.mode);return}if(r.subcommand==="agent"){if(!r.agentTarget){await Vn();return}_n(r.agentTarget)||(console.error(`Unknown agent '${r.agentTarget}'. Known: ${hr().join(", ")}.`),process.exit(1));let l=await br(process.cwd(),r.agentTarget);if(l){console.log(`Viewer '${r.agentTarget}' is already running for this project:
734
+ `);let c=new Na;c.on("reload",async()=>{try{console.log("Re-running..."),await a()}catch(l){console.error("Error:",l)}}),Lt({bulbPath:r,emitter:c})}}var qs="0.11.3";async function La(){let r=Vr(process.argv.slice(2));if(r.version&&(console.log(`typebulb ${qs}`),process.exit(0)),r.help&&(zr(),process.exit(0)),r.subcommand==="logs"){await rs(r.file||void 0,{follow:r.follow,lines:r.lines});return}if(r.subcommand==="stop"){r.all?await ss():await ns(r.file||void 0);return}if(r.subcommand==="skill"){await Qn(qs);return}if(r.subcommand==="models"){await Kn(r.mode);return}if(r.subcommand==="agent"){if(!r.agentTarget){await Vn();return}_n(r.agentTarget)||(console.error(`Unknown agent '${r.agentTarget}'. Known: ${hr().join(", ")}.`),process.exit(1));let l=await br(process.cwd(),r.agentTarget);if(l){console.log(`Viewer '${r.agentTarget}' is already running for this project:
735
735
  ${l.url}`),r.open&&await Pe(l.url);return}await Hs(r);return}if(r.subcommand==="trust"||r.subcommand==="untrust"){await Fn(r.file||void 0,r.subcommand==="trust");return}let e;if(!r.file||r.file==="."){let l=await En(process.cwd());l||(console.error("No .bulb.md file found in current directory"),process.exit(1)),e=l}else e=X.resolve(r.file);await Gs.access(e).then(()=>!0,()=>!1)||(hr().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 n=r.file&&r.file!=="."?r.file:X.relative(process.cwd(),e)||X.basename(e),s=`npx typebulb --trust ${n.includes(" ")?`"${n}"`:n}`;if(r.subcommand==="predict"){await Mn(e,s);return}let o=!r.noTrust&&le(e);o&&!r.trust&&console.log("trust: granted from memory (run `typebulb untrust` to revoke)"),r.trust=r.noTrust?!1:r.trust||o;let i;try{i=await G(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 Jr(r.local)}catch(l){console.error(l instanceof Error?l.message:String(l)),process.exit(1)}console.log(`replace: ${a.name} \u2192 ${X.relative(process.cwd(),a.dir)||"."}`)}if(r.subcommand==="check"){await Bn(e,a);return}let c=X.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:
736
736
  ${s}`),process.exit(1)),await zs(e,r.watch,r.mode,a,c);return}await ms(e,r,s,a,c)}La().catch(r=>{console.error("Error:",r.message),process.exit(1)});
package/dist/render.js CHANGED
@@ -345,7 +345,7 @@ ${s.map(({variableName:n,uniqueLocalName:i})=>` reactHotLoader.register(${n}, "
345
345
  }
346
346
  })();
347
347
  `;function ic(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}var ac=` *, *::before, *::after { box-sizing: border-box; }
348
- body { margin: 0; font-family: system-ui, -apple-system, sans-serif; }
348
+ body { margin: 0; display: flow-root; font-family: system-ui, -apple-system, sans-serif; }
349
349
  html[data-theme="dark"] { color-scheme: dark; }
350
350
  html[data-theme="light"] { color-scheme: light; }`;function cc(e,t){let s=n=>n.replace(/<\/script/gi,"<\\/script");return` <script>
351
351
  (function() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "typebulb",
3
- "version": "0.11.1",
3
+ "version": "0.11.3",
4
4
  "description": "Local bulb runner CLI for Typebulb",
5
5
  "license": "MIT",
6
6
  "engines": { "node": ">=18" },