typebulb 0.9.8 → 0.10.0

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
@@ -1,8 +1,8 @@
1
1
  # typebulb
2
2
 
3
- Run single-file markdown apps that execute in many execution contexts:
3
+ Run single-file markdown apps that run in many contexts:
4
4
 
5
- 1. Localhost in your browser and in `nodejs`, which can talk via a secure bridge.
5
+ 1. Localhost in your browser and optionally in `nodejs`, which can talk via a secure bridge.
6
6
  2. Embedded in agent messages when viewed with `npx typebulb agent:claude`.
7
7
  3. Published on [typebulb.com](https://typebulb.com) or edited in its online IDE. See [FAQ](https://typebulb.com/faq).
8
8
 
@@ -10,7 +10,7 @@ Run single-file markdown apps that execute in many execution contexts:
10
10
 
11
11
  A `.bulb.md` file bundles code, styles, data, and config in one file.
12
12
 
13
- >The latter part of this document is primarily targeted at LLM agents, so that they can successfully write and execute bulbs with the typebulb CLI. This readme therefore doubles as a skill document.
13
+ >This document doubles as a skill: it is written so an LLM agent can read it and successfully write and run bulbs with the typebulb CLI.
14
14
 
15
15
  ## Features
16
16
 
@@ -27,22 +27,7 @@ A `.bulb.md` file bundles code, styles, data, and config in one file.
27
27
  - **AI calls** — `tb.ai()` for general-purpose AI (chatbots, agents, experiments). `tb.models()` lists available models. Set API keys in `.env` (see below). Requires `--trust`.
28
28
  - **Sandboxed by default** — A plain `npx typebulb my-app.bulb.md` runs with no filesystem or `server.ts` (like typebulb.com); `--trust` grants those for a run. Trust is **remembered**: `typebulb trust <file>` elevates a bulb once so later plain runs are trusted, `untrust` revokes it, and `--no-trust` forces sandboxed for a single run.
29
29
  - **Predict trust** — `typebulb predict <file>` reports the capability a bulb will likely need (fs / AI / `server.ts`) without running it, so you can decide on `--trust` up front rather than after a mid-run permission failure.
30
- - **Agent session viewer** — `typebulb agent:claude` opens the Typebulb agent viewer, a browser view over a Claude Code session that renders embedded bulbs, KaTeX, and mermaid live inline, plus runs/stops project bulbs (see [Claude](#claude)). `typebulb agent` (no target) prints this README as a skill on stdout and reports the running viewer on stderr (exit 0/1) the one command an agent runs cold.
31
-
32
- ## Claude
33
-
34
- If the user has Claude Code, consider running `npx typebulb agent:claude`. You can call `npx typebulb agent` to:
35
-
36
- * determine if it's already running (its stderr reports the running agent viewer, its exit code 0/1 says whether one is up).
37
- * get a dump of this readme in skill format.
38
-
39
- This gives the user a great scratchpad experience:
40
-
41
- * a view over any Claude Code Session, where assistant messages containing bulbs are rendered as sandboxed embedded bulbs inline in the conversation, as well as KaTeX math and mermaid diagrams.
42
- * the ability to run and stop any bulb in their project.
43
- * the ability to promote any embedded bulb to a bulb.md file in the typebulbs folder.
44
-
45
- One hitch: this will open a browser window, but not within VS Code, so the experience is poorly integrated. However there's a workaround: the user can click on the localhost link you give them, and it will open in VS Code. So to avoid the browser opening initially, use the `--no-open` flag.
30
+ - **Agent viewer** — `typebulb agent:claude` opens the agent viewer, a browser view over a Claude Code session that renders embedded bulbs, KaTeX, and mermaid live inline, plus runs/stops local bulbs (see [Claude](#claude)). `typebulb agent` (no target) is the first command an agent runs: it tells the agent how to show a bulb inline or build one locally. `typebulb skill` prints this whole README as an Agent Skill the agent can read and save.
46
31
 
47
32
  ## Quick Start
48
33
 
@@ -132,8 +117,9 @@ npm install -g typebulb
132
117
 
133
118
  ```
134
119
  typebulb [file.bulb.md] Run a bulb (defaults to .bulb.md in cwd)
135
- typebulb agent:claude Open the built-in agent session viewer
136
- typebulb agent Print the bulb-authoring skill to stdout; running viewer on stderr
120
+ typebulb agent:claude Open the agent viewer (a Claude Code session)
121
+ typebulb agent Start here how to show a bulb inline or build one locally
122
+ typebulb skill Print this README as an Agent Skill on stdout
137
123
  typebulb check [file.bulb.md] Type-check a bulb without running it
138
124
  typebulb predict [file] Report the capability a bulb probably needs, without running it
139
125
  typebulb logs [file|pid] Print a running bulb's captured console (-f follow, -n N tail)
@@ -192,18 +178,6 @@ const { text } = await tb.ai({
192
178
 
193
179
  Provider support varies — the level is mapped to provider-specific parameters (e.g. Anthropic's adaptive thinking, OpenAI's reasoning effort).
194
180
 
195
- ## Limitations
196
-
197
- - **Inference** — `tb.infer()` is not supported locally. Bulbs that use inference will render but cannot run inference calls. Use `tb.ai()` for programmatic AI access instead.
198
-
199
- ---
200
-
201
- ## Local or embedded?
202
-
203
- - **First, is anyone watching?** An embed only renders live when the user has the Typebulb agent viewer open; with none it shows as raw text. Run `typebulb agent`: its stderr shows `agent: claude` and it exits 0 when a viewer is up, so embed away; `agent: none` / exit 1 means go **local**. (Its stdout is this authoring skill.)
204
- - **Something to see right now, in the flow of the conversation** — a chart of some numbers, a quick simulation, an illustrative widget. → **embedded**: emit it in a `bulb` block so it renders live inline.
205
- - **A tool worth keeping** — something to reuse, run on its own, or refine over several turns. → **local**: write a `.bulb.md` file run with `npx typebulb`. An embedded block is throwaway and can't be edited in place, so it's the wrong fit for anything iterative.
206
-
207
181
  ## Blocks
208
182
 
209
183
  A bulb is a single **markdown** file — the minimum viable structure for a small sandboxed app. Its named **blocks** hold the code, plus optional styles, data, and config. Every block except `code.tsx` is optional. Mechanically, each block is a `**name**` header on its own line followed by a fenced code block, and the file opens with YAML frontmatter (`format: typebulb/v1`, `name:`).
@@ -219,17 +193,6 @@ A bulb is a single **markdown** file — the minimum viable structure for a smal
219
193
  | `**notes.md**` | Persistent context for the AI assistant, carried across conversations and clones. Not run. |
220
194
  | `**server.ts**` | Node.js code; its exports become `tb.server.<name>()` in the browser. **Local only.** |
221
195
 
222
- Extra notes:
223
-
224
- - **`data.txt` — why keep data here rather than inline in code or a prompt?** Correctness and auditability: forcing the code to *process* the data means you can verify the output, instead of trusting an LLM not to paraphrase, abridge, or distort values pasted straight into a prompt.
225
- - **`notes.md`** is useful for API docs, examples, or skills the LLM needs to author the bulb.
226
-
227
- ## Writing the code
228
-
229
- - **Mount to the container your `index.html` declares.** The corpus convention is `<div id="root"></div>` with `createRoot(document.getElementById("root")!)`.
230
- - **All imports at the top of `code.tsx`.** Bare imports (`react`, `d3`, `three`, …) auto-resolve from a CDN — no install step. Declare them in `config.json` `dependencies` anyway: that's what lets `npx typebulb check` fetch type defs (without it you get errors like `TS2875: react/jsx-runtime`) and pins versions.
231
- - **Theme-aware styling.** Style off CSS variables / `currentColor` so the bulb reads correctly in both light and dark; the host sets the theme.
232
-
233
196
  ## The `tb.*` API, by target
234
197
 
235
198
  `tb` is a pre-declared global your code can use without importing. What each call does, and where it works:
@@ -252,11 +215,29 @@ Extra notes:
252
215
 
253
216
  - **❌ (embedded):** the call throws `"not available in an embedded bulb"` — an embed is a client-only sandboxed iframe with **no persistent storage** either (`localStorage`, `IndexedDB`, cookies, same-origin Workers all fail), so keep state in memory. `tb.mode === 'embedded'` lets a bulb detect this and self-adjust.
254
217
 
255
- ## Self-testing a local bulb
218
+ ## Portability back to typebulb.com
219
+
220
+ A local `.bulb.md` can be re-imported into typebulb.com. If it has a `**server.ts**` block you'll be warned on import, since `server.ts` is only meaningful locally.
221
+
222
+ ## Claude
256
223
 
257
- To confirm a bulb works, run it, instrument with `tb.server.log(...)` (prints to the server's stdout, captured in the log — and works **even on a sandboxed bulb**), and read it back with `typebulb logs`. That's the loop to verify behaviour without asking the user to copy-paste console output. `tb.fs.write(...)` is handy for dumping large outputs.
224
+ The agent viewer currently supports Claude Code only. `npx typebulb agent:claude` gives the user a great scratchpad experience:
258
225
 
259
- ## Emitting an embedded bulb
226
+ * a view over the Claude Code session, where assistant messages containing bulbs render as sandboxed embedded bulbs inline in the conversation, alongside KaTeX math and mermaid diagrams.
227
+ * run and stop any bulb in their project.
228
+ * promote any embedded bulb to a `.bulb.md` file in the `typebulbs/` folder.
229
+
230
+ It opens a browser window outside VS Code, so start it yourself with `npx typebulb agent:claude --no-open` and give the user the localhost link to open in VS Code — don't wait for the user to run it.
231
+
232
+ To keep this skill on hand across sessions, run `npx typebulb skill` and copy its output into your skills folder (for Claude Code, `.claude/skills/typebulb/SKILL.md`) — only if the user asks.
233
+
234
+ ### When Claude should output local vs embedded bulbs
235
+
236
+ - **First, is anyone watching?** An embed only renders live when the agent viewer is open; with none it shows as raw text. `typebulb agent` tells you which case you're in. If no viewer is up and you want to show something inline, start it yourself — `npx typebulb agent:claude --no-open` — and share the link; don't make the user do it.
237
+ - **Something to see right now, in the flow of the conversation** — a chart of some numbers, a quick simulation, an illustrative widget. → **embedded**: emit it in a `bulb` block so it renders live inline.
238
+ - **A tool worth keeping** — something to reuse, run on its own, or refine over several turns. → **local**: write a `.bulb.md` file run with `npx typebulb`. An embedded block is throwaway and can't be edited in place, so it's the wrong fit for anything iterative.
239
+
240
+ ### Emitting an embedded bulb
260
241
 
261
242
  To render a bulb live inline, wrap the **entire** bulb — frontmatter and all blocks — in a fenced code block whose opening line is **four backticks immediately followed by `bulb`**, and whose closing line is four backticks. Four, not three, so the bulb's own triple-backtick code fences nest inside without prematurely closing the outer block.
262
243
 
@@ -270,14 +251,12 @@ The agent viewer turns that block into a live, sandboxed app, with a *breakout
270
251
  .wrap { margin: 0 auto; padding: 24px 16px; } /* not: margin: 24px auto */
271
252
  ```
272
253
 
273
- ## Portability back to typebulb.com
274
-
275
- A local `.bulb.md` can be re-imported into typebulb.com. If it has a `**server.ts**` block you'll be warned on import, since `server.ts` is only meaningful locally.
276
-
277
- ## Authoring details
278
-
279
- Smaller facts from the bulb authoring docs that apply to local bulbs too:
254
+ ## Tips for Agents
280
255
 
256
+ - **Self-testing a local bulb** — To confirm a bulb works, run it, instrument with `tb.server.log(...)` (prints to the server's stdout, captured in the log — and works **even on a sandboxed bulb**), and read it back with `typebulb logs`. That's the loop to verify behaviour without asking the user to copy-paste console output. `tb.fs.write(...)` is handy for dumping large outputs.
257
+ - **Mount to the container your `index.html` declares.** The corpus convention is `<div id="root"></div>` with `createRoot(document.getElementById("root")!)`.
258
+ - **All imports at the top of `code.tsx`.** Bare imports (`react`, `d3`, `three`, …) auto-resolve from a CDN — no install step. Declare them in `config.json` `dependencies` anyway: that's what lets `npx typebulb check` fetch type defs (without it you get errors like `TS2875: react/jsx-runtime`) and pins versions.
259
+ - **Theme-aware styling.** Style off CSS variables / `currentColor` so the bulb reads correctly in both light and dark; the host sets the theme.
281
260
  - **`tb.ai()` takes more than the basics** — the full shape is `tb.ai({ messages, system?, reasoning?, provider?, model?, webSearch? })` → `Promise<{ text }>` (non-streaming). `webSearch` defaults **on** in the CLI (you supply your own key); pass `webSearch: false` to turn it off.
282
261
  - **`tb.theme` drives the `html[data-theme]` attribute** — style off that selector (`html[data-theme="dark"] { … }`); don't read `tb.theme` to branch your rendering.
283
262
  - **`color-scheme` is set for you** — the host always applies `html[data-theme="dark"] { color-scheme: dark }` / `html[data-theme="light"] { color-scheme: light }` on top of your `styles.css`.
@@ -9,8 +9,7 @@ name: Claude Bulb
9
9
  import { existsSync, openSync, readSync, closeSync, statSync, readdirSync, watchFile, unwatchFile, mkdirSync, writeFileSync, readFileSync, unlinkSync } from 'fs'
10
10
  import { join } from 'path'
11
11
  import { homedir } from 'os'
12
- import { spawn } from 'child_process'
13
- import { launchBulbServer, listBulbServers, stopBulbServer, readServerLog, listBulbFiles as listProjectBulbFiles, slugifyBulbName, bulbName, isBulbTrusted, setBulbTrusted, predictBulbTrust } from 'typebulb/servers'
12
+ import { launchBulbServer, listBulbServers, stopBulbServer, readServerLog, listBulbFiles as listProjectBulbFiles, slugifyBulbName, bulbName, isBulbTrusted, setBulbTrusted, predictBulbTrust, openInEditor } from 'typebulb/servers'
14
13
 
15
14
  function errorMessage(err: unknown): string {
16
15
  return (err as Error)?.message ?? String(err)
@@ -370,19 +369,32 @@ const INTERNAL_PATTERNS = [
370
369
  /^No response requested\.?$/i,
371
370
  /^<task-notification\b/i, // harness protocol envelopes, not human-facing
372
371
  /^<system-reminder\b/i,
373
- /^<ide_[a-z_]+>[\s\S]*<\/ide_[a-z_]+>$/i, // whole IDE-injected context block (opened-file, selection, …)
374
372
  ]
375
373
  function isInternal(text: string): boolean {
376
374
  const t = text.trim()
377
375
  return !!t && INTERNAL_PATTERNS.some(p => p.test(t))
378
376
  }
379
377
 
380
- // A real user-authored text block: a `type:'text'` block surviving isInternal drops synthetic /
381
- // IDE-context blocks (e.g. <ide_opened_file>) so they're neither rendered nor mistaken for the
382
- // kickoff prompt. The string-content case (one whole block) is a plain isInternal check at the use
383
- // site; this is the array shape, shared by applyEntry (the transcript) and readPreview (the picker).
384
- function isUserTextBlock(b: ContentBlock | undefined): b is ContentBlock & { text: string } {
385
- return !!b && b.type === 'text' && typeof b.text === 'string' && !!b.text && !isInternal(b.text)
378
+ // IDE-injected context (opened-file, selection, …) the editor integration splices into the user's
379
+ // text block sometimes as the whole block, often inline beside what the user typed. Unlike the
380
+ // envelopes above it can't be anchored start-to-end, so strip the tag spans wherever they sit; what
381
+ // the user actually typed survives. A wholly-IDE block strips to '' and drops out entirely.
382
+ const IDE_CONTEXT = /<ide_[a-z_]+>[\s\S]*?<\/ide_[a-z_]+>/gi
383
+ function stripIdeContext(text: string): string {
384
+ return text.replace(IDE_CONTEXT, '')
385
+ }
386
+
387
+ // The display-ready text of a user message: IDE context stripped out, internal/synthetic noise
388
+ // reduced to ''. Empty ⇒ nothing human-authored to show. Shared by applyEntry (the transcript), the
389
+ // queued-command path, and readPreview (the picker) — so an "<ide_opened_file>" block is neither
390
+ // rendered nor mistaken for the kickoff prompt.
391
+ function cleanUserText(text: string): string {
392
+ const t = stripIdeContext(text).trim()
393
+ return t && !isInternal(t) ? t : ''
394
+ }
395
+ // Same, for an array-shaped `type:'text'` block; '' for non-text blocks.
396
+ function userTextBlock(b: ContentBlock | undefined): string {
397
+ return b?.type === 'text' && typeof b.text === 'string' ? cleanUserText(b.text) : ''
386
398
  }
387
399
 
388
400
  // Guard the per-entry dispatch: it runs inside the watchFile callback, so an
@@ -399,15 +411,15 @@ function applyEntry(entry: JsonlEntry) {
399
411
  if (entry.type === 'user') {
400
412
  const content = entry.message?.content
401
413
  if (typeof content === 'string') {
402
- if (!isInternal(content)) {
403
- s.buffer.push({ type: 'user', text: content })
404
- }
414
+ const text = cleanUserText(content)
415
+ if (text) s.buffer.push({ type: 'user', text })
405
416
  } else if (Array.isArray(content)) {
406
417
  for (const b of content) {
407
418
  if (b?.type === 'tool_result') {
408
419
  s.buffer.push({ type: 'tool_result', id: b.tool_use_id ?? '', content: toText(b.content), isError: !!b.is_error })
409
- } else if (isUserTextBlock(b)) {
410
- s.buffer.push({ type: 'user', text: b.text })
420
+ } else {
421
+ const text = userTextBlock(b)
422
+ if (text) s.buffer.push({ type: 'user', text })
411
423
  }
412
424
  }
413
425
  }
@@ -415,10 +427,8 @@ function applyEntry(entry: JsonlEntry) {
415
427
  // A message the user queued while CC was mid-turn. CC records it here, not as
416
428
  // a user turn, and never re-emits it — so without this branch it's lost from
417
429
  // the view. (Other attachment subtypes, e.g. 'selection', stay hidden.)
418
- const text = toText(entry.attachment.prompt) // string in current CC; toText also tolerates older array shapes
419
- if (text && !isInternal(text)) {
420
- s.buffer.push({ type: 'user', text })
421
- }
430
+ const text = cleanUserText(toText(entry.attachment.prompt)) // string in current CC; toText also tolerates older array shapes
431
+ if (text) s.buffer.push({ type: 'user', text })
422
432
  } else if (entry.type === 'assistant') {
423
433
  const content = entry.message?.content
424
434
  const blocks: ContentBlock[] = Array.isArray(content) ? content : []
@@ -537,11 +547,11 @@ function readPreview(file: string): string {
537
547
  const content = e.message?.content
538
548
  let extracted = ''
539
549
  if (typeof content === 'string') {
540
- if (!isInternal(content)) extracted = content
550
+ extracted = cleanUserText(content)
541
551
  } else if (Array.isArray(content)) {
542
- // Concatenate the real user-text blocks; isUserTextBlock drops synthetic/IDE-context ones so
543
- // an "<ide_opened_file>" entry isn't mistaken for the kickoff prompt — we fall through to it.
544
- extracted = content.filter(isUserTextBlock).map(b => b.text).join(' ')
552
+ // Concatenate the real user-text blocks; userTextBlock strips IDE context / drops internal
553
+ // ones so an "<ide_opened_file>" entry isn't mistaken for the kickoff prompt — we fall through.
554
+ extracted = content.map(userTextBlock).filter(Boolean).join(' ')
545
555
  }
546
556
  const cleaned = extracted.replace(/\s+/g, ' ').trim()
547
557
  // Strip the fixed reincarnation lead-in so those sessions surface their distinctive summary.
@@ -572,12 +582,9 @@ export async function attach(sessionId: string) {
572
582
  // ---- editor integration ----
573
583
 
574
584
  export async function openFile(filePath: string, line?: number) {
575
- // shell:true so Windows resolves `code.cmd`; detached+unref so the editor
576
- // doesn't tie to the bulb's lifetime. `-g file:line` jumps to a cited line.
577
- const args = line ? ['-g', `${filePath}:${line}`] : [filePath]
578
- const proc = spawn('code', args, { shell: true, detached: true, stdio: 'ignore' })
579
- proc.on('error', err => console.error('[claude-bulb] code launch failed:', err?.message ?? err))
580
- proc.unref()
585
+ // The detached spawn + editor resolution is the typebulb capability (openInEditor); the host
586
+ // owns only the policy that a relative-path citation routes here (onMarkdownClick in code.tsx).
587
+ openInEditor(filePath, line)
581
588
  return { ok: true }
582
589
  }
583
590
 
@@ -3256,7 +3263,7 @@ a.server-port:hover { color: var(--accent); text-decoration: underline; }
3256
3263
  "beautiful-mermaid": "^1.1.3",
3257
3264
  "dompurify": "^3.2.6",
3258
3265
  "highlight.js": "^11.10.0",
3259
- "typebulb": "^0.9.8"
3266
+ "typebulb": "^0.10.0"
3260
3267
  }
3261
3268
  }
3262
3269
  ```
package/dist/index.js CHANGED
@@ -1,14 +1,15 @@
1
1
  #!/usr/bin/env node
2
- import*as ge from"fs/promises";import*as S from"path";import{fileURLToPath as ao}from"url";import{spawn as co}from"child_process";import{EventEmitter as Kt}from"events";import*as Qt from"fs/promises";import{existsSync as se,readFileSync as xn}from"fs";import*as P from"path";import{pathToFileURL as Sn}from"url";import{resolve as dt}from"resolve.exports";import{init as Zt,parse as er}from"es-module-lexer";function tr(r,e){let t=P.join(r,"package.json");try{return JSON.parse(xn(t,"utf8"))}catch{throw new Error(`--replace package '${e}' has no readable package.json at ${t}`)}}var lt=["browser","import","default"],Xt=["node","import","default"];function rr(r){let e=r.indexOf("=");if(e===-1)throw new Error(`--replace must be <name>=<path> (got '${r}')`);let t=r.slice(0,e).trim(),n=r.slice(e+1).trim();if(!t)throw new Error(`--replace missing package name (got '${r}')`);if(!n)throw new Error(`--replace missing path for '${t}'`);if(t.startsWith("@"))throw new Error(`--replace does not support scoped names yet; '${t}' is scoped`);return{name:t,dir:P.resolve(n)}}async function nr(r){let{name:e,dir:t}=r;if(!se(t))throw new Error(`--replace path for '${e}' does not exist: ${t}`);let n=tr(t,e),s=Rn(n,e),o=P.resolve(t,s);if(!se(o))throw new Error(`--replace package '${e}' entry not found on disk: ${o} \u2014 did you build it (e.g. \`pnpm run build\`)?`);let i=P.dirname(o),a=`/local/${e}/${P.basename(o)}`,c=Pn(n,t);return await En(e,o,i),{name:e,dir:t,entryAbs:o,serveDir:i,entryUrl:a,typesAbs:c}}function Rn(r,e){if(r.exports!==void 0){let n;try{n=dt(r,".",{browser:!0,conditions:lt})}catch(o){throw new Error(`--replace package '${e}' "exports" does not resolve a browser entry (conditions: ${lt.join(", ")}): ${o instanceof Error?o.message:o}`)}let s=ut(n);if(!s)throw new Error(`--replace package '${e}' "exports" did not resolve "." to a single file (conditions: ${lt.join(", ")}); too complex to override.`);return s}let t=r.module??r.main;if(!t)throw new Error(`--replace package '${e}' has no "exports", "module", or "main" entry to resolve.`);return t}function Pn(r,e){if(r.exports!==void 0)try{let n=dt(r,".",{conditions:["types"]}),s=ut(n);if(s){let o=P.resolve(e,s);if(se(o))return o}}catch{}let t=r.types??r.typings;if(t){let n=P.resolve(e,t);if(se(n))return n}}function ut(r){if(typeof r=="string")return r;if(Array.isArray(r))return r.find(e=>typeof e=="string")}async function En(r,e,t){await Zt;let n=P.normalize(t),s=new Set,o=[e];for(;o.length;){let i=o.shift();if(s.has(i))continue;s.add(i);let a;try{a=await Qt.readFile(i,"utf8")}catch{continue}let c,l;try{[c,,,l]=er(a,i)}catch{continue}if(i===e&&!l)throw new Error(`override package '${r}' entry is not an ES module (no import/export syntax); CommonJS or non-module entries aren't supported (esm.sh would have to transform it).`);for(let p of c){if(p.d===-2)continue;let d=p.n;if(d&&!d.startsWith("node:")){if(d.startsWith("./")||d.startsWith("../")||d.startsWith("/")){let h=kn(i,d,n);h&&!s.has(h)&&o.push(h);continue}throw new Error(`override package must ship self-contained (bundle its dependencies); ${r} externalizes '${d}'`)}}}}function kn(r,e,t){let n=e.replace(/[?#].*$/,""),s=P.resolve(P.dirname(r),n),o=[s,s+".js",s+".mjs",P.join(s,"index.js"),P.join(s,"index.mjs")];for(let i of o)if(P.normalize(i).startsWith(t)&&se(i))return i}function Tn(r,e,t){let n=tr(r,e),s;if(n.exports!==void 0)try{s=ut(dt(n,t,{conditions:Xt}))}catch(i){throw new Error(`--replace package '${e}' "exports" does not resolve a node entry for '${t}' (conditions: ${Xt.join(", ")}): ${i instanceof Error?i.message:i}`)}else t==="."&&(s=n.main??n.module);if(!s)throw new Error(`--replace package '${e}' has no node export for '${t}'.`);let o=P.resolve(r,s);if(!se(o))throw new Error(`--replace package '${e}' built file not found: ${o} \u2014 did you build it (e.g. \`pnpm run build\`)?`);return Sn(o).href}async function sr(r,e){await Zt;let t;try{[t]=er(r)}catch{return r}let n="",s=0;for(let o of t){if(o.d!==-1)continue;let i=o.n;if(!i||i!==e.name&&!i.startsWith(e.name+"/"))continue;let a=i===e.name?".":"."+i.slice(e.name.length),c=Tn(e.dir,e.name,a);n+=r.slice(s,o.s)+c,s=o.e}return n+r.slice(s)}function or(r){let e={subcommand:"run",file:"",port:3e3,watch:!0,open:!0,server:!1,trust:!1,noTrust:!1,follow:!1,help:!1,version:!1},t=["check","predict","logs","stop","trust","untrust"],n=r[0];if(n==="agent"||n?.startsWith("agent:")){e.subcommand="agent";let s=n.indexOf(":");if(s!==-1){let o=n.slice(s+1);o&&(e.agentTarget=o)}r=r.slice(1)}else n&&t.includes(n)&&(e.subcommand=n,r=r.slice(1));for(let s=0;s<r.length;s++){let o=r[s];if(o==="--help"||o==="-h")e.help=!0;else if(o==="--version"||o==="-V")e.version=!0;else if(o==="--no-watch")e.watch=!1;else if(o==="--no-open")e.open=!1;else if(o==="--server")e.server=!0;else if(o==="--trust")e.trust=!0;else if(o==="--no-trust")e.noTrust=!0;else if(o==="--mode"){let i=r[++s];(!i||i.startsWith("-"))&&(console.error("Missing value for --mode (e.g. --mode staging)"),process.exit(1)),e.mode=i}else if(o==="--follow"||o==="-f")e.follow=!0;else if(o==="--lines"||o==="-n"){let i=parseInt(r[++s],10);(isNaN(i)||i<0)&&(console.error(`Invalid --lines value: ${r[s]}`),process.exit(1)),e.lines=i}else if(o==="--port"||o==="-p"){let i=r[++s],a=parseInt(i,10);isNaN(a)&&(console.error(`Invalid port: ${i}`),process.exit(1)),e.port=a}else if(o==="--replace"||o.startsWith("--replace=")){let i=o.startsWith("--replace=")?o.slice(10):r[++s]??"";try{let a=rr(i);if(e.local)throw new Error(`--replace can only be used once (got '${e.local.name}' and '${a.name}')`);e.local=a}catch(a){console.error(a instanceof Error?a.message:String(a)),process.exit(1)}}else o.startsWith("-")||(e.file=o)}return e}function ir(){console.log(`
2
+ import*as ge from"fs/promises";import*as S from"path";import{fileURLToPath as co}from"url";import{spawn as lo}from"child_process";import{EventEmitter as Yt}from"events";import*as Qt from"fs/promises";import{existsSync as oe,readFileSync as Sn}from"fs";import*as R from"path";import{pathToFileURL as Pn}from"url";import{resolve as dt}from"resolve.exports";import{init as Zt,parse as er}from"es-module-lexer";function tr(r,e){let t=R.join(r,"package.json");try{return JSON.parse(Sn(t,"utf8"))}catch{throw new Error(`--replace package '${e}' has no readable package.json at ${t}`)}}var lt=["browser","import","default"],Xt=["node","import","default"];function rr(r){let e=r.indexOf("=");if(e===-1)throw new Error(`--replace must be <name>=<path> (got '${r}')`);let t=r.slice(0,e).trim(),n=r.slice(e+1).trim();if(!t)throw new Error(`--replace missing package name (got '${r}')`);if(!n)throw new Error(`--replace missing path for '${t}'`);if(t.startsWith("@"))throw new Error(`--replace does not support scoped names yet; '${t}' is scoped`);return{name:t,dir:R.resolve(n)}}async function nr(r){let{name:e,dir:t}=r;if(!oe(t))throw new Error(`--replace path for '${e}' does not exist: ${t}`);let n=tr(t,e),s=Rn(n,e),o=R.resolve(t,s);if(!oe(o))throw new Error(`--replace package '${e}' entry not found on disk: ${o} \u2014 did you build it (e.g. \`pnpm run build\`)?`);let i=R.dirname(o),a=`/local/${e}/${R.basename(o)}`,c=En(n,t);return await kn(e,o,i),{name:e,dir:t,entryAbs:o,serveDir:i,entryUrl:a,typesAbs:c}}function Rn(r,e){if(r.exports!==void 0){let n;try{n=dt(r,".",{browser:!0,conditions:lt})}catch(o){throw new Error(`--replace package '${e}' "exports" does not resolve a browser entry (conditions: ${lt.join(", ")}): ${o instanceof Error?o.message:o}`)}let s=ut(n);if(!s)throw new Error(`--replace package '${e}' "exports" did not resolve "." to a single file (conditions: ${lt.join(", ")}); too complex to override.`);return s}let t=r.module??r.main;if(!t)throw new Error(`--replace package '${e}' has no "exports", "module", or "main" entry to resolve.`);return t}function En(r,e){if(r.exports!==void 0)try{let n=dt(r,".",{conditions:["types"]}),s=ut(n);if(s){let o=R.resolve(e,s);if(oe(o))return o}}catch{}let t=r.types??r.typings;if(t){let n=R.resolve(e,t);if(oe(n))return n}}function ut(r){if(typeof r=="string")return r;if(Array.isArray(r))return r.find(e=>typeof e=="string")}async function kn(r,e,t){await Zt;let n=R.normalize(t),s=new Set,o=[e];for(;o.length;){let i=o.shift();if(s.has(i))continue;s.add(i);let a;try{a=await Qt.readFile(i,"utf8")}catch{continue}let c,l;try{[c,,,l]=er(a,i)}catch{continue}if(i===e&&!l)throw new Error(`override package '${r}' entry is not an ES module (no import/export syntax); CommonJS or non-module entries aren't supported (esm.sh would have to transform it).`);for(let p of c){if(p.d===-2)continue;let d=p.n;if(d&&!d.startsWith("node:")){if(d.startsWith("./")||d.startsWith("../")||d.startsWith("/")){let h=Tn(i,d,n);h&&!s.has(h)&&o.push(h);continue}throw new Error(`override package must ship self-contained (bundle its dependencies); ${r} externalizes '${d}'`)}}}}function Tn(r,e,t){let n=e.replace(/[?#].*$/,""),s=R.resolve(R.dirname(r),n),o=[s,s+".js",s+".mjs",R.join(s,"index.js"),R.join(s,"index.mjs")];for(let i of o)if(R.normalize(i).startsWith(t)&&oe(i))return i}function _n(r,e,t){let n=tr(r,e),s;if(n.exports!==void 0)try{s=ut(dt(n,t,{conditions:Xt}))}catch(i){throw new Error(`--replace package '${e}' "exports" does not resolve a node entry for '${t}' (conditions: ${Xt.join(", ")}): ${i instanceof Error?i.message:i}`)}else t==="."&&(s=n.main??n.module);if(!s)throw new Error(`--replace package '${e}' has no node export for '${t}'.`);let o=R.resolve(r,s);if(!oe(o))throw new Error(`--replace package '${e}' built file not found: ${o} \u2014 did you build it (e.g. \`pnpm run build\`)?`);return Pn(o).href}async function sr(r,e){await Zt;let t;try{[t]=er(r)}catch{return r}let n="",s=0;for(let o of t){if(o.d!==-1)continue;let i=o.n;if(!i||i!==e.name&&!i.startsWith(e.name+"/"))continue;let a=i===e.name?".":"."+i.slice(e.name.length),c=_n(e.dir,e.name,a);n+=r.slice(s,o.s)+c,s=o.e}return n+r.slice(s)}function or(r){let e={subcommand:"run",file:"",port:3e3,watch:!0,open:!0,server:!1,trust:!1,noTrust:!1,follow:!1,help:!1,version:!1},t=["check","predict","logs","stop","trust","untrust","skill"],n=r[0];if(n==="agent"||n?.startsWith("agent:")){e.subcommand="agent";let s=n.indexOf(":");if(s!==-1){let o=n.slice(s+1);o&&(e.agentTarget=o)}r=r.slice(1)}else n&&t.includes(n)&&(e.subcommand=n,r=r.slice(1));for(let s=0;s<r.length;s++){let o=r[s];if(o==="--help"||o==="-h")e.help=!0;else if(o==="--version"||o==="-V")e.version=!0;else if(o==="--no-watch")e.watch=!1;else if(o==="--no-open")e.open=!1;else if(o==="--server")e.server=!0;else if(o==="--trust")e.trust=!0;else if(o==="--no-trust")e.noTrust=!0;else if(o==="--mode"){let i=r[++s];(!i||i.startsWith("-"))&&(console.error("Missing value for --mode (e.g. --mode staging)"),process.exit(1)),e.mode=i}else if(o==="--follow"||o==="-f")e.follow=!0;else if(o==="--lines"||o==="-n"){let i=parseInt(r[++s],10);(isNaN(i)||i<0)&&(console.error(`Invalid --lines value: ${r[s]}`),process.exit(1)),e.lines=i}else if(o==="--port"||o==="-p"){let i=r[++s],a=parseInt(i,10);isNaN(a)&&(console.error(`Invalid port: ${i}`),process.exit(1)),e.port=a}else if(o==="--replace"||o.startsWith("--replace=")){let i=o.startsWith("--replace=")?o.slice(10):r[++s]??"";try{let a=rr(i);if(e.local)throw new Error(`--replace can only be used once (got '${e.local.name}' and '${a.name}')`);e.local=a}catch(a){console.error(a instanceof Error?a.message:String(a)),process.exit(1)}}else o.startsWith("-")||(e.file=o)}return e}function ir(){console.log(`
3
3
  typebulb - Local bulb runner for Typebulb
4
4
 
5
5
  Usage:
6
6
  typebulb [file.bulb.md] Run a bulb (defaults to .bulb.md in cwd)
7
- typebulb agent Print the bulb-authoring skill (stdout) plus the
8
- running agent viewer (stderr); exit 0 if one is
9
- running, else 1. The one command an agent runs cold.
10
- typebulb agent:claude Open the Claude Code session viewer (a browser
11
- surface; 'agent:<name>' selects which agent).
7
+ typebulb agent Start here \u2014 tells the agent how to show a bulb inline
8
+ or build one locally; exit 0 if a viewer is up, else 1.
9
+ typebulb agent:claude Open the agent viewer (a browser view over a Claude
10
+ Code session; 'agent:<name>' selects which agent).
11
+ typebulb skill Print this README as an Agent Skill (stdout), for the
12
+ agent to read and copy into its own skills folder.
12
13
  typebulb check [file.bulb.md] Type-check a bulb without running it
13
14
  typebulb predict [file] Report the capability a bulb probably needs
14
15
  (fs / AI / server.ts) without running it.
@@ -82,10 +83,10 @@ Examples:
82
83
  typebulb my-editor.bulb.md
83
84
  typebulb --no-watch --port 8080 my-editor.bulb.md
84
85
  typebulb .
85
- `)}import{readFileSync as _n,existsSync as Cn}from"fs";import*as U from"path";function An(r){return[...r?[`.env.${r}.local`,`.env.${r}`]:[],".env.local",".env"]}function pt(r,e=process.cwd()){let t={},n=[];for(let s of An(r)){let o;try{o=_n(U.resolve(e,s),"utf-8")}catch{continue}n.push(s);for(let[i,a]of On(o))process.env[i]===void 0&&(process.env[i]=a,t[i]=s)}return{mode:r,sources:t,loaded:n}}function*On(r){for(let e of r.split(`
86
- `)){let t=e.trim();if(!t||t.startsWith("#"))continue;let n=t.indexOf("=");if(n===-1)continue;let s=t.slice(0,n).trim(),o=t.slice(n+1).trim();(o.startsWith('"')&&o.endsWith('"')||o.startsWith("'")&&o.endsWith("'"))&&(o=o.slice(1,-1)),yield[s,o]}}function In(r){let e=new Set,t=/process\.env\.([A-Za-z_$][\w$]*)|process\.env\[\s*['"]([^'"]+)['"]\s*\]/g;for(let n;n=t.exec(r);)e.add(n[1]??n[2]);return[...e]}function ft(r,e,t){let{sources:n,mode:s,loaded:o}=r,i=process.cwd(),a=U.dirname(e),c=`(mode: ${s??"none"})`,l=t?In(t):[],p=l.filter(m=>n[m]).map(m=>`${m} \u2190 ${n[m]}`);p.length?console.log(`env: ${p.join(", ")} ${c}`):o.length&&console.log(`env: loaded ${o.join(", ")} ${c}`),s&&!o.some(m=>m===`.env.${s}`||m===`.env.${s}.local`)&&console.log(`env: mode=${s} \u2014 no .env.${s} found; using .env`);let d=U.resolve(a)!==U.resolve(i);if(d)for(let m of[".env.local",".env"])Cn(U.join(a,m))&&console.log(`env: ${U.join(a,m)} present but not loaded (cwd is ${i})`);let h=l.filter(m=>process.env[m]===void 0);if(h.length){let m=d?` \u2014 try running from ${a}`:"";console.log(`env: server.ts reads ${h.join(", ")} but ${h.length>1?"they are":"it's"} unset${m}`)}}import*as G from"fs/promises";import*as et from"path";import{pathToFileURL as vs}from"url";var $n={code:{path:"code.tsx",language:"typescript"},css:{path:"styles.css",language:"css"},html:{path:"index.html",language:"html"},config:{path:"config.json",language:"json"},notes:{path:"notes.md",language:"markdown"},data:{path:"data.txt",language:"text"},infer:{path:"infer.md",language:"markdown"},insight:{path:"insight.json",language:"json"},server:{path:"server.ts",language:"typescript"}};function ar(r){try{let e=r.split(`
87
- `),t=0;if(e[t]?.trim()!=="---")return null;t++;let n=[];for(;t<e.length&&e[t]?.trim()!=="---";)n.push(e[t]),t++;if(e[t]?.trim()!=="---")return null;t++;let s=Dn(n);if(!s)return null;let o=new Map;for(;t<e.length;){let a=e[t]?.trim()?.match(/^\*\*(.+)\*\*$/);if(a){let c=a[1].trim();for(t++;t<e.length&&e[t]?.trim()==="";)t++;let l=e[t]?.match(/^(`{3,})(\w*)\s*$/);if(!l){t++;continue}let p=l[1];t++;let d=[];for(;t<e.length&&!e[t]?.match(new RegExp(`^${p}\\s*$`));)d.push(e[t]),t++;t++,o.set(c,d.join(`
88
- `))}else t++}return{frontmatter:s,files:o}}catch{return null}}function Dn(r){let e={};for(let t of r){let n=t.indexOf(":");if(n===-1)continue;let s=t.slice(0,n).trim(),o=t.slice(n+1).trim();switch(s){case"format":e.format=o;break;case"name":e.name=Fn(o);break}}return!e.format?.startsWith("typebulb")||!e.name?null:e}function Fn(r){return r.startsWith('"')&&r.endsWith('"')?r.slice(1,-1).replace(/\\"/g,'"'):r.startsWith("'")&&r.endsWith("'")?r.slice(1,-1):r}function cr(r){let e=t=>r.files.get($n[t].path)||"";return{name:r.frontmatter.name,code:e("code"),css:e("css"),html:e("html"),config:e("config"),notes:e("notes"),data:e("data"),infer:e("infer"),insight:e("insight"),server:e("server")}}function Mn(r){try{return JSON.parse(r),!0}catch{}return!!(/^\s*<[\s\S]*>/.test(r)||/^---\s*$/m.test(r)||/^\w[\w\s]*:[ \t]/m.test(r))}function lr(r){let e=r.trim();return e?Mn(e)?[e]:r.split(/\n\n\n+/).map(t=>t.trim()).filter(Boolean):[]}function dr(r){if(!r.trim())return{};try{return JSON.parse(r)}catch{return{}}}import{transform as jn}from"sucrase";function ht(r,e={}){let t=e.serverOnly?["typescript"]:["typescript","jsx"];try{let{code:n}=jn(r,{transforms:t,jsxRuntime:"automatic",jsxImportSource:e.jsxImportSource||"react",production:!0});return{code:n}}catch(n){return{code:"",error:String(n)}}}var ye="https://esm.sh",be="https://cdn.jsdelivr.net/npm/",mt="https://data.jsdelivr.com/v1/package/npm/";function ur(r){let e=(r||"").replace(/^\/+/,"").replace(/\/+$/,"");return e?e.split("/"):[]}var b=class r{constructor(e,t,n){let s=typeof e=="string"?r.parse(e):e;this.name=s.name,this.version=oe(t??s.version),this.subpath=oe(n??s.subpath)}static parse(e){let t=ur(e||"");if(!t.length)return new r({name:""});if(t[0].startsWith("@")){let s=t[0],[o,i]=pr(t[1]??""),a=oe(t.slice(2).join("/"));return new r({name:`${s}/${o}`,version:i,subpath:a})}else{let[s,o]=pr(t[0]),i=oe(t.slice(1).join("/"));return new r({name:s,version:o,subpath:i})}}static fromUrl(e){try{let t=new URL(e),n=new URL(ye).host,s=new URL(be).host;if(t.host===n){let o=ur(t.pathname.replace(/^\/v\d+\//,"/"));if(!o.length)return;let i=o[0].startsWith("@")?`${o[0]}/${o[1]??""}`:o[0];return r.parse(i)}if(t.host===s){let o=t.pathname.split("/npm/")[1];if(!o)return;let i=o.split("/")[0]||"";return r.parse(i)}return}catch{return}}static versionFromUrl(e){return r.fromUrl(e)?.version}format(){let e=this.version?`${this.name}@${this.version}`:this.name;return this.subpath?`${e}/${this.subpath}`:e}root(){return this.name}static rootOf(e){return r.parse(e).name}withVersion(e){return new r({name:this.name,version:oe(e),subpath:this.subpath})}withPreferredVersion(e,t){let n=e||t;return n?this.withVersion(n):this}static isBare(e){if(!e||e.startsWith(".")||e.startsWith("/"))return!1;let t=e.toLowerCase();return!t.startsWith("http://")&&!t.startsWith("https://")}},oe=r=>r&&r.length?r:void 0,pr=r=>{let e=r.indexOf("@");return e<0?[r,void 0]:[r.slice(0,e),oe(r.slice(e+1))]};async function T(r){try{return await r()}catch{return}}var ve=class{constructor(e,t){this.cache=e,this.http=t,this.esmHost=ye,this.jsDelivrBase=be,this.jsDelivrMeta=mt,this.pinMs=1e4,this.versionsIndexMs=1440*60*1e3,this.metaTtlMs=10080*60*1e3,this.pinCache=new Map}normalizeRelative(e){let t=e||"";return t.startsWith("./")?t.slice(2):t.replace(/^\/+/,"")}ensureLeadingDotSlash(e){return e.startsWith("./")?e:`./${e}`}baseDir(e){let t=typeof e=="string"?new b(e):e;return`${this.jsDelivrBase}${t.name}${t.version?`@${t.version}`:""}/`}file(e,t){return new URL(this.normalizeRelative(t),this.baseDir(e)).toString()}packageJson(e){return this.file(e,"package.json")}buildEsmUrl(e,t={}){let{target:n="es2022",bundle:s=!1,external:o}=t,i=new URLSearchParams({target:n});return s&&i.append("bundle",""),o?.length&&i.append("external",o.join(",")),`${this.esmHost}/${e}?${i.toString()}`}async pinEsmUrl(e,t="es2022"){let n=this.buildEsmUrl(e,{target:t}),s=await T(()=>this.http.head(n));return s?.ok?s.url||n:void 0}async resolveExactVersion(e){let t=Date.now(),n=this.pinCache.get(e);if(n&&t-n.ts<this.pinMs)return n.value;let s=await this.tryResolveFromUrls([this.buildEsmUrl(e),`${this.esmHost}/${e}`]);return this.pinCache.set(e,{value:s,ts:t}),s}async tryResolveFromUrls(e){for(let t of e){let n=await T(()=>this.http.head(t)),s=this.parseVersionFromUrl(n?.url||t);if(s)return s}}async fetchVersionsIndex(e){if(await this.cache.isNegative(e))return;let t=await this.cache.getIndex(e);if(t&&Date.now()-t.updatedAt<this.versionsIndexMs)return{versions:t.versions,distTags:t.distTags};let n=await T(()=>this.http.getJson(`${this.jsDelivrMeta}${encodeURIComponent(e)}`));if(!n?.versions?.length){await this.cache.recordNegative(e);return}await this.cache.clearNegative(e);let s=n.distTags&&Object.keys(n.distTags).length?n.distTags:void 0;return await this.cache.setIndex(e,n.versions,s),n}parseVersionFromUrl(e){let t=b.fromUrl(e)?.version;return t&&/\d+\.\d+\.\d+/.test(t)?t:void 0}async fetchPackageMeta(e,t){let n=await this.cache.getMeta(e,t);if(n&&Date.now()-n.updatedAt<this.metaTtlMs){let{dependencies:p,peerDependencies:d,peerDependenciesMeta:h}=n;return{name:e,version:t,dependencies:p,peerDependencies:d,peerDependenciesMeta:h}}let s=this.packageJson(new b(`${e}@${t}`)),o=await T(()=>this.http.getJson(s));if(!o)return;let i=p=>p&&Object.keys(p).length?p:void 0,a=i(o.dependencies),c=i(o.peerDependencies),l=i(o.peerDependenciesMeta);return await this.cache.setMeta(e,t,a,c,l),{name:e,version:t,dependencies:a,peerDependencies:c,peerDependenciesMeta:l}}};var fr=r=>r.startsWith("@types/"),we=r=>Object.keys(r?.peerDependencies||{}).filter(e=>!fr(e)),gt=r=>Object.keys(r?.dependencies||{}).filter(e=>!fr(e)),Nn=r=>we(r).filter(e=>!r?.peerDependenciesMeta?.[e]?.optional),xe=class{constructor(e){this.cdn=e}async resolve(e,t){let n=await this.fetchMeta(e),{allRoots:s,autoAddedPeers:o}=await this.expandWithPeers(n,t),i=this.computeFlags(s);return{allRoots:s,flags:i,autoAddedPeers:o}}async fetchMeta(e){return Promise.all(e.map(async({name:t,version:n})=>({name:t,version:n,meta:await this.cdn.fetchPackageMeta(t,n)})))}async expandWithPeers(e,t){let n=new Map(e.map(o=>[o.name,o])),s=[];for(let o of e)for(let i of Nn(o.meta))!n.has(i)&&!s.some(a=>a.name===i)&&s.push({name:i,requiredBy:o.name});for(let{name:o,requiredBy:i}of s)try{let a=await t(o),c=await this.cdn.fetchPackageMeta(o,a);n.set(o,{name:o,version:a,meta:c})}catch(a){console.warn(`[typebulb] Failed to resolve peer "${o}" for "${i}":`,a)}return{allRoots:[...n.values()],autoAddedPeers:s.filter(o=>n.has(o.name))}}computeFlags(e){let t=new Set(e.flatMap(o=>we(o.meta))),n=new Map;for(let o of e)for(let i of gt(o.meta))n.set(i,(n.get(i)||0)+1);let s=new Set([...n.entries()].filter(([,o])=>o>=2).map(([o])=>o));return new Map(e.map(o=>[o.name,{isPeerRoot:t.has(o.name),hasPeers:we(o.meta).length>0,isSharedDep:s.has(o.name)}]))}};var Se=class{constructor(e,t,n){this.cache=e,this.cdn=t,this.semver=n}selectVersionFromIndex(e,t,n){return this.semver.selectBestVersion(e,{range:t,distTags:n})}async learnExactVersion(e){let t=await T(()=>this.cdn.fetchVersionsIndex(e));if(t?.versions?.length){let n=this.semver.selectBestVersion(t.versions,{distTags:t.distTags});if(n)return n}return this.cdn.resolveExactVersion(e)}async resolveExactForRoot(e,t){if(!t)return this.learnExactVersion(e);let n=await this.cache.getPinnedExact(e,t);if(n){if(this.semver.isExactVersion(n))return n;console.warn("[versionResolver] Rejecting invalid cached version for",e,":",n)}let s=await T(()=>this.cdn.fetchVersionsIndex(e));if(s?.versions?.length){let i=this.selectVersionFromIndex(s.versions,t,s.distTags);if(i){if(this.semver.isExactVersion(i))return await this.cache.setPinnedExact(e,t,i),i}else{console.warn("[versionResolver] Invalidating stale versions cache for",e,"- range",t,"not satisfied"),await this.cache.invalidateVersionsCache(e);let a=await T(()=>this.cdn.fetchVersionsIndex(e));if(a?.versions?.length){let c=this.selectVersionFromIndex(a.versions,t,a.distTags);if(c&&this.semver.isExactVersion(c))return await this.cache.setPinnedExact(e,t,c),c}}}let o=await this.cdn.resolveExactVersion(`${e}@${t}`);if(o&&this.semver.isExactVersion(o))return await this.cache.setPinnedExact(e,t,o),o}async effectivePackage(e,t){let n=new b(e),s=n.root(),o=t[s],i=o?await T(()=>this.cache.getPinnedExact(s,o))??await T(()=>this.resolveExactForRoot(s,o)):void 0;return{effectivePackage:i?n.withVersion(i).format():e,root:s,range:o,pinned:i}}};import{init as Ln,parse as Bn}from"es-module-lexer";var ie=class r{constructor(e,t,n,s){this.version=e,this.cdn=t,this.peer=n,this.cache=s}extractImportsSync(e){let t=new Set;for(let n of r.importPatterns){n.lastIndex=0;for(let s of e.matchAll(n))b.isBare(s[1])&&t.add(s[1])}return Array.from(t)}async extractImports(e){let t=new Set,n=s=>{b.isBare(s)&&t.add(s)};try{await Ln;let[s]=Bn(e);s.forEach(o=>n(e.slice(o.s,o.e).trim()))}catch{return this.extractImportsSync(e)}return Array.from(t)}async buildImportMap(e,t,n){let s=(await this.extractImports(e)).filter(d=>!n?.has(b.rootOf(d))),o=[...new Set(s.map(b.rootOf))],i=await Promise.all(o.map(async d=>({name:d,version:await this.resolveVersion(d,t)}))),{allRoots:a,flags:c,autoAddedPeers:l}=await this.peer.resolve(i,d=>this.resolveVersion(d,t)),p=this.buildEntries([...s,...l.map(d=>d.name)],a,c,t);return{importMap:{imports:Object.fromEntries(p)},prefetchUrls:p.map(([,d])=>d)}}async resolveVersion(e,t){let n=t[e],s=n?`${e}@${n}`:e,o=await this.version.resolveExactForRoot(e,n);if(!o){let i=await T(()=>this.cdn.pinEsmUrl(s));if(!i)throw new Error(`Cannot resolve ${s}: no matching version is published (the package or version may not exist, or the registry was unreachable).`);o=b.versionFromUrl(i),o&&n&&await T(()=>this.cache.setPinnedExact(e,n,o))}if(!o)throw new Error(`Cannot resolve ${s}: no concrete version found.`);return o}buildEntries(e,t,n,s){let o=new Map(t.map(g=>[g.name,g])),i=g=>{let R=o.get(b.rootOf(g));return new b(g).withPreferredVersion(R.version,s[R.name]).format()},a=new Set([...n.entries()].filter(([,g])=>g.isPeerRoot||g.isSharedDep).map(([g])=>g)),c=new Set(e.filter(g=>g!==b.rootOf(g)).map(b.rootOf)),l=[],p=new Set,d=new Set(e.filter(g=>g===b.rootOf(g))),h=new Set;for(let g of e){let R=b.rootOf(g),j=o.get(R),{isPeerRoot:B,hasPeers:C,isSharedDep:u}=n.get(R),f=c.has(R),y=g!==R,v=!(B||u)&&(f||!C),_=this.singletonDepsOf(j,a),H=y&&d.has(R);H&&h.add(R);let N=H?[..._,R]:_.length?_:void 0;l.push([g,this.cdn.buildEsmUrl(i(g),{bundle:v,external:N})]),p.add(g)}let m=new Set([...a,...h]);for(let g of m)o.has(g)&&(p.has(g)||l.push([g,this.cdn.buildEsmUrl(i(g),{})]),l.push([`${g}/`,`${this.cdn.esmHost}/${i(g)}/`]));return l}singletonDepsOf(e,t){return[...new Set([...we(e.meta),...gt(e.meta)])].filter(n=>t.has(n))}};ie.importPatterns=[/\bimport\s+(?:[^'";]*?from\s*)?['"]([^'"]+)['"]/g,/\bexport\s+[^'";]*?from\s*['"]([^'"]+)['"]/g];import{gt as hr,satisfies as Un,maxSatisfying as yt,major as Wn,prerelease as Jn,rsort as Hn,valid as Vn}from"semver";var Be=class{cmp(e,t){return e===t?0:hr(e,t)?1:hr(t,e)?-1:0}satisfies(e,t){return!e||!e.trim()?!0:!!Un(t,e,{includePrerelease:!0})}pickMaxSatisfying(e,t){if(!e?.length)return;let n=yt(e,t,{includePrerelease:!0});return n===null?void 0:n}pickLatest(e){return e?.length?Hn(e)[0]:void 0}selectBestVersion(e,t){if(!e?.length)return;let n=t?.range?.trim()||"*",s=t?.preferStable??!0,o=t?.distTags?.latest;if(o&&e.includes(o)&&this.satisfies(n,o))return o;if(s){let a=yt(e,n,{includePrerelease:!1});if(a)return a}return yt(e,n,{includePrerelease:!0})??void 0}majorOf(e){return Wn(e)}isPrerelease(e){return Jn(e)!==null}isExactVersion(e){return Vn(e)!==null}},X=new Be;function mr(r,e){let t=new ve(r,e),n=new xe(t),s=new Se(r,t,X);return{packageService:new ie(s,t,n,r),versionResolver:s,cdnClient:t,peerResolver:n}}import*as Ar from"fs/promises";import*as D from"path";var bt=[{name:"es5"},{name:"es2015.core"},{name:"es2015.collection"},{name:"es2015.promise"},{name:"es2015.iterable"},{name:"es2015.symbol"},{name:"es2015.symbol.wellknown"},{name:"es2015.generator"},{name:"es2015.proxy"},{name:"es2015.reflect"},{name:"es2016.array.include"},{name:"es2016.intl"},{name:"es2017.object"},{name:"es2017.string"},{name:"es2017.sharedmemory"},{name:"es2017.typedarrays"},{name:"es2017.date"},{name:"es2017.intl"},{name:"es2018.asynciterable"},{name:"es2018.asyncgenerator"},{name:"es2018.promise"},{name:"es2018.regexp"},{name:"es2018.intl"},{name:"es2019.array"},{name:"es2019.object"},{name:"es2019.string"},{name:"es2019.symbol"},{name:"es2019.intl"},{name:"es2020.bigint"},{name:"es2020.promise"},{name:"es2020.string"},{name:"es2020.sharedmemory"},{name:"es2020.date"},{name:"es2020.number"},{name:"es2020.symbol.wellknown"},{name:"es2020.intl"},{name:"es2021.promise"},{name:"es2021.string"},{name:"es2021.weakref"},{name:"es2021.intl"},{name:"es2022.array"},{name:"es2022.object"},{name:"es2022.error"},{name:"es2022.string"},{name:"es2022.regexp"},{name:"es2022.intl"},{name:"es2023.array"},{name:"es2023.collection"},{name:"es2023.intl",since:"5.5"},{name:"es2024.arraybuffer",since:"5.5"},{name:"es2024.collection",since:"5.5"},{name:"es2024.object",since:"5.5"},{name:"es2024.promise",since:"5.5"},{name:"es2024.regexp",since:"5.5"},{name:"es2024.sharedmemory",since:"5.5"},{name:"es2024.string",since:"5.5"},{name:"esnext.array",since:"5.5"},{name:"esnext.collection"},{name:"esnext.decorators"},{name:"esnext.disposable"},{name:"esnext.error",since:"5.5"},{name:"esnext.float16",since:"5.5"},{name:"esnext.iterator",since:"5.5"},{name:"esnext.object"},{name:"esnext.promise"},{name:"esnext.sharedmemory",since:"5.5"},{name:"esnext.intl"}],vt=[{name:"dom"},{name:"dom.iterable"},{name:"dom.asynciterable"}];var gr=`
86
+ `)}import{readFileSync as Cn,existsSync as An}from"fs";import*as U from"path";function In(r){return[...r?[`.env.${r}.local`,`.env.${r}`]:[],".env.local",".env"]}function pt(r,e=process.cwd()){let t={},n=[];for(let s of In(r)){let o;try{o=Cn(U.resolve(e,s),"utf-8")}catch{continue}n.push(s);for(let[i,a]of On(o))process.env[i]===void 0&&(process.env[i]=a,t[i]=s)}return{mode:r,sources:t,loaded:n}}function*On(r){for(let e of r.split(`
87
+ `)){let t=e.trim();if(!t||t.startsWith("#"))continue;let n=t.indexOf("=");if(n===-1)continue;let s=t.slice(0,n).trim(),o=t.slice(n+1).trim();(o.startsWith('"')&&o.endsWith('"')||o.startsWith("'")&&o.endsWith("'"))&&(o=o.slice(1,-1)),yield[s,o]}}function $n(r){let e=new Set,t=/process\.env\.([A-Za-z_$][\w$]*)|process\.env\[\s*['"]([^'"]+)['"]\s*\]/g;for(let n;n=t.exec(r);)e.add(n[1]??n[2]);return[...e]}function ft(r,e,t){let{sources:n,mode:s,loaded:o}=r,i=process.cwd(),a=U.dirname(e),c=`(mode: ${s??"none"})`,l=t?$n(t):[],p=l.filter(m=>n[m]).map(m=>`${m} \u2190 ${n[m]}`);p.length?console.log(`env: ${p.join(", ")} ${c}`):o.length&&console.log(`env: loaded ${o.join(", ")} ${c}`),s&&!o.some(m=>m===`.env.${s}`||m===`.env.${s}.local`)&&console.log(`env: mode=${s} \u2014 no .env.${s} found; using .env`);let d=U.resolve(a)!==U.resolve(i);if(d)for(let m of[".env.local",".env"])An(U.join(a,m))&&console.log(`env: ${U.join(a,m)} present but not loaded (cwd is ${i})`);let h=l.filter(m=>process.env[m]===void 0);if(h.length){let m=d?` \u2014 try running from ${a}`:"";console.log(`env: server.ts reads ${h.join(", ")} but ${h.length>1?"they are":"it's"} unset${m}`)}}import*as z from"fs/promises";import*as et from"path";import{pathToFileURL as ws}from"url";var Dn={code:{path:"code.tsx",language:"typescript"},css:{path:"styles.css",language:"css"},html:{path:"index.html",language:"html"},config:{path:"config.json",language:"json"},notes:{path:"notes.md",language:"markdown"},data:{path:"data.txt",language:"text"},infer:{path:"infer.md",language:"markdown"},insight:{path:"insight.json",language:"json"},server:{path:"server.ts",language:"typescript"}};function ar(r){try{let e=r.split(`
88
+ `),t=0;if(e[t]?.trim()!=="---")return null;t++;let n=[];for(;t<e.length&&e[t]?.trim()!=="---";)n.push(e[t]),t++;if(e[t]?.trim()!=="---")return null;t++;let s=jn(n);if(!s)return null;let o=new Map;for(;t<e.length;){let a=e[t]?.trim()?.match(/^\*\*(.+)\*\*$/);if(a){let c=a[1].trim();for(t++;t<e.length&&e[t]?.trim()==="";)t++;let l=e[t]?.match(/^(`{3,})(\w*)\s*$/);if(!l){t++;continue}let p=l[1];t++;let d=[];for(;t<e.length&&!e[t]?.match(new RegExp(`^${p}\\s*$`));)d.push(e[t]),t++;t++,o.set(c,d.join(`
89
+ `))}else t++}return{frontmatter:s,files:o}}catch{return null}}function jn(r){let e={};for(let t of r){let n=t.indexOf(":");if(n===-1)continue;let s=t.slice(0,n).trim(),o=t.slice(n+1).trim();switch(s){case"format":e.format=o;break;case"name":e.name=Fn(o);break}}return!e.format?.startsWith("typebulb")||!e.name?null:e}function Fn(r){return r.startsWith('"')&&r.endsWith('"')?r.slice(1,-1).replace(/\\"/g,'"'):r.startsWith("'")&&r.endsWith("'")?r.slice(1,-1):r}function cr(r){let e=t=>r.files.get(Dn[t].path)||"";return{name:r.frontmatter.name,code:e("code"),css:e("css"),html:e("html"),config:e("config"),notes:e("notes"),data:e("data"),infer:e("infer"),insight:e("insight"),server:e("server")}}function Mn(r){try{return JSON.parse(r),!0}catch{}return!!(/^\s*<[\s\S]*>/.test(r)||/^---\s*$/m.test(r)||/^\w[\w\s]*:[ \t]/m.test(r))}function lr(r){let e=r.trim();return e?Mn(e)?[e]:r.split(/\n\n\n+/).map(t=>t.trim()).filter(Boolean):[]}function dr(r){if(!r.trim())return{};try{return JSON.parse(r)}catch{return{}}}import{transform as Nn}from"sucrase";function ht(r,e={}){let t=e.serverOnly?["typescript"]:["typescript","jsx"];try{let{code:n}=Nn(r,{transforms:t,jsxRuntime:"automatic",jsxImportSource:e.jsxImportSource||"react",production:!0});return{code:n}}catch(n){return{code:"",error:String(n)}}}var be="https://esm.sh",ye="https://cdn.jsdelivr.net/npm/",mt="https://data.jsdelivr.com/v1/package/npm/";function ur(r){let e=(r||"").replace(/^\/+/,"").replace(/\/+$/,"");return e?e.split("/"):[]}var y=class r{constructor(e,t,n){let s=typeof e=="string"?r.parse(e):e;this.name=s.name,this.version=ie(t??s.version),this.subpath=ie(n??s.subpath)}static parse(e){let t=ur(e||"");if(!t.length)return new r({name:""});if(t[0].startsWith("@")){let s=t[0],[o,i]=pr(t[1]??""),a=ie(t.slice(2).join("/"));return new r({name:`${s}/${o}`,version:i,subpath:a})}else{let[s,o]=pr(t[0]),i=ie(t.slice(1).join("/"));return new r({name:s,version:o,subpath:i})}}static fromUrl(e){try{let t=new URL(e),n=new URL(be).host,s=new URL(ye).host;if(t.host===n){let o=ur(t.pathname.replace(/^\/v\d+\//,"/"));if(!o.length)return;let i=o[0].startsWith("@")?`${o[0]}/${o[1]??""}`:o[0];return r.parse(i)}if(t.host===s){let o=t.pathname.split("/npm/")[1];if(!o)return;let i=o.split("/")[0]||"";return r.parse(i)}return}catch{return}}static versionFromUrl(e){return r.fromUrl(e)?.version}format(){let e=this.version?`${this.name}@${this.version}`:this.name;return this.subpath?`${e}/${this.subpath}`:e}root(){return this.name}static rootOf(e){return r.parse(e).name}withVersion(e){return new r({name:this.name,version:ie(e),subpath:this.subpath})}withPreferredVersion(e,t){let n=e||t;return n?this.withVersion(n):this}static isBare(e){if(!e||e.startsWith(".")||e.startsWith("/"))return!1;let t=e.toLowerCase();return!t.startsWith("http://")&&!t.startsWith("https://")}},ie=r=>r&&r.length?r:void 0,pr=r=>{let e=r.indexOf("@");return e<0?[r,void 0]:[r.slice(0,e),ie(r.slice(e+1))]};async function T(r){try{return await r()}catch{return}}var ve=class{constructor(e,t){this.cache=e,this.http=t,this.esmHost=be,this.jsDelivrBase=ye,this.jsDelivrMeta=mt,this.pinMs=1e4,this.versionsIndexMs=1440*60*1e3,this.metaTtlMs=10080*60*1e3,this.pinCache=new Map}normalizeRelative(e){let t=e||"";return t.startsWith("./")?t.slice(2):t.replace(/^\/+/,"")}ensureLeadingDotSlash(e){return e.startsWith("./")?e:`./${e}`}baseDir(e){let t=typeof e=="string"?new y(e):e;return`${this.jsDelivrBase}${t.name}${t.version?`@${t.version}`:""}/`}file(e,t){return new URL(this.normalizeRelative(t),this.baseDir(e)).toString()}packageJson(e){return this.file(e,"package.json")}buildEsmUrl(e,t={}){let{target:n="es2022",bundle:s=!1,external:o}=t,i=new URLSearchParams({target:n});return s&&i.append("bundle",""),o?.length&&i.append("external",o.join(",")),`${this.esmHost}/${e}?${i.toString()}`}async pinEsmUrl(e,t="es2022"){let n=this.buildEsmUrl(e,{target:t}),s=await T(()=>this.http.head(n));return s?.ok?s.url||n:void 0}async resolveExactVersion(e){let t=Date.now(),n=this.pinCache.get(e);if(n&&t-n.ts<this.pinMs)return n.value;let s=await this.tryResolveFromUrls([this.buildEsmUrl(e),`${this.esmHost}/${e}`]);return this.pinCache.set(e,{value:s,ts:t}),s}async tryResolveFromUrls(e){for(let t of e){let n=await T(()=>this.http.head(t)),s=this.parseVersionFromUrl(n?.url||t);if(s)return s}}async fetchVersionsIndex(e){if(await this.cache.isNegative(e))return;let t=await this.cache.getIndex(e);if(t&&Date.now()-t.updatedAt<this.versionsIndexMs)return{versions:t.versions,distTags:t.distTags};let n=await T(()=>this.http.getJson(`${this.jsDelivrMeta}${encodeURIComponent(e)}`));if(!n?.versions?.length){await this.cache.recordNegative(e);return}await this.cache.clearNegative(e);let s=n.distTags&&Object.keys(n.distTags).length?n.distTags:void 0;return await this.cache.setIndex(e,n.versions,s),n}parseVersionFromUrl(e){let t=y.fromUrl(e)?.version;return t&&/\d+\.\d+\.\d+/.test(t)?t:void 0}async fetchPackageMeta(e,t){let n=await this.cache.getMeta(e,t);if(n&&Date.now()-n.updatedAt<this.metaTtlMs){let{dependencies:p,peerDependencies:d,peerDependenciesMeta:h}=n;return{name:e,version:t,dependencies:p,peerDependencies:d,peerDependenciesMeta:h}}let s=this.packageJson(new y(`${e}@${t}`)),o=await T(()=>this.http.getJson(s));if(!o)return;let i=p=>p&&Object.keys(p).length?p:void 0,a=i(o.dependencies),c=i(o.peerDependencies),l=i(o.peerDependenciesMeta);return await this.cache.setMeta(e,t,a,c,l),{name:e,version:t,dependencies:a,peerDependencies:c,peerDependenciesMeta:l}}};var fr=r=>r.startsWith("@types/"),we=r=>Object.keys(r?.peerDependencies||{}).filter(e=>!fr(e)),gt=r=>Object.keys(r?.dependencies||{}).filter(e=>!fr(e)),Ln=r=>we(r).filter(e=>!r?.peerDependenciesMeta?.[e]?.optional),xe=class{constructor(e){this.cdn=e}async resolve(e,t){let n=await this.fetchMeta(e),{allRoots:s,autoAddedPeers:o}=await this.expandWithPeers(n,t),i=this.computeFlags(s);return{allRoots:s,flags:i,autoAddedPeers:o}}async fetchMeta(e){return Promise.all(e.map(async({name:t,version:n})=>({name:t,version:n,meta:await this.cdn.fetchPackageMeta(t,n)})))}async expandWithPeers(e,t){let n=new Map(e.map(o=>[o.name,o])),s=[];for(let o of e)for(let i of Ln(o.meta))!n.has(i)&&!s.some(a=>a.name===i)&&s.push({name:i,requiredBy:o.name});for(let{name:o,requiredBy:i}of s)try{let a=await t(o),c=await this.cdn.fetchPackageMeta(o,a);n.set(o,{name:o,version:a,meta:c})}catch(a){console.warn(`[typebulb] Failed to resolve peer "${o}" for "${i}":`,a)}return{allRoots:[...n.values()],autoAddedPeers:s.filter(o=>n.has(o.name))}}computeFlags(e){let t=new Set(e.flatMap(o=>we(o.meta))),n=new Map;for(let o of e)for(let i of gt(o.meta))n.set(i,(n.get(i)||0)+1);let s=new Set([...n.entries()].filter(([,o])=>o>=2).map(([o])=>o));return new Map(e.map(o=>[o.name,{isPeerRoot:t.has(o.name),hasPeers:we(o.meta).length>0,isSharedDep:s.has(o.name)}]))}};var Se=class{constructor(e,t,n){this.cache=e,this.cdn=t,this.semver=n}selectVersionFromIndex(e,t,n){return this.semver.selectBestVersion(e,{range:t,distTags:n})}async learnExactVersion(e){let t=await T(()=>this.cdn.fetchVersionsIndex(e));if(t?.versions?.length){let n=this.semver.selectBestVersion(t.versions,{distTags:t.distTags});if(n)return n}return this.cdn.resolveExactVersion(e)}async resolveExactForRoot(e,t){if(!t)return this.learnExactVersion(e);let n=await this.cache.getPinnedExact(e,t);if(n){if(this.semver.isExactVersion(n))return n;console.warn("[versionResolver] Rejecting invalid cached version for",e,":",n)}let s=await T(()=>this.cdn.fetchVersionsIndex(e));if(s?.versions?.length){let i=this.selectVersionFromIndex(s.versions,t,s.distTags);if(i){if(this.semver.isExactVersion(i))return await this.cache.setPinnedExact(e,t,i),i}else{console.warn("[versionResolver] Invalidating stale versions cache for",e,"- range",t,"not satisfied"),await this.cache.invalidateVersionsCache(e);let a=await T(()=>this.cdn.fetchVersionsIndex(e));if(a?.versions?.length){let c=this.selectVersionFromIndex(a.versions,t,a.distTags);if(c&&this.semver.isExactVersion(c))return await this.cache.setPinnedExact(e,t,c),c}}}let o=await this.cdn.resolveExactVersion(`${e}@${t}`);if(o&&this.semver.isExactVersion(o))return await this.cache.setPinnedExact(e,t,o),o}async effectivePackage(e,t){let n=new y(e),s=n.root(),o=t[s],i=o?await T(()=>this.cache.getPinnedExact(s,o))??await T(()=>this.resolveExactForRoot(s,o)):void 0;return{effectivePackage:i?n.withVersion(i).format():e,root:s,range:o,pinned:i}}};import{init as Bn,parse as Un}from"es-module-lexer";var ae=class r{constructor(e,t,n,s){this.version=e,this.cdn=t,this.peer=n,this.cache=s}extractImportsSync(e){let t=new Set;for(let n of r.importPatterns){n.lastIndex=0;for(let s of e.matchAll(n))y.isBare(s[1])&&t.add(s[1])}return Array.from(t)}async extractImports(e){let t=new Set,n=s=>{y.isBare(s)&&t.add(s)};try{await Bn;let[s]=Un(e);s.forEach(o=>n(e.slice(o.s,o.e).trim()))}catch{return this.extractImportsSync(e)}return Array.from(t)}async buildImportMap(e,t,n){let s=(await this.extractImports(e)).filter(d=>!n?.has(y.rootOf(d))),o=[...new Set(s.map(y.rootOf))],i=await Promise.all(o.map(async d=>({name:d,version:await this.resolveVersion(d,t)}))),{allRoots:a,flags:c,autoAddedPeers:l}=await this.peer.resolve(i,d=>this.resolveVersion(d,t)),p=this.buildEntries([...s,...l.map(d=>d.name)],a,c,t);return{importMap:{imports:Object.fromEntries(p)},prefetchUrls:p.map(([,d])=>d)}}async resolveVersion(e,t){let n=t[e],s=n?`${e}@${n}`:e,o=await this.version.resolveExactForRoot(e,n);if(!o){let i=await T(()=>this.cdn.pinEsmUrl(s));if(!i)throw new Error(`Cannot resolve ${s}: no matching version is published (the package or version may not exist, or the registry was unreachable).`);o=y.versionFromUrl(i),o&&n&&await T(()=>this.cache.setPinnedExact(e,n,o))}if(!o)throw new Error(`Cannot resolve ${s}: no concrete version found.`);return o}buildEntries(e,t,n,s){let o=new Map(t.map(g=>[g.name,g])),i=g=>{let P=o.get(y.rootOf(g));return new y(g).withPreferredVersion(P.version,s[P.name]).format()},a=new Set([...n.entries()].filter(([,g])=>g.isPeerRoot||g.isSharedDep).map(([g])=>g)),c=new Set(e.filter(g=>g!==y.rootOf(g)).map(y.rootOf)),l=[],p=new Set,d=new Set(e.filter(g=>g===y.rootOf(g))),h=new Set;for(let g of e){let P=y.rootOf(g),M=o.get(P),{isPeerRoot:B,hasPeers:C,isSharedDep:u}=n.get(P),f=c.has(P),b=g!==P,v=!(B||u)&&(f||!C),_=this.singletonDepsOf(M,a),V=b&&d.has(P);V&&h.add(P);let N=V?[..._,P]:_.length?_:void 0;l.push([g,this.cdn.buildEsmUrl(i(g),{bundle:v,external:N})]),p.add(g)}let m=new Set([...a,...h]);for(let g of m)o.has(g)&&(p.has(g)||l.push([g,this.cdn.buildEsmUrl(i(g),{})]),l.push([`${g}/`,`${this.cdn.esmHost}/${i(g)}/`]));return l}singletonDepsOf(e,t){return[...new Set([...we(e.meta),...gt(e.meta)])].filter(n=>t.has(n))}};ae.importPatterns=[/\bimport\s+(?:[^'";]*?from\s*)?['"]([^'"]+)['"]/g,/\bexport\s+[^'";]*?from\s*['"]([^'"]+)['"]/g];import{gt as hr,satisfies as Wn,maxSatisfying as bt,major as Jn,prerelease as Vn,rsort as Hn,valid as qn}from"semver";var Be=class{cmp(e,t){return e===t?0:hr(e,t)?1:hr(t,e)?-1:0}satisfies(e,t){return!e||!e.trim()?!0:!!Wn(t,e,{includePrerelease:!0})}pickMaxSatisfying(e,t){if(!e?.length)return;let n=bt(e,t,{includePrerelease:!0});return n===null?void 0:n}pickLatest(e){return e?.length?Hn(e)[0]:void 0}selectBestVersion(e,t){if(!e?.length)return;let n=t?.range?.trim()||"*",s=t?.preferStable??!0,o=t?.distTags?.latest;if(o&&e.includes(o)&&this.satisfies(n,o))return o;if(s){let a=bt(e,n,{includePrerelease:!1});if(a)return a}return bt(e,n,{includePrerelease:!0})??void 0}majorOf(e){return Jn(e)}isPrerelease(e){return Vn(e)!==null}isExactVersion(e){return qn(e)!==null}},X=new Be;function mr(r,e){let t=new ve(r,e),n=new xe(t),s=new Se(r,t,X);return{packageService:new ae(s,t,n,r),versionResolver:s,cdnClient:t,peerResolver:n}}import*as Ar from"fs/promises";import*as D from"path";var yt=[{name:"es5"},{name:"es2015.core"},{name:"es2015.collection"},{name:"es2015.promise"},{name:"es2015.iterable"},{name:"es2015.symbol"},{name:"es2015.symbol.wellknown"},{name:"es2015.generator"},{name:"es2015.proxy"},{name:"es2015.reflect"},{name:"es2016.array.include"},{name:"es2016.intl"},{name:"es2017.object"},{name:"es2017.string"},{name:"es2017.sharedmemory"},{name:"es2017.typedarrays"},{name:"es2017.date"},{name:"es2017.intl"},{name:"es2018.asynciterable"},{name:"es2018.asyncgenerator"},{name:"es2018.promise"},{name:"es2018.regexp"},{name:"es2018.intl"},{name:"es2019.array"},{name:"es2019.object"},{name:"es2019.string"},{name:"es2019.symbol"},{name:"es2019.intl"},{name:"es2020.bigint"},{name:"es2020.promise"},{name:"es2020.string"},{name:"es2020.sharedmemory"},{name:"es2020.date"},{name:"es2020.number"},{name:"es2020.symbol.wellknown"},{name:"es2020.intl"},{name:"es2021.promise"},{name:"es2021.string"},{name:"es2021.weakref"},{name:"es2021.intl"},{name:"es2022.array"},{name:"es2022.object"},{name:"es2022.error"},{name:"es2022.string"},{name:"es2022.regexp"},{name:"es2022.intl"},{name:"es2023.array"},{name:"es2023.collection"},{name:"es2023.intl",since:"5.5"},{name:"es2024.arraybuffer",since:"5.5"},{name:"es2024.collection",since:"5.5"},{name:"es2024.object",since:"5.5"},{name:"es2024.promise",since:"5.5"},{name:"es2024.regexp",since:"5.5"},{name:"es2024.sharedmemory",since:"5.5"},{name:"es2024.string",since:"5.5"},{name:"esnext.array",since:"5.5"},{name:"esnext.collection"},{name:"esnext.decorators"},{name:"esnext.disposable"},{name:"esnext.error",since:"5.5"},{name:"esnext.float16",since:"5.5"},{name:"esnext.iterator",since:"5.5"},{name:"esnext.object"},{name:"esnext.promise"},{name:"esnext.sharedmemory",since:"5.5"},{name:"esnext.intl"}],vt=[{name:"dom"},{name:"dom.iterable"},{name:"dom.asynciterable"}];var gr=`
89
90
  /**
90
91
  * Get raw data chunk from the Data tab.
91
92
  * @param index - Chunk index (0-based). Separate chunks with 2 blank lines.
@@ -96,7 +97,7 @@ Examples:
96
97
  * @param index - Chunk index (0-based)
97
98
  * @throws If chunk is not valid JSON/JSON-ish
98
99
  */
99
- json<T = unknown>(index: number): T;`,yr=`
100
+ json<T = unknown>(index: number): T;`,br=`
100
101
  /**
101
102
  * Get the insight data produced by the inference layer.
102
103
  *
@@ -105,7 +106,7 @@ Examples:
105
106
  *
106
107
  * @returns The parsed insight JSON, or undefined if no insight is available
107
108
  */
108
- insight<T = unknown>(): T | undefined;`,br=`
109
+ insight<T = unknown>(): T | undefined;`,yr=`
109
110
  /**
110
111
  * General-purpose AI call.
111
112
  *
@@ -137,7 +138,7 @@ Examples:
137
138
  friendlyName: string;
138
139
  /** Provider display name, e.g. "Anthropic" */
139
140
  providerName: string;
140
- }>>;`,qn="\n /**\n * The bulb's theme override (`<html data-theme>`).\n *\n * - Get: the current override \u2014 `'dark'` | `'light'`, or `undefined` when\n * following the OS preference.\n * - Set `'dark'`/`'light'` to force and persist it (per-bulb); set\n * `undefined` to clear the override and follow the OS again.\n *\n * Drives `<html data-theme>`, so render off `html[data-theme=\"\u2026\"]` selectors\n * (or observe the attribute) rather than reading `tb.theme`.\n */\n theme: 'light' | 'dark' | undefined;",wr=`
141
+ }>>;`,Gn="\n /**\n * The bulb's theme override (`<html data-theme>`).\n *\n * - Get: the current override \u2014 `'dark'` | `'light'`, or `undefined` when\n * following the OS preference.\n * - Set `'dark'`/`'light'` to force and persist it (per-bulb); set\n * `undefined` to clear the override and follow the OS again.\n *\n * Drives `<html data-theme>`, so render off `html[data-theme=\"\u2026\"]` selectors\n * (or observe the attribute) rather than reading `tb.theme`.\n */\n theme: 'light' | 'dark' | undefined;",wr=`
141
142
  /**
142
143
  * The mode this bulb is running in.
143
144
  *
@@ -169,7 +170,7 @@ Examples:
169
170
  */
170
171
  server: {
171
172
  log(...args: any[]): Promise<void>;
172
- };`,Gn=`
173
+ };`,Yn=`
173
174
  /**
174
175
  * Async value inspector for tensor-like objects.
175
176
  *
@@ -249,18 +250,18 @@ Examples:
249
250
  * Typebulb utilities namespace.
250
251
  * Type \`tb.\` to discover available helpers.
251
252
  */
252
- declare const tb: {${gr}${Gn}${yr}${Kn}${br}${xr}${vr}${qn}${wr}
253
+ declare const tb: {${gr}${Yn}${br}${Kn}${yr}${xr}${vr}${Gn}${wr}
253
254
  };
254
255
  `,xt=`
255
256
  /**
256
257
  * Typebulb utilities namespace (server-side).
257
258
  * Type \`tb.\` to discover available helpers.
258
259
  */
259
- declare const tb: {${gr}${yr}${br}${xr}${zn}${vr}${wr}
260
+ declare const tb: {${gr}${br}${yr}${xr}${zn}${vr}${wr}
260
261
  };
261
- `;var Q=class{constructor(e){this.store=e}async isNegative(e){let t=await Ue(()=>this.store.get(e));return!!t&&t.until>Date.now()}async recordNegative(e){let n=((await Ue(()=>this.store.get(e)))?.attempts||0)+1;await Ue(()=>this.store.set(e,{until:Date.now()+Yn(n),attempts:n}))}async clearNegative(e){await Ue(()=>this.store.delete(e))}};function Yn(r){return Math.min(9e5*Math.pow(2,Math.max(0,r-1)),864e5)}async function Ue(r){try{return await r()}catch{return}}import rs from"p-limit";import{resolve as Sr}from"resolve.exports";var ae=class{constructor(e){this.fetchDts=e}fetchDtsText(e){return this.tryUrls([e])}async tryUrls(e){for(let t of e){let n=await this.fetchDts(t);if(n&&(this.looksLikeDts(n.dts)||/\.(d\.ts|d\.mts)(?:[?#].*)?$/i.test(n.url)||/[?&]dts(?:[&#]|$)/i.test(n.url)))return n}}looksLikeDts(e){return/^\s*export\s*\{\s*\}\s*;?\s*$/m.test(e)?!0:/declare\s+(module|namespace|class|interface|function|const|var|let)/.test(e)||/interface\s+\w+/.test(e)||/type\s+\w+\s*=/.test(e)}};var V={maxRelativeTypeRefs:500,maxBareDeps:8,maxBareDepth:3,prefetchConcurrency:4,negativeTtlMs:1e4},Re=["index.d.ts","index.d.mts"],Pe=/\.d\.(ts|mts)$/i;function St(r){if(Pe.test(r))return!0;try{return new URL(r,"file://").search.includes("dts")}catch{return r.includes("?")&&r.includes("dts")}}function We(r){return[`${r}.d.ts`,`${r}.d.mts`]}async function Ee(r,{retries:e=2,timeoutMs:t=15e3,init:n}={}){for(let s=0;s<=e;s++){let o=new AbortController,i=setTimeout(()=>o.abort(),t);try{let a=await fetch(r,{...n,signal:o.signal});if(Xn(a.status)&&s<e)continue;return a}catch{if(s<e)continue;return}finally{clearTimeout(i)}}}function Xn(r){return r===408||r===429||r>=500&&r<600}var ke=class extends ae{constructor(e,t){super(e),this.cdnClient=t}async loadPackageAtVersionedRoot(e,t){let n=this.cdnClient.packageJson(new b({name:e,version:t})),s=await Ee(n);if(!s?.ok)return;let o;try{o=await s.json()}catch{return}if(o)return{pkg:o,baseDir:this.cdnClient.baseDir(new b({name:e,version:t??o.version})),version:t}}extractPathFromResult(e){if(typeof e=="string")return e;if(Array.isArray(e))return e.find(t=>typeof t=="string")}async tryUntilSuccess(e,t){for(let n of e){let s=await t(n);if(s)return s}}async resolveFromSelected(e,t){if(e.kind==="types"){let s=this.cdnClient.normalizeRelative(e.path);if(!s||s==="/"||s===".")return this.tryUntilSuccess([...Re],t);if(!Pe.test(s)){let o=await this.tryUntilSuccess(this.declarationCandidatesFor(s),t);if(o)return o}return t(s)}let n=this.declarationCandidatesFor(e.path);return this.tryUntilSuccess([...Re,...n],t)}toResolutionResult(e){return{kind:Pe.test(e)?"types":"probe",path:e}}resolveExportsPath(e,t){let n=t||".",s=e;try{let o=this.extractPathFromResult(Sr(s,n,{conditions:["types"]}));if(o)return o}catch{}try{return this.extractPathFromResult(Sr(s,n,{browser:!0,conditions:["import","default","module","browser","node"]}))}catch{return}}async resolve(e){try{let t=b.parse(e),{pkg:n,baseDir:s}=await this.loadPackageAtVersionedRoot(t.name,t.version)||{};if(!n||!s)return;let o={name:t.name,version:t.version},i=new b(o).format(),a=new b({...o,subpath:t.subpath}).format(),c=d=>this.fetchCandidateFrom(s,t.name,d);if(t.subpath){let d=this.cdnClient.ensureLeadingDotSlash(t.subpath),h=this.resolveExportsPath(n,d);if(h){let g=await this.resolveFromSelected(this.toResolutionResult(h),c);if(g)return{...g,resolvedPkg:a}}let m=await this.tryUntilSuccess(this.declarationCandidatesFor(d),c);if(m)return{...m,resolvedPkg:a}}let l=n.types??n.typings;if(l){let d=await this.resolveFromSelected({kind:"types",path:l},c);if(d)return{...d,resolvedPkg:i}}let p=this.resolveExportsPath(n,".");if(p){let d=await this.resolveFromSelected(this.toResolutionResult(p),c);if(d)return{...d,resolvedPkg:i}}return}catch{return}}async fetchCandidateFrom(e,t,n){let s=this.cdnClient.normalizeRelative(n),o=new URL(s,e).toString(),i=await this.fetchDtsText(o);return i?{dts:i.dts,url:i.url,resolvedPkg:t}:void 0}declarationCandidatesFor(e){if(!e||e==="./"||e==="/")return[...Re];let t=e.replace(/\.(mjs|cjs|js|mts|cts|ts)$/i,""),n=We(t),s=t.endsWith("/")?t:`${t}/`;return n.push(...We(`${s}index`)),n}};import{gunzipSync as Qn}from"fflate";var ce=class{async fetchAndExtract(e,t){let n=this.getTarballUrl(e,t),s=await Ee(n,{timeoutMs:3e4});if(!s?.ok)return new Map;let o=new Uint8Array(await s.arrayBuffer());return this.extractDtsFiles(o)}getTarballUrl(e,t){return`https://registry.npmjs.org/${e.replace("/","%2F")}/-/${e.split("/").pop()}-${t}.tgz`}normalizeTarPath(e){let t=e.replace(/^package\//,""),n=t.indexOf("/");return n>0?t.substring(n+1):t}extractDtsFiles(e){let t=new Map;try{let n=Qn(e),s=new TextDecoder("utf-8"),o=0;for(;o<n.length-512;){let i=n.slice(o,o+512);if(i[0]===0)break;let a=i.slice(0,100),c=a.indexOf(0),l=s.decode(a.slice(0,c>0?c:100)).trim(),p=i.slice(124,136),d=s.decode(p).trim().replace(/\0/g,""),h=parseInt(d,8)||0,m=String.fromCharCode(i[156]);if(o+=512,(m==="0"||m==="\0")&&(l.endsWith(".d.ts")||l.endsWith(".d.mts"))){let g=n.slice(o,o+h);t.set(this.normalizeTarPath(l),s.decode(g))}o+=Math.ceil(h/512)*512}}catch{}return t}},Zn=new ce;var Te=class extends ae{constructor(e,t,n,s=new ce){super(e),this.cdnClient=t,this.cache=n,this.tarballFetcher=s}typesNameCandidates(e){let t=e.startsWith("@")?e.slice(1).replace("/","__"):e;return t.includes(".")?[t,t.split(".").join("-"),t.split(".").join("")]:[t]}selectTypesVersion(e,t,n){try{if(n){let o=X.majorOf(n),i=e.filter(a=>X.majorOf(a)===o);if(i.length)return i.sort((a,c)=>X.cmp(c,a))[0]}let s=t?.latest;return s&&e.includes(s)?s:e[0]}catch{return e[0]}}async fetchFromVersionedRoot(e,t){let n=new b(e),s=n.version;if(!s)return;let o;try{o=await this.tarballFetcher.fetchAndExtract(n.name,s)}catch{return}if(!o||o.size===0)return;for(let[a,c]of o.entries()){let l=this.cdnClient.file(e,a);try{await this.cache.setCachedFile(l,c)}catch{}}let i=t.subpath?[t.subpath+".d.ts",t.subpath+"/index.d.ts"]:["index.d.ts"];for(let a of i){let c=o.get(a);if(c)return{dts:c,url:this.cdnClient.file(e,a),resolvedPkg:t.subpath?new b(t).format():t.name}}}async resolve(e){let t=b.parse(e);if(t.name)for(let n of this.typesNameCandidates(t.name)){let s=`@types/${n}`,o;try{o=await this.cdnClient.fetchVersionsIndex(s)}catch{continue}if(!o?.versions?.length)continue;let i=this.selectTypesVersion(o.versions,o.distTags,t.version),a=await this.fetchFromVersionedRoot(`${s}@${i}`,t);if(a)return a}}};var _e=class{collectRelativeTypeRefs(e){return this.collectRefs(e).filter(t=>t.startsWith("./")||t.startsWith("../"))}collectBareModuleRefs(e){return this.collectRefs(e).filter(t=>this.isBare(t))}collectRefs(e){let t=new Set,n=(s,o)=>(t.add(s[o]),null);return this.matchAll(e,/(import|export)\s+[^'"\n]*from\s*['"]([^'"\n]+)['"]/,s=>n(s,2)),this.matchAll(e,/export\s*\*\s*from\s*['"]([^'"\n]+)['"]/,s=>n(s,1)),Array.from(t)}matchAll(e,t,n){let s=[];try{let o=new RegExp(t.source,"g"),i;for(;i=o.exec(e);){let a=n(i);a!==null&&s.push(a)}}catch{}return s}isBare(e){return!(e.startsWith("./")||e.startsWith("../")||e.startsWith("file:")||e.startsWith("http://")||e.startsWith("https://"))}};var Rr="file:///node_modules",Ce=class{constructor(){this.epoch=0,this.listeners=new Set}getEpoch(){return this.epoch}bumpEpoch(){this.epoch+=1;for(let e of this.listeners)try{e(this.epoch)}catch{}return this.epoch}onEpochChange(e){return this.listeners.add(e),()=>{this.listeners.delete(e)}}epochDir(){return`__tsepoch_${this.epoch}`}pathForMain(e){return`${Rr}/${this.epochDir()}/${e}/index.d.ts`}pathFor(e,t){let n=es(t);return`${Rr}/${this.epochDir()}/${e}/${n}`}};function es(r){let e=r||"";return e.startsWith("./")?e.slice(2):e.replace(/^\/+/,"")}import{LRUCache as ts}from"lru-cache";function Rt(r){let e=new ts({ttl:1e4,max:500}),t=new Map;return async function(s){try{if(await r.isNegative(s))return;let o=e.get(s);if(o&&Date.now()-o<1e4)return;let i=await r.getCachedFile(s);if(i)return{dts:i,url:s};let a=t.get(s);if(a)return a;let c=(async()=>{let l=await fetch(s,{cache:"no-store"});if(!l.ok){l.status===404&&(e.set(s,Date.now()),await r.recordNegative(s));return}let p=await l.text(),d=l.url||s;return await r.clearNegative(s),await r.setCachedFile(d,p),{dts:p,url:d}})();return t.set(s,c),await c.finally(()=>t.delete(s))}catch{return}}}var Je=class{constructor(e){this.inFlight=new Map,this.scanner=new _e,this.cache=e.cache,this.cdnClient=e.cdnClient,this.versionResolver=e.versionResolver,this.packageService=e.packageService,this.fetchDts=Rt(e.cache),this.typescriptProvider=new ke(this.fetchDts,e.cdnClient),this.definitelyTypedProvider=new Te(this.fetchDts,e.cdnClient,e.cache),this.virtualFs=new Ce}withInFlight(e,t){let n=this.inFlight.get(e);if(n)return n;let s=t().finally(()=>this.inFlight.delete(e));return this.inFlight.set(e,s),s}invalidate(){this.virtualFs.bumpEpoch(),this.inFlight.clear()}capArray(e,t){return e.length<=t?e:e.slice(0,t)}pushFileIfNew(e,t,n){e.some(s=>s.path===t)||e.push({path:t,content:n})}createStubDef(e){let t=this.virtualFs.pathForMain(e);return{pkg:e,mainPath:t,files:[{path:t,content:"export const _shim: any; export default _shim;"}],shims:[{module:e,path:t}]}}async trySubpathWithRootFallback(e,t){let n=new b(e);return n.subpath?this.fetchRootDts(n.name,t):void 0}async fetchViaProviders(e){for(let t of[this.typescriptProvider,this.definitelyTypedProvider])try{let n=await t.resolve(e);if(n?.dts)return n}catch{}}subpathsMatch(e,t){return new b(e).subpath===new b(t).subpath}async fetchRootDts(e,t){let{effectivePackage:n,root:s,pinned:o}=await this.versionResolver.effectivePackage(e,t),i=await this.cache.getCachedDts(n);if(i?.content){let c=i.url??this.cdnClient.file(o?`${s}@${o}`:s,"index.d.ts");return{dts:i.content,url:c,resolvedPkg:n}}let a;try{a=await this.fetchViaProviders(n)}catch{return}if(!(!a?.dts||!a.url)){try{await this.cache.setCachedFile(a.url,a.dts)}catch{}if(this.subpathsMatch(n,a.resolvedPkg||n)){try{await this.cache.setCachedDts(n,a.dts,a.url)}catch{}return a}}}extractPackageRootUrl(e){let t=e.pathname.match(/^(.+@[^/]+\/)/);return t?new URL(t[1],e.origin):new URL("./",e)}toVirtualPath(e,t,n){let s=t.pathname.startsWith(e.pathname)?t.pathname.slice(e.pathname.length):`__deps__/${encodeURIComponent(t.toString()).replace(/%/g,"_")}.d.ts`;return this.virtualFs.pathFor(n,s)}computeEntryPath(e,t){if(!e)return{mainPath:this.virtualFs.pathForMain(t),packageRootUrl:void 0};let n=new URL(e),s=this.extractPackageRootUrl(n);return{mainPath:this.toVirtualPath(s,n,t),packageRootUrl:s}}async expandRelativeRefs(e,t,n,s,o=new Set,i){if(!o.has(t)&&(o.add(t),!(o.size>V.maxRelativeTypeRefs)))try{let a=new URL(t),c=new URL("./",a);i??(i=this.extractPackageRootUrl(a));let l=this.capArray(this.scanner.collectRelativeTypeRefs(e),V.maxRelativeTypeRefs);for(let p of l)await this.tryRelativeRef(p,c,i,n,s,o)}catch{}}async tryRelativeRef(e,t,n,s,o,i){try{let a=new URL(e,t),c=a.pathname+a.search,l=St(c)?[c]:this.typescriptProvider.declarationCandidatesFor(c);for(let p of l){let h=new URL(p,a).toString();if(i.has(h))return;let m=await this.fetchDts(h);if(m?.dts){let g=this.toVirtualPath(n,new URL(m.url),s);this.pushFileIfNew(o,g,m.dts),await this.expandRelativeRefs(m.dts,m.url,s,o,i,n);return}}}catch{}}isDifferentPackage(e,t){return e===t?!1:new b(e).name!==new b(t).name}ambientlyDeclares(e,t){for(let n of e.matchAll(/declare\s+module\s+['"]([^'"]+)['"]/g)){let s=n[1];if(s===t||s.endsWith("/*")&&t.startsWith(s.slice(0,-1)))return!0}return!1}markFileAmbient(e,t){let n=e.find(s=>s.path===t);n&&(n.ambient=!0)}async prefetchBareDeps(e,t,n,s,o){try{let i=this.capArray(this.scanner.collectBareModuleRefs(e),V.maxBareDeps).filter(l=>this.isDifferentPackage(l,t));if(!i.length)return;let a=new Set([t]),c=rs(V.prefetchConcurrency);await Promise.all(i.map(l=>c(()=>this.prefetchBareDepsRecursive(l,n,s,V.maxBareDepth,a,o).catch(()=>{}))))}catch{}}async prefetchBareDepsRecursive(e,t,n,s,o,i){if(s<=0||o.has(e))return;o.add(e);let a=await this.fetchRootDts(e,i);if(!a?.dts)return;let c=a.resolvedPkg||e,l=this.virtualFs.pathForMain(c);this.pushFileIfNew(t,l,a.dts),this.ambientlyDeclares(a.dts,e)?this.markFileAmbient(t,l):n.push({module:e,path:l}),a.url&&await this.expandRelativeRefs(a.dts,a.url,c,t);let p=this.capArray(this.scanner.collectBareModuleRefs(a.dts),V.maxBareDeps).filter(d=>!o.has(d));for(let d of p)await this.prefetchBareDepsRecursive(d,t,n,s-1,o,i)}async resolve(e,t,n){let s=await this.packageService.extractImports(e),o=n?[...s,...n]:s;return(await Promise.all(o.map(a=>this.resolveOne(a,t)))).filter(a=>!!a)}async resolveOne(e,t){let{effectivePackage:n}=await this.versionResolver.effectivePackage(e,t);return this.withInFlight(n,async()=>{let s=await this.fetchRootDts(e,t)??await this.trySubpathWithRootFallback(e,t);return s?this.buildDefFromContent(e,s,s.resolvedPkg||e,t):this.createStubDef(e)})}async buildDefFromContent(e,t,n,s){let{dts:o,url:i,resolvedPkg:a}=t,c=new b(a||n),l=c.version?`${c.name}@${c.version}`:c.name,{mainPath:p,packageRootUrl:d}=this.computeEntryPath(i,l),h=[{path:p,content:o}],m=[];i&&await this.expandRelativeRefs(o,i,l,h,void 0,d);let g=h.map(C=>C.content).join(`
262
- `);await this.prefetchBareDeps(g,l,h,m,s);let R=c.format(),j=e===R?[e]:[e,R],B=j.some(C=>this.ambientlyDeclares(o,C));return B?this.markFileAmbient(h,p):m.push(...j.map(C=>({module:C,path:p}))),{pkg:e,mainPath:p,files:h,shims:m,ambient:B}}};function Pt(r){return new Je(r)}import*as L from"fs/promises";import*as W from"path";import*as kr from"os";import*as Et from"fs/promises";import*as Pr from"crypto";function $(r){return Pr.createHash("sha1").update(r).digest("hex")}async function Z(r){try{return JSON.parse(await Et.readFile(r,"utf8"))}catch{return}}async function He(r){try{return await Et.readFile(r,"utf8")}catch{return}}var Er=1,q=W.join(kr.homedir(),".typebulb","cache"),Ae=W.join(q,"packages"),Oe=W.join(q,"proxy"),Ve=W.join(q,"dts"),ns=W.join(q,"emit"),kt;function x(){return kt||(kt=ss()),kt}function qe(r,e){return W.join(ns,$(r),e)}async function ss(){await L.mkdir(q,{recursive:!0});let r=W.join(q,"version.json");if((await os(r))?.version===Er)return;let t=await L.readdir(q).catch(()=>[]);await Promise.all(t.map(n=>L.rm(W.join(q,n),{recursive:!0,force:!0}))),await L.writeFile(r,JSON.stringify({version:Er})+`
263
- `,"utf8")}async function os(r){try{let e=await L.readFile(r,"utf8");return JSON.parse(e)}catch{return}}import*as z from"fs/promises";import*as Tr from"path";async function A(r,e){await z.mkdir(Tr.dirname(r),{recursive:!0});let t=`${r}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2,8)}`;await z.writeFile(t,e,"utf8"),await z.rename(t,r).catch(async n=>{throw await z.rm(t,{force:!0}).catch(()=>{}),n})}var le=class{constructor(e){this.filePath=e}mem;loadPromise;load(){return this.mem?Promise.resolve(this.mem):(this.loadPromise||(this.loadPromise=Z(this.filePath).then(e=>(this.mem=new Map(Object.entries(e??{})),this.mem))),this.loadPromise)}async get(e){return(await this.load()).get(e)}async set(e,t){let n=await this.load();n.set(e,t),await this.persist(n)}async delete(e){let t=await this.load();t.delete(e)&&await this.persist(t)}async persist(e){await A(this.filePath,JSON.stringify(Object.fromEntries(e)))}};var Tt=D.join(Ae,"indexes"),_r=D.join(Ae,"pinned"),is=D.join(Ae,"meta"),as=D.join(Ae,"negative.json"),de=Symbol("missing"),Ge=class{pinnedMem=new Map;indexMem=new Map;metaMem=new Map;negativeCache=new Q(new le(as));async getPinnedExact(e,t){let n=`${e}@${t}`,s=this.pinnedMem.get(n);if(s!==void 0)return s===de?void 0:s;await x();let o=await He(D.join(_r,$(n)+".txt"));return this.pinnedMem.set(n,o??de),o}async setPinnedExact(e,t,n){let s=`${e}@${t}`;this.pinnedMem.set(s,n),await x(),await A(D.join(_r,$(s)+".txt"),n)}async getIndex(e){let t=this.indexMem.get(e);if(t!==void 0)return t===de?void 0:t;await x();let n=await Z(D.join(Tt,ze(e)+".json"));return this.indexMem.set(e,n??de),n}async setIndex(e,t,n){let s={versions:t,distTags:n,updatedAt:Date.now()};this.indexMem.set(e,s),await x(),await A(D.join(Tt,ze(e)+".json"),JSON.stringify(s))}async invalidateVersionsCache(e){this.indexMem.delete(e),await Ar.rm(D.join(Tt,ze(e)+".json"),{force:!0})}async isNegative(e){return await x(),this.negativeCache.isNegative(e)}async recordNegative(e){await x(),await this.negativeCache.recordNegative(e)}async clearNegative(e){await this.negativeCache.clearNegative(e)}async getMeta(e,t){let n=`${e}@${t}`,s=this.metaMem.get(n);if(s!==void 0)return s===de?void 0:s;await x();let o=await Z(Cr(e,t));return this.metaMem.set(n,o??de),o}async setMeta(e,t,n,s,o){let i={dependencies:n,peerDependencies:s,peerDependenciesMeta:o,updatedAt:Date.now()};this.metaMem.set(`${e}@${t}`,i),await x(),await A(Cr(e,t),JSON.stringify(i))}};function Cr(r,e){return D.join(is,ze(r),encodeURIComponent(e)+".json")}function ze(r){return r.replace(/\//g,"__")}var Or={async getJson(r){try{let e=await fetch(r,{redirect:"follow"});return e.ok?await e.json():void 0}catch{return}},async head(r){try{let e=await fetch(r,{method:"HEAD",redirect:"follow"});return{ok:e.ok,url:e.url}}catch{return}}};var cs=new Ge,{packageService:Ke,versionResolver:Ir,cdnClient:$r,peerResolver:Sa}=mr(cs,Or);var Dr=`
262
+ `;var Q=class{constructor(e){this.store=e}async isNegative(e){let t=await Ue(()=>this.store.get(e));return!!t&&t.until>Date.now()}async recordNegative(e){let n=((await Ue(()=>this.store.get(e)))?.attempts||0)+1;await Ue(()=>this.store.set(e,{until:Date.now()+Xn(n),attempts:n}))}async clearNegative(e){await Ue(()=>this.store.delete(e))}};function Xn(r){return Math.min(9e5*Math.pow(2,Math.max(0,r-1)),864e5)}async function Ue(r){try{return await r()}catch{return}}import ns from"p-limit";import{resolve as Sr}from"resolve.exports";var ce=class{constructor(e){this.fetchDts=e}fetchDtsText(e){return this.tryUrls([e])}async tryUrls(e){for(let t of e){let n=await this.fetchDts(t);if(n&&(this.looksLikeDts(n.dts)||/\.(d\.ts|d\.mts)(?:[?#].*)?$/i.test(n.url)||/[?&]dts(?:[&#]|$)/i.test(n.url)))return n}}looksLikeDts(e){return/^\s*export\s*\{\s*\}\s*;?\s*$/m.test(e)?!0:/declare\s+(module|namespace|class|interface|function|const|var|let)/.test(e)||/interface\s+\w+/.test(e)||/type\s+\w+\s*=/.test(e)}};var H={maxRelativeTypeRefs:500,maxBareDeps:8,maxBareDepth:3,prefetchConcurrency:4,negativeTtlMs:1e4},Pe=["index.d.ts","index.d.mts"],Re=/\.d\.(ts|mts)$/i;function St(r){if(Re.test(r))return!0;try{return new URL(r,"file://").search.includes("dts")}catch{return r.includes("?")&&r.includes("dts")}}function We(r){return[`${r}.d.ts`,`${r}.d.mts`]}async function Ee(r,{retries:e=2,timeoutMs:t=15e3,init:n}={}){for(let s=0;s<=e;s++){let o=new AbortController,i=setTimeout(()=>o.abort(),t);try{let a=await fetch(r,{...n,signal:o.signal});if(Qn(a.status)&&s<e)continue;return a}catch{if(s<e)continue;return}finally{clearTimeout(i)}}}function Qn(r){return r===408||r===429||r>=500&&r<600}var ke=class extends ce{constructor(e,t){super(e),this.cdnClient=t}async loadPackageAtVersionedRoot(e,t){let n=this.cdnClient.packageJson(new y({name:e,version:t})),s=await Ee(n);if(!s?.ok)return;let o;try{o=await s.json()}catch{return}if(o)return{pkg:o,baseDir:this.cdnClient.baseDir(new y({name:e,version:t??o.version})),version:t}}extractPathFromResult(e){if(typeof e=="string")return e;if(Array.isArray(e))return e.find(t=>typeof t=="string")}async tryUntilSuccess(e,t){for(let n of e){let s=await t(n);if(s)return s}}async resolveFromSelected(e,t){if(e.kind==="types"){let s=this.cdnClient.normalizeRelative(e.path);if(!s||s==="/"||s===".")return this.tryUntilSuccess([...Pe],t);if(!Re.test(s)){let o=await this.tryUntilSuccess(this.declarationCandidatesFor(s),t);if(o)return o}return t(s)}let n=this.declarationCandidatesFor(e.path);return this.tryUntilSuccess([...Pe,...n],t)}toResolutionResult(e){return{kind:Re.test(e)?"types":"probe",path:e}}resolveExportsPath(e,t){let n=t||".",s=e;try{let o=this.extractPathFromResult(Sr(s,n,{conditions:["types"]}));if(o)return o}catch{}try{return this.extractPathFromResult(Sr(s,n,{browser:!0,conditions:["import","default","module","browser","node"]}))}catch{return}}async resolve(e){try{let t=y.parse(e),{pkg:n,baseDir:s}=await this.loadPackageAtVersionedRoot(t.name,t.version)||{};if(!n||!s)return;let o={name:t.name,version:t.version},i=new y(o).format(),a=new y({...o,subpath:t.subpath}).format(),c=d=>this.fetchCandidateFrom(s,t.name,d);if(t.subpath){let d=this.cdnClient.ensureLeadingDotSlash(t.subpath),h=this.resolveExportsPath(n,d);if(h){let g=await this.resolveFromSelected(this.toResolutionResult(h),c);if(g)return{...g,resolvedPkg:a}}let m=await this.tryUntilSuccess(this.declarationCandidatesFor(d),c);if(m)return{...m,resolvedPkg:a}}let l=n.types??n.typings;if(l){let d=await this.resolveFromSelected({kind:"types",path:l},c);if(d)return{...d,resolvedPkg:i}}let p=this.resolveExportsPath(n,".");if(p){let d=await this.resolveFromSelected(this.toResolutionResult(p),c);if(d)return{...d,resolvedPkg:i}}return}catch{return}}async fetchCandidateFrom(e,t,n){let s=this.cdnClient.normalizeRelative(n),o=new URL(s,e).toString(),i=await this.fetchDtsText(o);return i?{dts:i.dts,url:i.url,resolvedPkg:t}:void 0}declarationCandidatesFor(e){if(!e||e==="./"||e==="/")return[...Pe];let t=e.replace(/\.(mjs|cjs|js|mts|cts|ts)$/i,""),n=We(t),s=t.endsWith("/")?t:`${t}/`;return n.push(...We(`${s}index`)),n}};import{gunzipSync as Zn}from"fflate";var le=class{async fetchAndExtract(e,t){let n=this.getTarballUrl(e,t),s=await Ee(n,{timeoutMs:3e4});if(!s?.ok)return new Map;let o=new Uint8Array(await s.arrayBuffer());return this.extractDtsFiles(o)}getTarballUrl(e,t){return`https://registry.npmjs.org/${e.replace("/","%2F")}/-/${e.split("/").pop()}-${t}.tgz`}normalizeTarPath(e){let t=e.replace(/^package\//,""),n=t.indexOf("/");return n>0?t.substring(n+1):t}extractDtsFiles(e){let t=new Map;try{let n=Zn(e),s=new TextDecoder("utf-8"),o=0;for(;o<n.length-512;){let i=n.slice(o,o+512);if(i[0]===0)break;let a=i.slice(0,100),c=a.indexOf(0),l=s.decode(a.slice(0,c>0?c:100)).trim(),p=i.slice(124,136),d=s.decode(p).trim().replace(/\0/g,""),h=parseInt(d,8)||0,m=String.fromCharCode(i[156]);if(o+=512,(m==="0"||m==="\0")&&(l.endsWith(".d.ts")||l.endsWith(".d.mts"))){let g=n.slice(o,o+h);t.set(this.normalizeTarPath(l),s.decode(g))}o+=Math.ceil(h/512)*512}}catch{}return t}},es=new le;var Te=class extends ce{constructor(e,t,n,s=new le){super(e),this.cdnClient=t,this.cache=n,this.tarballFetcher=s}typesNameCandidates(e){let t=e.startsWith("@")?e.slice(1).replace("/","__"):e;return t.includes(".")?[t,t.split(".").join("-"),t.split(".").join("")]:[t]}selectTypesVersion(e,t,n){try{if(n){let o=X.majorOf(n),i=e.filter(a=>X.majorOf(a)===o);if(i.length)return i.sort((a,c)=>X.cmp(c,a))[0]}let s=t?.latest;return s&&e.includes(s)?s:e[0]}catch{return e[0]}}async fetchFromVersionedRoot(e,t){let n=new y(e),s=n.version;if(!s)return;let o;try{o=await this.tarballFetcher.fetchAndExtract(n.name,s)}catch{return}if(!o||o.size===0)return;for(let[a,c]of o.entries()){let l=this.cdnClient.file(e,a);try{await this.cache.setCachedFile(l,c)}catch{}}let i=t.subpath?[t.subpath+".d.ts",t.subpath+"/index.d.ts"]:["index.d.ts"];for(let a of i){let c=o.get(a);if(c)return{dts:c,url:this.cdnClient.file(e,a),resolvedPkg:t.subpath?new y(t).format():t.name}}}async resolve(e){let t=y.parse(e);if(t.name)for(let n of this.typesNameCandidates(t.name)){let s=`@types/${n}`,o;try{o=await this.cdnClient.fetchVersionsIndex(s)}catch{continue}if(!o?.versions?.length)continue;let i=this.selectTypesVersion(o.versions,o.distTags,t.version),a=await this.fetchFromVersionedRoot(`${s}@${i}`,t);if(a)return a}}};var _e=class{collectRelativeTypeRefs(e){return this.collectRefs(e).filter(t=>t.startsWith("./")||t.startsWith("../"))}collectBareModuleRefs(e){return this.collectRefs(e).filter(t=>this.isBare(t))}collectRefs(e){let t=new Set,n=(s,o)=>(t.add(s[o]),null);return this.matchAll(e,/(import|export)\s+[^'"\n]*from\s*['"]([^'"\n]+)['"]/,s=>n(s,2)),this.matchAll(e,/export\s*\*\s*from\s*['"]([^'"\n]+)['"]/,s=>n(s,1)),Array.from(t)}matchAll(e,t,n){let s=[];try{let o=new RegExp(t.source,"g"),i;for(;i=o.exec(e);){let a=n(i);a!==null&&s.push(a)}}catch{}return s}isBare(e){return!(e.startsWith("./")||e.startsWith("../")||e.startsWith("file:")||e.startsWith("http://")||e.startsWith("https://"))}};var Pr="file:///node_modules",Ce=class{constructor(){this.epoch=0,this.listeners=new Set}getEpoch(){return this.epoch}bumpEpoch(){this.epoch+=1;for(let e of this.listeners)try{e(this.epoch)}catch{}return this.epoch}onEpochChange(e){return this.listeners.add(e),()=>{this.listeners.delete(e)}}epochDir(){return`__tsepoch_${this.epoch}`}pathForMain(e){return`${Pr}/${this.epochDir()}/${e}/index.d.ts`}pathFor(e,t){let n=ts(t);return`${Pr}/${this.epochDir()}/${e}/${n}`}};function ts(r){let e=r||"";return e.startsWith("./")?e.slice(2):e.replace(/^\/+/,"")}import{LRUCache as rs}from"lru-cache";function Pt(r){let e=new rs({ttl:1e4,max:500}),t=new Map;return async function(s){try{if(await r.isNegative(s))return;let o=e.get(s);if(o&&Date.now()-o<1e4)return;let i=await r.getCachedFile(s);if(i)return{dts:i,url:s};let a=t.get(s);if(a)return a;let c=(async()=>{let l=await fetch(s,{cache:"no-store"});if(!l.ok){l.status===404&&(e.set(s,Date.now()),await r.recordNegative(s));return}let p=await l.text(),d=l.url||s;return await r.clearNegative(s),await r.setCachedFile(d,p),{dts:p,url:d}})();return t.set(s,c),await c.finally(()=>t.delete(s))}catch{return}}}var Je=class{constructor(e){this.inFlight=new Map,this.scanner=new _e,this.cache=e.cache,this.cdnClient=e.cdnClient,this.versionResolver=e.versionResolver,this.packageService=e.packageService,this.fetchDts=Pt(e.cache),this.typescriptProvider=new ke(this.fetchDts,e.cdnClient),this.definitelyTypedProvider=new Te(this.fetchDts,e.cdnClient,e.cache),this.virtualFs=new Ce}withInFlight(e,t){let n=this.inFlight.get(e);if(n)return n;let s=t().finally(()=>this.inFlight.delete(e));return this.inFlight.set(e,s),s}invalidate(){this.virtualFs.bumpEpoch(),this.inFlight.clear()}capArray(e,t){return e.length<=t?e:e.slice(0,t)}pushFileIfNew(e,t,n){e.some(s=>s.path===t)||e.push({path:t,content:n})}createStubDef(e){let t=this.virtualFs.pathForMain(e);return{pkg:e,mainPath:t,files:[{path:t,content:"export const _shim: any; export default _shim;"}],shims:[{module:e,path:t}]}}async trySubpathWithRootFallback(e,t){let n=new y(e);return n.subpath?this.fetchRootDts(n.name,t):void 0}async fetchViaProviders(e){for(let t of[this.typescriptProvider,this.definitelyTypedProvider])try{let n=await t.resolve(e);if(n?.dts)return n}catch{}}subpathsMatch(e,t){return new y(e).subpath===new y(t).subpath}async fetchRootDts(e,t){let{effectivePackage:n,root:s,pinned:o}=await this.versionResolver.effectivePackage(e,t),i=await this.cache.getCachedDts(n);if(i?.content){let c=i.url??this.cdnClient.file(o?`${s}@${o}`:s,"index.d.ts");return{dts:i.content,url:c,resolvedPkg:n}}let a;try{a=await this.fetchViaProviders(n)}catch{return}if(!(!a?.dts||!a.url)){try{await this.cache.setCachedFile(a.url,a.dts)}catch{}if(this.subpathsMatch(n,a.resolvedPkg||n)){try{await this.cache.setCachedDts(n,a.dts,a.url)}catch{}return a}}}extractPackageRootUrl(e){let t=e.pathname.match(/^(.+@[^/]+\/)/);return t?new URL(t[1],e.origin):new URL("./",e)}toVirtualPath(e,t,n){let s=t.pathname.startsWith(e.pathname)?t.pathname.slice(e.pathname.length):`__deps__/${encodeURIComponent(t.toString()).replace(/%/g,"_")}.d.ts`;return this.virtualFs.pathFor(n,s)}computeEntryPath(e,t){if(!e)return{mainPath:this.virtualFs.pathForMain(t),packageRootUrl:void 0};let n=new URL(e),s=this.extractPackageRootUrl(n);return{mainPath:this.toVirtualPath(s,n,t),packageRootUrl:s}}async expandRelativeRefs(e,t,n,s,o=new Set,i){if(!o.has(t)&&(o.add(t),!(o.size>H.maxRelativeTypeRefs)))try{let a=new URL(t),c=new URL("./",a);i??(i=this.extractPackageRootUrl(a));let l=this.capArray(this.scanner.collectRelativeTypeRefs(e),H.maxRelativeTypeRefs);for(let p of l)await this.tryRelativeRef(p,c,i,n,s,o)}catch{}}async tryRelativeRef(e,t,n,s,o,i){try{let a=new URL(e,t),c=a.pathname+a.search,l=St(c)?[c]:this.typescriptProvider.declarationCandidatesFor(c);for(let p of l){let h=new URL(p,a).toString();if(i.has(h))return;let m=await this.fetchDts(h);if(m?.dts){let g=this.toVirtualPath(n,new URL(m.url),s);this.pushFileIfNew(o,g,m.dts),await this.expandRelativeRefs(m.dts,m.url,s,o,i,n);return}}}catch{}}isDifferentPackage(e,t){return e===t?!1:new y(e).name!==new y(t).name}ambientlyDeclares(e,t){for(let n of e.matchAll(/declare\s+module\s+['"]([^'"]+)['"]/g)){let s=n[1];if(s===t||s.endsWith("/*")&&t.startsWith(s.slice(0,-1)))return!0}return!1}markFileAmbient(e,t){let n=e.find(s=>s.path===t);n&&(n.ambient=!0)}async prefetchBareDeps(e,t,n,s,o){try{let i=this.capArray(this.scanner.collectBareModuleRefs(e),H.maxBareDeps).filter(l=>this.isDifferentPackage(l,t));if(!i.length)return;let a=new Set([t]),c=ns(H.prefetchConcurrency);await Promise.all(i.map(l=>c(()=>this.prefetchBareDepsRecursive(l,n,s,H.maxBareDepth,a,o).catch(()=>{}))))}catch{}}async prefetchBareDepsRecursive(e,t,n,s,o,i){if(s<=0||o.has(e))return;o.add(e);let a=await this.fetchRootDts(e,i);if(!a?.dts)return;let c=a.resolvedPkg||e,l=this.virtualFs.pathForMain(c);this.pushFileIfNew(t,l,a.dts),this.ambientlyDeclares(a.dts,e)?this.markFileAmbient(t,l):n.push({module:e,path:l}),a.url&&await this.expandRelativeRefs(a.dts,a.url,c,t);let p=this.capArray(this.scanner.collectBareModuleRefs(a.dts),H.maxBareDeps).filter(d=>!o.has(d));for(let d of p)await this.prefetchBareDepsRecursive(d,t,n,s-1,o,i)}async resolve(e,t,n){let s=await this.packageService.extractImports(e),o=n?[...s,...n]:s;return(await Promise.all(o.map(a=>this.resolveOne(a,t)))).filter(a=>!!a)}async resolveOne(e,t){let{effectivePackage:n}=await this.versionResolver.effectivePackage(e,t);return this.withInFlight(n,async()=>{let s=await this.fetchRootDts(e,t)??await this.trySubpathWithRootFallback(e,t);return s?this.buildDefFromContent(e,s,s.resolvedPkg||e,t):this.createStubDef(e)})}async buildDefFromContent(e,t,n,s){let{dts:o,url:i,resolvedPkg:a}=t,c=new y(a||n),l=c.version?`${c.name}@${c.version}`:c.name,{mainPath:p,packageRootUrl:d}=this.computeEntryPath(i,l),h=[{path:p,content:o}],m=[];i&&await this.expandRelativeRefs(o,i,l,h,void 0,d);let g=h.map(C=>C.content).join(`
263
+ `);await this.prefetchBareDeps(g,l,h,m,s);let P=c.format(),M=e===P?[e]:[e,P],B=M.some(C=>this.ambientlyDeclares(o,C));return B?this.markFileAmbient(h,p):m.push(...M.map(C=>({module:C,path:p}))),{pkg:e,mainPath:p,files:h,shims:m,ambient:B}}};function Rt(r){return new Je(r)}import*as L from"fs/promises";import*as W from"path";import*as kr from"os";import*as Et from"fs/promises";import*as Rr from"crypto";function $(r){return Rr.createHash("sha1").update(r).digest("hex")}async function Z(r){try{return JSON.parse(await Et.readFile(r,"utf8"))}catch{return}}async function Ve(r){try{return await Et.readFile(r,"utf8")}catch{return}}var Er=1,q=W.join(kr.homedir(),".typebulb","cache"),Ae=W.join(q,"packages"),Ie=W.join(q,"proxy"),He=W.join(q,"dts"),ss=W.join(q,"emit"),kt;function x(){return kt||(kt=os()),kt}function qe(r,e){return W.join(ss,$(r),e)}async function os(){await L.mkdir(q,{recursive:!0});let r=W.join(q,"version.json");if((await is(r))?.version===Er)return;let t=await L.readdir(q).catch(()=>[]);await Promise.all(t.map(n=>L.rm(W.join(q,n),{recursive:!0,force:!0}))),await L.writeFile(r,JSON.stringify({version:Er})+`
264
+ `,"utf8")}async function is(r){try{let e=await L.readFile(r,"utf8");return JSON.parse(e)}catch{return}}import*as G from"fs/promises";import*as Tr from"path";async function A(r,e){await G.mkdir(Tr.dirname(r),{recursive:!0});let t=`${r}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2,8)}`;await G.writeFile(t,e,"utf8"),await G.rename(t,r).catch(async n=>{throw await G.rm(t,{force:!0}).catch(()=>{}),n})}var de=class{constructor(e){this.filePath=e}mem;loadPromise;load(){return this.mem?Promise.resolve(this.mem):(this.loadPromise||(this.loadPromise=Z(this.filePath).then(e=>(this.mem=new Map(Object.entries(e??{})),this.mem))),this.loadPromise)}async get(e){return(await this.load()).get(e)}async set(e,t){let n=await this.load();n.set(e,t),await this.persist(n)}async delete(e){let t=await this.load();t.delete(e)&&await this.persist(t)}async persist(e){await A(this.filePath,JSON.stringify(Object.fromEntries(e)))}};var Tt=D.join(Ae,"indexes"),_r=D.join(Ae,"pinned"),as=D.join(Ae,"meta"),cs=D.join(Ae,"negative.json"),ue=Symbol("missing"),ze=class{pinnedMem=new Map;indexMem=new Map;metaMem=new Map;negativeCache=new Q(new de(cs));async getPinnedExact(e,t){let n=`${e}@${t}`,s=this.pinnedMem.get(n);if(s!==void 0)return s===ue?void 0:s;await x();let o=await Ve(D.join(_r,$(n)+".txt"));return this.pinnedMem.set(n,o??ue),o}async setPinnedExact(e,t,n){let s=`${e}@${t}`;this.pinnedMem.set(s,n),await x(),await A(D.join(_r,$(s)+".txt"),n)}async getIndex(e){let t=this.indexMem.get(e);if(t!==void 0)return t===ue?void 0:t;await x();let n=await Z(D.join(Tt,Ge(e)+".json"));return this.indexMem.set(e,n??ue),n}async setIndex(e,t,n){let s={versions:t,distTags:n,updatedAt:Date.now()};this.indexMem.set(e,s),await x(),await A(D.join(Tt,Ge(e)+".json"),JSON.stringify(s))}async invalidateVersionsCache(e){this.indexMem.delete(e),await Ar.rm(D.join(Tt,Ge(e)+".json"),{force:!0})}async isNegative(e){return await x(),this.negativeCache.isNegative(e)}async recordNegative(e){await x(),await this.negativeCache.recordNegative(e)}async clearNegative(e){await this.negativeCache.clearNegative(e)}async getMeta(e,t){let n=`${e}@${t}`,s=this.metaMem.get(n);if(s!==void 0)return s===ue?void 0:s;await x();let o=await Z(Cr(e,t));return this.metaMem.set(n,o??ue),o}async setMeta(e,t,n,s,o){let i={dependencies:n,peerDependencies:s,peerDependenciesMeta:o,updatedAt:Date.now()};this.metaMem.set(`${e}@${t}`,i),await x(),await A(Cr(e,t),JSON.stringify(i))}};function Cr(r,e){return D.join(as,Ge(r),encodeURIComponent(e)+".json")}function Ge(r){return r.replace(/\//g,"__")}var Ir={async getJson(r){try{let e=await fetch(r,{redirect:"follow"});return e.ok?await e.json():void 0}catch{return}},async head(r){try{let e=await fetch(r,{method:"HEAD",redirect:"follow"});return{ok:e.ok,url:e.url}}catch{return}}};var ls=new ze,{packageService:Ye,versionResolver:Or,cdnClient:$r,peerResolver:Pa}=mr(ls,Ir);var Dr=`
264
265
  (() => {
265
266
  // Embedded (bulb-in-a-bulb): runs inside a sandboxed iframe with no parent
266
267
  // bridge, so privileged tb.* (AI, fs, server RPC) can't reach a host and would
@@ -470,12 +471,12 @@ declare const tb: {${gr}${yr}${br}${xr}${zn}${vr}${wr}
470
471
  };
471
472
  }
472
473
  })();
473
- `;function Fr(r){let{name:e,code:t,css:n,html:s,data:o,insight:i,importMap:a,watch:c,theme:l}=r,p=s.trim()||'<div id="app"></div>',d=m=>m.replace(/<\/script/gi,"<\\/script"),h={imports:us(a.imports)};return`<!DOCTYPE html>
474
+ `;function jr(r){let{name:e,code:t,css:n,html:s,data:o,insight:i,importMap:a,watch:c,theme:l}=r,p=s.trim()||'<div id="app"></div>',d=m=>m.replace(/<\/script/gi,"<\\/script"),h={imports:ps(a.imports)};return`<!DOCTYPE html>
474
475
  <html>
475
476
  <head>
476
477
  <meta charset="utf-8">
477
478
  <meta name="viewport" content="width=device-width, initial-scale=1">
478
- <title>${ds(e)} - typebulb</title>
479
+ <title>${us(e)} - typebulb</title>
479
480
  <script>
480
481
  // Theme engine. Sets html[data-theme] before stylesheets paint (no flash) and
481
482
  // exposes the tb.theme accessor via window.__tbTheme. The override is persisted
@@ -544,13 +545,13 @@ ${c?"<script>window.__TYPEBULB_WATCH__ = true;</script>":""}
544
545
  ${Dr}
545
546
  </script>
546
547
 
547
- ${ls}
548
+ ${ds}
548
549
 
549
550
  <script type="module">
550
551
  ${d(t)}
551
552
  </script>
552
553
  </body>
553
- </html>`}var ls=`<script>
554
+ </html>`}var ds=`<script>
554
555
  (function () {
555
556
  if (window.parent === window) return;
556
557
  var de = document.documentElement;
@@ -621,41 +622,47 @@ ${d(t)}
621
622
  }
622
623
  });
623
624
  })();
624
- </script>`;function ds(r){return r.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function us(r){let e={};for(let[t,n]of Object.entries(r))e[t]=n.startsWith("https://")?"/proxy/"+n:n;return e}import*as Xe from"fs/promises";import*as Ye from"path";import{existsSync as Mr,readFileSync as ps}from"fs";import{execFile as fs}from"child_process";import{promisify as hs}from"util";import{satisfies as ms}from"semver";var gs=hs(fs);async function Qe(r,e,t){let s=r.map(i=>ys(i,t)).filter(i=>!bs(i,e));if(s.length===0)return;await Xe.mkdir(e,{recursive:!0});let o=Ye.join(e,"package.json");Mr(o)||await Xe.writeFile(o,JSON.stringify({name:"typebulb-server",private:!0})),console.log(` Installing: ${s.join(", ")}`),await gs("npm",["install","--no-audit","--no-fund",...s],{cwd:e,shell:!0})}function ys(r,e){if(!e||Nr(r))return r;let t=e[r];return t?`${r}@${t}`:r}function bs(r,e){let t=Ye.join(e,"node_modules",jr(r));if(!Mr(t))return!1;let n=Nr(r);if(!n)return!0;try{let s=JSON.parse(ps(Ye.join(t,"package.json"),"utf-8")).version;return ms(s,n)}catch{return!1}}function Ze(r){let e=new Set,t=/\bimport\s+(?:[\s\S]*?\s+from\s+)?['"]([^./][^'"]*)['"]/g,n;for(;n=t.exec(r);){let s=n[1];if(s.includes(":"))continue;let o=s.startsWith("@")?s.split("/").slice(0,2).join("/"):s.split("/")[0];e.add(o)}return[...e]}function jr(r){if(r.startsWith("@")){let t=r.indexOf("/");if(t<0)return r;let n=r.indexOf("@",t+1);return n<0?r:r.slice(0,n)}let e=r.indexOf("@");return e<0?r:r.slice(0,e)}function Nr(r){let e=jr(r);return r.length>e.length?r.slice(e.length+1):""}async function Lr(r){let t=(await G.readdir(r)).find(n=>n.endsWith(".bulb.md"));return t?et.join(r,t):null}async function ue(r){let e=await G.readFile(r,"utf-8"),t=ar(e);if(!t)throw new Error("Invalid .bulb.md file format");let n=cr(t);return{bulb:n,config:dr(n.config)}}async function _t(r,e,t,n){let s=ht(r,{serverOnly:!0});if(s.error)throw new Error(`Server compilation error: ${s.error}`);let o=s.code;t&&(o=await sr(o,t));let i=et.join(e,".typebulb");await G.mkdir(i,{recursive:!0});let a=Ze(o);a.length>0&&await Qe(a,i,n);let c=et.join(i,"server.mjs");return await G.writeFile(c,o,"utf-8"),await import(`${vs(c).href}?t=${Date.now()}`)}async function Ct(r,e,t,n,s){let{bulb:o,config:i}=await ue(r),a=lr(o.data),c=ht(o.code,{jsxImportSource:i.jsxImportSource});c.error&&console.error("Compilation error:",c.error);let{importMap:l}=await Ke.buildImportMap(c.code,i.dependencies??{},n?new Set([n.name]):void 0);n&&(l.imports[n.name]=n.entryUrl);let p=Fr({name:o.name,code:c.code,css:o.css,html:o.html,data:a,insight:o.insight,importMap:l,watch:e}),d=null;return o.server&&t&&(d=await _t(o.server,s,n,i.dependencies)),{html:p,bulb:o,serverExports:d}}function At(r){if(r.server.trim())return"server-side code (server.ts)";let e=r.code;if(/\btb\s*\.\s*fs\b/.test(e)||e.includes("/__fs"))return"the filesystem";if(/\btb\s*\.\s*ai\b/.test(e)||e.includes("/__ai"))return"AI (your API keys)";if(/\btb\s*\.\s*server\s*\.\s*(?!log\b)\w/.test(e)||e.includes("/__api"))return"server-side code (server.ts)"}import{Hono as _s}from"hono";import{serve as Cs}from"@hono/node-server";import{streamSSE as As}from"hono/streaming";import*as re from"fs/promises";import*as M from"path";var O=class extends Error{constructor(e,t="unknown",n=!1){super(e),this.code=t,this.retryable=n}},F=class{getPath(e,t){return this.path}parseStreamChunk(e){return this.checkAndThrowError(e),this.parseProviderStreamChunk(e)}isReasoningEnabled(e){return e?.reasoning!==void 0&&e.reasoning>0}extractSystemMessages(e,t=`
625
+ </script>`;function us(r){return r.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function ps(r){let e={};for(let[t,n]of Object.entries(r))e[t]=n.startsWith("https://")?"/proxy/"+n:n;return e}import*as Xe from"fs/promises";import*as Ke from"path";import{existsSync as Fr,readFileSync as fs}from"fs";import{execFile as hs}from"child_process";import{promisify as ms}from"util";import{satisfies as gs}from"semver";var bs=ms(hs);async function Qe(r,e,t){let s=r.map(i=>ys(i,t)).filter(i=>!vs(i,e));if(s.length===0)return;await Xe.mkdir(e,{recursive:!0});let o=Ke.join(e,"package.json");Fr(o)||await Xe.writeFile(o,JSON.stringify({name:"typebulb-server",private:!0})),console.log(` Installing: ${s.join(", ")}`),await bs("npm",["install","--no-audit","--no-fund",...s],{cwd:e,shell:!0})}function ys(r,e){if(!e||Nr(r))return r;let t=e[r];return t?`${r}@${t}`:r}function vs(r,e){let t=Ke.join(e,"node_modules",Mr(r));if(!Fr(t))return!1;let n=Nr(r);if(!n)return!0;try{let s=JSON.parse(fs(Ke.join(t,"package.json"),"utf-8")).version;return gs(s,n)}catch{return!1}}function Ze(r){let e=new Set,t=/\bimport\s+(?:[\s\S]*?\s+from\s+)?['"]([^./][^'"]*)['"]/g,n;for(;n=t.exec(r);){let s=n[1];if(s.includes(":"))continue;let o=s.startsWith("@")?s.split("/").slice(0,2).join("/"):s.split("/")[0];e.add(o)}return[...e]}function Mr(r){if(r.startsWith("@")){let t=r.indexOf("/");if(t<0)return r;let n=r.indexOf("@",t+1);return n<0?r:r.slice(0,n)}let e=r.indexOf("@");return e<0?r:r.slice(0,e)}function Nr(r){let e=Mr(r);return r.length>e.length?r.slice(e.length+1):""}async function Lr(r){let t=(await z.readdir(r)).find(n=>n.endsWith(".bulb.md"));return t?et.join(r,t):null}async function pe(r){let e=await z.readFile(r,"utf-8"),t=ar(e);if(!t)throw new Error("Invalid .bulb.md file format");let n=cr(t);return{bulb:n,config:dr(n.config)}}async function _t(r,e,t,n){let s=ht(r,{serverOnly:!0});if(s.error)throw new Error(`Server compilation error: ${s.error}`);let o=s.code;t&&(o=await sr(o,t));let i=et.join(e,".typebulb");await z.mkdir(i,{recursive:!0});let a=Ze(o);a.length>0&&await Qe(a,i,n);let c=et.join(i,"server.mjs");return await z.writeFile(c,o,"utf-8"),await import(`${ws(c).href}?t=${Date.now()}`)}async function Ct(r,e,t,n,s){let{bulb:o,config:i}=await pe(r),a=lr(o.data),c=ht(o.code,{jsxImportSource:i.jsxImportSource});c.error&&console.error("Compilation error:",c.error);let{importMap:l}=await Ye.buildImportMap(c.code,i.dependencies??{},n?new Set([n.name]):void 0);n&&(l.imports[n.name]=n.entryUrl);let p=jr({name:o.name,code:c.code,css:o.css,html:o.html,data:a,insight:o.insight,importMap:l,watch:e}),d=null;return o.server&&t&&(d=await _t(o.server,s,n,i.dependencies)),{html:p,bulb:o,serverExports:d}}function At(r){if(r.server.trim())return"server-side code (server.ts)";let e=r.code;if(/\btb\s*\.\s*fs\b/.test(e)||e.includes("/__fs"))return"the filesystem";if(/\btb\s*\.\s*ai\b/.test(e)||e.includes("/__ai"))return"AI (your API keys)";if(/\btb\s*\.\s*server\s*\.\s*(?!log\b)\w/.test(e)||e.includes("/__api"))return"server-side code (server.ts)"}import{Hono as Cs}from"hono";import{serve as As}from"@hono/node-server";import{streamSSE as Is}from"hono/streaming";import*as ne from"fs/promises";import*as F from"path";var I=class extends Error{constructor(e,t="unknown",n=!1){super(e),this.code=t,this.retryable=n}},j=class{getPath(e,t){return this.path}parseStreamChunk(e){return this.checkAndThrowError(e),this.parseProviderStreamChunk(e)}isReasoningEnabled(e){return e?.reasoning!==void 0&&e.reasoning>0}extractSystemMessages(e,t=`
625
626
 
626
- `){let n=e.filter(s=>s.role==="system").map(s=>s.content);return{system:n.length?n.join(t):void 0,conversationMessages:e.filter(s=>s.role!=="system")}}parseJsonError(e,t,n=!1){if(!e)return{message:`HTTP ${t}`};try{let s=JSON.parse(e);if(s.error&&typeof s.error=="object"){let o={message:s.error.message||`HTTP ${t}`,type:s.error.type};return n&&(o.code=s.error.code),o}return s.message?{message:s.message}:{message:e}}catch{return{message:e}}}checkAndThrowError(e){if("type"in e&&e.type==="error"&&"message"in e){let t=e.message,n=e.code||"unknown",s=!!e.retryable;throw new O(t,n,s)}if("error"in e&&e.error){let t=this.extractErrorMessage(e.error);throw new O(t)}}extractErrorMessage(e){if(typeof e=="string")try{let t=JSON.parse(e);return t.error?.message||t.message||e}catch{return e}return typeof e=="object"&&e!==null?e.message||JSON.stringify(e):`${this.providerName} returned an error`}};var Ie=class extends F{constructor(){super(...arguments),this.providerName="Anthropic",this.defaultBaseUrl="https://api.anthropic.com",this.path="/v1/messages"}buildHeaders(e){return{"x-api-key":e,"anthropic-version":"2023-06-01","Content-Type":"application/json",Accept:"application/json"}}buildPayload(e,t,n,s){let{system:o,conversationMessages:i}=this.extractSystemMessages(e),a={model:t,max_tokens:this.getMaxTokens(t),messages:this.withLastMessageCached(i),stream:s};if(n?.webSearch!==!1&&(a.tools=[{type:"web_search_20250305",name:"web_search"}]),o&&(a.system=[{type:"text",text:o,cache_control:{type:"ephemeral"}}]),this.isReasoningEnabled(n)){let c=n.reasoning;if(this.isModernModel(t)){let l={0:"low",1:"low",2:"medium",3:"high"};a.thinking={type:"adaptive"},a.output_config={effort:l[c]}}else{let l={0:0,1:2048,2:4096,3:8192};a.thinking={type:"enabled",budget_tokens:l[c]}}}return a}parseError(e,t){return this.parseJsonError(e,t)}parseNonStreamingResponse(e){if(!this.isAnthropicResponse(e))return{text:""};let t=e.content.filter(s=>s.type==="text").map(s=>s.text).join(""),n=e.content.filter(s=>s.type==="thinking").map(s=>s.thinking).join(`
627
+ `){let n=e.filter(s=>s.role==="system").map(s=>s.content);return{system:n.length?n.join(t):void 0,conversationMessages:e.filter(s=>s.role!=="system")}}parseJsonError(e,t,n=!1){if(!e)return{message:`HTTP ${t}`};try{let s=JSON.parse(e);if(s.error&&typeof s.error=="object"){let o={message:s.error.message||`HTTP ${t}`,type:s.error.type};return n&&(o.code=s.error.code),o}return s.message?{message:s.message}:{message:e}}catch{return{message:e}}}checkAndThrowError(e){if("type"in e&&e.type==="error"&&"message"in e){let t=e.message,n=e.code||"unknown",s=!!e.retryable;throw new I(t,n,s)}if("error"in e&&e.error){let t=this.extractErrorMessage(e.error);throw new I(t)}}extractErrorMessage(e){if(typeof e=="string")try{let t=JSON.parse(e);return t.error?.message||t.message||e}catch{return e}return typeof e=="object"&&e!==null?e.message||JSON.stringify(e):`${this.providerName} returned an error`}};var Oe=class extends j{constructor(){super(...arguments),this.providerName="Anthropic",this.defaultBaseUrl="https://api.anthropic.com",this.path="/v1/messages"}buildHeaders(e){return{"x-api-key":e,"anthropic-version":"2023-06-01","Content-Type":"application/json",Accept:"application/json"}}buildPayload(e,t,n,s){let{system:o,conversationMessages:i}=this.extractSystemMessages(e),a={model:t,max_tokens:this.getMaxTokens(t),messages:this.withLastMessageCached(i),stream:s};if(n?.webSearch!==!1&&(a.tools=[{type:"web_search_20250305",name:"web_search"}]),o&&(a.system=[{type:"text",text:o,cache_control:{type:"ephemeral"}}]),this.isReasoningEnabled(n)){let c=n.reasoning;if(this.isModernModel(t)){let l={0:"low",1:"low",2:"medium",3:"high"};a.thinking={type:"adaptive"},a.output_config={effort:l[c]}}else{let l={0:0,1:2048,2:4096,3:8192};a.thinking={type:"enabled",budget_tokens:l[c]}}}return a}parseError(e,t){return this.parseJsonError(e,t)}parseNonStreamingResponse(e){if(!this.isAnthropicResponse(e))return{text:""};let t=e.content.filter(s=>s.type==="text").map(s=>s.text).join(""),n=e.content.filter(s=>s.type==="thinking").map(s=>s.thinking).join(`
627
628
 
628
- `);return{text:t,reasoning:n||void 0}}parseProviderStreamChunk(e){if(!("type"in e))return null;switch(e.type){case"content_block_delta":return e.delta.type==="text_delta"?{text:e.delta.text||""}:e.delta.type==="thinking_delta"?{reasoning:e.delta.thinking||""}:null;case"message_start":case"content_block_start":case"content_block_stop":case"message_delta":case"message_stop":case"ping":return null;default:return null}}withLastMessageCached(e){let t=e.length-1;return e.map((n,s)=>s===t?{role:n.role,content:[{type:"text",text:n.content,cache_control:{type:"ephemeral"}}]}:n)}isAnthropicResponse(e){return"content"in e&&Array.isArray(e.content)&&"type"in e&&e.type==="message"}isModernModel(e){let t=e.match(/^claude-\w+-(\d+)-(\d+)/);return!!t&&(+t[1]>4||+t[1]==4&&+t[2]>=6)}getMaxTokens(e){return this.isModernModel(e)?64e3:32e3}};var $e=class extends F{constructor(){super(...arguments),this.providerName="OpenAI",this.defaultBaseUrl="https://api.openai.com",this.path="/v1/responses",this.effortMap={0:"minimal",1:"low",2:"medium",3:"high"}}buildHeaders(e){return{Authorization:`Bearer ${e}`,"Content-Type":"application/json",Accept:"application/json"}}buildPayload(e,t,n,s){let o=this.convertMessagesToInput(e),i={model:t,input:o,stream:s};return n?.webSearch!==!1&&(i.tools=[{type:"web_search"}]),this.isReasoningEnabled(n)&&(i.reasoning={effort:this.effortMap[n.reasoning],summary:"auto"}),i}parseError(e,t){return this.parseJsonError(e,t,!0)}parseNonStreamingResponse(e){if(!this.isResponsesApiResponse(e))return{text:""};let t=e.output_text||"",n;if(e.output&&Array.isArray(e.output))for(let s of e.output)s.type==="reasoning"&&s.summary&&(n=s.summary.map(o=>o.text).join(`
629
- `)),!t&&s.type==="message"&&s.content&&(t=s.content.filter(o=>o.type==="output_text").map(o=>o.text).join(""));return{text:t,reasoning:n}}parseProviderStreamChunk(e){if(!this.isResponsesApiEvent(e))return null;switch(e.type){case"error":return null;case"response.failed":{let s=e.response?.error,o=s?.message||"Response failed",i=s?.code==="insufficient_quota"||s?.code==="rate_limit_exceeded";throw new O(o,i?"rate_limit":"unknown",i)}case"response.output_text.delta":return{text:e.delta};case"response.reasoning_summary_text.delta":return{reasoning:e.delta};case"response.created":case"response.in_progress":case"response.output_item.added":case"response.output_item.done":case"response.content_part.added":case"response.content_part.done":case"response.output_text.done":case"response.output_text.annotation.added":case"response.reasoning_summary_text.done":case"response.completed":case"response.web_search_call.in_progress":case"response.web_search_call.searching":case"response.web_search_call.completed":return null;default:return null}}convertMessagesToInput(e){return e.map(t=>t.role==="system"?`System: ${t.content}`:t.role==="user"?`User: ${t.content}`:t.role==="assistant"?`Assistant: ${t.content}`:t.content).join(`
629
+ `);return{text:t,reasoning:n||void 0}}parseProviderStreamChunk(e){if(!("type"in e))return null;switch(e.type){case"content_block_delta":return e.delta.type==="text_delta"?{text:e.delta.text||""}:e.delta.type==="thinking_delta"?{reasoning:e.delta.thinking||""}:null;case"message_start":case"content_block_start":case"content_block_stop":case"message_delta":case"message_stop":case"ping":return null;default:return null}}withLastMessageCached(e){let t=e.length-1;return e.map((n,s)=>s===t?{role:n.role,content:[{type:"text",text:n.content,cache_control:{type:"ephemeral"}}]}:n)}isAnthropicResponse(e){return"content"in e&&Array.isArray(e.content)&&"type"in e&&e.type==="message"}isModernModel(e){let t=e.match(/^claude-\w+-(\d+)-(\d+)/);return!!t&&(+t[1]>4||+t[1]==4&&+t[2]>=6)}getMaxTokens(e){return this.isModernModel(e)?64e3:32e3}};var $e=class extends j{constructor(){super(...arguments),this.providerName="OpenAI",this.defaultBaseUrl="https://api.openai.com",this.path="/v1/responses",this.effortMap={0:"minimal",1:"low",2:"medium",3:"high"}}buildHeaders(e){return{Authorization:`Bearer ${e}`,"Content-Type":"application/json",Accept:"application/json"}}buildPayload(e,t,n,s){let o=this.convertMessagesToInput(e),i={model:t,input:o,stream:s};return n?.webSearch!==!1&&(i.tools=[{type:"web_search"}]),this.isReasoningEnabled(n)&&(i.reasoning={effort:this.effortMap[n.reasoning],summary:"auto"}),i}parseError(e,t){return this.parseJsonError(e,t,!0)}parseNonStreamingResponse(e){if(!this.isResponsesApiResponse(e))return{text:""};let t=e.output_text||"",n;if(e.output&&Array.isArray(e.output))for(let s of e.output)s.type==="reasoning"&&s.summary&&(n=s.summary.map(o=>o.text).join(`
630
+ `)),!t&&s.type==="message"&&s.content&&(t=s.content.filter(o=>o.type==="output_text").map(o=>o.text).join(""));return{text:t,reasoning:n}}parseProviderStreamChunk(e){if(!this.isResponsesApiEvent(e))return null;switch(e.type){case"error":return null;case"response.failed":{let s=e.response?.error,o=s?.message||"Response failed",i=s?.code==="insufficient_quota"||s?.code==="rate_limit_exceeded";throw new I(o,i?"rate_limit":"unknown",i)}case"response.output_text.delta":return{text:e.delta};case"response.reasoning_summary_text.delta":return{reasoning:e.delta};case"response.created":case"response.in_progress":case"response.output_item.added":case"response.output_item.done":case"response.content_part.added":case"response.content_part.done":case"response.output_text.done":case"response.output_text.annotation.added":case"response.reasoning_summary_text.done":case"response.completed":case"response.web_search_call.in_progress":case"response.web_search_call.searching":case"response.web_search_call.completed":return null;default:return null}}convertMessagesToInput(e){return e.map(t=>t.role==="system"?`System: ${t.content}`:t.role==="user"?`User: ${t.content}`:t.role==="assistant"?`Assistant: ${t.content}`:t.content).join(`
630
631
 
631
- `)}isResponsesApiEvent(e){return"type"in e&&typeof e.type=="string"}isResponsesApiResponse(e){return"object"in e&&e.object==="response"}};var De=class extends F{constructor(){super(...arguments),this.providerName="Gemini",this.defaultBaseUrl="https://generativelanguage.googleapis.com",this.path="/v1beta/models"}getPath(e,t){return`/v1beta/models/${e}:${t?"streamGenerateContent":"generateContent"}${t?"?alt=sse":""}`}buildHeaders(e){return{"Content-Type":"application/json","x-goog-api-key":e}}buildPayload(e,t,n,s){let{system:o,conversationMessages:i}=this.extractSystemMessages(e,`
632
+ `)}isResponsesApiEvent(e){return"type"in e&&typeof e.type=="string"}isResponsesApiResponse(e){return"object"in e&&e.object==="response"}};var De=class extends j{constructor(){super(...arguments),this.providerName="Gemini",this.defaultBaseUrl="https://generativelanguage.googleapis.com",this.path="/v1beta/models"}getPath(e,t){return`/v1beta/models/${e}:${t?"streamGenerateContent":"generateContent"}${t?"?alt=sse":""}`}buildHeaders(e){return{"Content-Type":"application/json","x-goog-api-key":e}}buildPayload(e,t,n,s){let{system:o,conversationMessages:i}=this.extractSystemMessages(e,`
632
633
  `),c={contents:i.map(l=>({role:l.role==="assistant"?"model":"user",parts:[{text:l.content}]}))};return n?.webSearch!==!1&&(c.tools=[{google_search:{}}]),o&&(c.systemInstruction={role:"system",parts:[{text:o}]}),this.isReasoningEnabled(n)&&(c.generationConfig={temperature:.7+n.reasoning*.1}),c}parseError(e,t){if(!e)return{message:`HTTP ${t}`};try{let n=JSON.parse(e),s=Array.isArray(n)?n[0]?.error:n?.error;return s&&typeof s=="object"?{message:(s.message||`HTTP ${t}`).split(`
633
- `)[0],type:s.status,code:s.code?.toString()}:n.message?{message:n.message}:{message:e}}catch{return{message:e}}}parseNonStreamingResponse(e){if(this.checkGeminiError(e),!this.isGeminiResponse(e))return{text:"",status:"failed",error:"Invalid response format"};let t=this.extractText(e)||"",n=e.candidates?.[0]?.finishReason,s="complete";return n==="MAX_TOKENS"?s="interrupted":(n==="SAFETY"||n==="RECITATION")&&(s="failed"),{text:t,status:s}}parseProviderStreamChunk(e){if(this.checkGeminiError(e),!this.isGeminiResponse(e))return null;let t=this.extractText(e);return t?{text:t}:null}isGeminiResponse(e){return typeof e=="object"&&e!==null&&"candidates"in e&&Array.isArray(e.candidates)}extractText(e){let t=e.candidates?.[0];if(t?.content?.parts)return t.content.parts.map(n=>n.text).filter(Boolean).join("")}checkGeminiError(e){if(typeof e=="object"&&e!==null&&"error"in e){let t=e.error,n;if(typeof t=="string")n=t;else if(typeof t=="object"&&t!==null){let s=t;n=s.message||s.status||"Gemini returned an error"}else n="Gemini returned an error";throw new O(n)}if(this.isGeminiResponse(e)&&e.promptFeedback?.blockReason){let t=e.promptFeedback.blockReason;throw new O(`Prompt blocked: ${t}`)}}};var Fe=class extends F{constructor(){super(...arguments),this.providerName="OpenRouter",this.defaultBaseUrl="https://openrouter.ai/api",this.path="/api/v1/chat/completions",this.effortMap={0:"low",1:"low",2:"medium",3:"high"}}buildHeaders(e,t){let n={Authorization:`Bearer ${e}`,"x-api-key":e,"Content-Type":"application/json",Accept:"application/json","X-Title":"Typebulb"};return t&&(n["HTTP-Referer"]=t,n.Referer=t,n.Origin=t),n}buildPayload(e,t,n,s){let o={model:t,messages:e,stream:s};return n?.webSearch===!0&&(o.plugins=[{id:"web"}]),this.isReasoningEnabled(n)&&(o.reasoning={effort:this.effortMap[n.reasoning]}),o}parseError(e,t){return this.parseJsonError(e,t,!0)}parseNonStreamingResponse(e){if(!this.hasChoices(e))return{text:""};let t=e.choices[0],n=t?.message?.content??t?.text??"",s=t?.message?.reasoning??e.reasoning;return{text:n,reasoning:s}}parseProviderStreamChunk(e){if(!this.hasChoices(e))return null;let t=e.choices[0];if(!t)return null;let n=t.delta||t.message;if(!n)return null;let s=n.content||void 0,o=n.reasoning||void 0;return!s&&!o?null:{text:s,reasoning:o}}hasChoices(e){return typeof e=="object"&&e!==null&&"choices"in e&&Array.isArray(e.choices)}};var ws=new Map([["openai",new $e],["openrouter",new Fe],["anthropic",new Ie],["gemini",new De]]);function ee(r){let e=ws.get(r);if(!e)throw new Error(`Unsupported protocol: ${r}`);return e}async function Ot(r,e){let t=ee(r.protocol),n=t.getPath(e.model,e.stream),s=new URL(n,r.baseUrl).toString(),o=t.buildHeaders(r.apiKey,e.origin),i=t.buildPayload(e.messages,e.model,{reasoning:e.reasoning,webSearch:e.webSearch},e.stream);return e.modifyPayload?.(i),fetch(s,{method:"POST",headers:o,body:JSON.stringify(i),signal:e.signal})}async function It(r,e){let t=ee(e),n=await r.text().catch(()=>""),{message:s}=t.parseError(n,r.status),o=r.status,i="unknown";return o===429?i="rate_limit":o===413&&(i="context_exceeded"),{code:i,message:s,retryable:o===429}}function Br(r){let e=r.indexOf(`\r
634
+ `)[0],type:s.status,code:s.code?.toString()}:n.message?{message:n.message}:{message:e}}catch{return{message:e}}}parseNonStreamingResponse(e){if(this.checkGeminiError(e),!this.isGeminiResponse(e))return{text:"",status:"failed",error:"Invalid response format"};let t=this.extractText(e)||"",n=e.candidates?.[0]?.finishReason,s="complete";return n==="MAX_TOKENS"?s="interrupted":(n==="SAFETY"||n==="RECITATION")&&(s="failed"),{text:t,status:s}}parseProviderStreamChunk(e){if(this.checkGeminiError(e),!this.isGeminiResponse(e))return null;let t=this.extractText(e);return t?{text:t}:null}isGeminiResponse(e){return typeof e=="object"&&e!==null&&"candidates"in e&&Array.isArray(e.candidates)}extractText(e){let t=e.candidates?.[0];if(t?.content?.parts)return t.content.parts.map(n=>n.text).filter(Boolean).join("")}checkGeminiError(e){if(typeof e=="object"&&e!==null&&"error"in e){let t=e.error,n;if(typeof t=="string")n=t;else if(typeof t=="object"&&t!==null){let s=t;n=s.message||s.status||"Gemini returned an error"}else n="Gemini returned an error";throw new I(n)}if(this.isGeminiResponse(e)&&e.promptFeedback?.blockReason){let t=e.promptFeedback.blockReason;throw new I(`Prompt blocked: ${t}`)}}};var je=class extends j{constructor(){super(...arguments),this.providerName="OpenRouter",this.defaultBaseUrl="https://openrouter.ai/api",this.path="/api/v1/chat/completions",this.effortMap={0:"low",1:"low",2:"medium",3:"high"}}buildHeaders(e,t){let n={Authorization:`Bearer ${e}`,"x-api-key":e,"Content-Type":"application/json",Accept:"application/json","X-Title":"Typebulb"};return t&&(n["HTTP-Referer"]=t,n.Referer=t,n.Origin=t),n}buildPayload(e,t,n,s){let o={model:t,messages:e,stream:s};return n?.webSearch===!0&&(o.plugins=[{id:"web"}]),this.isReasoningEnabled(n)&&(o.reasoning={effort:this.effortMap[n.reasoning]}),o}parseError(e,t){return this.parseJsonError(e,t,!0)}parseNonStreamingResponse(e){if(!this.hasChoices(e))return{text:""};let t=e.choices[0],n=t?.message?.content??t?.text??"",s=t?.message?.reasoning??e.reasoning;return{text:n,reasoning:s}}parseProviderStreamChunk(e){if(!this.hasChoices(e))return null;let t=e.choices[0];if(!t)return null;let n=t.delta||t.message;if(!n)return null;let s=n.content||void 0,o=n.reasoning||void 0;return!s&&!o?null:{text:s,reasoning:o}}hasChoices(e){return typeof e=="object"&&e!==null&&"choices"in e&&Array.isArray(e.choices)}};var xs=new Map([["openai",new $e],["openrouter",new je],["anthropic",new Oe],["gemini",new De]]);function ee(r){let e=xs.get(r);if(!e)throw new Error(`Unsupported protocol: ${r}`);return e}async function It(r,e){let t=ee(r.protocol),n=t.getPath(e.model,e.stream),s=new URL(n,r.baseUrl).toString(),o=t.buildHeaders(r.apiKey,e.origin),i=t.buildPayload(e.messages,e.model,{reasoning:e.reasoning,webSearch:e.webSearch},e.stream);return e.modifyPayload?.(i),fetch(s,{method:"POST",headers:o,body:JSON.stringify(i),signal:e.signal})}async function Ot(r,e){let t=ee(e),n=await r.text().catch(()=>""),{message:s}=t.parseError(n,r.status),o=r.status,i="unknown";return o===429?i="rate_limit":o===413&&(i="context_exceeded"),{code:i,message:s,retryable:o===429}}function Br(r){let e=r.indexOf(`\r
634
635
  \r
635
636
  `),t=r.indexOf(`
636
637
 
637
638
  `);return e!==-1&&(t===-1||e<t)?{pos:e,len:4}:t!==-1?{pos:t,len:2}:{pos:-1,len:0}}function $t(r){let t=r.split(/\r?\n/).filter(s=>s.startsWith("data:"));if(!t.length)return null;let n=t.map(s=>s.replace(/^data:\s?/,"")).join(`
638
- `).trim();if(!n)return null;if(n==="[DONE]")return"done";try{return JSON.parse(n)}catch{return null}}async function Ur(r,e,t){let n=new TextDecoder,s="",o=!1,i=t?new Promise((a,c)=>{t.aborted&&c(new Error("Aborted")),t.addEventListener("abort",()=>c(new Error("Aborted")),{once:!0})}):null;for(;;){let a=i?await Promise.race([r.read(),i]):await r.read(),{done:c,value:l}=a;if(c){if(s.trim()){let h=$t(s);h!==null&&h!=="done"&&e(h)}break}o=!0,s+=n.decode(l,{stream:!0});let{pos:p,len:d}=Br(s);for(;p!==-1;){let h=s.slice(0,p);s=s.slice(p+d);let m=$t(h);if(m==="done"){s="";break}m!==null&&e(m),{pos:p,len:d}=Br(s)}}return{receivedAnyData:o}}async function Dt(r,e){let t=e??(r.headers.get("X-Provider-Protocol")||"openai"),n=ee(t);if(!r.body)throw new Error("Response body is missing");let s=r.body.getReader(),o="";return await Ur(s,i=>{let a=n.parseStreamChunk(i);a?.text&&(o+=a.text)}),o}import*as Ft from"fs/promises";import*as Me from"path";var tt=class{async get(e){let t=$(e),n=Me.join(Oe,t+".bin"),s=Me.join(Oe,t+".json");try{let[o,i]=await Promise.all([Ft.readFile(n),Ft.readFile(s,"utf8")]),a=JSON.parse(i);return{body:o,contentType:a.contentType,cacheControl:a.cacheControl}}catch{return}}async set(e,t){await x();let n=$(e),s=Me.join(Oe,n+".bin"),o=Me.join(Oe,n+".json"),i={url:e,contentType:t.contentType,cacheControl:t.cacheControl};await Promise.all([A(s,t.body),A(o,JSON.stringify(i))])}};import{readdir as Rs,readFile as Vr,writeFile as qr,unlink as je,mkdir as Ps}from"fs/promises";import{mkdirSync as Es,writeFileSync as Jr,appendFileSync as ks,readFileSync as zr}from"fs";import*as pe from"path";import{join as Mt,resolve as xs}from"path";import{homedir as Ss}from"os";function rt(){let r=process.env.TYPEBULB_SERVERS_DIR;return r?Mt(r,".."):Mt(Ss(),".typebulb")}function te(){return process.env.TYPEBULB_SERVERS_DIR||Mt(rt(),"servers")}function K(r){let e=xs(r);return(process.platform==="win32"?e.toLowerCase():e).replace(/\\/g,"/")}function Wr(r,e){let t=K(r),n=K(e);return t.startsWith(n.endsWith("/")?n:n+"/")?!t.includes("/node_modules/"):!1}var Hr=1e6;function jt(r){return pe.join(te(),`${r}.json`)}function nt(r){return pe.join(te(),`${r}.log`)}function Gr(r){let e=nt(r);try{Es(te(),{recursive:!0}),Jr(e,"")}catch{return()=>{}}let t=process.stdout.write.bind(process.stdout),n=process.stderr.write.bind(process.stderr),s=0,o=!1,i=a=>{if(!o)try{let c=typeof a=="string"?Buffer.from(a,"utf8"):Buffer.from(a);if(ks(e,c),s+=c.length,s>2*Hr){let l=zr(e),p=l.subarray(Math.max(0,l.length-Hr));Jr(e,p),s=p.length}}catch{o=!0}};return process.stdout.write=((a,...c)=>(i(a),t(a,...c))),process.stderr.write=((a,...c)=>(i(a),n(a,...c))),()=>{process.stdout.write=t,process.stderr.write=n}}function Nt(r,e=0){try{let t=zr(nt(r)),n=e>=0&&e<=t.length?e:0;return{text:t.subarray(n).toString("utf8"),offset:t.length}}catch{return{text:"",offset:0}}}function Ts(r){try{return process.kill(r,0),!0}catch(e){return e.code==="EPERM"}}async function Kr(r){await Ps(te(),{recursive:!0}),await qr(jt(r.pid),JSON.stringify(r))}async function Yr(r,e){let t=jt(r);try{let n=JSON.parse(await Vr(t,"utf8"));if(n.denied===e)return;n.denied=e,await qr(t,JSON.stringify(n))}catch{}}async function Lt(r){await je(jt(r)).catch(()=>{}),await je(nt(r)).catch(()=>{})}async function fe(r){let e;try{e=await Rs(te())}catch{return[]}let t=[];return await Promise.all(e.map(async s=>{if(!s.endsWith(".json"))return;let o=pe.join(te(),s),i;try{i=JSON.parse(await Vr(o,"utf8"))}catch{await je(o).catch(()=>{});return}i&&typeof i.pid=="number"&&Ts(i.pid)?t.push(i):(await je(o).catch(()=>{}),i?.pid&&await je(nt(i.pid)).catch(()=>{}))})),(r?t.filter(s=>Wr(s.file,r)):t).sort((s,o)=>s.startedAt-o.startedAt)}async function Xr(r){try{process.kill(r,"SIGTERM")}catch{}await Lt(r)}var en="127.0.0.1",Os=new Set(["localhost","127.0.0.1","::1"]);function Is(r){if(r)try{return new URL(r.includes("://")?r:`http://${r}`).hostname}catch{return}}function Qr(r){let e=Is(r);return!!e&&Os.has(e)}function st(r){return r instanceof Error?r.message:"Unknown error"}async function tn(r){let{getHtml:e,basePath:t,port:n,reloadEmitter:s,getServerExports:o,localOverride:i,trusted:a=!1,trustHint:c}=r,l=new _s;l.use("*",async(u,f)=>{if(!Qr(u.req.header("host")))return u.text("Forbidden: untrusted Host",403);await f()}),l.use("*",async(u,f)=>{await f(),u.res.headers.set("Cross-Origin-Opener-Policy","same-origin"),u.res.headers.set("Cross-Origin-Embedder-Policy","credentialless")});let p=["/__fs/*","/__api/*","/__ai"],d=async(u,f)=>{if(!a){let y=new URL(u.req.url).pathname,w=y.startsWith("/__fs")?"the filesystem":y==="/__ai"?"AI (your API keys)":"server-side code (server.ts)";Yr(process.pid,w);let v=c?`
639
- ${c}`:"";return u.text(`Forbidden: this capability requires --trust.${v}`,403)}await f()},h=async(u,f)=>{let y=u.req.header("sec-fetch-site");if(y){if(y==="cross-site")return u.text("Forbidden: cross-site request",403)}else{let w=u.req.header("origin");if(w&&!Qr(w))return u.text("Forbidden: cross-origin request",403)}await f()};for(let u of p)l.use(u,d),l.use(u,h);l.use("/__log",h),l.post("/__log",async u=>{try{let{args:f}=await u.req.json();console.log(...f||[])}catch{}return u.json({ok:!0})}),l.get("/",u=>u.html(e())),l.post("/__fs/read",async u=>{try{let{path:f}=await u.req.json(),y=Ut(f,t),w=await re.readFile(y);return new Response(new Uint8Array(w),{headers:{"Content-Type":"application/octet-stream"}})}catch(f){let y=st(f);return u.json({error:y},400)}}),l.post("/__fs/write",async u=>{try{let f=u.req.query("path");if(!f)return u.json({error:"Missing path"},400);let y=Ut(f,t);return await re.mkdir(M.dirname(y),{recursive:!0}),await re.writeFile(y,Buffer.from(await u.req.arrayBuffer())),u.json({success:!0})}catch(f){let y=st(f);return u.json({error:y},400)}});let m={log:console.log};l.post("/__api/:name",async u=>{try{let f=o?.(),y=u.req.param("name"),w=f?.[y]??m[y];if(!w||typeof w!="function")return u.json({error:`API function '${y}' not found`},404);let{args:v}=await u.req.json(),_=await w(...v||[]);return u.json({result:_})}catch(f){let y=st(f);return u.json({error:y},500)}}),l.post("/__ai",async u=>{try{let{messages:f,system:y,reasoning:w,provider:v,model:_,webSearch:H}=await u.req.json();if(!f||!Array.isArray(f)||f.length===0)return u.json({message:"messages array is required",code:"unknown",retryable:!1},400);let N=$s(v,_);if(typeof N=="string")return u.json({message:N,code:"unknown",retryable:!1},400);let ct=[...y?[{role:"system",content:y}]:[],...f.map(Le=>({role:Le.role,content:Le.content}))],ne=await Ot(N,{model:N.model,messages:ct,stream:!0,reasoning:w??0,webSearch:H??!0});if(!ne.ok){let Le=await It(ne,N.protocol);return u.json(Le,ne.status)}let Yt=await Dt(ne,N.protocol);return Yt||console.warn("[tb.ai] Empty response from provider"),u.json({text:Yt})}catch(f){if(f instanceof O)return u.json({message:f.message,code:f.code,retryable:f.retryable},500);let y=st(f);return u.json({message:y,code:"unknown",retryable:!1},500)}}),l.get("/__models",async u=>{try{let f=await Ms();return u.json(f)}catch{return u.json([],200)}});let g=["esm.sh","unpkg.com","cdn.jsdelivr.net","cdnjs.cloudflare.com"],R=new tt;if(l.get("/proxy/*",async u=>{let f=new URL(u.req.url),w=(f.pathname+f.search).slice(7),v=w.lastIndexOf("https://");return v===-1?u.text("Invalid proxy URL",400):j(u,w.slice(v))}),i){let u=`/local/${i.name}/`;l.get("/local/*",async f=>{let{pathname:y}=new URL(f.req.url);if(!y.startsWith(u))return f.text("Not Found",404);let w=decodeURIComponent(y.slice(u.length));try{let v=Ut(w,i.serveDir),_=await re.readFile(v);return new Response(_,{headers:{"Content-Type":js(v)}})}catch{return f.text("Not Found",404)}})}async function j(u,f){let y;try{y=new URL(f)}catch{return u.text("Invalid URL",400)}if(y.protocol!=="https:")return u.text("HTTPS only",400);if(!g.includes(y.hostname))return u.text("Host not allowed",403);let w=await R.get(f);if(w)return new Response(w.body,{status:200,headers:Bt(w.contentType,w.cacheControl)});try{let v=await fetch(f,{headers:{Accept:u.req.header("Accept")||"*/*"},redirect:"follow"});if(!v.ok)return u.text(`Upstream ${v.status}`,v.status);let _=v.headers.get("Content-Type")||void 0,H=v.headers.get("Cache-Control")||void 0;if(v.body){let[N,ct]=v.body.tee();return(async()=>{try{let ne=await new Response(ct).arrayBuffer();await R.set(f,{body:Buffer.from(ne),contentType:_,cacheControl:H})}catch{}})(),new Response(N,{status:v.status,headers:Bt(_,H)})}return new Response(null,{status:v.status,headers:Bt(_,H)})}catch(v){return u.text(`Proxy fetch failed: ${v instanceof Error?v.message:v}`,502)}}s&&l.get("/__reload",u=>As(u,async f=>{let y=()=>{f.writeSSE({event:"reload",data:""})};for(s.on("reload",y),f.onAbort(()=>{s.removeListener("reload",y)});;)await f.sleep(3e4)}));let B=/^\/(v\d+\/|stable\/|node\/|gh\/|@[^/]+\/[^@/]+@|[^@/]+@)/;l.notFound(async u=>{if(u.req.method!=="GET")return u.text("Not Found",404);let f=new URL(u.req.url);return B.test(f.pathname)?j(u,"https://esm.sh"+f.pathname+f.search):u.text("Not Found",404)});let C=Cs({fetch:l.fetch,port:n,hostname:en});return{port:n,close:()=>C.close()}}var rn={anthropic:"ANTHROPIC_API_KEY",openai:"OPENAI_API_KEY",gemini:"GOOGLE_API_KEY",openrouter:"OPENROUTER_API_KEY"};function $s(r,e){let t=r??process.env.TB_AI_PROVIDER,n=e??process.env.TB_AI_MODEL;if(!t)return"No provider specified. Set TB_AI_PROVIDER in your .env file or pass provider in the tb.ai() call.";if(!n)return"No model specified. Set TB_AI_MODEL in your .env file or pass model in the tb.ai() call.";let s;try{s=ee(t)}catch{return`Unknown provider '${t}'.`}let o=rn[t],i=process.env[o];return i?{apiKey:i,baseUrl:s.defaultBaseUrl,protocol:t,model:n,isFreeModel:!1}:`No API key for '${t}'. Set ${o} in your .env file.`}var Ds="https://api.typebulb.com/api/models",Fs=1440*60*1e3,he=null;async function Ms(){if(!he||Date.now()-he.fetchedAt>Fs){let r=await fetch(Ds);if(!r.ok)return he?Zr(he.models):[];he={models:await r.json(),fetchedAt:Date.now()}}return Zr(he.models)}function Zr(r){let e=new Set(Object.entries(rn).filter(([,t])=>!!process.env[t]).map(([t])=>t));return r.filter(t=>e.has(t.provider))}function Bt(r,e){let t=new Headers;return r&&t.set("Content-Type",r),e&&t.set("Cache-Control",e),t.set("Access-Control-Allow-Origin","*"),t.set("Cross-Origin-Resource-Policy","cross-origin"),t}function js(r){switch(M.extname(r).toLowerCase()){case".js":case".mjs":return"text/javascript";case".wasm":return"application/wasm";case".json":case".map":return"application/json";default:return"application/octet-stream"}}function Ut(r,e){let t=M.resolve(e,r),n=M.normalize(e),s=M.normalize(t);if(s!==n&&!s.startsWith(n+M.sep))throw new Error("Path traversal detected - access denied");return t}async function Wt(r){let e=await import("net");return new Promise(t=>{let n=e.createServer();n.listen(r,en,()=>{let s=n.address(),o=typeof s=="object"&&s?s.port:r;n.close(()=>t(o))}),n.on("error",()=>{t(Wt(r+1))})})}import Ns from"open";async function nn(r){await Ns(r)}import sn from"chokidar";var on={persistent:!0,ignoreInitial:!0,awaitWriteFinish:{stabilityThreshold:100,pollInterval:50}};function Jt(r){let{bulbPath:e,emitter:t}=r,n=sn.watch(e,on);return n.on("change",()=>{t.emit("reload")}),()=>n.close()}function an(r){let{dir:e,onChange:t,debounceMs:n=150}=r,s,o=sn.watch(e,on);return o.on("all",()=>{s&&clearTimeout(s),s=setTimeout(t,n)}),()=>{s&&clearTimeout(s),o.close()}}import*as k from"fs/promises";import*as E from"path";import*as me from"path";var Ls=me.join(Ve,"pkg"),Bs=me.join(Ve,"files"),Us=me.join(Ve,"negative.json"),it=class{pkgMem=new Map;fileMem=new Map;negativeCache=new Q(new le(Us));async getCachedDts(e){if(this.pkgMem.has(e))return this.pkgMem.get(e);await x();let t=await Z(cn(e));return this.pkgMem.set(e,t),t}async setCachedDts(e,t,n){let s={content:t,url:n};this.pkgMem.set(e,s),await ot(async()=>{await x(),await A(cn(e),JSON.stringify(s))})}async getCachedFile(e){if(this.fileMem.has(e))return this.fileMem.get(e);await x();let t=await He(ln(e));return this.fileMem.set(e,t),t}async setCachedFile(e,t){this.fileMem.set(e,t),await ot(async()=>{await x(),await A(ln(e),t)})}isNegative(e){return this.negativeCache.isNegative(e)}async recordNegative(e){await ot(async()=>{await x(),await this.negativeCache.recordNegative(e)})}clearNegative(e){return ot(()=>this.negativeCache.clearNegative(e))}};async function ot(r){try{await r()}catch{}}function cn(r){return me.join(Ls,$(r)+".json")}function ln(r){return me.join(Bs,$(r)+".txt")}var Ht;function Ws(){return Ht||(Ht=Pt({cache:new it,cdnClient:$r,packageService:Ke,versionResolver:Ir})),Ht}var dn="file:///node_modules/";async function un(r){let e=qe(r.emitKey,"typecheck");await x(),await k.rm(e,{recursive:!0,force:!0}),await k.mkdir(e,{recursive:!0});let t=qs(r.jsxImportSource,r.dependencies),n=await Ws().resolve(r.code,r.dependencies,t),s=r.local?.name,o=s?n.filter(p=>p.pkg!==s):n,i=new Set;for(let p of o)for(let d of p.files){let h=at(d.path);if(!h||i.has(h))continue;i.add(h);let m=E.join(e,"node_modules",h);await k.mkdir(E.dirname(m),{recursive:!0}),await k.writeFile(m,d.content,"utf8")}let a={};for(let p of o)for(let d of p.shims){let h=at(d.path);h&&(a[d.module]=[`./node_modules/${h}`])}for(let p of o){if(p.ambient)continue;let d=at(p.mainPath);d&&(a[p.pkg]=[`./node_modules/${d}`])}let c=new Set;for(let p of o)for(let d of p.files){if(!d.ambient)continue;let h=at(d.path);h&&c.add(`node_modules/${h}`)}if(r.local){delete a[r.local.name];let p=await zs(r.local,e);p?a[r.local.name]=[`./node_modules/${r.local.name}/${p}`]:console.warn(` local: '${r.local.name}' ships no type defs; check cannot type against it.`)}let l=Js(r.jsxImportSource,a,[...c]);return await k.writeFile(E.join(e,"tsconfig.json"),JSON.stringify(l,null,2)+`
640
- `,"utf8"),await k.writeFile(E.join(e,"code.tsx"),r.code,"utf8"),await k.writeFile(E.join(e,"tb.d.ts"),wt,"utf8"),{dir:e}}function Js(r,e,t=[]){return{compilerOptions:{target:"es2023",module:"esnext",moduleResolution:"bundler",lib:Hs([...bt,...vt]),jsx:"react-jsx",jsxImportSource:r??"react",strict:!0,noEmit:!0,skipLibCheck:!0,esModuleInterop:!0,allowSyntheticDefaultImports:!0,forceConsistentCasingInFileNames:!0,baseUrl:".",paths:e},include:["code.tsx","tb.d.ts",...t]}}function Hs(r){return r.filter(e=>!e.since).map(e=>Vs(e.name))}function Vs(r){return r.split(".").map(e=>/^es\d+$/i.test(e)?e.toUpperCase():e==="dom"?"DOM":e==="esnext"?"ESNext":e.charAt(0).toUpperCase()+e.slice(1)).join(".")}function qs(r,e){let t=r??("react"in e?"react":void 0);return t?[`${t}/jsx-runtime`,`${t}/jsx-dev-runtime`]:[]}function at(r){if(!r.startsWith(dn))return;let e=r.slice(dn.length),t=e.indexOf("/");if(!(t<0))return e.slice(t+1)}async function zs(r,e){if(!r.typesAbs)return;let t=E.dirname(r.typesAbs),n=E.join(e,"node_modules",r.name);for(let s of await Gs(t)){let o=E.join(n,E.relative(t,s));await k.mkdir(E.dirname(o),{recursive:!0}),await k.copyFile(s,o)}return E.basename(r.typesAbs)}async function Gs(r){let e=[];async function t(n){let s=await k.readdir(n,{withFileTypes:!0});for(let o of s){let i=E.join(n,o.name);o.isDirectory()?await t(i):/\.d\.ts(\.map)?$/.test(o.name)&&e.push(i)}}return await t(r),e}import*as I from"fs/promises";import*as J from"path";import{existsSync as Ks}from"fs";var Ys="^22";async function pn(r){let e=qe(r.emitKey,"typecheck-server");await x(),await I.rm(e,{recursive:!0,force:!0}),await I.mkdir(e,{recursive:!0});let t=J.join(r.bulbDir,".typebulb"),n=Ze(r.server).filter(i=>i!==r.local?.name);await Qe([`@types/node@${Ys}`,...n],t,r.dependencies);let s=J.join(t,"node_modules"),o=J.join(e,"node_modules");return await Qs(s,o),await I.writeFile(J.join(e,"server.ts"),r.server,"utf8"),await I.writeFile(J.join(e,"tb.d.ts"),xt,"utf8"),await I.writeFile(J.join(e,"tsconfig.json"),JSON.stringify(Xs(r.local),null,2)+`
641
- `,"utf8"),{dir:e}}function Xs(r){let e={target:"es2023",module:"esnext",moduleResolution:"bundler",lib:["ES2023"],types:["node"],strict:!0,noEmit:!0,skipLibCheck:!0,esModuleInterop:!0,allowSyntheticDefaultImports:!0,forceConsistentCasingInFileNames:!0};if(r?.typesAbs){let t=o=>o.replace(/\\/g,"/"),n=t(J.dirname(r.typesAbs)),s=t(r.typesAbs).replace(/\.d\.ts$/,"");e.baseUrl=".",e.paths={[r.name]:[s],[`${r.name}/*`]:[`${n}/*`]}}return{compilerOptions:e,include:["server.ts","tb.d.ts"]}}async function Qs(r,e){if(!Ks(r)){await I.mkdir(e,{recursive:!0});return}await I.rm(e,{recursive:!0,force:!0});let t=process.platform==="win32"?"junction":"dir";await I.symlink(r,e,t)}import{readFileSync as Zs,writeFileSync as eo,mkdirSync as to}from"fs";import{join as ro}from"path";function fn(){return ro(rt(),"trust.json")}function Vt(){try{let r=JSON.parse(Zs(fn(),"utf8"));return new Set(Array.isArray(r)?r:[])}catch{return new Set}}function no(r){to(rt(),{recursive:!0}),eo(fn(),JSON.stringify([...r]))}function qt(r){return Vt().has(K(r))}function hn(r,e){let t=Vt(),n=K(r);(e?t.has(n):!t.has(n))||(e?t.add(n):t.delete(n),no(t))}function mn(){return[...Vt()]}import*as Y from"path";import{fileURLToPath as so}from"url";var zt={claude:{file:"claude.bulb.md",srcEnv:"TYPEBULB_CLAUDE_SRC",viewer:!0}};function Ne(r){let e=zt[r];if(!e)return;let t=e.srcEnv?process.env[e.srcEnv]:void 0;return t?Y.resolve(t):Y.join(Y.dirname(so(import.meta.url)),"bulbs",e.file)}function gn(r){let e=Y.basename(r).toLowerCase();for(let[t,n]of Object.entries(zt))if(n.viewer&&n.file.toLowerCase()===e)return t}function Gt(){return Object.entries(zt).filter(([,r])=>r.viewer).map(([r])=>r)}var oo="---\nname: typebulb\ndescription: Author and run Typebulb bulbs \u2014 single-file markdown apps (TypeScript/TSX: charts, simulations, diagrams, calculators, interactive UIs) that run locally via `npx typebulb` or render live inline in a Claude Code session through claude.bulb. Covers the bulb format, the `tb.*` API, trust, and the local run/embed workflow. Use when the user wants a bulb, a quick local interactive tool, or something visual rendered inline in the conversation.\n---";function io(r){let e=r.split(/\r?\n/),t;for(let n=0;n<e.length;n++){let s=e[n];if(t){let i=/^([`~]+)\s*$/.exec(s);i&&i[1][0]===t[0]&&i[1].length>=t.length&&(t=void 0);continue}let o=/^([`~]{3,})/.exec(s);if(o){t=o[1];continue}if(/^-{3,}\s*$/.test(s))return e.slice(n+1).join(`
642
- `).trim()}throw new Error("No `---` divider found in the README; cannot locate the skill body.")}function yn(r){return`${oo}
643
-
644
- ${io(r)}
645
- `}var lo="0.9.8";async function uo(r,e){let{bulb:t,config:n}=await ue(r);!t.code&&!t.server&&(console.error("Bulb has neither **code.tsx** nor **server.ts**; nothing to check."),process.exit(1));let s=[];if(t.code){let{dir:i}=await un({code:t.code,dependencies:n.dependencies??{},jsxImportSource:n.jsxImportSource,emitKey:r,local:e});s.push({role:"client",dir:i})}if(t.server){let{dir:i}=await pn({server:t.server,bulbDir:S.dirname(r),emitKey:r,local:e?{name:e.name,typesAbs:e.typesAbs}:void 0,dependencies:n.dependencies});s.push({role:"server",dir:i})}let o=!1;for(let{role:i,dir:a}of s){let{stdout:c,exitCode:l}=await fo(a);for(let p of c.split(/\r?\n/))p.trim()&&console.log(`${i} ${p}`);l!==0&&(o=!0)}o&&process.exit(1)}async function po(r,e){let{bulb:t}=await ue(r),n=At(t);if(qt(r)){console.log("remembered-trusted \u2014 runs with filesystem / AI / server.ts automatically (`typebulb untrust` to revoke)."),n&&console.log(` (it uses ${n})`);return}n?(console.log(`This bulb appears to use ${n}; it runs Restricted unless you grant trust:`),console.log(` ${e}`)):console.log("No privileged capability detected \u2014 runs Restricted by default. (A clean scan is a hint, not a guarantee.)")}function fo(r){return new Promise(e=>{let t=co("npx",["tsc","--noEmit"],{cwd:r,shell:!0}),n="";t.stdout?.on("data",s=>{n+=s.toString()}),t.stderr?.on("data",s=>{n+=s.toString()}),t.on("close",s=>e({stdout:n,exitCode:s??1}))})}async function ho(r,e,t,n,s){let o=pt(t),i=!1,a=async()=>{let{bulb:c,config:l}=await ue(r);i||(ft(o,r,c.server),i=!0),await _t(c.server,s,n,l.dependencies)};if(console.log(`Running ${S.basename(r)}...`),await a(),e){console.log(`Watching for changes...
646
- `);let c=new Kt;c.on("reload",async()=>{try{console.log("Re-running..."),await a()}catch(l){console.error("Error:",l)}}),Jt({bulbPath:r,emitter:c})}}async function mo(r,e,t,n,s){let o=process.cwd(),i=Gr(process.pid),a=e.watch?new Kt:void 0,c=pt(e.mode);console.log(`Loading ${S.basename(r)}...`);let{html:l,bulb:p,serverExports:d}=await Ct(r,e.watch,e.trust,n,s);ft(c,r,p.server);let h=await Wt(e.port),m=await tn({getHtml:()=>l,basePath:o,port:h,reloadEmitter:a,getServerExports:()=>d,localOverride:n?{name:n.name,serveDir:n.serveDir}:void 0,trusted:e.trust,trustHint:t}),g=`http://localhost:${h}`,R=e.trust?void 0:At(p);await Kr({pid:process.pid,port:h,url:g,file:r,startedAt:Date.now(),trust:e.trust,predicted:R}),console.log(`
647
- ${p.name}`),console.log(` ${g}`),e.trust?console.log(" trust: granted (filesystem, AI, server.ts enabled)"):console.log(R?` trust: sandboxed \u2014 this bulb appears to use ${R}; re-run with --trust to enable it:
639
+ `).trim();if(!n)return null;if(n==="[DONE]")return"done";try{return JSON.parse(n)}catch{return null}}async function Ur(r,e,t){let n=new TextDecoder,s="",o=!1,i=t?new Promise((a,c)=>{t.aborted&&c(new Error("Aborted")),t.addEventListener("abort",()=>c(new Error("Aborted")),{once:!0})}):null;for(;;){let a=i?await Promise.race([r.read(),i]):await r.read(),{done:c,value:l}=a;if(c){if(s.trim()){let h=$t(s);h!==null&&h!=="done"&&e(h)}break}o=!0,s+=n.decode(l,{stream:!0});let{pos:p,len:d}=Br(s);for(;p!==-1;){let h=s.slice(0,p);s=s.slice(p+d);let m=$t(h);if(m==="done"){s="";break}m!==null&&e(m),{pos:p,len:d}=Br(s)}}return{receivedAnyData:o}}async function Dt(r,e){let t=e??(r.headers.get("X-Provider-Protocol")||"openai"),n=ee(t);if(!r.body)throw new Error("Response body is missing");let s=r.body.getReader(),o="";return await Ur(s,i=>{let a=n.parseStreamChunk(i);a?.text&&(o+=a.text)}),o}import*as jt from"fs/promises";import*as Fe from"path";var tt=class{async get(e){let t=$(e),n=Fe.join(Ie,t+".bin"),s=Fe.join(Ie,t+".json");try{let[o,i]=await Promise.all([jt.readFile(n),jt.readFile(s,"utf8")]),a=JSON.parse(i);return{body:o,contentType:a.contentType,cacheControl:a.cacheControl}}catch{return}}async set(e,t){await x();let n=$(e),s=Fe.join(Ie,n+".bin"),o=Fe.join(Ie,n+".json"),i={url:e,contentType:t.contentType,cacheControl:t.cacheControl};await Promise.all([A(s,t.body),A(o,JSON.stringify(i))])}};import{readdir as Rs,readFile as Hr,writeFile as qr,unlink as Me,mkdir as Es}from"fs/promises";import{mkdirSync as ks,writeFileSync as Jr,appendFileSync as Ts,readFileSync as Gr}from"fs";import*as re from"path";import{join as Ft,resolve as Ss}from"path";import{homedir as Ps}from"os";function rt(){let r=process.env.TYPEBULB_SERVERS_DIR;return r?Ft(r,".."):Ft(Ps(),".typebulb")}function te(){return process.env.TYPEBULB_SERVERS_DIR||Ft(rt(),"servers")}function Y(r){let e=Ss(r);return(process.platform==="win32"?e.toLowerCase():e).replace(/\\/g,"/")}function Wr(r,e){let t=Y(r),n=Y(e);return t.startsWith(n.endsWith("/")?n:n+"/")?!t.includes("/node_modules/"):!1}var Vr=1e6;function Mt(r){return re.join(te(),`${r}.json`)}function nt(r){return re.join(te(),`${r}.log`)}function zr(r){let e=nt(r);try{ks(te(),{recursive:!0}),Jr(e,"")}catch{return()=>{}}let t=process.stdout.write.bind(process.stdout),n=process.stderr.write.bind(process.stderr),s=0,o=!1,i=a=>{if(!o)try{let c=typeof a=="string"?Buffer.from(a,"utf8"):Buffer.from(a);if(Ts(e,c),s+=c.length,s>2*Vr){let l=Gr(e),p=l.subarray(Math.max(0,l.length-Vr));Jr(e,p),s=p.length}}catch{o=!0}};return process.stdout.write=((a,...c)=>(i(a),t(a,...c))),process.stderr.write=((a,...c)=>(i(a),n(a,...c))),()=>{process.stdout.write=t,process.stderr.write=n}}function Nt(r,e=0){try{let t=Gr(nt(r)),n=e>=0&&e<=t.length?e:0;return{text:t.subarray(n).toString("utf8"),offset:t.length}}catch{return{text:"",offset:0}}}function _s(r){try{return process.kill(r,0),!0}catch(e){return e.code==="EPERM"}}async function Yr(r){await Es(te(),{recursive:!0}),await qr(Mt(r.pid),JSON.stringify(r))}async function Kr(r,e){let t=Mt(r);try{let n=JSON.parse(await Hr(t,"utf8"));if(n.denied===e)return;n.denied=e,await qr(t,JSON.stringify(n))}catch{}}async function Lt(r){await Me(Mt(r)).catch(()=>{}),await Me(nt(r)).catch(()=>{})}async function fe(r){let e;try{e=await Rs(te())}catch{return[]}let t=[];return await Promise.all(e.map(async s=>{if(!s.endsWith(".json"))return;let o=re.join(te(),s),i;try{i=JSON.parse(await Hr(o,"utf8"))}catch{await Me(o).catch(()=>{});return}i&&typeof i.pid=="number"&&_s(i.pid)?t.push(i):(await Me(o).catch(()=>{}),i?.pid&&await Me(nt(i.pid)).catch(()=>{}))})),(r?t.filter(s=>Wr(s.file,r)):t).sort((s,o)=>s.startedAt-o.startedAt)}async function Xr(r){try{process.kill(r,"SIGTERM")}catch{}await Lt(r)}var en="127.0.0.1",Os=new Set(["localhost","127.0.0.1","::1"]);function $s(r){if(r)try{return new URL(r.includes("://")?r:`http://${r}`).hostname}catch{return}}function Qr(r){let e=$s(r);return!!e&&Os.has(e)}function st(r){return r instanceof Error?r.message:"Unknown error"}async function tn(r){let{getHtml:e,basePath:t,port:n,reloadEmitter:s,getServerExports:o,localOverride:i,trusted:a=!1,trustHint:c}=r,l=new Cs;l.use("*",async(u,f)=>{if(!Qr(u.req.header("host")))return u.text("Forbidden: untrusted Host",403);await f()}),l.use("*",async(u,f)=>{await f(),u.res.headers.set("Cross-Origin-Opener-Policy","same-origin"),u.res.headers.set("Cross-Origin-Embedder-Policy","credentialless")});let p=["/__fs/*","/__api/*","/__ai"],d=async(u,f)=>{if(!a){let b=new URL(u.req.url).pathname,w=b.startsWith("/__fs")?"the filesystem":b==="/__ai"?"AI (your API keys)":"server-side code (server.ts)";Kr(process.pid,w);let v=c?`
640
+ ${c}`:"";return u.text(`Forbidden: this capability requires --trust.${v}`,403)}await f()},h=async(u,f)=>{let b=u.req.header("sec-fetch-site");if(b){if(b==="cross-site")return u.text("Forbidden: cross-site request",403)}else{let w=u.req.header("origin");if(w&&!Qr(w))return u.text("Forbidden: cross-origin request",403)}await f()};for(let u of p)l.use(u,d),l.use(u,h);l.use("/__log",h),l.post("/__log",async u=>{try{let{args:f}=await u.req.json();console.log(...f||[])}catch{}return u.json({ok:!0})}),l.get("/",u=>u.html(e())),l.post("/__fs/read",async u=>{try{let{path:f}=await u.req.json(),b=Ut(f,t),w=await ne.readFile(b);return new Response(new Uint8Array(w),{headers:{"Content-Type":"application/octet-stream"}})}catch(f){let b=st(f);return u.json({error:b},400)}}),l.post("/__fs/write",async u=>{try{let f=u.req.query("path");if(!f)return u.json({error:"Missing path"},400);let b=Ut(f,t);return await ne.mkdir(F.dirname(b),{recursive:!0}),await ne.writeFile(b,Buffer.from(await u.req.arrayBuffer())),u.json({success:!0})}catch(f){let b=st(f);return u.json({error:b},400)}});let m={log:console.log};l.post("/__api/:name",async u=>{try{let f=o?.(),b=u.req.param("name"),w=f?.[b]??m[b];if(!w||typeof w!="function")return u.json({error:`API function '${b}' not found`},404);let{args:v}=await u.req.json(),_=await w(...v||[]);return u.json({result:_})}catch(f){let b=st(f);return u.json({error:b},500)}}),l.post("/__ai",async u=>{try{let{messages:f,system:b,reasoning:w,provider:v,model:_,webSearch:V}=await u.req.json();if(!f||!Array.isArray(f)||f.length===0)return u.json({message:"messages array is required",code:"unknown",retryable:!1},400);let N=Ds(v,_);if(typeof N=="string")return u.json({message:N,code:"unknown",retryable:!1},400);let ct=[...b?[{role:"system",content:b}]:[],...f.map(Le=>({role:Le.role,content:Le.content}))],se=await It(N,{model:N.model,messages:ct,stream:!0,reasoning:w??0,webSearch:V??!0});if(!se.ok){let Le=await Ot(se,N.protocol);return u.json(Le,se.status)}let Kt=await Dt(se,N.protocol);return Kt||console.warn("[tb.ai] Empty response from provider"),u.json({text:Kt})}catch(f){if(f instanceof I)return u.json({message:f.message,code:f.code,retryable:f.retryable},500);let b=st(f);return u.json({message:b,code:"unknown",retryable:!1},500)}}),l.get("/__models",async u=>{try{let f=await Ms();return u.json(f)}catch{return u.json([],200)}});let g=["esm.sh","unpkg.com","cdn.jsdelivr.net","cdnjs.cloudflare.com"],P=new tt;if(l.get("/proxy/*",async u=>{let f=new URL(u.req.url),w=(f.pathname+f.search).slice(7),v=w.lastIndexOf("https://");return v===-1?u.text("Invalid proxy URL",400):M(u,w.slice(v))}),i){let u=`/local/${i.name}/`;l.get("/local/*",async f=>{let{pathname:b}=new URL(f.req.url);if(!b.startsWith(u))return f.text("Not Found",404);let w=decodeURIComponent(b.slice(u.length));try{let v=Ut(w,i.serveDir),_=await ne.readFile(v);return new Response(_,{headers:{"Content-Type":Ns(v)}})}catch{return f.text("Not Found",404)}})}async function M(u,f){let b;try{b=new URL(f)}catch{return u.text("Invalid URL",400)}if(b.protocol!=="https:")return u.text("HTTPS only",400);if(!g.includes(b.hostname))return u.text("Host not allowed",403);let w=await P.get(f);if(w)return new Response(w.body,{status:200,headers:Bt(w.contentType,w.cacheControl)});try{let v=await fetch(f,{headers:{Accept:u.req.header("Accept")||"*/*"},redirect:"follow"});if(!v.ok)return u.text(`Upstream ${v.status}`,v.status);let _=v.headers.get("Content-Type")||void 0,V=v.headers.get("Cache-Control")||void 0;if(v.body){let[N,ct]=v.body.tee();return(async()=>{try{let se=await new Response(ct).arrayBuffer();await P.set(f,{body:Buffer.from(se),contentType:_,cacheControl:V})}catch{}})(),new Response(N,{status:v.status,headers:Bt(_,V)})}return new Response(null,{status:v.status,headers:Bt(_,V)})}catch(v){return u.text(`Proxy fetch failed: ${v instanceof Error?v.message:v}`,502)}}s&&l.get("/__reload",u=>Is(u,async f=>{let b=()=>{f.writeSSE({event:"reload",data:""})};for(s.on("reload",b),f.onAbort(()=>{s.removeListener("reload",b)});;)await f.sleep(3e4)}));let B=/^\/(v\d+\/|stable\/|node\/|gh\/|@[^/]+\/[^@/]+@|[^@/]+@)/;l.notFound(async u=>{if(u.req.method!=="GET")return u.text("Not Found",404);let f=new URL(u.req.url);return B.test(f.pathname)?M(u,"https://esm.sh"+f.pathname+f.search):u.text("Not Found",404)});let C=As({fetch:l.fetch,port:n,hostname:en});return{port:n,close:()=>C.close()}}var rn={anthropic:"ANTHROPIC_API_KEY",openai:"OPENAI_API_KEY",gemini:"GOOGLE_API_KEY",openrouter:"OPENROUTER_API_KEY"};function Ds(r,e){let t=r??process.env.TB_AI_PROVIDER,n=e??process.env.TB_AI_MODEL;if(!t)return"No provider specified. Set TB_AI_PROVIDER in your .env file or pass provider in the tb.ai() call.";if(!n)return"No model specified. Set TB_AI_MODEL in your .env file or pass model in the tb.ai() call.";let s;try{s=ee(t)}catch{return`Unknown provider '${t}'.`}let o=rn[t],i=process.env[o];return i?{apiKey:i,baseUrl:s.defaultBaseUrl,protocol:t,model:n,isFreeModel:!1}:`No API key for '${t}'. Set ${o} in your .env file.`}var js="https://api.typebulb.com/api/models",Fs=1440*60*1e3,he=null;async function Ms(){if(!he||Date.now()-he.fetchedAt>Fs){let r=await fetch(js);if(!r.ok)return he?Zr(he.models):[];he={models:await r.json(),fetchedAt:Date.now()}}return Zr(he.models)}function Zr(r){let e=new Set(Object.entries(rn).filter(([,t])=>!!process.env[t]).map(([t])=>t));return r.filter(t=>e.has(t.provider))}function Bt(r,e){let t=new Headers;return r&&t.set("Content-Type",r),e&&t.set("Cache-Control",e),t.set("Access-Control-Allow-Origin","*"),t.set("Cross-Origin-Resource-Policy","cross-origin"),t}function Ns(r){switch(F.extname(r).toLowerCase()){case".js":case".mjs":return"text/javascript";case".wasm":return"application/wasm";case".json":case".map":return"application/json";default:return"application/octet-stream"}}function Ut(r,e){let t=F.resolve(e,r),n=F.normalize(e),s=F.normalize(t);if(s!==n&&!s.startsWith(n+F.sep))throw new Error("Path traversal detected - access denied");return t}async function Wt(r){let e=await import("net");return new Promise(t=>{let n=e.createServer();n.listen(r,en,()=>{let s=n.address(),o=typeof s=="object"&&s?s.port:r;n.close(()=>t(o))}),n.on("error",()=>{t(Wt(r+1))})})}import Ls from"open";async function nn(r){await Ls(r)}import sn from"chokidar";var on={persistent:!0,ignoreInitial:!0,awaitWriteFinish:{stabilityThreshold:100,pollInterval:50}};function Jt(r){let{bulbPath:e,emitter:t}=r,n=sn.watch(e,on);return n.on("change",()=>{t.emit("reload")}),()=>n.close()}function an(r){let{dir:e,onChange:t,debounceMs:n=150}=r,s,o=sn.watch(e,on);return o.on("all",()=>{s&&clearTimeout(s),s=setTimeout(t,n)}),()=>{s&&clearTimeout(s),o.close()}}import*as k from"fs/promises";import*as E from"path";import*as me from"path";var Bs=me.join(He,"pkg"),Us=me.join(He,"files"),Ws=me.join(He,"negative.json"),it=class{pkgMem=new Map;fileMem=new Map;negativeCache=new Q(new de(Ws));async getCachedDts(e){if(this.pkgMem.has(e))return this.pkgMem.get(e);await x();let t=await Z(cn(e));return this.pkgMem.set(e,t),t}async setCachedDts(e,t,n){let s={content:t,url:n};this.pkgMem.set(e,s),await ot(async()=>{await x(),await A(cn(e),JSON.stringify(s))})}async getCachedFile(e){if(this.fileMem.has(e))return this.fileMem.get(e);await x();let t=await Ve(ln(e));return this.fileMem.set(e,t),t}async setCachedFile(e,t){this.fileMem.set(e,t),await ot(async()=>{await x(),await A(ln(e),t)})}isNegative(e){return this.negativeCache.isNegative(e)}async recordNegative(e){await ot(async()=>{await x(),await this.negativeCache.recordNegative(e)})}clearNegative(e){return ot(()=>this.negativeCache.clearNegative(e))}};async function ot(r){try{await r()}catch{}}function cn(r){return me.join(Bs,$(r)+".json")}function ln(r){return me.join(Us,$(r)+".txt")}var Vt;function Js(){return Vt||(Vt=Rt({cache:new it,cdnClient:$r,packageService:Ye,versionResolver:Or})),Vt}var dn="file:///node_modules/";async function un(r){let e=qe(r.emitKey,"typecheck");await x(),await k.rm(e,{recursive:!0,force:!0}),await k.mkdir(e,{recursive:!0});let t=Gs(r.jsxImportSource,r.dependencies),n=await Js().resolve(r.code,r.dependencies,t),s=r.local?.name,o=s?n.filter(p=>p.pkg!==s):n,i=new Set;for(let p of o)for(let d of p.files){let h=at(d.path);if(!h||i.has(h))continue;i.add(h);let m=E.join(e,"node_modules",h);await k.mkdir(E.dirname(m),{recursive:!0}),await k.writeFile(m,d.content,"utf8")}let a={};for(let p of o)for(let d of p.shims){let h=at(d.path);h&&(a[d.module]=[`./node_modules/${h}`])}for(let p of o){if(p.ambient)continue;let d=at(p.mainPath);d&&(a[p.pkg]=[`./node_modules/${d}`])}let c=new Set;for(let p of o)for(let d of p.files){if(!d.ambient)continue;let h=at(d.path);h&&c.add(`node_modules/${h}`)}if(r.local){delete a[r.local.name];let p=await zs(r.local,e);p?a[r.local.name]=[`./node_modules/${r.local.name}/${p}`]:console.warn(` local: '${r.local.name}' ships no type defs; check cannot type against it.`)}let l=Vs(r.jsxImportSource,a,[...c]);return await k.writeFile(E.join(e,"tsconfig.json"),JSON.stringify(l,null,2)+`
641
+ `,"utf8"),await k.writeFile(E.join(e,"code.tsx"),r.code,"utf8"),await k.writeFile(E.join(e,"tb.d.ts"),wt,"utf8"),{dir:e}}function Vs(r,e,t=[]){return{compilerOptions:{target:"es2023",module:"esnext",moduleResolution:"bundler",lib:Hs([...yt,...vt]),jsx:"react-jsx",jsxImportSource:r??"react",strict:!0,noEmit:!0,skipLibCheck:!0,esModuleInterop:!0,allowSyntheticDefaultImports:!0,forceConsistentCasingInFileNames:!0,baseUrl:".",paths:e},include:["code.tsx","tb.d.ts",...t]}}function Hs(r){return r.filter(e=>!e.since).map(e=>qs(e.name))}function qs(r){return r.split(".").map(e=>/^es\d+$/i.test(e)?e.toUpperCase():e==="dom"?"DOM":e==="esnext"?"ESNext":e.charAt(0).toUpperCase()+e.slice(1)).join(".")}function Gs(r,e){let t=r??("react"in e?"react":void 0);return t?[`${t}/jsx-runtime`,`${t}/jsx-dev-runtime`]:[]}function at(r){if(!r.startsWith(dn))return;let e=r.slice(dn.length),t=e.indexOf("/");if(!(t<0))return e.slice(t+1)}async function zs(r,e){if(!r.typesAbs)return;let t=E.dirname(r.typesAbs),n=E.join(e,"node_modules",r.name);for(let s of await Ys(t)){let o=E.join(n,E.relative(t,s));await k.mkdir(E.dirname(o),{recursive:!0}),await k.copyFile(s,o)}return E.basename(r.typesAbs)}async function Ys(r){let e=[];async function t(n){let s=await k.readdir(n,{withFileTypes:!0});for(let o of s){let i=E.join(n,o.name);o.isDirectory()?await t(i):/\.d\.ts(\.map)?$/.test(o.name)&&e.push(i)}}return await t(r),e}import*as O from"fs/promises";import*as J from"path";import{existsSync as Ks}from"fs";var Xs="^22";async function pn(r){let e=qe(r.emitKey,"typecheck-server");await x(),await O.rm(e,{recursive:!0,force:!0}),await O.mkdir(e,{recursive:!0});let t=J.join(r.bulbDir,".typebulb"),n=Ze(r.server).filter(i=>i!==r.local?.name);await Qe([`@types/node@${Xs}`,...n],t,r.dependencies);let s=J.join(t,"node_modules"),o=J.join(e,"node_modules");return await Zs(s,o),await O.writeFile(J.join(e,"server.ts"),r.server,"utf8"),await O.writeFile(J.join(e,"tb.d.ts"),xt,"utf8"),await O.writeFile(J.join(e,"tsconfig.json"),JSON.stringify(Qs(r.local),null,2)+`
642
+ `,"utf8"),{dir:e}}function Qs(r){let e={target:"es2023",module:"esnext",moduleResolution:"bundler",lib:["ES2023"],types:["node"],strict:!0,noEmit:!0,skipLibCheck:!0,esModuleInterop:!0,allowSyntheticDefaultImports:!0,forceConsistentCasingInFileNames:!0};if(r?.typesAbs){let t=o=>o.replace(/\\/g,"/"),n=t(J.dirname(r.typesAbs)),s=t(r.typesAbs).replace(/\.d\.ts$/,"");e.baseUrl=".",e.paths={[r.name]:[s],[`${r.name}/*`]:[`${n}/*`]}}return{compilerOptions:e,include:["server.ts","tb.d.ts"]}}async function Zs(r,e){if(!Ks(r)){await O.mkdir(e,{recursive:!0});return}await O.rm(e,{recursive:!0,force:!0});let t=process.platform==="win32"?"junction":"dir";await O.symlink(r,e,t)}import{readFileSync as eo,writeFileSync as to,mkdirSync as ro}from"fs";import{join as no}from"path";function fn(){return no(rt(),"trust.json")}function Ht(){try{let r=JSON.parse(eo(fn(),"utf8"));return new Set(Array.isArray(r)?r:[])}catch{return new Set}}function so(r){ro(rt(),{recursive:!0}),to(fn(),JSON.stringify([...r]))}function qt(r){return Ht().has(Y(r))}function hn(r,e){let t=Ht(),n=Y(r);(e?t.has(n):!t.has(n))||(e?t.add(n):t.delete(n),so(t))}function mn(){return[...Ht()]}import*as K from"path";import{fileURLToPath as oo}from"url";var Gt={claude:{file:"claude.bulb.md",srcEnv:"TYPEBULB_CLAUDE_SRC",viewer:!0}};function Ne(r){let e=Gt[r];if(!e)return;let t=e.srcEnv?process.env[e.srcEnv]:void 0;return t?K.resolve(t):K.join(K.dirname(oo(import.meta.url)),"bulbs",e.file)}function gn(r){let e=K.basename(r).toLowerCase();for(let[t,n]of Object.entries(Gt))if(n.viewer&&n.file.toLowerCase()===e)return t}function zt(){return Object.entries(Gt).filter(([,r])=>r.viewer).map(([r])=>r)}function io(r){return`---
643
+ name: typebulb
644
+ description: Author and run Typebulb bulbs \u2014 single-file markdown apps (TypeScript/TSX: charts, simulations, diagrams, calculators, interactive UIs) that run locally via \`npx typebulb\` or render live inline in a Claude Code session through claude.bulb. Covers the bulb format, the \`tb.*\` API, trust, and the local run/embed workflow. Use when the user wants a bulb, a quick local interactive tool, or something visual rendered inline in the conversation.
645
+ version: ${r}
646
+ ---`}function ao(r){return`> Generated from typebulb v${r}. If \`npx typebulb --version\` reports a newer version, re-run \`npx typebulb skill\` to refresh this file.`}function bn(r,e){return`${io(e)}
647
+
648
+ ${ao(e)}
649
+
650
+ ${r.trim()}
651
+ `}var yn="0.10.0";async function uo(r,e){let{bulb:t,config:n}=await pe(r);!t.code&&!t.server&&(console.error("Bulb has neither **code.tsx** nor **server.ts**; nothing to check."),process.exit(1));let s=[];if(t.code){let{dir:i}=await un({code:t.code,dependencies:n.dependencies??{},jsxImportSource:n.jsxImportSource,emitKey:r,local:e});s.push({role:"client",dir:i})}if(t.server){let{dir:i}=await pn({server:t.server,bulbDir:S.dirname(r),emitKey:r,local:e?{name:e.name,typesAbs:e.typesAbs}:void 0,dependencies:n.dependencies});s.push({role:"server",dir:i})}let o=!1;for(let{role:i,dir:a}of s){let{stdout:c,exitCode:l}=await fo(a);for(let p of c.split(/\r?\n/))p.trim()&&console.log(`${i} ${p}`);l!==0&&(o=!0)}o&&process.exit(1)}async function po(r,e){let{bulb:t}=await pe(r),n=At(t);if(qt(r)){console.log("remembered-trusted \u2014 runs with filesystem / AI / server.ts automatically (`typebulb untrust` to revoke)."),n&&console.log(` (it uses ${n})`);return}n?(console.log(`This bulb appears to use ${n}; it runs Restricted unless you grant trust:`),console.log(` ${e}`)):console.log("No privileged capability detected \u2014 runs Restricted by default. (A clean scan is a hint, not a guarantee.)")}function fo(r){return new Promise(e=>{let t=lo("npx",["tsc","--noEmit"],{cwd:r,shell:!0}),n="";t.stdout?.on("data",s=>{n+=s.toString()}),t.stderr?.on("data",s=>{n+=s.toString()}),t.on("close",s=>e({stdout:n,exitCode:s??1}))})}async function ho(r,e,t,n,s){let o=pt(t),i=!1,a=async()=>{let{bulb:c,config:l}=await pe(r);i||(ft(o,r,c.server),i=!0),await _t(c.server,s,n,l.dependencies)};if(console.log(`Running ${S.basename(r)}...`),await a(),e){console.log(`Watching for changes...
652
+ `);let c=new Yt;c.on("reload",async()=>{try{console.log("Re-running..."),await a()}catch(l){console.error("Error:",l)}}),Jt({bulbPath:r,emitter:c})}}async function mo(r,e,t,n,s){let o=process.cwd(),i=zr(process.pid),a=e.watch?new Yt:void 0,c=pt(e.mode);console.log(`Loading ${S.basename(r)}...`);let{html:l,bulb:p,serverExports:d}=await Ct(r,e.watch,e.trust,n,s);ft(c,r,p.server);let h=await Wt(e.port),m=await tn({getHtml:()=>l,basePath:o,port:h,reloadEmitter:a,getServerExports:()=>d,localOverride:n?{name:n.name,serveDir:n.serveDir}:void 0,trusted:e.trust,trustHint:t}),g=`http://localhost:${h}`,P=e.trust?void 0:At(p);await Yr({pid:process.pid,port:h,url:g,file:r,startedAt:Date.now(),trust:e.trust,predicted:P}),console.log(`
653
+ ${p.name}`),console.log(` ${g}`),e.trust?console.log(" trust: granted (filesystem, AI, server.ts enabled)"):console.log(P?` trust: sandboxed \u2014 this bulb appears to use ${P}; re-run with --trust to enable it:
648
654
  ${t}
649
655
  `:` trust: sandboxed \u2014 re-run with --trust to enable filesystem / AI / server.ts
650
656
  `),e.watch&&console.log(` Watching for changes...
651
- `);let j,B;if(e.watch&&a){let u=new Kt;if(u.on("reload",async()=>{try{console.log("Recompiling...");let f=await Ct(r,!0,e.trust,n,s);l=f.html,d=f.serverExports,a.emit("reload"),console.log(`Done. Browser reloading...
652
- `)}catch(f){console.error("Compile error:",f)}}),j=Jt({bulbPath:r,emitter:u}),n){let{name:f,serveDir:y}=n;B=an({dir:y,onChange:()=>{console.log(`Local package '${f}' changed. Browser reloading...
657
+ `);let M,B;if(e.watch&&a){let u=new Yt;if(u.on("reload",async()=>{try{console.log("Recompiling...");let f=await Ct(r,!0,e.trust,n,s);l=f.html,d=f.serverExports,a.emit("reload"),console.log(`Done. Browser reloading...
658
+ `)}catch(f){console.error("Compile error:",f)}}),M=Jt({bulbPath:r,emitter:u}),n){let{name:f,serveDir:b}=n;B=an({dir:b,onChange:()=>{console.log(`Local package '${f}' changed. Browser reloading...
653
659
  `),a.emit("reload")}})}}e.open&&await nn(g);let C=async()=>{console.log(`
654
- Shutting down...`),m.close(),j?.(),B?.(),i(),await Lt(process.pid);let u=S.join(S.dirname(r),".typebulb","server.mjs");await ge.rm(u,{force:!0}).catch(()=>{}),process.exit(0)};process.on("SIGINT",C),process.on("SIGTERM",C)}function go(r,e){return/^\d+$/.test(e)?r.find(t=>t.pid===parseInt(e,10)):r.find(t=>K(t.file)===K(e))}function bn(r,e){for(let t of r)e(` ${t.url} pid ${t.pid} ${t.trust?"trusted":"restricted"} ${t.file}`)}function vn(r,e){if(!r.length){console.log("No running bulb servers.");return}console.log("Running bulb servers:"),bn(r,t=>console.log(t)),console.log(`
655
- `+e)}function wn(r,e,t){let n=go(r,e);if(n)return n;console.error(`No running server for '${e}'.`),r.length?(console.error(`Running servers (try \`typebulb ${t} <file|pid>\`):`),bn(r,s=>console.error(s))):console.error("No bulb servers are running."),process.exit(1)}async function yo(r,e){if(!r){vn(await fe(process.cwd()),"Run `typebulb logs <file|pid>` to print one server's console.");return}let t=wn(await fe(),Ne(r)??r,"logs"),n=Nt(t.pid),s=n.text;if(e.lines&&e.lines>0){let o=s.split(`
660
+ Shutting down...`),m.close(),M?.(),B?.(),i(),await Lt(process.pid);let u=S.join(S.dirname(r),".typebulb","server.mjs");await ge.rm(u,{force:!0}).catch(()=>{}),process.exit(0)};process.on("SIGINT",C),process.on("SIGTERM",C)}function go(r,e){return/^\d+$/.test(e)?r.find(t=>t.pid===parseInt(e,10)):r.find(t=>Y(t.file)===Y(e))}function vn(r,e){for(let t of r)e(` ${t.url} pid ${t.pid} ${t.trust?"trusted":"restricted"} ${t.file}`)}function wn(r,e){if(!r.length){console.log("No running bulb servers.");return}console.log("Running bulb servers:"),vn(r,t=>console.log(t)),console.log(`
661
+ `+e)}function xn(r,e,t){let n=go(r,e);if(n)return n;console.error(`No running server for '${e}'.`),r.length?(console.error(`Running servers (try \`typebulb ${t} <file|pid>\`):`),vn(r,s=>console.error(s))):console.error("No bulb servers are running."),process.exit(1)}async function bo(r,e){if(!r){wn(await fe(process.cwd()),"Run `typebulb logs <file|pid>` to print one server's console.");return}let t=xn(await fe(),Ne(r)??r,"logs"),n=Nt(t.pid),s=n.text;if(e.lines&&e.lines>0){let o=s.split(`
656
662
  `);o.length&&o[o.length-1]===""&&o.pop(),s=o.slice(-e.lines).join(`
657
663
  `)}if(process.stdout.write(s),s&&!s.endsWith(`
658
664
  `)&&process.stdout.write(`
659
- `),e.follow){let o=n.offset,i=setInterval(()=>{let c=Nt(t.pid,o);o=c.offset,c.text&&process.stdout.write(c.text)},500),a=()=>{clearInterval(i),process.exit(0)};process.on("SIGINT",a),process.on("SIGTERM",a),await new Promise(()=>{})}}async function bo(r){if(!r){vn(await fe(process.cwd()),"Run `typebulb stop <file|pid>` to stop one.");return}let e=wn(await fe(),Ne(r)??r,"stop");await Xr(e.pid),console.log(`Stopped ${S.basename(e.file)} (pid ${e.pid}, ${e.url}).`)}async function vo(r,e){if(!r){e||(console.error("Usage: typebulb untrust <file.bulb.md>"),process.exit(1));let n=mn();if(!n.length){console.log("No bulbs are remembered as trusted.");return}console.log("Trusted bulbs (run with fs/AI/server.ts without --trust):");for(let s of n)console.log(` ${s}`);return}let t=S.resolve(r);t.endsWith(".bulb.md")||(console.error("File must have .bulb.md extension"),process.exit(1)),hn(t,e),console.log(e?`Trusted ${S.basename(t)} \u2014 runs with fs / AI / server.ts (no --trust needed).`:`Untrusted ${S.basename(t)} \u2014 runs Restricted.`),console.log(` ${t}`)}async function wo(){let r=await fe(),e;for(let s of r){let o=gn(s.file);if(o){e=o;break}}process.stderr.write(`agent: ${e??"none"}
660
- `);let t=S.join(S.dirname(ao(import.meta.url)),"..","README.md"),n;try{n=await ge.readFile(t,"utf8")}catch{console.error(`Could not read the bundled README (expected at ${t}).`),process.exit(1)}process.stdout.write(yn(n)),process.exitCode=e?0:1}async function xo(){let r=or(process.argv.slice(2));if(r.version&&(console.log(`typebulb ${lo}`),process.exit(0)),r.help&&(ir(),process.exit(0)),r.subcommand==="logs"){await yo(r.file||void 0,{follow:r.follow,lines:r.lines});return}if(r.subcommand==="stop"){await bo(r.file||void 0);return}if(r.subcommand==="agent"){if(!r.agentTarget){await wo();return}Ne(r.agentTarget)||(console.error(`Unknown agent '${r.agentTarget}'. Known: ${Gt().join(", ")}.`),process.exit(1)),r.file=r.agentTarget,r.subcommand="run"}if(r.subcommand==="trust"||r.subcommand==="untrust"){await vo(r.file||void 0,r.subcommand==="trust");return}let e,t=!1;if(!r.file||r.file==="."){let l=await Lr(process.cwd());l||(console.error("No .bulb.md file found in current directory"),process.exit(1)),e=l}else e=S.resolve(r.file);if(!await ge.access(e).then(()=>!0,()=>!1)){let l=r.agentTarget?Ne(r.file):void 0;l?(e=l,t=!0):Gt().includes(r.file)?(console.error(`To open the ${r.file} session 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:S.relative(process.cwd(),e)||S.basename(e),o=`npx typebulb --trust ${s.includes(" ")?`"${s}"`:s}`;if(r.subcommand==="predict"){await po(e,o);return}if(t)r.trust=!r.noTrust,r.trust&&console.log("trust: granted (built-in bulb)");else{let l=!r.noTrust&&qt(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 ue(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 nr(r.local)}catch(l){console.error(l instanceof Error?l.message:String(l)),process.exit(1)}console.log(`replace: ${a.name} \u2192 ${S.relative(process.cwd(),a.dir)||"."}`)}if(r.subcommand==="check"){await uo(e,a);return}let c=t?process.cwd():S.dirname(e);if(process.env.TYPEBULB_BULB_PATH=e,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:
661
- ${o}`),process.exit(1)),await ho(e,r.watch,r.mode,a,c);return}await mo(e,r,o,a,c)}xo().catch(r=>{console.error("Error:",r.message),process.exit(1)});
665
+ `),e.follow){let o=n.offset,i=setInterval(()=>{let c=Nt(t.pid,o);o=c.offset,c.text&&process.stdout.write(c.text)},500),a=()=>{clearInterval(i),process.exit(0)};process.on("SIGINT",a),process.on("SIGTERM",a),await new Promise(()=>{})}}async function yo(r){if(!r){wn(await fe(process.cwd()),"Run `typebulb stop <file|pid>` to stop one.");return}let e=xn(await fe(),Ne(r)??r,"stop");await Xr(e.pid),console.log(`Stopped ${S.basename(e.file)} (pid ${e.pid}, ${e.url}).`)}async function vo(r,e){if(!r){e||(console.error("Usage: typebulb untrust <file.bulb.md>"),process.exit(1));let n=mn();if(!n.length){console.log("No bulbs are remembered as trusted.");return}console.log("Trusted bulbs (run with fs/AI/server.ts without --trust):");for(let s of n)console.log(` ${s}`);return}let t=S.resolve(r);t.endsWith(".bulb.md")||(console.error("File must have .bulb.md extension"),process.exit(1)),hn(t,e),console.log(e?`Trusted ${S.basename(t)} \u2014 runs with fs / AI / server.ts (no --trust needed).`:`Untrusted ${S.basename(t)} \u2014 runs Restricted.`),console.log(` ${t}`)}async function wo(){let r=await fe(),e;for(let s of r){let o=gn(s.file);if(o){e=o;break}}let t=e?"output a bulb block; it renders live here":"start the viewer yourself \u2014 `npx typebulb agent:claude --no-open` \u2014 share the localhost link it prints, then output a bulb block",n=[e?`You ran \`typebulb agent\`. Viewer '${e}' is up.`:"You ran `typebulb agent`. No viewer is running.",`- To show a bulb inline in this chat: ${t}.`,"- To make a bulb to keep and iterate on: write a .bulb.md and run `npx typebulb my-bulb.bulb.md`.","Working with bulbs? Run `npx typebulb skill` for the full authoring guide \u2014 save it to your skills folder if the user wants bulbs on hand across sessions."];process.stdout.write(n.join(`
666
+ `)+`
667
+ `),process.exitCode=e?0:1}async function xo(){let r=S.join(S.dirname(co(import.meta.url)),"..","README.md"),e;try{e=await ge.readFile(r,"utf8")}catch{console.error(`Could not read the bundled README (expected at ${r}).`),process.exit(1)}process.stdout.write(bn(e,yn))}async function So(){let r=or(process.argv.slice(2));if(r.version&&(console.log(`typebulb ${yn}`),process.exit(0)),r.help&&(ir(),process.exit(0)),r.subcommand==="logs"){await bo(r.file||void 0,{follow:r.follow,lines:r.lines});return}if(r.subcommand==="stop"){await yo(r.file||void 0);return}if(r.subcommand==="skill"){await xo();return}if(r.subcommand==="agent"){if(!r.agentTarget){await wo();return}Ne(r.agentTarget)||(console.error(`Unknown agent '${r.agentTarget}'. Known: ${zt().join(", ")}.`),process.exit(1)),r.file=r.agentTarget,r.subcommand="run"}if(r.subcommand==="trust"||r.subcommand==="untrust"){await vo(r.file||void 0,r.subcommand==="trust");return}let e,t=!1;if(!r.file||r.file==="."){let l=await Lr(process.cwd());l||(console.error("No .bulb.md file found in current directory"),process.exit(1)),e=l}else e=S.resolve(r.file);if(!await ge.access(e).then(()=>!0,()=>!1)){let l=r.agentTarget?Ne(r.file):void 0;l?(e=l,t=!0):zt().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:S.relative(process.cwd(),e)||S.basename(e),o=`npx typebulb --trust ${s.includes(" ")?`"${s}"`:s}`;if(r.subcommand==="predict"){await po(e,o);return}if(t)r.trust=!r.noTrust,r.trust&&console.log("trust: granted (built-in bulb)");else{let l=!r.noTrust&&qt(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 pe(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 nr(r.local)}catch(l){console.error(l instanceof Error?l.message:String(l)),process.exit(1)}console.log(`replace: ${a.name} \u2192 ${S.relative(process.cwd(),a.dir)||"."}`)}if(r.subcommand==="check"){await uo(e,a);return}let c=t?process.cwd():S.dirname(e);if(process.env.TYPEBULB_BULB_PATH=e,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:
668
+ ${o}`),process.exit(1)),await ho(e,r.watch,r.mode,a,c);return}await mo(e,r,o,a,c)}So().catch(r=>{console.error("Error:",r.message),process.exit(1)});
package/dist/servers.d.ts CHANGED
@@ -71,3 +71,7 @@ export declare function setBulbTrusted(file: string, trust: boolean): void
71
71
 
72
72
  /** Every remembered-trusted bulb path (absolute, normalized). */
73
73
  export declare function listTrustedBulbs(): string[]
74
+
75
+ /** Open `filePath` (optionally at `line`) in the user's editor, detached. Resolves
76
+ * TYPEBULB_EDITOR / VISUAL / EDITOR, defaulting to VS Code; fire-and-forget. */
77
+ export declare function openInEditor(filePath: string, line?: number): void
package/dist/servers.js CHANGED
@@ -1,3 +1,3 @@
1
- import{spawn as x}from"child_process";import{readdir as N,readFile as k,writeFile as mt,unlink as f,mkdir as dt}from"fs/promises";import{mkdirSync as bt,writeFileSync as ht,appendFileSync as yt,readFileSync as $}from"fs";import*as a from"path";import{join as h,resolve as E}from"path";import{homedir as L}from"os";function d(){let e=process.env.TYPEBULB_SERVERS_DIR;return e?h(e,".."):h(L(),".typebulb")}function l(){return process.env.TYPEBULB_SERVERS_DIR||h(d(),"servers")}function c(e){let t=E(e);return(process.platform==="win32"?t.toLowerCase():t).replace(/\\/g,"/")}function S(e,t){let r=c(e),n=c(t);return r.startsWith(n.endsWith("/")?n:n+"/")?!r.includes("/node_modules/"):!1}function O(e){return a.join(l(),`${e}.json`)}function g(e){return a.join(l(),`${e}.log`)}function R(e,t=0){try{let r=$(g(e)),n=t>=0&&t<=r.length?t:0;return{text:r.subarray(n).toString("utf8"),offset:r.length}}catch{return{text:"",offset:0}}}function A(e){try{return process.kill(e,0),!0}catch(t){return t.code==="EPERM"}}async function I(e){await f(O(e)).catch(()=>{}),await f(g(e)).catch(()=>{})}async function y(e){let t;try{t=await N(l())}catch{return[]}let r=[];return await Promise.all(t.map(async s=>{if(!s.endsWith(".json"))return;let i=a.join(l(),s),o;try{o=JSON.parse(await k(i,"utf8"))}catch{await f(i).catch(()=>{});return}o&&typeof o.pid=="number"&&A(o.pid)?r.push(o):(await f(i).catch(()=>{}),o?.pid&&await f(g(o.pid)).catch(()=>{}))})),(e?r.filter(s=>S(s.file,e)):r).sort((s,i)=>s.startedAt-i.startedAt)}async function W(e){try{process.kill(e,"SIGTERM")}catch{}await I(e)}var J=e=>new Promise(t=>setTimeout(t,e));async function M(e,t={}){let r=t.cwd??process.cwd(),n=a.resolve(r,e),s=(await y()).find(u=>u.file===n);if(s)return s;let i=["typebulb",...t.trust?["--trust"]:[],e,...t.open===!1?["--no-open"]:[]];(process.platform==="win32"?x("cmd",["/c","start","","/b","npx",...i],{cwd:r,stdio:"ignore",windowsHide:!0}):x("npx",i,{cwd:r,detached:!0,stdio:"ignore"})).unref();let p=Date.now()+2e4;for(;Date.now()<p;){await J(150);let u=(await y()).find(m=>m.file===n);if(u)return u}throw new Error(`Launched ${a.basename(e)} but it did not register within 20s.`)}import{readdirSync as U,readFileSync as z,statSync as H}from"fs";import{join as B,basename as Y}from"path";function b(e){let t=/^---[^\n]*\n([\s\S]*?)\n---/.exec(e),r=t?/^\s*name:\s*(.+?)\s*$/m.exec(t[1]):null;return r?r[1].replace(/^["']|["']$/g,""):void 0}function C(e){return(b(e)??"bulb").toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"bulb"}function K(e){return e.replace(/^---[^\n]*\r?\n[\s\S]*?\r?\n---[^\n]*\r?\n?/,"").replace(/^\r?\n+/,"")}function P(e,t,r){if(t>8)return r;let n;try{n=U(e,{withFileTypes:!0})}catch{return r}for(let s of n)if(s.isDirectory()){if(s.name.startsWith(".")||s.name==="node_modules")continue;P(B(e,s.name),t+1,r)}else s.isFile()&&s.name.endsWith(".bulb.md")&&r.push(B(e,s.name));return r}function G(e){return P(e,0,[]).map(t=>{let r=0;try{r=H(t).mtimeMs}catch{}let n;try{n=b(z(t,"utf8").slice(0,1024))}catch{}return{path:t,name:n??Y(t).replace(/\.bulb\.md$/,""),mtime:r}})}import{readFile as X}from"fs/promises";var V={code:{path:"code.tsx",language:"typescript"},css:{path:"styles.css",language:"css"},html:{path:"index.html",language:"html"},config:{path:"config.json",language:"json"},notes:{path:"notes.md",language:"markdown"},data:{path:"data.txt",language:"text"},infer:{path:"infer.md",language:"markdown"},insight:{path:"insight.json",language:"json"},server:{path:"server.ts",language:"typescript"}};function F(e){try{let t=e.split(`
2
- `),r=0;if(t[r]?.trim()!=="---")return null;r++;let n=[];for(;r<t.length&&t[r]?.trim()!=="---";)n.push(t[r]),r++;if(t[r]?.trim()!=="---")return null;r++;let s=q(n);if(!s)return null;let i=new Map;for(;r<t.length;){let p=t[r]?.trim()?.match(/^\*\*(.+)\*\*$/);if(p){let u=p[1].trim();for(r++;r<t.length&&t[r]?.trim()==="";)r++;let m=t[r]?.match(/^(`{3,})(\w*)\s*$/);if(!m){r++;continue}let T=m[1];r++;let v=[];for(;r<t.length&&!t[r]?.match(new RegExp(`^${T}\\s*$`));)v.push(t[r]),r++;r++,i.set(u,v.join(`
3
- `))}else r++}return{frontmatter:s,files:i}}catch{return null}}function q(e){let t={};for(let r of e){let n=r.indexOf(":");if(n===-1)continue;let s=r.slice(0,n).trim(),i=r.slice(n+1).trim();switch(s){case"format":t.format=i;break;case"name":t.name=Q(i);break}}return!t.format?.startsWith("typebulb")||!t.name?null:t}function Q(e){return e.startsWith('"')&&e.endsWith('"')?e.slice(1,-1).replace(/\\"/g,'"'):e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function j(e){let t=r=>e.files.get(V[r].path)||"";return{name:e.frontmatter.name,code:t("code"),css:t("css"),html:t("html"),config:t("config"),notes:t("notes"),data:t("data"),infer:t("infer"),insight:t("insight"),server:t("server")}}function _(e){if(e.server.trim())return"server-side code (server.ts)";let t=e.code;if(/\btb\s*\.\s*fs\b/.test(t)||t.includes("/__fs"))return"the filesystem";if(/\btb\s*\.\s*ai\b/.test(t)||t.includes("/__ai"))return"AI (your API keys)";if(/\btb\s*\.\s*server\s*\.\s*(?!log\b)\w/.test(t)||t.includes("/__api"))return"server-side code (server.ts)"}async function Z(e){try{let t=F(await X(e,"utf-8"));return t?_(j(t)):void 0}catch{return}}import{readFileSync as tt,writeFileSync as et,mkdirSync as rt}from"fs";import{join as nt}from"path";function D(){return nt(d(),"trust.json")}function w(){try{let e=JSON.parse(tt(D(),"utf8"));return new Set(Array.isArray(e)?e:[])}catch{return new Set}}function st(e){rt(d(),{recursive:!0}),et(D(),JSON.stringify([...e]))}function it(e){return w().has(c(e))}function ot(e,t){let r=w(),n=c(e);(t?r.has(n):!r.has(n))||(t?r.add(n):r.delete(n),st(r))}function at(){return[...w()]}export{b as bulbName,it as isBulbTrusted,M as launchBulbServer,G as listBulbFiles,y as listBulbServers,at as listTrustedBulbs,Z as predictBulbTrust,R as readServerLog,g as serverLogPath,ot as setBulbTrusted,C as slugifyBulbName,W as stopBulbServer,K as stripFrontmatter};
1
+ import{spawn as _}from"child_process";import{readdir as I,readFile as $,writeFile as xt,unlink as f,mkdir as Bt}from"fs/promises";import{mkdirSync as Ft,writeFileSync as Et,appendFileSync as jt,readFileSync as N}from"fs";import*as o from"path";import{fileURLToPath as O}from"url";import{join as y,resolve as D}from"path";import{homedir as L}from"os";function m(){let r=process.env.TYPEBULB_SERVERS_DIR;return r?y(r,".."):y(L(),".typebulb")}function l(){return process.env.TYPEBULB_SERVERS_DIR||y(m(),"servers")}function c(r){let t=D(r);return(process.platform==="win32"?t.toLowerCase():t).replace(/\\/g,"/")}function x(r,t){let e=c(r),n=c(t);return e.startsWith(n.endsWith("/")?n:n+"/")?!e.includes("/node_modules/"):!1}function R(r){return o.join(l(),`${r}.json`)}function d(r){return o.join(l(),`${r}.log`)}function k(r,t=0){try{let e=N(d(r)),n=t>=0&&t<=e.length?t:0;return{text:e.subarray(n).toString("utf8"),offset:e.length}}catch{return{text:"",offset:0}}}function A(r){try{return process.kill(r,0),!0}catch(t){return t.code==="EPERM"}}async function W(r){await f(R(r)).catch(()=>{}),await f(d(r)).catch(()=>{})}async function v(r){let t;try{t=await I(l())}catch{return[]}let e=[];return await Promise.all(t.map(async s=>{if(!s.endsWith(".json"))return;let i=o.join(l(),s),a;try{a=JSON.parse(await $(i,"utf8"))}catch{await f(i).catch(()=>{});return}a&&typeof a.pid=="number"&&A(a.pid)?e.push(a):(await f(i).catch(()=>{}),a?.pid&&await f(d(a.pid)).catch(()=>{}))})),(r?e.filter(s=>x(s.file,r)):e).sort((s,i)=>s.startedAt-i.startedAt)}async function J(r){try{process.kill(r,"SIGTERM")}catch{}await W(r)}var M=r=>new Promise(t=>setTimeout(t,r));function C(){return o.join(o.dirname(O(import.meta.url)),"index.js")}function U(r,t={}){return{command:process.execPath,args:[C(),...t.trust?["--trust"]:[],r,...t.open===!1?["--no-open"]:[]]}}async function K(r,t={}){let e=t.cwd??process.cwd(),n=o.resolve(e,r),s=(await v()).find(u=>u.file===n);if(s)return s;let{command:i,args:a}=U(r,t);_(i,a,{cwd:e,detached:!0,stdio:"ignore",windowsHide:!0}).unref();let b=Date.now()+2e4;for(;Date.now()<b;){await M(150);let u=(await v()).find(h=>h.file===n);if(u)return u}throw new Error(`Launched ${o.basename(r)} but it did not register within 20s.`)}import{readdirSync as z,readFileSync as H,statSync as G}from"fs";import{join as B,basename as q}from"path";function p(r){let t=/^---[^\n]*\n([\s\S]*?)\n---/.exec(r),e=t?/^\s*name:\s*(.+?)\s*$/m.exec(t[1]):null;return e?e[1].replace(/^["']|["']$/g,""):void 0}function Y(r){return(p(r)??"bulb").toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"bulb"}function V(r){return r.replace(/^---[^\n]*\r?\n[\s\S]*?\r?\n---[^\n]*\r?\n?/,"").replace(/^\r?\n+/,"")}function P(r,t,e){if(t>8)return e;let n;try{n=z(r,{withFileTypes:!0})}catch{return e}for(let s of n)if(s.isDirectory()){if(s.name.startsWith(".")||s.name==="node_modules")continue;P(B(r,s.name),t+1,e)}else s.isFile()&&s.name.endsWith(".bulb.md")&&e.push(B(r,s.name));return e}function Q(r){return P(r,0,[]).map(t=>{let e=0;try{e=G(t).mtimeMs}catch{}let n;try{n=p(H(t,"utf8").slice(0,1024))}catch{}return{path:t,name:n??q(t).replace(/\.bulb\.md$/,""),mtime:e}})}import{readFile as rt}from"fs/promises";var X={code:{path:"code.tsx",language:"typescript"},css:{path:"styles.css",language:"css"},html:{path:"index.html",language:"html"},config:{path:"config.json",language:"json"},notes:{path:"notes.md",language:"markdown"},data:{path:"data.txt",language:"text"},infer:{path:"infer.md",language:"markdown"},insight:{path:"insight.json",language:"json"},server:{path:"server.ts",language:"typescript"}};function F(r){try{let t=r.split(`
2
+ `),e=0;if(t[e]?.trim()!=="---")return null;e++;let n=[];for(;e<t.length&&t[e]?.trim()!=="---";)n.push(t[e]),e++;if(t[e]?.trim()!=="---")return null;e++;let s=Z(n);if(!s)return null;let i=new Map;for(;e<t.length;){let g=t[e]?.trim()?.match(/^\*\*(.+)\*\*$/);if(g){let b=g[1].trim();for(e++;e<t.length&&t[e]?.trim()==="";)e++;let u=t[e]?.match(/^(`{3,})(\w*)\s*$/);if(!u){e++;continue}let h=u[1];e++;let S=[];for(;e<t.length&&!t[e]?.match(new RegExp(`^${h}\\s*$`));)S.push(t[e]),e++;e++,i.set(b,S.join(`
3
+ `))}else e++}return{frontmatter:s,files:i}}catch{return null}}function Z(r){let t={};for(let e of r){let n=e.indexOf(":");if(n===-1)continue;let s=e.slice(0,n).trim(),i=e.slice(n+1).trim();switch(s){case"format":t.format=i;break;case"name":t.name=tt(i);break}}return!t.format?.startsWith("typebulb")||!t.name?null:t}function tt(r){return r.startsWith('"')&&r.endsWith('"')?r.slice(1,-1).replace(/\\"/g,'"'):r.startsWith("'")&&r.endsWith("'")?r.slice(1,-1):r}function E(r){let t=e=>r.files.get(X[e].path)||"";return{name:r.frontmatter.name,code:t("code"),css:t("css"),html:t("html"),config:t("config"),notes:t("notes"),data:t("data"),infer:t("infer"),insight:t("insight"),server:t("server")}}function j(r){if(r.server.trim())return"server-side code (server.ts)";let t=r.code;if(/\btb\s*\.\s*fs\b/.test(t)||t.includes("/__fs"))return"the filesystem";if(/\btb\s*\.\s*ai\b/.test(t)||t.includes("/__ai"))return"AI (your API keys)";if(/\btb\s*\.\s*server\s*\.\s*(?!log\b)\w/.test(t)||t.includes("/__api"))return"server-side code (server.ts)"}async function et(r){try{let t=F(await rt(r,"utf-8"));return t?j(E(t)):void 0}catch{return}}import{spawn as nt}from"child_process";import{basename as st}from"path";function it(){return process.env.TYPEBULB_EDITOR||process.env.VISUAL||process.env.EDITOR||"code"}var ot=/^(code|code-insiders|codium|vscodium|cursor|windsurf)(\.cmd|\.exe)?$/i;function at(r,t,e){return e==null?[t]:ot.test(st(r))?["-g",`${t}:${e}`]:[`+${e}`,t]}function ut(r,t){let e=it(),n=nt(e,at(e,r,t),{shell:!0,detached:!0,stdio:"ignore"});n.on("error",s=>console.error("[typebulb] editor launch failed:",s?.message??s)),n.unref()}import{readFileSync as ct,writeFileSync as lt,mkdirSync as ft}from"fs";import{join as mt}from"path";function T(){return mt(m(),"trust.json")}function w(){try{let r=JSON.parse(ct(T(),"utf8"));return new Set(Array.isArray(r)?r:[])}catch{return new Set}}function dt(r){ft(m(),{recursive:!0}),lt(T(),JSON.stringify([...r]))}function pt(r){return w().has(c(r))}function gt(r,t){let e=w(),n=c(r);(t?e.has(n):!e.has(n))||(t?e.add(n):e.delete(n),dt(e))}function bt(){return[...w()]}export{p as bulbName,pt as isBulbTrusted,K as launchBulbServer,Q as listBulbFiles,v as listBulbServers,bt as listTrustedBulbs,ut as openInEditor,et as predictBulbTrust,k as readServerLog,d as serverLogPath,gt as setBulbTrusted,Y as slugifyBulbName,J as stopBulbServer,V as stripFrontmatter};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "typebulb",
3
- "version": "0.9.8",
3
+ "version": "0.10.0",
4
4
  "description": "Local bulb runner CLI for Typebulb",
5
5
  "license": "MIT",
6
6
  "engines": { "node": ">=18" },