Replace static AddSources/CodeEditor with SandboxEditor that uses Monaco with real TypeScript types generated from OpenAPI specs. - generate-types.ts script fetches Cloudflare/Vercel/GitHub specs and produces .d.ts bundles via the executor core pipeline - Types served as static assets, fetched on demand per source toggle - Full IntelliSense: autocomplete, parameter types, return types - 2,603 Cloudflare + 281 Vercel + 1,079 GitHub typed tool methods
Unified · Split
| @@ -1,3 +1,4 @@ | |||
| 1 | dist/ | 1 | dist/ |
| 2 | node_modules/ | 2 | node_modules/ |
| 3 | .astro/ | 3 | .astro/ |
| 4 | public/types/ | ||
| @@ -7,11 +7,13 @@ · 6 unmodified lines | |||
| 7 | "dev": "astro dev", | 7 | "dev": "astro dev", |
| 8 | "build": "astro build", | 8 | "build": "astro build", |
| 9 | "preview": "astro preview", | 9 | "preview": "astro preview", |
| 10 | "typecheck": "astro check" | 10 | "typecheck": "astro check", |
| 11 | "generate-types": "bun run scripts/generate-types.ts" | ||
| 11 | }, | 12 | }, |
| 12 | "dependencies": { | 13 | "dependencies": { |
| 13 | "@astrojs/react": "^4.2.1", | 14 | "@astrojs/react": "^4.2.1", |
| 14 | "@astrojs/tailwind": "^6.0.2", | 15 | "@astrojs/tailwind": "^6.0.2", |
| 16 | "@monaco-editor/react": "^4.7.0", | ||
| 15 | "astro": "^5.10.1", | 17 | "astro": "^5.10.1", |
| 16 | "react": "^19.1.0", | 18 | "react": "^19.1.0", |
| 17 | "react-dom": "^19.1.0", | 19 | "react-dom": "^19.1.0", |
| @@ -0,0 +1,168 @@ | |||
| 1 | /** | ||
| 2 | * Fetches real OpenAPI specs and generates .d.ts type bundles for the Monaco editor. | ||
| 3 | * | ||
| 4 | * Usage: bun run scripts/generate-types.ts | ||
| 5 | * | ||
| 6 | * Outputs: | ||
| 7 | * public/types/<source>.d.ts — full type bundle per source (served as static asset) | ||
| 8 | * public/types/manifest.json — metadata about each source (tool count, file size) | ||
| 9 | */ | ||
| 10 | |||
| 11 | import { prepareOpenApiSpec } from "../../../../executor/packages/core/src/openapi-prepare"; | ||
| 12 | import { buildOpenApiToolsFromPrepared } from "../../../../executor/packages/core/src/openapi/tool-builder"; | ||
| 13 | import { buildWorkspaceTypeBundle } from "../../../../executor/packages/core/src/tool-typing/typebundle"; | ||
| 14 | import type { OpenApiToolSourceConfig } from "../../../../executor/packages/core/src/tool/source-types"; | ||
| 15 | import { mkdirSync } from "fs"; | ||
| 16 | import { join, dirname } from "path"; | ||
| 17 | |||
| 18 | interface SourceSpec { | ||
| 19 | name: string; | ||
| 20 | label: string; | ||
| 21 | icon: string; | ||
| 22 | description: string; | ||
| 23 | specUrl: string; | ||
| 24 | baseUrl?: string; | ||
| 25 | } | ||
| 26 | |||
| 27 | const SOURCES: SourceSpec[] = [ | ||
| 28 | { | ||
| 29 | name: "cloudflare", | ||
| 30 | label: "Cloudflare", | ||
| 31 | icon: "☁", | ||
| 32 | description: "DNS, Workers, R2, KV, Zones, WAF, and more", | ||
| 33 | specUrl: | ||
| 34 | "https://raw.githubusercontent.com/cloudflare/api-schemas/main/openapi.json", | ||
| 35 | baseUrl: "https://api.cloudflare.com/client/v4", | ||
| 36 | }, | ||
| 37 | { | ||
| 38 | name: "vercel", | ||
| 39 | label: "Vercel", | ||
| 40 | icon: "▲", | ||
| 41 | description: "Deployments, Domains, Environment Variables, Projects", | ||
| 42 | specUrl: "https://openapi.vercel.sh/", | ||
| 43 | baseUrl: "https://api.vercel.com", | ||
| 44 | }, | ||
| 45 | { | ||
| 46 | name: "github", | ||
| 47 | label: "GitHub", | ||
| 48 | icon: "⬡", | ||
| 49 | description: "Repos, Issues, Pull Requests, Actions, Packages", | ||
| 50 | specUrl: | ||
| 51 | "https://raw.githubusercontent.com/github/rest-api-description/main/descriptions/api.github.com/api.github.com.json", | ||
| 52 | baseUrl: "https://api.github.com", | ||
| 53 | }, | ||
| 54 | ]; | ||
| 55 | |||
| 56 | const OUT_DIR = join( | ||
| 57 | dirname(new URL(import.meta.url).pathname), | ||
| 58 | "../public/types", | ||
| 59 | ); | ||
| 60 | |||
| 61 | interface ManifestEntry { | ||
| 62 | name: string; | ||
| 63 | label: string; | ||
| 64 | icon: string; | ||
| 65 | description: string; | ||
| 66 | toolCount: number; | ||
| 67 | fileSizeKb: number; | ||
| 68 | file: string; | ||
| 69 | } | ||
| 70 | |||
| 71 | async function processSource(source: SourceSpec) { | ||
| 72 | console.log(`\n${"=".repeat(60)}`); | ||
| 73 | console.log(`Processing: ${source.name}`); | ||
| 74 | console.log(`${"=".repeat(60)}`); | ||
| 75 | |||
| 76 | // Step 1: Prepare the spec | ||
| 77 | console.log(" → Fetching and preparing spec..."); | ||
| 78 | let spec: string | Record<string, unknown> = source.specUrl; | ||
| 79 | |||
| 80 | if (!/\.json($|[?#])/i.test(source.specUrl)) { | ||
| 81 | console.log(" → URL doesn't end in .json, fetching manually..."); | ||
| 82 | const response = await fetch(source.specUrl); | ||
| 83 | if (!response.ok) { | ||
| 84 | throw new Error( | ||
| 85 | `Failed to fetch spec: ${response.status} ${response.statusText}`, | ||
| 86 | ); | ||
| 87 | } | ||
| 88 | spec = (await response.json()) as Record<string, unknown>; | ||
| 89 | } | ||
| 90 | |||
| 91 | const prepared = await prepareOpenApiSpec(spec, source.name, { | ||
| 92 | includeDts: true, | ||
| 93 | profile: "full", | ||
| 94 | }); | ||
| 95 | |||
| 96 | console.log(` → DTS status: ${prepared.dtsStatus}`); | ||
| 97 | console.log(` → Servers: ${prepared.servers.join(", ") || "(none)"}`); | ||
| 98 | |||
| 99 | // Step 2: Build tool definitions | ||
| 100 | console.log(" → Building tool definitions..."); | ||
| 101 | const sourceConfig: OpenApiToolSourceConfig = { | ||
| 102 | type: "openapi", | ||
| 103 | name: source.name, | ||
| 104 | spec: source.specUrl, | ||
| 105 | baseUrl: source.baseUrl, | ||
| 106 | }; | ||
| 107 | |||
| 108 | const tools = buildOpenApiToolsFromPrepared(sourceConfig, prepared); | ||
| 109 | console.log(` → Tools built: ${tools.length}`); | ||
| 110 | |||
| 111 | // Step 3: Build .d.ts type bundle | ||
| 112 | console.log(" → Building type bundle..."); | ||
| 113 | const sourceKey = `openapi:${source.name}`; | ||
| 114 | const dtsBundle = buildWorkspaceTypeBundle({ | ||
| 115 | tools, | ||
| 116 | openApiDtsBySource: prepared.dts ? { [sourceKey]: prepared.dts } : {}, | ||
| 117 | }); | ||
| 118 | |||
| 119 | const sizeKb = dtsBundle.length / 1024; | ||
| 120 | console.log(` → Bundle size: ${sizeKb.toFixed(1)} KB`); | ||
| 121 | |||
| 122 | return { toolCount: tools.length, dtsBundle, sizeKb }; | ||
| 123 | } | ||
| 124 | |||
| 125 | async function main() { | ||
| 126 | mkdirSync(OUT_DIR, { recursive: true }); | ||
| 127 | |||
| 128 | const manifest: ManifestEntry[] = []; | ||
| 129 | |||
| 130 | for (const source of SOURCES) { | ||
| 131 | try { | ||
| 132 | const result = await processSource(source); | ||
| 133 | const fileName = `${source.name}.d.ts`; | ||
| 134 | const outPath = join(OUT_DIR, fileName); | ||
| 135 | await Bun.write(outPath, result.dtsBundle); | ||
| 136 | console.log(` ✓ Written: ${outPath}`); | ||
| 137 | |||
| 138 | manifest.push({ | ||
| 139 | name: source.name, | ||
| 140 | label: source.label, | ||
| 141 | icon: source.icon, | ||
| 142 | description: source.description, | ||
| 143 | toolCount: result.toolCount, | ||
| 144 | fileSizeKb: Math.round(result.sizeKb), | ||
| 145 | file: fileName, | ||
| 146 | }); | ||
| 147 | } catch (err) { | ||
| 148 | console.error(` ✗ Failed to process ${source.name}:`, err); | ||
| 149 | } | ||
| 150 | } | ||
| 151 | |||
| 152 | // Write manifest | ||
| 153 | const manifestPath = join(OUT_DIR, "manifest.json"); | ||
| 154 | await Bun.write(manifestPath, JSON.stringify(manifest, null, 2)); | ||
| 155 | console.log(`\n✓ Manifest: ${manifestPath}`); | ||
| 156 | console.log(`\nSummary:`); | ||
| 157 | for (const entry of manifest) { | ||
| 158 | console.log( | ||
| 159 | ` ${entry.label}: ${entry.toolCount} tools, ${entry.fileSizeKb} KB`, | ||
| 160 | ); | ||
| 161 | } | ||
| 162 | console.log("\nDone!"); | ||
| 163 | } | ||
| 164 | |||
| 165 | main().catch((err) => { | ||
| 166 | console.error("Fatal error:", err); | ||
| 167 | process.exit(1); | ||
| 168 | }); | ||
| @@ -1,147 +0,0 @@ | |||
| 1 | import { useState } from "react"; | ||
| 2 | |||
| 3 | interface Source { | ||
| 4 | id: string; | ||
| 5 | name: string; | ||
| 6 | icon: string; | ||
| 7 | toolCount: number; | ||
| 8 | description: string; | ||
| 9 | } | ||
| 10 | |||
| 11 | const SOURCES: Source[] = [ | ||
| 12 | { | ||
| 13 | id: "cloudflare", | ||
| 14 | name: "Cloudflare", | ||
| 15 | icon: "☁", | ||
| 16 | toolCount: 1347, | ||
| 17 | description: "DNS, Workers, R2, KV, Zones, WAF, and more", | ||
| 18 | }, | ||
| 19 | { | ||
| 20 | id: "vercel", | ||
| 21 | name: "Vercel", | ||
| 22 | icon: "▲", | ||
| 23 | toolCount: 289, | ||
| 24 | description: "Deployments, Domains, Environment Variables, Projects", | ||
| 25 | }, | ||
| 26 | { | ||
| 27 | id: "posthog", | ||
| 28 | name: "PostHog", | ||
| 29 | icon: "🦔", | ||
| 30 | toolCount: 156, | ||
| 31 | description: "Events, Funnels, Feature Flags, Session Recordings", | ||
| 32 | }, | ||
| 33 | { | ||
| 34 | id: "github", | ||
| 35 | name: "GitHub", | ||
| 36 | icon: "⬡", | ||
| 37 | toolCount: 892, | ||
| 38 | description: "Repos, Issues, Pull Requests, Actions, Packages", | ||
| 39 | }, | ||
| 40 | { | ||
| 41 | id: "stripe", | ||
| 42 | name: "Stripe", | ||
| 43 | icon: "◈", | ||
| 44 | toolCount: 614, | ||
| 45 | description: "Charges, Subscriptions, Invoices, Customers, Payouts", | ||
| 46 | }, | ||
| 47 | { | ||
| 48 | id: "linear", | ||
| 49 | name: "Linear", | ||
| 50 | icon: "◇", | ||
| 51 | toolCount: 203, | ||
| 52 | description: "Issues, Projects, Cycles, Teams, Labels", | ||
| 53 | }, | ||
| 54 | ]; | ||
| 55 | |||
| 56 | export function AddSources() { | ||
| 57 | const [selected, setSelected] = useState<Set<string>>( | ||
| 58 | new Set(["cloudflare", "vercel", "posthog"]), | ||
| 59 | ); | ||
| 60 | |||
| 61 | const toggle = (id: string) => { | ||
| 62 | setSelected((prev) => { | ||
| 63 | const next = new Set(prev); | ||
| 64 | if (next.has(id)) next.delete(id); | ||
| 65 | else next.add(id); | ||
| 66 | return next; | ||
| 67 | }); | ||
| 68 | }; | ||
| 69 | |||
| 70 | const totalTools = SOURCES.filter((s) => selected.has(s.id)).reduce( | ||
| 71 | (sum, s) => sum + s.toolCount, | ||
| 72 | 0, | ||
| 73 | ); | ||
| 74 | |||
| 75 | return ( | ||
| 76 | <div> | ||
| 77 | <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3"> | ||
| 78 | {SOURCES.map((source) => { | ||
| 79 | const isSelected = selected.has(source.id); | ||
| 80 | return ( | ||
| 81 | <button | ||
| 82 | key={source.id} | ||
| 83 | onClick={() => toggle(source.id)} | ||
| 84 | className={`group text-left p-4 rounded-lg border transition-all duration-200 ${ | ||
| 85 | isSelected | ||
| 86 | ? "border-accent/40 bg-accent/[0.06]" | ||
| 87 | : "border-white/[0.08] bg-white/[0.02] hover:border-white/20" | ||
| 88 | }`} | ||
| 89 | > | ||
| 90 | <div className="flex items-center justify-between mb-2"> | ||
| 91 | <div className="flex items-center gap-2.5"> | ||
| 92 | <span className="text-lg">{source.icon}</span> | ||
| 93 | <span className="font-medium text-sm text-[#f5f5f5]"> | ||
| 94 | {source.name} | ||
| 95 | </span> | ||
| 96 | </div> | ||
| 97 | <div | ||
| 98 | className={`w-4 h-4 rounded border-2 flex items-center justify-center transition-all ${ | ||
| 99 | isSelected | ||
| 100 | ? "border-accent bg-accent" | ||
| 101 | : "border-white/20 bg-transparent" | ||
| 102 | }`} | ||
| 103 | > | ||
| 104 | {isSelected && ( | ||
| 105 | <svg | ||
| 106 | className="w-2.5 h-2.5 text-white" | ||
| 107 | fill="none" | ||
| 108 | viewBox="0 0 24 24" | ||
| 109 | stroke="currentColor" | ||
| 110 | strokeWidth={3} | ||
| 111 | > | ||
| 112 | <path | ||
| 113 | strokeLinecap="round" | ||
| 114 | strokeLinejoin="round" | ||
| 115 | d="M5 13l4 4L19 7" | ||
| 116 | /> | ||
| 117 | </svg> | ||
| 118 | )} | ||
| 119 | </div> | ||
| 120 | </div> | ||
| 121 | <p className="text-xs text-white/40 leading-relaxed"> | ||
| 122 | {source.description} | ||
| 123 | </p> | ||
| 124 | <div className="mt-2 text-[0.65rem] uppercase tracking-widest text-white/25"> | ||
| 125 | {source.toolCount.toLocaleString()} tools | ||
| 126 | </div> | ||
| 127 | </button> | ||
| 128 | ); | ||
| 129 | })} | ||
| 130 | </div> | ||
| 131 | <div className="mt-6 flex items-center justify-between text-sm"> | ||
| 132 | <span className="text-white/40"> | ||
| 133 | <span className="text-[#f5f5f5] font-medium"> | ||
| 134 | {selected.size} | ||
| 135 | </span>{" "} | ||
| 136 | sources selected | ||
| 137 | </span> | ||
| 138 | <span className="text-white/40"> | ||
| 139 | <span className="text-accent font-mono font-medium"> | ||
| 140 | {totalTools.toLocaleString()} | ||
| 141 | </span>{" "} | ||
| 142 | tools available | ||
| 143 | </span> | ||
| 144 | </div> | ||
| 145 | </div> | ||
| 146 | ); | ||
| 147 | } | ||
| @@ -1,148 +0,0 @@ | |||
| 1 | import { useState, useEffect, useRef } from "react"; | ||
| 2 | |||
| 3 | const CODE_EXAMPLE = `// Your agent writes TypeScript — not JSON tool calls | ||
| 4 | const zones = await tools.cloudflare.list_zones({ | ||
| 5 | account: { id: env.CF_ACCOUNT_ID }, | ||
| 6 | }) | ||
| 7 | |||
| 8 | const zone = zones.result.find(z => z.name === "example.com") | ||
| 9 | |||
| 10 | // Create a DNS record | ||
| 11 | await tools.cloudflare.create_dns_record({ | ||
| 12 | zone_id: zone.id, | ||
| 13 | type: "A", | ||
| 14 | name: "api", | ||
| 15 | content: "192.0.2.1", | ||
| 16 | proxied: true, | ||
| 17 | }) | ||
| 18 | |||
| 19 | // Check deployment status | ||
| 20 | const deploys = await tools.vercel.listDeployments({ | ||
| 21 | teamId: env.VERCEL_TEAM_ID, | ||
| 22 | limit: 5, | ||
| 23 | }) | ||
| 24 | |||
| 25 | return { | ||
| 26 | zone: zone.name, | ||
| 27 | dnsRecordCreated: true, | ||
| 28 | recentDeploys: deploys.deployments.map(d => ({ | ||
| 29 | url: d.url, | ||
| 30 | state: d.readyState, | ||
| 31 | created: d.created, | ||
| 32 | })), | ||
| 33 | }`; | ||
| 34 | |||
| 35 | const OUTPUT = `{ | ||
| 36 | "zone": "example.com", | ||
| 37 | "dnsRecordCreated": true, | ||
| 38 | "recentDeploys": [ | ||
| 39 | { | ||
| 40 | "url": "my-app-abc123.vercel.app", | ||
| 41 | "state": "READY", | ||
| 42 | "created": 1703044800000 | ||
| 43 | }, | ||
| 44 | { | ||
| 45 | "url": "my-app-def456.vercel.app", | ||
| 46 | "state": "READY", | ||
| 47 | "created": 1703041200000 | ||
| 48 | } | ||
| 49 | ] | ||
| 50 | }`; | ||
| 51 | |||
| 52 | export function CodeEditor() { | ||
| 53 | const [isRunning, setIsRunning] = useState(false); | ||
| 54 | const [showOutput, setShowOutput] = useState(false); | ||
| 55 | const outputRef = useRef<HTMLDivElement>(null); | ||
| 56 | |||
| 57 | const handleRun = () => { | ||
| 58 | setIsRunning(true); | ||
| 59 | setShowOutput(false); | ||
| 60 | setTimeout(() => { | ||
| 61 | setIsRunning(false); | ||
| 62 | setShowOutput(true); | ||
| 63 | }, 1500); | ||
| 64 | }; | ||
| 65 | |||
| 66 | useEffect(() => { | ||
| 67 | if (showOutput && outputRef.current) { | ||
| 68 | outputRef.current.scrollIntoView({ behavior: "smooth", block: "nearest" }); | ||
| 69 | } | ||
| 70 | }, [showOutput]); | ||
| 71 | |||
| 72 | return ( | ||
| 73 | <div> | ||
| 74 | <div className="bg-surface border border-white/[0.06] rounded-lg overflow-hidden"> | ||
| 75 | {/* Editor header */} | ||
| 76 | <div className="px-4 py-3 bg-white/[0.02] border-b border-white/[0.06] flex items-center justify-between"> | ||
| 77 | <div className="flex items-center gap-3"> | ||
| 78 | <span className="text-[0.65rem] uppercase tracking-widest text-white/30"> | ||
| 79 | execute.ts | ||
| 80 | </span> | ||
| 81 | <span className="text-[0.6rem] px-1.5 py-0.5 rounded bg-white/[0.06] text-white/30"> | ||
| 82 | TypeScript | ||
| 83 | </span> | ||
| 84 | </div> | ||
| 85 | <button | ||
| 86 | onClick={handleRun} | ||
| 87 | disabled={isRunning} | ||
| 88 | className={`px-3 py-1.5 text-xs font-medium rounded transition-all ${ | ||
| 89 | isRunning | ||
| 90 | ? "bg-white/10 text-white/40 cursor-wait" | ||
| 91 | : "bg-[#f5f5f5] text-surface hover:bg-white/90 active:scale-[0.98]" | ||
| 92 | }`} | ||
| 93 | > | ||
| 94 | {isRunning ? ( | ||
| 95 | <span className="flex items-center gap-1.5"> | ||
| 96 | <span className="w-3 h-3 border-2 border-white/30 border-t-white/80 rounded-full animate-spin" /> | ||
| 97 | Running... | ||
| 98 | </span> | ||
| 99 | ) : ( | ||
| 100 | "▶ Run" | ||
| 101 | )} | ||
| 102 | </button> | ||
| 103 | </div> | ||
| 104 | {/* Code body */} | ||
| 105 | <div className="p-4 overflow-x-auto"> | ||
| 106 | <pre className="!m-0 !p-0 !bg-transparent !border-none"> | ||
| 107 | <code className="!bg-transparent !p-0 font-mono text-[0.8rem] leading-7 text-white/70"> | ||
| 108 | {CODE_EXAMPLE} | ||
| 109 | </code> | ||
| 110 | </pre> | ||
| 111 | </div> | ||
| 112 | </div> | ||
| 113 | {/* Output */} | ||
| 114 | {(isRunning || showOutput) && ( | ||
| 115 | <div ref={outputRef} className="mt-3 bg-surface border border-white/[0.06] rounded-lg overflow-hidden animate-log-fade-in"> | ||
| 116 | <div className="px-4 py-3 bg-white/[0.02] border-b border-white/[0.06] flex items-center gap-2"> | ||
| 117 | <span className="text-[0.65rem] uppercase tracking-widest text-white/30"> | ||
| 118 | output | ||
| 119 | </span> | ||
| 120 | {isRunning && ( | ||
| 121 | <span className="w-3 h-3 border-2 border-white/20 border-t-green-400 rounded-full animate-spin" /> | ||
| 122 | )} | ||
| 123 | {showOutput && ( | ||
| 124 | <span className="text-[0.65rem] text-green-400"> | ||
| 125 | ✓ completed in 1.2s | ||
| 126 | </span> | ||
| 127 | )} | ||
| 128 | </div> | ||
| 129 | <div className="p-4 overflow-x-auto"> | ||
| 130 | {isRunning ? ( | ||
| 131 | <div className="font-mono text-xs text-white/30 space-y-2"> | ||
| 132 | <div className="animate-pulse">→ Resolving tool: cloudflare.list_zones...</div> | ||
| 133 | <div className="animate-pulse" style={{ animationDelay: "0.3s" }}>→ Policy check: allow (matched role "Infrastructure Admin")</div> | ||
| 134 | <div className="animate-pulse" style={{ animationDelay: "0.6s" }}>→ Executing with credentials: cf_api_token_****</div> | ||
| 135 | </div> | ||
| 136 | ) : ( | ||
| 137 | <pre className="!m-0 !p-0 !bg-transparent !border-none"> | ||
| 138 | <code className="!bg-transparent !p-0 font-mono text-[0.8rem] leading-7 text-green-400/70"> | ||
| 139 | {OUTPUT} | ||
| 140 | </code> | ||
| 141 | </pre> | ||
| 142 | )} | ||
| 143 | </div> | ||
| 144 | </div> | ||
| 145 | )} | ||
| 146 | </div> | ||
| 147 | ); | ||
| 148 | } | ||
| @@ -0,0 +1,331 @@ | |||
| 1 | import { useState, useEffect, useRef, useCallback } from "react"; | ||
| 2 | import Editor, { type OnMount, type Monaco } from "@monaco-editor/react"; | ||
| 3 | |||
| 4 | // --------------------------------------------------------------------------- | ||
| 5 | // Types | ||
| 6 | // --------------------------------------------------------------------------- | ||
| 7 | |||
| 8 | interface SourceManifestEntry { | ||
| 9 | name: string; | ||
| 10 | label: string; | ||
| 11 | icon: string; | ||
| 12 | description: string; | ||
| 13 | toolCount: number; | ||
| 14 | fileSizeKb: number; | ||
| 15 | file: string; | ||
| 16 | } | ||
| 17 | |||
| 18 | interface LoadedSource { | ||
| 19 | name: string; | ||
| 20 | dts: string; | ||
| 21 | disposable?: { dispose(): void }; | ||
| 22 | } | ||
| 23 | |||
| 24 | // --------------------------------------------------------------------------- | ||
| 25 | // Default code shown in the editor | ||
| 26 | // --------------------------------------------------------------------------- | ||
| 27 | |||
| 28 | const DEFAULT_CODE = `// Select sources above to enable autocomplete for real API types. | ||
| 29 | // Try typing "tools." and see what's available. | ||
| 30 | |||
| 31 | const zones = await tools.cloudflare.zones.list_zones({}) | ||
| 32 | |||
| 33 | const zone = zones.result?.find(z => z.name === "example.com") | ||
| 34 | |||
| 35 | if (zone) { | ||
| 36 | await tools.cloudflare.dns.create_dns_record({ | ||
| 37 | zone_id: zone.id, | ||
| 38 | type: "A", | ||
| 39 | name: "api", | ||
| 40 | content: "192.0.2.1", | ||
| 41 | proxied: true, | ||
| 42 | }) | ||
| 43 | } | ||
| 44 | |||
| 45 | const deploys = await tools.vercel.deployments.list_deployments({ | ||
| 46 | limit: 5, | ||
| 47 | }) | ||
| 48 | |||
| 49 | return { | ||
| 50 | zone: zone?.name, | ||
| 51 | recentDeploys: deploys.deployments?.map(d => ({ | ||
| 52 | url: d.url, | ||
| 53 | state: d.readyState, | ||
| 54 | })), | ||
| 55 | } | ||
| 56 | `; | ||
| 57 | |||
| 58 | // --------------------------------------------------------------------------- | ||
| 59 | // Component | ||
| 60 | // --------------------------------------------------------------------------- | ||
| 61 | |||
| 62 | const FALLBACK_MANIFEST: SourceManifestEntry[] = [ | ||
| 63 | { name: "cloudflare", label: "Cloudflare", icon: "☁", description: "DNS, Workers, R2, KV, Zones, WAF", toolCount: 2603, fileSizeKb: 11196, file: "cloudflare.d.ts" }, | ||
| 64 | { name: "vercel", label: "Vercel", icon: "▲", description: "Deployments, Domains, Projects", toolCount: 281, fileSizeKb: 2511, file: "vercel.d.ts" }, | ||
| 65 | { name: "github", label: "GitHub", icon: "⬡", description: "Repos, Issues, Pull Requests, Actions", toolCount: 1079, fileSizeKb: 6301, file: "github.d.ts" }, | ||
| 66 | ]; | ||
| 67 | |||
| 68 | export function SandboxEditor() { | ||
| 69 | const [manifest, setManifest] = useState<SourceManifestEntry[]>(FALLBACK_MANIFEST); | ||
| 70 | const [selected, setSelected] = useState<Set<string>>(new Set(["cloudflare", "vercel", "github"])); | ||
| 71 | const [loading, setLoading] = useState<Set<string>>(new Set()); | ||
| 72 | const [loaded, setLoaded] = useState<Map<string, LoadedSource>>(new Map()); | ||
| 73 | const monacoRef = useRef<Monaco | null>(null); | ||
| 74 | const editorRef = useRef<Parameters<OnMount>[0] | null>(null); | ||
| 75 | |||
| 76 | // Fetch manifest on mount (overrides fallback with real data if available) | ||
| 77 | useEffect(() => { | ||
| 78 | fetch("/types/manifest.json") | ||
| 79 | .then((r) => { | ||
| 80 | if (!r.ok) throw new Error(`${r.status}`); | ||
| 81 | return r.json(); | ||
| 82 | }) | ||
| 83 | .then((data: SourceManifestEntry[]) => setManifest(data)) | ||
| 84 | .catch(() => { | ||
| 85 | // Keep fallback manifest — editor still shows, just no types loaded | ||
| 86 | }); | ||
| 87 | }, []); | ||
| 88 | |||
| 89 | // Load/unload type definitions when selection changes | ||
| 90 | useEffect(() => { | ||
| 91 | const monaco = monacoRef.current; | ||
| 92 | if (!monaco) return; | ||
| 93 | |||
| 94 | // Load newly selected sources | ||
| 95 | for (const name of selected) { | ||
| 96 | if (loaded.has(name) || loading.has(name)) continue; | ||
| 97 | |||
| 98 | const entry = manifest.find((e) => e.name === name); | ||
| 99 | if (!entry) continue; | ||
| 100 | |||
| 101 | setLoading((prev) => new Set(prev).add(name)); | ||
| 102 | |||
| 103 | fetch(`/types/${entry.file}`) | ||
| 104 | .then((r) => r.text()) | ||
| 105 | .then((dts) => { | ||
| 106 | const uri = `file:///types/${name}.d.ts`; | ||
| 107 | const disposable = | ||
| 108 | monaco.languages.typescript.typescriptDefaults.addExtraLib( | ||
| 109 | dts, | ||
| 110 | uri, | ||
| 111 | ); | ||
| 112 | |||
| 113 | setLoaded((prev) => { | ||
| 114 | const next = new Map(prev); | ||
| 115 | next.set(name, { name, dts, disposable }); | ||
| 116 | return next; | ||
| 117 | }); | ||
| 118 | setLoading((prev) => { | ||
| 119 | const next = new Set(prev); | ||
| 120 | next.delete(name); | ||
| 121 | return next; | ||
| 122 | }); | ||
| 123 | }) | ||
| 124 | .catch((err) => { | ||
| 125 | console.error(`Failed to load types for ${name}:`, err); | ||
| 126 | setLoading((prev) => { | ||
| 127 | const next = new Set(prev); | ||
| 128 | next.delete(name); | ||
| 129 | return next; | ||
| 130 | }); | ||
| 131 | }); | ||
| 132 | } | ||
| 133 | |||
| 134 | // Dispose deselected sources | ||
| 135 | for (const [name, source] of loaded) { | ||
| 136 | if (!selected.has(name)) { | ||
| 137 | source.disposable?.dispose(); | ||
| 138 | setLoaded((prev) => { | ||
| 139 | const next = new Map(prev); | ||
| 140 | next.delete(name); | ||
| 141 | return next; | ||
| 142 | }); | ||
| 143 | } | ||
| 144 | } | ||
| 145 | }, [selected, manifest, loaded, loading]); | ||
| 146 | |||
| 147 | const toggle = useCallback((name: string) => { | ||
| 148 | setSelected((prev) => { | ||
| 149 | const next = new Set(prev); | ||
| 150 | if (next.has(name)) next.delete(name); | ||
| 151 | else next.add(name); | ||
| 152 | return next; | ||
| 153 | }); | ||
| 154 | }, []); | ||
| 155 | |||
| 156 | const handleMount: OnMount = (editor, monaco) => { | ||
| 157 | editorRef.current = editor; | ||
| 158 | monacoRef.current = monaco; | ||
| 159 | |||
| 160 | // Configure TypeScript compiler | ||
| 161 | monaco.languages.typescript.typescriptDefaults.setCompilerOptions({ | ||
| 162 | target: monaco.languages.typescript.ScriptTarget.ESNext, | ||
| 163 | module: monaco.languages.typescript.ModuleKind.ESNext, | ||
| 164 | moduleResolution: | ||
| 165 | monaco.languages.typescript.ModuleResolutionKind.NodeJs, | ||
| 166 | allowNonTsExtensions: true, | ||
| 167 | strict: true, | ||
| 168 | noEmit: true, | ||
| 169 | esModuleInterop: true, | ||
| 170 | lib: ["esnext"], | ||
| 171 | }); | ||
| 172 | |||
| 173 | // Disable built-in lib fetching — we provide our own types | ||
| 174 | monaco.languages.typescript.typescriptDefaults.setEagerModelSync(true); | ||
| 175 | monaco.languages.typescript.typescriptDefaults.setDiagnosticsOptions({ | ||
| 176 | noSemanticValidation: false, | ||
| 177 | noSyntaxValidation: false, | ||
| 178 | }); | ||
| 179 | }; | ||
| 180 | |||
| 181 | const totalTools = manifest | ||
| 182 | .filter((s) => selected.has(s.name)) | ||
| 183 | .reduce((sum, s) => sum + s.toolCount, 0); | ||
| 184 | |||
| 185 | return ( | ||
| 186 | <div> | ||
| 187 | {/* Source toggles */} | ||
| 188 | <div className="grid grid-cols-1 sm:grid-cols-3 gap-3 mb-4"> | ||
| 189 | {manifest.map((source) => { | ||
| 190 | const isSelected = selected.has(source.name); | ||
| 191 | const isLoading = loading.has(source.name); | ||
| 192 | const isLoaded = loaded.has(source.name); | ||
| 193 | |||
| 194 | return ( | ||
| 195 | <button | ||
| 196 | key={source.name} | ||
| 197 | onClick={() => toggle(source.name)} | ||
| 198 | className={`group text-left p-3 rounded-lg border transition-all duration-200 ${ | ||
| 199 | isSelected | ||
| 200 | ? "border-accent/40 bg-accent/[0.06]" | ||
| 201 | : "border-white/[0.08] bg-white/[0.02] hover:border-white/20" | ||
| 202 | }`} | ||
| 203 | > | ||
| 204 | <div className="flex items-center justify-between"> | ||
| 205 | <div className="flex items-center gap-2"> | ||
| 206 | <span className="text-base">{source.icon}</span> | ||
| 207 | <span className="font-medium text-sm text-[#f5f5f5]"> | ||
| 208 | {source.label} | ||
| 209 | </span> | ||
| 210 | {isLoading && ( | ||
| 211 | <span className="w-3 h-3 border-2 border-white/20 border-t-accent rounded-full animate-spin" /> | ||
| 212 | )} | ||
| 213 | {isSelected && isLoaded && ( | ||
| 214 | <span className="text-[0.6rem] text-green-400/60"> | ||
| 215 | ✓ | ||
| 216 | </span> | ||
| 217 | )} | ||
| 218 | </div> | ||
| 219 | <div | ||
| 220 | className={`w-4 h-4 rounded border-2 flex items-center justify-center transition-all ${ | ||
| 221 | isSelected | ||
| 222 | ? "border-accent bg-accent" | ||
| 223 | : "border-white/20 bg-transparent" | ||
| 224 | }`} | ||
| 225 | > | ||
| 226 | {isSelected && ( | ||
| 227 | <svg | ||
| 228 | className="w-2.5 h-2.5 text-white" | ||
| 229 | fill="none" | ||
| 230 | viewBox="0 0 24 24" | ||
| 231 | stroke="currentColor" | ||
| 232 | strokeWidth={3} | ||
| 233 | > | ||
| 234 | <path | ||
| 235 | strokeLinecap="round" | ||
| 236 | strokeLinejoin="round" | ||
| 237 | d="M5 13l4 4L19 7" | ||
| 238 | /> | ||
| 239 | </svg> | ||
| 240 | )} | ||
| 241 | </div> | ||
| 242 | </div> | ||
| 243 | <div className="mt-1.5 flex items-center justify-between"> | ||
| 244 | <span className="text-xs text-white/40"> | ||
| 245 | {source.description} | ||
| 246 | </span> | ||
| 247 | </div> | ||
| 248 | <div className="mt-1 text-[0.6rem] uppercase tracking-widest text-white/25"> | ||
| 249 | {source.toolCount.toLocaleString()} tools | ||
| 250 | </div> | ||
| 251 | </button> | ||
| 252 | ); | ||
| 253 | })} | ||
| 254 | </div> | ||
| 255 | |||
| 256 | {/* Stats bar */} | ||
| 257 | <div className="flex items-center justify-between text-xs text-white/40 mb-3 px-1"> | ||
| 258 | <span> | ||
| 259 | <span className="text-[#f5f5f5] font-medium">{selected.size}</span>{" "} | ||
| 260 | source{selected.size !== 1 ? "s" : ""} selected | ||
| 261 | </span> | ||
| 262 | <span> | ||
| 263 | <span className="text-accent font-mono font-medium"> | ||
| 264 | {totalTools.toLocaleString()} | ||
| 265 | </span>{" "} | ||
| 266 | typed tools available | ||
| 267 | </span> | ||
| 268 | </div> | ||
| 269 | |||
| 270 | {/* Monaco Editor */} | ||
| 271 | <div className="bg-surface border border-white/[0.06] rounded-lg overflow-hidden"> | ||
| 272 | <div className="px-4 py-3 bg-white/[0.02] border-b border-white/[0.06] flex items-center justify-between"> | ||
| 273 | <div className="flex items-center gap-3"> | ||
| 274 | <span className="text-[0.65rem] uppercase tracking-widest text-white/30"> | ||
| 275 | sandbox.ts | ||
| 276 | </span> | ||
| 277 | <span className="text-[0.6rem] px-1.5 py-0.5 rounded bg-white/[0.06] text-white/30"> | ||
| 278 | TypeScript | ||
| 279 | </span> | ||
| 280 | </div> | ||
| 281 | <div className="flex items-center gap-2 text-[0.6rem] text-white/25"> | ||
| 282 | {loading.size > 0 && ( | ||
| 283 | <span className="flex items-center gap-1.5"> | ||
| 284 | <span className="w-2.5 h-2.5 border-2 border-white/20 border-t-accent rounded-full animate-spin" /> | ||
| 285 | Loading types... | ||
| 286 | </span> | ||
| 287 | )} | ||
| 288 | {loading.size === 0 && loaded.size > 0 && ( | ||
| 289 | <span className="text-green-400/50">Types loaded</span> | ||
| 290 | )} | ||
| 291 | </div> | ||
| 292 | </div> | ||
| 293 | <Editor | ||
| 294 | height="420px" | ||
| 295 | defaultLanguage="typescript" | ||
| 296 | defaultValue={DEFAULT_CODE} | ||
| 297 | theme="vs-dark" | ||
| 298 | onMount={handleMount} | ||
| 299 | options={{ | ||
| 300 | minimap: { enabled: false }, | ||
| 301 | fontSize: 13, | ||
| 302 | lineHeight: 24, | ||
| 303 | padding: { top: 16, bottom: 16 }, | ||
| 304 | scrollBeyondLastLine: false, | ||
| 305 | wordWrap: "on", | ||
| 306 | tabSize: 2, | ||
| 307 | automaticLayout: true, | ||
| 308 | suggestOnTriggerCharacters: true, | ||
| 309 | quickSuggestions: true, | ||
| 310 | renderLineHighlight: "none", | ||
| 311 | overviewRulerBorder: false, | ||
| 312 | hideCursorInOverviewRuler: true, | ||
| 313 | scrollbar: { | ||
| 314 | verticalScrollbarSize: 6, | ||
| 315 | horizontalScrollbarSize: 6, | ||
| 316 | }, | ||
| 317 | fontFamily: "'JetBrains Mono', monospace", | ||
| 318 | fontLigatures: true, | ||
| 319 | }} | ||
| 320 | /> | ||
| 321 | </div> | ||
| 322 | |||
| 323 | {/* Hint */} | ||
| 324 | <div className="mt-4 px-4 py-3 bg-blue-500/[0.05] border-l-2 border-blue-400 text-sm text-white/60"> | ||
| 325 | These are <span className="text-[#f5f5f5] font-medium">real types</span> generated | ||
| 326 | from the actual OpenAPI specs — {totalTools.toLocaleString()} typed tool methods across {selected.size} sources. | ||
| 327 | Try typing <code className="text-accent">tools.</code> and using autocomplete. | ||
| 328 | </div> | ||
| 329 | </div> | ||
| 330 | ); | ||
| 331 | } | ||
| @@ -2,9 +2,8 @@ · 1 unmodified line | |||
| 2 | import Base from "../layouts/Base.astro"; | 2 | import Base from "../layouts/Base.astro"; |
| 3 | import Hero from "../components/Hero.astro"; | 3 | import Hero from "../components/Hero.astro"; |
| 4 | import Section from "../components/Section.astro"; | 4 | import Section from "../components/Section.astro"; |
| 5 | import { AddSources } from "../components/AddSources"; | 5 | import { SandboxEditor } from "../components/SandboxEditor"; |
| 6 | import { SystemPrompt } from "../components/SystemPrompt"; | 6 | import { SystemPrompt } from "../components/SystemPrompt"; |
| 7 | import { CodeEditor } from "../components/CodeEditor"; | ||
| 8 | import { ExampleQueries } from "../components/ExampleQueries"; | 7 | import { ExampleQueries } from "../components/ExampleQueries"; |
| 9 | import { ApprovalFlow } from "../components/ApprovalFlow"; | 8 | import { ApprovalFlow } from "../components/ApprovalFlow"; |
| 10 | import { UsageCards } from "../components/UsageCards"; | 9 | import { UsageCards } from "../components/UsageCards"; |
| @@ -33,20 +32,15 @@ import { UsageCards } from "../components/UsageCards"; · 22 unmodified lines | |||
| 33 | </p> | 32 | </p> |
| 34 | 33 | ||
| 35 | <!-- ====================================================== | 34 | <!-- ====================================================== |
| 36 | ADD SOURCES | 35 | SANDBOX EDITOR — Sources + Monaco with real types |
| 37 | ====================================================== --> | 36 | ====================================================== --> |
| 38 | <h2>Add any API as a source</h2> | 37 | <h2>Add sources, get real types</h2> |
| 39 | <p> | 38 | <p> |
| 40 | Connect OpenAPI specs, MCP servers, or GraphQL endpoints. Each source is compiled into typed, discoverable tools — not raw schema definitions pasted into context. | 39 | Connect OpenAPI specs, MCP servers, or GraphQL endpoints. Each source is compiled into a full TypeScript type bundle — real types from the real spec, loaded into a real editor. Toggle sources and see the types update live. |
| 41 | </p> | 40 | </p> |
| 42 | 41 | ||
| 43 | <div class="my-8 bg-surface-elevated border border-white/[0.08] rounded-lg overflow-hidden"> | 42 | <div class="my-8"> |
| 44 | <div class="px-5 py-4 bg-white/[0.02] border-b border-white/[0.06]"> | 43 | <SandboxEditor client:only="react" /> |
| 45 | <h4 class="font-serif text-lg font-normal m-0">Add sources</h4> | ||
| 46 | </div> | ||
| 47 | <div class="p-5"> | ||
| 48 | <AddSources client:visible /> | ||
| 49 | </div> | ||
| 50 | </div> | 44 | </div> |
| 51 | 45 | ||
| 52 | <!-- ====================================================== | 46 | <!-- ====================================================== |
| @@ -61,18 +55,6 @@ import { UsageCards } from "../components/UsageCards"; · 8 unmodified lines | |||
| 61 | <SystemPrompt client:visible /> | 55 | <SystemPrompt client:visible /> |
| 62 | </div> | 56 | </div> |
| 63 | 57 | ||
| 64 | <!-- ====================================================== | ||
| 65 | CODE EDITOR | ||
| 66 | ====================================================== --> | ||
| 67 | <h2>Your agent writes code, not JSON</h2> | ||
| 68 | <p> | ||
| 69 | Instead of rigid JSON tool calls that fail on the first typo, your agent writes TypeScript in a sandboxed runtime. It gets autocomplete-style discovery, can chain multiple operations, handle errors, and return structured results — all in a single execution. | ||
| 70 | </p> | ||
| 71 | |||
| 72 | <div class="my-8"> | ||
| 73 | <CodeEditor client:visible /> | ||
| 74 | </div> | ||
| 75 | |||
| 76 | <blockquote> | 58 | <blockquote> |
| 77 | The sandbox has no filesystem, no process access, no imports. The only way to reach the outside world is through the <code>tools</code> object — and every call goes through your policies. | 59 | The sandbox has no filesystem, no process access, no imports. The only way to reach the outside world is through the <code>tools</code> object — and every call goes through your policies. |
| 78 | </blockquote> | 60 | </blockquote> |
| @@ -85,6 +85,7 @@ · 84 unmodified lines | |||
| 85 | "dependencies": { | 85 | "dependencies": { |
| 86 | "@astrojs/react": "^4.2.1", | 86 | "@astrojs/react": "^4.2.1", |
| 87 | "@astrojs/tailwind": "^6.0.2", | 87 | "@astrojs/tailwind": "^6.0.2", |
| 88 | "@monaco-editor/react": "^4.7.0", | ||
| 88 | "astro": "^5.10.1", | 89 | "astro": "^5.10.1", |
| 89 | "react": "^19.1.0", | 90 | "react": "^19.1.0", |
| 90 | "react-dom": "^19.1.0", | 91 | "react-dom": "^19.1.0", |
| @@ -531,6 +532,10 @@ · 440 unmodified lines | |||
| 531 | 532 | ||
| 532 | "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.27.1", "", { "dependencies": { "@hono/node-server": "^1.19.9", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.2.1", "express-rate-limit": "^8.2.1", "hono": "^4.11.4", "jose": "^6.1.3", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.1" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-sr6GbP+4edBwFndLbM60gf07z0FQ79gaExpnsjMGePXqFcSSb7t6iscpjk9DhFhwd+mTEQrzNafGP8/iGGFYaA=="], | 533 | "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.27.1", "", { "dependencies": { "@hono/node-server": "^1.19.9", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.2.1", "express-rate-limit": "^8.2.1", "hono": "^4.11.4", "jose": "^6.1.3", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.1" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-sr6GbP+4edBwFndLbM60gf07z0FQ79gaExpnsjMGePXqFcSSb7t6iscpjk9DhFhwd+mTEQrzNafGP8/iGGFYaA=="], |
| 533 | 534 | ||
| 535 | "@monaco-editor/loader": ["@monaco-editor/loader@1.7.0", "", { "dependencies": { "state-local": "^1.0.6" } }, "sha512-gIwR1HrJrrx+vfyOhYmCZ0/JcWqG5kbfG7+d3f/C1LXk2EvzAbHSg3MQ5lO2sMlo9izoAZ04shohfKLVT6crVA=="], | ||
| 536 | |||
| 537 | "@monaco-editor/react": ["@monaco-editor/react@4.7.0", "", { "dependencies": { "@monaco-editor/loader": "^1.5.0" }, "peerDependencies": { "monaco-editor": ">= 0.25.0 < 1", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-cyzXQCtO47ydzxpQtCGSQGOC8Gk3ZUeBXFAxD+CWXYFo5OqZyZUonFl0DwUlTyAfRHntBfw2p3w4s9R6oe1eCA=="], | ||
| 538 | |||
| 534 | "@msgpackr-extract/msgpackr-extract-darwin-arm64": ["@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw=="], | 539 | "@msgpackr-extract/msgpackr-extract-darwin-arm64": ["@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw=="], |
| 535 | 540 | ||
| 536 | "@msgpackr-extract/msgpackr-extract-darwin-x64": ["@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw=="], | 541 | "@msgpackr-extract/msgpackr-extract-darwin-x64": ["@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw=="], |
| @@ -787,6 +792,8 @@ · 250 unmodified lines | |||
| 787 | 792 | ||
| 788 | "@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="], | 793 | "@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="], |
| 789 | 794 | ||
| 795 | "@types/trusted-types": ["@types/trusted-types@2.0.7", "", {}, "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw=="], | ||
| 796 | |||
| 790 | "@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="], | 797 | "@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="], |
| 791 | 798 | ||
| 792 | "@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="], | 799 | "@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="], |
| @@ -1109,6 +1116,8 @@ · 316 unmodified lines | |||
| 1109 | 1116 | ||
| 1110 | "domhandler": ["domhandler@5.0.3", "", { "dependencies": { "domelementtype": "^2.3.0" } }, "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w=="], | 1117 | "domhandler": ["domhandler@5.0.3", "", { "dependencies": { "domelementtype": "^2.3.0" } }, "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w=="], |
| 1111 | 1118 | ||
| 1119 | "dompurify": ["dompurify@3.2.7", "", { "optionalDependencies": { "@types/trusted-types": "^2.0.7" } }, "sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw=="], | ||
| 1120 | |||
| 1112 | "domutils": ["domutils@3.2.2", "", { "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3" } }, "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw=="], | 1121 | "domutils": ["domutils@3.2.2", "", { "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3" } }, "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw=="], |
| 1113 | 1122 | ||
| 1114 | "dset": ["dset@3.1.4", "", {}, "sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA=="], | 1123 | "dset": ["dset@3.1.4", "", {}, "sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA=="], |
| @@ -1387,6 +1396,8 @@ · 272 unmodified lines | |||
| 1387 | 1396 | ||
| 1388 | "markdown-table": ["markdown-table@3.0.4", "", {}, "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw=="], | 1397 | "markdown-table": ["markdown-table@3.0.4", "", {}, "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw=="], |
| 1389 | 1398 | ||
| 1399 | "marked": ["marked@14.0.0", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ=="], | ||
| 1400 | |||
| 1390 | "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], | 1401 | "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], |
| 1391 | 1402 | ||
| 1392 | "mdast-util-definitions": ["mdast-util-definitions@6.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "unist-util-visit": "^5.0.0" } }, "sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ=="], | 1403 | "mdast-util-definitions": ["mdast-util-definitions@6.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "unist-util-visit": "^5.0.0" } }, "sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ=="], |
| @@ -1499,6 +1510,8 @@ · 106 unmodified lines | |||
| 1499 | 1510 | ||
| 1500 | "mkdirp": ["mkdirp@1.0.4", "", { "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="], | 1511 | "mkdirp": ["mkdirp@1.0.4", "", { "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="], |
| 1501 | 1512 | ||
| 1513 | "monaco-editor": ["monaco-editor@0.55.1", "", { "dependencies": { "dompurify": "3.2.7", "marked": "14.0.0" } }, "sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A=="], | ||
| 1514 | |||
| 1502 | "mri": ["mri@1.2.0", "", {}, "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="], | 1515 | "mri": ["mri@1.2.0", "", {}, "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="], |
| 1503 | 1516 | ||
| 1504 | "mrmime": ["mrmime@2.0.1", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="], | 1517 | "mrmime": ["mrmime@2.0.1", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="], |
| @@ -1801,6 +1814,8 @@ · 296 unmodified lines | |||
| 1801 | 1814 | ||
| 1802 | "stat-mode": ["stat-mode@0.3.0", "", {}, "sha512-QjMLR0A3WwFY2aZdV0okfFEJB5TRjkggXZjxP3A1RsWsNHNu3YPv8btmtc6iCFZ0Rul3FE93OYogvhOUClU+ng=="], | 1815 | "stat-mode": ["stat-mode@0.3.0", "", {}, "sha512-QjMLR0A3WwFY2aZdV0okfFEJB5TRjkggXZjxP3A1RsWsNHNu3YPv8btmtc6iCFZ0Rul3FE93OYogvhOUClU+ng=="], |
| 1803 | 1816 | ||
| 1817 | "state-local": ["state-local@1.0.7", "", {}, "sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w=="], | ||
| 1818 | |||
| 1804 | "statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="], | 1819 | "statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="], |
| 1805 | 1820 | ||
| 1806 | "std-env": ["std-env@3.10.0", "", {}, "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg=="], | 1821 | "std-env": ["std-env@3.10.0", "", {}, "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg=="], |