@assistant-ui/x-generative-compiler 0.0.3 → 0.0.5

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 AgentbaseAI Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -1 +1 @@
1
- {"version":3,"file":"compile.d.ts","names":[],"sources":["../src/compile.ts"],"mappings":";;;KAmBY,QAAA;AAAA,UAkCK,cAAA;EAlCL;EAoCV,MAAA,EAAQ,MAAM;;EAEd,QAAA;EAtCkB;EAwClB,UAAA;EAN6B;;;;;;;;EAe7B,gBAAA;AAAA;AAAA,UAGe,aAAA;EACf,IAAA;EACA,GAAG;AAAA;AAAA;AAAA,cAIQ,sBAAA,SAA+B,KAAK;cACnC,OAAA,UAAiB,QAAA;AAAA;;iBAOf,kBAAA,CAAmB,IAAY;;;;;iBA4B/B,iBAAA,CACd,IAAA,UACA,OAAA,EAAS,cAAA,GACR,aAAa"}
1
+ {"version":3,"file":"compile.d.ts","names":[],"sources":["../src/compile.ts"],"mappings":";;;KAoBY,QAAA;AAAA,UAkCK,cAAA;EAlCL;EAoCV,MAAA,EAAQ,MAAM;;EAEd,QAAA;EAtCkB;EAwClB,UAAA;EAN6B;;;;;;;;EAe7B,gBAAA;AAAA;AAAA,UAGe,aAAA;EACf,IAAA;EACA,GAAG;AAAA;AAAA;AAAA,cAIQ,sBAAA,SAA+B,KAAK;cACnC,OAAA,UAAiB,QAAA;AAAA;;iBAOf,kBAAA,CAAmB,IAAY;;;;;iBA4B/B,iBAAA,CACd,IAAA,UACA,OAAA,EAAS,cAAA,GACR,aAAa"}
package/dist/compile.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { DIRECTIVE } from "./constants.js";
2
+ import { version } from "./package.js";
2
3
  import { existsSync, readFileSync } from "node:fs";
3
4
  import { createRequire } from "node:module";
4
5
  import * as nodePath from "node:path";
@@ -75,7 +76,7 @@ function compileGenerative(code, options) {
75
76
  ensureCompilerCompatibleWithCore(ast, filename);
76
77
  ensureDefaultExport(ast, filename);
77
78
  const generativeInstances = collectGenerativeInstances(ast);
78
- const safeToolkitSpreads = collectSafeToolkitSpreads(ast);
79
+ const safeToolkitSpreads = collectSafeToolkitSpreads(ast, filename);
79
80
  const flags = {
80
81
  keptRender: false,
81
82
  keptBackendExecute: false
@@ -113,7 +114,7 @@ function compileGenerative(code, options) {
113
114
  };
114
115
  }
115
116
  const checkedCorePackageJsonPaths = /* @__PURE__ */ new Set();
116
- let compilerPackageVersion;
117
+ const COMPILER_VERSION = version;
117
118
  function ensureCompilerCompatibleWithCore(ast, filename) {
118
119
  const corePackageJsonPath = resolveCorePackageJson(ast, filename);
119
120
  if (!corePackageJsonPath || checkedCorePackageJsonPaths.has(corePackageJsonPath)) return;
@@ -123,24 +124,15 @@ function ensureCompilerCompatibleWithCore(ast, filename) {
123
124
  checkedCorePackageJsonPaths.add(corePackageJsonPath);
124
125
  return;
125
126
  }
126
- const compilerVersion = getCompilerPackageVersion();
127
127
  let compatible = false;
128
128
  try {
129
- compatible = satisfies(compilerVersion, range, { includePrerelease: true });
129
+ compatible = satisfies(COMPILER_VERSION, range, { includePrerelease: true });
130
130
  } catch {
131
131
  throw new GenerativeCompileError(`${CORE_PACKAGE}@${corePackageJson.version ?? "unknown"} declares an invalid optionalDevDependencies range for ${COMPILER_PACKAGE}: ` + JSON.stringify(range), filename);
132
132
  }
133
- if (!compatible) throw new GenerativeCompileError(`${CORE_PACKAGE}@${corePackageJson.version ?? "unknown"} requires ${COMPILER_PACKAGE} ${range}, but the current compiler is ${compilerVersion}. Update @assistant-ui/next or @assistant-ui/vite so their compiler satisfies the core package's optionalDevDependencies range.`, filename);
133
+ if (!compatible) throw new GenerativeCompileError(`${CORE_PACKAGE}@${corePackageJson.version ?? "unknown"} requires ${COMPILER_PACKAGE} ${range}, but the current compiler is ${COMPILER_VERSION}. Update @assistant-ui/next, @assistant-ui/vite, or @assistant-ui/metro so their compiler satisfies the core package's optionalDevDependencies range.`, filename);
134
134
  checkedCorePackageJsonPaths.add(corePackageJsonPath);
135
135
  }
136
- function getCompilerPackageVersion() {
137
- if (compilerPackageVersion) return compilerPackageVersion;
138
- const packageJsonPath = findPackageJson(import.meta.url, COMPILER_PACKAGE);
139
- const packageJson = packageJsonPath ? readPackageJson(packageJsonPath) : null;
140
- if (!packageJson?.version) throw new GenerativeCompileError(`could not determine ${COMPILER_PACKAGE}'s package version`);
141
- compilerPackageVersion = packageJson.version;
142
- return compilerPackageVersion;
143
- }
144
136
  function resolveCorePackageJson(ast, filename) {
145
137
  for (const packageName of collectImportedDistributionPackages(ast)) {
146
138
  const packageJsonPath = resolvePackageJson(packageName, filename);
@@ -175,11 +167,13 @@ function resolvePackageJson(packageName, filename) {
175
167
  }
176
168
  }
177
169
  function normalizeRequirePath(filename) {
178
- if (filename) {
179
- const cleanFilename = filename.split(/[?#]/, 1)[0];
180
- if (nodePath.isAbsolute(cleanFilename)) return cleanFilename;
181
- }
182
- return import.meta.url;
170
+ return cleanAbsoluteFilename(filename) ?? import.meta.url;
171
+ }
172
+ /** Strips a `?query`/`#hash` suffix and returns the path only if it is absolute. */
173
+ function cleanAbsoluteFilename(filename) {
174
+ if (!filename) return null;
175
+ const clean = filename.split(/[?#]/, 1)[0];
176
+ return nodePath.isAbsolute(clean) ? clean : null;
183
177
  }
184
178
  function findPackageJson(fromPathOrUrl, packageName) {
185
179
  let current = nodePath.dirname(fromPathOrUrl.startsWith("file:") ? new URL(fromPathOrUrl).pathname : nodePath.resolve(fromPathOrUrl));
@@ -220,7 +214,7 @@ function readPackageJson(packageJsonPath) {
220
214
  function ensureDefaultExport(ast, filename) {
221
215
  const def = ast.program.body.find((stmt) => t.isExportDefaultDeclaration(stmt));
222
216
  if (!def) throw new GenerativeCompileError("missing a default export", filename);
223
- if (!unwrapToCall(def.declaration, TOOLKIT_WRAPPER)) throw new GenerativeCompileError(`the default export must be ${TOOLKIT_WRAPPER}({ ... }) (imported from "@assistant-ui/react"); wrapping is required so a backend \`execute\` can't be authored in a way that reaches the client`, filename);
217
+ if (!unwrapToToolkitCall(def.declaration)) throw new GenerativeCompileError(`the default export must be ${TOOLKIT_WRAPPER}({ ... }) or ${MCP_TOOLKIT_WRAPPER}({ ... }) (imported from "@assistant-ui/react"); wrapping is required so a backend \`execute\` can't be authored in a way that reaches the client`, filename);
224
218
  }
225
219
  /**
226
220
  * Unwraps a node through `satisfies`/`as`/parens to a call of the named function,
@@ -250,23 +244,215 @@ function collectGenerativeInstances(ast) {
250
244
  return names;
251
245
  }
252
246
  /**
253
- * Local toolkit variables whose initializer is visible to this compiler pass
254
- * are safe to spread. `defineToolkit(...)` initializers are compiled in-place
255
- * before a later spread reads them; `defineMcpToolkit(...)` entries cannot
256
- * contain executable code.
247
+ * Toolkit identifiers that are safe to spread into a `defineToolkit({ ... })`.
248
+ *
249
+ * Two kinds qualify:
250
+ *
251
+ * - A local variable whose initializer is visible to this compiler pass: a
252
+ * `defineToolkit(...)` binding is compiled in-place before a later spread
253
+ * reads it, and `defineMcpToolkit(...)` entries can't contain executable code.
254
+ * - The default import of another `"use generative"` module: that module is
255
+ * split per-target by its own compiler pass, so spreading its default-exported
256
+ * toolkit can't leak a backend `execute` to the client. Only the default
257
+ * export crosses the generative-module boundary, so named imports don't
258
+ * qualify — they would be `undefined` once that module is build-split.
257
259
  */
258
- function collectSafeToolkitSpreads(ast) {
260
+ function collectSafeToolkitSpreads(ast, filename) {
259
261
  const names = /* @__PURE__ */ new Set();
262
+ const generativeBySource = /* @__PURE__ */ new Map();
260
263
  for (const statement of ast.program.body) {
261
- if (!t.isVariableDeclaration(statement)) continue;
262
- for (const declaration of statement.declarations) {
263
- const { id, init } = declaration;
264
- if (!t.isIdentifier(id) || !init) continue;
265
- if (unwrapToToolkitCall(init)) names.add(id.name);
264
+ if (t.isVariableDeclaration(statement)) {
265
+ for (const declaration of statement.declarations) {
266
+ const { id, init } = declaration;
267
+ if (t.isIdentifier(id) && init && unwrapToToolkitCall(init)) names.add(id.name);
268
+ }
269
+ continue;
270
+ }
271
+ if (t.isImportDeclaration(statement)) {
272
+ const defaultSpecifier = statement.specifiers.find((specifier) => t.isImportDefaultSpecifier(specifier));
273
+ if (!defaultSpecifier) continue;
274
+ const source = statement.source.value;
275
+ let isGenerative = generativeBySource.get(source);
276
+ if (isGenerative === void 0) {
277
+ isGenerative = isGenerativeImport(source, filename);
278
+ generativeBySource.set(source, isGenerative);
279
+ }
280
+ if (isGenerative) names.add(defaultSpecifier.local.name);
266
281
  }
267
282
  }
268
283
  return names;
269
284
  }
285
+ const MODULE_EXTENSIONS = [
286
+ ".ts",
287
+ ".tsx",
288
+ ".mts",
289
+ ".cts",
290
+ ".js",
291
+ ".jsx",
292
+ ".mjs",
293
+ ".cjs"
294
+ ];
295
+ /** Extensions a specifier may carry that actually map to a TS source file. */
296
+ const REWRITABLE_JS_EXTENSIONS = new Set([
297
+ ".js",
298
+ ".jsx",
299
+ ".mjs",
300
+ ".cjs"
301
+ ]);
302
+ /**
303
+ * Whether an import specifier resolves on disk to a `"use generative"` module.
304
+ * Relative specifiers and `tsconfig` path aliases (e.g. `@/tools`) are resolved;
305
+ * anything else (a bare package, an unresolvable alias) is treated as
306
+ * non-generative, and thus an unsafe spread.
307
+ */
308
+ function isGenerativeImport(source, filename) {
309
+ const cleanFilename = cleanAbsoluteFilename(filename);
310
+ if (!cleanFilename) return false;
311
+ const resolved = resolveImportedModuleFile(source, cleanFilename);
312
+ if (!resolved) return false;
313
+ try {
314
+ return isGenerativeModule(readFileSync(resolved, "utf8"));
315
+ } catch {
316
+ return false;
317
+ }
318
+ }
319
+ /** Resolves an import specifier (relative or `tsconfig`-aliased) to a file on disk. */
320
+ function resolveImportedModuleFile(source, fromFilename) {
321
+ if (source.startsWith(".")) return resolveModuleFileAtPath(nodePath.resolve(nodePath.dirname(fromFilename), source));
322
+ return resolveAliasImport(source, fromFilename);
323
+ }
324
+ /**
325
+ * Resolves a candidate module path, trying TS/JS extensions then index files. A
326
+ * specifier may carry a `.js`-family extension that maps to a `.ts`/`.tsx`
327
+ * source (TypeScript's `bundler`/`nodenext` resolution), so the extension is
328
+ * dropped before probing.
329
+ */
330
+ function resolveModuleFileAtPath(base) {
331
+ const ext = nodePath.extname(base);
332
+ if (ext && existsSync(base)) return base;
333
+ const stem = REWRITABLE_JS_EXTENSIONS.has(ext) ? base.slice(0, -ext.length) : base;
334
+ for (const candidateExt of MODULE_EXTENSIONS) {
335
+ const candidate = `${stem}${candidateExt}`;
336
+ if (existsSync(candidate)) return candidate;
337
+ }
338
+ for (const candidateExt of MODULE_EXTENSIONS) {
339
+ const candidate = nodePath.join(base, `index${candidateExt}`);
340
+ if (existsSync(candidate)) return candidate;
341
+ }
342
+ return null;
343
+ }
344
+ /** Resolves a `tsconfig` path alias (e.g. `@/tools/x`) to a file on disk. */
345
+ function resolveAliasImport(source, fromFilename) {
346
+ const tsconfig = loadTsconfigAliases(nodePath.dirname(fromFilename));
347
+ if (!tsconfig) return null;
348
+ const patterns = Object.entries(tsconfig.paths).sort(([a], [b]) => aliasSpecificity(b) - aliasSpecificity(a));
349
+ for (const [pattern, targets] of patterns) {
350
+ const matched = matchAliasPattern(pattern, source);
351
+ if (matched === null) continue;
352
+ for (const target of targets) {
353
+ const specifier = substituteAliasWildcard(target, matched);
354
+ const file = resolveModuleFileAtPath(nodePath.resolve(tsconfig.baseDir, specifier));
355
+ if (file) return file;
356
+ }
357
+ }
358
+ return null;
359
+ }
360
+ /** Ranks a `paths` key: an exact key outranks any wildcard; longer prefixes win. */
361
+ function aliasSpecificity(pattern) {
362
+ const star = pattern.indexOf("*");
363
+ return star === -1 ? pattern.length + 1 : star;
364
+ }
365
+ /** Substitutes the single `*` in a `paths` target with the matched text. */
366
+ function substituteAliasWildcard(target, matched) {
367
+ const star = target.indexOf("*");
368
+ if (star === -1) return target;
369
+ return target.slice(0, star) + matched + target.slice(star + 1);
370
+ }
371
+ /**
372
+ * Matches an import specifier against a `tsconfig` `paths` key. Returns the text
373
+ * captured by the key's `*` (or `""` for an exact, wildcard-free key), or `null`
374
+ * when the specifier doesn't match.
375
+ */
376
+ function matchAliasPattern(pattern, source) {
377
+ const star = pattern.indexOf("*");
378
+ if (star === -1) return pattern === source ? "" : null;
379
+ const prefix = pattern.slice(0, star);
380
+ const suffix = pattern.slice(star + 1);
381
+ if (source.length >= prefix.length + suffix.length && source.startsWith(prefix) && source.endsWith(suffix)) return source.slice(prefix.length, source.length - suffix.length);
382
+ return null;
383
+ }
384
+ /**
385
+ * Memoizes resolved aliases per start directory. The compiler runs once per
386
+ * file across a build, so without this every aliased spread re-walks and
387
+ * re-parses the same `tsconfig.json`. Process-lifetime, like
388
+ * `checkedCorePackageJsonPaths`.
389
+ */
390
+ const tsconfigAliasesByDir = /* @__PURE__ */ new Map();
391
+ /** Walks up from a directory to the nearest `tsconfig.json` that declares `paths`. */
392
+ function loadTsconfigAliases(fromDir) {
393
+ const cached = tsconfigAliasesByDir.get(fromDir);
394
+ if (cached !== void 0) return cached;
395
+ let aliases = null;
396
+ let dir = fromDir;
397
+ for (;;) {
398
+ const tsconfigPath = nodePath.join(dir, "tsconfig.json");
399
+ if (existsSync(tsconfigPath)) {
400
+ aliases = readTsconfigAliases(tsconfigPath, /* @__PURE__ */ new Set());
401
+ if (aliases) break;
402
+ }
403
+ const parent = nodePath.dirname(dir);
404
+ if (parent === dir) break;
405
+ dir = parent;
406
+ }
407
+ tsconfigAliasesByDir.set(fromDir, aliases);
408
+ return aliases;
409
+ }
410
+ /** Reads `baseUrl`/`paths` from a tsconfig, following a single `extends` chain. */
411
+ function readTsconfigAliases(tsconfigPath, seen) {
412
+ if (seen.has(tsconfigPath)) return null;
413
+ seen.add(tsconfigPath);
414
+ let config;
415
+ try {
416
+ config = parseJsonc(readFileSync(tsconfigPath, "utf8"));
417
+ } catch {
418
+ return null;
419
+ }
420
+ if (!config) return null;
421
+ const configDir = nodePath.dirname(tsconfigPath);
422
+ const { baseUrl, paths } = config.compilerOptions ?? {};
423
+ if (paths) return {
424
+ baseDir: baseUrl ? nodePath.resolve(configDir, baseUrl) : configDir,
425
+ paths
426
+ };
427
+ const extendsList = Array.isArray(config.extends) ? config.extends : config.extends ? [config.extends] : [];
428
+ for (let i = extendsList.length - 1; i >= 0; i--) {
429
+ const entry = extendsList[i];
430
+ if (typeof entry !== "string") continue;
431
+ const extended = resolveExtendedTsconfig(entry, configDir);
432
+ if (extended) {
433
+ const aliases = readTsconfigAliases(extended, seen);
434
+ if (aliases) return aliases;
435
+ }
436
+ }
437
+ return null;
438
+ }
439
+ /** Resolves a tsconfig `extends` value (relative path or installed package). */
440
+ function resolveExtendedTsconfig(extendsValue, configDir) {
441
+ if (extendsValue.startsWith(".")) {
442
+ const base = nodePath.resolve(configDir, extendsValue);
443
+ return (nodePath.extname(base) === ".json" ? [base] : [`${base}.json`, base]).find((candidate) => existsSync(candidate)) ?? null;
444
+ }
445
+ try {
446
+ return createRequire(nodePath.join(configDir, "package.json")).resolve(extendsValue.endsWith(".json") ? extendsValue : `${extendsValue}.json`);
447
+ } catch {
448
+ return null;
449
+ }
450
+ }
451
+ /** Parses JSON with `//` and block comments and trailing commas stripped (tsconfig is JSONC). */
452
+ function parseJsonc(text) {
453
+ const withoutTrailingCommas = text.replace(/"(?:[^"\\]|\\.)*"|\/\/[^\n\r]*|\/\*[\s\S]*?\*\//g, (match) => match.startsWith("\"") ? match : "").replace(/,(\s*[}\]])/g, "$1");
454
+ return JSON.parse(withoutTrailingCommas);
455
+ }
270
456
  function unwrapToToolkitCall(node) {
271
457
  return unwrapToCall(node, TOOLKIT_WRAPPER) ?? unwrapToCall(node, MCP_TOOLKIT_WRAPPER);
272
458
  }
@@ -1 +1 @@
1
- {"version":3,"file":"compile.js","names":[],"sources":["../src/compile.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport * as nodePath from \"node:path\";\nimport { parse } from \"@babel/parser\";\nimport _traverse, { type NodePath } from \"@babel/traverse\";\nimport _generate from \"@babel/generator\";\nimport * as t from \"@babel/types\";\nimport { satisfies } from \"semver\";\nimport { DIRECTIVE, type Target } from \"./constants\";\n\n// @babel/traverse and @babel/generator are CJS; their default export is the\n// function itself under some interop and `{ default }` under others.\nconst traverse = (\n typeof _traverse === \"function\" ? _traverse : (_traverse as any).default\n) as typeof _traverse;\nconst generate = (\n typeof _generate === \"function\" ? _generate : (_generate as any).default\n) as typeof _generate;\n\nexport type ToolType = \"frontend\" | \"backend\" | \"human\" | \"provider\";\n\n/** The required wrapper around a toolkit's tools (stripped at build time). */\nconst TOOLKIT_WRAPPER = \"defineToolkit\";\n/** The helper that produces MCP-only toolkit fragments. */\nconst MCP_TOOLKIT_WRAPPER = \"defineMcpToolkit\";\n/** The required wrapper around a generative-UI library (stripped at build time). */\nconst COMPONENTS_WRAPPER = \"defineGenerativeComponents\";\n/** The core package whose metadata declares supported compiler versions. */\nconst CORE_PACKAGE = \"@assistant-ui/core\";\n/** This package, checked against core's compatibility range. */\nconst COMPILER_PACKAGE = \"@assistant-ui/x-generative-compiler\";\n/** Packages that re-export core's generative markers. */\nconst DISTRIBUTION_PACKAGES = [\n CORE_PACKAGE,\n \"@assistant-ui/react\",\n \"@assistant-ui/react-native\",\n \"@assistant-ui/react-ink\",\n] as const;\n/**\n * The class whose instances expose split-by-condition tools (`present()`,\n * `promptUser()`). A toolkit entry that calls a method on one of these passes\n * through untouched — the library, not this compiler, routes its halves.\n */\nconst GENERATIVE_FACTORY = \"JSONGenerativeUI\";\n\n/** Mutable per-build outcomes the toolkit pass reports back for directive/guard injection. */\ninterface TargetFlags {\n /** A `render` survived on a client build (→ emit `\"use client\"`). */\n keptRender: boolean;\n /** A backend `execute` survived on a server build (→ emit `import \"server-only\"`). */\n keptBackendExecute: boolean;\n}\n\nexport interface CompileOptions {\n /** Which build target to emit. */\n target: Target;\n /** Source filename, used for error messages and source maps. */\n filename?: string;\n /** Emit a source map alongside the code. */\n sourceMaps?: boolean;\n /**\n * Whether the `server` target prepends `import \"server-only\"` when it keeps a\n * backend `execute`. Defaults to `true` (the Next.js/RSC convention, where the\n * guard fires via the `react-server` condition). Set `false` for bundlers\n * without a `react-server` layer (e.g. a Vite/TanStack Start `ssr` build),\n * where the split is already structural and importing `server-only` would\n * throw — see the Vite integration.\n */\n injectServerOnly?: boolean;\n}\n\nexport interface CompileResult {\n code: string;\n map?: object | null;\n}\n\n/** Thrown when a `\"use generative\"` file violates an authoring constraint. */\nexport class GenerativeCompileError extends Error {\n constructor(message: string, filename?: string) {\n super(`[assistant-ui/next]${filename ? ` ${filename}:` : \"\"} ${message}`);\n this.name = \"GenerativeCompileError\";\n }\n}\n\n/** Whether a source string opts into generative compilation via the directive. */\nexport function isGenerativeModule(code: string): boolean {\n // The directive must be a leading statement, preceded only by an optional BOM,\n // whitespace, and line/block comments. Scanned linearly — a regex over the\n // comment prefix is prone to catastrophic backtracking on crafted input.\n let i = code.charCodeAt(0) === 0xfeff ? 1 : 0;\n for (;;) {\n while (i < code.length && /\\s/.test(code[i]!)) i++;\n if (code.startsWith(\"//\", i)) {\n const nl = code.indexOf(\"\\n\", i);\n if (nl === -1) return false;\n i = nl + 1;\n } else if (code.startsWith(\"/*\", i)) {\n const end = code.indexOf(\"*/\", i + 2);\n if (end === -1) return false;\n i = end + 2;\n } else {\n break;\n }\n }\n return (\n code.startsWith(`\"${DIRECTIVE}\"`, i) || code.startsWith(`'${DIRECTIVE}'`, i)\n );\n}\n\n/**\n * Rewrites a `\"use generative\"` module for a single build target, keeping only the\n * regions that target needs and pruning the imports the dropped regions used.\n */\nexport function compileGenerative(\n code: string,\n options: CompileOptions,\n): CompileResult {\n const { target, filename } = options;\n\n const ast = parse(code, {\n sourceType: \"module\",\n plugins: [\"typescript\", \"jsx\", \"explicitResourceManagement\"],\n });\n\n if (!ast.program.directives.some((d) => d.value.value === DIRECTIVE)) {\n throw new GenerativeCompileError(\n `missing \"${DIRECTIVE}\" directive`,\n filename,\n );\n }\n\n ensureCompilerCompatibleWithCore(ast, filename);\n\n // A module may hold several `defineToolkit(...)` / `defineGenerativeComponents(...)`\n // calls anywhere (e.g. a library built inside `new JSONGenerativeUI(...)` plus\n // the toolkit that exposes it). Tools may reference a `JSONGenerativeUI`\n // instance's `present()`/`promptUser()`, which the library — not this compiler —\n // splits across builds via export conditions; collect those instance names so\n // such entries pass through.\n ensureDefaultExport(ast, filename);\n const generativeInstances = collectGenerativeInstances(ast);\n const safeToolkitSpreads = collectSafeToolkitSpreads(ast);\n\n const flags: TargetFlags = { keptRender: false, keptBackendExecute: false };\n\n traverse(ast, {\n CallExpression(path: NodePath<t.CallExpression>) {\n const callee = path.node.callee;\n const object = t.isObjectExpression(path.node.arguments[0])\n ? path.node.arguments[0]\n : null;\n\n if (t.isIdentifier(callee, { name: COMPONENTS_WRAPPER })) {\n if (!object) {\n throw new GenerativeCompileError(\n `${COMPONENTS_WRAPPER}() takes an inline object literal of components`,\n filename,\n );\n }\n compileComponents(object, target, flags, filename);\n // Unwrap the authoring helper to the bare library object so its import\n // can be pruned.\n path.replaceWith(object);\n path.skip();\n return;\n }\n\n if (t.isIdentifier(callee, { name: TOOLKIT_WRAPPER })) {\n if (!object) {\n throw new GenerativeCompileError(\n `${TOOLKIT_WRAPPER}() takes an inline object literal of tools`,\n filename,\n );\n }\n compileToolkit(\n object,\n target,\n generativeInstances,\n safeToolkitSpreads,\n flags,\n filename,\n );\n path.replaceWith(object);\n path.skip();\n }\n },\n });\n\n const { keptRender, keptBackendExecute } = flags;\n\n pruneUnused(ast);\n\n // Replace the module directives with the target-appropriate one.\n ast.program.directives = ast.program.directives.filter(\n (d) => d.value.value !== DIRECTIVE && d.value.value !== \"use client\",\n );\n if (target === \"client\" && keptRender) {\n ast.program.directives.unshift(\n t.directive(t.directiveLiteral(\"use client\")),\n );\n }\n if (\n target === \"server\" &&\n keptBackendExecute &&\n (options.injectServerOnly ?? true)\n ) {\n ast.program.body.unshift(\n t.importDeclaration([], t.stringLiteral(\"server-only\")),\n );\n }\n\n const result = generate(\n ast,\n {\n sourceMaps: options.sourceMaps ?? false,\n filename,\n jsescOption: { minimal: true },\n },\n code,\n );\n\n return { code: result.code, map: result.map };\n}\n\ninterface PackageJson {\n name?: string;\n version?: string;\n optionalDevDependencies?: Record<string, string>;\n}\n\nconst checkedCorePackageJsonPaths = new Set<string>();\nlet compilerPackageVersion: string | undefined;\n\nfunction ensureCompilerCompatibleWithCore(\n ast: t.File,\n filename: string | undefined,\n): void {\n const corePackageJsonPath = resolveCorePackageJson(ast, filename);\n if (\n !corePackageJsonPath ||\n checkedCorePackageJsonPaths.has(corePackageJsonPath)\n ) {\n return;\n }\n\n const corePackageJson = readPackageJson(corePackageJsonPath);\n const range = corePackageJson?.optionalDevDependencies?.[COMPILER_PACKAGE];\n if (!range) {\n checkedCorePackageJsonPaths.add(corePackageJsonPath);\n return;\n }\n\n const compilerVersion = getCompilerPackageVersion();\n let compatible = false;\n try {\n compatible = satisfies(compilerVersion, range, {\n includePrerelease: true,\n });\n } catch {\n throw new GenerativeCompileError(\n `${CORE_PACKAGE}@${corePackageJson.version ?? \"unknown\"} declares an ` +\n `invalid optionalDevDependencies range for ${COMPILER_PACKAGE}: ` +\n JSON.stringify(range),\n filename,\n );\n }\n\n if (!compatible) {\n throw new GenerativeCompileError(\n `${CORE_PACKAGE}@${corePackageJson.version ?? \"unknown\"} requires ` +\n `${COMPILER_PACKAGE} ${range}, but the current compiler is ` +\n `${compilerVersion}. Update @assistant-ui/next or @assistant-ui/vite ` +\n \"so their compiler satisfies the core package's \" +\n \"optionalDevDependencies range.\",\n filename,\n );\n }\n\n checkedCorePackageJsonPaths.add(corePackageJsonPath);\n}\n\nfunction getCompilerPackageVersion(): string {\n if (compilerPackageVersion) return compilerPackageVersion;\n\n const packageJsonPath = findPackageJson(import.meta.url, COMPILER_PACKAGE);\n const packageJson = packageJsonPath ? readPackageJson(packageJsonPath) : null;\n if (!packageJson?.version) {\n throw new GenerativeCompileError(\n `could not determine ${COMPILER_PACKAGE}'s package version`,\n );\n }\n compilerPackageVersion = packageJson.version;\n return compilerPackageVersion;\n}\n\nfunction resolveCorePackageJson(\n ast: t.File,\n filename: string | undefined,\n): string | null {\n for (const packageName of collectImportedDistributionPackages(ast)) {\n const packageJsonPath = resolvePackageJson(packageName, filename);\n if (!packageJsonPath) continue;\n if (packageName === CORE_PACKAGE) return packageJsonPath;\n\n const corePackageJsonPath = resolvePackageJson(\n CORE_PACKAGE,\n packageJsonPath,\n );\n if (corePackageJsonPath) return corePackageJsonPath;\n }\n\n return null;\n}\n\nfunction collectImportedDistributionPackages(ast: t.File): Set<string> {\n const packages = new Set<string>();\n\n for (const statement of ast.program.body) {\n const source =\n (t.isImportDeclaration(statement) ||\n t.isExportNamedDeclaration(statement) ||\n t.isExportAllDeclaration(statement)) &&\n statement.source\n ? statement.source.value\n : null;\n if (!source) continue;\n\n const packageName = packageNameFromSpecifier(source);\n if (packageName) packages.add(packageName);\n }\n\n return packages;\n}\n\nfunction packageNameFromSpecifier(specifier: string): string | null {\n for (const packageName of DISTRIBUTION_PACKAGES) {\n if (specifier === packageName || specifier.startsWith(`${packageName}/`)) {\n return packageName;\n }\n }\n\n return null;\n}\n\nfunction resolvePackageJson(\n packageName: string,\n filename: string | undefined,\n): string | null {\n const requirePath = normalizeRequirePath(filename);\n const require = createRequire(requirePath);\n\n try {\n return findPackageJson(require.resolve(packageName), packageName);\n } catch {\n return findPackageJsonFromNodeModules(packageName, requirePath);\n }\n}\n\nfunction normalizeRequirePath(filename: string | undefined): string {\n if (filename) {\n const cleanFilename = filename.split(/[?#]/, 1)[0]!;\n if (nodePath.isAbsolute(cleanFilename)) return cleanFilename;\n }\n return import.meta.url;\n}\n\nfunction findPackageJson(\n fromPathOrUrl: string,\n packageName: string,\n): string | null {\n let current = nodePath.dirname(\n fromPathOrUrl.startsWith(\"file:\")\n ? new URL(fromPathOrUrl).pathname\n : nodePath.resolve(fromPathOrUrl),\n );\n\n for (;;) {\n const packageJsonPath = nodePath.join(current, \"package.json\");\n const packageJson = readPackageJson(packageJsonPath);\n if (packageJson?.name === packageName) return packageJsonPath;\n\n const parent = nodePath.dirname(current);\n if (parent === current) return null;\n current = parent;\n }\n}\n\nfunction findPackageJsonFromNodeModules(\n packageName: string,\n fromPathOrUrl: string,\n): string | null {\n const parts = packageName.split(\"/\");\n let current = nodePath.dirname(\n fromPathOrUrl.startsWith(\"file:\")\n ? new URL(fromPathOrUrl).pathname\n : nodePath.resolve(fromPathOrUrl),\n );\n\n for (;;) {\n const packageJsonPath = nodePath.join(\n current,\n \"node_modules\",\n ...parts,\n \"package.json\",\n );\n const packageJson = readPackageJson(packageJsonPath);\n if (packageJson?.name === packageName) return packageJsonPath;\n\n const parent = nodePath.dirname(current);\n if (parent === current) return null;\n current = parent;\n }\n}\n\nfunction readPackageJson(packageJsonPath: string): PackageJson | null {\n if (!existsSync(packageJsonPath)) return null;\n try {\n return JSON.parse(readFileSync(packageJsonPath, \"utf8\")) as PackageJson;\n } catch (error) {\n throw new GenerativeCompileError(\n `could not parse package metadata at ${packageJsonPath}: ${\n error instanceof Error ? error.message : String(error)\n }`,\n );\n }\n}\n\n/**\n * Errors unless the module's default export is the toolkit — a `defineToolkit(...)`\n * call (through `satisfies`/`as`/parens). This is the security boundary: the\n * default export is what the runtime registers, so it must be wrapped (and thus\n * split). A bare `export default { ... }` would ship a backend `execute` to the\n * client even if some *other* `defineToolkit(...)` exists elsewhere in the file.\n */\nfunction ensureDefaultExport(ast: t.File, filename: string | undefined): void {\n const def = ast.program.body.find(\n (stmt): stmt is t.ExportDefaultDeclaration =>\n t.isExportDefaultDeclaration(stmt),\n );\n if (!def) {\n throw new GenerativeCompileError(\"missing a default export\", filename);\n }\n if (!unwrapToCall(def.declaration, TOOLKIT_WRAPPER)) {\n throw new GenerativeCompileError(\n `the default export must be ${TOOLKIT_WRAPPER}({ ... }) (imported from ` +\n '\"@assistant-ui/react\"); wrapping is required so a backend `execute` ' +\n \"can't be authored in a way that reaches the client\",\n filename,\n );\n }\n}\n\n/**\n * Unwraps a node through `satisfies`/`as`/parens to a call of the named function,\n * or returns `null`.\n */\nfunction unwrapToCall(node: t.Node, name: string): t.CallExpression | null {\n if (t.isTSSatisfiesExpression(node) || t.isTSAsExpression(node)) {\n return unwrapToCall(node.expression, name);\n }\n if (t.isParenthesizedExpression(node)) {\n return unwrapToCall(node.expression, name);\n }\n if (t.isCallExpression(node) && t.isIdentifier(node.callee, { name })) {\n return node;\n }\n return null;\n}\n\n/**\n * Collects the names bound to `new JSONGenerativeUI(...)` (e.g.\n * `const generative = new JSONGenerativeUI({ library })`). A toolkit entry that\n * calls a method on one of these is a generative tool whose halves the library\n * routes by export condition, so it passes through the toolkit pass untouched.\n */\nfunction collectGenerativeInstances(ast: t.File): Set<string> {\n const names = new Set<string>();\n for (const statement of ast.program.body) {\n if (!t.isVariableDeclaration(statement)) continue;\n for (const declaration of statement.declarations) {\n const { id, init } = declaration;\n if (\n t.isIdentifier(id) &&\n t.isNewExpression(init) &&\n t.isIdentifier(init.callee, { name: GENERATIVE_FACTORY })\n ) {\n names.add(id.name);\n }\n }\n }\n return names;\n}\n\n/**\n * Local toolkit variables whose initializer is visible to this compiler pass\n * are safe to spread. `defineToolkit(...)` initializers are compiled in-place\n * before a later spread reads them; `defineMcpToolkit(...)` entries cannot\n * contain executable code.\n */\nfunction collectSafeToolkitSpreads(ast: t.File): Set<string> {\n const names = new Set<string>();\n for (const statement of ast.program.body) {\n if (!t.isVariableDeclaration(statement)) continue;\n for (const declaration of statement.declarations) {\n const { id, init } = declaration;\n if (!t.isIdentifier(id) || !init) continue;\n if (unwrapToToolkitCall(init)) names.add(id.name);\n }\n }\n return names;\n}\n\nfunction unwrapToToolkitCall(node: t.Node): t.CallExpression | null {\n return (\n unwrapToCall(node, TOOLKIT_WRAPPER) ??\n unwrapToCall(node, MCP_TOOLKIT_WRAPPER)\n );\n}\n\nfunction isSafeToolkitSpread(\n entry: t.SpreadElement,\n safeToolkitSpreads: Set<string>,\n): boolean {\n if (t.isIdentifier(entry.argument)) {\n return safeToolkitSpreads.has(entry.argument.name);\n }\n\n const directMcpToolkit = unwrapToCall(entry.argument, MCP_TOOLKIT_WRAPPER);\n return (\n !!directMcpToolkit && t.isObjectExpression(directMcpToolkit.arguments[0])\n );\n}\n\n/** The `JSONGenerativeUI` methods that produce a split-by-condition tool. */\nconst GENERATIVE_TOOL_METHODS = new Set([\"present\", \"promptUser\"]);\n\n/**\n * Whether a toolkit entry's value is a call to a tool-producing method on a\n * collected `JSONGenerativeUI` instance (`generative.present()`), which passes\n * through. The method name is checked too, so a typo like `generative.presnt()`\n * is a compile error here rather than a pass-through that fails at runtime.\n */\nfunction isGenerativeToolEntry(value: t.Node, instances: Set<string>): boolean {\n return (\n t.isCallExpression(value) &&\n t.isMemberExpression(value.callee) &&\n !value.callee.computed &&\n t.isIdentifier(value.callee.object) &&\n instances.has(value.callee.object.name) &&\n t.isIdentifier(value.callee.property) &&\n GENERATIVE_TOOL_METHODS.has(value.callee.property.name)\n );\n}\n\n/**\n * Splits a `defineGenerativeComponents({ ... })` library for a build target:\n * a component's `render` (and the client imports it alone uses) is dropped on\n * the server; `properties`/`description` stay on both, since they drive the tool\n * schema either way. Mutates the object in place.\n */\nfunction compileComponents(\n object: t.ObjectExpression,\n target: Target,\n flags: TargetFlags,\n filename: string | undefined,\n): void {\n for (const entry of object.properties) {\n const value = entryValue(entry);\n if (!value) {\n throw new GenerativeCompileError(\n `each component in ${COMPONENTS_WRAPPER}() must be an inline object ` +\n \"literal (`name: { ... }`) so its `render` can be routed\",\n filename,\n );\n }\n if (!findMember(value, \"render\")) continue;\n // The client keeps `render` (and so needs the module marked `\"use client\"`);\n // the server drops it, since only the schema reaches the model there.\n if (target === \"client\") flags.keptRender = true;\n else removeMember(value, \"render\");\n }\n}\n\n/**\n * Splits a `defineToolkit({ ... })` for a build target. Each inline tool is\n * routed by inferred type (see the per-entry logic); a generative entry like\n * `generative.present()` passes through, the library having already split it.\n * Mutates the object in place and records outcomes in {@link TargetFlags}.\n */\nfunction compileToolkit(\n object: t.ObjectExpression,\n target: Target,\n instances: Set<string>,\n safeToolkitSpreads: Set<string>,\n flags: TargetFlags,\n filename: string | undefined,\n): void {\n const nextProperties: t.ObjectExpression[\"properties\"] = [];\n\n for (const entry of object.properties) {\n const value = entryValue(entry);\n if (!value) {\n if (\n t.isSpreadElement(entry) &&\n isSafeToolkitSpread(entry, safeToolkitSpreads)\n ) {\n nextProperties.push(entry);\n continue;\n }\n // A generative tool (`generative.present()`) is split by the library's\n // export conditions, so it is safe to keep verbatim. Anything else — a\n // method or opaque call like `makeTool()` — can't be analyzed, so its\n // `execute` could reach the client unstripped.\n const raw = entryRawValue(entry);\n if (raw && isGenerativeToolEntry(raw, instances)) {\n nextProperties.push(entry);\n continue;\n }\n throw new GenerativeCompileError(\n \"each tool must be an inline object literal (`name: { ... }`) or a \" +\n \"compiler-visible toolkit spread / generative tool (e.g. \" +\n \"`...defineMcpToolkit(...)`, `...baseToolkit`, or \" +\n \"`generative.present()`) so its `execute` can be routed\",\n filename,\n );\n }\n\n // Nature is inferred from `execute` (see inferToolType), not an authored\n // `type`. The resolved type is written back below so the runtime keeps it.\n const execute = findMember(value, \"execute\");\n const isStub = execute ? executeIsStubTool(execute) : false;\n const isExternal = execute ? executeIsExternalTool(execute) : false;\n const type = inferToolType(value, filename);\n const hasRender = !!findMember(value, \"render\");\n const hasRenderText = !!findMember(value, \"renderText\");\n\n if (type === \"frontend\" && !hasRender && !hasRenderText) {\n throw new GenerativeCompileError(\n \"a frontend tool must declare a `render` or `renderText` \" +\n \"(it has no server execute to show otherwise)\",\n filename,\n );\n }\n\n if (type === \"human\" && !hasRender) {\n throw new GenerativeCompileError(\n \"a human tool must declare a `render` so it can collect input\",\n filename,\n );\n }\n\n if (type === \"provider\" && execute) {\n applyProviderToolConfig(value, execute, filename);\n }\n\n if (isExternal) {\n if (!hasRender && !hasRenderText) {\n throw new GenerativeCompileError(\n \"an external tool must declare a `render` or `renderText` \" +\n \"(assistant-ui only renders calls for tools defined elsewhere)\",\n filename,\n );\n }\n if (target === \"server\") continue;\n stripExternalToolMetadata(value);\n }\n\n if (target === \"client\") {\n // A non-stub frontend execute stays (its `\"use client\"` marker is no longer needed\n // once the module is client); backend, sentinel, and stub executes are dropped.\n if (execute && type === \"frontend\" && !isStub) stripUseClient(execute);\n else if (execute) removeMember(value, \"execute\");\n if (hasRender || hasRenderText) flags.keptRender = true;\n } else {\n // server: render is never needed; only a non-external backend execute survives.\n if (hasRender) removeMember(value, \"render\");\n if (hasRenderText) removeMember(value, \"renderText\");\n if (execute) {\n if (type === \"backend\" && !isExternal) flags.keptBackendExecute = true;\n else removeMember(value, \"execute\");\n }\n }\n\n setToolType(value, type);\n setBackendDefault(value, target, type);\n nextProperties.push(entry);\n }\n\n object.properties = nextProperties;\n}\n\nfunction applyProviderToolConfig(\n object: t.ObjectExpression,\n execute: t.ObjectProperty | t.ObjectMethod,\n filename: string | undefined,\n): void {\n if (\n !t.isObjectProperty(execute) ||\n !t.isCallExpression(execute.value) ||\n execute.value.arguments.length !== 1 ||\n !t.isObjectExpression(execute.value.arguments[0])\n ) {\n throw new GenerativeCompileError(\n \"`providerTool(...)` must receive an inline object literal\",\n filename,\n );\n }\n\n const existingNames = new Set(\n object.properties.flatMap((prop) => {\n if (!t.isObjectProperty(prop) && !t.isObjectMethod(prop)) return [];\n const name = memberName(prop.key, prop.computed);\n return name ? [name] : [];\n }),\n );\n const configNames = new Set<string>();\n\n for (const prop of execute.value.arguments[0].properties) {\n if (!t.isObjectProperty(prop)) {\n throw new GenerativeCompileError(\n \"`providerTool(...)` config can only contain object properties\",\n filename,\n );\n }\n const name = memberName(prop.key, prop.computed);\n if (!name) {\n throw new GenerativeCompileError(\n \"`providerTool(...)` config can only contain static property names\",\n filename,\n );\n }\n if (\n t.isFunctionExpression(prop.value) ||\n t.isArrowFunctionExpression(prop.value)\n ) {\n throw new GenerativeCompileError(\n \"`providerTool(...)` config cannot contain function-valued properties\",\n filename,\n );\n }\n if (existingNames.has(name) || configNames.has(name)) {\n throw new GenerativeCompileError(\n \"`providerTool(...)` config cannot duplicate tool properties\",\n filename,\n );\n }\n configNames.add(name);\n object.properties.push(prop);\n }\n}\n\ntype Entry = t.ObjectExpression[\"properties\"][number];\n\n/** The raw AST value of an entry (any expression), or null for spreads/methods. */\nfunction entryRawValue(entry: Entry): t.Expression | null {\n if (t.isObjectProperty(entry) && t.isExpression(entry.value)) {\n return entry.value;\n }\n return null;\n}\n\nfunction entryValue(entry: Entry): t.ObjectExpression | null {\n if (t.isObjectProperty(entry) && t.isObjectExpression(entry.value)) {\n return entry.value;\n }\n return null;\n}\n\n/** A member of an entry object: `render`/`execute`/`type`, as property or method. */\nfunction findMember(\n object: t.ObjectExpression,\n name: string,\n): t.ObjectProperty | t.ObjectMethod | undefined {\n return object.properties.find(\n (p): p is t.ObjectProperty | t.ObjectMethod =>\n (t.isObjectProperty(p) || t.isObjectMethod(p)) &&\n memberName(p.key, p.computed) === name,\n );\n}\n\nfunction removeMember(object: t.ObjectExpression, name: string): void {\n object.properties = object.properties.filter(\n (p) =>\n !(\n (t.isObjectProperty(p) || t.isObjectMethod(p)) &&\n memberName(p.key, p.computed) === name\n ),\n );\n}\n\n/** The `BlockStatement` body of an `execute` member, if it has one. */\nfunction executeBody(\n member: t.ObjectProperty | t.ObjectMethod,\n): t.BlockStatement | undefined {\n if (t.isObjectMethod(member)) return member.body;\n const value = member.value;\n if (\n (t.isArrowFunctionExpression(value) || t.isFunctionExpression(value)) &&\n t.isBlockStatement(value.body)\n ) {\n return value.body;\n }\n return undefined;\n}\n\n/** Whether an `execute` opts into the client via a leading `\"use client\"`. */\nfunction executeIsClient(member: t.ObjectProperty | t.ObjectMethod): boolean {\n return !!executeBody(member)?.directives.some(\n (d) => d.value.value === \"use client\",\n );\n}\n\nfunction executeIsSentinel(\n member: t.ObjectProperty | t.ObjectMethod,\n name: string,\n): boolean {\n return (\n t.isObjectProperty(member) &&\n t.isCallExpression(member.value) &&\n t.isIdentifier(member.value.callee, { name })\n );\n}\n\n/** Whether an `execute` is the human-in-the-loop sentinel. */\nfunction executeIsHumanTool(\n member: t.ObjectProperty | t.ObjectMethod,\n): boolean {\n return (\n executeIsSentinel(member, \"humanTool\") ||\n executeIsSentinel(member, \"hitlTool\") ||\n executeIsSentinel(member, \"hitl\")\n );\n}\n\n/** Whether an `execute` is the provider-tool sentinel. */\nfunction executeIsProviderTool(\n member: t.ObjectProperty | t.ObjectMethod,\n): boolean {\n return executeIsSentinel(member, \"providerTool\");\n}\n\n/** Whether an `execute` is the local override sentinel. */\nfunction executeIsStubTool(member: t.ObjectProperty | t.ObjectMethod): boolean {\n return executeIsSentinel(member, \"stubTool\");\n}\n\n/** Whether an `execute` is the externally-defined backend tool sentinel. */\nfunction executeIsExternalTool(\n member: t.ObjectProperty | t.ObjectMethod,\n): boolean {\n return executeIsSentinel(member, \"externalTool\");\n}\n\n/** Drops the `\"use client\"` directive from an `execute` body (kept frontend). */\nfunction stripUseClient(member: t.ObjectProperty | t.ObjectMethod): void {\n const body = executeBody(member);\n if (body) {\n body.directives = body.directives.filter(\n (d) => d.value.value !== \"use client\",\n );\n }\n}\n\n/**\n * The tool's nature, inferred from its (mandatory) `execute` rather than an\n * authored `type`: `humanTool()` → `human`; `providerTool(...)` → `provider`;\n * `stubTool()` → `frontend`; `externalTool()` → `backend`; `\"use client\"` →\n * `frontend`; otherwise `backend`.\n * The loader writes the result back as a `type` field (see {@link setToolType})\n * so the runtime keeps it.\n */\nfunction inferToolType(\n object: t.ObjectExpression,\n filename: string | undefined,\n): ToolType {\n const execute = findMember(object, \"execute\");\n if (!execute) {\n throw new GenerativeCompileError(\n \"every tool must declare an `execute`; use `humanTool()` for a \" +\n \"human-in-the-loop tool\",\n filename,\n );\n }\n if (executeIsHumanTool(execute)) return \"human\";\n if (executeIsProviderTool(execute)) return \"provider\";\n if (executeIsStubTool(execute)) return \"frontend\";\n if (executeIsExternalTool(execute)) return \"backend\";\n return executeIsClient(execute) ? \"frontend\" : \"backend\";\n}\n\nfunction stripExternalToolMetadata(object: t.ObjectExpression): void {\n // Mirror BackendTool's forbidden metadata fields: execute is stripped by the\n // main routing loop, while streamCall is also removed because there is no\n // assistant-ui executor to stream from.\n removeMember(object, \"description\");\n removeMember(object, \"parameters\");\n removeMember(object, \"disabled\");\n removeMember(object, \"toModelOutput\");\n removeMember(object, \"experimental_onSchemaValidationError\");\n removeMember(object, \"providerOptions\");\n removeMember(object, \"streamCall\");\n}\n\n/** Writes the resolved `type` back onto the tool object (replacing any author's). */\nfunction setToolType(object: t.ObjectExpression, type: ToolType): void {\n removeMember(object, \"type\");\n // Append (not prepend) so the inferred type wins over any earlier spread.\n object.properties.push(\n t.objectProperty(t.identifier(\"type\"), t.stringLiteral(type)),\n );\n}\n\nfunction setBackendDefault(\n object: t.ObjectExpression,\n target: Target,\n type: ToolType,\n): void {\n // Always strip any hand-authored marker first; only re-add it for client\n // frontend/human tools whose schema is already known by the backend.\n removeMember(object, \"unstable_backendDefault\");\n if (target !== \"client\" || (type !== \"frontend\" && type !== \"human\")) return;\n\n object.properties.push(\n t.objectProperty(\n t.identifier(\"unstable_backendDefault\"),\n t.objectExpression([\n t.objectProperty(t.identifier(\"parameters\"), t.booleanLiteral(true)),\n ]),\n ),\n );\n}\n\nfunction memberName(\n key: t.Node,\n computed: boolean | undefined,\n): string | undefined {\n if (computed) return undefined;\n if (t.isIdentifier(key)) return key.name;\n if (t.isStringLiteral(key)) return key.value;\n return undefined;\n}\n\n/**\n * Removes declarations and import specifiers left unreferenced after region\n * removal, to a fixpoint (a dropped helper frees what it used). Keeps exports,\n * side-effect imports, and possibly-side-effectful initializers.\n */\nfunction pruneUnused(ast: t.File): void {\n const hadSpecifiers = new WeakSet<t.ImportDeclaration>();\n for (const stmt of ast.program.body) {\n if (t.isImportDeclaration(stmt) && stmt.specifiers.length > 0) {\n hadSpecifiers.add(stmt);\n }\n }\n\n let removedSomething = true;\n while (removedSomething) {\n removedSomething = false;\n traverse(ast, {\n Program(path: NodePath<t.Program>) {\n path.scope.crawl();\n const isUnused = (name: string): boolean => {\n const binding = path.scope.getBinding(name);\n return !!binding && !binding.referenced;\n };\n\n path.node.body = path.node.body.filter((stmt) => {\n if (\n (t.isFunctionDeclaration(stmt) || t.isClassDeclaration(stmt)) &&\n stmt.id &&\n isUnused(stmt.id.name)\n ) {\n removedSomething = true;\n return false;\n }\n if (t.isVariableDeclaration(stmt)) {\n stmt.declarations = stmt.declarations.filter((decl) => {\n // Handles destructuring too: drop the declarator only when *every*\n // bound name is unused (else a `const { a } = server` survives and\n // keeps a server import in the client graph). Restricted to plain\n // patterns so a default/computed-key side effect isn't dropped.\n const names = Object.keys(t.getBindingIdentifiers(decl.id));\n if (\n names.length > 0 &&\n isPlainPattern(decl.id) &&\n isRemovableInit(decl.init) &&\n names.every(isUnused)\n ) {\n removedSomething = true;\n return false;\n }\n return true;\n });\n if (stmt.declarations.length === 0) return false;\n }\n return true;\n });\n path.stop();\n },\n });\n }\n\n traverse(ast, {\n Program(path: NodePath<t.Program>) {\n path.scope.crawl();\n for (const stmt of path.node.body) {\n if (!t.isImportDeclaration(stmt)) continue;\n stmt.specifiers = stmt.specifiers.filter((spec) => {\n const binding = path.scope.getBinding(spec.local.name);\n return binding ? binding.referenced : true;\n });\n }\n path.node.body = path.node.body.filter(\n (stmt) =>\n !(\n t.isImportDeclaration(stmt) &&\n stmt.specifiers.length === 0 &&\n hadSpecifiers.has(stmt)\n ),\n );\n path.stop();\n },\n });\n}\n\n/**\n * Whether a binding pattern is side-effect-free to drop: a plain identifier, or\n * an object/array pattern of plain bindings — no default values\n * (`{ a = expr }`) or computed keys (`{ [expr]: a }`), which would evaluate (and\n * thus could have side effects) at destructuring time.\n */\nfunction isPlainPattern(node: t.Node): boolean {\n if (t.isIdentifier(node)) return true;\n if (t.isObjectPattern(node)) {\n return node.properties.every((p) =>\n t.isRestElement(p)\n ? isPlainPattern(p.argument)\n : !p.computed && isPlainPattern(p.value),\n );\n }\n if (t.isArrayPattern(node)) {\n return node.elements.every((el) => el == null || isPlainPattern(el));\n }\n return false; // AssignmentPattern (default), member expr, etc.\n}\n\n/** Whether a variable initializer is safe to drop (no observable side effects). */\nfunction isRemovableInit(node: t.Expression | null | undefined): boolean {\n if (node == null) return true;\n if (t.isTSAsExpression(node) || t.isTSSatisfiesExpression(node)) {\n return isRemovableInit(node.expression);\n }\n // Containers are removable only if every element is — a nested call (e.g.\n // `[track()]`) has an observable side effect that dropping would lose.\n if (t.isArrayExpression(node)) {\n return node.elements.every(\n (el) => el == null || (t.isExpression(el) && isRemovableInit(el)),\n );\n }\n if (t.isObjectExpression(node)) {\n return node.properties.every(\n (p) =>\n t.isObjectProperty(p) &&\n !p.computed &&\n t.isExpression(p.value) &&\n isRemovableInit(p.value),\n );\n }\n if (t.isTemplateLiteral(node)) {\n return node.expressions.every(\n (e) => t.isExpression(e) && isRemovableInit(e),\n );\n }\n return (\n t.isArrowFunctionExpression(node) ||\n t.isFunctionExpression(node) ||\n t.isClassExpression(node) ||\n t.isIdentifier(node) ||\n // non-computed only — `obj[fn()]` could hide a side-effectful key\n (t.isMemberExpression(node) && !node.computed) ||\n t.isJSXElement(node) ||\n t.isJSXFragment(node) ||\n t.isLiteral(node)\n );\n}\n"],"mappings":";;;;;;;;;;AAYA,MAAM,WACJ,OAAO,cAAc,aAAa,YAAa,UAAkB;AAEnE,MAAM,WACJ,OAAO,cAAc,aAAa,YAAa,UAAkB;;AAMnE,MAAM,kBAAkB;;AAExB,MAAM,sBAAsB;;AAE5B,MAAM,qBAAqB;;AAE3B,MAAM,eAAe;;AAErB,MAAM,mBAAmB;;AAEzB,MAAM,wBAAwB;CAC5B;CACA;CACA;CACA;AACF;;;;;;AAMA,MAAM,qBAAqB;;AAkC3B,IAAa,yBAAb,cAA4C,MAAM;CAChD,YAAY,SAAiB,UAAmB;EAC9C,MAAM,sBAAsB,WAAW,IAAI,SAAS,KAAK,GAAG,GAAG,SAAS;EACxE,KAAK,OAAO;CACd;AACF;;AAGA,SAAgB,mBAAmB,MAAuB;CAIxD,IAAI,IAAI,KAAK,WAAW,CAAC,MAAM,QAAS,IAAI;CAC5C,SAAS;EACP,OAAO,IAAI,KAAK,UAAU,KAAK,KAAK,KAAK,EAAG,GAAG;EAC/C,IAAI,KAAK,WAAW,MAAM,CAAC,GAAG;GAC5B,MAAM,KAAK,KAAK,QAAQ,MAAM,CAAC;GAC/B,IAAI,OAAO,IAAI,OAAO;GACtB,IAAI,KAAK;EACX,OAAO,IAAI,KAAK,WAAW,MAAM,CAAC,GAAG;GACnC,MAAM,MAAM,KAAK,QAAQ,MAAM,IAAI,CAAC;GACpC,IAAI,QAAQ,IAAI,OAAO;GACvB,IAAI,MAAM;EACZ,OACE;CAEJ;CACA,OACE,KAAK,WAAW,oBAAkB,CAAC,KAAK,KAAK,WAAW,oBAAkB,CAAC;AAE/E;;;;;AAMA,SAAgB,kBACd,MACA,SACe;CACf,MAAM,EAAE,QAAQ,aAAa;CAE7B,MAAM,MAAM,MAAM,MAAM;EACtB,YAAY;EACZ,SAAS;GAAC;GAAc;GAAO;EAA4B;CAC7D,CAAC;CAED,IAAI,CAAC,IAAI,QAAQ,WAAW,MAAM,MAAM,EAAE,MAAM,UAAA,gBAAmB,GACjE,MAAM,IAAI,uBACR,YAAY,UAAU,cACtB,QACF;CAGF,iCAAiC,KAAK,QAAQ;CAQ9C,oBAAoB,KAAK,QAAQ;CACjC,MAAM,sBAAsB,2BAA2B,GAAG;CAC1D,MAAM,qBAAqB,0BAA0B,GAAG;CAExD,MAAM,QAAqB;EAAE,YAAY;EAAO,oBAAoB;CAAM;CAE1E,SAAS,KAAK,EACZ,eAAe,MAAkC;EAC/C,MAAM,SAAS,KAAK,KAAK;EACzB,MAAM,SAAS,EAAE,mBAAmB,KAAK,KAAK,UAAU,EAAE,IACtD,KAAK,KAAK,UAAU,KACpB;EAEJ,IAAI,EAAE,aAAa,QAAQ,EAAE,MAAM,mBAAmB,CAAC,GAAG;GACxD,IAAI,CAAC,QACH,MAAM,IAAI,uBACR,GAAG,mBAAmB,kDACtB,QACF;GAEF,kBAAkB,QAAQ,QAAQ,OAAO,QAAQ;GAGjD,KAAK,YAAY,MAAM;GACvB,KAAK,KAAK;GACV;EACF;EAEA,IAAI,EAAE,aAAa,QAAQ,EAAE,MAAM,gBAAgB,CAAC,GAAG;GACrD,IAAI,CAAC,QACH,MAAM,IAAI,uBACR,GAAG,gBAAgB,6CACnB,QACF;GAEF,eACE,QACA,QACA,qBACA,oBACA,OACA,QACF;GACA,KAAK,YAAY,MAAM;GACvB,KAAK,KAAK;EACZ;CACF,EACF,CAAC;CAED,MAAM,EAAE,YAAY,uBAAuB;CAE3C,YAAY,GAAG;CAGf,IAAI,QAAQ,aAAa,IAAI,QAAQ,WAAW,QAC7C,MAAM,EAAE,MAAM,UAAA,oBAAuB,EAAE,MAAM,UAAU,YAC1D;CACA,IAAI,WAAW,YAAY,YACzB,IAAI,QAAQ,WAAW,QACrB,EAAE,UAAU,EAAE,iBAAiB,YAAY,CAAC,CAC9C;CAEF,IACE,WAAW,YACX,uBACC,QAAQ,oBAAoB,OAE7B,IAAI,QAAQ,KAAK,QACf,EAAE,kBAAkB,CAAC,GAAG,EAAE,cAAc,aAAa,CAAC,CACxD;CAGF,MAAM,SAAS,SACb,KACA;EACE,YAAY,QAAQ,cAAc;EAClC;EACA,aAAa,EAAE,SAAS,KAAK;CAC/B,GACA,IACF;CAEA,OAAO;EAAE,MAAM,OAAO;EAAM,KAAK,OAAO;CAAI;AAC9C;AAQA,MAAM,8CAA8B,IAAI,IAAY;AACpD,IAAI;AAEJ,SAAS,iCACP,KACA,UACM;CACN,MAAM,sBAAsB,uBAAuB,KAAK,QAAQ;CAChE,IACE,CAAC,uBACD,4BAA4B,IAAI,mBAAmB,GAEnD;CAGF,MAAM,kBAAkB,gBAAgB,mBAAmB;CAC3D,MAAM,QAAQ,iBAAiB,0BAA0B;CACzD,IAAI,CAAC,OAAO;EACV,4BAA4B,IAAI,mBAAmB;EACnD;CACF;CAEA,MAAM,kBAAkB,0BAA0B;CAClD,IAAI,aAAa;CACjB,IAAI;EACF,aAAa,UAAU,iBAAiB,OAAO,EAC7C,mBAAmB,KACrB,CAAC;CACH,QAAQ;EACN,MAAM,IAAI,uBACR,GAAG,aAAa,GAAG,gBAAgB,WAAW,UAAU,yDACT,iBAAiB,MAC9D,KAAK,UAAU,KAAK,GACtB,QACF;CACF;CAEA,IAAI,CAAC,YACH,MAAM,IAAI,uBACR,GAAG,aAAa,GAAG,gBAAgB,WAAW,UAAU,YACnD,iBAAiB,GAAG,MAAM,gCAC1B,gBAAgB,kIAGrB,QACF;CAGF,4BAA4B,IAAI,mBAAmB;AACrD;AAEA,SAAS,4BAAoC;CAC3C,IAAI,wBAAwB,OAAO;CAEnC,MAAM,kBAAkB,gBAAgB,OAAO,KAAK,KAAK,gBAAgB;CACzE,MAAM,cAAc,kBAAkB,gBAAgB,eAAe,IAAI;CACzE,IAAI,CAAC,aAAa,SAChB,MAAM,IAAI,uBACR,uBAAuB,iBAAiB,mBAC1C;CAEF,yBAAyB,YAAY;CACrC,OAAO;AACT;AAEA,SAAS,uBACP,KACA,UACe;CACf,KAAK,MAAM,eAAe,oCAAoC,GAAG,GAAG;EAClE,MAAM,kBAAkB,mBAAmB,aAAa,QAAQ;EAChE,IAAI,CAAC,iBAAiB;EACtB,IAAI,gBAAgB,cAAc,OAAO;EAEzC,MAAM,sBAAsB,mBAC1B,cACA,eACF;EACA,IAAI,qBAAqB,OAAO;CAClC;CAEA,OAAO;AACT;AAEA,SAAS,oCAAoC,KAA0B;CACrE,MAAM,2BAAW,IAAI,IAAY;CAEjC,KAAK,MAAM,aAAa,IAAI,QAAQ,MAAM;EACxC,MAAM,UACH,EAAE,oBAAoB,SAAS,KAC9B,EAAE,yBAAyB,SAAS,KACpC,EAAE,uBAAuB,SAAS,MACpC,UAAU,SACN,UAAU,OAAO,QACjB;EACN,IAAI,CAAC,QAAQ;EAEb,MAAM,cAAc,yBAAyB,MAAM;EACnD,IAAI,aAAa,SAAS,IAAI,WAAW;CAC3C;CAEA,OAAO;AACT;AAEA,SAAS,yBAAyB,WAAkC;CAClE,KAAK,MAAM,eAAe,uBACxB,IAAI,cAAc,eAAe,UAAU,WAAW,GAAG,YAAY,EAAE,GACrE,OAAO;CAIX,OAAO;AACT;AAEA,SAAS,mBACP,aACA,UACe;CACf,MAAM,cAAc,qBAAqB,QAAQ;CACjD,MAAM,UAAU,cAAc,WAAW;CAEzC,IAAI;EACF,OAAO,gBAAgB,QAAQ,QAAQ,WAAW,GAAG,WAAW;CAClE,QAAQ;EACN,OAAO,+BAA+B,aAAa,WAAW;CAChE;AACF;AAEA,SAAS,qBAAqB,UAAsC;CAClE,IAAI,UAAU;EACZ,MAAM,gBAAgB,SAAS,MAAM,QAAQ,CAAC,EAAE;EAChD,IAAI,SAAS,WAAW,aAAa,GAAG,OAAO;CACjD;CACA,OAAO,OAAO,KAAK;AACrB;AAEA,SAAS,gBACP,eACA,aACe;CACf,IAAI,UAAU,SAAS,QACrB,cAAc,WAAW,OAAO,IAC5B,IAAI,IAAI,aAAa,EAAE,WACvB,SAAS,QAAQ,aAAa,CACpC;CAEA,SAAS;EACP,MAAM,kBAAkB,SAAS,KAAK,SAAS,cAAc;EAE7D,IADoB,gBAAgB,eACtB,GAAG,SAAS,aAAa,OAAO;EAE9C,MAAM,SAAS,SAAS,QAAQ,OAAO;EACvC,IAAI,WAAW,SAAS,OAAO;EAC/B,UAAU;CACZ;AACF;AAEA,SAAS,+BACP,aACA,eACe;CACf,MAAM,QAAQ,YAAY,MAAM,GAAG;CACnC,IAAI,UAAU,SAAS,QACrB,cAAc,WAAW,OAAO,IAC5B,IAAI,IAAI,aAAa,EAAE,WACvB,SAAS,QAAQ,aAAa,CACpC;CAEA,SAAS;EACP,MAAM,kBAAkB,SAAS,KAC/B,SACA,gBACA,GAAG,OACH,cACF;EAEA,IADoB,gBAAgB,eACtB,GAAG,SAAS,aAAa,OAAO;EAE9C,MAAM,SAAS,SAAS,QAAQ,OAAO;EACvC,IAAI,WAAW,SAAS,OAAO;EAC/B,UAAU;CACZ;AACF;AAEA,SAAS,gBAAgB,iBAA6C;CACpE,IAAI,CAAC,WAAW,eAAe,GAAG,OAAO;CACzC,IAAI;EACF,OAAO,KAAK,MAAM,aAAa,iBAAiB,MAAM,CAAC;CACzD,SAAS,OAAO;EACd,MAAM,IAAI,uBACR,uCAAuC,gBAAgB,IACrD,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAEzD;CACF;AACF;;;;;;;;AASA,SAAS,oBAAoB,KAAa,UAAoC;CAC5E,MAAM,MAAM,IAAI,QAAQ,KAAK,MAC1B,SACC,EAAE,2BAA2B,IAAI,CACrC;CACA,IAAI,CAAC,KACH,MAAM,IAAI,uBAAuB,4BAA4B,QAAQ;CAEvE,IAAI,CAAC,aAAa,IAAI,aAAa,eAAe,GAChD,MAAM,IAAI,uBACR,8BAA8B,gBAAgB,oJAG9C,QACF;AAEJ;;;;;AAMA,SAAS,aAAa,MAAc,MAAuC;CACzE,IAAI,EAAE,wBAAwB,IAAI,KAAK,EAAE,iBAAiB,IAAI,GAC5D,OAAO,aAAa,KAAK,YAAY,IAAI;CAE3C,IAAI,EAAE,0BAA0B,IAAI,GAClC,OAAO,aAAa,KAAK,YAAY,IAAI;CAE3C,IAAI,EAAE,iBAAiB,IAAI,KAAK,EAAE,aAAa,KAAK,QAAQ,EAAE,KAAK,CAAC,GAClE,OAAO;CAET,OAAO;AACT;;;;;;;AAQA,SAAS,2BAA2B,KAA0B;CAC5D,MAAM,wBAAQ,IAAI,IAAY;CAC9B,KAAK,MAAM,aAAa,IAAI,QAAQ,MAAM;EACxC,IAAI,CAAC,EAAE,sBAAsB,SAAS,GAAG;EACzC,KAAK,MAAM,eAAe,UAAU,cAAc;GAChD,MAAM,EAAE,IAAI,SAAS;GACrB,IACE,EAAE,aAAa,EAAE,KACjB,EAAE,gBAAgB,IAAI,KACtB,EAAE,aAAa,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAC,GAExD,MAAM,IAAI,GAAG,IAAI;EAErB;CACF;CACA,OAAO;AACT;;;;;;;AAQA,SAAS,0BAA0B,KAA0B;CAC3D,MAAM,wBAAQ,IAAI,IAAY;CAC9B,KAAK,MAAM,aAAa,IAAI,QAAQ,MAAM;EACxC,IAAI,CAAC,EAAE,sBAAsB,SAAS,GAAG;EACzC,KAAK,MAAM,eAAe,UAAU,cAAc;GAChD,MAAM,EAAE,IAAI,SAAS;GACrB,IAAI,CAAC,EAAE,aAAa,EAAE,KAAK,CAAC,MAAM;GAClC,IAAI,oBAAoB,IAAI,GAAG,MAAM,IAAI,GAAG,IAAI;EAClD;CACF;CACA,OAAO;AACT;AAEA,SAAS,oBAAoB,MAAuC;CAClE,OACE,aAAa,MAAM,eAAe,KAClC,aAAa,MAAM,mBAAmB;AAE1C;AAEA,SAAS,oBACP,OACA,oBACS;CACT,IAAI,EAAE,aAAa,MAAM,QAAQ,GAC/B,OAAO,mBAAmB,IAAI,MAAM,SAAS,IAAI;CAGnD,MAAM,mBAAmB,aAAa,MAAM,UAAU,mBAAmB;CACzE,OACE,CAAC,CAAC,oBAAoB,EAAE,mBAAmB,iBAAiB,UAAU,EAAE;AAE5E;;AAGA,MAAM,0BAA0B,IAAI,IAAI,CAAC,WAAW,YAAY,CAAC;;;;;;;AAQjE,SAAS,sBAAsB,OAAe,WAAiC;CAC7E,OACE,EAAE,iBAAiB,KAAK,KACxB,EAAE,mBAAmB,MAAM,MAAM,KACjC,CAAC,MAAM,OAAO,YACd,EAAE,aAAa,MAAM,OAAO,MAAM,KAClC,UAAU,IAAI,MAAM,OAAO,OAAO,IAAI,KACtC,EAAE,aAAa,MAAM,OAAO,QAAQ,KACpC,wBAAwB,IAAI,MAAM,OAAO,SAAS,IAAI;AAE1D;;;;;;;AAQA,SAAS,kBACP,QACA,QACA,OACA,UACM;CACN,KAAK,MAAM,SAAS,OAAO,YAAY;EACrC,MAAM,QAAQ,WAAW,KAAK;EAC9B,IAAI,CAAC,OACH,MAAM,IAAI,uBACR,qBAAqB,mBAAmB,0FAExC,QACF;EAEF,IAAI,CAAC,WAAW,OAAO,QAAQ,GAAG;EAGlC,IAAI,WAAW,UAAU,MAAM,aAAa;OACvC,aAAa,OAAO,QAAQ;CACnC;AACF;;;;;;;AAQA,SAAS,eACP,QACA,QACA,WACA,oBACA,OACA,UACM;CACN,MAAM,iBAAmD,CAAC;CAE1D,KAAK,MAAM,SAAS,OAAO,YAAY;EACrC,MAAM,QAAQ,WAAW,KAAK;EAC9B,IAAI,CAAC,OAAO;GACV,IACE,EAAE,gBAAgB,KAAK,KACvB,oBAAoB,OAAO,kBAAkB,GAC7C;IACA,eAAe,KAAK,KAAK;IACzB;GACF;GAKA,MAAM,MAAM,cAAc,KAAK;GAC/B,IAAI,OAAO,sBAAsB,KAAK,SAAS,GAAG;IAChD,eAAe,KAAK,KAAK;IACzB;GACF;GACA,MAAM,IAAI,uBACR,qOAIA,QACF;EACF;EAIA,MAAM,UAAU,WAAW,OAAO,SAAS;EAC3C,MAAM,SAAS,UAAU,kBAAkB,OAAO,IAAI;EACtD,MAAM,aAAa,UAAU,sBAAsB,OAAO,IAAI;EAC9D,MAAM,OAAO,cAAc,OAAO,QAAQ;EAC1C,MAAM,YAAY,CAAC,CAAC,WAAW,OAAO,QAAQ;EAC9C,MAAM,gBAAgB,CAAC,CAAC,WAAW,OAAO,YAAY;EAEtD,IAAI,SAAS,cAAc,CAAC,aAAa,CAAC,eACxC,MAAM,IAAI,uBACR,wGAEA,QACF;EAGF,IAAI,SAAS,WAAW,CAAC,WACvB,MAAM,IAAI,uBACR,gEACA,QACF;EAGF,IAAI,SAAS,cAAc,SACzB,wBAAwB,OAAO,SAAS,QAAQ;EAGlD,IAAI,YAAY;GACd,IAAI,CAAC,aAAa,CAAC,eACjB,MAAM,IAAI,uBACR,0HAEA,QACF;GAEF,IAAI,WAAW,UAAU;GACzB,0BAA0B,KAAK;EACjC;EAEA,IAAI,WAAW,UAAU;GAGvB,IAAI,WAAW,SAAS,cAAc,CAAC,QAAQ,eAAe,OAAO;QAChE,IAAI,SAAS,aAAa,OAAO,SAAS;GAC/C,IAAI,aAAa,eAAe,MAAM,aAAa;EACrD,OAAO;GAEL,IAAI,WAAW,aAAa,OAAO,QAAQ;GAC3C,IAAI,eAAe,aAAa,OAAO,YAAY;GACnD,IAAI,SACF,IAAI,SAAS,aAAa,CAAC,YAAY,MAAM,qBAAqB;QAC7D,aAAa,OAAO,SAAS;EAEtC;EAEA,YAAY,OAAO,IAAI;EACvB,kBAAkB,OAAO,QAAQ,IAAI;EACrC,eAAe,KAAK,KAAK;CAC3B;CAEA,OAAO,aAAa;AACtB;AAEA,SAAS,wBACP,QACA,SACA,UACM;CACN,IACE,CAAC,EAAE,iBAAiB,OAAO,KAC3B,CAAC,EAAE,iBAAiB,QAAQ,KAAK,KACjC,QAAQ,MAAM,UAAU,WAAW,KACnC,CAAC,EAAE,mBAAmB,QAAQ,MAAM,UAAU,EAAE,GAEhD,MAAM,IAAI,uBACR,6DACA,QACF;CAGF,MAAM,gBAAgB,IAAI,IACxB,OAAO,WAAW,SAAS,SAAS;EAClC,IAAI,CAAC,EAAE,iBAAiB,IAAI,KAAK,CAAC,EAAE,eAAe,IAAI,GAAG,OAAO,CAAC;EAClE,MAAM,OAAO,WAAW,KAAK,KAAK,KAAK,QAAQ;EAC/C,OAAO,OAAO,CAAC,IAAI,IAAI,CAAC;CAC1B,CAAC,CACH;CACA,MAAM,8BAAc,IAAI,IAAY;CAEpC,KAAK,MAAM,QAAQ,QAAQ,MAAM,UAAU,GAAG,YAAY;EACxD,IAAI,CAAC,EAAE,iBAAiB,IAAI,GAC1B,MAAM,IAAI,uBACR,iEACA,QACF;EAEF,MAAM,OAAO,WAAW,KAAK,KAAK,KAAK,QAAQ;EAC/C,IAAI,CAAC,MACH,MAAM,IAAI,uBACR,qEACA,QACF;EAEF,IACE,EAAE,qBAAqB,KAAK,KAAK,KACjC,EAAE,0BAA0B,KAAK,KAAK,GAEtC,MAAM,IAAI,uBACR,wEACA,QACF;EAEF,IAAI,cAAc,IAAI,IAAI,KAAK,YAAY,IAAI,IAAI,GACjD,MAAM,IAAI,uBACR,+DACA,QACF;EAEF,YAAY,IAAI,IAAI;EACpB,OAAO,WAAW,KAAK,IAAI;CAC7B;AACF;;AAKA,SAAS,cAAc,OAAmC;CACxD,IAAI,EAAE,iBAAiB,KAAK,KAAK,EAAE,aAAa,MAAM,KAAK,GACzD,OAAO,MAAM;CAEf,OAAO;AACT;AAEA,SAAS,WAAW,OAAyC;CAC3D,IAAI,EAAE,iBAAiB,KAAK,KAAK,EAAE,mBAAmB,MAAM,KAAK,GAC/D,OAAO,MAAM;CAEf,OAAO;AACT;;AAGA,SAAS,WACP,QACA,MAC+C;CAC/C,OAAO,OAAO,WAAW,MACtB,OACE,EAAE,iBAAiB,CAAC,KAAK,EAAE,eAAe,CAAC,MAC5C,WAAW,EAAE,KAAK,EAAE,QAAQ,MAAM,IACtC;AACF;AAEA,SAAS,aAAa,QAA4B,MAAoB;CACpE,OAAO,aAAa,OAAO,WAAW,QACnC,MACC,GACG,EAAE,iBAAiB,CAAC,KAAK,EAAE,eAAe,CAAC,MAC5C,WAAW,EAAE,KAAK,EAAE,QAAQ,MAAM,KAExC;AACF;;AAGA,SAAS,YACP,QAC8B;CAC9B,IAAI,EAAE,eAAe,MAAM,GAAG,OAAO,OAAO;CAC5C,MAAM,QAAQ,OAAO;CACrB,KACG,EAAE,0BAA0B,KAAK,KAAK,EAAE,qBAAqB,KAAK,MACnE,EAAE,iBAAiB,MAAM,IAAI,GAE7B,OAAO,MAAM;AAGjB;;AAGA,SAAS,gBAAgB,QAAoD;CAC3E,OAAO,CAAC,CAAC,YAAY,MAAM,GAAG,WAAW,MACtC,MAAM,EAAE,MAAM,UAAU,YAC3B;AACF;AAEA,SAAS,kBACP,QACA,MACS;CACT,OACE,EAAE,iBAAiB,MAAM,KACzB,EAAE,iBAAiB,OAAO,KAAK,KAC/B,EAAE,aAAa,OAAO,MAAM,QAAQ,EAAE,KAAK,CAAC;AAEhD;;AAGA,SAAS,mBACP,QACS;CACT,OACE,kBAAkB,QAAQ,WAAW,KACrC,kBAAkB,QAAQ,UAAU,KACpC,kBAAkB,QAAQ,MAAM;AAEpC;;AAGA,SAAS,sBACP,QACS;CACT,OAAO,kBAAkB,QAAQ,cAAc;AACjD;;AAGA,SAAS,kBAAkB,QAAoD;CAC7E,OAAO,kBAAkB,QAAQ,UAAU;AAC7C;;AAGA,SAAS,sBACP,QACS;CACT,OAAO,kBAAkB,QAAQ,cAAc;AACjD;;AAGA,SAAS,eAAe,QAAiD;CACvE,MAAM,OAAO,YAAY,MAAM;CAC/B,IAAI,MACF,KAAK,aAAa,KAAK,WAAW,QAC/B,MAAM,EAAE,MAAM,UAAU,YAC3B;AAEJ;;;;;;;;;AAUA,SAAS,cACP,QACA,UACU;CACV,MAAM,UAAU,WAAW,QAAQ,SAAS;CAC5C,IAAI,CAAC,SACH,MAAM,IAAI,uBACR,wFAEA,QACF;CAEF,IAAI,mBAAmB,OAAO,GAAG,OAAO;CACxC,IAAI,sBAAsB,OAAO,GAAG,OAAO;CAC3C,IAAI,kBAAkB,OAAO,GAAG,OAAO;CACvC,IAAI,sBAAsB,OAAO,GAAG,OAAO;CAC3C,OAAO,gBAAgB,OAAO,IAAI,aAAa;AACjD;AAEA,SAAS,0BAA0B,QAAkC;CAInE,aAAa,QAAQ,aAAa;CAClC,aAAa,QAAQ,YAAY;CACjC,aAAa,QAAQ,UAAU;CAC/B,aAAa,QAAQ,eAAe;CACpC,aAAa,QAAQ,sCAAsC;CAC3D,aAAa,QAAQ,iBAAiB;CACtC,aAAa,QAAQ,YAAY;AACnC;;AAGA,SAAS,YAAY,QAA4B,MAAsB;CACrE,aAAa,QAAQ,MAAM;CAE3B,OAAO,WAAW,KAChB,EAAE,eAAe,EAAE,WAAW,MAAM,GAAG,EAAE,cAAc,IAAI,CAAC,CAC9D;AACF;AAEA,SAAS,kBACP,QACA,QACA,MACM;CAGN,aAAa,QAAQ,yBAAyB;CAC9C,IAAI,WAAW,YAAa,SAAS,cAAc,SAAS,SAAU;CAEtE,OAAO,WAAW,KAChB,EAAE,eACA,EAAE,WAAW,yBAAyB,GACtC,EAAE,iBAAiB,CACjB,EAAE,eAAe,EAAE,WAAW,YAAY,GAAG,EAAE,eAAe,IAAI,CAAC,CACrE,CAAC,CACH,CACF;AACF;AAEA,SAAS,WACP,KACA,UACoB;CACpB,IAAI,UAAU,OAAO,KAAA;CACrB,IAAI,EAAE,aAAa,GAAG,GAAG,OAAO,IAAI;CACpC,IAAI,EAAE,gBAAgB,GAAG,GAAG,OAAO,IAAI;AAEzC;;;;;;AAOA,SAAS,YAAY,KAAmB;CACtC,MAAM,gCAAgB,IAAI,QAA6B;CACvD,KAAK,MAAM,QAAQ,IAAI,QAAQ,MAC7B,IAAI,EAAE,oBAAoB,IAAI,KAAK,KAAK,WAAW,SAAS,GAC1D,cAAc,IAAI,IAAI;CAI1B,IAAI,mBAAmB;CACvB,OAAO,kBAAkB;EACvB,mBAAmB;EACnB,SAAS,KAAK,EACZ,QAAQ,MAA2B;GACjC,KAAK,MAAM,MAAM;GACjB,MAAM,YAAY,SAA0B;IAC1C,MAAM,UAAU,KAAK,MAAM,WAAW,IAAI;IAC1C,OAAO,CAAC,CAAC,WAAW,CAAC,QAAQ;GAC/B;GAEA,KAAK,KAAK,OAAO,KAAK,KAAK,KAAK,QAAQ,SAAS;IAC/C,KACG,EAAE,sBAAsB,IAAI,KAAK,EAAE,mBAAmB,IAAI,MAC3D,KAAK,MACL,SAAS,KAAK,GAAG,IAAI,GACrB;KACA,mBAAmB;KACnB,OAAO;IACT;IACA,IAAI,EAAE,sBAAsB,IAAI,GAAG;KACjC,KAAK,eAAe,KAAK,aAAa,QAAQ,SAAS;MAKrD,MAAM,QAAQ,OAAO,KAAK,EAAE,sBAAsB,KAAK,EAAE,CAAC;MAC1D,IACE,MAAM,SAAS,KACf,eAAe,KAAK,EAAE,KACtB,gBAAgB,KAAK,IAAI,KACzB,MAAM,MAAM,QAAQ,GACpB;OACA,mBAAmB;OACnB,OAAO;MACT;MACA,OAAO;KACT,CAAC;KACD,IAAI,KAAK,aAAa,WAAW,GAAG,OAAO;IAC7C;IACA,OAAO;GACT,CAAC;GACD,KAAK,KAAK;EACZ,EACF,CAAC;CACH;CAEA,SAAS,KAAK,EACZ,QAAQ,MAA2B;EACjC,KAAK,MAAM,MAAM;EACjB,KAAK,MAAM,QAAQ,KAAK,KAAK,MAAM;GACjC,IAAI,CAAC,EAAE,oBAAoB,IAAI,GAAG;GAClC,KAAK,aAAa,KAAK,WAAW,QAAQ,SAAS;IACjD,MAAM,UAAU,KAAK,MAAM,WAAW,KAAK,MAAM,IAAI;IACrD,OAAO,UAAU,QAAQ,aAAa;GACxC,CAAC;EACH;EACA,KAAK,KAAK,OAAO,KAAK,KAAK,KAAK,QAC7B,SACC,EACE,EAAE,oBAAoB,IAAI,KAC1B,KAAK,WAAW,WAAW,KAC3B,cAAc,IAAI,IAAI,EAE5B;EACA,KAAK,KAAK;CACZ,EACF,CAAC;AACH;;;;;;;AAQA,SAAS,eAAe,MAAuB;CAC7C,IAAI,EAAE,aAAa,IAAI,GAAG,OAAO;CACjC,IAAI,EAAE,gBAAgB,IAAI,GACxB,OAAO,KAAK,WAAW,OAAO,MAC5B,EAAE,cAAc,CAAC,IACb,eAAe,EAAE,QAAQ,IACzB,CAAC,EAAE,YAAY,eAAe,EAAE,KAAK,CAC3C;CAEF,IAAI,EAAE,eAAe,IAAI,GACvB,OAAO,KAAK,SAAS,OAAO,OAAO,MAAM,QAAQ,eAAe,EAAE,CAAC;CAErE,OAAO;AACT;;AAGA,SAAS,gBAAgB,MAAgD;CACvE,IAAI,QAAQ,MAAM,OAAO;CACzB,IAAI,EAAE,iBAAiB,IAAI,KAAK,EAAE,wBAAwB,IAAI,GAC5D,OAAO,gBAAgB,KAAK,UAAU;CAIxC,IAAI,EAAE,kBAAkB,IAAI,GAC1B,OAAO,KAAK,SAAS,OAClB,OAAO,MAAM,QAAS,EAAE,aAAa,EAAE,KAAK,gBAAgB,EAAE,CACjE;CAEF,IAAI,EAAE,mBAAmB,IAAI,GAC3B,OAAO,KAAK,WAAW,OACpB,MACC,EAAE,iBAAiB,CAAC,KACpB,CAAC,EAAE,YACH,EAAE,aAAa,EAAE,KAAK,KACtB,gBAAgB,EAAE,KAAK,CAC3B;CAEF,IAAI,EAAE,kBAAkB,IAAI,GAC1B,OAAO,KAAK,YAAY,OACrB,MAAM,EAAE,aAAa,CAAC,KAAK,gBAAgB,CAAC,CAC/C;CAEF,OACE,EAAE,0BAA0B,IAAI,KAChC,EAAE,qBAAqB,IAAI,KAC3B,EAAE,kBAAkB,IAAI,KACxB,EAAE,aAAa,IAAI,KAElB,EAAE,mBAAmB,IAAI,KAAK,CAAC,KAAK,YACrC,EAAE,aAAa,IAAI,KACnB,EAAE,cAAc,IAAI,KACpB,EAAE,UAAU,IAAI;AAEpB"}
1
+ {"version":3,"file":"compile.js","names":["pkgJson.version"],"sources":["../src/compile.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport * as nodePath from \"node:path\";\nimport { parse } from \"@babel/parser\";\nimport _traverse, { type NodePath } from \"@babel/traverse\";\nimport _generate from \"@babel/generator\";\nimport * as t from \"@babel/types\";\nimport { satisfies } from \"semver\";\nimport { DIRECTIVE, type Target } from \"./constants\";\nimport pkgJson from \"../package.json\" with { type: \"json\" };\n\n// @babel/traverse and @babel/generator are CJS; their default export is the\n// function itself under some interop and `{ default }` under others.\nconst traverse = (\n typeof _traverse === \"function\" ? _traverse : (_traverse as any).default\n) as typeof _traverse;\nconst generate = (\n typeof _generate === \"function\" ? _generate : (_generate as any).default\n) as typeof _generate;\n\nexport type ToolType = \"frontend\" | \"backend\" | \"human\" | \"provider\";\n\n/** The required wrapper around a toolkit's tools (stripped at build time). */\nconst TOOLKIT_WRAPPER = \"defineToolkit\";\n/** The helper that produces MCP-only toolkit fragments. */\nconst MCP_TOOLKIT_WRAPPER = \"defineMcpToolkit\";\n/** The required wrapper around a generative-UI library (stripped at build time). */\nconst COMPONENTS_WRAPPER = \"defineGenerativeComponents\";\n/** The core package whose metadata declares supported compiler versions. */\nconst CORE_PACKAGE = \"@assistant-ui/core\";\n/** This package, checked against core's compatibility range. */\nconst COMPILER_PACKAGE = \"@assistant-ui/x-generative-compiler\";\n/** Packages that re-export core's generative markers. */\nconst DISTRIBUTION_PACKAGES = [\n CORE_PACKAGE,\n \"@assistant-ui/react\",\n \"@assistant-ui/react-native\",\n \"@assistant-ui/react-ink\",\n] as const;\n/**\n * The class whose instances expose split-by-condition tools (`present()`,\n * `promptUser()`). A toolkit entry that calls a method on one of these passes\n * through untouched — the library, not this compiler, routes its halves.\n */\nconst GENERATIVE_FACTORY = \"JSONGenerativeUI\";\n\n/** Mutable per-build outcomes the toolkit pass reports back for directive/guard injection. */\ninterface TargetFlags {\n /** A `render` survived on a client build (→ emit `\"use client\"`). */\n keptRender: boolean;\n /** A backend `execute` survived on a server build (→ emit `import \"server-only\"`). */\n keptBackendExecute: boolean;\n}\n\nexport interface CompileOptions {\n /** Which build target to emit. */\n target: Target;\n /** Source filename, used for error messages and source maps. */\n filename?: string;\n /** Emit a source map alongside the code. */\n sourceMaps?: boolean;\n /**\n * Whether the `server` target prepends `import \"server-only\"` when it keeps a\n * backend `execute`. Defaults to `true` (the Next.js/RSC convention, where the\n * guard fires via the `react-server` condition). Set `false` for bundlers\n * without a `react-server` layer (e.g. a Vite/TanStack Start `ssr` build),\n * where the split is already structural and importing `server-only` would\n * throw — see the Vite integration.\n */\n injectServerOnly?: boolean;\n}\n\nexport interface CompileResult {\n code: string;\n map?: object | null;\n}\n\n/** Thrown when a `\"use generative\"` file violates an authoring constraint. */\nexport class GenerativeCompileError extends Error {\n constructor(message: string, filename?: string) {\n super(`[assistant-ui/next]${filename ? ` ${filename}:` : \"\"} ${message}`);\n this.name = \"GenerativeCompileError\";\n }\n}\n\n/** Whether a source string opts into generative compilation via the directive. */\nexport function isGenerativeModule(code: string): boolean {\n // The directive must be a leading statement, preceded only by an optional BOM,\n // whitespace, and line/block comments. Scanned linearly — a regex over the\n // comment prefix is prone to catastrophic backtracking on crafted input.\n let i = code.charCodeAt(0) === 0xfeff ? 1 : 0;\n for (;;) {\n while (i < code.length && /\\s/.test(code[i]!)) i++;\n if (code.startsWith(\"//\", i)) {\n const nl = code.indexOf(\"\\n\", i);\n if (nl === -1) return false;\n i = nl + 1;\n } else if (code.startsWith(\"/*\", i)) {\n const end = code.indexOf(\"*/\", i + 2);\n if (end === -1) return false;\n i = end + 2;\n } else {\n break;\n }\n }\n return (\n code.startsWith(`\"${DIRECTIVE}\"`, i) || code.startsWith(`'${DIRECTIVE}'`, i)\n );\n}\n\n/**\n * Rewrites a `\"use generative\"` module for a single build target, keeping only the\n * regions that target needs and pruning the imports the dropped regions used.\n */\nexport function compileGenerative(\n code: string,\n options: CompileOptions,\n): CompileResult {\n const { target, filename } = options;\n\n const ast = parse(code, {\n sourceType: \"module\",\n plugins: [\"typescript\", \"jsx\", \"explicitResourceManagement\"],\n });\n\n if (!ast.program.directives.some((d) => d.value.value === DIRECTIVE)) {\n throw new GenerativeCompileError(\n `missing \"${DIRECTIVE}\" directive`,\n filename,\n );\n }\n\n ensureCompilerCompatibleWithCore(ast, filename);\n\n // A module may hold several `defineToolkit(...)` / `defineGenerativeComponents(...)`\n // calls anywhere (e.g. a library built inside `new JSONGenerativeUI(...)` plus\n // the toolkit that exposes it). Tools may reference a `JSONGenerativeUI`\n // instance's `present()`/`promptUser()`, which the library — not this compiler —\n // splits across builds via export conditions; collect those instance names so\n // such entries pass through.\n ensureDefaultExport(ast, filename);\n const generativeInstances = collectGenerativeInstances(ast);\n const safeToolkitSpreads = collectSafeToolkitSpreads(ast, filename);\n\n const flags: TargetFlags = { keptRender: false, keptBackendExecute: false };\n\n traverse(ast, {\n CallExpression(path: NodePath<t.CallExpression>) {\n const callee = path.node.callee;\n const object = t.isObjectExpression(path.node.arguments[0])\n ? path.node.arguments[0]\n : null;\n\n if (t.isIdentifier(callee, { name: COMPONENTS_WRAPPER })) {\n if (!object) {\n throw new GenerativeCompileError(\n `${COMPONENTS_WRAPPER}() takes an inline object literal of components`,\n filename,\n );\n }\n compileComponents(object, target, flags, filename);\n // Unwrap the authoring helper to the bare library object so its import\n // can be pruned.\n path.replaceWith(object);\n path.skip();\n return;\n }\n\n if (t.isIdentifier(callee, { name: TOOLKIT_WRAPPER })) {\n if (!object) {\n throw new GenerativeCompileError(\n `${TOOLKIT_WRAPPER}() takes an inline object literal of tools`,\n filename,\n );\n }\n compileToolkit(\n object,\n target,\n generativeInstances,\n safeToolkitSpreads,\n flags,\n filename,\n );\n path.replaceWith(object);\n path.skip();\n }\n },\n });\n\n const { keptRender, keptBackendExecute } = flags;\n\n pruneUnused(ast);\n\n // Replace the module directives with the target-appropriate one.\n ast.program.directives = ast.program.directives.filter(\n (d) => d.value.value !== DIRECTIVE && d.value.value !== \"use client\",\n );\n if (target === \"client\" && keptRender) {\n ast.program.directives.unshift(\n t.directive(t.directiveLiteral(\"use client\")),\n );\n }\n if (\n target === \"server\" &&\n keptBackendExecute &&\n (options.injectServerOnly ?? true)\n ) {\n ast.program.body.unshift(\n t.importDeclaration([], t.stringLiteral(\"server-only\")),\n );\n }\n\n const result = generate(\n ast,\n {\n sourceMaps: options.sourceMaps ?? false,\n filename,\n jsescOption: { minimal: true },\n },\n code,\n );\n\n return { code: result.code, map: result.map };\n}\n\ninterface PackageJson {\n name?: string;\n version?: string;\n optionalDevDependencies?: Record<string, string>;\n}\n\nconst checkedCorePackageJsonPaths = new Set<string>();\n\n// This compiler's own version, inlined from package.json at build time. Read via\n// an import (not by walking the filesystem at runtime) so the literal survives\n// being bundled into a host package like `@assistant-ui/metro`, where no\n// standalone `@assistant-ui/x-generative-compiler` sits on disk to walk up to.\nconst COMPILER_VERSION = pkgJson.version;\n\nfunction ensureCompilerCompatibleWithCore(\n ast: t.File,\n filename: string | undefined,\n): void {\n const corePackageJsonPath = resolveCorePackageJson(ast, filename);\n if (\n !corePackageJsonPath ||\n checkedCorePackageJsonPaths.has(corePackageJsonPath)\n ) {\n return;\n }\n\n const corePackageJson = readPackageJson(corePackageJsonPath);\n const range = corePackageJson?.optionalDevDependencies?.[COMPILER_PACKAGE];\n if (!range) {\n checkedCorePackageJsonPaths.add(corePackageJsonPath);\n return;\n }\n\n let compatible = false;\n try {\n compatible = satisfies(COMPILER_VERSION, range, {\n includePrerelease: true,\n });\n } catch {\n throw new GenerativeCompileError(\n `${CORE_PACKAGE}@${corePackageJson.version ?? \"unknown\"} declares an ` +\n `invalid optionalDevDependencies range for ${COMPILER_PACKAGE}: ` +\n JSON.stringify(range),\n filename,\n );\n }\n\n if (!compatible) {\n throw new GenerativeCompileError(\n `${CORE_PACKAGE}@${corePackageJson.version ?? \"unknown\"} requires ` +\n `${COMPILER_PACKAGE} ${range}, but the current compiler is ` +\n `${COMPILER_VERSION}. Update @assistant-ui/next, @assistant-ui/vite, ` +\n \"or @assistant-ui/metro so their compiler satisfies the core package's \" +\n \"optionalDevDependencies range.\",\n filename,\n );\n }\n\n checkedCorePackageJsonPaths.add(corePackageJsonPath);\n}\n\nfunction resolveCorePackageJson(\n ast: t.File,\n filename: string | undefined,\n): string | null {\n for (const packageName of collectImportedDistributionPackages(ast)) {\n const packageJsonPath = resolvePackageJson(packageName, filename);\n if (!packageJsonPath) continue;\n if (packageName === CORE_PACKAGE) return packageJsonPath;\n\n const corePackageJsonPath = resolvePackageJson(\n CORE_PACKAGE,\n packageJsonPath,\n );\n if (corePackageJsonPath) return corePackageJsonPath;\n }\n\n return null;\n}\n\nfunction collectImportedDistributionPackages(ast: t.File): Set<string> {\n const packages = new Set<string>();\n\n for (const statement of ast.program.body) {\n const source =\n (t.isImportDeclaration(statement) ||\n t.isExportNamedDeclaration(statement) ||\n t.isExportAllDeclaration(statement)) &&\n statement.source\n ? statement.source.value\n : null;\n if (!source) continue;\n\n const packageName = packageNameFromSpecifier(source);\n if (packageName) packages.add(packageName);\n }\n\n return packages;\n}\n\nfunction packageNameFromSpecifier(specifier: string): string | null {\n for (const packageName of DISTRIBUTION_PACKAGES) {\n if (specifier === packageName || specifier.startsWith(`${packageName}/`)) {\n return packageName;\n }\n }\n\n return null;\n}\n\nfunction resolvePackageJson(\n packageName: string,\n filename: string | undefined,\n): string | null {\n const requirePath = normalizeRequirePath(filename);\n const require = createRequire(requirePath);\n\n try {\n return findPackageJson(require.resolve(packageName), packageName);\n } catch {\n return findPackageJsonFromNodeModules(packageName, requirePath);\n }\n}\n\nfunction normalizeRequirePath(filename: string | undefined): string {\n return cleanAbsoluteFilename(filename) ?? import.meta.url;\n}\n\n/** Strips a `?query`/`#hash` suffix and returns the path only if it is absolute. */\nfunction cleanAbsoluteFilename(filename: string | undefined): string | null {\n if (!filename) return null;\n const clean = filename.split(/[?#]/, 1)[0]!;\n return nodePath.isAbsolute(clean) ? clean : null;\n}\n\nfunction findPackageJson(\n fromPathOrUrl: string,\n packageName: string,\n): string | null {\n let current = nodePath.dirname(\n fromPathOrUrl.startsWith(\"file:\")\n ? new URL(fromPathOrUrl).pathname\n : nodePath.resolve(fromPathOrUrl),\n );\n\n for (;;) {\n const packageJsonPath = nodePath.join(current, \"package.json\");\n const packageJson = readPackageJson(packageJsonPath);\n if (packageJson?.name === packageName) return packageJsonPath;\n\n const parent = nodePath.dirname(current);\n if (parent === current) return null;\n current = parent;\n }\n}\n\nfunction findPackageJsonFromNodeModules(\n packageName: string,\n fromPathOrUrl: string,\n): string | null {\n const parts = packageName.split(\"/\");\n let current = nodePath.dirname(\n fromPathOrUrl.startsWith(\"file:\")\n ? new URL(fromPathOrUrl).pathname\n : nodePath.resolve(fromPathOrUrl),\n );\n\n for (;;) {\n const packageJsonPath = nodePath.join(\n current,\n \"node_modules\",\n ...parts,\n \"package.json\",\n );\n const packageJson = readPackageJson(packageJsonPath);\n if (packageJson?.name === packageName) return packageJsonPath;\n\n const parent = nodePath.dirname(current);\n if (parent === current) return null;\n current = parent;\n }\n}\n\nfunction readPackageJson(packageJsonPath: string): PackageJson | null {\n if (!existsSync(packageJsonPath)) return null;\n try {\n return JSON.parse(readFileSync(packageJsonPath, \"utf8\")) as PackageJson;\n } catch (error) {\n throw new GenerativeCompileError(\n `could not parse package metadata at ${packageJsonPath}: ${\n error instanceof Error ? error.message : String(error)\n }`,\n );\n }\n}\n\n/**\n * Errors unless the module's default export is the toolkit — a `defineToolkit(...)`\n * call (through `satisfies`/`as`/parens). This is the security boundary: the\n * default export is what the runtime registers, so it must be wrapped (and thus\n * split). A bare `export default { ... }` would ship a backend `execute` to the\n * client even if some *other* `defineToolkit(...)` exists elsewhere in the file.\n */\nfunction ensureDefaultExport(ast: t.File, filename: string | undefined): void {\n const def = ast.program.body.find(\n (stmt): stmt is t.ExportDefaultDeclaration =>\n t.isExportDefaultDeclaration(stmt),\n );\n if (!def) {\n throw new GenerativeCompileError(\"missing a default export\", filename);\n }\n if (!unwrapToToolkitCall(def.declaration)) {\n throw new GenerativeCompileError(\n `the default export must be ${TOOLKIT_WRAPPER}({ ... }) or ` +\n `${MCP_TOOLKIT_WRAPPER}({ ... }) (imported from \"@assistant-ui/react\"); ` +\n \"wrapping is required so a backend `execute` can't be authored in a way \" +\n \"that reaches the client\",\n filename,\n );\n }\n}\n\n/**\n * Unwraps a node through `satisfies`/`as`/parens to a call of the named function,\n * or returns `null`.\n */\nfunction unwrapToCall(node: t.Node, name: string): t.CallExpression | null {\n if (t.isTSSatisfiesExpression(node) || t.isTSAsExpression(node)) {\n return unwrapToCall(node.expression, name);\n }\n if (t.isParenthesizedExpression(node)) {\n return unwrapToCall(node.expression, name);\n }\n if (t.isCallExpression(node) && t.isIdentifier(node.callee, { name })) {\n return node;\n }\n return null;\n}\n\n/**\n * Collects the names bound to `new JSONGenerativeUI(...)` (e.g.\n * `const generative = new JSONGenerativeUI({ library })`). A toolkit entry that\n * calls a method on one of these is a generative tool whose halves the library\n * routes by export condition, so it passes through the toolkit pass untouched.\n */\nfunction collectGenerativeInstances(ast: t.File): Set<string> {\n const names = new Set<string>();\n for (const statement of ast.program.body) {\n if (!t.isVariableDeclaration(statement)) continue;\n for (const declaration of statement.declarations) {\n const { id, init } = declaration;\n if (\n t.isIdentifier(id) &&\n t.isNewExpression(init) &&\n t.isIdentifier(init.callee, { name: GENERATIVE_FACTORY })\n ) {\n names.add(id.name);\n }\n }\n }\n return names;\n}\n\n/**\n * Toolkit identifiers that are safe to spread into a `defineToolkit({ ... })`.\n *\n * Two kinds qualify:\n *\n * - A local variable whose initializer is visible to this compiler pass: a\n * `defineToolkit(...)` binding is compiled in-place before a later spread\n * reads it, and `defineMcpToolkit(...)` entries can't contain executable code.\n * - The default import of another `\"use generative\"` module: that module is\n * split per-target by its own compiler pass, so spreading its default-exported\n * toolkit can't leak a backend `execute` to the client. Only the default\n * export crosses the generative-module boundary, so named imports don't\n * qualify — they would be `undefined` once that module is build-split.\n */\nfunction collectSafeToolkitSpreads(\n ast: t.File,\n filename: string | undefined,\n): Set<string> {\n const names = new Set<string>();\n const generativeBySource = new Map<string, boolean>();\n\n for (const statement of ast.program.body) {\n if (t.isVariableDeclaration(statement)) {\n for (const declaration of statement.declarations) {\n const { id, init } = declaration;\n if (t.isIdentifier(id) && init && unwrapToToolkitCall(init)) {\n names.add(id.name);\n }\n }\n continue;\n }\n\n if (t.isImportDeclaration(statement)) {\n const defaultSpecifier = statement.specifiers.find(\n (specifier): specifier is t.ImportDefaultSpecifier =>\n t.isImportDefaultSpecifier(specifier),\n );\n if (!defaultSpecifier) continue;\n\n const source = statement.source.value;\n let isGenerative = generativeBySource.get(source);\n if (isGenerative === undefined) {\n isGenerative = isGenerativeImport(source, filename);\n generativeBySource.set(source, isGenerative);\n }\n if (isGenerative) names.add(defaultSpecifier.local.name);\n }\n }\n\n return names;\n}\n\nconst MODULE_EXTENSIONS = [\n \".ts\",\n \".tsx\",\n \".mts\",\n \".cts\",\n \".js\",\n \".jsx\",\n \".mjs\",\n \".cjs\",\n] as const;\n\n/** Extensions a specifier may carry that actually map to a TS source file. */\nconst REWRITABLE_JS_EXTENSIONS = new Set([\".js\", \".jsx\", \".mjs\", \".cjs\"]);\n\n/**\n * Whether an import specifier resolves on disk to a `\"use generative\"` module.\n * Relative specifiers and `tsconfig` path aliases (e.g. `@/tools`) are resolved;\n * anything else (a bare package, an unresolvable alias) is treated as\n * non-generative, and thus an unsafe spread.\n */\nfunction isGenerativeImport(\n source: string,\n filename: string | undefined,\n): boolean {\n const cleanFilename = cleanAbsoluteFilename(filename);\n if (!cleanFilename) return false;\n\n const resolved = resolveImportedModuleFile(source, cleanFilename);\n if (!resolved) return false;\n\n try {\n return isGenerativeModule(readFileSync(resolved, \"utf8\"));\n } catch {\n return false;\n }\n}\n\n/** Resolves an import specifier (relative or `tsconfig`-aliased) to a file on disk. */\nfunction resolveImportedModuleFile(\n source: string,\n fromFilename: string,\n): string | null {\n if (source.startsWith(\".\")) {\n const base = nodePath.resolve(nodePath.dirname(fromFilename), source);\n return resolveModuleFileAtPath(base);\n }\n return resolveAliasImport(source, fromFilename);\n}\n\n/**\n * Resolves a candidate module path, trying TS/JS extensions then index files. A\n * specifier may carry a `.js`-family extension that maps to a `.ts`/`.tsx`\n * source (TypeScript's `bundler`/`nodenext` resolution), so the extension is\n * dropped before probing.\n */\nfunction resolveModuleFileAtPath(base: string): string | null {\n const ext = nodePath.extname(base);\n if (ext && existsSync(base)) return base;\n\n const stem = REWRITABLE_JS_EXTENSIONS.has(ext)\n ? base.slice(0, -ext.length)\n : base;\n\n for (const candidateExt of MODULE_EXTENSIONS) {\n const candidate = `${stem}${candidateExt}`;\n if (existsSync(candidate)) return candidate;\n }\n for (const candidateExt of MODULE_EXTENSIONS) {\n const candidate = nodePath.join(base, `index${candidateExt}`);\n if (existsSync(candidate)) return candidate;\n }\n return null;\n}\n\ninterface TsconfigAliases {\n /** Absolute directory that `paths` targets resolve against. */\n baseDir: string;\n paths: Record<string, string[]>;\n}\n\n/** Resolves a `tsconfig` path alias (e.g. `@/tools/x`) to a file on disk. */\nfunction resolveAliasImport(\n source: string,\n fromFilename: string,\n): string | null {\n const tsconfig = loadTsconfigAliases(nodePath.dirname(fromFilename));\n if (!tsconfig) return null;\n\n // TypeScript matches the most specific key first: an exact (wildcard-free) key\n // beats a wildcard one, and a longer static prefix beats a shorter one.\n const patterns = Object.entries(tsconfig.paths).sort(\n ([a], [b]) => aliasSpecificity(b) - aliasSpecificity(a),\n );\n\n for (const [pattern, targets] of patterns) {\n const matched = matchAliasPattern(pattern, source);\n if (matched === null) continue;\n\n for (const target of targets) {\n const specifier = substituteAliasWildcard(target, matched);\n const file = resolveModuleFileAtPath(\n nodePath.resolve(tsconfig.baseDir, specifier),\n );\n if (file) return file;\n }\n }\n return null;\n}\n\n/** Ranks a `paths` key: an exact key outranks any wildcard; longer prefixes win. */\nfunction aliasSpecificity(pattern: string): number {\n const star = pattern.indexOf(\"*\");\n return star === -1 ? pattern.length + 1 : star;\n}\n\n/** Substitutes the single `*` in a `paths` target with the matched text. */\nfunction substituteAliasWildcard(target: string, matched: string): string {\n const star = target.indexOf(\"*\");\n if (star === -1) return target;\n return target.slice(0, star) + matched + target.slice(star + 1);\n}\n\n/**\n * Matches an import specifier against a `tsconfig` `paths` key. Returns the text\n * captured by the key's `*` (or `\"\"` for an exact, wildcard-free key), or `null`\n * when the specifier doesn't match.\n */\nfunction matchAliasPattern(pattern: string, source: string): string | null {\n const star = pattern.indexOf(\"*\");\n if (star === -1) return pattern === source ? \"\" : null;\n\n const prefix = pattern.slice(0, star);\n const suffix = pattern.slice(star + 1);\n if (\n source.length >= prefix.length + suffix.length &&\n source.startsWith(prefix) &&\n source.endsWith(suffix)\n ) {\n return source.slice(prefix.length, source.length - suffix.length);\n }\n return null;\n}\n\n/**\n * Memoizes resolved aliases per start directory. The compiler runs once per\n * file across a build, so without this every aliased spread re-walks and\n * re-parses the same `tsconfig.json`. Process-lifetime, like\n * `checkedCorePackageJsonPaths`.\n */\nconst tsconfigAliasesByDir = new Map<string, TsconfigAliases | null>();\n\n/** Walks up from a directory to the nearest `tsconfig.json` that declares `paths`. */\nfunction loadTsconfigAliases(fromDir: string): TsconfigAliases | null {\n const cached = tsconfigAliasesByDir.get(fromDir);\n if (cached !== undefined) return cached;\n\n let aliases: TsconfigAliases | null = null;\n let dir = fromDir;\n for (;;) {\n const tsconfigPath = nodePath.join(dir, \"tsconfig.json\");\n if (existsSync(tsconfigPath)) {\n aliases = readTsconfigAliases(tsconfigPath, new Set());\n if (aliases) break;\n }\n const parent = nodePath.dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n\n tsconfigAliasesByDir.set(fromDir, aliases);\n return aliases;\n}\n\n/** Reads `baseUrl`/`paths` from a tsconfig, following a single `extends` chain. */\nfunction readTsconfigAliases(\n tsconfigPath: string,\n seen: Set<string>,\n): TsconfigAliases | null {\n if (seen.has(tsconfigPath)) return null;\n seen.add(tsconfigPath);\n\n let config: {\n extends?: string | string[];\n compilerOptions?: { baseUrl?: string; paths?: Record<string, string[]> };\n } | null;\n try {\n config = parseJsonc(readFileSync(tsconfigPath, \"utf8\"));\n } catch {\n return null;\n }\n if (!config) return null;\n\n const configDir = nodePath.dirname(tsconfigPath);\n const { baseUrl, paths } = config.compilerOptions ?? {};\n\n if (paths) {\n return {\n baseDir: baseUrl ? nodePath.resolve(configDir, baseUrl) : configDir,\n paths,\n };\n }\n\n // `extends` may be a string or (TS 5.0+) a string array; later entries take\n // precedence, so try them last-first. Parsed from untrusted JSONC, so the\n // array case is a real runtime shape, not just a type.\n const extendsList = Array.isArray(config.extends)\n ? config.extends\n : config.extends\n ? [config.extends]\n : [];\n for (let i = extendsList.length - 1; i >= 0; i--) {\n const entry = extendsList[i];\n if (typeof entry !== \"string\") continue;\n const extended = resolveExtendedTsconfig(entry, configDir);\n if (extended) {\n const aliases = readTsconfigAliases(extended, seen);\n if (aliases) return aliases;\n }\n }\n return null;\n}\n\n/** Resolves a tsconfig `extends` value (relative path or installed package). */\nfunction resolveExtendedTsconfig(\n extendsValue: string,\n configDir: string,\n): string | null {\n if (extendsValue.startsWith(\".\")) {\n const base = nodePath.resolve(configDir, extendsValue);\n const candidates =\n nodePath.extname(base) === \".json\" ? [base] : [`${base}.json`, base];\n return candidates.find((candidate) => existsSync(candidate)) ?? null;\n }\n try {\n return createRequire(nodePath.join(configDir, \"package.json\")).resolve(\n extendsValue.endsWith(\".json\") ? extendsValue : `${extendsValue}.json`,\n );\n } catch {\n return null;\n }\n}\n\n/** Parses JSON with `//` and block comments and trailing commas stripped (tsconfig is JSONC). */\nfunction parseJsonc(text: string): any {\n const withoutComments = text.replace(\n /\"(?:[^\"\\\\]|\\\\.)*\"|\\/\\/[^\\n\\r]*|\\/\\*[\\s\\S]*?\\*\\//g,\n (match) => (match.startsWith('\"') ? match : \"\"),\n );\n const withoutTrailingCommas = withoutComments.replace(/,(\\s*[}\\]])/g, \"$1\");\n return JSON.parse(withoutTrailingCommas);\n}\n\nfunction unwrapToToolkitCall(node: t.Node): t.CallExpression | null {\n return (\n unwrapToCall(node, TOOLKIT_WRAPPER) ??\n unwrapToCall(node, MCP_TOOLKIT_WRAPPER)\n );\n}\n\nfunction isSafeToolkitSpread(\n entry: t.SpreadElement,\n safeToolkitSpreads: Set<string>,\n): boolean {\n if (t.isIdentifier(entry.argument)) {\n return safeToolkitSpreads.has(entry.argument.name);\n }\n\n const directMcpToolkit = unwrapToCall(entry.argument, MCP_TOOLKIT_WRAPPER);\n return (\n !!directMcpToolkit && t.isObjectExpression(directMcpToolkit.arguments[0])\n );\n}\n\n/** The `JSONGenerativeUI` methods that produce a split-by-condition tool. */\nconst GENERATIVE_TOOL_METHODS = new Set([\"present\", \"promptUser\"]);\n\n/**\n * Whether a toolkit entry's value is a call to a tool-producing method on a\n * collected `JSONGenerativeUI` instance (`generative.present()`), which passes\n * through. The method name is checked too, so a typo like `generative.presnt()`\n * is a compile error here rather than a pass-through that fails at runtime.\n */\nfunction isGenerativeToolEntry(value: t.Node, instances: Set<string>): boolean {\n return (\n t.isCallExpression(value) &&\n t.isMemberExpression(value.callee) &&\n !value.callee.computed &&\n t.isIdentifier(value.callee.object) &&\n instances.has(value.callee.object.name) &&\n t.isIdentifier(value.callee.property) &&\n GENERATIVE_TOOL_METHODS.has(value.callee.property.name)\n );\n}\n\n/**\n * Splits a `defineGenerativeComponents({ ... })` library for a build target:\n * a component's `render` (and the client imports it alone uses) is dropped on\n * the server; `properties`/`description` stay on both, since they drive the tool\n * schema either way. Mutates the object in place.\n */\nfunction compileComponents(\n object: t.ObjectExpression,\n target: Target,\n flags: TargetFlags,\n filename: string | undefined,\n): void {\n for (const entry of object.properties) {\n const value = entryValue(entry);\n if (!value) {\n throw new GenerativeCompileError(\n `each component in ${COMPONENTS_WRAPPER}() must be an inline object ` +\n \"literal (`name: { ... }`) so its `render` can be routed\",\n filename,\n );\n }\n if (!findMember(value, \"render\")) continue;\n // The client keeps `render` (and so needs the module marked `\"use client\"`);\n // the server drops it, since only the schema reaches the model there.\n if (target === \"client\") flags.keptRender = true;\n else removeMember(value, \"render\");\n }\n}\n\n/**\n * Splits a `defineToolkit({ ... })` for a build target. Each inline tool is\n * routed by inferred type (see the per-entry logic); a generative entry like\n * `generative.present()` passes through, the library having already split it.\n * Mutates the object in place and records outcomes in {@link TargetFlags}.\n */\nfunction compileToolkit(\n object: t.ObjectExpression,\n target: Target,\n instances: Set<string>,\n safeToolkitSpreads: Set<string>,\n flags: TargetFlags,\n filename: string | undefined,\n): void {\n const nextProperties: t.ObjectExpression[\"properties\"] = [];\n\n for (const entry of object.properties) {\n const value = entryValue(entry);\n if (!value) {\n if (\n t.isSpreadElement(entry) &&\n isSafeToolkitSpread(entry, safeToolkitSpreads)\n ) {\n nextProperties.push(entry);\n continue;\n }\n // A generative tool (`generative.present()`) is split by the library's\n // export conditions, so it is safe to keep verbatim. Anything else — a\n // method or opaque call like `makeTool()` — can't be analyzed, so its\n // `execute` could reach the client unstripped.\n const raw = entryRawValue(entry);\n if (raw && isGenerativeToolEntry(raw, instances)) {\n nextProperties.push(entry);\n continue;\n }\n throw new GenerativeCompileError(\n \"each tool must be an inline object literal (`name: { ... }`) or a \" +\n \"compiler-visible toolkit spread / generative tool (e.g. \" +\n \"`...defineMcpToolkit(...)`, `...baseToolkit`, or \" +\n \"`generative.present()`) so its `execute` can be routed\",\n filename,\n );\n }\n\n // Nature is inferred from `execute` (see inferToolType), not an authored\n // `type`. The resolved type is written back below so the runtime keeps it.\n const execute = findMember(value, \"execute\");\n const isStub = execute ? executeIsStubTool(execute) : false;\n const isExternal = execute ? executeIsExternalTool(execute) : false;\n const type = inferToolType(value, filename);\n const hasRender = !!findMember(value, \"render\");\n const hasRenderText = !!findMember(value, \"renderText\");\n\n if (type === \"frontend\" && !hasRender && !hasRenderText) {\n throw new GenerativeCompileError(\n \"a frontend tool must declare a `render` or `renderText` \" +\n \"(it has no server execute to show otherwise)\",\n filename,\n );\n }\n\n if (type === \"human\" && !hasRender) {\n throw new GenerativeCompileError(\n \"a human tool must declare a `render` so it can collect input\",\n filename,\n );\n }\n\n if (type === \"provider\" && execute) {\n applyProviderToolConfig(value, execute, filename);\n }\n\n if (isExternal) {\n if (!hasRender && !hasRenderText) {\n throw new GenerativeCompileError(\n \"an external tool must declare a `render` or `renderText` \" +\n \"(assistant-ui only renders calls for tools defined elsewhere)\",\n filename,\n );\n }\n if (target === \"server\") continue;\n stripExternalToolMetadata(value);\n }\n\n if (target === \"client\") {\n // A non-stub frontend execute stays (its `\"use client\"` marker is no longer needed\n // once the module is client); backend, sentinel, and stub executes are dropped.\n if (execute && type === \"frontend\" && !isStub) stripUseClient(execute);\n else if (execute) removeMember(value, \"execute\");\n if (hasRender || hasRenderText) flags.keptRender = true;\n } else {\n // server: render is never needed; only a non-external backend execute survives.\n if (hasRender) removeMember(value, \"render\");\n if (hasRenderText) removeMember(value, \"renderText\");\n if (execute) {\n if (type === \"backend\" && !isExternal) flags.keptBackendExecute = true;\n else removeMember(value, \"execute\");\n }\n }\n\n setToolType(value, type);\n setBackendDefault(value, target, type);\n nextProperties.push(entry);\n }\n\n object.properties = nextProperties;\n}\n\nfunction applyProviderToolConfig(\n object: t.ObjectExpression,\n execute: t.ObjectProperty | t.ObjectMethod,\n filename: string | undefined,\n): void {\n if (\n !t.isObjectProperty(execute) ||\n !t.isCallExpression(execute.value) ||\n execute.value.arguments.length !== 1 ||\n !t.isObjectExpression(execute.value.arguments[0])\n ) {\n throw new GenerativeCompileError(\n \"`providerTool(...)` must receive an inline object literal\",\n filename,\n );\n }\n\n const existingNames = new Set(\n object.properties.flatMap((prop) => {\n if (!t.isObjectProperty(prop) && !t.isObjectMethod(prop)) return [];\n const name = memberName(prop.key, prop.computed);\n return name ? [name] : [];\n }),\n );\n const configNames = new Set<string>();\n\n for (const prop of execute.value.arguments[0].properties) {\n if (!t.isObjectProperty(prop)) {\n throw new GenerativeCompileError(\n \"`providerTool(...)` config can only contain object properties\",\n filename,\n );\n }\n const name = memberName(prop.key, prop.computed);\n if (!name) {\n throw new GenerativeCompileError(\n \"`providerTool(...)` config can only contain static property names\",\n filename,\n );\n }\n if (\n t.isFunctionExpression(prop.value) ||\n t.isArrowFunctionExpression(prop.value)\n ) {\n throw new GenerativeCompileError(\n \"`providerTool(...)` config cannot contain function-valued properties\",\n filename,\n );\n }\n if (existingNames.has(name) || configNames.has(name)) {\n throw new GenerativeCompileError(\n \"`providerTool(...)` config cannot duplicate tool properties\",\n filename,\n );\n }\n configNames.add(name);\n object.properties.push(prop);\n }\n}\n\ntype Entry = t.ObjectExpression[\"properties\"][number];\n\n/** The raw AST value of an entry (any expression), or null for spreads/methods. */\nfunction entryRawValue(entry: Entry): t.Expression | null {\n if (t.isObjectProperty(entry) && t.isExpression(entry.value)) {\n return entry.value;\n }\n return null;\n}\n\nfunction entryValue(entry: Entry): t.ObjectExpression | null {\n if (t.isObjectProperty(entry) && t.isObjectExpression(entry.value)) {\n return entry.value;\n }\n return null;\n}\n\n/** A member of an entry object: `render`/`execute`/`type`, as property or method. */\nfunction findMember(\n object: t.ObjectExpression,\n name: string,\n): t.ObjectProperty | t.ObjectMethod | undefined {\n return object.properties.find(\n (p): p is t.ObjectProperty | t.ObjectMethod =>\n (t.isObjectProperty(p) || t.isObjectMethod(p)) &&\n memberName(p.key, p.computed) === name,\n );\n}\n\nfunction removeMember(object: t.ObjectExpression, name: string): void {\n object.properties = object.properties.filter(\n (p) =>\n !(\n (t.isObjectProperty(p) || t.isObjectMethod(p)) &&\n memberName(p.key, p.computed) === name\n ),\n );\n}\n\n/** The `BlockStatement` body of an `execute` member, if it has one. */\nfunction executeBody(\n member: t.ObjectProperty | t.ObjectMethod,\n): t.BlockStatement | undefined {\n if (t.isObjectMethod(member)) return member.body;\n const value = member.value;\n if (\n (t.isArrowFunctionExpression(value) || t.isFunctionExpression(value)) &&\n t.isBlockStatement(value.body)\n ) {\n return value.body;\n }\n return undefined;\n}\n\n/** Whether an `execute` opts into the client via a leading `\"use client\"`. */\nfunction executeIsClient(member: t.ObjectProperty | t.ObjectMethod): boolean {\n return !!executeBody(member)?.directives.some(\n (d) => d.value.value === \"use client\",\n );\n}\n\nfunction executeIsSentinel(\n member: t.ObjectProperty | t.ObjectMethod,\n name: string,\n): boolean {\n return (\n t.isObjectProperty(member) &&\n t.isCallExpression(member.value) &&\n t.isIdentifier(member.value.callee, { name })\n );\n}\n\n/** Whether an `execute` is the human-in-the-loop sentinel. */\nfunction executeIsHumanTool(\n member: t.ObjectProperty | t.ObjectMethod,\n): boolean {\n return (\n executeIsSentinel(member, \"humanTool\") ||\n executeIsSentinel(member, \"hitlTool\") ||\n executeIsSentinel(member, \"hitl\")\n );\n}\n\n/** Whether an `execute` is the provider-tool sentinel. */\nfunction executeIsProviderTool(\n member: t.ObjectProperty | t.ObjectMethod,\n): boolean {\n return executeIsSentinel(member, \"providerTool\");\n}\n\n/** Whether an `execute` is the local override sentinel. */\nfunction executeIsStubTool(member: t.ObjectProperty | t.ObjectMethod): boolean {\n return executeIsSentinel(member, \"stubTool\");\n}\n\n/** Whether an `execute` is the externally-defined backend tool sentinel. */\nfunction executeIsExternalTool(\n member: t.ObjectProperty | t.ObjectMethod,\n): boolean {\n return executeIsSentinel(member, \"externalTool\");\n}\n\n/** Drops the `\"use client\"` directive from an `execute` body (kept frontend). */\nfunction stripUseClient(member: t.ObjectProperty | t.ObjectMethod): void {\n const body = executeBody(member);\n if (body) {\n body.directives = body.directives.filter(\n (d) => d.value.value !== \"use client\",\n );\n }\n}\n\n/**\n * The tool's nature, inferred from its (mandatory) `execute` rather than an\n * authored `type`: `humanTool()` → `human`; `providerTool(...)` → `provider`;\n * `stubTool()` → `frontend`; `externalTool()` → `backend`; `\"use client\"` →\n * `frontend`; otherwise `backend`.\n * The loader writes the result back as a `type` field (see {@link setToolType})\n * so the runtime keeps it.\n */\nfunction inferToolType(\n object: t.ObjectExpression,\n filename: string | undefined,\n): ToolType {\n const execute = findMember(object, \"execute\");\n if (!execute) {\n throw new GenerativeCompileError(\n \"every tool must declare an `execute`; use `humanTool()` for a \" +\n \"human-in-the-loop tool\",\n filename,\n );\n }\n if (executeIsHumanTool(execute)) return \"human\";\n if (executeIsProviderTool(execute)) return \"provider\";\n if (executeIsStubTool(execute)) return \"frontend\";\n if (executeIsExternalTool(execute)) return \"backend\";\n return executeIsClient(execute) ? \"frontend\" : \"backend\";\n}\n\nfunction stripExternalToolMetadata(object: t.ObjectExpression): void {\n // Mirror BackendTool's forbidden metadata fields: execute is stripped by the\n // main routing loop, while streamCall is also removed because there is no\n // assistant-ui executor to stream from.\n removeMember(object, \"description\");\n removeMember(object, \"parameters\");\n removeMember(object, \"disabled\");\n removeMember(object, \"toModelOutput\");\n removeMember(object, \"experimental_onSchemaValidationError\");\n removeMember(object, \"providerOptions\");\n removeMember(object, \"streamCall\");\n}\n\n/** Writes the resolved `type` back onto the tool object (replacing any author's). */\nfunction setToolType(object: t.ObjectExpression, type: ToolType): void {\n removeMember(object, \"type\");\n // Append (not prepend) so the inferred type wins over any earlier spread.\n object.properties.push(\n t.objectProperty(t.identifier(\"type\"), t.stringLiteral(type)),\n );\n}\n\nfunction setBackendDefault(\n object: t.ObjectExpression,\n target: Target,\n type: ToolType,\n): void {\n // Always strip any hand-authored marker first; only re-add it for client\n // frontend/human tools whose schema is already known by the backend.\n removeMember(object, \"unstable_backendDefault\");\n if (target !== \"client\" || (type !== \"frontend\" && type !== \"human\")) return;\n\n object.properties.push(\n t.objectProperty(\n t.identifier(\"unstable_backendDefault\"),\n t.objectExpression([\n t.objectProperty(t.identifier(\"parameters\"), t.booleanLiteral(true)),\n ]),\n ),\n );\n}\n\nfunction memberName(\n key: t.Node,\n computed: boolean | undefined,\n): string | undefined {\n if (computed) return undefined;\n if (t.isIdentifier(key)) return key.name;\n if (t.isStringLiteral(key)) return key.value;\n return undefined;\n}\n\n/**\n * Removes declarations and import specifiers left unreferenced after region\n * removal, to a fixpoint (a dropped helper frees what it used). Keeps exports,\n * side-effect imports, and possibly-side-effectful initializers.\n */\nfunction pruneUnused(ast: t.File): void {\n const hadSpecifiers = new WeakSet<t.ImportDeclaration>();\n for (const stmt of ast.program.body) {\n if (t.isImportDeclaration(stmt) && stmt.specifiers.length > 0) {\n hadSpecifiers.add(stmt);\n }\n }\n\n let removedSomething = true;\n while (removedSomething) {\n removedSomething = false;\n traverse(ast, {\n Program(path: NodePath<t.Program>) {\n path.scope.crawl();\n const isUnused = (name: string): boolean => {\n const binding = path.scope.getBinding(name);\n return !!binding && !binding.referenced;\n };\n\n path.node.body = path.node.body.filter((stmt) => {\n if (\n (t.isFunctionDeclaration(stmt) || t.isClassDeclaration(stmt)) &&\n stmt.id &&\n isUnused(stmt.id.name)\n ) {\n removedSomething = true;\n return false;\n }\n if (t.isVariableDeclaration(stmt)) {\n stmt.declarations = stmt.declarations.filter((decl) => {\n // Handles destructuring too: drop the declarator only when *every*\n // bound name is unused (else a `const { a } = server` survives and\n // keeps a server import in the client graph). Restricted to plain\n // patterns so a default/computed-key side effect isn't dropped.\n const names = Object.keys(t.getBindingIdentifiers(decl.id));\n if (\n names.length > 0 &&\n isPlainPattern(decl.id) &&\n isRemovableInit(decl.init) &&\n names.every(isUnused)\n ) {\n removedSomething = true;\n return false;\n }\n return true;\n });\n if (stmt.declarations.length === 0) return false;\n }\n return true;\n });\n path.stop();\n },\n });\n }\n\n traverse(ast, {\n Program(path: NodePath<t.Program>) {\n path.scope.crawl();\n for (const stmt of path.node.body) {\n if (!t.isImportDeclaration(stmt)) continue;\n stmt.specifiers = stmt.specifiers.filter((spec) => {\n const binding = path.scope.getBinding(spec.local.name);\n return binding ? binding.referenced : true;\n });\n }\n path.node.body = path.node.body.filter(\n (stmt) =>\n !(\n t.isImportDeclaration(stmt) &&\n stmt.specifiers.length === 0 &&\n hadSpecifiers.has(stmt)\n ),\n );\n path.stop();\n },\n });\n}\n\n/**\n * Whether a binding pattern is side-effect-free to drop: a plain identifier, or\n * an object/array pattern of plain bindings — no default values\n * (`{ a = expr }`) or computed keys (`{ [expr]: a }`), which would evaluate (and\n * thus could have side effects) at destructuring time.\n */\nfunction isPlainPattern(node: t.Node): boolean {\n if (t.isIdentifier(node)) return true;\n if (t.isObjectPattern(node)) {\n return node.properties.every((p) =>\n t.isRestElement(p)\n ? isPlainPattern(p.argument)\n : !p.computed && isPlainPattern(p.value),\n );\n }\n if (t.isArrayPattern(node)) {\n return node.elements.every((el) => el == null || isPlainPattern(el));\n }\n return false; // AssignmentPattern (default), member expr, etc.\n}\n\n/** Whether a variable initializer is safe to drop (no observable side effects). */\nfunction isRemovableInit(node: t.Expression | null | undefined): boolean {\n if (node == null) return true;\n if (t.isTSAsExpression(node) || t.isTSSatisfiesExpression(node)) {\n return isRemovableInit(node.expression);\n }\n // Containers are removable only if every element is — a nested call (e.g.\n // `[track()]`) has an observable side effect that dropping would lose.\n if (t.isArrayExpression(node)) {\n return node.elements.every(\n (el) => el == null || (t.isExpression(el) && isRemovableInit(el)),\n );\n }\n if (t.isObjectExpression(node)) {\n return node.properties.every(\n (p) =>\n t.isObjectProperty(p) &&\n !p.computed &&\n t.isExpression(p.value) &&\n isRemovableInit(p.value),\n );\n }\n if (t.isTemplateLiteral(node)) {\n return node.expressions.every(\n (e) => t.isExpression(e) && isRemovableInit(e),\n );\n }\n return (\n t.isArrowFunctionExpression(node) ||\n t.isFunctionExpression(node) ||\n t.isClassExpression(node) ||\n t.isIdentifier(node) ||\n // non-computed only — `obj[fn()]` could hide a side-effectful key\n (t.isMemberExpression(node) && !node.computed) ||\n t.isJSXElement(node) ||\n t.isJSXFragment(node) ||\n t.isLiteral(node)\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ //#region package.json
2
+ var version = "0.0.5";
3
+ //#endregion
4
+ export { version };
5
+
6
+ //# sourceMappingURL=package.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package.js","names":[],"sources":["../package.json"],"sourcesContent":[""],"mappings":""}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@assistant-ui/x-generative-compiler",
3
3
  "private": false,
4
- "version": "0.0.3",
4
+ "version": "0.0.5",
5
5
  "description": "Internal: the framework-agnostic \"use generative\" compiler that splits a colocated tool (schema + server-only execute + client-only render) into per-target builds. Shared by @assistant-ui/next and @assistant-ui/vite.",
6
6
  "keywords": [
7
7
  "assistant-ui",
@@ -28,25 +28,20 @@
28
28
  "README.md"
29
29
  ],
30
30
  "sideEffects": false,
31
- "scripts": {
32
- "build": "aui-build",
33
- "test": "vitest run",
34
- "test:watch": "vitest"
35
- },
36
31
  "dependencies": {
37
32
  "@babel/generator": "^7.29.7",
38
33
  "@babel/parser": "^7.29.7",
39
34
  "@babel/traverse": "^7.29.7",
40
35
  "@babel/types": "^7.29.7",
41
- "semver": "^7.8.1"
36
+ "semver": "^7.8.4"
42
37
  },
43
38
  "devDependencies": {
44
- "@assistant-ui/x-buildutils": "workspace:*",
45
39
  "@types/babel__generator": "^7.27.0",
46
40
  "@types/babel__traverse": "^7.28.0",
47
- "@types/node": "^25.9.1",
41
+ "@types/node": "^25.9.3",
48
42
  "@types/semver": "^7.7.1",
49
- "vitest": "^4.1.7"
43
+ "vitest": "^4.1.8",
44
+ "@assistant-ui/x-buildutils": "0.0.14"
50
45
  },
51
46
  "publishConfig": {
52
47
  "access": "public",
@@ -60,5 +55,10 @@
60
55
  },
61
56
  "bugs": {
62
57
  "url": "https://github.com/assistant-ui/assistant-ui/issues"
58
+ },
59
+ "scripts": {
60
+ "build": "aui-build",
61
+ "test": "vitest run",
62
+ "test:watch": "vitest"
63
63
  }
64
- }
64
+ }
@@ -73,6 +73,50 @@ function createCompatibilityFixture(range: string | null): string {
73
73
  return filename;
74
74
  }
75
75
 
76
+ /**
77
+ * Writes a child module to disk next to a (not-yet-written) `toolkit.tsx` and
78
+ * returns the parent's filename, so a parent compiled from a string can resolve
79
+ * `./tools/child` relative to it. Used to exercise cross-file toolkit spreads.
80
+ */
81
+ function createMergeFixture(childSource: string): string {
82
+ const appRoot = mkdtempSync(nodePath.join(tmpdir(), "aui-generative-merge-"));
83
+ const toolsRoot = nodePath.join(appRoot, "src", "tools");
84
+ mkdirSync(toolsRoot, { recursive: true });
85
+ writeFileSync(nodePath.join(toolsRoot, "weather.tsx"), childSource);
86
+ return nodePath.join(appRoot, "src", "toolkit.tsx");
87
+ }
88
+
89
+ /**
90
+ * Like {@link createMergeFixture}, but also writes a (JSONC) `tsconfig.json`
91
+ * with a `@/*` path alias so alias resolution can be exercised. The child lives
92
+ * at `src/tools/weather.tsx` and `@/*` maps to `./src/*`.
93
+ */
94
+ function createAliasMergeFixture(childSource: string): string {
95
+ const filename = createMergeFixture(childSource);
96
+ const appRoot = nodePath.dirname(nodePath.dirname(filename));
97
+ writeFileSync(
98
+ nodePath.join(appRoot, "tsconfig.json"),
99
+ `{
100
+ // path aliases
101
+ "compilerOptions": {
102
+ "baseUrl": ".",
103
+ "paths": { "@/*": ["./src/*"] },
104
+ }
105
+ }`,
106
+ );
107
+ return filename;
108
+ }
109
+
110
+ const generativeChild = `"use generative";
111
+ import { defineToolkit } from "@assistant-ui/react";
112
+ export default defineToolkit({
113
+ get_weather: {
114
+ execute: async () => 1,
115
+ render: () => null,
116
+ },
117
+ });
118
+ `;
119
+
76
120
  const source = `"use generative";
77
121
  import { z } from "zod";
78
122
  import { db } from "@/db";
@@ -497,6 +541,139 @@ export default defineToolkit({
497
541
  );
498
542
  });
499
543
 
544
+ it("allows spreading the default import of a generative module", () => {
545
+ const filename = createMergeFixture(generativeChild);
546
+ const src = `"use generative";
547
+ import { defineToolkit } from "@assistant-ui/react";
548
+ import weatherTools from "./tools/weather";
549
+ export default defineToolkit({
550
+ ...weatherTools,
551
+ });`;
552
+
553
+ const server = compileGenerative(src, { target: "server", filename }).code;
554
+ expect(server).toContain("...weatherTools");
555
+ expect(server).toContain('from "./tools/weather"');
556
+
557
+ const client = compileGenerative(src, { target: "client", filename }).code;
558
+ expect(client).toContain("...weatherTools");
559
+ expect(client).toContain('from "./tools/weather"');
560
+ });
561
+
562
+ it("rejects spreading the default import of a non-generative module", () => {
563
+ const filename = createMergeFixture(
564
+ `export default { get_weather: { execute: async () => 1 } };\n`,
565
+ );
566
+ const src = `"use generative";
567
+ import { defineToolkit } from "@assistant-ui/react";
568
+ import weatherTools from "./tools/weather";
569
+ export default defineToolkit({
570
+ ...weatherTools,
571
+ });`;
572
+
573
+ expect(() =>
574
+ compileGenerative(src, { target: "client", filename }),
575
+ ).toThrow(/compiler-visible toolkit spread/);
576
+ });
577
+
578
+ it("rejects spreading a named import even from a generative module", () => {
579
+ const filename = createMergeFixture(generativeChild);
580
+ const src = `"use generative";
581
+ import { defineToolkit } from "@assistant-ui/react";
582
+ import { weatherTools } from "./tools/weather";
583
+ export default defineToolkit({
584
+ ...weatherTools,
585
+ });`;
586
+
587
+ expect(() =>
588
+ compileGenerative(src, { target: "client", filename }),
589
+ ).toThrow(/compiler-visible toolkit spread/);
590
+ });
591
+
592
+ it("resolves a tsconfig path alias when spreading a generative module", () => {
593
+ const filename = createAliasMergeFixture(generativeChild);
594
+ const src = `"use generative";
595
+ import { defineToolkit } from "@assistant-ui/react";
596
+ import weatherTools from "@/tools/weather";
597
+ export default defineToolkit({
598
+ ...weatherTools,
599
+ });`;
600
+
601
+ const client = compileGenerative(src, { target: "client", filename }).code;
602
+ expect(client).toContain("...weatherTools");
603
+ expect(client).toContain('from "@/tools/weather"');
604
+ });
605
+
606
+ it("prefers the most specific tsconfig path alias", () => {
607
+ const appRoot = mkdtempSync(
608
+ nodePath.join(tmpdir(), "aui-generative-alias-spec-"),
609
+ );
610
+ mkdirSync(nodePath.join(appRoot, "src", "tools"), { recursive: true });
611
+ mkdirSync(nodePath.join(appRoot, "generated"), { recursive: true });
612
+ // The broader `@/*` alias would resolve here — a non-generative module.
613
+ writeFileSync(
614
+ nodePath.join(appRoot, "src", "tools", "weather.tsx"),
615
+ `export default { get_weather: { execute: async () => 1 } };\n`,
616
+ );
617
+ // The more specific `@/tools/*` alias resolves to the generative module.
618
+ writeFileSync(
619
+ nodePath.join(appRoot, "generated", "weather.tsx"),
620
+ generativeChild,
621
+ );
622
+ writeFileSync(
623
+ nodePath.join(appRoot, "tsconfig.json"),
624
+ `{
625
+ "compilerOptions": {
626
+ "baseUrl": ".",
627
+ "paths": {
628
+ "@/*": ["./src/*"],
629
+ "@/tools/*": ["./generated/*"]
630
+ }
631
+ }
632
+ }`,
633
+ );
634
+ const filename = nodePath.join(appRoot, "src", "toolkit.tsx");
635
+ const src = `"use generative";
636
+ import { defineToolkit } from "@assistant-ui/react";
637
+ import weatherTools from "@/tools/weather";
638
+ export default defineToolkit({
639
+ ...weatherTools,
640
+ });`;
641
+
642
+ // `@/tools/*` is more specific than `@/*`, so it wins and the spread is the
643
+ // generative module (allowed) rather than the non-generative `@/*` target.
644
+ const client = compileGenerative(src, { target: "client", filename }).code;
645
+ expect(client).toContain("...weatherTools");
646
+ });
647
+
648
+ it("resolves a .js specifier to its .tsx source when spreading", () => {
649
+ const filename = createMergeFixture(generativeChild);
650
+ const src = `"use generative";
651
+ import { defineToolkit } from "@assistant-ui/react";
652
+ import weatherTools from "./tools/weather.js";
653
+ export default defineToolkit({
654
+ ...weatherTools,
655
+ });`;
656
+
657
+ const client = compileGenerative(src, { target: "client", filename }).code;
658
+ expect(client).toContain("...weatherTools");
659
+ });
660
+
661
+ it("allows defineMcpToolkit as the default export", () => {
662
+ const src = `"use generative";
663
+ import { defineMcpToolkit } from "@assistant-ui/react";
664
+ export default defineMcpToolkit({
665
+ docs: { type: "http", url: "https://mcp.example.com/mcp" },
666
+ });`;
667
+
668
+ const server = compileGenerative(src, { target: "server" }).code;
669
+ expect(server).toContain("defineMcpToolkit");
670
+ expect(server).toContain("docs");
671
+
672
+ const client = compileGenerative(src, { target: "client" }).code;
673
+ expect(client).toContain("defineMcpToolkit");
674
+ expect(client).toContain("docs");
675
+ });
676
+
500
677
  it("still allows a flat toolkit tool named tools", () => {
501
678
  const src = `"use generative";
502
679
  import { defineToolkit } from "@assistant-ui/react";
package/src/compile.ts CHANGED
@@ -7,6 +7,7 @@ import _generate from "@babel/generator";
7
7
  import * as t from "@babel/types";
8
8
  import { satisfies } from "semver";
9
9
  import { DIRECTIVE, type Target } from "./constants";
10
+ import pkgJson from "../package.json" with { type: "json" };
10
11
 
11
12
  // @babel/traverse and @babel/generator are CJS; their default export is the
12
13
  // function itself under some interop and `{ default }` under others.
@@ -139,7 +140,7 @@ export function compileGenerative(
139
140
  // such entries pass through.
140
141
  ensureDefaultExport(ast, filename);
141
142
  const generativeInstances = collectGenerativeInstances(ast);
142
- const safeToolkitSpreads = collectSafeToolkitSpreads(ast);
143
+ const safeToolkitSpreads = collectSafeToolkitSpreads(ast, filename);
143
144
 
144
145
  const flags: TargetFlags = { keptRender: false, keptBackendExecute: false };
145
146
 
@@ -229,7 +230,12 @@ interface PackageJson {
229
230
  }
230
231
 
231
232
  const checkedCorePackageJsonPaths = new Set<string>();
232
- let compilerPackageVersion: string | undefined;
233
+
234
+ // This compiler's own version, inlined from package.json at build time. Read via
235
+ // an import (not by walking the filesystem at runtime) so the literal survives
236
+ // being bundled into a host package like `@assistant-ui/metro`, where no
237
+ // standalone `@assistant-ui/x-generative-compiler` sits on disk to walk up to.
238
+ const COMPILER_VERSION = pkgJson.version;
233
239
 
234
240
  function ensureCompilerCompatibleWithCore(
235
241
  ast: t.File,
@@ -250,10 +256,9 @@ function ensureCompilerCompatibleWithCore(
250
256
  return;
251
257
  }
252
258
 
253
- const compilerVersion = getCompilerPackageVersion();
254
259
  let compatible = false;
255
260
  try {
256
- compatible = satisfies(compilerVersion, range, {
261
+ compatible = satisfies(COMPILER_VERSION, range, {
257
262
  includePrerelease: true,
258
263
  });
259
264
  } catch {
@@ -269,8 +274,8 @@ function ensureCompilerCompatibleWithCore(
269
274
  throw new GenerativeCompileError(
270
275
  `${CORE_PACKAGE}@${corePackageJson.version ?? "unknown"} requires ` +
271
276
  `${COMPILER_PACKAGE} ${range}, but the current compiler is ` +
272
- `${compilerVersion}. Update @assistant-ui/next or @assistant-ui/vite ` +
273
- "so their compiler satisfies the core package's " +
277
+ `${COMPILER_VERSION}. Update @assistant-ui/next, @assistant-ui/vite, ` +
278
+ "or @assistant-ui/metro so their compiler satisfies the core package's " +
274
279
  "optionalDevDependencies range.",
275
280
  filename,
276
281
  );
@@ -279,20 +284,6 @@ function ensureCompilerCompatibleWithCore(
279
284
  checkedCorePackageJsonPaths.add(corePackageJsonPath);
280
285
  }
281
286
 
282
- function getCompilerPackageVersion(): string {
283
- if (compilerPackageVersion) return compilerPackageVersion;
284
-
285
- const packageJsonPath = findPackageJson(import.meta.url, COMPILER_PACKAGE);
286
- const packageJson = packageJsonPath ? readPackageJson(packageJsonPath) : null;
287
- if (!packageJson?.version) {
288
- throw new GenerativeCompileError(
289
- `could not determine ${COMPILER_PACKAGE}'s package version`,
290
- );
291
- }
292
- compilerPackageVersion = packageJson.version;
293
- return compilerPackageVersion;
294
- }
295
-
296
287
  function resolveCorePackageJson(
297
288
  ast: t.File,
298
289
  filename: string | undefined,
@@ -357,11 +348,14 @@ function resolvePackageJson(
357
348
  }
358
349
 
359
350
  function normalizeRequirePath(filename: string | undefined): string {
360
- if (filename) {
361
- const cleanFilename = filename.split(/[?#]/, 1)[0]!;
362
- if (nodePath.isAbsolute(cleanFilename)) return cleanFilename;
363
- }
364
- return import.meta.url;
351
+ return cleanAbsoluteFilename(filename) ?? import.meta.url;
352
+ }
353
+
354
+ /** Strips a `?query`/`#hash` suffix and returns the path only if it is absolute. */
355
+ function cleanAbsoluteFilename(filename: string | undefined): string | null {
356
+ if (!filename) return null;
357
+ const clean = filename.split(/[?#]/, 1)[0]!;
358
+ return nodePath.isAbsolute(clean) ? clean : null;
365
359
  }
366
360
 
367
361
  function findPackageJson(
@@ -440,11 +434,12 @@ function ensureDefaultExport(ast: t.File, filename: string | undefined): void {
440
434
  if (!def) {
441
435
  throw new GenerativeCompileError("missing a default export", filename);
442
436
  }
443
- if (!unwrapToCall(def.declaration, TOOLKIT_WRAPPER)) {
437
+ if (!unwrapToToolkitCall(def.declaration)) {
444
438
  throw new GenerativeCompileError(
445
- `the default export must be ${TOOLKIT_WRAPPER}({ ... }) (imported from ` +
446
- '"@assistant-ui/react"); wrapping is required so a backend `execute` ' +
447
- "can't be authored in a way that reaches the client",
439
+ `the default export must be ${TOOLKIT_WRAPPER}({ ... }) or ` +
440
+ `${MCP_TOOLKIT_WRAPPER}({ ... }) (imported from "@assistant-ui/react"); ` +
441
+ "wrapping is required so a backend `execute` can't be authored in a way " +
442
+ "that reaches the client",
448
443
  filename,
449
444
  );
450
445
  }
@@ -492,24 +487,309 @@ function collectGenerativeInstances(ast: t.File): Set<string> {
492
487
  }
493
488
 
494
489
  /**
495
- * Local toolkit variables whose initializer is visible to this compiler pass
496
- * are safe to spread. `defineToolkit(...)` initializers are compiled in-place
497
- * before a later spread reads them; `defineMcpToolkit(...)` entries cannot
498
- * contain executable code.
490
+ * Toolkit identifiers that are safe to spread into a `defineToolkit({ ... })`.
491
+ *
492
+ * Two kinds qualify:
493
+ *
494
+ * - A local variable whose initializer is visible to this compiler pass: a
495
+ * `defineToolkit(...)` binding is compiled in-place before a later spread
496
+ * reads it, and `defineMcpToolkit(...)` entries can't contain executable code.
497
+ * - The default import of another `"use generative"` module: that module is
498
+ * split per-target by its own compiler pass, so spreading its default-exported
499
+ * toolkit can't leak a backend `execute` to the client. Only the default
500
+ * export crosses the generative-module boundary, so named imports don't
501
+ * qualify — they would be `undefined` once that module is build-split.
499
502
  */
500
- function collectSafeToolkitSpreads(ast: t.File): Set<string> {
503
+ function collectSafeToolkitSpreads(
504
+ ast: t.File,
505
+ filename: string | undefined,
506
+ ): Set<string> {
501
507
  const names = new Set<string>();
508
+ const generativeBySource = new Map<string, boolean>();
509
+
502
510
  for (const statement of ast.program.body) {
503
- if (!t.isVariableDeclaration(statement)) continue;
504
- for (const declaration of statement.declarations) {
505
- const { id, init } = declaration;
506
- if (!t.isIdentifier(id) || !init) continue;
507
- if (unwrapToToolkitCall(init)) names.add(id.name);
511
+ if (t.isVariableDeclaration(statement)) {
512
+ for (const declaration of statement.declarations) {
513
+ const { id, init } = declaration;
514
+ if (t.isIdentifier(id) && init && unwrapToToolkitCall(init)) {
515
+ names.add(id.name);
516
+ }
517
+ }
518
+ continue;
519
+ }
520
+
521
+ if (t.isImportDeclaration(statement)) {
522
+ const defaultSpecifier = statement.specifiers.find(
523
+ (specifier): specifier is t.ImportDefaultSpecifier =>
524
+ t.isImportDefaultSpecifier(specifier),
525
+ );
526
+ if (!defaultSpecifier) continue;
527
+
528
+ const source = statement.source.value;
529
+ let isGenerative = generativeBySource.get(source);
530
+ if (isGenerative === undefined) {
531
+ isGenerative = isGenerativeImport(source, filename);
532
+ generativeBySource.set(source, isGenerative);
533
+ }
534
+ if (isGenerative) names.add(defaultSpecifier.local.name);
508
535
  }
509
536
  }
537
+
510
538
  return names;
511
539
  }
512
540
 
541
+ const MODULE_EXTENSIONS = [
542
+ ".ts",
543
+ ".tsx",
544
+ ".mts",
545
+ ".cts",
546
+ ".js",
547
+ ".jsx",
548
+ ".mjs",
549
+ ".cjs",
550
+ ] as const;
551
+
552
+ /** Extensions a specifier may carry that actually map to a TS source file. */
553
+ const REWRITABLE_JS_EXTENSIONS = new Set([".js", ".jsx", ".mjs", ".cjs"]);
554
+
555
+ /**
556
+ * Whether an import specifier resolves on disk to a `"use generative"` module.
557
+ * Relative specifiers and `tsconfig` path aliases (e.g. `@/tools`) are resolved;
558
+ * anything else (a bare package, an unresolvable alias) is treated as
559
+ * non-generative, and thus an unsafe spread.
560
+ */
561
+ function isGenerativeImport(
562
+ source: string,
563
+ filename: string | undefined,
564
+ ): boolean {
565
+ const cleanFilename = cleanAbsoluteFilename(filename);
566
+ if (!cleanFilename) return false;
567
+
568
+ const resolved = resolveImportedModuleFile(source, cleanFilename);
569
+ if (!resolved) return false;
570
+
571
+ try {
572
+ return isGenerativeModule(readFileSync(resolved, "utf8"));
573
+ } catch {
574
+ return false;
575
+ }
576
+ }
577
+
578
+ /** Resolves an import specifier (relative or `tsconfig`-aliased) to a file on disk. */
579
+ function resolveImportedModuleFile(
580
+ source: string,
581
+ fromFilename: string,
582
+ ): string | null {
583
+ if (source.startsWith(".")) {
584
+ const base = nodePath.resolve(nodePath.dirname(fromFilename), source);
585
+ return resolveModuleFileAtPath(base);
586
+ }
587
+ return resolveAliasImport(source, fromFilename);
588
+ }
589
+
590
+ /**
591
+ * Resolves a candidate module path, trying TS/JS extensions then index files. A
592
+ * specifier may carry a `.js`-family extension that maps to a `.ts`/`.tsx`
593
+ * source (TypeScript's `bundler`/`nodenext` resolution), so the extension is
594
+ * dropped before probing.
595
+ */
596
+ function resolveModuleFileAtPath(base: string): string | null {
597
+ const ext = nodePath.extname(base);
598
+ if (ext && existsSync(base)) return base;
599
+
600
+ const stem = REWRITABLE_JS_EXTENSIONS.has(ext)
601
+ ? base.slice(0, -ext.length)
602
+ : base;
603
+
604
+ for (const candidateExt of MODULE_EXTENSIONS) {
605
+ const candidate = `${stem}${candidateExt}`;
606
+ if (existsSync(candidate)) return candidate;
607
+ }
608
+ for (const candidateExt of MODULE_EXTENSIONS) {
609
+ const candidate = nodePath.join(base, `index${candidateExt}`);
610
+ if (existsSync(candidate)) return candidate;
611
+ }
612
+ return null;
613
+ }
614
+
615
+ interface TsconfigAliases {
616
+ /** Absolute directory that `paths` targets resolve against. */
617
+ baseDir: string;
618
+ paths: Record<string, string[]>;
619
+ }
620
+
621
+ /** Resolves a `tsconfig` path alias (e.g. `@/tools/x`) to a file on disk. */
622
+ function resolveAliasImport(
623
+ source: string,
624
+ fromFilename: string,
625
+ ): string | null {
626
+ const tsconfig = loadTsconfigAliases(nodePath.dirname(fromFilename));
627
+ if (!tsconfig) return null;
628
+
629
+ // TypeScript matches the most specific key first: an exact (wildcard-free) key
630
+ // beats a wildcard one, and a longer static prefix beats a shorter one.
631
+ const patterns = Object.entries(tsconfig.paths).sort(
632
+ ([a], [b]) => aliasSpecificity(b) - aliasSpecificity(a),
633
+ );
634
+
635
+ for (const [pattern, targets] of patterns) {
636
+ const matched = matchAliasPattern(pattern, source);
637
+ if (matched === null) continue;
638
+
639
+ for (const target of targets) {
640
+ const specifier = substituteAliasWildcard(target, matched);
641
+ const file = resolveModuleFileAtPath(
642
+ nodePath.resolve(tsconfig.baseDir, specifier),
643
+ );
644
+ if (file) return file;
645
+ }
646
+ }
647
+ return null;
648
+ }
649
+
650
+ /** Ranks a `paths` key: an exact key outranks any wildcard; longer prefixes win. */
651
+ function aliasSpecificity(pattern: string): number {
652
+ const star = pattern.indexOf("*");
653
+ return star === -1 ? pattern.length + 1 : star;
654
+ }
655
+
656
+ /** Substitutes the single `*` in a `paths` target with the matched text. */
657
+ function substituteAliasWildcard(target: string, matched: string): string {
658
+ const star = target.indexOf("*");
659
+ if (star === -1) return target;
660
+ return target.slice(0, star) + matched + target.slice(star + 1);
661
+ }
662
+
663
+ /**
664
+ * Matches an import specifier against a `tsconfig` `paths` key. Returns the text
665
+ * captured by the key's `*` (or `""` for an exact, wildcard-free key), or `null`
666
+ * when the specifier doesn't match.
667
+ */
668
+ function matchAliasPattern(pattern: string, source: string): string | null {
669
+ const star = pattern.indexOf("*");
670
+ if (star === -1) return pattern === source ? "" : null;
671
+
672
+ const prefix = pattern.slice(0, star);
673
+ const suffix = pattern.slice(star + 1);
674
+ if (
675
+ source.length >= prefix.length + suffix.length &&
676
+ source.startsWith(prefix) &&
677
+ source.endsWith(suffix)
678
+ ) {
679
+ return source.slice(prefix.length, source.length - suffix.length);
680
+ }
681
+ return null;
682
+ }
683
+
684
+ /**
685
+ * Memoizes resolved aliases per start directory. The compiler runs once per
686
+ * file across a build, so without this every aliased spread re-walks and
687
+ * re-parses the same `tsconfig.json`. Process-lifetime, like
688
+ * `checkedCorePackageJsonPaths`.
689
+ */
690
+ const tsconfigAliasesByDir = new Map<string, TsconfigAliases | null>();
691
+
692
+ /** Walks up from a directory to the nearest `tsconfig.json` that declares `paths`. */
693
+ function loadTsconfigAliases(fromDir: string): TsconfigAliases | null {
694
+ const cached = tsconfigAliasesByDir.get(fromDir);
695
+ if (cached !== undefined) return cached;
696
+
697
+ let aliases: TsconfigAliases | null = null;
698
+ let dir = fromDir;
699
+ for (;;) {
700
+ const tsconfigPath = nodePath.join(dir, "tsconfig.json");
701
+ if (existsSync(tsconfigPath)) {
702
+ aliases = readTsconfigAliases(tsconfigPath, new Set());
703
+ if (aliases) break;
704
+ }
705
+ const parent = nodePath.dirname(dir);
706
+ if (parent === dir) break;
707
+ dir = parent;
708
+ }
709
+
710
+ tsconfigAliasesByDir.set(fromDir, aliases);
711
+ return aliases;
712
+ }
713
+
714
+ /** Reads `baseUrl`/`paths` from a tsconfig, following a single `extends` chain. */
715
+ function readTsconfigAliases(
716
+ tsconfigPath: string,
717
+ seen: Set<string>,
718
+ ): TsconfigAliases | null {
719
+ if (seen.has(tsconfigPath)) return null;
720
+ seen.add(tsconfigPath);
721
+
722
+ let config: {
723
+ extends?: string | string[];
724
+ compilerOptions?: { baseUrl?: string; paths?: Record<string, string[]> };
725
+ } | null;
726
+ try {
727
+ config = parseJsonc(readFileSync(tsconfigPath, "utf8"));
728
+ } catch {
729
+ return null;
730
+ }
731
+ if (!config) return null;
732
+
733
+ const configDir = nodePath.dirname(tsconfigPath);
734
+ const { baseUrl, paths } = config.compilerOptions ?? {};
735
+
736
+ if (paths) {
737
+ return {
738
+ baseDir: baseUrl ? nodePath.resolve(configDir, baseUrl) : configDir,
739
+ paths,
740
+ };
741
+ }
742
+
743
+ // `extends` may be a string or (TS 5.0+) a string array; later entries take
744
+ // precedence, so try them last-first. Parsed from untrusted JSONC, so the
745
+ // array case is a real runtime shape, not just a type.
746
+ const extendsList = Array.isArray(config.extends)
747
+ ? config.extends
748
+ : config.extends
749
+ ? [config.extends]
750
+ : [];
751
+ for (let i = extendsList.length - 1; i >= 0; i--) {
752
+ const entry = extendsList[i];
753
+ if (typeof entry !== "string") continue;
754
+ const extended = resolveExtendedTsconfig(entry, configDir);
755
+ if (extended) {
756
+ const aliases = readTsconfigAliases(extended, seen);
757
+ if (aliases) return aliases;
758
+ }
759
+ }
760
+ return null;
761
+ }
762
+
763
+ /** Resolves a tsconfig `extends` value (relative path or installed package). */
764
+ function resolveExtendedTsconfig(
765
+ extendsValue: string,
766
+ configDir: string,
767
+ ): string | null {
768
+ if (extendsValue.startsWith(".")) {
769
+ const base = nodePath.resolve(configDir, extendsValue);
770
+ const candidates =
771
+ nodePath.extname(base) === ".json" ? [base] : [`${base}.json`, base];
772
+ return candidates.find((candidate) => existsSync(candidate)) ?? null;
773
+ }
774
+ try {
775
+ return createRequire(nodePath.join(configDir, "package.json")).resolve(
776
+ extendsValue.endsWith(".json") ? extendsValue : `${extendsValue}.json`,
777
+ );
778
+ } catch {
779
+ return null;
780
+ }
781
+ }
782
+
783
+ /** Parses JSON with `//` and block comments and trailing commas stripped (tsconfig is JSONC). */
784
+ function parseJsonc(text: string): any {
785
+ const withoutComments = text.replace(
786
+ /"(?:[^"\\]|\\.)*"|\/\/[^\n\r]*|\/\*[\s\S]*?\*\//g,
787
+ (match) => (match.startsWith('"') ? match : ""),
788
+ );
789
+ const withoutTrailingCommas = withoutComments.replace(/,(\s*[}\]])/g, "$1");
790
+ return JSON.parse(withoutTrailingCommas);
791
+ }
792
+
513
793
  function unwrapToToolkitCall(node: t.Node): t.CallExpression | null {
514
794
  return (
515
795
  unwrapToCall(node, TOOLKIT_WRAPPER) ??