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