theokit 0.48.7 → 0.48.8
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/dist/{actions-virtual-module-GB5FWUPS.js → actions-virtual-module-IICWQK43.js} +2 -3
- package/dist/{actions-virtual-module-GB5FWUPS.js.map → actions-virtual-module-IICWQK43.js.map} +1 -1
- package/dist/{agent-47XWDGIR.js → agent-WZLCEXD4.js} +2 -2
- package/dist/{app-typed-client-5QDNHANF.js → app-typed-client-4GDSR5T3.js} +2 -3
- package/dist/{app-typed-client-5QDNHANF.js.map → app-typed-client-4GDSR5T3.js.map} +1 -1
- package/dist/{build-4CAGKYYT.js → build-5TKAROT4.js} +2 -2
- package/dist/{chunk-H6YBKIUN.js → chunk-ABUVJU3P.js} +574 -161
- package/dist/chunk-ABUVJU3P.js.map +1 -0
- package/dist/{chunk-JZ25BBLP.js → chunk-HENNMZUH.js} +2 -2
- package/dist/{chunk-3GUXSNHY.js → chunk-RPIL7VRZ.js} +86 -3
- package/dist/chunk-RPIL7VRZ.js.map +1 -0
- package/dist/{chunk-AXQF3I4L.js → chunk-ZGNA66JK.js} +39 -122
- package/dist/chunk-ZGNA66JK.js.map +1 -0
- package/dist/cli/index.js +5 -5
- package/dist/{dev-F67X4F5E.js → dev-XGAJQ7DH.js} +4 -5
- package/dist/{dev-F67X4F5E.js.map → dev-XGAJQ7DH.js.map} +1 -1
- package/dist/{internal-api-ICU7ITJD.js → internal-api-AKYIRMT2.js} +7 -9
- package/dist/{mcp-AJHKPAU4.js → mcp-D7K6NJMW.js} +2 -2
- package/dist/{start-IITIEJTY.js → start-YR4TQQP2.js} +10 -8
- package/dist/start-YR4TQQP2.js.map +1 -0
- package/dist/{vite-plugin-MXHY6MSV.js → vite-plugin-PUUCR6LR.js} +4 -5
- package/package.json +1 -1
- package/dist/chunk-3GUXSNHY.js.map +0 -1
- package/dist/chunk-7CQ6DEWZ.js +0 -421
- package/dist/chunk-7CQ6DEWZ.js.map +0 -1
- package/dist/chunk-AXQF3I4L.js.map +0 -1
- package/dist/chunk-H6YBKIUN.js.map +0 -1
- package/dist/start-IITIEJTY.js.map +0 -1
- /package/dist/{agent-47XWDGIR.js.map → agent-WZLCEXD4.js.map} +0 -0
- /package/dist/{build-4CAGKYYT.js.map → build-5TKAROT4.js.map} +0 -0
- /package/dist/{chunk-JZ25BBLP.js.map → chunk-HENNMZUH.js.map} +0 -0
- /package/dist/{internal-api-ICU7ITJD.js.map → internal-api-AKYIRMT2.js.map} +0 -0
- /package/dist/{mcp-AJHKPAU4.js.map → mcp-D7K6NJMW.js.map} +0 -0
- /package/dist/{vite-plugin-MXHY6MSV.js.map → vite-plugin-PUUCR6LR.js.map} +0 -0
|
@@ -5,17 +5,22 @@ import {
|
|
|
5
5
|
handleMcpJsonRpc,
|
|
6
6
|
isMcpPath
|
|
7
7
|
} from "./chunk-2CVV6CNN.js";
|
|
8
|
+
import {
|
|
9
|
+
findRootDiv
|
|
10
|
+
} from "./chunk-3PWQQWT6.js";
|
|
8
11
|
import {
|
|
9
12
|
RUN_ID_HEADER,
|
|
10
13
|
SSE_BASE_HEADERS,
|
|
11
14
|
SSE_DONE_FRAME,
|
|
15
|
+
applySecurityHeaders,
|
|
12
16
|
encodeSse,
|
|
13
17
|
formatSseFrame,
|
|
18
|
+
generateNonce,
|
|
14
19
|
getRunEventCache,
|
|
15
20
|
makeThreadStartRun,
|
|
16
21
|
mintRunId,
|
|
17
22
|
parseAgentRequestBody
|
|
18
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-ABUVJU3P.js";
|
|
19
24
|
import {
|
|
20
25
|
getApprovalRegistry
|
|
21
26
|
} from "./chunk-6GGWS7J3.js";
|
|
@@ -114,6 +119,83 @@ function hoistHeadTags(template, ssrHtml) {
|
|
|
114
119
|
return { template: hoisted, html };
|
|
115
120
|
}
|
|
116
121
|
|
|
122
|
+
// src/vite-plugin/ssr-dev-middleware.ts
|
|
123
|
+
import { readFileSync } from "fs";
|
|
124
|
+
import { resolve } from "path";
|
|
125
|
+
function applyNonceToInlineScripts(html, nonce) {
|
|
126
|
+
return html.replace(
|
|
127
|
+
/<script(?![^>]*\ssrc=)(?![^>]*\snonce=)([^>]*)>/gi,
|
|
128
|
+
`<script nonce="${nonce}"$1>`
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
function isSsrRenderResult(value) {
|
|
132
|
+
if (typeof value !== "object" || value === null) return false;
|
|
133
|
+
if (!("html" in value)) return false;
|
|
134
|
+
return typeof value.html === "string";
|
|
135
|
+
}
|
|
136
|
+
function setupSsrDevMiddleware(server, opts) {
|
|
137
|
+
server.middlewares.use((req, res, next) => {
|
|
138
|
+
void (async () => {
|
|
139
|
+
const url = req.url ?? "/";
|
|
140
|
+
if (url.startsWith("/api/") || url.startsWith("/@") || url.startsWith("/node_modules/") || url.includes(".")) {
|
|
141
|
+
next();
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
try {
|
|
145
|
+
const indexPath = resolve(opts.projectRoot, "index.html");
|
|
146
|
+
let template = readFileSync(indexPath, "utf-8");
|
|
147
|
+
const nonce = generateNonce();
|
|
148
|
+
template = await server.transformIndexHtml(url, template);
|
|
149
|
+
template = applyNonceToInlineScripts(template, nonce);
|
|
150
|
+
applySecurityHeaders(
|
|
151
|
+
res,
|
|
152
|
+
opts.securityHeaders ?? {},
|
|
153
|
+
{ production: process.env.NODE_ENV === "production" },
|
|
154
|
+
{ nonce }
|
|
155
|
+
);
|
|
156
|
+
const mod = await server.ssrLoadModule(opts.virtualEntryServerId);
|
|
157
|
+
const result = await mod.render(url, { nonce });
|
|
158
|
+
if (result && typeof result === "object" && "redirect" in result) {
|
|
159
|
+
res.writeHead(302, {
|
|
160
|
+
Location: result.redirect.headers.get("location") ?? "/"
|
|
161
|
+
});
|
|
162
|
+
res.end();
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
let ssrHtml;
|
|
166
|
+
let hydrationScript = "";
|
|
167
|
+
if (typeof result === "string") {
|
|
168
|
+
ssrHtml = result;
|
|
169
|
+
} else if (isSsrRenderResult(result)) {
|
|
170
|
+
ssrHtml = result.html;
|
|
171
|
+
const dataJson = JSON.stringify(result.hydrationData).replace(/</g, "\\u003c");
|
|
172
|
+
hydrationScript = `<script nonce="${nonce}">window.__staticRouterHydrationData=${dataJson}</script>`;
|
|
173
|
+
} else {
|
|
174
|
+
ssrHtml = "";
|
|
175
|
+
}
|
|
176
|
+
const hoisted = hoistHeadTags(template, ssrHtml);
|
|
177
|
+
template = hoisted.template;
|
|
178
|
+
ssrHtml = hoisted.html;
|
|
179
|
+
const rootDiv = findRootDiv(template);
|
|
180
|
+
if (!rootDiv) {
|
|
181
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
182
|
+
res.end(template);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
const splitIdx = rootDiv.insertAt;
|
|
186
|
+
const html = template.slice(0, splitIdx) + ssrHtml + hydrationScript + template.slice(splitIdx);
|
|
187
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
188
|
+
res.end(html);
|
|
189
|
+
} catch (err) {
|
|
190
|
+
server.ssrFixStacktrace(err);
|
|
191
|
+
console.error("[SSR Dev Error]", err);
|
|
192
|
+
next();
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
})();
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
|
|
117
199
|
// src/server/agent/agent-card-handler.ts
|
|
118
200
|
import { buildAgentCard, compileAgentModule } from "@theokit/agents";
|
|
119
201
|
var WELL_KNOWN = /^\/\.well-known\/([^/]+)\/agent-card\.json$/;
|
|
@@ -624,6 +706,7 @@ export {
|
|
|
624
706
|
writeWebResponseToServerResponse,
|
|
625
707
|
extractHeadTags,
|
|
626
708
|
injectIntoHead,
|
|
627
|
-
|
|
709
|
+
applyNonceToInlineScripts,
|
|
710
|
+
setupSsrDevMiddleware
|
|
628
711
|
};
|
|
629
|
-
//# sourceMappingURL=chunk-
|
|
712
|
+
//# sourceMappingURL=chunk-RPIL7VRZ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/server/transformer.ts","../src/vite-plugin/hoist-head-tags.ts","../src/vite-plugin/ssr-dev-middleware.ts","../src/server/agent/agent-card-handler.ts","../src/server/agent/approve-agent.ts","../src/server/agent/list-approvals-handler.ts","../src/server/agent/handle-agent-run-reconnect.ts","../src/server/agent/thread-dispatcher.ts","../src/server/agent/thread-run-registry.ts","../src/server/agent/handle-thread-routes.ts","../src/server/agent/serve-aux-routes.ts","../src/server/http/node-web-adapter.ts"],"sourcesContent":["import superjson from 'superjson'\n\n/**\n * T5.2 — pluggable response/request transformer.\n *\n * `superjson` is the default, preserving Date/Map/Set/BigInt/etc.\n * `json` is the lightweight option (plain JSON.stringify/parse).\n * Users can supply a custom object implementing this contract.\n */\nexport interface TheoTransformer {\n name: string\n serialize: (value: unknown) => string\n deserialize: (raw: string) => unknown\n}\n\nexport const superjsonTransformer: TheoTransformer = {\n name: 'superjson',\n serialize: (v) => JSON.stringify(superjson.serialize(v)),\n deserialize: (raw) => {\n const parsed = JSON.parse(raw) as Parameters<typeof superjson.deserialize>[0]\n return superjson.deserialize(parsed)\n },\n}\n\nexport const jsonTransformer: TheoTransformer = {\n name: 'json',\n serialize: (v) => JSON.stringify(v),\n deserialize: (raw) => JSON.parse(raw) as unknown,\n}\n\nconst BUILT_INS: Record<string, TheoTransformer> = {\n superjson: superjsonTransformer,\n json: jsonTransformer,\n}\n\nexport function resolveTransformer(\n selector: 'json' | 'superjson' | TheoTransformer,\n): TheoTransformer {\n if (typeof selector === 'string') {\n // selector is 'json' | 'superjson' literal — both keys exist in\n // BUILT_INS by construction. Type system guarantees a hit; we keep\n // a defensive fallback that the compiler cannot see is unreachable\n // at runtime, just in case someone adds a new literal to the union\n // but forgets to register the built-in.\n const built = BUILT_INS[selector]\n // Defensive: the public union ensures `built` is defined, but if a\n // future contributor extends the union without registering the impl,\n // the cast keeps the failure mode loud.\n if ((built as TheoTransformer | undefined) === undefined) {\n throw new Error(\n `Unknown transformer \"${selector}\". Built-in options: ${Object.keys(BUILT_INS).join(', ')}.`,\n )\n }\n return built\n }\n if (\n typeof selector !== 'object' ||\n typeof selector.serialize !== 'function' ||\n typeof selector.deserialize !== 'function'\n ) {\n throw new Error(\n `Custom transformer must have serialize and deserialize functions. Got: ${JSON.stringify(selector)}`,\n )\n }\n return selector\n}\n","/**\n * Moves the document metadata a route rendered into the `<head>` where it belongs.\n *\n * ## Why this exists\n *\n * React 19 hoists `<title>`, `<meta>` and `<link>` into the head — **in the browser**, by moving\n * DOM nodes after hydration. On the server it emits them inline, wherever the component sat, and\n * the SSR output is injected inside `<div id=\"root\">`. So a route's own metadata ships in the\n * BODY.\n *\n * For a reader that changes nothing: hydration moves the tags a moment later. For a crawler it\n * changes everything, because the ones that matter never run JavaScript. Every social unfurler —\n * X, LinkedIn, Slack, Discord, WhatsApp — reads the served `<head>` and stops. Without this, every\n * page of a site unfurls with whatever static fallback `index.html` happens to carry: share ten\n * different documentation pages, get ten identical cards.\n *\n * Turning SSR on to fix social previews and finding they still do not work is a bad afternoon, so\n * the framework does the hoist itself (usetheokit/theokit#319).\n *\n * ## Precedence\n *\n * The route wins over the template. `index.html` holds site-wide defaults; a page that states its\n * own title, description or canonical is being specific on purpose, and shipping both would leave\n * the crawler to pick — in practice the first one, which is the generic one.\n */\n\n/**\n * Tags React hoists, and therefore the ones worth moving.\n *\n * Two separate patterns rather than one with an alternation: a single expression covering both the\n * self-closing tags and the `<title>…</title>` pair needs a lazy `[\\s\\S]*?` next to a lazy\n * `[^>]*?`, and that nests two unbounded quantifiers — catastrophic backtracking on hostile input,\n * which here is a served HTML document. Each pattern below is linear: `[^>]` and `[^<]` cannot\n * cross the delimiter that ends the match.\n */\nconst VOID_METADATA = /<(?:meta|link)\\b[^>]*>/gi\n/** `<title>` content is text, so it cannot contain `<` — the class is what keeps this linear. */\nconst TITLE_TAG = /<title\\b[^>]*>[^<]*<\\/title>/gi\n\n/** Runs `replacer` over every hoistable tag, in document order. */\nfunction replaceHoistable(html: string, replacer: (tag: string) => string): string {\n return html.replace(TITLE_TAG, replacer).replace(VOID_METADATA, replacer)\n}\n\n/**\n * The identity of a metadata tag, used to decide what the route replaces.\n *\n * `<meta name=\"description\">` and `<meta property=\"og:title\">` are distinct slots; two `<meta>`\n * tags with different names are not duplicates. A `<link>` is keyed by `rel`, so a route's\n * canonical replaces the template's while a stylesheet link is left alone.\n *\n * Anything unkeyed (a `<link rel=\"preconnect\">`, say) returns `undefined` and is simply appended —\n * additive tags must not evict each other.\n */\nexport function metadataKey(tag: string): string | undefined {\n if (/^<title\\b/i.test(tag)) return 'title'\n\n const name = /\\bname=[\"']([^\"']+)[\"']/i.exec(tag)?.[1]\n const property = /\\bproperty=[\"']([^\"']+)[\"']/i.exec(tag)?.[1]\n const rel = /\\brel=[\"']([^\"']+)[\"']/i.exec(tag)?.[1]\n\n if (/^<meta\\b/i.test(tag)) {\n if (property !== undefined) return `property:${property.toLowerCase()}`\n if (name !== undefined) return `name:${name.toLowerCase()}`\n return undefined\n }\n\n if (/^<link\\b/i.test(tag) && rel !== undefined) {\n const slug = rel.toLowerCase()\n // Only single-valued rels are slots. `stylesheet`, `preload` and friends are additive: keying\n // them would let one page's stylesheet evict another's.\n return slug === 'canonical' || slug === 'manifest' ? `link:${slug}` : undefined\n }\n\n return undefined\n}\n\nexport interface HoistedHead {\n /** The rendered HTML with its metadata tags removed. */\n html: string\n /** Those tags, ready to be placed in the head. */\n headTags: string[]\n}\n\n/** Pulls hoistable metadata out of rendered SSR markup. */\nexport function extractHeadTags(ssrHtml: string): HoistedHead {\n const headTags: string[] = []\n const html = replaceHoistable(ssrHtml, (tag) => {\n headTags.push(tag)\n return ''\n })\n return { html, headTags }\n}\n\n/**\n * Inserts `headTags` into the template's head, dropping any template tag the route supersedes.\n *\n * Returns the template untouched when there is nothing to hoist or no `</head>` to hoist into —\n * a missing head is a malformed template, and rewriting it further would not help anyone.\n */\nexport function injectIntoHead(template: string, headTags: string[]): string {\n if (headTags.length === 0) return template\n\n const closingHead = template.toLowerCase().lastIndexOf('</head>')\n if (closingHead === -1) return template\n\n const supersededKeys = new Set(\n headTags.map((tag) => metadataKey(tag)).filter((key): key is string => key !== undefined),\n )\n\n let head = template.slice(0, closingHead)\n if (supersededKeys.size > 0) {\n head = replaceHoistable(head, (tag) => {\n const key = metadataKey(tag)\n return key !== undefined && supersededKeys.has(key) ? '' : tag\n })\n }\n\n return `${head} ${headTags.join('\\n ')}\\n ${template.slice(closingHead)}`\n}\n\n/**\n * The whole operation: strip metadata from the rendered markup and place it in the template's head.\n */\nexport function hoistHeadTags(\n template: string,\n ssrHtml: string,\n): { template: string; html: string } {\n const { html, headTags } = extractHeadTags(ssrHtml)\n const hoisted = injectIntoHead(template, headTags)\n\n // Fail SAFE, not silent. `injectIntoHead` returns the template untouched when it finds no\n // `</head>` — and if we returned the stripped body alongside it, the metadata would be removed\n // from one place and added to neither. It would vanish, with nothing to show for it.\n //\n // That is not hypothetical: a template whose COMMENT mentioned `<div id=\"root\">` split at the\n // comment, leaving a \"head\" half with no `</head>` in it, and every route silently lost its\n // title and canonical. Metadata in the wrong place still works after hydration; metadata that is\n // gone never comes back.\n if (hoisted === template) return { template, html: ssrHtml }\n\n return { template: hoisted, html }\n}\n","/**\n * T2.2 (architecture-medium-deferrals plan, ADR D2) — SSR dev middleware\n * extracted from `vite-plugin/index.ts` for SRP.\n *\n * `setupSsrDevMiddleware(server, opts)` registers a Connect-style middleware\n * on the Vite dev server that:\n * 1. Skips API, static, and HMR requests (let other middlewares handle).\n * 2. Reads `index.html`, runs `transformIndexHtml`.\n * 3. Generates per-request nonce, applies security headers (CSP + Cache-Control).\n * 4. Calls `ssrLoadModule(VIRTUAL_ENTRY_SERVER_ID).render(url, { nonce })`.\n * 5. Injects rendered HTML (with hydration script) into root div.\n * 6. On error: ssrFixStacktrace + fallback to CSR via `next()`.\n *\n * No-op when `ssrEnabled === false`. Caller's responsibility to gate.\n */\n\nimport { readFileSync } from 'node:fs'\nimport { resolve } from 'node:path'\n\nimport type { ViteDevServer } from 'vite'\n\nimport { findRootDiv } from '../core/contracts/find-root-div.js'\nimport {\n applySecurityHeaders,\n generateNonce,\n type SecurityHeadersConfig,\n} from '../server/internal-api.js'\n\nimport { hoistHeadTags } from './hoist-head-tags.js'\n\ninterface SsrRenderResult {\n html: string\n hydrationData: {\n loaderData?: unknown\n actionData?: unknown\n errors?: unknown\n }\n}\n\ninterface SsrEntryServer {\n render: (\n url: string,\n opts: { nonce: string },\n ) => Promise<SsrRenderResult | { redirect: Response } | string>\n}\n\n/**\n * Stamps the request nonce onto every inline `<script>` the HTML already carries.\n *\n * `transformIndexHtml` lets Vite plugins inject their own scripts, and they know nothing about our\n * CSP. `@vitejs/plugin-react` injects its refresh preamble as an INLINE module script with no\n * nonce, so a nonce-based `script-src` blocks it, `window.$RefreshReg$` is never defined, and the\n * first component module throws \"@vitejs/plugin-react can't detect preamble\". SSR still produced\n * the HTML, so the page looks fine and simply never hydrates — nothing interactive works, and the\n * one console error points at Vite rather than at us (usetheokit/theokit#319).\n *\n * Only scripts WITHOUT `src` are stamped: a same-origin `src` is already covered by `'self'`, and\n * an inline script is the only kind a nonce is needed for. Scripts that already carry a nonce are\n * left alone, so the render's own output is never rewritten.\n *\n * Deliberately not a general HTML parser: this runs per request in dev, on markup we produced or a\n * Vite plugin injected, and the pattern only ever matches an opening `<script>` tag.\n */\nexport function applyNonceToInlineScripts(html: string, nonce: string): string {\n return html.replace(\n /<script(?![^>]*\\ssrc=)(?![^>]*\\snonce=)([^>]*)>/gi,\n `<script nonce=\"${nonce}\"$1>`,\n )\n}\n\nfunction isSsrRenderResult(value: unknown): value is SsrRenderResult {\n if (typeof value !== 'object' || value === null) return false\n if (!('html' in value)) return false\n return typeof (value as Record<string, unknown>).html === 'string'\n}\n\ninterface SsrDevMiddlewareOptions {\n projectRoot: string\n virtualEntryServerId: string\n securityHeaders: SecurityHeadersConfig | undefined\n}\n\n/**\n * Attach the SSR dev middleware to a Vite dev server. Caller decides whether\n * to invoke this based on `ssrEnabled` — this function does not gate.\n */\nexport function setupSsrDevMiddleware(server: ViteDevServer, opts: SsrDevMiddlewareOptions): void {\n server.middlewares.use((req, res, next) => {\n void (async () => {\n const url = req.url ?? '/'\n // Skip API, static, and HMR requests\n if (\n url.startsWith('/api/') ||\n url.startsWith('/@') ||\n url.startsWith('/node_modules/') ||\n url.includes('.')\n ) {\n next()\n return\n }\n\n try {\n const indexPath = resolve(opts.projectRoot, 'index.html')\n // eslint-disable-next-line security/detect-non-literal-fs-filename -- projectRoot is from `theokit dev`'s caller-controlled cwd\n let template = readFileSync(indexPath, 'utf-8')\n\n // T4.1 — Generate a per-request nonce and apply security headers BEFORE render.\n // The same nonce flows into React's renderToPipeableStream({ nonce }) so every\n // emitted <script> carries it AND into the CSP script-src directive.\n // EC-3: applySecurityHeaders also forces Cache-Control: private, no-store.\n //\n // The nonce is minted BEFORE `transformIndexHtml` so the scripts Vite plugins inject can be\n // stamped with it. Minting it afterwards left the React refresh preamble unnonced, the CSP\n // blocked it, and the app never hydrated (usetheokit/theokit#319).\n const nonce = generateNonce()\n\n template = await server.transformIndexHtml(url, template)\n template = applyNonceToInlineScripts(template, nonce)\n applySecurityHeaders(\n res,\n opts.securityHeaders ?? {},\n { production: process.env.NODE_ENV === 'production' },\n { nonce },\n )\n\n const mod = (await server.ssrLoadModule(opts.virtualEntryServerId)) as SsrEntryServer\n const result = await mod.render(url, { nonce })\n\n if (result && typeof result === 'object' && 'redirect' in result) {\n res.writeHead(302, {\n Location: result.redirect.headers.get('location') ?? '/',\n })\n res.end()\n return\n }\n\n // Backward-compat: old render returned string. New shape returns\n // { html, hydrationData } so the framework can emit the hydration\n // data script OUTSIDE the React root (fixes hydration mismatch).\n let ssrHtml: string\n let hydrationScript = ''\n if (typeof result === 'string') {\n ssrHtml = result\n } else if (isSsrRenderResult(result)) {\n ssrHtml = result.html\n const dataJson = JSON.stringify(result.hydrationData).replace(/</g, '\\\\u003c')\n hydrationScript = `<script nonce=\"${nonce}\">window.__staticRouterHydrationData=${dataJson}</script>`\n } else {\n ssrHtml = ''\n }\n // Move the route's <title>/<meta>/<link> out of the rendered body and into the head.\n // React only hoists those in the browser, after hydration — a crawler that does not run JS\n // would otherwise never see a page's own title or social card (usetheokit/theokit#319).\n const hoisted = hoistHeadTags(template, ssrHtml)\n template = hoisted.template\n ssrHtml = hoisted.html\n\n const rootDiv = findRootDiv(template)\n if (!rootDiv) {\n res.writeHead(200, { 'Content-Type': 'text/html' })\n res.end(template)\n return\n }\n\n const splitIdx = rootDiv.insertAt\n const html =\n template.slice(0, splitIdx) + ssrHtml + hydrationScript + template.slice(splitIdx)\n\n res.writeHead(200, { 'Content-Type': 'text/html' })\n res.end(html)\n } catch (err) {\n server.ssrFixStacktrace(err as Error)\n console.error('[SSR Dev Error]', err)\n // Fallback to CSR\n next()\n return\n }\n })()\n })\n}\n","/**\n * M15 (theokit-ai-first) — serve the A2A agent card at `/.well-known/<name>/agent-card.json`.\n *\n * `buildAgentCard` (@theokit/agents) is the pure generator; this handler compiles a loaded agent\n * module to its tools + streaming capability, builds the card, and returns it as a Web-Standard\n * JSON `Response` (G8). The dev middleware + prod handler branch to this before the agent POST route.\n */\nimport { type AgentManifestEntry, buildAgentCard, compileAgentModule } from '@theokit/agents'\n\nconst WELL_KNOWN = /^\\/\\.well-known\\/([^/]+)\\/agent-card\\.json$/\n\n/** Return the agent name when `urlPath` is a well-known card path, else `null`. */\nexport function isAgentCardPath(urlPath: string): string | null {\n const match = WELL_KNOWN.exec(urlPath)\n return match ? decodeURIComponent(match[1]) : null\n}\n\n/** Build a minimal manifest entry (the subset `buildAgentCard` reads) from a compiled agent. */\nfunction toManifestEntry(name: string, route: string, mod: unknown): AgentManifestEntry {\n const compiled = compileAgentModule(mod, `agent card for \"${name}\"`)\n return {\n name,\n route,\n stream: compiled.stream,\n mainLoop: { method: '', strategy: '' },\n guards: [],\n interceptors: [],\n tools: compiled.tools.map((t) => ({\n name: t.name,\n description: t.description,\n approval: false,\n trace: false,\n audit: false,\n })),\n subAgents: [],\n }\n}\n\n/**\n * Serve the A2A card for a loaded agent module. Returns 200 with the card JSON, or 500 with an\n * error body if the module is not a valid agent (fail-clear, not a silent empty card).\n */\nexport function handleAgentCard(\n mod: unknown,\n name: string,\n route: string,\n baseUrl: string,\n): Response {\n try {\n const card = buildAgentCard(toManifestEntry(name, route, mod), { baseUrl })\n return new Response(JSON.stringify(card), {\n status: 200,\n headers: { 'content-type': 'application/json; charset=utf-8' },\n })\n } catch (err) {\n return new Response(\n JSON.stringify({\n error: {\n code: 'AGENT_CARD_FAILED',\n message: err instanceof Error ? err.message : 'card build failed',\n },\n }),\n { status: 500, headers: { 'content-type': 'application/json; charset=utf-8' } },\n )\n }\n}\n","/**\n * M4 (theokit-ai-first) — the HITL approve endpoint: `POST /api/agents/<name>/approve/<approvalId>`.\n *\n * The counterpart to `mountAgent`'s HITL pause. While a gated tool holds the SDK run paused (the\n * awaited `pre_tool_call` hook), the client POSTs here with `{ approved }`; this resolves the\n * pending approval in the shared registry, which un-pauses the run (allow) or vetoes the tool (deny).\n *\n * Web-Standard `Request` → `Response`, one wiring point shared by dev (vite middleware) and prod\n * (built server) so the two never drift (EC-4 parity with `mountAgent`). The registry is INJECTED —\n * dev/prod pass the process singleton (`getApprovalRegistry`), tests pass a fresh instance.\n */\nimport { validateCsrfRequest, type CsrfMode } from '../security/csrf.js'\n\nimport type { ApprovalDecision, ApprovalRegistry } from './approval-registry.js'\n\n/** The path segment separating the agent name from the approval id. */\nconst APPROVE_SEGMENT = '/approve/'\n\n/**\n * Extract the `<approvalId>` from a `/api/agents/<name>/approve/<approvalId>` path.\n * Returns `null` when the path has no `/approve/` segment or an empty / nested id.\n */\nexport function parseApprovalId(urlPath: string): string | null {\n const at = urlPath.indexOf(APPROVE_SEGMENT)\n if (at === -1) return null\n const id = urlPath.slice(at + APPROVE_SEGMENT.length)\n return id.length > 0 && !id.includes('/') ? id : null\n}\n\n/** True when `urlPath` targets a HITL approve endpoint (used by dev/prod routing to branch early). */\nexport function isApprovalPath(urlPath: string): boolean {\n return urlPath.includes(APPROVE_SEGMENT)\n}\n\nfunction jsonError(status: number, code: string, message: string): Response {\n return new Response(JSON.stringify({ error: { code, message } }), {\n status,\n headers: { 'content-type': 'application/json' },\n })\n}\n\n/**\n * M20 — cap on the serialized custom payload (16 KiB). A payload is a small structured note\n * (edited args, a reviewer comment), not a data channel — an oversized one is rejected fail-fast\n * rather than silently truncated (Rule 8).\n */\nconst MAX_PAYLOAD_BYTES = 16 * 1024\n\n/**\n * Extract an {@link ApprovalDecision} from an untrusted body; `null` when the shape is wrong.\n *\n * M20 — accepts an optional `reason` (string) and `payload` (object, capped at\n * {@link MAX_PAYLOAD_BYTES}). Backward-compatible: `{ approved }` and `{ approved, reason }` parse\n * unchanged. A non-object or oversized `payload` is rejected (returns `null` → the route 400s).\n *\n * @public\n */\nexport function parseApprovalBody(body: unknown): ApprovalDecision | null {\n if (typeof body !== 'object' || body === null) return null\n const b = body as Record<string, unknown>\n if (typeof b.approved !== 'boolean') return null\n const decision: ApprovalDecision = { approved: b.approved }\n if (b.reason !== undefined) {\n if (typeof b.reason !== 'string') return null\n decision.reason = b.reason\n }\n if (b.payload !== undefined) {\n if (typeof b.payload !== 'object' || b.payload === null || Array.isArray(b.payload)) return null\n if (JSON.stringify(b.payload).length > MAX_PAYLOAD_BYTES) return null\n decision.payload = b.payload\n }\n return decision\n}\n\n/**\n * Resolve a pending HITL approval. CSRF-guarded like `mountAgent` (the custom `X-Theo-Action`\n * header + Origin match) — a cross-origin POST must not approve a paused tool. Returns:\n * 403 CSRF_FAILED — strict CSRF check failed\n * 400 BAD_REQUEST — no `/approve/<id>` in the path, or body lacks a boolean `approved`\n * 404 NOT_PENDING — the id is unknown or already settled (idempotent double-submit)\n * 200 { resolved:true } — the approval was settled by this call\n */\nexport async function handleAgentApproval(\n request: Request,\n urlPath: string,\n registry: ApprovalRegistry,\n csrfMode: CsrfMode = 'strict',\n): Promise<Response> {\n if (csrfMode !== 'off') {\n const csrf = validateCsrfRequest(request)\n if (!csrf.valid && csrfMode === 'strict') {\n return jsonError(403, 'CSRF_FAILED', `CSRF check failed: ${csrf.reason}`)\n }\n }\n\n const approvalId = parseApprovalId(urlPath)\n if (approvalId === null) {\n return jsonError(400, 'BAD_REQUEST', 'Approval path must be /api/agents/<name>/approve/<id>.')\n }\n\n let body: unknown = null\n try {\n body = await request.json()\n } catch {\n /* invalid/empty JSON → handled below as a 400 */\n }\n const parsed = parseApprovalBody(body)\n if (parsed === null) {\n return jsonError(400, 'BAD_REQUEST', 'Request body must contain a boolean `approved`.')\n }\n\n const resolved = registry.resolve(approvalId, parsed)\n if (!resolved) {\n return jsonError(404, 'NOT_PENDING', `No pending approval for id '${approvalId}'.`)\n }\n return new Response(JSON.stringify({ resolved: true }), {\n status: 200,\n headers: { 'content-type': 'application/json' },\n })\n}\n","/**\n * M14 (theokit-ai-first) — GET /api/agents/<name>/approvals: list pending HITL approvals.\n *\n * Serves `ApprovalRegistry.list()` as JSON. Single-process contract (ADR 0038) — the list is\n * process-wide; the `<name>` segment is accepted for a future per-agent/durable store but the\n * in-process registry lists all pending approvals. Web Standards Response (G8).\n */\nimport type { ApprovalRegistry } from './approval-registry.js'\n\nconst LIST_PATH = /^\\/api\\/agents\\/([^/]+)\\/approvals$/\n\n/** Return the agent name when `urlPath` is the approvals-listing path, else `null`. */\nexport function isListApprovalsPath(urlPath: string): string | null {\n const match = LIST_PATH.exec(urlPath)\n return match ? decodeURIComponent(match[1]) : null\n}\n\n/** Serve the currently-pending approvals as `{ approvals: [...] }` JSON. */\nexport function handleListApprovals(registry: ApprovalRegistry): Response {\n return new Response(JSON.stringify({ approvals: registry.list() }), {\n status: 200,\n headers: { 'content-type': 'application/json; charset=utf-8' },\n })\n}\n","import {\n encodeSse,\n formatSseFrame,\n RUN_ID_HEADER,\n SSE_BASE_HEADERS,\n SSE_DONE_FRAME,\n} from './durable-ui-message-stream-response.js'\nimport type { RunEventCache } from './run-event-cache.js'\n\n/**\n * M37 (ADR-0046 D5) — the reconnect / observe endpoint handler for\n * `GET /api/agents/<name>/runs/<runId>/stream`.\n *\n * Replays the frames the client missed (`seq > Last-Event-ID`, SSE-native), then\n * — if the run is still live — follows the live tail; a SECOND client can\n * observe a run a first started. Run already ended ⇒ replay + `[DONE]`. Unknown\n * `runId` ⇒ 404. The request `AbortSignal` unsubscribes on disconnect.\n */\n\nconst RUN_STREAM_PATH = /^\\/api\\/agents\\/([^/]+)\\/runs\\/([^/]+)\\/stream$/\n\n/**\n * Match `GET /api/agents/<name>/runs/<runId>/stream`; returns the decoded\n * `{ name, runId }` or `null` to fall through (mirrors `isMcpPath` etc.).\n */\nexport function isAgentRunStreamPath(urlPath: string): { name: string; runId: string } | null {\n const m = RUN_STREAM_PATH.exec(urlPath)\n return m ? { name: decodeURIComponent(m[1]), runId: decodeURIComponent(m[2]) } : null\n}\n\n/** Parse `Last-Event-ID` (a frame `seq`) to a number; absent/invalid ⇒ -1 (replay from the start). */\nfunction parseLastEventId(raw: string | null): number {\n if (raw === null) return -1\n const n = Number.parseInt(raw, 10)\n return Number.isInteger(n) && n >= 0 ? n : -1\n}\n\nexport function handleAgentRunReconnect(\n runId: string,\n request: Request,\n cache: RunEventCache,\n): Response {\n // Unknown run ⇒ 404 (a run never started here, or already evicted).\n if (!cache.has(runId)) {\n return new Response(\n JSON.stringify({ error: { code: 'RUN_NOT_FOUND', message: `Unknown run '${runId}'.` } }),\n {\n status: 404,\n headers: { 'content-type': 'application/json' },\n },\n )\n }\n\n const afterSeq = parseLastEventId(request.headers.get('last-event-id'))\n\n const stream = new ReadableStream<Uint8Array>({\n start(controller) {\n let closed = false\n const safeEnqueue = (text: string): void => {\n if (closed) return\n try {\n controller.enqueue(encodeSse(text))\n } catch {\n /* controller already closed by an abort race — ignore */\n }\n }\n const close = (): void => {\n if (closed) return\n safeEnqueue(SSE_DONE_FRAME)\n closed = true\n try {\n controller.close()\n } catch {\n /* already closed */\n }\n }\n\n // Atomic: snapshot replay frames AND subscribe to the live tail in one tick.\n const res = cache.attach(\n runId,\n afterSeq,\n (frame) => {\n safeEnqueue(formatSseFrame(frame.seq, frame.data))\n },\n () => {\n close()\n },\n )\n // Evicted between has() and attach() (rare TOCTOU) ⇒ just end the stream.\n if (!res.known) {\n close()\n return\n }\n for (const frame of res.replay) {\n safeEnqueue(formatSseFrame(frame.seq, frame.data))\n }\n if (res.ended) {\n close()\n return\n }\n // Client disconnects ⇒ detach the live listener + close.\n request.signal.addEventListener('abort', () => {\n res.unsubscribe()\n close()\n })\n },\n })\n\n return new Response(stream, { headers: { ...SSE_BASE_HEADERS, [RUN_ID_HEADER]: runId } })\n}\n","/**\n * M39 (ADR-0048) — the thread follow-up dispatcher.\n *\n * Drives a run over the M37 durable cache HEADLESS — it iterates the SDK chunk\n * generator and `cache.append`s directly, NOT via a `Response` `ReadableStream`\n * (whose backpressure would stall a run with no HTTP reader). Subscribers read\n * from the cache via the thread / reconnect stream.\n *\n * - Post to an IDLE thread ⇒ start a run + pump.\n * - Post to an ACTIVE thread ⇒ FIFO-queue the follow-up.\n * - On terminal ⇒ `registry.endRun` hands back the next queued follow-up, which\n * is dispatched as a continuation on the SAME sessionId (⇒ the SDK continues\n * the conversation via its `ConversationStorageAdapter`).\n *\n * This adds NO agent loop — it reuses the SDK run (`startRun`) + the M37 cache.\n * Single-process (ADR-0048 D2).\n */\n\nimport type { WireChunk as UIMessageChunk } from '@theokit/presenter/wire'\n\nimport { type RunEventCache, mintRunId } from './run-event-cache.js'\nimport type { ThreadRunRegistry } from './thread-run-registry.js'\n\ninterface ThreadDispatchDeps {\n readonly registry: ThreadRunRegistry\n readonly cache: RunEventCache\n /** Start a run for a follow-up on `sessionId`; returns the SDK chunk stream. */\n readonly startRun: (sessionId: string, message: string) => AsyncIterable<UIMessageChunk>\n}\n\n/** Result of posting a follow-up: the started `runId` (idle thread) or `queued` (active thread). */\ntype PostFollowUpResult = { runId: string } | { queued: true }\n\n/**\n * Post a follow-up on a thread. IDLE ⇒ start a run (returns its `runId`); ACTIVE\n * ⇒ FIFO-queue it (returns `{ queued: true }`) — dispatched when the active run ends.\n */\nexport function postThreadFollowUp(\n deps: ThreadDispatchDeps,\n sessionId: string,\n message: string,\n): PostFollowUpResult {\n if (deps.registry.getActive(sessionId) !== null) {\n deps.registry.queue(sessionId, { message })\n return { queued: true }\n }\n return { runId: startAndPump(deps, sessionId, message) }\n}\n\n/** Mint a runId, mark the thread active, and pump the run into the cache headless. */\nfunction startAndPump(deps: ThreadDispatchDeps, sessionId: string, message: string): string {\n const runId = mintRunId()\n // Register the run in the cache SYNCHRONOUSLY (before the async pump appends its\n // first frame) so a subscriber resolving the active runId can attach immediately.\n deps.cache.begin(runId)\n deps.registry.startRun(sessionId, runId)\n pumpIntoCache(deps, sessionId, runId, deps.startRun(sessionId, message))\n return runId\n}\n\n/**\n * Drive `chunks` into the cache under `runId`, then end the run and dispatch the\n * next queued follow-up (if any) as a continuation. Fire-and-forget — the caller\n * does not await the run; subscribers observe it via the cache.\n */\nfunction pumpIntoCache(\n deps: ThreadDispatchDeps,\n sessionId: string,\n runId: string,\n chunks: AsyncIterable<UIMessageChunk>,\n): void {\n void (async () => {\n try {\n for await (const chunk of chunks) {\n deps.cache.append(runId, JSON.stringify(chunk))\n }\n } catch {\n // The SDK translator owns error semantics (surfaces failures as chunks);\n // the transport guarantees only a terminated, cache-ended run.\n } finally {\n deps.cache.end(runId)\n const next = deps.registry.endRun(sessionId, runId)\n if (next !== undefined) startAndPump(deps, sessionId, next.message)\n }\n })()\n}\n","/**\n * M39 (ADR-0048) — the in-process thread→run registry.\n *\n * A thread is the existing `sessionId` (the SDK conversation key). This registry\n * tracks, per thread, the single ACTIVE run, a FIFO queue of follow-ups to\n * dispatch as continuations, and one-shot \"next run\" waiters (so a client can\n * subscribe to a thread before posting a message and attach when the run starts).\n *\n * Pure state only — it never starts a run or touches the transport. The route\n * layer owns dispatch: on `endRun` it receives the next queued follow-up (if any)\n * and starts the continuation over the M37 durable transport.\n *\n * Single-process contract (ADR-0048 D2): a multi-instance deploy needs a shared\n * registry + leasing — that is infra (TheoCloud), explicitly out of M39. The\n * interface is injectable so a durable impl slots in later without touching the\n * routes. We do NOT build a distributed store now (YAGNI).\n */\n\n/** A follow-up message queued on an active thread, dispatched as a continuation. */\nexport interface FollowUp {\n readonly message: string\n}\n\nexport interface ThreadRunRegistry {\n /** The active runId for a thread, or `null` when the thread is idle. */\n getActive(sessionId: string): string | null\n /** Mark a run started for a thread (sets it active; fires + clears one-shot waiters). */\n startRun(sessionId: string, runId: string): void\n /**\n * Mark `runId` ended for a thread. A no-op unless `runId` is the current active\n * run (a stale terminal never clears a newer run). Clears the active run and\n * returns the next FIFO follow-up to dispatch as a continuation, or `undefined`.\n */\n endRun(sessionId: string, runId: string): FollowUp | undefined\n /** FIFO-enqueue a follow-up on a thread (dispatched when the active run ends). */\n queue(sessionId: string, followUp: FollowUp): void\n /**\n * Register a ONE-SHOT waiter fired with the runId of the NEXT run started on\n * this thread. Returns an unsubscribe fn. Used by subscribe-by-thread on an\n * idle thread (attach when the next run starts).\n */\n onNextRun(sessionId: string, cb: (runId: string) => void): () => void\n}\n\ninterface ThreadState {\n activeRunId: string | null\n readonly queue: FollowUp[]\n readonly waiters: Set<(runId: string) => void>\n}\n\nexport function createInProcessThreadRunRegistry(): ThreadRunRegistry {\n const threads = new Map<string, ThreadState>()\n const ensure = (sessionId: string): ThreadState => {\n let s = threads.get(sessionId)\n if (s === undefined) {\n s = { activeRunId: null, queue: [], waiters: new Set() }\n threads.set(sessionId, s)\n }\n return s\n }\n\n return {\n getActive(sessionId) {\n return threads.get(sessionId)?.activeRunId ?? null\n },\n startRun(sessionId, runId) {\n const s = ensure(sessionId)\n s.activeRunId = runId\n // Fire one-shot waiters, then clear them (single-threaded → no re-entrancy race).\n const waiters = [...s.waiters]\n s.waiters.clear()\n for (const cb of waiters) cb(runId)\n },\n endRun(sessionId, runId) {\n const s = threads.get(sessionId)\n if (s?.activeRunId !== runId) return undefined\n s.activeRunId = null\n return s.queue.shift()\n },\n queue(sessionId, followUp) {\n ensure(sessionId).queue.push(followUp)\n },\n onNextRun(sessionId, cb) {\n const s = ensure(sessionId)\n s.waiters.add(cb)\n return () => {\n s.waiters.delete(cb)\n }\n },\n }\n}\n\nlet serverRegistry: ThreadRunRegistry | undefined\n\n/** Process-wide singleton (mirrors `getRunEventCache` / `getApprovalRegistry`). */\nexport function getThreadRunRegistry(): ThreadRunRegistry {\n serverRegistry ??= createInProcessThreadRunRegistry()\n return serverRegistry\n}\n","/**\n * M39 (ADR-0048) — the thread signal routes over the M37 durable transport:\n *\n * - `POST /api/agents/<name>/threads/<sessionId>/message` — a follow-up. ACTIVE\n * run ⇒ FIFO-queue (dispatched as a continuation when it ends); IDLE ⇒ start a\n * run. Returns `202` (the run streams headless into the cache; observe it via\n * the thread stream). Spends LLM tokens ⇒ CSRF-gated (parity with mount-agent).\n * - `GET /api/agents/<name>/threads/<sessionId>/stream` — subscribe. ACTIVE ⇒\n * attach to the durable stream (reuse the M37 reconnect handler); IDLE ⇒ wait\n * (bounded) for the next run on the thread, then attach (subscribe-then-post).\n *\n * These DRIVE the SDK run (via `makeThreadStartRun`) + the M37 cache — no new loop.\n */\n\nimport { validateCsrfRequest, type CsrfMode } from '../security/csrf.js'\n\nimport { makeThreadStartRun } from './build-agent-streamer.js'\nimport {\n encodeSse,\n formatSseFrame,\n RUN_ID_HEADER,\n SSE_BASE_HEADERS,\n SSE_DONE_FRAME,\n} from './durable-ui-message-stream-response.js'\nimport { handleAgentRunReconnect } from './handle-agent-run-reconnect.js'\nimport { parseAgentRequestBody } from './mount-agent.js'\nimport { getRunEventCache, type RunEventCache } from './run-event-cache.js'\nimport { postThreadFollowUp } from './thread-dispatcher.js'\nimport { getThreadRunRegistry, type ThreadRunRegistry } from './thread-run-registry.js'\n\nconst THREAD_MESSAGE_PATH = /^\\/api\\/agents\\/([^/]+)\\/threads\\/([^/]+)\\/message$/\nconst THREAD_STREAM_PATH = /^\\/api\\/agents\\/([^/]+)\\/threads\\/([^/]+)\\/stream$/\n\n/** How long a subscribe-to-idle-thread waits for the next run before closing. */\nconst DEFAULT_IDLE_WAIT_MS = 30_000\n\nfunction matchThread(re: RegExp, urlPath: string): { name: string; sessionId: string } | null {\n const m = re.exec(urlPath)\n return m ? { name: decodeURIComponent(m[1]), sessionId: decodeURIComponent(m[2]) } : null\n}\n\nexport const isThreadMessagePath = (urlPath: string) => matchThread(THREAD_MESSAGE_PATH, urlPath)\nexport const isThreadStreamPath = (urlPath: string) => matchThread(THREAD_STREAM_PATH, urlPath)\n\nfunction jsonError(status: number, code: string, message: string): Response {\n return new Response(JSON.stringify({ error: { code, message } }), {\n status,\n headers: { 'content-type': 'application/json; charset=utf-8' },\n })\n}\n\n/** Inputs for {@link handleThreadMessage} (bundled to stay within the arity budget). */\ninterface ThreadMessageArgs {\n readonly mod: unknown\n readonly apiKey: string\n readonly sessionId: string\n readonly request: Request\n readonly source: string\n readonly csrfMode?: CsrfMode\n}\n\n/** POST a follow-up on a thread. Returns `202` with `{ runId }` (started) or `{ queued: true }`. */\nexport async function handleThreadMessage(args: ThreadMessageArgs): Promise<Response> {\n const { mod, apiKey, sessionId, request, source, csrfMode = 'strict' } = args\n // A follow-up drives the agent (spends LLM tokens) — reject a cross-origin POST.\n if (csrfMode === 'strict') {\n const csrf = validateCsrfRequest(request)\n if (!csrf.valid) return jsonError(403, 'CSRF_FAILED', `CSRF check failed: ${csrf.reason}`)\n }\n let body: unknown = null\n try {\n body = await request.json()\n } catch {\n /* invalid/empty JSON → 400 below */\n }\n const input = parseAgentRequestBody(body)\n if (input === null) {\n return jsonError(400, 'BAD_REQUEST', 'Request must contain a non-empty message.')\n }\n const result = postThreadFollowUp(\n {\n registry: getThreadRunRegistry(),\n cache: getRunEventCache(),\n startRun: makeThreadStartRun(mod, apiKey, source),\n },\n sessionId,\n input.message,\n )\n const headers: Record<string, string> = { 'content-type': 'application/json; charset=utf-8' }\n if ('runId' in result) headers[RUN_ID_HEADER] = result.runId\n return new Response(JSON.stringify(result), { status: 202, headers })\n}\n\n/** GET the thread's durable stream. Active ⇒ attach now; idle ⇒ wait (bounded) for the next run. */\nexport function handleThreadStream(\n sessionId: string,\n request: Request,\n registry: ThreadRunRegistry = getThreadRunRegistry(),\n cache: RunEventCache = getRunEventCache(),\n idleWaitMs = DEFAULT_IDLE_WAIT_MS,\n): Response {\n const active = registry.getActive(sessionId)\n if (active !== null && cache.has(active)) {\n // Reuse the M37 reconnect handler — replay + live tail on the active run.\n return handleAgentRunReconnect(active, request, cache)\n }\n return waitThenAttachStream(sessionId, request, registry, cache, idleWaitMs)\n}\n\n/** Subscribe to an idle thread: wait (bounded) for the NEXT run to start, then attach + tail. */\nfunction waitThenAttachStream(\n sessionId: string,\n request: Request,\n registry: ThreadRunRegistry,\n cache: RunEventCache,\n idleWaitMs: number,\n): Response {\n const stream = new ReadableStream<Uint8Array>({\n start(controller) {\n let closed = false\n const send = (text: string): void => {\n if (closed) return\n try {\n controller.enqueue(encodeSse(text))\n } catch {\n /* closed by an abort race */\n }\n }\n let detachAttach: (() => void) | undefined\n const close = (): void => {\n if (closed) return\n send(SSE_DONE_FRAME)\n closed = true\n try {\n controller.close()\n } catch {\n /* already closed */\n }\n }\n const offNext = registry.onNextRun(sessionId, (runId) => {\n const res = cache.attach(\n runId,\n -1,\n (frame) => {\n send(formatSseFrame(frame.seq, frame.data))\n },\n () => {\n close()\n },\n )\n if (!res.known) {\n close()\n return\n }\n for (const frame of res.replay) send(formatSseFrame(frame.seq, frame.data))\n if (res.ended) {\n close()\n return\n }\n detachAttach = res.unsubscribe\n })\n // HIGH-1 — the waiter teardown MUST run on BOTH the idle-wait timeout AND the\n // client abort, else the (one-shot) `onNextRun` waiter leaks in the registry\n // when a timed-out subscriber's session never receives another run.\n const teardownWaiter = (): void => {\n offNext()\n detachAttach?.()\n }\n const timer = setTimeout(() => {\n teardownWaiter()\n close()\n }, idleWaitMs)\n timer.unref()\n request.signal.addEventListener('abort', () => {\n teardownWaiter()\n clearTimeout(timer)\n close()\n })\n },\n })\n return new Response(stream, { headers: { ...SSE_BASE_HEADERS } })\n}\n","/**\n * M15/M16 follow-up — shared dispatcher for the agent AUXILIARY routes that BOTH dev (vite\n * middleware) and prod (`theokit start` handler) must serve identically. Before this, these routes\n * were wired only into the dev middleware, so a built/deployed app served none of them (agent cards,\n * MCP, pending-approvals listing all 404'd in production).\n *\n * Single source of truth (DRY): one Web-Request→Response dispatcher, two callers. It handles the\n * routes that derive purely from the agent module + shared registry:\n * - **M15** `GET /.well-known/<name>/agent-card.json` → {@link handleAgentCard}\n * - **M14** `GET /api/agents/<name>/approvals` → {@link handleListApprovals}\n * - **M16** `POST /api/agents/<name>/mcp` → {@link handleMcpJsonRpc}\n *\n * Channels (M27) are NOT here: a channel webhook needs app-supplied `validators` + `onMessage`, so\n * the app wires `handleChannelWebhook` in its own route (it cannot be auto-derived from the module).\n * The HITL approve route stays in each caller (it carries caller-specific rate-limiting/CSRF plumbing).\n */\nimport type { AgentNode } from '../scan/agent-scan.js'\nimport { validateCsrfRequest, type CsrfMode } from '../security/csrf.js'\n\nimport { isAgentCardPath, handleAgentCard } from './agent-card-handler.js'\nimport { getApprovalRegistry } from './approval-registry.js'\nimport { handleAgentRunReconnect, isAgentRunStreamPath } from './handle-agent-run-reconnect.js'\nimport {\n handleThreadMessage,\n handleThreadStream,\n isThreadMessagePath,\n isThreadStreamPath,\n} from './handle-thread-routes.js'\nimport { isListApprovalsPath, handleListApprovals } from './list-approvals-handler.js'\nimport { extractAppResources } from './mcp-app-resources.js'\nimport { isMcpPath, handleMcpJsonRpc } from './mcp-handler.js'\nimport { getRunEventCache } from './run-event-cache.js'\n\n/** JSON error envelope (mirrors mount-agent.ts:37 — the parity source for the MCP CSRF gate). */\nfunction jsonError(status: number, code: string, message: string): Response {\n return new Response(JSON.stringify({ error: { code, message } }), {\n status,\n headers: { 'content-type': 'application/json; charset=utf-8' },\n })\n}\n\n/** Dependencies the aux dispatcher needs from its caller (dev or prod). */\ninterface AuxRouteDeps {\n /** Discovered agents (from `scanAgents`). */\n agents: readonly AgentNode[]\n /** Load an agent module from its file path (dev: vite loader; prod: dynamic import). */\n loadModule: (filePath: string) => Promise<unknown>\n /** Absolute base URL (`http(s)://host`) for the agent-card endpoint URLs. */\n baseUrl: string\n /**\n * M34 (#97) — CSRF enforcement mode for the MCP route. `POST /api/agents/<name>/mcp` drives the\n * agent (spends LLM tokens), so a cross-origin POST MUST be rejected in `'strict'` — parity with\n * the agent-run route (`mount-agent.ts:83-91`). Defaults to `'strict'` (safe-by-default); a caller\n * that already gated upstream may pass `'off'`.\n */\n csrfMode?: CsrfMode\n /**\n * M39 — lazily resolve the provider apiKey. Required only for the thread\n * follow-up route (which drives the agent); resolved on demand so non-agent\n * aux routes (card, approvals, stream) never need a provider key.\n */\n resolveApiKey?: () => string\n}\n\n/**\n * Serve an agent auxiliary route. Returns a `Response` when `urlPath` matches an aux route (card /\n * list-approvals / mcp) and the method + agent resolve; returns `null` to fall through (not an aux\n * route, wrong method, or unknown agent — the caller then owns the 404/next).\n */\nexport async function serveAgentAuxRoute(\n request: Request,\n urlPath: string,\n deps: AuxRouteDeps,\n): Promise<Response | null> {\n const method = request.method.toUpperCase()\n\n // M15 — A2A agent card at `/.well-known/<name>/agent-card.json` (GET).\n const cardName = isAgentCardPath(urlPath)\n if (cardName !== null) {\n if (method !== 'GET') return null\n const agent = deps.agents.find((a) => a.name === cardName)\n if (!agent) return null\n const mod = await deps.loadModule(agent.filePath)\n return handleAgentCard(mod, agent.name, agent.agentPath, deps.baseUrl)\n }\n\n // M14 — GET /api/agents/<name>/approvals (pending HITL approvals).\n if (isListApprovalsPath(urlPath)) {\n if (method !== 'GET') return null\n return handleListApprovals(getApprovalRegistry())\n }\n\n // M37 — GET /api/agents/<name>/runs/<runId>/stream (durable reconnect / observe).\n // INTENTIONALLY open (no CSRF, no auth gate): a GET is not CSRF-vulnerable, the\n // run-start POST is already gated, and the `runId` is a 122-bit UUID (unguessable).\n // Observe-by-runId is a FEATURE (ADR-0046 D5) — a second client resumes a run a\n // first started. Do NOT add a custom-header CSRF check here: browsers send NO\n // custom headers with `EventSource`, so it would break native SSE reconnect.\n const runStream = isAgentRunStreamPath(urlPath)\n if (runStream !== null) {\n if (method !== 'GET') return null\n if (!deps.agents.some((a) => a.name === runStream.name)) return null\n return handleAgentRunReconnect(runStream.runId, request, getRunEventCache())\n }\n\n // M39 — thread signal routes (follow-up message + subscribe-by-thread). Extracted\n // to keep this dispatcher within the cognitive-complexity budget (G6).\n const threadResponse = await serveThreadRoute(request, method, urlPath, deps)\n if (threadResponse !== null) return threadResponse\n\n // M16 — POST /api/agents/<name>/mcp (JSON-RPC MCP server). Extracted to keep this dispatcher\n // within the cognitive-complexity budget (G6).\n const mcpName = isMcpPath(urlPath)\n if (mcpName !== null) {\n return serveMcpRoute(request, method, mcpName, deps)\n }\n\n return null\n}\n\n/**\n * M39 — serve the thread routes:\n * - `POST .../threads/<sessionId>/message` (follow-up) — loads the module, drives\n * the run headless via the thread dispatcher. Needs `resolveApiKey` (drives the\n * agent) → 501 when absent (rather than a silent 404).\n * - `GET .../threads/<sessionId>/stream` (subscribe) — attach to the active/next\n * run's durable stream. INTENTIONALLY open (GET, no custom headers — like the\n * M37 reconnect route).\n *\n * SECURITY (thread stream): unlike the M37 reconnect route — keyed on an\n * `mintRunId()` UUID (122-bit unguessable) — the thread stream is keyed on the\n * caller-supplied `sessionId`. The open GET is safe ONLY if the `sessionId` is\n * unguessable (e.g. a client-minted UUID). An app that uses a PREDICTABLE\n * sessionId (user id, email, sequential id) MUST add its own auth gate before\n * this endpoint, or any party who can guess the sessionId can read the thread's\n * live conversation stream.\n *\n * Returns `null` to fall through (not a thread route, wrong method, unknown agent).\n */\nasync function serveThreadRoute(\n request: Request,\n method: string,\n urlPath: string,\n deps: AuxRouteDeps,\n): Promise<Response | null> {\n const stream = isThreadStreamPath(urlPath)\n if (stream !== null) {\n if (method !== 'GET') return null\n if (!deps.agents.some((a) => a.name === stream.name)) return null\n return handleThreadStream(stream.sessionId, request)\n }\n\n const msg = isThreadMessagePath(urlPath)\n if (msg !== null) {\n if (method !== 'POST') return null\n const agent = deps.agents.find((a) => a.name === msg.name)\n if (!agent) return null\n if (deps.resolveApiKey === undefined) {\n // MEDIUM-1 — the path matched but the caller wired no provider-key resolver.\n // Fail loudly (501) instead of a silent 404 that reads as \"route not found\".\n return jsonError(\n 501,\n 'NOT_CONFIGURED',\n 'Thread follow-up requires a provider API key (resolveApiKey was not provided to serveAgentAuxRoute).',\n )\n }\n const mod = await deps.loadModule(agent.filePath)\n return handleThreadMessage({\n mod,\n apiKey: deps.resolveApiKey(),\n sessionId: msg.sessionId,\n request,\n source: `agent \"${msg.name}\"`,\n csrfMode: deps.csrfMode ?? 'strict',\n })\n }\n return null\n}\n\n/**\n * Serve the MCP route with the M34 gates: default-DENY opt-in → CSRF → dispatch. Returns `null` to\n * fall through (wrong method / unknown or non-opted-in agent), a 403 on CSRF failure, else the\n * JSON-RPC response.\n */\nasync function serveMcpRoute(\n request: Request,\n method: string,\n mcpName: string,\n deps: AuxRouteDeps,\n): Promise<Response | null> {\n if (method !== 'POST') return null\n const agent = deps.agents.find((a) => a.name === mcpName)\n if (!agent) return null\n\n const mod = await deps.loadModule(agent.filePath)\n\n // M34 — DEFAULT-DENY: an agent is NOT exposed on MCP unless it explicitly opts in with a named\n // `export const mcp = true` (blueprint D5 — default-EXPOSE is the footgun magnified by the\n // multi-surface thesis). Absent the opt-in, fall through to 404 (the agent is web-only). This is a\n // breaking change from the M16 auto-mount (documented in the CHANGELOG § Security).\n if (!isMcpExposed(mod)) return null\n\n // M34 (#97) — enforce CSRF BEFORE any work. The MCP route drives the agent (real LLM tokens), so a\n // cross-origin POST must be rejected — parity with the agent-run route (`mount-agent.ts:83-91`).\n const csrfMode = deps.csrfMode ?? 'strict'\n if (csrfMode === 'strict') {\n const csrf = validateCsrfRequest(request)\n if (!csrf.valid) return jsonError(403, 'CSRF_FAILED', `CSRF check failed: ${csrf.reason}`)\n }\n\n let body: unknown = null\n try {\n body = await request.json()\n } catch {\n /* malformed/empty JSON → handleMcpJsonRpc returns a -32600 envelope */\n }\n // M30 — pass the agent's declared `ui://` App resources (named `appResources` export) so the MCP\n // server advertises + serves them via resources/list + resources/read.\n return handleMcpJsonRpc(mod, agent.name, body, extractAppResources(mod))\n}\n\n/**\n * M34 — DEFAULT-DENY opt-in check: is this agent module exposed on the MCP surface? An agent opts in\n * with a named `export const mcp = true` (mirroring the `appResources` named-export convention).\n * Anything else (absent / falsy) → NOT exposed. Read at the emit layer (blueprint D5).\n */\nfunction isMcpExposed(mod: unknown): boolean {\n return (mod as { mcp?: unknown } | null | undefined)?.mcp === true\n}\n","/**\n * T5a.2 Phase G slice 5/N — Node adapter shim for the Web request handler.\n *\n * Bridges Node's `IncomingMessage` + `ServerResponse` shape to the\n * Web-Standards `executeWebRequest` (Phase A → G slices 1-4). Per\n * ADR-0028 R3a, the Node adapter is the ONLY place IncomingMessage ↔\n * Request conversion happens — every other layer of `server/` flows\n * through Web `Request`/`Response`.\n *\n * **Two conversions:**\n *\n * 1. `incomingMessageToWebRequest(req)` — Node → Web. Reads\n * `req.method`, `req.url`, `req.headers`, and (for POST/PUT/etc.)\n * drains the Node Readable body into a Web `ReadableStream`. The\n * request URL is resolved to absolute form using `req.headers.host`\n * (Web Request guarantees absolute URL).\n *\n * 2. `writeWebResponseToServerResponse(response, res)` — Web → Node.\n * Sets status code + status text, copies headers (including all\n * `Set-Cookie` values via `getSetCookie()`), then drains the Web\n * `ReadableStream` body into the Node ServerResponse.\n *\n * Plus the convenience composer `executeWebRequestFromNode(req, res,\n * routeModule, opts?)` that wires both ends — exactly what api-middleware\n * (and the prod CLI start path) need to migrate from the legacy\n * `executeRoute` to `executeWebRequest` without touching call sites.\n *\n * v1.0 § Phase G slice 5/N (closes the executor bridge surface).\n */\nimport type { IncomingMessage, ServerResponse } from 'node:http'\n\nimport { executeWebRequest, type ExecuteWebRequestOptions } from '../web-handler.js'\n\nimport { incomingMessageToWebRequest } from './node-request.js'\n\n// The primitive `IncomingMessage` → Web `Request` converters live in\n// `node-request.js` (dependency-free, shared with the executor). Re-exported\n// here so existing importers of the adapter keep resolving them.\nexport { incomingMessageToWebRequest } from './node-request.js'\n\n/**\n * Write a Web `Response` into a Node `ServerResponse`. Mirrors the Node\n * `res.writeHead` + `res.end` pattern.\n *\n * Set-Cookie is the only multi-value header the Web spec exposes via\n * `getSetCookie()`. We append each entry individually so Node emits\n * separate `Set-Cookie:` lines per the HTTP spec.\n *\n * If the Response body is a `ReadableStream`, it's piped chunk-by-chunk\n * to `res`. Empty body (null) → just close.\n */\nexport async function writeWebResponseToServerResponse(\n response: Response,\n res: ServerResponse,\n): Promise<void> {\n // Status + headers FIRST (writeHead locks them).\n // EC-3: Set-Cookie needs special handling (writeHead's plain object\n // shape conflicts with multi-value headers; we set them via setHeader\n // BEFORE writeHead so the array form is preserved).\n const setCookies = response.headers.getSetCookie()\n if (setCookies.length > 0) {\n res.setHeader('Set-Cookie', setCookies)\n }\n const otherHeaders: Record<string, string> = {}\n for (const [key, value] of response.headers.entries()) {\n if (key.toLowerCase() === 'set-cookie') continue\n otherHeaders[key] = value\n }\n res.writeHead(response.status, response.statusText, otherHeaders)\n\n // Body — drain ReadableStream OR just end() for null body.\n if (response.body === null) {\n res.end()\n return\n }\n const reader = response.body.getReader()\n try {\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n // Node's res.write accepts Uint8Array natively (no conversion needed).\n res.write(value)\n }\n res.end()\n } finally {\n reader.releaseLock()\n }\n}\n\n/**\n * Convenience composer — full request lifecycle Node → Web → Node.\n *\n * Use case: existing api-middleware (and the prod CLI start path)\n * receive Node `(req, res)` from `http.createServer`. To migrate to the\n * Web-Standards executor without rewriting every call site, wrap with\n * this composer:\n *\n * import * as users from './app/users/route.js'\n * await executeWebRequestFromNode(req, res, users, { csrfMode: 'strict' })\n *\n * The Web request is built, dispatched through executeWebRequest, and\n * the Response is drained back into `res`. Caller does NOT need to call\n * `res.end()` afterwards — this composer handles it.\n */\nexport async function executeWebRequestFromNode(\n req: IncomingMessage,\n res: ServerResponse,\n routeModule: Parameters<typeof executeWebRequest>[1],\n opts?: ExecuteWebRequestOptions,\n): Promise<void> {\n const webRequest = incomingMessageToWebRequest(req)\n const webResponse = await executeWebRequest(webRequest, routeModule, opts)\n await writeWebResponseToServerResponse(webResponse, res)\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,OAAO,eAAe;AAef,IAAM,uBAAwC;AAAA,EACnD,MAAM;AAAA,EACN,WAAW,CAAC,MAAM,KAAK,UAAU,UAAU,UAAU,CAAC,CAAC;AAAA,EACvD,aAAa,CAAC,QAAQ;AACpB,UAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,WAAO,UAAU,YAAY,MAAM;AAAA,EACrC;AACF;AAEO,IAAM,kBAAmC;AAAA,EAC9C,MAAM;AAAA,EACN,WAAW,CAAC,MAAM,KAAK,UAAU,CAAC;AAAA,EAClC,aAAa,CAAC,QAAQ,KAAK,MAAM,GAAG;AACtC;AAEA,IAAM,YAA6C;AAAA,EACjD,WAAW;AAAA,EACX,MAAM;AACR;AAEO,SAAS,mBACd,UACiB;AACjB,MAAI,OAAO,aAAa,UAAU;AAMhC,UAAM,QAAQ,UAAU,QAAQ;AAIhC,QAAK,UAA0C,QAAW;AACxD,YAAM,IAAI;AAAA,QACR,wBAAwB,QAAQ,wBAAwB,OAAO,KAAK,SAAS,EAAE,KAAK,IAAI,CAAC;AAAA,MAC3F;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACA,MACE,OAAO,aAAa,YACpB,OAAO,SAAS,cAAc,cAC9B,OAAO,SAAS,gBAAgB,YAChC;AACA,UAAM,IAAI;AAAA,MACR,0EAA0E,KAAK,UAAU,QAAQ,CAAC;AAAA,IACpG;AAAA,EACF;AACA,SAAO;AACT;;;AC9BA,IAAM,gBAAgB;AAEtB,IAAM,YAAY;AAGlB,SAAS,iBAAiB,MAAc,UAA2C;AACjF,SAAO,KAAK,QAAQ,WAAW,QAAQ,EAAE,QAAQ,eAAe,QAAQ;AAC1E;AAYO,SAAS,YAAY,KAAiC;AAC3D,MAAI,aAAa,KAAK,GAAG,EAAG,QAAO;AAEnC,QAAM,OAAO,2BAA2B,KAAK,GAAG,IAAI,CAAC;AACrD,QAAM,WAAW,+BAA+B,KAAK,GAAG,IAAI,CAAC;AAC7D,QAAM,MAAM,0BAA0B,KAAK,GAAG,IAAI,CAAC;AAEnD,MAAI,YAAY,KAAK,GAAG,GAAG;AACzB,QAAI,aAAa,OAAW,QAAO,YAAY,SAAS,YAAY,CAAC;AACrE,QAAI,SAAS,OAAW,QAAO,QAAQ,KAAK,YAAY,CAAC;AACzD,WAAO;AAAA,EACT;AAEA,MAAI,YAAY,KAAK,GAAG,KAAK,QAAQ,QAAW;AAC9C,UAAM,OAAO,IAAI,YAAY;AAG7B,WAAO,SAAS,eAAe,SAAS,aAAa,QAAQ,IAAI,KAAK;AAAA,EACxE;AAEA,SAAO;AACT;AAUO,SAAS,gBAAgB,SAA8B;AAC5D,QAAM,WAAqB,CAAC;AAC5B,QAAM,OAAO,iBAAiB,SAAS,CAAC,QAAQ;AAC9C,aAAS,KAAK,GAAG;AACjB,WAAO;AAAA,EACT,CAAC;AACD,SAAO,EAAE,MAAM,SAAS;AAC1B;AAQO,SAAS,eAAe,UAAkB,UAA4B;AAC3E,MAAI,SAAS,WAAW,EAAG,QAAO;AAElC,QAAM,cAAc,SAAS,YAAY,EAAE,YAAY,SAAS;AAChE,MAAI,gBAAgB,GAAI,QAAO;AAE/B,QAAM,iBAAiB,IAAI;AAAA,IACzB,SAAS,IAAI,CAAC,QAAQ,YAAY,GAAG,CAAC,EAAE,OAAO,CAAC,QAAuB,QAAQ,MAAS;AAAA,EAC1F;AAEA,MAAI,OAAO,SAAS,MAAM,GAAG,WAAW;AACxC,MAAI,eAAe,OAAO,GAAG;AAC3B,WAAO,iBAAiB,MAAM,CAAC,QAAQ;AACrC,YAAM,MAAM,YAAY,GAAG;AAC3B,aAAO,QAAQ,UAAa,eAAe,IAAI,GAAG,IAAI,KAAK;AAAA,IAC7D,CAAC;AAAA,EACH;AAEA,SAAO,GAAG,IAAI,OAAO,SAAS,KAAK,QAAQ,CAAC;AAAA,IAAO,SAAS,MAAM,WAAW,CAAC;AAChF;AAKO,SAAS,cACd,UACA,SACoC;AACpC,QAAM,EAAE,MAAM,SAAS,IAAI,gBAAgB,OAAO;AAClD,QAAM,UAAU,eAAe,UAAU,QAAQ;AAUjD,MAAI,YAAY,SAAU,QAAO,EAAE,UAAU,MAAM,QAAQ;AAE3D,SAAO,EAAE,UAAU,SAAS,KAAK;AACnC;;;AC9HA,SAAS,oBAAoB;AAC7B,SAAS,eAAe;AA8CjB,SAAS,0BAA0B,MAAc,OAAuB;AAC7E,SAAO,KAAK;AAAA,IACV;AAAA,IACA,kBAAkB,KAAK;AAAA,EACzB;AACF;AAEA,SAAS,kBAAkB,OAA0C;AACnE,MAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;AACxD,MAAI,EAAE,UAAU,OAAQ,QAAO;AAC/B,SAAO,OAAQ,MAAkC,SAAS;AAC5D;AAYO,SAAS,sBAAsB,QAAuB,MAAqC;AAChG,SAAO,YAAY,IAAI,CAAC,KAAK,KAAK,SAAS;AACzC,UAAM,YAAY;AAChB,YAAM,MAAM,IAAI,OAAO;AAEvB,UACE,IAAI,WAAW,OAAO,KACtB,IAAI,WAAW,IAAI,KACnB,IAAI,WAAW,gBAAgB,KAC/B,IAAI,SAAS,GAAG,GAChB;AACA,aAAK;AACL;AAAA,MACF;AAEA,UAAI;AACF,cAAM,YAAY,QAAQ,KAAK,aAAa,YAAY;AAExD,YAAI,WAAW,aAAa,WAAW,OAAO;AAU9C,cAAM,QAAQ,cAAc;AAE5B,mBAAW,MAAM,OAAO,mBAAmB,KAAK,QAAQ;AACxD,mBAAW,0BAA0B,UAAU,KAAK;AACpD;AAAA,UACE;AAAA,UACA,KAAK,mBAAmB,CAAC;AAAA,UACzB,EAAE,YAAY,QAAQ,IAAI,aAAa,aAAa;AAAA,UACpD,EAAE,MAAM;AAAA,QACV;AAEA,cAAM,MAAO,MAAM,OAAO,cAAc,KAAK,oBAAoB;AACjE,cAAM,SAAS,MAAM,IAAI,OAAO,KAAK,EAAE,MAAM,CAAC;AAE9C,YAAI,UAAU,OAAO,WAAW,YAAY,cAAc,QAAQ;AAChE,cAAI,UAAU,KAAK;AAAA,YACjB,UAAU,OAAO,SAAS,QAAQ,IAAI,UAAU,KAAK;AAAA,UACvD,CAAC;AACD,cAAI,IAAI;AACR;AAAA,QACF;AAKA,YAAI;AACJ,YAAI,kBAAkB;AACtB,YAAI,OAAO,WAAW,UAAU;AAC9B,oBAAU;AAAA,QACZ,WAAW,kBAAkB,MAAM,GAAG;AACpC,oBAAU,OAAO;AACjB,gBAAM,WAAW,KAAK,UAAU,OAAO,aAAa,EAAE,QAAQ,MAAM,SAAS;AAC7E,4BAAkB,kBAAkB,KAAK,wCAAwC,QAAQ;AAAA,QAC3F,OAAO;AACL,oBAAU;AAAA,QACZ;AAIA,cAAM,UAAU,cAAc,UAAU,OAAO;AAC/C,mBAAW,QAAQ;AACnB,kBAAU,QAAQ;AAElB,cAAM,UAAU,YAAY,QAAQ;AACpC,YAAI,CAAC,SAAS;AACZ,cAAI,UAAU,KAAK,EAAE,gBAAgB,YAAY,CAAC;AAClD,cAAI,IAAI,QAAQ;AAChB;AAAA,QACF;AAEA,cAAM,WAAW,QAAQ;AACzB,cAAM,OACJ,SAAS,MAAM,GAAG,QAAQ,IAAI,UAAU,kBAAkB,SAAS,MAAM,QAAQ;AAEnF,YAAI,UAAU,KAAK,EAAE,gBAAgB,YAAY,CAAC;AAClD,YAAI,IAAI,IAAI;AAAA,MACd,SAAS,KAAK;AACZ,eAAO,iBAAiB,GAAY;AACpC,gBAAQ,MAAM,mBAAmB,GAAG;AAEpC,aAAK;AACL;AAAA,MACF;AAAA,IACF,GAAG;AAAA,EACL,CAAC;AACH;;;AC5KA,SAAkC,gBAAgB,0BAA0B;AAE5E,IAAM,aAAa;AAGZ,SAAS,gBAAgB,SAAgC;AAC9D,QAAM,QAAQ,WAAW,KAAK,OAAO;AACrC,SAAO,QAAQ,mBAAmB,MAAM,CAAC,CAAC,IAAI;AAChD;AAGA,SAAS,gBAAgB,MAAc,OAAe,KAAkC;AACtF,QAAM,WAAW,mBAAmB,KAAK,mBAAmB,IAAI,GAAG;AACnE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,QAAQ,SAAS;AAAA,IACjB,UAAU,EAAE,QAAQ,IAAI,UAAU,GAAG;AAAA,IACrC,QAAQ,CAAC;AAAA,IACT,cAAc,CAAC;AAAA,IACf,OAAO,SAAS,MAAM,IAAI,CAAC,OAAO;AAAA,MAChC,MAAM,EAAE;AAAA,MACR,aAAa,EAAE;AAAA,MACf,UAAU;AAAA,MACV,OAAO;AAAA,MACP,OAAO;AAAA,IACT,EAAE;AAAA,IACF,WAAW,CAAC;AAAA,EACd;AACF;AAMO,SAAS,gBACd,KACA,MACA,OACA,SACU;AACV,MAAI;AACF,UAAM,OAAO,eAAe,gBAAgB,MAAM,OAAO,GAAG,GAAG,EAAE,QAAQ,CAAC;AAC1E,WAAO,IAAI,SAAS,KAAK,UAAU,IAAI,GAAG;AAAA,MACxC,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,kCAAkC;AAAA,IAC/D,CAAC;AAAA,EACH,SAAS,KAAK;AACZ,WAAO,IAAI;AAAA,MACT,KAAK,UAAU;AAAA,QACb,OAAO;AAAA,UACL,MAAM;AAAA,UACN,SAAS,eAAe,QAAQ,IAAI,UAAU;AAAA,QAChD;AAAA,MACF,CAAC;AAAA,MACD,EAAE,QAAQ,KAAK,SAAS,EAAE,gBAAgB,kCAAkC,EAAE;AAAA,IAChF;AAAA,EACF;AACF;;;ACjDA,IAAM,kBAAkB;AAMjB,SAAS,gBAAgB,SAAgC;AAC9D,QAAM,KAAK,QAAQ,QAAQ,eAAe;AAC1C,MAAI,OAAO,GAAI,QAAO;AACtB,QAAM,KAAK,QAAQ,MAAM,KAAK,gBAAgB,MAAM;AACpD,SAAO,GAAG,SAAS,KAAK,CAAC,GAAG,SAAS,GAAG,IAAI,KAAK;AACnD;AAGO,SAAS,eAAe,SAA0B;AACvD,SAAO,QAAQ,SAAS,eAAe;AACzC;AAEA,SAAS,UAAU,QAAgB,MAAc,SAA2B;AAC1E,SAAO,IAAI,SAAS,KAAK,UAAU,EAAE,OAAO,EAAE,MAAM,QAAQ,EAAE,CAAC,GAAG;AAAA,IAChE;AAAA,IACA,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,EAChD,CAAC;AACH;AAOA,IAAM,oBAAoB,KAAK;AAWxB,SAAS,kBAAkB,MAAwC;AACxE,MAAI,OAAO,SAAS,YAAY,SAAS,KAAM,QAAO;AACtD,QAAM,IAAI;AACV,MAAI,OAAO,EAAE,aAAa,UAAW,QAAO;AAC5C,QAAM,WAA6B,EAAE,UAAU,EAAE,SAAS;AAC1D,MAAI,EAAE,WAAW,QAAW;AAC1B,QAAI,OAAO,EAAE,WAAW,SAAU,QAAO;AACzC,aAAS,SAAS,EAAE;AAAA,EACtB;AACA,MAAI,EAAE,YAAY,QAAW;AAC3B,QAAI,OAAO,EAAE,YAAY,YAAY,EAAE,YAAY,QAAQ,MAAM,QAAQ,EAAE,OAAO,EAAG,QAAO;AAC5F,QAAI,KAAK,UAAU,EAAE,OAAO,EAAE,SAAS,kBAAmB,QAAO;AACjE,aAAS,UAAU,EAAE;AAAA,EACvB;AACA,SAAO;AACT;AAUA,eAAsB,oBACpB,SACA,SACA,UACA,WAAqB,UACF;AACnB,MAAI,aAAa,OAAO;AACtB,UAAM,OAAO,oBAAoB,OAAO;AACxC,QAAI,CAAC,KAAK,SAAS,aAAa,UAAU;AACxC,aAAO,UAAU,KAAK,eAAe,sBAAsB,KAAK,MAAM,EAAE;AAAA,IAC1E;AAAA,EACF;AAEA,QAAM,aAAa,gBAAgB,OAAO;AAC1C,MAAI,eAAe,MAAM;AACvB,WAAO,UAAU,KAAK,eAAe,wDAAwD;AAAA,EAC/F;AAEA,MAAI,OAAgB;AACpB,MAAI;AACF,WAAO,MAAM,QAAQ,KAAK;AAAA,EAC5B,QAAQ;AAAA,EAER;AACA,QAAM,SAAS,kBAAkB,IAAI;AACrC,MAAI,WAAW,MAAM;AACnB,WAAO,UAAU,KAAK,eAAe,iDAAiD;AAAA,EACxF;AAEA,QAAM,WAAW,SAAS,QAAQ,YAAY,MAAM;AACpD,MAAI,CAAC,UAAU;AACb,WAAO,UAAU,KAAK,eAAe,+BAA+B,UAAU,IAAI;AAAA,EACpF;AACA,SAAO,IAAI,SAAS,KAAK,UAAU,EAAE,UAAU,KAAK,CAAC,GAAG;AAAA,IACtD,QAAQ;AAAA,IACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,EAChD,CAAC;AACH;;;AC9GA,IAAM,YAAY;AAGX,SAAS,oBAAoB,SAAgC;AAClE,QAAM,QAAQ,UAAU,KAAK,OAAO;AACpC,SAAO,QAAQ,mBAAmB,MAAM,CAAC,CAAC,IAAI;AAChD;AAGO,SAAS,oBAAoB,UAAsC;AACxE,SAAO,IAAI,SAAS,KAAK,UAAU,EAAE,WAAW,SAAS,KAAK,EAAE,CAAC,GAAG;AAAA,IAClE,QAAQ;AAAA,IACR,SAAS,EAAE,gBAAgB,kCAAkC;AAAA,EAC/D,CAAC;AACH;;;ACJA,IAAM,kBAAkB;AAMjB,SAAS,qBAAqB,SAAyD;AAC5F,QAAM,IAAI,gBAAgB,KAAK,OAAO;AACtC,SAAO,IAAI,EAAE,MAAM,mBAAmB,EAAE,CAAC,CAAC,GAAG,OAAO,mBAAmB,EAAE,CAAC,CAAC,EAAE,IAAI;AACnF;AAGA,SAAS,iBAAiB,KAA4B;AACpD,MAAI,QAAQ,KAAM,QAAO;AACzB,QAAM,IAAI,OAAO,SAAS,KAAK,EAAE;AACjC,SAAO,OAAO,UAAU,CAAC,KAAK,KAAK,IAAI,IAAI;AAC7C;AAEO,SAAS,wBACd,OACA,SACA,OACU;AAEV,MAAI,CAAC,MAAM,IAAI,KAAK,GAAG;AACrB,WAAO,IAAI;AAAA,MACT,KAAK,UAAU,EAAE,OAAO,EAAE,MAAM,iBAAiB,SAAS,gBAAgB,KAAK,KAAK,EAAE,CAAC;AAAA,MACvF;AAAA,QACE,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAChD;AAAA,IACF;AAAA,EACF;AAEA,QAAM,WAAW,iBAAiB,QAAQ,QAAQ,IAAI,eAAe,CAAC;AAEtE,QAAM,SAAS,IAAI,eAA2B;AAAA,IAC5C,MAAM,YAAY;AAChB,UAAI,SAAS;AACb,YAAM,cAAc,CAAC,SAAuB;AAC1C,YAAI,OAAQ;AACZ,YAAI;AACF,qBAAW,QAAQ,UAAU,IAAI,CAAC;AAAA,QACpC,QAAQ;AAAA,QAER;AAAA,MACF;AACA,YAAM,QAAQ,MAAY;AACxB,YAAI,OAAQ;AACZ,oBAAY,cAAc;AAC1B,iBAAS;AACT,YAAI;AACF,qBAAW,MAAM;AAAA,QACnB,QAAQ;AAAA,QAER;AAAA,MACF;AAGA,YAAM,MAAM,MAAM;AAAA,QAChB;AAAA,QACA;AAAA,QACA,CAAC,UAAU;AACT,sBAAY,eAAe,MAAM,KAAK,MAAM,IAAI,CAAC;AAAA,QACnD;AAAA,QACA,MAAM;AACJ,gBAAM;AAAA,QACR;AAAA,MACF;AAEA,UAAI,CAAC,IAAI,OAAO;AACd,cAAM;AACN;AAAA,MACF;AACA,iBAAW,SAAS,IAAI,QAAQ;AAC9B,oBAAY,eAAe,MAAM,KAAK,MAAM,IAAI,CAAC;AAAA,MACnD;AACA,UAAI,IAAI,OAAO;AACb,cAAM;AACN;AAAA,MACF;AAEA,cAAQ,OAAO,iBAAiB,SAAS,MAAM;AAC7C,YAAI,YAAY;AAChB,cAAM;AAAA,MACR,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AAED,SAAO,IAAI,SAAS,QAAQ,EAAE,SAAS,EAAE,GAAG,kBAAkB,CAAC,aAAa,GAAG,MAAM,EAAE,CAAC;AAC1F;;;ACxEO,SAAS,mBACd,MACA,WACA,SACoB;AACpB,MAAI,KAAK,SAAS,UAAU,SAAS,MAAM,MAAM;AAC/C,SAAK,SAAS,MAAM,WAAW,EAAE,QAAQ,CAAC;AAC1C,WAAO,EAAE,QAAQ,KAAK;AAAA,EACxB;AACA,SAAO,EAAE,OAAO,aAAa,MAAM,WAAW,OAAO,EAAE;AACzD;AAGA,SAAS,aAAa,MAA0B,WAAmB,SAAyB;AAC1F,QAAM,QAAQ,UAAU;AAGxB,OAAK,MAAM,MAAM,KAAK;AACtB,OAAK,SAAS,SAAS,WAAW,KAAK;AACvC,gBAAc,MAAM,WAAW,OAAO,KAAK,SAAS,WAAW,OAAO,CAAC;AACvE,SAAO;AACT;AAOA,SAAS,cACP,MACA,WACA,OACA,QACM;AACN,QAAM,YAAY;AAChB,QAAI;AACF,uBAAiB,SAAS,QAAQ;AAChC,aAAK,MAAM,OAAO,OAAO,KAAK,UAAU,KAAK,CAAC;AAAA,MAChD;AAAA,IACF,QAAQ;AAAA,IAGR,UAAE;AACA,WAAK,MAAM,IAAI,KAAK;AACpB,YAAM,OAAO,KAAK,SAAS,OAAO,WAAW,KAAK;AAClD,UAAI,SAAS,OAAW,cAAa,MAAM,WAAW,KAAK,OAAO;AAAA,IACpE;AAAA,EACF,GAAG;AACL;;;ACnCO,SAAS,mCAAsD;AACpE,QAAM,UAAU,oBAAI,IAAyB;AAC7C,QAAM,SAAS,CAAC,cAAmC;AACjD,QAAI,IAAI,QAAQ,IAAI,SAAS;AAC7B,QAAI,MAAM,QAAW;AACnB,UAAI,EAAE,aAAa,MAAM,OAAO,CAAC,GAAG,SAAS,oBAAI,IAAI,EAAE;AACvD,cAAQ,IAAI,WAAW,CAAC;AAAA,IAC1B;AACA,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL,UAAU,WAAW;AACnB,aAAO,QAAQ,IAAI,SAAS,GAAG,eAAe;AAAA,IAChD;AAAA,IACA,SAAS,WAAW,OAAO;AACzB,YAAM,IAAI,OAAO,SAAS;AAC1B,QAAE,cAAc;AAEhB,YAAM,UAAU,CAAC,GAAG,EAAE,OAAO;AAC7B,QAAE,QAAQ,MAAM;AAChB,iBAAW,MAAM,QAAS,IAAG,KAAK;AAAA,IACpC;AAAA,IACA,OAAO,WAAW,OAAO;AACvB,YAAM,IAAI,QAAQ,IAAI,SAAS;AAC/B,UAAI,GAAG,gBAAgB,MAAO,QAAO;AACrC,QAAE,cAAc;AAChB,aAAO,EAAE,MAAM,MAAM;AAAA,IACvB;AAAA,IACA,MAAM,WAAW,UAAU;AACzB,aAAO,SAAS,EAAE,MAAM,KAAK,QAAQ;AAAA,IACvC;AAAA,IACA,UAAU,WAAW,IAAI;AACvB,YAAM,IAAI,OAAO,SAAS;AAC1B,QAAE,QAAQ,IAAI,EAAE;AAChB,aAAO,MAAM;AACX,UAAE,QAAQ,OAAO,EAAE;AAAA,MACrB;AAAA,IACF;AAAA,EACF;AACF;AAEA,IAAI;AAGG,SAAS,uBAA0C;AACxD,qBAAmB,iCAAiC;AACpD,SAAO;AACT;;;ACpEA,IAAM,sBAAsB;AAC5B,IAAM,qBAAqB;AAG3B,IAAM,uBAAuB;AAE7B,SAAS,YAAY,IAAY,SAA6D;AAC5F,QAAM,IAAI,GAAG,KAAK,OAAO;AACzB,SAAO,IAAI,EAAE,MAAM,mBAAmB,EAAE,CAAC,CAAC,GAAG,WAAW,mBAAmB,EAAE,CAAC,CAAC,EAAE,IAAI;AACvF;AAEO,IAAM,sBAAsB,CAAC,YAAoB,YAAY,qBAAqB,OAAO;AACzF,IAAM,qBAAqB,CAAC,YAAoB,YAAY,oBAAoB,OAAO;AAE9F,SAASA,WAAU,QAAgB,MAAc,SAA2B;AAC1E,SAAO,IAAI,SAAS,KAAK,UAAU,EAAE,OAAO,EAAE,MAAM,QAAQ,EAAE,CAAC,GAAG;AAAA,IAChE;AAAA,IACA,SAAS,EAAE,gBAAgB,kCAAkC;AAAA,EAC/D,CAAC;AACH;AAaA,eAAsB,oBAAoB,MAA4C;AACpF,QAAM,EAAE,KAAK,QAAQ,WAAW,SAAS,QAAQ,WAAW,SAAS,IAAI;AAEzE,MAAI,aAAa,UAAU;AACzB,UAAM,OAAO,oBAAoB,OAAO;AACxC,QAAI,CAAC,KAAK,MAAO,QAAOA,WAAU,KAAK,eAAe,sBAAsB,KAAK,MAAM,EAAE;AAAA,EAC3F;AACA,MAAI,OAAgB;AACpB,MAAI;AACF,WAAO,MAAM,QAAQ,KAAK;AAAA,EAC5B,QAAQ;AAAA,EAER;AACA,QAAM,QAAQ,sBAAsB,IAAI;AACxC,MAAI,UAAU,MAAM;AAClB,WAAOA,WAAU,KAAK,eAAe,2CAA2C;AAAA,EAClF;AACA,QAAM,SAAS;AAAA,IACb;AAAA,MACE,UAAU,qBAAqB;AAAA,MAC/B,OAAO,iBAAiB;AAAA,MACxB,UAAU,mBAAmB,KAAK,QAAQ,MAAM;AAAA,IAClD;AAAA,IACA;AAAA,IACA,MAAM;AAAA,EACR;AACA,QAAM,UAAkC,EAAE,gBAAgB,kCAAkC;AAC5F,MAAI,WAAW,OAAQ,SAAQ,aAAa,IAAI,OAAO;AACvD,SAAO,IAAI,SAAS,KAAK,UAAU,MAAM,GAAG,EAAE,QAAQ,KAAK,QAAQ,CAAC;AACtE;AAGO,SAAS,mBACd,WACA,SACA,WAA8B,qBAAqB,GACnD,QAAuB,iBAAiB,GACxC,aAAa,sBACH;AACV,QAAM,SAAS,SAAS,UAAU,SAAS;AAC3C,MAAI,WAAW,QAAQ,MAAM,IAAI,MAAM,GAAG;AAExC,WAAO,wBAAwB,QAAQ,SAAS,KAAK;AAAA,EACvD;AACA,SAAO,qBAAqB,WAAW,SAAS,UAAU,OAAO,UAAU;AAC7E;AAGA,SAAS,qBACP,WACA,SACA,UACA,OACA,YACU;AACV,QAAM,SAAS,IAAI,eAA2B;AAAA,IAC5C,MAAM,YAAY;AAChB,UAAI,SAAS;AACb,YAAM,OAAO,CAAC,SAAuB;AACnC,YAAI,OAAQ;AACZ,YAAI;AACF,qBAAW,QAAQ,UAAU,IAAI,CAAC;AAAA,QACpC,QAAQ;AAAA,QAER;AAAA,MACF;AACA,UAAI;AACJ,YAAM,QAAQ,MAAY;AACxB,YAAI,OAAQ;AACZ,aAAK,cAAc;AACnB,iBAAS;AACT,YAAI;AACF,qBAAW,MAAM;AAAA,QACnB,QAAQ;AAAA,QAER;AAAA,MACF;AACA,YAAM,UAAU,SAAS,UAAU,WAAW,CAAC,UAAU;AACvD,cAAM,MAAM,MAAM;AAAA,UAChB;AAAA,UACA;AAAA,UACA,CAAC,UAAU;AACT,iBAAK,eAAe,MAAM,KAAK,MAAM,IAAI,CAAC;AAAA,UAC5C;AAAA,UACA,MAAM;AACJ,kBAAM;AAAA,UACR;AAAA,QACF;AACA,YAAI,CAAC,IAAI,OAAO;AACd,gBAAM;AACN;AAAA,QACF;AACA,mBAAW,SAAS,IAAI,OAAQ,MAAK,eAAe,MAAM,KAAK,MAAM,IAAI,CAAC;AAC1E,YAAI,IAAI,OAAO;AACb,gBAAM;AACN;AAAA,QACF;AACA,uBAAe,IAAI;AAAA,MACrB,CAAC;AAID,YAAM,iBAAiB,MAAY;AACjC,gBAAQ;AACR,uBAAe;AAAA,MACjB;AACA,YAAM,QAAQ,WAAW,MAAM;AAC7B,uBAAe;AACf,cAAM;AAAA,MACR,GAAG,UAAU;AACb,YAAM,MAAM;AACZ,cAAQ,OAAO,iBAAiB,SAAS,MAAM;AAC7C,uBAAe;AACf,qBAAa,KAAK;AAClB,cAAM;AAAA,MACR,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AACD,SAAO,IAAI,SAAS,QAAQ,EAAE,SAAS,EAAE,GAAG,iBAAiB,EAAE,CAAC;AAClE;;;ACnJA,SAASC,WAAU,QAAgB,MAAc,SAA2B;AAC1E,SAAO,IAAI,SAAS,KAAK,UAAU,EAAE,OAAO,EAAE,MAAM,QAAQ,EAAE,CAAC,GAAG;AAAA,IAChE;AAAA,IACA,SAAS,EAAE,gBAAgB,kCAAkC;AAAA,EAC/D,CAAC;AACH;AA8BA,eAAsB,mBACpB,SACA,SACA,MAC0B;AAC1B,QAAM,SAAS,QAAQ,OAAO,YAAY;AAG1C,QAAM,WAAW,gBAAgB,OAAO;AACxC,MAAI,aAAa,MAAM;AACrB,QAAI,WAAW,MAAO,QAAO;AAC7B,UAAM,QAAQ,KAAK,OAAO,KAAK,CAAC,MAAM,EAAE,SAAS,QAAQ;AACzD,QAAI,CAAC,MAAO,QAAO;AACnB,UAAM,MAAM,MAAM,KAAK,WAAW,MAAM,QAAQ;AAChD,WAAO,gBAAgB,KAAK,MAAM,MAAM,MAAM,WAAW,KAAK,OAAO;AAAA,EACvE;AAGA,MAAI,oBAAoB,OAAO,GAAG;AAChC,QAAI,WAAW,MAAO,QAAO;AAC7B,WAAO,oBAAoB,oBAAoB,CAAC;AAAA,EAClD;AAQA,QAAM,YAAY,qBAAqB,OAAO;AAC9C,MAAI,cAAc,MAAM;AACtB,QAAI,WAAW,MAAO,QAAO;AAC7B,QAAI,CAAC,KAAK,OAAO,KAAK,CAAC,MAAM,EAAE,SAAS,UAAU,IAAI,EAAG,QAAO;AAChE,WAAO,wBAAwB,UAAU,OAAO,SAAS,iBAAiB,CAAC;AAAA,EAC7E;AAIA,QAAM,iBAAiB,MAAM,iBAAiB,SAAS,QAAQ,SAAS,IAAI;AAC5E,MAAI,mBAAmB,KAAM,QAAO;AAIpC,QAAM,UAAU,UAAU,OAAO;AACjC,MAAI,YAAY,MAAM;AACpB,WAAO,cAAc,SAAS,QAAQ,SAAS,IAAI;AAAA,EACrD;AAEA,SAAO;AACT;AAqBA,eAAe,iBACb,SACA,QACA,SACA,MAC0B;AAC1B,QAAM,SAAS,mBAAmB,OAAO;AACzC,MAAI,WAAW,MAAM;AACnB,QAAI,WAAW,MAAO,QAAO;AAC7B,QAAI,CAAC,KAAK,OAAO,KAAK,CAAC,MAAM,EAAE,SAAS,OAAO,IAAI,EAAG,QAAO;AAC7D,WAAO,mBAAmB,OAAO,WAAW,OAAO;AAAA,EACrD;AAEA,QAAM,MAAM,oBAAoB,OAAO;AACvC,MAAI,QAAQ,MAAM;AAChB,QAAI,WAAW,OAAQ,QAAO;AAC9B,UAAM,QAAQ,KAAK,OAAO,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI,IAAI;AACzD,QAAI,CAAC,MAAO,QAAO;AACnB,QAAI,KAAK,kBAAkB,QAAW;AAGpC,aAAOA;AAAA,QACL;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AACA,UAAM,MAAM,MAAM,KAAK,WAAW,MAAM,QAAQ;AAChD,WAAO,oBAAoB;AAAA,MACzB;AAAA,MACA,QAAQ,KAAK,cAAc;AAAA,MAC3B,WAAW,IAAI;AAAA,MACf;AAAA,MACA,QAAQ,UAAU,IAAI,IAAI;AAAA,MAC1B,UAAU,KAAK,YAAY;AAAA,IAC7B,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAOA,eAAe,cACb,SACA,QACA,SACA,MAC0B;AAC1B,MAAI,WAAW,OAAQ,QAAO;AAC9B,QAAM,QAAQ,KAAK,OAAO,KAAK,CAAC,MAAM,EAAE,SAAS,OAAO;AACxD,MAAI,CAAC,MAAO,QAAO;AAEnB,QAAM,MAAM,MAAM,KAAK,WAAW,MAAM,QAAQ;AAMhD,MAAI,CAAC,aAAa,GAAG,EAAG,QAAO;AAI/B,QAAM,WAAW,KAAK,YAAY;AAClC,MAAI,aAAa,UAAU;AACzB,UAAM,OAAO,oBAAoB,OAAO;AACxC,QAAI,CAAC,KAAK,MAAO,QAAOA,WAAU,KAAK,eAAe,sBAAsB,KAAK,MAAM,EAAE;AAAA,EAC3F;AAEA,MAAI,OAAgB;AACpB,MAAI;AACF,WAAO,MAAM,QAAQ,KAAK;AAAA,EAC5B,QAAQ;AAAA,EAER;AAGA,SAAO,iBAAiB,KAAK,MAAM,MAAM,MAAM,oBAAoB,GAAG,CAAC;AACzE;AAOA,SAAS,aAAa,KAAuB;AAC3C,SAAQ,KAA8C,QAAQ;AAChE;;;ACjLA,eAAsB,iCACpB,UACA,KACe;AAKf,QAAM,aAAa,SAAS,QAAQ,aAAa;AACjD,MAAI,WAAW,SAAS,GAAG;AACzB,QAAI,UAAU,cAAc,UAAU;AAAA,EACxC;AACA,QAAM,eAAuC,CAAC;AAC9C,aAAW,CAAC,KAAK,KAAK,KAAK,SAAS,QAAQ,QAAQ,GAAG;AACrD,QAAI,IAAI,YAAY,MAAM,aAAc;AACxC,iBAAa,GAAG,IAAI;AAAA,EACtB;AACA,MAAI,UAAU,SAAS,QAAQ,SAAS,YAAY,YAAY;AAGhE,MAAI,SAAS,SAAS,MAAM;AAC1B,QAAI,IAAI;AACR;AAAA,EACF;AACA,QAAM,SAAS,SAAS,KAAK,UAAU;AACvC,MAAI;AACF,eAAS;AACP,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,UAAI,KAAM;AAEV,UAAI,MAAM,KAAK;AAAA,IACjB;AACA,QAAI,IAAI;AAAA,EACV,UAAE;AACA,WAAO,YAAY;AAAA,EACrB;AACF;","names":["jsonError","jsonError"]}
|
|
@@ -2,20 +2,17 @@
|
|
|
2
2
|
import "tsx/esm";
|
|
3
3
|
import {
|
|
4
4
|
handleAgentApproval,
|
|
5
|
-
hoistHeadTags,
|
|
6
5
|
isAgentCardPath,
|
|
7
6
|
isApprovalPath,
|
|
8
7
|
isListApprovalsPath,
|
|
9
8
|
resolveTransformer,
|
|
10
9
|
serveAgentAuxRoute,
|
|
10
|
+
setupSsrDevMiddleware,
|
|
11
11
|
writeWebResponseToServerResponse
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-RPIL7VRZ.js";
|
|
13
13
|
import {
|
|
14
14
|
isMcpPath
|
|
15
15
|
} from "./chunk-2CVV6CNN.js";
|
|
16
|
-
import {
|
|
17
|
-
findRootDiv
|
|
18
|
-
} from "./chunk-3PWQQWT6.js";
|
|
19
16
|
import {
|
|
20
17
|
isRouteFile,
|
|
21
18
|
scanRoutes
|
|
@@ -34,23 +31,20 @@ import {
|
|
|
34
31
|
CSP_REPORT_PATH,
|
|
35
32
|
CsrfReadinessStore,
|
|
36
33
|
TRACE_HEADER,
|
|
37
|
-
createCorsHandler,
|
|
38
|
-
extractTraceId,
|
|
39
|
-
handleBatchRequest,
|
|
40
|
-
handleCspReport,
|
|
41
|
-
handleCsrfReadiness
|
|
42
|
-
} from "./chunk-7CQ6DEWZ.js";
|
|
43
|
-
import {
|
|
44
34
|
applySecurityHeaders,
|
|
35
|
+
createCorsHandler,
|
|
45
36
|
createPluginRunnerFromConfig,
|
|
46
37
|
createRateLimiter,
|
|
47
38
|
createViteLoader,
|
|
48
39
|
executeAction,
|
|
49
40
|
executeRoute,
|
|
41
|
+
extractTraceId,
|
|
50
42
|
findSuggestion,
|
|
51
|
-
|
|
43
|
+
handleBatchRequest,
|
|
44
|
+
handleCspReport,
|
|
45
|
+
handleCsrfReadiness,
|
|
52
46
|
mountAgent
|
|
53
|
-
} from "./chunk-
|
|
47
|
+
} from "./chunk-ABUVJU3P.js";
|
|
54
48
|
import {
|
|
55
49
|
getApprovalRegistry,
|
|
56
50
|
resolveProvider
|
|
@@ -74,7 +68,7 @@ import {
|
|
|
74
68
|
|
|
75
69
|
// src/vite-plugin/index.ts
|
|
76
70
|
import { existsSync as existsSync7 } from "fs";
|
|
77
|
-
import { resolve as
|
|
71
|
+
import { resolve as resolve6, dirname as dirname4 } from "path";
|
|
78
72
|
import { fileURLToPath } from "url";
|
|
79
73
|
|
|
80
74
|
// src/vite-plugin/config-hook.ts
|
|
@@ -293,7 +287,7 @@ async function resolvePluginConfig(projectRoot) {
|
|
|
293
287
|
}
|
|
294
288
|
|
|
295
289
|
// src/vite-plugin/configure-server-hook.ts
|
|
296
|
-
import { resolve as
|
|
290
|
+
import { resolve as resolve3, basename } from "path";
|
|
297
291
|
|
|
298
292
|
// src/devtools/server-side/route-manifest.ts
|
|
299
293
|
function buildPath(parents, segment) {
|
|
@@ -621,10 +615,10 @@ async function handleBatchIfMatch(req, res, ctx) {
|
|
|
621
615
|
async function handleBatchInline(req, res, batching, requestId) {
|
|
622
616
|
try {
|
|
623
617
|
const chunks = [];
|
|
624
|
-
await new Promise((
|
|
618
|
+
await new Promise((resolve7, reject) => {
|
|
625
619
|
req.on("data", (c) => chunks.push(c));
|
|
626
620
|
req.on("end", () => {
|
|
627
|
-
|
|
621
|
+
resolve7();
|
|
628
622
|
});
|
|
629
623
|
req.on("error", reject);
|
|
630
624
|
});
|
|
@@ -811,83 +805,6 @@ function createApiMiddleware(vite, serverDir, rateLimitConfigOrOptions) {
|
|
|
811
805
|
};
|
|
812
806
|
}
|
|
813
807
|
|
|
814
|
-
// src/vite-plugin/ssr-dev-middleware.ts
|
|
815
|
-
import { readFileSync as readFileSync2 } from "fs";
|
|
816
|
-
import { resolve as resolve3 } from "path";
|
|
817
|
-
function applyNonceToInlineScripts(html, nonce) {
|
|
818
|
-
return html.replace(
|
|
819
|
-
/<script(?![^>]*\ssrc=)(?![^>]*\snonce=)([^>]*)>/gi,
|
|
820
|
-
`<script nonce="${nonce}"$1>`
|
|
821
|
-
);
|
|
822
|
-
}
|
|
823
|
-
function isSsrRenderResult(value) {
|
|
824
|
-
if (typeof value !== "object" || value === null) return false;
|
|
825
|
-
if (!("html" in value)) return false;
|
|
826
|
-
return typeof value.html === "string";
|
|
827
|
-
}
|
|
828
|
-
function setupSsrDevMiddleware(server, opts) {
|
|
829
|
-
server.middlewares.use((req, res, next) => {
|
|
830
|
-
void (async () => {
|
|
831
|
-
const url = req.url ?? "/";
|
|
832
|
-
if (url.startsWith("/api/") || url.startsWith("/@") || url.startsWith("/node_modules/") || url.includes(".")) {
|
|
833
|
-
next();
|
|
834
|
-
return;
|
|
835
|
-
}
|
|
836
|
-
try {
|
|
837
|
-
const indexPath = resolve3(opts.projectRoot, "index.html");
|
|
838
|
-
let template = readFileSync2(indexPath, "utf-8");
|
|
839
|
-
const nonce = generateNonce();
|
|
840
|
-
template = await server.transformIndexHtml(url, template);
|
|
841
|
-
template = applyNonceToInlineScripts(template, nonce);
|
|
842
|
-
applySecurityHeaders(
|
|
843
|
-
res,
|
|
844
|
-
opts.securityHeaders ?? {},
|
|
845
|
-
{ production: process.env.NODE_ENV === "production" },
|
|
846
|
-
{ nonce }
|
|
847
|
-
);
|
|
848
|
-
const mod = await server.ssrLoadModule(opts.virtualEntryServerId);
|
|
849
|
-
const result = await mod.render(url, { nonce });
|
|
850
|
-
if (result && typeof result === "object" && "redirect" in result) {
|
|
851
|
-
res.writeHead(302, {
|
|
852
|
-
Location: result.redirect.headers.get("location") ?? "/"
|
|
853
|
-
});
|
|
854
|
-
res.end();
|
|
855
|
-
return;
|
|
856
|
-
}
|
|
857
|
-
let ssrHtml;
|
|
858
|
-
let hydrationScript = "";
|
|
859
|
-
if (typeof result === "string") {
|
|
860
|
-
ssrHtml = result;
|
|
861
|
-
} else if (isSsrRenderResult(result)) {
|
|
862
|
-
ssrHtml = result.html;
|
|
863
|
-
const dataJson = JSON.stringify(result.hydrationData).replace(/</g, "\\u003c");
|
|
864
|
-
hydrationScript = `<script nonce="${nonce}">window.__staticRouterHydrationData=${dataJson}</script>`;
|
|
865
|
-
} else {
|
|
866
|
-
ssrHtml = "";
|
|
867
|
-
}
|
|
868
|
-
const hoisted = hoistHeadTags(template, ssrHtml);
|
|
869
|
-
template = hoisted.template;
|
|
870
|
-
ssrHtml = hoisted.html;
|
|
871
|
-
const rootDiv = findRootDiv(template);
|
|
872
|
-
if (!rootDiv) {
|
|
873
|
-
res.writeHead(200, { "Content-Type": "text/html" });
|
|
874
|
-
res.end(template);
|
|
875
|
-
return;
|
|
876
|
-
}
|
|
877
|
-
const splitIdx = rootDiv.insertAt;
|
|
878
|
-
const html = template.slice(0, splitIdx) + ssrHtml + hydrationScript + template.slice(splitIdx);
|
|
879
|
-
res.writeHead(200, { "Content-Type": "text/html" });
|
|
880
|
-
res.end(html);
|
|
881
|
-
} catch (err) {
|
|
882
|
-
server.ssrFixStacktrace(err);
|
|
883
|
-
console.error("[SSR Dev Error]", err);
|
|
884
|
-
next();
|
|
885
|
-
return;
|
|
886
|
-
}
|
|
887
|
-
})();
|
|
888
|
-
});
|
|
889
|
-
}
|
|
890
|
-
|
|
891
808
|
// src/vite-plugin/ws-upgrade.ts
|
|
892
809
|
function setupWsUpgrade(server, serverDir) {
|
|
893
810
|
const wsRoutes = scanWebSocketRoutes(serverDir);
|
|
@@ -972,7 +889,7 @@ async function runConfigureServer(server, ctx) {
|
|
|
972
889
|
csrfReadinessStore
|
|
973
890
|
})
|
|
974
891
|
);
|
|
975
|
-
const configPath =
|
|
892
|
+
const configPath = resolve3(ctx.projectRoot, "theo.config.ts");
|
|
976
893
|
server.watcher.on("change", (file) => {
|
|
977
894
|
if (file === configPath) {
|
|
978
895
|
console.warn(
|
|
@@ -1002,7 +919,7 @@ async function runConfigureServer(server, ctx) {
|
|
|
1002
919
|
const openApiCfg = ctx.resolvedOpenApi;
|
|
1003
920
|
const { reEmitOpenApi } = await import("./dev-emit-GWD6IXV7.js");
|
|
1004
921
|
const openApiServerDir = ctx.serverDir;
|
|
1005
|
-
const openApiDistDir =
|
|
922
|
+
const openApiDistDir = resolve3(ctx.projectRoot, ctx.resolvedDistDir);
|
|
1006
923
|
const isRouteFileForOpenApi = (file) => file.startsWith(openApiServerDir) && /\.(ts|tsx|js|mjs)$/.test(file);
|
|
1007
924
|
void reEmitOpenApi(openApiServerDir, openApiDistDir, openApiCfg);
|
|
1008
925
|
server.watcher.on("change", (file) => {
|
|
@@ -1050,16 +967,16 @@ async function integrateStudio(importStudio = () => import(
|
|
|
1050
967
|
}
|
|
1051
968
|
|
|
1052
969
|
// src/vite-plugin/integrate-ui.ts
|
|
1053
|
-
import { existsSync as existsSync4, readFileSync as
|
|
970
|
+
import { existsSync as existsSync4, readFileSync as readFileSync3 } from "fs";
|
|
1054
971
|
import { dirname as dirname3, join as join3 } from "path";
|
|
1055
972
|
import { pathToFileURL } from "url";
|
|
1056
973
|
|
|
1057
974
|
// src/vite-plugin/auto-detect.ts
|
|
1058
|
-
import { existsSync as existsSync3, readFileSync as
|
|
975
|
+
import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
|
|
1059
976
|
import { dirname as dirname2, join as join2 } from "path";
|
|
1060
977
|
function isDeclared(name, projectRoot) {
|
|
1061
978
|
try {
|
|
1062
|
-
const raw =
|
|
979
|
+
const raw = readFileSync2(join2(projectRoot, "package.json"), "utf-8");
|
|
1063
980
|
const pkg = JSON.parse(raw);
|
|
1064
981
|
return Boolean(
|
|
1065
982
|
pkg.dependencies?.[name] ?? pkg.devDependencies?.[name] ?? pkg.peerDependencies?.[name]
|
|
@@ -1074,7 +991,7 @@ function resolvePackageJson(name, cwd) {
|
|
|
1074
991
|
const pkgJsonPath = join2(dir, "node_modules", ...name.split("/"), "package.json");
|
|
1075
992
|
if (existsSync3(pkgJsonPath)) {
|
|
1076
993
|
try {
|
|
1077
|
-
const raw =
|
|
994
|
+
const raw = readFileSync2(pkgJsonPath, "utf-8");
|
|
1078
995
|
const pkg = JSON.parse(raw);
|
|
1079
996
|
if (pkg.name === name) {
|
|
1080
997
|
return { path: pkgJsonPath, version: pkg.version };
|
|
@@ -1109,7 +1026,7 @@ function findOwningPackageJson(entry, expectedName) {
|
|
|
1109
1026
|
const candidate = join2(dir, "package.json");
|
|
1110
1027
|
if (existsSync3(candidate)) {
|
|
1111
1028
|
try {
|
|
1112
|
-
const raw =
|
|
1029
|
+
const raw = readFileSync2(candidate, "utf-8");
|
|
1113
1030
|
const pkg = JSON.parse(raw);
|
|
1114
1031
|
if (pkg.name === expectedName) {
|
|
1115
1032
|
return { path: candidate, version: pkg.version };
|
|
@@ -1141,7 +1058,7 @@ function detectPackage(name, cwd) {
|
|
|
1141
1058
|
const nmPkgJson = join2(nmPath, "package.json");
|
|
1142
1059
|
if (existsSync3(nmPkgJson)) {
|
|
1143
1060
|
try {
|
|
1144
|
-
const raw =
|
|
1061
|
+
const raw = readFileSync2(nmPkgJson, "utf-8");
|
|
1145
1062
|
const pkg = JSON.parse(raw);
|
|
1146
1063
|
if (pkg.name === name) {
|
|
1147
1064
|
return { installed: true, version: pkg.version, resolvedPath: nmPkgJson };
|
|
@@ -1173,7 +1090,7 @@ function resolveConsumerImport(name, cwd) {
|
|
|
1173
1090
|
const pkgJsonPath = join3(pkgDir, "package.json");
|
|
1174
1091
|
if (existsSync4(pkgJsonPath)) {
|
|
1175
1092
|
try {
|
|
1176
|
-
const raw =
|
|
1093
|
+
const raw = readFileSync3(pkgJsonPath, "utf-8");
|
|
1177
1094
|
const pkg = JSON.parse(raw);
|
|
1178
1095
|
let entry;
|
|
1179
1096
|
const dotExport = pkg.exports?.["."];
|
|
@@ -1309,17 +1226,17 @@ async function integrateUseTheoUI(cwd, opts) {
|
|
|
1309
1226
|
|
|
1310
1227
|
// src/vite-plugin/resolve-theo-root.ts
|
|
1311
1228
|
import { existsSync as existsSync5 } from "fs";
|
|
1312
|
-
import { resolve as
|
|
1229
|
+
import { resolve as resolve4 } from "path";
|
|
1313
1230
|
function resolveTheoRootDir(currentDir) {
|
|
1314
|
-
if (existsSync5(
|
|
1231
|
+
if (existsSync5(resolve4(currentDir, "client"))) {
|
|
1315
1232
|
return currentDir;
|
|
1316
1233
|
}
|
|
1317
|
-
return
|
|
1234
|
+
return resolve4(currentDir, "..");
|
|
1318
1235
|
}
|
|
1319
1236
|
|
|
1320
1237
|
// src/vite-plugin/transform-html-hook.ts
|
|
1321
1238
|
import { existsSync as existsSync6 } from "fs";
|
|
1322
|
-
import { resolve as
|
|
1239
|
+
import { resolve as resolve5 } from "path";
|
|
1323
1240
|
|
|
1324
1241
|
// src/vite-plugin/inject-devtools.ts
|
|
1325
1242
|
var DEVTOOLS_VIRTUAL_ID = "/@theo/devtools/entry.js";
|
|
@@ -1419,7 +1336,7 @@ function runTransformIndexHtml(html, ctx) {
|
|
|
1419
1336
|
next = devtools.html;
|
|
1420
1337
|
const styles = injectStylesheets(next, {
|
|
1421
1338
|
isDev: ctx.isDevMode.value,
|
|
1422
|
-
hasPackage: (name) => existsSync6(
|
|
1339
|
+
hasPackage: (name) => existsSync6(resolve5(ctx.projectRoot, "node_modules", ...name.split("/")))
|
|
1423
1340
|
});
|
|
1424
1341
|
next = styles.html;
|
|
1425
1342
|
return next;
|
|
@@ -1979,7 +1896,7 @@ function findConsumerConfig(projectRoot, basename2) {
|
|
|
1979
1896
|
let dir = projectRoot;
|
|
1980
1897
|
for (let level = 0; level < 3; level++) {
|
|
1981
1898
|
for (const ext of extensions) {
|
|
1982
|
-
const candidate =
|
|
1899
|
+
const candidate = resolve6(dir, `${basename2}${ext}`);
|
|
1983
1900
|
if (existsSync7(candidate)) return candidate;
|
|
1984
1901
|
}
|
|
1985
1902
|
const parent = dirname4(dir);
|
|
@@ -1991,7 +1908,7 @@ function findConsumerConfig(projectRoot, basename2) {
|
|
|
1991
1908
|
async function theoPluginAsync(rootOrOptions) {
|
|
1992
1909
|
const options = typeof rootOrOptions === "string" ? { root: rootOrOptions } : rootOrOptions ?? {};
|
|
1993
1910
|
const projectRoot = options.root ?? process.cwd();
|
|
1994
|
-
const serverDirAbs =
|
|
1911
|
+
const serverDirAbs = resolve6(projectRoot, options.serverDir ?? "server");
|
|
1995
1912
|
const agentsDirName = options.agentsDir ?? "agents";
|
|
1996
1913
|
const consumerTailwindConfig = findConsumerConfig(projectRoot, "tailwind.config");
|
|
1997
1914
|
const consumerPostcssConfig = findConsumerConfig(projectRoot, "postcss.config");
|
|
@@ -2010,23 +1927,23 @@ async function theoPluginAsync(rootOrOptions) {
|
|
|
2010
1927
|
})
|
|
2011
1928
|
);
|
|
2012
1929
|
}
|
|
2013
|
-
const { appTypedClientPlugin } = await import("./app-typed-client-
|
|
1930
|
+
const { appTypedClientPlugin } = await import("./app-typed-client-4GDSR5T3.js");
|
|
2014
1931
|
const appClientPlugin = appTypedClientPlugin({
|
|
2015
1932
|
cwd: projectRoot,
|
|
2016
1933
|
serverDir: serverDirAbs,
|
|
2017
|
-
distDir:
|
|
1934
|
+
distDir: resolve6(projectRoot, ".theokit")
|
|
2018
1935
|
});
|
|
2019
|
-
const { actionsVirtualModule } = await import("./actions-virtual-module-
|
|
1936
|
+
const { actionsVirtualModule } = await import("./actions-virtual-module-IICWQK43.js");
|
|
2020
1937
|
const actionsPlugin = actionsVirtualModule({
|
|
2021
1938
|
serverDir: serverDirAbs,
|
|
2022
|
-
distDir:
|
|
1939
|
+
distDir: resolve6(projectRoot, ".theokit")
|
|
2023
1940
|
});
|
|
2024
1941
|
const { agentsTypedClientPlugin } = await import("./agents-typed-client-D4OA2TXB.js");
|
|
2025
|
-
const { generateManifest } = await import("./internal-api-
|
|
1942
|
+
const { generateManifest } = await import("./internal-api-AKYIRMT2.js");
|
|
2026
1943
|
const agentsClientPlugin = agentsTypedClientPlugin({
|
|
2027
1944
|
projectRoot,
|
|
2028
1945
|
agentsDir: agentsDirName,
|
|
2029
|
-
distDir:
|
|
1946
|
+
distDir: resolve6(projectRoot, ".theokit"),
|
|
2030
1947
|
// Agents live at <projectRoot>/<agentsDir>; generateManifest scans them via the server dir's
|
|
2031
1948
|
// parent (projectRoot for the canonical layout) + the agents dir name (#95 follow-up).
|
|
2032
1949
|
scanManifest: () => generateManifest(serverDirAbs, projectRoot, agentsDirName)
|
|
@@ -2054,10 +1971,10 @@ async function theoPluginAsync(rootOrOptions) {
|
|
|
2054
1971
|
}
|
|
2055
1972
|
function buildOptimizeDepsInclude(projectRoot, viteOptimizeDeps) {
|
|
2056
1973
|
const include = [];
|
|
2057
|
-
if (existsSync7(
|
|
1974
|
+
if (existsSync7(resolve6(projectRoot, "node_modules", "@theokit", "ui"))) {
|
|
2058
1975
|
include.push("@theokit/ui");
|
|
2059
1976
|
}
|
|
2060
|
-
if (existsSync7(
|
|
1977
|
+
if (existsSync7(resolve6(projectRoot, "node_modules", "lucide-react"))) {
|
|
2061
1978
|
include.push("lucide-react");
|
|
2062
1979
|
}
|
|
2063
1980
|
include.push("devalue");
|
|
@@ -2083,8 +2000,8 @@ var VIRTUAL_MODULE_IDS = {
|
|
|
2083
2000
|
function theoPlugin(rootOrOptions) {
|
|
2084
2001
|
const options = typeof rootOrOptions === "string" ? { root: rootOrOptions } : rootOrOptions ?? {};
|
|
2085
2002
|
const projectRoot = options.root ?? process.cwd();
|
|
2086
|
-
const appDir =
|
|
2087
|
-
const serverDir =
|
|
2003
|
+
const appDir = resolve6(projectRoot, options.appDir ?? "app");
|
|
2004
|
+
const serverDir = resolve6(projectRoot, options.serverDir ?? "server");
|
|
2088
2005
|
const agentsDir = options.agentsDir ?? "agents";
|
|
2089
2006
|
const ssrEnabled = options.ssr ?? false;
|
|
2090
2007
|
const currentDir = dirname4(fileURLToPath(import.meta.url));
|
|
@@ -2204,4 +2121,4 @@ export {
|
|
|
2204
2121
|
theoPluginAsync,
|
|
2205
2122
|
theoPlugin
|
|
2206
2123
|
};
|
|
2207
|
-
//# sourceMappingURL=chunk-
|
|
2124
|
+
//# sourceMappingURL=chunk-ZGNA66JK.js.map
|