@happyvertical/smrt-dev-mcp 0.60.9 → 0.60.11

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 (60) hide show
  1. package/AGENTS.md +33 -1
  2. package/README.md +17 -1
  3. package/agents/agent-skills.md +16 -0
  4. package/agents/intent-duplicates.md +26 -0
  5. package/dist/agent-skills.d.ts +2 -0
  6. package/dist/agent-skills.d.ts.map +1 -1
  7. package/dist/agent-skills.js +61 -0
  8. package/dist/agent-skills.js.map +1 -0
  9. package/dist/dev-plane.js +2 -2
  10. package/dist/{http-CCiO7qQW.js → http-BqKiyqgN.js} +2 -2
  11. package/dist/{http-CCiO7qQW.js.map → http-BqKiyqgN.js.map} +1 -1
  12. package/dist/index.js +13 -445
  13. package/dist/index.js.map +1 -1
  14. package/dist/knowledge/index.d.ts +1 -1
  15. package/dist/knowledge/index.d.ts.map +1 -1
  16. package/dist/knowledge/intents/audit-trail.md +63 -0
  17. package/dist/knowledge/intents/auth-and-users.md +67 -0
  18. package/dist/knowledge/intents/background-work.md +72 -0
  19. package/dist/knowledge/intents/feature-flags-and-entitlements.md +60 -0
  20. package/dist/knowledge/intents/file-and-asset-storage.md +71 -0
  21. package/dist/knowledge/intents/human-approvals.md +56 -0
  22. package/dist/knowledge/intents/index.md +41 -0
  23. package/dist/knowledge/intents/money-and-rates.md +65 -0
  24. package/dist/knowledge/intents/outbound-messages.md +67 -0
  25. package/dist/knowledge/intents/prompts-and-ai-operations.md +72 -0
  26. package/dist/knowledge/intents/relationships-and-trees.md +56 -0
  27. package/dist/knowledge/intents/scheduled-runs.md +61 -0
  28. package/dist/knowledge/intents/search-facts-knowledge.md +68 -0
  29. package/dist/knowledge/intents/secrets-and-config.md +66 -0
  30. package/dist/knowledge/intents/tenant-scoping.md +63 -0
  31. package/dist/knowledge/intents/webhooks-and-events.md +71 -0
  32. package/dist/knowledge/okf-bundle.d.ts +61 -0
  33. package/dist/knowledge/okf-bundle.d.ts.map +1 -0
  34. package/dist/{knowledge-DqoDX-lZ.js → knowledge-DUiMUjEg.js} +218 -3
  35. package/dist/knowledge-DUiMUjEg.js.map +1 -0
  36. package/dist/knowledge.js +2 -2
  37. package/dist/review-cli-DJIWUlFp.js +75 -0
  38. package/dist/review-cli-DJIWUlFp.js.map +1 -0
  39. package/dist/review-smrt-project-ByEwPcor.js +774 -0
  40. package/dist/review-smrt-project-ByEwPcor.js.map +1 -0
  41. package/dist/smrt-knowledge.okf.md +65 -0
  42. package/dist/{tool-catalog-RHq7nyCm.js → tool-catalog-BhnSCF8g.js} +11 -2
  43. package/dist/tool-catalog-BhnSCF8g.js.map +1 -0
  44. package/dist/tool-catalog.d.ts.map +1 -1
  45. package/dist/tools/intent-detector.d.ts +57 -0
  46. package/dist/tools/intent-detector.d.ts.map +1 -0
  47. package/dist/tools/intent-index.d.ts +40 -0
  48. package/dist/tools/intent-index.d.ts.map +1 -0
  49. package/dist/tools/review-cli.d.ts +40 -0
  50. package/dist/tools/review-cli.d.ts.map +1 -0
  51. package/dist/tools/review-smrt-project.d.ts +25 -0
  52. package/dist/tools/review-smrt-project.d.ts.map +1 -1
  53. package/package.json +10 -6
  54. package/plugin.json +1 -1
  55. package/skills/smrt-catalog/SKILL.md +42 -0
  56. package/skills/smrt-catalog/evals.json +28 -0
  57. package/skills/smrt-contribute/SKILL.md +73 -0
  58. package/skills/smrt-contribute/evals.json +18 -0
  59. package/dist/knowledge-DqoDX-lZ.js.map +0 -1
  60. package/dist/tool-catalog-RHq7nyCm.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,49 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
  import { f as redactConnectionString, m as ProjectRuntimeResolutionError } from "./tools-B0uaPTz0.js";
3
- import { i as SERVER_VERSION, n as startRuntimeHttpHost, r as SERVER_NAME } from "./http-CCiO7qQW.js";
4
- import { n as TOOLS, t as REVIEW_SKILL_NAME } from "./tool-catalog-RHq7nyCm.js";
5
- import { a as buildReviewContext, c as compactContextResult, i as buildPackageSpecialistContext, n as buildContext, o as checkKnowledgeFreshness, r as buildKnowledgeIndex, s as checkKnowledgeFreshnessFromIndex, t as buildArchitectureContext } from "./knowledge-DqoDX-lZ.js";
6
- import { existsSync, readFileSync, realpathSync } from "node:fs";
7
- import { dirname, join, relative, resolve, sep } from "node:path";
3
+ import { getAgentSkill, listAgentSkills } from "./agent-skills.js";
4
+ import { i as SERVER_VERSION, n as startRuntimeHttpHost, r as SERVER_NAME } from "./http-BqKiyqgN.js";
5
+ import { n as TOOLS, t as REVIEW_SKILL_NAME } from "./tool-catalog-BhnSCF8g.js";
6
+ import { a as buildReviewContext, c as compactContextResult, i as buildPackageSpecialistContext, n as buildContext, o as checkKnowledgeFreshness, r as buildKnowledgeIndex, s as checkKnowledgeFreshnessFromIndex, t as buildArchitectureContext } from "./knowledge-DUiMUjEg.js";
7
+ import { t as reviewSmrtProject } from "./review-smrt-project-ByEwPcor.js";
8
+ import { realpathSync } from "node:fs";
8
9
  import { fileURLToPath, pathToFileURL } from "node:url";
9
10
  import { ProtocolError, ProtocolErrorCode, Server } from "@modelcontextprotocol/server";
10
11
  import { serveStdio } from "@modelcontextprotocol/server/stdio";
11
- import { access, readFile, readdir } from "node:fs/promises";
12
- //#region src/agent-skills.ts
13
- var AGENT_SKILLS = [{
14
- name: "smrt-code-review",
15
- description: "Harness-agnostic downstream SMRT code review workflow using smrt-dev-mcp deterministic context and prompt bundles.",
16
- path: "skills/smrt-code-review/SKILL.md",
17
- skillFile: "skills/smrt-code-review/SKILL.md",
18
- references: ["skills/smrt-code-review/references/review-output.md"]
19
- }];
20
- function listAgentSkills() {
21
- return AGENT_SKILLS.map(({ skillFile: _skillFile, ...skill }) => skill);
22
- }
23
- function getAgentSkill(options) {
24
- const skill = AGENT_SKILLS.find((item) => item.name === options.name);
25
- if (!skill) throw new Error(`Unknown agent skill: ${options.name}`);
26
- return {
27
- name: skill.name,
28
- description: skill.description,
29
- path: skill.path,
30
- references: skill.references,
31
- skillMarkdown: readPackageFile(skill.skillFile),
32
- referenceFiles: options.includeReferences === false ? [] : skill.references.map((path) => ({
33
- path,
34
- content: readPackageFile(path)
35
- }))
36
- };
37
- }
38
- function readPackageFile(relativePath) {
39
- return readFileSync(join(resolvePackageRoot(), relativePath), "utf8");
40
- }
41
- function resolvePackageRoot() {
42
- const packageRoot = dirname(dirname(fileURLToPath(import.meta.url)));
43
- if (!existsSync(join(packageRoot, "package.json"))) throw new Error(`Unable to resolve smrt-dev-mcp package root from ${import.meta.url}`);
44
- return packageRoot;
45
- }
46
- //#endregion
47
12
  //#region src/tools/generate-smrt-class.ts
48
13
  var TYPE_MAPPING = {
49
14
  text: {
@@ -232,409 +197,6 @@ function compactObject(value) {
232
197
  return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== void 0));
233
198
  }
234
199
  //#endregion
235
- //#region src/tools/review-smrt-project.ts
236
- /**
237
- * Ecosystem-aware downstream project review.
238
- * Advisory only: scans manifests and source files, then reports alignment risks.
239
- */
240
- var SOURCE_EXTENSIONS = /\.(tsx?|jsx?|svelte)$/;
241
- var SKIP_DIRS = /* @__PURE__ */ new Set([
242
- "node_modules",
243
- "dist",
244
- "build",
245
- ".git",
246
- ".smrt",
247
- ".svelte-kit",
248
- "coverage"
249
- ]);
250
- var DEPENDENCY_SECTIONS = [
251
- "dependencies",
252
- "devDependencies",
253
- "peerDependencies",
254
- "optionalDependencies"
255
- ];
256
- var SMRT_PACKAGE_PREFIX = "@happyvertical/smrt-";
257
- var HAPPYVERTICAL_PACKAGE_PREFIX = "@happyvertical/";
258
- async function reviewSmrtProject(args) {
259
- const projectPath = resolve(args.directory ?? args.rootDir ?? process.cwd());
260
- if (!await pathExists(projectPath)) return JSON.stringify({
261
- projectPath,
262
- packageCount: 0,
263
- packages: [],
264
- findings: [],
265
- summary: {
266
- high: 0,
267
- medium: 0,
268
- low: 0
269
- },
270
- diagnostics: [{
271
- severity: "warning",
272
- message: `Project directory does not exist: ${projectPath}`
273
- }]
274
- }, null, 2);
275
- const packageContexts = await buildPackageContexts(projectPath);
276
- const sourceFiles = await listSourceFiles(projectPath, packageContexts);
277
- await attachSourceFiles(sourceFiles, packageContexts, projectPath);
278
- const findings = limitFindings([
279
- ...findMissingHappyVerticalDependencies(packageContexts),
280
- ...findCustomManifestGeneration(sourceFiles, projectPath),
281
- ...findDirectStorageBypasses(sourceFiles, packageContexts, projectPath),
282
- ...findCustomHttpShells(sourceFiles, packageContexts, projectPath),
283
- ...findLocalAuthTenancy(sourceFiles, packageContexts, projectPath),
284
- ...findUiShellDrift(packageContexts, projectPath),
285
- ...findMissingManifestArtifacts(sourceFiles, packageContexts, projectPath)
286
- ], args.maxFindings);
287
- const packages = packageContexts.map(packageInventory).sort((left, right) => left.path.localeCompare(right.path));
288
- const summary = summarizeFindings(findings);
289
- return JSON.stringify({
290
- projectPath,
291
- packageCount: packages.length,
292
- packages,
293
- findings: args.includeSourceEvidence === false ? findings.map(({ evidence: _evidence, ...finding }) => finding) : findings,
294
- summary,
295
- referenceChecks: [
296
- "Prefer SMRT scanner/runtime manifests over custom manifest builders.",
297
- "Prefer SvelteKit plus @happyvertical/smrt-svelte for app shells.",
298
- "Prefer @happyvertical/sql and @happyvertical/files/assets/content over direct durable node:fs storage.",
299
- "Prefer smrt-users, smrt-tenancy, and profile/audit packages over local static auth seams."
300
- ],
301
- suggestedFollowUpIssues: findings.map((finding) => ({
302
- title: finding.suggestedIssueTitle,
303
- severity: finding.severity,
304
- area: finding.area
305
- }))
306
- }, null, 2);
307
- }
308
- async function buildPackageContexts(projectPath) {
309
- const packageJsonPaths = await listPackageJsonFiles(projectPath);
310
- const contexts = await Promise.all(packageJsonPaths.map(async (packageJsonPath) => {
311
- const json = JSON.parse(await readFile(packageJsonPath, "utf-8"));
312
- const directory = dirname(packageJsonPath);
313
- return {
314
- directory,
315
- relativePath: relative(projectPath, directory) || ".",
316
- packageJsonPath,
317
- json,
318
- dependencies: collectDependencies(json),
319
- scripts: isRecord$1(json.scripts) ? json.scripts : {},
320
- imports: /* @__PURE__ */ new Map(),
321
- sourceFiles: []
322
- };
323
- }));
324
- if (contexts.length === 0) contexts.push({
325
- directory: projectPath,
326
- relativePath: ".",
327
- packageJsonPath: join(projectPath, "package.json"),
328
- json: {},
329
- dependencies: /* @__PURE__ */ new Set(),
330
- scripts: {},
331
- imports: /* @__PURE__ */ new Map(),
332
- sourceFiles: []
333
- });
334
- return contexts.sort((left, right) => left.directory.length - right.directory.length);
335
- }
336
- async function listPackageJsonFiles(projectPath) {
337
- const files = [];
338
- await visit(projectPath, async (filePath, entryName) => {
339
- if (entryName === "package.json") files.push(filePath);
340
- });
341
- return files;
342
- }
343
- async function listSourceFiles(projectPath, packages) {
344
- const files = [];
345
- await visit(projectPath, async (filePath, entryName) => {
346
- if (!SOURCE_EXTENSIONS.test(entryName)) return;
347
- if (entryName.endsWith(".d.ts") || entryName.endsWith(".test.ts") || entryName.endsWith(".spec.ts")) return;
348
- const packageDir = findOwningPackage(filePath, packages).directory;
349
- const content = await readFile(filePath, "utf-8");
350
- files.push({
351
- path: filePath,
352
- packageDir,
353
- content
354
- });
355
- });
356
- return files;
357
- }
358
- async function attachSourceFiles(sourceFiles, packages, projectPath) {
359
- for (const sourceFile of sourceFiles) {
360
- const owner = packages.find((pkg) => pkg.directory === sourceFile.packageDir);
361
- if (!owner) continue;
362
- owner.sourceFiles.push(sourceFile);
363
- for (const importedPackage of extractImports(sourceFile.content)) {
364
- if (!importedPackage.startsWith(HAPPYVERTICAL_PACKAGE_PREFIX)) continue;
365
- const evidence = {
366
- filePath: relative(projectPath, sourceFile.path),
367
- line: lineNumber(sourceFile.content, importedPackage),
368
- detail: `Imports ${importedPackage}`
369
- };
370
- const existing = owner.imports.get(importedPackage) ?? [];
371
- existing.push(evidence);
372
- owner.imports.set(importedPackage, existing);
373
- }
374
- }
375
- }
376
- function findMissingHappyVerticalDependencies(packages) {
377
- return packages.flatMap((pkg) => {
378
- const ownName = typeof pkg.json.name === "string" ? pkg.json.name : void 0;
379
- const missing = Array.from(pkg.imports.keys()).filter((importedPackage) => importedPackage !== ownName && !pkg.dependencies.has(importedPackage));
380
- if (missing.length === 0) return [];
381
- return [{
382
- severity: missing.some((name) => name.startsWith(SMRT_PACKAGE_PREFIX)) ? "high" : "medium",
383
- area: "dependencies",
384
- code: "missing-happyvertical-dependencies",
385
- title: `${packageLabel(pkg)} imports HappyVertical packages that package.json does not declare`,
386
- evidence: missing.flatMap((name) => pkg.imports.get(name) ?? []),
387
- recommendation: "Declare every imported @happyvertical package in the owning package manifest so downstream installs and generated knowledge stay reproducible.",
388
- suggestedIssueTitle: `Declare missing HappyVertical dependencies in ${packageLabel(pkg)}`
389
- }];
390
- });
391
- }
392
- function findCustomManifestGeneration(sourceFiles, projectPath) {
393
- return sourceFiles.filter((file) => /manifest\.json/.test(file.content) && /objects\s*:/.test(file.content) && /\b(writeFile|writeFileSync)\b/.test(file.content) && !/@happyvertical\/smrt-scanner/.test(file.content)).map((file) => ({
394
- severity: "high",
395
- area: "manifest",
396
- code: "custom-object-manifest-generation",
397
- title: "Custom SMRT object manifest generation detected",
398
- evidence: [{
399
- filePath: relative(projectPath, file.path),
400
- line: lineNumber(file.content, "manifest.json"),
401
- detail: "Writes a manifest.json object inventory outside the SMRT scanner/runtime path."
402
- }],
403
- recommendation: "Use the SMRT scanner/runtime manifest path so defaults, relationships, schemas, tenant fields, and cross-package references match framework behavior.",
404
- suggestedIssueTitle: "Replace custom object manifest generation with SMRT scanner/runtime manifest generation"
405
- }));
406
- }
407
- function findDirectStorageBypasses(sourceFiles, packages, projectPath) {
408
- return sourceFiles.flatMap((file) => {
409
- const owner = findOwningPackage(file.path, packages);
410
- const usesFs = /from\s+['"](?:node:fs|node:fs\/promises|fs|fs\/promises)['"]|require\(['"](?:node:fs|node:fs\/promises|fs|fs\/promises)['"]\)/.test(file.content);
411
- const writesDurableData = /\b(writeFile|appendFile|mkdir|rm|rename)\b/.test(file.content) && /(\.json|data|storage|persist|cache|db)/i.test(file.content);
412
- const usesDirectSql = /from\s+['"](?:better-sqlite3|sqlite3|pg|mysql2?|knex|drizzle-orm)['"]/.test(file.content);
413
- if ((!usesFs || !writesDurableData) && !usesDirectSql) return [];
414
- if (owner.dependencies.has("@happyvertical/sql") || owner.dependencies.has("@happyvertical/files") || owner.dependencies.has("@happyvertical/smrt-assets") || owner.dependencies.has("@happyvertical/smrt-content")) return [];
415
- return [{
416
- severity: "medium",
417
- area: "storage",
418
- code: "direct-storage-bypass",
419
- title: `${packageLabel(owner)} appears to bypass HappyVertical storage packages`,
420
- evidence: [{
421
- filePath: relative(projectPath, file.path),
422
- line: lineNumber(file.content, usesDirectSql ? "sqlite" : "writeFile"),
423
- detail: usesDirectSql ? "Imports a direct SQL/storage library without @happyvertical/sql." : "Uses node:fs-style durable writes without @happyvertical/files/assets/content."
424
- }],
425
- recommendation: "Route durable data through @happyvertical/sql, @happyvertical/files, SMRT assets, or SMRT content unless this is explicitly build-only tooling.",
426
- suggestedIssueTitle: `Review direct storage usage in ${packageLabel(owner)}`
427
- }];
428
- });
429
- }
430
- function findCustomHttpShells(sourceFiles, packages, projectPath) {
431
- const evidenceByPackage = /* @__PURE__ */ new Map();
432
- for (const pkg of packages) {
433
- if (pkg.dependencies.has("@sveltejs/kit")) continue;
434
- const routerDependencies = [
435
- "express",
436
- "fastify",
437
- "hono",
438
- "koa"
439
- ].filter((dep) => pkg.dependencies.has(dep));
440
- if (routerDependencies.length === 0) continue;
441
- appendEvidence(evidenceByPackage, pkg, {
442
- filePath: relative(projectPath, pkg.packageJsonPath),
443
- detail: `Declares custom router package(s): ${routerDependencies.join(", ")}.`
444
- });
445
- }
446
- for (const file of sourceFiles) {
447
- const owner = findOwningPackage(file.path, packages);
448
- if (owner.dependencies.has("@sveltejs/kit")) continue;
449
- if (!/from\s+['"](?:node:http|http|node:https|https)['"]|createServer\s*\(/.test(file.content)) continue;
450
- appendEvidence(evidenceByPackage, owner, {
451
- filePath: relative(projectPath, file.path),
452
- line: lineNumber(file.content, "createServer"),
453
- detail: "Custom HTTP routing found without the SvelteKit/SMRT app-shell dependency pattern."
454
- });
455
- }
456
- return Array.from(evidenceByPackage.entries()).map(([owner, evidence]) => ({
457
- severity: "medium",
458
- area: "api-shell",
459
- code: "custom-http-shell",
460
- title: `${packageLabel(owner)} uses a custom HTTP shell`,
461
- evidence,
462
- recommendation: "Compare the app shell against the Anytown/Ergot SvelteKit + SMRT shell pattern before adding custom HTTP infrastructure.",
463
- suggestedIssueTitle: `Align ${packageLabel(owner)} app shell with SMRT/SvelteKit conventions`
464
- }));
465
- }
466
- function appendEvidence(evidenceByPackage, pkg, evidence) {
467
- const existing = evidenceByPackage.get(pkg);
468
- if (existing) {
469
- existing.push(evidence);
470
- return;
471
- }
472
- evidenceByPackage.set(pkg, [evidence]);
473
- }
474
- function findLocalAuthTenancy(sourceFiles, packages, projectPath) {
475
- return sourceFiles.flatMap((file) => {
476
- const owner = findOwningPackage(file.path, packages);
477
- const pathSignal = /(auth|tenant|audit|session|rbac|user)/i.test(file.path);
478
- const codeSignal = /\b(tenantId|tenant|role|permission|session|auditLog|apiKey)\b/.test(file.content);
479
- if (!pathSignal || !codeSignal) return [];
480
- if (owner.dependencies.has("@happyvertical/smrt-users") || owner.dependencies.has("@happyvertical/smrt-tenancy") || owner.dependencies.has("@happyvertical/smrt-profiles")) return [];
481
- return [{
482
- severity: "medium",
483
- area: "auth-tenancy",
484
- code: "local-auth-tenancy",
485
- title: `${packageLabel(owner)} contains local auth/tenancy/audit logic`,
486
- evidence: [{
487
- filePath: relative(projectPath, file.path),
488
- line: lineNumber(file.content, "tenant"),
489
- detail: "Auth, tenancy, session, role, or audit terminology appears without smrt-users/smrt-tenancy/smrt-profiles dependencies."
490
- }],
491
- recommendation: "Add explicit adapters to smrt-users, smrt-tenancy, and profile/audit models or document why this local implementation is intentionally isolated.",
492
- suggestedIssueTitle: `Review auth and tenancy adapters in ${packageLabel(owner)}`
493
- }];
494
- });
495
- }
496
- function findUiShellDrift(packages, projectPath) {
497
- return packages.flatMap((pkg) => {
498
- if (!(pkg.sourceFiles.some((file) => file.path.endsWith(".svelte")) || /(?:web|ui|app|site|frontend)/i.test(packageLabel(pkg)) || pkg.dependencies.has("svelte") || pkg.dependencies.has("vite"))) return [];
499
- if (pkg.dependencies.has("@happyvertical/smrt-svelte")) return [];
500
- return [{
501
- severity: "low",
502
- area: "ui-shell",
503
- code: "missing-smrt-svelte-shell",
504
- title: `${packageLabel(pkg)} looks like UI work without @happyvertical/smrt-svelte`,
505
- evidence: [{
506
- filePath: relative(projectPath, pkg.packageJsonPath),
507
- detail: "UI-facing package does not declare @happyvertical/smrt-svelte."
508
- }],
509
- recommendation: "Use @happyvertical/smrt-svelte and the SvelteKit shell pattern for downstream app UI unless this package is intentionally framework-agnostic.",
510
- suggestedIssueTitle: `Check SMRT Svelte shell alignment for ${packageLabel(pkg)}`
511
- }];
512
- });
513
- }
514
- function findMissingManifestArtifacts(sourceFiles, packages, projectPath) {
515
- return packages.flatMap((pkg) => {
516
- if (!pkg.sourceFiles.some((file) => /@smrt\s*\(/.test(file.content))) return [];
517
- if (sourceFiles.some((file) => file.packageDir === pkg.directory && /@happyvertical\/smrt-scanner/.test(file.content)) || pathExistsSyncHint(join(pkg.directory, ".smrt", "manifest.json")) || pathExistsSyncHint(join(pkg.directory, "dist", "manifest.json"))) return [];
518
- return [{
519
- severity: "low",
520
- area: "manifest",
521
- code: "missing-generated-manifest-artifact",
522
- title: `${packageLabel(pkg)} has @smrt objects but no generated manifest artifact was found`,
523
- evidence: [{
524
- filePath: relative(projectPath, pkg.packageJsonPath),
525
- detail: "No .smrt/manifest.json or dist/manifest.json was visible during review."
526
- }],
527
- recommendation: "Run the package build/test manifest generation path and verify it uses the SMRT scanner/runtime manifest pipeline.",
528
- suggestedIssueTitle: `Verify SMRT manifest generation for ${packageLabel(pkg)}`
529
- }];
530
- });
531
- }
532
- async function visit(dir, onFile) {
533
- let entries;
534
- try {
535
- entries = await readdir(dir, { withFileTypes: true });
536
- } catch {
537
- return;
538
- }
539
- for (const entry of entries) {
540
- const fullPath = join(dir, entry.name);
541
- if (entry.isDirectory()) {
542
- if (SKIP_DIRS.has(entry.name)) continue;
543
- await visit(fullPath, onFile);
544
- continue;
545
- }
546
- if (entry.isFile()) await onFile(fullPath, entry.name);
547
- }
548
- }
549
- function collectDependencies(packageJson) {
550
- const dependencies = /* @__PURE__ */ new Set();
551
- for (const sectionName of DEPENDENCY_SECTIONS) {
552
- const section = packageJson[sectionName];
553
- if (!isRecord$1(section)) continue;
554
- for (const dependencyName of Object.keys(section)) dependencies.add(dependencyName);
555
- }
556
- return dependencies;
557
- }
558
- function extractImports(content) {
559
- const imports = /* @__PURE__ */ new Set();
560
- for (const pattern of [
561
- /(?:import|export)\s+(?:type\s+)?(?:[^'"]+\s+from\s+)?['"]([^'"]+)['"]/g,
562
- /\bimport\s*\(\s*['"]([^'"]+)['"]\s*\)/g,
563
- /\brequire\s*\(\s*['"]([^'"]+)['"]\s*\)/g
564
- ]) for (const match of content.matchAll(pattern)) {
565
- const imported = normalizePackageImport(match[1]);
566
- if (imported) imports.add(imported);
567
- }
568
- return Array.from(imports);
569
- }
570
- function normalizePackageImport(value) {
571
- if (!value || value.startsWith(".") || value.startsWith("/")) return void 0;
572
- if (value.startsWith("@")) {
573
- const [scope, name] = value.split("/");
574
- return scope && name ? `${scope}/${name}` : value;
575
- }
576
- return value.split("/")[0];
577
- }
578
- function findOwningPackage(filePath, packages) {
579
- const normalized = resolve(filePath);
580
- return packages.filter((pkg) => normalized === pkg.directory || normalized.startsWith(`${pkg.directory}${sep}`)).sort((left, right) => right.directory.length - left.directory.length)[0] ?? packages[0];
581
- }
582
- function packageInventory(pkg) {
583
- const declaredHappyVerticalDependencies = Array.from(pkg.dependencies).filter((dependency) => dependency.startsWith(HAPPYVERTICAL_PACKAGE_PREFIX)).sort();
584
- const importedHappyVerticalPackages = Array.from(pkg.imports.keys()).sort();
585
- const ownName = typeof pkg.json.name === "string" ? pkg.json.name : void 0;
586
- return {
587
- name: packageLabel(pkg),
588
- path: pkg.relativePath,
589
- private: typeof pkg.json.private === "boolean" ? pkg.json.private : void 0,
590
- scripts: Object.keys(pkg.scripts).sort(),
591
- declaredHappyVerticalDependencies,
592
- importedHappyVerticalPackages,
593
- missingHappyVerticalDependencies: importedHappyVerticalPackages.filter((name) => name !== ownName && !pkg.dependencies.has(name)),
594
- hasSvelteKit: pkg.dependencies.has("@sveltejs/kit"),
595
- hasSmrtSvelte: pkg.dependencies.has("@happyvertical/smrt-svelte")
596
- };
597
- }
598
- function summarizeFindings(findings) {
599
- return findings.reduce((summary, finding) => {
600
- summary[finding.severity]++;
601
- return summary;
602
- }, {
603
- high: 0,
604
- medium: 0,
605
- low: 0
606
- });
607
- }
608
- function limitFindings(findings, maxFindings) {
609
- const sorted = findings.sort((left, right) => severityRank(left.severity) - severityRank(right.severity) || left.area.localeCompare(right.area) || left.title.localeCompare(right.title));
610
- return maxFindings && maxFindings > 0 ? sorted.slice(0, maxFindings) : sorted;
611
- }
612
- function severityRank(severity) {
613
- return severity === "high" ? 0 : severity === "medium" ? 1 : 2;
614
- }
615
- function packageLabel(pkg) {
616
- return typeof pkg.json.name === "string" ? pkg.json.name : pkg.relativePath;
617
- }
618
- function lineNumber(content, needle) {
619
- const index = content.indexOf(needle);
620
- if (index < 0) return void 0;
621
- return content.slice(0, index).split("\n").length;
622
- }
623
- function isRecord$1(value) {
624
- return !!value && typeof value === "object" && !Array.isArray(value);
625
- }
626
- async function pathExists(path) {
627
- try {
628
- await access(path);
629
- return true;
630
- } catch {
631
- return false;
632
- }
633
- }
634
- function pathExistsSyncHint(path) {
635
- return existsSync(path);
636
- }
637
- //#endregion
638
200
  //#region src/index.ts
639
201
  /**
640
202
  * SMRT Development MCP Server
@@ -1227,7 +789,13 @@ async function mainHttp(cli) {
1227
789
  process.on("SIGINT", shutdown);
1228
790
  process.on("SIGTERM", shutdown);
1229
791
  }
1230
- if (isEntrypoint()) {
792
+ if (isEntrypoint()) if (process.argv[2] === "review") import("./review-cli-DJIWUlFp.js").then(({ runReviewCli }) => runReviewCli(process.argv.slice(3))).then((code) => {
793
+ process.exitCode = code;
794
+ }).catch((error) => {
795
+ console.error(`[${SERVER_NAME}] review failed:`, error);
796
+ process.exit(1);
797
+ });
798
+ else {
1231
799
  const cli = parseHttpCliArgs(process.argv.slice(2));
1232
800
  (cli.http ? mainHttp(cli) : main()).catch((error) => {
1233
801
  console.error(`[${SERVER_NAME}] Fatal error:`, error);