@happyvertical/smrt-core 0.37.0 → 0.37.1

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.
Files changed (45) hide show
  1. package/dist/consumer-plugin/index.js.map +1 -1
  2. package/dist/manifest/discover-smrt-packages.d.ts +10 -0
  3. package/dist/manifest/discover-smrt-packages.d.ts.map +1 -1
  4. package/dist/manifest/discover-smrt-packages.js.map +1 -1
  5. package/dist/manifest/generator.d.ts.map +1 -1
  6. package/dist/manifest/generator.js +34 -37
  7. package/dist/manifest/generator.js.map +1 -1
  8. package/dist/manifest/index.js +2 -2
  9. package/dist/manifest/index.js.map +1 -1
  10. package/dist/manifest/manifest-loader.d.ts +10 -0
  11. package/dist/manifest/manifest-loader.d.ts.map +1 -1
  12. package/dist/manifest/manifest-loader.js.map +1 -1
  13. package/dist/manifest/static-manifest.js +2 -2
  14. package/dist/manifest/static-manifest.js.map +1 -1
  15. package/dist/manifest/store.js +2 -2
  16. package/dist/manifest/test-manifest-stub.js +2 -2
  17. package/dist/manifest/test-manifest-stub.js.map +1 -1
  18. package/dist/manifest.json +2 -2
  19. package/dist/migrations/differ.d.ts +104 -13
  20. package/dist/migrations/differ.d.ts.map +1 -1
  21. package/dist/migrations/differ.js +199 -26
  22. package/dist/migrations/differ.js.map +1 -1
  23. package/dist/node_modules/.pnpm/{minimatch@10.2.3 → minimatch@10.2.5}/node_modules/minimatch/dist/esm/assert-valid-pattern.js.map +1 -1
  24. package/dist/node_modules/.pnpm/{minimatch@10.2.3 → minimatch@10.2.5}/node_modules/minimatch/dist/esm/ast.js +1 -7
  25. package/dist/node_modules/.pnpm/minimatch@10.2.5/node_modules/minimatch/dist/esm/ast.js.map +1 -0
  26. package/dist/node_modules/.pnpm/{minimatch@10.2.3 → minimatch@10.2.5}/node_modules/minimatch/dist/esm/brace-expressions.js.map +1 -1
  27. package/dist/node_modules/.pnpm/{minimatch@10.2.3 → minimatch@10.2.5}/node_modules/minimatch/dist/esm/escape.js.map +1 -1
  28. package/dist/node_modules/.pnpm/{minimatch@10.2.3 → minimatch@10.2.5}/node_modules/minimatch/dist/esm/index.js +17 -14
  29. package/dist/node_modules/.pnpm/minimatch@10.2.5/node_modules/minimatch/dist/esm/index.js.map +1 -0
  30. package/dist/node_modules/.pnpm/minimatch@10.2.5/node_modules/minimatch/dist/esm/unescape.js +10 -0
  31. package/dist/node_modules/.pnpm/{minimatch@10.2.3 → minimatch@10.2.5}/node_modules/minimatch/dist/esm/unescape.js.map +1 -1
  32. package/dist/object.d.ts.map +1 -1
  33. package/dist/object.js.map +1 -1
  34. package/dist/scanner/manifest-generator.d.ts.map +1 -1
  35. package/dist/scanner/manifest-generator.js +22 -20
  36. package/dist/scanner/manifest-generator.js.map +1 -1
  37. package/dist/smrt-knowledge.json +7 -7
  38. package/dist/vite-plugin/index.js +1 -1
  39. package/package.json +7 -7
  40. package/dist/node_modules/.pnpm/minimatch@10.2.3/node_modules/minimatch/dist/esm/ast.js.map +0 -1
  41. package/dist/node_modules/.pnpm/minimatch@10.2.3/node_modules/minimatch/dist/esm/index.js.map +0 -1
  42. package/dist/node_modules/.pnpm/minimatch@10.2.3/node_modules/minimatch/dist/esm/unescape.js +0 -10
  43. /package/dist/node_modules/.pnpm/{minimatch@10.2.3 → minimatch@10.2.5}/node_modules/minimatch/dist/esm/assert-valid-pattern.js +0 -0
  44. /package/dist/node_modules/.pnpm/{minimatch@10.2.3 → minimatch@10.2.5}/node_modules/minimatch/dist/esm/brace-expressions.js +0 -0
  45. /package/dist/node_modules/.pnpm/{minimatch@10.2.3 → minimatch@10.2.5}/node_modules/minimatch/dist/esm/escape.js +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/consumer-plugin/index.ts"],"sourcesContent":["/**\n * Vite plugin for consuming SMRT packages\n * Solves virtual module resolution in downstream projects\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { Plugin } from 'vite';\nimport { generateDeclarations } from '../prebuild/index.js';\nimport type { SmartObjectManifest } from '../scanner/types.js';\n\n/**\n * Loosely-typed view of an object definition as carried by an external\n * package's static manifest. The static manifests are read from JSON at the\n * package boundary, so only the fields this plugin consumes are typed; the\n * index signature preserves any additional fields (e.g. for spreads). This is\n * a structural superset of a manifest `SmartObjectDefinition` plus the\n * consumer-only `hasCollection` marker.\n */\ninterface ConsumerObjectDefinition {\n className?: string;\n packageName?: string;\n packageVersion?: string;\n qualifiedName?: string;\n importPath?: string;\n exportName?: string;\n collectionExportName?: string;\n hasCollection?: boolean;\n collection?: string;\n extends?: string;\n extendsQualified?: string;\n extendsTypeArg?: string;\n [key: string]: unknown;\n}\n\n/**\n * Aggregated manifest assembled by the consumer plugin from one or more\n * external package manifests. Loosely typed because the inputs originate from\n * JSON read at the package boundary.\n */\ninterface ConsumerManifest {\n version: string;\n timestamp: number;\n packageName?: string;\n packageVersion?: string;\n objects: Record<string, ConsumerObjectDefinition>;\n}\n\n/**\n * Minimal structural shape of a parsed `package.json` consumed here (name,\n * version, and the export map used to derive import paths). The index\n * signature keeps the remaining fields accessible.\n */\ninterface ConsumerPackageJson {\n name?: string;\n version?: string;\n main?: string;\n exports?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\nexport interface SmrtConsumerOptions {\n /** SMRT packages to scan (e.g., ['@my-org/products', '@my-org/content']) */\n packages?: string[];\n /** Generate TypeScript declarations */\n generateTypes?: boolean;\n /** Output directory for generated types */\n typesDir?: string;\n /** Project root path */\n projectRoot?: string;\n /** SvelteKit integration mode */\n svelteKit?: boolean;\n /** Use static types only (for federation builds) */\n staticTypes?: boolean;\n /** Disable file scanning */\n disableScanning?: boolean;\n}\n\nconst VIRTUAL_MODULES = {\n '@smrt/routes': 'smrt:routes',\n '@smrt/client': 'smrt:client',\n '@smrt/mcp': 'smrt:mcp',\n '@smrt/types': 'smrt:types',\n '@smrt/manifest': 'smrt:manifest',\n};\n\n/**\n * Consumer plugin for projects that use SMRT packages\n */\nexport function smrtConsumer(options: SmrtConsumerOptions = {}): Plugin {\n const {\n packages = [],\n generateTypes = true,\n typesDir = 'src/types/smrt-generated',\n projectRoot = process.cwd(),\n disableScanning = false,\n } = options;\n\n let smrtPackages: string[] = [];\n let typeManifest: ConsumerManifest | null = null;\n let typesGenerated = false;\n\n return {\n name: 'smrt-consumer',\n\n async buildStart() {\n console.log('[smrt:consumer] Initializing SMRT consumer plugin');\n\n // Discover SMRT packages if not explicitly specified\n if (packages.length === 0 && !disableScanning) {\n smrtPackages = await discoverSmrtPackages(projectRoot);\n } else {\n smrtPackages = packages;\n }\n\n if (smrtPackages.length > 0) {\n console.log(\n `[smrt:consumer] Found SMRT packages: ${smrtPackages.join(', ')}`,\n );\n\n // Aggregate type manifests from discovered packages\n typeManifest = await aggregateTypeManifests(smrtPackages, projectRoot);\n\n // Save aggregated manifest for CLI discovery\n await saveAggregatedManifest(typeManifest, projectRoot);\n\n // Generate registration file for CLI class loading\n await generateRegistrationFile(typeManifest, projectRoot);\n\n // Generate types if requested\n if (generateTypes && !typesGenerated) {\n await generateProjectTypes(typeManifest, typesDir, projectRoot);\n typesGenerated = true;\n }\n } else {\n console.log('[smrt:consumer] No SMRT packages found');\n typeManifest = { version: '1.0.0', timestamp: Date.now(), objects: {} };\n }\n },\n\n resolveId(id, _importer) {\n // Resolve virtual modules to generated type declarations\n if (id in VIRTUAL_MODULES) {\n const typeFileName = getTypeFileName(id);\n const typePath = path.join(projectRoot, typesDir, typeFileName);\n\n // If types file exists, resolve to it\n if (fs.existsSync(typePath)) {\n return typePath;\n }\n\n // Otherwise use virtual module ID for runtime resolution\n return `\\0${VIRTUAL_MODULES[id as keyof typeof VIRTUAL_MODULES]}`;\n }\n return null;\n },\n\n async load(id) {\n // Handle virtual modules if types aren't available\n const cleanId = id.startsWith('\\0') ? id.slice(1) : id;\n\n if (!typeManifest) {\n typeManifest = { version: '1.0.0', timestamp: Date.now(), objects: {} };\n }\n\n switch (cleanId) {\n case 'smrt:routes':\n return generateFallbackRoutesModule();\n\n case 'smrt:client':\n return generateFallbackClientModule(typeManifest);\n\n case 'smrt:mcp':\n return generateFallbackMcpModule();\n\n case 'smrt:types':\n return generateFallbackTypesModule(typeManifest);\n\n case 'smrt:manifest':\n return generateFallbackManifestModule(typeManifest);\n\n default:\n return null;\n }\n },\n };\n}\n\n/**\n * Discover SMRT packages in node_modules\n */\nasync function discoverSmrtPackages(projectRoot: string): Promise<string[]> {\n const packages: string[] = [];\n const nodeModulesPath = path.join(projectRoot, 'node_modules');\n\n if (!fs.existsSync(nodeModulesPath)) {\n return packages;\n }\n\n try {\n // Check package.json for workspace dependencies\n const packageJsonPath = path.join(projectRoot, 'package.json');\n if (fs.existsSync(packageJsonPath)) {\n const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));\n const allDeps = {\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n ...packageJson.peerDependencies,\n };\n\n // Look for packages that likely contain SMRT objects\n for (const [name, version] of Object.entries(allDeps)) {\n if (\n typeof version === 'string' &&\n (name.includes('smrt') ||\n name.includes('@have/') ||\n (await hasSmrtManifest(nodeModulesPath, name)))\n ) {\n packages.push(name);\n }\n }\n }\n } catch (error) {\n console.warn('[smrt:consumer] Error discovering packages:', error);\n }\n\n return packages;\n}\n\n/**\n * Check if a package has SMRT manifest\n */\nasync function hasSmrtManifest(\n nodeModulesPath: string,\n packageName: string,\n): Promise<boolean> {\n const packagePath = path.join(nodeModulesPath, packageName);\n const manifestPath = path.join(\n packagePath,\n 'dist',\n 'manifest',\n 'static-manifest.js',\n );\n return fs.existsSync(manifestPath);\n}\n\n/**\n * Aggregate type manifests from multiple packages\n */\nasync function aggregateTypeManifests(\n packages: string[],\n projectRoot: string,\n): Promise<ConsumerManifest> {\n const aggregatedManifest: ConsumerManifest = {\n version: '1.0.0',\n timestamp: Date.now(),\n objects: {},\n };\n\n for (const packageName of packages) {\n try {\n const packageDir = path.join(projectRoot, 'node_modules', packageName);\n\n // Load package.json for version and export information\n const packageJsonPath = path.join(packageDir, 'package.json');\n let packageJson: ConsumerPackageJson;\n try {\n const packageJsonContent = fs.readFileSync(packageJsonPath, 'utf-8');\n packageJson = JSON.parse(packageJsonContent) as ConsumerPackageJson;\n } catch {\n console.warn(\n `[smrt:consumer] Could not read package.json for ${packageName}`,\n );\n continue;\n }\n\n // Try multiple manifest locations\n const manifestCandidates = [\n path.join(packageDir, 'dist', 'manifest', 'static-manifest.js'),\n path.join(packageDir, 'dist', 'manifest.json'),\n path.join(packageDir, 'manifest.json'),\n ];\n\n for (const manifestPath of manifestCandidates) {\n if (fs.existsSync(manifestPath)) {\n // Import or read the manifest\n let manifest: Partial<ConsumerManifest> | undefined;\n if (manifestPath.endsWith('.js')) {\n const manifestModule = await import(manifestPath);\n manifest = manifestModule.staticManifest || manifestModule.default;\n } else {\n const manifestContent = fs.readFileSync(manifestPath, 'utf-8');\n manifest = JSON.parse(manifestContent) as Partial<ConsumerManifest>;\n }\n\n if (manifest?.objects) {\n console.log(\n `[smrt:consumer] Loaded manifest from ${packageName} (${Object.keys(manifest.objects).length} objects)`,\n );\n\n // ENHANCED: Preserve package metadata for each object\n for (const [objectName, objectDef] of Object.entries(\n manifest.objects,\n )) {\n const def = objectDef;\n\n aggregatedManifest.objects[objectName] = {\n ...def,\n // Ensure package metadata is preserved/set\n packageName:\n def.packageName || manifest.packageName || packageName,\n packageVersion:\n def.packageVersion ||\n manifest.packageVersion ||\n packageJson.version,\n // Add fallback import paths if missing\n importPath: def.importPath || determineImportPath(packageJson),\n exportName: def.exportName || def.className || objectName,\n collectionExportName:\n def.collectionExportName ||\n `${def.className || objectName}Collection`,\n };\n }\n\n break; // Use first found manifest for this package\n }\n }\n }\n } catch (error) {\n console.warn(\n `[smrt:consumer] Error loading manifest from ${packageName}:`,\n error,\n );\n }\n }\n\n return aggregatedManifest;\n}\n\n/**\n * Determine import path from package.json\n */\nfunction determineImportPath(packageJson: ConsumerPackageJson): string {\n const packageName = packageJson.name;\n\n if (!packageName) {\n throw new Error('Package name not found in package.json');\n }\n\n // Strategy 1: Check for specific exports\n if (packageJson.exports) {\n // Check for objects export\n if (packageJson.exports['./objects']) {\n return `${packageName}/objects`;\n }\n\n // Check for main export\n const mainExport = packageJson.exports['.'];\n if (mainExport) {\n // Handle conditional exports\n if (typeof mainExport === 'object' && mainExport !== null) {\n const conditional = mainExport as Record<string, unknown>;\n if (conditional.import) {\n return packageName;\n }\n if (conditional.default) {\n return packageName;\n }\n }\n return packageName;\n }\n }\n\n // Strategy 2: Check main field\n if (packageJson.main) {\n return packageName;\n }\n\n // Strategy 3: Fallback to package name\n return packageName;\n}\n\n/**\n * Save aggregated manifest to .smrt/manifest.json for CLI discovery\n */\nasync function saveAggregatedManifest(\n manifest: ConsumerManifest,\n projectRoot: string,\n): Promise<void> {\n const smrtDir = path.join(projectRoot, '.smrt');\n const manifestPath = path.join(smrtDir, 'manifest.json');\n\n try {\n // Create .smrt directory if it doesn't exist\n if (!fs.existsSync(smrtDir)) {\n fs.mkdirSync(smrtDir, { recursive: true });\n }\n\n // Write manifest\n fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), 'utf-8');\n\n console.log(\n `[smrt:consumer] Saved aggregated manifest to .smrt/manifest.json (${Object.keys(manifest.objects).length} objects)`,\n );\n } catch (error) {\n console.warn('[smrt:consumer] Failed to save aggregated manifest:', error);\n }\n}\n\n/**\n * Generate registration file for CLI class loading\n *\n * Creates .smrt/register.js with static imports and registrations\n * for all external SMRT objects discovered during build.\n */\nasync function generateRegistrationFile(\n manifest: ConsumerManifest,\n projectRoot: string,\n): Promise<void> {\n const smrtDir = path.join(projectRoot, '.smrt');\n const registerPath = path.join(smrtDir, 'register.js');\n\n // Build import statements and registrations\n const imports: string[] = [];\n const registrations: string[] = [];\n let importedEntryCount = 0;\n let registeredObjectCount = 0;\n\n const manifestObjects = manifest.objects;\n const manifestObjectLookup = new Map<string, ConsumerObjectDefinition>();\n for (const [key, def] of Object.entries(manifestObjects)) {\n const candidate = def;\n const lookupKeys = [\n key,\n key.includes(':') ? key.split(':').pop() : undefined,\n candidate.qualifiedName,\n candidate.className,\n candidate.exportName,\n ];\n\n for (const lookupKey of lookupKeys) {\n if (lookupKey && !manifestObjectLookup.has(lookupKey)) {\n manifestObjectLookup.set(lookupKey, candidate);\n }\n }\n }\n\n const collectionClassMemo = new WeakMap<object, boolean>();\n\n const isCollectionClass = (\n def: ConsumerObjectDefinition | undefined,\n seen = new Set<string>(),\n ): boolean => {\n if (!def || typeof def !== 'object') {\n return false;\n }\n\n const cached = collectionClassMemo.get(def);\n if (cached !== undefined) {\n return cached;\n }\n\n if (\n def?.extends === 'SmrtCollection' ||\n def?.extendsTypeArg !== undefined\n ) {\n collectionClassMemo.set(def, true);\n return true;\n }\n\n const parentName = def?.extendsQualified || def?.extends;\n if (!parentName || seen.has(parentName)) {\n collectionClassMemo.set(def, false);\n return false;\n }\n seen.add(parentName);\n\n const parentDef = manifestObjectLookup.get(parentName);\n const isCollection = parentDef ? isCollectionClass(parentDef, seen) : false;\n collectionClassMemo.set(def, isCollection);\n\n return isCollection;\n };\n\n for (const [objectName, objectDef] of Object.entries(manifestObjects)) {\n const def = objectDef;\n\n // Skip local objects (they're imported from local entry point)\n if (!def.packageName || def.packageName === manifest.packageName) {\n continue;\n }\n\n const importPath = def.importPath || def.packageName;\n const exportName = def.exportName || def.className || objectName;\n const collectionExportName = def.collectionExportName;\n const hasCollection = def.hasCollection; // Check if collection class actually exists\n const tableName = def.collection || objectName.toLowerCase();\n\n // Generate import statement\n // Only import collection if it exists (hasCollection is truthy)\n if (hasCollection && collectionExportName) {\n imports.push(\n `import { ${exportName}, ${collectionExportName} } from '${importPath}';`,\n );\n } else {\n imports.push(`import { ${exportName} } from '${importPath}';`);\n }\n importedEntryCount++;\n\n if (isCollectionClass(def)) {\n continue;\n }\n\n // Generate registration calls\n // The import above already triggers the @smrt() decorator which registers the class\n // properly with its simple name and qualified name. We call register() again with\n // an empty config just to ensure the class is registered (in case it lacks a decorator).\n // Do NOT pass { name: qualifiedName } as that creates a separate registry entry.\n registrations.push(\n `ObjectRegistry.register(${exportName}, { name: ${JSON.stringify(exportName)}, packageName: ${JSON.stringify(def.packageName)} });`,\n );\n\n // Only register collection if it exists\n if (hasCollection && collectionExportName) {\n registrations.push(\n `ObjectRegistry.registerCollection('${tableName}', ${collectionExportName});`,\n );\n }\n\n registeredObjectCount++;\n }\n\n // Skip generation if no external entries\n if (importedEntryCount === 0) {\n console.log('[smrt:consumer] No external entries - skipping register.js');\n return;\n }\n\n const registeredObjectLabel =\n registeredObjectCount === 1 ? 'object' : 'objects';\n\n // Generate file content\n const content = `/**\n * Auto-generated by @happyvertical/smrt-core/consumer-plugin\n * DO NOT EDIT - This file is regenerated on every build\n *\n * Registers SMRT objects from external packages for CLI discovery.\n * Generated at: ${new Date().toISOString()}\n */\n\nimport { ObjectRegistry } from '@happyvertical/smrt-core';\n\n${imports.join('\\n')}\n\n// Register all objects (executed during module evaluation)\n${registrations.join('\\n')}\n\nexport function registerAll() {\n // Objects are already registered during module evaluation\n console.log('[smrt:register] Registered ${registeredObjectCount} external ${registeredObjectLabel}');\n}\n`;\n\n // Create .smrt directory if needed\n if (!fs.existsSync(smrtDir)) {\n fs.mkdirSync(smrtDir, { recursive: true });\n }\n\n // Write registration file\n fs.writeFileSync(registerPath, content, 'utf-8');\n\n console.log(\n `[smrt:consumer] Generated .smrt/register.js with ${importedEntryCount} external entries (${registeredObjectCount} registered ${registeredObjectLabel})`,\n );\n}\n\n/**\n * Generate project-specific types\n */\nasync function generateProjectTypes(\n typeManifest: ConsumerManifest,\n typesDir: string,\n projectRoot: string,\n): Promise<void> {\n if (!typeManifest || Object.keys(typeManifest.objects).length === 0) {\n console.log(\n '[smrt:consumer] No SMRT objects found, skipping type generation',\n );\n return;\n }\n\n await generateDeclarations({\n // The aggregated manifest is a runtime SMRT manifest assembled from external\n // package manifests; it is intentionally typed loosely at the JSON boundary,\n // so narrow it to the declaration generator's strict manifest shape here.\n manifest: typeManifest as unknown as SmartObjectManifest,\n outDir: typesDir,\n projectRoot,\n includeVirtualModules: true,\n includeObjectTypes: true,\n });\n\n console.log(\n `[smrt:consumer] Generated types for ${Object.keys(typeManifest.objects).length} objects`,\n );\n}\n\n/**\n * Get type file name for virtual module\n */\nfunction getTypeFileName(virtualModule: string): string {\n const moduleMap: Record<string, string> = {\n '@smrt/routes': 'smrt-routes.d.ts',\n '@smrt/client': 'smrt-client.d.ts',\n '@smrt/mcp': 'smrt-mcp.d.ts',\n '@smrt/types': 'smrt-types.d.ts',\n '@smrt/manifest': 'smrt-manifest.d.ts',\n };\n return moduleMap[virtualModule] || 'smrt-unknown.d.ts';\n}\n\n/**\n * Fallback modules for when types aren't available\n */\nfunction generateFallbackRoutesModule(): string {\n return `\n// Fallback routes module\nexport function setupRoutes(app) {\n console.warn('[smrt:consumer] No routes available - SMRT packages may not be properly configured');\n}\nexport default setupRoutes;\n`;\n}\n\nfunction generateFallbackClientModule(manifest: ConsumerManifest): string {\n const objects = Object.entries(manifest?.objects || {});\n if (objects.length === 0) {\n return `\n// Fallback client module\nexport function createClient(basePath = '/api/v1') {\n console.warn('[smrt:consumer] No API client available - SMRT packages may not be properly configured');\n return {};\n}\nexport default createClient;\n`;\n }\n\n // Generate basic client from manifest\n const clientMethods = objects\n .map(([name, obj]) => {\n const { collection } = obj;\n return `\n ${name}: {\n list: () => fetch(basePath + '/${collection}').then(r => r.json()),\n get: (id) => fetch(basePath + '/${collection}/' + id).then(r => r.json()),\n create: (data) => fetch(basePath + '/${collection}', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(data)\n }).then(r => r.json()),\n update: (id, data) => fetch(basePath + '/${collection}/' + id, {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(data)\n }).then(r => r.json()),\n delete: (id) => fetch(basePath + '/${collection}/' + id, {\n method: 'DELETE'\n }).then(r => r.ok)\n }`;\n })\n .join(',');\n\n return `\n// Auto-generated API client from SMRT consumer\nexport function createClient(basePath = '/api/v1') {\n return {${clientMethods}\n };\n}\nexport default createClient;\n`;\n}\n\nfunction generateFallbackMcpModule(): string {\n return `\n// Fallback MCP module\nexport const tools = [];\nexport function createMCPServer() {\n console.warn('[smrt:consumer] No MCP tools available - SMRT packages may not be properly configured');\n return { name: 'smrt-consumer', version: '1.0.0', tools: [] };\n}\nexport default createMCPServer;\n`;\n}\n\nfunction generateFallbackTypesModule(manifest: ConsumerManifest): string {\n const objects = Object.entries(manifest?.objects || {});\n if (objects.length === 0) {\n return `// No types available`;\n }\n\n // Generate basic interfaces\n const interfaces = objects.map(([_name, obj]) => {\n return `export interface ${obj.className}Data {\n id?: string;\n created_at?: string;\n updated_at?: string;\n [key: string]: any;\n}`;\n });\n\n return interfaces.join('\\n\\n');\n}\n\nfunction generateFallbackManifestModule(manifest: ConsumerManifest): string {\n return `\n// Auto-generated manifest from SMRT consumer\nexport const manifest = ${JSON.stringify(manifest, null, 2)};\nexport default manifest;\n`;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../src/consumer-plugin/index.ts"],"sourcesContent":["/**\n * Vite plugin for consuming SMRT packages\n * Solves virtual module resolution in downstream projects\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { Plugin } from 'vite';\nimport { generateDeclarations } from '../prebuild/index.js';\nimport type { SmartObjectManifest } from '../scanner/types.js';\n\n/**\n * Loosely-typed view of an object definition as carried by an external\n * package's static manifest. The static manifests are read from JSON at the\n * package boundary, so only the fields this plugin consumes are typed; the\n * index signature preserves any additional fields (e.g. for spreads). This is\n * a structural superset of a manifest `SmartObjectDefinition` plus the\n * consumer-only `hasCollection` marker.\n */\ninterface ConsumerObjectDefinition {\n className?: string;\n packageName?: string;\n packageVersion?: string;\n qualifiedName?: string;\n importPath?: string;\n exportName?: string;\n collectionExportName?: string;\n hasCollection?: boolean;\n collection?: string;\n extends?: string;\n extendsQualified?: string;\n extendsTypeArg?: string;\n [key: string]: unknown;\n}\n\n/**\n * Aggregated manifest assembled by the consumer plugin from one or more\n * external package manifests. Loosely typed because the inputs originate from\n * JSON read at the package boundary.\n */\ninterface ConsumerManifest {\n version: string;\n timestamp: number;\n packageName?: string;\n packageVersion?: string;\n objects: Record<string, ConsumerObjectDefinition>;\n}\n\n/**\n * Minimal structural shape of a parsed `package.json` consumed here (name,\n * version, and the export map used to derive import paths). The index\n * signature keeps the remaining fields accessible.\n */\ninterface ConsumerPackageJson {\n name?: string;\n version?: string;\n main?: string;\n exports?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\nexport interface SmrtConsumerOptions {\n /** SMRT packages to scan (e.g., ['@my-org/products', '@my-org/content']) */\n packages?: string[];\n /** Generate TypeScript declarations */\n generateTypes?: boolean;\n /** Output directory for generated types */\n typesDir?: string;\n /** Project root path */\n projectRoot?: string;\n /** SvelteKit integration mode */\n svelteKit?: boolean;\n /** Use static types only (for federation builds) */\n staticTypes?: boolean;\n /** Disable file scanning */\n disableScanning?: boolean;\n}\n\nconst VIRTUAL_MODULES = {\n '@smrt/routes': 'smrt:routes',\n '@smrt/client': 'smrt:client',\n '@smrt/mcp': 'smrt:mcp',\n '@smrt/types': 'smrt:types',\n '@smrt/manifest': 'smrt:manifest',\n};\n\n/**\n * Consumer plugin for projects that use SMRT packages\n */\nexport function smrtConsumer(options: SmrtConsumerOptions = {}): Plugin {\n const {\n packages = [],\n generateTypes = true,\n typesDir = 'src/types/smrt-generated',\n projectRoot = process.cwd(),\n disableScanning = false,\n } = options;\n\n let smrtPackages: string[] = [];\n let typeManifest: ConsumerManifest | null = null;\n let typesGenerated = false;\n\n return {\n name: 'smrt-consumer',\n\n async buildStart() {\n console.log('[smrt:consumer] Initializing SMRT consumer plugin');\n\n // Discover SMRT packages if not explicitly specified\n if (packages.length === 0 && !disableScanning) {\n smrtPackages = await discoverSmrtPackages(projectRoot);\n } else {\n smrtPackages = packages;\n }\n\n if (smrtPackages.length > 0) {\n console.log(\n `[smrt:consumer] Found SMRT packages: ${smrtPackages.join(', ')}`,\n );\n\n // Aggregate type manifests from discovered packages\n typeManifest = await aggregateTypeManifests(smrtPackages, projectRoot);\n\n // Save aggregated manifest for CLI discovery\n await saveAggregatedManifest(typeManifest, projectRoot);\n\n // Generate registration file for CLI class loading\n await generateRegistrationFile(typeManifest, projectRoot);\n\n // Generate types if requested\n if (generateTypes && !typesGenerated) {\n await generateProjectTypes(typeManifest, typesDir, projectRoot);\n typesGenerated = true;\n }\n } else {\n console.log('[smrt:consumer] No SMRT packages found');\n typeManifest = { version: '1.0.0', timestamp: Date.now(), objects: {} };\n }\n },\n\n resolveId(id, _importer) {\n // Resolve virtual modules to generated type declarations\n if (id in VIRTUAL_MODULES) {\n const typeFileName = getTypeFileName(id);\n const typePath = path.join(projectRoot, typesDir, typeFileName);\n\n // If types file exists, resolve to it\n if (fs.existsSync(typePath)) {\n return typePath;\n }\n\n // Otherwise use virtual module ID for runtime resolution\n return `\\0${VIRTUAL_MODULES[id as keyof typeof VIRTUAL_MODULES]}`;\n }\n return null;\n },\n\n async load(id) {\n // Handle virtual modules if types aren't available\n const cleanId = id.startsWith('\\0') ? id.slice(1) : id;\n\n if (!typeManifest) {\n typeManifest = { version: '1.0.0', timestamp: Date.now(), objects: {} };\n }\n\n switch (cleanId) {\n case 'smrt:routes':\n return generateFallbackRoutesModule();\n\n case 'smrt:client':\n return generateFallbackClientModule(typeManifest);\n\n case 'smrt:mcp':\n return generateFallbackMcpModule();\n\n case 'smrt:types':\n return generateFallbackTypesModule(typeManifest);\n\n case 'smrt:manifest':\n return generateFallbackManifestModule(typeManifest);\n\n default:\n return null;\n }\n },\n };\n}\n\n/**\n * Discover SMRT packages from a consumer app's dependencies.\n *\n * Intentional split (#1579): this **consumer-plugin** path is async and\n * resolves SMRT packages from the downstream app's `package.json` dependency\n * names (`@have/`/`smrt` heuristic + `hasSmrtManifest` probe) inside the Vite\n * consumer plugin. It is deliberately separate from the build-time\n * `discoverSmrtPackages()` in `src/manifest/discover-smrt-packages.ts` — a\n * synchronous, lockfile-cached `node_modules` manifest scan used for manifest\n * generation. Different inputs, contexts, and lifecycles, not duplicated logic.\n */\nasync function discoverSmrtPackages(projectRoot: string): Promise<string[]> {\n const packages: string[] = [];\n const nodeModulesPath = path.join(projectRoot, 'node_modules');\n\n if (!fs.existsSync(nodeModulesPath)) {\n return packages;\n }\n\n try {\n // Check package.json for workspace dependencies\n const packageJsonPath = path.join(projectRoot, 'package.json');\n if (fs.existsSync(packageJsonPath)) {\n const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));\n const allDeps = {\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n ...packageJson.peerDependencies,\n };\n\n // Look for packages that likely contain SMRT objects\n for (const [name, version] of Object.entries(allDeps)) {\n if (\n typeof version === 'string' &&\n (name.includes('smrt') ||\n name.includes('@have/') ||\n (await hasSmrtManifest(nodeModulesPath, name)))\n ) {\n packages.push(name);\n }\n }\n }\n } catch (error) {\n console.warn('[smrt:consumer] Error discovering packages:', error);\n }\n\n return packages;\n}\n\n/**\n * Check if a package has SMRT manifest\n */\nasync function hasSmrtManifest(\n nodeModulesPath: string,\n packageName: string,\n): Promise<boolean> {\n const packagePath = path.join(nodeModulesPath, packageName);\n const manifestPath = path.join(\n packagePath,\n 'dist',\n 'manifest',\n 'static-manifest.js',\n );\n return fs.existsSync(manifestPath);\n}\n\n/**\n * Aggregate type manifests from multiple packages\n */\nasync function aggregateTypeManifests(\n packages: string[],\n projectRoot: string,\n): Promise<ConsumerManifest> {\n const aggregatedManifest: ConsumerManifest = {\n version: '1.0.0',\n timestamp: Date.now(),\n objects: {},\n };\n\n for (const packageName of packages) {\n try {\n const packageDir = path.join(projectRoot, 'node_modules', packageName);\n\n // Load package.json for version and export information\n const packageJsonPath = path.join(packageDir, 'package.json');\n let packageJson: ConsumerPackageJson;\n try {\n const packageJsonContent = fs.readFileSync(packageJsonPath, 'utf-8');\n packageJson = JSON.parse(packageJsonContent) as ConsumerPackageJson;\n } catch {\n console.warn(\n `[smrt:consumer] Could not read package.json for ${packageName}`,\n );\n continue;\n }\n\n // Try multiple manifest locations\n const manifestCandidates = [\n path.join(packageDir, 'dist', 'manifest', 'static-manifest.js'),\n path.join(packageDir, 'dist', 'manifest.json'),\n path.join(packageDir, 'manifest.json'),\n ];\n\n for (const manifestPath of manifestCandidates) {\n if (fs.existsSync(manifestPath)) {\n // Import or read the manifest\n let manifest: Partial<ConsumerManifest> | undefined;\n if (manifestPath.endsWith('.js')) {\n const manifestModule = await import(manifestPath);\n manifest = manifestModule.staticManifest || manifestModule.default;\n } else {\n const manifestContent = fs.readFileSync(manifestPath, 'utf-8');\n manifest = JSON.parse(manifestContent) as Partial<ConsumerManifest>;\n }\n\n if (manifest?.objects) {\n console.log(\n `[smrt:consumer] Loaded manifest from ${packageName} (${Object.keys(manifest.objects).length} objects)`,\n );\n\n // ENHANCED: Preserve package metadata for each object\n for (const [objectName, objectDef] of Object.entries(\n manifest.objects,\n )) {\n const def = objectDef;\n\n aggregatedManifest.objects[objectName] = {\n ...def,\n // Ensure package metadata is preserved/set\n packageName:\n def.packageName || manifest.packageName || packageName,\n packageVersion:\n def.packageVersion ||\n manifest.packageVersion ||\n packageJson.version,\n // Add fallback import paths if missing\n importPath: def.importPath || determineImportPath(packageJson),\n exportName: def.exportName || def.className || objectName,\n collectionExportName:\n def.collectionExportName ||\n `${def.className || objectName}Collection`,\n };\n }\n\n break; // Use first found manifest for this package\n }\n }\n }\n } catch (error) {\n console.warn(\n `[smrt:consumer] Error loading manifest from ${packageName}:`,\n error,\n );\n }\n }\n\n return aggregatedManifest;\n}\n\n/**\n * Determine import path from package.json\n */\nfunction determineImportPath(packageJson: ConsumerPackageJson): string {\n const packageName = packageJson.name;\n\n if (!packageName) {\n throw new Error('Package name not found in package.json');\n }\n\n // Strategy 1: Check for specific exports\n if (packageJson.exports) {\n // Check for objects export\n if (packageJson.exports['./objects']) {\n return `${packageName}/objects`;\n }\n\n // Check for main export\n const mainExport = packageJson.exports['.'];\n if (mainExport) {\n // Handle conditional exports\n if (typeof mainExport === 'object' && mainExport !== null) {\n const conditional = mainExport as Record<string, unknown>;\n if (conditional.import) {\n return packageName;\n }\n if (conditional.default) {\n return packageName;\n }\n }\n return packageName;\n }\n }\n\n // Strategy 2: Check main field\n if (packageJson.main) {\n return packageName;\n }\n\n // Strategy 3: Fallback to package name\n return packageName;\n}\n\n/**\n * Save aggregated manifest to .smrt/manifest.json for CLI discovery\n */\nasync function saveAggregatedManifest(\n manifest: ConsumerManifest,\n projectRoot: string,\n): Promise<void> {\n const smrtDir = path.join(projectRoot, '.smrt');\n const manifestPath = path.join(smrtDir, 'manifest.json');\n\n try {\n // Create .smrt directory if it doesn't exist\n if (!fs.existsSync(smrtDir)) {\n fs.mkdirSync(smrtDir, { recursive: true });\n }\n\n // Write manifest\n fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), 'utf-8');\n\n console.log(\n `[smrt:consumer] Saved aggregated manifest to .smrt/manifest.json (${Object.keys(manifest.objects).length} objects)`,\n );\n } catch (error) {\n console.warn('[smrt:consumer] Failed to save aggregated manifest:', error);\n }\n}\n\n/**\n * Generate registration file for CLI class loading\n *\n * Creates .smrt/register.js with static imports and registrations\n * for all external SMRT objects discovered during build.\n */\nasync function generateRegistrationFile(\n manifest: ConsumerManifest,\n projectRoot: string,\n): Promise<void> {\n const smrtDir = path.join(projectRoot, '.smrt');\n const registerPath = path.join(smrtDir, 'register.js');\n\n // Build import statements and registrations\n const imports: string[] = [];\n const registrations: string[] = [];\n let importedEntryCount = 0;\n let registeredObjectCount = 0;\n\n const manifestObjects = manifest.objects;\n const manifestObjectLookup = new Map<string, ConsumerObjectDefinition>();\n for (const [key, def] of Object.entries(manifestObjects)) {\n const candidate = def;\n const lookupKeys = [\n key,\n key.includes(':') ? key.split(':').pop() : undefined,\n candidate.qualifiedName,\n candidate.className,\n candidate.exportName,\n ];\n\n for (const lookupKey of lookupKeys) {\n if (lookupKey && !manifestObjectLookup.has(lookupKey)) {\n manifestObjectLookup.set(lookupKey, candidate);\n }\n }\n }\n\n const collectionClassMemo = new WeakMap<object, boolean>();\n\n const isCollectionClass = (\n def: ConsumerObjectDefinition | undefined,\n seen = new Set<string>(),\n ): boolean => {\n if (!def || typeof def !== 'object') {\n return false;\n }\n\n const cached = collectionClassMemo.get(def);\n if (cached !== undefined) {\n return cached;\n }\n\n if (\n def?.extends === 'SmrtCollection' ||\n def?.extendsTypeArg !== undefined\n ) {\n collectionClassMemo.set(def, true);\n return true;\n }\n\n const parentName = def?.extendsQualified || def?.extends;\n if (!parentName || seen.has(parentName)) {\n collectionClassMemo.set(def, false);\n return false;\n }\n seen.add(parentName);\n\n const parentDef = manifestObjectLookup.get(parentName);\n const isCollection = parentDef ? isCollectionClass(parentDef, seen) : false;\n collectionClassMemo.set(def, isCollection);\n\n return isCollection;\n };\n\n for (const [objectName, objectDef] of Object.entries(manifestObjects)) {\n const def = objectDef;\n\n // Skip local objects (they're imported from local entry point)\n if (!def.packageName || def.packageName === manifest.packageName) {\n continue;\n }\n\n const importPath = def.importPath || def.packageName;\n const exportName = def.exportName || def.className || objectName;\n const collectionExportName = def.collectionExportName;\n const hasCollection = def.hasCollection; // Check if collection class actually exists\n const tableName = def.collection || objectName.toLowerCase();\n\n // Generate import statement\n // Only import collection if it exists (hasCollection is truthy)\n if (hasCollection && collectionExportName) {\n imports.push(\n `import { ${exportName}, ${collectionExportName} } from '${importPath}';`,\n );\n } else {\n imports.push(`import { ${exportName} } from '${importPath}';`);\n }\n importedEntryCount++;\n\n if (isCollectionClass(def)) {\n continue;\n }\n\n // Generate registration calls\n // The import above already triggers the @smrt() decorator which registers the class\n // properly with its simple name and qualified name. We call register() again with\n // an empty config just to ensure the class is registered (in case it lacks a decorator).\n // Do NOT pass { name: qualifiedName } as that creates a separate registry entry.\n registrations.push(\n `ObjectRegistry.register(${exportName}, { name: ${JSON.stringify(exportName)}, packageName: ${JSON.stringify(def.packageName)} });`,\n );\n\n // Only register collection if it exists\n if (hasCollection && collectionExportName) {\n registrations.push(\n `ObjectRegistry.registerCollection('${tableName}', ${collectionExportName});`,\n );\n }\n\n registeredObjectCount++;\n }\n\n // Skip generation if no external entries\n if (importedEntryCount === 0) {\n console.log('[smrt:consumer] No external entries - skipping register.js');\n return;\n }\n\n const registeredObjectLabel =\n registeredObjectCount === 1 ? 'object' : 'objects';\n\n // Generate file content\n const content = `/**\n * Auto-generated by @happyvertical/smrt-core/consumer-plugin\n * DO NOT EDIT - This file is regenerated on every build\n *\n * Registers SMRT objects from external packages for CLI discovery.\n * Generated at: ${new Date().toISOString()}\n */\n\nimport { ObjectRegistry } from '@happyvertical/smrt-core';\n\n${imports.join('\\n')}\n\n// Register all objects (executed during module evaluation)\n${registrations.join('\\n')}\n\nexport function registerAll() {\n // Objects are already registered during module evaluation\n console.log('[smrt:register] Registered ${registeredObjectCount} external ${registeredObjectLabel}');\n}\n`;\n\n // Create .smrt directory if needed\n if (!fs.existsSync(smrtDir)) {\n fs.mkdirSync(smrtDir, { recursive: true });\n }\n\n // Write registration file\n fs.writeFileSync(registerPath, content, 'utf-8');\n\n console.log(\n `[smrt:consumer] Generated .smrt/register.js with ${importedEntryCount} external entries (${registeredObjectCount} registered ${registeredObjectLabel})`,\n );\n}\n\n/**\n * Generate project-specific types\n */\nasync function generateProjectTypes(\n typeManifest: ConsumerManifest,\n typesDir: string,\n projectRoot: string,\n): Promise<void> {\n if (!typeManifest || Object.keys(typeManifest.objects).length === 0) {\n console.log(\n '[smrt:consumer] No SMRT objects found, skipping type generation',\n );\n return;\n }\n\n await generateDeclarations({\n // The aggregated manifest is a runtime SMRT manifest assembled from external\n // package manifests; it is intentionally typed loosely at the JSON boundary,\n // so narrow it to the declaration generator's strict manifest shape here.\n manifest: typeManifest as unknown as SmartObjectManifest,\n outDir: typesDir,\n projectRoot,\n includeVirtualModules: true,\n includeObjectTypes: true,\n });\n\n console.log(\n `[smrt:consumer] Generated types for ${Object.keys(typeManifest.objects).length} objects`,\n );\n}\n\n/**\n * Get type file name for virtual module\n */\nfunction getTypeFileName(virtualModule: string): string {\n const moduleMap: Record<string, string> = {\n '@smrt/routes': 'smrt-routes.d.ts',\n '@smrt/client': 'smrt-client.d.ts',\n '@smrt/mcp': 'smrt-mcp.d.ts',\n '@smrt/types': 'smrt-types.d.ts',\n '@smrt/manifest': 'smrt-manifest.d.ts',\n };\n return moduleMap[virtualModule] || 'smrt-unknown.d.ts';\n}\n\n/**\n * Fallback modules for when types aren't available\n */\nfunction generateFallbackRoutesModule(): string {\n return `\n// Fallback routes module\nexport function setupRoutes(app) {\n console.warn('[smrt:consumer] No routes available - SMRT packages may not be properly configured');\n}\nexport default setupRoutes;\n`;\n}\n\nfunction generateFallbackClientModule(manifest: ConsumerManifest): string {\n const objects = Object.entries(manifest?.objects || {});\n if (objects.length === 0) {\n return `\n// Fallback client module\nexport function createClient(basePath = '/api/v1') {\n console.warn('[smrt:consumer] No API client available - SMRT packages may not be properly configured');\n return {};\n}\nexport default createClient;\n`;\n }\n\n // Generate basic client from manifest\n const clientMethods = objects\n .map(([name, obj]) => {\n const { collection } = obj;\n return `\n ${name}: {\n list: () => fetch(basePath + '/${collection}').then(r => r.json()),\n get: (id) => fetch(basePath + '/${collection}/' + id).then(r => r.json()),\n create: (data) => fetch(basePath + '/${collection}', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(data)\n }).then(r => r.json()),\n update: (id, data) => fetch(basePath + '/${collection}/' + id, {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(data)\n }).then(r => r.json()),\n delete: (id) => fetch(basePath + '/${collection}/' + id, {\n method: 'DELETE'\n }).then(r => r.ok)\n }`;\n })\n .join(',');\n\n return `\n// Auto-generated API client from SMRT consumer\nexport function createClient(basePath = '/api/v1') {\n return {${clientMethods}\n };\n}\nexport default createClient;\n`;\n}\n\nfunction generateFallbackMcpModule(): string {\n return `\n// Fallback MCP module\nexport const tools = [];\nexport function createMCPServer() {\n console.warn('[smrt:consumer] No MCP tools available - SMRT packages may not be properly configured');\n return { name: 'smrt-consumer', version: '1.0.0', tools: [] };\n}\nexport default createMCPServer;\n`;\n}\n\nfunction generateFallbackTypesModule(manifest: ConsumerManifest): string {\n const objects = Object.entries(manifest?.objects || {});\n if (objects.length === 0) {\n return `// No types available`;\n }\n\n // Generate basic interfaces\n const interfaces = objects.map(([_name, obj]) => {\n return `export interface ${obj.className}Data {\n id?: string;\n created_at?: string;\n updated_at?: string;\n [key: string]: any;\n}`;\n });\n\n return interfaces.join('\\n\\n');\n}\n\nfunction generateFallbackManifestModule(manifest: ConsumerManifest): string {\n return `\n// Auto-generated manifest from SMRT consumer\nexport const manifest = ${JSON.stringify(manifest, null, 2)};\nexport default manifest;\n`;\n}\n"],"names":[],"mappings":"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"}
@@ -42,6 +42,16 @@ export interface DiscoveryOptions {
42
42
  * - Automatically invalidates when any manifest.json changes (packages rebuilt)
43
43
  *
44
44
  * Disable with SMRT_DISABLE_DISCOVERY_CACHE=true for debugging
45
+ *
46
+ * Intentional split (#1579): this is the **build-time** discovery path —
47
+ * synchronous, scans `node_modules` for `manifest.json` files with
48
+ * `moduleType: "smrt"`, and caches by lockfile/manifest hash for fast manifest
49
+ * generation. It is deliberately distinct from the consumer-plugin's
50
+ * `discoverSmrtPackages(projectRoot)` (`src/consumer-plugin/index.ts`), which is
51
+ * **async**, reads a downstream app's `package.json` dependency names with a
52
+ * lightweight `@have/`/`smrt` heuristic, and runs inside the Vite consumer
53
+ * plugin. Different inputs, contexts, and lifecycles — not duplicated logic to
54
+ * consolidate.
45
55
  */
46
56
  export declare function discoverSmrtPackages(options?: DiscoveryOptions): string[];
47
57
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"discover-smrt-packages.d.ts","sourceRoot":"","sources":["../../src/manifest/discover-smrt-packages.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAoBH,oCAAoC;AACpC,UAAU,UAAU;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAKD;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,UAAU,CAE/C;AA2ID,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,MAAsB,GAC9B,MAAM,GAAG,IAAI,CAoBf;AAkPD,MAAM,WAAW,gBAAgB;IAC/B,gDAAgD;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4CAA4C;IAC5C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,0BAA0B;IAC1B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,yBAAyB;IACzB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,GAAE,gBAAqB,GAAG,MAAM,EAAE,CAsE7E"}
1
+ {"version":3,"file":"discover-smrt-packages.d.ts","sourceRoot":"","sources":["../../src/manifest/discover-smrt-packages.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAoBH,oCAAoC;AACpC,UAAU,UAAU;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAKD;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,UAAU,CAE/C;AA2ID,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,MAAsB,GAC9B,MAAM,GAAG,IAAI,CAoBf;AAkPD,MAAM,WAAW,gBAAgB;IAC/B,gDAAgD;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4CAA4C;IAC5C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,0BAA0B;IAC1B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,yBAAyB;IACzB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,GAAE,gBAAqB,GAAG,MAAM,EAAE,CAsE7E"}
@@ -1 +1 @@
1
- {"version":3,"file":"discover-smrt-packages.js","sources":["../../src/manifest/discover-smrt-packages.ts"],"sourcesContent":["/**\n * SMRT Package Discovery\n *\n * Discovers all SMRT packages in node_modules by:\n * 1. Scanning node_modules directory for installed packages\n * 2. Following symlinks for workspace: dependencies\n * 3. Checking for a package manifest (`dist/manifest.json`,\n * `.smrt/manifest.json`, or `src/manifest/manifest.json`) with moduleType: \"smrt\"\n * 4. Caching results based on lockfile hash and manifest timestamps\n *\n * Cache Strategy:\n * - ENABLED by default (5-50x faster startup)\n * - Automatically invalidates when lockfile or any manifest.json changes\n * - Disable with SMRT_DISABLE_DISCOVERY_CACHE=true for debugging\n */\n\nimport { createHash } from 'node:crypto';\nimport {\n existsSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n realpathSync,\n statSync,\n writeFileSync,\n} from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { dirname, join } from 'node:path';\nimport { parse } from '../utils/json.js';\n\nconst CACHE_DIR = '.smrt';\nconst CACHE_FILE = 'discovery-cache.json';\nconst CACHE_VERSION = 4;\n\n/** Timing data for --timing flag */\ninterface TimingData {\n discovery?: number;\n cacheCheck?: number;\n total?: number;\n}\n\n/** Module-level timing storage */\nlet lastTimingData: TimingData = {};\n\n/**\n * Get timing data from last discovery operation\n */\nexport function getDiscoveryTiming(): TimingData {\n return { ...lastTimingData };\n}\n\n/**\n * Get hash of lockfile for cache invalidation\n */\nfunction getLockfileHash(baseDir: string): string | null {\n // Check for pnpm or npm lockfile\n const lockfile = existsSync(join(baseDir, 'pnpm-lock.yaml'))\n ? join(baseDir, 'pnpm-lock.yaml')\n : join(baseDir, 'package-lock.json');\n\n if (!existsSync(lockfile)) {\n return null;\n }\n\n const content = readFileSync(lockfile, 'utf-8');\n return createHash('sha256').update(content).digest('hex');\n}\n\n/**\n * Get hash of package.json for cache invalidation when a package workspace\n * changes its declared dependencies without a colocated lockfile.\n */\nfunction getPackageJsonHash(baseDir: string): string | null {\n const packageJsonPath = join(baseDir, 'package.json');\n\n if (!existsSync(packageJsonPath)) {\n return null;\n }\n\n const content = readFileSync(packageJsonPath, 'utf-8');\n return createHash('sha256').update(content).digest('hex');\n}\n\n/**\n * Get a hash of all manifest timestamps for cache invalidation\n * This catches changes to SMRT packages even when lockfile hasn't changed\n */\nfunction getManifestTimestampsHash(\n baseDir: string,\n packages: string[],\n): string {\n const timestamps: string[] = [];\n\n for (const pkgName of packages) {\n try {\n const manifestPath = resolveManifestPath(pkgName, baseDir);\n\n if (manifestPath && existsSync(manifestPath)) {\n const stats = statSync(manifestPath);\n timestamps.push(`${pkgName}:${stats.mtimeMs}`);\n }\n } catch {\n // Ignore errors, package may have been removed\n }\n }\n\n return createHash('sha256').update(timestamps.join('|')).digest('hex');\n}\n\ninterface DiscoveryCache {\n version: number;\n lockfileHash: string | null;\n packageJsonHash: string | null;\n manifestsHash: string;\n timestamp: number;\n packages: string[];\n}\n\nfunction findManifestPath(pkgPath: string): string | null {\n const candidates = [\n join(pkgPath, 'dist', 'manifest.json'),\n join(pkgPath, '.smrt', 'manifest.json'),\n join(pkgPath, 'src', 'manifest', 'manifest.json'),\n ];\n\n for (const candidate of candidates) {\n if (existsSync(candidate)) {\n return candidate;\n }\n }\n\n return null;\n}\n\nfunction normalizePackagePath(pkgPath: string): string {\n try {\n return realpathSync(pkgPath);\n } catch {\n return pkgPath;\n }\n}\n\nfunction resolvePackageDir(\n packageName: string,\n baseDir: string = process.cwd(),\n): string | null {\n try {\n const requireFromBase = createRequire(join(baseDir, 'package.json'));\n const packageEntry = requireFromBase.resolve(packageName);\n let currentDir = dirname(packageEntry);\n let resolvedPackageDir: string | null = null;\n\n for (let i = 0; i < 10; i++) {\n const packageJsonPath = join(currentDir, 'package.json');\n\n if (existsSync(packageJsonPath)) {\n const packageJson = parse<{ name?: string }>(\n readFileSync(packageJsonPath, 'utf-8'),\n );\n\n if (packageJson.name === packageName) {\n resolvedPackageDir = currentDir;\n }\n }\n\n const parentDir = dirname(currentDir);\n if (parentDir === currentDir) {\n break;\n }\n\n currentDir = parentDir;\n }\n\n if (resolvedPackageDir) {\n return normalizePackagePath(resolvedPackageDir);\n }\n } catch {\n // Fall through to direct node_modules lookup below.\n }\n\n const directPath = join(baseDir, 'node_modules', packageName);\n if (existsSync(directPath)) {\n return normalizePackagePath(directPath);\n }\n\n return null;\n}\n\nexport function resolveManifestPath(\n packageName: string,\n baseDir: string = process.cwd(),\n): string | null {\n const pkgPath = resolvePackageDir(packageName, baseDir);\n if (!pkgPath) {\n return null;\n }\n\n const manifestPath = findManifestPath(pkgPath);\n if (!manifestPath) {\n return null;\n }\n\n try {\n const manifest = parse<{ moduleType?: string }>(\n readFileSync(manifestPath, 'utf-8'),\n );\n\n return manifest.moduleType === 'smrt' ? manifestPath : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Load cached discovery results if valid\n * Cache is invalidated if:\n * - Lockfile hash changed (dependencies changed)\n * - Manifest timestamps hash changed (SMRT packages rebuilt)\n */\nfunction getCachedDiscovery(\n baseDir: string,\n verbose: boolean,\n): { packages: string[]; reason?: string } | null {\n const cachePath = join(baseDir, CACHE_DIR, CACHE_FILE);\n\n if (!existsSync(cachePath)) {\n return null;\n }\n\n try {\n const cache: DiscoveryCache = parse(readFileSync(cachePath, 'utf-8'));\n if (cache.version !== CACHE_VERSION) {\n if (verbose) {\n console.log('[discovery] Cache invalid: discovery version changed');\n }\n return null;\n }\n\n const currentLockfileHash = getLockfileHash(baseDir);\n const currentPackageJsonHash = getPackageJsonHash(baseDir);\n\n // Check lockfile hash\n if (cache.lockfileHash !== currentLockfileHash) {\n if (verbose) {\n console.log('[discovery] Cache invalid: lockfile changed');\n }\n return null;\n }\n\n if (cache.packageJsonHash !== currentPackageJsonHash) {\n if (verbose) {\n console.log('[discovery] Cache invalid: package.json changed');\n }\n return null;\n }\n\n // Check manifest timestamps (only if we have cached packages)\n if (cache.packages.length > 0) {\n const currentManifestsHash = getManifestTimestampsHash(\n baseDir,\n cache.packages,\n );\n if (cache.manifestsHash !== currentManifestsHash) {\n if (verbose) {\n console.log('[discovery] Cache invalid: manifest(s) changed');\n }\n return null;\n }\n }\n\n return { packages: cache.packages };\n } catch (error) {\n if (verbose) {\n console.warn(\n '[discovery] Failed to read cache:',\n (error as Error).message,\n );\n }\n return null;\n }\n}\n\n/**\n * Save discovery results to cache\n */\nfunction saveCachedDiscovery(\n baseDir: string,\n packages: string[],\n verbose: boolean,\n): void {\n const cache: DiscoveryCache = {\n version: CACHE_VERSION,\n lockfileHash: getLockfileHash(baseDir),\n packageJsonHash: getPackageJsonHash(baseDir),\n manifestsHash: getManifestTimestampsHash(baseDir, packages),\n timestamp: Date.now(),\n packages: packages,\n };\n\n try {\n mkdirSync(join(baseDir, CACHE_DIR), { recursive: true });\n writeFileSync(\n join(baseDir, CACHE_DIR, CACHE_FILE),\n JSON.stringify(cache, null, 2),\n );\n if (verbose) {\n console.log(`[discovery] Saved cache with ${packages.length} package(s)`);\n }\n } catch (error) {\n if (verbose) {\n console.warn(\n '[discovery] Failed to save cache:',\n (error as Error).message,\n );\n }\n }\n}\n\n/**\n * Check if a package provides a SMRT manifest\n *\n * Supports both regular npm dependencies and workspace: symlinks\n */\nfunction hasManifestExport(packageName: string, baseDir: string): boolean {\n return resolveManifestPath(packageName, baseDir) !== null;\n}\n\nfunction getDeclaredSmrtPackages(baseDir: string, verbose: boolean): string[] {\n const packageJsonPath = join(baseDir, 'package.json');\n if (!existsSync(packageJsonPath)) {\n return [];\n }\n\n try {\n const packageJson = parse<{\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n peerDependencies?: Record<string, string>;\n }>(readFileSync(packageJsonPath, 'utf-8'));\n\n const allDeps = {\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n ...packageJson.peerDependencies,\n };\n\n return Object.keys(allDeps).filter((pkgName) => {\n if (!pkgName.startsWith('@happyvertical/smrt-')) {\n return false;\n }\n\n const hasManifest = hasManifestExport(pkgName, baseDir);\n if (verbose && hasManifest) {\n console.log(`[discovery] ✅ Found declared SMRT package: ${pkgName}`);\n }\n\n return hasManifest;\n });\n } catch (error) {\n if (verbose) {\n console.warn(\n '[discovery] Failed to read declared dependencies:',\n (error as Error).message,\n );\n }\n return [];\n }\n}\n\n/**\n * Scan node_modules recursively for packages\n */\nfunction* scanNodeModules(baseDir: string): Generator<string> {\n const nodeModulesPath = join(baseDir, 'node_modules');\n\n if (!existsSync(nodeModulesPath)) {\n return;\n }\n\n try {\n const entries = readdirSync(nodeModulesPath);\n\n for (const entry of entries) {\n if (entry === '.bin' || entry === '.pnpm' || entry === '.cache') {\n continue;\n }\n\n const entryPath = join(nodeModulesPath, entry);\n\n try {\n const stats = statSync(entryPath);\n\n if (stats.isDirectory() || stats.isSymbolicLink()) {\n // Scoped packages (e.g., @happyvertical/smrt-core)\n if (entry.startsWith('@')) {\n const scopeEntries = readdirSync(entryPath);\n for (const scopedPkg of scopeEntries) {\n yield `${entry}/${scopedPkg}`;\n }\n } else {\n // Regular packages\n yield entry;\n }\n }\n } catch {}\n }\n } catch (error) {\n // node_modules doesn't exist or can't be read\n return;\n }\n}\n\n/**\n * Perform fresh discovery of SMRT packages\n */\nfunction performDiscovery(baseDir: string, verbose: boolean): string[] {\n if (verbose) {\n console.log('[discovery] Scanning node_modules for SMRT packages...');\n }\n\n try {\n const smrtPackages = new Set<string>();\n\n // Scan node_modules for all packages\n for (const pkgName of scanNodeModules(baseDir)) {\n if (hasManifestExport(pkgName, baseDir)) {\n smrtPackages.add(pkgName);\n if (verbose) {\n console.log(`[discovery] ✅ Found SMRT package: ${pkgName}`);\n }\n }\n }\n\n for (const pkgName of getDeclaredSmrtPackages(baseDir, verbose)) {\n smrtPackages.add(pkgName);\n }\n\n if (verbose) {\n console.log(\n `[discovery] Discovered ${smrtPackages.size} SMRT package(s)`,\n );\n }\n\n return Array.from(smrtPackages);\n } catch (error) {\n console.error(\n '[discovery] Failed to discover packages:',\n (error as Error).message,\n );\n return [];\n }\n}\n\nexport interface DiscoveryOptions {\n /** Override project root for discovery/cache */\n baseDir?: string;\n /** Force fresh discovery, ignoring cache */\n noCache?: boolean;\n /** Show verbose output */\n verbose?: boolean;\n /** Record timing data */\n timing?: boolean;\n}\n\n/**\n * Main discovery function\n *\n * Cache ENABLED by default (5-50x faster startup)\n * - Automatically invalidates when lockfile changes (dependencies updated)\n * - Automatically invalidates when any manifest.json changes (packages rebuilt)\n *\n * Disable with SMRT_DISABLE_DISCOVERY_CACHE=true for debugging\n */\nexport function discoverSmrtPackages(options: DiscoveryOptions = {}): string[] {\n const startTime = options.timing ? performance.now() : 0;\n lastTimingData = {};\n const baseDir = options.baseDir || process.cwd();\n\n const cacheDisabled =\n options.noCache || process.env.SMRT_DISABLE_DISCOVERY_CACHE === 'true';\n\n const verbose: boolean =\n options.verbose === true ||\n process.env.SMRT_VERBOSE === 'true' ||\n !!process.env.DEBUG?.includes('smrt');\n\n if (cacheDisabled) {\n if (verbose) {\n console.log('[discovery] Cache disabled, performing fresh discovery...');\n }\n\n const packages = performDiscovery(baseDir, verbose);\n\n if (options.timing) {\n lastTimingData.discovery = performance.now() - startTime;\n lastTimingData.total = lastTimingData.discovery;\n }\n\n return packages;\n }\n\n // Try cache first\n const cacheCheckStart = options.timing ? performance.now() : 0;\n const cached = getCachedDiscovery(baseDir, verbose);\n\n if (options.timing) {\n lastTimingData.cacheCheck = performance.now() - cacheCheckStart;\n }\n\n if (cached) {\n if (verbose) {\n console.log(\n `[discovery] ✅ Using cached SMRT packages (${cached.packages.length} package(s))`,\n );\n }\n\n if (options.timing) {\n lastTimingData.total = performance.now() - startTime;\n }\n\n return cached.packages;\n }\n\n // No valid cache - perform fresh discovery\n if (verbose) {\n console.log('[discovery] Cache miss, performing discovery...');\n }\n\n const discoveryStart = options.timing ? performance.now() : 0;\n const packages = performDiscovery(baseDir, verbose);\n\n if (options.timing) {\n lastTimingData.discovery = performance.now() - discoveryStart;\n }\n\n // Save to cache\n saveCachedDiscovery(baseDir, packages, verbose);\n\n if (options.timing) {\n lastTimingData.total = performance.now() - startTime;\n }\n\n return packages;\n}\n\n// Run if called directly\nif (import.meta.url === `file://${process.argv[1]}`) {\n const noCache = process.argv.includes('--no-cache');\n const verbose =\n process.argv.includes('--verbose') || process.argv.includes('-v');\n const timing = process.argv.includes('--timing');\n\n const packages = discoverSmrtPackages({ noCache, verbose, timing });\n\n console.log('\\nDiscovered SMRT packages:');\n console.log(JSON.stringify(packages, null, 2));\n\n if (timing) {\n const timingData = getDiscoveryTiming();\n console.log('\\nTiming:');\n if (timingData.cacheCheck !== undefined) {\n console.log(` Cache check: ${timingData.cacheCheck.toFixed(2)}ms`);\n }\n if (timingData.discovery !== undefined) {\n console.log(` Discovery: ${timingData.discovery.toFixed(2)}ms`);\n }\n if (timingData.total !== undefined) {\n console.log(` Total: ${timingData.total.toFixed(2)}ms`);\n }\n }\n}\n"],"names":["packages"],"mappings":"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"}
1
+ {"version":3,"file":"discover-smrt-packages.js","sources":["../../src/manifest/discover-smrt-packages.ts"],"sourcesContent":["/**\n * SMRT Package Discovery\n *\n * Discovers all SMRT packages in node_modules by:\n * 1. Scanning node_modules directory for installed packages\n * 2. Following symlinks for workspace: dependencies\n * 3. Checking for a package manifest (`dist/manifest.json`,\n * `.smrt/manifest.json`, or `src/manifest/manifest.json`) with moduleType: \"smrt\"\n * 4. Caching results based on lockfile hash and manifest timestamps\n *\n * Cache Strategy:\n * - ENABLED by default (5-50x faster startup)\n * - Automatically invalidates when lockfile or any manifest.json changes\n * - Disable with SMRT_DISABLE_DISCOVERY_CACHE=true for debugging\n */\n\nimport { createHash } from 'node:crypto';\nimport {\n existsSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n realpathSync,\n statSync,\n writeFileSync,\n} from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { dirname, join } from 'node:path';\nimport { parse } from '../utils/json.js';\n\nconst CACHE_DIR = '.smrt';\nconst CACHE_FILE = 'discovery-cache.json';\nconst CACHE_VERSION = 4;\n\n/** Timing data for --timing flag */\ninterface TimingData {\n discovery?: number;\n cacheCheck?: number;\n total?: number;\n}\n\n/** Module-level timing storage */\nlet lastTimingData: TimingData = {};\n\n/**\n * Get timing data from last discovery operation\n */\nexport function getDiscoveryTiming(): TimingData {\n return { ...lastTimingData };\n}\n\n/**\n * Get hash of lockfile for cache invalidation\n */\nfunction getLockfileHash(baseDir: string): string | null {\n // Check for pnpm or npm lockfile\n const lockfile = existsSync(join(baseDir, 'pnpm-lock.yaml'))\n ? join(baseDir, 'pnpm-lock.yaml')\n : join(baseDir, 'package-lock.json');\n\n if (!existsSync(lockfile)) {\n return null;\n }\n\n const content = readFileSync(lockfile, 'utf-8');\n return createHash('sha256').update(content).digest('hex');\n}\n\n/**\n * Get hash of package.json for cache invalidation when a package workspace\n * changes its declared dependencies without a colocated lockfile.\n */\nfunction getPackageJsonHash(baseDir: string): string | null {\n const packageJsonPath = join(baseDir, 'package.json');\n\n if (!existsSync(packageJsonPath)) {\n return null;\n }\n\n const content = readFileSync(packageJsonPath, 'utf-8');\n return createHash('sha256').update(content).digest('hex');\n}\n\n/**\n * Get a hash of all manifest timestamps for cache invalidation\n * This catches changes to SMRT packages even when lockfile hasn't changed\n */\nfunction getManifestTimestampsHash(\n baseDir: string,\n packages: string[],\n): string {\n const timestamps: string[] = [];\n\n for (const pkgName of packages) {\n try {\n const manifestPath = resolveManifestPath(pkgName, baseDir);\n\n if (manifestPath && existsSync(manifestPath)) {\n const stats = statSync(manifestPath);\n timestamps.push(`${pkgName}:${stats.mtimeMs}`);\n }\n } catch {\n // Ignore errors, package may have been removed\n }\n }\n\n return createHash('sha256').update(timestamps.join('|')).digest('hex');\n}\n\ninterface DiscoveryCache {\n version: number;\n lockfileHash: string | null;\n packageJsonHash: string | null;\n manifestsHash: string;\n timestamp: number;\n packages: string[];\n}\n\nfunction findManifestPath(pkgPath: string): string | null {\n const candidates = [\n join(pkgPath, 'dist', 'manifest.json'),\n join(pkgPath, '.smrt', 'manifest.json'),\n join(pkgPath, 'src', 'manifest', 'manifest.json'),\n ];\n\n for (const candidate of candidates) {\n if (existsSync(candidate)) {\n return candidate;\n }\n }\n\n return null;\n}\n\nfunction normalizePackagePath(pkgPath: string): string {\n try {\n return realpathSync(pkgPath);\n } catch {\n return pkgPath;\n }\n}\n\nfunction resolvePackageDir(\n packageName: string,\n baseDir: string = process.cwd(),\n): string | null {\n try {\n const requireFromBase = createRequire(join(baseDir, 'package.json'));\n const packageEntry = requireFromBase.resolve(packageName);\n let currentDir = dirname(packageEntry);\n let resolvedPackageDir: string | null = null;\n\n for (let i = 0; i < 10; i++) {\n const packageJsonPath = join(currentDir, 'package.json');\n\n if (existsSync(packageJsonPath)) {\n const packageJson = parse<{ name?: string }>(\n readFileSync(packageJsonPath, 'utf-8'),\n );\n\n if (packageJson.name === packageName) {\n resolvedPackageDir = currentDir;\n }\n }\n\n const parentDir = dirname(currentDir);\n if (parentDir === currentDir) {\n break;\n }\n\n currentDir = parentDir;\n }\n\n if (resolvedPackageDir) {\n return normalizePackagePath(resolvedPackageDir);\n }\n } catch {\n // Fall through to direct node_modules lookup below.\n }\n\n const directPath = join(baseDir, 'node_modules', packageName);\n if (existsSync(directPath)) {\n return normalizePackagePath(directPath);\n }\n\n return null;\n}\n\nexport function resolveManifestPath(\n packageName: string,\n baseDir: string = process.cwd(),\n): string | null {\n const pkgPath = resolvePackageDir(packageName, baseDir);\n if (!pkgPath) {\n return null;\n }\n\n const manifestPath = findManifestPath(pkgPath);\n if (!manifestPath) {\n return null;\n }\n\n try {\n const manifest = parse<{ moduleType?: string }>(\n readFileSync(manifestPath, 'utf-8'),\n );\n\n return manifest.moduleType === 'smrt' ? manifestPath : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Load cached discovery results if valid\n * Cache is invalidated if:\n * - Lockfile hash changed (dependencies changed)\n * - Manifest timestamps hash changed (SMRT packages rebuilt)\n */\nfunction getCachedDiscovery(\n baseDir: string,\n verbose: boolean,\n): { packages: string[]; reason?: string } | null {\n const cachePath = join(baseDir, CACHE_DIR, CACHE_FILE);\n\n if (!existsSync(cachePath)) {\n return null;\n }\n\n try {\n const cache: DiscoveryCache = parse(readFileSync(cachePath, 'utf-8'));\n if (cache.version !== CACHE_VERSION) {\n if (verbose) {\n console.log('[discovery] Cache invalid: discovery version changed');\n }\n return null;\n }\n\n const currentLockfileHash = getLockfileHash(baseDir);\n const currentPackageJsonHash = getPackageJsonHash(baseDir);\n\n // Check lockfile hash\n if (cache.lockfileHash !== currentLockfileHash) {\n if (verbose) {\n console.log('[discovery] Cache invalid: lockfile changed');\n }\n return null;\n }\n\n if (cache.packageJsonHash !== currentPackageJsonHash) {\n if (verbose) {\n console.log('[discovery] Cache invalid: package.json changed');\n }\n return null;\n }\n\n // Check manifest timestamps (only if we have cached packages)\n if (cache.packages.length > 0) {\n const currentManifestsHash = getManifestTimestampsHash(\n baseDir,\n cache.packages,\n );\n if (cache.manifestsHash !== currentManifestsHash) {\n if (verbose) {\n console.log('[discovery] Cache invalid: manifest(s) changed');\n }\n return null;\n }\n }\n\n return { packages: cache.packages };\n } catch (error) {\n if (verbose) {\n console.warn(\n '[discovery] Failed to read cache:',\n (error as Error).message,\n );\n }\n return null;\n }\n}\n\n/**\n * Save discovery results to cache\n */\nfunction saveCachedDiscovery(\n baseDir: string,\n packages: string[],\n verbose: boolean,\n): void {\n const cache: DiscoveryCache = {\n version: CACHE_VERSION,\n lockfileHash: getLockfileHash(baseDir),\n packageJsonHash: getPackageJsonHash(baseDir),\n manifestsHash: getManifestTimestampsHash(baseDir, packages),\n timestamp: Date.now(),\n packages: packages,\n };\n\n try {\n mkdirSync(join(baseDir, CACHE_DIR), { recursive: true });\n writeFileSync(\n join(baseDir, CACHE_DIR, CACHE_FILE),\n JSON.stringify(cache, null, 2),\n );\n if (verbose) {\n console.log(`[discovery] Saved cache with ${packages.length} package(s)`);\n }\n } catch (error) {\n if (verbose) {\n console.warn(\n '[discovery] Failed to save cache:',\n (error as Error).message,\n );\n }\n }\n}\n\n/**\n * Check if a package provides a SMRT manifest\n *\n * Supports both regular npm dependencies and workspace: symlinks\n */\nfunction hasManifestExport(packageName: string, baseDir: string): boolean {\n return resolveManifestPath(packageName, baseDir) !== null;\n}\n\nfunction getDeclaredSmrtPackages(baseDir: string, verbose: boolean): string[] {\n const packageJsonPath = join(baseDir, 'package.json');\n if (!existsSync(packageJsonPath)) {\n return [];\n }\n\n try {\n const packageJson = parse<{\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n peerDependencies?: Record<string, string>;\n }>(readFileSync(packageJsonPath, 'utf-8'));\n\n const allDeps = {\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n ...packageJson.peerDependencies,\n };\n\n return Object.keys(allDeps).filter((pkgName) => {\n if (!pkgName.startsWith('@happyvertical/smrt-')) {\n return false;\n }\n\n const hasManifest = hasManifestExport(pkgName, baseDir);\n if (verbose && hasManifest) {\n console.log(`[discovery] ✅ Found declared SMRT package: ${pkgName}`);\n }\n\n return hasManifest;\n });\n } catch (error) {\n if (verbose) {\n console.warn(\n '[discovery] Failed to read declared dependencies:',\n (error as Error).message,\n );\n }\n return [];\n }\n}\n\n/**\n * Scan node_modules recursively for packages\n */\nfunction* scanNodeModules(baseDir: string): Generator<string> {\n const nodeModulesPath = join(baseDir, 'node_modules');\n\n if (!existsSync(nodeModulesPath)) {\n return;\n }\n\n try {\n const entries = readdirSync(nodeModulesPath);\n\n for (const entry of entries) {\n if (entry === '.bin' || entry === '.pnpm' || entry === '.cache') {\n continue;\n }\n\n const entryPath = join(nodeModulesPath, entry);\n\n try {\n const stats = statSync(entryPath);\n\n if (stats.isDirectory() || stats.isSymbolicLink()) {\n // Scoped packages (e.g., @happyvertical/smrt-core)\n if (entry.startsWith('@')) {\n const scopeEntries = readdirSync(entryPath);\n for (const scopedPkg of scopeEntries) {\n yield `${entry}/${scopedPkg}`;\n }\n } else {\n // Regular packages\n yield entry;\n }\n }\n } catch {}\n }\n } catch (error) {\n // node_modules doesn't exist or can't be read\n return;\n }\n}\n\n/**\n * Perform fresh discovery of SMRT packages\n */\nfunction performDiscovery(baseDir: string, verbose: boolean): string[] {\n if (verbose) {\n console.log('[discovery] Scanning node_modules for SMRT packages...');\n }\n\n try {\n const smrtPackages = new Set<string>();\n\n // Scan node_modules for all packages\n for (const pkgName of scanNodeModules(baseDir)) {\n if (hasManifestExport(pkgName, baseDir)) {\n smrtPackages.add(pkgName);\n if (verbose) {\n console.log(`[discovery] ✅ Found SMRT package: ${pkgName}`);\n }\n }\n }\n\n for (const pkgName of getDeclaredSmrtPackages(baseDir, verbose)) {\n smrtPackages.add(pkgName);\n }\n\n if (verbose) {\n console.log(\n `[discovery] Discovered ${smrtPackages.size} SMRT package(s)`,\n );\n }\n\n return Array.from(smrtPackages);\n } catch (error) {\n console.error(\n '[discovery] Failed to discover packages:',\n (error as Error).message,\n );\n return [];\n }\n}\n\nexport interface DiscoveryOptions {\n /** Override project root for discovery/cache */\n baseDir?: string;\n /** Force fresh discovery, ignoring cache */\n noCache?: boolean;\n /** Show verbose output */\n verbose?: boolean;\n /** Record timing data */\n timing?: boolean;\n}\n\n/**\n * Main discovery function\n *\n * Cache ENABLED by default (5-50x faster startup)\n * - Automatically invalidates when lockfile changes (dependencies updated)\n * - Automatically invalidates when any manifest.json changes (packages rebuilt)\n *\n * Disable with SMRT_DISABLE_DISCOVERY_CACHE=true for debugging\n *\n * Intentional split (#1579): this is the **build-time** discovery path —\n * synchronous, scans `node_modules` for `manifest.json` files with\n * `moduleType: \"smrt\"`, and caches by lockfile/manifest hash for fast manifest\n * generation. It is deliberately distinct from the consumer-plugin's\n * `discoverSmrtPackages(projectRoot)` (`src/consumer-plugin/index.ts`), which is\n * **async**, reads a downstream app's `package.json` dependency names with a\n * lightweight `@have/`/`smrt` heuristic, and runs inside the Vite consumer\n * plugin. Different inputs, contexts, and lifecycles — not duplicated logic to\n * consolidate.\n */\nexport function discoverSmrtPackages(options: DiscoveryOptions = {}): string[] {\n const startTime = options.timing ? performance.now() : 0;\n lastTimingData = {};\n const baseDir = options.baseDir || process.cwd();\n\n const cacheDisabled =\n options.noCache || process.env.SMRT_DISABLE_DISCOVERY_CACHE === 'true';\n\n const verbose: boolean =\n options.verbose === true ||\n process.env.SMRT_VERBOSE === 'true' ||\n !!process.env.DEBUG?.includes('smrt');\n\n if (cacheDisabled) {\n if (verbose) {\n console.log('[discovery] Cache disabled, performing fresh discovery...');\n }\n\n const packages = performDiscovery(baseDir, verbose);\n\n if (options.timing) {\n lastTimingData.discovery = performance.now() - startTime;\n lastTimingData.total = lastTimingData.discovery;\n }\n\n return packages;\n }\n\n // Try cache first\n const cacheCheckStart = options.timing ? performance.now() : 0;\n const cached = getCachedDiscovery(baseDir, verbose);\n\n if (options.timing) {\n lastTimingData.cacheCheck = performance.now() - cacheCheckStart;\n }\n\n if (cached) {\n if (verbose) {\n console.log(\n `[discovery] ✅ Using cached SMRT packages (${cached.packages.length} package(s))`,\n );\n }\n\n if (options.timing) {\n lastTimingData.total = performance.now() - startTime;\n }\n\n return cached.packages;\n }\n\n // No valid cache - perform fresh discovery\n if (verbose) {\n console.log('[discovery] Cache miss, performing discovery...');\n }\n\n const discoveryStart = options.timing ? performance.now() : 0;\n const packages = performDiscovery(baseDir, verbose);\n\n if (options.timing) {\n lastTimingData.discovery = performance.now() - discoveryStart;\n }\n\n // Save to cache\n saveCachedDiscovery(baseDir, packages, verbose);\n\n if (options.timing) {\n lastTimingData.total = performance.now() - startTime;\n }\n\n return packages;\n}\n\n// Run if called directly\nif (import.meta.url === `file://${process.argv[1]}`) {\n const noCache = process.argv.includes('--no-cache');\n const verbose =\n process.argv.includes('--verbose') || process.argv.includes('-v');\n const timing = process.argv.includes('--timing');\n\n const packages = discoverSmrtPackages({ noCache, verbose, timing });\n\n console.log('\\nDiscovered SMRT packages:');\n console.log(JSON.stringify(packages, null, 2));\n\n if (timing) {\n const timingData = getDiscoveryTiming();\n console.log('\\nTiming:');\n if (timingData.cacheCheck !== undefined) {\n console.log(` Cache check: ${timingData.cacheCheck.toFixed(2)}ms`);\n }\n if (timingData.discovery !== undefined) {\n console.log(` Discovery: ${timingData.discovery.toFixed(2)}ms`);\n }\n if (timingData.total !== undefined) {\n console.log(` Total: ${timingData.total.toFixed(2)}ms`);\n }\n }\n}\n"],"names":["packages"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/manifest/generator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAkB/D;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IAErC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;IAGxB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAG/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAGlB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IAGpB;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;OAEG;IACH,wBAAwB,CAAC,EAAE,MAAM,EAAE,CAAC;CACrC;AAuCD;;;;;GAKG;AACH,qBAAa,eAAe;IAC1B;;OAEG;IACG,QAAQ,CACZ,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,mBAAmB,CAAC;IAkC/B,OAAO,CAAC,kBAAkB;IAa1B,OAAO,CAAC,iBAAiB;IAmBzB;;OAEG;IACH,OAAO,CAAC,aAAa;IAUrB;;OAEG;YACW,gBAAgB;IAoD9B;;;;;OAKG;YACW,oBAAoB;IAyDlC;;;;;;OAMG;IACH,OAAO,CAAC,cAAc;IAiCtB;;OAEG;YACW,WAAW;IAyCzB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAuCxB;;OAEG;YACW,yBAAyB;IAkFvC;;OAEG;YACW,uBAAuB;IAwCrC;;OAEG;IACH,OAAO,CAAC,eAAe;IAavB;;OAEG;IACH,OAAO,CAAC,mBAAmB;CAuB5B"}
1
+ {"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/manifest/generator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAuB/D;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IAErC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;IAGxB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAG/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAGlB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IAGpB;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;OAEG;IACH,wBAAwB,CAAC,EAAE,MAAM,EAAE,CAAC;CACrC;AAuCD;;;;;GAKG;AACH,qBAAa,eAAe;IAC1B;;OAEG;IACG,QAAQ,CACZ,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,mBAAmB,CAAC;IAkC/B,OAAO,CAAC,kBAAkB;IAa1B,OAAO,CAAC,iBAAiB;IAmBzB;;OAEG;IACH,OAAO,CAAC,aAAa;IAUrB;;OAEG;YACW,gBAAgB;IAoD9B;;;;;OAKG;YACW,oBAAoB;IAyDlC;;;;;;OAMG;IACH,OAAO,CAAC,cAAc;IAiCtB;;OAEG;YACW,WAAW;IAyCzB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAuCxB;;OAEG;YACW,yBAAyB;IA6EvC;;OAEG;YACW,uBAAuB;IAwCrC;;OAEG;IACH,OAAO,CAAC,eAAe;IAavB;;OAEG;IACH,OAAO,CAAC,mBAAmB;CAuB5B"}
@@ -1,3 +1,4 @@
1
+ import { createLogger } from "@happyvertical/logger";
1
2
  import { existsSync, readFileSync, mkdirSync, writeFileSync } from "node:fs";
2
3
  import { isAbsolute, relative, resolve, dirname } from "node:path";
3
4
  import fg from "fast-glob";
@@ -5,6 +6,7 @@ import { ManifestGenerator } from "../scanner/manifest-generator.js";
5
6
  import { importWorkspaceModule } from "../utils/import-workspace-module.js";
6
7
  import { discoverSmrtPackages, resolveManifestPath } from "./discover-smrt-packages.js";
7
8
  import { ManifestManager } from "./manager.js";
9
+ const logger = createLogger({ level: "info" });
8
10
  async function importScanner() {
9
11
  return importWorkspaceModule({
10
12
  packageName: "@happyvertical/smrt-scanner",
@@ -20,10 +22,10 @@ class ManifestBuilder {
20
22
  async generate(options = {}) {
21
23
  const files = this.discoverFiles(options);
22
24
  if (files.length === 0) {
23
- console.log("[smrt] No source files found");
25
+ logger.info("[smrt] No source files found");
24
26
  return this.createEmptyManifest(options);
25
27
  }
26
- console.log(`[smrt] Scanning ${files.length} source file(s)...`);
28
+ logger.info(`[smrt] Scanning ${files.length} source file(s)...`);
27
29
  const scannerConfig = await this.configureScanner(options);
28
30
  const scannedManifest = await this.scanAndBuildManifest(
29
31
  scannerConfig,
@@ -86,26 +88,26 @@ class ManifestBuilder {
86
88
  const viteBaseClasses = await this.loadViteConfigBaseClasses();
87
89
  if (viteBaseClasses && viteBaseClasses.length > 0) {
88
90
  baseClasses = viteBaseClasses;
89
- console.log(
91
+ logger.info(
90
92
  `[smrt] Using baseClasses from vite.config.ts: ${baseClasses.join(", ")}`
91
93
  );
92
94
  }
93
95
  }
94
96
  let smrtDependencies = [];
95
97
  if (options.discoverExternalPackages) {
96
- console.log("[smrt] Discovering external SMRT packages...");
98
+ logger.info("[smrt] Discovering external SMRT packages...");
97
99
  smrtDependencies = discoverSmrtPackages();
98
- console.log(
100
+ logger.info(
99
101
  `[smrt] Found ${smrtDependencies.length} SMRT package(s): ${smrtDependencies.join(", ")}`
100
102
  );
101
103
  if (options.includeExternalBaseClasses) {
102
104
  const externalClasses = await this.loadExternalBaseClasses(smrtDependencies);
103
105
  if (externalClasses.length > 0) {
104
106
  baseClasses = [...baseClasses, ...externalClasses];
105
- console.log(
107
+ logger.info(
106
108
  `[smrt] Added ${externalClasses.length} external base class(es) to scanner`
107
109
  );
108
- console.log(`[smrt] Total baseClasses: ${baseClasses.length}`);
110
+ logger.info(`[smrt] Total baseClasses: ${baseClasses.length}`);
109
111
  }
110
112
  }
111
113
  }
@@ -180,9 +182,9 @@ class ManifestBuilder {
180
182
  const packageInfo = this.readPackageJson();
181
183
  if (packageInfo.name) {
182
184
  manifest.packageName = packageInfo.name;
183
- console.log(`[smrt] Injected package name: ${packageInfo.name}`);
185
+ logger.info(`[smrt] Injected package name: ${packageInfo.name}`);
184
186
  } else {
185
- console.warn(
187
+ logger.warn(
186
188
  "[smrt] Warning: Could not read package.json, packageName will be undefined"
187
189
  );
188
190
  }
@@ -212,8 +214,8 @@ class ManifestBuilder {
212
214
  writeFileSync(stubPath, tsContent);
213
215
  }
214
216
  const objectCount = Object.keys(manifest.objects).length;
215
- console.log(`[smrt] ✅ Generated manifest with ${objectCount} object(s)`);
216
- console.log(`[smrt] Unified: ${unifiedPath}`);
217
+ logger.info(`[smrt] ✅ Generated manifest with ${objectCount} object(s)`);
218
+ logger.info(`[smrt] Unified: ${unifiedPath}`);
217
219
  }
218
220
  /**
219
221
  * Generate TypeScript stub file with manifest constant
@@ -250,59 +252,54 @@ export default ${exportName};
250
252
  try {
251
253
  const viteConfigPath = resolve(process.cwd(), "vite.config.ts");
252
254
  if (!existsSync(viteConfigPath)) {
253
- console.log("[smrt] vite.config.ts not found");
255
+ logger.info("[smrt] vite.config.ts not found");
254
256
  return null;
255
257
  }
256
- console.log("[smrt] Found vite.config.ts, attempting to load...");
258
+ logger.info("[smrt] Found vite.config.ts, attempting to load...");
257
259
  const { loadConfigFromFile } = await import("vite");
258
260
  const loaded = await loadConfigFromFile(
259
261
  { command: "build", mode: "test" },
260
262
  viteConfigPath
261
263
  );
262
264
  if (!loaded?.config?.plugins) {
263
- console.log("[smrt] No plugins found in vite config");
265
+ logger.info("[smrt] No plugins found in vite config");
264
266
  return null;
265
267
  }
266
268
  const plugins = loaded.config.plugins;
267
- console.log(
268
- "[smrt] Vite config loaded, plugins:",
269
- plugins.map((p) => p?.name)
270
- );
269
+ logger.info("[smrt] Vite config loaded", {
270
+ plugins: plugins.map((p) => p?.name)
271
+ });
271
272
  const smrtPlugin = plugins.find((p) => p?.name === "smrt-auto-service");
272
273
  if (!smrtPlugin) {
273
- console.log(
274
+ logger.info(
274
275
  "[smrt] smrt-auto-service plugin not found in plugins array"
275
276
  );
276
277
  return null;
277
278
  }
278
- console.log("[smrt] Found smrt-auto-service plugin");
279
+ logger.info("[smrt] Found smrt-auto-service plugin");
279
280
  const api = smrtPlugin.api;
280
281
  let opts = (typeof api === "object" && api !== null ? api.options : void 0) || smrtPlugin.options || smrtPlugin._options;
281
282
  if (!opts && typeof api === "function") {
282
283
  try {
283
284
  opts = api().options;
284
285
  } catch (e) {
285
- console.log("[smrt] Could not call plugin.api()");
286
+ logger.info("[smrt] Could not call plugin.api()");
286
287
  }
287
288
  }
288
289
  if (opts?.baseClasses) {
289
- console.log(
290
- "[smrt] Plugin options:",
291
- JSON.stringify({
292
- baseClasses: opts.baseClasses,
293
- followImports: opts.followImports
294
- })
295
- );
290
+ logger.info("[smrt] Plugin options", {
291
+ baseClasses: opts.baseClasses,
292
+ followImports: opts.followImports
293
+ });
296
294
  return opts.baseClasses;
297
295
  }
298
- console.log("[smrt] Could not access plugin options");
296
+ logger.info("[smrt] Could not access plugin options");
299
297
  return null;
300
298
  } catch (error) {
301
- console.log(
302
- "[smrt] Error loading vite.config.ts:",
303
- error instanceof Error ? error.message : String(error)
304
- );
305
- console.log("[smrt] Using default baseClasses");
299
+ logger.warn("[smrt] Error loading vite.config.ts", {
300
+ error: error instanceof Error ? error.message : String(error)
301
+ });
302
+ logger.info("[smrt] Using default baseClasses");
306
303
  return null;
307
304
  }
308
305
  }
@@ -314,7 +311,7 @@ export default ${exportName};
314
311
  for (const pkgName of packages) {
315
312
  const manifestPath = resolveManifestPath(pkgName, process.cwd());
316
313
  if (!manifestPath) {
317
- console.log(`[smrt] ${pkgName}: no SMRT manifest resolved`);
314
+ logger.info(`[smrt] ${pkgName}: no SMRT manifest resolved`);
318
315
  continue;
319
316
  }
320
317
  try {
@@ -328,11 +325,11 @@ export default ${exportName};
328
325
  externalBaseClasses.push(className);
329
326
  }
330
327
  }
331
- console.log(
328
+ logger.info(
332
329
  `[smrt] ${pkgName}: found ${foundClassNames.length} class(es) - ${foundClassNames.join(", ")}`
333
330
  );
334
331
  } catch (error) {
335
- console.log(
332
+ logger.info(
336
333
  `[smrt] ${pkgName}: manifest not found or invalid - ${error instanceof Error ? error.message : String(error)}`
337
334
  );
338
335
  }