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 +168 -24
- package/dist/bulbs/claude.bulb.md +33 -22
- package/dist/index.js +53 -45
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,8 +1,33 @@
|
|
|
1
1
|
# typebulb
|
|
2
2
|
|
|
3
|
-
Run single-file
|
|
3
|
+
Run single-file markdown apps that execute in many execution contexts:
|
|
4
4
|
|
|
5
|
-
|
|
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:
|
|
39
|
+
name: Counter
|
|
15
40
|
---
|
|
16
41
|
|
|
17
42
|
**code.tsx**
|
|
18
43
|
|
|
19
44
|
```tsx
|
|
20
|
-
|
|
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
|
-
##
|
|
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
|
-
##
|
|
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
|
-
|
|
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
|
-
//
|
|
381
|
-
//
|
|
382
|
-
//
|
|
383
|
-
//
|
|
384
|
-
|
|
385
|
-
|
|
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
|
-
|
|
403
|
-
|
|
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
|
|
410
|
-
|
|
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
|
|
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
|
-
|
|
551
|
+
extracted = cleanUserText(content)
|
|
541
552
|
} else if (Array.isArray(content)) {
|
|
542
|
-
// Concatenate the real user-text blocks;
|
|
543
|
-
// an "<ide_opened_file>" entry isn't mistaken for the kickoff prompt — we fall through
|
|
544
|
-
extracted = content.
|
|
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.
|
|
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
|
|
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
|
|
8
|
-
|
|
9
|
-
|
|
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
|
|
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
|
|
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=
|
|
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;`,
|
|
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;`,
|
|
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 }>;`,
|
|
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
|
-
}>>;`,
|
|
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';`,
|
|
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
|
-
};`,
|
|
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
|
-
};`,
|
|
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>;`,
|
|
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>>;`,
|
|
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: {${
|
|
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: {${
|
|
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
|
|
261
|
-
`,"utf8")}async function
|
|
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
|
|
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>${
|
|
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
|
-
${
|
|
545
|
+
${Dr}
|
|
543
546
|
</script>
|
|
544
547
|
|
|
545
|
-
${
|
|
548
|
+
${ls}
|
|
546
549
|
|
|
547
550
|
<script type="module">
|
|
548
551
|
${d(t)}
|
|
549
552
|
</script>
|
|
550
553
|
</body>
|
|
551
|
-
</html>`}var
|
|
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
|
|
625
|
+
</script>`;function ds(r){return r.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
637
|
-
${c}`:"";return u.text(`Forbidden: this capability requires --trust.${
|
|
638
|
-
`,"utf8"),await k.writeFile(E.join(e,"code.tsx"),r.code,"utf8"),await k.writeFile(E.join(e,"tb.d.ts"),
|
|
639
|
-
`,"utf8"),{dir:e}}function
|
|
640
|
-
|
|
641
|
-
|
|
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
|
|
646
|
-
`)}catch(f){console.error("Compile error:",f)}}),j=Jt({bulbPath:r,emitter:u}),n){let{name:f,serveDir:
|
|
647
|
-
`),a.emit("reload")}})}}e.open&&await
|
|
648
|
-
Shutting down...`),m.close(),j?.(),B?.(),i(),await Lt(process.pid);let u=
|
|
649
|
-
`+e)}function
|
|
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
|
|
654
|
-
|
|
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)});
|