@happyvertical/smrt-core 0.51.1 → 0.51.3

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.
@@ -1 +1 @@
1
- {"version":3,"file":"manifest-generator.js","names":[],"sources":["../../src/scanner/manifest-generator.ts"],"sourcesContent":["/**\n * Manifest generator for creating service manifests from AST scan results\n */\n\nimport { createHash } from 'node:crypto';\nimport { createRequire } from 'node:module';\nimport { createLogger } from '@happyvertical/logger';\nimport {\n createManifestClassNamePredicate,\n resolveApiMethodExposure,\n resolveCustomActionMetadata,\n resolveEffectiveActionMetadata,\n} from '../generators/custom-action.js';\nimport {\n loadExternalManifestSync,\n lookupInManifest,\n} from '../manifest/manifest-loader.js';\nimport {\n defaultConflictColumns,\n resolveTenantColumn,\n} from '../schema/conflict-target.js';\nimport type { DatabaseEngine } from '../schema/ddl/types.js';\nimport { resolveForeignKeyDeleteAction } from '../schema/foreign-key-policy.js';\nimport { SchemaGenerator } from '../schema/generator.js';\nimport type {\n ColumnDefinition,\n SchemaDefinition,\n SQLDataType,\n} from '../schema/types.js';\nimport { generateToolManifest } from '../tools/tool-generator.js';\nimport { classnameToTablename, toSnakeCase } from '../utils/naming.js';\nimport { createQualifiedName } from '../utils/qualified-names.js';\nimport { isTestFile } from './test-file-patterns.js';\nimport type {\n AgentAdminRouteManifest,\n AgentComponentDeclaration,\n AgentFeature,\n AgentManifest,\n AgentMenuItem,\n AgentPermission,\n AgentUISlotManifest,\n FieldDefinition,\n ManifestColumnDefinition,\n ManifestSchema,\n MethodDefinition,\n ScanResult,\n SmartObjectDefinition,\n SmartObjectManifest,\n SmrtVisibility,\n ValidationRule,\n} from './types.js';\nimport { MANIFEST_TIMESTAMP } from './types.js';\n\n/** Package.json shape consumed for import-path and component discovery. */\ninterface PackageJsonLike {\n name?: string;\n main?: string;\n exports?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\n/**\n * Object form of the `@smrt({ tenantScoped })` config. Mirrors the object\n * branch of `SmartObjectConfig['tenantScoped']`; all keys optional because\n * the boolean shorthand normalizes to `{}`.\n */\ninterface TenantScopedOptions {\n mode?: 'required' | 'optional';\n field?: string;\n autoFilter?: boolean;\n autoPopulate?: boolean;\n allowSuperAdminBypass?: boolean;\n}\n\n/** JSON Schema property entry emitted for a field in generated MCP tools. */\ninterface JsonSchemaProperty {\n type: string;\n description: string;\n minimum?: number;\n maximum?: number;\n minLength?: number;\n maxLength?: number;\n}\n\ntype SchemaGeneratorLike = {\n generateSQL: (schema: SchemaDefinition, engine?: DatabaseEngine) => string;\n};\n\n// Create require function for synchronous module loading in ESM context\nconst require = createRequire(import.meta.url);\n\n// Build-time schema/manifest-generation diagnostics route through the shared\n// logger (S14 / dim-9, #1579) instead of unconditional stdout writes.\nconst logger = createLogger({ level: 'info' });\n\n/**\n * Framework abstract base classes whose declared fields must be merged\n * into every subclass's `fields` map.\n *\n * These classes live in SMRT framework packages, have no `@smrt()`\n * decorator, no table of their own, and contribute structural fields\n * (e.g. `SmrtHierarchical.parentId`) that subclasses query against —\n * without merging, downstream WHERE-clause validation rejects queries on\n * those columns.\n *\n * SmrtObject / SmrtClass / SmrtCollection are intentionally NOT in this\n * set even though they live in core. SmrtObject's universal columns\n * (`id`, `slug`, `context`, `created_at`, `updated_at`) are added by a\n * separate universal-baseline mechanism in `fieldsFromClass`, and merging\n * them here would double-write with subtly different `_meta` payloads\n * and regress existing field expectations.\n *\n * Keep in sync with `FRAMEWORK_BASE_CLASSES` in\n * `packages/scanner/src/inheritance-resolver.ts` — note that set is\n * broader: it controls scanner-level chain termination and stub\n * resolution, while this one only controls field merging.\n */\nconst FRAMEWORK_ABSTRACT_BASE_NAMES = new Set([\n 'SmrtJunction',\n 'SmrtHierarchical',\n 'SmrtPolymorphicAssociation',\n 'SmrtReport',\n 'SmrtReportCollection',\n]);\n\n/**\n * Framework base classes to exclude from the ancestor **method** merge\n * below (#2624). Unlike fields, methods are never columns, so they never\n * needed the STI-vs-CTI field-merge rule above — they inherited it only by\n * sharing the same loop.\n *\n * Deliberately NARROWER than `FRAMEWORK_ABSTRACT_BASE_NAMES`: only the\n * three universal object/collection primitives (`SmrtObject`, `SmrtClass`,\n * `SmrtCollection`) are internal-only. These are the same three the\n * runtime resolver's `getAllMethods()`\n * (`packages/core/src/registry/inheritance-resolver.ts`) explicitly skips\n * by name, and the same three the field-merge doc comment above excludes\n * from `FRAMEWORK_ABSTRACT_BASE_NAMES` for the identical reason: their\n * surface (`save`, `destroy`, `toJSON`, `withTransaction`, ...) is generic\n * object-lifecycle plumbing, never a subclass-specific action.\n *\n * `FRAMEWORK_ABSTRACT_BASE_NAMES` (`SmrtJunction`, `SmrtHierarchical`,\n * `SmrtPolymorphicAssociation`, `SmrtReport`, `SmrtReportCollection`) is\n * intentionally NOT folded in here, unlike an earlier version of this fix.\n * Those classes are mixin-style bases whose declared methods ARE the\n * subclass's real, intended public API — the same way `SmrtHierarchical.\n * parentId` is a real, intended field, which is exactly why\n * `FRAMEWORK_ABSTRACT_BASE_NAMES` fields already merge into every subclass\n * regardless of STI/CTI (see above). Directly confirmed for two of the\n * five: `SmrtJunction.attach`/`detach`/`byLeft`/`byRight`/`setLinks`\n * (`packages/core/src/junction.ts`) — a `packages/template-sveltekit/\n * __tests__/runtimeProfileParity.test.ts` snapshot broke when an earlier\n * revision of this fix folded all 8 `FRAMEWORK_BASE_CLASSES` in here,\n * which is how this got caught — and `SmrtHierarchical.getParent`/\n * `getChildren`/`getAncestors`/`getDescendants`/`getHierarchy`/`moveTo`\n * (`packages/core/src/hierarchical.ts`). `SmrtPolymorphicAssociation`\n * follows the identical pattern by inspection but has no dedicated\n * regression test yet. `SmrtReport`/`SmrtReportCollection` are the\n * least-audited of the five: `SmrtReportCollection` overrides `list`/`get`\n * (`packages/reports/src/report.ts`), which are also the universal CRUD\n * operation names — a downstream `class X extends SmrtReportCollection`\n * with default (non-strict) MCP config would have seen a generated\n * custom-action tool collide with the standard `list`/`get` tool name.\n * #2646 closed that separately and independently of this exclusion set: the\n * MCP generator now refuses to expose a CRUD-named method as a custom action,\n * matching case-folded because its tool ids are lowercased whole. Each emitter\n * reserves on its own terms, and not all of them read the shared\n * `CRUD_OPERATIONS` list yet — see its docblock in\n * `generators/custom-action.ts` for the per-emitter rules. Keep in sync with the field-merge set's own doc comment; this one\n * governs method merging only.\n */\nconst FRAMEWORK_METHOD_BASE_NAMES = new Set([\n 'SmrtObject',\n 'SmrtClass',\n 'SmrtCollection',\n]);\n\n/**\n * Deterministic string comparator (#2749). Manifest object iteration order\n * follows scan/discovery order, which is not stable across runs, so any\n * emitted artifact keyed off `Object.entries(manifest.objects)` needs a\n * stable sort before emission.\n */\nfunction compareText(left: string, right: string): number {\n if (left < right) return -1;\n if (left > right) return 1;\n return 0;\n}\n\n/**\n * True when a package.json `exports` condition resolves to a non-JS asset\n * (e.g. the `./manifest`/`./manifest.json` convention pointing at\n * `dist/manifest.json`), so subpath matching (smrt#2845's\n * `matchExportsSubpath`) never attributes a scanned object to it — no\n * `@smrt()` class's source file can be loaded from a JSON target.\n */\nfunction targetsJsonAsset(condition: unknown): boolean {\n if (typeof condition === 'string') return condition.endsWith('.json');\n if (condition && typeof condition === 'object') {\n const record = condition as Record<string, unknown>;\n const target = record.import ?? record.default ?? record.require;\n return typeof target === 'string' && target.endsWith('.json');\n }\n return false;\n}\n\n/**\n * Infer visibility from file path and explicit config\n *\n * Priority:\n * 1. Explicit visibility in decorator config\n * 2. Auto-detect test files → 'test'\n * 3. Default to 'public'\n */\nfunction inferVisibility(\n filePath: string,\n explicitVisibility?: SmrtVisibility,\n): SmrtVisibility {\n if (explicitVisibility) return explicitVisibility;\n if (isTestFile(filePath)) return 'test';\n return 'public';\n}\n\nexport class ManifestGenerator {\n /**\n * Generate manifest from scan results\n *\n * @param scanResults - Array of scan results containing object definitions\n * @param options - Optional configuration\n * @param options.packageName - Package name to inject into manifest and object definitions\n * @param options.packageVersion - Package version\n * @param options.packageJson - Full package.json object for determining import paths\n * @param options.smrtDependencies - List of SMRT package dependencies to include in manifest\n * @param options.includeVisibility - Array of visibility levels to include (default: all)\n * - For published packages: ['public']\n * - For development: ['public', 'internal', 'test'] or omit for all\n */\n generateManifest(\n scanResults: ScanResult[],\n options?: {\n packageName?: string;\n packageVersion?: string;\n packageJson?: PackageJsonLike;\n smrtDependencies?: string[];\n includeVisibility?: SmrtVisibility[];\n },\n ): SmartObjectManifest {\n const manifest: SmartObjectManifest = {\n version: '1.0.0',\n timestamp: MANIFEST_TIMESTAMP,\n objects: {},\n };\n\n // Set package metadata at manifest level if provided\n if (options?.packageName) {\n manifest.packageName = options.packageName;\n }\n if (options?.packageVersion) {\n manifest.packageVersion = options.packageVersion;\n }\n // Set smrtDependencies BEFORE mergeInheritedFields() so external packages can be loaded\n if (options?.smrtDependencies) {\n manifest.smrtDependencies = options.smrtDependencies;\n }\n\n for (const result of scanResults) {\n for (const objectDef of result.objects) {\n // Set package metadata on object definition if provided\n if (options?.packageName) {\n objectDef.packageName = options.packageName;\n }\n if (options?.packageVersion) {\n objectDef.packageVersion = options.packageVersion;\n }\n\n // Generate qualified name (required for manifest keying)\n // Must have packageName to generate qualified name\n if (objectDef.packageName) {\n objectDef.qualifiedName = createQualifiedName(\n objectDef.packageName,\n objectDef.className,\n );\n }\n\n // Infer visibility from file path and decorator config\n objectDef.visibility = inferVisibility(\n objectDef.filePath,\n objectDef.decoratorConfig?.visibility as SmrtVisibility | undefined,\n );\n\n // Filter by visibility if specified\n // Skip objects that don't match the requested visibility levels\n if (\n options?.includeVisibility &&\n options.includeVisibility.length > 0 &&\n !options.includeVisibility.includes(objectDef.visibility)\n ) {\n // Skip this object - visibility not in allowed list\n continue;\n }\n\n // Determine import path from package.json exports\n if (options?.packageName && options?.packageJson) {\n objectDef.importPath = this.determineImportPath(\n options.packageJson,\n objectDef.filePath,\n );\n }\n\n // Set export names (defaults to className)\n objectDef.exportName = objectDef.exportName || objectDef.className;\n objectDef.collectionExportName =\n objectDef.collectionExportName || `${objectDef.className}Collection`;\n\n // Generate AI tools from methods if AI config exists\n if (objectDef.decoratorConfig.ai) {\n const methods = Object.values(objectDef.methods);\n const tools = generateToolManifest(\n methods,\n objectDef.decoratorConfig.ai,\n );\n\n // Store tools in object definition\n if (tools.length > 0) {\n objectDef.tools = tools;\n }\n }\n\n // Determine manifest key: use qualified name if available, fall back to lowercase name\n // During transition, some objects may not have qualified names\n const manifestKey = objectDef.qualifiedName || objectDef.name;\n\n // Check for collisions using the manifest key\n if (manifest.objects[manifestKey]) {\n const existing = manifest.objects[manifestKey];\n throw new Error(\n `Class name collision detected: '${objectDef.className}' (${manifestKey}) is defined in multiple files:\\n` +\n ` 1. ${existing.filePath}\\n` +\n ` 2. ${objectDef.filePath}\\n\\n` +\n `Class names must be unique within a package. Use different class names or separate packages.`,\n );\n }\n\n manifest.objects[manifestKey] = objectDef;\n }\n }\n\n this.applyGenerationPasses(manifest, {\n packageName: options?.packageName,\n packageJson: options?.packageJson,\n });\n\n return manifest;\n }\n\n /**\n * Run every manifest generation pass, in order, on a manifest whose\n * `objects` have been collected. This is THE pass sequence: the OXC vite\n * plugin (`vite-plugin/index.ts`) and `ManifestBuilder.buildManifest()`\n * call it too, so the three producers cannot drift — before #2360\n * `ManifestBuilder` skipped the report passes and its manifests carried\n * `(slug, context)` conflict indexes for `@report` classes while the\n * runtime upserted on the report's group columns.\n *\n * @param manifest - manifest with `objects` populated (and\n * `smrtDependencies` set, so external STI bases resolve)\n * @param options - package metadata for the agent-manifest pass\n */\n applyGenerationPasses(\n manifest: SmartObjectManifest,\n options?: { packageName?: string; packageJson?: PackageJsonLike },\n ): void {\n // Report cache rows are safe to scope by tenant even when a report is\n // global: optional mode keeps tenant-less rows readable outside a tenant\n // context and gives tenant-scoped reports the tenant_id column their raw\n // aggregate refresh path must write.\n this.normalizeReportTenantScope(manifest);\n\n // Second pass: materialize implicit tenant fields before inheritance and schema generation.\n this.injectTenantScopedFields(manifest);\n\n // Third pass: Merge inherited fields for STI classes\n // This ensures STI subclasses have all parent fields inline in the manifest\n this.mergeInheritedFields(manifest);\n\n // Report models are read-only cache tables. Fill in the generated surface\n // and natural conflict key from report metadata before schema generation.\n this.normalizeReportObjects(manifest);\n\n // Tenant-scoped classes key on `[tenant column, ...natural key]` (#2360);\n // materialize that default so schema generation, the knowledge artifact\n // and the runtime read the same conflict target.\n this.normalizeConflictColumns(manifest);\n\n // Fourth pass: Generate validation rules for all objects\n // This pre-computes validation rules from field definitions, eliminating\n // the need to compile validator closures at runtime (Issue #782)\n this.generateValidationRules(manifest);\n\n // Fifth pass: Generate schemas for each object (build-time schema generation)\n // This pre-computes DDL, indexes, and columns for efficient external package consumption\n this.generateSchemas(manifest);\n this.assertTenantScopedSchemaContract(manifest);\n\n // Sixth pass: Generate agent manifests for Agent subclasses\n // Derives permissions, features, menuItems, and components from code\n this.generateAgentManifests(\n manifest,\n options?.packageName,\n options?.packageJson,\n );\n\n // Seventh pass: stamp the subpath consumers should import each object\n // from. `generateManifest()`'s own per-object loop already does this,\n // but the Vite plugin and `ManifestBuilder` (the other two manifest\n // producers this pass sequence exists to keep from drifting, #2360)\n // build their manifest via `ManifestAdapter.toManifest()` and call\n // `applyGenerationPasses()` directly — never through `generateManifest()`\n // — so their objects reached this pass with no `importPath` at all. That\n // is smrt#2845: `DataSurfaceActionIdempotencyState` in\n // `@happyvertical/smrt-agents` lives under `src/server/` (served only by\n // the `./server` export), but the published manifest carried no\n // `importPath`, so consumer registration\n // (`consumer-plugin/index.ts`'s own `determineImportPath`) fell back to\n // the bare package specifier the object was never exported from.\n this.resolveImportPaths(\n manifest,\n options?.packageName,\n options?.packageJson,\n );\n }\n\n /**\n * Stamp `importPath` (via {@link determineImportPath}) on every object\n * that does not already have one. Safe to call unconditionally: objects\n * that went through `generateManifest()`'s own inline assignment already\n * carry an `importPath` and are left untouched.\n */\n resolveImportPaths(\n manifest: SmartObjectManifest,\n packageName?: string,\n packageJson?: PackageJsonLike,\n ): void {\n if (!packageName || !packageJson) return;\n\n for (const obj of Object.values(manifest.objects)) {\n if (obj.importPath) continue;\n obj.importPath = this.determineImportPath(packageJson, obj.filePath);\n }\n }\n\n /**\n * Materialize tenantScoped schema fields.\n *\n * Runtime registration already injects tenant fields for\n * `@smrt({ tenantScoped: true })`, but published manifests must contain the\n * same field before schema generation so migrations create `tenant_id`.\n */\n injectTenantScopedFields(manifest: SmartObjectManifest): void {\n for (const objectDef of Object.values(manifest.objects)) {\n this.injectTenantScopedField(objectDef);\n }\n }\n\n private injectTenantScopedField(objectDef: SmartObjectDefinition): void {\n const tenantScoped = objectDef.decoratorConfig?.tenantScoped;\n if (!tenantScoped) {\n return;\n }\n\n const { tenantConfig } = this.normalizeTenantScopedConfig(tenantScoped);\n const fieldName = tenantConfig.field;\n const existingField = objectDef.fields[fieldName];\n const tenancyMeta = {\n isTenantIdField: true,\n ...tenantConfig,\n };\n\n if (existingField) {\n const fieldTypeFailure = this.getTenantScopedFieldTypeFailure(\n objectDef,\n fieldName,\n );\n if (fieldTypeFailure) {\n throw new Error(\n `Tenant-scoped field configuration invalid: ${fieldTypeFailure}`,\n );\n }\n\n existingField._meta = {\n ...existingField._meta,\n sqlType: 'UUID',\n __tenancy: {\n ...existingField._meta?.__tenancy,\n ...tenancyMeta,\n },\n };\n return;\n }\n\n objectDef.fields[fieldName] = {\n type: 'text',\n // Use the normalized tenant mode so the boolean shorthand has the same\n // requiredness in manifests as it does during runtime registration.\n required: tenantConfig.mode === 'required',\n _meta: {\n generated: true,\n source: 'tenantScoped_decorator',\n sqlType: 'UUID',\n __tenancy: tenancyMeta,\n },\n };\n\n logger.info(\n `[manifest-generator] Injected ${fieldName} field for ${objectDef.className} (tenantScoped: ${JSON.stringify(tenantConfig)})`,\n );\n }\n\n assertTenantScopedSchemaContract(manifest: SmartObjectManifest): void {\n const failures: string[] = [];\n\n for (const objectDef of Object.values(manifest.objects)) {\n const tenantScoped = objectDef.decoratorConfig?.tenantScoped;\n if (!tenantScoped) {\n continue;\n }\n\n const { tenantConfig } = this.normalizeTenantScopedConfig(tenantScoped);\n const fieldName = tenantConfig.field;\n const columnName = toSnakeCase(fieldName);\n\n if (!objectDef.fields[fieldName]) {\n failures.push(\n `${objectDef.className}: missing tenant-scoped field \"${fieldName}\"`,\n );\n continue;\n }\n\n const fieldTypeFailure = this.getTenantScopedFieldTypeFailure(\n objectDef,\n fieldName,\n );\n if (fieldTypeFailure) {\n failures.push(fieldTypeFailure);\n continue;\n }\n\n const schemaOwner = this.getTenantScopedSchemaOwner(objectDef, manifest);\n const schemaOwnerContext =\n schemaOwner === objectDef\n ? ''\n : ` on STI base \"${schemaOwner.className}\"`;\n\n if (!schemaOwner.schema?.columns) {\n failures.push(\n `${objectDef.className}: schema has not been generated for tenant-scoped column \"${columnName}\"${schemaOwnerContext}`,\n );\n continue;\n }\n\n if (!schemaOwner.schema.columns[columnName]) {\n failures.push(\n `${objectDef.className}: schema is missing tenant-scoped column \"${columnName}\"${schemaOwnerContext}`,\n );\n }\n }\n\n if (failures.length > 0) {\n throw new Error(\n `Tenant-scoped schema contract failed:\\n${failures\n .map((failure) => ` - ${failure}`)\n .join('\\n')}`,\n );\n }\n }\n\n private getTenantScopedSchemaOwner(\n objectDef: SmartObjectDefinition,\n manifest: SmartObjectManifest,\n ): SmartObjectDefinition {\n if (!this.isSTIChildClass(objectDef, manifest)) {\n return objectDef;\n }\n\n const stiBase = this.findSTIBaseInfo(objectDef, manifest);\n if (!stiBase) {\n return objectDef;\n }\n\n const localBase = Object.values(manifest.objects).find(\n (candidate) => candidate.className === stiBase.className,\n );\n\n return localBase ?? objectDef;\n }\n\n private getTenantScopedFieldTypeFailure(\n objectDef: SmartObjectDefinition,\n fieldName: string,\n ): string | undefined {\n const field = objectDef.fields[fieldName];\n if (!field) {\n return undefined;\n }\n\n if (field.type !== 'text' && field.type !== 'foreignKey') {\n return `${objectDef.className}: tenant-scoped field \"${fieldName}\" must use type \"text\" or \"foreignKey\"; received \"${field.type}\"`;\n }\n\n const sqlType = field._meta?.sqlType;\n if (sqlType && !['TEXT', 'UUID'].includes(String(sqlType).toUpperCase())) {\n return `${objectDef.className}: tenant-scoped field \"${fieldName}\" must use SQL type \"UUID\" or legacy \"TEXT\"; received \"${sqlType}\"`;\n }\n\n return undefined;\n }\n\n private normalizeTenantScopedConfig(tenantScoped: unknown): {\n tenantConfig: {\n mode: string;\n field: string;\n autoFilter: boolean;\n autoPopulate: boolean;\n allowSuperAdminBypass: boolean;\n };\n } {\n const tenantOptions: TenantScopedOptions =\n typeof tenantScoped === 'boolean'\n ? {}\n : (tenantScoped as TenantScopedOptions);\n\n return {\n tenantConfig: {\n mode: tenantOptions.mode ?? 'required',\n field: tenantOptions.field ?? 'tenantId',\n autoFilter: tenantOptions.autoFilter ?? true,\n autoPopulate: tenantOptions.autoPopulate ?? true,\n allowSuperAdminBypass: tenantOptions.allowSuperAdminBypass ?? false,\n },\n };\n }\n\n /**\n * Generate pre-computed validation rules for all objects in the manifest.\n *\n * This extracts validation constraints (required, min, max, minLength, maxLength, pattern)\n * from field definitions and stores them as serializable rules in the manifest.\n *\n * At runtime, these rules can be evaluated without creating validator closures,\n * significantly reducing CLI startup time for projects with many SMRT objects.\n *\n * @param manifest - The manifest to process in-place\n */\n generateValidationRules(manifest: SmartObjectManifest): void {\n for (const [name, obj] of Object.entries(manifest.objects)) {\n const rules: ValidationRule[] = [];\n let skippedAutoPopulatedTenantRequiredRule = false;\n\n for (const [fieldName, field] of Object.entries(obj.fields)) {\n // Skip transient fields (they're not persisted, so no validation needed)\n if (field.transient || field._meta?.transient) {\n continue;\n }\n\n const options = field._meta || {};\n\n // Required field rule\n const isAutoPopulatedTenantField =\n options.__tenancy?.isTenantIdField === true &&\n options.__tenancy.autoPopulate !== false;\n if (\n (options.required || field.required) &&\n !isAutoPopulatedTenantField\n ) {\n rules.push({\n field: fieldName,\n rule: 'required',\n fieldType: field.type,\n });\n } else if (\n isAutoPopulatedTenantField &&\n (options.required || field.required)\n ) {\n // Tenant IDs can be required in the manifest and database while still\n // being absent at this pre-interceptor validation stage. Tenancy's\n // beforeSave hook stamps them from the active context before writing.\n skippedAutoPopulatedTenantRequiredRule = true;\n }\n\n // Numeric range rules (for integer, decimal fields)\n if (field.type === 'integer' || field.type === 'decimal') {\n if (options.min !== undefined || field.min !== undefined) {\n rules.push({\n field: fieldName,\n rule: 'min',\n value: options.min ?? field.min,\n fieldType: field.type,\n });\n }\n\n if (options.max !== undefined || field.max !== undefined) {\n rules.push({\n field: fieldName,\n rule: 'max',\n value: options.max ?? field.max,\n fieldType: field.type,\n });\n }\n }\n\n // String length rules (for text fields)\n if (field.type === 'text') {\n if (\n options.minLength !== undefined ||\n field.minLength !== undefined\n ) {\n rules.push({\n field: fieldName,\n rule: 'minLength',\n value: options.minLength ?? field.minLength,\n fieldType: field.type,\n });\n }\n\n if (\n options.maxLength !== undefined ||\n field.maxLength !== undefined\n ) {\n rules.push({\n field: fieldName,\n rule: 'maxLength',\n value: options.maxLength ?? field.maxLength,\n fieldType: field.type,\n });\n }\n\n // Pattern rule (regex validation)\n // Note: Custom validator functions (options.validate) cannot be serialized\n // and will fall back to compiled validators at runtime\n // Note: Pattern is only available in field options, not in FieldDefinition\n const pattern = options.pattern;\n if (pattern) {\n rules.push({\n field: fieldName,\n rule: 'pattern',\n // RegExp patterns expose `.source`; a JSON-collapsed RegExp ({})\n // has none, preserving the prior `undefined` value exactly.\n value:\n typeof pattern === 'string'\n ? pattern\n : (pattern as { source?: string }).source,\n fieldType: field.type,\n });\n }\n }\n }\n\n // An explicit empty list is meaningful when the sole required field is\n // auto-populated by tenancy: it prevents runtime registration from\n // recompiling a pre-interceptor required validator for that field.\n if (rules.length > 0 || skippedAutoPopulatedTenantRequiredRule) {\n obj.validationRules = rules;\n }\n }\n }\n\n /**\n * Generate pre-computed schemas for all objects in the manifest.\n *\n * This enables external package consumers to use pre-generated schemas\n * without calling generateSchema() at runtime, eliminating latency.\n *\n * IMPORTANT: For STI classes, we aggregate ALL descendants from both local\n * and external packages to ensure complete schemas are generated.\n *\n * This method is public to allow external callers (like OXC scanner) to use it.\n *\n * @param manifest - The manifest to process in-place\n */\n generateSchemas(manifest: SmartObjectManifest): void {\n const generator = new SchemaGenerator();\n\n // Create aggregated manifest that includes external package objects\n // This ensures STI schema generation finds ALL descendants\n const aggregatedManifest = this.createAggregatedManifest(manifest);\n const schemaClasses = new Map(\n Object.values(aggregatedManifest.objects).map((obj) => [\n obj.className,\n obj,\n ]),\n );\n\n // An external class with the same simple name cannot replace a local item.\n for (const obj of Object.values(manifest.objects))\n schemaClasses.set(obj.className, obj);\n\n for (const [name, obj] of Object.entries(manifest.objects)) {\n // Collections access their item model's table; an independent schema can\n // contradict that model's tenant/conflict identity during aggregation.\n if (this.extendsCollection(obj, schemaClasses)) {\n delete obj.schema;\n continue;\n }\n if (FRAMEWORK_ABSTRACT_BASE_NAMES.has(obj.className)) {\n continue;\n }\n\n // Determine table name (may have been inherited from external STI base)\n // Use obj.className (PascalCase) for consistent table name derivation with runtime\n const tableName =\n obj.decoratorConfig?.tableName ||\n this.classNameToTableName(obj.className);\n\n // Check if this is an STI class. `mergeInheritedFields()` copies the\n // base's `tableStrategy` onto every descendant, so both the root and\n // its children arrive here; `isSTIChildClass` covers a child whose\n // strategy was not inherited.\n if (\n obj.decoratorConfig?.tableStrategy === 'sti' ||\n this.isSTIChildClass(obj, manifest)\n ) {\n // Every class in an STI hierarchy — root, local child, or a child of\n // an EXTERNAL base — carries the schema of the ONE shared table,\n // generated from the ROOT base so descendant discovery, the\n // discriminator-partial unique indexes and the base-declared /\n // descendant-declared distinction are computed against the same\n // hierarchy on every class (#527, #2359). A child generated as if it\n // were the root would treat its own descendant-only `unique: true`\n // fields as base-declared and emit a full unique index that\n // `getAllSchemasAsDefinitions()` then merges into the table beside\n // the correct partial one.\n const stiRoot = this.findSTIBaseInfo(obj, manifest);\n const rootKey = stiRoot\n ? (this.resolveManifestKey(stiRoot.className, aggregatedManifest) ??\n stiRoot.className)\n : name;\n const rootTableName = stiRoot?.tableName || tableName;\n const rootConfig =\n aggregatedManifest.objects[rootKey]?.decoratorConfig ??\n obj.decoratorConfig;\n\n logger.info(\n `[manifest-generator] Generating STI schema for ${name} (root: ${rootKey}, table: ${rootTableName})`,\n );\n\n // Use aggregated manifest to find descendants from ALL packages\n obj.schema = generator.generateSTISchemaFromManifest(\n rootKey,\n rootTableName,\n obj.fields,\n aggregatedManifest,\n rootConfig,\n );\n this.applySqlTypeOverrides(obj);\n } else {\n // CTI class - generate individual table schema\n logger.info(\n `[manifest-generator] Generating CTI schema for ${name} (table: ${tableName})`,\n );\n\n obj.schema = generator.generateCTISchemaFromManifest(\n name,\n tableName,\n obj.fields,\n obj.decoratorConfig,\n );\n this.applySqlTypeOverrides(obj);\n }\n }\n\n this.resolveSamePackageForeignKeyColumnTypes(manifest, generator);\n\n // Preserve collection metadata, but take persistence identity from the item\n // model only after every model schema (including FK repair) is complete.\n for (const obj of Object.values(manifest.objects)) {\n if (!this.extendsCollection(obj, schemaClasses)) continue;\n let current: SmartObjectDefinition | undefined = obj;\n const visited = new Set<SmartObjectDefinition>();\n while (current && !visited.has(current)) {\n visited.add(current);\n const item = this.findItemClass(\n current,\n aggregatedManifest,\n schemaClasses,\n );\n if (item?.schema && !this.extendsCollection(item, schemaClasses)) {\n obj.schema = structuredClone(item.schema);\n break;\n }\n current = current.extends\n ? schemaClasses.get(current.extends)\n : undefined;\n }\n }\n }\n\n normalizeReportObjects(manifest: SmartObjectManifest): void {\n for (const obj of Object.values(manifest.objects)) {\n if (!obj.decoratorConfig?.report) continue;\n\n obj.decoratorConfig.api ??= { include: ['list', 'get'] };\n obj.decoratorConfig.mcp ??= { include: ['list', 'get'] };\n\n if (obj.decoratorConfig.conflictColumns) continue;\n\n const tenantScoped = obj.decoratorConfig.tenantScoped;\n const tenantField =\n tenantScoped && typeof tenantScoped === 'object'\n ? tenantScoped.field || 'tenantId'\n : tenantScoped\n ? 'tenantId'\n : undefined;\n const tenantColumn =\n tenantField && obj.fields[tenantField] ? toSnakeCase(tenantField) : '';\n\n const conflictColumns = Object.entries(obj.fields)\n .filter(([, field]) => {\n const kind = field._meta?.__report?.kind;\n return kind === 'group' || kind === 'bucket';\n })\n .map(([fieldName]) => toSnakeCase(fieldName));\n\n obj.decoratorConfig.conflictColumns =\n conflictColumns.length > 0\n ? [...(tenantColumn ? [tenantColumn] : []), ...conflictColumns]\n : ['id'];\n }\n }\n\n normalizeReportTenantScope(manifest: SmartObjectManifest): void {\n for (const obj of Object.values(manifest.objects)) {\n if (!obj.decoratorConfig?.report) continue;\n obj.decoratorConfig.tenantScoped ??= { mode: 'optional' };\n }\n }\n\n /**\n * Materialize the tenant-aware default conflict target (#2360).\n *\n * A tenant-scoped class that declares no `@smrt({ conflictColumns })` keys\n * on `[tenant column, ...natural key]` — `(tenant_id, slug, context)` for\n * a class-per-table object, `(tenant_id, slug, context, _meta_type)` for a\n * single-table hierarchy — so two tenants can each own the same slug and\n * neither `save()` adopts the other's row. Writing the resolved key into\n * `decoratorConfig.conflictColumns` (mirroring `normalizeReportObjects`)\n * makes the manifest, the generated schema, the knowledge artifact and\n * `ObjectRegistry.getConflictColumns()` read one value.\n *\n * Only schema owners are normalized: an STI child inherits the table (and\n * therefore the key) from its root, and `getConflictColumns()` resolves a\n * child through its root at runtime. Explicit `conflictColumns` and\n * `@report` classes (keyed by `normalizeReportObjects`) are left alone.\n * Runs after `injectTenantScopedFields()` and `mergeInheritedFields()` so\n * the tenant field and the inherited `tableStrategy` are in place, and\n * before `generateSchemas()`.\n */\n normalizeConflictColumns(manifest: SmartObjectManifest): void {\n for (const obj of Object.values(manifest.objects)) {\n if (!obj.decoratorConfig) continue;\n if (FRAMEWORK_ABSTRACT_BASE_NAMES.has(obj.className)) continue;\n if (obj.decoratorConfig.conflictColumns) continue;\n if (obj.decoratorConfig.report) continue;\n if (this.isSTIChildClass(obj, manifest)) continue;\n\n const tenantScoped = obj.decoratorConfig.tenantScoped;\n if (!tenantScoped) continue;\n\n const { tenantConfig } = this.normalizeTenantScopedConfig(tenantScoped);\n const tenantColumn = resolveTenantColumn(\n tenantConfig.field,\n (fieldName) => Boolean(obj.fields[fieldName]),\n toSnakeCase,\n );\n if (!tenantColumn) continue;\n\n obj.decoratorConfig.conflictColumns = defaultConflictColumns(\n obj.decoratorConfig.tableStrategy === 'sti' ? 'sti' : 'cti',\n tenantColumn,\n );\n }\n }\n\n private resolveSamePackageForeignKeyColumnTypes(\n manifest: SmartObjectManifest,\n generator: SchemaGeneratorLike,\n ): void {\n // One representative schema per table for target-id lookups, plus EVERY\n // schema that describes a table: each class of an STI hierarchy carries a\n // copy of the shared table's schema (#2359), and every copy must receive\n // the same reconciled type or `getAllSchemasAsDefinitions()`'s\n // first-wins column merge can surface an unreconciled one.\n const schemaByTable = new Map<string, ManifestSchema>();\n const schemasByTable = new Map<string, ManifestSchema[]>();\n const ownerBySchema = new Map<\n ManifestSchema,\n { name: string; obj: SmartObjectDefinition }\n >();\n const changedSchemas = new Set<ManifestSchema>();\n const objectsByName = new Map<string, SmartObjectDefinition>();\n\n for (const [name, obj] of Object.entries(manifest.objects)) {\n objectsByName.set(obj.className, obj);\n objectsByName.set(obj.className.toLowerCase(), obj);\n if (obj.schema?.tableName) {\n schemaByTable.set(obj.schema.tableName, obj.schema);\n const siblings = schemasByTable.get(obj.schema.tableName) ?? [];\n siblings.push(obj.schema);\n schemasByTable.set(obj.schema.tableName, siblings);\n ownerBySchema.set(obj.schema, { name, obj });\n }\n }\n\n for (const obj of Object.values(manifest.objects)) {\n const sourceTable = this.getObjectTableName(obj);\n if (!sourceTable) {\n continue;\n }\n\n const sourceSchemas = schemasByTable.get(sourceTable);\n if (!sourceSchemas || sourceSchemas.length === 0) {\n continue;\n }\n\n for (const [fieldName, field] of Object.entries(obj.fields || {})) {\n if (\n field.type !== 'foreignKey' ||\n !field.related ||\n field._meta?.__tenancy?.isTenantIdField === true\n ) {\n continue;\n }\n\n const emitConstraint = field._meta?.constraint !== false;\n\n const columnName = toSnakeCase(fieldName);\n const targetSchema = this.findForeignKeyTargetSchema(\n field.related,\n manifest,\n schemaByTable,\n obj.packageName,\n );\n if (!targetSchema) {\n for (const sourceSchema of sourceSchemas) {\n const sourceColumn = sourceSchema.columns[columnName];\n if (sourceColumn?.foreignKey) {\n sourceSchema.columns[columnName] = {\n ...sourceColumn,\n foreignKey: undefined,\n };\n changedSchemas.add(sourceSchema);\n }\n }\n continue;\n }\n\n const [, declaredTargetColumn] = field.related.split('.');\n const targetColumn =\n declaredTargetColumn ||\n Object.entries(targetSchema.columns).find(\n ([, definition]) => definition.primaryKey === true,\n )?.[0] ||\n 'id';\n const targetIdType = targetSchema.columns[targetColumn]?.type;\n const conflictOwner =\n this.findSTIBase(obj, objectsByName, manifest) ?? obj;\n const conflictColumns = new Set(\n (conflictOwner.decoratorConfig?.conflictColumns || []).map((column) =>\n toSnakeCase(column),\n ),\n );\n const { action } = resolveForeignKeyDeleteAction({\n declared: field._meta?.onDelete,\n isConflictColumn: conflictColumns.has(columnName),\n isTenantIdField: false,\n });\n\n for (const sourceSchema of sourceSchemas) {\n const sourceColumn = sourceSchema.columns[columnName];\n if (!sourceColumn) {\n continue;\n }\n const nextColumn = {\n ...sourceColumn,\n ...(!field._meta?.sqlType && targetIdType\n ? { type: targetIdType }\n : {}),\n foreignKey: emitConstraint\n ? {\n table: targetSchema.tableName,\n column: targetColumn,\n onDelete: action,\n onUpdate: 'CASCADE' as const,\n ...(typeof field._meta?.constraint === 'object'\n ? { engines: [...field._meta.constraint.engines] }\n : {}),\n }\n : undefined,\n };\n if (JSON.stringify(nextColumn) === JSON.stringify(sourceColumn)) {\n continue;\n }\n sourceSchema.columns[columnName] = nextColumn;\n changedSchemas.add(sourceSchema);\n }\n }\n }\n\n for (const schema of changedSchemas) {\n this.refreshManifestSchemaDDL(\n schema,\n generator,\n ownerBySchema.get(schema),\n manifest,\n );\n }\n }\n\n private findForeignKeyTargetSchema(\n related: string,\n manifest: SmartObjectManifest,\n schemaByTable: Map<string, ManifestSchema>,\n sourcePackageName?: string,\n ): ManifestSchema | undefined {\n const relatedTarget = related.split('.')[0];\n if (schemaByTable.has(relatedTarget)) {\n return schemaByTable.get(relatedTarget);\n }\n\n const candidates = Object.values(manifest.objects).filter(\n (candidate) =>\n candidate.className === relatedTarget ||\n candidate.qualifiedName === relatedTarget ||\n candidate.name === relatedTarget ||\n candidate.decoratorConfig?.tableName === relatedTarget ||\n candidate.schema?.tableName === relatedTarget,\n );\n const localTarget = candidates.find(\n (candidate) => candidate.packageName === sourcePackageName,\n );\n if (!localTarget && candidates.length > 1) {\n throw new Error(\n `Ambiguous foreign key target ${relatedTarget} from package ${sourcePackageName}`,\n );\n }\n const targetObj = localTarget ?? candidates[0];\n\n if (!targetObj && relatedTarget.includes(':')) {\n return undefined;\n }\n\n const targetTable = targetObj\n ? this.getObjectTableName(targetObj)\n : this.classNameToTableName(relatedTarget);\n\n return targetTable ? schemaByTable.get(targetTable) : undefined;\n }\n\n private getObjectTableName(obj: SmartObjectDefinition): string | undefined {\n return (\n obj.schema?.tableName ||\n obj.decoratorConfig?.tableName ||\n this.classNameToTableName(obj.className)\n );\n }\n\n private refreshManifestSchemaDDL(\n schema: ManifestSchema,\n generator: SchemaGeneratorLike,\n owner: { name: string; obj: SmartObjectDefinition } | undefined,\n manifest: SmartObjectManifest,\n ): void {\n const columns: Record<string, ColumnDefinition> = {};\n for (const [name, column] of Object.entries(schema.columns)) {\n columns[name] = {\n // ManifestColumnDefinition stores `type` as a plain string; it is\n // always a valid SQLDataType for DDL rendering.\n type: column.type as SQLDataType,\n primaryKey: column.primaryKey,\n notNull: column.notNull,\n unique: column.unique,\n defaultValue: column.default,\n foreignKey: column.foreignKey ? { ...column.foreignKey } : undefined,\n };\n }\n\n const schemaDefinition: SchemaDefinition = {\n tableName: schema.tableName,\n columns,\n indexes: (schema.indexes || []).map((index) => ({\n name: index.name,\n columns: index.columns,\n unique: index.unique,\n ...(index.nullsNotDistinct ? { nullsNotDistinct: true } : {}),\n where: index.where,\n jsonPath: index.jsonPath,\n })),\n triggers: [],\n foreignKeys: Object.entries(columns).flatMap(([column, definition]) =>\n definition.foreignKey\n ? [\n {\n column,\n referencesTable: definition.foreignKey.table,\n referencesColumn: definition.foreignKey.column,\n onDelete: definition.foreignKey.onDelete,\n onUpdate: definition.foreignKey.onUpdate,\n ...(definition.foreignKey.engines\n ? { engines: definition.foreignKey.engines }\n : {}),\n },\n ]\n : [],\n ),\n dependencies: Object.values(columns)\n .flatMap((definition) =>\n definition.foreignKey ? [definition.foreignKey.table] : [],\n )\n .filter((dependency) => dependency !== schema.tableName),\n version: schema.version,\n packageName: '',\n };\n\n schema.ddl = generator.generateSQL(schemaDefinition);\n schema.version = this.computeManifestSchemaVersion(schema, owner, manifest);\n }\n\n private computeManifestSchemaVersion(\n schema: ManifestSchema,\n owner: { name: string; obj: SmartObjectDefinition } | undefined,\n manifest: SmartObjectManifest,\n ): string {\n if (schema.columns._meta_type && owner) {\n const baseClassName =\n owner.obj.decoratorConfig?.tableStrategy === 'sti'\n ? owner.name\n : this.findSTIBaseInfo(owner.obj, manifest)?.className || owner.name;\n\n return createHash('sha256')\n .update(\n JSON.stringify({\n columns: schema.columns,\n baseClassName,\n descendants: this.findDescendantsInManifest(\n baseClassName,\n manifest,\n ),\n }),\n )\n .digest('hex')\n .substring(0, 8);\n }\n\n return createHash('sha256')\n .update(\n JSON.stringify({\n columns: schema.columns,\n className: owner?.name || schema.tableName,\n }),\n )\n .digest('hex')\n .substring(0, 8);\n }\n\n private findDescendantsInManifest(\n baseClassName: string,\n manifest: SmartObjectManifest,\n visited: Set<string> = new Set(),\n ): string[] {\n const descendants: string[] = [];\n if (visited.has(baseClassName)) {\n return descendants;\n }\n visited.add(baseClassName);\n\n const baseClassLower = this.simpleClassName(baseClassName).toLowerCase();\n\n for (const [name, obj] of Object.entries(manifest.objects)) {\n const classNameLower = this.simpleClassName(obj.className).toLowerCase();\n const extendsLower = obj.extends\n ? this.simpleClassName(obj.extends).toLowerCase()\n : undefined;\n\n if (\n classNameLower === baseClassLower &&\n extendsLower === baseClassLower\n ) {\n continue;\n }\n\n if (extendsLower === baseClassLower) {\n descendants.push(name);\n descendants.push(\n ...this.findDescendantsInManifest(name, manifest, visited),\n );\n }\n }\n\n return descendants;\n }\n\n private applySqlTypeOverrides(obj: SmartObjectDefinition): void {\n if (!obj.schema?.columns) {\n return;\n }\n\n for (const [fieldName, field] of Object.entries(obj.fields || {})) {\n const sqlType = field?._meta?.sqlType;\n const referenceKind = this.getReferenceKind(field);\n if (!sqlType && !referenceKind) {\n continue;\n }\n\n const columnName = toSnakeCase(fieldName);\n if (!obj.schema.columns[columnName]) {\n continue;\n }\n\n obj.schema.columns[columnName] = {\n ...obj.schema.columns[columnName],\n ...(sqlType ? { type: String(sqlType).toUpperCase() } : {}),\n ...(referenceKind ? { referenceKind } : {}),\n };\n }\n }\n\n private getReferenceKind(\n field: SmartObjectDefinition['fields'][string] | undefined,\n ): ManifestColumnDefinition['referenceKind'] | undefined {\n if (field?._meta?.__tenancy?.isTenantIdField) {\n return 'tenantId';\n }\n\n if (field?.type === 'foreignKey') {\n return 'foreignKey';\n }\n\n if (field?.type === 'crossPackageRef') {\n return 'crossPackageRef';\n }\n\n return undefined;\n }\n\n /**\n * Create an aggregated manifest that includes objects from all external packages\n *\n * This is used for STI schema generation to ensure ALL descendants are found,\n * regardless of which package they're defined in.\n *\n * @param manifest - The local manifest\n * @returns Aggregated manifest with local + external objects\n */\n private createAggregatedManifest(\n manifest: SmartObjectManifest,\n ): SmartObjectManifest {\n // Start with a copy of local objects\n const aggregatedObjects: Record<string, SmartObjectDefinition> = {\n ...manifest.objects,\n };\n\n // Load and merge external package objects\n if (manifest.smrtDependencies && manifest.smrtDependencies.length > 0) {\n for (const packageName of manifest.smrtDependencies) {\n const externalManifest = loadExternalManifestSync(packageName);\n if (externalManifest) {\n // Merge external objects (local objects take precedence on collision)\n for (const [name, obj] of Object.entries(externalManifest.objects)) {\n if (!aggregatedObjects[name]) {\n aggregatedObjects[name] = obj;\n }\n }\n\n logger.info(\n `[manifest-generator] Aggregated ${Object.keys(externalManifest.objects).length} objects from ${packageName}`,\n );\n }\n }\n }\n\n return {\n ...manifest,\n objects: aggregatedObjects,\n };\n }\n\n /**\n * Check if an object is an STI child class (inherits from STI base)\n *\n * Walks up the inheritance chain to find if any ancestor has tableStrategy: 'sti'.\n * Also checks external SMRT packages for parent class definitions.\n */\n private isSTIChildClass(\n obj: SmartObjectDefinition,\n manifest: SmartObjectManifest,\n ): boolean {\n if (!obj.extends) return false;\n\n // Build a lookup map for efficient access\n const objectsByName = new Map<string, SmartObjectDefinition>();\n for (const [_name, objDef] of Object.entries(manifest.objects)) {\n objectsByName.set(objDef.className, objDef);\n objectsByName.set(objDef.className.toLowerCase(), objDef);\n }\n\n // Walk up the inheritance chain looking for STI base\n let currentClass: string | undefined = obj.extends;\n const visited = new Set<string>();\n\n while (currentClass) {\n if (visited.has(currentClass)) break;\n visited.add(currentClass);\n\n let parentObj = objectsByName.get(currentClass);\n\n // If parent not in current manifest, try loading from external SMRT packages\n if (\n !parentObj &&\n manifest.smrtDependencies &&\n manifest.smrtDependencies.length > 0\n ) {\n parentObj = this.loadParentFromExternalPackage(\n currentClass,\n manifest.smrtDependencies,\n objectsByName,\n );\n }\n\n if (!parentObj) break; // Parent not found anywhere (e.g., SmrtObject)\n\n if (parentObj.decoratorConfig?.tableStrategy === 'sti') {\n return true; // Found STI ancestor\n }\n\n currentClass = parentObj.extends;\n }\n\n return false;\n }\n\n /**\n * Resolve a class name (simple `Content` or qualified `@pkg:Content`) to\n * the key it is stored under in `manifest.objects`, or `undefined` when the\n * manifest does not carry it. Manifest keys are qualified names; `extends`\n * and {@link findSTIBaseInfo} report simple names.\n */\n private resolveManifestKey(\n className: string,\n manifest: SmartObjectManifest,\n ): string | undefined {\n if (manifest.objects[className]) return className;\n const simpleName = className.includes(':')\n ? className.slice(className.lastIndexOf(':') + 1)\n : className;\n for (const [key, obj] of Object.entries(manifest.objects)) {\n if (obj.qualifiedName === className || obj.className === simpleName) {\n return key;\n }\n }\n return undefined;\n }\n\n /**\n * Find full STI base class info (className + tableName)\n *\n * Walks up the inheritance chain to find the STI base class and returns\n * both its className and tableName. This is critical for external STI bases\n * where the child needs to use the base's table name for schema generation.\n */\n private findSTIBaseInfo(\n obj: SmartObjectDefinition,\n manifest: SmartObjectManifest,\n ): { className: string; tableName: string } | undefined {\n if (!obj.extends) return undefined;\n\n // Build a lookup map for efficient access\n const objectsByName = new Map<string, SmartObjectDefinition>();\n for (const [_name, objDef] of Object.entries(manifest.objects)) {\n objectsByName.set(objDef.className, objDef);\n objectsByName.set(objDef.className.toLowerCase(), objDef);\n }\n\n // Track the oldest STI base found as we walk up\n // (we need to keep walking to find the ROOT STI class, not the first one)\n let stiBaseInfo: { className: string; tableName: string } | undefined;\n\n // Walk up the inheritance chain looking for the OLDEST STI base\n let currentClass: string | undefined = obj.extends;\n const visited = new Set<string>();\n\n while (currentClass) {\n if (visited.has(currentClass)) break;\n visited.add(currentClass);\n\n let parentObj = objectsByName.get(currentClass);\n\n // If parent not in current manifest, try loading from external SMRT packages\n if (\n !parentObj &&\n manifest.smrtDependencies &&\n manifest.smrtDependencies.length > 0\n ) {\n parentObj = this.loadParentFromExternalPackage(\n currentClass,\n manifest.smrtDependencies,\n objectsByName,\n );\n }\n\n if (!parentObj) break;\n\n if (parentObj.decoratorConfig?.tableStrategy === 'sti') {\n // Found an STI ancestor - it becomes the new candidate base\n // Keep walking to find the OLDEST/ROOT STI class in the hierarchy\n const tableName =\n parentObj.decoratorConfig?.tableName ||\n parentObj.schema?.tableName ||\n this.classNameToTableName(parentObj.className);\n stiBaseInfo = {\n className: parentObj.className,\n tableName,\n };\n }\n\n currentClass = parentObj.extends;\n }\n\n return stiBaseInfo; // Return the oldest STI ancestor found (or undefined if none)\n }\n\n /**\n * Convert class name to table name (snake_case pluralized)\n *\n * IMPORTANT: Must use the same algorithm as runtime's tableNameFromClass()\n * to ensure manifest-generated table names match runtime-derived names.\n */\n private classNameToTableName(className: string): string {\n // Use the shared pluralization function that handles English plurals correctly\n // (e.g., 'Currency' → 'currencies', 'JournalEntry' → 'journal_entries')\n return classnameToTablename(className);\n }\n\n private normalizeFrameworkInheritedField(\n ancestorName: string,\n fieldName: string,\n fieldDef: FieldDefinition,\n childClassName: string,\n ): FieldDefinition {\n if (\n this.simpleClassName(ancestorName) === 'SmrtHierarchical' &&\n fieldName === 'parentId'\n ) {\n return {\n ...fieldDef,\n type: 'foreignKey',\n related: childClassName,\n required: false,\n _meta: {\n ...(fieldDef._meta || {}),\n nullable: true,\n },\n };\n }\n\n return fieldDef;\n }\n\n private simpleClassName(className: string): string {\n return className.includes(':')\n ? className.split(':').pop() || className\n : className;\n }\n\n /**\n * Merge inherited fields into child classes (build-time inheritance resolution)\n *\n * For STI hierarchies, child classes don't define their own fields in source code\n * (they inherit from parent). This method merges parent fields into child manifests\n * so that runtime code doesn't need to do field resolution.\n *\n * Also handles collection classes (SmrtCollection<T>) that should inherit their\n * item class's tableName and collection when the item uses STI.\n *\n * Handles multi-level inheritance (grandparents, great-grandparents, etc.)\n * Automatically loads parent class definitions from external SMRT packages when needed\n *\n * @param manifest - The manifest to process in-place\n */\n public mergeInheritedFields(manifest: SmartObjectManifest): void {\n // Build a map of className -> objectDef for fast lookup\n const objectsByName = new Map<string, SmartObjectDefinition>();\n for (const [name, obj] of Object.entries(manifest.objects)) {\n objectsByName.set(obj.className, obj);\n // Also store by lowercase name for case-insensitive lookup\n objectsByName.set(obj.className.toLowerCase(), obj);\n }\n\n // FIRST PASS: Handle STI field merging and tableName inheritance\n // This must happen FIRST so that item classes (like Meeting) have their tableName\n // inherited from their STI base (like Event) before collection classes (like Meetings)\n // try to read it\n for (const obj of Object.values(manifest.objects)) {\n if (!obj.extends) continue; // No parent, skip\n\n // Always walk the chain below — fields and methods now have\n // independent merge rules (#2624):\n // FIELDS merge when ANY of:\n // (a) STI is in play — shared table with parent, full chain\n // merges.\n // (b) An ancestor in the chain is a framework abstract base class\n // (SmrtHierarchical, SmrtJunction, …) — those have no table of\n // their own, so structural fields they declare (e.g.\n // `SmrtHierarchical.parentId`) must propagate into every CTI\n // subclass's manifest, otherwise WHERE-clause validation\n // rejects queries against the inherited column.\n // For plain CTI through a user-defined base with its own table,\n // field merging is skipped per-ancestor below — each class keeps\n // its own table layout.\n // METHODS merge from every ancestor except framework base classes,\n // independent of STI/CTI — a concrete decorated ancestor's public\n // methods are real inherited API regardless of table strategy.\n // There is no early exit here for a \"plain CTI through a\n // user-defined base\" class: that is exactly the case whose\n // methods previously went unmerged (the under-report half of\n // #2624).\n const usesSTI = this.isSTIClass(obj, objectsByName, manifest);\n\n logger.info(\n `[manifest-generator] Merging inherited fields for ${obj.className} from ${obj.extends}`,\n );\n\n // Build full inheritance chain (base -> child)\n const inheritanceChain: string[] = [];\n let currentClass: string | undefined = obj.extends;\n const visited = new Set<string>();\n\n while (currentClass) {\n if (visited.has(currentClass)) {\n logger.warn(\n `[manifest-generator] Circular inheritance detected for ${obj.className}`,\n );\n break;\n }\n visited.add(currentClass);\n inheritanceChain.unshift(currentClass); // Add to front (building base -> child)\n\n let parentObj = objectsByName.get(currentClass);\n\n // Skip self-reference: when a local class has the same name as its\n // imported parent (e.g., local Performer extends external Performer),\n // objectsByName returns the child itself. Skip it so we fall through\n // to the external package lookup.\n if (parentObj === obj) {\n parentObj = undefined;\n }\n\n // If parent not in current manifest, try loading from external SMRT packages\n if (\n !parentObj &&\n manifest.smrtDependencies &&\n manifest.smrtDependencies.length > 0\n ) {\n parentObj = this.loadParentFromExternalPackage(\n currentClass,\n manifest.smrtDependencies,\n objectsByName,\n );\n }\n\n if (!parentObj) break; // Parent not found anywhere (e.g., SmrtObject)\n currentClass = parentObj.extends;\n }\n\n logger.info(\n `[manifest-generator] Inheritance chain for ${obj.className}: ${inheritanceChain.join(' -> ')}`,\n );\n\n // Merge fields from ancestors (base to child).\n //\n // STI path: pull in fields from every ancestor — they all share one\n // table.\n //\n // Non-STI (framework-base) path: pull in fields ONLY from framework\n // abstract bases (SmrtHierarchical, …). User-defined ancestors with\n // their own `@smrt()` decorator have their own tables in CTI, so\n // merging their columns onto a descendant would generate the wrong\n // schema.\n const mergedFields: Record<string, FieldDefinition> = {};\n const mergedFieldOwners = new Map<string, string>();\n const mergedMethods: Record<string, MethodDefinition> = {};\n\n for (const ancestorName of inheritanceChain) {\n const ancestor = objectsByName.get(ancestorName);\n if (!ancestor) continue;\n\n const ancestorIsFrameworkBase =\n FRAMEWORK_ABSTRACT_BASE_NAMES.has(ancestorName);\n\n // FIELDS: STI subclasses share one table, so every ancestor's\n // columns are needed. CTI subclasses pull fields only from framework\n // abstract bases — a concrete `@smrt()` ancestor has its own table,\n // so merging its columns here would generate the wrong schema.\n if (usesSTI || ancestorIsFrameworkBase) {\n // Keep the oldest concrete STI declaration, but let a concrete\n // class replace a framework abstract default. For example, Event\n // refines SmrtHierarchical.parentId with its relationship target\n // and an engine-scoped physical constraint. The local child's own\n // fields are still applied after this loop.\n for (const [fieldName, fieldDef] of Object.entries(ancestor.fields)) {\n const existingOwner = mergedFieldOwners.get(fieldName);\n const replacesFrameworkDefault =\n existingOwner !== undefined &&\n FRAMEWORK_ABSTRACT_BASE_NAMES.has(\n this.simpleClassName(existingOwner),\n ) &&\n !FRAMEWORK_ABSTRACT_BASE_NAMES.has(\n this.simpleClassName(ancestorName),\n );\n if (!existingOwner || replacesFrameworkDefault) {\n mergedFields[fieldName] = this.normalizeFrameworkInheritedField(\n ancestorName,\n fieldName,\n fieldDef,\n obj.className,\n );\n mergedFieldOwners.set(fieldName, ancestorName);\n }\n }\n }\n\n // METHODS (#2624): methods are not columns and never needed the\n // STI/CTI field rule above — they inherited it only by sharing the\n // loop. Give them their own rule instead: merge from every ancestor\n // except the universal object/collection primitives in\n // FRAMEWORK_METHOD_BASE_NAMES (see its doc comment — deliberately\n // narrower than FRAMEWORK_ABSTRACT_BASE_NAMES), independent of\n // `usesSTI`. This both stops STI subclasses from absorbing\n // `SmrtObject`/`SmrtClass`/`SmrtCollection` internals (over-merge)\n // and lets CTI subclasses inherit a concrete decorated ancestor's\n // own public methods (under-merge), matching the runtime resolver's\n // `getAllMethods()` — while still letting a framework abstract\n // base's own intended API (e.g. SmrtJunction.attach/detach,\n // SmrtHierarchical.getChildren) merge in, the same way its fields\n // already do.\n //\n // Assignment is unconditional (not \"first ancestor wins\"): the\n // outer loop walks `inheritanceChain` base-to-child, so a later\n // (more-derived) ancestor's override must replace an earlier one —\n // e.g. a middle class that overrides a grandparent method. This\n // matches the runtime resolver's own `getAllMethods()`, which\n // walks the same base-to-child order and does a plain `Map.set()`\n // per ancestor for the identical reason (see its \"Child methods\n // override parent methods (no merging)\" comment). The child's own\n // methods still win over everything via the unconditional\n // \"Add child's own methods\" step below.\n if (!FRAMEWORK_METHOD_BASE_NAMES.has(ancestorName)) {\n for (const [methodName, methodDef] of Object.entries(\n ancestor.methods || {},\n )) {\n mergedMethods[methodName] = methodDef;\n }\n }\n }\n\n // Add child's own fields (override any parent fields with same name)\n for (const [fieldName, fieldDef] of Object.entries(obj.fields)) {\n mergedFields[fieldName] = fieldDef;\n }\n\n // Add child's own methods\n for (const [methodName, methodDef] of Object.entries(obj.methods || {})) {\n mergedMethods[methodName] = methodDef;\n }\n\n // Update object definition with merged fields\n obj.fields = mergedFields;\n obj.methods = mergedMethods;\n\n // Inherit tableName and collection from STI base class\n // STI subclasses share the parent's table, so they should use the same collection name\n const stiBase = this.findSTIBase(obj, objectsByName, manifest);\n if (stiBase && stiBase !== obj) {\n // Determine the STI base's table name (explicit or derived from className)\n // Note: We don't use stiBase.collection as fallback because collection uses\n // lowercase-only format (e.g., 'querytestevents') while tableName needs\n // snake_case format (e.g., 'query_test_events')\n const baseTableName =\n stiBase.decoratorConfig?.tableName ||\n this.classNameToTableName(stiBase.className);\n\n // Inherit tableName from STI base\n obj.decoratorConfig = obj.decoratorConfig || {};\n obj.decoratorConfig.tableName = baseTableName;\n logger.info(\n `[manifest-generator] ${obj.className} inherits tableName: '${baseTableName}' from ${stiBase.className}`,\n );\n\n // Inherit tableStrategy from STI base (so runtime doesn't need to walk inheritance chain)\n if (stiBase.decoratorConfig?.tableStrategy) {\n obj.decoratorConfig.tableStrategy =\n stiBase.decoratorConfig.tableStrategy;\n logger.info(\n `[manifest-generator] ${obj.className} inherits tableStrategy: '${stiBase.decoratorConfig.tableStrategy}' from ${stiBase.className}`,\n );\n }\n\n // Inherit collection name from STI base (all STI classes share one table)\n if (stiBase.collection !== obj.collection) {\n logger.info(\n `[manifest-generator] ${obj.className} inherits collection: '${stiBase.collection}' from ${stiBase.className}`,\n );\n obj.collection = stiBase.collection;\n }\n }\n\n logger.info(\n `[manifest-generator] ✅ ${obj.className} now has ${Object.keys(mergedFields).length} fields (including inherited)`,\n );\n }\n\n // SECOND PASS: Handle collection classes that should inherit from their item class\n // This must happen AFTER STI field merging so item classes have their tableName set\n for (const obj of Object.values(manifest.objects)) {\n // Check if this is a collection class (extends SmrtCollection)\n const isCollection =\n obj.extends === 'SmrtCollection' ||\n this.extendsCollection(obj, objectsByName);\n\n if (isCollection) {\n // Find the item class from _itemClass static property\n const itemClass = this.findItemClass(obj, manifest, objectsByName);\n\n if (itemClass) {\n logger.info(\n `[manifest-generator] ${obj.className} is a collection class for ${itemClass.className}`,\n );\n\n // Inherit tableName from item class (which may have inherited it from STI base)\n if (itemClass.decoratorConfig?.tableName) {\n obj.decoratorConfig = obj.decoratorConfig || {};\n obj.decoratorConfig.tableName = itemClass.decoratorConfig.tableName;\n logger.info(\n `[manifest-generator] ${obj.className} inherits tableName: '${itemClass.decoratorConfig.tableName}' from item class ${itemClass.className}`,\n );\n }\n\n // Inherit collection name from item class\n if (itemClass.collection !== obj.collection) {\n logger.info(\n `[manifest-generator] ${obj.className} inherits collection: '${itemClass.collection}' from item class ${itemClass.className} (was '${obj.collection}')`,\n );\n obj.collection = itemClass.collection;\n }\n\n // Inherit a full route opt-out (api/mcp/cli === false) from the\n // item class unless the collection class explicitly overrides it\n // itself. Decorator-only registration never gives an undecorated\n // collection its own independent route surface, so an item class\n // that fully opts out of generated routes (e.g. api: false for a\n // tenant-isolation fail-closed class such as SmrtJob, #2750) must\n // not leave its collection independently advertised in the\n // manifest path.\n //\n // Deliberately scoped to the boolean `false` opt-out only, never\n // to an object-form config (e.g. `{ include: [...] }`): those\n // configs list method names specific to the ITEM class's own\n // instance methods, which do not correspond 1:1 to the\n // COLLECTION class's methods of the same name (different\n // signatures, e.g. a bulk/collection `create` vs. a single-record\n // `create`) -- copying them verbatim previously broke unrelated\n // packages whose item class narrows its own api/cli/mcp surface\n // with an include list (e.g. @happyvertical/smrt-subscriptions's\n // TenantUsageMetric), producing a spurious \"CLI command not\n // exposed via the api\" build error on the collection.\n for (const key of ['api', 'mcp', 'cli'] as const) {\n const itemValue = itemClass.decoratorConfig?.[key];\n if (\n itemValue === false &&\n obj.decoratorConfig?.[key] === undefined\n ) {\n obj.decoratorConfig = obj.decoratorConfig || {};\n obj.decoratorConfig[key] = false;\n logger.info(\n `[manifest-generator] ${obj.className} inherits ${key}: false from item class ${itemClass.className}`,\n );\n }\n }\n }\n }\n }\n }\n\n /**\n * Check if a class extends SmrtCollection (directly or indirectly)\n *\n * @param obj - The object definition to check\n * @param objectsByName - Map of className -> objectDef for lookups\n * @returns true if this class extends SmrtCollection\n */\n private extendsCollection(\n obj: SmartObjectDefinition,\n objectsByName: Map<string, SmartObjectDefinition>,\n ): boolean {\n if (!obj.extends) return false;\n\n // Walk up inheritance chain looking for SmrtCollection\n let currentClass: string | undefined = obj.extends;\n const visited = new Set<string>();\n\n while (currentClass) {\n if (visited.has(currentClass)) break;\n visited.add(currentClass);\n\n if (currentClass === 'SmrtCollection') return true;\n\n const parentObj = objectsByName.get(currentClass);\n if (!parentObj) break;\n\n currentClass = parentObj.extends;\n }\n\n return false;\n }\n\n /**\n * Find the item class for a collection class\n *\n * Lookup priority:\n * 1. extendsTypeArg - Generic type argument from extends clause (e.g., \"Meeting\" from SmrtCollection<Meeting>)\n * 2. _itemClass static property - May be captured by AST scanner\n * 3. Name-based inference - Fallback (e.g., \"Meetings\" -> \"Meeting\")\n *\n * @param collectionObj - The collection class definition\n * @param manifest - The manifest\n * @param objectsByName - Map of className -> objectDef for lookups\n * @returns Item class definition or undefined\n */\n private findItemClass(\n collectionObj: SmartObjectDefinition,\n manifest: SmartObjectManifest,\n objectsByName: Map<string, SmartObjectDefinition>,\n ): SmartObjectDefinition | undefined {\n // PRIORITY 1: Use generic type argument from extends clause\n // This is the most reliable method: SmrtCollection<Meeting> -> \"Meeting\"\n if (collectionObj.extendsTypeArg) {\n const itemClassName = collectionObj.extendsTypeArg;\n logger.info(\n `[manifest-generator] ${collectionObj.className} has extendsTypeArg: ${itemClassName}`,\n );\n\n // Try to find the item class by name in local manifest\n const itemClass = objectsByName.get(itemClassName);\n if (itemClass) {\n logger.info(\n `[manifest-generator] Found item class ${itemClassName} in local manifest`,\n );\n return itemClass;\n }\n\n // Try loading from external packages\n if (manifest.smrtDependencies && manifest.smrtDependencies.length > 0) {\n const externalItemClass = this.loadParentFromExternalPackage(\n itemClassName,\n manifest.smrtDependencies,\n objectsByName,\n );\n if (externalItemClass) {\n logger.info(\n `[manifest-generator] Found item class ${itemClassName} in external package`,\n );\n return externalItemClass;\n }\n }\n }\n\n // PRIORITY 2: Look for _itemClass static field in the collection class\n // This is defined like: static readonly _itemClass = Meeting;\n // Note: AST scanner currently skips static properties, so this rarely works\n const itemClassField = collectionObj.fields._itemClass;\n\n if (itemClassField) {\n // Extract class name from the field's default value or metadata\n // The AST scanner might capture this as a reference\n const itemClassName = itemClassField.related || itemClassField.default;\n\n if (itemClassName && typeof itemClassName === 'string') {\n // Try to find the item class by name\n const itemClass = objectsByName.get(itemClassName);\n if (itemClass) {\n return itemClass;\n }\n\n // Try loading from external packages\n if (manifest.smrtDependencies && manifest.smrtDependencies.length > 0) {\n return this.loadParentFromExternalPackage(\n itemClassName,\n manifest.smrtDependencies,\n objectsByName,\n );\n }\n }\n }\n\n // PRIORITY 3: Fallback - Try to infer from collection class name\n // Generate candidate item class names and check if they exist\n const collectionName = collectionObj.className;\n const candidates: string[] = [];\n\n // Strip \"Collection\" suffix first if present\n let baseName = collectionName;\n if (baseName.endsWith('Collection')) {\n baseName = baseName.slice(0, -'Collection'.length);\n }\n\n // Generate singularization candidates (order matters - try most specific first)\n // 1. Exact name (e.g., \"Event\" from \"EventCollection\")\n candidates.push(baseName);\n\n // 2. Remove trailing 's' (e.g., \"Meetings\" -> \"Meeting\")\n if (baseName.endsWith('s') && baseName.length > 1) {\n candidates.push(baseName.slice(0, -1));\n }\n\n // 3. Handle 'ies' -> 'y' (e.g., \"Categories\" -> \"Category\")\n if (baseName.endsWith('ies') && baseName.length > 3) {\n candidates.push(`${baseName.slice(0, -3)}y`);\n }\n\n // 4. Handle 'es' -> '' for words ending in s/x/z/ch/sh (e.g., \"Statuses\" -> \"Status\")\n if (baseName.endsWith('es') && baseName.length > 2) {\n candidates.push(baseName.slice(0, -2));\n }\n\n // Try each candidate against local classes first, then external packages\n // Skip candidates that match the collection class itself\n for (const candidate of candidates) {\n if (candidate === collectionObj.className) continue; // Don't match self\n const itemClass = objectsByName.get(candidate);\n if (itemClass) {\n return itemClass;\n }\n }\n\n // Try loading from external packages\n if (manifest.smrtDependencies && manifest.smrtDependencies.length > 0) {\n for (const candidate of candidates) {\n if (candidate === collectionObj.className) continue; // Don't match self\n const itemClass = this.loadParentFromExternalPackage(\n candidate,\n manifest.smrtDependencies,\n objectsByName,\n );\n if (itemClass) {\n return itemClass;\n }\n }\n }\n\n return undefined;\n }\n\n /**\n * Check if a class uses STI (either explicitly or inherited from an ancestor)\n *\n * Walks up the inheritance chain to find if any ancestor has tableStrategy: 'sti'.\n * If found, all descendants inherit STI and should have fields merged.\n * Also checks external SMRT packages for parent class definitions.\n *\n * @param obj - The object definition to check\n * @param objectsByName - Map of className -> objectDef for lookups\n * @param manifest - The manifest (for accessing smrtDependencies)\n * @returns true if this class uses STI (directly or inherited)\n */\n private isSTIClass(\n obj: SmartObjectDefinition,\n objectsByName: Map<string, SmartObjectDefinition>,\n manifest: SmartObjectManifest,\n ): boolean {\n // Check if explicitly marked as STI\n if (obj.decoratorConfig?.tableStrategy === 'sti') {\n return true;\n }\n\n // Walk up the inheritance chain looking for STI base\n let currentClass: string | undefined = obj.extends;\n const visited = new Set<string>();\n\n while (currentClass) {\n if (visited.has(currentClass)) {\n break; // Circular inheritance, stop\n }\n visited.add(currentClass);\n\n let parentDef = objectsByName.get(currentClass);\n\n // Skip self-reference (local class with same name as imported parent)\n if (parentDef === obj) {\n parentDef = undefined;\n }\n\n // If parent not in current manifest, try loading from external SMRT packages\n if (\n !parentDef &&\n manifest.smrtDependencies &&\n manifest.smrtDependencies.length > 0\n ) {\n parentDef = this.loadParentFromExternalPackage(\n currentClass,\n manifest.smrtDependencies,\n objectsByName,\n );\n }\n\n if (!parentDef) break; // Parent not found anywhere\n\n // Check if this ancestor uses STI\n if (parentDef.decoratorConfig?.tableStrategy === 'sti') {\n return true; // Found STI ancestor\n }\n\n currentClass = parentDef.extends;\n }\n\n return false; // No STI in hierarchy\n }\n\n /**\n * Find the STI base class for a given object\n *\n * Walks up the inheritance chain to find the first ancestor that defines\n * tableStrategy: 'sti'. This is the class that owns the shared table.\n *\n * @param obj - The object definition to find the STI base for\n * @param objectsByName - Map of className -> objectDef for lookups\n * @param manifest - The manifest (for accessing smrtDependencies)\n * @returns The STI base class definition, or the object itself if it's the base\n */\n private findSTIBase(\n obj: SmartObjectDefinition,\n objectsByName: Map<string, SmartObjectDefinition>,\n manifest: SmartObjectManifest,\n ): SmartObjectDefinition | undefined {\n // Track the oldest STI class found as we walk up\n let stiBase: SmartObjectDefinition | undefined;\n\n // If this object explicitly defines STI, it's a candidate (but ancestors may also be STI)\n if (obj.decoratorConfig?.tableStrategy === 'sti') {\n stiBase = obj;\n }\n\n // Walk up the inheritance chain looking for the oldest STI base\n let currentClass: string | undefined = obj.extends;\n const visited = new Set<string>();\n\n while (currentClass) {\n if (visited.has(currentClass)) {\n break; // Circular inheritance, stop\n }\n visited.add(currentClass);\n\n let parentDef = objectsByName.get(currentClass);\n\n // Skip self-reference (local class with same name as imported parent)\n if (parentDef === obj) {\n parentDef = undefined;\n }\n\n // If parent not in current manifest, try loading from external SMRT packages\n if (\n !parentDef &&\n manifest.smrtDependencies &&\n manifest.smrtDependencies.length > 0\n ) {\n parentDef = this.loadParentFromExternalPackage(\n currentClass,\n manifest.smrtDependencies,\n objectsByName,\n );\n }\n\n if (!parentDef) break; // Parent not found anywhere\n\n // Check if this ancestor defines STI - if so, it becomes the new candidate base\n // (we keep walking to find the oldest/root STI class)\n if (parentDef.decoratorConfig?.tableStrategy === 'sti') {\n stiBase = parentDef;\n }\n\n currentClass = parentDef.extends;\n }\n\n return stiBase; // Return the oldest STI ancestor found (or undefined if none)\n }\n\n /**\n * Load parent class definition from external SMRT packages\n *\n * When a child class extends a parent from an external package (e.g., praeco's Council extends\n * smrt-profiles' Organization), this method loads the parent's manifest and extracts the\n * parent's field definitions.\n *\n * @param parentClassName - Name of the parent class to find\n * @param smrtDependencies - List of external SMRT packages to search\n * @param objectsByName - Map to cache loaded external objects\n * @returns Parent object definition if found, undefined otherwise\n */\n private loadParentFromExternalPackage(\n parentClassName: string,\n smrtDependencies: string[],\n objectsByName: Map<string, SmartObjectDefinition>,\n ): SmartObjectDefinition | undefined {\n // Try each external SMRT dependency\n for (const packageName of smrtDependencies) {\n const externalManifest = loadExternalManifestSync(packageName);\n\n if (!externalManifest) {\n continue;\n }\n\n // Use lookupInManifest for O(1) lookup via cached className index\n // Handles both qualified names and simple class names\n const parentObj = lookupInManifest(externalManifest, parentClassName);\n\n if (parentObj) {\n // Cache the loaded parent object for future lookups\n objectsByName.set(parentObj.className, parentObj);\n objectsByName.set(parentObj.className.toLowerCase(), parentObj);\n\n return parentObj;\n }\n }\n\n return undefined;\n }\n\n /**\n * Determine import path from package.json exports\n *\n * Tries the following strategies in order:\n * 1. package.json exports[\"./objects\"] - Specific objects export\n * 2. package.json exports[\".\"] - Main export\n * 3. package.json main - Main field\n * 4. Fallback to package name\n */\n /**\n * Determine the specifier consumers should import an object from.\n *\n * `filePath` was accepted (and ignored — the parameter was named\n * `_filePath`) since before this fix, so every object always resolved to\n * the bare package name regardless of where it actually lived. That is\n * wrong for an object scanned from a file only a non-root `exports`\n * subpath serves (e.g. `./server`): the manifest advertised the object as\n * importable from the package root, but the root bundle never exports it,\n * so a consumer dynamically importing by manifest metadata (or generating\n * `.smrt/register.js`, `consumer-plugin/index.ts`'s own\n * `determineImportPath`) silently failed to find it. That is smrt#2845 —\n * `DataSurfaceActionIdempotencyState` in `@happyvertical/smrt-agents` lives\n * under `src/server/` (served only by the `./server` export), but the\n * manifest pointed consumers at the bare `@happyvertical/smrt-agents`\n * specifier.\n *\n * Strategy: match `filePath` against the package's `exports` subpaths —\n * `src/<segment>/...` or `src/<segment>.ts` maps to the `./<segment>`\n * export key — and prefer the longest matching segment. Falls back to the\n * legacy behavior (bare package name, with the `./objects` special case)\n * when the file does not match any subpath, which covers objects reachable\n * from the root `.` entry point.\n */\n private determineImportPath(\n packageJson: PackageJsonLike,\n filePath?: string,\n ): string {\n // Only invoked once a package name is known (guarded at the call site),\n // so `name` is always present here.\n const packageName = packageJson.name as string;\n\n if (packageJson.exports && typeof packageJson.exports === 'object') {\n const subpathSegment = this.matchExportsSubpath(\n packageJson.exports,\n filePath,\n );\n if (subpathSegment) {\n return `${packageName}/${subpathSegment}`;\n }\n\n // Legacy special case, kept for packages whose `./objects` export\n // predates file-path-based matching and whose objects' `filePath`\n // does not follow the `src/objects/...` convention above.\n if (packageJson.exports['./objects']) {\n return `${packageName}/objects`;\n }\n }\n\n // Strategy 2/3: main field or bare fallback — both resolve to the\n // package root, which is where an unmatched object is assumed to live.\n return packageName;\n }\n\n /**\n * Match a scanned object's `filePath` against a package's `exports` map,\n * returning the longest matching non-root subpath segment (e.g. `\"server\"`\n * for `./server`), or `undefined` when the file does not correspond to any\n * declared subpath (the object is assumed reachable from the root `.`\n * entry point instead).\n */\n private matchExportsSubpath(\n exportsMap: Record<string, unknown>,\n filePath?: string,\n ): string | undefined {\n if (!filePath) return undefined;\n\n const normalized = filePath.replace(/\\\\/g, '/');\n const srcMarker = 'src/';\n const srcIndex = normalized.lastIndexOf(srcMarker);\n if (srcIndex === -1) return undefined;\n const relativeToSrc = normalized.slice(srcIndex + srcMarker.length);\n\n // Path components with any source-file extension stripped from the last\n // one, so `lib/models/Category.ts` and `server.js` both compare as plain\n // component lists (`['lib','models','Category']`, `['server']`).\n const pathParts = relativeToSrc.split('/');\n const lastIndex = pathParts.length - 1;\n pathParts[lastIndex] = pathParts[lastIndex].replace(\n /\\.(ts|tsx|js|jsx|mjs|cjs)$/,\n '',\n );\n\n const segments = Object.keys(exportsMap)\n .filter(\n (key) =>\n key !== '.' &&\n key !== './package.json' &&\n !key.includes('*') &&\n // Exclude subpaths that resolve to a non-JS asset (e.g. the\n // `./manifest`/`./manifest.json` convention pointing at\n // `dist/manifest.json`). No @smrt object's source file can ever\n // legitimately resolve there, so this only guards against a\n // coincidental `src/manifest/...` path being misattributed to it.\n !targetsJsonAsset(exportsMap[key]),\n )\n .map((key) => key.replace(/^\\.\\//, ''))\n .filter((segment) => segment.length > 0)\n // Longest first so a nested segment (rare) wins over a shorter prefix.\n .sort((a, b) => b.length - a.length);\n\n return segments.find((segment) => {\n const segmentParts = segment.split('/');\n // Match the segment's components as a contiguous run anywhere in the\n // file's path — not just a root-level prefix. Handles both a direct\n // subpath directory (`server/x.ts` for `./server`) and a re-export\n // barrel whose real source lives deeper than its export key implies\n // (`@happyvertical/smrt-products`: `./models` -> `src/models.ts` ->\n // `export * from './lib/models/index'`, with the actual `@smrt()`\n // classes scanned from `src/lib/models/*.ts` — `relativeToSrc` is\n // `lib/models/Category.ts`, which contains `models` as a component,\n // just not at index 0).\n for (\n let start = 0;\n start <= pathParts.length - segmentParts.length;\n start++\n ) {\n if (\n segmentParts.every(\n (part, offset) => pathParts[start + offset] === part,\n )\n ) {\n return true;\n }\n }\n return false;\n });\n }\n\n /**\n * Generate TypeScript interfaces from manifest\n */\n generateTypeDefinitions(manifest: SmartObjectManifest): string {\n const interfaces: string[] = [];\n\n // Manifest key order follows scan/discovery order, which is not stable\n // across runs (#2749): the vite-plugin's server-mode `@smrt/types`\n // resolution calls this method directly, so sort deterministically\n // before emitting for the same reason as the prebuild/client-mode paths.\n const sortedEntries = Object.entries(manifest.objects).sort(\n ([leftKey, left], [rightKey, right]) =>\n compareText(\n left.qualifiedName || leftKey,\n right.qualifiedName || rightKey,\n ) || compareText(leftKey, rightKey),\n );\n for (const [_name, obj] of sortedEntries) {\n interfaces.push(this.generateInterface(obj));\n }\n\n return interfaces.join('\\n\\n');\n }\n\n /**\n * Generate a single interface definition\n */\n private generateInterface(obj: SmartObjectDefinition): string {\n const fields = Object.entries(obj.fields)\n .map(([name, field]) => {\n const optional = !field.required ? '?' : '';\n const type = this.mapFieldTypeToTS(field.type);\n return ` ${name}${optional}: ${type};`;\n })\n .join('\\n');\n\n return `export interface ${obj.className}Data {\n${fields}\n}`;\n }\n\n /**\n * Map field types to TypeScript types\n */\n private mapFieldTypeToTS(fieldType: string): string {\n switch (fieldType) {\n case 'text':\n return 'string';\n case 'decimal':\n return 'number';\n case 'integer':\n return 'number';\n case 'boolean':\n return 'boolean';\n case 'datetime':\n return 'Date | string';\n case 'json':\n return 'any';\n case 'foreignKey':\n return 'string';\n case 'crossPackageRef':\n return 'string';\n default:\n return 'any';\n }\n }\n\n /**\n * Generate simple endpoint list for testing/documentation\n */\n generateRestEndpoints(manifest: SmartObjectManifest): string {\n const endpoints: string[] = [];\n\n for (const [_name, obj] of Object.entries(manifest.objects)) {\n const apiConfig = obj.decoratorConfig.api;\n if (apiConfig !== false) {\n endpoints.push(...this.getSimpleEndpoints(obj, manifest));\n }\n }\n\n return endpoints.join('\\n');\n }\n\n /**\n * Generate REST endpoint code implementations\n */\n generateRestEndpointCode(manifest: SmartObjectManifest): string {\n const endpoints: string[] = [];\n\n for (const [_name, obj] of Object.entries(manifest.objects)) {\n const apiConfig = obj.decoratorConfig.api;\n if (apiConfig !== false) {\n endpoints.push(this.generateRestEndpoint(obj));\n }\n }\n\n return endpoints.join('\\n\\n');\n }\n\n /**\n * Get simple endpoint strings for an object\n */\n private getApiRouteMetadata(\n obj: SmartObjectDefinition,\n actionName: string,\n actionDef: MethodDefinition | { isStatic?: boolean },\n ): {\n scope: 'item' | 'collection';\n method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';\n path: string;\n } {\n const config =\n obj.decoratorConfig.api && typeof obj.decoratorConfig.api === 'object'\n ? obj.decoratorConfig.api\n : undefined;\n // `@method({ httpMethod, path })` wins field by field over the class-level\n // `api.routes[action]` entry, the same merge `resolveApiActionRouteConfig`\n // and the knowledge artifact perform. Reading `routes` alone printed the\n // PRE-migration verb and path for a class that had moved to the decorator\n // (#2686).\n const effective = resolveEffectiveActionMetadata({\n actionName,\n method: actionDef,\n apiConfig: config,\n });\n const normalizedPath = (effective.path || actionName)\n .split('/')\n .map((segment) => segment.trim())\n .filter(Boolean)\n .join('/');\n const isCollectionClass =\n obj.extends === 'SmrtCollection' || !!obj.extendsTypeArg;\n\n const defaultScope =\n isCollectionClass || actionDef.isStatic ? 'collection' : 'item';\n\n return {\n scope: resolveCustomActionMetadata({\n actionName,\n method: actionDef,\n apiConfig: config,\n defaultScope,\n }).scope,\n method: effective.httpMethod ?? 'POST',\n path: normalizedPath || actionName,\n };\n }\n\n private getSimpleEndpoints(\n obj: SmartObjectDefinition,\n manifest?: SmartObjectManifest,\n ): string[] {\n const { collection } = obj;\n const config = obj.decoratorConfig.api;\n const exclude = (typeof config === 'object' && config?.exclude) || [];\n const include =\n (typeof config === 'object' && config?.include) || undefined;\n const isCollectionClass =\n obj.extends === 'SmrtCollection' || !!obj.extendsTypeArg;\n const isModelClassName = createManifestClassNamePredicate(manifest);\n\n const endpoints: string[] = [];\n\n // Determine which operations to include\n const shouldInclude = (op: string) => {\n if (include && !include.includes(op)) return false;\n if (exclude.includes(op)) return false;\n return true;\n };\n\n if (!isCollectionClass) {\n if (shouldInclude('list')) {\n endpoints.push(`GET /${collection}`);\n }\n if (shouldInclude('create')) {\n endpoints.push(`POST /${collection}`);\n }\n if (shouldInclude('get')) {\n endpoints.push(`GET /${collection}/:id`);\n }\n if (shouldInclude('update')) {\n endpoints.push(`PUT /${collection}/:id`);\n }\n if (shouldInclude('delete')) {\n endpoints.push(`DELETE /${collection}/:id`);\n }\n }\n\n // Custom actions read the ONE shared exposure resolver rather than a local\n // copy of the include/exclude rule. This listing is a published virtual\n // module (`@happyvertical/smrt-virt-routes`), so a stale rule here\n // advertises operations whose routes the emitters never wrote -- exactly\n // the consumer disagreement #2686 exists to close.\n for (const [actionName, actionDef] of Object.entries(obj.methods)) {\n if (\n !resolveApiMethodExposure({\n actionName,\n method: actionDef,\n apiConfig: config,\n isCollectionClass,\n ...(isModelClassName ? { isModelClassName } : {}),\n }).exposed\n ) {\n continue;\n }\n\n const route = this.getApiRouteMetadata(obj, actionName, actionDef);\n const suffix = route.scope === 'collection' ? '' : '/:id';\n endpoints.push(`${route.method} /${collection}${suffix}/${route.path}`);\n }\n\n return endpoints;\n }\n\n /**\n * Generate a single REST endpoint\n */\n private generateRestEndpoint(obj: SmartObjectDefinition): string {\n const { collection, className } = obj;\n const config = obj.decoratorConfig.api;\n const exclude = (typeof config === 'object' && config?.exclude) || [];\n const include =\n (typeof config === 'object' && config?.include) || undefined;\n\n const operations = [];\n\n // Determine which operations to include\n const shouldInclude = (op: string) => {\n if (include && !include.includes(op)) return false;\n if (exclude.includes(op)) return false;\n return true;\n };\n\n if (shouldInclude('list')) {\n operations.push(` // GET /${collection} - List ${collection}`);\n operations.push(` app.get('/${collection}', async (req: Request) => {`);\n operations.push(\n ` const collection = await get${className}Collection();`,\n );\n operations.push(' const items = await collection.list(req.query);');\n operations.push(' return Response.json(items);');\n operations.push(' });');\n }\n\n if (shouldInclude('get')) {\n operations.push(` // GET /${collection}/:id - Get ${className}`);\n operations.push(\n ` app.get('/${collection}/:id', async (req: Request) => {`,\n );\n operations.push(\n ` const collection = await get${className}Collection();`,\n );\n operations.push(' const item = await collection.get(req.params.id);');\n operations.push(\n ` if (!item) return new Response('Not found', { status: 404 });`,\n );\n operations.push(' return Response.json(item);');\n operations.push(' });');\n }\n\n if (shouldInclude('create')) {\n operations.push(` // POST /${collection} - Create ${className}`);\n operations.push(` app.post('/${collection}', async (req: Request) => {`);\n operations.push(\n ` const collection = await get${className}Collection();`,\n );\n operations.push(' const data = await req.json();');\n operations.push(' const item = await collection.create(data);');\n operations.push(' return Response.json(item, { status: 201 });');\n operations.push(' });');\n }\n\n if (shouldInclude('update')) {\n operations.push(` // PUT /${collection}/:id - Update ${className}`);\n operations.push(\n ` app.put('/${collection}/:id', async (req: Request) => {`,\n );\n operations.push(\n ` const collection = await get${className}Collection();`,\n );\n operations.push(' const data = await req.json();');\n operations.push(\n ' const item = await collection.update(req.params.id, data);',\n );\n operations.push(\n ` if (!item) return new Response('Not found', { status: 404 });`,\n );\n operations.push(' return Response.json(item);');\n operations.push(' });');\n }\n\n if (shouldInclude('delete')) {\n operations.push(` // DELETE /${collection}/:id - Delete ${className}`);\n operations.push(\n ` app.delete('/${collection}/:id', async (req: Request) => {`,\n );\n operations.push(\n ` const collection = await get${className}Collection();`,\n );\n operations.push(\n ' const success = await collection.delete(req.params.id);',\n );\n operations.push(\n ` if (!success) return new Response('Not found', { status: 404 });`,\n );\n operations.push(` return new Response('', { status: 204 });`);\n operations.push(' });');\n }\n\n return `// ${className} endpoints\\n${operations.join('\\n')}`;\n }\n\n /**\n * Generate simple MCP tool names for testing/documentation\n */\n generateMCPTools(manifest: SmartObjectManifest): string {\n const tools: string[] = [];\n\n for (const obj of this.selectMCPToolOwners(manifest)) {\n tools.push(...this.getSimpleMCPToolNames(obj));\n }\n\n return tools.join('\\n');\n }\n\n /**\n * Choose exactly one canonical MCP owner per `collection`.\n *\n * MCP tool names are keyed on `collection`, but the framework's normal shape\n * puts a model class and its `FooCollection` access class in the manifest\n * under the SAME collection. Emitting both produces duplicate tool names with\n * differing create/update schemas, and an MCP client that indexes tools by\n * name then resolves an arbitrary one (#2631 review).\n *\n * Owners are ranked, in order:\n *\n * 1. The model class beats the collection-access class. `create`/`update`\n * input schemas derive from `obj.fields`, and the row shape lives on the\n * model, not on the access class.\n * 2. The shallowest class in the collection's own inheritance tree wins. An\n * STI family shares one `collection`, and the base defines the shared row\n * contract; a leaf subclass would narrow the emitted schema to one variant\n * of a table the tool addresses as a whole.\n * 3. Remaining ties break lexically on the qualified name, so the emitted\n * surface is deterministic across generation passes.\n */\n private selectMCPToolOwners(\n manifest: SmartObjectManifest,\n ): SmartObjectDefinition[] {\n const candidatesByCollection = new Map<string, SmartObjectDefinition[]>();\n\n for (const obj of Object.values(manifest.objects)) {\n if (obj.decoratorConfig.mcp === false) continue;\n const bucket = candidatesByCollection.get(obj.collection);\n if (bucket) bucket.push(obj);\n else candidatesByCollection.set(obj.collection, [obj]);\n }\n\n return [...candidatesByCollection.entries()]\n .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))\n .map(([, candidates]) => {\n const depths = this.inheritanceDepthsWithin(candidates);\n let owner = candidates[0];\n for (const candidate of candidates.slice(1)) {\n if (this.preferMCPToolOwner(candidate, owner, depths)) {\n owner = candidate;\n }\n }\n return owner;\n });\n }\n\n /** Stable identity for an MCP owner candidate. */\n private mcpOwnerKey(obj: SmartObjectDefinition): string {\n return obj.qualifiedName || obj.className;\n }\n\n /**\n * Depth of each candidate inside the candidate set's OWN inheritance tree,\n * keyed by {@link mcpOwnerKey}. A candidate with no candidate ancestor is a\n * root at depth 0. Ancestors outside the set (framework bases, classes in\n * other collections) do not add depth: only the shared-collection family\n * decides which member is canonical.\n *\n * Parents resolve on `extendsQualified` first. Two packages may legally\n * contribute same-simple-name classes to one collection, so a simple-name\n * match is used only when it is unambiguous within the candidate set —\n * otherwise the walk stops rather than linking unrelated classes.\n */\n private inheritanceDepthsWithin(\n candidates: SmartObjectDefinition[],\n ): Map<string, number> {\n const byQualified = new Map<string, SmartObjectDefinition>();\n const bySimpleName = new Map<string, SmartObjectDefinition | null>();\n for (const candidate of candidates) {\n byQualified.set(this.mcpOwnerKey(candidate), candidate);\n const simple = this.simpleClassName(candidate.className);\n // `null` marks an ambiguous simple name; never resolve through it.\n bySimpleName.set(simple, bySimpleName.has(simple) ? null : candidate);\n }\n\n const resolveParent = (\n obj: SmartObjectDefinition,\n ): SmartObjectDefinition | undefined => {\n if (obj.extendsQualified) return byQualified.get(obj.extendsQualified);\n if (!obj.extends) return undefined;\n return bySimpleName.get(this.simpleClassName(obj.extends)) ?? undefined;\n };\n\n const depths = new Map<string, number>();\n for (const candidate of candidates) {\n const key = this.mcpOwnerKey(candidate);\n let depth = 0;\n let current: SmartObjectDefinition | undefined = candidate;\n const visited = new Set<string>([key]);\n while (current) {\n const parent: SmartObjectDefinition | undefined =\n resolveParent(current);\n if (!parent) break;\n const parentKey = this.mcpOwnerKey(parent);\n // Circular or self-referential extends: stop rather than loop.\n if (visited.has(parentKey)) break;\n visited.add(parentKey);\n depth += 1;\n current = parent;\n }\n depths.set(key, depth);\n }\n return depths;\n }\n\n /** True when `candidate` is the better canonical MCP owner than `current`. */\n private preferMCPToolOwner(\n candidate: SmartObjectDefinition,\n current: SmartObjectDefinition,\n depths: Map<string, number>,\n ): boolean {\n const candidateIsCollection = this.isCollectionAccessClass(candidate);\n const currentIsCollection = this.isCollectionAccessClass(current);\n if (candidateIsCollection !== currentIsCollection) {\n return !candidateIsCollection;\n }\n\n const candidateKey = this.mcpOwnerKey(candidate);\n const currentKey = this.mcpOwnerKey(current);\n\n const candidateDepth = depths.get(candidateKey) ?? 0;\n const currentDepth = depths.get(currentKey) ?? 0;\n if (candidateDepth !== currentDepth) {\n return candidateDepth < currentDepth;\n }\n\n return candidateKey < currentKey;\n }\n\n /**\n * Collection-access class detection, matching the convention already used by\n * `generateRestRoutes` (direct base / generic type argument) plus the\n * `FooCollection` naming fallback this generator uses elsewhere, so a deeper\n * subclass that carries no type argument of its own is still recognised.\n */\n private isCollectionAccessClass(obj: SmartObjectDefinition): boolean {\n return (\n obj.extends === 'SmrtCollection' ||\n !!obj.extendsTypeArg ||\n obj.className.endsWith('Collection')\n );\n }\n\n /**\n * Generate MCP tool JSON definitions\n */\n generateMCPToolsCode(manifest: SmartObjectManifest): string {\n const tools: string[] = [];\n\n for (const obj of this.selectMCPToolOwners(manifest)) {\n const code = this.generateMCPTool(obj);\n // An object whose every operation is excluded contributes nothing;\n // pushing '' would emit a hole in the array literal (#2631).\n if (code) tools.push(code);\n }\n\n return tools.length > 0 ? `[\\n${tools.join(',\\n')}\\n]` : '[]';\n }\n\n /**\n * Get simple MCP tool names for an object\n */\n private getSimpleMCPToolNames(obj: SmartObjectDefinition): string[] {\n const { collection } = obj;\n const config = obj.decoratorConfig.mcp;\n const exclude = (typeof config === 'object' && config?.exclude) || [];\n const include =\n (typeof config === 'object' && config?.include) || undefined;\n\n const tools: string[] = [];\n\n const shouldInclude = (op: string) => {\n if (include && !include.includes(op)) return false;\n if (exclude.includes(op)) return false;\n return true;\n };\n\n if (shouldInclude('list')) {\n tools.push(`list_${collection}`);\n }\n if (shouldInclude('get')) {\n tools.push(`get_${collection}`);\n }\n if (shouldInclude('create')) {\n tools.push(`create_${collection}`);\n }\n if (shouldInclude('update')) {\n tools.push(`update_${collection}`);\n }\n if (shouldInclude('delete')) {\n tools.push(`delete_${collection}`);\n }\n\n return tools;\n }\n\n /**\n * Generate a single MCP tool\n */\n private generateMCPTool(obj: SmartObjectDefinition): string {\n const { collection } = obj;\n const config = obj.decoratorConfig.mcp;\n const exclude = (typeof config === 'object' && config?.exclude) || [];\n const include =\n (typeof config === 'object' && config?.include) || undefined;\n\n const tools = [];\n\n const shouldInclude = (op: string) => {\n if (include && !include.includes(op)) return false;\n if (exclude.includes(op)) return false;\n return true;\n };\n\n if (shouldInclude('list')) {\n tools.push(` {\n name: \"list_${collection}\",\n description: \"List ${collection}\",\n inputSchema: {\n type: \"object\",\n properties: {\n limit: { type: \"number\" },\n offset: { type: \"number\" },\n where: { type: \"object\" }\n }\n }\n }`);\n }\n\n if (shouldInclude('get')) {\n tools.push(` {\n name: \"get_${collection}\",\n description: \"Get a ${collection} entry by ID\",\n inputSchema: {\n type: \"object\",\n properties: {\n id: { type: \"string\", description: \"The ${collection} entry ID\" }\n },\n required: [\"id\"]\n }\n }`);\n }\n\n const schemaProperties = JSON.stringify(\n this.generateSchemaProperties(obj.fields),\n null,\n 6,\n );\n\n if (shouldInclude('create')) {\n const requiredFields = Object.entries(obj.fields)\n .filter(([_, field]) => field.required)\n .map(([fieldName]) => fieldName);\n\n tools.push(` {\n name: \"create_${collection}\",\n description: \"Create a new ${collection} entry\",\n inputSchema: {\n type: \"object\",\n properties: ${schemaProperties},\n required: ${JSON.stringify(requiredFields)}\n }\n }`);\n }\n\n if (shouldInclude('update')) {\n tools.push(` {\n name: \"update_${collection}\",\n description: \"Update an existing ${collection} entry\",\n inputSchema: {\n type: \"object\",\n properties: {\n id: { type: \"string\", description: \"The ${collection} entry ID\" },\n data: {\n type: \"object\",\n description: \"Fields to update on the ${collection} entry\",\n properties: ${schemaProperties}\n }\n },\n required: [\"id\", \"data\"]\n }\n }`);\n }\n\n if (shouldInclude('delete')) {\n tools.push(` {\n name: \"delete_${collection}\",\n description: \"Delete a ${collection} entry by ID\",\n inputSchema: {\n type: \"object\",\n properties: {\n id: { type: \"string\", description: \"The ${collection} entry ID\" }\n },\n required: [\"id\"]\n }\n }`);\n }\n\n return tools.join(',\\n');\n }\n\n /**\n * Generate JSON schema properties for fields\n */\n private generateSchemaProperties(\n fields: Record<string, FieldDefinition>,\n ): Record<string, JsonSchemaProperty> {\n const properties: Record<string, JsonSchemaProperty> = {};\n\n for (const [name, field] of Object.entries(fields)) {\n properties[name] = {\n type: this.mapFieldTypeToJSON(field.type),\n description: field.description || `The ${name} field`,\n };\n\n if (field.min !== undefined) properties[name].minimum = field.min;\n if (field.max !== undefined) properties[name].maximum = field.max;\n if (field.minLength !== undefined)\n properties[name].minLength = field.minLength;\n if (field.maxLength !== undefined)\n properties[name].maxLength = field.maxLength;\n }\n\n return properties;\n }\n\n /**\n * Map field types to JSON Schema types\n */\n private mapFieldTypeToJSON(fieldType: string): string {\n switch (fieldType) {\n case 'text':\n return 'string';\n case 'decimal':\n return 'number';\n case 'integer':\n return 'integer';\n case 'boolean':\n return 'boolean';\n case 'datetime':\n return 'string';\n case 'json':\n return 'object';\n case 'foreignKey':\n return 'string';\n case 'crossPackageRef':\n return 'string';\n default:\n return 'string';\n }\n }\n\n /**\n * Generate agent manifests for Agent subclasses (fifth pass).\n *\n * For any SmartObjectDefinition with `agent` in its decoratorConfig,\n * auto-generates:\n * - Permissions from uiSlots (manage:*) and CLI/MCP methods (execute:*)\n * - Features from uiSlots and exposed methods\n * - Menu items from uiSlots\n * - Component declarations from package.json exports\n *\n * @param manifest - The manifest to process in-place\n * @param packageName - Package name for component export paths\n * @param packageJson - Full package.json for component discovery\n */\n generateAgentManifests(\n manifest: SmartObjectManifest,\n packageName?: string,\n packageJson?: PackageJsonLike,\n ): void {\n for (const obj of Object.values(manifest.objects)) {\n if (!obj.decoratorConfig.agent) continue;\n\n const agentConfig = obj.decoratorConfig.agent;\n const slug = obj.className.toLowerCase();\n // staticProperties is an untyped AST capture; assert the shape the\n // scanner records for `static uiSlots` on Agent subclasses.\n const uiSlots: Record<string, AgentUISlotManifest> =\n (obj.staticProperties?.uiSlots as\n | Record<string, AgentUISlotManifest>\n | undefined) ?? {};\n\n // Derive permissions\n const permissions: AgentPermission[] = [];\n\n // From uiSlots: manage:<slotId>\n for (const [slotId, slot] of Object.entries(uiSlots)) {\n permissions.push({\n id: `manage:${slotId}`,\n label: `Manage ${(slot as AgentUISlotManifest).label || slotId}`,\n category: 'slot',\n defaultGranted: true,\n });\n }\n\n // From CLI/MCP methods: execute:<methodName>\n const exposedMethods = this.getExposedMethods(obj);\n for (const methodName of exposedMethods) {\n permissions.push({\n id: `execute:${methodName}`,\n label: `Execute ${methodName}`,\n category: 'method',\n defaultGranted: true,\n });\n }\n\n // Derive features\n const features: AgentFeature[] = [];\n\n for (const [slotId, slot] of Object.entries(uiSlots)) {\n const typedSlot = slot as AgentUISlotManifest;\n features.push({\n id: slotId,\n label: typedSlot.label || slotId,\n description: typedSlot.description,\n type: 'slot',\n });\n }\n\n for (const methodName of exposedMethods) {\n features.push({\n id: methodName,\n label: methodName,\n type: 'method',\n });\n }\n\n // Derive menu items from uiSlots (sorted by order)\n const menuItems: AgentMenuItem[] = Object.entries(uiSlots)\n .map(([slotId, slot]) => {\n const typedSlot = slot as AgentUISlotManifest;\n return {\n id: slotId,\n label: typedSlot.label || slotId,\n icon: typedSlot.icon,\n order: typedSlot.order ?? 999,\n path: `/agents/${slug}/${slotId}`,\n requiredPermission: `manage:${slotId}`,\n };\n })\n .sort((a, b) => a.order - b.order);\n\n // Derive component declarations from package.json exports\n const components: AgentComponentDeclaration[] = [];\n if (packageName && packageJson?.exports) {\n for (const [exportKey, exportValue] of Object.entries(\n packageJson.exports,\n )) {\n // Match patterns like './admin', './town', etc.\n if (exportKey === '.' || exportKey === './manifest') continue;\n\n // Check if this export has a svelte condition (component export)\n const hasSvelteCondition = this.hasSvelteExport(exportValue);\n if (hasSvelteCondition) {\n const type = exportKey.replace('./', '');\n components.push({\n exportPath: `${packageName}/${type}`,\n type,\n });\n }\n }\n }\n\n // Capture adminRoutes from static property (same pattern as uiSlots)\n const adminRoutes: AgentAdminRouteManifest[] =\n (obj.staticProperties?.adminRoutes as\n | AgentAdminRouteManifest[]\n | undefined) ?? [];\n\n // Capture signalSubscriptions from static property\n const signalSubscriptions: string[] =\n (obj.staticProperties?.signalSubscriptions as string[] | undefined) ??\n [];\n\n const agentManifest: AgentManifest = {\n name: obj.className,\n slug,\n icon: agentConfig.icon,\n tier: agentConfig.tier || 'free',\n description: agentConfig.description,\n uiSlots,\n ...(adminRoutes.length > 0 ? { adminRoutes } : {}),\n ...(signalSubscriptions.length > 0 ? { signalSubscriptions } : {}),\n permissions,\n features,\n menuItems,\n components,\n };\n\n obj.agent = agentManifest;\n\n logger.info(\n `[manifest-generator] Generated agent manifest for ${obj.className}: ` +\n `${permissions.length} permissions, ${features.length} features, ` +\n `${menuItems.length} menu items, ${components.length} components`,\n );\n }\n }\n\n /**\n * Get deduplicated list of method names exposed via CLI and MCP config\n */\n private getExposedMethods(obj: SmartObjectDefinition): string[] {\n const methods = new Set<string>();\n\n const cliConfig = obj.decoratorConfig.cli;\n if (cliConfig && typeof cliConfig === 'object' && cliConfig.include) {\n for (const m of cliConfig.include) {\n methods.add(m);\n }\n }\n\n const mcpConfig = obj.decoratorConfig.mcp;\n if (mcpConfig && typeof mcpConfig === 'object' && mcpConfig.include) {\n for (const m of mcpConfig.include) {\n methods.add(m);\n }\n }\n\n return Array.from(methods);\n }\n\n /**\n * Check if an export value has a svelte condition (indicating a component export)\n */\n private hasSvelteExport(exportValue: unknown): boolean {\n if (!exportValue || typeof exportValue !== 'object') return false;\n\n // Check for { svelte: ... } condition\n if ('svelte' in exportValue) return true;\n\n // Check nested conditions like { import: { svelte: ... } }\n for (const val of Object.values(exportValue)) {\n if (val && typeof val === 'object' && 'svelte' in (val as object)) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * Save manifest to file\n */\n saveManifest(manifest: SmartObjectManifest, filePath: string): void {\n const fs = require('node:fs');\n fs.writeFileSync(filePath, JSON.stringify(manifest, null, 2));\n }\n\n /**\n * Load manifest from file\n */\n loadManifest(filePath: string): SmartObjectManifest {\n const fs = require('node:fs');\n const content = fs.readFileSync(filePath, 'utf-8');\n return JSON.parse(content);\n }\n}\n\n/**\n * Convenience function to generate manifest\n *\n * @param scanResults - Array of scan results containing object definitions\n * @param options - Optional configuration (passed to ManifestGenerator.generateManifest)\n */\nexport function generateManifest(\n scanResults: ScanResult[],\n options?: {\n packageName?: string;\n packageVersion?: string;\n packageJson?: PackageJsonLike;\n smrtDependencies?: string[];\n includeVisibility?: SmrtVisibility[];\n },\n): SmartObjectManifest {\n const generator = new ManifestGenerator();\n return generator.generateManifest(scanResults, options);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"manifest-generator.js","names":[],"sources":["../../src/scanner/manifest-generator.ts"],"sourcesContent":["/**\n * Manifest generator for creating service manifests from AST scan results\n */\n\nimport { createHash } from 'node:crypto';\nimport { createRequire } from 'node:module';\nimport { createLogger } from '@happyvertical/logger';\nimport {\n createManifestClassNamePredicate,\n resolveApiMethodExposure,\n resolveCustomActionMetadata,\n resolveEffectiveActionMetadata,\n} from '../generators/custom-action.js';\nimport {\n loadExternalManifestSync,\n lookupInManifest,\n} from '../manifest/manifest-loader.js';\nimport { VERBOSE_ENABLED } from '../registry/shared-state.js';\nimport {\n defaultConflictColumns,\n resolveTenantColumn,\n} from '../schema/conflict-target.js';\nimport type { DatabaseEngine } from '../schema/ddl/types.js';\nimport { resolveForeignKeyDeleteAction } from '../schema/foreign-key-policy.js';\nimport { SchemaGenerator } from '../schema/generator.js';\nimport type {\n ColumnDefinition,\n SchemaDefinition,\n SQLDataType,\n} from '../schema/types.js';\nimport { generateToolManifest } from '../tools/tool-generator.js';\nimport { classnameToTablename, toSnakeCase } from '../utils/naming.js';\nimport { createQualifiedName } from '../utils/qualified-names.js';\nimport { isTestFile } from './test-file-patterns.js';\nimport type {\n AgentAdminRouteManifest,\n AgentComponentDeclaration,\n AgentFeature,\n AgentManifest,\n AgentMenuItem,\n AgentPermission,\n AgentUISlotManifest,\n FieldDefinition,\n ManifestColumnDefinition,\n ManifestSchema,\n MethodDefinition,\n ScanResult,\n SmartObjectDefinition,\n SmartObjectManifest,\n SmrtVisibility,\n ValidationRule,\n} from './types.js';\nimport { MANIFEST_TIMESTAMP } from './types.js';\n\n/** Package.json shape consumed for import-path and component discovery. */\ninterface PackageJsonLike {\n name?: string;\n main?: string;\n exports?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\n/**\n * Object form of the `@smrt({ tenantScoped })` config. Mirrors the object\n * branch of `SmartObjectConfig['tenantScoped']`; all keys optional because\n * the boolean shorthand normalizes to `{}`.\n */\ninterface TenantScopedOptions {\n mode?: 'required' | 'optional';\n field?: string;\n autoFilter?: boolean;\n autoPopulate?: boolean;\n allowSuperAdminBypass?: boolean;\n}\n\n/** JSON Schema property entry emitted for a field in generated MCP tools. */\ninterface JsonSchemaProperty {\n type: string;\n description: string;\n minimum?: number;\n maximum?: number;\n minLength?: number;\n maxLength?: number;\n}\n\ntype SchemaGeneratorLike = {\n generateSQL: (schema: SchemaDefinition, engine?: DatabaseEngine) => string;\n};\n\n// Create require function for synchronous module loading in ESM context\nconst require = createRequire(import.meta.url);\n\n// Build-time schema/manifest-generation diagnostics route through the shared\n// logger (S14 / dim-9, #1579) instead of unconditional stdout writes. Level\n// follows the repo-wide SMRT_VERBOSE/DEBUG convention (#2896) so per-class\n// detail is opt-in rather than always-on info.\nconst logger = createLogger({ level: VERBOSE_ENABLED ? 'debug' : 'info' });\n\n/**\n * Framework abstract base classes whose declared fields must be merged\n * into every subclass's `fields` map.\n *\n * These classes live in SMRT framework packages, have no `@smrt()`\n * decorator, no table of their own, and contribute structural fields\n * (e.g. `SmrtHierarchical.parentId`) that subclasses query against —\n * without merging, downstream WHERE-clause validation rejects queries on\n * those columns.\n *\n * SmrtObject / SmrtClass / SmrtCollection are intentionally NOT in this\n * set even though they live in core. SmrtObject's universal columns\n * (`id`, `slug`, `context`, `created_at`, `updated_at`) are added by a\n * separate universal-baseline mechanism in `fieldsFromClass`, and merging\n * them here would double-write with subtly different `_meta` payloads\n * and regress existing field expectations.\n *\n * Keep in sync with `FRAMEWORK_BASE_CLASSES` in\n * `packages/scanner/src/inheritance-resolver.ts` — note that set is\n * broader: it controls scanner-level chain termination and stub\n * resolution, while this one only controls field merging.\n */\nconst FRAMEWORK_ABSTRACT_BASE_NAMES = new Set([\n 'SmrtJunction',\n 'SmrtHierarchical',\n 'SmrtPolymorphicAssociation',\n 'SmrtReport',\n 'SmrtReportCollection',\n]);\n\n/**\n * Framework base classes to exclude from the ancestor **method** merge\n * below (#2624). Unlike fields, methods are never columns, so they never\n * needed the STI-vs-CTI field-merge rule above — they inherited it only by\n * sharing the same loop.\n *\n * Deliberately NARROWER than `FRAMEWORK_ABSTRACT_BASE_NAMES`: only the\n * three universal object/collection primitives (`SmrtObject`, `SmrtClass`,\n * `SmrtCollection`) are internal-only. These are the same three the\n * runtime resolver's `getAllMethods()`\n * (`packages/core/src/registry/inheritance-resolver.ts`) explicitly skips\n * by name, and the same three the field-merge doc comment above excludes\n * from `FRAMEWORK_ABSTRACT_BASE_NAMES` for the identical reason: their\n * surface (`save`, `destroy`, `toJSON`, `withTransaction`, ...) is generic\n * object-lifecycle plumbing, never a subclass-specific action.\n *\n * `FRAMEWORK_ABSTRACT_BASE_NAMES` (`SmrtJunction`, `SmrtHierarchical`,\n * `SmrtPolymorphicAssociation`, `SmrtReport`, `SmrtReportCollection`) is\n * intentionally NOT folded in here, unlike an earlier version of this fix.\n * Those classes are mixin-style bases whose declared methods ARE the\n * subclass's real, intended public API — the same way `SmrtHierarchical.\n * parentId` is a real, intended field, which is exactly why\n * `FRAMEWORK_ABSTRACT_BASE_NAMES` fields already merge into every subclass\n * regardless of STI/CTI (see above). Directly confirmed for two of the\n * five: `SmrtJunction.attach`/`detach`/`byLeft`/`byRight`/`setLinks`\n * (`packages/core/src/junction.ts`) — a `packages/template-sveltekit/\n * __tests__/runtimeProfileParity.test.ts` snapshot broke when an earlier\n * revision of this fix folded all 8 `FRAMEWORK_BASE_CLASSES` in here,\n * which is how this got caught — and `SmrtHierarchical.getParent`/\n * `getChildren`/`getAncestors`/`getDescendants`/`getHierarchy`/`moveTo`\n * (`packages/core/src/hierarchical.ts`). `SmrtPolymorphicAssociation`\n * follows the identical pattern by inspection but has no dedicated\n * regression test yet. `SmrtReport`/`SmrtReportCollection` are the\n * least-audited of the five: `SmrtReportCollection` overrides `list`/`get`\n * (`packages/reports/src/report.ts`), which are also the universal CRUD\n * operation names — a downstream `class X extends SmrtReportCollection`\n * with default (non-strict) MCP config would have seen a generated\n * custom-action tool collide with the standard `list`/`get` tool name.\n * #2646 closed that separately and independently of this exclusion set: the\n * MCP generator now refuses to expose a CRUD-named method as a custom action,\n * matching case-folded because its tool ids are lowercased whole. Each emitter\n * reserves on its own terms, and not all of them read the shared\n * `CRUD_OPERATIONS` list yet — see its docblock in\n * `generators/custom-action.ts` for the per-emitter rules. Keep in sync with the field-merge set's own doc comment; this one\n * governs method merging only.\n */\nconst FRAMEWORK_METHOD_BASE_NAMES = new Set([\n 'SmrtObject',\n 'SmrtClass',\n 'SmrtCollection',\n]);\n\n/**\n * Deterministic string comparator (#2749). Manifest object iteration order\n * follows scan/discovery order, which is not stable across runs, so any\n * emitted artifact keyed off `Object.entries(manifest.objects)` needs a\n * stable sort before emission.\n */\nfunction compareText(left: string, right: string): number {\n if (left < right) return -1;\n if (left > right) return 1;\n return 0;\n}\n\n/**\n * True when a package.json `exports` condition resolves to a non-JS asset\n * (e.g. the `./manifest`/`./manifest.json` convention pointing at\n * `dist/manifest.json`), so subpath matching (smrt#2845's\n * `matchExportsSubpath`) never attributes a scanned object to it — no\n * `@smrt()` class's source file can be loaded from a JSON target.\n */\nfunction targetsJsonAsset(condition: unknown): boolean {\n if (typeof condition === 'string') return condition.endsWith('.json');\n if (condition && typeof condition === 'object') {\n const record = condition as Record<string, unknown>;\n const target = record.import ?? record.default ?? record.require;\n return typeof target === 'string' && target.endsWith('.json');\n }\n return false;\n}\n\n/**\n * Infer visibility from file path and explicit config\n *\n * Priority:\n * 1. Explicit visibility in decorator config\n * 2. Auto-detect test files → 'test'\n * 3. Default to 'public'\n */\nfunction inferVisibility(\n filePath: string,\n explicitVisibility?: SmrtVisibility,\n): SmrtVisibility {\n if (explicitVisibility) return explicitVisibility;\n if (isTestFile(filePath)) return 'test';\n return 'public';\n}\n\nexport class ManifestGenerator {\n /**\n * Generate manifest from scan results\n *\n * @param scanResults - Array of scan results containing object definitions\n * @param options - Optional configuration\n * @param options.packageName - Package name to inject into manifest and object definitions\n * @param options.packageVersion - Package version\n * @param options.packageJson - Full package.json object for determining import paths\n * @param options.smrtDependencies - List of SMRT package dependencies to include in manifest\n * @param options.includeVisibility - Array of visibility levels to include (default: all)\n * - For published packages: ['public']\n * - For development: ['public', 'internal', 'test'] or omit for all\n */\n generateManifest(\n scanResults: ScanResult[],\n options?: {\n packageName?: string;\n packageVersion?: string;\n packageJson?: PackageJsonLike;\n smrtDependencies?: string[];\n includeVisibility?: SmrtVisibility[];\n },\n ): SmartObjectManifest {\n const manifest: SmartObjectManifest = {\n version: '1.0.0',\n timestamp: MANIFEST_TIMESTAMP,\n objects: {},\n };\n\n // Set package metadata at manifest level if provided\n if (options?.packageName) {\n manifest.packageName = options.packageName;\n }\n if (options?.packageVersion) {\n manifest.packageVersion = options.packageVersion;\n }\n // Set smrtDependencies BEFORE mergeInheritedFields() so external packages can be loaded\n if (options?.smrtDependencies) {\n manifest.smrtDependencies = options.smrtDependencies;\n }\n\n for (const result of scanResults) {\n for (const objectDef of result.objects) {\n // Set package metadata on object definition if provided\n if (options?.packageName) {\n objectDef.packageName = options.packageName;\n }\n if (options?.packageVersion) {\n objectDef.packageVersion = options.packageVersion;\n }\n\n // Generate qualified name (required for manifest keying)\n // Must have packageName to generate qualified name\n if (objectDef.packageName) {\n objectDef.qualifiedName = createQualifiedName(\n objectDef.packageName,\n objectDef.className,\n );\n }\n\n // Infer visibility from file path and decorator config\n objectDef.visibility = inferVisibility(\n objectDef.filePath,\n objectDef.decoratorConfig?.visibility as SmrtVisibility | undefined,\n );\n\n // Filter by visibility if specified\n // Skip objects that don't match the requested visibility levels\n if (\n options?.includeVisibility &&\n options.includeVisibility.length > 0 &&\n !options.includeVisibility.includes(objectDef.visibility)\n ) {\n // Skip this object - visibility not in allowed list\n continue;\n }\n\n // Determine import path from package.json exports\n if (options?.packageName && options?.packageJson) {\n objectDef.importPath = this.determineImportPath(\n options.packageJson,\n objectDef.filePath,\n );\n }\n\n // Set export names (defaults to className)\n objectDef.exportName = objectDef.exportName || objectDef.className;\n objectDef.collectionExportName =\n objectDef.collectionExportName || `${objectDef.className}Collection`;\n\n // Generate AI tools from methods if AI config exists\n if (objectDef.decoratorConfig.ai) {\n const methods = Object.values(objectDef.methods);\n const tools = generateToolManifest(\n methods,\n objectDef.decoratorConfig.ai,\n );\n\n // Store tools in object definition\n if (tools.length > 0) {\n objectDef.tools = tools;\n }\n }\n\n // Determine manifest key: use qualified name if available, fall back to lowercase name\n // During transition, some objects may not have qualified names\n const manifestKey = objectDef.qualifiedName || objectDef.name;\n\n // Check for collisions using the manifest key\n if (manifest.objects[manifestKey]) {\n const existing = manifest.objects[manifestKey];\n throw new Error(\n `Class name collision detected: '${objectDef.className}' (${manifestKey}) is defined in multiple files:\\n` +\n ` 1. ${existing.filePath}\\n` +\n ` 2. ${objectDef.filePath}\\n\\n` +\n `Class names must be unique within a package. Use different class names or separate packages.`,\n );\n }\n\n manifest.objects[manifestKey] = objectDef;\n }\n }\n\n this.applyGenerationPasses(manifest, {\n packageName: options?.packageName,\n packageJson: options?.packageJson,\n });\n\n return manifest;\n }\n\n /**\n * Run every manifest generation pass, in order, on a manifest whose\n * `objects` have been collected. This is THE pass sequence: the OXC vite\n * plugin (`vite-plugin/index.ts`) and `ManifestBuilder.buildManifest()`\n * call it too, so the three producers cannot drift — before #2360\n * `ManifestBuilder` skipped the report passes and its manifests carried\n * `(slug, context)` conflict indexes for `@report` classes while the\n * runtime upserted on the report's group columns.\n *\n * @param manifest - manifest with `objects` populated (and\n * `smrtDependencies` set, so external STI bases resolve)\n * @param options - package metadata for the agent-manifest pass\n */\n applyGenerationPasses(\n manifest: SmartObjectManifest,\n options?: { packageName?: string; packageJson?: PackageJsonLike },\n ): void {\n // Report cache rows are safe to scope by tenant even when a report is\n // global: optional mode keeps tenant-less rows readable outside a tenant\n // context and gives tenant-scoped reports the tenant_id column their raw\n // aggregate refresh path must write.\n this.normalizeReportTenantScope(manifest);\n\n // Second pass: materialize implicit tenant fields before inheritance and schema generation.\n this.injectTenantScopedFields(manifest);\n\n // Third pass: Merge inherited fields for STI classes\n // This ensures STI subclasses have all parent fields inline in the manifest\n this.mergeInheritedFields(manifest);\n\n // Report models are read-only cache tables. Fill in the generated surface\n // and natural conflict key from report metadata before schema generation.\n this.normalizeReportObjects(manifest);\n\n // Tenant-scoped classes key on `[tenant column, ...natural key]` (#2360);\n // materialize that default so schema generation, the knowledge artifact\n // and the runtime read the same conflict target.\n this.normalizeConflictColumns(manifest);\n\n // Fourth pass: Generate validation rules for all objects\n // This pre-computes validation rules from field definitions, eliminating\n // the need to compile validator closures at runtime (Issue #782)\n this.generateValidationRules(manifest);\n\n // Fifth pass: Generate schemas for each object (build-time schema generation)\n // This pre-computes DDL, indexes, and columns for efficient external package consumption\n this.generateSchemas(manifest);\n this.assertTenantScopedSchemaContract(manifest);\n\n // Sixth pass: Generate agent manifests for Agent subclasses\n // Derives permissions, features, menuItems, and components from code\n this.generateAgentManifests(\n manifest,\n options?.packageName,\n options?.packageJson,\n );\n\n // Seventh pass: stamp the subpath consumers should import each object\n // from. `generateManifest()`'s own per-object loop already does this,\n // but the Vite plugin and `ManifestBuilder` (the other two manifest\n // producers this pass sequence exists to keep from drifting, #2360)\n // build their manifest via `ManifestAdapter.toManifest()` and call\n // `applyGenerationPasses()` directly — never through `generateManifest()`\n // — so their objects reached this pass with no `importPath` at all. That\n // is smrt#2845: `DataSurfaceActionIdempotencyState` in\n // `@happyvertical/smrt-agents` lives under `src/server/` (served only by\n // the `./server` export), but the published manifest carried no\n // `importPath`, so consumer registration\n // (`consumer-plugin/index.ts`'s own `determineImportPath`) fell back to\n // the bare package specifier the object was never exported from.\n this.resolveImportPaths(\n manifest,\n options?.packageName,\n options?.packageJson,\n );\n }\n\n /**\n * Stamp `importPath` (via {@link determineImportPath}) on every object\n * that does not already have one. Safe to call unconditionally: objects\n * that went through `generateManifest()`'s own inline assignment already\n * carry an `importPath` and are left untouched.\n */\n resolveImportPaths(\n manifest: SmartObjectManifest,\n packageName?: string,\n packageJson?: PackageJsonLike,\n ): void {\n if (!packageName || !packageJson) return;\n\n for (const obj of Object.values(manifest.objects)) {\n if (obj.importPath) continue;\n obj.importPath = this.determineImportPath(packageJson, obj.filePath);\n }\n }\n\n /**\n * Materialize tenantScoped schema fields.\n *\n * Runtime registration already injects tenant fields for\n * `@smrt({ tenantScoped: true })`, but published manifests must contain the\n * same field before schema generation so migrations create `tenant_id`.\n */\n injectTenantScopedFields(manifest: SmartObjectManifest): void {\n for (const objectDef of Object.values(manifest.objects)) {\n this.injectTenantScopedField(objectDef);\n }\n }\n\n private injectTenantScopedField(objectDef: SmartObjectDefinition): void {\n const tenantScoped = objectDef.decoratorConfig?.tenantScoped;\n if (!tenantScoped) {\n return;\n }\n\n const { tenantConfig } = this.normalizeTenantScopedConfig(tenantScoped);\n const fieldName = tenantConfig.field;\n const existingField = objectDef.fields[fieldName];\n const tenancyMeta = {\n isTenantIdField: true,\n ...tenantConfig,\n };\n\n if (existingField) {\n const fieldTypeFailure = this.getTenantScopedFieldTypeFailure(\n objectDef,\n fieldName,\n );\n if (fieldTypeFailure) {\n throw new Error(\n `Tenant-scoped field configuration invalid: ${fieldTypeFailure}`,\n );\n }\n\n existingField._meta = {\n ...existingField._meta,\n sqlType: 'UUID',\n __tenancy: {\n ...existingField._meta?.__tenancy,\n ...tenancyMeta,\n },\n };\n return;\n }\n\n objectDef.fields[fieldName] = {\n type: 'text',\n // Use the normalized tenant mode so the boolean shorthand has the same\n // requiredness in manifests as it does during runtime registration.\n required: tenantConfig.mode === 'required',\n _meta: {\n generated: true,\n source: 'tenantScoped_decorator',\n sqlType: 'UUID',\n __tenancy: tenancyMeta,\n },\n };\n\n logger.debug(\n `[manifest-generator] Injected ${fieldName} field for ${objectDef.className} (tenantScoped: ${JSON.stringify(tenantConfig)})`,\n );\n }\n\n assertTenantScopedSchemaContract(manifest: SmartObjectManifest): void {\n const failures: string[] = [];\n\n for (const objectDef of Object.values(manifest.objects)) {\n const tenantScoped = objectDef.decoratorConfig?.tenantScoped;\n if (!tenantScoped) {\n continue;\n }\n\n const { tenantConfig } = this.normalizeTenantScopedConfig(tenantScoped);\n const fieldName = tenantConfig.field;\n const columnName = toSnakeCase(fieldName);\n\n if (!objectDef.fields[fieldName]) {\n failures.push(\n `${objectDef.className}: missing tenant-scoped field \"${fieldName}\"`,\n );\n continue;\n }\n\n const fieldTypeFailure = this.getTenantScopedFieldTypeFailure(\n objectDef,\n fieldName,\n );\n if (fieldTypeFailure) {\n failures.push(fieldTypeFailure);\n continue;\n }\n\n const schemaOwner = this.getTenantScopedSchemaOwner(objectDef, manifest);\n const schemaOwnerContext =\n schemaOwner === objectDef\n ? ''\n : ` on STI base \"${schemaOwner.className}\"`;\n\n if (!schemaOwner.schema?.columns) {\n failures.push(\n `${objectDef.className}: schema has not been generated for tenant-scoped column \"${columnName}\"${schemaOwnerContext}`,\n );\n continue;\n }\n\n if (!schemaOwner.schema.columns[columnName]) {\n failures.push(\n `${objectDef.className}: schema is missing tenant-scoped column \"${columnName}\"${schemaOwnerContext}`,\n );\n }\n }\n\n if (failures.length > 0) {\n throw new Error(\n `Tenant-scoped schema contract failed:\\n${failures\n .map((failure) => ` - ${failure}`)\n .join('\\n')}`,\n );\n }\n }\n\n private getTenantScopedSchemaOwner(\n objectDef: SmartObjectDefinition,\n manifest: SmartObjectManifest,\n ): SmartObjectDefinition {\n if (!this.isSTIChildClass(objectDef, manifest)) {\n return objectDef;\n }\n\n const stiBase = this.findSTIBaseInfo(objectDef, manifest);\n if (!stiBase) {\n return objectDef;\n }\n\n const localBase = Object.values(manifest.objects).find(\n (candidate) => candidate.className === stiBase.className,\n );\n\n return localBase ?? objectDef;\n }\n\n private getTenantScopedFieldTypeFailure(\n objectDef: SmartObjectDefinition,\n fieldName: string,\n ): string | undefined {\n const field = objectDef.fields[fieldName];\n if (!field) {\n return undefined;\n }\n\n if (field.type !== 'text' && field.type !== 'foreignKey') {\n return `${objectDef.className}: tenant-scoped field \"${fieldName}\" must use type \"text\" or \"foreignKey\"; received \"${field.type}\"`;\n }\n\n const sqlType = field._meta?.sqlType;\n if (sqlType && !['TEXT', 'UUID'].includes(String(sqlType).toUpperCase())) {\n return `${objectDef.className}: tenant-scoped field \"${fieldName}\" must use SQL type \"UUID\" or legacy \"TEXT\"; received \"${sqlType}\"`;\n }\n\n return undefined;\n }\n\n private normalizeTenantScopedConfig(tenantScoped: unknown): {\n tenantConfig: {\n mode: string;\n field: string;\n autoFilter: boolean;\n autoPopulate: boolean;\n allowSuperAdminBypass: boolean;\n };\n } {\n const tenantOptions: TenantScopedOptions =\n typeof tenantScoped === 'boolean'\n ? {}\n : (tenantScoped as TenantScopedOptions);\n\n return {\n tenantConfig: {\n mode: tenantOptions.mode ?? 'required',\n field: tenantOptions.field ?? 'tenantId',\n autoFilter: tenantOptions.autoFilter ?? true,\n autoPopulate: tenantOptions.autoPopulate ?? true,\n allowSuperAdminBypass: tenantOptions.allowSuperAdminBypass ?? false,\n },\n };\n }\n\n /**\n * Generate pre-computed validation rules for all objects in the manifest.\n *\n * This extracts validation constraints (required, min, max, minLength, maxLength, pattern)\n * from field definitions and stores them as serializable rules in the manifest.\n *\n * At runtime, these rules can be evaluated without creating validator closures,\n * significantly reducing CLI startup time for projects with many SMRT objects.\n *\n * @param manifest - The manifest to process in-place\n */\n generateValidationRules(manifest: SmartObjectManifest): void {\n for (const [name, obj] of Object.entries(manifest.objects)) {\n const rules: ValidationRule[] = [];\n let skippedAutoPopulatedTenantRequiredRule = false;\n\n for (const [fieldName, field] of Object.entries(obj.fields)) {\n // Skip transient fields (they're not persisted, so no validation needed)\n if (field.transient || field._meta?.transient) {\n continue;\n }\n\n const options = field._meta || {};\n\n // Required field rule\n const isAutoPopulatedTenantField =\n options.__tenancy?.isTenantIdField === true &&\n options.__tenancy.autoPopulate !== false;\n if (\n (options.required || field.required) &&\n !isAutoPopulatedTenantField\n ) {\n rules.push({\n field: fieldName,\n rule: 'required',\n fieldType: field.type,\n });\n } else if (\n isAutoPopulatedTenantField &&\n (options.required || field.required)\n ) {\n // Tenant IDs can be required in the manifest and database while still\n // being absent at this pre-interceptor validation stage. Tenancy's\n // beforeSave hook stamps them from the active context before writing.\n skippedAutoPopulatedTenantRequiredRule = true;\n }\n\n // Numeric range rules (for integer, decimal fields)\n if (field.type === 'integer' || field.type === 'decimal') {\n if (options.min !== undefined || field.min !== undefined) {\n rules.push({\n field: fieldName,\n rule: 'min',\n value: options.min ?? field.min,\n fieldType: field.type,\n });\n }\n\n if (options.max !== undefined || field.max !== undefined) {\n rules.push({\n field: fieldName,\n rule: 'max',\n value: options.max ?? field.max,\n fieldType: field.type,\n });\n }\n }\n\n // String length rules (for text fields)\n if (field.type === 'text') {\n if (\n options.minLength !== undefined ||\n field.minLength !== undefined\n ) {\n rules.push({\n field: fieldName,\n rule: 'minLength',\n value: options.minLength ?? field.minLength,\n fieldType: field.type,\n });\n }\n\n if (\n options.maxLength !== undefined ||\n field.maxLength !== undefined\n ) {\n rules.push({\n field: fieldName,\n rule: 'maxLength',\n value: options.maxLength ?? field.maxLength,\n fieldType: field.type,\n });\n }\n\n // Pattern rule (regex validation)\n // Note: Custom validator functions (options.validate) cannot be serialized\n // and will fall back to compiled validators at runtime\n // Note: Pattern is only available in field options, not in FieldDefinition\n const pattern = options.pattern;\n if (pattern) {\n rules.push({\n field: fieldName,\n rule: 'pattern',\n // RegExp patterns expose `.source`; a JSON-collapsed RegExp ({})\n // has none, preserving the prior `undefined` value exactly.\n value:\n typeof pattern === 'string'\n ? pattern\n : (pattern as { source?: string }).source,\n fieldType: field.type,\n });\n }\n }\n }\n\n // An explicit empty list is meaningful when the sole required field is\n // auto-populated by tenancy: it prevents runtime registration from\n // recompiling a pre-interceptor required validator for that field.\n if (rules.length > 0 || skippedAutoPopulatedTenantRequiredRule) {\n obj.validationRules = rules;\n }\n }\n }\n\n /**\n * Generate pre-computed schemas for all objects in the manifest.\n *\n * This enables external package consumers to use pre-generated schemas\n * without calling generateSchema() at runtime, eliminating latency.\n *\n * IMPORTANT: For STI classes, we aggregate ALL descendants from both local\n * and external packages to ensure complete schemas are generated.\n *\n * This method is public to allow external callers (like OXC scanner) to use it.\n *\n * @param manifest - The manifest to process in-place\n */\n generateSchemas(manifest: SmartObjectManifest): void {\n const generator = new SchemaGenerator();\n\n // Create aggregated manifest that includes external package objects\n // This ensures STI schema generation finds ALL descendants\n const aggregatedManifest = this.createAggregatedManifest(manifest);\n const schemaClasses = new Map(\n Object.values(aggregatedManifest.objects).map((obj) => [\n obj.className,\n obj,\n ]),\n );\n\n // An external class with the same simple name cannot replace a local item.\n for (const obj of Object.values(manifest.objects))\n schemaClasses.set(obj.className, obj);\n\n for (const [name, obj] of Object.entries(manifest.objects)) {\n // Collections access their item model's table; an independent schema can\n // contradict that model's tenant/conflict identity during aggregation.\n if (this.extendsCollection(obj, schemaClasses)) {\n delete obj.schema;\n continue;\n }\n if (FRAMEWORK_ABSTRACT_BASE_NAMES.has(obj.className)) {\n continue;\n }\n\n // Determine table name (may have been inherited from external STI base)\n // Use obj.className (PascalCase) for consistent table name derivation with runtime\n const tableName =\n obj.decoratorConfig?.tableName ||\n this.classNameToTableName(obj.className);\n\n // Check if this is an STI class. `mergeInheritedFields()` copies the\n // base's `tableStrategy` onto every descendant, so both the root and\n // its children arrive here; `isSTIChildClass` covers a child whose\n // strategy was not inherited.\n if (\n obj.decoratorConfig?.tableStrategy === 'sti' ||\n this.isSTIChildClass(obj, manifest)\n ) {\n // Every class in an STI hierarchy — root, local child, or a child of\n // an EXTERNAL base — carries the schema of the ONE shared table,\n // generated from the ROOT base so descendant discovery, the\n // discriminator-partial unique indexes and the base-declared /\n // descendant-declared distinction are computed against the same\n // hierarchy on every class (#527, #2359). A child generated as if it\n // were the root would treat its own descendant-only `unique: true`\n // fields as base-declared and emit a full unique index that\n // `getAllSchemasAsDefinitions()` then merges into the table beside\n // the correct partial one.\n const stiRoot = this.findSTIBaseInfo(obj, manifest);\n const rootKey = stiRoot\n ? (this.resolveManifestKey(stiRoot.className, aggregatedManifest) ??\n stiRoot.className)\n : name;\n const rootTableName = stiRoot?.tableName || tableName;\n const rootConfig =\n aggregatedManifest.objects[rootKey]?.decoratorConfig ??\n obj.decoratorConfig;\n\n logger.debug(\n `[manifest-generator] Generating STI schema for ${name} (root: ${rootKey}, table: ${rootTableName})`,\n );\n\n // Use aggregated manifest to find descendants from ALL packages\n obj.schema = generator.generateSTISchemaFromManifest(\n rootKey,\n rootTableName,\n obj.fields,\n aggregatedManifest,\n rootConfig,\n );\n this.applySqlTypeOverrides(obj);\n } else {\n // CTI class - generate individual table schema\n logger.debug(\n `[manifest-generator] Generating CTI schema for ${name} (table: ${tableName})`,\n );\n\n obj.schema = generator.generateCTISchemaFromManifest(\n name,\n tableName,\n obj.fields,\n obj.decoratorConfig,\n );\n this.applySqlTypeOverrides(obj);\n }\n }\n\n this.resolveSamePackageForeignKeyColumnTypes(manifest, generator);\n\n // Preserve collection metadata, but take persistence identity from the item\n // model only after every model schema (including FK repair) is complete.\n for (const obj of Object.values(manifest.objects)) {\n if (!this.extendsCollection(obj, schemaClasses)) continue;\n let current: SmartObjectDefinition | undefined = obj;\n const visited = new Set<SmartObjectDefinition>();\n while (current && !visited.has(current)) {\n visited.add(current);\n const item = this.findItemClass(\n current,\n aggregatedManifest,\n schemaClasses,\n );\n if (item?.schema && !this.extendsCollection(item, schemaClasses)) {\n obj.schema = structuredClone(item.schema);\n break;\n }\n current = current.extends\n ? schemaClasses.get(current.extends)\n : undefined;\n }\n }\n }\n\n normalizeReportObjects(manifest: SmartObjectManifest): void {\n for (const obj of Object.values(manifest.objects)) {\n if (!obj.decoratorConfig?.report) continue;\n\n obj.decoratorConfig.api ??= { include: ['list', 'get'] };\n obj.decoratorConfig.mcp ??= { include: ['list', 'get'] };\n\n if (obj.decoratorConfig.conflictColumns) continue;\n\n const tenantScoped = obj.decoratorConfig.tenantScoped;\n const tenantField =\n tenantScoped && typeof tenantScoped === 'object'\n ? tenantScoped.field || 'tenantId'\n : tenantScoped\n ? 'tenantId'\n : undefined;\n const tenantColumn =\n tenantField && obj.fields[tenantField] ? toSnakeCase(tenantField) : '';\n\n const conflictColumns = Object.entries(obj.fields)\n .filter(([, field]) => {\n const kind = field._meta?.__report?.kind;\n return kind === 'group' || kind === 'bucket';\n })\n .map(([fieldName]) => toSnakeCase(fieldName));\n\n obj.decoratorConfig.conflictColumns =\n conflictColumns.length > 0\n ? [...(tenantColumn ? [tenantColumn] : []), ...conflictColumns]\n : ['id'];\n }\n }\n\n normalizeReportTenantScope(manifest: SmartObjectManifest): void {\n for (const obj of Object.values(manifest.objects)) {\n if (!obj.decoratorConfig?.report) continue;\n obj.decoratorConfig.tenantScoped ??= { mode: 'optional' };\n }\n }\n\n /**\n * Materialize the tenant-aware default conflict target (#2360).\n *\n * A tenant-scoped class that declares no `@smrt({ conflictColumns })` keys\n * on `[tenant column, ...natural key]` — `(tenant_id, slug, context)` for\n * a class-per-table object, `(tenant_id, slug, context, _meta_type)` for a\n * single-table hierarchy — so two tenants can each own the same slug and\n * neither `save()` adopts the other's row. Writing the resolved key into\n * `decoratorConfig.conflictColumns` (mirroring `normalizeReportObjects`)\n * makes the manifest, the generated schema, the knowledge artifact and\n * `ObjectRegistry.getConflictColumns()` read one value.\n *\n * Only schema owners are normalized: an STI child inherits the table (and\n * therefore the key) from its root, and `getConflictColumns()` resolves a\n * child through its root at runtime. Explicit `conflictColumns` and\n * `@report` classes (keyed by `normalizeReportObjects`) are left alone.\n * Runs after `injectTenantScopedFields()` and `mergeInheritedFields()` so\n * the tenant field and the inherited `tableStrategy` are in place, and\n * before `generateSchemas()`.\n */\n normalizeConflictColumns(manifest: SmartObjectManifest): void {\n for (const obj of Object.values(manifest.objects)) {\n if (!obj.decoratorConfig) continue;\n if (FRAMEWORK_ABSTRACT_BASE_NAMES.has(obj.className)) continue;\n if (obj.decoratorConfig.conflictColumns) continue;\n if (obj.decoratorConfig.report) continue;\n if (this.isSTIChildClass(obj, manifest)) continue;\n\n const tenantScoped = obj.decoratorConfig.tenantScoped;\n if (!tenantScoped) continue;\n\n const { tenantConfig } = this.normalizeTenantScopedConfig(tenantScoped);\n const tenantColumn = resolveTenantColumn(\n tenantConfig.field,\n (fieldName) => Boolean(obj.fields[fieldName]),\n toSnakeCase,\n );\n if (!tenantColumn) continue;\n\n obj.decoratorConfig.conflictColumns = defaultConflictColumns(\n obj.decoratorConfig.tableStrategy === 'sti' ? 'sti' : 'cti',\n tenantColumn,\n );\n }\n }\n\n private resolveSamePackageForeignKeyColumnTypes(\n manifest: SmartObjectManifest,\n generator: SchemaGeneratorLike,\n ): void {\n // One representative schema per table for target-id lookups, plus EVERY\n // schema that describes a table: each class of an STI hierarchy carries a\n // copy of the shared table's schema (#2359), and every copy must receive\n // the same reconciled type or `getAllSchemasAsDefinitions()`'s\n // first-wins column merge can surface an unreconciled one.\n const schemaByTable = new Map<string, ManifestSchema>();\n const schemasByTable = new Map<string, ManifestSchema[]>();\n const ownerBySchema = new Map<\n ManifestSchema,\n { name: string; obj: SmartObjectDefinition }\n >();\n const changedSchemas = new Set<ManifestSchema>();\n const objectsByName = new Map<string, SmartObjectDefinition>();\n\n for (const [name, obj] of Object.entries(manifest.objects)) {\n objectsByName.set(obj.className, obj);\n objectsByName.set(obj.className.toLowerCase(), obj);\n if (obj.schema?.tableName) {\n schemaByTable.set(obj.schema.tableName, obj.schema);\n const siblings = schemasByTable.get(obj.schema.tableName) ?? [];\n siblings.push(obj.schema);\n schemasByTable.set(obj.schema.tableName, siblings);\n ownerBySchema.set(obj.schema, { name, obj });\n }\n }\n\n for (const obj of Object.values(manifest.objects)) {\n const sourceTable = this.getObjectTableName(obj);\n if (!sourceTable) {\n continue;\n }\n\n const sourceSchemas = schemasByTable.get(sourceTable);\n if (!sourceSchemas || sourceSchemas.length === 0) {\n continue;\n }\n\n for (const [fieldName, field] of Object.entries(obj.fields || {})) {\n if (\n field.type !== 'foreignKey' ||\n !field.related ||\n field._meta?.__tenancy?.isTenantIdField === true\n ) {\n continue;\n }\n\n const emitConstraint = field._meta?.constraint !== false;\n\n const columnName = toSnakeCase(fieldName);\n const targetSchema = this.findForeignKeyTargetSchema(\n field.related,\n manifest,\n schemaByTable,\n obj.packageName,\n );\n if (!targetSchema) {\n for (const sourceSchema of sourceSchemas) {\n const sourceColumn = sourceSchema.columns[columnName];\n if (sourceColumn?.foreignKey) {\n sourceSchema.columns[columnName] = {\n ...sourceColumn,\n foreignKey: undefined,\n };\n changedSchemas.add(sourceSchema);\n }\n }\n continue;\n }\n\n const [, declaredTargetColumn] = field.related.split('.');\n const targetColumn =\n declaredTargetColumn ||\n Object.entries(targetSchema.columns).find(\n ([, definition]) => definition.primaryKey === true,\n )?.[0] ||\n 'id';\n const targetIdType = targetSchema.columns[targetColumn]?.type;\n const conflictOwner =\n this.findSTIBase(obj, objectsByName, manifest) ?? obj;\n const conflictColumns = new Set(\n (conflictOwner.decoratorConfig?.conflictColumns || []).map((column) =>\n toSnakeCase(column),\n ),\n );\n const { action } = resolveForeignKeyDeleteAction({\n declared: field._meta?.onDelete,\n isConflictColumn: conflictColumns.has(columnName),\n isTenantIdField: false,\n });\n\n for (const sourceSchema of sourceSchemas) {\n const sourceColumn = sourceSchema.columns[columnName];\n if (!sourceColumn) {\n continue;\n }\n const nextColumn = {\n ...sourceColumn,\n ...(!field._meta?.sqlType && targetIdType\n ? { type: targetIdType }\n : {}),\n foreignKey: emitConstraint\n ? {\n table: targetSchema.tableName,\n column: targetColumn,\n onDelete: action,\n onUpdate: 'CASCADE' as const,\n ...(typeof field._meta?.constraint === 'object'\n ? { engines: [...field._meta.constraint.engines] }\n : {}),\n }\n : undefined,\n };\n if (JSON.stringify(nextColumn) === JSON.stringify(sourceColumn)) {\n continue;\n }\n sourceSchema.columns[columnName] = nextColumn;\n changedSchemas.add(sourceSchema);\n }\n }\n }\n\n for (const schema of changedSchemas) {\n this.refreshManifestSchemaDDL(\n schema,\n generator,\n ownerBySchema.get(schema),\n manifest,\n );\n }\n }\n\n private findForeignKeyTargetSchema(\n related: string,\n manifest: SmartObjectManifest,\n schemaByTable: Map<string, ManifestSchema>,\n sourcePackageName?: string,\n ): ManifestSchema | undefined {\n const relatedTarget = related.split('.')[0];\n if (schemaByTable.has(relatedTarget)) {\n return schemaByTable.get(relatedTarget);\n }\n\n const candidates = Object.values(manifest.objects).filter(\n (candidate) =>\n candidate.className === relatedTarget ||\n candidate.qualifiedName === relatedTarget ||\n candidate.name === relatedTarget ||\n candidate.decoratorConfig?.tableName === relatedTarget ||\n candidate.schema?.tableName === relatedTarget,\n );\n const localTarget = candidates.find(\n (candidate) => candidate.packageName === sourcePackageName,\n );\n if (!localTarget && candidates.length > 1) {\n throw new Error(\n `Ambiguous foreign key target ${relatedTarget} from package ${sourcePackageName}`,\n );\n }\n const targetObj = localTarget ?? candidates[0];\n\n if (!targetObj && relatedTarget.includes(':')) {\n return undefined;\n }\n\n const targetTable = targetObj\n ? this.getObjectTableName(targetObj)\n : this.classNameToTableName(relatedTarget);\n\n return targetTable ? schemaByTable.get(targetTable) : undefined;\n }\n\n private getObjectTableName(obj: SmartObjectDefinition): string | undefined {\n return (\n obj.schema?.tableName ||\n obj.decoratorConfig?.tableName ||\n this.classNameToTableName(obj.className)\n );\n }\n\n private refreshManifestSchemaDDL(\n schema: ManifestSchema,\n generator: SchemaGeneratorLike,\n owner: { name: string; obj: SmartObjectDefinition } | undefined,\n manifest: SmartObjectManifest,\n ): void {\n const columns: Record<string, ColumnDefinition> = {};\n for (const [name, column] of Object.entries(schema.columns)) {\n columns[name] = {\n // ManifestColumnDefinition stores `type` as a plain string; it is\n // always a valid SQLDataType for DDL rendering.\n type: column.type as SQLDataType,\n primaryKey: column.primaryKey,\n notNull: column.notNull,\n unique: column.unique,\n defaultValue: column.default,\n foreignKey: column.foreignKey ? { ...column.foreignKey } : undefined,\n };\n }\n\n const schemaDefinition: SchemaDefinition = {\n tableName: schema.tableName,\n columns,\n indexes: (schema.indexes || []).map((index) => ({\n name: index.name,\n columns: index.columns,\n unique: index.unique,\n ...(index.nullsNotDistinct ? { nullsNotDistinct: true } : {}),\n where: index.where,\n jsonPath: index.jsonPath,\n })),\n triggers: [],\n foreignKeys: Object.entries(columns).flatMap(([column, definition]) =>\n definition.foreignKey\n ? [\n {\n column,\n referencesTable: definition.foreignKey.table,\n referencesColumn: definition.foreignKey.column,\n onDelete: definition.foreignKey.onDelete,\n onUpdate: definition.foreignKey.onUpdate,\n ...(definition.foreignKey.engines\n ? { engines: definition.foreignKey.engines }\n : {}),\n },\n ]\n : [],\n ),\n dependencies: Object.values(columns)\n .flatMap((definition) =>\n definition.foreignKey ? [definition.foreignKey.table] : [],\n )\n .filter((dependency) => dependency !== schema.tableName),\n version: schema.version,\n packageName: '',\n };\n\n schema.ddl = generator.generateSQL(schemaDefinition);\n schema.version = this.computeManifestSchemaVersion(schema, owner, manifest);\n }\n\n private computeManifestSchemaVersion(\n schema: ManifestSchema,\n owner: { name: string; obj: SmartObjectDefinition } | undefined,\n manifest: SmartObjectManifest,\n ): string {\n if (schema.columns._meta_type && owner) {\n const baseClassName =\n owner.obj.decoratorConfig?.tableStrategy === 'sti'\n ? owner.name\n : this.findSTIBaseInfo(owner.obj, manifest)?.className || owner.name;\n\n return createHash('sha256')\n .update(\n JSON.stringify({\n columns: schema.columns,\n baseClassName,\n descendants: this.findDescendantsInManifest(\n baseClassName,\n manifest,\n ),\n }),\n )\n .digest('hex')\n .substring(0, 8);\n }\n\n return createHash('sha256')\n .update(\n JSON.stringify({\n columns: schema.columns,\n className: owner?.name || schema.tableName,\n }),\n )\n .digest('hex')\n .substring(0, 8);\n }\n\n private findDescendantsInManifest(\n baseClassName: string,\n manifest: SmartObjectManifest,\n visited: Set<string> = new Set(),\n ): string[] {\n const descendants: string[] = [];\n if (visited.has(baseClassName)) {\n return descendants;\n }\n visited.add(baseClassName);\n\n const baseClassLower = this.simpleClassName(baseClassName).toLowerCase();\n\n for (const [name, obj] of Object.entries(manifest.objects)) {\n const classNameLower = this.simpleClassName(obj.className).toLowerCase();\n const extendsLower = obj.extends\n ? this.simpleClassName(obj.extends).toLowerCase()\n : undefined;\n\n if (\n classNameLower === baseClassLower &&\n extendsLower === baseClassLower\n ) {\n continue;\n }\n\n if (extendsLower === baseClassLower) {\n descendants.push(name);\n descendants.push(\n ...this.findDescendantsInManifest(name, manifest, visited),\n );\n }\n }\n\n return descendants;\n }\n\n private applySqlTypeOverrides(obj: SmartObjectDefinition): void {\n if (!obj.schema?.columns) {\n return;\n }\n\n for (const [fieldName, field] of Object.entries(obj.fields || {})) {\n const sqlType = field?._meta?.sqlType;\n const referenceKind = this.getReferenceKind(field);\n if (!sqlType && !referenceKind) {\n continue;\n }\n\n const columnName = toSnakeCase(fieldName);\n if (!obj.schema.columns[columnName]) {\n continue;\n }\n\n obj.schema.columns[columnName] = {\n ...obj.schema.columns[columnName],\n ...(sqlType ? { type: String(sqlType).toUpperCase() } : {}),\n ...(referenceKind ? { referenceKind } : {}),\n };\n }\n }\n\n private getReferenceKind(\n field: SmartObjectDefinition['fields'][string] | undefined,\n ): ManifestColumnDefinition['referenceKind'] | undefined {\n if (field?._meta?.__tenancy?.isTenantIdField) {\n return 'tenantId';\n }\n\n if (field?.type === 'foreignKey') {\n return 'foreignKey';\n }\n\n if (field?.type === 'crossPackageRef') {\n return 'crossPackageRef';\n }\n\n return undefined;\n }\n\n /**\n * Create an aggregated manifest that includes objects from all external packages\n *\n * This is used for STI schema generation to ensure ALL descendants are found,\n * regardless of which package they're defined in.\n *\n * @param manifest - The local manifest\n * @returns Aggregated manifest with local + external objects\n */\n private createAggregatedManifest(\n manifest: SmartObjectManifest,\n ): SmartObjectManifest {\n // Start with a copy of local objects\n const aggregatedObjects: Record<string, SmartObjectDefinition> = {\n ...manifest.objects,\n };\n\n // Load and merge external package objects\n if (manifest.smrtDependencies && manifest.smrtDependencies.length > 0) {\n for (const packageName of manifest.smrtDependencies) {\n const externalManifest = loadExternalManifestSync(packageName);\n if (externalManifest) {\n // Merge external objects (local objects take precedence on collision)\n for (const [name, obj] of Object.entries(externalManifest.objects)) {\n if (!aggregatedObjects[name]) {\n aggregatedObjects[name] = obj;\n }\n }\n\n logger.debug(\n `[manifest-generator] Aggregated ${Object.keys(externalManifest.objects).length} objects from ${packageName}`,\n );\n }\n }\n }\n\n return {\n ...manifest,\n objects: aggregatedObjects,\n };\n }\n\n /**\n * Check if an object is an STI child class (inherits from STI base)\n *\n * Walks up the inheritance chain to find if any ancestor has tableStrategy: 'sti'.\n * Also checks external SMRT packages for parent class definitions.\n */\n private isSTIChildClass(\n obj: SmartObjectDefinition,\n manifest: SmartObjectManifest,\n ): boolean {\n if (!obj.extends) return false;\n\n // Build a lookup map for efficient access\n const objectsByName = new Map<string, SmartObjectDefinition>();\n for (const [_name, objDef] of Object.entries(manifest.objects)) {\n objectsByName.set(objDef.className, objDef);\n objectsByName.set(objDef.className.toLowerCase(), objDef);\n }\n\n // Walk up the inheritance chain looking for STI base\n let currentClass: string | undefined = obj.extends;\n const visited = new Set<string>();\n\n while (currentClass) {\n if (visited.has(currentClass)) break;\n visited.add(currentClass);\n\n let parentObj = objectsByName.get(currentClass);\n\n // If parent not in current manifest, try loading from external SMRT packages\n if (\n !parentObj &&\n manifest.smrtDependencies &&\n manifest.smrtDependencies.length > 0\n ) {\n parentObj = this.loadParentFromExternalPackage(\n currentClass,\n manifest.smrtDependencies,\n objectsByName,\n );\n }\n\n if (!parentObj) break; // Parent not found anywhere (e.g., SmrtObject)\n\n if (parentObj.decoratorConfig?.tableStrategy === 'sti') {\n return true; // Found STI ancestor\n }\n\n currentClass = parentObj.extends;\n }\n\n return false;\n }\n\n /**\n * Resolve a class name (simple `Content` or qualified `@pkg:Content`) to\n * the key it is stored under in `manifest.objects`, or `undefined` when the\n * manifest does not carry it. Manifest keys are qualified names; `extends`\n * and {@link findSTIBaseInfo} report simple names.\n */\n private resolveManifestKey(\n className: string,\n manifest: SmartObjectManifest,\n ): string | undefined {\n if (manifest.objects[className]) return className;\n const simpleName = className.includes(':')\n ? className.slice(className.lastIndexOf(':') + 1)\n : className;\n for (const [key, obj] of Object.entries(manifest.objects)) {\n if (obj.qualifiedName === className || obj.className === simpleName) {\n return key;\n }\n }\n return undefined;\n }\n\n /**\n * Find full STI base class info (className + tableName)\n *\n * Walks up the inheritance chain to find the STI base class and returns\n * both its className and tableName. This is critical for external STI bases\n * where the child needs to use the base's table name for schema generation.\n */\n private findSTIBaseInfo(\n obj: SmartObjectDefinition,\n manifest: SmartObjectManifest,\n ): { className: string; tableName: string } | undefined {\n if (!obj.extends) return undefined;\n\n // Build a lookup map for efficient access\n const objectsByName = new Map<string, SmartObjectDefinition>();\n for (const [_name, objDef] of Object.entries(manifest.objects)) {\n objectsByName.set(objDef.className, objDef);\n objectsByName.set(objDef.className.toLowerCase(), objDef);\n }\n\n // Track the oldest STI base found as we walk up\n // (we need to keep walking to find the ROOT STI class, not the first one)\n let stiBaseInfo: { className: string; tableName: string } | undefined;\n\n // Walk up the inheritance chain looking for the OLDEST STI base\n let currentClass: string | undefined = obj.extends;\n const visited = new Set<string>();\n\n while (currentClass) {\n if (visited.has(currentClass)) break;\n visited.add(currentClass);\n\n let parentObj = objectsByName.get(currentClass);\n\n // If parent not in current manifest, try loading from external SMRT packages\n if (\n !parentObj &&\n manifest.smrtDependencies &&\n manifest.smrtDependencies.length > 0\n ) {\n parentObj = this.loadParentFromExternalPackage(\n currentClass,\n manifest.smrtDependencies,\n objectsByName,\n );\n }\n\n if (!parentObj) break;\n\n if (parentObj.decoratorConfig?.tableStrategy === 'sti') {\n // Found an STI ancestor - it becomes the new candidate base\n // Keep walking to find the OLDEST/ROOT STI class in the hierarchy\n const tableName =\n parentObj.decoratorConfig?.tableName ||\n parentObj.schema?.tableName ||\n this.classNameToTableName(parentObj.className);\n stiBaseInfo = {\n className: parentObj.className,\n tableName,\n };\n }\n\n currentClass = parentObj.extends;\n }\n\n return stiBaseInfo; // Return the oldest STI ancestor found (or undefined if none)\n }\n\n /**\n * Convert class name to table name (snake_case pluralized)\n *\n * IMPORTANT: Must use the same algorithm as runtime's tableNameFromClass()\n * to ensure manifest-generated table names match runtime-derived names.\n */\n private classNameToTableName(className: string): string {\n // Use the shared pluralization function that handles English plurals correctly\n // (e.g., 'Currency' → 'currencies', 'JournalEntry' → 'journal_entries')\n return classnameToTablename(className);\n }\n\n private normalizeFrameworkInheritedField(\n ancestorName: string,\n fieldName: string,\n fieldDef: FieldDefinition,\n childClassName: string,\n ): FieldDefinition {\n if (\n this.simpleClassName(ancestorName) === 'SmrtHierarchical' &&\n fieldName === 'parentId'\n ) {\n return {\n ...fieldDef,\n type: 'foreignKey',\n related: childClassName,\n required: false,\n _meta: {\n ...(fieldDef._meta || {}),\n nullable: true,\n },\n };\n }\n\n return fieldDef;\n }\n\n private simpleClassName(className: string): string {\n return className.includes(':')\n ? className.split(':').pop() || className\n : className;\n }\n\n /**\n * Merge inherited fields into child classes (build-time inheritance resolution)\n *\n * For STI hierarchies, child classes don't define their own fields in source code\n * (they inherit from parent). This method merges parent fields into child manifests\n * so that runtime code doesn't need to do field resolution.\n *\n * Also handles collection classes (SmrtCollection<T>) that should inherit their\n * item class's tableName and collection when the item uses STI.\n *\n * Handles multi-level inheritance (grandparents, great-grandparents, etc.)\n * Automatically loads parent class definitions from external SMRT packages when needed\n *\n * @param manifest - The manifest to process in-place\n */\n public mergeInheritedFields(manifest: SmartObjectManifest): void {\n // Build a map of className -> objectDef for fast lookup\n const objectsByName = new Map<string, SmartObjectDefinition>();\n for (const [name, obj] of Object.entries(manifest.objects)) {\n objectsByName.set(obj.className, obj);\n // Also store by lowercase name for case-insensitive lookup\n objectsByName.set(obj.className.toLowerCase(), obj);\n }\n\n // FIRST PASS: Handle STI field merging and tableName inheritance\n // This must happen FIRST so that item classes (like Meeting) have their tableName\n // inherited from their STI base (like Event) before collection classes (like Meetings)\n // try to read it\n for (const obj of Object.values(manifest.objects)) {\n if (!obj.extends) continue; // No parent, skip\n\n // Always walk the chain below — fields and methods now have\n // independent merge rules (#2624):\n // FIELDS merge when ANY of:\n // (a) STI is in play — shared table with parent, full chain\n // merges.\n // (b) An ancestor in the chain is a framework abstract base class\n // (SmrtHierarchical, SmrtJunction, …) — those have no table of\n // their own, so structural fields they declare (e.g.\n // `SmrtHierarchical.parentId`) must propagate into every CTI\n // subclass's manifest, otherwise WHERE-clause validation\n // rejects queries against the inherited column.\n // For plain CTI through a user-defined base with its own table,\n // field merging is skipped per-ancestor below — each class keeps\n // its own table layout.\n // METHODS merge from every ancestor except framework base classes,\n // independent of STI/CTI — a concrete decorated ancestor's public\n // methods are real inherited API regardless of table strategy.\n // There is no early exit here for a \"plain CTI through a\n // user-defined base\" class: that is exactly the case whose\n // methods previously went unmerged (the under-report half of\n // #2624).\n const usesSTI = this.isSTIClass(obj, objectsByName, manifest);\n\n logger.debug(\n `[manifest-generator] Merging inherited fields for ${obj.className} from ${obj.extends}`,\n );\n\n // Build full inheritance chain (base -> child)\n const inheritanceChain: string[] = [];\n let currentClass: string | undefined = obj.extends;\n const visited = new Set<string>();\n\n while (currentClass) {\n if (visited.has(currentClass)) {\n logger.warn(\n `[manifest-generator] Circular inheritance detected for ${obj.className}`,\n );\n break;\n }\n visited.add(currentClass);\n inheritanceChain.unshift(currentClass); // Add to front (building base -> child)\n\n let parentObj = objectsByName.get(currentClass);\n\n // Skip self-reference: when a local class has the same name as its\n // imported parent (e.g., local Performer extends external Performer),\n // objectsByName returns the child itself. Skip it so we fall through\n // to the external package lookup.\n if (parentObj === obj) {\n parentObj = undefined;\n }\n\n // If parent not in current manifest, try loading from external SMRT packages\n if (\n !parentObj &&\n manifest.smrtDependencies &&\n manifest.smrtDependencies.length > 0\n ) {\n parentObj = this.loadParentFromExternalPackage(\n currentClass,\n manifest.smrtDependencies,\n objectsByName,\n );\n }\n\n if (!parentObj) break; // Parent not found anywhere (e.g., SmrtObject)\n currentClass = parentObj.extends;\n }\n\n logger.debug(\n `[manifest-generator] Inheritance chain for ${obj.className}: ${inheritanceChain.join(' -> ')}`,\n );\n\n // Merge fields from ancestors (base to child).\n //\n // STI path: pull in fields from every ancestor — they all share one\n // table.\n //\n // Non-STI (framework-base) path: pull in fields ONLY from framework\n // abstract bases (SmrtHierarchical, …). User-defined ancestors with\n // their own `@smrt()` decorator have their own tables in CTI, so\n // merging their columns onto a descendant would generate the wrong\n // schema.\n const mergedFields: Record<string, FieldDefinition> = {};\n const mergedFieldOwners = new Map<string, string>();\n const mergedMethods: Record<string, MethodDefinition> = {};\n\n for (const ancestorName of inheritanceChain) {\n const ancestor = objectsByName.get(ancestorName);\n if (!ancestor) continue;\n\n const ancestorIsFrameworkBase =\n FRAMEWORK_ABSTRACT_BASE_NAMES.has(ancestorName);\n\n // FIELDS: STI subclasses share one table, so every ancestor's\n // columns are needed. CTI subclasses pull fields only from framework\n // abstract bases — a concrete `@smrt()` ancestor has its own table,\n // so merging its columns here would generate the wrong schema.\n if (usesSTI || ancestorIsFrameworkBase) {\n // Keep the oldest concrete STI declaration, but let a concrete\n // class replace a framework abstract default. For example, Event\n // refines SmrtHierarchical.parentId with its relationship target\n // and an engine-scoped physical constraint. The local child's own\n // fields are still applied after this loop.\n for (const [fieldName, fieldDef] of Object.entries(ancestor.fields)) {\n const existingOwner = mergedFieldOwners.get(fieldName);\n const replacesFrameworkDefault =\n existingOwner !== undefined &&\n FRAMEWORK_ABSTRACT_BASE_NAMES.has(\n this.simpleClassName(existingOwner),\n ) &&\n !FRAMEWORK_ABSTRACT_BASE_NAMES.has(\n this.simpleClassName(ancestorName),\n );\n if (!existingOwner || replacesFrameworkDefault) {\n mergedFields[fieldName] = this.normalizeFrameworkInheritedField(\n ancestorName,\n fieldName,\n fieldDef,\n obj.className,\n );\n mergedFieldOwners.set(fieldName, ancestorName);\n }\n }\n }\n\n // METHODS (#2624): methods are not columns and never needed the\n // STI/CTI field rule above — they inherited it only by sharing the\n // loop. Give them their own rule instead: merge from every ancestor\n // except the universal object/collection primitives in\n // FRAMEWORK_METHOD_BASE_NAMES (see its doc comment — deliberately\n // narrower than FRAMEWORK_ABSTRACT_BASE_NAMES), independent of\n // `usesSTI`. This both stops STI subclasses from absorbing\n // `SmrtObject`/`SmrtClass`/`SmrtCollection` internals (over-merge)\n // and lets CTI subclasses inherit a concrete decorated ancestor's\n // own public methods (under-merge), matching the runtime resolver's\n // `getAllMethods()` — while still letting a framework abstract\n // base's own intended API (e.g. SmrtJunction.attach/detach,\n // SmrtHierarchical.getChildren) merge in, the same way its fields\n // already do.\n //\n // Assignment is unconditional (not \"first ancestor wins\"): the\n // outer loop walks `inheritanceChain` base-to-child, so a later\n // (more-derived) ancestor's override must replace an earlier one —\n // e.g. a middle class that overrides a grandparent method. This\n // matches the runtime resolver's own `getAllMethods()`, which\n // walks the same base-to-child order and does a plain `Map.set()`\n // per ancestor for the identical reason (see its \"Child methods\n // override parent methods (no merging)\" comment). The child's own\n // methods still win over everything via the unconditional\n // \"Add child's own methods\" step below.\n if (!FRAMEWORK_METHOD_BASE_NAMES.has(ancestorName)) {\n for (const [methodName, methodDef] of Object.entries(\n ancestor.methods || {},\n )) {\n mergedMethods[methodName] = methodDef;\n }\n }\n }\n\n // Add child's own fields (override any parent fields with same name)\n for (const [fieldName, fieldDef] of Object.entries(obj.fields)) {\n mergedFields[fieldName] = fieldDef;\n }\n\n // Add child's own methods\n for (const [methodName, methodDef] of Object.entries(obj.methods || {})) {\n mergedMethods[methodName] = methodDef;\n }\n\n // Update object definition with merged fields\n obj.fields = mergedFields;\n obj.methods = mergedMethods;\n\n // Inherit tableName and collection from STI base class\n // STI subclasses share the parent's table, so they should use the same collection name\n const stiBase = this.findSTIBase(obj, objectsByName, manifest);\n if (stiBase && stiBase !== obj) {\n // Determine the STI base's table name (explicit or derived from className)\n // Note: We don't use stiBase.collection as fallback because collection uses\n // lowercase-only format (e.g., 'querytestevents') while tableName needs\n // snake_case format (e.g., 'query_test_events')\n const baseTableName =\n stiBase.decoratorConfig?.tableName ||\n this.classNameToTableName(stiBase.className);\n\n // Inherit tableName from STI base\n obj.decoratorConfig = obj.decoratorConfig || {};\n obj.decoratorConfig.tableName = baseTableName;\n logger.debug(\n `[manifest-generator] ${obj.className} inherits tableName: '${baseTableName}' from ${stiBase.className}`,\n );\n\n // Inherit tableStrategy from STI base (so runtime doesn't need to walk inheritance chain)\n if (stiBase.decoratorConfig?.tableStrategy) {\n obj.decoratorConfig.tableStrategy =\n stiBase.decoratorConfig.tableStrategy;\n logger.debug(\n `[manifest-generator] ${obj.className} inherits tableStrategy: '${stiBase.decoratorConfig.tableStrategy}' from ${stiBase.className}`,\n );\n }\n\n // Inherit collection name from STI base (all STI classes share one table)\n if (stiBase.collection !== obj.collection) {\n logger.debug(\n `[manifest-generator] ${obj.className} inherits collection: '${stiBase.collection}' from ${stiBase.className}`,\n );\n obj.collection = stiBase.collection;\n }\n }\n\n logger.debug(\n `[manifest-generator] ✅ ${obj.className} now has ${Object.keys(mergedFields).length} fields (including inherited)`,\n );\n }\n\n // SECOND PASS: Handle collection classes that should inherit from their item class\n // This must happen AFTER STI field merging so item classes have their tableName set\n for (const obj of Object.values(manifest.objects)) {\n // Check if this is a collection class (extends SmrtCollection)\n const isCollection =\n obj.extends === 'SmrtCollection' ||\n this.extendsCollection(obj, objectsByName);\n\n if (isCollection) {\n // Find the item class from _itemClass static property\n const itemClass = this.findItemClass(obj, manifest, objectsByName);\n\n if (itemClass) {\n logger.debug(\n `[manifest-generator] ${obj.className} is a collection class for ${itemClass.className}`,\n );\n\n // Inherit tableName from item class (which may have inherited it from STI base)\n if (itemClass.decoratorConfig?.tableName) {\n obj.decoratorConfig = obj.decoratorConfig || {};\n obj.decoratorConfig.tableName = itemClass.decoratorConfig.tableName;\n logger.debug(\n `[manifest-generator] ${obj.className} inherits tableName: '${itemClass.decoratorConfig.tableName}' from item class ${itemClass.className}`,\n );\n }\n\n // Inherit collection name from item class\n if (itemClass.collection !== obj.collection) {\n logger.debug(\n `[manifest-generator] ${obj.className} inherits collection: '${itemClass.collection}' from item class ${itemClass.className} (was '${obj.collection}')`,\n );\n obj.collection = itemClass.collection;\n }\n\n // Inherit a full route opt-out (api/mcp/cli === false) from the\n // item class unless the collection class explicitly overrides it\n // itself. Decorator-only registration never gives an undecorated\n // collection its own independent route surface, so an item class\n // that fully opts out of generated routes (e.g. api: false for a\n // tenant-isolation fail-closed class such as SmrtJob, #2750) must\n // not leave its collection independently advertised in the\n // manifest path.\n //\n // Deliberately scoped to the boolean `false` opt-out only, never\n // to an object-form config (e.g. `{ include: [...] }`): those\n // configs list method names specific to the ITEM class's own\n // instance methods, which do not correspond 1:1 to the\n // COLLECTION class's methods of the same name (different\n // signatures, e.g. a bulk/collection `create` vs. a single-record\n // `create`) -- copying them verbatim previously broke unrelated\n // packages whose item class narrows its own api/cli/mcp surface\n // with an include list (e.g. @happyvertical/smrt-subscriptions's\n // TenantUsageMetric), producing a spurious \"CLI command not\n // exposed via the api\" build error on the collection.\n for (const key of ['api', 'mcp', 'cli'] as const) {\n const itemValue = itemClass.decoratorConfig?.[key];\n if (\n itemValue === false &&\n obj.decoratorConfig?.[key] === undefined\n ) {\n obj.decoratorConfig = obj.decoratorConfig || {};\n obj.decoratorConfig[key] = false;\n logger.debug(\n `[manifest-generator] ${obj.className} inherits ${key}: false from item class ${itemClass.className}`,\n );\n }\n }\n }\n }\n }\n }\n\n /**\n * Check if a class extends SmrtCollection (directly or indirectly)\n *\n * @param obj - The object definition to check\n * @param objectsByName - Map of className -> objectDef for lookups\n * @returns true if this class extends SmrtCollection\n */\n private extendsCollection(\n obj: SmartObjectDefinition,\n objectsByName: Map<string, SmartObjectDefinition>,\n ): boolean {\n if (!obj.extends) return false;\n\n // Walk up inheritance chain looking for SmrtCollection\n let currentClass: string | undefined = obj.extends;\n const visited = new Set<string>();\n\n while (currentClass) {\n if (visited.has(currentClass)) break;\n visited.add(currentClass);\n\n if (currentClass === 'SmrtCollection') return true;\n\n const parentObj = objectsByName.get(currentClass);\n if (!parentObj) break;\n\n currentClass = parentObj.extends;\n }\n\n return false;\n }\n\n /**\n * Find the item class for a collection class\n *\n * Lookup priority:\n * 1. extendsTypeArg - Generic type argument from extends clause (e.g., \"Meeting\" from SmrtCollection<Meeting>)\n * 2. _itemClass static property - May be captured by AST scanner\n * 3. Name-based inference - Fallback (e.g., \"Meetings\" -> \"Meeting\")\n *\n * @param collectionObj - The collection class definition\n * @param manifest - The manifest\n * @param objectsByName - Map of className -> objectDef for lookups\n * @returns Item class definition or undefined\n */\n private findItemClass(\n collectionObj: SmartObjectDefinition,\n manifest: SmartObjectManifest,\n objectsByName: Map<string, SmartObjectDefinition>,\n ): SmartObjectDefinition | undefined {\n // PRIORITY 1: Use generic type argument from extends clause\n // This is the most reliable method: SmrtCollection<Meeting> -> \"Meeting\"\n if (collectionObj.extendsTypeArg) {\n const itemClassName = collectionObj.extendsTypeArg;\n logger.debug(\n `[manifest-generator] ${collectionObj.className} has extendsTypeArg: ${itemClassName}`,\n );\n\n // Try to find the item class by name in local manifest\n const itemClass = objectsByName.get(itemClassName);\n if (itemClass) {\n logger.debug(\n `[manifest-generator] Found item class ${itemClassName} in local manifest`,\n );\n return itemClass;\n }\n\n // Try loading from external packages\n if (manifest.smrtDependencies && manifest.smrtDependencies.length > 0) {\n const externalItemClass = this.loadParentFromExternalPackage(\n itemClassName,\n manifest.smrtDependencies,\n objectsByName,\n );\n if (externalItemClass) {\n logger.debug(\n `[manifest-generator] Found item class ${itemClassName} in external package`,\n );\n return externalItemClass;\n }\n }\n }\n\n // PRIORITY 2: Look for _itemClass static field in the collection class\n // This is defined like: static readonly _itemClass = Meeting;\n // Note: AST scanner currently skips static properties, so this rarely works\n const itemClassField = collectionObj.fields._itemClass;\n\n if (itemClassField) {\n // Extract class name from the field's default value or metadata\n // The AST scanner might capture this as a reference\n const itemClassName = itemClassField.related || itemClassField.default;\n\n if (itemClassName && typeof itemClassName === 'string') {\n // Try to find the item class by name\n const itemClass = objectsByName.get(itemClassName);\n if (itemClass) {\n return itemClass;\n }\n\n // Try loading from external packages\n if (manifest.smrtDependencies && manifest.smrtDependencies.length > 0) {\n return this.loadParentFromExternalPackage(\n itemClassName,\n manifest.smrtDependencies,\n objectsByName,\n );\n }\n }\n }\n\n // PRIORITY 3: Fallback - Try to infer from collection class name\n // Generate candidate item class names and check if they exist\n const collectionName = collectionObj.className;\n const candidates: string[] = [];\n\n // Strip \"Collection\" suffix first if present\n let baseName = collectionName;\n if (baseName.endsWith('Collection')) {\n baseName = baseName.slice(0, -'Collection'.length);\n }\n\n // Generate singularization candidates (order matters - try most specific first)\n // 1. Exact name (e.g., \"Event\" from \"EventCollection\")\n candidates.push(baseName);\n\n // 2. Remove trailing 's' (e.g., \"Meetings\" -> \"Meeting\")\n if (baseName.endsWith('s') && baseName.length > 1) {\n candidates.push(baseName.slice(0, -1));\n }\n\n // 3. Handle 'ies' -> 'y' (e.g., \"Categories\" -> \"Category\")\n if (baseName.endsWith('ies') && baseName.length > 3) {\n candidates.push(`${baseName.slice(0, -3)}y`);\n }\n\n // 4. Handle 'es' -> '' for words ending in s/x/z/ch/sh (e.g., \"Statuses\" -> \"Status\")\n if (baseName.endsWith('es') && baseName.length > 2) {\n candidates.push(baseName.slice(0, -2));\n }\n\n // Try each candidate against local classes first, then external packages\n // Skip candidates that match the collection class itself\n for (const candidate of candidates) {\n if (candidate === collectionObj.className) continue; // Don't match self\n const itemClass = objectsByName.get(candidate);\n if (itemClass) {\n return itemClass;\n }\n }\n\n // Try loading from external packages\n if (manifest.smrtDependencies && manifest.smrtDependencies.length > 0) {\n for (const candidate of candidates) {\n if (candidate === collectionObj.className) continue; // Don't match self\n const itemClass = this.loadParentFromExternalPackage(\n candidate,\n manifest.smrtDependencies,\n objectsByName,\n );\n if (itemClass) {\n return itemClass;\n }\n }\n }\n\n return undefined;\n }\n\n /**\n * Check if a class uses STI (either explicitly or inherited from an ancestor)\n *\n * Walks up the inheritance chain to find if any ancestor has tableStrategy: 'sti'.\n * If found, all descendants inherit STI and should have fields merged.\n * Also checks external SMRT packages for parent class definitions.\n *\n * @param obj - The object definition to check\n * @param objectsByName - Map of className -> objectDef for lookups\n * @param manifest - The manifest (for accessing smrtDependencies)\n * @returns true if this class uses STI (directly or inherited)\n */\n private isSTIClass(\n obj: SmartObjectDefinition,\n objectsByName: Map<string, SmartObjectDefinition>,\n manifest: SmartObjectManifest,\n ): boolean {\n // Check if explicitly marked as STI\n if (obj.decoratorConfig?.tableStrategy === 'sti') {\n return true;\n }\n\n // Walk up the inheritance chain looking for STI base\n let currentClass: string | undefined = obj.extends;\n const visited = new Set<string>();\n\n while (currentClass) {\n if (visited.has(currentClass)) {\n break; // Circular inheritance, stop\n }\n visited.add(currentClass);\n\n let parentDef = objectsByName.get(currentClass);\n\n // Skip self-reference (local class with same name as imported parent)\n if (parentDef === obj) {\n parentDef = undefined;\n }\n\n // If parent not in current manifest, try loading from external SMRT packages\n if (\n !parentDef &&\n manifest.smrtDependencies &&\n manifest.smrtDependencies.length > 0\n ) {\n parentDef = this.loadParentFromExternalPackage(\n currentClass,\n manifest.smrtDependencies,\n objectsByName,\n );\n }\n\n if (!parentDef) break; // Parent not found anywhere\n\n // Check if this ancestor uses STI\n if (parentDef.decoratorConfig?.tableStrategy === 'sti') {\n return true; // Found STI ancestor\n }\n\n currentClass = parentDef.extends;\n }\n\n return false; // No STI in hierarchy\n }\n\n /**\n * Find the STI base class for a given object\n *\n * Walks up the inheritance chain to find the first ancestor that defines\n * tableStrategy: 'sti'. This is the class that owns the shared table.\n *\n * @param obj - The object definition to find the STI base for\n * @param objectsByName - Map of className -> objectDef for lookups\n * @param manifest - The manifest (for accessing smrtDependencies)\n * @returns The STI base class definition, or the object itself if it's the base\n */\n private findSTIBase(\n obj: SmartObjectDefinition,\n objectsByName: Map<string, SmartObjectDefinition>,\n manifest: SmartObjectManifest,\n ): SmartObjectDefinition | undefined {\n // Track the oldest STI class found as we walk up\n let stiBase: SmartObjectDefinition | undefined;\n\n // If this object explicitly defines STI, it's a candidate (but ancestors may also be STI)\n if (obj.decoratorConfig?.tableStrategy === 'sti') {\n stiBase = obj;\n }\n\n // Walk up the inheritance chain looking for the oldest STI base\n let currentClass: string | undefined = obj.extends;\n const visited = new Set<string>();\n\n while (currentClass) {\n if (visited.has(currentClass)) {\n break; // Circular inheritance, stop\n }\n visited.add(currentClass);\n\n let parentDef = objectsByName.get(currentClass);\n\n // Skip self-reference (local class with same name as imported parent)\n if (parentDef === obj) {\n parentDef = undefined;\n }\n\n // If parent not in current manifest, try loading from external SMRT packages\n if (\n !parentDef &&\n manifest.smrtDependencies &&\n manifest.smrtDependencies.length > 0\n ) {\n parentDef = this.loadParentFromExternalPackage(\n currentClass,\n manifest.smrtDependencies,\n objectsByName,\n );\n }\n\n if (!parentDef) break; // Parent not found anywhere\n\n // Check if this ancestor defines STI - if so, it becomes the new candidate base\n // (we keep walking to find the oldest/root STI class)\n if (parentDef.decoratorConfig?.tableStrategy === 'sti') {\n stiBase = parentDef;\n }\n\n currentClass = parentDef.extends;\n }\n\n return stiBase; // Return the oldest STI ancestor found (or undefined if none)\n }\n\n /**\n * Load parent class definition from external SMRT packages\n *\n * When a child class extends a parent from an external package (e.g., praeco's Council extends\n * smrt-profiles' Organization), this method loads the parent's manifest and extracts the\n * parent's field definitions.\n *\n * @param parentClassName - Name of the parent class to find\n * @param smrtDependencies - List of external SMRT packages to search\n * @param objectsByName - Map to cache loaded external objects\n * @returns Parent object definition if found, undefined otherwise\n */\n private loadParentFromExternalPackage(\n parentClassName: string,\n smrtDependencies: string[],\n objectsByName: Map<string, SmartObjectDefinition>,\n ): SmartObjectDefinition | undefined {\n // Try each external SMRT dependency\n for (const packageName of smrtDependencies) {\n const externalManifest = loadExternalManifestSync(packageName);\n\n if (!externalManifest) {\n continue;\n }\n\n // Use lookupInManifest for O(1) lookup via cached className index\n // Handles both qualified names and simple class names\n const parentObj = lookupInManifest(externalManifest, parentClassName);\n\n if (parentObj) {\n // Cache the loaded parent object for future lookups\n objectsByName.set(parentObj.className, parentObj);\n objectsByName.set(parentObj.className.toLowerCase(), parentObj);\n\n return parentObj;\n }\n }\n\n return undefined;\n }\n\n /**\n * Determine import path from package.json exports\n *\n * Tries the following strategies in order:\n * 1. package.json exports[\"./objects\"] - Specific objects export\n * 2. package.json exports[\".\"] - Main export\n * 3. package.json main - Main field\n * 4. Fallback to package name\n */\n /**\n * Determine the specifier consumers should import an object from.\n *\n * `filePath` was accepted (and ignored — the parameter was named\n * `_filePath`) since before this fix, so every object always resolved to\n * the bare package name regardless of where it actually lived. That is\n * wrong for an object scanned from a file only a non-root `exports`\n * subpath serves (e.g. `./server`): the manifest advertised the object as\n * importable from the package root, but the root bundle never exports it,\n * so a consumer dynamically importing by manifest metadata (or generating\n * `.smrt/register.js`, `consumer-plugin/index.ts`'s own\n * `determineImportPath`) silently failed to find it. That is smrt#2845 —\n * `DataSurfaceActionIdempotencyState` in `@happyvertical/smrt-agents` lives\n * under `src/server/` (served only by the `./server` export), but the\n * manifest pointed consumers at the bare `@happyvertical/smrt-agents`\n * specifier.\n *\n * Strategy: match `filePath` against the package's `exports` subpaths —\n * `src/<segment>/...` or `src/<segment>.ts` maps to the `./<segment>`\n * export key — and prefer the longest matching segment. Falls back to the\n * legacy behavior (bare package name, with the `./objects` special case)\n * when the file does not match any subpath, which covers objects reachable\n * from the root `.` entry point.\n */\n private determineImportPath(\n packageJson: PackageJsonLike,\n filePath?: string,\n ): string {\n // Only invoked once a package name is known (guarded at the call site),\n // so `name` is always present here.\n const packageName = packageJson.name as string;\n\n if (packageJson.exports && typeof packageJson.exports === 'object') {\n const subpathSegment = this.matchExportsSubpath(\n packageJson.exports,\n filePath,\n );\n if (subpathSegment) {\n return `${packageName}/${subpathSegment}`;\n }\n\n // Legacy special case, kept for packages whose `./objects` export\n // predates file-path-based matching and whose objects' `filePath`\n // does not follow the `src/objects/...` convention above.\n if (packageJson.exports['./objects']) {\n return `${packageName}/objects`;\n }\n }\n\n // Strategy 2/3: main field or bare fallback — both resolve to the\n // package root, which is where an unmatched object is assumed to live.\n return packageName;\n }\n\n /**\n * Match a scanned object's `filePath` against a package's `exports` map,\n * returning the longest matching non-root subpath segment (e.g. `\"server\"`\n * for `./server`), or `undefined` when the file does not correspond to any\n * declared subpath (the object is assumed reachable from the root `.`\n * entry point instead).\n */\n private matchExportsSubpath(\n exportsMap: Record<string, unknown>,\n filePath?: string,\n ): string | undefined {\n if (!filePath) return undefined;\n\n const normalized = filePath.replace(/\\\\/g, '/');\n const srcMarker = 'src/';\n const srcIndex = normalized.lastIndexOf(srcMarker);\n if (srcIndex === -1) return undefined;\n const relativeToSrc = normalized.slice(srcIndex + srcMarker.length);\n\n // Path components with any source-file extension stripped from the last\n // one, so `lib/models/Category.ts` and `server.js` both compare as plain\n // component lists (`['lib','models','Category']`, `['server']`).\n const pathParts = relativeToSrc.split('/');\n const lastIndex = pathParts.length - 1;\n pathParts[lastIndex] = pathParts[lastIndex].replace(\n /\\.(ts|tsx|js|jsx|mjs|cjs)$/,\n '',\n );\n\n const segments = Object.keys(exportsMap)\n .filter(\n (key) =>\n key !== '.' &&\n key !== './package.json' &&\n !key.includes('*') &&\n // Exclude subpaths that resolve to a non-JS asset (e.g. the\n // `./manifest`/`./manifest.json` convention pointing at\n // `dist/manifest.json`). No @smrt object's source file can ever\n // legitimately resolve there, so this only guards against a\n // coincidental `src/manifest/...` path being misattributed to it.\n !targetsJsonAsset(exportsMap[key]),\n )\n .map((key) => key.replace(/^\\.\\//, ''))\n .filter((segment) => segment.length > 0)\n // Longest first so a nested segment (rare) wins over a shorter prefix.\n .sort((a, b) => b.length - a.length);\n\n return segments.find((segment) => {\n const segmentParts = segment.split('/');\n // Match the segment's components as a contiguous run anywhere in the\n // file's path — not just a root-level prefix. Handles both a direct\n // subpath directory (`server/x.ts` for `./server`) and a re-export\n // barrel whose real source lives deeper than its export key implies\n // (`@happyvertical/smrt-products`: `./models` -> `src/models.ts` ->\n // `export * from './lib/models/index'`, with the actual `@smrt()`\n // classes scanned from `src/lib/models/*.ts` — `relativeToSrc` is\n // `lib/models/Category.ts`, which contains `models` as a component,\n // just not at index 0).\n for (\n let start = 0;\n start <= pathParts.length - segmentParts.length;\n start++\n ) {\n if (\n segmentParts.every(\n (part, offset) => pathParts[start + offset] === part,\n )\n ) {\n return true;\n }\n }\n return false;\n });\n }\n\n /**\n * Generate TypeScript interfaces from manifest\n */\n generateTypeDefinitions(manifest: SmartObjectManifest): string {\n const interfaces: string[] = [];\n\n // Manifest key order follows scan/discovery order, which is not stable\n // across runs (#2749): the vite-plugin's server-mode `@smrt/types`\n // resolution calls this method directly, so sort deterministically\n // before emitting for the same reason as the prebuild/client-mode paths.\n const sortedEntries = Object.entries(manifest.objects).sort(\n ([leftKey, left], [rightKey, right]) =>\n compareText(\n left.qualifiedName || leftKey,\n right.qualifiedName || rightKey,\n ) || compareText(leftKey, rightKey),\n );\n for (const [_name, obj] of sortedEntries) {\n interfaces.push(this.generateInterface(obj));\n }\n\n return interfaces.join('\\n\\n');\n }\n\n /**\n * Generate a single interface definition\n */\n private generateInterface(obj: SmartObjectDefinition): string {\n const fields = Object.entries(obj.fields)\n .map(([name, field]) => {\n const optional = !field.required ? '?' : '';\n const type = this.mapFieldTypeToTS(field.type);\n return ` ${name}${optional}: ${type};`;\n })\n .join('\\n');\n\n return `export interface ${obj.className}Data {\n${fields}\n}`;\n }\n\n /**\n * Map field types to TypeScript types\n */\n private mapFieldTypeToTS(fieldType: string): string {\n switch (fieldType) {\n case 'text':\n return 'string';\n case 'decimal':\n return 'number';\n case 'integer':\n return 'number';\n case 'boolean':\n return 'boolean';\n case 'datetime':\n return 'Date | string';\n case 'json':\n return 'any';\n case 'foreignKey':\n return 'string';\n case 'crossPackageRef':\n return 'string';\n default:\n return 'any';\n }\n }\n\n /**\n * Generate simple endpoint list for testing/documentation\n */\n generateRestEndpoints(manifest: SmartObjectManifest): string {\n const endpoints: string[] = [];\n\n for (const [_name, obj] of Object.entries(manifest.objects)) {\n const apiConfig = obj.decoratorConfig.api;\n if (apiConfig !== false) {\n endpoints.push(...this.getSimpleEndpoints(obj, manifest));\n }\n }\n\n return endpoints.join('\\n');\n }\n\n /**\n * Generate REST endpoint code implementations\n */\n generateRestEndpointCode(manifest: SmartObjectManifest): string {\n const endpoints: string[] = [];\n\n for (const [_name, obj] of Object.entries(manifest.objects)) {\n const apiConfig = obj.decoratorConfig.api;\n if (apiConfig !== false) {\n endpoints.push(this.generateRestEndpoint(obj));\n }\n }\n\n return endpoints.join('\\n\\n');\n }\n\n /**\n * Get simple endpoint strings for an object\n */\n private getApiRouteMetadata(\n obj: SmartObjectDefinition,\n actionName: string,\n actionDef: MethodDefinition | { isStatic?: boolean },\n ): {\n scope: 'item' | 'collection';\n method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';\n path: string;\n } {\n const config =\n obj.decoratorConfig.api && typeof obj.decoratorConfig.api === 'object'\n ? obj.decoratorConfig.api\n : undefined;\n // `@method({ httpMethod, path })` wins field by field over the class-level\n // `api.routes[action]` entry, the same merge `resolveApiActionRouteConfig`\n // and the knowledge artifact perform. Reading `routes` alone printed the\n // PRE-migration verb and path for a class that had moved to the decorator\n // (#2686).\n const effective = resolveEffectiveActionMetadata({\n actionName,\n method: actionDef,\n apiConfig: config,\n });\n const normalizedPath = (effective.path || actionName)\n .split('/')\n .map((segment) => segment.trim())\n .filter(Boolean)\n .join('/');\n const isCollectionClass =\n obj.extends === 'SmrtCollection' || !!obj.extendsTypeArg;\n\n const defaultScope =\n isCollectionClass || actionDef.isStatic ? 'collection' : 'item';\n\n return {\n scope: resolveCustomActionMetadata({\n actionName,\n method: actionDef,\n apiConfig: config,\n defaultScope,\n }).scope,\n method: effective.httpMethod ?? 'POST',\n path: normalizedPath || actionName,\n };\n }\n\n private getSimpleEndpoints(\n obj: SmartObjectDefinition,\n manifest?: SmartObjectManifest,\n ): string[] {\n const { collection } = obj;\n const config = obj.decoratorConfig.api;\n const exclude = (typeof config === 'object' && config?.exclude) || [];\n const include =\n (typeof config === 'object' && config?.include) || undefined;\n const isCollectionClass =\n obj.extends === 'SmrtCollection' || !!obj.extendsTypeArg;\n const isModelClassName = createManifestClassNamePredicate(manifest);\n\n const endpoints: string[] = [];\n\n // Determine which operations to include\n const shouldInclude = (op: string) => {\n if (include && !include.includes(op)) return false;\n if (exclude.includes(op)) return false;\n return true;\n };\n\n if (!isCollectionClass) {\n if (shouldInclude('list')) {\n endpoints.push(`GET /${collection}`);\n }\n if (shouldInclude('create')) {\n endpoints.push(`POST /${collection}`);\n }\n if (shouldInclude('get')) {\n endpoints.push(`GET /${collection}/:id`);\n }\n if (shouldInclude('update')) {\n endpoints.push(`PUT /${collection}/:id`);\n }\n if (shouldInclude('delete')) {\n endpoints.push(`DELETE /${collection}/:id`);\n }\n }\n\n // Custom actions read the ONE shared exposure resolver rather than a local\n // copy of the include/exclude rule. This listing is a published virtual\n // module (`@happyvertical/smrt-virt-routes`), so a stale rule here\n // advertises operations whose routes the emitters never wrote -- exactly\n // the consumer disagreement #2686 exists to close.\n for (const [actionName, actionDef] of Object.entries(obj.methods)) {\n if (\n !resolveApiMethodExposure({\n actionName,\n method: actionDef,\n apiConfig: config,\n isCollectionClass,\n ...(isModelClassName ? { isModelClassName } : {}),\n }).exposed\n ) {\n continue;\n }\n\n const route = this.getApiRouteMetadata(obj, actionName, actionDef);\n const suffix = route.scope === 'collection' ? '' : '/:id';\n endpoints.push(`${route.method} /${collection}${suffix}/${route.path}`);\n }\n\n return endpoints;\n }\n\n /**\n * Generate a single REST endpoint\n */\n private generateRestEndpoint(obj: SmartObjectDefinition): string {\n const { collection, className } = obj;\n const config = obj.decoratorConfig.api;\n const exclude = (typeof config === 'object' && config?.exclude) || [];\n const include =\n (typeof config === 'object' && config?.include) || undefined;\n\n const operations = [];\n\n // Determine which operations to include\n const shouldInclude = (op: string) => {\n if (include && !include.includes(op)) return false;\n if (exclude.includes(op)) return false;\n return true;\n };\n\n if (shouldInclude('list')) {\n operations.push(` // GET /${collection} - List ${collection}`);\n operations.push(` app.get('/${collection}', async (req: Request) => {`);\n operations.push(\n ` const collection = await get${className}Collection();`,\n );\n operations.push(' const items = await collection.list(req.query);');\n operations.push(' return Response.json(items);');\n operations.push(' });');\n }\n\n if (shouldInclude('get')) {\n operations.push(` // GET /${collection}/:id - Get ${className}`);\n operations.push(\n ` app.get('/${collection}/:id', async (req: Request) => {`,\n );\n operations.push(\n ` const collection = await get${className}Collection();`,\n );\n operations.push(' const item = await collection.get(req.params.id);');\n operations.push(\n ` if (!item) return new Response('Not found', { status: 404 });`,\n );\n operations.push(' return Response.json(item);');\n operations.push(' });');\n }\n\n if (shouldInclude('create')) {\n operations.push(` // POST /${collection} - Create ${className}`);\n operations.push(` app.post('/${collection}', async (req: Request) => {`);\n operations.push(\n ` const collection = await get${className}Collection();`,\n );\n operations.push(' const data = await req.json();');\n operations.push(' const item = await collection.create(data);');\n operations.push(' return Response.json(item, { status: 201 });');\n operations.push(' });');\n }\n\n if (shouldInclude('update')) {\n operations.push(` // PUT /${collection}/:id - Update ${className}`);\n operations.push(\n ` app.put('/${collection}/:id', async (req: Request) => {`,\n );\n operations.push(\n ` const collection = await get${className}Collection();`,\n );\n operations.push(' const data = await req.json();');\n operations.push(\n ' const item = await collection.update(req.params.id, data);',\n );\n operations.push(\n ` if (!item) return new Response('Not found', { status: 404 });`,\n );\n operations.push(' return Response.json(item);');\n operations.push(' });');\n }\n\n if (shouldInclude('delete')) {\n operations.push(` // DELETE /${collection}/:id - Delete ${className}`);\n operations.push(\n ` app.delete('/${collection}/:id', async (req: Request) => {`,\n );\n operations.push(\n ` const collection = await get${className}Collection();`,\n );\n operations.push(\n ' const success = await collection.delete(req.params.id);',\n );\n operations.push(\n ` if (!success) return new Response('Not found', { status: 404 });`,\n );\n operations.push(` return new Response('', { status: 204 });`);\n operations.push(' });');\n }\n\n return `// ${className} endpoints\\n${operations.join('\\n')}`;\n }\n\n /**\n * Generate simple MCP tool names for testing/documentation\n */\n generateMCPTools(manifest: SmartObjectManifest): string {\n const tools: string[] = [];\n\n for (const obj of this.selectMCPToolOwners(manifest)) {\n tools.push(...this.getSimpleMCPToolNames(obj));\n }\n\n return tools.join('\\n');\n }\n\n /**\n * Choose exactly one canonical MCP owner per `collection`.\n *\n * MCP tool names are keyed on `collection`, but the framework's normal shape\n * puts a model class and its `FooCollection` access class in the manifest\n * under the SAME collection. Emitting both produces duplicate tool names with\n * differing create/update schemas, and an MCP client that indexes tools by\n * name then resolves an arbitrary one (#2631 review).\n *\n * Owners are ranked, in order:\n *\n * 1. The model class beats the collection-access class. `create`/`update`\n * input schemas derive from `obj.fields`, and the row shape lives on the\n * model, not on the access class.\n * 2. The shallowest class in the collection's own inheritance tree wins. An\n * STI family shares one `collection`, and the base defines the shared row\n * contract; a leaf subclass would narrow the emitted schema to one variant\n * of a table the tool addresses as a whole.\n * 3. Remaining ties break lexically on the qualified name, so the emitted\n * surface is deterministic across generation passes.\n */\n private selectMCPToolOwners(\n manifest: SmartObjectManifest,\n ): SmartObjectDefinition[] {\n const candidatesByCollection = new Map<string, SmartObjectDefinition[]>();\n\n for (const obj of Object.values(manifest.objects)) {\n if (obj.decoratorConfig.mcp === false) continue;\n const bucket = candidatesByCollection.get(obj.collection);\n if (bucket) bucket.push(obj);\n else candidatesByCollection.set(obj.collection, [obj]);\n }\n\n return [...candidatesByCollection.entries()]\n .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))\n .map(([, candidates]) => {\n const depths = this.inheritanceDepthsWithin(candidates);\n let owner = candidates[0];\n for (const candidate of candidates.slice(1)) {\n if (this.preferMCPToolOwner(candidate, owner, depths)) {\n owner = candidate;\n }\n }\n return owner;\n });\n }\n\n /** Stable identity for an MCP owner candidate. */\n private mcpOwnerKey(obj: SmartObjectDefinition): string {\n return obj.qualifiedName || obj.className;\n }\n\n /**\n * Depth of each candidate inside the candidate set's OWN inheritance tree,\n * keyed by {@link mcpOwnerKey}. A candidate with no candidate ancestor is a\n * root at depth 0. Ancestors outside the set (framework bases, classes in\n * other collections) do not add depth: only the shared-collection family\n * decides which member is canonical.\n *\n * Parents resolve on `extendsQualified` first. Two packages may legally\n * contribute same-simple-name classes to one collection, so a simple-name\n * match is used only when it is unambiguous within the candidate set —\n * otherwise the walk stops rather than linking unrelated classes.\n */\n private inheritanceDepthsWithin(\n candidates: SmartObjectDefinition[],\n ): Map<string, number> {\n const byQualified = new Map<string, SmartObjectDefinition>();\n const bySimpleName = new Map<string, SmartObjectDefinition | null>();\n for (const candidate of candidates) {\n byQualified.set(this.mcpOwnerKey(candidate), candidate);\n const simple = this.simpleClassName(candidate.className);\n // `null` marks an ambiguous simple name; never resolve through it.\n bySimpleName.set(simple, bySimpleName.has(simple) ? null : candidate);\n }\n\n const resolveParent = (\n obj: SmartObjectDefinition,\n ): SmartObjectDefinition | undefined => {\n if (obj.extendsQualified) return byQualified.get(obj.extendsQualified);\n if (!obj.extends) return undefined;\n return bySimpleName.get(this.simpleClassName(obj.extends)) ?? undefined;\n };\n\n const depths = new Map<string, number>();\n for (const candidate of candidates) {\n const key = this.mcpOwnerKey(candidate);\n let depth = 0;\n let current: SmartObjectDefinition | undefined = candidate;\n const visited = new Set<string>([key]);\n while (current) {\n const parent: SmartObjectDefinition | undefined =\n resolveParent(current);\n if (!parent) break;\n const parentKey = this.mcpOwnerKey(parent);\n // Circular or self-referential extends: stop rather than loop.\n if (visited.has(parentKey)) break;\n visited.add(parentKey);\n depth += 1;\n current = parent;\n }\n depths.set(key, depth);\n }\n return depths;\n }\n\n /** True when `candidate` is the better canonical MCP owner than `current`. */\n private preferMCPToolOwner(\n candidate: SmartObjectDefinition,\n current: SmartObjectDefinition,\n depths: Map<string, number>,\n ): boolean {\n const candidateIsCollection = this.isCollectionAccessClass(candidate);\n const currentIsCollection = this.isCollectionAccessClass(current);\n if (candidateIsCollection !== currentIsCollection) {\n return !candidateIsCollection;\n }\n\n const candidateKey = this.mcpOwnerKey(candidate);\n const currentKey = this.mcpOwnerKey(current);\n\n const candidateDepth = depths.get(candidateKey) ?? 0;\n const currentDepth = depths.get(currentKey) ?? 0;\n if (candidateDepth !== currentDepth) {\n return candidateDepth < currentDepth;\n }\n\n return candidateKey < currentKey;\n }\n\n /**\n * Collection-access class detection, matching the convention already used by\n * `generateRestRoutes` (direct base / generic type argument) plus the\n * `FooCollection` naming fallback this generator uses elsewhere, so a deeper\n * subclass that carries no type argument of its own is still recognised.\n */\n private isCollectionAccessClass(obj: SmartObjectDefinition): boolean {\n return (\n obj.extends === 'SmrtCollection' ||\n !!obj.extendsTypeArg ||\n obj.className.endsWith('Collection')\n );\n }\n\n /**\n * Generate MCP tool JSON definitions\n */\n generateMCPToolsCode(manifest: SmartObjectManifest): string {\n const tools: string[] = [];\n\n for (const obj of this.selectMCPToolOwners(manifest)) {\n const code = this.generateMCPTool(obj);\n // An object whose every operation is excluded contributes nothing;\n // pushing '' would emit a hole in the array literal (#2631).\n if (code) tools.push(code);\n }\n\n return tools.length > 0 ? `[\\n${tools.join(',\\n')}\\n]` : '[]';\n }\n\n /**\n * Get simple MCP tool names for an object\n */\n private getSimpleMCPToolNames(obj: SmartObjectDefinition): string[] {\n const { collection } = obj;\n const config = obj.decoratorConfig.mcp;\n const exclude = (typeof config === 'object' && config?.exclude) || [];\n const include =\n (typeof config === 'object' && config?.include) || undefined;\n\n const tools: string[] = [];\n\n const shouldInclude = (op: string) => {\n if (include && !include.includes(op)) return false;\n if (exclude.includes(op)) return false;\n return true;\n };\n\n if (shouldInclude('list')) {\n tools.push(`list_${collection}`);\n }\n if (shouldInclude('get')) {\n tools.push(`get_${collection}`);\n }\n if (shouldInclude('create')) {\n tools.push(`create_${collection}`);\n }\n if (shouldInclude('update')) {\n tools.push(`update_${collection}`);\n }\n if (shouldInclude('delete')) {\n tools.push(`delete_${collection}`);\n }\n\n return tools;\n }\n\n /**\n * Generate a single MCP tool\n */\n private generateMCPTool(obj: SmartObjectDefinition): string {\n const { collection } = obj;\n const config = obj.decoratorConfig.mcp;\n const exclude = (typeof config === 'object' && config?.exclude) || [];\n const include =\n (typeof config === 'object' && config?.include) || undefined;\n\n const tools = [];\n\n const shouldInclude = (op: string) => {\n if (include && !include.includes(op)) return false;\n if (exclude.includes(op)) return false;\n return true;\n };\n\n if (shouldInclude('list')) {\n tools.push(` {\n name: \"list_${collection}\",\n description: \"List ${collection}\",\n inputSchema: {\n type: \"object\",\n properties: {\n limit: { type: \"number\" },\n offset: { type: \"number\" },\n where: { type: \"object\" }\n }\n }\n }`);\n }\n\n if (shouldInclude('get')) {\n tools.push(` {\n name: \"get_${collection}\",\n description: \"Get a ${collection} entry by ID\",\n inputSchema: {\n type: \"object\",\n properties: {\n id: { type: \"string\", description: \"The ${collection} entry ID\" }\n },\n required: [\"id\"]\n }\n }`);\n }\n\n const schemaProperties = JSON.stringify(\n this.generateSchemaProperties(obj.fields),\n null,\n 6,\n );\n\n if (shouldInclude('create')) {\n const requiredFields = Object.entries(obj.fields)\n .filter(([_, field]) => field.required)\n .map(([fieldName]) => fieldName);\n\n tools.push(` {\n name: \"create_${collection}\",\n description: \"Create a new ${collection} entry\",\n inputSchema: {\n type: \"object\",\n properties: ${schemaProperties},\n required: ${JSON.stringify(requiredFields)}\n }\n }`);\n }\n\n if (shouldInclude('update')) {\n tools.push(` {\n name: \"update_${collection}\",\n description: \"Update an existing ${collection} entry\",\n inputSchema: {\n type: \"object\",\n properties: {\n id: { type: \"string\", description: \"The ${collection} entry ID\" },\n data: {\n type: \"object\",\n description: \"Fields to update on the ${collection} entry\",\n properties: ${schemaProperties}\n }\n },\n required: [\"id\", \"data\"]\n }\n }`);\n }\n\n if (shouldInclude('delete')) {\n tools.push(` {\n name: \"delete_${collection}\",\n description: \"Delete a ${collection} entry by ID\",\n inputSchema: {\n type: \"object\",\n properties: {\n id: { type: \"string\", description: \"The ${collection} entry ID\" }\n },\n required: [\"id\"]\n }\n }`);\n }\n\n return tools.join(',\\n');\n }\n\n /**\n * Generate JSON schema properties for fields\n */\n private generateSchemaProperties(\n fields: Record<string, FieldDefinition>,\n ): Record<string, JsonSchemaProperty> {\n const properties: Record<string, JsonSchemaProperty> = {};\n\n for (const [name, field] of Object.entries(fields)) {\n properties[name] = {\n type: this.mapFieldTypeToJSON(field.type),\n description: field.description || `The ${name} field`,\n };\n\n if (field.min !== undefined) properties[name].minimum = field.min;\n if (field.max !== undefined) properties[name].maximum = field.max;\n if (field.minLength !== undefined)\n properties[name].minLength = field.minLength;\n if (field.maxLength !== undefined)\n properties[name].maxLength = field.maxLength;\n }\n\n return properties;\n }\n\n /**\n * Map field types to JSON Schema types\n */\n private mapFieldTypeToJSON(fieldType: string): string {\n switch (fieldType) {\n case 'text':\n return 'string';\n case 'decimal':\n return 'number';\n case 'integer':\n return 'integer';\n case 'boolean':\n return 'boolean';\n case 'datetime':\n return 'string';\n case 'json':\n return 'object';\n case 'foreignKey':\n return 'string';\n case 'crossPackageRef':\n return 'string';\n default:\n return 'string';\n }\n }\n\n /**\n * Generate agent manifests for Agent subclasses (fifth pass).\n *\n * For any SmartObjectDefinition with `agent` in its decoratorConfig,\n * auto-generates:\n * - Permissions from uiSlots (manage:*) and CLI/MCP methods (execute:*)\n * - Features from uiSlots and exposed methods\n * - Menu items from uiSlots\n * - Component declarations from package.json exports\n *\n * @param manifest - The manifest to process in-place\n * @param packageName - Package name for component export paths\n * @param packageJson - Full package.json for component discovery\n */\n generateAgentManifests(\n manifest: SmartObjectManifest,\n packageName?: string,\n packageJson?: PackageJsonLike,\n ): void {\n for (const obj of Object.values(manifest.objects)) {\n if (!obj.decoratorConfig.agent) continue;\n\n const agentConfig = obj.decoratorConfig.agent;\n const slug = obj.className.toLowerCase();\n // staticProperties is an untyped AST capture; assert the shape the\n // scanner records for `static uiSlots` on Agent subclasses.\n const uiSlots: Record<string, AgentUISlotManifest> =\n (obj.staticProperties?.uiSlots as\n | Record<string, AgentUISlotManifest>\n | undefined) ?? {};\n\n // Derive permissions\n const permissions: AgentPermission[] = [];\n\n // From uiSlots: manage:<slotId>\n for (const [slotId, slot] of Object.entries(uiSlots)) {\n permissions.push({\n id: `manage:${slotId}`,\n label: `Manage ${(slot as AgentUISlotManifest).label || slotId}`,\n category: 'slot',\n defaultGranted: true,\n });\n }\n\n // From CLI/MCP methods: execute:<methodName>\n const exposedMethods = this.getExposedMethods(obj);\n for (const methodName of exposedMethods) {\n permissions.push({\n id: `execute:${methodName}`,\n label: `Execute ${methodName}`,\n category: 'method',\n defaultGranted: true,\n });\n }\n\n // Derive features\n const features: AgentFeature[] = [];\n\n for (const [slotId, slot] of Object.entries(uiSlots)) {\n const typedSlot = slot as AgentUISlotManifest;\n features.push({\n id: slotId,\n label: typedSlot.label || slotId,\n description: typedSlot.description,\n type: 'slot',\n });\n }\n\n for (const methodName of exposedMethods) {\n features.push({\n id: methodName,\n label: methodName,\n type: 'method',\n });\n }\n\n // Derive menu items from uiSlots (sorted by order)\n const menuItems: AgentMenuItem[] = Object.entries(uiSlots)\n .map(([slotId, slot]) => {\n const typedSlot = slot as AgentUISlotManifest;\n return {\n id: slotId,\n label: typedSlot.label || slotId,\n icon: typedSlot.icon,\n order: typedSlot.order ?? 999,\n path: `/agents/${slug}/${slotId}`,\n requiredPermission: `manage:${slotId}`,\n };\n })\n .sort((a, b) => a.order - b.order);\n\n // Derive component declarations from package.json exports\n const components: AgentComponentDeclaration[] = [];\n if (packageName && packageJson?.exports) {\n for (const [exportKey, exportValue] of Object.entries(\n packageJson.exports,\n )) {\n // Match patterns like './admin', './town', etc.\n if (exportKey === '.' || exportKey === './manifest') continue;\n\n // Check if this export has a svelte condition (component export)\n const hasSvelteCondition = this.hasSvelteExport(exportValue);\n if (hasSvelteCondition) {\n const type = exportKey.replace('./', '');\n components.push({\n exportPath: `${packageName}/${type}`,\n type,\n });\n }\n }\n }\n\n // Capture adminRoutes from static property (same pattern as uiSlots)\n const adminRoutes: AgentAdminRouteManifest[] =\n (obj.staticProperties?.adminRoutes as\n | AgentAdminRouteManifest[]\n | undefined) ?? [];\n\n // Capture signalSubscriptions from static property\n const signalSubscriptions: string[] =\n (obj.staticProperties?.signalSubscriptions as string[] | undefined) ??\n [];\n\n const agentManifest: AgentManifest = {\n name: obj.className,\n slug,\n icon: agentConfig.icon,\n tier: agentConfig.tier || 'free',\n description: agentConfig.description,\n uiSlots,\n ...(adminRoutes.length > 0 ? { adminRoutes } : {}),\n ...(signalSubscriptions.length > 0 ? { signalSubscriptions } : {}),\n permissions,\n features,\n menuItems,\n components,\n };\n\n obj.agent = agentManifest;\n\n logger.debug(\n `[manifest-generator] Generated agent manifest for ${obj.className}: ` +\n `${permissions.length} permissions, ${features.length} features, ` +\n `${menuItems.length} menu items, ${components.length} components`,\n );\n }\n }\n\n /**\n * Get deduplicated list of method names exposed via CLI and MCP config\n */\n private getExposedMethods(obj: SmartObjectDefinition): string[] {\n const methods = new Set<string>();\n\n const cliConfig = obj.decoratorConfig.cli;\n if (cliConfig && typeof cliConfig === 'object' && cliConfig.include) {\n for (const m of cliConfig.include) {\n methods.add(m);\n }\n }\n\n const mcpConfig = obj.decoratorConfig.mcp;\n if (mcpConfig && typeof mcpConfig === 'object' && mcpConfig.include) {\n for (const m of mcpConfig.include) {\n methods.add(m);\n }\n }\n\n return Array.from(methods);\n }\n\n /**\n * Check if an export value has a svelte condition (indicating a component export)\n */\n private hasSvelteExport(exportValue: unknown): boolean {\n if (!exportValue || typeof exportValue !== 'object') return false;\n\n // Check for { svelte: ... } condition\n if ('svelte' in exportValue) return true;\n\n // Check nested conditions like { import: { svelte: ... } }\n for (const val of Object.values(exportValue)) {\n if (val && typeof val === 'object' && 'svelte' in (val as object)) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * Save manifest to file\n */\n saveManifest(manifest: SmartObjectManifest, filePath: string): void {\n const fs = require('node:fs');\n fs.writeFileSync(filePath, JSON.stringify(manifest, null, 2));\n }\n\n /**\n * Load manifest from file\n */\n loadManifest(filePath: string): SmartObjectManifest {\n const fs = require('node:fs');\n const content = fs.readFileSync(filePath, 'utf-8');\n return JSON.parse(content);\n }\n}\n\n/**\n * Convenience function to generate manifest\n *\n * @param scanResults - Array of scan results containing object definitions\n * @param options - Optional configuration (passed to ManifestGenerator.generateManifest)\n */\nexport function generateManifest(\n scanResults: ScanResult[],\n options?: {\n packageName?: string;\n packageVersion?: string;\n packageJson?: PackageJsonLike;\n smrtDependencies?: string[];\n includeVisibility?: SmrtVisibility[];\n },\n): SmartObjectManifest {\n const generator = new ManifestGenerator();\n return generator.generateManifest(scanResults, options);\n}\n"],"mappings":"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"}