typebulb 0.9.7 → 0.9.9

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,33 @@
1
1
  # typebulb
2
2
 
3
- Run single-file apps from markdown. A `.bulb.md` file bundles code, styles, data, and config in one file. `typebulb` compiles and serves it locally with hot reload.
3
+ Run single-file markdown apps that execute in many execution contexts:
4
4
 
5
- Create bulbs on [typebulb.com](https://typebulb.com) and export, or generate `.bulb.md` files with any AI coding tool. See the [FAQ](https://typebulb.com/faq) for the bulb format and `tb.*` API reference.
5
+ 1. Localhost in your browser and in `nodejs`, which can talk via a secure bridge.
6
+ 2. Embedded in agent messages when viewed with `npx typebulb agent:claude`.
7
+ 3. Published on [typebulb.com](https://typebulb.com) or edited in its online IDE. See [FAQ](https://typebulb.com/faq).
8
+
9
+ `typebulb` serves the first two cases, by compiling and serving hot-reloadable bulbs locally.
10
+
11
+ A `.bulb.md` file bundles code, styles, data, and config in one file.
12
+
13
+ >This whole 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
+
15
+ ## Features
16
+
17
+ - **Server-side code** — Add a `**server.ts**` section; exported functions become callable from the browser via `tb.server.<name>()` (e.g., `export async function query(...)` → `await tb.server.query(...)`). Requires `--trust`.
18
+ - **CLI logging** — `tb.server.log(...)` prints to the CLI's stdout
19
+ - **Env files** — `.env` / `.env.local` load from cwd, `.env.local` overriding `.env` (an exported shell var wins over both). `--mode <name>` adds `.env.<name>` to switch environments (local/staging/prod); a startup line reports which keys loaded from where.
20
+ - **Server mode** — `--server` runs only the `**server.ts**` section in Node, skipping the web server. Bulbs with only `**server.ts**` (no `**code.tsx**`) use this mode automatically.
21
+ - **Type-check without running** — `typebulb check <file>` runs `tsc --noEmit` against the bulb and exits non-zero on errors. Useful for AI editors / CI.
22
+ - **Filesystem access** — `tb.fs.read()` (UTF-8 text), `tb.fs.readBytes()` (raw `Uint8Array`), and `tb.fs.write()` (text or bytes) for local files. Requires `--trust`.
23
+ - **Hot reload** — Recompiles on save and refreshes the browser (on by default; disable with `--no-watch`)
24
+ - **Package resolution** — Client dependencies are automatically resolved by generating import maps (same resolver as typebulb.com). Server dependencies are automatically installed via npm.
25
+ - **Replace dependency** — `--replace <name>=<path>` replaces a declared dependency with a local *built* package folder (browser-ready ESM, no external bare imports) instead of a CDN, for testing an unpublished build. Supplies both runtime bytes and types; applies to `run` and `check`. Under `--watch` the folder is watched and the browser reloads on rebuild (`--no-watch` freezes it). Dev-only; nothing is written to the bulb.
26
+ - **Local caching** — Resolver metadata and CDN package bytes are cached under `~/.typebulb/cache/`, so repeat runs don't re-hit the network and warm runs work offline.
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
+ - **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
+ - **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 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.
6
31
 
7
32
  ## Quick Start
8
33
 
@@ -11,13 +36,26 @@ A bulb is a markdown file with named code blocks:
11
36
  ````markdown
12
37
  ---
13
38
  format: typebulb/v1
14
- name: My App
39
+ name: Counter
15
40
  ---
16
41
 
17
42
  **code.tsx**
18
43
 
19
44
  ```tsx
20
- document.getElementById("root")!.textContent = "Hello from a bulb!";
45
+ import React, { useState } from "react"
46
+ import { createRoot } from "react-dom/client"
47
+
48
+ function App() {
49
+ const [n, setN] = useState(0)
50
+ return (
51
+ <div className="card">
52
+ <h1>Count: {n}</h1>
53
+ <button onClick={() => setN(n + 1)}>increment</button>
54
+ </div>
55
+ )
56
+ }
57
+
58
+ createRoot(document.getElementById("root")!).render(<App />)
21
59
  ```
22
60
 
23
61
  **index.html**
@@ -25,6 +63,42 @@ document.getElementById("root")!.textContent = "Hello from a bulb!";
25
63
  ```html
26
64
  <div id="root"></div>
27
65
  ```
66
+
67
+ **styles.css**
68
+
69
+ ```css
70
+ .card {
71
+ max-width: 360px;
72
+ margin: 0 auto; /* horizontal centering only */
73
+ padding: 24px 16px; /* vertical space as padding, never margin (see Emitting an embedded bulb) */
74
+ font: 14px system-ui, sans-serif;
75
+ display: grid;
76
+ gap: 12px;
77
+ text-align: center;
78
+ }
79
+ h1 { font-size: 20px; margin: 0; }
80
+ button {
81
+ font: inherit;
82
+ padding: 6px 14px;
83
+ border: 1px solid currentColor; /* theme-aware: inherits light/dark */
84
+ border-radius: 6px;
85
+ background: transparent;
86
+ color: inherit;
87
+ cursor: pointer;
88
+ }
89
+ ```
90
+
91
+ **config.json**
92
+
93
+ ```json
94
+ {
95
+ "description": "A button that increments a counter.",
96
+ "dependencies": {
97
+ "react": "^19.2.3",
98
+ "react-dom": "^19.2.3"
99
+ }
100
+ }
101
+ ```
28
102
  ````
29
103
 
30
104
  Run it:
@@ -43,13 +117,15 @@ npm install -g typebulb
43
117
 
44
118
  ```
45
119
  typebulb [file.bulb.md] Run a bulb (defaults to .bulb.md in cwd)
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
46
123
  typebulb check [file.bulb.md] Type-check a bulb without running it
47
124
  typebulb predict [file] Report the capability a bulb probably needs, without running it
48
125
  typebulb logs [file|pid] Print a running bulb's captured console (-f follow, -n N tail)
49
126
  typebulb stop [file|pid] Stop a running bulb (no arg: list this project's running servers)
50
127
  typebulb trust [file] Remember a bulb as trusted (no arg: list trusted bulbs)
51
128
  typebulb untrust <file> Forget a bulb's trust (back to sandboxed)
52
- typebulb claude Launch claude.bulb, the built-in session viewer
53
129
  typebulb --no-watch <file> Disable hot reload
54
130
  typebulb --port 3333 <file> Custom port
55
131
  typebulb --no-open <file> Don't auto-open browser
@@ -62,23 +138,7 @@ typebulb --help Show help
62
138
  typebulb --version Show version
63
139
  ```
64
140
 
65
- ## Features
66
-
67
- - **Server-side code** — Add a `**server.ts**` section; exported functions become callable from the browser via `tb.server.<name>()` (e.g., `export async function query(...)` → `await tb.server.query(...)`). Requires `--trust`.
68
- - **CLI logging** — `tb.server.log(...)` prints to the CLI's stdout
69
- - **Env files** — `.env` / `.env.local` load from cwd, `.env.local` overriding `.env` (an exported shell var wins over both). `--mode <name>` adds `.env.<name>` to switch environments (local/staging/prod); a startup line reports which keys loaded from where.
70
- - **Server mode** — `--server` runs only the `**server.ts**` section in Node, skipping the web server. Bulbs with only `**server.ts**` (no `**code.tsx**`) use this mode automatically.
71
- - **Type-check without running** — `typebulb check <file>` runs `tsc --noEmit` against the bulb and exits non-zero on errors. Useful for AI editors / CI.
72
- - **Filesystem access** — `tb.fs.read()` (UTF-8 text), `tb.fs.readBytes()` (raw `Uint8Array`), and `tb.fs.write()` (text or bytes) for local files. Requires `--trust`.
73
- - **Hot reload** — Recompiles on save and refreshes the browser (on by default; disable with `--no-watch`)
74
- - **Package resolution** — Client dependencies are automatically resolved by generating import maps (same resolver as typebulb.com). Server dependencies are automatically installed via npm.
75
- - **Replace dependency** — `--replace <name>=<path>` replaces a declared dependency with a local *built* package folder (browser-ready ESM, no external bare imports) instead of a CDN, for testing an unpublished build. Supplies both runtime bytes and types; applies to `run` and `check`. Under `--watch` the folder is watched and the browser reloads on rebuild (`--no-watch` freezes it). Dev-only; nothing is written to the bulb.
76
- - **Local caching** — Resolver metadata and CDN package bytes are cached under `~/.typebulb/cache/`, so repeat runs don't re-hit the network and warm runs work offline.
77
- - **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`.
78
- - **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.
79
- - **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.
80
-
81
- ## AI Setup
141
+ ## AI API Setup
82
142
 
83
143
  Bulbs can call AI providers via `tb.ai()`. Add API keys to your `.env` file:
84
144
 
@@ -118,9 +178,93 @@ const { text } = await tb.ai({
118
178
 
119
179
  Provider support varies — the level is mapped to provider-specific parameters (e.g. Anthropic's adaptive thinking, OpenAI's reasoning effort).
120
180
 
121
- ## Limitations
181
+ ## Blocks
182
+
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:`).
184
+
185
+ | Block | Purpose |
186
+ |-------|---------|
187
+ | `**code.tsx**` | **Required.** App logic and UI (TypeScript/TSX). |
188
+ | `**index.html**` | The mount container. Include it — nearly every bulb does (e.g. `<div id="root"></div>`). Only pure console apps omit it. |
189
+ | `**styles.css**` | CSS. |
190
+ | `**config.json**` | `dependencies` and a `description`. |
191
+ | `**data.txt**` | Read-only data your code processes via `tb.data(n)` (raw string) / `tb.json(n)` (parsed) — JSON, CSV, XML, YAML, or plain text. Multiple chunks are separated by **two blank lines**. |
192
+ | `**infer.md**` / `**insight.json**` | Runtime one-shot LLM call via `tb.infer()` — a typebulb.com feature; not supported locally. |
193
+ | `**notes.md**` | Persistent context for the AI assistant, carried across conversations and clones. Not run. |
194
+ | `**server.ts**` | Node.js code; its exports become `tb.server.<name>()` in the browser. **Local only.** |
195
+
196
+ ## The `tb.*` API, by target
197
+
198
+ `tb` is a pre-declared global your code can use without importing. What each call does, and where it works:
199
+
200
+ | API | What it does | Local | Embedded |
201
+ |-----|--------------|:-----:|:--------:|
202
+ | `tb.data(n)` / `tb.json(n)` | Read data chunk `n` from the `data.txt` block — raw string, or parsed JSON | ✅ | ✅ |
203
+ | `tb.insight()` | Read the `insight.json` block as JSON | ✅ | ✅ |
204
+ | `tb.theme` | Get/set the light/dark override; `undefined` follows the OS | ✅ | ✅ |
205
+ | `tb.mode` | Runtime mode — `'local'` (CLI) or `'embedded'` (sandboxed iframe); `'editor'`/`'published'` on typebulb.com | ✅ | ✅ |
206
+ | `tb.proxy(url)` | Rewrite a CDN URL to load through the host origin (Web Worker / WASM) | ✅ | ✅ |
207
+ | `tb.dump(...)` | Log values (incl. lazy / device-backed tensors) to the browser console | ✅ | ✅ |
208
+ | `tb.copy(text)` | Copy text to the clipboard | ✅ | ✅ |
209
+ | `tb.url()` | Get the bulb URL (the served localhost URL, locally) | ✅ | ✅ |
210
+ | `tb.models()` | List available AI models (for dynamic model selectors); returns `[]` when embedded (no host AI) | ✅ | ✅ |
211
+ | `tb.fs.read/readBytes/write` | Read and write local files | ✅ `--trust` | ❌ |
212
+ | `tb.server.<name>(...)` | Call a function exported from the `server.ts` block | ✅ `--trust` | ❌ |
213
+ | `tb.ai({ messages, … })` | General-purpose AI call (chat, agents) | ✅ `--trust` | ❌ |
214
+ | `tb.infer()` | One-shot LLM call driven by the `infer.md` block | ❌ | ❌ |
215
+
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.
217
+
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
223
+
224
+ The agent viewer currently supports Claude Code only. `npx typebulb agent:claude` gives the user a great scratchpad experience:
225
+
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
241
+
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.
243
+
244
+ The agent viewer turns that block into a live, sandboxed app, with a *breakout ↗* control that saves it as a `.bulb.md` in the `typebulbs/` folder — editable with hot reload, and sandboxed unless you trust it. Embedded bulbs are client-only — no `server.ts`, no `tb.fs`/`tb.ai`, no storage.
245
+
246
+ **Sizing is the viewer's job, not yours.** The agent viewer renders each embed *inline* by default — fit to the conversation column, with height capped so a tall bulb doesn't run away — plus a per-embed toggle to *spread* it to the full transcript width and height. Don't fight the layout from inside the bulb: no need to set a width, reserve height, or guess how much room you'll get.
247
+
248
+ **One layout rule the bulb must get right: vertical space on the root is `padding`, not `margin`.** The embed auto-sizes by reporting `document.body.scrollHeight`, and a vertical margin on the root element *collapses* (a body's first/last child margin escapes through to the viewport) so it isn't captured in that measurement — the host then sizes the frame a margin short and you get a stray scrollbar. The page-style `margin: 32px auto` common on a standalone wrapper is exactly this trap. Keep the horizontal `auto` for centering, but move the vertical part to padding:
249
+
250
+ ```css
251
+ .wrap { margin: 0 auto; padding: 24px 16px; } /* not: margin: 24px auto */
252
+ ```
122
253
 
123
- - **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.
254
+ ## Tips for Agents
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.
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.
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.
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`.
263
+ - **`tb.json<T>(n)` is generic** — `tb.json<Album[]>(0)` returns typed parsed JSON; `tb.data(n)` returns the raw string.
264
+ - **`tb.proxy()` is for same-origin Web Worker / WASM loads** — e.g. ffmpeg or tesseract: `tb.proxy("https://unpkg.com/...")` routes the CDN URL through the local server's origin.
265
+ - **Prefer an `index.html` fragment** over a full HTML document — usually just the mount stub (`<div id="root"></div>`).
266
+ - **`config.json` → `ts.jsxImportSource`** — the one supported `ts` option; defaults to `react`. Set it to use a different JSX runtime (e.g. `preact`).
267
+ - **Never invent a connection string or API key** — a `server.ts` that needs a database or API reads it from `.env` (loaded from the directory you run in). Ask the user for the value; don't fabricate one or commit it.
124
268
 
125
269
  ## License
126
270
 
@@ -370,19 +370,32 @@ const INTERNAL_PATTERNS = [
370
370
  /^No response requested\.?$/i,
371
371
  /^<task-notification\b/i, // harness protocol envelopes, not human-facing
372
372
  /^<system-reminder\b/i,
373
- /^<ide_[a-z_]+>[\s\S]*<\/ide_[a-z_]+>$/i, // whole IDE-injected context block (opened-file, selection, …)
374
373
  ]
375
374
  function isInternal(text: string): boolean {
376
375
  const t = text.trim()
377
376
  return !!t && INTERNAL_PATTERNS.some(p => p.test(t))
378
377
  }
379
378
 
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)
379
+ // IDE-injected context (opened-file, selection, …) the editor integration splices into the user's
380
+ // text block sometimes as the whole block, often inline beside what the user typed. Unlike the
381
+ // envelopes above it can't be anchored start-to-end, so strip the tag spans wherever they sit; what
382
+ // the user actually typed survives. A wholly-IDE block strips to '' and drops out entirely.
383
+ const IDE_CONTEXT = /<ide_[a-z_]+>[\s\S]*?<\/ide_[a-z_]+>/gi
384
+ function stripIdeContext(text: string): string {
385
+ return text.replace(IDE_CONTEXT, '')
386
+ }
387
+
388
+ // The display-ready text of a user message: IDE context stripped out, internal/synthetic noise
389
+ // reduced to ''. Empty ⇒ nothing human-authored to show. Shared by applyEntry (the transcript), the
390
+ // queued-command path, and readPreview (the picker) — so an "<ide_opened_file>" block is neither
391
+ // rendered nor mistaken for the kickoff prompt.
392
+ function cleanUserText(text: string): string {
393
+ const t = stripIdeContext(text).trim()
394
+ return t && !isInternal(t) ? t : ''
395
+ }
396
+ // Same, for an array-shaped `type:'text'` block; '' for non-text blocks.
397
+ function userTextBlock(b: ContentBlock | undefined): string {
398
+ return b?.type === 'text' && typeof b.text === 'string' ? cleanUserText(b.text) : ''
386
399
  }
387
400
 
388
401
  // Guard the per-entry dispatch: it runs inside the watchFile callback, so an
@@ -399,15 +412,15 @@ function applyEntry(entry: JsonlEntry) {
399
412
  if (entry.type === 'user') {
400
413
  const content = entry.message?.content
401
414
  if (typeof content === 'string') {
402
- if (!isInternal(content)) {
403
- s.buffer.push({ type: 'user', text: content })
404
- }
415
+ const text = cleanUserText(content)
416
+ if (text) s.buffer.push({ type: 'user', text })
405
417
  } else if (Array.isArray(content)) {
406
418
  for (const b of content) {
407
419
  if (b?.type === 'tool_result') {
408
420
  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 })
421
+ } else {
422
+ const text = userTextBlock(b)
423
+ if (text) s.buffer.push({ type: 'user', text })
411
424
  }
412
425
  }
413
426
  }
@@ -415,10 +428,8 @@ function applyEntry(entry: JsonlEntry) {
415
428
  // A message the user queued while CC was mid-turn. CC records it here, not as
416
429
  // a user turn, and never re-emits it — so without this branch it's lost from
417
430
  // 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
- }
431
+ const text = cleanUserText(toText(entry.attachment.prompt)) // string in current CC; toText also tolerates older array shapes
432
+ if (text) s.buffer.push({ type: 'user', text })
422
433
  } else if (entry.type === 'assistant') {
423
434
  const content = entry.message?.content
424
435
  const blocks: ContentBlock[] = Array.isArray(content) ? content : []
@@ -537,11 +548,11 @@ function readPreview(file: string): string {
537
548
  const content = e.message?.content
538
549
  let extracted = ''
539
550
  if (typeof content === 'string') {
540
- if (!isInternal(content)) extracted = content
551
+ extracted = cleanUserText(content)
541
552
  } 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(' ')
553
+ // Concatenate the real user-text blocks; userTextBlock strips IDE context / drops internal
554
+ // ones so an "<ide_opened_file>" entry isn't mistaken for the kickoff prompt — we fall through.
555
+ extracted = content.map(userTextBlock).filter(Boolean).join(' ')
545
556
  }
546
557
  const cleaned = extracted.replace(/\s+/g, ' ').trim()
547
558
  // Strip the fixed reincarnation lead-in so those sessions surface their distinctive summary.
@@ -2522,7 +2533,7 @@ body {
2522
2533
  }
2523
2534
  /* The filter (.bulb-filter-control) pins at the top; the row list scrolls inside the capped box —
2524
2535
  same shape as the launcher's .servers-pop / .bulb-list. */
2525
- .picker-list { display: flex; flex-direction: column; gap: .15rem; flex: 1; min-height: 0; overflow-y: auto; }
2536
+ .picker-list { display: flex; flex-direction: column; gap: .15rem; flex: 1; min-height: 0; overflow-y: auto; padding-right: 4px; }
2526
2537
  .picker-empty { padding: .8rem; color: var(--muted); font-size: .85rem; text-align: center; }
2527
2538
  .picker-row {
2528
2539
  display: flex;
@@ -3256,7 +3267,7 @@ a.server-port:hover { color: var(--accent); text-decoration: underline; }
3256
3267
  "beautiful-mermaid": "^1.1.3",
3257
3268
  "dompurify": "^3.2.6",
3258
3269
  "highlight.js": "^11.10.0",
3259
- "typebulb": "^0.9.7"
3270
+ "typebulb": "^0.9.9"
3260
3271
  }
3261
3272
  }
3262
3273
  ```
package/dist/index.js CHANGED
@@ -1,12 +1,15 @@
1
1
  #!/usr/bin/env node
2
- import*as at from"fs/promises";import*as P from"path";import{spawn as ro}from"child_process";import{EventEmitter as zt}from"events";import*as Kt from"fs/promises";import{existsSync as ne,readFileSync as yn}from"fs";import*as R from"path";import{pathToFileURL as bn}from"url";import{resolve as dt}from"resolve.exports";import{init as Xt,parse as Qt}from"es-module-lexer";function Zt(r,e){let t=R.join(r,"package.json");try{return JSON.parse(yn(t,"utf8"))}catch{throw new Error(`--replace package '${e}' has no readable package.json at ${t}`)}}var lt=["browser","import","default"],Yt=["node","import","default"];function er(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 tr(r){let{name:e,dir:t}=r;if(!ne(t))throw new Error(`--replace path for '${e}' does not exist: ${t}`);let n=Zt(t,e),s=vn(n,e),o=R.resolve(t,s);if(!ne(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=wn(n,t);return await xn(e,o,i),{name:e,dir:t,entryAbs:o,serveDir:i,entryUrl:a,typesAbs:c}}function vn(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 wn(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(ne(o))return o}}catch{}let t=r.types??r.typings;if(t){let n=R.resolve(e,t);if(ne(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 xn(r,e,t){await Xt;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 Kt.readFile(i,"utf8")}catch{continue}let c,l;try{[c,,,l]=Qt(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=Sn(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 Sn(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)&&ne(i))return i}function Rn(r,e,t){let n=Zt(r,e),s;if(n.exports!==void 0)try{s=ut(dt(n,t,{conditions:Yt}))}catch(i){throw new Error(`--replace package '${e}' "exports" does not resolve a node entry for '${t}' (conditions: ${Yt.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(!ne(o))throw new Error(`--replace package '${e}' built file not found: ${o} \u2014 did you build it (e.g. \`pnpm run build\`)?`);return bn(o).href}async function rr(r,e){await Xt;let t;try{[t]=Qt(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=Rn(e.dir,e.name,a);n+=r.slice(s,o.s)+c,s=o.e}return n+r.slice(s)}function nr(r){let e={subcommand:"run",file:"",port:3e3,watch:!0,open:!0,server:!1,trust:!1,noTrust:!1,follow:!1,help:!1,version:!1};["check","predict","logs","stop","trust","untrust"].includes(r[0])&&(e.subcommand=r[0],r=r.slice(1));for(let n=0;n<r.length;n++){let s=r[n];if(s==="--help"||s==="-h")e.help=!0;else if(s==="--version"||s==="-V")e.version=!0;else if(s==="--no-watch")e.watch=!1;else if(s==="--no-open")e.open=!1;else if(s==="--server")e.server=!0;else if(s==="--trust")e.trust=!0;else if(s==="--no-trust")e.noTrust=!0;else if(s==="--mode"){let o=r[++n];(!o||o.startsWith("-"))&&(console.error("Missing value for --mode (e.g. --mode staging)"),process.exit(1)),e.mode=o}else if(s==="--follow"||s==="-f")e.follow=!0;else if(s==="--lines"||s==="-n"){let o=parseInt(r[++n],10);(isNaN(o)||o<0)&&(console.error(`Invalid --lines value: ${r[n]}`),process.exit(1)),e.lines=o}else if(s==="--port"||s==="-p"){let o=r[++n],i=parseInt(o,10);isNaN(i)&&(console.error(`Invalid port: ${o}`),process.exit(1)),e.port=i}else if(s==="--replace"||s.startsWith("--replace=")){let o=s.startsWith("--replace=")?s.slice(10):r[++n]??"";try{let i=er(o);if(e.local)throw new Error(`--replace can only be used once (got '${e.local.name}' and '${i.name}')`);e.local=i}catch(i){console.error(i instanceof Error?i.message:String(i)),process.exit(1)}}else s.startsWith("-")||(e.file=s)}return e}function sr(){console.log(`
2
+ import*as ge from"fs/promises";import*as S from"path";import{fileURLToPath as io}from"url";import{spawn as ao}from"child_process";import{EventEmitter as Yt}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","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 claude Launch claude.bulb, the built-in viewer for
8
- Claude Code sessions (ships inside the CLI; no
9
- download, no file to place, runs trusted).
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.
10
13
  typebulb check [file.bulb.md] Type-check a bulb without running it
11
14
  typebulb predict [file] Report the capability a bulb probably needs
12
15
  (fs / AI / server.ts) without running it.
@@ -80,10 +83,10 @@ Examples:
80
83
  typebulb my-editor.bulb.md
81
84
  typebulb --no-watch --port 8080 my-editor.bulb.md
82
85
  typebulb .
83
- `)}import{readFileSync as Pn,existsSync as En}from"fs";import*as U from"path";function kn(r){return[...r?[`.env.${r}.local`,`.env.${r}`]:[],".env.local",".env"]}function pt(r,e=process.cwd()){let t={},n=[];for(let s of kn(r)){let o;try{o=Pn(U.resolve(e,s),"utf-8")}catch{continue}n.push(s);for(let[i,a]of Tn(o))process.env[i]===void 0&&(process.env[i]=a,t[i]=s)}return{mode:r,sources:t,loaded:n}}function*Tn(r){for(let e of r.split(`
84
- `)){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"])En(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 Qe from"path";import{pathToFileURL as ms}from"url";var Cn={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 or(r){try{let e=r.split(`
85
- `),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=In(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(`
86
- `))}else t++}return{frontmatter:s,files:o}}catch{return null}}function In(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=On(o);break}}return!e.format?.startsWith("typebulb")||!e.name?null:e}function On(r){return r.startsWith('"')&&r.endsWith('"')?r.slice(1,-1).replace(/\\"/g,'"'):r.startsWith("'")&&r.endsWith("'")?r.slice(1,-1):r}function ir(r){let e=t=>r.files.get(Cn[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 An(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 ar(r){let e=r.trim();return e?An(e)?[e]:r.split(/\n\n\n+/).map(t=>t.trim()).filter(Boolean):[]}function cr(r){if(!r.trim())return{};try{return JSON.parse(r)}catch{return{}}}import{transform as $n}from"sucrase";function ht(r,e={}){let t=e.serverOnly?["typescript"]:["typescript","jsx"];try{let{code:n}=$n(r,{transforms:t,jsxRuntime:"automatic",jsxImportSource:e.jsxImportSource||"react",production:!0});return{code:n}}catch(n){return{code:"",error:String(n)}}}var me="https://esm.sh",ge="https://cdn.jsdelivr.net/npm/",mt="https://data.jsdelivr.com/v1/package/npm/";function lr(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=se(t??s.version),this.subpath=se(n??s.subpath)}static parse(e){let t=lr(e||"");if(!t.length)return new r({name:""});if(t[0].startsWith("@")){let s=t[0],[o,i]=dr(t[1]??""),a=se(t.slice(2).join("/"));return new r({name:`${s}/${o}`,version:i,subpath:a})}else{let[s,o]=dr(t[0]),i=se(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(me).host,s=new URL(ge).host;if(t.host===n){let o=lr(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:se(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://")}},se=r=>r&&r.length?r:void 0,dr=r=>{let e=r.indexOf("@");return e<0?[r,void 0]:[r.slice(0,e),se(r.slice(e+1))]};async function T(r){try{return await r()}catch{return}}var ye=class{constructor(e,t){this.cache=e,this.http=t,this.esmHost=me,this.jsDelivrBase=ge,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 ur=r=>r.startsWith("@types/"),be=r=>Object.keys(r?.peerDependencies||{}).filter(e=>!ur(e)),gt=r=>Object.keys(r?.dependencies||{}).filter(e=>!ur(e)),Dn=r=>be(r).filter(e=>!r?.peerDependenciesMeta?.[e]?.optional),ve=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 Dn(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=>be(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:be(o.meta).length>0,isSharedDep:s.has(o.name)}]))}};var we=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 Mn,parse as Fn}from"es-module-lexer";var oe=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 Mn;let[s]=Fn(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 S=o.get(b.rootOf(g));return new b(g).withPreferredVersion(S.version,s[S.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 S=b.rootOf(g),j=o.get(S),{isPeerRoot:B,hasPeers:C,isSharedDep:u}=n.get(S),f=c.has(S),y=g!==S,v=!(B||u)&&(f||!C),_=this.singletonDepsOf(j,a),H=y&&d.has(S);H&&h.add(S);let N=H?[..._,S]:_.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([...be(e.meta),...gt(e.meta)])].filter(n=>t.has(n))}};oe.importPatterns=[/\bimport\s+(?:[^'";]*?from\s*)?['"]([^'"]+)['"]/g,/\bexport\s+[^'";]*?from\s*['"]([^'"]+)['"]/g];import{gt as pr,satisfies as jn,maxSatisfying as yt,major as Nn,prerelease as Ln,rsort as Bn,valid as Un}from"semver";var Ne=class{cmp(e,t){return e===t?0:pr(e,t)?1:pr(t,e)?-1:0}satisfies(e,t){return!e||!e.trim()?!0:!!jn(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?Bn(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 Nn(e)}isPrerelease(e){return Ln(e)!==null}isExactVersion(e){return Un(e)!==null}},K=new Ne;function fr(r,e){let t=new ye(r,e),n=new ve(t),s=new we(r,t,K);return{packageService:new oe(s,t,n,r),versionResolver:s,cdnClient:t,peerResolver:n}}import*as _r 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 hr=`
86
+ `)}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(`
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 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 ws}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(`
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=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(`
89
+ `))}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 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=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(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: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 we=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/"),ve=r=>Object.keys(r?.peerDependencies||{}).filter(e=>!fr(e)),gt=r=>Object.keys(r?.dependencies||{}).filter(e=>!fr(e)),Nn=r=>ve(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=>ve(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:ve(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 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))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 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(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 R=o.get(y.rootOf(g));return new y(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!==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 R=y.rootOf(g),j=o.get(R),{isPeerRoot:B,hasPeers:C,isSharedDep:u}=n.get(R),f=c.has(R),b=g!==R,w=!(B||u)&&(f||!C),_=this.singletonDepsOf(j,a),V=b&&d.has(R);V&&h.add(R);let N=V?[..._,R]:_.length?_:void 0;l.push([g,this.cdn.buildEsmUrl(i(g),{bundle:w,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([...ve(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 bt,major as Wn,prerelease as Jn,rsort as Vn,valid as Hn}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=bt(e,t,{includePrerelease:!0});return n===null?void 0:n}pickLatest(e){return e?.length?Vn(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 Wn(e)}isPrerelease(e){return Jn(e)!==null}isExactVersion(e){return Hn(e)!==null}},X=new Be;function mr(r,e){let t=new we(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 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"}],wt=[{name:"dom"},{name:"dom.iterable"},{name:"dom.asynciterable"}];var gr=`
87
90
  /**
88
91
  * Get raw data chunk from the Data tab.
89
92
  * @param index - Chunk index (0-based). Separate chunks with 2 blank lines.
@@ -94,7 +97,7 @@ Examples:
94
97
  * @param index - Chunk index (0-based)
95
98
  * @throws If chunk is not valid JSON/JSON-ish
96
99
  */
97
- json<T = unknown>(index: number): T;`,mr=`
100
+ json<T = unknown>(index: number): T;`,br=`
98
101
  /**
99
102
  * Get the insight data produced by the inference layer.
100
103
  *
@@ -103,7 +106,7 @@ Examples:
103
106
  *
104
107
  * @returns The parsed insight JSON, or undefined if no insight is available
105
108
  */
106
- insight<T = unknown>(): T | undefined;`,gr=`
109
+ insight<T = unknown>(): T | undefined;`,yr=`
107
110
  /**
108
111
  * General-purpose AI call.
109
112
  *
@@ -120,7 +123,7 @@ Examples:
120
123
  model?: string;
121
124
  /** Enable/disable web search. Default: on for BYOK, always off for free model. */
122
125
  webSearch?: boolean;
123
- }): Promise<{ text: string }>;`,yr=`
126
+ }): Promise<{ text: string }>;`,wr=`
124
127
  /**
125
128
  * Returns AI models available to the current user.
126
129
  * Models are filtered by the user's configured API keys.
@@ -135,7 +138,7 @@ Examples:
135
138
  friendlyName: string;
136
139
  /** Provider display name, e.g. "Anthropic" */
137
140
  providerName: string;
138
- }>>;`,Wn="\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;",br=`
141
+ }>>;`,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;",vr=`
139
142
  /**
140
143
  * The mode this bulb is running in.
141
144
  *
@@ -145,7 +148,7 @@ Examples:
145
148
  * - \`'embedded'\` \u2014 Running as a bulb embedded inside another bulb (sandboxed,
146
149
  * client-only: AI, filesystem, and server RPC are unavailable)
147
150
  */
148
- mode: 'local' | 'editor' | 'published' | 'embedded';`,vr=`
151
+ mode: 'local' | 'editor' | 'published' | 'embedded';`,xr=`
149
152
  /**
150
153
  * Local filesystem access (CLI only).
151
154
  *
@@ -159,7 +162,7 @@ Examples:
159
162
  readBytes(path: string): Promise<Uint8Array>;
160
163
  /** Write text or raw bytes to a file. Creates parent directories if needed. */
161
164
  write(path: string, content: string | Uint8Array): Promise<boolean>;
162
- };`,Jn=`
165
+ };`,zn=`
163
166
  /**
164
167
  * Server-side function proxy. The built-in \`log\` prints to CLI stdout
165
168
  * (falls back to console.log on web). On the server side, this object only
@@ -167,7 +170,7 @@ Examples:
167
170
  */
168
171
  server: {
169
172
  log(...args: any[]): Promise<void>;
170
- };`,Hn=`
173
+ };`,Gn=`
171
174
  /**
172
175
  * Async value inspector for tensor-like objects.
173
176
  *
@@ -234,7 +237,7 @@ Examples:
234
237
  *
235
238
  * @returns The full canonical URL
236
239
  */
237
- url(): Promise<string>;`,Vn=`
240
+ url(): Promise<string>;`,Yn=`
238
241
  /**
239
242
  * Server-side function proxy.
240
243
  *
@@ -242,23 +245,23 @@ Examples:
242
245
  * \`tb.server.log(...)\` is a built-in that prints to CLI stdout (falls back to console.log on web).
243
246
  * User exports override built-ins of the same name.
244
247
  */
245
- server: Record<string, (...args: any[]) => Promise<any>>;`,wt=`
248
+ server: Record<string, (...args: any[]) => Promise<any>>;`,vt=`
246
249
  /**
247
250
  * Typebulb utilities namespace.
248
251
  * Type \`tb.\` to discover available helpers.
249
252
  */
250
- declare const tb: {${hr}${Hn}${mr}${Vn}${gr}${vr}${yr}${Wn}${br}
253
+ declare const tb: {${gr}${Gn}${br}${Yn}${yr}${xr}${wr}${qn}${vr}
251
254
  };
252
255
  `,xt=`
253
256
  /**
254
257
  * Typebulb utilities namespace (server-side).
255
258
  * Type \`tb.\` to discover available helpers.
256
259
  */
257
- declare const tb: {${hr}${mr}${gr}${vr}${Jn}${yr}${br}
260
+ declare const tb: {${gr}${br}${yr}${xr}${zn}${wr}${vr}
258
261
  };
259
- `;var X=class{constructor(e){this.store=e}async isNegative(e){let t=await Le(()=>this.store.get(e));return!!t&&t.until>Date.now()}async recordNegative(e){let n=((await Le(()=>this.store.get(e)))?.attempts||0)+1;await Le(()=>this.store.set(e,{until:Date.now()+qn(n),attempts:n}))}async clearNegative(e){await Le(()=>this.store.delete(e))}};function qn(r){return Math.min(9e5*Math.pow(2,Math.max(0,r-1)),864e5)}async function Le(r){try{return await r()}catch{return}}import Qn from"p-limit";import{resolve as wr}from"resolve.exports";var ie=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},xe=["index.d.ts","index.d.mts"],Se=/\.d\.(ts|mts)$/i;function St(r){if(Se.test(r))return!0;try{return new URL(r,"file://").search.includes("dts")}catch{return r.includes("?")&&r.includes("dts")}}function Be(r){return[`${r}.d.ts`,`${r}.d.mts`]}async function Re(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(zn(a.status)&&s<e)continue;return a}catch{if(s<e)continue;return}finally{clearTimeout(i)}}}function zn(r){return r===408||r===429||r>=500&&r<600}var Pe=class extends ie{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 Re(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([...xe],t);if(!Se.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([...xe,...n],t)}toResolutionResult(e){return{kind:Se.test(e)?"types":"probe",path:e}}resolveExportsPath(e,t){let n=t||".",s=e;try{let o=this.extractPathFromResult(wr(s,n,{conditions:["types"]}));if(o)return o}catch{}try{return this.extractPathFromResult(wr(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[...xe];let t=e.replace(/\.(mjs|cjs|js|mts|cts|ts)$/i,""),n=Be(t),s=t.endsWith("/")?t:`${t}/`;return n.push(...Be(`${s}index`)),n}};import{gunzipSync as Gn}from"fflate";var ae=class{async fetchAndExtract(e,t){let n=this.getTarballUrl(e,t),s=await Re(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=Gn(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}},Yn=new ae;var Ee=class extends ie{constructor(e,t,n,s=new ae){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=K.majorOf(n),i=e.filter(a=>K.majorOf(a)===o);if(i.length)return i.sort((a,c)=>K.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 ke=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 xr="file:///node_modules",Te=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`${xr}/${this.epochDir()}/${e}/index.d.ts`}pathFor(e,t){let n=Kn(t);return`${xr}/${this.epochDir()}/${e}/${n}`}};function Kn(r){let e=r||"";return e.startsWith("./")?e.slice(2):e.replace(/^\/+/,"")}import{LRUCache as Xn}from"lru-cache";function Rt(r){let e=new Xn({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 Ue=class{constructor(e){this.inFlight=new Map,this.scanner=new ke,this.cache=e.cache,this.cdnClient=e.cdnClient,this.versionResolver=e.versionResolver,this.packageService=e.packageService,this.fetchDts=Rt(e.cache),this.typescriptProvider=new Pe(this.fetchDts,e.cdnClient),this.definitelyTypedProvider=new Ee(this.fetchDts,e.cdnClient,e.cache),this.virtualFs=new Te}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=Qn(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(`
260
- `);await this.prefetchBareDeps(g,l,h,m,s);let S=c.format(),j=e===S?[e]:[e,S],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 Ue(r)}import*as L from"fs/promises";import*as W from"path";import*as Pr from"os";import*as Et from"fs/promises";import*as Sr from"crypto";function $(r){return Sr.createHash("sha1").update(r).digest("hex")}async function Q(r){try{return JSON.parse(await Et.readFile(r,"utf8"))}catch{return}}async function We(r){try{return await Et.readFile(r,"utf8")}catch{return}}var Rr=1,q=W.join(Pr.homedir(),".typebulb","cache"),_e=W.join(q,"packages"),Ce=W.join(q,"proxy"),Je=W.join(q,"dts"),Zn=W.join(q,"emit"),kt;function x(){return kt||(kt=es()),kt}function He(r,e){return W.join(Zn,$(r),e)}async function es(){await L.mkdir(q,{recursive:!0});let r=W.join(q,"version.json");if((await ts(r))?.version===Rr)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:Rr})+`
261
- `,"utf8")}async function ts(r){try{let e=await L.readFile(r,"utf8");return JSON.parse(e)}catch{return}}import*as z from"fs/promises";import*as Er from"path";async function I(r,e){await z.mkdir(Er.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 ce=class{constructor(e){this.filePath=e}mem;loadPromise;load(){return this.mem?Promise.resolve(this.mem):(this.loadPromise||(this.loadPromise=Q(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 I(this.filePath,JSON.stringify(Object.fromEntries(e)))}};var Tt=D.join(_e,"indexes"),kr=D.join(_e,"pinned"),rs=D.join(_e,"meta"),ns=D.join(_e,"negative.json"),le=Symbol("missing"),qe=class{pinnedMem=new Map;indexMem=new Map;metaMem=new Map;negativeCache=new X(new ce(ns));async getPinnedExact(e,t){let n=`${e}@${t}`,s=this.pinnedMem.get(n);if(s!==void 0)return s===le?void 0:s;await x();let o=await We(D.join(kr,$(n)+".txt"));return this.pinnedMem.set(n,o??le),o}async setPinnedExact(e,t,n){let s=`${e}@${t}`;this.pinnedMem.set(s,n),await x(),await I(D.join(kr,$(s)+".txt"),n)}async getIndex(e){let t=this.indexMem.get(e);if(t!==void 0)return t===le?void 0:t;await x();let n=await Q(D.join(Tt,Ve(e)+".json"));return this.indexMem.set(e,n??le),n}async setIndex(e,t,n){let s={versions:t,distTags:n,updatedAt:Date.now()};this.indexMem.set(e,s),await x(),await I(D.join(Tt,Ve(e)+".json"),JSON.stringify(s))}async invalidateVersionsCache(e){this.indexMem.delete(e),await _r.rm(D.join(Tt,Ve(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===le?void 0:s;await x();let o=await Q(Tr(e,t));return this.metaMem.set(n,o??le),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 I(Tr(e,t),JSON.stringify(i))}};function Tr(r,e){return D.join(rs,Ve(r),encodeURIComponent(e)+".json")}function Ve(r){return r.replace(/\//g,"__")}var Cr={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 ss=new qe,{packageService:ze,versionResolver:Ir,cdnClient:Or,peerResolver:ma}=fr(ss,Cr);var Ar=`
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()+Kn(n),attempts:n}))}async clearNegative(e){await Ue(()=>this.store.delete(e))}};function Kn(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 H={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 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([...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=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[...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 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 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 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=rs(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 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 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"),Oe=W.join(q,"proxy"),He=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})+`
264
+ `,"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 Ve(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:Ye,versionResolver:Ir,cdnClient:$r,peerResolver:Sa}=mr(cs,Or);var Dr=`
262
265
  (() => {
263
266
  // Embedded (bulb-in-a-bulb): runs inside a sandboxed iframe with no parent
264
267
  // bridge, so privileged tb.* (AI, fs, server RPC) can't reach a host and would
@@ -468,12 +471,12 @@ declare const tb: {${hr}${mr}${gr}${vr}${Jn}${yr}${br}
468
471
  };
469
472
  }
470
473
  })();
471
- `;function $r(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:as(a.imports)};return`<!DOCTYPE html>
474
+ `;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>
472
475
  <html>
473
476
  <head>
474
477
  <meta charset="utf-8">
475
478
  <meta name="viewport" content="width=device-width, initial-scale=1">
476
- <title>${is(e)} - typebulb</title>
479
+ <title>${ds(e)} - typebulb</title>
477
480
  <script>
478
481
  // Theme engine. Sets html[data-theme] before stylesheets paint (no flash) and
479
482
  // exposes the tb.theme accessor via window.__tbTheme. The override is persisted
@@ -539,16 +542,16 @@ ${i?`<script>window.__TB_INSIGHT__ = ${d(JSON.stringify(i))};</script>`:""}
539
542
  ${c?"<script>window.__TYPEBULB_WATCH__ = true;</script>":""}
540
543
 
541
544
  <script>
542
- ${Ar}
545
+ ${Dr}
543
546
  </script>
544
547
 
545
- ${os}
548
+ ${ls}
546
549
 
547
550
  <script type="module">
548
551
  ${d(t)}
549
552
  </script>
550
553
  </body>
551
- </html>`}var os=`<script>
554
+ </html>`}var ls=`<script>
552
555
  (function () {
553
556
  if (window.parent === window) return;
554
557
  var de = document.documentElement;
@@ -619,36 +622,41 @@ ${d(t)}
619
622
  }
620
623
  });
621
624
  })();
622
- </script>`;function is(r){return r.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function as(r){let e={};for(let[t,n]of Object.entries(r))e[t]=n.startsWith("https://")?"/proxy/"+n:n;return e}import*as Ye from"fs/promises";import*as Ge from"path";import{existsSync as Dr,readFileSync as cs}from"fs";import{execFile as ls}from"child_process";import{promisify as ds}from"util";import{satisfies as us}from"semver";var ps=ds(ls);async function Ke(r,e,t){let s=r.map(i=>fs(i,t)).filter(i=>!hs(i,e));if(s.length===0)return;await Ye.mkdir(e,{recursive:!0});let o=Ge.join(e,"package.json");Dr(o)||await Ye.writeFile(o,JSON.stringify({name:"typebulb-server",private:!0})),console.log(` Installing: ${s.join(", ")}`),await ps("npm",["install","--no-audit","--no-fund",...s],{cwd:e,shell:!0})}function fs(r,e){if(!e||Fr(r))return r;let t=e[r];return t?`${r}@${t}`:r}function hs(r,e){let t=Ge.join(e,"node_modules",Mr(r));if(!Dr(t))return!1;let n=Fr(r);if(!n)return!0;try{let s=JSON.parse(cs(Ge.join(t,"package.json"),"utf-8")).version;return us(s,n)}catch{return!1}}function Xe(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 Fr(r){let e=Mr(r);return r.length>e.length?r.slice(e.length+1):""}async function jr(r){let t=(await G.readdir(r)).find(n=>n.endsWith(".bulb.md"));return t?Qe.join(r,t):null}async function de(r){let e=await G.readFile(r,"utf-8"),t=or(e);if(!t)throw new Error("Invalid .bulb.md file format");let n=ir(t);return{bulb:n,config:cr(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 rr(o,t));let i=Qe.join(e,".typebulb");await G.mkdir(i,{recursive:!0});let a=Xe(o);a.length>0&&await Ke(a,i,n);let c=Qe.join(i,"server.mjs");return await G.writeFile(c,o,"utf-8"),await import(`${ms(c).href}?t=${Date.now()}`)}async function Ct(r,e,t,n,s){let{bulb:o,config:i}=await de(r),a=ar(o.data),c=ht(o.code,{jsxImportSource:i.jsxImportSource});c.error&&console.error("Compilation error:",c.error);let{importMap:l}=await ze.buildImportMap(c.code,i.dependencies??{},n?new Set([n.name]):void 0);n&&(l.imports[n.name]=n.entryUrl);let p=$r({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 It(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 Ps}from"hono";import{serve as Es}from"@hono/node-server";import{streamSSE as ks}from"hono/streaming";import*as te from"fs/promises";import*as F from"path";var O=class extends Error{constructor(e,t="unknown",n=!1){super(e),this.code=t,this.retryable=n}},M=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 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 Ke 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=>bs(i,t)).filter(i=>!ys(i,e));if(s.length===0)return;await Xe.mkdir(e,{recursive:!0});let o=Ke.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 bs(r,e){if(!e||Nr(r))return r;let t=e[r];return t?`${r}@${t}`:r}function ys(r,e){let t=Ke.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(Ke.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(`${ws(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 Ye.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=`
623
626
 
624
- `){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 M{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 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(`
625
628
 
626
- `);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 Oe=class extends M{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
+ `);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(`
627
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 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(`
628
631
 
629
- `)}isResponsesApiEvent(e){return"type"in e&&typeof e.type=="string"}isResponsesApiResponse(e){return"object"in e&&e.object==="response"}};var Ae=class extends M{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 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,`
630
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(`
631
- `)[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 $e=class extends M{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 gs=new Map([["openai",new Oe],["openrouter",new $e],["anthropic",new Ie],["gemini",new Ae]]);function Z(r){let e=gs.get(r);if(!e)throw new Error(`Unsupported protocol: ${r}`);return e}async function Ot(r,e){let t=Z(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 At(r,e){let t=Z(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 Nr(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 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 vs=new Map([["openai",new $e],["openrouter",new Fe],["anthropic",new Ie],["gemini",new De]]);function ee(r){let e=vs.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
632
635
  \r
633
636
  `),t=r.indexOf(`
634
637
 
635
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(`
636
- `).trim();if(!n)return null;if(n==="[DONE]")return"done";try{return JSON.parse(n)}catch{return null}}async function Lr(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}=Nr(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}=Nr(s)}}return{receivedAnyData:o}}async function Dt(r,e){let t=e??(r.headers.get("X-Provider-Protocol")||"openai"),n=Z(t);if(!r.body)throw new Error("Response body is missing");let s=r.body.getReader(),o="";return await Lr(s,i=>{let a=n.parseStreamChunk(i);a?.text&&(o+=a.text)}),o}import*as Mt from"fs/promises";import*as De from"path";var Ze=class{async get(e){let t=$(e),n=De.join(Ce,t+".bin"),s=De.join(Ce,t+".json");try{let[o,i]=await Promise.all([Mt.readFile(n),Mt.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=De.join(Ce,n+".bin"),o=De.join(Ce,n+".json"),i={url:e,contentType:t.contentType,cacheControl:t.cacheControl};await Promise.all([I(s,t.body),I(o,JSON.stringify(i))])}};import{readdir as vs,readFile as Jr,writeFile as Hr,unlink as Me,mkdir as ws}from"fs/promises";import{mkdirSync as xs,writeFileSync as Ur,appendFileSync as Ss,readFileSync as Vr}from"fs";import*as ue from"path";import{join as Ft,resolve as ys}from"path";import{homedir as bs}from"os";function et(){let r=process.env.TYPEBULB_SERVERS_DIR;return r?Ft(r,".."):Ft(bs(),".typebulb")}function ee(){return process.env.TYPEBULB_SERVERS_DIR||Ft(et(),"servers")}function Y(r){let e=ys(r);return(process.platform==="win32"?e.toLowerCase():e).replace(/\\/g,"/")}function Br(r,e){let t=Y(r),n=Y(e);return t.startsWith(n.endsWith("/")?n:n+"/")?!t.includes("/node_modules/"):!1}var Wr=1e6;function jt(r){return ue.join(ee(),`${r}.json`)}function tt(r){return ue.join(ee(),`${r}.log`)}function qr(r){let e=tt(r);try{xs(ee(),{recursive:!0}),Ur(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(Ss(e,c),s+=c.length,s>2*Wr){let l=Vr(e),p=l.subarray(Math.max(0,l.length-Wr));Ur(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=Vr(tt(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 Rs(r){try{return process.kill(r,0),!0}catch(e){return e.code==="EPERM"}}async function zr(r){await ws(ee(),{recursive:!0}),await Hr(jt(r.pid),JSON.stringify(r))}async function Gr(r,e){let t=jt(r);try{let n=JSON.parse(await Jr(t,"utf8"));if(n.denied===e)return;n.denied=e,await Hr(t,JSON.stringify(n))}catch{}}async function Lt(r){await Me(jt(r)).catch(()=>{}),await Me(tt(r)).catch(()=>{})}async function Fe(r){let e;try{e=await vs(ee())}catch{return[]}let t=[];return await Promise.all(e.map(async s=>{if(!s.endsWith(".json"))return;let o=ue.join(ee(),s),i;try{i=JSON.parse(await Jr(o,"utf8"))}catch{await Me(o).catch(()=>{});return}i&&typeof i.pid=="number"&&Rs(i.pid)?t.push(i):(await Me(o).catch(()=>{}),i?.pid&&await Me(tt(i.pid)).catch(()=>{}))})),(r?t.filter(s=>Br(s.file,r)):t).sort((s,o)=>s.startedAt-o.startedAt)}async function Yr(r){try{process.kill(r,"SIGTERM")}catch{}await Lt(r)}var Qr="127.0.0.1",Ts=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 Kr(r){let e=_s(r);return!!e&&Ts.has(e)}function rt(r){return r instanceof Error?r.message:"Unknown error"}async function Zr(r){let{getHtml:e,basePath:t,port:n,reloadEmitter:s,getServerExports:o,localOverride:i,trusted:a=!1,trustHint:c}=r,l=new Ps;l.use("*",async(u,f)=>{if(!Kr(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)";Gr(process.pid,w);let v=c?`
637
- ${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&&!Kr(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 te.readFile(y);return new Response(new Uint8Array(w),{headers:{"Content-Type":"application/octet-stream"}})}catch(f){let y=rt(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 te.mkdir(F.dirname(y),{recursive:!0}),await te.writeFile(y,Buffer.from(await u.req.arrayBuffer())),u.json({success:!0})}catch(f){let y=rt(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=rt(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=Cs(v,_);if(typeof N=="string")return u.json({message:N,code:"unknown",retryable:!1},400);let ct=[...y?[{role:"system",content:y}]:[],...f.map(je=>({role:je.role,content:je.content}))],re=await Ot(N,{model:N.model,messages:ct,stream:!0,reasoning:w??0,webSearch:H??!0});if(!re.ok){let je=await At(re,N.protocol);return u.json(je,re.status)}let Gt=await Dt(re,N.protocol);return Gt||console.warn("[tb.ai] Empty response from provider"),u.json({text:Gt})}catch(f){if(f instanceof O)return u.json({message:f.message,code:f.code,retryable:f.retryable},500);let y=rt(f);return u.json({message:y,code:"unknown",retryable:!1},500)}}),l.get("/__models",async u=>{try{let f=await As();return u.json(f)}catch{return u.json([],200)}});let g=["esm.sh","unpkg.com","cdn.jsdelivr.net","cdnjs.cloudflare.com"],S=new Ze;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 te.readFile(v);return new Response(_,{headers:{"Content-Type":$s(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 S.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 re=await new Response(ct).arrayBuffer();await S.set(f,{body:Buffer.from(re),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=>ks(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=Es({fetch:l.fetch,port:n,hostname:Qr});return{port:n,close:()=>C.close()}}var en={anthropic:"ANTHROPIC_API_KEY",openai:"OPENAI_API_KEY",gemini:"GOOGLE_API_KEY",openrouter:"OPENROUTER_API_KEY"};function Cs(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=Z(t)}catch{return`Unknown provider '${t}'.`}let o=en[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 Is="https://api.typebulb.com/api/models",Os=1440*60*1e3,pe=null;async function As(){if(!pe||Date.now()-pe.fetchedAt>Os){let r=await fetch(Is);if(!r.ok)return pe?Xr(pe.models):[];pe={models:await r.json(),fetchedAt:Date.now()}}return Xr(pe.models)}function Xr(r){let e=new Set(Object.entries(en).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 $s(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,Qr,()=>{let s=n.address(),o=typeof s=="object"&&s?s.port:r;n.close(()=>t(o))}),n.on("error",()=>{t(Wt(r+1))})})}import Ds from"open";async function tn(r){await Ds(r)}import rn from"chokidar";var nn={persistent:!0,ignoreInitial:!0,awaitWriteFinish:{stabilityThreshold:100,pollInterval:50}};function Jt(r){let{bulbPath:e,emitter:t}=r,n=rn.watch(e,nn);return n.on("change",()=>{t.emit("reload")}),()=>n.close()}function sn(r){let{dir:e,onChange:t,debounceMs:n=150}=r,s,o=rn.watch(e,nn);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 fe from"path";var Ms=fe.join(Je,"pkg"),Fs=fe.join(Je,"files"),js=fe.join(Je,"negative.json"),st=class{pkgMem=new Map;fileMem=new Map;negativeCache=new X(new ce(js));async getCachedDts(e){if(this.pkgMem.has(e))return this.pkgMem.get(e);await x();let t=await Q(on(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 nt(async()=>{await x(),await I(on(e),JSON.stringify(s))})}async getCachedFile(e){if(this.fileMem.has(e))return this.fileMem.get(e);await x();let t=await We(an(e));return this.fileMem.set(e,t),t}async setCachedFile(e,t){this.fileMem.set(e,t),await nt(async()=>{await x(),await I(an(e),t)})}isNegative(e){return this.negativeCache.isNegative(e)}async recordNegative(e){await nt(async()=>{await x(),await this.negativeCache.recordNegative(e)})}clearNegative(e){return nt(()=>this.negativeCache.clearNegative(e))}};async function nt(r){try{await r()}catch{}}function on(r){return fe.join(Ms,$(r)+".json")}function an(r){return fe.join(Fs,$(r)+".txt")}var Ht;function Ns(){return Ht||(Ht=Pt({cache:new st,cdnClient:Or,packageService:ze,versionResolver:Ir})),Ht}var cn="file:///node_modules/";async function ln(r){let e=He(r.emitKey,"typecheck");await x(),await k.rm(e,{recursive:!0,force:!0}),await k.mkdir(e,{recursive:!0});let t=Ws(r.jsxImportSource,r.dependencies),n=await Ns().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=ot(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=ot(d.path);h&&(a[d.module]=[`./node_modules/${h}`])}for(let p of o){if(p.ambient)continue;let d=ot(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=ot(d.path);h&&c.add(`node_modules/${h}`)}if(r.local){delete a[r.local.name];let p=await Js(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=Ls(r.jsxImportSource,a,[...c]);return await k.writeFile(E.join(e,"tsconfig.json"),JSON.stringify(l,null,2)+`
638
- `,"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 Ls(r,e,t=[]){return{compilerOptions:{target:"es2023",module:"esnext",moduleResolution:"bundler",lib:Bs([...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 Bs(r){return r.filter(e=>!e.since).map(e=>Us(e.name))}function Us(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 Ws(r,e){let t=r??("react"in e?"react":void 0);return t?[`${t}/jsx-runtime`,`${t}/jsx-dev-runtime`]:[]}function ot(r){if(!r.startsWith(cn))return;let e=r.slice(cn.length),t=e.indexOf("/");if(!(t<0))return e.slice(t+1)}async function Js(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 Hs(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 Hs(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 A from"fs/promises";import*as J from"path";import{existsSync as Vs}from"fs";var qs="^22";async function dn(r){let e=He(r.emitKey,"typecheck-server");await x(),await A.rm(e,{recursive:!0,force:!0}),await A.mkdir(e,{recursive:!0});let t=J.join(r.bulbDir,".typebulb"),n=Xe(r.server).filter(i=>i!==r.local?.name);await Ke([`@types/node@${qs}`,...n],t,r.dependencies);let s=J.join(t,"node_modules"),o=J.join(e,"node_modules");return await Gs(s,o),await A.writeFile(J.join(e,"server.ts"),r.server,"utf8"),await A.writeFile(J.join(e,"tb.d.ts"),xt,"utf8"),await A.writeFile(J.join(e,"tsconfig.json"),JSON.stringify(zs(r.local),null,2)+`
639
- `,"utf8"),{dir:e}}function zs(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 Gs(r,e){if(!Vs(r)){await A.mkdir(e,{recursive:!0});return}await A.rm(e,{recursive:!0,force:!0});let t=process.platform==="win32"?"junction":"dir";await A.symlink(r,e,t)}import{readFileSync as Ys,writeFileSync as Ks,mkdirSync as Xs}from"fs";import{join as Qs}from"path";function un(){return Qs(et(),"trust.json")}function Vt(){try{let r=JSON.parse(Ys(un(),"utf8"));return new Set(Array.isArray(r)?r:[])}catch{return new Set}}function Zs(r){Xs(et(),{recursive:!0}),Ks(un(),JSON.stringify([...r]))}function qt(r){return Vt().has(Y(r))}function pn(r,e){let t=Vt(),n=Y(r);(e?t.has(n):!t.has(n))||(e?t.add(n):t.delete(n),Zs(t))}function fn(){return[...Vt()]}import*as he from"path";import{fileURLToPath as eo}from"url";var to={claude:{file:"claude.bulb.md",srcEnv:"TYPEBULB_CLAUDE_SRC"}};function it(r){let e=to[r];if(!e)return;let t=e.srcEnv?process.env[e.srcEnv]:void 0;return t?he.resolve(t):he.join(he.dirname(eo(import.meta.url)),"bulbs",e.file)}var no="0.9.7";async function so(r,e){let{bulb:t,config:n}=await de(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 ln({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 dn({server:t.server,bulbDir:P.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 io(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 oo(r,e){let{bulb:t}=await de(r),n=It(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 io(r){return new Promise(e=>{let t=ro("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 ao(r,e,t,n,s){let o=pt(t),i=!1,a=async()=>{let{bulb:c,config:l}=await de(r);i||(ft(o,r,c.server),i=!0),await _t(c.server,s,n,l.dependencies)};if(console.log(`Running ${P.basename(r)}...`),await a(),e){console.log(`Watching for changes...
640
- `);let c=new zt;c.on("reload",async()=>{try{console.log("Re-running..."),await a()}catch(l){console.error("Error:",l)}}),Jt({bulbPath:r,emitter:c})}}async function co(r,e,t,n,s){let o=process.cwd(),i=qr(process.pid),a=e.watch?new zt:void 0,c=pt(e.mode);console.log(`Loading ${P.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 Zr({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}`,S=e.trust?void 0:It(p);await zr({pid:process.pid,port:h,url:g,file:r,startedAt:Date.now(),trust:e.trust,predicted:S}),console.log(`
641
- ${p.name}`),console.log(` ${g}`),e.trust?console.log(" trust: granted (filesystem, AI, server.ts enabled)"):console.log(S?` trust: sandboxed \u2014 this bulb appears to use ${S}; 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 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 Hr,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 Y(r){let e=xs(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 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*Vr){let l=zr(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=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 Yr(r){await Ps(te(),{recursive:!0}),await qr(jt(r.pid),JSON.stringify(r))}async function Kr(r,e){let t=jt(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 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 Hr(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 b=new URL(u.req.url).pathname,v=b.startsWith("/__fs")?"the filesystem":b==="/__ai"?"AI (your API keys)":"server-side code (server.ts)";Kr(process.pid,v);let w=c?`
640
+ ${c}`:"";return u.text(`Forbidden: this capability requires --trust.${w}`,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 v=u.req.header("origin");if(v&&!Qr(v))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),v=await re.readFile(b);return new Response(new Uint8Array(v),{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 re.mkdir(M.dirname(b),{recursive:!0}),await re.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"),v=f?.[b]??m[b];if(!v||typeof v!="function")return u.json({error:`API function '${b}' not found`},404);let{args:w}=await u.req.json(),_=await v(...w||[]);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:v,provider:w,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=$s(w,_);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}))],ne=await Ot(N,{model:N.model,messages:ct,stream:!0,reasoning:v??0,webSearch:V??!0});if(!ne.ok){let Le=await It(ne,N.protocol);return u.json(Le,ne.status)}let Kt=await Dt(ne,N.protocol);return Kt||console.warn("[tb.ai] Empty response from provider"),u.json({text:Kt})}catch(f){if(f instanceof O)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"],R=new tt;if(l.get("/proxy/*",async u=>{let f=new URL(u.req.url),v=(f.pathname+f.search).slice(7),w=v.lastIndexOf("https://");return w===-1?u.text("Invalid proxy URL",400):j(u,v.slice(w))}),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 v=decodeURIComponent(b.slice(u.length));try{let w=Ut(v,i.serveDir),_=await re.readFile(w);return new Response(_,{headers:{"Content-Type":js(w)}})}catch{return f.text("Not Found",404)}})}async function j(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 v=await R.get(f);if(v)return new Response(v.body,{status:200,headers:Bt(v.contentType,v.cacheControl)});try{let w=await fetch(f,{headers:{Accept:u.req.header("Accept")||"*/*"},redirect:"follow"});if(!w.ok)return u.text(`Upstream ${w.status}`,w.status);let _=w.headers.get("Content-Type")||void 0,V=w.headers.get("Cache-Control")||void 0;if(w.body){let[N,ct]=w.body.tee();return(async()=>{try{let ne=await new Response(ct).arrayBuffer();await R.set(f,{body:Buffer.from(ne),contentType:_,cacheControl:V})}catch{}})(),new Response(N,{status:w.status,headers:Bt(_,V)})}return new Response(null,{status:w.status,headers:Bt(_,V)})}catch(w){return u.text(`Proxy fetch failed: ${w instanceof Error?w.message:w}`,502)}}s&&l.get("/__reload",u=>As(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)?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(He,"pkg"),Bs=me.join(He,"files"),Us=me.join(He,"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 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(Ls,$(r)+".json")}function ln(r){return me.join(Bs,$(r)+".txt")}var Vt;function Ws(){return Vt||(Vt=Pt({cache:new it,cdnClient:$r,packageService:Ye,versionResolver:Ir})),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=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)+`
641
+ `,"utf8"),await k.writeFile(E.join(e,"code.tsx"),r.code,"utf8"),await k.writeFile(E.join(e,"tb.d.ts"),vt,"utf8"),{dir:e}}function Js(r,e,t=[]){return{compilerOptions:{target:"es2023",module:"esnext",moduleResolution:"bundler",lib:Vs([...yt,...wt]),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 Vs(r){return r.filter(e=>!e.since).map(e=>Hs(e.name))}function Hs(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 Ys}from"fs";var Ks="^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@${Ks}`,...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)+`
642
+ `,"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(!Ys(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 Ht(){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 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),no(t))}function mn(){return[...Ht()]}import*as K 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?K.resolve(t):K.join(K.dirname(so(import.meta.url)),"bulbs",e.file)}function gn(r){let e=K.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 bn(r){return`${oo}
643
+
644
+ ${r.trim()}
645
+ `}var co="0.9.9";async function lo(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 po(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 uo(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 po(r){return new Promise(e=>{let t=ao("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 fo(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 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 ho(r,e,t,n,s){let o=process.cwd(),i=Gr(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}`,R=e.trust?void 0:At(p);await Yr({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:
642
648
  ${t}
643
649
  `:` trust: sandboxed \u2014 re-run with --trust to enable filesystem / AI / server.ts
644
650
  `),e.watch&&console.log(` Watching for changes...
645
- `);let j,B;if(e.watch&&a){let u=new zt;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...
646
- `)}catch(f){console.error("Compile error:",f)}}),j=Jt({bulbPath:r,emitter:u}),n){let{name:f,serveDir:y}=n;B=sn({dir:y,onChange:()=>{console.log(`Local package '${f}' changed. Browser reloading...
647
- `),a.emit("reload")}})}}e.open&&await tn(g);let C=async()=>{console.log(`
648
- Shutting down...`),m.close(),j?.(),B?.(),i(),await Lt(process.pid);let u=P.join(P.dirname(r),".typebulb","server.mjs");await at.rm(u,{force:!0}).catch(()=>{}),process.exit(0)};process.on("SIGINT",C),process.on("SIGTERM",C)}function lo(r,e){return/^\d+$/.test(e)?r.find(t=>t.pid===parseInt(e,10)):r.find(t=>Y(t.file)===Y(e))}function hn(r,e){for(let t of r)e(` ${t.url} pid ${t.pid} ${t.trust?"trusted":"restricted"} ${t.file}`)}function mn(r,e){if(!r.length){console.log("No running bulb servers.");return}console.log("Running bulb servers:"),hn(r,t=>console.log(t)),console.log(`
649
- `+e)}function gn(r,e,t){let n=lo(r,e);if(n)return n;console.error(`No running server for '${e}'.`),r.length?(console.error(`Running servers (try \`typebulb ${t} <file|pid>\`):`),hn(r,s=>console.error(s))):console.error("No bulb servers are running."),process.exit(1)}async function uo(r,e){if(!r){mn(await Fe(process.cwd()),"Run `typebulb logs <file|pid>` to print one server's console.");return}let t=gn(await Fe(),it(r)??r,"logs"),n=Nt(t.pid),s=n.text;if(e.lines&&e.lines>0){let o=s.split(`
651
+ `);let j,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...
652
+ `)}catch(f){console.error("Compile error:",f)}}),j=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
+ `),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 mo(r,e){return/^\d+$/.test(e)?r.find(t=>t.pid===parseInt(e,10)):r.find(t=>Y(t.file)===Y(e))}function yn(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:"),yn(r,t=>console.log(t)),console.log(`
655
+ `+e)}function vn(r,e,t){let n=mo(r,e);if(n)return n;console.error(`No running server for '${e}'.`),r.length?(console.error(`Running servers (try \`typebulb ${t} <file|pid>\`):`),yn(r,s=>console.error(s))):console.error("No bulb servers are running."),process.exit(1)}async function go(r,e){if(!r){wn(await fe(process.cwd()),"Run `typebulb logs <file|pid>` to print one server's console.");return}let t=vn(await fe(),Ne(r)??r,"logs"),n=Nt(t.pid),s=n.text;if(e.lines&&e.lines>0){let o=s.split(`
650
656
  `);o.length&&o[o.length-1]===""&&o.pop(),s=o.slice(-e.lines).join(`
651
657
  `)}if(process.stdout.write(s),s&&!s.endsWith(`
652
658
  `)&&process.stdout.write(`
653
- `),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 po(r){if(!r){mn(await Fe(process.cwd()),"Run `typebulb stop <file|pid>` to stop one.");return}let e=gn(await Fe(),it(r)??r,"stop");await Yr(e.pid),console.log(`Stopped ${P.basename(e.file)} (pid ${e.pid}, ${e.url}).`)}async function fo(r,e){if(!r){e||(console.error("Usage: typebulb untrust <file.bulb.md>"),process.exit(1));let n=fn();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=P.resolve(r);t.endsWith(".bulb.md")||(console.error("File must have .bulb.md extension"),process.exit(1)),pn(t,e),console.log(e?`Trusted ${P.basename(t)} \u2014 runs with fs / AI / server.ts (no --trust needed).`:`Untrusted ${P.basename(t)} \u2014 runs Restricted.`),console.log(` ${t}`)}async function ho(){let r=nr(process.argv.slice(2));if(r.version&&(console.log(`typebulb ${no}`),process.exit(0)),r.help&&(sr(),process.exit(0)),r.subcommand==="logs"){await uo(r.file||void 0,{follow:r.follow,lines:r.lines});return}if(r.subcommand==="stop"){await po(r.file||void 0);return}if(r.subcommand==="trust"||r.subcommand==="untrust"){await fo(r.file||void 0,r.subcommand==="trust");return}let e,t=!1;if(!r.file||r.file==="."){let l=await jr(process.cwd());l||(console.error("No .bulb.md file found in current directory"),process.exit(1)),e=l}else e=P.resolve(r.file);if(!await at.access(e).then(()=>!0,()=>!1)){let l=it(r.file);l?(e=l,t=!0):(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:P.relative(process.cwd(),e)||P.basename(e),o=`npx typebulb --trust ${s.includes(" ")?`"${s}"`:s}`;if(r.subcommand==="predict"){await oo(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 de(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 tr(r.local)}catch(l){console.error(l instanceof Error?l.message:String(l)),process.exit(1)}console.log(`replace: ${a.name} \u2192 ${P.relative(process.cwd(),a.dir)||"."}`)}if(r.subcommand==="check"){await so(e,a);return}let c=t?process.cwd():P.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:
654
- ${o}`),process.exit(1)),await ao(e,r.watch,r.mode,a,c);return}await co(e,r,o,a,c)}ho().catch(r=>{console.error("Error:",r.message),process.exit(1)});
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){wn(await fe(process.cwd()),"Run `typebulb stop <file|pid>` to stop one.");return}let e=vn(await fe(),Ne(r)??r,"stop");await Xr(e.pid),console.log(`Stopped ${S.basename(e.file)} (pid ${e.pid}, ${e.url}).`)}async function yo(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` and copy its output to your skills folder."];process.stdout.write(n.join(`
660
+ `)+`
661
+ `),process.exitCode=e?0:1}async function vo(){let r=S.join(S.dirname(io(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))}async function xo(){let r=or(process.argv.slice(2));if(r.version&&(console.log(`typebulb ${co}`),process.exit(0)),r.help&&(ir(),process.exit(0)),r.subcommand==="logs"){await go(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==="skill"){await vo();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 yo(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} 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 uo(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 lo(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:
662
+ ${o}`),process.exit(1)),await fo(e,r.watch,r.mode,a,c);return}await ho(e,r,o,a,c)}xo().catch(r=>{console.error("Error:",r.message),process.exit(1)});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "typebulb",
3
- "version": "0.9.7",
3
+ "version": "0.9.9",
4
4
  "description": "Local bulb runner CLI for Typebulb",
5
5
  "license": "MIT",
6
6
  "engines": { "node": ">=18" },