@happyvertical/smrt-core 0.43.2 → 0.43.4
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/agents/collection-reads.md +30 -0
- package/agents/generators.md +18 -0
- package/dist/__typechecks__/custom-action-metadata.d.ts +2 -0
- package/dist/__typechecks__/custom-action-metadata.d.ts.map +1 -0
- package/dist/browser.js +2 -2
- package/dist/collection.d.ts +56 -3
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +61 -56
- package/dist/collection.js.map +1 -1
- package/dist/generators/custom-action.d.ts +11 -2
- package/dist/generators/custom-action.d.ts.map +1 -1
- package/dist/generators/custom-action.js +18 -1
- package/dist/generators/custom-action.js.map +1 -1
- package/dist/generators/index.d.ts +1 -1
- package/dist/generators/index.d.ts.map +1 -1
- package/dist/generators/rest.d.ts.map +1 -1
- package/dist/generators/rest.js +3 -2
- package/dist/generators/rest.js.map +1 -1
- package/dist/generators/tool-schema.d.ts +8 -2
- package/dist/generators/tool-schema.d.ts.map +1 -1
- package/dist/generators/tool-schema.js +46 -8
- package/dist/generators/tool-schema.js.map +1 -1
- package/dist/index.js +2 -2
- package/dist/manifest/static-manifest.js +3 -3
- package/dist/manifest/static-manifest.js.map +1 -1
- package/dist/manifest/store.js +1 -1
- package/dist/manifest/store.js.map +1 -1
- package/dist/manifest.json +3 -3
- package/dist/prebuild/index.d.ts.map +1 -1
- package/dist/prebuild/index.js +17 -0
- package/dist/prebuild/index.js.map +1 -1
- package/dist/registry/types.d.ts +13 -0
- package/dist/registry/types.d.ts.map +1 -1
- package/dist/smrt-knowledge.json +9 -9
- package/dist/vite-plugin/index.d.ts.map +1 -1
- package/dist/vite-plugin/index.js +23 -1
- package/dist/vite-plugin/index.js.map +1 -1
- package/dist/vite-plugin/web-collections.d.ts +49 -1
- package/dist/vite-plugin/web-collections.d.ts.map +1 -1
- package/dist/vite-plugin/web-collections.js +185 -19
- package/dist/vite-plugin/web-collections.js.map +1 -1
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/vite-plugin/index.ts"],"sourcesContent":["/**\n * Vite plugin for automatic SMRT service generation\n * Provides virtual modules for REST, MCP, and other services\n */\n\nimport { existsSync, readFileSync } from 'node:fs';\nimport { dirname, join, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type {\n DomainKnowledgeConfig,\n DomainKnowledgeManifest,\n} from '@happyvertical/smrt-types';\nimport type { Plugin, ResolvedConfig, ViteDevServer } from 'vite';\nimport {\n loadVerifiedSmrtGenerationSnapshot,\n type SmrtGenerationSnapshotOptions,\n} from '../generation-snapshot.js';\nimport { buildDomainKnowledgeManifest } from '../knowledge.js';\nimport { discoverSmrtPackages } from '../manifest/discover-smrt-packages.js';\nimport {\n DETERMINISTIC_GENERATED_AT,\n type SmartObjectManifest,\n} from '../scanner/types.js';\nimport { importWorkspaceModule } from '../utils/import-workspace-module.js';\nimport type { ScannerModule } from '../utils/scanner-module.js';\nimport {\n renderApiClientCrudType,\n renderApiClientCustomMethodParameters,\n selectApiClientEntries,\n} from './api-client-entries.js';\nimport {\n GENERATED_CLIENT_BASE_METHODS,\n GENERATED_CLIENT_CRUD_METHODS,\n generateClientModule,\n} from './generated-client.js';\nimport { importBuildAwareModule } from './import-build-aware.js';\nimport {\n findCliApiCoherenceViolations,\n generateSvelteKitRoutes,\n validateCliIncludeAgainstApi,\n} from './sveltekit-generator.js';\nimport {\n buildWebCollectionDefinition,\n buildWebToolDescriptors,\n computeWebManifestHash,\n selectWebCollectionEntries,\n} from './web-collections.js';\n\nexport {\n loadVerifiedSmrtGenerationSnapshot,\n type SerializeSmrtGenerationSnapshotOptions,\n type SmrtGenerationSnapshotArtifact,\n type SmrtGenerationSnapshotOptions,\n type SmrtGenerationSnapshotView,\n serializeSmrtGenerationSnapshot,\n sha256SmrtGenerationSnapshot,\n} from '../generation-snapshot.js';\nexport type {\n CliApiCoherenceViolation,\n SvelteKitOptions,\n} from './sveltekit-generator.js';\n// Re-export SvelteKit route generator for CLI usage\nexport {\n findCliApiCoherenceViolations,\n generateSvelteKitRoutes,\n methodNameToKebab,\n resolveApiActionRouteConfig,\n resolveApiActionSet,\n validateCliIncludeAgainstApi,\n} from './sveltekit-generator.js';\n\n/**\n * Minimal structural shape of a parsed `package.json`. Only the fields the\n * plugin reads are typed; the index signature keeps the rest accessible (e.g.\n * `exports`, consumed downstream by agent-manifest generation).\n */\ninterface PackageJsonShape {\n name?: string;\n version?: string;\n [key: string]: unknown;\n}\n\nexport interface SmrtPluginOptions {\n /** Root directory that owns generated manifests and SvelteKit routes. */\n projectRoot?: string;\n /**\n * Reuse an immutable, verified manifest instead of scanning sources or\n * writing manifest files. Generated routes, virtual modules, and type\n * declarations still consume the verified manifest.\n */\n generationSnapshot?: SmrtGenerationSnapshotOptions;\n /** Glob patterns for SMRT source files */\n include?: string[];\n /** Patterns to exclude */\n exclude?: string[];\n /**\n * Follow symbolic links while discovering sources. Defaults to `false`: a\n * pnpm `node_modules` is a symlink graph with cycles, so a link-following\n * walk does not terminate on a real install (#2275). Enable it only for a\n * project that genuinely keeps sources behind a link.\n */\n followSymbolicLinks?: boolean;\n /** Output directory for generated files */\n outDir?: string;\n /** Enable hot module replacement */\n hmr?: boolean;\n /** Watch for file changes */\n watch?: boolean;\n /** Generate types */\n generateTypes?: boolean;\n /** Custom base classes to scan for */\n baseClasses?: string[];\n /** Follow import chains to detect inheritance (e.g., Event extends SmrtObject) */\n followImports?: boolean;\n /** Directory to write TypeScript declarations (relative to project root) */\n typeDeclarationsPath?: string;\n /** Plugin execution mode - controls Node.js vs browser compatibility */\n mode?: 'server' | 'client' | 'auto';\n /**\n * @deprecated OXC scanner is now the only scanner. This option is ignored.\n */\n experimentalFastScanner?: boolean;\n /** SvelteKit route auto-generation options */\n svelteKit?: {\n /** Enable SvelteKit route generation (default: false) */\n enabled: boolean;\n /** Output directory for generated routes (default: 'src/routes/api') */\n routesDir?: string;\n /** Directory containing SMRT objects (default: 'src/lib/objects') */\n objectsDir?: string;\n /** Directory for configuration file (default: 'src/lib/server') */\n configPath?: string;\n /** Configuration file name (default: 'smrt.ts') */\n configFileName?: string;\n /**\n * Apply kebab-case to custom-method URL segments (e.g. `discoverFromUrl`\n * becomes `/discover-from-url`). Opt-in for one minor; default flips in\n * the next major. An explicit `api.routes[name].path` always wins.\n */\n kebabRoutes?: boolean;\n /**\n * Change-feed `_changes` route generation (#1758). Enabled by default\n * (the route is auth-guarded fail-closed); `{ enabled: false }` skips it.\n */\n changesRoute?: { enabled?: boolean };\n /**\n * Live `_events` SSE route generation (#1763). Enabled by default (the\n * route is auth-guarded fail-closed, same-origin only); `{ enabled: false }`\n * skips it. `maxSubscribers` caps active streams per process (#1860).\n */\n eventsRoute?: { enabled?: boolean; maxSubscribers?: number };\n };\n /** Domain-scoped agent/developer knowledge artifact generation. */\n knowledge?: DomainKnowledgeConfig | false;\n /**\n * Validate that every method in `cli.include` is exposed via the API\n * (so HTTP-based CLI consumers can actually reach them). Default: true.\n * Per-class opt-out via `cli: { skipApiCheck: true }`.\n */\n validateCliApiCoherence?: boolean;\n}\n\nconst VIRTUAL_MODULES = {\n '@happyvertical/smrt-virt-routes': 'smrt:routes',\n '@happyvertical/smrt-virt-client': 'smrt:client',\n '@happyvertical/smrt-virt-mcp': 'smrt:mcp',\n '@happyvertical/smrt-virt-types': 'smrt:types',\n '@happyvertical/smrt-virt-manifest': 'smrt:manifest',\n '@happyvertical/smrt-virt-ui': 'smrt:ui',\n '@happyvertical/smrt-virt-cli': 'smrt:cli',\n '@happyvertical/smrt-virt-web': 'smrt:web',\n};\n\nasync function importScanner() {\n return importWorkspaceModule<ScannerModule>({\n packageName: '@happyvertical/smrt-scanner',\n distEntry: 'packages/scanner/dist/index.js',\n sourceEntry: 'packages/scanner/src/index.ts',\n purpose: 'Vite manifest scanning',\n });\n}\n\n/**\n * Matches a package's `__smrt-register__` self-registration shim by module id\n * (query strings stripped). node_modules is excluded: only the package's OWN\n * shim is rewritten during its library build, never a dependency's compiled\n * output.\n */\nconst REGISTER_SHIM_RE = /[\\\\/]__smrt-register__\\.(?:ts|mts|js|mjs)$/;\n\nexport function isRegisterShimModuleId(id: string): boolean {\n const cleanId = id.split('?')[0];\n return REGISTER_SHIM_RE.test(cleanId) && !cleanId.includes('node_modules');\n}\n\n/**\n * Generate the replacement `__smrt-register__` module with the build-time\n * manifest inlined as data (issues #1506/#1507).\n *\n * The source shim resolves `new URL('./manifest.json', import.meta.url)` at\n * runtime, which assumes the compiled module ends up next to\n * `dist/manifest.json`. That held for the package's own dist (with the #1331\n * upward-search recovery), but breaks once a CONSUMER bundles the package\n * into its own output — e.g. a SvelteKit server build relocates the module\n * into `build/server/chunks/`, the URL resolves to a manifest that does not\n * exist, registration silently no-ops, and every plain (undecorated) field is\n * dropped from INSERTs and rejected by WHERE validation. Inlining the\n * manifest at library-build time removes the runtime filesystem lookup\n * entirely, so no downstream bundler layout can break registration.\n *\n * `JSON.parse('<literal>')` is used instead of an object literal: it parses\n * faster for large payloads and sidesteps identifier/keyword edge cases.\n */\nexport function generateInlineRegisterModule(\n manifest: SmartObjectManifest,\n): string {\n const manifestLiteral = JSON.stringify(JSON.stringify(manifest));\n return [\n '// Generated by @happyvertical/smrt-core smrtPlugin at library build time.',\n '// The package manifest is inlined so self-registration cannot miss when a',\n '// downstream bundler relocates this module away from dist/manifest.json',\n '// (https://github.com/happyvertical/smrt/issues/1506,',\n '// https://github.com/happyvertical/smrt/issues/1507).',\n \"import { ObjectRegistry } from '@happyvertical/smrt-core';\",\n '',\n `ObjectRegistry.registerPackageManifest(JSON.parse(${manifestLiteral}));`,\n '',\n ].join('\\n');\n}\n\nexport function smrtPlugin(options: SmrtPluginOptions = {}): Plugin {\n const {\n projectRoot: configuredProjectRoot,\n generationSnapshot,\n include = ['src/**/*.ts', 'src/**/*.js'],\n exclude = ['**/*.test.ts', '**/*.spec.ts', '**/node_modules/**'],\n followSymbolicLinks = false,\n hmr = true,\n watch = true,\n generateTypes = true,\n baseClasses = ['SmrtObject', 'SmartObject'],\n followImports = true, // Default true: needed for multi-package inheritance\n typeDeclarationsPath = 'src/types',\n mode = 'auto',\n svelteKit = {\n enabled: false,\n routesDir: 'src/routes/api',\n objectsDir: 'src/lib/objects',\n configPath: 'src/lib/server',\n configFileName: 'smrt.ts',\n },\n knowledge,\n validateCliApiCoherence = true,\n } = options;\n\n /**\n * Dev-watcher variant of the cli↔api coherence lint: warn instead of throw,\n * so an in-flight decorator edit doesn't kill the dev server. Uses the same\n * remediation text as the strict build-time gate (`validateCliIncludeAgainstApi`)\n * so the dev-server message is as actionable as the build failure.\n */\n function warnCliApiCoherenceViolations(m: SmartObjectManifest): void {\n if (!validateCliApiCoherence) return;\n const violations = findCliApiCoherenceViolations(m);\n if (violations.length === 0) return;\n for (const { className, unreachable } of violations) {\n for (const action of unreachable) {\n console.warn(\n `[smrt] ${className}.${action} is declared in cli.include but is not ` +\n `exposed via the api. Build will fail until this is resolved.\\n` +\n ` Either:\\n` +\n ` - Add '${action}' to api.include, or\\n` +\n ` - Remove '${action}' from cli.include.\\n` +\n ` The CLI invokes methods over HTTP; methods without API routes are unreachable.\\n` +\n ` If this CLI is intentionally invoked in-process (no HTTP), set\\n` +\n ` \\`cli: { skipApiCheck: true }\\` on the @smrt() decorator to acknowledge.`,\n );\n }\n }\n }\n\n let server: ViteDevServer | undefined;\n let manifest: SmartObjectManifest | null = null;\n let pluginMode: 'server' | 'client' = 'server';\n let projectRoot: string = process.cwd();\n let config: ResolvedConfig | null = null; // Store resolved config for closeBundle hook\n let resolvedPluginNames: string[] = [];\n let hasFreshConfigResolvedManifest = false;\n let configHookManifest: SmartObjectManifest | null = null;\n let generatedRoutesDuringConfig = false;\n\n async function generateConfiguredSvelteKitRoutes(\n rootDir: string,\n currentManifest: SmartObjectManifest,\n ): Promise<void> {\n await generateSvelteKitRoutes(rootDir, currentManifest, {\n enabled: svelteKit.enabled,\n routesDir: svelteKit.routesDir || 'src/routes/api',\n objectsDir: svelteKit.objectsDir || 'src/lib/objects',\n configPath: svelteKit.configPath || 'src/lib/server',\n configFileName: svelteKit.configFileName || 'smrt.ts',\n kebabRoutes: svelteKit.kebabRoutes ?? false,\n changesRoute: svelteKit.changesRoute,\n eventsRoute: svelteKit.eventsRoute,\n knowledge: await resolveKnowledgeConfig(rootDir, currentManifest),\n });\n }\n\n /**\n * Write manifest to .smrt/manifest.json for CLI discovery.\n * This ensures `smrt db:migrate`, `smrt db:status`, etc. can find\n * locally-defined SMRT objects in non-library builds (Issue #963).\n */\n async function writeLocalManifest(\n m: SmartObjectManifest,\n rootDir: string,\n ): Promise<void> {\n try {\n const { writeFileSync, mkdirSync } = await import('node:fs');\n const { resolve } = await import('node:path');\n\n const smrtDir = resolve(rootDir, '.smrt');\n mkdirSync(smrtDir, { recursive: true });\n\n const manifestPath = resolve(smrtDir, 'manifest.json');\n writeFileSync(manifestPath, JSON.stringify(m, null, 2), 'utf-8');\n await writeDomainKnowledgeArtifact(\n m,\n rootDir,\n resolve(smrtDir, 'smrt-knowledge.json'),\n manifestPath,\n );\n\n const objectCount = Object.keys(m.objects).length;\n console.log(\n `[smrt] Wrote local manifest with ${objectCount} objects to .smrt/manifest.json`,\n );\n } catch (error) {\n console.error('[smrt] Error writing local manifest:', error);\n }\n }\n\n /**\n * @param deterministic - Emit a fixed `generatedAt` instead of the clock.\n * Set for artifacts written into the build output directory: `dist/` is\n * compared byte-for-byte by downstream caches, and a fresh checkout has no\n * previous file for {@link preserveKnowledgeGeneratedAt} to carry a value\n * forward from, so every build would otherwise emit different bytes\n * (#2223). The working copy under `.smrt/` keeps a real timestamp, which\n * is where it is useful to a human and where preservation already works.\n */\n async function writeDomainKnowledgeArtifact(\n m: SmartObjectManifest,\n rootDir: string,\n outputPath: string,\n manifestPath: string,\n deterministic = false,\n ): Promise<void> {\n const resolvedKnowledge = await resolveKnowledgeConfig(rootDir, m);\n if (resolvedKnowledge.enabled === false) {\n return;\n }\n\n const { mkdirSync, writeFileSync } = await import('node:fs');\n const { dirname } = await import('node:path');\n mkdirSync(dirname(outputPath), { recursive: true });\n const artifact = buildDomainKnowledgeManifest({\n manifest: m,\n rootDir,\n manifestPath,\n config: resolvedKnowledge,\n });\n const emitted = deterministic\n ? { ...artifact, generatedAt: DETERMINISTIC_GENERATED_AT }\n : preserveKnowledgeGeneratedAt(outputPath, artifact);\n writeFileSync(outputPath, JSON.stringify(emitted, null, 2), 'utf-8');\n }\n\n async function resolveKnowledgeConfig(\n rootDir: string,\n m: SmartObjectManifest,\n ): Promise<DomainKnowledgeConfig> {\n if (knowledge === false) return { enabled: false };\n const packageName = m.packageName ?? readPackageName(rootDir);\n const defaults: DomainKnowledgeConfig = {\n enabled: true,\n api: {\n enabled: false,\n basePath: '/__smrt/knowledge',\n requireAdmin: true,\n includeDocs: false,\n includePrompts: false,\n },\n includeDocs: true,\n includePrompts: true,\n };\n\n let fileKnowledge: DomainKnowledgeConfig = {};\n let packageKnowledge: DomainKnowledgeConfig = {};\n try {\n const previousCwd = process.cwd();\n process.chdir(rootDir);\n try {\n const { loadConfig } = await import('@happyvertical/smrt-config');\n const config = await loadConfig({ cache: false });\n fileKnowledge = (config.knowledge ?? {}) as DomainKnowledgeConfig;\n packageKnowledge = (\n packageName ? (config.packages?.[packageName]?.knowledge ?? {}) : {}\n ) as DomainKnowledgeConfig;\n } finally {\n process.chdir(previousCwd);\n }\n } catch {\n fileKnowledge = {};\n packageKnowledge = {};\n }\n\n return mergeKnowledgeConfig(\n defaults,\n fileKnowledge,\n packageKnowledge,\n knowledge || {},\n );\n }\n\n function mergeKnowledgeConfig(\n ...configs: Array<DomainKnowledgeConfig | undefined | null | false>\n ): DomainKnowledgeConfig {\n const merged: DomainKnowledgeConfig = {};\n for (const next of configs) {\n if (!next) continue;\n const hasApi = Boolean(merged.api || next.api);\n const api = hasApi\n ? { ...(merged.api ?? {}), ...(next.api ?? {}) }\n : undefined;\n Object.assign(merged, next);\n if (api) merged.api = api;\n }\n return merged;\n }\n\n function preserveKnowledgeGeneratedAt(\n outputPath: string,\n nextKnowledge: DomainKnowledgeManifest,\n ): DomainKnowledgeManifest {\n if (!existsSync(outputPath)) return nextKnowledge;\n\n try {\n const current = JSON.parse(\n readFileSync(outputPath, 'utf8'),\n ) as Partial<DomainKnowledgeManifest>;\n if (\n semanticKnowledgeJson(current) === semanticKnowledgeJson(nextKnowledge)\n ) {\n return {\n ...nextKnowledge,\n generatedAt: current.generatedAt ?? nextKnowledge.generatedAt,\n };\n }\n } catch {\n // Replace malformed artifacts.\n }\n\n return nextKnowledge;\n }\n\n function semanticKnowledgeJson(\n artifact: Partial<DomainKnowledgeManifest>,\n ): string {\n const { generatedAt: _generatedAt, ...rest } = artifact ?? {};\n return JSON.stringify(sortJson(rest));\n }\n\n function sortJson(value: unknown): unknown {\n if (Array.isArray(value)) return value.map(sortJson);\n if (value && typeof value === 'object') {\n return Object.fromEntries(\n Object.entries(value as Record<string, unknown>)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([key, entry]) => [key, sortJson(entry)]),\n );\n }\n return value;\n }\n\n function readPackageName(rootDir: string): string | undefined {\n try {\n const pkg = JSON.parse(\n readFileSync(join(rootDir, 'package.json'), 'utf8'),\n );\n return typeof pkg.name === 'string' ? pkg.name : undefined;\n } catch {\n return undefined;\n }\n }\n\n function validateConsumerPluginSetup(\n m: SmartObjectManifest,\n context: 'configResolved' | 'buildStart',\n ): void {\n if (config?.mode === 'test') {\n return;\n }\n\n if (config?.build?.lib) {\n return;\n }\n\n const consumerDependencies = (m.smrtDependencies || []).filter(\n (dependency) => dependency !== '@happyvertical/smrt-core',\n );\n if (consumerDependencies.length === 0) {\n return;\n }\n\n const hasConsumerPlugin = resolvedPluginNames.some(\n (name) => name === 'smrt-consumer',\n );\n if (hasConsumerPlugin) {\n return;\n }\n\n const dependencySummary =\n consumerDependencies.length <= 4\n ? consumerDependencies.join(', ')\n : `${consumerDependencies.slice(0, 4).join(', ')}, +${consumerDependencies.length - 4} more`;\n\n throw new Error(\n `[smrt] Consumer project misconfiguration detected during ${context}: found external SMRT dependencies (${dependencySummary}) but vite.config is missing smrtConsumer(). Add \"import { smrtConsumer } from '@happyvertical/smrt-core/consumer-plugin'\" and register it alongside smrtPlugin() so .smrt/register.js is generated for CLI/runtime class loading.`,\n );\n }\n\n function validateLibraryMinifySetup(\n m: SmartObjectManifest,\n context: 'configResolved' | 'buildStart',\n ): void {\n if (!config?.build?.lib) {\n return;\n }\n\n if (Object.keys(m.objects || {}).length === 0) {\n return;\n }\n\n if (config.build.minify === false) {\n return;\n }\n\n throw new Error(\n `[smrt] Library package misconfiguration detected during ${context}: packages that publish SMRT objects must set Vite build.minify = false. Minification rewrites runtime class names and breaks manifest registration, STI resolution, and collection queries in downstream apps.`,\n );\n }\n\n return {\n name: 'smrt-auto-service',\n // SvelteKit inventories routes in a `config.order = 'pre'` hook. Put SMRT\n // in Vite's earlier plugin tier so this plugin's own pre hook runs first\n // even when the documented plugin array lists sveltekit() before us.\n enforce: 'pre',\n\n // SvelteKit inventories filesystem routes in its config hook. Generate\n // SMRT routes in an earlier config hook so a clean checkout's first build\n // sees them; configResolved is too late because Vite runs those hooks\n // concurrently (#2313).\n config: {\n order: 'pre',\n async handler(userConfig) {\n if (!svelteKit.enabled) return;\n\n projectRoot =\n configuredProjectRoot ??\n resolve(process.cwd(), userConfig.root ?? '.');\n configHookManifest = await scanAndGenerateManifest(projectRoot);\n await generateConfiguredSvelteKitRoutes(\n projectRoot,\n configHookManifest,\n );\n generatedRoutesDuringConfig = true;\n },\n },\n\n // Expose options for external access (e.g., test manifest generation)\n api: {\n options: {\n ...(configuredProjectRoot === undefined\n ? {}\n : { projectRoot: configuredProjectRoot }),\n ...(generationSnapshot === undefined ? {} : { generationSnapshot }),\n baseClasses,\n followImports,\n include,\n exclude,\n },\n },\n\n async configResolved(resolvedConfig) {\n hasFreshConfigResolvedManifest = false;\n // Store config for closeBundle hook\n config = resolvedConfig;\n resolvedPluginNames = (resolvedConfig.plugins || []).map(\n (plugin) => plugin?.name || '',\n );\n\n // Store project root for file scanning\n projectRoot = configuredProjectRoot ?? resolvedConfig.root;\n\n // Detect plugin mode based on build configuration\n if (mode === 'auto') {\n const isSSRBuild = resolvedConfig.build?.ssr;\n const isFederationBuild = resolvedConfig.plugins.some((p) =>\n p.name?.includes('federation'),\n );\n const isClientBuild =\n isFederationBuild ||\n (!isSSRBuild && resolvedConfig.build?.target === 'esnext');\n\n pluginMode = isClientBuild ? 'client' : 'server';\n } else {\n pluginMode = mode;\n }\n\n console.log(`[smrt] Running in ${pluginMode} mode`);\n\n // Scan files and generate initial manifest in all modes\n manifest =\n configHookManifest ?? (await scanAndGenerateManifest(projectRoot));\n configHookManifest = null;\n\n // Write local manifest for CLI discovery (Issue #963)\n if (manifest && !generationSnapshot) {\n await writeLocalManifest(manifest, projectRoot);\n }\n if (manifest) {\n validateLibraryMinifySetup(manifest, 'configResolved');\n validateConsumerPluginSetup(manifest, 'configResolved');\n if (validateCliApiCoherence) {\n validateCliIncludeAgainstApi(manifest);\n }\n }\n\n // Generate SvelteKit routes if enabled\n if (svelteKit.enabled && manifest && !generatedRoutesDuringConfig) {\n await generateConfiguredSvelteKitRoutes(projectRoot, manifest);\n }\n generatedRoutesDuringConfig = false;\n\n // Vite calls buildStart immediately after configResolved for the initial\n // build. The manifest already reflects the same source tree, so let that\n // first hook reuse it. Later buildStart calls are watch rebuilds and must\n // rescan changed classes.\n hasFreshConfigResolvedManifest = true;\n },\n\n async buildStart() {\n if (hasFreshConfigResolvedManifest) {\n hasFreshConfigResolvedManifest = false;\n // configureServer may be attached between configResolved and\n // buildStart. Emit declarations from the reused manifest even though\n // the scanner itself does not need to run again.\n if (generateTypes && server && manifest) {\n await generateTypeDeclarationFile(\n manifest,\n projectRoot,\n typeDeclarationsPath,\n );\n }\n return;\n }\n\n // Rescan files on build start in all modes\n manifest = await scanAndGenerateManifest(projectRoot);\n\n // Write local manifest for CLI discovery (Issue #963)\n if (manifest && !generationSnapshot) {\n await writeLocalManifest(manifest, projectRoot);\n }\n if (manifest) {\n validateLibraryMinifySetup(manifest, 'buildStart');\n validateConsumerPluginSetup(manifest, 'buildStart');\n if (validateCliApiCoherence) {\n validateCliIncludeAgainstApi(manifest);\n }\n }\n },\n\n transform(_code, id) {\n // Library builds only: inline the scanned manifest into the package's\n // __smrt-register__ shim so the published dist registers field metadata\n // as data instead of resolving ./manifest.json at runtime. Runtime URL\n // resolution silently no-ops when a consumer's bundler (e.g. a\n // SvelteKit server build) relocates the module into its own chunks\n // directory, dropping every plain field from the registry (#1506,\n // #1507). Dev/test flows are untouched: the vitest plugin populates\n // manifests through its own path, and non-library builds keep the\n // original shim.\n if (!config?.build?.lib || !manifest) {\n return null;\n }\n if (!isRegisterShimModuleId(id)) {\n return null;\n }\n return {\n code: generateInlineRegisterModule(manifest),\n map: null,\n };\n },\n\n shouldTransformCachedModule({ id }) {\n // In `vite build --watch`, rollup caches transform results keyed on the\n // module's own code. The inlined register shim depends on the manifest\n // (rescanned each buildStart), not on the shim's unchanged source — so\n // force a re-transform or a field edit elsewhere in the package would\n // ship a stale inlined manifest.\n if (config?.build?.lib && isRegisterShimModuleId(id)) {\n return true;\n }\n return null;\n },\n\n configureServer(devServer) {\n server = devServer;\n\n // Serve default HTML when no index.html exists\n // Skip for SvelteKit projects (they use src/app.html and handle routing themselves)\n devServer.middlewares.use(async (req, res, next) => {\n // Skip default UI entirely for SvelteKit projects\n if (svelteKit.enabled) {\n return next();\n }\n\n if (req.url === '/' || req.url === '/index.html') {\n try {\n const { existsSync } = await import('node:fs');\n const { join } = await import('node:path');\n\n const projectRoot = devServer.config.root;\n const indexPath = join(projectRoot, 'index.html');\n\n // If index.html exists, let Vite handle it\n if (existsSync(indexPath)) {\n return next();\n }\n\n // Otherwise, serve default SMRT UI\n console.log('[smrt] Serving default UI (no index.html found)');\n let html = getDefaultHTML();\n\n // Apply Vite's HTML transformation to process module imports\n html = await devServer.transformIndexHtml('/', html);\n\n res.setHeader('Content-Type', 'text/html');\n res.end(html);\n return;\n } catch (error) {\n console.error('[smrt] Error serving default HTML:', error);\n return next();\n }\n }\n next();\n });\n\n // Set up file watching in all modes when enabled\n if (watch && hmr && !generationSnapshot) {\n // Watch for file changes\n const watcher = devServer.watcher;\n\n // Guard each watcher handler: scanAndGenerateManifest re-throws on a\n // mid-edit scan error, and an unhandled rejection in a watcher callback\n // can crash the dev server. Log and keep the previous manifest (#1378).\n watcher.on('change', async (file) => {\n try {\n if (await shouldRescan(file)) {\n console.log(`[smrt] Rescanning due to change in ${file}`);\n manifest = await scanAndGenerateManifest(projectRoot);\n\n // Write local manifest for CLI discovery (Issue #963)\n if (manifest) {\n await writeLocalManifest(manifest, projectRoot);\n warnCliApiCoherenceViolations(manifest);\n }\n\n // Generate SvelteKit routes if enabled\n if (svelteKit.enabled && manifest && server) {\n await generateSvelteKitRoutes(projectRoot, manifest, {\n enabled: svelteKit.enabled,\n routesDir: svelteKit.routesDir || 'src/routes/api',\n objectsDir: svelteKit.objectsDir || 'src/lib/objects',\n configPath: svelteKit.configPath || 'src/lib/server',\n configFileName: svelteKit.configFileName || 'smrt.ts',\n kebabRoutes: svelteKit.kebabRoutes ?? false,\n changesRoute: svelteKit.changesRoute,\n eventsRoute: svelteKit.eventsRoute,\n knowledge: await resolveKnowledgeConfig(\n projectRoot,\n manifest,\n ),\n });\n }\n\n // Invalidate virtual modules\n Object.values(VIRTUAL_MODULES).forEach((id) => {\n const module = server?.moduleGraph.getModuleById(id);\n if (module) {\n server?.reloadModule(module);\n }\n });\n }\n } catch (error) {\n console.error(\n `[smrt] Failed to rescan after change in ${file}:`,\n error,\n );\n }\n });\n\n watcher.on('add', async (file) => {\n try {\n if (await shouldRescan(file)) {\n console.log(`[smrt] Rescanning due to new file ${file}`);\n manifest = await scanAndGenerateManifest(projectRoot);\n\n // Write local manifest for CLI discovery (Issue #963)\n if (manifest) {\n await writeLocalManifest(manifest, projectRoot);\n warnCliApiCoherenceViolations(manifest);\n }\n\n // Generate SvelteKit routes if enabled\n if (svelteKit.enabled && manifest && server) {\n await generateSvelteKitRoutes(projectRoot, manifest, {\n enabled: svelteKit.enabled,\n routesDir: svelteKit.routesDir || 'src/routes/api',\n objectsDir: svelteKit.objectsDir || 'src/lib/objects',\n configPath: svelteKit.configPath || 'src/lib/server',\n configFileName: svelteKit.configFileName || 'smrt.ts',\n kebabRoutes: svelteKit.kebabRoutes ?? false,\n changesRoute: svelteKit.changesRoute,\n eventsRoute: svelteKit.eventsRoute,\n knowledge: await resolveKnowledgeConfig(\n projectRoot,\n manifest,\n ),\n });\n }\n }\n } catch (error) {\n console.error(\n `[smrt] Failed to rescan after adding ${file}:`,\n error,\n );\n }\n });\n\n watcher.on('unlink', async (file) => {\n try {\n if (await shouldRescan(file)) {\n console.log(`[smrt] Rescanning due to removed file ${file}`);\n manifest = await scanAndGenerateManifest(projectRoot);\n\n // Write local manifest for CLI discovery (Issue #963)\n if (manifest) {\n await writeLocalManifest(manifest, projectRoot);\n warnCliApiCoherenceViolations(manifest);\n }\n\n // Generate SvelteKit routes if enabled\n if (svelteKit.enabled && manifest && server) {\n await generateSvelteKitRoutes(projectRoot, manifest, {\n enabled: svelteKit.enabled,\n routesDir: svelteKit.routesDir || 'src/routes/api',\n objectsDir: svelteKit.objectsDir || 'src/lib/objects',\n configPath: svelteKit.configPath || 'src/lib/server',\n configFileName: svelteKit.configFileName || 'smrt.ts',\n kebabRoutes: svelteKit.kebabRoutes ?? false,\n changesRoute: svelteKit.changesRoute,\n eventsRoute: svelteKit.eventsRoute,\n knowledge: await resolveKnowledgeConfig(\n projectRoot,\n manifest,\n ),\n });\n }\n }\n } catch (error) {\n console.error(\n `[smrt] Failed to rescan after removing ${file}:`,\n error,\n );\n }\n });\n }\n },\n\n resolveId(id) {\n // Resolve virtual module imports\n if (id in VIRTUAL_MODULES) {\n return `\\0${VIRTUAL_MODULES[id as keyof typeof VIRTUAL_MODULES]}`;\n }\n\n // Resolve virtual index.html for dev UI (only in dev mode)\n if (id === '/index.html' && server) {\n return `\\0smrt:index-html`;\n }\n\n return null;\n },\n\n async load(id) {\n // Load virtual modules (strip the \\0 prefix)\n const cleanId = id.startsWith('\\0') ? id.slice(1) : id;\n\n if (!manifest) {\n manifest = await scanAndGenerateManifest(projectRoot);\n }\n\n switch (cleanId) {\n case 'smrt:routes':\n // Routes module available in all modes\n return await generateRoutesModule(manifest);\n\n case 'smrt:client':\n // Client module available in both modes\n return generateClientModule(manifest, {\n kebabRoutes: svelteKit.kebabRoutes ?? false,\n });\n\n case 'smrt:mcp':\n // MCP module available in all modes\n return await generateMCPModule(manifest);\n\n case 'smrt:types':\n // Types module available in both modes\n return await generateTypesModule(manifest, pluginMode);\n\n case 'smrt:manifest':\n // Manifest module available in both modes\n return generateManifestModule(manifest);\n\n case 'smrt:ui':\n // UI module for default development interface\n return await loadDefaultUI();\n\n case 'smrt:index-html':\n // Virtual index.html for projects without one\n return await loadDefaultHTML();\n\n case 'smrt:cli':\n // CLI module for command-line interface generation\n return await generateCLIModule(manifest);\n\n case 'smrt:web':\n // Web collection definitions for the browser client data runtime\n // (@happyvertical/smrt-web, #1761)\n return generateWebModule(manifest, {\n kebabRoutes: svelteKit.kebabRoutes ?? false,\n });\n\n default:\n return null;\n }\n },\n\n transformIndexHtml: {\n order: 'pre',\n handler: async (html, _ctx) => {\n // Only provide default HTML if no index.html exists in project\n if (!server) return html;\n\n try {\n const { existsSync } = await import('node:fs');\n const { join } = await import('node:path');\n\n const projectRoot = server.config.root;\n const indexPath = join(projectRoot, 'index.html');\n\n // If index.html exists, use it as-is\n if (existsSync(indexPath)) {\n return html;\n }\n\n // Otherwise, provide default SMRT UI\n return await loadDefaultHTML();\n } catch (error) {\n console.error('[smrt] Error checking for index.html:', error);\n return html;\n }\n },\n },\n\n async closeBundle() {\n // Write manifest to disk during library builds\n // This allows published packages to include their manifest\n if (!manifest || !config?.build?.lib || generationSnapshot) {\n return;\n }\n\n try {\n const { writeFileSync, mkdirSync } = await import('node:fs');\n const { resolve, dirname } = await import('node:path');\n\n // Determine output directory.\n // `rollupOptions.output` may be a single object or an array; mirror the\n // prior runtime behavior where reading `.dir` off an array yields\n // undefined and falls through to `build.outDir`.\n const rollupOutput = config.build?.rollupOptions?.output;\n const rollupOutputDir = Array.isArray(rollupOutput)\n ? undefined\n : rollupOutput?.dir;\n const outDir = rollupOutputDir || config.build?.outDir || 'dist';\n const manifestPath = resolve(projectRoot, outDir, 'manifest.json');\n const knowledgePath = resolve(\n projectRoot,\n outDir,\n 'smrt-knowledge.json',\n );\n\n // Ensure directory exists\n mkdirSync(dirname(manifestPath), { recursive: true });\n\n // Write manifest file\n writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), 'utf-8');\n await writeDomainKnowledgeArtifact(\n manifest,\n projectRoot,\n knowledgePath,\n manifestPath,\n true,\n );\n\n const objectCount = Object.keys(manifest.objects).length;\n console.log(\n `[smrt] Wrote manifest with ${objectCount} objects to ${manifestPath}`,\n );\n } catch (error) {\n console.error('[smrt] Error writing manifest file:', error);\n }\n },\n };\n\n async function scanAndGenerateManifest(\n rootDir: string,\n ): Promise<SmartObjectManifest> {\n if (generationSnapshot) {\n const verified = loadVerifiedSmrtGenerationSnapshot<SmartObjectManifest>(\n generationSnapshot,\n rootDir,\n 'project',\n );\n console.log(\n `[smrt] Reusing verified generation snapshot (${generationSnapshot.provenance})`,\n );\n if (generateTypes && server) {\n await generateTypeDeclarationFile(\n verified,\n rootDir,\n typeDeclarationsPath,\n );\n }\n return verified;\n }\n\n // NOTE: We do NOT use the framework's static manifest here\n // The static manifest JSON that core emits at build time\n // contains framework objects (like 'pleb') which should not be included\n // when scanning user code in consuming applications.\n //\n // smrtPlugin is designed to scan USER code dynamically, not load\n // framework objects. For consuming apps that need framework objects,\n // they should use smrtConsumer plugin instead.\n\n // Always use OXC-based scanner (consolidated in Issue #951)\n try {\n return await scanWithOxc(rootDir);\n } catch (error) {\n if (\n error instanceof Error &&\n error.message.includes('Cannot find package')\n ) {\n console.error(\n '[smrt] @happyvertical/smrt-scanner is required but not installed.',\n );\n console.error(\n '[smrt] Install it: pnpm add @happyvertical/smrt-scanner',\n );\n }\n console.error('[smrt] Error scanning files:', error);\n // Re-throw to fail the build - don't silently continue with empty manifest\n throw error;\n }\n }\n\n /**\n * Scan files using OXC-based scanner (experimental fast path)\n * Uses Rust-based oxc-parser for 2-3x faster parsing\n */\n async function scanWithOxc(rootDir: string): Promise<SmartObjectManifest> {\n const startTime = performance.now();\n\n try {\n // Import the OXC scanner package\n const { OxcScanner, ManifestAdapter } = await importScanner();\n\n console.log(`[smrt] Using experimental OXC scanner for faster builds`);\n\n // Create scanner with options. Always exclude .svelte files as OXC barfs on <style> tags\n const safeExclude = [...(exclude || []), '**/*.svelte'];\n const scanner = new OxcScanner({\n cwd: rootDir,\n include,\n exclude: safeExclude,\n followSymbolicLinks,\n });\n\n // Scan and resolve inheritance\n const { results, resolved } = await scanner.scanAndResolve();\n\n // Check for errors\n if (results.errors.length > 0) {\n console.error(\n `\\n[smrt] ❌ Build failed: ${results.errors.length} error(s) during scanning:\\n`,\n );\n for (const error of results.errors) {\n console.error(\n ` ${error.filePath}:${error.line || '?'}: ${error.message}\\n`,\n );\n }\n throw new Error(\n '[smrt] Build aborted due to scan errors. See above for details.',\n );\n }\n\n // Read package.json for metadata BEFORE creating manifest (Issue #713)\n // This ensures qualified names are generated correctly for namespace isolation\n // packageJson is also needed for agent manifest generation (component discovery)\n let packageName: string | undefined;\n let packageVersion: string | undefined;\n let packageJson: PackageJsonShape | undefined;\n try {\n const { readFileSync } = await import('node:fs');\n const { join } = await import('node:path');\n const pkgPath = join(rootDir, 'package.json');\n const pkgContent = readFileSync(pkgPath, 'utf-8');\n packageJson = JSON.parse(pkgContent) as PackageJsonShape;\n packageName = packageJson.name || undefined;\n packageVersion = packageJson.version || undefined;\n } catch {\n // package.json not found or invalid - continue without packageName\n console.warn(\n '[smrt] Warning: package.json not found. Qualified names will not be generated.',\n );\n }\n\n // Convert to manifest format with packageName for qualified names (Issue #713)\n const adapter = new ManifestAdapter();\n const newManifest = adapter.toManifest(resolved, {\n packageName,\n packageVersion,\n typeAliases: results.typeAliases,\n });\n\n // Add moduleType identifier\n newManifest.moduleType = 'smrt';\n\n // Keep this as a normal module import: dynamic source imports with a\n // `.js` specifier do not reliably resolve through tsx during publish-time\n // workspace builds, even though the compiled dist path exists.\n const smrtDependencies = discoverSmrtPackages({ baseDir: rootDir });\n if (smrtDependencies.length > 0) {\n newManifest.smrtDependencies = smrtDependencies;\n console.log(\n `[smrt] Found ${smrtDependencies.length} SMRT dependencies: ${smrtDependencies.join(', ')}`,\n );\n }\n\n // Run all manifest generation passes (same as TypeScript scanner path)\n const { ManifestGenerator } = await importBuildAwareModule<\n typeof import('../scanner/index.js')\n >({\n source: '../scanner/index.ts',\n dist: '../scanner.js',\n });\n const manifestGen = new ManifestGenerator();\n // THE pass sequence — shared with generateManifest() and\n // ManifestBuilder so the three producers cannot drift (#2360).\n manifestGen.applyGenerationPasses(newManifest, {\n packageName,\n packageJson,\n });\n\n const elapsed = performance.now() - startTime;\n\n // Log results\n const objectCount = Object.keys(newManifest.objects).length;\n if (objectCount > 0) {\n const names = Object.keys(newManifest.objects).join(', ');\n console.log(`[smrt] Found ${objectCount} SMRT objects: ${names}`);\n } else {\n console.log('[smrt] No SMRT objects found');\n }\n console.log(`[smrt] OXC scan completed in ${elapsed.toFixed(2)}ms`);\n\n // Generate TypeScript declarations if enabled\n if (generateTypes && server) {\n await generateTypeDeclarationFile(\n newManifest,\n rootDir,\n typeDeclarationsPath,\n );\n }\n\n return newManifest;\n } catch (error) {\n console.error('[smrt] Error in OXC scanner:', error);\n throw error;\n }\n }\n\n async function shouldRescan(file: string): Promise<boolean> {\n // Only rescan in server mode\n if (pluginMode === 'client') {\n return false;\n }\n\n try {\n // Conditionally import minimatch\n const { minimatch } = await import('minimatch');\n\n const isIncluded = include.some((pattern) => minimatch(file, pattern));\n const isExcluded = exclude.some((pattern) => minimatch(file, pattern));\n\n return isIncluded && !isExcluded;\n } catch (error) {\n console.warn('[smrt] Error checking file patterns:', error);\n return false;\n }\n }\n}\n\n/**\n * Generate virtual routes module\n */\nasync function generateRoutesModule(\n manifest: SmartObjectManifest,\n): Promise<string> {\n try {\n const { ManifestGenerator } = await importBuildAwareModule<\n typeof import('../scanner/index.js')\n >({\n source: '../scanner/index.ts',\n dist: '../scanner.js',\n });\n const generator = new ManifestGenerator();\n const routes = generator.generateRestEndpoints(manifest);\n\n return `\n// Auto-generated REST routes from SMRT objects\n// This file is generated automatically - do not edit\n\n/**\n * Setup routes on an Express-like app\n *\n * NOTE: This virtual module function is for documentation only.\n * For actual route registration, use:\n * - import { startRestServer } from '@happyvertical/smrt-core'\n * - Or APIGenerator from '@happyvertical/smrt-core/generators'\n *\n * @param app - Express-like app instance\n * @param options - Route configuration options\n * @param options.basePath - Base path for all routes (default: '/api/v1')\n */\nexport function setupRoutes(app, options = {}) {\n const basePath = options.basePath || '/api/v1';\n\n console.warn('[smrt] setupRoutes is a documentation function only.');\n console.warn('[smrt] Use startRestServer() or APIGenerator for actual route registration.');\n console.warn('[smrt] Available endpoints:');\n${routes\n .split('\\\\n')\n .map((line) => ` console.warn(\\` \\${basePath}${line.trim()}\\`);`)\n .join('\\\\n')}\n}\n\nexport { setupRoutes as default };\n`;\n } catch (error) {\n console.warn('[smrt] Error generating routes module:', error);\n return 'export function setupRoutes(app, options = {}) { console.warn(\"Routes generation failed\"); }';\n }\n}\n\n/**\n * Generate the virtual web-collection definition module\n * (`@happyvertical/smrt-virt-web`, #1761).\n *\n * Emits typed per-collection metadata — REST collection name, endpoint path,\n * id field, exposed CRUD actions, and persisted field definitions — for every\n * API-exposed model in the manifest. This is the codegen contract consumed by\n * `@happyvertical/smrt-web` to construct client collections over the generated\n * REST surface. Deliberately data-only: no fetch code is emitted here, so the\n * runtime wrapper owns all HTTP/error semantics in one place. Selection and the\n * per-collection shape live in {@link selectWebCollectionEntries} /\n * {@link buildWebCollectionDefinition} so this value emission, the matching d.ts\n * type emission, and the #1764 shape digest cannot drift.\n */\nfunction generateWebModule(\n manifest: SmartObjectManifest,\n options: { kebabRoutes?: boolean } = {},\n): string {\n const definitions: Record<string, unknown> = {};\n\n // Emit one definition per MATERIALIZABLE collection (list-exposed), built via\n // the SHARED buildWebCollectionDefinition — the single source of truth the\n // shape digest (#1764) also hashes, so the emitted shape and the hashed shape\n // can never drift (a drift would let the hash under-cover a change → stale\n // caches). See buildWebCollectionDefinition's docblock.\n for (const entry of selectWebCollectionEntries(manifest)) {\n definitions[entry.collection] = {\n ...buildWebCollectionDefinition(entry, manifest),\n // WebMCP/MCP tool descriptors (#1812) — layered ON TOP of the shared shape\n // so the #1764 shape digest (computeWebManifestHash, which calls\n // buildWebCollectionDefinition directly) keeps hashing only the row shape.\n toolDescriptors: buildWebToolDescriptors(entry, options),\n };\n }\n\n // The web-collection SHAPE digest (#1764): a deterministic, replica-stable\n // hash of the exact `definitions` shape emitted below. Persistence keys its\n // durable namespace on it (a contract-changing deploy drops old caches) and\n // the generated read ETag folds it in (a shape-only deploy busts validators).\n // Built via the shared selectors so it can never disagree with what ships.\n const manifestHash = computeWebManifestHash(manifest);\n\n return `\n// Auto-generated web collection definitions from SMRT objects (#1761)\n// This file is generated automatically - do not edit\n\nexport const collectionDefinitions = ${JSON.stringify(definitions, null, 2)};\n\n// Build-time inject of the web-collection shape digest (#1764) — see\n// computeWebManifestHash. A change here means old persisted client rows may\n// mis-hydrate, so persistence namespaces and read ETags key on it.\nexport const manifestHash = ${JSON.stringify(manifestHash)};\n\nexport function getCollectionDefinition(name) {\n const definition = collectionDefinitions[name];\n if (!definition) {\n throw new Error(\n \\`[smrt] Unknown web collection definition: \\${name}. Known: \\${Object.keys(collectionDefinitions).join(', ')}\\`,\n );\n }\n return definition;\n}\n\nexport { collectionDefinitions as default };\n`;\n}\n\n/**\n * Generate virtual MCP module\n */\nasync function generateMCPModule(\n manifest: SmartObjectManifest,\n): Promise<string> {\n try {\n const { ManifestGenerator } = await importBuildAwareModule<\n typeof import('../scanner/index.js')\n >({\n source: '../scanner/index.ts',\n dist: '../scanner.js',\n });\n const generator = new ManifestGenerator();\n const tools = generator.generateMCPTools(manifest);\n\n return `\n// Auto-generated MCP tools from SMRT objects\n// This file is generated automatically - do not edit\n\nimport { SmrtMCPServer } from '@happyvertical/smrt-core/runtime';\n\nexport const tools = ${tools};\n\nexport function createMCPServer(options = {}) {\n const server = new SmrtMCPServer({\n name: options.name || 'smrt-auto-generated',\n version: options.version || '1.0.0',\n ...options\n });\n\n // Add all generated tools to the server\n for (const tool of tools) {\n server.addTool(tool, async (params) => {\n // Tool execution will be handled by the application\n throw new Error(\\`Tool '\\${tool.name}' handler must be provided by application\\`);\n });\n }\n\n return server;\n}\n\nexport { createMCPServer as default };\n`;\n } catch (error) {\n console.warn('[smrt] Error generating MCP module:', error);\n return `\nimport { SmrtMCPServer } from '@happyvertical/smrt-core/runtime';\nexport const tools = [];\nexport function createMCPServer(options = {}) {\n console.warn(\"MCP generation failed\");\n return new SmrtMCPServer({\n name: options.name || 'smrt-client',\n version: options.version || '1.0.0',\n ...options\n });\n}\n`;\n }\n}\n\n/**\n * Generate client-mode types without server dependencies\n */\nfunction generateClientModeTypes(manifest: SmartObjectManifest): string {\n const typeDefinitions: string[] = [];\n\n // Generate interfaces for each object in the manifest\n for (const [objectName, objectMeta] of Object.entries(manifest.objects)) {\n const fields = objectMeta.fields || {};\n const propertyLines: string[] = [];\n\n for (const [fieldName, fieldDef] of Object.entries(fields)) {\n let type = 'any';\n\n // Map SMRT field types to TypeScript types\n switch (fieldDef.type) {\n case 'text':\n type = 'string';\n break;\n case 'decimal':\n case 'integer':\n type = 'number';\n break;\n case 'boolean':\n type = 'boolean';\n break;\n case 'datetime':\n type = 'string';\n break;\n case 'json':\n type = 'any';\n break;\n case 'foreignKey':\n type = 'string';\n break;\n default:\n type = 'any';\n }\n\n const optional = !fieldDef.required ? '?' : '';\n propertyLines.push(` ${fieldName}${optional}: ${type};`);\n }\n\n // Add common SmrtObject properties\n propertyLines.unshift(\n ' id?: string;',\n ' created_at?: string;',\n ' updated_at?: string;',\n );\n\n const interfaceDef = `export interface ${objectName}Data {\\n${propertyLines.join('\\n')}\\n}`;\n typeDefinitions.push(interfaceDef);\n }\n\n return typeDefinitions.join('\\n\\n');\n}\n\n/**\n * Generate virtual types module\n */\nasync function generateTypesModule(\n manifest: SmartObjectManifest,\n mode: 'server' | 'client' = 'server',\n): Promise<string> {\n let interfaces = '';\n\n try {\n // Only use scanner in server mode to avoid Node.js dependencies in browser builds\n if (mode !== 'client') {\n const { ManifestGenerator } = await importBuildAwareModule<\n typeof import('../scanner/index.js')\n >({\n source: '../scanner/index.ts',\n dist: '../scanner.js',\n });\n const generator = new ManifestGenerator();\n interfaces = generator.generateTypeDefinitions(manifest);\n } else {\n // In client mode, generate basic interfaces directly from manifest\n interfaces = generateClientModeTypes(manifest);\n }\n\n return `\n// Auto-generated TypeScript types from SMRT objects\n// This file is generated automatically - do not edit\n\n${interfaces}\n\nexport interface Request {\n params: Record<string, string>;\n query: Record<string, any>;\n json(): Promise<any>;\n}\n\nexport interface Response {\n json(data: any, init?: { status?: number }): Response;\n status(code: number): Response;\n}\n`;\n } catch (error) {\n console.warn('[smrt] Error generating types module:', error);\n return `\n// Auto-generated TypeScript types from SMRT objects (fallback)\n// This file is generated automatically - do not edit\n\nexport interface Request {\n params: Record<string, string>;\n query: Record<string, any>;\n json(): Promise<any>;\n}\n\nexport interface Response {\n json(data: any, init?: { status?: number }): Response;\n status(code: number): Response;\n}\n`;\n }\n}\n\n/**\n * Generate virtual manifest module\n */\nfunction generateManifestModule(manifest: SmartObjectManifest): string {\n return `\n// Auto-generated manifest from SMRT objects\n// This file is generated automatically - do not edit\n\nexport const manifest = ${JSON.stringify(manifest, null, 2)};\n\nexport { manifest as default };\n`;\n}\n\n/**\n * Generate TypeScript declaration file for virtual modules\n * This eliminates the need for manual type maintenance\n */\nexport async function generateTypeDeclarationFile(\n manifest: SmartObjectManifest,\n projectRoot: string,\n typeDeclarationsPath: string,\n): Promise<void> {\n try {\n // Conditionally import path and fs modules\n const [{ join }, { existsSync, mkdirSync, writeFileSync }] =\n await Promise.all([import('node:path'), import('node:fs')]);\n\n const declarationsDir = join(projectRoot, typeDeclarationsPath);\n const declarationsFile = join(declarationsDir, 'virtual-modules.d.ts');\n\n // Create directory if it doesn't exist\n if (!existsSync(declarationsDir)) {\n mkdirSync(declarationsDir, { recursive: true });\n }\n\n // Generate interface definitions for each discovered SMRT object\n const objectInterfaces = Object.entries(manifest.objects)\n .map(([_name, obj]) => {\n const interfaceName = `${obj.className}Data`;\n const fields = Object.entries(obj.fields)\n .map(([fieldName, field]) => {\n const optional = field.required === false ? '?' : '';\n const type = mapTypeScriptType(field.type);\n return ` ${fieldName}${optional}: ${type};`;\n })\n .join('\\n');\n\n // Timestamps are snake_case on the wire (#1797): the server returns\n // `created_at`/`updated_at` exactly as SmrtObject.toJSON() emits them,\n // matching the prebuild + client-mode type paths.\n return ` export interface ${interfaceName} {\n id?: string;\n${fields}\n created_at?: string;\n updated_at?: string;\n }`;\n })\n .join('\\n\\n');\n\n // Generate API client interface for each object\n // Always use plural collection names (standard REST convention).\n // Filter custom methods through resolveApiActionSet so the declared\n // type surface matches what generateClientModule actually emits at\n // runtime — otherwise consumers see methods in autocomplete that are\n // undefined at runtime.\n const apiClientInterface = selectApiClientEntries(manifest)\n .map(\n ({\n obj,\n clientKey,\n dataInterfaceName,\n crudMethods,\n customMethods: exposedMethods,\n }) => {\n const { methods = {} } = obj;\n const interfaceName = dataInterfaceName;\n const exposedActionNames = new Set(\n exposedMethods.map((method) => method.name),\n );\n const customMethods = Object.entries(methods).filter(\n ([name, method]) =>\n !GENERATED_CLIENT_CRUD_METHODS.has(name) &&\n method.isPublic &&\n exposedActionNames.has(name),\n );\n\n // Generate custom method signatures\n const customMethodSignatures = customMethods\n .map(([methodName]) => {\n const exposedMethod = exposedMethods.find(\n ({ name }) => name === methodName,\n );\n if (!exposedMethod) return '';\n const signature = renderApiClientCustomMethodParameters(\n exposedMethod,\n mapTypeScriptType,\n );\n return ` ${methodName}(${signature}): Promise<any>;`;\n })\n .join('\\n');\n\n const overriddenBaseMethods = customMethods\n .map(([methodName]) => methodName)\n .filter((methodName) =>\n GENERATED_CLIENT_BASE_METHODS.has(methodName),\n );\n const crudOperationsType = renderApiClientCrudType(\n interfaceName,\n crudMethods,\n overriddenBaseMethods,\n );\n\n if (customMethods.length > 0) {\n const intersection = crudOperationsType\n ? `${crudOperationsType} & `\n : '';\n return ` ${JSON.stringify(clientKey)}: ${intersection}{\\n${customMethodSignatures}\\n };`;\n }\n\n return ` ${JSON.stringify(clientKey)}: ${crudOperationsType ?? 'Record<string, never>'};`;\n },\n )\n .join('\\n');\n\n // Typed web collection definitions (#1761): one entry per REST collection,\n // with the row type threaded through the phantom `_row` carrier so\n // downstream factories (`@happyvertical/smrt-web`) can infer it. Selection\n // shares selectWebCollectionEntries with the runtime module so the declared\n // types and the emitted values cannot drift.\n const webCollectionInterface = selectWebCollectionEntries(manifest)\n .map(\n ({ collection, obj }) =>\n ` ${JSON.stringify(collection)}: SmrtWebCollectionDefinition<import('@happyvertical/smrt-virt-types').${obj.className}Data>;`,\n )\n .join('\\n');\n\n // Generate MCP tool interfaces based on discovered methods\n const _mcpTools = Object.entries(manifest.objects).flatMap(([_name, obj]) =>\n Object.entries(obj.methods).map(([methodName, method]) => ({\n name: `${methodName}_${obj.collection}`,\n description: `${method.name} operation on ${obj.collection}`,\n inputSchema: {\n type: 'object',\n properties: Object.fromEntries(\n method.parameters.map((param) => [\n param.name,\n { type: mapJsonSchemaType(param.type) },\n ]),\n ),\n required: method.parameters\n .filter((p) => p.optional !== true)\n .map((p) => p.name),\n },\n })),\n );\n\n const typeDeclarations = `/**\n * Auto-generated TypeScript declarations for SMRT virtual modules\n * Generated from discovered @smrt() decorated classes\n * \n * DO NOT EDIT THIS FILE MANUALLY\n * This file is automatically regenerated when SMRT objects change\n */\n\n// Manifest module - Contains discovered SMRT objects metadata\ndeclare module '@happyvertical/smrt-virt-manifest' {\n export interface SmrtObjectField {\n type: string;\n required?: boolean;\n default?: any;\n }\n\n export interface SmrtObjectMethod {\n name: string;\n parameters: Array<{\n name: string;\n type: string;\n required?: boolean;\n }>;\n returnType: string;\n isAsync: boolean;\n }\n\n export interface SmrtObjectDefinition {\n className: string;\n collection: string;\n fields: Record<string, SmrtObjectField>;\n methods: Record<string, SmrtObjectMethod>;\n decoratorConfig: any;\n }\n\n export interface SmrtManifest {\n version: string;\n timestamp: number;\n objects: Record<string, SmrtObjectDefinition>;\n }\n\n export const manifest: SmrtManifest;\n}\n\n// Routes module - Auto-generated REST route setup\ndeclare module '@happyvertical/smrt-virt-routes' {\n export interface RouteApp {\n get(path: string, handler: (req: any, res: any) => void): void;\n post(path: string, handler: (req: any, res: any) => void): void;\n put(path: string, handler: (req: any, res: any) => void): void;\n delete(path: string, handler: (req: any, res: any) => void): void;\n }\n\n export interface RouteOptions {\n basePath?: string;\n [key: string]: any;\n }\n\n export function setupRoutes(app: RouteApp, options?: RouteOptions): void;\n export default setupRoutes;\n}\n\n// Client module - Auto-generated API client\n// Wire-shape policy (#1797): the server returns BARE JSON — a bare array for\n// list/search, a bare object for get/create/update — with snake_case field\n// names (created_at, updated_at). These declarations match that shape (no\n// envelope, no camelCase). Fetchers reject on non-2xx with a SmrtClientError\n// (#1796). Shared CRUD wire types stay aligned with the prebuild declaration\n// path; Vite-only custom action declarations are layered onto them below.\ndeclare module '@happyvertical/smrt-virt-client' {\n /** Structured custom-action failure nested under an API error body's \\`error\\` key. */\n export interface SmrtClientFailure {\n ok: false;\n code: string;\n message: string;\n status?: number;\n }\n\n /** Shape of a JSON error body carried by a rejected request (SmrtClientError.body). */\n export interface ApiError {\n error?: string | SmrtClientFailure;\n message?: string;\n }\n\n /** Typed error thrown by every fetcher on a non-2xx response (#1796). */\n export interface SmrtClientError extends Error {\n name: 'SmrtClientError';\n status: number;\n /** Machine-readable code from a structured custom-action failure, when present. */\n code?: string;\n body?: ApiError | string;\n }\n\n export interface CrudOperations<T = any> {\n list(params?: Record<string, any>): Promise<T[]>;\n get(id: string): Promise<T>;\n create(data: Partial<T>): Promise<T>;\n update(id: string, data: Partial<T>): Promise<T>;\n delete(id: string): Promise<boolean>;\n search(query: string): Promise<T[]>;\n }\n\n export interface ApiClient {\n${apiClientInterface}\n }\n\n export function createClient(basePath?: string): ApiClient;\n export default createClient;\n}\n\n// MCP module - Auto-generated Model Context Protocol tools\ndeclare module '@happyvertical/smrt-virt-mcp' {\n import type { SmrtMCPServer, MCPServerOptions } from '@happyvertical/smrt-core/runtime';\n\n export interface McpTool {\n name: string;\n description: string;\n inputSchema: {\n type: string;\n properties: Record<string, any>;\n required?: string[];\n };\n }\n\n export const tools: McpTool[];\n export function createMCPServer(options?: MCPServerOptions): SmrtMCPServer;\n export default createMCPServer;\n}\n\n// Types module - Auto-generated TypeScript interfaces\ndeclare module '@happyvertical/smrt-virt-types' {\n export const types: string;\n\n // Auto-generated interfaces for discovered SMRT objects\n${objectInterfaces}\n\n export default types;\n}\n\n// Web module - Typed collection definitions for the browser client data\n// runtime (@happyvertical/smrt-web, #1761)\ndeclare module '@happyvertical/smrt-virt-web' {\n export type SmrtWebFieldType =\n | 'text'\n | 'decimal'\n | 'boolean'\n | 'integer'\n | 'datetime'\n | 'json'\n | 'foreignKey'\n | 'crossPackageRef';\n\n /** Static \\`@field({ ui })\\` hints (#2046) — the field-policy rail seed. */\n export interface SmrtWebFieldUIHints {\n basic?: boolean;\n group?: string;\n order?: number;\n locked?: boolean;\n }\n\n export interface SmrtWebFieldDefinition {\n type: SmrtWebFieldType;\n required?: boolean;\n nullable?: boolean;\n default?: unknown;\n /** Developer-authored \\`@field({ description })\\` (#2046) — end-user help seed. */\n description?: string;\n /** Static \\`@field({ ui })\\` hints (#2046). */\n ui?: SmrtWebFieldUIHints;\n }\n\n export type SmrtWebRelationshipKind =\n | 'foreignKey'\n | 'crossPackageRef'\n | 'oneToMany'\n | 'manyToMany';\n\n /**\n * A manifest-derived edge to a sibling REST collection. Mutating this\n * collection invalidates the caches of the collections named by these edges\n * (#1761 relationship-derived invalidation).\n */\n export interface SmrtWebRelationship {\n field: string;\n kind: SmrtWebRelationshipKind;\n relatedCollection: string;\n }\n\n export interface WebToolRouteDescriptor {\n method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';\n scope: 'item' | 'collection';\n path: string[];\n parameterAliases?: Record<string, string>;\n optionsBag?: boolean;\n }\n\n /** A WebMCP/MCP tool descriptor for one collection action (#1812). */\n export interface WebToolDescriptor {\n action: string;\n name: string;\n description: string;\n inputSchema: Record<string, unknown>;\n readOnly: boolean;\n route?: WebToolRouteDescriptor;\n }\n\n export interface SmrtWebCollectionDefinition<TData = Record<string, unknown>> {\n name: string;\n /** Canonical qualified model identity (\\`@package/name:ClassName\\`) for policy APIs. */\n objectRef: string;\n className: string;\n endpoint: string;\n idField: string;\n actions: string[];\n fields: Record<string, SmrtWebFieldDefinition>;\n /** Manifest-derived relationship edges to sibling REST collections. */\n relationships: SmrtWebRelationship[];\n /** WebMCP/MCP tool descriptors for the exposed actions (#1812). */\n toolDescriptors: WebToolDescriptor[];\n /** Phantom row-type carrier for inference — never present at runtime. */\n _row?: TData;\n }\n\n export interface SmrtWebCollectionDefinitions {\n${webCollectionInterface}\n }\n\n export const collectionDefinitions: SmrtWebCollectionDefinitions;\n export function getCollectionDefinition<\n K extends keyof SmrtWebCollectionDefinitions,\n >(name: K): SmrtWebCollectionDefinitions[K];\n /**\n * Build-time web-collection shape digest (#1764). A deterministic,\n * replica-stable hash of the emitted collection definitions; a change means\n * old persisted client rows may mis-hydrate. Consumers fold it into the\n * durable persistence namespace and the version-awareness updateAvailable\n * contract signal. One of the co-managed emission sites that must not drift —\n * the runtime value, this ambient d.ts, the physical @smrt/web d.ts, and the\n * hand-written @happyvertical/smrt-web type mirror.\n */\n export const manifestHash: string;\n export default collectionDefinitions;\n}\n\n// CLI module - Auto-generated command-line interface\ndeclare module '@happyvertical/smrt-virt-cli' {\n export interface CLIConfig {\n name?: string;\n version?: string;\n description?: string;\n prompt?: boolean;\n colors?: boolean;\n }\n\n export interface CLIContext {\n db?: any;\n ai?: any;\n user?: {\n id: string;\n roles?: string[];\n };\n }\n\n export interface CLICommandMap {\n [objectName: string]: {\n collection: string;\n commands: string[];\n };\n }\n\n export const cliCommands: CLICommandMap;\n\n export function setupCLI(config?: CLIConfig, context?: CLIContext): {\n run: (argv: string[]) => Promise<void>;\n generator: any;\n };\n\n export function getCLIHandler(config?: CLIConfig, context?: CLIContext): (argv: string[]) => Promise<void>;\n\n export default setupCLI;\n}`;\n\n // Write the declarations file\n writeFileSync(declarationsFile, typeDeclarations);\n console.log(\n `[smrt] Generated TypeScript declarations: ${declarationsFile}`,\n );\n } catch (error) {\n console.error('[smrt] Error generating TypeScript declarations:', error);\n }\n}\n\n/**\n * Map SMRT field types to TypeScript types\n */\nfunction mapTypeScriptType(smrtType: string): string {\n const typeMap: Record<string, string> = {\n text: 'string',\n integer: 'number',\n decimal: 'number',\n datetime: 'string',\n json: 'any',\n foreignKey: 'string',\n crossPackageRef: 'string',\n oneToMany: 'any[]',\n manyToMany: 'any[]',\n meta: 'any',\n string: 'string',\n number: 'number',\n boolean: 'boolean',\n array: 'any[]',\n object: 'Record<string, any>',\n date: 'string',\n Date: 'string',\n };\n return typeMap[smrtType] || 'any';\n}\n\n/**\n * Map TypeScript types to JSON Schema types for MCP tools\n */\nfunction mapJsonSchemaType(tsType: string): string {\n const typeMap: Record<string, string> = {\n string: 'string',\n number: 'number',\n boolean: 'boolean',\n array: 'array',\n object: 'object',\n any: 'string',\n };\n return typeMap[tsType] || 'string';\n}\n\n/**\n * Get default HTML template with inlined JavaScript (inlined for distribution)\n */\nfunction getDefaultHTML(): string {\n const uiScript = getDefaultUIModule();\n\n // Build HTML without template literals to avoid escaping issues\n return (\n '<!DOCTYPE html>\\n' +\n '<html lang=\"en\">\\n' +\n '<head>\\n' +\n ' <meta charset=\"UTF-8\">\\n' +\n ' <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\\n' +\n ' <title>SMRT Development UI</title>\\n' +\n ' <style>\\n' +\n ' * { margin: 0; padding: 0; box-sizing: border-box; }\\n' +\n ' body {\\n' +\n ' font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;\\n' +\n ' background: #f5f5f5;\\n' +\n ' color: #333;\\n' +\n ' }\\n' +\n ' .container { max-width: 1200px; margin: 0 auto; padding: 20px; }\\n' +\n ' header {\\n' +\n ' background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\\n' +\n ' color: white;\\n' +\n ' padding: 40px 0;\\n' +\n ' margin-bottom: 40px;\\n' +\n ' box-shadow: 0 4px 6px rgba(0,0,0,0.1);\\n' +\n ' }\\n' +\n ' header h1 { font-size: 2.5em; font-weight: 700; margin-bottom: 10px; }\\n' +\n ' .subtitle { font-size: 1.1em; opacity: 0.9; }\\n' +\n ' .stats {\\n' +\n ' display: grid;\\n' +\n ' grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\\n' +\n ' gap: 20px;\\n' +\n ' margin-bottom: 40px;\\n' +\n ' }\\n' +\n ' .stat-card {\\n' +\n ' background: white;\\n' +\n ' padding: 20px;\\n' +\n ' border-radius: 8px;\\n' +\n ' box-shadow: 0 2px 4px rgba(0,0,0,0.1);\\n' +\n ' text-align: center;\\n' +\n ' }\\n' +\n ' .stat-value { font-size: 2.5em; font-weight: 700; color: #667eea; margin-bottom: 5px; }\\n' +\n ' .stat-label { font-size: 0.9em; color: #666; text-transform: uppercase; letter-spacing: 1px; }\\n' +\n ' .collections { display: grid; gap: 30px; }\\n' +\n ' .collection-card {\\n' +\n ' background: white;\\n' +\n ' border-radius: 8px;\\n' +\n ' box-shadow: 0 2px 4px rgba(0,0,0,0.1);\\n' +\n ' overflow: hidden;\\n' +\n ' }\\n' +\n ' .collection-header {\\n' +\n ' background: #667eea;\\n' +\n ' color: white;\\n' +\n ' padding: 15px 20px;\\n' +\n ' display: flex;\\n' +\n ' justify-content: space-between;\\n' +\n ' align-items: center;\\n' +\n ' }\\n' +\n ' .collection-title { font-size: 1.3em; font-weight: 600; }\\n' +\n ' .collection-count {\\n' +\n ' background: rgba(255,255,255,0.2);\\n' +\n ' padding: 5px 15px;\\n' +\n ' border-radius: 20px;\\n' +\n ' font-size: 0.9em;\\n' +\n ' }\\n' +\n ' .collection-body { padding: 20px; }\\n' +\n ' .field-list {\\n' +\n ' display: grid;\\n' +\n ' grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));\\n' +\n ' gap: 15px;\\n' +\n ' margin-bottom: 20px;\\n' +\n ' }\\n' +\n ' .field {\\n' +\n ' padding: 10px;\\n' +\n ' background: #f8f9fa;\\n' +\n ' border-radius: 4px;\\n' +\n ' border-left: 3px solid #667eea;\\n' +\n ' }\\n' +\n ' .field-name { font-weight: 600; color: #333; margin-bottom: 3px; }\\n' +\n ' .field-type { font-size: 0.85em; color: #666; }\\n' +\n ' .actions { display: flex; gap: 10px; flex-wrap: wrap; }\\n' +\n ' .btn {\\n' +\n ' padding: 10px 20px;\\n' +\n ' border: none;\\n' +\n ' border-radius: 4px;\\n' +\n ' font-size: 0.9em;\\n' +\n ' cursor: pointer;\\n' +\n ' transition: all 0.2s;\\n' +\n ' text-decoration: none;\\n' +\n ' display: inline-block;\\n' +\n ' }\\n' +\n ' .btn-primary { background: #667eea; color: white; }\\n' +\n ' .btn-primary:hover { background: #5568d3; transform: translateY(-1px); }\\n' +\n ' .btn-secondary { background: #e0e0e0; color: #333; }\\n' +\n ' .btn-secondary:hover { background: #d0d0d0; }\\n' +\n ' .loading { text-align: center; padding: 40px; color: #666; }\\n' +\n ' .error {\\n' +\n ' background: #fee;\\n' +\n ' border: 1px solid #fcc;\\n' +\n ' color: #c33;\\n' +\n ' padding: 15px;\\n' +\n ' border-radius: 4px;\\n' +\n ' margin-bottom: 20px;\\n' +\n ' }\\n' +\n ' .empty-state { text-align: center; padding: 60px 20px; color: #999; }\\n' +\n ' .empty-state svg { width: 100px; height: 100px; margin-bottom: 20px; opacity: 0.3; }\\n' +\n ' </style>\\n' +\n '</head>\\n' +\n '<body>\\n' +\n ' <div id=\"app\">\\n' +\n ' <div class=\"loading\">Loading SMRT UI...</div>\\n' +\n ' </div>\\n' +\n ' <script type=\"module\">\\n' +\n uiScript +\n '\\n </script>\\n' +\n '</body>\\n' +\n '</html>'\n );\n}\n\n/**\n * Get default UI module from template file\n * Loads the JavaScript template\n */\nfunction getDefaultUIModule(): string {\n try {\n // Get current file directory\n const __dirname = dirname(fileURLToPath(import.meta.url));\n\n // Load template file (works in both src and dist)\n const templatePath = join(__dirname, 'templates/default-ui.js');\n\n return readFileSync(templatePath, 'utf-8').trim();\n } catch (error) {\n console.error('[smrt] Error loading UI template:', error);\n // Fallback to minimal UI\n return `\nasync function createUI() {\n const app = document.getElementById('app');\n if (!app) return;\n app.innerHTML = '<div class=\"container\" style=\"padding:40px;text-align:center;\"><h1>🎯 SMRT Development UI</h1><p>Template file not found. UI code could not be loaded.</p></div>';\n}\ncreateUI();\n`;\n }\n}\n\n/**\n * Load default HTML template for projects without index.html\n */\nasync function loadDefaultHTML(): Promise<string> {\n return getDefaultHTML();\n}\n\n/**\n * Load default UI module\n */\nasync function loadDefaultUI(): Promise<string> {\n return getDefaultUIModule();\n}\n\n/**\n * Generate virtual CLI module\n */\nasync function generateCLIModule(\n manifest: SmartObjectManifest,\n): Promise<string> {\n try {\n // Import CLI types\n const commands: string[] = [];\n const objectImports: string[] = [];\n\n // Generate CLI setup code for each object\n for (const [className, objectDef] of Object.entries(manifest.objects)) {\n const config = objectDef.decoratorConfig;\n const cliConfig = config?.cli;\n\n // Skip if CLI is disabled\n if (cliConfig === false) continue;\n\n // Determine which operations to include\n const excluded =\n (typeof cliConfig === 'object' ? cliConfig.exclude : []) || [];\n const included = typeof cliConfig === 'object' ? cliConfig.include : null;\n\n const shouldInclude = (command: string) => {\n if (included && !included.includes(command)) return false;\n if (excluded.includes(command)) return false;\n return true;\n };\n\n // Collection name (metadata) and the command segment. Commands are keyed\n // by the simple class name (e.g. `document:list`) to match what\n // `CLIGenerator` resolves and the dev `smrt` CLI convention — NOT the\n // plural collection name, which the runtime resolver does not accept.\n const collectionName = objectDef.collection;\n const commandName = (objectDef.className || className).toLowerCase();\n\n // Generate import statement for the object class\n objectImports.push(\n `// Import ${className} and ${className}Collection for CLI operations`,\n );\n\n // Generate command registration\n const availableCommands: string[] = [];\n\n // Standard CRUD commands\n if (shouldInclude('list'))\n availableCommands.push(`'${commandName}:list'`);\n if (shouldInclude('get')) availableCommands.push(`'${commandName}:get'`);\n if (shouldInclude('create'))\n availableCommands.push(`'${commandName}:create'`);\n if (shouldInclude('update'))\n availableCommands.push(`'${commandName}:update'`);\n if (shouldInclude('delete'))\n availableCommands.push(`'${commandName}:delete'`);\n\n // Custom action methods\n for (const [methodName, _method] of Object.entries(objectDef.methods)) {\n // Skip private methods and standard CRUD\n if (\n methodName.startsWith('_') ||\n ['list', 'get', 'create', 'update', 'delete', 'save'].includes(\n methodName,\n )\n )\n continue;\n\n if (shouldInclude(methodName)) {\n availableCommands.push(`'${commandName}:${methodName}'`);\n }\n }\n\n if (availableCommands.length > 0) {\n commands.push(`\n // ${className} commands\n ${className}: {\n collection: '${collectionName}',\n commands: [${availableCommands.join(', ')}]\n }`);\n }\n }\n\n return `\n// Auto-generated CLI module from SMRT objects\n// This file is generated automatically - do not edit\n\nimport { CLIGenerator } from '@happyvertical/smrt-core/generators/cli';\n\n/**\n * @typedef {import('@happyvertical/smrt-core/generators/cli').CLIConfig} CLIConfig\n * @typedef {import('@happyvertical/smrt-core/generators/cli').CLIContext} CLIContext\n */\n\n${objectImports.join('\\n')}\n\n/**\n * Available CLI commands by object\n */\nexport const cliCommands = {${commands.join(',\\n')}\n};\n\n/**\n * Setup CLI with auto-generated commands\n *\n * @param {CLIConfig} [config={}] - CLI configuration\n * @param {CLIContext} [context={}] - CLI context\n * @returns {{run: function(string[]): Promise<void>, generator: *}}\n *\n * @example\n * import { setupCLI } from '@happyvertical/smrt-virt-cli';\n *\n * const cli = setupCLI({\n * name: 'my-app',\n * version: '1.0.0'\n * });\n *\n * cli.run(process.argv);\n */\nexport function setupCLI(config = {}, context = {}) {\n const generator = new CLIGenerator(config, context);\n return {\n run: async (argv) => {\n const handler = generator.generateHandler();\n await handler(argv.slice(2)); // Remove 'node' and script name\n },\n generator\n };\n}\n\n/**\n * Get CLI handler directly\n *\n * @param {CLIConfig} [config={}] - CLI configuration\n * @param {CLIContext} [context={}] - CLI context\n * @returns {function(string[]): Promise<void>}\n */\nexport function getCLIHandler(config = {}, context = {}) {\n const generator = new CLIGenerator(config, context);\n return generator.generateHandler();\n}\n\nexport default setupCLI;\n`;\n } catch (error) {\n console.warn('[smrt] Error generating CLI module:', error);\n return `\n// Error generating CLI module\nexport const cliCommands = {};\nexport function setupCLI() {\n console.warn(\"CLI generation failed\");\n return { run: async () => {} };\n}\nexport function getCLIHandler() {\n return async () => console.warn(\"CLI generation failed\");\n}\nexport default setupCLI;\n`;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/vite-plugin/index.ts"],"sourcesContent":["/**\n * Vite plugin for automatic SMRT service generation\n * Provides virtual modules for REST, MCP, and other services\n */\n\nimport { existsSync, readFileSync } from 'node:fs';\nimport { dirname, join, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type {\n DomainKnowledgeConfig,\n DomainKnowledgeManifest,\n} from '@happyvertical/smrt-types';\nimport type { Plugin, ResolvedConfig, ViteDevServer } from 'vite';\nimport {\n loadVerifiedSmrtGenerationSnapshot,\n type SmrtGenerationSnapshotOptions,\n} from '../generation-snapshot.js';\nimport { buildDomainKnowledgeManifest } from '../knowledge.js';\nimport { discoverSmrtPackages } from '../manifest/discover-smrt-packages.js';\nimport {\n DETERMINISTIC_GENERATED_AT,\n type SmartObjectManifest,\n} from '../scanner/types.js';\nimport { importWorkspaceModule } from '../utils/import-workspace-module.js';\nimport type { ScannerModule } from '../utils/scanner-module.js';\nimport {\n renderApiClientCrudType,\n renderApiClientCustomMethodParameters,\n selectApiClientEntries,\n} from './api-client-entries.js';\nimport {\n GENERATED_CLIENT_BASE_METHODS,\n GENERATED_CLIENT_CRUD_METHODS,\n generateClientModule,\n} from './generated-client.js';\nimport { importBuildAwareModule } from './import-build-aware.js';\nimport {\n findCliApiCoherenceViolations,\n generateSvelteKitRoutes,\n validateCliIncludeAgainstApi,\n} from './sveltekit-generator.js';\nimport {\n buildWebCollectionDefinition,\n buildWebMcpToolDefinitions,\n buildWebToolDescriptors,\n computeWebManifestHash,\n selectWebCollectionEntries,\n} from './web-collections.js';\n\nexport {\n loadVerifiedSmrtGenerationSnapshot,\n type SerializeSmrtGenerationSnapshotOptions,\n type SmrtGenerationSnapshotArtifact,\n type SmrtGenerationSnapshotOptions,\n type SmrtGenerationSnapshotView,\n serializeSmrtGenerationSnapshot,\n sha256SmrtGenerationSnapshot,\n} from '../generation-snapshot.js';\nexport type {\n CliApiCoherenceViolation,\n SvelteKitOptions,\n} from './sveltekit-generator.js';\n// Re-export SvelteKit route generator for CLI usage\nexport {\n findCliApiCoherenceViolations,\n generateSvelteKitRoutes,\n methodNameToKebab,\n resolveApiActionRouteConfig,\n resolveApiActionSet,\n validateCliIncludeAgainstApi,\n} from './sveltekit-generator.js';\n\n/**\n * Minimal structural shape of a parsed `package.json`. Only the fields the\n * plugin reads are typed; the index signature keeps the rest accessible (e.g.\n * `exports`, consumed downstream by agent-manifest generation).\n */\ninterface PackageJsonShape {\n name?: string;\n version?: string;\n [key: string]: unknown;\n}\n\nexport interface SmrtPluginOptions {\n /** Root directory that owns generated manifests and SvelteKit routes. */\n projectRoot?: string;\n /**\n * Reuse an immutable, verified manifest instead of scanning sources or\n * writing manifest files. Generated routes, virtual modules, and type\n * declarations still consume the verified manifest.\n */\n generationSnapshot?: SmrtGenerationSnapshotOptions;\n /** Glob patterns for SMRT source files */\n include?: string[];\n /** Patterns to exclude */\n exclude?: string[];\n /**\n * Follow symbolic links while discovering sources. Defaults to `false`: a\n * pnpm `node_modules` is a symlink graph with cycles, so a link-following\n * walk does not terminate on a real install (#2275). Enable it only for a\n * project that genuinely keeps sources behind a link.\n */\n followSymbolicLinks?: boolean;\n /** Output directory for generated files */\n outDir?: string;\n /** Enable hot module replacement */\n hmr?: boolean;\n /** Watch for file changes */\n watch?: boolean;\n /** Generate types */\n generateTypes?: boolean;\n /** Custom base classes to scan for */\n baseClasses?: string[];\n /** Follow import chains to detect inheritance (e.g., Event extends SmrtObject) */\n followImports?: boolean;\n /** Directory to write TypeScript declarations (relative to project root) */\n typeDeclarationsPath?: string;\n /** Plugin execution mode - controls Node.js vs browser compatibility */\n mode?: 'server' | 'client' | 'auto';\n /**\n * @deprecated OXC scanner is now the only scanner. This option is ignored.\n */\n experimentalFastScanner?: boolean;\n /** SvelteKit route auto-generation options */\n svelteKit?: {\n /** Enable SvelteKit route generation (default: false) */\n enabled: boolean;\n /** Output directory for generated routes (default: 'src/routes/api') */\n routesDir?: string;\n /** Directory containing SMRT objects (default: 'src/lib/objects') */\n objectsDir?: string;\n /** Directory for configuration file (default: 'src/lib/server') */\n configPath?: string;\n /** Configuration file name (default: 'smrt.ts') */\n configFileName?: string;\n /**\n * Apply kebab-case to custom-method URL segments (e.g. `discoverFromUrl`\n * becomes `/discover-from-url`). Opt-in for one minor; default flips in\n * the next major. An explicit `api.routes[name].path` always wins.\n */\n kebabRoutes?: boolean;\n /**\n * Change-feed `_changes` route generation (#1758). Enabled by default\n * (the route is auth-guarded fail-closed); `{ enabled: false }` skips it.\n */\n changesRoute?: { enabled?: boolean };\n /**\n * Live `_events` SSE route generation (#1763). Enabled by default (the\n * route is auth-guarded fail-closed, same-origin only); `{ enabled: false }`\n * skips it. `maxSubscribers` caps active streams per process (#1860).\n */\n eventsRoute?: { enabled?: boolean; maxSubscribers?: number };\n };\n /** Domain-scoped agent/developer knowledge artifact generation. */\n knowledge?: DomainKnowledgeConfig | false;\n /**\n * Validate that every method in `cli.include` is exposed via the API\n * (so HTTP-based CLI consumers can actually reach them). Default: true.\n * Per-class opt-out via `cli: { skipApiCheck: true }`.\n */\n validateCliApiCoherence?: boolean;\n}\n\nconst VIRTUAL_MODULES = {\n '@happyvertical/smrt-virt-routes': 'smrt:routes',\n '@happyvertical/smrt-virt-client': 'smrt:client',\n '@happyvertical/smrt-virt-mcp': 'smrt:mcp',\n '@happyvertical/smrt-virt-types': 'smrt:types',\n '@happyvertical/smrt-virt-manifest': 'smrt:manifest',\n '@happyvertical/smrt-virt-ui': 'smrt:ui',\n '@happyvertical/smrt-virt-cli': 'smrt:cli',\n '@happyvertical/smrt-virt-web': 'smrt:web',\n};\n\nasync function importScanner() {\n return importWorkspaceModule<ScannerModule>({\n packageName: '@happyvertical/smrt-scanner',\n distEntry: 'packages/scanner/dist/index.js',\n sourceEntry: 'packages/scanner/src/index.ts',\n purpose: 'Vite manifest scanning',\n });\n}\n\n/**\n * Matches a package's `__smrt-register__` self-registration shim by module id\n * (query strings stripped). node_modules is excluded: only the package's OWN\n * shim is rewritten during its library build, never a dependency's compiled\n * output.\n */\nconst REGISTER_SHIM_RE = /[\\\\/]__smrt-register__\\.(?:ts|mts|js|mjs)$/;\n\nexport function isRegisterShimModuleId(id: string): boolean {\n const cleanId = id.split('?')[0];\n return REGISTER_SHIM_RE.test(cleanId) && !cleanId.includes('node_modules');\n}\n\n/**\n * Generate the replacement `__smrt-register__` module with the build-time\n * manifest inlined as data (issues #1506/#1507).\n *\n * The source shim resolves `new URL('./manifest.json', import.meta.url)` at\n * runtime, which assumes the compiled module ends up next to\n * `dist/manifest.json`. That held for the package's own dist (with the #1331\n * upward-search recovery), but breaks once a CONSUMER bundles the package\n * into its own output — e.g. a SvelteKit server build relocates the module\n * into `build/server/chunks/`, the URL resolves to a manifest that does not\n * exist, registration silently no-ops, and every plain (undecorated) field is\n * dropped from INSERTs and rejected by WHERE validation. Inlining the\n * manifest at library-build time removes the runtime filesystem lookup\n * entirely, so no downstream bundler layout can break registration.\n *\n * `JSON.parse('<literal>')` is used instead of an object literal: it parses\n * faster for large payloads and sidesteps identifier/keyword edge cases.\n */\nexport function generateInlineRegisterModule(\n manifest: SmartObjectManifest,\n): string {\n const manifestLiteral = JSON.stringify(JSON.stringify(manifest));\n return [\n '// Generated by @happyvertical/smrt-core smrtPlugin at library build time.',\n '// The package manifest is inlined so self-registration cannot miss when a',\n '// downstream bundler relocates this module away from dist/manifest.json',\n '// (https://github.com/happyvertical/smrt/issues/1506,',\n '// https://github.com/happyvertical/smrt/issues/1507).',\n \"import { ObjectRegistry } from '@happyvertical/smrt-core';\",\n '',\n `ObjectRegistry.registerPackageManifest(JSON.parse(${manifestLiteral}));`,\n '',\n ].join('\\n');\n}\n\nexport function smrtPlugin(options: SmrtPluginOptions = {}): Plugin {\n const {\n projectRoot: configuredProjectRoot,\n generationSnapshot,\n include = ['src/**/*.ts', 'src/**/*.js'],\n exclude = ['**/*.test.ts', '**/*.spec.ts', '**/node_modules/**'],\n followSymbolicLinks = false,\n hmr = true,\n watch = true,\n generateTypes = true,\n baseClasses = ['SmrtObject', 'SmartObject'],\n followImports = true, // Default true: needed for multi-package inheritance\n typeDeclarationsPath = 'src/types',\n mode = 'auto',\n svelteKit = {\n enabled: false,\n routesDir: 'src/routes/api',\n objectsDir: 'src/lib/objects',\n configPath: 'src/lib/server',\n configFileName: 'smrt.ts',\n },\n knowledge,\n validateCliApiCoherence = true,\n } = options;\n\n /**\n * Dev-watcher variant of the cli↔api coherence lint: warn instead of throw,\n * so an in-flight decorator edit doesn't kill the dev server. Uses the same\n * remediation text as the strict build-time gate (`validateCliIncludeAgainstApi`)\n * so the dev-server message is as actionable as the build failure.\n */\n function warnCliApiCoherenceViolations(m: SmartObjectManifest): void {\n if (!validateCliApiCoherence) return;\n const violations = findCliApiCoherenceViolations(m);\n if (violations.length === 0) return;\n for (const { className, unreachable } of violations) {\n for (const action of unreachable) {\n console.warn(\n `[smrt] ${className}.${action} is declared in cli.include but is not ` +\n `exposed via the api. Build will fail until this is resolved.\\n` +\n ` Either:\\n` +\n ` - Add '${action}' to api.include, or\\n` +\n ` - Remove '${action}' from cli.include.\\n` +\n ` The CLI invokes methods over HTTP; methods without API routes are unreachable.\\n` +\n ` If this CLI is intentionally invoked in-process (no HTTP), set\\n` +\n ` \\`cli: { skipApiCheck: true }\\` on the @smrt() decorator to acknowledge.`,\n );\n }\n }\n }\n\n let server: ViteDevServer | undefined;\n let manifest: SmartObjectManifest | null = null;\n let pluginMode: 'server' | 'client' = 'server';\n let projectRoot: string = process.cwd();\n let config: ResolvedConfig | null = null; // Store resolved config for closeBundle hook\n let resolvedPluginNames: string[] = [];\n let hasFreshConfigResolvedManifest = false;\n let configHookManifest: SmartObjectManifest | null = null;\n let generatedRoutesDuringConfig = false;\n\n async function generateConfiguredSvelteKitRoutes(\n rootDir: string,\n currentManifest: SmartObjectManifest,\n ): Promise<void> {\n await generateSvelteKitRoutes(rootDir, currentManifest, {\n enabled: svelteKit.enabled,\n routesDir: svelteKit.routesDir || 'src/routes/api',\n objectsDir: svelteKit.objectsDir || 'src/lib/objects',\n configPath: svelteKit.configPath || 'src/lib/server',\n configFileName: svelteKit.configFileName || 'smrt.ts',\n kebabRoutes: svelteKit.kebabRoutes ?? false,\n changesRoute: svelteKit.changesRoute,\n eventsRoute: svelteKit.eventsRoute,\n knowledge: await resolveKnowledgeConfig(rootDir, currentManifest),\n });\n }\n\n /**\n * Write manifest to .smrt/manifest.json for CLI discovery.\n * This ensures `smrt db:migrate`, `smrt db:status`, etc. can find\n * locally-defined SMRT objects in non-library builds (Issue #963).\n */\n async function writeLocalManifest(\n m: SmartObjectManifest,\n rootDir: string,\n ): Promise<void> {\n try {\n const { writeFileSync, mkdirSync } = await import('node:fs');\n const { resolve } = await import('node:path');\n\n const smrtDir = resolve(rootDir, '.smrt');\n mkdirSync(smrtDir, { recursive: true });\n\n const manifestPath = resolve(smrtDir, 'manifest.json');\n writeFileSync(manifestPath, JSON.stringify(m, null, 2), 'utf-8');\n await writeDomainKnowledgeArtifact(\n m,\n rootDir,\n resolve(smrtDir, 'smrt-knowledge.json'),\n manifestPath,\n );\n\n const objectCount = Object.keys(m.objects).length;\n console.log(\n `[smrt] Wrote local manifest with ${objectCount} objects to .smrt/manifest.json`,\n );\n } catch (error) {\n console.error('[smrt] Error writing local manifest:', error);\n }\n }\n\n /**\n * @param deterministic - Emit a fixed `generatedAt` instead of the clock.\n * Set for artifacts written into the build output directory: `dist/` is\n * compared byte-for-byte by downstream caches, and a fresh checkout has no\n * previous file for {@link preserveKnowledgeGeneratedAt} to carry a value\n * forward from, so every build would otherwise emit different bytes\n * (#2223). The working copy under `.smrt/` keeps a real timestamp, which\n * is where it is useful to a human and where preservation already works.\n */\n async function writeDomainKnowledgeArtifact(\n m: SmartObjectManifest,\n rootDir: string,\n outputPath: string,\n manifestPath: string,\n deterministic = false,\n ): Promise<void> {\n const resolvedKnowledge = await resolveKnowledgeConfig(rootDir, m);\n if (resolvedKnowledge.enabled === false) {\n return;\n }\n\n const { mkdirSync, writeFileSync } = await import('node:fs');\n const { dirname } = await import('node:path');\n mkdirSync(dirname(outputPath), { recursive: true });\n const artifact = buildDomainKnowledgeManifest({\n manifest: m,\n rootDir,\n manifestPath,\n config: resolvedKnowledge,\n });\n const emitted = deterministic\n ? { ...artifact, generatedAt: DETERMINISTIC_GENERATED_AT }\n : preserveKnowledgeGeneratedAt(outputPath, artifact);\n writeFileSync(outputPath, JSON.stringify(emitted, null, 2), 'utf-8');\n }\n\n async function resolveKnowledgeConfig(\n rootDir: string,\n m: SmartObjectManifest,\n ): Promise<DomainKnowledgeConfig> {\n if (knowledge === false) return { enabled: false };\n const packageName = m.packageName ?? readPackageName(rootDir);\n const defaults: DomainKnowledgeConfig = {\n enabled: true,\n api: {\n enabled: false,\n basePath: '/__smrt/knowledge',\n requireAdmin: true,\n includeDocs: false,\n includePrompts: false,\n },\n includeDocs: true,\n includePrompts: true,\n };\n\n let fileKnowledge: DomainKnowledgeConfig = {};\n let packageKnowledge: DomainKnowledgeConfig = {};\n try {\n const previousCwd = process.cwd();\n process.chdir(rootDir);\n try {\n const { loadConfig } = await import('@happyvertical/smrt-config');\n const config = await loadConfig({ cache: false });\n fileKnowledge = (config.knowledge ?? {}) as DomainKnowledgeConfig;\n packageKnowledge = (\n packageName ? (config.packages?.[packageName]?.knowledge ?? {}) : {}\n ) as DomainKnowledgeConfig;\n } finally {\n process.chdir(previousCwd);\n }\n } catch {\n fileKnowledge = {};\n packageKnowledge = {};\n }\n\n return mergeKnowledgeConfig(\n defaults,\n fileKnowledge,\n packageKnowledge,\n knowledge || {},\n );\n }\n\n function mergeKnowledgeConfig(\n ...configs: Array<DomainKnowledgeConfig | undefined | null | false>\n ): DomainKnowledgeConfig {\n const merged: DomainKnowledgeConfig = {};\n for (const next of configs) {\n if (!next) continue;\n const hasApi = Boolean(merged.api || next.api);\n const api = hasApi\n ? { ...(merged.api ?? {}), ...(next.api ?? {}) }\n : undefined;\n Object.assign(merged, next);\n if (api) merged.api = api;\n }\n return merged;\n }\n\n function preserveKnowledgeGeneratedAt(\n outputPath: string,\n nextKnowledge: DomainKnowledgeManifest,\n ): DomainKnowledgeManifest {\n if (!existsSync(outputPath)) return nextKnowledge;\n\n try {\n const current = JSON.parse(\n readFileSync(outputPath, 'utf8'),\n ) as Partial<DomainKnowledgeManifest>;\n if (\n semanticKnowledgeJson(current) === semanticKnowledgeJson(nextKnowledge)\n ) {\n return {\n ...nextKnowledge,\n generatedAt: current.generatedAt ?? nextKnowledge.generatedAt,\n };\n }\n } catch {\n // Replace malformed artifacts.\n }\n\n return nextKnowledge;\n }\n\n function semanticKnowledgeJson(\n artifact: Partial<DomainKnowledgeManifest>,\n ): string {\n const { generatedAt: _generatedAt, ...rest } = artifact ?? {};\n return JSON.stringify(sortJson(rest));\n }\n\n function sortJson(value: unknown): unknown {\n if (Array.isArray(value)) return value.map(sortJson);\n if (value && typeof value === 'object') {\n return Object.fromEntries(\n Object.entries(value as Record<string, unknown>)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([key, entry]) => [key, sortJson(entry)]),\n );\n }\n return value;\n }\n\n function readPackageName(rootDir: string): string | undefined {\n try {\n const pkg = JSON.parse(\n readFileSync(join(rootDir, 'package.json'), 'utf8'),\n );\n return typeof pkg.name === 'string' ? pkg.name : undefined;\n } catch {\n return undefined;\n }\n }\n\n function validateConsumerPluginSetup(\n m: SmartObjectManifest,\n context: 'configResolved' | 'buildStart',\n ): void {\n if (config?.mode === 'test') {\n return;\n }\n\n if (config?.build?.lib) {\n return;\n }\n\n const consumerDependencies = (m.smrtDependencies || []).filter(\n (dependency) => dependency !== '@happyvertical/smrt-core',\n );\n if (consumerDependencies.length === 0) {\n return;\n }\n\n const hasConsumerPlugin = resolvedPluginNames.some(\n (name) => name === 'smrt-consumer',\n );\n if (hasConsumerPlugin) {\n return;\n }\n\n const dependencySummary =\n consumerDependencies.length <= 4\n ? consumerDependencies.join(', ')\n : `${consumerDependencies.slice(0, 4).join(', ')}, +${consumerDependencies.length - 4} more`;\n\n throw new Error(\n `[smrt] Consumer project misconfiguration detected during ${context}: found external SMRT dependencies (${dependencySummary}) but vite.config is missing smrtConsumer(). Add \"import { smrtConsumer } from '@happyvertical/smrt-core/consumer-plugin'\" and register it alongside smrtPlugin() so .smrt/register.js is generated for CLI/runtime class loading.`,\n );\n }\n\n function validateLibraryMinifySetup(\n m: SmartObjectManifest,\n context: 'configResolved' | 'buildStart',\n ): void {\n if (!config?.build?.lib) {\n return;\n }\n\n if (Object.keys(m.objects || {}).length === 0) {\n return;\n }\n\n if (config.build.minify === false) {\n return;\n }\n\n throw new Error(\n `[smrt] Library package misconfiguration detected during ${context}: packages that publish SMRT objects must set Vite build.minify = false. Minification rewrites runtime class names and breaks manifest registration, STI resolution, and collection queries in downstream apps.`,\n );\n }\n\n return {\n name: 'smrt-auto-service',\n // SvelteKit inventories routes in a `config.order = 'pre'` hook. Put SMRT\n // in Vite's earlier plugin tier so this plugin's own pre hook runs first\n // even when the documented plugin array lists sveltekit() before us.\n enforce: 'pre',\n\n // SvelteKit inventories filesystem routes in its config hook. Generate\n // SMRT routes in an earlier config hook so a clean checkout's first build\n // sees them; configResolved is too late because Vite runs those hooks\n // concurrently (#2313).\n config: {\n order: 'pre',\n async handler(userConfig) {\n if (!svelteKit.enabled) return;\n\n projectRoot =\n configuredProjectRoot ??\n resolve(process.cwd(), userConfig.root ?? '.');\n configHookManifest = await scanAndGenerateManifest(projectRoot);\n await generateConfiguredSvelteKitRoutes(\n projectRoot,\n configHookManifest,\n );\n generatedRoutesDuringConfig = true;\n },\n },\n\n // Expose options for external access (e.g., test manifest generation)\n api: {\n options: {\n ...(configuredProjectRoot === undefined\n ? {}\n : { projectRoot: configuredProjectRoot }),\n ...(generationSnapshot === undefined ? {} : { generationSnapshot }),\n baseClasses,\n followImports,\n include,\n exclude,\n },\n },\n\n async configResolved(resolvedConfig) {\n hasFreshConfigResolvedManifest = false;\n // Store config for closeBundle hook\n config = resolvedConfig;\n resolvedPluginNames = (resolvedConfig.plugins || []).map(\n (plugin) => plugin?.name || '',\n );\n\n // Store project root for file scanning\n projectRoot = configuredProjectRoot ?? resolvedConfig.root;\n\n // Detect plugin mode based on build configuration\n if (mode === 'auto') {\n const isSSRBuild = resolvedConfig.build?.ssr;\n const isFederationBuild = resolvedConfig.plugins.some((p) =>\n p.name?.includes('federation'),\n );\n const isClientBuild =\n isFederationBuild ||\n (!isSSRBuild && resolvedConfig.build?.target === 'esnext');\n\n pluginMode = isClientBuild ? 'client' : 'server';\n } else {\n pluginMode = mode;\n }\n\n console.log(`[smrt] Running in ${pluginMode} mode`);\n\n // Scan files and generate initial manifest in all modes\n manifest =\n configHookManifest ?? (await scanAndGenerateManifest(projectRoot));\n configHookManifest = null;\n\n // Write local manifest for CLI discovery (Issue #963)\n if (manifest && !generationSnapshot) {\n await writeLocalManifest(manifest, projectRoot);\n }\n if (manifest) {\n validateLibraryMinifySetup(manifest, 'configResolved');\n validateConsumerPluginSetup(manifest, 'configResolved');\n if (validateCliApiCoherence) {\n validateCliIncludeAgainstApi(manifest);\n }\n }\n\n // Generate SvelteKit routes if enabled\n if (svelteKit.enabled && manifest && !generatedRoutesDuringConfig) {\n await generateConfiguredSvelteKitRoutes(projectRoot, manifest);\n }\n generatedRoutesDuringConfig = false;\n\n // Vite calls buildStart immediately after configResolved for the initial\n // build. The manifest already reflects the same source tree, so let that\n // first hook reuse it. Later buildStart calls are watch rebuilds and must\n // rescan changed classes.\n hasFreshConfigResolvedManifest = true;\n },\n\n async buildStart() {\n if (hasFreshConfigResolvedManifest) {\n hasFreshConfigResolvedManifest = false;\n // configureServer may be attached between configResolved and\n // buildStart. Emit declarations from the reused manifest even though\n // the scanner itself does not need to run again.\n if (generateTypes && server && manifest) {\n await generateTypeDeclarationFile(\n manifest,\n projectRoot,\n typeDeclarationsPath,\n );\n }\n return;\n }\n\n // Rescan files on build start in all modes\n manifest = await scanAndGenerateManifest(projectRoot);\n\n // Write local manifest for CLI discovery (Issue #963)\n if (manifest && !generationSnapshot) {\n await writeLocalManifest(manifest, projectRoot);\n }\n if (manifest) {\n validateLibraryMinifySetup(manifest, 'buildStart');\n validateConsumerPluginSetup(manifest, 'buildStart');\n if (validateCliApiCoherence) {\n validateCliIncludeAgainstApi(manifest);\n }\n }\n },\n\n transform(_code, id) {\n // Library builds only: inline the scanned manifest into the package's\n // __smrt-register__ shim so the published dist registers field metadata\n // as data instead of resolving ./manifest.json at runtime. Runtime URL\n // resolution silently no-ops when a consumer's bundler (e.g. a\n // SvelteKit server build) relocates the module into its own chunks\n // directory, dropping every plain field from the registry (#1506,\n // #1507). Dev/test flows are untouched: the vitest plugin populates\n // manifests through its own path, and non-library builds keep the\n // original shim.\n if (!config?.build?.lib || !manifest) {\n return null;\n }\n if (!isRegisterShimModuleId(id)) {\n return null;\n }\n return {\n code: generateInlineRegisterModule(manifest),\n map: null,\n };\n },\n\n shouldTransformCachedModule({ id }) {\n // In `vite build --watch`, rollup caches transform results keyed on the\n // module's own code. The inlined register shim depends on the manifest\n // (rescanned each buildStart), not on the shim's unchanged source — so\n // force a re-transform or a field edit elsewhere in the package would\n // ship a stale inlined manifest.\n if (config?.build?.lib && isRegisterShimModuleId(id)) {\n return true;\n }\n return null;\n },\n\n configureServer(devServer) {\n server = devServer;\n\n // Serve default HTML when no index.html exists\n // Skip for SvelteKit projects (they use src/app.html and handle routing themselves)\n devServer.middlewares.use(async (req, res, next) => {\n // Skip default UI entirely for SvelteKit projects\n if (svelteKit.enabled) {\n return next();\n }\n\n if (req.url === '/' || req.url === '/index.html') {\n try {\n const { existsSync } = await import('node:fs');\n const { join } = await import('node:path');\n\n const projectRoot = devServer.config.root;\n const indexPath = join(projectRoot, 'index.html');\n\n // If index.html exists, let Vite handle it\n if (existsSync(indexPath)) {\n return next();\n }\n\n // Otherwise, serve default SMRT UI\n console.log('[smrt] Serving default UI (no index.html found)');\n let html = getDefaultHTML();\n\n // Apply Vite's HTML transformation to process module imports\n html = await devServer.transformIndexHtml('/', html);\n\n res.setHeader('Content-Type', 'text/html');\n res.end(html);\n return;\n } catch (error) {\n console.error('[smrt] Error serving default HTML:', error);\n return next();\n }\n }\n next();\n });\n\n // Set up file watching in all modes when enabled\n if (watch && hmr && !generationSnapshot) {\n // Watch for file changes\n const watcher = devServer.watcher;\n\n // Guard each watcher handler: scanAndGenerateManifest re-throws on a\n // mid-edit scan error, and an unhandled rejection in a watcher callback\n // can crash the dev server. Log and keep the previous manifest (#1378).\n watcher.on('change', async (file) => {\n try {\n if (await shouldRescan(file)) {\n console.log(`[smrt] Rescanning due to change in ${file}`);\n manifest = await scanAndGenerateManifest(projectRoot);\n\n // Write local manifest for CLI discovery (Issue #963)\n if (manifest) {\n await writeLocalManifest(manifest, projectRoot);\n warnCliApiCoherenceViolations(manifest);\n }\n\n // Generate SvelteKit routes if enabled\n if (svelteKit.enabled && manifest && server) {\n await generateSvelteKitRoutes(projectRoot, manifest, {\n enabled: svelteKit.enabled,\n routesDir: svelteKit.routesDir || 'src/routes/api',\n objectsDir: svelteKit.objectsDir || 'src/lib/objects',\n configPath: svelteKit.configPath || 'src/lib/server',\n configFileName: svelteKit.configFileName || 'smrt.ts',\n kebabRoutes: svelteKit.kebabRoutes ?? false,\n changesRoute: svelteKit.changesRoute,\n eventsRoute: svelteKit.eventsRoute,\n knowledge: await resolveKnowledgeConfig(\n projectRoot,\n manifest,\n ),\n });\n }\n\n // Invalidate virtual modules\n Object.values(VIRTUAL_MODULES).forEach((id) => {\n const module = server?.moduleGraph.getModuleById(id);\n if (module) {\n server?.reloadModule(module);\n }\n });\n }\n } catch (error) {\n console.error(\n `[smrt] Failed to rescan after change in ${file}:`,\n error,\n );\n }\n });\n\n watcher.on('add', async (file) => {\n try {\n if (await shouldRescan(file)) {\n console.log(`[smrt] Rescanning due to new file ${file}`);\n manifest = await scanAndGenerateManifest(projectRoot);\n\n // Write local manifest for CLI discovery (Issue #963)\n if (manifest) {\n await writeLocalManifest(manifest, projectRoot);\n warnCliApiCoherenceViolations(manifest);\n }\n\n // Generate SvelteKit routes if enabled\n if (svelteKit.enabled && manifest && server) {\n await generateSvelteKitRoutes(projectRoot, manifest, {\n enabled: svelteKit.enabled,\n routesDir: svelteKit.routesDir || 'src/routes/api',\n objectsDir: svelteKit.objectsDir || 'src/lib/objects',\n configPath: svelteKit.configPath || 'src/lib/server',\n configFileName: svelteKit.configFileName || 'smrt.ts',\n kebabRoutes: svelteKit.kebabRoutes ?? false,\n changesRoute: svelteKit.changesRoute,\n eventsRoute: svelteKit.eventsRoute,\n knowledge: await resolveKnowledgeConfig(\n projectRoot,\n manifest,\n ),\n });\n }\n }\n } catch (error) {\n console.error(\n `[smrt] Failed to rescan after adding ${file}:`,\n error,\n );\n }\n });\n\n watcher.on('unlink', async (file) => {\n try {\n if (await shouldRescan(file)) {\n console.log(`[smrt] Rescanning due to removed file ${file}`);\n manifest = await scanAndGenerateManifest(projectRoot);\n\n // Write local manifest for CLI discovery (Issue #963)\n if (manifest) {\n await writeLocalManifest(manifest, projectRoot);\n warnCliApiCoherenceViolations(manifest);\n }\n\n // Generate SvelteKit routes if enabled\n if (svelteKit.enabled && manifest && server) {\n await generateSvelteKitRoutes(projectRoot, manifest, {\n enabled: svelteKit.enabled,\n routesDir: svelteKit.routesDir || 'src/routes/api',\n objectsDir: svelteKit.objectsDir || 'src/lib/objects',\n configPath: svelteKit.configPath || 'src/lib/server',\n configFileName: svelteKit.configFileName || 'smrt.ts',\n kebabRoutes: svelteKit.kebabRoutes ?? false,\n changesRoute: svelteKit.changesRoute,\n eventsRoute: svelteKit.eventsRoute,\n knowledge: await resolveKnowledgeConfig(\n projectRoot,\n manifest,\n ),\n });\n }\n }\n } catch (error) {\n console.error(\n `[smrt] Failed to rescan after removing ${file}:`,\n error,\n );\n }\n });\n }\n },\n\n resolveId(id) {\n // Resolve virtual module imports\n if (id in VIRTUAL_MODULES) {\n return `\\0${VIRTUAL_MODULES[id as keyof typeof VIRTUAL_MODULES]}`;\n }\n\n // Resolve virtual index.html for dev UI (only in dev mode)\n if (id === '/index.html' && server) {\n return `\\0smrt:index-html`;\n }\n\n return null;\n },\n\n async load(id) {\n // Load virtual modules (strip the \\0 prefix)\n const cleanId = id.startsWith('\\0') ? id.slice(1) : id;\n\n if (!manifest) {\n manifest = await scanAndGenerateManifest(projectRoot);\n }\n\n switch (cleanId) {\n case 'smrt:routes':\n // Routes module available in all modes\n return await generateRoutesModule(manifest);\n\n case 'smrt:client':\n // Client module available in both modes\n return generateClientModule(manifest, {\n kebabRoutes: svelteKit.kebabRoutes ?? false,\n });\n\n case 'smrt:mcp':\n // MCP module available in all modes\n return await generateMCPModule(manifest);\n\n case 'smrt:types':\n // Types module available in both modes\n return await generateTypesModule(manifest, pluginMode);\n\n case 'smrt:manifest':\n // Manifest module available in both modes\n return generateManifestModule(manifest);\n\n case 'smrt:ui':\n // UI module for default development interface\n return await loadDefaultUI();\n\n case 'smrt:index-html':\n // Virtual index.html for projects without one\n return await loadDefaultHTML();\n\n case 'smrt:cli':\n // CLI module for command-line interface generation\n return await generateCLIModule(manifest);\n\n case 'smrt:web':\n // Web collection definitions for the browser client data runtime\n // (@happyvertical/smrt-web, #1761)\n return generateWebModule(manifest, {\n kebabRoutes: svelteKit.kebabRoutes ?? false,\n });\n\n default:\n return null;\n }\n },\n\n transformIndexHtml: {\n order: 'pre',\n handler: async (html, _ctx) => {\n // Only provide default HTML if no index.html exists in project\n if (!server) return html;\n\n try {\n const { existsSync } = await import('node:fs');\n const { join } = await import('node:path');\n\n const projectRoot = server.config.root;\n const indexPath = join(projectRoot, 'index.html');\n\n // If index.html exists, use it as-is\n if (existsSync(indexPath)) {\n return html;\n }\n\n // Otherwise, provide default SMRT UI\n return await loadDefaultHTML();\n } catch (error) {\n console.error('[smrt] Error checking for index.html:', error);\n return html;\n }\n },\n },\n\n async closeBundle() {\n // Write manifest to disk during library builds\n // This allows published packages to include their manifest\n if (!manifest || !config?.build?.lib || generationSnapshot) {\n return;\n }\n\n try {\n const { writeFileSync, mkdirSync } = await import('node:fs');\n const { resolve, dirname } = await import('node:path');\n\n // Determine output directory.\n // `rollupOptions.output` may be a single object or an array; mirror the\n // prior runtime behavior where reading `.dir` off an array yields\n // undefined and falls through to `build.outDir`.\n const rollupOutput = config.build?.rollupOptions?.output;\n const rollupOutputDir = Array.isArray(rollupOutput)\n ? undefined\n : rollupOutput?.dir;\n const outDir = rollupOutputDir || config.build?.outDir || 'dist';\n const manifestPath = resolve(projectRoot, outDir, 'manifest.json');\n const knowledgePath = resolve(\n projectRoot,\n outDir,\n 'smrt-knowledge.json',\n );\n\n // Ensure directory exists\n mkdirSync(dirname(manifestPath), { recursive: true });\n\n // Write manifest file\n writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), 'utf-8');\n await writeDomainKnowledgeArtifact(\n manifest,\n projectRoot,\n knowledgePath,\n manifestPath,\n true,\n );\n\n const objectCount = Object.keys(manifest.objects).length;\n console.log(\n `[smrt] Wrote manifest with ${objectCount} objects to ${manifestPath}`,\n );\n } catch (error) {\n console.error('[smrt] Error writing manifest file:', error);\n }\n },\n };\n\n async function scanAndGenerateManifest(\n rootDir: string,\n ): Promise<SmartObjectManifest> {\n if (generationSnapshot) {\n const verified = loadVerifiedSmrtGenerationSnapshot<SmartObjectManifest>(\n generationSnapshot,\n rootDir,\n 'project',\n );\n console.log(\n `[smrt] Reusing verified generation snapshot (${generationSnapshot.provenance})`,\n );\n if (generateTypes && server) {\n await generateTypeDeclarationFile(\n verified,\n rootDir,\n typeDeclarationsPath,\n );\n }\n return verified;\n }\n\n // NOTE: We do NOT use the framework's static manifest here\n // The static manifest JSON that core emits at build time\n // contains framework objects (like 'pleb') which should not be included\n // when scanning user code in consuming applications.\n //\n // smrtPlugin is designed to scan USER code dynamically, not load\n // framework objects. For consuming apps that need framework objects,\n // they should use smrtConsumer plugin instead.\n\n // Always use OXC-based scanner (consolidated in Issue #951)\n try {\n return await scanWithOxc(rootDir);\n } catch (error) {\n if (\n error instanceof Error &&\n error.message.includes('Cannot find package')\n ) {\n console.error(\n '[smrt] @happyvertical/smrt-scanner is required but not installed.',\n );\n console.error(\n '[smrt] Install it: pnpm add @happyvertical/smrt-scanner',\n );\n }\n console.error('[smrt] Error scanning files:', error);\n // Re-throw to fail the build - don't silently continue with empty manifest\n throw error;\n }\n }\n\n /**\n * Scan files using OXC-based scanner (experimental fast path)\n * Uses Rust-based oxc-parser for 2-3x faster parsing\n */\n async function scanWithOxc(rootDir: string): Promise<SmartObjectManifest> {\n const startTime = performance.now();\n\n try {\n // Import the OXC scanner package\n const { OxcScanner, ManifestAdapter } = await importScanner();\n\n console.log(`[smrt] Using experimental OXC scanner for faster builds`);\n\n // Create scanner with options. Always exclude .svelte files as OXC barfs on <style> tags\n const safeExclude = [...(exclude || []), '**/*.svelte'];\n const scanner = new OxcScanner({\n cwd: rootDir,\n include,\n exclude: safeExclude,\n followSymbolicLinks,\n });\n\n // Scan and resolve inheritance\n const { results, resolved } = await scanner.scanAndResolve();\n\n // Check for errors\n if (results.errors.length > 0) {\n console.error(\n `\\n[smrt] ❌ Build failed: ${results.errors.length} error(s) during scanning:\\n`,\n );\n for (const error of results.errors) {\n console.error(\n ` ${error.filePath}:${error.line || '?'}: ${error.message}\\n`,\n );\n }\n throw new Error(\n '[smrt] Build aborted due to scan errors. See above for details.',\n );\n }\n\n // Read package.json for metadata BEFORE creating manifest (Issue #713)\n // This ensures qualified names are generated correctly for namespace isolation\n // packageJson is also needed for agent manifest generation (component discovery)\n let packageName: string | undefined;\n let packageVersion: string | undefined;\n let packageJson: PackageJsonShape | undefined;\n try {\n const { readFileSync } = await import('node:fs');\n const { join } = await import('node:path');\n const pkgPath = join(rootDir, 'package.json');\n const pkgContent = readFileSync(pkgPath, 'utf-8');\n packageJson = JSON.parse(pkgContent) as PackageJsonShape;\n packageName = packageJson.name || undefined;\n packageVersion = packageJson.version || undefined;\n } catch {\n // package.json not found or invalid - continue without packageName\n console.warn(\n '[smrt] Warning: package.json not found. Qualified names will not be generated.',\n );\n }\n\n // Convert to manifest format with packageName for qualified names (Issue #713)\n const adapter = new ManifestAdapter();\n const newManifest = adapter.toManifest(resolved, {\n packageName,\n packageVersion,\n typeAliases: results.typeAliases,\n });\n\n // Add moduleType identifier\n newManifest.moduleType = 'smrt';\n\n // Keep this as a normal module import: dynamic source imports with a\n // `.js` specifier do not reliably resolve through tsx during publish-time\n // workspace builds, even though the compiled dist path exists.\n const smrtDependencies = discoverSmrtPackages({ baseDir: rootDir });\n if (smrtDependencies.length > 0) {\n newManifest.smrtDependencies = smrtDependencies;\n console.log(\n `[smrt] Found ${smrtDependencies.length} SMRT dependencies: ${smrtDependencies.join(', ')}`,\n );\n }\n\n // Run all manifest generation passes (same as TypeScript scanner path)\n const { ManifestGenerator } = await importBuildAwareModule<\n typeof import('../scanner/index.js')\n >({\n source: '../scanner/index.ts',\n dist: '../scanner.js',\n });\n const manifestGen = new ManifestGenerator();\n // THE pass sequence — shared with generateManifest() and\n // ManifestBuilder so the three producers cannot drift (#2360).\n manifestGen.applyGenerationPasses(newManifest, {\n packageName,\n packageJson,\n });\n\n const elapsed = performance.now() - startTime;\n\n // Log results\n const objectCount = Object.keys(newManifest.objects).length;\n if (objectCount > 0) {\n const names = Object.keys(newManifest.objects).join(', ');\n console.log(`[smrt] Found ${objectCount} SMRT objects: ${names}`);\n } else {\n console.log('[smrt] No SMRT objects found');\n }\n console.log(`[smrt] OXC scan completed in ${elapsed.toFixed(2)}ms`);\n\n // Generate TypeScript declarations if enabled\n if (generateTypes && server) {\n await generateTypeDeclarationFile(\n newManifest,\n rootDir,\n typeDeclarationsPath,\n );\n }\n\n return newManifest;\n } catch (error) {\n console.error('[smrt] Error in OXC scanner:', error);\n throw error;\n }\n }\n\n async function shouldRescan(file: string): Promise<boolean> {\n // Only rescan in server mode\n if (pluginMode === 'client') {\n return false;\n }\n\n try {\n // Conditionally import minimatch\n const { minimatch } = await import('minimatch');\n\n const isIncluded = include.some((pattern) => minimatch(file, pattern));\n const isExcluded = exclude.some((pattern) => minimatch(file, pattern));\n\n return isIncluded && !isExcluded;\n } catch (error) {\n console.warn('[smrt] Error checking file patterns:', error);\n return false;\n }\n }\n}\n\n/**\n * Generate virtual routes module\n */\nasync function generateRoutesModule(\n manifest: SmartObjectManifest,\n): Promise<string> {\n try {\n const { ManifestGenerator } = await importBuildAwareModule<\n typeof import('../scanner/index.js')\n >({\n source: '../scanner/index.ts',\n dist: '../scanner.js',\n });\n const generator = new ManifestGenerator();\n const routes = generator.generateRestEndpoints(manifest);\n\n return `\n// Auto-generated REST routes from SMRT objects\n// This file is generated automatically - do not edit\n\n/**\n * Setup routes on an Express-like app\n *\n * NOTE: This virtual module function is for documentation only.\n * For actual route registration, use:\n * - import { startRestServer } from '@happyvertical/smrt-core'\n * - Or APIGenerator from '@happyvertical/smrt-core/generators'\n *\n * @param app - Express-like app instance\n * @param options - Route configuration options\n * @param options.basePath - Base path for all routes (default: '/api/v1')\n */\nexport function setupRoutes(app, options = {}) {\n const basePath = options.basePath || '/api/v1';\n\n console.warn('[smrt] setupRoutes is a documentation function only.');\n console.warn('[smrt] Use startRestServer() or APIGenerator for actual route registration.');\n console.warn('[smrt] Available endpoints:');\n${routes\n .split('\\\\n')\n .map((line) => ` console.warn(\\` \\${basePath}${line.trim()}\\`);`)\n .join('\\\\n')}\n}\n\nexport { setupRoutes as default };\n`;\n } catch (error) {\n console.warn('[smrt] Error generating routes module:', error);\n return 'export function setupRoutes(app, options = {}) { console.warn(\"Routes generation failed\"); }';\n }\n}\n\n/**\n * Generate the virtual web-collection definition module\n * (`@happyvertical/smrt-virt-web`, #1761).\n *\n * Emits typed per-collection metadata — REST collection name, endpoint path,\n * id field, exposed CRUD actions, and persisted field definitions — for every\n * API-exposed model in the manifest. This is the codegen contract consumed by\n * `@happyvertical/smrt-web` to construct client collections over the generated\n * REST surface. Deliberately data-only: no fetch code is emitted here, so the\n * runtime wrapper owns all HTTP/error semantics in one place. Selection and the\n * per-collection shape live in {@link selectWebCollectionEntries} /\n * {@link buildWebCollectionDefinition} so this value emission, the matching d.ts\n * type emission, and the #1764 shape digest cannot drift.\n */\nfunction generateWebModule(\n manifest: SmartObjectManifest,\n options: { kebabRoutes?: boolean } = {},\n): string {\n const definitions: Record<string, unknown> = {};\n\n // Emit one definition per MATERIALIZABLE collection (list-exposed), built via\n // the SHARED buildWebCollectionDefinition — the single source of truth the\n // shape digest (#1764) also hashes, so the emitted shape and the hashed shape\n // can never drift (a drift would let the hash under-cover a change → stale\n // caches). See buildWebCollectionDefinition's docblock.\n for (const entry of selectWebCollectionEntries(manifest)) {\n definitions[entry.collection] = {\n ...buildWebCollectionDefinition(entry, manifest),\n // WebMCP/MCP tool descriptors (#1812) — layered ON TOP of the shared shape\n // so the #1764 shape digest (computeWebManifestHash, which calls\n // buildWebCollectionDefinition directly) keeps hashing only the row shape.\n toolDescriptors: buildWebToolDescriptors(entry, options),\n };\n }\n\n // The web-collection SHAPE digest (#1764): a deterministic, replica-stable\n // hash of the exact `definitions` shape emitted below. Persistence keys its\n // durable namespace on it (a contract-changing deploy drops old caches) and\n // the generated read ETag folds it in (a shape-only deploy busts validators).\n // Built via the shared selectors so it can never disagree with what ships.\n const manifestHash = computeWebManifestHash(manifest);\n const webMcpToolDefinitions = buildWebMcpToolDefinitions(manifest, options);\n\n return `\n// Auto-generated web collection definitions from SMRT objects (#1761)\n// This file is generated automatically - do not edit\n\nexport const collectionDefinitions = ${JSON.stringify(definitions, null, 2)};\n\n// Canonical browser-tool definitions. This export is independent of list\n// materialization, so get-only and custom-action-only API routes are included.\nexport const webMcpToolDefinitions = ${JSON.stringify(webMcpToolDefinitions, null, 2)};\n\n// Build-time inject of the web-collection shape digest (#1764) — see\n// computeWebManifestHash. A change here means old persisted client rows may\n// mis-hydrate, so persistence namespaces and read ETags key on it.\nexport const manifestHash = ${JSON.stringify(manifestHash)};\n\nexport function getCollectionDefinition(name) {\n const definition = collectionDefinitions[name];\n if (!definition) {\n throw new Error(\n \\`[smrt] Unknown web collection definition: \\${name}. Known: \\${Object.keys(collectionDefinitions).join(', ')}\\`,\n );\n }\n return definition;\n}\n\nexport { collectionDefinitions as default };\n`;\n}\n\n/**\n * Generate virtual MCP module\n */\nasync function generateMCPModule(\n manifest: SmartObjectManifest,\n): Promise<string> {\n try {\n const { ManifestGenerator } = await importBuildAwareModule<\n typeof import('../scanner/index.js')\n >({\n source: '../scanner/index.ts',\n dist: '../scanner.js',\n });\n const generator = new ManifestGenerator();\n const tools = generator.generateMCPTools(manifest);\n\n return `\n// Auto-generated MCP tools from SMRT objects\n// This file is generated automatically - do not edit\n\nimport { SmrtMCPServer } from '@happyvertical/smrt-core/runtime';\n\nexport const tools = ${tools};\n\nexport function createMCPServer(options = {}) {\n const server = new SmrtMCPServer({\n name: options.name || 'smrt-auto-generated',\n version: options.version || '1.0.0',\n ...options\n });\n\n // Add all generated tools to the server\n for (const tool of tools) {\n server.addTool(tool, async (params) => {\n // Tool execution will be handled by the application\n throw new Error(\\`Tool '\\${tool.name}' handler must be provided by application\\`);\n });\n }\n\n return server;\n}\n\nexport { createMCPServer as default };\n`;\n } catch (error) {\n console.warn('[smrt] Error generating MCP module:', error);\n return `\nimport { SmrtMCPServer } from '@happyvertical/smrt-core/runtime';\nexport const tools = [];\nexport function createMCPServer(options = {}) {\n console.warn(\"MCP generation failed\");\n return new SmrtMCPServer({\n name: options.name || 'smrt-client',\n version: options.version || '1.0.0',\n ...options\n });\n}\n`;\n }\n}\n\n/**\n * Generate client-mode types without server dependencies\n */\nfunction generateClientModeTypes(manifest: SmartObjectManifest): string {\n const typeDefinitions: string[] = [];\n\n // Generate interfaces for each object in the manifest\n for (const [objectName, objectMeta] of Object.entries(manifest.objects)) {\n const fields = objectMeta.fields || {};\n const propertyLines: string[] = [];\n\n for (const [fieldName, fieldDef] of Object.entries(fields)) {\n let type = 'any';\n\n // Map SMRT field types to TypeScript types\n switch (fieldDef.type) {\n case 'text':\n type = 'string';\n break;\n case 'decimal':\n case 'integer':\n type = 'number';\n break;\n case 'boolean':\n type = 'boolean';\n break;\n case 'datetime':\n type = 'string';\n break;\n case 'json':\n type = 'any';\n break;\n case 'foreignKey':\n type = 'string';\n break;\n default:\n type = 'any';\n }\n\n const optional = !fieldDef.required ? '?' : '';\n propertyLines.push(` ${fieldName}${optional}: ${type};`);\n }\n\n // Add common SmrtObject properties\n propertyLines.unshift(\n ' id?: string;',\n ' created_at?: string;',\n ' updated_at?: string;',\n );\n\n const interfaceDef = `export interface ${objectName}Data {\\n${propertyLines.join('\\n')}\\n}`;\n typeDefinitions.push(interfaceDef);\n }\n\n return typeDefinitions.join('\\n\\n');\n}\n\n/**\n * Generate virtual types module\n */\nasync function generateTypesModule(\n manifest: SmartObjectManifest,\n mode: 'server' | 'client' = 'server',\n): Promise<string> {\n let interfaces = '';\n\n try {\n // Only use scanner in server mode to avoid Node.js dependencies in browser builds\n if (mode !== 'client') {\n const { ManifestGenerator } = await importBuildAwareModule<\n typeof import('../scanner/index.js')\n >({\n source: '../scanner/index.ts',\n dist: '../scanner.js',\n });\n const generator = new ManifestGenerator();\n interfaces = generator.generateTypeDefinitions(manifest);\n } else {\n // In client mode, generate basic interfaces directly from manifest\n interfaces = generateClientModeTypes(manifest);\n }\n\n return `\n// Auto-generated TypeScript types from SMRT objects\n// This file is generated automatically - do not edit\n\n${interfaces}\n\nexport interface Request {\n params: Record<string, string>;\n query: Record<string, any>;\n json(): Promise<any>;\n}\n\nexport interface Response {\n json(data: any, init?: { status?: number }): Response;\n status(code: number): Response;\n}\n`;\n } catch (error) {\n console.warn('[smrt] Error generating types module:', error);\n return `\n// Auto-generated TypeScript types from SMRT objects (fallback)\n// This file is generated automatically - do not edit\n\nexport interface Request {\n params: Record<string, string>;\n query: Record<string, any>;\n json(): Promise<any>;\n}\n\nexport interface Response {\n json(data: any, init?: { status?: number }): Response;\n status(code: number): Response;\n}\n`;\n }\n}\n\n/**\n * Generate virtual manifest module\n */\nfunction generateManifestModule(manifest: SmartObjectManifest): string {\n return `\n// Auto-generated manifest from SMRT objects\n// This file is generated automatically - do not edit\n\nexport const manifest = ${JSON.stringify(manifest, null, 2)};\n\nexport { manifest as default };\n`;\n}\n\n/**\n * Generate TypeScript declaration file for virtual modules\n * This eliminates the need for manual type maintenance\n */\nexport async function generateTypeDeclarationFile(\n manifest: SmartObjectManifest,\n projectRoot: string,\n typeDeclarationsPath: string,\n): Promise<void> {\n try {\n // Conditionally import path and fs modules\n const [{ join }, { existsSync, mkdirSync, writeFileSync }] =\n await Promise.all([import('node:path'), import('node:fs')]);\n\n const declarationsDir = join(projectRoot, typeDeclarationsPath);\n const declarationsFile = join(declarationsDir, 'virtual-modules.d.ts');\n\n // Create directory if it doesn't exist\n if (!existsSync(declarationsDir)) {\n mkdirSync(declarationsDir, { recursive: true });\n }\n\n // Generate interface definitions for each discovered SMRT object\n const objectInterfaces = Object.entries(manifest.objects)\n .map(([_name, obj]) => {\n const interfaceName = `${obj.className}Data`;\n const fields = Object.entries(obj.fields)\n .map(([fieldName, field]) => {\n const optional = field.required === false ? '?' : '';\n const type = mapTypeScriptType(field.type);\n return ` ${fieldName}${optional}: ${type};`;\n })\n .join('\\n');\n\n // Timestamps are snake_case on the wire (#1797): the server returns\n // `created_at`/`updated_at` exactly as SmrtObject.toJSON() emits them,\n // matching the prebuild + client-mode type paths.\n return ` export interface ${interfaceName} {\n id?: string;\n${fields}\n created_at?: string;\n updated_at?: string;\n }`;\n })\n .join('\\n\\n');\n\n // Generate API client interface for each object\n // Always use plural collection names (standard REST convention).\n // Filter custom methods through resolveApiActionSet so the declared\n // type surface matches what generateClientModule actually emits at\n // runtime — otherwise consumers see methods in autocomplete that are\n // undefined at runtime.\n const apiClientInterface = selectApiClientEntries(manifest)\n .map(\n ({\n obj,\n clientKey,\n dataInterfaceName,\n crudMethods,\n customMethods: exposedMethods,\n }) => {\n const { methods = {} } = obj;\n const interfaceName = dataInterfaceName;\n const exposedActionNames = new Set(\n exposedMethods.map((method) => method.name),\n );\n const customMethods = Object.entries(methods).filter(\n ([name, method]) =>\n !GENERATED_CLIENT_CRUD_METHODS.has(name) &&\n method.isPublic &&\n exposedActionNames.has(name),\n );\n\n // Generate custom method signatures\n const customMethodSignatures = customMethods\n .map(([methodName]) => {\n const exposedMethod = exposedMethods.find(\n ({ name }) => name === methodName,\n );\n if (!exposedMethod) return '';\n const signature = renderApiClientCustomMethodParameters(\n exposedMethod,\n mapTypeScriptType,\n );\n return ` ${methodName}(${signature}): Promise<any>;`;\n })\n .join('\\n');\n\n const overriddenBaseMethods = customMethods\n .map(([methodName]) => methodName)\n .filter((methodName) =>\n GENERATED_CLIENT_BASE_METHODS.has(methodName),\n );\n const crudOperationsType = renderApiClientCrudType(\n interfaceName,\n crudMethods,\n overriddenBaseMethods,\n );\n\n if (customMethods.length > 0) {\n const intersection = crudOperationsType\n ? `${crudOperationsType} & `\n : '';\n return ` ${JSON.stringify(clientKey)}: ${intersection}{\\n${customMethodSignatures}\\n };`;\n }\n\n return ` ${JSON.stringify(clientKey)}: ${crudOperationsType ?? 'Record<string, never>'};`;\n },\n )\n .join('\\n');\n\n // Typed web collection definitions (#1761): one entry per REST collection,\n // with the row type threaded through the phantom `_row` carrier so\n // downstream factories (`@happyvertical/smrt-web`) can infer it. Selection\n // shares selectWebCollectionEntries with the runtime module so the declared\n // types and the emitted values cannot drift.\n const webCollectionInterface = selectWebCollectionEntries(manifest)\n .map(\n ({ collection, obj }) =>\n ` ${JSON.stringify(collection)}: SmrtWebCollectionDefinition<import('@happyvertical/smrt-virt-types').${obj.className}Data>;`,\n )\n .join('\\n');\n\n // Generate MCP tool interfaces based on discovered methods\n const _mcpTools = Object.entries(manifest.objects).flatMap(([_name, obj]) =>\n Object.entries(obj.methods).map(([methodName, method]) => ({\n name: `${methodName}_${obj.collection}`,\n description: `${method.name} operation on ${obj.collection}`,\n inputSchema: {\n type: 'object',\n properties: Object.fromEntries(\n method.parameters.map((param) => [\n param.name,\n { type: mapJsonSchemaType(param.type) },\n ]),\n ),\n required: method.parameters\n .filter((p) => p.optional !== true)\n .map((p) => p.name),\n },\n })),\n );\n\n const typeDeclarations = `/**\n * Auto-generated TypeScript declarations for SMRT virtual modules\n * Generated from discovered @smrt() decorated classes\n * \n * DO NOT EDIT THIS FILE MANUALLY\n * This file is automatically regenerated when SMRT objects change\n */\n\n// Manifest module - Contains discovered SMRT objects metadata\ndeclare module '@happyvertical/smrt-virt-manifest' {\n export interface SmrtObjectField {\n type: string;\n required?: boolean;\n default?: any;\n }\n\n export interface SmrtObjectMethod {\n name: string;\n parameters: Array<{\n name: string;\n type: string;\n required?: boolean;\n }>;\n returnType: string;\n isAsync: boolean;\n }\n\n export interface SmrtObjectDefinition {\n className: string;\n collection: string;\n fields: Record<string, SmrtObjectField>;\n methods: Record<string, SmrtObjectMethod>;\n decoratorConfig: any;\n }\n\n export interface SmrtManifest {\n version: string;\n timestamp: number;\n objects: Record<string, SmrtObjectDefinition>;\n }\n\n export const manifest: SmrtManifest;\n}\n\n// Routes module - Auto-generated REST route setup\ndeclare module '@happyvertical/smrt-virt-routes' {\n export interface RouteApp {\n get(path: string, handler: (req: any, res: any) => void): void;\n post(path: string, handler: (req: any, res: any) => void): void;\n put(path: string, handler: (req: any, res: any) => void): void;\n delete(path: string, handler: (req: any, res: any) => void): void;\n }\n\n export interface RouteOptions {\n basePath?: string;\n [key: string]: any;\n }\n\n export function setupRoutes(app: RouteApp, options?: RouteOptions): void;\n export default setupRoutes;\n}\n\n// Client module - Auto-generated API client\n// Wire-shape policy (#1797): the server returns BARE JSON — a bare array for\n// list/search, a bare object for get/create/update — with snake_case field\n// names (created_at, updated_at). These declarations match that shape (no\n// envelope, no camelCase). Fetchers reject on non-2xx with a SmrtClientError\n// (#1796). Shared CRUD wire types stay aligned with the prebuild declaration\n// path; Vite-only custom action declarations are layered onto them below.\ndeclare module '@happyvertical/smrt-virt-client' {\n /** Structured custom-action failure nested under an API error body's \\`error\\` key. */\n export interface SmrtClientFailure {\n ok: false;\n code: string;\n message: string;\n status?: number;\n }\n\n /** Shape of a JSON error body carried by a rejected request (SmrtClientError.body). */\n export interface ApiError {\n error?: string | SmrtClientFailure;\n message?: string;\n }\n\n /** Typed error thrown by every fetcher on a non-2xx response (#1796). */\n export interface SmrtClientError extends Error {\n name: 'SmrtClientError';\n status: number;\n /** Machine-readable code from a structured custom-action failure, when present. */\n code?: string;\n body?: ApiError | string;\n }\n\n export interface CrudOperations<T = any> {\n list(params?: Record<string, any>): Promise<T[]>;\n get(id: string): Promise<T>;\n create(data: Partial<T>): Promise<T>;\n update(id: string, data: Partial<T>): Promise<T>;\n delete(id: string): Promise<boolean>;\n search(query: string): Promise<T[]>;\n }\n\n export interface ApiClient {\n${apiClientInterface}\n }\n\n export function createClient(basePath?: string): ApiClient;\n export default createClient;\n}\n\n// MCP module - Auto-generated Model Context Protocol tools\ndeclare module '@happyvertical/smrt-virt-mcp' {\n import type { SmrtMCPServer, MCPServerOptions } from '@happyvertical/smrt-core/runtime';\n\n export interface McpTool {\n name: string;\n description: string;\n inputSchema: {\n type: string;\n properties: Record<string, any>;\n required?: string[];\n };\n }\n\n export const tools: McpTool[];\n export function createMCPServer(options?: MCPServerOptions): SmrtMCPServer;\n export default createMCPServer;\n}\n\n// Types module - Auto-generated TypeScript interfaces\ndeclare module '@happyvertical/smrt-virt-types' {\n export const types: string;\n\n // Auto-generated interfaces for discovered SMRT objects\n${objectInterfaces}\n\n export default types;\n}\n\n// Web module - Typed collection definitions for the browser client data\n// runtime (@happyvertical/smrt-web, #1761)\ndeclare module '@happyvertical/smrt-virt-web' {\n export type SmrtWebFieldType =\n | 'text'\n | 'decimal'\n | 'boolean'\n | 'integer'\n | 'datetime'\n | 'json'\n | 'foreignKey'\n | 'crossPackageRef';\n\n /** Static \\`@field({ ui })\\` hints (#2046) — the field-policy rail seed. */\n export interface SmrtWebFieldUIHints {\n basic?: boolean;\n group?: string;\n order?: number;\n locked?: boolean;\n }\n\n export interface SmrtWebFieldDefinition {\n type: SmrtWebFieldType;\n required?: boolean;\n nullable?: boolean;\n default?: unknown;\n /** Developer-authored \\`@field({ description })\\` (#2046) — end-user help seed. */\n description?: string;\n /** Static \\`@field({ ui })\\` hints (#2046). */\n ui?: SmrtWebFieldUIHints;\n }\n\n export type SmrtWebRelationshipKind =\n | 'foreignKey'\n | 'crossPackageRef'\n | 'oneToMany'\n | 'manyToMany';\n\n /**\n * A manifest-derived edge to a sibling REST collection. Mutating this\n * collection invalidates the caches of the collections named by these edges\n * (#1761 relationship-derived invalidation).\n */\n export interface SmrtWebRelationship {\n field: string;\n kind: SmrtWebRelationshipKind;\n relatedCollection: string;\n }\n\n export interface WebToolRouteDescriptor {\n method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';\n scope: 'item' | 'collection';\n path: string[];\n parameterAliases?: Record<string, string>;\n optionsBag?: boolean;\n }\n\n /** A WebMCP/MCP tool descriptor for one collection action (#1812). */\n export interface WebToolDescriptor {\n action: string;\n name: string;\n description: string;\n inputSchema: Record<string, unknown>;\n readOnly: boolean;\n effect: 'read' | 'write' | 'destructive';\n idempotent: boolean;\n openWorld: boolean;\n route?: WebToolRouteDescriptor;\n }\n\n /** Canonical data-only definition for one generated browser tool. */\n export interface WebMcpToolDefinition extends WebToolDescriptor {\n collection: string;\n objectRef: string;\n className: string;\n endpoint: string;\n idField: string;\n idType: 'uuid' | 'text';\n route: WebToolRouteDescriptor;\n relationships: SmrtWebRelationship[];\n }\n\n export interface SmrtWebCollectionDefinition<TData = Record<string, unknown>> {\n name: string;\n /** Canonical qualified model identity (\\`@package/name:ClassName\\`) for policy APIs. */\n objectRef: string;\n className: string;\n endpoint: string;\n idField: string;\n actions: string[];\n fields: Record<string, SmrtWebFieldDefinition>;\n /** Manifest-derived relationship edges to sibling REST collections. */\n relationships: SmrtWebRelationship[];\n /** WebMCP/MCP tool descriptors for the exposed actions (#1812). */\n toolDescriptors: WebToolDescriptor[];\n /** Phantom row-type carrier for inference — never present at runtime. */\n _row?: TData;\n }\n\n export interface SmrtWebCollectionDefinitions {\n${webCollectionInterface}\n }\n\n export const collectionDefinitions: SmrtWebCollectionDefinitions;\n /** Every API-backed WebMCP tool, independent of list materialization. */\n export const webMcpToolDefinitions: readonly WebMcpToolDefinition[];\n export function getCollectionDefinition<\n K extends keyof SmrtWebCollectionDefinitions,\n >(name: K): SmrtWebCollectionDefinitions[K];\n /**\n * Build-time web-collection shape digest (#1764). A deterministic,\n * replica-stable hash of the emitted collection definitions; a change means\n * old persisted client rows may mis-hydrate. Consumers fold it into the\n * durable persistence namespace and the version-awareness updateAvailable\n * contract signal. One of the co-managed emission sites that must not drift —\n * the runtime value, this ambient d.ts, the physical @smrt/web d.ts, and the\n * hand-written @happyvertical/smrt-web type mirror.\n */\n export const manifestHash: string;\n export default collectionDefinitions;\n}\n\n// CLI module - Auto-generated command-line interface\ndeclare module '@happyvertical/smrt-virt-cli' {\n export interface CLIConfig {\n name?: string;\n version?: string;\n description?: string;\n prompt?: boolean;\n colors?: boolean;\n }\n\n export interface CLIContext {\n db?: any;\n ai?: any;\n user?: {\n id: string;\n roles?: string[];\n };\n }\n\n export interface CLICommandMap {\n [objectName: string]: {\n collection: string;\n commands: string[];\n };\n }\n\n export const cliCommands: CLICommandMap;\n\n export function setupCLI(config?: CLIConfig, context?: CLIContext): {\n run: (argv: string[]) => Promise<void>;\n generator: any;\n };\n\n export function getCLIHandler(config?: CLIConfig, context?: CLIContext): (argv: string[]) => Promise<void>;\n\n export default setupCLI;\n}`;\n\n // Write the declarations file\n writeFileSync(declarationsFile, typeDeclarations);\n console.log(\n `[smrt] Generated TypeScript declarations: ${declarationsFile}`,\n );\n } catch (error) {\n console.error('[smrt] Error generating TypeScript declarations:', error);\n }\n}\n\n/**\n * Map SMRT field types to TypeScript types\n */\nfunction mapTypeScriptType(smrtType: string): string {\n const typeMap: Record<string, string> = {\n text: 'string',\n integer: 'number',\n decimal: 'number',\n datetime: 'string',\n json: 'any',\n foreignKey: 'string',\n crossPackageRef: 'string',\n oneToMany: 'any[]',\n manyToMany: 'any[]',\n meta: 'any',\n string: 'string',\n number: 'number',\n boolean: 'boolean',\n array: 'any[]',\n object: 'Record<string, any>',\n date: 'string',\n Date: 'string',\n };\n return typeMap[smrtType] || 'any';\n}\n\n/**\n * Map TypeScript types to JSON Schema types for MCP tools\n */\nfunction mapJsonSchemaType(tsType: string): string {\n const typeMap: Record<string, string> = {\n string: 'string',\n number: 'number',\n boolean: 'boolean',\n array: 'array',\n object: 'object',\n any: 'string',\n };\n return typeMap[tsType] || 'string';\n}\n\n/**\n * Get default HTML template with inlined JavaScript (inlined for distribution)\n */\nfunction getDefaultHTML(): string {\n const uiScript = getDefaultUIModule();\n\n // Build HTML without template literals to avoid escaping issues\n return (\n '<!DOCTYPE html>\\n' +\n '<html lang=\"en\">\\n' +\n '<head>\\n' +\n ' <meta charset=\"UTF-8\">\\n' +\n ' <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\\n' +\n ' <title>SMRT Development UI</title>\\n' +\n ' <style>\\n' +\n ' * { margin: 0; padding: 0; box-sizing: border-box; }\\n' +\n ' body {\\n' +\n ' font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;\\n' +\n ' background: #f5f5f5;\\n' +\n ' color: #333;\\n' +\n ' }\\n' +\n ' .container { max-width: 1200px; margin: 0 auto; padding: 20px; }\\n' +\n ' header {\\n' +\n ' background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\\n' +\n ' color: white;\\n' +\n ' padding: 40px 0;\\n' +\n ' margin-bottom: 40px;\\n' +\n ' box-shadow: 0 4px 6px rgba(0,0,0,0.1);\\n' +\n ' }\\n' +\n ' header h1 { font-size: 2.5em; font-weight: 700; margin-bottom: 10px; }\\n' +\n ' .subtitle { font-size: 1.1em; opacity: 0.9; }\\n' +\n ' .stats {\\n' +\n ' display: grid;\\n' +\n ' grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\\n' +\n ' gap: 20px;\\n' +\n ' margin-bottom: 40px;\\n' +\n ' }\\n' +\n ' .stat-card {\\n' +\n ' background: white;\\n' +\n ' padding: 20px;\\n' +\n ' border-radius: 8px;\\n' +\n ' box-shadow: 0 2px 4px rgba(0,0,0,0.1);\\n' +\n ' text-align: center;\\n' +\n ' }\\n' +\n ' .stat-value { font-size: 2.5em; font-weight: 700; color: #667eea; margin-bottom: 5px; }\\n' +\n ' .stat-label { font-size: 0.9em; color: #666; text-transform: uppercase; letter-spacing: 1px; }\\n' +\n ' .collections { display: grid; gap: 30px; }\\n' +\n ' .collection-card {\\n' +\n ' background: white;\\n' +\n ' border-radius: 8px;\\n' +\n ' box-shadow: 0 2px 4px rgba(0,0,0,0.1);\\n' +\n ' overflow: hidden;\\n' +\n ' }\\n' +\n ' .collection-header {\\n' +\n ' background: #667eea;\\n' +\n ' color: white;\\n' +\n ' padding: 15px 20px;\\n' +\n ' display: flex;\\n' +\n ' justify-content: space-between;\\n' +\n ' align-items: center;\\n' +\n ' }\\n' +\n ' .collection-title { font-size: 1.3em; font-weight: 600; }\\n' +\n ' .collection-count {\\n' +\n ' background: rgba(255,255,255,0.2);\\n' +\n ' padding: 5px 15px;\\n' +\n ' border-radius: 20px;\\n' +\n ' font-size: 0.9em;\\n' +\n ' }\\n' +\n ' .collection-body { padding: 20px; }\\n' +\n ' .field-list {\\n' +\n ' display: grid;\\n' +\n ' grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));\\n' +\n ' gap: 15px;\\n' +\n ' margin-bottom: 20px;\\n' +\n ' }\\n' +\n ' .field {\\n' +\n ' padding: 10px;\\n' +\n ' background: #f8f9fa;\\n' +\n ' border-radius: 4px;\\n' +\n ' border-left: 3px solid #667eea;\\n' +\n ' }\\n' +\n ' .field-name { font-weight: 600; color: #333; margin-bottom: 3px; }\\n' +\n ' .field-type { font-size: 0.85em; color: #666; }\\n' +\n ' .actions { display: flex; gap: 10px; flex-wrap: wrap; }\\n' +\n ' .btn {\\n' +\n ' padding: 10px 20px;\\n' +\n ' border: none;\\n' +\n ' border-radius: 4px;\\n' +\n ' font-size: 0.9em;\\n' +\n ' cursor: pointer;\\n' +\n ' transition: all 0.2s;\\n' +\n ' text-decoration: none;\\n' +\n ' display: inline-block;\\n' +\n ' }\\n' +\n ' .btn-primary { background: #667eea; color: white; }\\n' +\n ' .btn-primary:hover { background: #5568d3; transform: translateY(-1px); }\\n' +\n ' .btn-secondary { background: #e0e0e0; color: #333; }\\n' +\n ' .btn-secondary:hover { background: #d0d0d0; }\\n' +\n ' .loading { text-align: center; padding: 40px; color: #666; }\\n' +\n ' .error {\\n' +\n ' background: #fee;\\n' +\n ' border: 1px solid #fcc;\\n' +\n ' color: #c33;\\n' +\n ' padding: 15px;\\n' +\n ' border-radius: 4px;\\n' +\n ' margin-bottom: 20px;\\n' +\n ' }\\n' +\n ' .empty-state { text-align: center; padding: 60px 20px; color: #999; }\\n' +\n ' .empty-state svg { width: 100px; height: 100px; margin-bottom: 20px; opacity: 0.3; }\\n' +\n ' </style>\\n' +\n '</head>\\n' +\n '<body>\\n' +\n ' <div id=\"app\">\\n' +\n ' <div class=\"loading\">Loading SMRT UI...</div>\\n' +\n ' </div>\\n' +\n ' <script type=\"module\">\\n' +\n uiScript +\n '\\n </script>\\n' +\n '</body>\\n' +\n '</html>'\n );\n}\n\n/**\n * Get default UI module from template file\n * Loads the JavaScript template\n */\nfunction getDefaultUIModule(): string {\n try {\n // Get current file directory\n const __dirname = dirname(fileURLToPath(import.meta.url));\n\n // Load template file (works in both src and dist)\n const templatePath = join(__dirname, 'templates/default-ui.js');\n\n return readFileSync(templatePath, 'utf-8').trim();\n } catch (error) {\n console.error('[smrt] Error loading UI template:', error);\n // Fallback to minimal UI\n return `\nasync function createUI() {\n const app = document.getElementById('app');\n if (!app) return;\n app.innerHTML = '<div class=\"container\" style=\"padding:40px;text-align:center;\"><h1>🎯 SMRT Development UI</h1><p>Template file not found. UI code could not be loaded.</p></div>';\n}\ncreateUI();\n`;\n }\n}\n\n/**\n * Load default HTML template for projects without index.html\n */\nasync function loadDefaultHTML(): Promise<string> {\n return getDefaultHTML();\n}\n\n/**\n * Load default UI module\n */\nasync function loadDefaultUI(): Promise<string> {\n return getDefaultUIModule();\n}\n\n/**\n * Generate virtual CLI module\n */\nasync function generateCLIModule(\n manifest: SmartObjectManifest,\n): Promise<string> {\n try {\n // Import CLI types\n const commands: string[] = [];\n const objectImports: string[] = [];\n\n // Generate CLI setup code for each object\n for (const [className, objectDef] of Object.entries(manifest.objects)) {\n const config = objectDef.decoratorConfig;\n const cliConfig = config?.cli;\n\n // Skip if CLI is disabled\n if (cliConfig === false) continue;\n\n // Determine which operations to include\n const excluded =\n (typeof cliConfig === 'object' ? cliConfig.exclude : []) || [];\n const included = typeof cliConfig === 'object' ? cliConfig.include : null;\n\n const shouldInclude = (command: string) => {\n if (included && !included.includes(command)) return false;\n if (excluded.includes(command)) return false;\n return true;\n };\n\n // Collection name (metadata) and the command segment. Commands are keyed\n // by the simple class name (e.g. `document:list`) to match what\n // `CLIGenerator` resolves and the dev `smrt` CLI convention — NOT the\n // plural collection name, which the runtime resolver does not accept.\n const collectionName = objectDef.collection;\n const commandName = (objectDef.className || className).toLowerCase();\n\n // Generate import statement for the object class\n objectImports.push(\n `// Import ${className} and ${className}Collection for CLI operations`,\n );\n\n // Generate command registration\n const availableCommands: string[] = [];\n\n // Standard CRUD commands\n if (shouldInclude('list'))\n availableCommands.push(`'${commandName}:list'`);\n if (shouldInclude('get')) availableCommands.push(`'${commandName}:get'`);\n if (shouldInclude('create'))\n availableCommands.push(`'${commandName}:create'`);\n if (shouldInclude('update'))\n availableCommands.push(`'${commandName}:update'`);\n if (shouldInclude('delete'))\n availableCommands.push(`'${commandName}:delete'`);\n\n // Custom action methods\n for (const [methodName, _method] of Object.entries(objectDef.methods)) {\n // Skip private methods and standard CRUD\n if (\n methodName.startsWith('_') ||\n ['list', 'get', 'create', 'update', 'delete', 'save'].includes(\n methodName,\n )\n )\n continue;\n\n if (shouldInclude(methodName)) {\n availableCommands.push(`'${commandName}:${methodName}'`);\n }\n }\n\n if (availableCommands.length > 0) {\n commands.push(`\n // ${className} commands\n ${className}: {\n collection: '${collectionName}',\n commands: [${availableCommands.join(', ')}]\n }`);\n }\n }\n\n return `\n// Auto-generated CLI module from SMRT objects\n// This file is generated automatically - do not edit\n\nimport { CLIGenerator } from '@happyvertical/smrt-core/generators/cli';\n\n/**\n * @typedef {import('@happyvertical/smrt-core/generators/cli').CLIConfig} CLIConfig\n * @typedef {import('@happyvertical/smrt-core/generators/cli').CLIContext} CLIContext\n */\n\n${objectImports.join('\\n')}\n\n/**\n * Available CLI commands by object\n */\nexport const cliCommands = {${commands.join(',\\n')}\n};\n\n/**\n * Setup CLI with auto-generated commands\n *\n * @param {CLIConfig} [config={}] - CLI configuration\n * @param {CLIContext} [context={}] - CLI context\n * @returns {{run: function(string[]): Promise<void>, generator: *}}\n *\n * @example\n * import { setupCLI } from '@happyvertical/smrt-virt-cli';\n *\n * const cli = setupCLI({\n * name: 'my-app',\n * version: '1.0.0'\n * });\n *\n * cli.run(process.argv);\n */\nexport function setupCLI(config = {}, context = {}) {\n const generator = new CLIGenerator(config, context);\n return {\n run: async (argv) => {\n const handler = generator.generateHandler();\n await handler(argv.slice(2)); // Remove 'node' and script name\n },\n generator\n };\n}\n\n/**\n * Get CLI handler directly\n *\n * @param {CLIConfig} [config={}] - CLI configuration\n * @param {CLIContext} [context={}] - CLI context\n * @returns {function(string[]): Promise<void>}\n */\nexport function getCLIHandler(config = {}, context = {}) {\n const generator = new CLIGenerator(config, context);\n return generator.generateHandler();\n}\n\nexport default setupCLI;\n`;\n } catch (error) {\n console.warn('[smrt] Error generating CLI module:', error);\n return `\n// Error generating CLI module\nexport const cliCommands = {};\nexport function setupCLI() {\n console.warn(\"CLI generation failed\");\n return { run: async () => {} };\n}\nexport function getCLIHandler() {\n return async () => console.warn(\"CLI generation failed\");\n}\nexport default setupCLI;\n`;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAmKA,IAAM,kBAAkB;CACtB,mCAAmC;CACnC,mCAAmC;CACnC,gCAAgC;CAChC,kCAAkC;CAClC,qCAAqC;CACrC,+BAA+B;CAC/B,gCAAgC;CAChC,gCAAgC;AAClC;AAEA,eAAe,gBAAgB;CAC7B,OAAO,sBAAqC;EAC1C,aAAa;EACb,WAAW;EACX,aAAa;EACb,SAAS;CACX,CAAC;AACH;;;;;;;AAQA,IAAM,mBAAmB;AAEzB,SAAgB,uBAAuB,IAAqB;CAC1D,MAAM,UAAU,GAAG,MAAM,GAAG,CAAC,CAAC;CAC9B,OAAO,iBAAiB,KAAK,OAAO,KAAK,CAAC,QAAQ,SAAS,cAAc;AAC3E;;;;;;;;;;;;;;;;;;;AAoBA,SAAgB,6BACd,UACQ;CAER,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA,qDATsB,KAAK,UAAU,KAAK,UAAU,QAAQ,CASP,EAAgB;EACrE;CACF,CAAC,CAAC,KAAK,IAAI;AACb;AAEA,SAAgB,WAAW,UAA6B,CAAC,GAAW;CAClE,MAAM,EACJ,aAAa,uBACb,oBACA,UAAU,CAAC,eAAe,aAAa,GACvC,UAAU;EAAC;EAAgB;EAAgB;CAAoB,GAC/D,sBAAsB,OACtB,MAAM,MACN,QAAQ,MACR,gBAAgB,MAChB,cAAc,CAAC,cAAc,aAAa,GAC1C,gBAAgB,MAChB,uBAAuB,aACvB,OAAO,QACP,YAAY;EACV,SAAS;EACT,WAAW;EACX,YAAY;EACZ,YAAY;EACZ,gBAAgB;CAClB,GACA,WACA,0BAA0B,SACxB;;;;;;;CAQJ,SAAS,8BAA8B,GAA8B;EACnE,IAAI,CAAC,yBAAyB;EAC9B,MAAM,aAAa,8BAA8B,CAAC;EAClD,IAAI,WAAW,WAAW,GAAG;EAC7B,KAAK,MAAM,EAAE,WAAW,iBAAiB,YACvC,KAAK,MAAM,UAAU,aACnB,QAAQ,KACN,UAAU,UAAU,GAAG,OAAO,6HAGd,OAAO,sCACJ,OAAO,oPAI5B;CAGN;CAEA,IAAI;CACJ,IAAI,WAAuC;CAC3C,IAAI,aAAkC;CACtC,IAAI,cAAsB,QAAQ,IAAI;CACtC,IAAI,SAAgC;CACpC,IAAI,sBAAgC,CAAC;CACrC,IAAI,iCAAiC;CACrC,IAAI,qBAAiD;CACrD,IAAI,8BAA8B;CAElC,eAAe,kCACb,SACA,iBACe;EACf,MAAM,wBAAwB,SAAS,iBAAiB;GACtD,SAAS,UAAU;GACnB,WAAW,UAAU,aAAa;GAClC,YAAY,UAAU,cAAc;GACpC,YAAY,UAAU,cAAc;GACpC,gBAAgB,UAAU,kBAAkB;GAC5C,aAAa,UAAU,eAAe;GACtC,cAAc,UAAU;GACxB,aAAa,UAAU;GACvB,WAAW,MAAM,uBAAuB,SAAS,eAAe;EAClE,CAAC;CACH;;;;;;CAOA,eAAe,mBACb,GACA,SACe;EACf,IAAI;GACF,MAAM,EAAE,eAAe,cAAc,MAAM,OAAO;GAClD,MAAM,EAAE,YAAY,MAAM,OAAO;GAEjC,MAAM,UAAU,QAAQ,SAAS,OAAO;GACxC,UAAU,SAAS,EAAE,WAAW,KAAK,CAAC;GAEtC,MAAM,eAAe,QAAQ,SAAS,eAAe;GACrD,cAAc,cAAc,KAAK,UAAU,GAAG,MAAM,CAAC,GAAG,OAAO;GAC/D,MAAM,6BACJ,GACA,SACA,QAAQ,SAAS,qBAAqB,GACtC,YACF;GAEA,MAAM,cAAc,OAAO,KAAK,EAAE,OAAO,CAAC,CAAC;GAC3C,QAAQ,IACN,oCAAoC,YAAY,gCAClD;EACF,SAAS,OAAO;GACd,QAAQ,MAAM,wCAAwC,KAAK;EAC7D;CACF;;;;;;;;;;CAWA,eAAe,6BACb,GACA,SACA,YACA,cACA,gBAAgB,OACD;EACf,MAAM,oBAAoB,MAAM,uBAAuB,SAAS,CAAC;EACjE,IAAI,kBAAkB,YAAY,OAChC;EAGF,MAAM,EAAE,WAAW,kBAAkB,MAAM,OAAO;EAClD,MAAM,EAAE,YAAY,MAAM,OAAO;EACjC,UAAU,QAAQ,UAAU,GAAG,EAAE,WAAW,KAAK,CAAC;EAClD,MAAM,WAAW,6BAA6B;GAC5C,UAAU;GACV;GACA;GACA,QAAQ;EACV,CAAC;EACD,MAAM,UAAU,gBACZ;GAAE,GAAG;GAAU,aAAa;EAA2B,IACvD,6BAA6B,YAAY,QAAQ;EACrD,cAAc,YAAY,KAAK,UAAU,SAAS,MAAM,CAAC,GAAG,OAAO;CACrE;CAEA,eAAe,uBACb,SACA,GACgC;EAChC,IAAI,cAAc,OAAO,OAAO,EAAE,SAAS,MAAM;EACjD,MAAM,cAAc,EAAE,eAAe,gBAAgB,OAAO;EAC5D,MAAM,WAAkC;GACtC,SAAS;GACT,KAAK;IACH,SAAS;IACT,UAAU;IACV,cAAc;IACd,aAAa;IACb,gBAAgB;GAClB;GACA,aAAa;GACb,gBAAgB;EAClB;EAEA,IAAI,gBAAuC,CAAC;EAC5C,IAAI,mBAA0C,CAAC;EAC/C,IAAI;GACF,MAAM,cAAc,QAAQ,IAAI;GAChC,QAAQ,MAAM,OAAO;GACrB,IAAI;IACF,MAAM,EAAE,eAAe,MAAM,OAAO;IACpC,MAAM,SAAS,MAAM,WAAW,EAAE,OAAO,MAAM,CAAC;IAChD,gBAAiB,OAAO,aAAa,CAAC;IACtC,mBACE,cAAe,OAAO,WAAW,YAAY,EAAE,aAAa,CAAC,IAAK,CAAC;GAEvE,UAAU;IACR,QAAQ,MAAM,WAAW;GAC3B;EACF,QAAQ;GACN,gBAAgB,CAAC;GACjB,mBAAmB,CAAC;EACtB;EAEA,OAAO,qBACL,UACA,eACA,kBACA,aAAa,CAAC,CAChB;CACF;CAEA,SAAS,qBACP,GAAG,SACoB;EACvB,MAAM,SAAgC,CAAC;EACvC,KAAK,MAAM,QAAQ,SAAS;GAC1B,IAAI,CAAC,MAAM;GAEX,MAAM,MADS,QAAQ,OAAO,OAAO,KAAK,GAC9B,IACR;IAAE,GAAI,OAAO,OAAO,CAAC;IAAI,GAAI,KAAK,OAAO,CAAC;GAAG,IAC7C,KAAA;GACJ,OAAO,OAAO,QAAQ,IAAI;GAC1B,IAAI,KAAK,OAAO,MAAM;EACxB;EACA,OAAO;CACT;CAEA,SAAS,6BACP,YACA,eACyB;EACzB,IAAI,CAAC,WAAW,UAAU,GAAG,OAAO;EAEpC,IAAI;GACF,MAAM,UAAU,KAAK,MACnB,aAAa,YAAY,MAAM,CACjC;GACA,IACE,sBAAsB,OAAO,MAAM,sBAAsB,aAAa,GAEtE,OAAO;IACL,GAAG;IACH,aAAa,QAAQ,eAAe,cAAc;GACpD;EAEJ,QAAQ,CAER;EAEA,OAAO;CACT;CAEA,SAAS,sBACP,UACQ;EACR,MAAM,EAAE,aAAa,cAAc,GAAG,SAAS,YAAY,CAAC;EAC5D,OAAO,KAAK,UAAU,SAAS,IAAI,CAAC;CACtC;CAEA,SAAS,SAAS,OAAyB;EACzC,IAAI,MAAM,QAAQ,KAAK,GAAG,OAAO,MAAM,IAAI,QAAQ;EACnD,IAAI,SAAS,OAAO,UAAU,UAC5B,OAAO,OAAO,YACZ,OAAO,QAAQ,KAAgC,CAAC,CAC7C,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,CACtC,KAAK,CAAC,KAAK,WAAW,CAAC,KAAK,SAAS,KAAK,CAAC,CAAC,CACjD;EAEF,OAAO;CACT;CAEA,SAAS,gBAAgB,SAAqC;EAC5D,IAAI;GACF,MAAM,MAAM,KAAK,MACf,aAAa,KAAK,SAAS,cAAc,GAAG,MAAM,CACpD;GACA,OAAO,OAAO,IAAI,SAAS,WAAW,IAAI,OAAO,KAAA;EACnD,QAAQ;GACN;EACF;CACF;CAEA,SAAS,4BACP,GACA,SACM;EACN,IAAI,QAAQ,SAAS,QACnB;EAGF,IAAI,QAAQ,OAAO,KACjB;EAGF,MAAM,wBAAwB,EAAE,oBAAoB,CAAC,EAAA,CAAG,QACrD,eAAe,eAAe,0BACjC;EACA,IAAI,qBAAqB,WAAW,GAClC;EAMF,IAH0B,oBAAoB,MAC3C,SAAS,SAAS,eAEjB,GACF;EAGF,MAAM,oBACJ,qBAAqB,UAAU,IAC3B,qBAAqB,KAAK,IAAI,IAC9B,GAAG,qBAAqB,MAAM,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,KAAK,qBAAqB,SAAS,EAAE;EAE1F,MAAM,IAAI,MACR,4DAA4D,QAAQ,sCAAsC,kBAAkB,mOAC9H;CACF;CAEA,SAAS,2BACP,GACA,SACM;EACN,IAAI,CAAC,QAAQ,OAAO,KAClB;EAGF,IAAI,OAAO,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,GAC1C;EAGF,IAAI,OAAO,MAAM,WAAW,OAC1B;EAGF,MAAM,IAAI,MACR,2DAA2D,QAAQ,gNACrE;CACF;CAEA,OAAO;EACL,MAAM;EAIN,SAAS;EAMT,QAAQ;GACN,OAAO;GACP,MAAM,QAAQ,YAAY;IACxB,IAAI,CAAC,UAAU,SAAS;IAExB,cACE,yBACA,QAAQ,QAAQ,IAAI,GAAG,WAAW,QAAQ,GAAG;IAC/C,qBAAqB,MAAM,wBAAwB,WAAW;IAC9D,MAAM,kCACJ,aACA,kBACF;IACA,8BAA8B;GAChC;EACF;EAGA,KAAK,EACH,SAAS;GACP,GAAI,0BAA0B,KAAA,IAC1B,CAAC,IACD,EAAE,aAAa,sBAAsB;GACzC,GAAI,uBAAuB,KAAA,IAAY,CAAC,IAAI,EAAE,mBAAmB;GACjE;GACA;GACA;GACA;EACF,EACF;EAEA,MAAM,eAAe,gBAAgB;GACnC,iCAAiC;GAEjC,SAAS;GACT,uBAAuB,eAAe,WAAW,CAAC,EAAA,CAAG,KAClD,WAAW,QAAQ,QAAQ,EAC9B;GAGA,cAAc,yBAAyB,eAAe;GAGtD,IAAI,SAAS,QAAQ;IACnB,MAAM,aAAa,eAAe,OAAO;IAQzC,aAP0B,eAAe,QAAQ,MAAM,MACrD,EAAE,MAAM,SAAS,YAAY,CAG7B,KACC,CAAC,cAAc,eAAe,OAAO,WAAW,WAEtB,WAAW;GAC1C,OACE,aAAa;GAGf,QAAQ,IAAI,qBAAqB,WAAW,MAAM;GAGlD,WACE,sBAAuB,MAAM,wBAAwB,WAAW;GAClE,qBAAqB;GAGrB,IAAI,YAAY,CAAC,oBACf,MAAM,mBAAmB,UAAU,WAAW;GAEhD,IAAI,UAAU;IACZ,2BAA2B,UAAU,gBAAgB;IACrD,4BAA4B,UAAU,gBAAgB;IACtD,IAAI,yBACF,6BAA6B,QAAQ;GAEzC;GAGA,IAAI,UAAU,WAAW,YAAY,CAAC,6BACpC,MAAM,kCAAkC,aAAa,QAAQ;GAE/D,8BAA8B;GAM9B,iCAAiC;EACnC;EAEA,MAAM,aAAa;GACjB,IAAI,gCAAgC;IAClC,iCAAiC;IAIjC,IAAI,iBAAiB,UAAU,UAC7B,MAAM,4BACJ,UACA,aACA,oBACF;IAEF;GACF;GAGA,WAAW,MAAM,wBAAwB,WAAW;GAGpD,IAAI,YAAY,CAAC,oBACf,MAAM,mBAAmB,UAAU,WAAW;GAEhD,IAAI,UAAU;IACZ,2BAA2B,UAAU,YAAY;IACjD,4BAA4B,UAAU,YAAY;IAClD,IAAI,yBACF,6BAA6B,QAAQ;GAEzC;EACF;EAEA,UAAU,OAAO,IAAI;GAUnB,IAAI,CAAC,QAAQ,OAAO,OAAO,CAAC,UAC1B,OAAO;GAET,IAAI,CAAC,uBAAuB,EAAE,GAC5B,OAAO;GAET,OAAO;IACL,MAAM,6BAA6B,QAAQ;IAC3C,KAAK;GACP;EACF;EAEA,4BAA4B,EAAE,MAAM;GAMlC,IAAI,QAAQ,OAAO,OAAO,uBAAuB,EAAE,GACjD,OAAO;GAET,OAAO;EACT;EAEA,gBAAgB,WAAW;GACzB,SAAS;GAIT,UAAU,YAAY,IAAI,OAAO,KAAK,KAAK,SAAS;IAElD,IAAI,UAAU,SACZ,OAAO,KAAK;IAGd,IAAI,IAAI,QAAQ,OAAO,IAAI,QAAQ,eACjC,IAAI;KACF,MAAM,EAAE,eAAe,MAAM,OAAO;KACpC,MAAM,EAAE,SAAS,MAAM,OAAO;KAE9B,MAAM,cAAc,UAAU,OAAO;KAIrC,IAAI,WAHc,KAAK,aAAa,YAGrB,CAAS,GACtB,OAAO,KAAK;KAId,QAAQ,IAAI,iDAAiD;KAC7D,IAAI,OAAO,eAAe;KAG1B,OAAO,MAAM,UAAU,mBAAmB,KAAK,IAAI;KAEnD,IAAI,UAAU,gBAAgB,WAAW;KACzC,IAAI,IAAI,IAAI;KACZ;IACF,SAAS,OAAO;KACd,QAAQ,MAAM,sCAAsC,KAAK;KACzD,OAAO,KAAK;IACd;IAEF,KAAK;GACP,CAAC;GAGD,IAAI,SAAS,OAAO,CAAC,oBAAoB;IAEvC,MAAM,UAAU,UAAU;IAK1B,QAAQ,GAAG,UAAU,OAAO,SAAS;KACnC,IAAI;MACF,IAAI,MAAM,aAAa,IAAI,GAAG;OAC5B,QAAQ,IAAI,sCAAsC,MAAM;OACxD,WAAW,MAAM,wBAAwB,WAAW;OAGpD,IAAI,UAAU;QACZ,MAAM,mBAAmB,UAAU,WAAW;QAC9C,8BAA8B,QAAQ;OACxC;OAGA,IAAI,UAAU,WAAW,YAAY,QACnC,MAAM,wBAAwB,aAAa,UAAU;QACnD,SAAS,UAAU;QACnB,WAAW,UAAU,aAAa;QAClC,YAAY,UAAU,cAAc;QACpC,YAAY,UAAU,cAAc;QACpC,gBAAgB,UAAU,kBAAkB;QAC5C,aAAa,UAAU,eAAe;QACtC,cAAc,UAAU;QACxB,aAAa,UAAU;QACvB,WAAW,MAAM,uBACf,aACA,QACF;OACF,CAAC;OAIH,OAAO,OAAO,eAAe,CAAC,CAAC,SAAS,OAAO;QAC7C,MAAM,SAAS,QAAQ,YAAY,cAAc,EAAE;QACnD,IAAI,QACF,QAAQ,aAAa,MAAM;OAE/B,CAAC;MACH;KACF,SAAS,OAAO;MACd,QAAQ,MACN,2CAA2C,KAAK,IAChD,KACF;KACF;IACF,CAAC;IAED,QAAQ,GAAG,OAAO,OAAO,SAAS;KAChC,IAAI;MACF,IAAI,MAAM,aAAa,IAAI,GAAG;OAC5B,QAAQ,IAAI,qCAAqC,MAAM;OACvD,WAAW,MAAM,wBAAwB,WAAW;OAGpD,IAAI,UAAU;QACZ,MAAM,mBAAmB,UAAU,WAAW;QAC9C,8BAA8B,QAAQ;OACxC;OAGA,IAAI,UAAU,WAAW,YAAY,QACnC,MAAM,wBAAwB,aAAa,UAAU;QACnD,SAAS,UAAU;QACnB,WAAW,UAAU,aAAa;QAClC,YAAY,UAAU,cAAc;QACpC,YAAY,UAAU,cAAc;QACpC,gBAAgB,UAAU,kBAAkB;QAC5C,aAAa,UAAU,eAAe;QACtC,cAAc,UAAU;QACxB,aAAa,UAAU;QACvB,WAAW,MAAM,uBACf,aACA,QACF;OACF,CAAC;MAEL;KACF,SAAS,OAAO;MACd,QAAQ,MACN,wCAAwC,KAAK,IAC7C,KACF;KACF;IACF,CAAC;IAED,QAAQ,GAAG,UAAU,OAAO,SAAS;KACnC,IAAI;MACF,IAAI,MAAM,aAAa,IAAI,GAAG;OAC5B,QAAQ,IAAI,yCAAyC,MAAM;OAC3D,WAAW,MAAM,wBAAwB,WAAW;OAGpD,IAAI,UAAU;QACZ,MAAM,mBAAmB,UAAU,WAAW;QAC9C,8BAA8B,QAAQ;OACxC;OAGA,IAAI,UAAU,WAAW,YAAY,QACnC,MAAM,wBAAwB,aAAa,UAAU;QACnD,SAAS,UAAU;QACnB,WAAW,UAAU,aAAa;QAClC,YAAY,UAAU,cAAc;QACpC,YAAY,UAAU,cAAc;QACpC,gBAAgB,UAAU,kBAAkB;QAC5C,aAAa,UAAU,eAAe;QACtC,cAAc,UAAU;QACxB,aAAa,UAAU;QACvB,WAAW,MAAM,uBACf,aACA,QACF;OACF,CAAC;MAEL;KACF,SAAS,OAAO;MACd,QAAQ,MACN,0CAA0C,KAAK,IAC/C,KACF;KACF;IACF,CAAC;GACH;EACF;EAEA,UAAU,IAAI;GAEZ,IAAI,MAAM,iBACR,OAAO,KAAK,gBAAgB;GAI9B,IAAI,OAAO,iBAAiB,QAC1B,OAAO;GAGT,OAAO;EACT;EAEA,MAAM,KAAK,IAAI;GAEb,MAAM,UAAU,GAAG,WAAW,IAAI,IAAI,GAAG,MAAM,CAAC,IAAI;GAEpD,IAAI,CAAC,UACH,WAAW,MAAM,wBAAwB,WAAW;GAGtD,QAAQ,SAAR;IACE,KAAK,eAEH,OAAO,MAAM,qBAAqB,QAAQ;IAE5C,KAAK,eAEH,OAAO,qBAAqB,UAAU,EACpC,aAAa,UAAU,eAAe,MACxC,CAAC;IAEH,KAAK,YAEH,OAAO,MAAM,kBAAkB,QAAQ;IAEzC,KAAK,cAEH,OAAO,MAAM,oBAAoB,UAAU,UAAU;IAEvD,KAAK,iBAEH,OAAO,uBAAuB,QAAQ;IAExC,KAAK,WAEH,OAAO,MAAM,cAAc;IAE7B,KAAK,mBAEH,OAAO,MAAM,gBAAgB;IAE/B,KAAK,YAEH,OAAO,MAAM,kBAAkB,QAAQ;IAEzC,KAAK,YAGH,OAAO,kBAAkB,UAAU,EACjC,aAAa,UAAU,eAAe,MACxC,CAAC;IAEH,SACE,OAAO;GACX;EACF;EAEA,oBAAoB;GAClB,OAAO;GACP,SAAS,OAAO,MAAM,SAAS;IAE7B,IAAI,CAAC,QAAQ,OAAO;IAEpB,IAAI;KACF,MAAM,EAAE,eAAe,MAAM,OAAO;KACpC,MAAM,EAAE,SAAS,MAAM,OAAO;KAE9B,MAAM,cAAc,OAAO,OAAO;KAIlC,IAAI,WAHc,KAAK,aAAa,YAGrB,CAAS,GACtB,OAAO;KAIT,OAAO,MAAM,gBAAgB;IAC/B,SAAS,OAAO;KACd,QAAQ,MAAM,yCAAyC,KAAK;KAC5D,OAAO;IACT;GACF;EACF;EAEA,MAAM,cAAc;GAGlB,IAAI,CAAC,YAAY,CAAC,QAAQ,OAAO,OAAO,oBACtC;GAGF,IAAI;IACF,MAAM,EAAE,eAAe,cAAc,MAAM,OAAO;IAClD,MAAM,EAAE,SAAS,YAAY,MAAM,OAAO;IAM1C,MAAM,eAAe,OAAO,OAAO,eAAe;IAIlD,MAAM,UAHkB,MAAM,QAAQ,YAAY,IAC9C,KAAA,IACA,cAAc,QACgB,OAAO,OAAO,UAAU;IAC1D,MAAM,eAAe,QAAQ,aAAa,QAAQ,eAAe;IACjE,MAAM,gBAAgB,QACpB,aACA,QACA,qBACF;IAGA,UAAU,QAAQ,YAAY,GAAG,EAAE,WAAW,KAAK,CAAC;IAGpD,cAAc,cAAc,KAAK,UAAU,UAAU,MAAM,CAAC,GAAG,OAAO;IACtE,MAAM,6BACJ,UACA,aACA,eACA,cACA,IACF;IAEA,MAAM,cAAc,OAAO,KAAK,SAAS,OAAO,CAAC,CAAC;IAClD,QAAQ,IACN,8BAA8B,YAAY,cAAc,cAC1D;GACF,SAAS,OAAO;IACd,QAAQ,MAAM,uCAAuC,KAAK;GAC5D;EACF;CACF;CAEA,eAAe,wBACb,SAC8B;EAC9B,IAAI,oBAAoB;GACtB,MAAM,WAAW,mCACf,oBACA,SACA,SACF;GACA,QAAQ,IACN,gDAAgD,mBAAmB,WAAW,EAChF;GACA,IAAI,iBAAiB,QACnB,MAAM,4BACJ,UACA,SACA,oBACF;GAEF,OAAO;EACT;EAYA,IAAI;GACF,OAAO,MAAM,YAAY,OAAO;EAClC,SAAS,OAAO;GACd,IACE,iBAAiB,SACjB,MAAM,QAAQ,SAAS,qBAAqB,GAC5C;IACA,QAAQ,MACN,mEACF;IACA,QAAQ,MACN,yDACF;GACF;GACA,QAAQ,MAAM,gCAAgC,KAAK;GAEnD,MAAM;EACR;CACF;;;;;CAMA,eAAe,YAAY,SAA+C;EACxE,MAAM,YAAY,YAAY,IAAI;EAElC,IAAI;GAEF,MAAM,EAAE,YAAY,oBAAoB,MAAM,cAAc;GAE5D,QAAQ,IAAI,yDAAyD;GAGrE,MAAM,cAAc,CAAC,GAAI,WAAW,CAAC,GAAI,aAAa;GAStD,MAAM,EAAE,SAAS,aAAa,MAAM,IARhB,WAAW;IAC7B,KAAK;IACL;IACA,SAAS;IACT;GACF,CAGoC,CAAA,CAAQ,eAAe;GAG3D,IAAI,QAAQ,OAAO,SAAS,GAAG;IAC7B,QAAQ,MACN,4BAA4B,QAAQ,OAAO,OAAO,6BACpD;IACA,KAAK,MAAM,SAAS,QAAQ,QAC1B,QAAQ,MACN,KAAK,MAAM,SAAS,GAAG,MAAM,QAAQ,IAAI,IAAI,MAAM,QAAQ,GAC7D;IAEF,MAAM,IAAI,MACR,iEACF;GACF;GAKA,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;IACF,MAAM,EAAE,iBAAiB,MAAM,OAAO;IACtC,MAAM,EAAE,SAAS,MAAM,OAAO;IAE9B,MAAM,aAAa,aADH,KAAK,SAAS,cACE,GAAS,OAAO;IAChD,cAAc,KAAK,MAAM,UAAU;IACnC,cAAc,YAAY,QAAQ,KAAA;IAClC,iBAAiB,YAAY,WAAW,KAAA;GAC1C,QAAQ;IAEN,QAAQ,KACN,gFACF;GACF;GAIA,MAAM,cAAc,IADA,gBACA,CAAA,CAAQ,WAAW,UAAU;IAC/C;IACA;IACA,aAAa,QAAQ;GACvB,CAAC;GAGD,YAAY,aAAa;GAKzB,MAAM,mBAAmB,qBAAqB,EAAE,SAAS,QAAQ,CAAC;GAClE,IAAI,iBAAiB,SAAS,GAAG;IAC/B,YAAY,mBAAmB;IAC/B,QAAQ,IACN,gBAAgB,iBAAiB,OAAO,sBAAsB,iBAAiB,KAAK,IAAI,GAC1F;GACF;GAGA,MAAM,EAAE,sBAAsB,MAAM,uBAElC;IACA,QAAQ;IACR,MAAM;GACR,CAAC;GAID,IAHwB,kBAGxB,CAAA,CAAY,sBAAsB,aAAa;IAC7C;IACA;GACF,CAAC;GAED,MAAM,UAAU,YAAY,IAAI,IAAI;GAGpC,MAAM,cAAc,OAAO,KAAK,YAAY,OAAO,CAAC,CAAC;GACrD,IAAI,cAAc,GAAG;IACnB,MAAM,QAAQ,OAAO,KAAK,YAAY,OAAO,CAAC,CAAC,KAAK,IAAI;IACxD,QAAQ,IAAI,gBAAgB,YAAY,iBAAiB,OAAO;GAClE,OACE,QAAQ,IAAI,8BAA8B;GAE5C,QAAQ,IAAI,gCAAgC,QAAQ,QAAQ,CAAC,EAAE,GAAG;GAGlE,IAAI,iBAAiB,QACnB,MAAM,4BACJ,aACA,SACA,oBACF;GAGF,OAAO;EACT,SAAS,OAAO;GACd,QAAQ,MAAM,gCAAgC,KAAK;GACnD,MAAM;EACR;CACF;CAEA,eAAe,aAAa,MAAgC;EAE1D,IAAI,eAAe,UACjB,OAAO;EAGT,IAAI;GAEF,MAAM,EAAE,cAAc,MAAM,OAAO;GAEnC,MAAM,aAAa,QAAQ,MAAM,YAAY,UAAU,MAAM,OAAO,CAAC;GACrE,MAAM,aAAa,QAAQ,MAAM,YAAY,UAAU,MAAM,OAAO,CAAC;GAErE,OAAO,cAAc,CAAC;EACxB,SAAS,OAAO;GACd,QAAQ,KAAK,wCAAwC,KAAK;GAC1D,OAAO;EACT;CACF;AACF;;;;AAKA,eAAe,qBACb,UACiB;CACjB,IAAI;EACF,MAAM,EAAE,sBAAsB,MAAM,uBAElC;GACA,QAAQ;GACR,MAAM;EACR,CAAC;EAID,OAAO;;;;;;;;;;;;;;;;;;;;;;EAFQ,IADO,kBACP,CAAA,CAAU,sBAAsB,QAwBjD,CAAA,CACC,MAAM,KAAK,CAAC,CACZ,KAAK,SAAS,kCAAkC,KAAK,KAAK,EAAE,KAAK,CAAC,CAClE,KAAK,KAAK,EAAE;;;;;CAKb,SAAS,OAAO;EACd,QAAQ,KAAK,0CAA0C,KAAK;EAC5D,OAAO;CACT;AACF;;;;;;;;;;;;;;;AAgBA,SAAS,kBACP,UACA,UAAqC,CAAC,GAC9B;CACR,MAAM,cAAuC,CAAC;CAO9C,KAAK,MAAM,SAAS,2BAA2B,QAAQ,GACrD,YAAY,MAAM,cAAc;EAC9B,GAAG,6BAA6B,OAAO,QAAQ;EAI/C,iBAAiB,wBAAwB,OAAO,OAAO;CACzD;CAQF,MAAM,eAAe,uBAAuB,QAAQ;CACpD,MAAM,wBAAwB,2BAA2B,UAAU,OAAO;CAE1E,OAAO;;;;uCAI8B,KAAK,UAAU,aAAa,MAAM,CAAC,EAAE;;;;uCAIrC,KAAK,UAAU,uBAAuB,MAAM,CAAC,EAAE;;;;;8BAKxD,KAAK,UAAU,YAAY,EAAE;;;;;;;;;;;;;;AAc3D;;;;AAKA,eAAe,kBACb,UACiB;CACjB,IAAI;EACF,MAAM,EAAE,sBAAsB,MAAM,uBAElC;GACA,QAAQ;GACR,MAAM;EACR,CAAC;EAID,OAAO;;;;;;uBAFO,IADQ,kBACR,CAAA,CAAU,iBAAiB,QAQtB,EAAM;;;;;;;;;;;;;;;;;;;;;;CAsB3B,SAAS,OAAO;EACd,QAAQ,KAAK,uCAAuC,KAAK;EACzD,OAAO;;;;;;;;;;;;CAYT;AACF;;;;AAKA,SAAS,wBAAwB,UAAuC;CACtE,MAAM,kBAA4B,CAAC;CAGnC,KAAK,MAAM,CAAC,YAAY,eAAe,OAAO,QAAQ,SAAS,OAAO,GAAG;EACvE,MAAM,SAAS,WAAW,UAAU,CAAC;EACrC,MAAM,gBAA0B,CAAC;EAEjC,KAAK,MAAM,CAAC,WAAW,aAAa,OAAO,QAAQ,MAAM,GAAG;GAC1D,IAAI,OAAO;GAGX,QAAQ,SAAS,MAAjB;IACE,KAAK;KACH,OAAO;KACP;IACF,KAAK;IACL,KAAK;KACH,OAAO;KACP;IACF,KAAK;KACH,OAAO;KACP;IACF,KAAK;KACH,OAAO;KACP;IACF,KAAK;KACH,OAAO;KACP;IACF,KAAK;KACH,OAAO;KACP;IACF,SACE,OAAO;GACX;GAEA,MAAM,WAAW,CAAC,SAAS,WAAW,MAAM;GAC5C,cAAc,KAAK,KAAK,YAAY,SAAS,IAAI,KAAK,EAAE;EAC1D;EAGA,cAAc,QACZ,kBACA,0BACA,wBACF;EAEA,MAAM,eAAe,oBAAoB,WAAW,UAAU,cAAc,KAAK,IAAI,EAAE;EACvF,gBAAgB,KAAK,YAAY;CACnC;CAEA,OAAO,gBAAgB,KAAK,MAAM;AACpC;;;;AAKA,eAAe,oBACb,UACA,OAA4B,UACX;CACjB,IAAI,aAAa;CAEjB,IAAI;EAEF,IAAI,SAAS,UAAU;GACrB,MAAM,EAAE,sBAAsB,MAAM,uBAElC;IACA,QAAQ;IACR,MAAM;GACR,CAAC;GAED,aAAa,IADS,kBACT,CAAA,CAAU,wBAAwB,QAAQ;EACzD,OAEE,aAAa,wBAAwB,QAAQ;EAG/C,OAAO;;;;EAIT,WAAW;;;;;;;;;;;;;CAaX,SAAS,OAAO;EACd,QAAQ,KAAK,yCAAyC,KAAK;EAC3D,OAAO;;;;;;;;;;;;;;;CAeT;AACF;;;;AAKA,SAAS,uBAAuB,UAAuC;CACrE,OAAO;;;;0BAIiB,KAAK,UAAU,UAAU,MAAM,CAAC,EAAE;;;;AAI5D;;;;;AAMA,eAAsB,4BACpB,UACA,aACA,sBACe;CACf,IAAI;EAEF,MAAM,CAAC,EAAE,QAAQ,EAAE,YAAY,WAAW,mBACxC,MAAM,QAAQ,IAAI,CAAC,OAAO,cAAc,OAAO,UAAU,CAAC;EAE5D,MAAM,kBAAkB,KAAK,aAAa,oBAAoB;EAC9D,MAAM,mBAAmB,KAAK,iBAAiB,sBAAsB;EAGrE,IAAI,CAAC,WAAW,eAAe,GAC7B,UAAU,iBAAiB,EAAE,WAAW,KAAK,CAAC;EAIhD,MAAM,mBAAmB,OAAO,QAAQ,SAAS,OAAO,CAAC,CACtD,KAAK,CAAC,OAAO,SAAS;GAarB,OAAO,sBAAsB,GAZJ,IAAI,UAAU,MAYI;;EAX5B,OAAO,QAAQ,IAAI,MAAM,CAAC,CACtC,KAAK,CAAC,WAAW,WAAW;IAG3B,OAAO,OAAO,YAFG,MAAM,aAAa,QAAQ,MAAM,GAEf,IADtB,kBAAkB,MAAM,IACE,EAAK;GAC9C,CAAC,CAAC,CACD,KAAK,IAOd,EAAO;;;;EAIH,CAAC,CAAC,CACD,KAAK,MAAM;EAQd,MAAM,qBAAqB,uBAAuB,QAAQ,CAAC,CACxD,KACE,EACC,KACA,WACA,mBACA,aACA,eAAe,qBACX;GACJ,MAAM,EAAE,UAAU,CAAC,MAAM;GACzB,MAAM,gBAAgB;GACtB,MAAM,qBAAqB,IAAI,IAC7B,eAAe,KAAK,WAAW,OAAO,IAAI,CAC5C;GACA,MAAM,gBAAgB,OAAO,QAAQ,OAAO,CAAC,CAAC,QAC3C,CAAC,MAAM,YACN,CAAC,8BAA8B,IAAI,IAAI,KACvC,OAAO,YACP,mBAAmB,IAAI,IAAI,CAC/B;GAGA,MAAM,yBAAyB,cAC5B,KAAK,CAAC,gBAAgB;IACrB,MAAM,gBAAgB,eAAe,MAClC,EAAE,WAAW,SAAS,UACzB;IACA,IAAI,CAAC,eAAe,OAAO;IAK3B,OAAO,SAAS,WAAW,GAJT,sCAChB,eACA,iBAE4B,EAAU;GAC1C,CAAC,CAAC,CACD,KAAK,IAAI;GAOZ,MAAM,qBAAqB,wBACzB,eACA,aAP4B,cAC3B,KAAK,CAAC,gBAAgB,UAAU,CAAC,CACjC,QAAQ,eACP,8BAA8B,IAAI,UAAU,CAK9C,CACF;GAEA,IAAI,cAAc,SAAS,GAAG;IAC5B,MAAM,eAAe,qBACjB,GAAG,mBAAmB,OACtB;IACJ,OAAO,OAAO,KAAK,UAAU,SAAS,EAAE,IAAI,aAAa,KAAK,uBAAuB;GACvF;GAEA,OAAO,OAAO,KAAK,UAAU,SAAS,EAAE,IAAI,sBAAsB,wBAAwB;EAC5F,CACF,CAAC,CACA,KAAK,IAAI;EAOZ,MAAM,yBAAyB,2BAA2B,QAAQ,CAAC,CAChE,KACE,EAAE,YAAY,UACb,OAAO,KAAK,UAAU,UAAU,EAAE,yEAAyE,IAAI,UAAU,OAC7H,CAAC,CACA,KAAK,IAAI;EAGM,OAAO,QAAQ,SAAS,OAAO,CAAC,CAAC,SAAS,CAAC,OAAO,SAClE,OAAO,QAAQ,IAAI,OAAO,CAAC,CAAC,KAAK,CAAC,YAAY,aAAa;GACzD,MAAM,GAAG,WAAW,GAAG,IAAI;GAC3B,aAAa,GAAG,OAAO,KAAK,gBAAgB,IAAI;GAChD,aAAa;IACX,MAAM;IACN,YAAY,OAAO,YACjB,OAAO,WAAW,KAAK,UAAU,CAC/B,MAAM,MACN,EAAE,MAAM,kBAAkB,MAAM,IAAI,EAAE,CACxC,CAAC,CACH;IACA,UAAU,OAAO,WACd,QAAQ,MAAM,EAAE,aAAa,IAAI,CAAC,CAClC,KAAK,MAAM,EAAE,IAAI;GACtB;EACF,EAAE,CACJ;EA8SA,cAAc,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EArMlC,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+BnB,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyGjB,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6D2B;EAChD,QAAQ,IACN,6CAA6C,kBAC/C;CACF,SAAS,OAAO;EACd,QAAQ,MAAM,oDAAoD,KAAK;CACzE;AACF;;;;AAKA,SAAS,kBAAkB,UAA0B;CAoBnD,OAAO;EAlBL,MAAM;EACN,SAAS;EACT,SAAS;EACT,UAAU;EACV,MAAM;EACN,YAAY;EACZ,iBAAiB;EACjB,WAAW;EACX,YAAY;EACZ,MAAM;EACN,QAAQ;EACR,QAAQ;EACR,SAAS;EACT,OAAO;EACP,QAAQ;EACR,MAAM;EACN,MAAM;CAED,EAAQ,aAAa;AAC9B;;;;AAKA,SAAS,kBAAkB,QAAwB;CASjD,OAAO;EAPL,QAAQ;EACR,QAAQ;EACR,SAAS;EACT,OAAO;EACP,QAAQ;EACR,KAAK;CAEA,EAAQ,WAAW;AAC5B;;;;AAKA,SAAS,iBAAyB;CAIhC,OACE,q9GAJe,mBAgHf,IACA;AAIJ;;;;;AAMA,SAAS,qBAA6B;CACpC,IAAI;EAOF,OAAO,aAFc,KAHH,QAAQ,cAAc,OAAO,KAAK,GAAG,CAG7B,GAAW,yBAEjB,GAAc,OAAO,CAAC,CAAC,KAAK;CAClD,SAAS,OAAO;EACd,QAAQ,MAAM,qCAAqC,KAAK;EAExD,OAAO;;;;;;;;CAQT;AACF;;;;AAKA,eAAe,kBAAmC;CAChD,OAAO,eAAe;AACxB;;;;AAKA,eAAe,gBAAiC;CAC9C,OAAO,mBAAmB;AAC5B;;;;AAKA,eAAe,kBACb,UACiB;CACjB,IAAI;EAEF,MAAM,WAAqB,CAAC;EAC5B,MAAM,gBAA0B,CAAC;EAGjC,KAAK,MAAM,CAAC,WAAW,cAAc,OAAO,QAAQ,SAAS,OAAO,GAAG;GAErE,MAAM,YADS,UAAU,iBACC;GAG1B,IAAI,cAAc,OAAO;GAGzB,MAAM,YACH,OAAO,cAAc,WAAW,UAAU,UAAU,CAAC,MAAM,CAAC;GAC/D,MAAM,WAAW,OAAO,cAAc,WAAW,UAAU,UAAU;GAErE,MAAM,iBAAiB,YAAoB;IACzC,IAAI,YAAY,CAAC,SAAS,SAAS,OAAO,GAAG,OAAO;IACpD,IAAI,SAAS,SAAS,OAAO,GAAG,OAAO;IACvC,OAAO;GACT;GAMA,MAAM,iBAAiB,UAAU;GACjC,MAAM,eAAe,UAAU,aAAa,UAAA,CAAW,YAAY;GAGnE,cAAc,KACZ,aAAa,UAAU,OAAO,UAAU,8BAC1C;GAGA,MAAM,oBAA8B,CAAC;GAGrC,IAAI,cAAc,MAAM,GACtB,kBAAkB,KAAK,IAAI,YAAY,OAAO;GAChD,IAAI,cAAc,KAAK,GAAG,kBAAkB,KAAK,IAAI,YAAY,MAAM;GACvE,IAAI,cAAc,QAAQ,GACxB,kBAAkB,KAAK,IAAI,YAAY,SAAS;GAClD,IAAI,cAAc,QAAQ,GACxB,kBAAkB,KAAK,IAAI,YAAY,SAAS;GAClD,IAAI,cAAc,QAAQ,GACxB,kBAAkB,KAAK,IAAI,YAAY,SAAS;GAGlD,KAAK,MAAM,CAAC,YAAY,YAAY,OAAO,QAAQ,UAAU,OAAO,GAAG;IAErE,IACE,WAAW,WAAW,GAAG,KACzB;KAAC;KAAQ;KAAO;KAAU;KAAU;KAAU;IAAM,CAAC,CAAC,SACpD,UACF,GAEA;IAEF,IAAI,cAAc,UAAU,GAC1B,kBAAkB,KAAK,IAAI,YAAY,GAAG,WAAW,EAAE;GAE3D;GAEA,IAAI,kBAAkB,SAAS,GAC7B,SAAS,KAAK;OACf,UAAU;IACb,UAAU;mBACK,eAAe;iBACjB,kBAAkB,KAAK,IAAI,EAAE;IAC1C;EAEA;EAEA,OAAO;;;;;;;;;;;EAWT,cAAc,KAAK,IAAI,EAAE;;;;;8BAKG,SAAS,KAAK,KAAK,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6CjD,SAAS,OAAO;EACd,QAAQ,KAAK,uCAAuC,KAAK;EACzD,OAAO;;;;;;;;;;;;CAYT;AACF"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ToolDescriptor } from '../generators/tool-schema.js';
|
|
1
|
+
import { ToolDescriptor, ToolIdType, ToolRouteDescriptor } from '../generators/tool-schema.js';
|
|
2
2
|
import { FieldDefinition, FieldUIHints, SmartObjectDefinition, SmartObjectManifest } from '../scanner/types.js';
|
|
3
3
|
/**
|
|
4
4
|
* The field types that actually reach an emitted web collection definition:
|
|
@@ -54,6 +54,38 @@ export interface WebCollectionEntry {
|
|
|
54
54
|
/** Sorted set of exposed CRUD + custom actions. */
|
|
55
55
|
actions: string[];
|
|
56
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* One canonical WebMCP tool candidate. `obj` owns the REST collection and row
|
|
59
|
+
* contract; `actionHost` declares the action. They differ for custom methods
|
|
60
|
+
* declared on a `SmrtCollection` subclass.
|
|
61
|
+
*/
|
|
62
|
+
export interface WebMcpToolEntry {
|
|
63
|
+
collection: string;
|
|
64
|
+
obj: SmartObjectDefinition;
|
|
65
|
+
actionHost: SmartObjectDefinition;
|
|
66
|
+
action: string;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Transport-complete, data-only definition for one generated browser tool.
|
|
70
|
+
* Unlike {@link WebCollectionEntry}, this shape does not imply that a list
|
|
71
|
+
* route or cache-backed browser collection exists.
|
|
72
|
+
*/
|
|
73
|
+
export interface WebMcpToolDefinition extends ToolDescriptor {
|
|
74
|
+
/** Stable definition identity is `(collection, action)`. */
|
|
75
|
+
collection: string;
|
|
76
|
+
/** Canonical qualified identity of the row model owning the collection. */
|
|
77
|
+
objectRef: string;
|
|
78
|
+
/** Row-model class used by the shared MCP tool vocabulary. */
|
|
79
|
+
className: string;
|
|
80
|
+
/** Path below the generated API base path. */
|
|
81
|
+
endpoint: string;
|
|
82
|
+
idField: string;
|
|
83
|
+
idType: ToolIdType;
|
|
84
|
+
/** Always present so a fetch-only registrar needs no action heuristics. */
|
|
85
|
+
route: ToolRouteDescriptor;
|
|
86
|
+
/** Cache-invalidation edges for materialized sibling collections. */
|
|
87
|
+
relationships: WebRelationship[];
|
|
88
|
+
}
|
|
57
89
|
/**
|
|
58
90
|
* Resolve a manifest object deterministically across aggregated packages.
|
|
59
91
|
*
|
|
@@ -84,6 +116,14 @@ export declare function resolveCollectionItemObject(manifest: SmartObjectManifes
|
|
|
84
116
|
* required to MATERIALIZE a client collection — that is what persists).
|
|
85
117
|
*/
|
|
86
118
|
export declare function selectWebCollectionEntries(manifest: SmartObjectManifest): WebCollectionEntry[];
|
|
119
|
+
/**
|
|
120
|
+
* Select every generated WebMCP action independently of collection
|
|
121
|
+
* materialization. Object actions establish the owning row model first;
|
|
122
|
+
* collection-class actions then supplement missing `(collection, action)`
|
|
123
|
+
* identities. Therefore an object action wins an exact collision, while all
|
|
124
|
+
* ordering is independent of manifest insertion order.
|
|
125
|
+
*/
|
|
126
|
+
export declare function selectWebMcpToolEntries(manifest: SmartObjectManifest): WebMcpToolEntry[];
|
|
87
127
|
/**
|
|
88
128
|
* Build the per-collection web-collection definition literal — the SINGLE
|
|
89
129
|
* source of truth for the shape emitted by {@link generateWebModule} and hashed
|
|
@@ -150,6 +190,14 @@ export declare function buildWebRelationships(obj: SmartObjectDefinition, manife
|
|
|
150
190
|
export declare function buildWebToolDescriptors(entry: WebCollectionEntry, options?: {
|
|
151
191
|
kebabRoutes?: boolean;
|
|
152
192
|
}): ToolDescriptor[];
|
|
193
|
+
/** Build the canonical, transport-complete definition for one selected tool. */
|
|
194
|
+
export declare function buildWebMcpToolDefinition(entry: WebMcpToolEntry, manifest: SmartObjectManifest, options?: {
|
|
195
|
+
kebabRoutes?: boolean;
|
|
196
|
+
}): WebMcpToolDefinition;
|
|
197
|
+
/** Emit every API-backed WebMCP tool, including non-list models. */
|
|
198
|
+
export declare function buildWebMcpToolDefinitions(manifest: SmartObjectManifest, options?: {
|
|
199
|
+
kebabRoutes?: boolean;
|
|
200
|
+
}): WebMcpToolDefinition[];
|
|
153
201
|
/**
|
|
154
202
|
* A deterministic, replica-stable digest of the web-collection SHAPE (#1764).
|
|
155
203
|
*
|