@happyvertical/smrt-dev-mcp 0.60.9 → 0.60.10

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 (50) hide show
  1. package/AGENTS.md +27 -1
  2. package/README.md +17 -1
  3. package/agents/intent-duplicates.md +26 -0
  4. package/dist/dev-plane.js +2 -2
  5. package/dist/{http-CCiO7qQW.js → http-BqKiyqgN.js} +2 -2
  6. package/dist/{http-CCiO7qQW.js.map → http-BqKiyqgN.js.map} +1 -1
  7. package/dist/index.js +12 -409
  8. package/dist/index.js.map +1 -1
  9. package/dist/knowledge/index.d.ts +1 -1
  10. package/dist/knowledge/index.d.ts.map +1 -1
  11. package/dist/knowledge/intents/audit-trail.md +63 -0
  12. package/dist/knowledge/intents/auth-and-users.md +67 -0
  13. package/dist/knowledge/intents/background-work.md +72 -0
  14. package/dist/knowledge/intents/feature-flags-and-entitlements.md +60 -0
  15. package/dist/knowledge/intents/file-and-asset-storage.md +71 -0
  16. package/dist/knowledge/intents/human-approvals.md +56 -0
  17. package/dist/knowledge/intents/index.md +41 -0
  18. package/dist/knowledge/intents/money-and-rates.md +65 -0
  19. package/dist/knowledge/intents/outbound-messages.md +67 -0
  20. package/dist/knowledge/intents/prompts-and-ai-operations.md +72 -0
  21. package/dist/knowledge/intents/relationships-and-trees.md +56 -0
  22. package/dist/knowledge/intents/scheduled-runs.md +61 -0
  23. package/dist/knowledge/intents/search-facts-knowledge.md +68 -0
  24. package/dist/knowledge/intents/secrets-and-config.md +66 -0
  25. package/dist/knowledge/intents/tenant-scoping.md +63 -0
  26. package/dist/knowledge/intents/webhooks-and-events.md +71 -0
  27. package/dist/knowledge/okf-bundle.d.ts +61 -0
  28. package/dist/knowledge/okf-bundle.d.ts.map +1 -0
  29. package/dist/{knowledge-DqoDX-lZ.js → knowledge-DUiMUjEg.js} +218 -3
  30. package/dist/knowledge-DUiMUjEg.js.map +1 -0
  31. package/dist/knowledge.js +2 -2
  32. package/dist/review-cli-DJIWUlFp.js +75 -0
  33. package/dist/review-cli-DJIWUlFp.js.map +1 -0
  34. package/dist/review-smrt-project-ByEwPcor.js +774 -0
  35. package/dist/review-smrt-project-ByEwPcor.js.map +1 -0
  36. package/dist/smrt-knowledge.okf.md +60 -0
  37. package/dist/{tool-catalog-RHq7nyCm.js → tool-catalog-BhnSCF8g.js} +11 -2
  38. package/dist/tool-catalog-BhnSCF8g.js.map +1 -0
  39. package/dist/tool-catalog.d.ts.map +1 -1
  40. package/dist/tools/intent-detector.d.ts +57 -0
  41. package/dist/tools/intent-detector.d.ts.map +1 -0
  42. package/dist/tools/intent-index.d.ts +40 -0
  43. package/dist/tools/intent-index.d.ts.map +1 -0
  44. package/dist/tools/review-cli.d.ts +40 -0
  45. package/dist/tools/review-cli.d.ts.map +1 -0
  46. package/dist/tools/review-smrt-project.d.ts +25 -0
  47. package/dist/tools/review-smrt-project.d.ts.map +1 -1
  48. package/package.json +6 -6
  49. package/dist/knowledge-DqoDX-lZ.js.map +0 -1
  50. package/dist/tool-catalog-RHq7nyCm.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-smrt-project-ByEwPcor.js","names":[],"sources":["../src/tools/intent-detector.ts","../src/tools/intent-index.ts","../src/tools/review-smrt-project.ts"],"sourcesContent":["/**\n * Table-driven hand-rolled-equivalent detector (#4690).\n *\n * The engine knows signal *kinds* (`import`, `call`, `regex`, `decimal-field`),\n * never intents: every rule comes from a parsed intent-index row. A new row\n * with signals therefore needs no code change here. Tokens of an unknown kind\n * are skipped with a note so an index that is newer than this tool degrades\n * instead of failing.\n */\n\nimport type { IntentRow, IntentSignal } from './intent-index.js';\n\nexport interface DetectorFile {\n /** Path relative to the reviewed project root. */\n relativePath: string;\n content: string;\n /** Normalised package specifiers imported by the file. */\n imports: string[];\n}\n\nexport interface DetectorPackage {\n name?: string;\n relativePath: string;\n /** Home packages of any row that resolve in package.json or node_modules. */\n installed: ReadonlySet<string>;\n files: DetectorFile[];\n}\n\nexport interface SignalEvidence {\n filePath: string;\n line: number;\n signal: string;\n detail: string;\n}\n\nexport interface HandRolledFinding {\n code: string;\n intent: string;\n intentPage: string;\n componentPages: string[];\n entryPoint: string;\n packageName: string;\n packagePath: string;\n /** Home packages the consumer declares or has installed, yet never imports. */\n installedHomePackages: string[];\n homePackages: string[];\n matchedSignals: string[];\n evidence: SignalEvidence[];\n}\n\nexport interface DetectOptions {\n /** Receives one human-readable note per skipped signal token. */\n onNote?: (note: string) => void;\n /** Evidence entries kept per finding. */\n maxEvidence?: number;\n}\n\ntype LineMatcher = (line: string) => boolean;\ntype SignalCompiler = (\n signal: IntentSignal,\n) => { matchLine: LineMatcher } | { matchImport: string } | { error: string };\n\nconst COMMENT_LINE = /^\\s*(\\/\\/|\\/\\*|\\*|<!--)/;\n\nfunction normalizeSpecifier(value: string): string {\n if (value.startsWith('@')) {\n const [scope, name] = value.split('/');\n return scope && name ? `${scope}/${name}` : value;\n }\n return value.split('/')[0];\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/** `*_cents`-style glob (`*` = any run) -> case-insensitive anchored regex. */\nfunction globToRegExp(glob: string): RegExp {\n const pattern = glob\n .split('*')\n .map((part) => escapeRegExp(part))\n .join('.*');\n return new RegExp(`^${pattern}$`, 'i');\n}\n\nfunction camelToSnake(name: string): string {\n return name.replace(/([a-z0-9])([A-Z])/g, '$1_$2').toLowerCase();\n}\n\nconst DECIMAL_PROPERTY =\n /^\\s*(?:(?:public|private|protected|readonly|static)\\s+)*(\\w+)\\s*(?::\\s*number\\s*)?=\\s*-?\\d+\\.\\d+/;\nconst DECIMAL_TYPED_FIELD =\n /@field\\(\\s*\\{[^}]*type\\s*:\\s*['\"]decimal['\"][^}]*\\}\\s*\\)\\s*(?:(?:public|private|protected|readonly)\\s+)*(\\w+)/;\n\n/**\n * Signal grammar. Add a kind here only when an index row cannot be expressed\n * with the existing ones; intents themselves never appear in this file.\n *\n * - `import:<module>` the module (or a subpath of it) is imported.\n * - `call:<ident>` `ident(` appears in code.\n * - `regex:<pattern>` the JavaScript regular expression matches a line.\n * - `decimal-field:<glob>` a property whose name matches the glob (compared\n * as written and as snake_case) is declared with a decimal literal\n * (`= 0.0`) or `@field({ type: 'decimal' })`.\n */\nconst COMPILERS: Record<string, SignalCompiler> = {\n import: (signal) => ({ matchImport: normalizeSpecifier(signal.value) }),\n call: (signal) => {\n if (!/^[\\w$.]+$/.test(signal.value)) {\n return { error: `invalid identifier \"${signal.value}\"` };\n }\n const pattern = new RegExp(\n `(?<![\\\\w$])${escapeRegExp(signal.value)}\\\\s*\\\\(`,\n );\n return { matchLine: (line) => pattern.test(line) };\n },\n regex: (signal) => {\n try {\n const pattern = new RegExp(signal.value);\n return { matchLine: (line) => pattern.test(line) };\n } catch (error) {\n return {\n error: `invalid regular expression (${error instanceof Error ? error.message : String(error)})`,\n };\n }\n },\n 'decimal-field': (signal) => {\n const glob = globToRegExp(signal.value);\n const matches = (name: string | undefined) =>\n !!name && (glob.test(name) || glob.test(camelToSnake(name)));\n return {\n matchLine: (line) =>\n matches(DECIMAL_PROPERTY.exec(line)?.[1]) ||\n matches(DECIMAL_TYPED_FIELD.exec(line)?.[1]),\n };\n },\n};\n\nexport const SUPPORTED_SIGNAL_KINDS = Object.keys(COMPILERS);\n\ninterface CompiledSignal {\n raw: string;\n matchLine?: LineMatcher;\n matchImport?: string;\n}\n\nfunction compileRow(\n row: IntentRow,\n noted: Set<string>,\n onNote: (note: string) => void,\n): CompiledSignal[] {\n const compiled: CompiledSignal[] = [];\n for (const signal of row.signals) {\n const compiler = COMPILERS[signal.kind];\n const skip = (reason: string) => {\n const key = `${row.intentPage}\\0${signal.raw}`;\n if (noted.has(key)) return;\n noted.add(key);\n onNote(\n `intent index: skipping signal \\`${signal.raw}\\` for ${row.intentPage} (${reason})`,\n );\n };\n if (!compiler) {\n skip(`unknown signal kind \"${signal.kind}\"`);\n continue;\n }\n const result = compiler(signal);\n if ('error' in result) skip(result.error);\n else compiled.push({ raw: signal.raw, ...result });\n }\n return compiled;\n}\n\nfunction importLine(file: DetectorFile, specifier: string): number {\n const lines = file.content.split('\\n');\n const pattern = new RegExp(`['\"]${escapeRegExp(specifier)}(?:/[^'\"]*)?['\"]`);\n const index = lines.findIndex(\n (line) => !COMMENT_LINE.test(line) && pattern.test(line),\n );\n return index < 0 ? 1 : index + 1;\n}\n\n/**\n * For every (intent row, package) where a signal is present and the package\n * imports none of the row's home packages, emit one finding.\n */\nexport function detectHandRolled(\n rows: readonly IntentRow[],\n packages: readonly DetectorPackage[],\n options: DetectOptions = {},\n): HandRolledFinding[] {\n const onNote = options.onNote ?? (() => undefined);\n const maxEvidence = options.maxEvidence ?? 6;\n const noted = new Set<string>();\n const findings: HandRolledFinding[] = [];\n\n for (const row of rows) {\n const signals = compileRow(row, noted, onNote);\n if (signals.length === 0 || row.homePackages.length === 0) continue;\n const homeNames = row.homePackages.map((home) => home.packageName);\n\n for (const pkg of packages) {\n if (pkg.name && homeNames.includes(pkg.name)) continue;\n const importsHome = pkg.files.some((file) =>\n file.imports.some((specifier) => homeNames.includes(specifier)),\n );\n if (importsHome) continue;\n\n const evidence: SignalEvidence[] = [];\n const matched = new Set<string>();\n for (const file of pkg.files) {\n for (const signal of signals) {\n if (signal.matchImport !== undefined) {\n if (!file.imports.includes(signal.matchImport)) continue;\n matched.add(signal.raw);\n evidence.push({\n filePath: file.relativePath,\n line: importLine(file, signal.matchImport),\n signal: signal.raw,\n detail: `Imports ${signal.matchImport}`,\n });\n } else if (signal.matchLine) {\n const lines = file.content.split('\\n');\n for (let index = 0; index < lines.length; index += 1) {\n if (COMMENT_LINE.test(lines[index])) continue;\n if (!signal.matchLine(lines[index])) continue;\n matched.add(signal.raw);\n evidence.push({\n filePath: file.relativePath,\n line: index + 1,\n signal: signal.raw,\n detail: `Matches ${signal.raw}`,\n });\n break; // first hit per signal per file\n }\n }\n }\n }\n if (evidence.length === 0) continue;\n\n evidence.sort(\n (left, right) =>\n left.filePath.localeCompare(right.filePath) || left.line - right.line,\n );\n findings.push({\n code: `hand-rolled-${row.intentPage.replace(/^\\/intents\\//, '').replace(/\\.md$/, '')}`,\n intent: row.intent,\n intentPage: row.intentPage,\n componentPages: row.homePackages.map((home) => home.componentPage),\n entryPoint: row.entryPoint,\n packageName: pkg.name ?? pkg.relativePath,\n packagePath: pkg.relativePath,\n installedHomePackages: homeNames.filter((name) =>\n pkg.installed.has(name),\n ),\n homePackages: homeNames,\n matchedSignals: Array.from(matched),\n evidence: evidence.slice(0, maxEvidence),\n });\n }\n }\n return findings;\n}\n","/**\n * Pure parser for the developer-intent index (`intents/index.md`).\n *\n * The index is one markdown table whose last column lists `;`-separated\n * backticked signal tokens (`import:node-cron`, `call:setInterval`,\n * `regex:...`). The duplicate-detection pass is driven entirely by these rows,\n * so a new row with signals needs no code change (#4690).\n */\n\nexport interface IntentSignal {\n /** Token kind: the text before the first colon (`import`, `call`, ...). */\n kind: string;\n /** Token value: everything after the first colon. */\n value: string;\n /** The token exactly as written in the table. */\n raw: string;\n}\n\nexport interface IntentHomePackage {\n /** Unscoped package name, e.g. `smrt-jobs`. */\n name: string;\n /** Published npm name, e.g. `@happyvertical/smrt-jobs`. */\n packageName: string;\n /** Component page concept ID, e.g. `/components/smrt-jobs.md`. */\n componentPage: string;\n}\n\nexport interface IntentRow {\n intent: string;\n /** Intent page concept ID, e.g. `/intents/scheduled-runs.md`. */\n intentPage: string;\n homePackages: IntentHomePackage[];\n entryPoint: string;\n signals: IntentSignal[];\n}\n\nconst PACKAGE_SCOPE = '@happyvertical/';\n\n/** Split a table row on unescaped pipes, unescaping `\\|` inside cells. */\nfunction splitRow(line: string): string[] {\n const cells: string[] = [];\n let current = '';\n for (let index = 0; index < line.length; index += 1) {\n const char = line[index];\n if (char === '\\\\' && line[index + 1] === '|') {\n current += '|';\n index += 1;\n } else if (char === '|') {\n cells.push(current);\n current = '';\n } else {\n current += char;\n }\n }\n cells.push(current);\n // A leading and trailing pipe produce empty edge cells.\n if (cells[0]?.trim() === '') cells.shift();\n if (cells.length > 0 && cells[cells.length - 1].trim() === '') cells.pop();\n return cells.map((cell) => cell.trim());\n}\n\nfunction linkTargets(cell: string): { text: string; href: string }[] {\n return Array.from(cell.matchAll(/\\[([^\\]]*)\\]\\(([^)\\s]+)\\)/g)).map(\n (match) => ({ text: match[1], href: match[2] }),\n );\n}\n\n/** `/intents/x.md`, `./x.md` or `x.md` -> `/<kind>/x.md`. */\nfunction conceptId(href: string, kind: 'intents' | 'components'): string {\n const base = href.split('#')[0].split('/').pop() ?? href;\n return `/${kind}/${base}`;\n}\n\nfunction parseSignals(cell: string): IntentSignal[] {\n const signals: IntentSignal[] = [];\n for (const match of cell.matchAll(/`([^`]+)`/g)) {\n const raw = match[1].trim();\n const colon = raw.indexOf(':');\n if (colon <= 0) {\n signals.push({ kind: '', value: raw, raw });\n continue;\n }\n signals.push({\n kind: raw.slice(0, colon).trim(),\n value: raw.slice(colon + 1),\n raw,\n });\n }\n return signals;\n}\n\n/**\n * Parse the first intent table found in `markdown`. Columns are located by\n * header name (`Intent`, `Page`, `Home package(s)`, `Entry point`,\n * `Hand-rolled signals`) so column order may change. Rows without a page link\n * are ignored.\n */\nexport function parseIntentIndex(markdown: string): IntentRow[] {\n const lines = markdown.split(/\\r?\\n/);\n const headerIndex = lines.findIndex(\n (line) => /^\\s*\\|/.test(line) && /\\bintent\\b/i.test(line),\n );\n if (headerIndex < 0) return [];\n\n const headers = splitRow(lines[headerIndex]).map((cell) =>\n cell.toLowerCase(),\n );\n const column = (needle: string, fallback: number): number => {\n const found = headers.findIndex((header) => header.includes(needle));\n return found >= 0 ? found : fallback;\n };\n const columns = {\n intent: column('intent', 0),\n page: column('page', 1),\n home: column('home', 2),\n entry: column('entry', 3),\n signals: column('signal', 4),\n };\n\n const rows: IntentRow[] = [];\n for (const line of lines.slice(headerIndex + 1)) {\n if (!/^\\s*\\|/.test(line)) {\n if (rows.length > 0 || line.trim() !== '') break;\n continue;\n }\n if (/^\\s*\\|[\\s:|-]+\\|\\s*$/.test(line)) continue; // delimiter row\n const cells = splitRow(line);\n const pageLink = linkTargets(cells[columns.page] ?? '')[0];\n if (!pageLink) continue;\n const homePackages = linkTargets(cells[columns.home] ?? '').map((link) => {\n const componentPage = conceptId(link.href, 'components');\n const name = componentPage\n .replace(/^\\/components\\//, '')\n .replace(/\\.md$/, '');\n return { name, packageName: `${PACKAGE_SCOPE}${name}`, componentPage };\n });\n rows.push({\n intent: cells[columns.intent] ?? '',\n intentPage: conceptId(pageLink.href, 'intents'),\n homePackages,\n entryPoint: cells[columns.entry] ?? '',\n signals: parseSignals(cells[columns.signals] ?? ''),\n });\n }\n return rows;\n}\n","/**\n * Ecosystem-aware downstream project review.\n * Advisory only: scans manifests and source files, then reports alignment risks.\n */\n\nimport { type Dirent, existsSync, readFileSync } from 'node:fs';\nimport { access, readdir, readFile } from 'node:fs/promises';\nimport {\n basename,\n dirname,\n isAbsolute,\n join,\n relative,\n resolve,\n sep,\n} from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport {\n type DetectorPackage,\n detectHandRolled,\n type HandRolledFinding,\n} from './intent-detector.js';\nimport { type IntentRow, parseIntentIndex } from './intent-index.js';\n\ninterface ReviewSmrtProjectArgs {\n directory?: string;\n rootDir?: string;\n includeSourceEvidence?: boolean;\n maxFindings?: number;\n /**\n * Intent index to drive duplicate detection. Its `regex:` tokens become\n * `RegExp`s, so this is trusted by the caller and never read from the\n * reviewed tree by default. Default: the full index shipped inside the\n * pinned `@happyvertical/smrt-dev-mcp` package (`dist/knowledge/intents`),\n * else `docs/knowledge/intents/index.md` when running from the smrt\n * monorepo checkout. Relative paths resolve against `directory`.\n */\n intentIndexPath?: string;\n /** Set false to skip the intent-driven duplicate-detection pass. */\n detectDuplicates?: boolean;\n /**\n * Test seam: package root used to locate the packaged index instead of this\n * module's own. Not part of the tool schema.\n */\n packageRoot?: string;\n}\n\n/** Relative location of the intent index inside this package's `dist/`. */\nexport const PACKAGED_INTENT_INDEX = join(\n 'dist',\n 'knowledge',\n 'intents',\n 'index.md',\n);\n\nfunction findOwnPackageRoot(): string | null {\n let current = dirname(fileURLToPath(import.meta.url));\n for (;;) {\n const manifest = join(current, 'package.json');\n if (existsSync(manifest)) {\n try {\n const json = JSON.parse(readFileSync(manifest, 'utf-8')) as {\n name?: string;\n };\n if (json.name === '@happyvertical/smrt-dev-mcp') return current;\n } catch {\n // Keep walking.\n }\n }\n const parent = dirname(current);\n if (parent === current) return null;\n current = parent;\n }\n}\n\n/**\n * Locations of the trusted default intent index, in resolution order (#4690):\n * the packaged full index, then the monorepo's committed index when this\n * package sits in `<repo>/packages/` of the smrt checkout. The reviewed\n * project's own tree is never consulted.\n */\nexport function defaultIntentIndexCandidates(packageRoot?: string): string[] {\n const root = packageRoot ?? findOwnPackageRoot();\n if (!root) return [];\n const candidates = [join(root, PACKAGED_INTENT_INDEX)];\n const packagesDir = dirname(root);\n if (basename(packagesDir) === 'packages') {\n const repoRoot = dirname(packagesDir);\n if (existsSync(join(repoRoot, 'pnpm-workspace.yaml'))) {\n candidates.push(\n join(repoRoot, 'docs', 'knowledge', 'intents', 'index.md'),\n );\n }\n }\n return candidates;\n}\n\ntype Severity = 'high' | 'medium' | 'low';\n\ninterface Evidence {\n filePath: string;\n line?: number;\n detail: string;\n}\n\ninterface Finding {\n severity: Severity;\n area:\n | 'dependencies'\n | 'storage'\n | 'api-shell'\n | 'manifest'\n | 'auth-tenancy'\n | 'ui-shell'\n | 'duplicate-detection';\n code: string;\n title: string;\n evidence: Evidence[];\n recommendation: string;\n suggestedIssueTitle: string;\n /** Duplicate-detection findings only (same anchors as `build-context`). */\n message?: string;\n file?: string;\n packageName?: string;\n intentPage?: string;\n componentPages?: string[];\n}\n\ninterface PackageInventory {\n name: string;\n path: string;\n private?: boolean;\n scripts: string[];\n declaredHappyVerticalDependencies: string[];\n importedHappyVerticalPackages: string[];\n missingHappyVerticalDependencies: string[];\n hasSvelteKit: boolean;\n hasSmrtSvelte: boolean;\n}\n\ninterface PackageContext {\n directory: string;\n relativePath: string;\n packageJsonPath: string;\n json: Record<string, unknown>;\n dependencies: Set<string>;\n scripts: Record<string, unknown>;\n imports: Map<string, Evidence[]>;\n sourceFiles: SourceFile[];\n}\n\ninterface SourceFile {\n path: string;\n packageDir: string;\n content: string;\n}\n\nconst SOURCE_EXTENSIONS = /\\.(tsx?|jsx?|svelte)$/;\nconst SKIP_DIRS = new Set([\n 'node_modules',\n 'dist',\n 'build',\n '.git',\n '.smrt',\n '.svelte-kit',\n 'coverage',\n]);\nconst DEPENDENCY_SECTIONS = [\n 'dependencies',\n 'devDependencies',\n 'peerDependencies',\n 'optionalDependencies',\n];\nconst SMRT_PACKAGE_PREFIX = '@happyvertical/smrt-';\nconst HAPPYVERTICAL_PACKAGE_PREFIX = '@happyvertical/';\n\nexport async function reviewSmrtProject(\n args: ReviewSmrtProjectArgs,\n): Promise<string> {\n const projectPath = resolve(args.directory ?? args.rootDir ?? process.cwd());\n if (!(await pathExists(projectPath))) {\n return JSON.stringify(\n {\n projectPath,\n packageCount: 0,\n packages: [],\n findings: [],\n summary: { high: 0, medium: 0, low: 0 },\n diagnostics: [\n {\n severity: 'warning',\n message: `Project directory does not exist: ${projectPath}`,\n },\n ],\n },\n null,\n 2,\n );\n }\n\n const packageContexts = await buildPackageContexts(projectPath);\n const sourceFiles = await listSourceFiles(projectPath, packageContexts);\n await attachSourceFiles(sourceFiles, packageContexts, projectPath);\n\n const duplicates = await runDuplicateDetection(\n args,\n projectPath,\n packageContexts,\n );\n\n const findings = limitFindings(\n [\n ...duplicates.findings,\n ...findMissingHappyVerticalDependencies(packageContexts),\n ...findCustomManifestGeneration(sourceFiles, projectPath),\n ...findDirectStorageBypasses(sourceFiles, packageContexts, projectPath),\n ...findCustomHttpShells(sourceFiles, packageContexts, projectPath),\n ...findLocalAuthTenancy(sourceFiles, packageContexts, projectPath),\n ...findUiShellDrift(packageContexts, projectPath),\n ...findMissingManifestArtifacts(\n sourceFiles,\n packageContexts,\n projectPath,\n ),\n ],\n args.maxFindings,\n );\n\n const packages = packageContexts\n .map(packageInventory)\n .sort((left, right) => left.path.localeCompare(right.path));\n const summary = summarizeFindings(findings);\n\n return JSON.stringify(\n {\n projectPath,\n packageCount: packages.length,\n packages,\n findings:\n args.includeSourceEvidence === false\n ? findings.map(({ evidence: _evidence, ...finding }) => finding)\n : findings,\n summary,\n duplicateDetection: duplicates.status,\n referenceChecks: [\n 'Prefer SMRT scanner/runtime manifests over custom manifest builders.',\n 'Prefer SvelteKit plus @happyvertical/smrt-svelte for app shells.',\n 'Prefer @happyvertical/sql and @happyvertical/files/assets/content over direct durable node:fs storage.',\n 'Prefer smrt-users, smrt-tenancy, and profile/audit packages over local static auth seams.',\n ],\n suggestedFollowUpIssues: findings.map((finding) => ({\n title: finding.suggestedIssueTitle,\n severity: finding.severity,\n area: finding.area,\n })),\n },\n null,\n 2,\n );\n}\n\nasync function buildPackageContexts(\n projectPath: string,\n): Promise<PackageContext[]> {\n const packageJsonPaths = await listPackageJsonFiles(projectPath);\n const contexts = await Promise.all(\n packageJsonPaths.map(async (packageJsonPath) => {\n const json = JSON.parse(\n await readFile(packageJsonPath, 'utf-8'),\n ) as Record<string, unknown>;\n const directory = dirname(packageJsonPath);\n return {\n directory,\n relativePath: relative(projectPath, directory) || '.',\n packageJsonPath,\n json,\n dependencies: collectDependencies(json),\n scripts: isRecord(json.scripts)\n ? (json.scripts as Record<string, unknown>)\n : {},\n imports: new Map<string, Evidence[]>(),\n sourceFiles: [],\n };\n }),\n );\n\n if (contexts.length === 0) {\n contexts.push({\n directory: projectPath,\n relativePath: '.',\n packageJsonPath: join(projectPath, 'package.json'),\n json: {},\n dependencies: new Set(),\n scripts: {},\n imports: new Map(),\n sourceFiles: [],\n });\n }\n\n return contexts.sort(\n (left, right) => left.directory.length - right.directory.length,\n );\n}\n\nasync function listPackageJsonFiles(projectPath: string): Promise<string[]> {\n const files: string[] = [];\n await visit(projectPath, async (filePath, entryName) => {\n if (entryName === 'package.json') files.push(filePath);\n });\n return files;\n}\n\nasync function listSourceFiles(\n projectPath: string,\n packages: PackageContext[],\n): Promise<SourceFile[]> {\n const files: SourceFile[] = [];\n await visit(projectPath, async (filePath, entryName) => {\n if (!SOURCE_EXTENSIONS.test(entryName)) return;\n if (\n entryName.endsWith('.d.ts') ||\n entryName.endsWith('.test.ts') ||\n entryName.endsWith('.spec.ts')\n ) {\n return;\n }\n\n const packageDir = findOwningPackage(filePath, packages).directory;\n const content = await readFile(filePath, 'utf-8');\n files.push({ path: filePath, packageDir, content });\n });\n return files;\n}\n\nasync function attachSourceFiles(\n sourceFiles: SourceFile[],\n packages: PackageContext[],\n projectPath: string,\n): Promise<void> {\n for (const sourceFile of sourceFiles) {\n const owner = packages.find(\n (pkg) => pkg.directory === sourceFile.packageDir,\n );\n if (!owner) continue;\n owner.sourceFiles.push(sourceFile);\n for (const importedPackage of extractImports(sourceFile.content)) {\n if (!importedPackage.startsWith(HAPPYVERTICAL_PACKAGE_PREFIX)) continue;\n const evidence = {\n filePath: relative(projectPath, sourceFile.path),\n line: lineNumber(sourceFile.content, importedPackage),\n detail: `Imports ${importedPackage}`,\n };\n const existing = owner.imports.get(importedPackage) ?? [];\n existing.push(evidence);\n owner.imports.set(importedPackage, existing);\n }\n }\n}\n\nfunction findMissingHappyVerticalDependencies(\n packages: PackageContext[],\n): Finding[] {\n return packages.flatMap((pkg) => {\n const ownName =\n typeof pkg.json.name === 'string' ? pkg.json.name : undefined;\n const missing = Array.from(pkg.imports.keys()).filter(\n (importedPackage) =>\n importedPackage !== ownName && !pkg.dependencies.has(importedPackage),\n );\n if (missing.length === 0) return [];\n\n const hasSmrtMissing = missing.some((name) =>\n name.startsWith(SMRT_PACKAGE_PREFIX),\n );\n return [\n {\n severity: hasSmrtMissing ? 'high' : 'medium',\n area: 'dependencies',\n code: 'missing-happyvertical-dependencies',\n title: `${packageLabel(pkg)} imports HappyVertical packages that package.json does not declare`,\n evidence: missing.flatMap((name) => pkg.imports.get(name) ?? []),\n recommendation:\n 'Declare every imported @happyvertical package in the owning package manifest so downstream installs and generated knowledge stay reproducible.',\n suggestedIssueTitle: `Declare missing HappyVertical dependencies in ${packageLabel(pkg)}`,\n },\n ];\n });\n}\n\nfunction findCustomManifestGeneration(\n sourceFiles: SourceFile[],\n projectPath: string,\n): Finding[] {\n return sourceFiles\n .filter(\n (file) =>\n /manifest\\.json/.test(file.content) &&\n /objects\\s*:/.test(file.content) &&\n /\\b(writeFile|writeFileSync)\\b/.test(file.content) &&\n !/@happyvertical\\/smrt-scanner/.test(file.content),\n )\n .map((file) => ({\n severity: 'high',\n area: 'manifest',\n code: 'custom-object-manifest-generation',\n title: 'Custom SMRT object manifest generation detected',\n evidence: [\n {\n filePath: relative(projectPath, file.path),\n line: lineNumber(file.content, 'manifest.json'),\n detail:\n 'Writes a manifest.json object inventory outside the SMRT scanner/runtime path.',\n },\n ],\n recommendation:\n 'Use the SMRT scanner/runtime manifest path so defaults, relationships, schemas, tenant fields, and cross-package references match framework behavior.',\n suggestedIssueTitle:\n 'Replace custom object manifest generation with SMRT scanner/runtime manifest generation',\n }));\n}\n\nfunction findDirectStorageBypasses(\n sourceFiles: SourceFile[],\n packages: PackageContext[],\n projectPath: string,\n): Finding[] {\n return sourceFiles.flatMap((file) => {\n const owner = findOwningPackage(file.path, packages);\n const usesFs =\n /from\\s+['\"](?:node:fs|node:fs\\/promises|fs|fs\\/promises)['\"]|require\\(['\"](?:node:fs|node:fs\\/promises|fs|fs\\/promises)['\"]\\)/.test(\n file.content,\n );\n const writesDurableData =\n /\\b(writeFile|appendFile|mkdir|rm|rename)\\b/.test(file.content) &&\n /(\\.json|data|storage|persist|cache|db)/i.test(file.content);\n const usesDirectSql =\n /from\\s+['\"](?:better-sqlite3|sqlite3|pg|mysql2?|knex|drizzle-orm)['\"]/.test(\n file.content,\n );\n if ((!usesFs || !writesDurableData) && !usesDirectSql) return [];\n\n const hasApprovedStorage =\n owner.dependencies.has('@happyvertical/sql') ||\n owner.dependencies.has('@happyvertical/files') ||\n owner.dependencies.has('@happyvertical/smrt-assets') ||\n owner.dependencies.has('@happyvertical/smrt-content');\n\n if (hasApprovedStorage) return [];\n\n return [\n {\n severity: 'medium',\n area: 'storage',\n code: 'direct-storage-bypass',\n title: `${packageLabel(owner)} appears to bypass HappyVertical storage packages`,\n evidence: [\n {\n filePath: relative(projectPath, file.path),\n line: lineNumber(\n file.content,\n usesDirectSql ? 'sqlite' : 'writeFile',\n ),\n detail: usesDirectSql\n ? 'Imports a direct SQL/storage library without @happyvertical/sql.'\n : 'Uses node:fs-style durable writes without @happyvertical/files/assets/content.',\n },\n ],\n recommendation:\n 'Route durable data through @happyvertical/sql, @happyvertical/files, SMRT assets, or SMRT content unless this is explicitly build-only tooling.',\n suggestedIssueTitle: `Review direct storage usage in ${packageLabel(owner)}`,\n },\n ];\n });\n}\n\nfunction findCustomHttpShells(\n sourceFiles: SourceFile[],\n packages: PackageContext[],\n projectPath: string,\n): Finding[] {\n const evidenceByPackage = new Map<PackageContext, Evidence[]>();\n\n for (const pkg of packages) {\n if (pkg.dependencies.has('@sveltejs/kit')) continue;\n\n const routerDependencies = ['express', 'fastify', 'hono', 'koa'].filter(\n (dep) => pkg.dependencies.has(dep),\n );\n if (routerDependencies.length === 0) continue;\n\n appendEvidence(evidenceByPackage, pkg, {\n filePath: relative(projectPath, pkg.packageJsonPath),\n detail: `Declares custom router package(s): ${routerDependencies.join(', ')}.`,\n });\n }\n\n for (const file of sourceFiles) {\n const owner = findOwningPackage(file.path, packages);\n if (owner.dependencies.has('@sveltejs/kit')) continue;\n\n const usesNodeHttp =\n /from\\s+['\"](?:node:http|http|node:https|https)['\"]|createServer\\s*\\(/.test(\n file.content,\n );\n if (!usesNodeHttp) continue;\n\n appendEvidence(evidenceByPackage, owner, {\n filePath: relative(projectPath, file.path),\n line: lineNumber(file.content, 'createServer'),\n detail:\n 'Custom HTTP routing found without the SvelteKit/SMRT app-shell dependency pattern.',\n });\n }\n\n return Array.from(evidenceByPackage.entries()).map(([owner, evidence]) => ({\n severity: 'medium',\n area: 'api-shell',\n code: 'custom-http-shell',\n title: `${packageLabel(owner)} uses a custom HTTP shell`,\n evidence,\n recommendation:\n 'Compare the app shell against the Anytown/Ergot SvelteKit + SMRT shell pattern before adding custom HTTP infrastructure.',\n suggestedIssueTitle: `Align ${packageLabel(owner)} app shell with SMRT/SvelteKit conventions`,\n }));\n}\n\nfunction appendEvidence(\n evidenceByPackage: Map<PackageContext, Evidence[]>,\n pkg: PackageContext,\n evidence: Evidence,\n): void {\n const existing = evidenceByPackage.get(pkg);\n if (existing) {\n existing.push(evidence);\n return;\n }\n\n evidenceByPackage.set(pkg, [evidence]);\n}\n\nfunction findLocalAuthTenancy(\n sourceFiles: SourceFile[],\n packages: PackageContext[],\n projectPath: string,\n): Finding[] {\n return sourceFiles.flatMap((file) => {\n const owner = findOwningPackage(file.path, packages);\n const pathSignal = /(auth|tenant|audit|session|rbac|user)/i.test(file.path);\n const codeSignal =\n /\\b(tenantId|tenant|role|permission|session|auditLog|apiKey)\\b/.test(\n file.content,\n );\n if (!pathSignal || !codeSignal) return [];\n\n const hasApprovedPackages =\n owner.dependencies.has('@happyvertical/smrt-users') ||\n owner.dependencies.has('@happyvertical/smrt-tenancy') ||\n owner.dependencies.has('@happyvertical/smrt-profiles');\n if (hasApprovedPackages) return [];\n\n return [\n {\n severity: 'medium',\n area: 'auth-tenancy',\n code: 'local-auth-tenancy',\n title: `${packageLabel(owner)} contains local auth/tenancy/audit logic`,\n evidence: [\n {\n filePath: relative(projectPath, file.path),\n line: lineNumber(file.content, 'tenant'),\n detail:\n 'Auth, tenancy, session, role, or audit terminology appears without smrt-users/smrt-tenancy/smrt-profiles dependencies.',\n },\n ],\n recommendation:\n 'Add explicit adapters to smrt-users, smrt-tenancy, and profile/audit models or document why this local implementation is intentionally isolated.',\n suggestedIssueTitle: `Review auth and tenancy adapters in ${packageLabel(owner)}`,\n },\n ];\n });\n}\n\nfunction findUiShellDrift(\n packages: PackageContext[],\n projectPath: string,\n): Finding[] {\n return packages.flatMap((pkg) => {\n const hasUiSource = pkg.sourceFiles.some((file) =>\n file.path.endsWith('.svelte'),\n );\n const likelyUiPackage =\n hasUiSource ||\n /(?:web|ui|app|site|frontend)/i.test(packageLabel(pkg)) ||\n pkg.dependencies.has('svelte') ||\n pkg.dependencies.has('vite');\n if (!likelyUiPackage) return [];\n if (pkg.dependencies.has('@happyvertical/smrt-svelte')) return [];\n\n return [\n {\n severity: 'low',\n area: 'ui-shell',\n code: 'missing-smrt-svelte-shell',\n title: `${packageLabel(pkg)} looks like UI work without @happyvertical/smrt-svelte`,\n evidence: [\n {\n filePath: relative(projectPath, pkg.packageJsonPath),\n detail:\n 'UI-facing package does not declare @happyvertical/smrt-svelte.',\n },\n ],\n recommendation:\n 'Use @happyvertical/smrt-svelte and the SvelteKit shell pattern for downstream app UI unless this package is intentionally framework-agnostic.',\n suggestedIssueTitle: `Check SMRT Svelte shell alignment for ${packageLabel(pkg)}`,\n },\n ];\n });\n}\n\nfunction findMissingManifestArtifacts(\n sourceFiles: SourceFile[],\n packages: PackageContext[],\n projectPath: string,\n): Finding[] {\n return packages.flatMap((pkg) => {\n const hasSmrtSource = pkg.sourceFiles.some((file) =>\n /@smrt\\s*\\(/.test(file.content),\n );\n if (!hasSmrtSource) return [];\n const hasManifest =\n sourceFiles.some(\n (file) =>\n file.packageDir === pkg.directory &&\n /@happyvertical\\/smrt-scanner/.test(file.content),\n ) ||\n pathExistsSyncHint(join(pkg.directory, '.smrt', 'manifest.json')) ||\n pathExistsSyncHint(join(pkg.directory, 'dist', 'manifest.json'));\n if (hasManifest) return [];\n\n return [\n {\n severity: 'low',\n area: 'manifest',\n code: 'missing-generated-manifest-artifact',\n title: `${packageLabel(pkg)} has @smrt objects but no generated manifest artifact was found`,\n evidence: [\n {\n filePath: relative(projectPath, pkg.packageJsonPath),\n detail:\n 'No .smrt/manifest.json or dist/manifest.json was visible during review.',\n },\n ],\n recommendation:\n 'Run the package build/test manifest generation path and verify it uses the SMRT scanner/runtime manifest pipeline.',\n suggestedIssueTitle: `Verify SMRT manifest generation for ${packageLabel(pkg)}`,\n },\n ];\n });\n}\n\nasync function visit(\n dir: string,\n onFile: (filePath: string, entryName: string) => Promise<void> | void,\n): Promise<void> {\n let entries: Dirent[];\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch {\n return;\n }\n\n for (const entry of entries) {\n const fullPath = join(dir, entry.name);\n if (entry.isDirectory()) {\n if (SKIP_DIRS.has(entry.name)) continue;\n await visit(fullPath, onFile);\n continue;\n }\n if (entry.isFile()) await onFile(fullPath, entry.name);\n }\n}\n\nfunction collectDependencies(\n packageJson: Record<string, unknown>,\n): Set<string> {\n const dependencies = new Set<string>();\n for (const sectionName of DEPENDENCY_SECTIONS) {\n const section = packageJson[sectionName];\n if (!isRecord(section)) continue;\n for (const dependencyName of Object.keys(section)) {\n dependencies.add(dependencyName);\n }\n }\n return dependencies;\n}\n\nfunction extractImports(content: string): string[] {\n const imports = new Set<string>();\n const patterns = [\n /(?:import|export)\\s+(?:type\\s+)?(?:[^'\"]+\\s+from\\s+)?['\"]([^'\"]+)['\"]/g,\n /\\bimport\\s*\\(\\s*['\"]([^'\"]+)['\"]\\s*\\)/g,\n /\\brequire\\s*\\(\\s*['\"]([^'\"]+)['\"]\\s*\\)/g,\n ];\n for (const pattern of patterns) {\n for (const match of content.matchAll(pattern)) {\n const imported = normalizePackageImport(match[1]);\n if (imported) imports.add(imported);\n }\n }\n return Array.from(imports);\n}\n\nfunction normalizePackageImport(value: string | undefined): string | undefined {\n if (!value || value.startsWith('.') || value.startsWith('/'))\n return undefined;\n if (value.startsWith('@')) {\n const [scope, name] = value.split('/');\n return scope && name ? `${scope}/${name}` : value;\n }\n return value.split('/')[0];\n}\n\nfunction findOwningPackage(\n filePath: string,\n packages: PackageContext[],\n): PackageContext {\n const normalized = resolve(filePath);\n const matches = packages\n .filter(\n (pkg) =>\n normalized === pkg.directory ||\n normalized.startsWith(`${pkg.directory}${sep}`),\n )\n .sort((left, right) => right.directory.length - left.directory.length);\n return matches[0] ?? packages[0];\n}\n\nfunction packageInventory(pkg: PackageContext): PackageInventory {\n const declaredHappyVerticalDependencies = Array.from(pkg.dependencies)\n .filter((dependency) => dependency.startsWith(HAPPYVERTICAL_PACKAGE_PREFIX))\n .sort();\n const importedHappyVerticalPackages = Array.from(pkg.imports.keys()).sort();\n const ownName = typeof pkg.json.name === 'string' ? pkg.json.name : undefined;\n return {\n name: packageLabel(pkg),\n path: pkg.relativePath,\n private:\n typeof pkg.json.private === 'boolean' ? pkg.json.private : undefined,\n scripts: Object.keys(pkg.scripts).sort(),\n declaredHappyVerticalDependencies,\n importedHappyVerticalPackages,\n missingHappyVerticalDependencies: importedHappyVerticalPackages.filter(\n (name) => name !== ownName && !pkg.dependencies.has(name),\n ),\n hasSvelteKit: pkg.dependencies.has('@sveltejs/kit'),\n hasSmrtSvelte: pkg.dependencies.has('@happyvertical/smrt-svelte'),\n };\n}\n\nfunction summarizeFindings(findings: Finding[]): Record<Severity, number> {\n return findings.reduce(\n (summary, finding) => {\n summary[finding.severity]++;\n return summary;\n },\n { high: 0, medium: 0, low: 0 },\n );\n}\n\nfunction limitFindings(\n findings: Finding[],\n maxFindings: number | undefined,\n): Finding[] {\n const sorted = findings.sort(\n (left, right) =>\n severityRank(left.severity) - severityRank(right.severity) ||\n left.area.localeCompare(right.area) ||\n left.title.localeCompare(right.title),\n );\n return maxFindings && maxFindings > 0 ? sorted.slice(0, maxFindings) : sorted;\n}\n\nfunction severityRank(severity: Severity): number {\n return severity === 'high' ? 0 : severity === 'medium' ? 1 : 2;\n}\n\nfunction packageLabel(pkg: PackageContext): string {\n return typeof pkg.json.name === 'string' ? pkg.json.name : pkg.relativePath;\n}\n\nfunction lineNumber(content: string, needle: string): number | undefined {\n const index = content.indexOf(needle);\n if (index < 0) return undefined;\n return content.slice(0, index).split('\\n').length;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === 'object' && !Array.isArray(value);\n}\n\nasync function pathExists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction pathExistsSyncHint(path: string): boolean {\n return existsSync(path);\n}\n\ninterface DuplicateDetectionStatus {\n enabled: boolean;\n indexPath: string | null;\n intentCount: number;\n notes: string[];\n}\n\nasync function runDuplicateDetection(\n args: ReviewSmrtProjectArgs,\n projectPath: string,\n packageContexts: PackageContext[],\n): Promise<{ findings: Finding[]; status: DuplicateDetectionStatus }> {\n const status: DuplicateDetectionStatus = {\n enabled: args.detectDuplicates !== false,\n indexPath: null,\n intentCount: 0,\n notes: [],\n };\n if (!status.enabled) return { findings: [], status };\n\n const explicit = args.intentIndexPath\n ? isAbsolute(args.intentIndexPath)\n ? args.intentIndexPath\n : resolve(projectPath, args.intentIndexPath)\n : undefined;\n const candidates = explicit\n ? [explicit]\n : defaultIntentIndexCandidates(args.packageRoot);\n const indexPath = candidates.find((candidate) => existsSync(candidate));\n if (!indexPath) {\n status.notes.push(\n `No intent index found (tried ${candidates.join(', ') || 'none'}); duplicate detection skipped. Reinstall @happyvertical/smrt-dev-mcp or pass intentIndexPath.`,\n );\n return { findings: [], status };\n }\n\n const rows: IntentRow[] = parseIntentIndex(\n await readFile(indexPath, 'utf-8'),\n );\n status.indexPath = indexPath;\n status.intentCount = rows.length;\n if (rows.length === 0) {\n status.notes.push(`Intent index ${indexPath} has no parsable rows.`);\n return { findings: [], status };\n }\n\n // Only SMRT consumers get advice: a project with no @happyvertical/smrt-*\n // dependency or import has no installed home package to prefer.\n const isSmrtConsumer = packageContexts.some(\n (pkg) =>\n Array.from(pkg.dependencies).some((name) =>\n name.startsWith(SMRT_PACKAGE_PREFIX),\n ) ||\n Array.from(pkg.imports.keys()).some((name) =>\n name.startsWith(SMRT_PACKAGE_PREFIX),\n ),\n );\n if (!isSmrtConsumer) {\n status.notes.push(\n 'No @happyvertical/smrt-* dependency or import found; duplicate detection skipped.',\n );\n return { findings: [], status };\n }\n\n const homeNames = new Set(\n rows.flatMap((row) => row.homePackages.map((home) => home.packageName)),\n );\n const packages: DetectorPackage[] = packageContexts.map((pkg) => ({\n name: typeof pkg.json.name === 'string' ? pkg.json.name : undefined,\n relativePath: pkg.relativePath,\n installed: new Set(\n Array.from(homeNames).filter(\n (name) =>\n pkg.dependencies.has(name) ||\n existsSync(join(pkg.directory, 'node_modules', name)) ||\n existsSync(join(projectPath, 'node_modules', name)),\n ),\n ),\n files: pkg.sourceFiles.map((file) => ({\n relativePath: relative(projectPath, file.path),\n content: file.content,\n imports: extractImports(file.content),\n })),\n }));\n\n const detected = detectHandRolled(rows, packages, {\n onNote: (note) => {\n status.notes.push(note);\n process.stderr.write(`[smrt-dev-mcp] ${note}\\n`);\n },\n });\n return { findings: detected.map(duplicateFinding), status };\n}\n\nfunction duplicateFinding(found: HandRolledFinding): Finding {\n const first = found.evidence[0];\n const installedUnused = found.installedHomePackages.length > 0;\n const homeList = found.homePackages.join(', ');\n const title = `${found.packageName} appears to hand-roll \"${found.intent}\"`;\n return {\n severity: installedUnused ? 'medium' : 'low',\n area: 'duplicate-detection',\n code: found.code,\n title,\n message: `${title} (signals: ${found.matchedSignals.join(', ')}); ${\n installedUnused\n ? `${found.installedHomePackages.join(', ')} is installed but never imported`\n : `none of ${homeList} is imported`\n }. Intent page ${found.intentPage}; component pages ${found.componentPages.join(', ')}.`,\n file: `${first.filePath}:${first.line}`,\n packageName: found.packageName,\n intentPage: found.intentPage,\n componentPages: found.componentPages,\n evidence: found.evidence.map((item) => ({\n filePath: item.filePath,\n line: item.line,\n detail: item.detail,\n })),\n recommendation: `Read ${found.intentPage} before keeping this implementation; the framework entry point is ${found.entryPoint} (${found.componentPages.join(', ')}). Advisory only: keep the hand-rolled code if it covers a case the package does not.`,\n suggestedIssueTitle: `Evaluate ${homeList} instead of hand-rolled ${found.intent.toLowerCase()} in ${found.packageName}`,\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ ---
2
+ type: "Component"
3
+ title: "@happyvertical/smrt-dev-mcp"
4
+ description: "Development MCP server for SMRT framework knowledge, review context, architecture context, and code generation"
5
+ status: "stable"
6
+ generated:
7
+ by: "smrt/scripts/generate-knowledge-okf.ts"
8
+ at: "2026-11-05T15:48:19Z"
9
+ audience: "internal"
10
+ evidence_level: "manifest-described"
11
+ source_revision: "sha256:a01eccec517d6947a1a35bb4e970a7e9696bbfde005f068ea4ea31a431326706"
12
+ sources:
13
+ - id: "manifest"
14
+ resource: "https://github.com/happyvertical/smrt/blob/main/packages/smrt-dev-mcp/package.json"
15
+ title: "@happyvertical/smrt-dev-mcp package manifest"
16
+ - id: "agents"
17
+ resource: "https://github.com/happyvertical/smrt/blob/main/packages/smrt-dev-mcp/AGENTS.md"
18
+ title: "@happyvertical/smrt-dev-mcp packages/smrt-dev-mcp/AGENTS.md"
19
+ - id: "agents-2"
20
+ resource: "https://github.com/happyvertical/smrt/blob/main/packages/smrt-dev-mcp/agents/intent-duplicates.md"
21
+ title: "@happyvertical/smrt-dev-mcp packages/smrt-dev-mcp/agents/intent-duplicates.md"
22
+ - id: "agents-3"
23
+ resource: "https://github.com/happyvertical/smrt/blob/main/packages/smrt-dev-mcp/agents/protocol-conformance.md"
24
+ title: "@happyvertical/smrt-dev-mcp packages/smrt-dev-mcp/agents/protocol-conformance.md"
25
+ ---
26
+
27
+ # @happyvertical/smrt-dev-mcp
28
+
29
+ ## Package
30
+
31
+ - Directory: `packages/smrt-dev-mcp`
32
+ - Private: no
33
+ - Object source: `none`
34
+ - Evidence level: `manifest-described`
35
+
36
+ ## Documentation
37
+
38
+ - `packages/smrt-dev-mcp/AGENTS.md`
39
+ - `packages/smrt-dev-mcp/agents/intent-duplicates.md`
40
+ - `packages/smrt-dev-mcp/agents/protocol-conformance.md`
41
+
42
+ ## Framework dependencies
43
+
44
+ - [smrt-config](/components/smrt-config.md)
45
+ - [smrt-core](/components/smrt-core.md)
46
+ - [smrt-scanner](/components/smrt-scanner.md)
47
+ - [smrt-types](/components/smrt-types.md)
48
+
49
+ ## SDK dependencies
50
+
51
+ - `@happyvertical/sql`
52
+
53
+ ## Exports
54
+
55
+ - `.`
56
+ - `./dev-plane`
57
+ - `./knowledge`
58
+ - `./runtime`
59
+ - `./schemas/agent-plugins-1.0.0/mcp.schema.json`
60
+ - `./schemas/agent-plugins-1.0.0/plugin.schema.json`
@@ -237,7 +237,7 @@ var TOOLS = [
237
237
  },
238
238
  {
239
239
  name: "review-smrt-project",
240
- description: "Advisory ecosystem alignment review for downstream SMRT projects",
240
+ description: "Advisory ecosystem alignment review for downstream SMRT projects, including intent-driven hand-rolled-equivalent detection",
241
241
  inputSchema: {
242
242
  type: "object",
243
243
  properties: {
@@ -257,6 +257,15 @@ var TOOLS = [
257
257
  maxFindings: {
258
258
  type: "number",
259
259
  description: "Optional maximum number of findings to return"
260
+ },
261
+ intentIndexPath: {
262
+ type: "string",
263
+ description: "Caller-trusted intent index driving duplicate detection (regex tokens become RegExp). Default: the full index packaged in this release, never read from the reviewed directory"
264
+ },
265
+ detectDuplicates: {
266
+ type: "boolean",
267
+ description: "Run the intent-driven hand-rolled-equivalent pass (default: true)",
268
+ default: true
260
269
  }
261
270
  }
262
271
  }
@@ -664,4 +673,4 @@ var TOOLS = [
664
673
  //#endregion
665
674
  export { TOOLS as n, REVIEW_SKILL_NAME as t };
666
675
 
667
- //# sourceMappingURL=tool-catalog-RHq7nyCm.js.map
676
+ //# sourceMappingURL=tool-catalog-BhnSCF8g.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-catalog-BhnSCF8g.js","names":[],"sources":["../src/tool-catalog.ts"],"sourcesContent":["import type { Tool } from '@modelcontextprotocol/server';\n\nexport const REVIEW_SKILL_NAME = 'smrt-code-review';\n\nconst JSON_SCHEMA_2020_12 = 'https://json-schema.org/draft/2020-12/schema';\n\nfunction compareToolNames(left: string, right: string): number {\n return left < right ? -1 : left > right ? 1 : 0;\n}\n\n/**\n * Stable success/error envelope for development tools. `data` preserves each\n * tool's existing payload exactly; coverage/diagnostics are promoted only when\n * the underlying result actually reports them.\n */\nconst DEV_MCP_OUTPUT_SCHEMA: NonNullable<Tool['outputSchema']> = {\n $schema: JSON_SCHEMA_2020_12,\n type: 'object',\n additionalProperties: false,\n required: ['ok', 'coverage', 'diagnostics', 'data'],\n properties: {\n ok: { type: 'boolean' },\n coverage: { type: ['object', 'null'], additionalProperties: true },\n diagnostics: {\n type: 'array',\n items: { type: 'object', additionalProperties: true },\n },\n data: {},\n },\n};\n\nconst KNOWLEDGE_DETAIL_DESCRIPTION =\n 'summary: authored package docs are listed by path to stay inside tool-result budgets. full: embed package docs and matching modules with structural object facts. complete: embed all modules and return full package records.';\n\nconst DATABASE_URL_PROPERTY = {\n type: 'string',\n description:\n 'Optional dev database URL override (read-only diagnostics); prefer SMRT_DEV_DB_URL or cli.database config',\n};\n\nconst DATABASE_TYPE_PROPERTY = {\n type: 'string',\n enum: ['sqlite', 'postgres', 'duckdb'],\n description:\n 'Optional engine hint for dbUrl or the environment connection (sqlite, postgres, duckdb); inferred from the URL scheme when omitted',\n};\n\nconst PROJECT_PATH_PROPERTY = {\n type: 'string',\n description:\n 'Project root to boot manifests from (default: the server working directory; pinned by the HTTP host; a different loaded project requires restart)',\n} as const;\n\nconst LIMIT_PROPERTY = {\n type: 'number',\n description: 'Row budget for result lists (default 50, capped at 500)',\n};\n\n// Tool definitions\nconst TOOL_DEFINITIONS: Array<\n Pick<Tool, 'name' | 'description' | 'inputSchema'>\n> = [\n // Code Generation Tools\n {\n name: 'generate-smrt-class',\n description: 'Generate a complete SMRT class with @smrt() decorator',\n inputSchema: {\n type: 'object',\n properties: {\n className: {\n type: 'string',\n description: 'Name of the class (PascalCase)',\n },\n properties: {\n type: 'array',\n description: 'Array of property definitions',\n items: {\n type: 'object',\n properties: {\n name: { type: 'string' },\n type: {\n type: 'string',\n enum: [\n 'text',\n 'integer',\n 'decimal',\n 'boolean',\n 'datetime',\n 'json',\n ],\n },\n required: { type: 'boolean' },\n nullable: { type: 'boolean' },\n description: { type: 'string' },\n defaultValue: {\n oneOf: [\n { type: 'string' },\n { type: 'number' },\n { type: 'boolean' },\n { type: 'object' },\n { type: 'null' },\n ],\n },\n },\n required: ['name', 'type'],\n },\n },\n baseClass: {\n type: 'string',\n enum: ['SmrtObject', 'SmrtCollection'],\n default: 'SmrtObject',\n },\n template: {\n type: 'string',\n enum: [\n 'basic',\n 'global-catalog',\n 'optional-catalog',\n 'tenant-project-object',\n 'tenant-event-log-object',\n 'cross-package-reference',\n ],\n default: 'basic',\n },\n tableName: { type: 'string' },\n conflictColumns: {\n type: 'array',\n items: { type: 'string' },\n },\n tenantScoped: {\n oneOf: [\n { type: 'boolean' },\n {\n type: 'object',\n properties: {\n mode: { type: 'string', enum: ['required', 'optional'] },\n field: { type: 'string' },\n autoFilter: { type: 'boolean' },\n autoPopulate: { type: 'boolean' },\n allowSuperAdminBypass: { type: 'boolean' },\n },\n },\n ],\n },\n includeTenantIdField: { type: 'boolean' },\n relationships: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n name: { type: 'string' },\n type: {\n type: 'string',\n enum: [\n 'foreignKey',\n 'crossPackageRef',\n 'oneToMany',\n 'manyToMany',\n ],\n },\n related: { type: 'string' },\n required: { type: 'boolean' },\n nullable: { type: 'boolean' },\n description: { type: 'string' },\n validate: { type: 'boolean' },\n foreignKey: { type: 'string' },\n through: { type: 'string' },\n sourceKey: { type: 'string' },\n targetKey: { type: 'string' },\n },\n required: ['name', 'type', 'related'],\n },\n },\n includeCompanionSnippets: { type: 'boolean', default: false },\n includeApiConfig: { type: 'boolean', default: true },\n includeMcpConfig: { type: 'boolean', default: true },\n includeCliConfig: { type: 'boolean', default: true },\n },\n required: ['className', 'properties'],\n },\n },\n // Project Introspection Tools\n {\n name: 'introspect-project',\n description:\n 'Scan a directory for SMRT objects. Returns a compact summary by default; pass detail: \"full\" for field, schema, and method details.',\n inputSchema: {\n type: 'object',\n properties: {\n directory: {\n type: 'string',\n description: 'Project directory (default: cwd)',\n },\n manifestPath: {\n type: 'string',\n description:\n 'Optional manifest path. Defaults to .smrt/manifest.json, dist/manifest.json, then source scanning.',\n },\n detail: {\n type: 'string',\n enum: ['summary', 'full'],\n default: 'summary',\n description:\n 'summary: one compact record per object. full: complete field/schema/method detail (large).',\n },\n maxChars: {\n type: 'number',\n description:\n 'Character budget for the `objects` payload. Objects past the budget are omitted and reported under `truncated`. Project metadata and diagnostics are always returned in full, so the serialized response is somewhat larger than this budget.',\n },\n cursor: {\n type: 'string',\n description:\n \"Resume after this className (objects are sorted alphabetically). Pass a previous response's `nextCursor` to read the next page instead of raising maxChars.\",\n },\n limit: {\n type: 'number',\n description:\n 'Maximum objects per page, applied before the character budget',\n },\n includeFields: {\n type: 'boolean',\n description: 'Include field details (detail: \"full\" only)',\n },\n includeRelationships: {\n type: 'boolean',\n description: 'Analyze relationships (detail: \"full\" only)',\n },\n includeMethods: {\n type: 'boolean',\n description: 'Include public method details (detail: \"full\" only)',\n },\n },\n },\n },\n {\n name: 'review-smrt-project',\n description:\n 'Advisory ecosystem alignment review for downstream SMRT projects, including intent-driven hand-rolled-equivalent detection',\n inputSchema: {\n type: 'object',\n properties: {\n directory: {\n type: 'string',\n description: 'Project directory (default: cwd)',\n },\n rootDir: {\n type: 'string',\n description: 'Compatibility alias for directory',\n },\n includeSourceEvidence: {\n type: 'boolean',\n description: 'Include file and line evidence in findings',\n default: true,\n },\n maxFindings: {\n type: 'number',\n description: 'Optional maximum number of findings to return',\n },\n intentIndexPath: {\n type: 'string',\n description:\n 'Caller-trusted intent index driving duplicate detection (regex tokens become RegExp). Default: the full index packaged in this release, never read from the reviewed directory',\n },\n detectDuplicates: {\n type: 'boolean',\n description:\n 'Run the intent-driven hand-rolled-equivalent pass (default: true)',\n default: true,\n },\n },\n },\n },\n {\n name: 'reflect-knowledge',\n description:\n 'Report deterministic SMRT + HappyVertical SDK knowledge coverage and freshness',\n inputSchema: {\n type: 'object',\n properties: {\n rootDir: {\n type: 'string',\n description: 'Project root directory (default: cwd)',\n },\n },\n },\n },\n {\n name: 'reflect-domain-knowledge',\n description:\n 'Report domain-scoped SMRT knowledge artifacts, SDK packages, and freshness',\n inputSchema: {\n type: 'object',\n properties: {\n rootDir: { type: 'string' },\n scope: {\n type: 'string',\n enum: ['project', 'local', 'package', 'sdk', 'installed'],\n default: 'project',\n },\n package: { type: 'string' },\n },\n },\n },\n {\n name: 'check-knowledge-freshness',\n description: 'Run deterministic freshness checks for SMRT agent knowledge',\n inputSchema: {\n type: 'object',\n properties: {\n rootDir: { type: 'string' },\n changed: {\n type: 'boolean',\n description: 'Limit stale-pattern checks to changed files',\n },\n strict: {\n type: 'boolean',\n description: 'Treat stale-pattern findings as errors',\n },\n },\n },\n },\n {\n name: 'build-context',\n description:\n 'Build model-ready SMRT context. task: \"review\" routes changedFiles/focus to package experts and returns file-anchored findings, package hints, and a prompt bundle; task: \"architecture\" ranks packages by the idea text and returns the bundle plus recommendations. Replaces build-review-context, build-domain-review-context, build-architecture-context, and build-domain-architecture-context.',\n inputSchema: {\n type: 'object',\n properties: {\n task: {\n type: 'string',\n enum: ['review', 'architecture'],\n description:\n 'review: changed files and focus. architecture: an idea or documentation.',\n },\n rootDir: { type: 'string' },\n changedFiles: {\n type: 'array',\n items: { type: 'string' },\n description: 'Files to route to package experts (task: review)',\n },\n focus: { type: 'string', description: 'Concern to prioritise' },\n documentation: {\n type: 'string',\n description: 'Existing docs, notes, or requirements',\n },\n idea: {\n type: 'string',\n description: 'Product or implementation idea (task: architecture)',\n },\n scope: {\n type: 'string',\n enum: ['project', 'local', 'package', 'sdk', 'installed'],\n default: 'project',\n },\n package: {\n type: 'string',\n description: 'Package name or short name to focus',\n },\n mode: {\n type: 'string',\n enum: ['findings', 'prompt-bundle', 'both'],\n default: 'both',\n description: 'task: review only',\n },\n detail: {\n type: 'string',\n enum: ['summary', 'full', 'complete'],\n default: 'summary',\n description: KNOWLEDGE_DETAIL_DESCRIPTION,\n },\n },\n required: ['task'],\n },\n },\n {\n name: 'smrt-review',\n description:\n 'Deprecated compatibility name for build-context with task: \"review\"; removed in the next minor release. For a formal downstream review, first call get-agent-skill with { \"name\": \"smrt-code-review\" }.',\n inputSchema: {\n type: 'object',\n properties: {\n rootDir: { type: 'string' },\n changedFiles: { type: 'array', items: { type: 'string' } },\n focus: { type: 'string' },\n documentation: { type: 'string' },\n mode: {\n type: 'string',\n enum: ['findings', 'prompt-bundle', 'both'],\n default: 'both',\n },\n detail: {\n type: 'string',\n enum: ['summary', 'full', 'complete'],\n default: 'summary',\n description: KNOWLEDGE_DETAIL_DESCRIPTION,\n },\n },\n },\n },\n {\n name: 'build-package-specialist-context',\n description:\n 'Build deterministic package specialist context for the SMRT workbench',\n inputSchema: {\n type: 'object',\n properties: {\n rootDir: { type: 'string' },\n package: {\n type: 'string',\n description:\n 'Package name or short package query, e.g. @happyvertical/smrt-content or content',\n },\n focus: { type: 'string' },\n },\n required: ['package'],\n },\n },\n {\n name: 'smrt-architecture',\n description:\n 'Deprecated compatibility name for build-context with task: \"architecture\"; removed in the next minor release.',\n inputSchema: {\n type: 'object',\n properties: {\n rootDir: { type: 'string' },\n idea: { type: 'string' },\n documentation: { type: 'string' },\n focus: { type: 'string' },\n detail: {\n type: 'string',\n enum: ['summary', 'full', 'complete'],\n default: 'summary',\n description: KNOWLEDGE_DETAIL_DESCRIPTION,\n },\n },\n },\n },\n {\n name: 'list-agent-skills',\n description:\n 'List bundled harness-agnostic agent skills shipped with smrt-dev-mcp',\n inputSchema: {\n type: 'object',\n properties: {},\n },\n },\n {\n name: 'get-agent-skill',\n description:\n 'Return a bundled harness-agnostic agent skill as Markdown plus optional references',\n inputSchema: {\n type: 'object',\n properties: {\n name: {\n type: 'string',\n enum: [REVIEW_SKILL_NAME],\n description: 'Bundled agent skill name',\n },\n includeReferences: {\n type: 'boolean',\n default: true,\n description: 'Include referenced files with the skill bundle',\n },\n },\n required: ['name'],\n },\n },\n {\n name: 'migration-status',\n description:\n 'Live migration status from the _smrt_schema_migrations system table (runtime provenance; read-only)',\n inputSchema: {\n type: 'object',\n properties: {\n projectPath: {\n type: 'string',\n description:\n 'Project root with the installed SMRT runtime (default: server working directory)',\n },\n dbUrl: DATABASE_URL_PROPERTY,\n dbType: DATABASE_TYPE_PROPERTY,\n limit: LIMIT_PROPERTY,\n },\n },\n },\n {\n name: 'job-health',\n description:\n 'Live job queue health from the _smrt_jobs/_smrt_workers system tables (runtime provenance; read-only)',\n inputSchema: {\n type: 'object',\n properties: {\n projectPath: {\n type: 'string',\n description:\n 'Project root with the installed SMRT runtime (default: server working directory)',\n },\n dbUrl: DATABASE_URL_PROPERTY,\n dbType: DATABASE_TYPE_PROPERTY,\n limit: LIMIT_PROPERTY,\n },\n },\n },\n {\n name: 'schedule-health',\n description:\n 'Live agent schedule health from the _smrt_agent_schedules system table (runtime provenance; read-only; sensitive agentConfig never read)',\n inputSchema: {\n type: 'object',\n properties: {\n projectPath: {\n type: 'string',\n description:\n 'Project root with the installed SMRT runtime (default: server working directory)',\n },\n dbUrl: DATABASE_URL_PROPERTY,\n dbType: DATABASE_TYPE_PROPERTY,\n limit: LIMIT_PROPERTY,\n },\n },\n },\n {\n name: 'dispatch-health',\n description:\n 'Live dispatch health from the _smrt_dispatch/_smrt_dispatch_subscriptions system tables (runtime provenance; read-only; payloads never read)',\n inputSchema: {\n type: 'object',\n properties: {\n projectPath: {\n type: 'string',\n description:\n 'Project root with the installed SMRT runtime (default: server working directory)',\n },\n dbUrl: DATABASE_URL_PROPERTY,\n dbType: DATABASE_TYPE_PROPERTY,\n limit: LIMIT_PROPERTY,\n },\n },\n },\n {\n name: 'recent-changes',\n description:\n 'Tail of the _smrt_changes change feed (runtime provenance; read-only; filter by table/tenant)',\n inputSchema: {\n type: 'object',\n properties: {\n projectPath: {\n type: 'string',\n description:\n 'Project root with the installed SMRT runtime (default: server working directory)',\n },\n dbUrl: DATABASE_URL_PROPERTY,\n dbType: DATABASE_TYPE_PROPERTY,\n since: {\n type: 'number',\n description: 'Cursor to read after (default 0)',\n },\n tables: {\n type: 'array',\n items: { type: 'string' },\n description: 'Restrict to these physical table names',\n },\n tenantId: {\n type: 'string',\n description: 'Tenant narrowing filter',\n },\n limit: LIMIT_PROPERTY,\n },\n },\n },\n {\n name: 'registry-drift',\n description:\n 'Registry drift report; _smrt_registry is retired and reported as such, never queried (read-only)',\n inputSchema: {\n type: 'object',\n properties: {\n projectPath: {\n type: 'string',\n description:\n 'Project root with the installed SMRT runtime (default: server working directory)',\n },\n dbUrl: DATABASE_URL_PROPERTY,\n dbType: DATABASE_TYPE_PROPERTY,\n },\n },\n },\n {\n name: 'runtime-registry',\n description:\n 'Sanitized snapshot of the booted ObjectRegistry from the project and installed manifests (booted provenance; read-only; no project code executed)',\n inputSchema: {\n type: 'object',\n properties: {\n projectPath: PROJECT_PATH_PROPERTY,\n objects: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Restrict field/method detail to these simple or qualified object names',\n },\n detail: {\n type: 'boolean',\n description:\n 'Include field and method detail for every object (default: only when objects is given)',\n },\n cursor: {\n type: 'string',\n description:\n \"Resume after this qualified object name; pass a previous response's `page.nextCursor`\",\n },\n limit: {\n type: 'number',\n description: 'Objects per page (default 50, capped at 500)',\n },\n },\n },\n },\n {\n name: 'runtime-object',\n description:\n 'One booted object: sanitized fields, methods, tenancy, inheritance, and the DDL the registry would generate (booted provenance; read-only)',\n inputSchema: {\n type: 'object',\n properties: {\n projectPath: PROJECT_PATH_PROPERTY,\n name: {\n type: 'string',\n description: 'Simple or qualified object name',\n },\n engine: {\n type: 'string',\n enum: ['sqlite', 'postgres', 'duckdb'],\n description: 'Engine for the DDL preview (default: registry default)',\n },\n },\n required: ['name'],\n },\n },\n {\n name: 'runtime-schema-diff',\n description:\n 'Booted registry schemas versus the live dev database using the db:diff comparer; introspection only, drops/relaxations never proposed (runtime provenance; read-only)',\n inputSchema: {\n type: 'object',\n properties: {\n projectPath: PROJECT_PATH_PROPERTY,\n dbUrl: DATABASE_URL_PROPERTY,\n dbType: DATABASE_TYPE_PROPERTY,\n },\n },\n },\n];\n\nexport const TOOLS: Tool[] = TOOL_DEFINITIONS.map((tool) => ({\n ...tool,\n inputSchema: {\n ...tool.inputSchema,\n $schema: JSON_SCHEMA_2020_12,\n },\n outputSchema: DEV_MCP_OUTPUT_SCHEMA,\n})).sort((left, right) => compareToolNames(left.name, right.name));\n"],"mappings":"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AAS;KACT,aACE;IACJ;IACA,UAAU;KACR,MAAM;KACN,aACE;IACJ;IACA,QAAQ;KACN,MAAM;KACN,aACE;IACJ;IACA,OAAO;KACL,MAAM;KACN,aACE;IACJ;IACA,eAAe;KACb,MAAM;KACN,aAAa;IACf;IACA,sBAAsB;KACpB,MAAM;KACN,aAAa;IACf;IACA,gBAAgB;KACd,MAAM;KACN,aAAa;IACf;GACF;EACF;CACF;CACA;EACE,MAAM;EACN,aACE;EACF,aAAa;GACX,MAAM;GACN,YAAY;IACV,WAAW;KACT,MAAM;KACN,aAAa;IACf;IACA,SAAS;KACP,MAAM;KACN,aAAa;IACf;IACA,uBAAuB;KACrB,MAAM;KACN,aAAa;KACb,SAAS;IACX;IACA,aAAa;KACX,MAAM;KACN,aAAa;IACf;IACA,iBAAiB;KACf,MAAM;KACN,aACE;IACJ;IACA,kBAAkB;KAChB,MAAM;KACN,aACE;KACF,SAAS;IACX;GACF;EACF;CACF;CACA;EACE,MAAM;EACN,aACE;EACF,aAAa;GACX,MAAM;GACN,YAAY,EACV,SAAS;IACP,MAAM;IACN,aAAa;GACf,EACF;EACF;CACF;CACA;EACE,MAAM;EACN,aACE;EACF,aAAa;GACX,MAAM;GACN,YAAY;IACV,SAAS,EAAE,MAAM,SAAS;IAC1B,OAAO;KACL,MAAM;KACN,MAAM;MAAC;MAAW;MAAS;MAAW;MAAO;KAAW;KACxD,SAAS;IACX;IACA,SAAS,EAAE,MAAM,SAAS;GAC5B;EACF;CACF;CACA;EACE,MAAM;EACN,aAAa;EACb,aAAa;GACX,MAAM;GACN,YAAY;IACV,SAAS,EAAE,MAAM,SAAS;IAC1B,SAAS;KACP,MAAM;KACN,aAAa;IACf;IACA,QAAQ;KACN,MAAM;KACN,aAAa;IACf;GACF;EACF;CACF;CACA;EACE,MAAM;EACN,aACE;EACF,aAAa;GACX,MAAM;GACN,YAAY;IACV,MAAM;KACJ,MAAM;KACN,MAAM,CAAC,UAAU,cAAc;KAC/B,aACE;IACJ;IACA,SAAS,EAAE,MAAM,SAAS;IAC1B,cAAc;KACZ,MAAM;KACN,OAAO,EAAE,MAAM,SAAS;KACxB,aAAa;IACf;IACA,OAAO;KAAE,MAAM;KAAU,aAAa;IAAwB;IAC9D,eAAe;KACb,MAAM;KACN,aAAa;IACf;IACA,MAAM;KACJ,MAAM;KACN,aAAa;IACf;IACA,OAAO;KACL,MAAM;KACN,MAAM;MAAC;MAAW;MAAS;MAAW;MAAO;KAAW;KACxD,SAAS;IACX;IACA,SAAS;KACP,MAAM;KACN,aAAa;IACf;IACA,MAAM;KACJ,MAAM;KACN,MAAM;MAAC;MAAY;MAAiB;KAAM;KAC1C,SAAS;KACT,aAAa;IACf;IACA,QAAQ;KACN,MAAM;KACN,MAAM;MAAC;MAAW;MAAQ;KAAU;KACpC,SAAS;KACT,aAAa;IACf;GACF;GACA,UAAU,CAAC,MAAM;EACnB;CACF;CACA;EACE,MAAM;EACN,aACE;EACF,aAAa;GACX,MAAM;GACN,YAAY;IACV,SAAS,EAAE,MAAM,SAAS;IAC1B,cAAc;KAAE,MAAM;KAAS,OAAO,EAAE,MAAM,SAAS;IAAE;IACzD,OAAO,EAAE,MAAM,SAAS;IACxB,eAAe,EAAE,MAAM,SAAS;IAChC,MAAM;KACJ,MAAM;KACN,MAAM;MAAC;MAAY;MAAiB;KAAM;KAC1C,SAAS;IACX;IACA,QAAQ;KACN,MAAM;KACN,MAAM;MAAC;MAAW;MAAQ;KAAU;KACpC,SAAS;KACT,aAAa;IACf;GACF;EACF;CACF;CACA;EACE,MAAM;EACN,aACE;EACF,aAAa;GACX,MAAM;GACN,YAAY;IACV,SAAS,EAAE,MAAM,SAAS;IAC1B,SAAS;KACP,MAAM;KACN,aACE;IACJ;IACA,OAAO,EAAE,MAAM,SAAS;GAC1B;GACA,UAAU,CAAC,SAAS;EACtB;CACF;CACA;EACE,MAAM;EACN,aACE;EACF,aAAa;GACX,MAAM;GACN,YAAY;IACV,SAAS,EAAE,MAAM,SAAS;IAC1B,MAAM,EAAE,MAAM,SAAS;IACvB,eAAe,EAAE,MAAM,SAAS;IAChC,OAAO,EAAE,MAAM,SAAS;IACxB,QAAQ;KACN,MAAM;KACN,MAAM;MAAC;MAAW;MAAQ;KAAU;KACpC,SAAS;KACT,aAAa;IACf;GACF;EACF;CACF;CACA;EACE,MAAM;EACN,aACE;EACF,aAAa;GACX,MAAM;GACN,YAAY,CAAC;EACf;CACF;CACA;EACE,MAAM;EACN,aACE;EACF,aAAa;GACX,MAAM;GACN,YAAY;IACV,MAAM;KACJ,MAAM;KACN,MAAM,CAAC,iBAAiB;KACxB,aAAa;IACf;IACA,mBAAmB;KACjB,MAAM;KACN,SAAS;KACT,aAAa;IACf;GACF;GACA,UAAU,CAAC,MAAM;EACnB;CACF;CACA;EACE,MAAM;EACN,aACE;EACF,aAAa;GACX,MAAM;GACN,YAAY;IACV,aAAa;KACX,MAAM;KACN,aACE;IACJ;IACA,OAAO;IACP,QAAQ;IACR,OAAO;GACT;EACF;CACF;CACA;EACE,MAAM;EACN,aACE;EACF,aAAa;GACX,MAAM;GACN,YAAY;IACV,aAAa;KACX,MAAM;KACN,aACE;IACJ;IACA,OAAO;IACP,QAAQ;IACR,OAAO;GACT;EACF;CACF;CACA;EACE,MAAM;EACN,aACE;EACF,aAAa;GACX,MAAM;GACN,YAAY;IACV,aAAa;KACX,MAAM;KACN,aACE;IACJ;IACA,OAAO;IACP,QAAQ;IACR,OAAO;GACT;EACF;CACF;CACA;EACE,MAAM;EACN,aACE;EACF,aAAa;GACX,MAAM;GACN,YAAY;IACV,aAAa;KACX,MAAM;KACN,aACE;IACJ;IACA,OAAO;IACP,QAAQ;IACR,OAAO;GACT;EACF;CACF;CACA;EACE,MAAM;EACN,aACE;EACF,aAAa;GACX,MAAM;GACN,YAAY;IACV,aAAa;KACX,MAAM;KACN,aACE;IACJ;IACA,OAAO;IACP,QAAQ;IACR,OAAO;KACL,MAAM;KACN,aAAa;IACf;IACA,QAAQ;KACN,MAAM;KACN,OAAO,EAAE,MAAM,SAAS;KACxB,aAAa;IACf;IACA,UAAU;KACR,MAAM;KACN,aAAa;IACf;IACA,OAAO;GACT;EACF;CACF;CACA;EACE,MAAM;EACN,aACE;EACF,aAAa;GACX,MAAM;GACN,YAAY;IACV,aAAa;KACX,MAAM;KACN,aACE;IACJ;IACA,OAAO;IACP,QAAQ;GACV;EACF;CACF;CACA;EACE,MAAM;EACN,aACE;EACF,aAAa;GACX,MAAM;GACN,YAAY;IACV,aAAa;IACb,SAAS;KACP,MAAM;KACN,OAAO,EAAE,MAAM,SAAS;KACxB,aACE;IACJ;IACA,QAAQ;KACN,MAAM;KACN,aACE;IACJ;IACA,QAAQ;KACN,MAAM;KACN,aACE;IACJ;IACA,OAAO;KACL,MAAM;KACN,aAAa;IACf;GACF;EACF;CACF;CACA;EACE,MAAM;EACN,aACE;EACF,aAAa;GACX,MAAM;GACN,YAAY;IACV,aAAa;IACb,MAAM;KACJ,MAAM;KACN,aAAa;IACf;IACA,QAAQ;KACN,MAAM;KACN,MAAM;MAAC;MAAU;MAAY;KAAQ;KACrC,aAAa;IACf;GACF;GACA,UAAU,CAAC,MAAM;EACnB;CACF;CACA;EACE,MAAM;EACN,aACE;EACF,aAAa;GACX,MAAM;GACN,YAAY;IACV,aAAa;IACb,OAAO;IACP,QAAQ;GACV;EACF;CACF;AAG2B,CAAA,CAAiB,KAAK,UAAU;CAC3D,GAAG;CACH,aAAa;EACX,GAAG,KAAK;EACR,SAAS;CACX;CACA,cAAc;AAChB,EAAE,CAAC,CAAC,MAAM,MAAM,UAAU,iBAAiB,KAAK,MAAM,MAAM,IAAI,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"tool-catalog.d.ts","sourceRoot":"","sources":["../src/tool-catalog.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,8BAA8B,CAAC;AAEzD,eAAO,MAAM,iBAAiB,qBAAqB,CAAC;AAkoBpD,eAAO,MAAM,KAAK,EAAE,IAAI,EAO0C,CAAC"}
1
+ {"version":3,"file":"tool-catalog.d.ts","sourceRoot":"","sources":["../src/tool-catalog.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,8BAA8B,CAAC;AAEzD,eAAO,MAAM,iBAAiB,qBAAqB,CAAC;AA6oBpD,eAAO,MAAM,KAAK,EAAE,IAAI,EAO0C,CAAC"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Table-driven hand-rolled-equivalent detector (#4690).
3
+ *
4
+ * The engine knows signal *kinds* (`import`, `call`, `regex`, `decimal-field`),
5
+ * never intents: every rule comes from a parsed intent-index row. A new row
6
+ * with signals therefore needs no code change here. Tokens of an unknown kind
7
+ * are skipped with a note so an index that is newer than this tool degrades
8
+ * instead of failing.
9
+ */
10
+ import type { IntentRow } from './intent-index.js';
11
+ export interface DetectorFile {
12
+ /** Path relative to the reviewed project root. */
13
+ relativePath: string;
14
+ content: string;
15
+ /** Normalised package specifiers imported by the file. */
16
+ imports: string[];
17
+ }
18
+ export interface DetectorPackage {
19
+ name?: string;
20
+ relativePath: string;
21
+ /** Home packages of any row that resolve in package.json or node_modules. */
22
+ installed: ReadonlySet<string>;
23
+ files: DetectorFile[];
24
+ }
25
+ export interface SignalEvidence {
26
+ filePath: string;
27
+ line: number;
28
+ signal: string;
29
+ detail: string;
30
+ }
31
+ export interface HandRolledFinding {
32
+ code: string;
33
+ intent: string;
34
+ intentPage: string;
35
+ componentPages: string[];
36
+ entryPoint: string;
37
+ packageName: string;
38
+ packagePath: string;
39
+ /** Home packages the consumer declares or has installed, yet never imports. */
40
+ installedHomePackages: string[];
41
+ homePackages: string[];
42
+ matchedSignals: string[];
43
+ evidence: SignalEvidence[];
44
+ }
45
+ export interface DetectOptions {
46
+ /** Receives one human-readable note per skipped signal token. */
47
+ onNote?: (note: string) => void;
48
+ /** Evidence entries kept per finding. */
49
+ maxEvidence?: number;
50
+ }
51
+ export declare const SUPPORTED_SIGNAL_KINDS: string[];
52
+ /**
53
+ * For every (intent row, package) where a signal is present and the package
54
+ * imports none of the row's home packages, emit one finding.
55
+ */
56
+ export declare function detectHandRolled(rows: readonly IntentRow[], packages: readonly DetectorPackage[], options?: DetectOptions): HandRolledFinding[];
57
+ //# sourceMappingURL=intent-detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"intent-detector.d.ts","sourceRoot":"","sources":["../../src/tools/intent-detector.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAgB,MAAM,mBAAmB,CAAC;AAEjE,MAAM,WAAW,YAAY;IAC3B,kDAAkD;IAClD,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,0DAA0D;IAC1D,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,6EAA6E;IAC7E,SAAS,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC/B,KAAK,EAAE,YAAY,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,+EAA+E;IAC/E,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,QAAQ,EAAE,cAAc,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,aAAa;IAC5B,iEAAiE;IACjE,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,yCAAyC;IACzC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAmFD,eAAO,MAAM,sBAAsB,UAAyB,CAAC;AA4C7D;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,SAAS,SAAS,EAAE,EAC1B,QAAQ,EAAE,SAAS,eAAe,EAAE,EACpC,OAAO,GAAE,aAAkB,GAC1B,iBAAiB,EAAE,CAwErB"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Pure parser for the developer-intent index (`intents/index.md`).
3
+ *
4
+ * The index is one markdown table whose last column lists `;`-separated
5
+ * backticked signal tokens (`import:node-cron`, `call:setInterval`,
6
+ * `regex:...`). The duplicate-detection pass is driven entirely by these rows,
7
+ * so a new row with signals needs no code change (#4690).
8
+ */
9
+ export interface IntentSignal {
10
+ /** Token kind: the text before the first colon (`import`, `call`, ...). */
11
+ kind: string;
12
+ /** Token value: everything after the first colon. */
13
+ value: string;
14
+ /** The token exactly as written in the table. */
15
+ raw: string;
16
+ }
17
+ export interface IntentHomePackage {
18
+ /** Unscoped package name, e.g. `smrt-jobs`. */
19
+ name: string;
20
+ /** Published npm name, e.g. `@happyvertical/smrt-jobs`. */
21
+ packageName: string;
22
+ /** Component page concept ID, e.g. `/components/smrt-jobs.md`. */
23
+ componentPage: string;
24
+ }
25
+ export interface IntentRow {
26
+ intent: string;
27
+ /** Intent page concept ID, e.g. `/intents/scheduled-runs.md`. */
28
+ intentPage: string;
29
+ homePackages: IntentHomePackage[];
30
+ entryPoint: string;
31
+ signals: IntentSignal[];
32
+ }
33
+ /**
34
+ * Parse the first intent table found in `markdown`. Columns are located by
35
+ * header name (`Intent`, `Page`, `Home package(s)`, `Entry point`,
36
+ * `Hand-rolled signals`) so column order may change. Rows without a page link
37
+ * are ignored.
38
+ */
39
+ export declare function parseIntentIndex(markdown: string): IntentRow[];
40
+ //# sourceMappingURL=intent-index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"intent-index.d.ts","sourceRoot":"","sources":["../../src/tools/intent-index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,WAAW,YAAY;IAC3B,2EAA2E;IAC3E,IAAI,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,KAAK,EAAE,MAAM,CAAC;IACd,iDAAiD;IACjD,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,iBAAiB;IAChC,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,2DAA2D;IAC3D,WAAW,EAAE,MAAM,CAAC;IACpB,kEAAkE;IAClE,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,iEAAiE;IACjE,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,iBAAiB,EAAE,CAAC;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,YAAY,EAAE,CAAC;CACzB;AAyDD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,CAgD9D"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * `smrt-dev-mcp review` — runs `review-smrt-project` from a shell so a CI job
3
+ * (the reusable consumer-knowledge-review workflow, #4690) can call it without
4
+ * speaking MCP. Advisory: the exit code is 0 unless `--fail-on-findings` is set
5
+ * and a duplicate-detection finding exists. It exits 2, never 0, when no
6
+ * intent index can be found.
7
+ */
8
+ export interface ReviewCliArgs {
9
+ directory?: string;
10
+ intentIndexPath?: string;
11
+ format: 'json' | 'summary';
12
+ failOnFindings: boolean;
13
+ }
14
+ interface ReviewFinding {
15
+ severity: string;
16
+ area: string;
17
+ code: string;
18
+ title: string;
19
+ message?: string;
20
+ file?: string;
21
+ intentPage?: string;
22
+ componentPages?: string[];
23
+ recommendation: string;
24
+ }
25
+ interface ReviewResult {
26
+ projectPath: string;
27
+ findings: ReviewFinding[];
28
+ duplicateDetection?: {
29
+ indexPath: string | null;
30
+ notes: string[];
31
+ };
32
+ }
33
+ export declare function parseReviewCliArgs(argv: readonly string[]): ReviewCliArgs;
34
+ /** Markdown suitable for `$GITHUB_STEP_SUMMARY`. */
35
+ export declare function renderReviewSummary(result: ReviewResult): string;
36
+ export declare function runReviewCli(argv: readonly string[], options?: {
37
+ packageRoot?: string;
38
+ }): Promise<number>;
39
+ export {};
40
+ //# sourceMappingURL=review-cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-cli.d.ts","sourceRoot":"","sources":["../../src/tools/review-cli.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,UAAU,aAAa;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,UAAU,YAAY;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,kBAAkB,CAAC,EAAE;QAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,KAAK,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;CACpE;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,aAAa,CA8BzE;AAMD,oDAAoD;AACpD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAgChE;AAED,wBAAsB,YAAY,CAChC,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAO,GACrC,OAAO,CAAC,MAAM,CAAC,CAsBjB"}
@@ -7,7 +7,32 @@ interface ReviewSmrtProjectArgs {
7
7
  rootDir?: string;
8
8
  includeSourceEvidence?: boolean;
9
9
  maxFindings?: number;
10
+ /**
11
+ * Intent index to drive duplicate detection. Its `regex:` tokens become
12
+ * `RegExp`s, so this is trusted by the caller and never read from the
13
+ * reviewed tree by default. Default: the full index shipped inside the
14
+ * pinned `@happyvertical/smrt-dev-mcp` package (`dist/knowledge/intents`),
15
+ * else `docs/knowledge/intents/index.md` when running from the smrt
16
+ * monorepo checkout. Relative paths resolve against `directory`.
17
+ */
18
+ intentIndexPath?: string;
19
+ /** Set false to skip the intent-driven duplicate-detection pass. */
20
+ detectDuplicates?: boolean;
21
+ /**
22
+ * Test seam: package root used to locate the packaged index instead of this
23
+ * module's own. Not part of the tool schema.
24
+ */
25
+ packageRoot?: string;
10
26
  }
27
+ /** Relative location of the intent index inside this package's `dist/`. */
28
+ export declare const PACKAGED_INTENT_INDEX: string;
29
+ /**
30
+ * Locations of the trusted default intent index, in resolution order (#4690):
31
+ * the packaged full index, then the monorepo's committed index when this
32
+ * package sits in `<repo>/packages/` of the smrt checkout. The reviewed
33
+ * project's own tree is never consulted.
34
+ */
35
+ export declare function defaultIntentIndexCandidates(packageRoot?: string): string[];
11
36
  export declare function reviewSmrtProject(args: ReviewSmrtProjectArgs): Promise<string>;
12
37
  export {};
13
38
  //# sourceMappingURL=review-smrt-project.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"review-smrt-project.d.ts","sourceRoot":"","sources":["../../src/tools/review-smrt-project.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,UAAU,qBAAqB;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AA0ED,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,qBAAqB,GAC1B,OAAO,CAAC,MAAM,CAAC,CAyEjB"}
1
+ {"version":3,"file":"review-smrt-project.d.ts","sourceRoot":"","sources":["../../src/tools/review-smrt-project.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAqBH,UAAU,qBAAqB;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;OAOG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,oEAAoE;IACpE,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,2EAA2E;AAC3E,eAAO,MAAM,qBAAqB,QAKjC,CAAC;AAsBF;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAc3E;AAiFD,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,qBAAqB,GAC1B,OAAO,CAAC,MAAM,CAAC,CAiFjB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@happyvertical/smrt-dev-mcp",
3
- "version": "0.60.9",
3
+ "version": "0.60.10",
4
4
  "description": "Development MCP server for SMRT framework knowledge, review context, architecture context, and code generation",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -54,15 +54,15 @@
54
54
  "homepage": "https://github.com/happyvertical/smrt/tree/main/packages/smrt-dev-mcp#readme",
55
55
  "license": "MIT",
56
56
  "dependencies": {
57
- "@happyvertical/smrt-scanner": "0.60.9",
57
+ "@happyvertical/smrt-scanner": "0.60.10",
58
58
  "@modelcontextprotocol/node": "2.1.2",
59
59
  "@modelcontextprotocol/server": "2.4.0",
60
- "@happyvertical/smrt-types": "0.60.9"
60
+ "@happyvertical/smrt-types": "0.60.10"
61
61
  },
62
62
  "devDependencies": {
63
- "@happyvertical/smrt-config": "0.60.9",
64
- "@happyvertical/smrt-core": "0.60.9",
65
- "@happyvertical/sql": "^0.111.3",
63
+ "@happyvertical/smrt-config": "0.60.10",
64
+ "@happyvertical/smrt-core": "0.60.10",
65
+ "@happyvertical/sql": "^0.111.5",
66
66
  "@modelcontextprotocol/client": "2.4.0",
67
67
  "@modelcontextprotocol/conformance": "0.2.0-alpha.11",
68
68
  "@types/node": "24.13.6",