codesift-mcp 0.5.28 → 0.7.0

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 (148) hide show
  1. package/README.md +7 -2
  2. package/dist/cli/commands.d.ts.map +1 -1
  3. package/dist/cli/commands.js +26 -1
  4. package/dist/cli/commands.js.map +1 -1
  5. package/dist/cli/git-hooks-installer.d.ts +31 -0
  6. package/dist/cli/git-hooks-installer.d.ts.map +1 -0
  7. package/dist/cli/git-hooks-installer.js +172 -0
  8. package/dist/cli/git-hooks-installer.js.map +1 -0
  9. package/dist/cli/help.d.ts.map +1 -1
  10. package/dist/cli/help.js +5 -0
  11. package/dist/cli/help.js.map +1 -1
  12. package/dist/cli/setup.d.ts +5 -0
  13. package/dist/cli/setup.d.ts.map +1 -1
  14. package/dist/cli/setup.js +15 -1
  15. package/dist/cli/setup.js.map +1 -1
  16. package/dist/parser/extractors/_shared.js +2 -2
  17. package/dist/parser/extractors/_shared.js.map +1 -1
  18. package/dist/parser/extractors/hono.d.ts.map +1 -1
  19. package/dist/parser/extractors/hono.js +47 -10
  20. package/dist/parser/extractors/hono.js.map +1 -1
  21. package/dist/parser/extractors/python.js +4 -5
  22. package/dist/parser/extractors/python.js.map +1 -1
  23. package/dist/parser/extractors/typescript.d.ts.map +1 -1
  24. package/dist/parser/extractors/typescript.js +70 -22
  25. package/dist/parser/extractors/typescript.js.map +1 -1
  26. package/dist/register-tool-loaders.d.ts +6 -0
  27. package/dist/register-tool-loaders.d.ts.map +1 -1
  28. package/dist/register-tool-loaders.js +12 -0
  29. package/dist/register-tool-loaders.js.map +1 -1
  30. package/dist/register-tools.d.ts.map +1 -1
  31. package/dist/register-tools.js +299 -12
  32. package/dist/register-tools.js.map +1 -1
  33. package/dist/storage/index-store.d.ts +13 -1
  34. package/dist/storage/index-store.d.ts.map +1 -1
  35. package/dist/storage/index-store.js +38 -38
  36. package/dist/storage/index-store.js.map +1 -1
  37. package/dist/storage/registry.d.ts +9 -0
  38. package/dist/storage/registry.d.ts.map +1 -1
  39. package/dist/storage/registry.js +28 -0
  40. package/dist/storage/registry.js.map +1 -1
  41. package/dist/tools/_helpers.d.ts +2 -0
  42. package/dist/tools/_helpers.d.ts.map +1 -1
  43. package/dist/tools/_helpers.js +2 -1
  44. package/dist/tools/_helpers.js.map +1 -1
  45. package/dist/tools/astro-audit.d.ts +40 -0
  46. package/dist/tools/astro-audit.d.ts.map +1 -1
  47. package/dist/tools/astro-audit.js +94 -5
  48. package/dist/tools/astro-audit.js.map +1 -1
  49. package/dist/tools/astro-content-collections.d.ts.map +1 -1
  50. package/dist/tools/astro-content-collections.js +1 -141
  51. package/dist/tools/astro-content-collections.js.map +1 -1
  52. package/dist/tools/astro-db-audit.d.ts +30 -0
  53. package/dist/tools/astro-db-audit.d.ts.map +1 -0
  54. package/dist/tools/astro-db-audit.js +244 -0
  55. package/dist/tools/astro-db-audit.js.map +1 -0
  56. package/dist/tools/astro-db-parser.d.ts +24 -0
  57. package/dist/tools/astro-db-parser.d.ts.map +1 -0
  58. package/dist/tools/astro-db-parser.js +150 -0
  59. package/dist/tools/astro-db-parser.js.map +1 -0
  60. package/dist/tools/astro-env-validator.d.ts +38 -0
  61. package/dist/tools/astro-env-validator.d.ts.map +1 -0
  62. package/dist/tools/astro-env-validator.js +190 -0
  63. package/dist/tools/astro-env-validator.js.map +1 -0
  64. package/dist/tools/astro-helpers.d.ts +13 -0
  65. package/dist/tools/astro-helpers.d.ts.map +1 -0
  66. package/dist/tools/astro-helpers.js +116 -0
  67. package/dist/tools/astro-helpers.js.map +1 -0
  68. package/dist/tools/astro-image-audit.d.ts +35 -0
  69. package/dist/tools/astro-image-audit.d.ts.map +1 -0
  70. package/dist/tools/astro-image-audit.js +129 -0
  71. package/dist/tools/astro-image-audit.js.map +1 -0
  72. package/dist/tools/astro-middleware.d.ts +26 -0
  73. package/dist/tools/astro-middleware.d.ts.map +1 -0
  74. package/dist/tools/astro-middleware.js +164 -0
  75. package/dist/tools/astro-middleware.js.map +1 -0
  76. package/dist/tools/astro-migration.d.ts.map +1 -1
  77. package/dist/tools/astro-migration.js +66 -0
  78. package/dist/tools/astro-migration.js.map +1 -1
  79. package/dist/tools/astro-sessions.d.ts +26 -0
  80. package/dist/tools/astro-sessions.d.ts.map +1 -0
  81. package/dist/tools/astro-sessions.js +140 -0
  82. package/dist/tools/astro-sessions.js.map +1 -0
  83. package/dist/tools/astro-svg-components.d.ts +32 -0
  84. package/dist/tools/astro-svg-components.d.ts.map +1 -0
  85. package/dist/tools/astro-svg-components.js +123 -0
  86. package/dist/tools/astro-svg-components.js.map +1 -0
  87. package/dist/tools/constant-resolution-tools.d.ts.map +1 -1
  88. package/dist/tools/constant-resolution-tools.js +8 -4
  89. package/dist/tools/constant-resolution-tools.js.map +1 -1
  90. package/dist/tools/context-tools.d.ts.map +1 -1
  91. package/dist/tools/context-tools.js +45 -7
  92. package/dist/tools/context-tools.js.map +1 -1
  93. package/dist/tools/index-tools.d.ts.map +1 -1
  94. package/dist/tools/index-tools.js +18 -41
  95. package/dist/tools/index-tools.js.map +1 -1
  96. package/dist/tools/pattern-tools.d.ts.map +1 -1
  97. package/dist/tools/pattern-tools.js +22 -26
  98. package/dist/tools/pattern-tools.js.map +1 -1
  99. package/dist/tools/project-tools.js +1 -1
  100. package/dist/tools/project-tools.js.map +1 -1
  101. package/dist/tools/python-constants-tools.d.ts +3 -1
  102. package/dist/tools/python-constants-tools.d.ts.map +1 -1
  103. package/dist/tools/python-constants-tools.js +3 -2
  104. package/dist/tools/python-constants-tools.js.map +1 -1
  105. package/dist/tools/react-tools.d.ts +22 -10
  106. package/dist/tools/react-tools.d.ts.map +1 -1
  107. package/dist/tools/react-tools.js +23 -17
  108. package/dist/tools/react-tools.js.map +1 -1
  109. package/dist/tools/sql-tools.d.ts +26 -0
  110. package/dist/tools/sql-tools.d.ts.map +1 -1
  111. package/dist/tools/sql-tools.js +84 -9
  112. package/dist/tools/sql-tools.js.map +1 -1
  113. package/dist/tools/status-tools.d.ts +1 -0
  114. package/dist/tools/status-tools.d.ts.map +1 -1
  115. package/dist/tools/status-tools.js +13 -19
  116. package/dist/tools/status-tools.js.map +1 -1
  117. package/dist/tools/symbol-tools.d.ts +11 -0
  118. package/dist/tools/symbol-tools.d.ts.map +1 -1
  119. package/dist/tools/symbol-tools.js +104 -6
  120. package/dist/tools/symbol-tools.js.map +1 -1
  121. package/dist/tools/typescript-constants-tools.d.ts +3 -0
  122. package/dist/tools/typescript-constants-tools.d.ts.map +1 -1
  123. package/dist/tools/typescript-constants-tools.js +53 -13
  124. package/dist/tools/typescript-constants-tools.js.map +1 -1
  125. package/dist/utils/constant-file-pattern.d.ts +6 -0
  126. package/dist/utils/constant-file-pattern.d.ts.map +1 -0
  127. package/dist/utils/constant-file-pattern.js +27 -0
  128. package/dist/utils/constant-file-pattern.js.map +1 -0
  129. package/dist/utils/heritage-edges.d.ts +13 -0
  130. package/dist/utils/heritage-edges.d.ts.map +1 -0
  131. package/dist/utils/heritage-edges.js +73 -0
  132. package/dist/utils/heritage-edges.js.map +1 -0
  133. package/dist/utils/import-graph.d.ts.map +1 -1
  134. package/dist/utils/import-graph.js +15 -9
  135. package/dist/utils/import-graph.js.map +1 -1
  136. package/dist/utils/ts-imports.d.ts +8 -1
  137. package/dist/utils/ts-imports.d.ts.map +1 -1
  138. package/dist/utils/ts-imports.js +48 -7
  139. package/dist/utils/ts-imports.js.map +1 -1
  140. package/dist/utils/tsconfig-paths.d.ts +6 -4
  141. package/dist/utils/tsconfig-paths.d.ts.map +1 -1
  142. package/dist/utils/tsconfig-paths.js +56 -21
  143. package/dist/utils/tsconfig-paths.js.map +1 -1
  144. package/hooks/hook-chain.sh +7 -0
  145. package/hooks/post-commit +8 -0
  146. package/hooks/post-commit-review-backlog.sh +107 -0
  147. package/package.json +2 -1
  148. package/rules/codesift.md +6 -3
@@ -1,3 +1,4 @@
1
+ import * as pathModule from "node:path";
1
2
  import { z } from "zod";
2
3
  /** Boolean that also accepts "true"/"false" strings (LLMs often send strings instead of booleans) */
3
4
  const zBool = () => z.union([z.boolean(), z.string().transform((s) => s === "true")]).optional();
@@ -5,7 +6,7 @@ import { wrapTool, registerShortener } from "./server-helpers.js";
5
6
  import { detectProjectLanguagesSync } from "./utils/language-detect.js";
6
7
  import { STUB_LANGUAGES } from "./parser/stub-languages.js";
7
8
  import { getUsageStats, formatUsageReport } from "./storage/usage-stats.js";
8
- import { indexFolder, indexFile, indexRepo, listAllRepos, invalidateCache, getCodeIndex, searchSymbols, searchText, semanticSearch, getFileTree, getFileOutline, getRepoOutline, suggestQueries, getSymbol, getSymbols, findAndShow, findReferences, findReferencesBatch, findDeadCode, getContextBundle, formatRefsCompact, formatSymbolCompact, formatSymbolsCompact, formatBundleCompact, traceCallChain, traceComponentTree, analyzeHooks, analyzeRenders, buildContextGraph, auditCompilerReadiness, reactQuickstart, impactAnalysis, traceRoute, detectCommunities, assembleContext, getKnowledgeMap, diffOutline, changedSymbols, generateClaudeMd, codebaseRetrieval, analyzeComplexity, findClones, analyzeHotspots, crossRepoSearchSymbols, crossRepoFindReferences, searchPatterns, listPatterns, generateReport, goToDefinition, getTypeInfo, renameSymbol, getCallHierarchy, indexConversations, searchConversations, searchAllConversations, findConversationsForSymbol, scanSecrets, resolvePhpNamespace, tracePhpEvent, findPhpViews, resolvePhpService, phpSecurityScan, phpProjectAudit, consolidateMemories, readMemory, createAnalysisPlan, writeScratchpad, readScratchpad, listScratchpad, updateStepStatus, getPlan, listPlans, frequencyAnalysis, findExtensionFunctions, analyzeSealedHierarchy, traceSuspendChain, analyzeKmpDeclarations, traceFlowChain, traceHiltGraph, traceComposeTree, analyzeComposeRecomposition, traceRoomSchema, extractKotlinSerializationContract, astroAnalyzeIslands, astroHydrationAudit, astroRouteMap, astroActionsAudit, astroAudit, nextjsRouteMap, nextjsMetadataAudit, frameworkAudit, astroConfigAnalyze, astroContentCollections, analyzeProject, getExtractorVersions, getModelGraph, getTestFixtures, findFrameworkWiring, runRuff, parsePyproject, resolveConstantValue, effectiveDjangoViewSecurity, findPythonCallers, taintTrace, analyzeDjangoSettings, runMypy, runPyright, analyzePythonDeps, pythonAudit, traceFastAPIDepends, analyzeAsyncCorrectness, getPydanticModels, reviewDiff, auditScan, indexStatus, auditAgentConfig, testImpactAnalysis, dependencyAudit, migrationLint, planTurn, formatPlanTurnResult, astroMigrationCheck, analyzePrismaSchema, findPerfHotspots, fanInFanOut, coChangeAnalysis, architectureSummary, nestAudit, explainQuery, generateWiki, } from "./register-tool-loaders.js";
9
+ import { indexFolder, indexFile, indexRepo, listAllRepos, invalidateCache, getCodeIndex, searchSymbols, searchText, semanticSearch, getFileTree, getFileOutline, getRepoOutline, suggestQueries, getSymbol, getSymbols, findAndShow, findReferences, findReferencesBatch, findDeadCode, getContextBundle, formatRefsCompact, formatSymbolCompact, formatSymbolsCompact, formatBundleCompact, traceCallChain, traceComponentTree, analyzeHooks, analyzeRenders, buildContextGraph, auditCompilerReadiness, reactQuickstart, impactAnalysis, traceRoute, detectCommunities, assembleContext, getKnowledgeMap, diffOutline, changedSymbols, generateClaudeMd, codebaseRetrieval, analyzeComplexity, findClones, analyzeHotspots, crossRepoSearchSymbols, crossRepoFindReferences, searchPatterns, listPatterns, generateReport, goToDefinition, getTypeInfo, renameSymbol, getCallHierarchy, indexConversations, searchConversations, searchAllConversations, findConversationsForSymbol, scanSecrets, resolvePhpNamespace, tracePhpEvent, findPhpViews, resolvePhpService, phpSecurityScan, phpProjectAudit, consolidateMemories, readMemory, createAnalysisPlan, writeScratchpad, readScratchpad, listScratchpad, updateStepStatus, getPlan, listPlans, frequencyAnalysis, findExtensionFunctions, analyzeSealedHierarchy, traceSuspendChain, analyzeKmpDeclarations, traceFlowChain, traceHiltGraph, traceComposeTree, analyzeComposeRecomposition, traceRoomSchema, extractKotlinSerializationContract, astroAnalyzeIslands, astroHydrationAudit, astroRouteMap, astroActionsAudit, astroAudit, nextjsRouteMap, nextjsMetadataAudit, frameworkAudit, astroConfigAnalyze, astroContentCollections, astroMiddlewareAudit, astroSessionsAudit, astroDbAudit, astroEnvValidator, astroImageAudit, astroSvgComponents, analyzeProject, getExtractorVersions, getModelGraph, getTestFixtures, findFrameworkWiring, runRuff, parsePyproject, resolveConstantValue, effectiveDjangoViewSecurity, findPythonCallers, taintTrace, analyzeDjangoSettings, runMypy, runPyright, analyzePythonDeps, pythonAudit, traceFastAPIDepends, analyzeAsyncCorrectness, getPydanticModels, reviewDiff, auditScan, indexStatus, auditAgentConfig, testImpactAnalysis, dependencyAudit, migrationLint, planTurn, formatPlanTurnResult, astroMigrationCheck, analyzePrismaSchema, findPerfHotspots, fanInFanOut, coChangeAnalysis, architectureSummary, nestAudit, explainQuery, generateWiki, } from "./register-tool-loaders.js";
9
10
  import { formatSnapshot, getContext, getSessionState } from "./storage/session-state.js";
10
11
  import { formatComplexityCompact, formatComplexityCounts, formatClonesCompact, formatClonesCounts, formatHotspotsCompact, formatHotspotsCounts, formatTraceRouteCompact, formatTraceRouteCounts } from "./formatters-shortening.js";
11
12
  import { formatSearchSymbols, formatFileTree, formatFileOutline, formatSearchPatterns, formatDeadCode, formatComplexity, formatClones, formatHotspots, formatRepoOutline, formatSuggestQueries, formatSecrets, formatConversations, formatRoles, formatAssembleContext, formatCommunities, formatCallTree, formatTraceRoute, formatKnowledgeMap, formatImpactAnalysis, formatDiffOutline, formatChangedSymbols, formatReviewDiff, formatPerfHotspots, formatFanInFanOut, formatCoChange, formatArchitectureSummary, formatNextjsRouteMap, formatNextjsMetadataAudit, formatFrameworkAudit } from "./formatters.js";
@@ -207,6 +208,16 @@ const FRAMEWORK_TOOL_GROUPS = {
207
208
  "resolve_php_service",
208
209
  "php_security_scan",
209
210
  "php_project_audit",
211
+ // PHP stacks (Yii2/Laravel/Symfony) overwhelmingly run on MySQL/Postgres with
212
+ // raw .sql migrations and ActiveRecord models. The SQL toolchain is the
213
+ // missing entry-point for schema/drift/lint/dml work — auto-revealing it
214
+ // here closes the gap that 0 SQL tools have ever been called from PHP repos.
215
+ "analyze_schema",
216
+ "trace_query",
217
+ "sql_audit",
218
+ "diff_migrations",
219
+ "search_columns",
220
+ "migration_lint",
210
221
  ],
211
222
  // Kotlin / Android / Gradle — detected by build.gradle.kts or settings.gradle.kts
212
223
  "build.gradle.kts": [
@@ -311,6 +322,70 @@ const FRAMEWORK_TOOL_GROUPS = {
311
322
  "analyze_prisma_schema",
312
323
  "migration_lint",
313
324
  ],
325
+ // Astro — detected by astro.config.{mjs,ts,cjs,js}. Auto-loads the full
326
+ // 13-tool Astro toolkit (7 core + 6 Astro 5 sub-tools from Tasks 2-7).
327
+ // astro_audit is the meta-tool entry point; sub-tools are listed for
328
+ // direct invocation via describe_tools.
329
+ "astro.config.mjs": [
330
+ "astro_route_map",
331
+ "astro_config_analyze",
332
+ "astro_content_collections",
333
+ "astro_actions_audit",
334
+ "astro_migration_check",
335
+ "astro_analyze_islands",
336
+ "astro_audit",
337
+ "astro_middleware",
338
+ "astro_sessions",
339
+ "astro_db_audit",
340
+ "astro_env_validator",
341
+ "astro_image_audit",
342
+ "astro_svg_components",
343
+ ],
344
+ "astro.config.ts": [
345
+ "astro_route_map",
346
+ "astro_config_analyze",
347
+ "astro_content_collections",
348
+ "astro_actions_audit",
349
+ "astro_migration_check",
350
+ "astro_analyze_islands",
351
+ "astro_audit",
352
+ "astro_middleware",
353
+ "astro_sessions",
354
+ "astro_db_audit",
355
+ "astro_env_validator",
356
+ "astro_image_audit",
357
+ "astro_svg_components",
358
+ ],
359
+ "astro.config.cjs": [
360
+ "astro_route_map",
361
+ "astro_config_analyze",
362
+ "astro_content_collections",
363
+ "astro_actions_audit",
364
+ "astro_migration_check",
365
+ "astro_analyze_islands",
366
+ "astro_audit",
367
+ "astro_middleware",
368
+ "astro_sessions",
369
+ "astro_db_audit",
370
+ "astro_env_validator",
371
+ "astro_image_audit",
372
+ "astro_svg_components",
373
+ ],
374
+ "astro.config.js": [
375
+ "astro_route_map",
376
+ "astro_config_analyze",
377
+ "astro_content_collections",
378
+ "astro_actions_audit",
379
+ "astro_migration_check",
380
+ "astro_analyze_islands",
381
+ "astro_audit",
382
+ "astro_middleware",
383
+ "astro_sessions",
384
+ "astro_db_audit",
385
+ "astro_env_validator",
386
+ "astro_image_audit",
387
+ "astro_svg_components",
388
+ ],
314
389
  };
315
390
  /**
316
391
  * React-specific tools — auto-enabled when a React project is detected.
@@ -363,6 +438,20 @@ const PRISMA_TOOLS = [
363
438
  "analyze_prisma_schema",
364
439
  "migration_lint",
365
440
  ];
441
+ /**
442
+ * Raw-SQL toolchain — auto-enabled when a project has loose `*.sql` files
443
+ * (migrations, seeds, mysqldump). Independent of any ORM. Targets the
444
+ * "PHP/Yii2 + MySQL legacy" segment that historically called 0 of these
445
+ * tools because they were hidden behind discover_tools.
446
+ */
447
+ const SQL_TOOLS = [
448
+ "analyze_schema",
449
+ "trace_query",
450
+ "sql_audit",
451
+ "diff_migrations",
452
+ "search_columns",
453
+ "migration_lint",
454
+ ];
366
455
  const AUTO_LOAD_CACHE_TTL_MS = 5_000;
367
456
  const autoLoadToolsCache = new Map();
368
457
  /**
@@ -386,14 +475,36 @@ export async function detectAutoLoadTools(cwd) {
386
475
  if (existsSync(join(cwd, "prisma", "schema.prisma"))) {
387
476
  toEnable.push(...PRISMA_TOOLS);
388
477
  }
478
+ // Raw SQL detection — fires on any project with loose `*.sql` files in
479
+ // common schema/migration dirs. Catches mysqldump/pg_dump artifacts and
480
+ // hand-written migrations across PHP/Python/Go/Java stacks regardless of
481
+ // ORM. Composer-based PHP repos already pull SQL_TOOLS via FRAMEWORK_TOOL_GROUPS;
482
+ // this branch covers everything else (e.g. Django + raw migrations,
483
+ // standalone schema repos).
484
+ if (hasSqlFilesShallow(cwd, readdirSync)) {
485
+ toEnable.push(...SQL_TOOLS);
486
+ }
389
487
  const detectFromPackageJson = (pkgRoot) => {
390
488
  const enabled = [];
391
489
  const pkgPath = join(pkgRoot, "package.json");
392
490
  if (!existsSync(pkgPath))
393
491
  return enabled;
492
+ let pkg;
394
493
  try {
395
- const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
396
- const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
494
+ pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
495
+ }
496
+ catch {
497
+ /* malformed or unreadable package.json — omit silently */
498
+ return enabled;
499
+ }
500
+ if (!pkg || typeof pkg !== "object" || Array.isArray(pkg))
501
+ return enabled;
502
+ try {
503
+ const manifest = pkg;
504
+ const allDeps = {
505
+ ...manifest.dependencies,
506
+ ...manifest.devDependencies,
507
+ };
397
508
  const hasReact = !!(allDeps["react"] ||
398
509
  allDeps["next"] ||
399
510
  allDeps["@remix-run/react"] ||
@@ -422,14 +533,18 @@ export async function detectAutoLoadTools(cwd) {
422
533
  // npm/yarn/pnpm workspaces field — content-based monorepo signal.
423
534
  // Complements the file-based signals (pnpm-workspace.yaml, lerna.json,
424
535
  // nx.json, turbo.json) so plain `"workspaces": [...]` setups also fire.
425
- const hasWorkspaces = Array.isArray(pkg.workspaces) ||
426
- (pkg.workspaces && typeof pkg.workspaces === "object" &&
427
- Array.isArray(pkg.workspaces.packages));
536
+ const ws = manifest.workspaces;
537
+ const hasWorkspaces = Array.isArray(ws) ||
538
+ (ws !== null &&
539
+ typeof ws === "object" &&
540
+ !Array.isArray(ws) &&
541
+ Array.isArray(ws.packages));
428
542
  if (hasWorkspaces)
429
543
  enabled.push(...MONOREPO_TOOLS);
430
544
  }
431
- catch {
432
- /* malformed package.json */
545
+ catch (err) {
546
+ const detail = err instanceof Error ? err.stack ?? err.message : String(err);
547
+ console.warn(`[codesift-mcp] detectFromPackageJson(${pkgRoot}): ${detail}`);
433
548
  }
434
549
  return enabled;
435
550
  };
@@ -481,7 +596,8 @@ export function detectAutoLoadToolsCached(cwd) {
481
596
  * Skips node_modules, dist, build, .next, .astro, .git.
482
597
  */
483
598
  function hasJsxFilesShallow(cwd, readdirSyncFn) {
484
- const { join } = require("node:path");
599
+ // ESM-safe path import (avoid `require("node:path")`, which throws under ESM).
600
+ const { join } = pathModule;
485
601
  const IGNORE = new Set([
486
602
  "node_modules", "dist", "build", ".next", ".astro", ".git",
487
603
  "out", "coverage", ".turbo", ".vercel", ".cache",
@@ -519,6 +635,65 @@ function hasJsxFilesShallow(cwd, readdirSyncFn) {
519
635
  }
520
636
  return false;
521
637
  }
638
+ /**
639
+ * Quick scan for *.sql files in conventional schema/migration directories.
640
+ * Used to auto-enable the SQL toolchain on any project that ships raw SQL
641
+ * regardless of language stack. Stops on first hit; depth capped at 3 so
642
+ * nested package dirs (e.g. monorepo apps/*) are still reachable.
643
+ */
644
+ function hasSqlFilesShallow(cwd, readdirSyncFn) {
645
+ const { join } = pathModule;
646
+ const IGNORE = new Set([
647
+ "node_modules", "dist", "build", ".next", ".astro", ".git",
648
+ "out", "coverage", ".turbo", ".vercel", ".cache", "vendor",
649
+ ]);
650
+ // SQL conventionally lives in dedicated dirs — scanning every src/ tree
651
+ // would trigger false positives on test fixtures and string-literal SQL.
652
+ const DEEP_ROOTS = [
653
+ "migrations", "migration", "db", "database", "schema", "schemas",
654
+ "sql", "ddl", "seeds", "seed", "supabase",
655
+ "prisma/migrations", "drizzle/migrations",
656
+ ];
657
+ function scanDeep(dir, depth) {
658
+ if (depth > 3)
659
+ return false;
660
+ let entries;
661
+ try {
662
+ entries = readdirSyncFn(dir, { withFileTypes: true });
663
+ }
664
+ catch {
665
+ return false;
666
+ }
667
+ for (const e of entries) {
668
+ if (e.isFile() && /\.sql$/i.test(e.name))
669
+ return true;
670
+ }
671
+ for (const e of entries) {
672
+ if (e.isDirectory() && !IGNORE.has(e.name) && !e.name.startsWith(".")) {
673
+ if (scanDeep(join(dir, e.name), depth + 1))
674
+ return true;
675
+ }
676
+ }
677
+ return false;
678
+ }
679
+ // Top-level: dump files like `schema.sql` / `init.sql` / `database.sql`.
680
+ try {
681
+ const rootEntries = readdirSyncFn(cwd, { withFileTypes: true });
682
+ for (const e of rootEntries) {
683
+ if (e.isFile() && /\.sql$/i.test(e.name))
684
+ return true;
685
+ }
686
+ }
687
+ catch { /* skip */ }
688
+ for (const root of DEEP_ROOTS) {
689
+ try {
690
+ if (scanDeep(join(cwd, root), 0))
691
+ return true;
692
+ }
693
+ catch { /* skip */ }
694
+ }
695
+ return false;
696
+ }
522
697
  // ---------------------------------------------------------------------------
523
698
  // Output schemas — typed results for structured validation & documentation
524
699
  // ---------------------------------------------------------------------------
@@ -3449,6 +3624,115 @@ const TOOL_DEFINITIONS = [
3449
3624
  return await astroAudit(opts);
3450
3625
  },
3451
3626
  },
3627
+ // --- Astro 5 sub-tools (Task 12). Discoverable via describe_tools — NOT in CORE. ---
3628
+ {
3629
+ name: "astro_middleware",
3630
+ category: "analysis",
3631
+ searchHint: "astro middleware onRequest sequence guards routes protected auth flows",
3632
+ description: "Parses src/middleware.ts (or .js) — detects onRequest exports, sequence(...) ordering, and guard if-blocks lacking redirect/throw/return Response. Issue codes MW00–MW03.",
3633
+ schema: lazySchema(() => ({
3634
+ project_root: z.string().optional().describe("Absolute path to project root (default: auto-detected)"),
3635
+ repo: z.string().optional(),
3636
+ })),
3637
+ handler: async (args) => {
3638
+ const opts = {};
3639
+ if (args.project_root != null)
3640
+ opts.project_root = args.project_root;
3641
+ if (args.repo != null)
3642
+ opts.repo = args.repo;
3643
+ return await astroMiddlewareAudit(opts);
3644
+ },
3645
+ },
3646
+ {
3647
+ name: "astro_sessions",
3648
+ category: "analysis",
3649
+ searchHint: "astro sessions experimental session adapter compatibility node vercel cloudflare",
3650
+ description: "Astro 5 Sessions API audit. Detects Astro.session.* / context.session.* usage; cross-checks experimental.session config + adapter compatibility. Issue codes SE01–SE04.",
3651
+ schema: lazySchema(() => ({
3652
+ project_root: z.string().optional(),
3653
+ repo: z.string().optional(),
3654
+ })),
3655
+ handler: async (args) => {
3656
+ const opts = {};
3657
+ if (args.project_root != null)
3658
+ opts.project_root = args.project_root;
3659
+ if (args.repo != null)
3660
+ opts.repo = args.repo;
3661
+ return await astroSessionsAudit(opts);
3662
+ },
3663
+ },
3664
+ {
3665
+ name: "astro_db_audit",
3666
+ category: "analysis",
3667
+ searchHint: "astro db defineTable schema columns foreign key index n+1 query loop",
3668
+ description: "Astro DB audit. Parses db/config.ts defineTable schemas; detects N+1 query patterns (db.select inside loops via AST), missing FK indexes (per-table scoped), reference cycles. Codes DB00–DB04.",
3669
+ schema: lazySchema(() => ({
3670
+ project_root: z.string().optional(),
3671
+ repo: z.string().optional(),
3672
+ })),
3673
+ handler: async (args) => {
3674
+ const opts = {};
3675
+ if (args.project_root != null)
3676
+ opts.project_root = args.project_root;
3677
+ if (args.repo != null)
3678
+ opts.repo = args.repo;
3679
+ return await astroDbAudit(opts);
3680
+ },
3681
+ },
3682
+ {
3683
+ name: "astro_env_validator",
3684
+ category: "analysis",
3685
+ searchHint: "astro env envField schema astro:env client server context import.meta.env",
3686
+ description: "Astro 5 astro:env validator. Parses env.schema (envField) and cross-checks against import.meta.env + astro:env/{client,server} imports. Codes EV01–EV04.",
3687
+ schema: lazySchema(() => ({
3688
+ project_root: z.string().optional(),
3689
+ repo: z.string().optional(),
3690
+ })),
3691
+ handler: async (args) => {
3692
+ const opts = {};
3693
+ if (args.project_root != null)
3694
+ opts.project_root = args.project_root;
3695
+ if (args.repo != null)
3696
+ opts.repo = args.repo;
3697
+ return await astroEnvValidator(opts);
3698
+ },
3699
+ },
3700
+ {
3701
+ name: "astro_image_audit",
3702
+ category: "analysis",
3703
+ searchHint: "astro image img alt accessibility Picture astro:assets getImage optimization",
3704
+ description: "Scans .astro pages for image usage: raw <img> vs <Image>/<Picture>, missing/empty alt attributes, getImage() without astro:assets import. Codes IM01–IM04.",
3705
+ schema: lazySchema(() => ({
3706
+ project_root: z.string().optional(),
3707
+ repo: z.string().optional(),
3708
+ })),
3709
+ handler: async (args) => {
3710
+ const opts = {};
3711
+ if (args.project_root != null)
3712
+ opts.project_root = args.project_root;
3713
+ if (args.repo != null)
3714
+ opts.repo = args.repo;
3715
+ return await astroImageAudit(opts);
3716
+ },
3717
+ },
3718
+ {
3719
+ name: "astro_svg_components",
3720
+ category: "analysis",
3721
+ searchHint: "astro svg component import legacy ?component native astro 5",
3722
+ description: "Detects *.svg?component imports, tracks per-file usage, flags legacy ?component on Astro 5+, surfaces PascalCase tags used without imports. Codes SV01–SV03.",
3723
+ schema: lazySchema(() => ({
3724
+ project_root: z.string().optional(),
3725
+ repo: z.string().optional(),
3726
+ })),
3727
+ handler: async (args) => {
3728
+ const opts = {};
3729
+ if (args.project_root != null)
3730
+ opts.project_root = args.project_root;
3731
+ if (args.repo != null)
3732
+ opts.repo = args.repo;
3733
+ return await astroSvgComponents(opts);
3734
+ },
3735
+ },
3452
3736
  // --- Hono framework tools (Task 23) ---
3453
3737
  {
3454
3738
  name: "trace_middleware_chain",
@@ -3701,13 +3985,14 @@ const TOOL_DEFINITIONS = [
3701
3985
  {
3702
3986
  name: "analyze_schema",
3703
3987
  category: "analysis",
3704
- searchHint: "SQL schema ERD entity relationship tables views columns foreign key database migration",
3705
- description: "Analyze SQL schema: tables, views, columns, foreign keys, relationships. Output as JSON or Mermaid ERD.",
3988
+ searchHint: "SQL schema ERD entity relationship tables views columns foreign key database migration MySQL Postgres SQLite dialect",
3989
+ description: "Analyze SQL schema: tables, views, columns, foreign keys, relationships. Auto-detects dialect (mysql/postgres/sqlite/mssql) from schema fingerprints. Output as JSON or Mermaid ERD.",
3706
3990
  schema: lazySchema(() => ({
3707
3991
  repo: z.string().optional().describe("Repository identifier (default: auto-detected from CWD)"),
3708
3992
  file_pattern: z.string().optional().describe("Filter SQL files by pattern (e.g. 'migrations/')"),
3709
3993
  output_format: z.enum(["json", "mermaid"]).optional().describe("Output format (default: json)"),
3710
3994
  include_columns: zBool().describe("Include column details in output (default: true)"),
3995
+ dialect: z.enum(["auto", "mysql", "postgres", "sqlite", "mssql", "unknown"]).optional().describe("Force dialect, or 'auto' to detect from ENGINE=InnoDB / SERIAL / AUTOINCREMENT etc. (default: auto)"),
3711
3996
  })),
3712
3997
  handler: async (args) => {
3713
3998
  const { analyzeSchema } = await import("./tools/sql-tools.js");
@@ -3718,9 +4003,11 @@ const TOOL_DEFINITIONS = [
3718
4003
  opts.output_format = args.output_format;
3719
4004
  if (args.include_columns != null)
3720
4005
  opts.include_columns = args.include_columns;
4006
+ if (args.dialect != null)
4007
+ opts.dialect = args.dialect;
3721
4008
  const result = await analyzeSchema(args.repo, opts);
3722
4009
  const parts = [];
3723
- parts.push(`Tables: ${result.tables.length} | Views: ${result.views.length} | Relationships: ${result.relationships.length}`);
4010
+ parts.push(`Tables: ${result.tables.length} | Views: ${result.views.length} | Relationships: ${result.relationships.length} | Dialect: ${result.detected_dialect}`);
3724
4011
  if (result.warnings.length > 0)
3725
4012
  parts.push(`Warnings: ${result.warnings.join("; ")}`);
3726
4013
  if (result.mermaid) {