@hivehub/rulebook 1.2.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 (379) hide show
  1. package/LICENSE +191 -0
  2. package/README.md +539 -0
  3. package/dist/agents/claude-code.d.ts +69 -0
  4. package/dist/agents/claude-code.d.ts.map +1 -0
  5. package/dist/agents/claude-code.js +180 -0
  6. package/dist/agents/claude-code.js.map +1 -0
  7. package/dist/agents/cursor-agent.d.ts +184 -0
  8. package/dist/agents/cursor-agent.d.ts.map +1 -0
  9. package/dist/agents/cursor-agent.js +299 -0
  10. package/dist/agents/cursor-agent.js.map +1 -0
  11. package/dist/agents/gemini-cli.d.ts +69 -0
  12. package/dist/agents/gemini-cli.d.ts.map +1 -0
  13. package/dist/agents/gemini-cli.js +180 -0
  14. package/dist/agents/gemini-cli.js.map +1 -0
  15. package/dist/cli/commands.d.ts +57 -0
  16. package/dist/cli/commands.d.ts.map +1 -0
  17. package/dist/cli/commands.js +1370 -0
  18. package/dist/cli/commands.js.map +1 -0
  19. package/dist/cli/docs-prompts.d.ts +3 -0
  20. package/dist/cli/docs-prompts.d.ts.map +1 -0
  21. package/dist/cli/docs-prompts.js +45 -0
  22. package/dist/cli/docs-prompts.js.map +1 -0
  23. package/dist/cli/prompts.d.ts +6 -0
  24. package/dist/cli/prompts.d.ts.map +1 -0
  25. package/dist/cli/prompts.js +376 -0
  26. package/dist/cli/prompts.js.map +1 -0
  27. package/dist/core/agent-manager.d.ts +89 -0
  28. package/dist/core/agent-manager.d.ts.map +1 -0
  29. package/dist/core/agent-manager.js +546 -0
  30. package/dist/core/agent-manager.js.map +1 -0
  31. package/dist/core/auto-fixer.d.ts +14 -0
  32. package/dist/core/auto-fixer.d.ts.map +1 -0
  33. package/dist/core/auto-fixer.js +207 -0
  34. package/dist/core/auto-fixer.js.map +1 -0
  35. package/dist/core/changelog-generator.d.ts +44 -0
  36. package/dist/core/changelog-generator.d.ts.map +1 -0
  37. package/dist/core/changelog-generator.js +222 -0
  38. package/dist/core/changelog-generator.js.map +1 -0
  39. package/dist/core/cli-bridge.d.ts +113 -0
  40. package/dist/core/cli-bridge.d.ts.map +1 -0
  41. package/dist/core/cli-bridge.js +1094 -0
  42. package/dist/core/cli-bridge.js.map +1 -0
  43. package/dist/core/config-manager.d.ts +65 -0
  44. package/dist/core/config-manager.d.ts.map +1 -0
  45. package/dist/core/config-manager.js +266 -0
  46. package/dist/core/config-manager.js.map +1 -0
  47. package/dist/core/coverage-checker.d.ts +14 -0
  48. package/dist/core/coverage-checker.d.ts.map +1 -0
  49. package/dist/core/coverage-checker.js +176 -0
  50. package/dist/core/coverage-checker.js.map +1 -0
  51. package/dist/core/custom-templates.d.ts +27 -0
  52. package/dist/core/custom-templates.d.ts.map +1 -0
  53. package/dist/core/custom-templates.js +122 -0
  54. package/dist/core/custom-templates.js.map +1 -0
  55. package/dist/core/dependency-checker.d.ts +21 -0
  56. package/dist/core/dependency-checker.d.ts.map +1 -0
  57. package/dist/core/dependency-checker.js +247 -0
  58. package/dist/core/dependency-checker.js.map +1 -0
  59. package/dist/core/detector.d.ts +3 -0
  60. package/dist/core/detector.d.ts.map +1 -0
  61. package/dist/core/detector.js +1443 -0
  62. package/dist/core/detector.js.map +1 -0
  63. package/dist/core/docs-generator.d.ts +9 -0
  64. package/dist/core/docs-generator.d.ts.map +1 -0
  65. package/dist/core/docs-generator.js +531 -0
  66. package/dist/core/docs-generator.js.map +1 -0
  67. package/dist/core/generator.d.ts +16 -0
  68. package/dist/core/generator.d.ts.map +1 -0
  69. package/dist/core/generator.js +561 -0
  70. package/dist/core/generator.js.map +1 -0
  71. package/dist/core/gitignore-generator.d.ts +13 -0
  72. package/dist/core/gitignore-generator.d.ts.map +1 -0
  73. package/dist/core/gitignore-generator.js +307 -0
  74. package/dist/core/gitignore-generator.js.map +1 -0
  75. package/dist/core/health-scorer.d.ts +22 -0
  76. package/dist/core/health-scorer.d.ts.map +1 -0
  77. package/dist/core/health-scorer.js +395 -0
  78. package/dist/core/health-scorer.js.map +1 -0
  79. package/dist/core/logger.d.ts +116 -0
  80. package/dist/core/logger.d.ts.map +1 -0
  81. package/dist/core/logger.js +289 -0
  82. package/dist/core/logger.js.map +1 -0
  83. package/dist/core/merger.d.ts +6 -0
  84. package/dist/core/merger.d.ts.map +1 -0
  85. package/dist/core/merger.js +131 -0
  86. package/dist/core/merger.js.map +1 -0
  87. package/dist/core/migrator.d.ts +19 -0
  88. package/dist/core/migrator.d.ts.map +1 -0
  89. package/dist/core/migrator.js +102 -0
  90. package/dist/core/migrator.js.map +1 -0
  91. package/dist/core/minimal-scaffolder.d.ts +8 -0
  92. package/dist/core/minimal-scaffolder.d.ts.map +1 -0
  93. package/dist/core/minimal-scaffolder.js +51 -0
  94. package/dist/core/minimal-scaffolder.js.map +1 -0
  95. package/dist/core/modern-console-new.d.ts +81 -0
  96. package/dist/core/modern-console-new.d.ts.map +1 -0
  97. package/dist/core/modern-console-new.js +340 -0
  98. package/dist/core/modern-console-new.js.map +1 -0
  99. package/dist/core/modern-console.d.ts +99 -0
  100. package/dist/core/modern-console.d.ts.map +1 -0
  101. package/dist/core/modern-console.js +568 -0
  102. package/dist/core/modern-console.js.map +1 -0
  103. package/dist/core/openspec-manager.d.ts +133 -0
  104. package/dist/core/openspec-manager.d.ts.map +1 -0
  105. package/dist/core/openspec-manager.js +605 -0
  106. package/dist/core/openspec-manager.js.map +1 -0
  107. package/dist/core/openspec-migrator.d.ts +27 -0
  108. package/dist/core/openspec-migrator.d.ts.map +1 -0
  109. package/dist/core/openspec-migrator.js +255 -0
  110. package/dist/core/openspec-migrator.js.map +1 -0
  111. package/dist/core/task-manager.d.ts +65 -0
  112. package/dist/core/task-manager.d.ts.map +1 -0
  113. package/dist/core/task-manager.js +318 -0
  114. package/dist/core/task-manager.js.map +1 -0
  115. package/dist/core/test-task-manager.d.ts +49 -0
  116. package/dist/core/test-task-manager.d.ts.map +1 -0
  117. package/dist/core/test-task-manager.js +121 -0
  118. package/dist/core/test-task-manager.js.map +1 -0
  119. package/dist/core/validator.d.ts +21 -0
  120. package/dist/core/validator.d.ts.map +1 -0
  121. package/dist/core/validator.js +177 -0
  122. package/dist/core/validator.js.map +1 -0
  123. package/dist/core/version-bumper.d.ts +19 -0
  124. package/dist/core/version-bumper.d.ts.map +1 -0
  125. package/dist/core/version-bumper.js +180 -0
  126. package/dist/core/version-bumper.js.map +1 -0
  127. package/dist/core/watcher.d.ts +9 -0
  128. package/dist/core/watcher.d.ts.map +1 -0
  129. package/dist/core/watcher.js +22 -0
  130. package/dist/core/watcher.js.map +1 -0
  131. package/dist/core/workflow-generator.d.ts +10 -0
  132. package/dist/core/workflow-generator.d.ts.map +1 -0
  133. package/dist/core/workflow-generator.js +279 -0
  134. package/dist/core/workflow-generator.js.map +1 -0
  135. package/dist/index.d.ts +3 -0
  136. package/dist/index.d.ts.map +1 -0
  137. package/dist/index.js +159 -0
  138. package/dist/index.js.map +1 -0
  139. package/dist/mcp/handlers/archive-task.d.ts +17 -0
  140. package/dist/mcp/handlers/archive-task.d.ts.map +1 -0
  141. package/dist/mcp/handlers/archive-task.js +36 -0
  142. package/dist/mcp/handlers/archive-task.js.map +1 -0
  143. package/dist/mcp/handlers/create-task.d.ts +17 -0
  144. package/dist/mcp/handlers/create-task.d.ts.map +1 -0
  145. package/dist/mcp/handlers/create-task.js +56 -0
  146. package/dist/mcp/handlers/create-task.js.map +1 -0
  147. package/dist/mcp/handlers/list-tasks.d.ts +22 -0
  148. package/dist/mcp/handlers/list-tasks.d.ts.map +1 -0
  149. package/dist/mcp/handlers/list-tasks.js +42 -0
  150. package/dist/mcp/handlers/list-tasks.js.map +1 -0
  151. package/dist/mcp/handlers/show-task.d.ts +25 -0
  152. package/dist/mcp/handlers/show-task.d.ts.map +1 -0
  153. package/dist/mcp/handlers/show-task.js +43 -0
  154. package/dist/mcp/handlers/show-task.js.map +1 -0
  155. package/dist/mcp/handlers/update-task.d.ts +17 -0
  156. package/dist/mcp/handlers/update-task.d.ts.map +1 -0
  157. package/dist/mcp/handlers/update-task.js +35 -0
  158. package/dist/mcp/handlers/update-task.js.map +1 -0
  159. package/dist/mcp/handlers/validate-task.d.ts +15 -0
  160. package/dist/mcp/handlers/validate-task.d.ts.map +1 -0
  161. package/dist/mcp/handlers/validate-task.js +27 -0
  162. package/dist/mcp/handlers/validate-task.js.map +1 -0
  163. package/dist/mcp/rulebook-config.d.ts +22 -0
  164. package/dist/mcp/rulebook-config.d.ts.map +1 -0
  165. package/dist/mcp/rulebook-config.js +65 -0
  166. package/dist/mcp/rulebook-config.js.map +1 -0
  167. package/dist/mcp/rulebook-server.d.ts +4 -0
  168. package/dist/mcp/rulebook-server.d.ts.map +1 -0
  169. package/dist/mcp/rulebook-server.js +246 -0
  170. package/dist/mcp/rulebook-server.js.map +1 -0
  171. package/dist/types.d.ts +190 -0
  172. package/dist/types.d.ts.map +1 -0
  173. package/dist/types.js +2 -0
  174. package/dist/types.js.map +1 -0
  175. package/dist/utils/file-system.d.ts +9 -0
  176. package/dist/utils/file-system.d.ts.map +1 -0
  177. package/dist/utils/file-system.js +51 -0
  178. package/dist/utils/file-system.js.map +1 -0
  179. package/dist/utils/git-hooks.d.ts +8 -0
  180. package/dist/utils/git-hooks.d.ts.map +1 -0
  181. package/dist/utils/git-hooks.js +440 -0
  182. package/dist/utils/git-hooks.js.map +1 -0
  183. package/dist/utils/rulesignore.d.ts +9 -0
  184. package/dist/utils/rulesignore.d.ts.map +1 -0
  185. package/dist/utils/rulesignore.js +42 -0
  186. package/dist/utils/rulesignore.js.map +1 -0
  187. package/package.json +106 -0
  188. package/templates/cli/AIDER.md +49 -0
  189. package/templates/cli/AMAZON_Q.md +25 -0
  190. package/templates/cli/AUGGIE.md +32 -0
  191. package/templates/cli/CLAUDE.md +32 -0
  192. package/templates/cli/CLAUDE_CODE.md +35 -0
  193. package/templates/cli/CLINE.md +32 -0
  194. package/templates/cli/CODEBUDDY.md +20 -0
  195. package/templates/cli/CODEIUM.md +20 -0
  196. package/templates/cli/CODEX.md +21 -0
  197. package/templates/cli/CONTINUE.md +34 -0
  198. package/templates/cli/CURSOR_CLI.md +28 -0
  199. package/templates/cli/FACTORY.md +18 -0
  200. package/templates/cli/GEMINI.md +35 -0
  201. package/templates/cli/KILOCODE.md +18 -0
  202. package/templates/cli/OPENCODE.md +18 -0
  203. package/templates/cli/_GENERIC_TEMPLATE.md +29 -0
  204. package/templates/commands/rulebook-task-apply.md +67 -0
  205. package/templates/commands/rulebook-task-archive.md +70 -0
  206. package/templates/commands/rulebook-task-create.md +93 -0
  207. package/templates/commands/rulebook-task-list.md +42 -0
  208. package/templates/commands/rulebook-task-show.md +52 -0
  209. package/templates/commands/rulebook-task-validate.md +53 -0
  210. package/templates/core/AGENT_AUTOMATION.md +184 -0
  211. package/templates/core/DAG.md +304 -0
  212. package/templates/core/DOCUMENTATION_RULES.md +37 -0
  213. package/templates/core/QUALITY_ENFORCEMENT.md +68 -0
  214. package/templates/core/RULEBOOK.md +1874 -0
  215. package/templates/frameworks/ANGULAR.md +36 -0
  216. package/templates/frameworks/DJANGO.md +83 -0
  217. package/templates/frameworks/ELECTRON.md +147 -0
  218. package/templates/frameworks/FLASK.md +38 -0
  219. package/templates/frameworks/FLUTTER.md +55 -0
  220. package/templates/frameworks/JQUERY.md +32 -0
  221. package/templates/frameworks/LARAVEL.md +38 -0
  222. package/templates/frameworks/NESTJS.md +43 -0
  223. package/templates/frameworks/NEXTJS.md +127 -0
  224. package/templates/frameworks/NUXT.md +40 -0
  225. package/templates/frameworks/RAILS.md +66 -0
  226. package/templates/frameworks/REACT.md +38 -0
  227. package/templates/frameworks/REACT_NATIVE.md +47 -0
  228. package/templates/frameworks/SPRING.md +39 -0
  229. package/templates/frameworks/SYMFONY.md +36 -0
  230. package/templates/frameworks/VUE.md +36 -0
  231. package/templates/frameworks/ZEND.md +35 -0
  232. package/templates/git/CI_CD_PATTERNS.md +661 -0
  233. package/templates/git/GITHUB_ACTIONS.md +728 -0
  234. package/templates/git/GITLAB_CI.md +730 -0
  235. package/templates/git/GIT_WORKFLOW.md +1157 -0
  236. package/templates/git/SECRETS_MANAGEMENT.md +585 -0
  237. package/templates/hooks/COMMIT_MSG.md +530 -0
  238. package/templates/hooks/POST_CHECKOUT.md +546 -0
  239. package/templates/hooks/PREPARE_COMMIT_MSG.md +619 -0
  240. package/templates/hooks/PRE_COMMIT.md +414 -0
  241. package/templates/hooks/PRE_PUSH.md +601 -0
  242. package/templates/hooks/csharp-pre-commit.sh +23 -0
  243. package/templates/hooks/csharp-pre-push.sh +23 -0
  244. package/templates/hooks/dart-pre-commit.sh +30 -0
  245. package/templates/hooks/dart-pre-push.sh +25 -0
  246. package/templates/hooks/elixir-pre-commit.sh +32 -0
  247. package/templates/hooks/elixir-pre-push.sh +31 -0
  248. package/templates/hooks/erlang-pre-commit.sh +30 -0
  249. package/templates/hooks/erlang-pre-push.sh +37 -0
  250. package/templates/hooks/go-pre-commit.sh +40 -0
  251. package/templates/hooks/go-pre-push.sh +31 -0
  252. package/templates/hooks/haskell-pre-commit.sh +41 -0
  253. package/templates/hooks/haskell-pre-push.sh +37 -0
  254. package/templates/hooks/java-pre-commit.sh +34 -0
  255. package/templates/hooks/java-pre-push.sh +24 -0
  256. package/templates/hooks/kotlin-pre-commit.sh +32 -0
  257. package/templates/hooks/kotlin-pre-push.sh +16 -0
  258. package/templates/hooks/php-pre-commit.sh +36 -0
  259. package/templates/hooks/php-pre-push.sh +26 -0
  260. package/templates/hooks/python-pre-commit.sh +51 -0
  261. package/templates/hooks/python-pre-push.sh +25 -0
  262. package/templates/hooks/ruby-pre-commit.sh +33 -0
  263. package/templates/hooks/ruby-pre-push.sh +32 -0
  264. package/templates/hooks/rust-pre-commit.sh +30 -0
  265. package/templates/hooks/rust-pre-push.sh +30 -0
  266. package/templates/hooks/scala-pre-commit.sh +32 -0
  267. package/templates/hooks/scala-pre-push.sh +24 -0
  268. package/templates/hooks/swift-pre-commit.sh +25 -0
  269. package/templates/hooks/swift-pre-push.sh +23 -0
  270. package/templates/hooks/typescript-pre-commit.sh +37 -0
  271. package/templates/hooks/typescript-pre-push.sh +36 -0
  272. package/templates/ides/COPILOT.md +37 -0
  273. package/templates/ides/CURSOR.md +43 -0
  274. package/templates/ides/JETBRAINS_AI.md +35 -0
  275. package/templates/ides/REPLIT.md +36 -0
  276. package/templates/ides/TABNINE.md +29 -0
  277. package/templates/ides/VSCODE.md +40 -0
  278. package/templates/ides/WINDSURF.md +36 -0
  279. package/templates/ides/ZED.md +32 -0
  280. package/templates/languages/ADA.md +58 -0
  281. package/templates/languages/C.md +333 -0
  282. package/templates/languages/CPP.md +743 -0
  283. package/templates/languages/CSHARP.md +417 -0
  284. package/templates/languages/DART.md +332 -0
  285. package/templates/languages/ELIXIR.md +454 -0
  286. package/templates/languages/ERLANG.md +361 -0
  287. package/templates/languages/GO.md +645 -0
  288. package/templates/languages/HASKELL.md +177 -0
  289. package/templates/languages/JAVA.md +607 -0
  290. package/templates/languages/JAVASCRIPT.md +631 -0
  291. package/templates/languages/JULIA.md +97 -0
  292. package/templates/languages/KOTLIN.md +511 -0
  293. package/templates/languages/LISP.md +100 -0
  294. package/templates/languages/LUA.md +74 -0
  295. package/templates/languages/OBJECTIVEC.md +90 -0
  296. package/templates/languages/PHP.md +416 -0
  297. package/templates/languages/PYTHON.md +682 -0
  298. package/templates/languages/R.md +350 -0
  299. package/templates/languages/RUBY.md +421 -0
  300. package/templates/languages/RUST.md +477 -0
  301. package/templates/languages/SAS.md +73 -0
  302. package/templates/languages/SCALA.md +348 -0
  303. package/templates/languages/SOLIDITY.md +580 -0
  304. package/templates/languages/SQL.md +137 -0
  305. package/templates/languages/SWIFT.md +466 -0
  306. package/templates/languages/TYPESCRIPT.md +591 -0
  307. package/templates/languages/ZIG.md +265 -0
  308. package/templates/modules/ATLASSIAN.md +255 -0
  309. package/templates/modules/CONTEXT7.md +54 -0
  310. package/templates/modules/FIGMA.md +267 -0
  311. package/templates/modules/GITHUB_MCP.md +64 -0
  312. package/templates/modules/GRAFANA.md +328 -0
  313. package/templates/modules/NOTION.md +247 -0
  314. package/templates/modules/PLAYWRIGHT.md +90 -0
  315. package/templates/modules/RULEBOOK_MCP.md +156 -0
  316. package/templates/modules/SERENA.md +337 -0
  317. package/templates/modules/SUPABASE.md +223 -0
  318. package/templates/modules/SYNAP.md +69 -0
  319. package/templates/modules/VECTORIZER.md +63 -0
  320. package/templates/services/AZURE_BLOB.md +184 -0
  321. package/templates/services/CASSANDRA.md +239 -0
  322. package/templates/services/DYNAMODB.md +308 -0
  323. package/templates/services/ELASTICSEARCH.md +347 -0
  324. package/templates/services/GCS.md +178 -0
  325. package/templates/services/INFLUXDB.md +265 -0
  326. package/templates/services/KAFKA.md +341 -0
  327. package/templates/services/MARIADB.md +183 -0
  328. package/templates/services/MEMCACHED.md +242 -0
  329. package/templates/services/MINIO.md +201 -0
  330. package/templates/services/MONGODB.md +268 -0
  331. package/templates/services/MYSQL.md +358 -0
  332. package/templates/services/NEO4J.md +247 -0
  333. package/templates/services/ORACLE.md +290 -0
  334. package/templates/services/POSTGRESQL.md +326 -0
  335. package/templates/services/RABBITMQ.md +286 -0
  336. package/templates/services/REDIS.md +292 -0
  337. package/templates/services/S3.md +298 -0
  338. package/templates/services/SQLITE.md +294 -0
  339. package/templates/services/SQLSERVER.md +294 -0
  340. package/templates/workflows/codespell.yml +31 -0
  341. package/templates/workflows/cpp-lint.yml +47 -0
  342. package/templates/workflows/cpp-publish.yml +119 -0
  343. package/templates/workflows/cpp-test.yml +77 -0
  344. package/templates/workflows/dotnet-lint.yml +29 -0
  345. package/templates/workflows/dotnet-publish.yml +40 -0
  346. package/templates/workflows/dotnet-test.yml +41 -0
  347. package/templates/workflows/elixir-lint.yml +45 -0
  348. package/templates/workflows/elixir-publish.yml +49 -0
  349. package/templates/workflows/elixir-test.yml +54 -0
  350. package/templates/workflows/erlang-lint.yml +47 -0
  351. package/templates/workflows/erlang-test.yml +62 -0
  352. package/templates/workflows/go-lint.yml +39 -0
  353. package/templates/workflows/go-publish.yml +95 -0
  354. package/templates/workflows/go-test.yml +59 -0
  355. package/templates/workflows/java-lint.yml +60 -0
  356. package/templates/workflows/java-publish.yml +120 -0
  357. package/templates/workflows/java-test.yml +85 -0
  358. package/templates/workflows/kotlin-lint.yml +34 -0
  359. package/templates/workflows/kotlin-publish.yml +56 -0
  360. package/templates/workflows/kotlin-test.yml +48 -0
  361. package/templates/workflows/php-lint.yml +39 -0
  362. package/templates/workflows/php-publish.yml +50 -0
  363. package/templates/workflows/php-test.yml +54 -0
  364. package/templates/workflows/python-lint.yml +47 -0
  365. package/templates/workflows/python-publish.yml +91 -0
  366. package/templates/workflows/python-test.yml +59 -0
  367. package/templates/workflows/rust-lint.yml +54 -0
  368. package/templates/workflows/rust-publish.yml +66 -0
  369. package/templates/workflows/rust-test.yml +75 -0
  370. package/templates/workflows/solidity-lint.yml +41 -0
  371. package/templates/workflows/solidity-test.yml +47 -0
  372. package/templates/workflows/swift-lint.yml +32 -0
  373. package/templates/workflows/swift-publish.yml +58 -0
  374. package/templates/workflows/swift-test.yml +44 -0
  375. package/templates/workflows/typescript-lint.yml +61 -0
  376. package/templates/workflows/typescript-publish.yml +60 -0
  377. package/templates/workflows/typescript-test.yml +73 -0
  378. package/templates/workflows/zig-lint.yml +27 -0
  379. package/templates/workflows/zig-test.yml +40 -0
@@ -0,0 +1,1443 @@
1
+ import path from 'path';
2
+ import { fileExists, findFiles, readFile, readJsonFile } from '../utils/file-system.js';
3
+ export async function detectProject(cwd = process.cwd()) {
4
+ const languages = await detectLanguages(cwd);
5
+ const modules = await detectModules(cwd);
6
+ const frameworks = await detectFrameworks(cwd, languages);
7
+ const services = await detectServices(cwd);
8
+ const existingAgents = await detectExistingAgents(cwd);
9
+ const gitHooks = await detectGitHooks(cwd);
10
+ return {
11
+ languages,
12
+ modules,
13
+ frameworks,
14
+ services,
15
+ existingAgents,
16
+ gitHooks,
17
+ };
18
+ }
19
+ async function detectLanguages(cwd) {
20
+ const detections = [];
21
+ // Detect Rust
22
+ const cargoToml = path.join(cwd, 'Cargo.toml');
23
+ if (await fileExists(cargoToml)) {
24
+ const rsFiles = await findFiles('**/*.rs', cwd);
25
+ detections.push({
26
+ language: 'rust',
27
+ confidence: rsFiles.length > 0 ? 1.0 : 0.8,
28
+ indicators: ['Cargo.toml', `${rsFiles.length} .rs files`],
29
+ });
30
+ }
31
+ // Detect TypeScript
32
+ const packageJson = path.join(cwd, 'package.json');
33
+ const tsConfig = path.join(cwd, 'tsconfig.json');
34
+ if ((await fileExists(packageJson)) || (await fileExists(tsConfig))) {
35
+ const tsFiles = await findFiles('**/*.ts', cwd);
36
+ detections.push({
37
+ language: 'typescript',
38
+ confidence: tsFiles.length > 0 ? 1.0 : 0.7,
39
+ indicators: [
40
+ (await fileExists(packageJson)) ? 'package.json' : '',
41
+ (await fileExists(tsConfig)) ? 'tsconfig.json' : '',
42
+ `${tsFiles.length} .ts files`,
43
+ ].filter(Boolean),
44
+ });
45
+ }
46
+ // Detect Python
47
+ const pyprojectToml = path.join(cwd, 'pyproject.toml');
48
+ const requirementsTxt = path.join(cwd, 'requirements.txt');
49
+ const setupPy = path.join(cwd, 'setup.py');
50
+ if ((await fileExists(pyprojectToml)) ||
51
+ (await fileExists(requirementsTxt)) ||
52
+ (await fileExists(setupPy))) {
53
+ const pyFiles = await findFiles('**/*.py', cwd);
54
+ detections.push({
55
+ language: 'python',
56
+ confidence: pyFiles.length > 0 ? 1.0 : 0.7,
57
+ indicators: [
58
+ (await fileExists(pyprojectToml)) ? 'pyproject.toml' : '',
59
+ (await fileExists(requirementsTxt)) ? 'requirements.txt' : '',
60
+ (await fileExists(setupPy)) ? 'setup.py' : '',
61
+ `${pyFiles.length} .py files`,
62
+ ].filter(Boolean),
63
+ });
64
+ }
65
+ // Detect Go
66
+ const goMod = path.join(cwd, 'go.mod');
67
+ if (await fileExists(goMod)) {
68
+ const goFiles = await findFiles('**/*.go', cwd);
69
+ detections.push({
70
+ language: 'go',
71
+ confidence: goFiles.length > 0 ? 1.0 : 0.8,
72
+ indicators: ['go.mod', `${goFiles.length} .go files`],
73
+ });
74
+ }
75
+ // Detect Java
76
+ const pomXml = path.join(cwd, 'pom.xml');
77
+ const buildGradle = path.join(cwd, 'build.gradle');
78
+ const buildGradleKts = path.join(cwd, 'build.gradle.kts');
79
+ if ((await fileExists(pomXml)) ||
80
+ (await fileExists(buildGradle)) ||
81
+ (await fileExists(buildGradleKts))) {
82
+ const javaFiles = await findFiles('**/*.java', cwd);
83
+ detections.push({
84
+ language: 'java',
85
+ confidence: javaFiles.length > 0 ? 1.0 : 0.7,
86
+ indicators: [
87
+ (await fileExists(pomXml)) ? 'pom.xml' : '',
88
+ (await fileExists(buildGradle)) ? 'build.gradle' : '',
89
+ (await fileExists(buildGradleKts)) ? 'build.gradle.kts' : '',
90
+ `${javaFiles.length} .java files`,
91
+ ].filter(Boolean),
92
+ });
93
+ }
94
+ // Detect C/C++
95
+ const cmakeLists = path.join(cwd, 'CMakeLists.txt');
96
+ const makeFile = path.join(cwd, 'Makefile');
97
+ if ((await fileExists(cmakeLists)) || (await fileExists(makeFile))) {
98
+ const cppFiles = await findFiles('**/*.{cpp,hpp,cc,h,c}', cwd);
99
+ detections.push({
100
+ language: 'cpp',
101
+ confidence: cppFiles.length > 0 ? 1.0 : 0.8,
102
+ indicators: [
103
+ (await fileExists(cmakeLists)) ? 'CMakeLists.txt' : '',
104
+ (await fileExists(makeFile)) ? 'Makefile' : '',
105
+ `${cppFiles.length} C/C++ files`,
106
+ ].filter(Boolean),
107
+ });
108
+ }
109
+ // Detect Solidity
110
+ const hardhatConfig = path.join(cwd, 'hardhat.config.js');
111
+ const foundryToml = path.join(cwd, 'foundry.toml');
112
+ if ((await fileExists(hardhatConfig)) || (await fileExists(foundryToml))) {
113
+ const solFiles = await findFiles('**/*.sol', cwd);
114
+ detections.push({
115
+ language: 'solidity',
116
+ confidence: solFiles.length > 0 ? 1.0 : 0.8,
117
+ indicators: [
118
+ (await fileExists(hardhatConfig)) ? 'hardhat.config.js' : '',
119
+ (await fileExists(foundryToml)) ? 'foundry.toml' : '',
120
+ `${solFiles.length} .sol files`,
121
+ ].filter(Boolean),
122
+ });
123
+ }
124
+ // Detect Zig
125
+ const buildZig = path.join(cwd, 'build.zig');
126
+ if (await fileExists(buildZig)) {
127
+ const zigFiles = await findFiles('**/*.zig', cwd);
128
+ detections.push({
129
+ language: 'zig',
130
+ confidence: zigFiles.length > 0 ? 1.0 : 0.9,
131
+ indicators: ['build.zig', `${zigFiles.length} .zig files`],
132
+ });
133
+ }
134
+ // Detect Erlang
135
+ const rebarConfig = path.join(cwd, 'rebar.config');
136
+ if (await fileExists(rebarConfig)) {
137
+ const erlFiles = await findFiles('**/*.erl', cwd);
138
+ detections.push({
139
+ language: 'erlang',
140
+ confidence: erlFiles.length > 0 ? 1.0 : 0.8,
141
+ indicators: ['rebar.config', `${erlFiles.length} .erl files`],
142
+ });
143
+ }
144
+ // Detect JavaScript (pure, not TypeScript)
145
+ if (await fileExists(packageJson)) {
146
+ const jsFiles = await findFiles('**/*.js', cwd);
147
+ const hasTS = detections.some((d) => d.language === 'typescript');
148
+ if (!hasTS && jsFiles.length > 0) {
149
+ const pkg = await readJsonFile(packageJson);
150
+ detections.push({
151
+ language: 'javascript',
152
+ confidence: 0.9,
153
+ indicators: [
154
+ 'package.json',
155
+ `${jsFiles.length} .js files`,
156
+ pkg?.type === 'module' ? 'ESM' : '',
157
+ ].filter(Boolean),
158
+ });
159
+ }
160
+ }
161
+ // Detect Dart
162
+ const pubspecYaml = path.join(cwd, 'pubspec.yaml');
163
+ if (await fileExists(pubspecYaml)) {
164
+ const dartFiles = await findFiles('**/*.dart', cwd);
165
+ detections.push({
166
+ language: 'dart',
167
+ confidence: dartFiles.length > 0 ? 1.0 : 0.8,
168
+ indicators: ['pubspec.yaml', `${dartFiles.length} .dart files`],
169
+ });
170
+ }
171
+ // Detect Ruby
172
+ const gemfile = path.join(cwd, 'Gemfile');
173
+ const gemspec = await findFiles('**/*.gemspec', cwd);
174
+ if ((await fileExists(gemfile)) || gemspec.length > 0) {
175
+ const rbFiles = await findFiles('**/*.rb', cwd);
176
+ detections.push({
177
+ language: 'ruby',
178
+ confidence: rbFiles.length > 0 ? 1.0 : 0.7,
179
+ indicators: [
180
+ (await fileExists(gemfile)) ? 'Gemfile' : '',
181
+ gemspec.length > 0 ? `${gemspec.length} .gemspec` : '',
182
+ `${rbFiles.length} .rb files`,
183
+ ].filter(Boolean),
184
+ });
185
+ }
186
+ // Detect Scala
187
+ const buildSbt = path.join(cwd, 'build.sbt');
188
+ if (await fileExists(buildSbt)) {
189
+ const scalaFiles = await findFiles('**/*.scala', cwd);
190
+ detections.push({
191
+ language: 'scala',
192
+ confidence: scalaFiles.length > 0 ? 1.0 : 0.8,
193
+ indicators: ['build.sbt', `${scalaFiles.length} .scala files`],
194
+ });
195
+ }
196
+ // Detect R
197
+ const descriptionFile = path.join(cwd, 'DESCRIPTION');
198
+ if (await fileExists(descriptionFile)) {
199
+ const rFiles = await findFiles('**/*.R', cwd);
200
+ detections.push({
201
+ language: 'r',
202
+ confidence: rFiles.length > 0 ? 1.0 : 0.8,
203
+ indicators: ['DESCRIPTION', `${rFiles.length} .R files`],
204
+ });
205
+ }
206
+ // Detect Haskell
207
+ const stackYaml = path.join(cwd, 'stack.yaml');
208
+ const cabalFiles = await findFiles('**/*.cabal', cwd);
209
+ if ((await fileExists(stackYaml)) || cabalFiles.length > 0) {
210
+ const hsFiles = await findFiles('**/*.hs', cwd);
211
+ detections.push({
212
+ language: 'haskell',
213
+ confidence: hsFiles.length > 0 ? 1.0 : 0.8,
214
+ indicators: [
215
+ (await fileExists(stackYaml)) ? 'stack.yaml' : '',
216
+ cabalFiles.length > 0 ? `${cabalFiles.length} .cabal` : '',
217
+ `${hsFiles.length} .hs files`,
218
+ ].filter(Boolean),
219
+ });
220
+ }
221
+ // Detect Julia
222
+ const projectToml = path.join(cwd, 'Project.toml');
223
+ if (await fileExists(projectToml)) {
224
+ const jlFiles = await findFiles('**/*.jl', cwd);
225
+ detections.push({
226
+ language: 'julia',
227
+ confidence: jlFiles.length > 0 ? 1.0 : 0.8,
228
+ indicators: ['Project.toml', `${jlFiles.length} .jl files`],
229
+ });
230
+ }
231
+ // Detect Lua
232
+ const luaFiles = await findFiles('**/*.lua', cwd);
233
+ if (luaFiles.length > 5) {
234
+ detections.push({
235
+ language: 'lua',
236
+ confidence: 0.9,
237
+ indicators: [`${luaFiles.length} .lua files`],
238
+ });
239
+ }
240
+ // Sort by confidence
241
+ return detections.sort((a, b) => b.confidence - a.confidence);
242
+ }
243
+ async function detectFrameworks(cwd, languages) {
244
+ const packageJsonPath = path.join(cwd, 'package.json');
245
+ let packageJson = null;
246
+ if (await fileExists(packageJsonPath)) {
247
+ try {
248
+ packageJson = await readJsonFile(packageJsonPath);
249
+ }
250
+ catch {
251
+ packageJson = null;
252
+ }
253
+ }
254
+ const composerJsonPath = path.join(cwd, 'composer.json');
255
+ let composerJson = null;
256
+ if (await fileExists(composerJsonPath)) {
257
+ try {
258
+ composerJson = await readJsonFile(composerJsonPath);
259
+ }
260
+ catch {
261
+ composerJson = null;
262
+ }
263
+ }
264
+ const languageSet = new Set(languages.map((l) => l.language));
265
+ const npmDeps = {
266
+ ...(packageJson && typeof packageJson === 'object'
267
+ ? (packageJson.dependencies ?? {})
268
+ : {}),
269
+ ...(packageJson && typeof packageJson === 'object'
270
+ ? (packageJson.devDependencies ?? {})
271
+ : {}),
272
+ };
273
+ const phpDeps = {
274
+ ...(composerJson && typeof composerJson === 'object'
275
+ ? (composerJson.require ?? {})
276
+ : {}),
277
+ ...(composerJson && typeof composerJson === 'object'
278
+ ? (composerJson['require-dev'] ?? {})
279
+ : {}),
280
+ };
281
+ const frameworkDefinitions = [
282
+ {
283
+ id: 'nestjs',
284
+ label: 'NestJS',
285
+ languages: ['typescript', 'javascript'],
286
+ detect: async () => {
287
+ if (npmDeps['@nestjs/core'] || npmDeps['@nestjs/common']) {
288
+ return {
289
+ detected: true,
290
+ confidence: 0.95,
291
+ indicators: ['package.json:@nestjs/core'],
292
+ };
293
+ }
294
+ const nestCli = path.join(cwd, 'nest-cli.json');
295
+ if (await fileExists(nestCli)) {
296
+ return {
297
+ detected: true,
298
+ confidence: 0.9,
299
+ indicators: ['nest-cli.json'],
300
+ };
301
+ }
302
+ return { detected: false, confidence: 0, indicators: [] };
303
+ },
304
+ },
305
+ {
306
+ id: 'spring',
307
+ label: 'Spring Boot',
308
+ languages: ['java', 'kotlin'],
309
+ detect: async () => {
310
+ const pomPath = path.join(cwd, 'pom.xml');
311
+ if (await fileExists(pomPath)) {
312
+ const content = await readFile(pomPath);
313
+ if (content.includes('spring-boot-starter')) {
314
+ return {
315
+ detected: true,
316
+ confidence: 0.95,
317
+ indicators: ['pom.xml:spring-boot-starter'],
318
+ };
319
+ }
320
+ }
321
+ const gradlePath = await findFirstExisting([
322
+ path.join(cwd, 'build.gradle'),
323
+ path.join(cwd, 'build.gradle.kts'),
324
+ ]);
325
+ if (gradlePath) {
326
+ const content = await readFile(gradlePath);
327
+ if (content.includes('spring-boot-starter')) {
328
+ return {
329
+ detected: true,
330
+ confidence: 0.9,
331
+ indicators: [`${path.basename(gradlePath)}:spring-boot-starter`],
332
+ };
333
+ }
334
+ }
335
+ return { detected: false, confidence: 0, indicators: [] };
336
+ },
337
+ },
338
+ {
339
+ id: 'laravel',
340
+ label: 'Laravel',
341
+ languages: ['php'],
342
+ detect: async () => {
343
+ if (phpDeps['laravel/framework']) {
344
+ return {
345
+ detected: true,
346
+ confidence: 0.95,
347
+ indicators: ['composer.json:laravel/framework'],
348
+ };
349
+ }
350
+ const artisanPath = path.join(cwd, 'artisan');
351
+ if (await fileExists(artisanPath)) {
352
+ return {
353
+ detected: true,
354
+ confidence: 0.9,
355
+ indicators: ['artisan'],
356
+ };
357
+ }
358
+ return { detected: false, confidence: 0, indicators: [] };
359
+ },
360
+ },
361
+ {
362
+ id: 'angular',
363
+ label: 'Angular',
364
+ languages: ['typescript', 'javascript'],
365
+ detect: async () => {
366
+ if (npmDeps['@angular/core']) {
367
+ return {
368
+ detected: true,
369
+ confidence: 0.95,
370
+ indicators: ['package.json:@angular/core'],
371
+ };
372
+ }
373
+ const angularConfig = path.join(cwd, 'angular.json');
374
+ if (await fileExists(angularConfig)) {
375
+ return {
376
+ detected: true,
377
+ confidence: 0.9,
378
+ indicators: ['angular.json'],
379
+ };
380
+ }
381
+ return { detected: false, confidence: 0, indicators: [] };
382
+ },
383
+ },
384
+ {
385
+ id: 'react',
386
+ label: 'React',
387
+ languages: ['typescript', 'javascript'],
388
+ detect: async () => {
389
+ if (npmDeps.react && (npmDeps['react-dom'] || npmDeps['react-native'])) {
390
+ const indicator = npmDeps['react-dom'] ? 'react-dom' : 'react-native';
391
+ return {
392
+ detected: true,
393
+ confidence: 0.9,
394
+ indicators: [`package.json:react`, `package.json:${indicator}`],
395
+ };
396
+ }
397
+ return { detected: false, confidence: 0, indicators: [] };
398
+ },
399
+ },
400
+ {
401
+ id: 'vue',
402
+ label: 'Vue.js',
403
+ languages: ['typescript', 'javascript'],
404
+ detect: async () => {
405
+ if (npmDeps.vue) {
406
+ return {
407
+ detected: true,
408
+ confidence: 0.9,
409
+ indicators: ['package.json:vue'],
410
+ };
411
+ }
412
+ const vueConfig = await findFirstExisting([
413
+ path.join(cwd, 'vite.config.ts'),
414
+ path.join(cwd, 'vite.config.js'),
415
+ ]);
416
+ if (vueConfig) {
417
+ const content = await readFile(vueConfig);
418
+ if (content.includes('@vitejs/plugin-vue') || content.includes('vue()')) {
419
+ return {
420
+ detected: true,
421
+ confidence: 0.8,
422
+ indicators: [path.basename(vueConfig)],
423
+ };
424
+ }
425
+ }
426
+ return { detected: false, confidence: 0, indicators: [] };
427
+ },
428
+ },
429
+ {
430
+ id: 'nuxt',
431
+ label: 'Nuxt',
432
+ languages: ['typescript', 'javascript'],
433
+ detect: async () => {
434
+ if (npmDeps.nuxt) {
435
+ return {
436
+ detected: true,
437
+ confidence: 0.9,
438
+ indicators: ['package.json:nuxt'],
439
+ };
440
+ }
441
+ const nuxtConfig = await findFiles('nuxt.config.*', cwd);
442
+ if (nuxtConfig.length > 0) {
443
+ return {
444
+ detected: true,
445
+ confidence: 0.85,
446
+ indicators: [path.basename(nuxtConfig[0])],
447
+ };
448
+ }
449
+ return { detected: false, confidence: 0, indicators: [] };
450
+ },
451
+ },
452
+ {
453
+ id: 'django',
454
+ label: 'Django',
455
+ languages: ['python'],
456
+ detect: async () => {
457
+ const requirementsPath = path.join(cwd, 'requirements.txt');
458
+ if (await fileExists(requirementsPath)) {
459
+ const content = await readFile(requirementsPath);
460
+ if (content.includes('Django')) {
461
+ return {
462
+ detected: true,
463
+ confidence: 0.95,
464
+ indicators: ['requirements.txt:Django'],
465
+ };
466
+ }
467
+ }
468
+ const managePy = path.join(cwd, 'manage.py');
469
+ if (await fileExists(managePy)) {
470
+ const content = await readFile(managePy);
471
+ if (content.includes('django')) {
472
+ return {
473
+ detected: true,
474
+ confidence: 0.9,
475
+ indicators: ['manage.py'],
476
+ };
477
+ }
478
+ }
479
+ return { detected: false, confidence: 0, indicators: [] };
480
+ },
481
+ },
482
+ {
483
+ id: 'flask',
484
+ label: 'Flask',
485
+ languages: ['python'],
486
+ detect: async () => {
487
+ const requirementsPath = path.join(cwd, 'requirements.txt');
488
+ if (await fileExists(requirementsPath)) {
489
+ const content = await readFile(requirementsPath);
490
+ if (content.includes('Flask')) {
491
+ return {
492
+ detected: true,
493
+ confidence: 0.95,
494
+ indicators: ['requirements.txt:Flask'],
495
+ };
496
+ }
497
+ }
498
+ return { detected: false, confidence: 0, indicators: [] };
499
+ },
500
+ },
501
+ {
502
+ id: 'rails',
503
+ label: 'Ruby on Rails',
504
+ languages: ['ruby'],
505
+ detect: async () => {
506
+ const gemfilePath = path.join(cwd, 'Gemfile');
507
+ if (await fileExists(gemfilePath)) {
508
+ const content = await readFile(gemfilePath);
509
+ if (content.includes('rails')) {
510
+ return {
511
+ detected: true,
512
+ confidence: 0.95,
513
+ indicators: ['Gemfile:rails'],
514
+ };
515
+ }
516
+ }
517
+ const railsPath = path.join(cwd, 'bin', 'rails');
518
+ if (await fileExists(railsPath)) {
519
+ return {
520
+ detected: true,
521
+ confidence: 0.9,
522
+ indicators: ['bin/rails'],
523
+ };
524
+ }
525
+ return { detected: false, confidence: 0, indicators: [] };
526
+ },
527
+ },
528
+ {
529
+ id: 'symfony',
530
+ label: 'Symfony',
531
+ languages: ['php'],
532
+ detect: async () => {
533
+ if (phpDeps['symfony/framework-bundle']) {
534
+ return {
535
+ detected: true,
536
+ confidence: 0.95,
537
+ indicators: ['composer.json:symfony/framework-bundle'],
538
+ };
539
+ }
540
+ const symfonyConfig = path.join(cwd, 'symfony.lock');
541
+ if (await fileExists(symfonyConfig)) {
542
+ return {
543
+ detected: true,
544
+ confidence: 0.9,
545
+ indicators: ['symfony.lock'],
546
+ };
547
+ }
548
+ return { detected: false, confidence: 0, indicators: [] };
549
+ },
550
+ },
551
+ {
552
+ id: 'zend',
553
+ label: 'Zend Framework',
554
+ languages: ['php'],
555
+ detect: async () => {
556
+ if (phpDeps['zendframework/zendframework'] || phpDeps['laminas/laminas-mvc']) {
557
+ return {
558
+ detected: true,
559
+ confidence: 0.95,
560
+ indicators: ['composer.json:zendframework or laminas'],
561
+ };
562
+ }
563
+ return { detected: false, confidence: 0, indicators: [] };
564
+ },
565
+ },
566
+ {
567
+ id: 'jquery',
568
+ label: 'jQuery',
569
+ languages: ['javascript', 'typescript'],
570
+ detect: async () => {
571
+ if (npmDeps['jquery']) {
572
+ return {
573
+ detected: true,
574
+ confidence: 0.95,
575
+ indicators: ['package.json:jquery'],
576
+ };
577
+ }
578
+ // Check for jQuery in HTML files
579
+ const indexHtml = path.join(cwd, 'index.html');
580
+ if (await fileExists(indexHtml)) {
581
+ const content = await readFile(indexHtml);
582
+ if (content.includes('jquery') || content.includes('jQuery')) {
583
+ return {
584
+ detected: true,
585
+ confidence: 0.8,
586
+ indicators: ['index.html:jquery'],
587
+ };
588
+ }
589
+ }
590
+ return { detected: false, confidence: 0, indicators: [] };
591
+ },
592
+ },
593
+ {
594
+ id: 'reactnative',
595
+ label: 'React Native',
596
+ languages: ['javascript', 'typescript'],
597
+ detect: async () => {
598
+ if (npmDeps['react-native']) {
599
+ return {
600
+ detected: true,
601
+ confidence: 0.95,
602
+ indicators: ['package.json:react-native'],
603
+ };
604
+ }
605
+ const appJson = path.join(cwd, 'app.json');
606
+ if (await fileExists(appJson)) {
607
+ const content = await readFile(appJson);
608
+ if (content.includes('react-native') || content.includes('expo')) {
609
+ return {
610
+ detected: true,
611
+ confidence: 0.9,
612
+ indicators: ['app.json'],
613
+ };
614
+ }
615
+ }
616
+ return { detected: false, confidence: 0, indicators: [] };
617
+ },
618
+ },
619
+ {
620
+ id: 'flutter',
621
+ label: 'Flutter',
622
+ languages: ['dart'],
623
+ detect: async () => {
624
+ const pubspecPath = path.join(cwd, 'pubspec.yaml');
625
+ if (await fileExists(pubspecPath)) {
626
+ const content = await readFile(pubspecPath);
627
+ if (content.includes('flutter:')) {
628
+ return {
629
+ detected: true,
630
+ confidence: 0.95,
631
+ indicators: ['pubspec.yaml:flutter'],
632
+ };
633
+ }
634
+ }
635
+ return { detected: false, confidence: 0, indicators: [] };
636
+ },
637
+ },
638
+ {
639
+ id: 'nextjs',
640
+ label: 'Next.js',
641
+ languages: ['typescript', 'javascript'],
642
+ detect: async () => {
643
+ if (npmDeps['next']) {
644
+ return {
645
+ detected: true,
646
+ confidence: 0.95,
647
+ indicators: ['package.json:next'],
648
+ };
649
+ }
650
+ const nextConfig = await findFirstExisting([
651
+ path.join(cwd, 'next.config.js'),
652
+ path.join(cwd, 'next.config.mjs'),
653
+ path.join(cwd, 'next.config.ts'),
654
+ ]);
655
+ if (nextConfig) {
656
+ return {
657
+ detected: true,
658
+ confidence: 0.9,
659
+ indicators: [path.basename(nextConfig)],
660
+ };
661
+ }
662
+ return { detected: false, confidence: 0, indicators: [] };
663
+ },
664
+ },
665
+ {
666
+ id: 'electron',
667
+ label: 'Electron',
668
+ languages: ['typescript', 'javascript'],
669
+ detect: async () => {
670
+ if (npmDeps['electron']) {
671
+ return {
672
+ detected: true,
673
+ confidence: 0.95,
674
+ indicators: ['package.json:electron'],
675
+ };
676
+ }
677
+ // Check for electron-builder or electron-forge
678
+ if (npmDeps['electron-builder'] || npmDeps['@electron-forge/cli']) {
679
+ return {
680
+ detected: true,
681
+ confidence: 0.9,
682
+ indicators: ['package.json:electron-builder or electron-forge'],
683
+ };
684
+ }
685
+ return { detected: false, confidence: 0, indicators: [] };
686
+ },
687
+ },
688
+ ];
689
+ const detections = [];
690
+ for (const definition of frameworkDefinitions) {
691
+ const match = await definition.detect();
692
+ const availableLanguages = definition.languages.filter((lang) => languageSet.has(lang));
693
+ const languagesForFramework = availableLanguages.length > 0 ? availableLanguages : definition.languages;
694
+ detections.push({
695
+ framework: definition.id,
696
+ detected: match.detected,
697
+ languages: languagesForFramework,
698
+ confidence: match.confidence,
699
+ indicators: match.indicators,
700
+ });
701
+ }
702
+ return detections.sort((a, b) => b.confidence - a.confidence);
703
+ }
704
+ async function detectModules(cwd) {
705
+ const modules = [];
706
+ // Check for MCP configuration files
707
+ const mcpConfigPaths = [
708
+ path.join(cwd, 'mcp.json'),
709
+ path.join(cwd, 'mcp-config.json'),
710
+ path.join(cwd, '.cursor', 'mcp.json'),
711
+ ];
712
+ for (const mcpPath of mcpConfigPaths) {
713
+ if (await fileExists(mcpPath)) {
714
+ try {
715
+ const config = await readJsonFile(mcpPath);
716
+ if (config) {
717
+ // Check for Vectorizer
718
+ if (config.mcpServers?.vectorizer || config.servers?.vectorizer) {
719
+ modules.push({
720
+ module: 'vectorizer',
721
+ detected: true,
722
+ source: mcpPath,
723
+ });
724
+ }
725
+ // Check for Synap
726
+ if (config.mcpServers?.synap || config.servers?.synap) {
727
+ modules.push({
728
+ module: 'synap',
729
+ detected: true,
730
+ source: mcpPath,
731
+ });
732
+ }
733
+ // Check for Context7
734
+ if (config.mcpServers?.context7 || config.servers?.context7) {
735
+ modules.push({
736
+ module: 'context7',
737
+ detected: true,
738
+ source: mcpPath,
739
+ });
740
+ }
741
+ // Check for GitHub MCP Server
742
+ if (config.mcpServers?.github || config.servers?.github) {
743
+ modules.push({
744
+ module: 'github',
745
+ detected: true,
746
+ source: mcpPath,
747
+ });
748
+ }
749
+ // Check for Playwright MCP Server
750
+ if (config.mcpServers?.playwright || config.servers?.playwright) {
751
+ modules.push({
752
+ module: 'playwright',
753
+ detected: true,
754
+ source: mcpPath,
755
+ });
756
+ }
757
+ // Check for Rulebook MCP Server
758
+ if (config.mcpServers?.rulebook || config.servers?.rulebook) {
759
+ modules.push({
760
+ module: 'rulebook_mcp',
761
+ detected: true,
762
+ source: mcpPath,
763
+ });
764
+ }
765
+ }
766
+ }
767
+ catch {
768
+ // Ignore JSON parse errors
769
+ }
770
+ }
771
+ }
772
+ // Add undetected modules
773
+ const detectedModules = new Set(modules.map((m) => m.module));
774
+ const allModules = ['vectorizer', 'synap', 'context7', 'github', 'playwright', 'rulebook_mcp'];
775
+ for (const module of allModules) {
776
+ if (!detectedModules.has(module)) {
777
+ modules.push({
778
+ module,
779
+ detected: false,
780
+ });
781
+ }
782
+ }
783
+ return modules;
784
+ }
785
+ async function detectExistingAgents(cwd) {
786
+ const agentsPath = path.join(cwd, 'AGENTS.md');
787
+ if (!(await fileExists(agentsPath))) {
788
+ return null;
789
+ }
790
+ const content = await readFile(agentsPath);
791
+ const blocks = parseAgentBlocks(content);
792
+ return {
793
+ exists: true,
794
+ path: agentsPath,
795
+ content,
796
+ blocks,
797
+ };
798
+ }
799
+ function parseAgentBlocks(content) {
800
+ const blocks = [];
801
+ const lines = content.split('\n');
802
+ let currentBlock = null;
803
+ for (let i = 0; i < lines.length; i++) {
804
+ const line = lines[i];
805
+ const startMatch = line.match(/<!--\s*([A-Z_]+):START\s*-->/);
806
+ const endMatch = line.match(/<!--\s*([A-Z_]+):END\s*-->/);
807
+ if (startMatch) {
808
+ currentBlock = {
809
+ name: startMatch[1],
810
+ startLine: i,
811
+ content: [line],
812
+ };
813
+ }
814
+ else if (endMatch && currentBlock) {
815
+ currentBlock.content.push(line);
816
+ blocks.push({
817
+ name: currentBlock.name,
818
+ startLine: currentBlock.startLine,
819
+ endLine: i,
820
+ content: currentBlock.content.join('\n'),
821
+ });
822
+ currentBlock = null;
823
+ }
824
+ else if (currentBlock) {
825
+ currentBlock.content.push(line);
826
+ }
827
+ }
828
+ return blocks;
829
+ }
830
+ async function detectGitHooks(cwd) {
831
+ const preCommitPath = path.join(cwd, '.git', 'hooks', 'pre-commit');
832
+ const prePushPath = path.join(cwd, '.git', 'hooks', 'pre-push');
833
+ return {
834
+ preCommitExists: await fileExists(preCommitPath),
835
+ prePushExists: await fileExists(prePushPath),
836
+ };
837
+ }
838
+ async function findFirstExisting(pathsToCheck) {
839
+ for (const filePath of pathsToCheck) {
840
+ if (await fileExists(filePath)) {
841
+ return filePath;
842
+ }
843
+ }
844
+ return null;
845
+ }
846
+ async function detectServices(cwd) {
847
+ const services = [];
848
+ const packageJson = path.join(cwd, 'package.json');
849
+ const envFile = path.join(cwd, '.env');
850
+ const dockerCompose = path.join(cwd, 'docker-compose.yml');
851
+ const dockerComposeYaml = path.join(cwd, 'docker-compose.yaml');
852
+ // Check package.json for database drivers
853
+ if (await fileExists(packageJson)) {
854
+ try {
855
+ const pkg = await readJsonFile(packageJson);
856
+ const allDeps = { ...(pkg?.dependencies || {}), ...(pkg?.devDependencies || {}) };
857
+ // PostgreSQL
858
+ if (allDeps['pg'] || allDeps['postgres'] || allDeps['@prisma/client']) {
859
+ services.push({
860
+ service: 'postgresql',
861
+ detected: true,
862
+ confidence: 0.9,
863
+ indicators: ['pg', 'postgres', '@prisma/client'].filter((dep) => allDeps[dep]),
864
+ source: packageJson,
865
+ });
866
+ }
867
+ // MySQL/MariaDB
868
+ if (allDeps['mysql2'] || allDeps['mysql'] || allDeps['mariadb']) {
869
+ services.push({
870
+ service: allDeps['mariadb'] ? 'mariadb' : 'mysql',
871
+ detected: true,
872
+ confidence: 0.9,
873
+ indicators: ['mysql2', 'mysql', 'mariadb'].filter((dep) => allDeps[dep]),
874
+ source: packageJson,
875
+ });
876
+ }
877
+ // MongoDB
878
+ if (allDeps['mongodb'] || allDeps['mongoose']) {
879
+ services.push({
880
+ service: 'mongodb',
881
+ detected: true,
882
+ confidence: 0.9,
883
+ indicators: ['mongodb', 'mongoose'].filter((dep) => allDeps[dep]),
884
+ source: packageJson,
885
+ });
886
+ }
887
+ // Redis
888
+ if (allDeps['redis'] || allDeps['ioredis'] || allDeps['@redis/client']) {
889
+ services.push({
890
+ service: 'redis',
891
+ detected: true,
892
+ confidence: 0.9,
893
+ indicators: ['redis', 'ioredis', '@redis/client'].filter((dep) => allDeps[dep]),
894
+ source: packageJson,
895
+ });
896
+ }
897
+ // Memcached
898
+ if (allDeps['memcached']) {
899
+ services.push({
900
+ service: 'memcached',
901
+ detected: true,
902
+ confidence: 0.9,
903
+ indicators: ['memcached'],
904
+ source: packageJson,
905
+ });
906
+ }
907
+ // Elasticsearch
908
+ if (allDeps['@elastic/elasticsearch'] || allDeps['elasticsearch']) {
909
+ services.push({
910
+ service: 'elasticsearch',
911
+ detected: true,
912
+ confidence: 0.9,
913
+ indicators: ['@elastic/elasticsearch', 'elasticsearch'].filter((dep) => allDeps[dep]),
914
+ source: packageJson,
915
+ });
916
+ }
917
+ // Neo4j
918
+ if (allDeps['neo4j-driver']) {
919
+ services.push({
920
+ service: 'neo4j',
921
+ detected: true,
922
+ confidence: 0.9,
923
+ indicators: ['neo4j-driver'],
924
+ source: packageJson,
925
+ });
926
+ }
927
+ // InfluxDB
928
+ if (allDeps['@influxdata/influxdb-client']) {
929
+ services.push({
930
+ service: 'influxdb',
931
+ detected: true,
932
+ confidence: 0.9,
933
+ indicators: ['@influxdata/influxdb-client'],
934
+ source: packageJson,
935
+ });
936
+ }
937
+ // RabbitMQ
938
+ if (allDeps['amqplib'] || allDeps['amqp-connection-manager']) {
939
+ services.push({
940
+ service: 'rabbitmq',
941
+ detected: true,
942
+ confidence: 0.9,
943
+ indicators: ['amqplib', 'amqp-connection-manager'].filter((dep) => allDeps[dep]),
944
+ source: packageJson,
945
+ });
946
+ }
947
+ // Kafka
948
+ if (allDeps['kafkajs'] || allDeps['node-rdkafka']) {
949
+ services.push({
950
+ service: 'kafka',
951
+ detected: true,
952
+ confidence: 0.9,
953
+ indicators: ['kafkajs', 'node-rdkafka'].filter((dep) => allDeps[dep]),
954
+ source: packageJson,
955
+ });
956
+ }
957
+ // AWS S3
958
+ if (allDeps['@aws-sdk/client-s3'] || allDeps['aws-sdk']) {
959
+ services.push({
960
+ service: 's3',
961
+ detected: true,
962
+ confidence: 0.8,
963
+ indicators: ['@aws-sdk/client-s3', 'aws-sdk'].filter((dep) => allDeps[dep]),
964
+ source: packageJson,
965
+ });
966
+ }
967
+ // Azure Blob
968
+ if (allDeps['@azure/storage-blob']) {
969
+ services.push({
970
+ service: 'azure_blob',
971
+ detected: true,
972
+ confidence: 0.9,
973
+ indicators: ['@azure/storage-blob'],
974
+ source: packageJson,
975
+ });
976
+ }
977
+ // Google Cloud Storage
978
+ if (allDeps['@google-cloud/storage']) {
979
+ services.push({
980
+ service: 'gcs',
981
+ detected: true,
982
+ confidence: 0.9,
983
+ indicators: ['@google-cloud/storage'],
984
+ source: packageJson,
985
+ });
986
+ }
987
+ // MinIO
988
+ if (allDeps['minio']) {
989
+ services.push({
990
+ service: 'minio',
991
+ detected: true,
992
+ confidence: 0.9,
993
+ indicators: ['minio'],
994
+ source: packageJson,
995
+ });
996
+ }
997
+ // SQLite
998
+ if (allDeps['better-sqlite3'] || allDeps['sqlite3']) {
999
+ services.push({
1000
+ service: 'sqlite',
1001
+ detected: true,
1002
+ confidence: 0.9,
1003
+ indicators: ['better-sqlite3', 'sqlite3'].filter((dep) => allDeps[dep]),
1004
+ source: packageJson,
1005
+ });
1006
+ }
1007
+ // Cassandra
1008
+ if (allDeps['cassandra-driver']) {
1009
+ services.push({
1010
+ service: 'cassandra',
1011
+ detected: true,
1012
+ confidence: 0.9,
1013
+ indicators: ['cassandra-driver'],
1014
+ source: packageJson,
1015
+ });
1016
+ }
1017
+ // DynamoDB
1018
+ if (allDeps['@aws-sdk/client-dynamodb'] || allDeps['aws-sdk']) {
1019
+ services.push({
1020
+ service: 'dynamodb',
1021
+ detected: true,
1022
+ confidence: 0.8,
1023
+ indicators: ['@aws-sdk/client-dynamodb', 'aws-sdk'].filter((dep) => allDeps[dep]),
1024
+ source: packageJson,
1025
+ });
1026
+ }
1027
+ // SQL Server
1028
+ if (allDeps['mssql'] || allDeps['tedious']) {
1029
+ services.push({
1030
+ service: 'sqlserver',
1031
+ detected: true,
1032
+ confidence: 0.9,
1033
+ indicators: ['mssql', 'tedious'].filter((dep) => allDeps[dep]),
1034
+ source: packageJson,
1035
+ });
1036
+ }
1037
+ // Oracle
1038
+ if (allDeps['oracledb']) {
1039
+ services.push({
1040
+ service: 'oracle',
1041
+ detected: true,
1042
+ confidence: 0.9,
1043
+ indicators: ['oracledb'],
1044
+ source: packageJson,
1045
+ });
1046
+ }
1047
+ }
1048
+ catch {
1049
+ // Ignore JSON parse errors
1050
+ }
1051
+ }
1052
+ // Check .env file for service connection strings
1053
+ if (await fileExists(envFile)) {
1054
+ try {
1055
+ const envContent = await readFile(envFile);
1056
+ const envLines = envContent.split('\n');
1057
+ for (const line of envLines) {
1058
+ const upperLine = line.toUpperCase();
1059
+ // PostgreSQL
1060
+ if (upperLine.includes('POSTGRES') ||
1061
+ (upperLine.includes('DATABASE_URL') && upperLine.includes('POSTGRES'))) {
1062
+ if (!services.find((s) => s.service === 'postgresql')) {
1063
+ services.push({
1064
+ service: 'postgresql',
1065
+ detected: true,
1066
+ confidence: 0.8,
1067
+ indicators: ['DATABASE_URL or POSTGRES_* env vars'],
1068
+ source: envFile,
1069
+ });
1070
+ }
1071
+ }
1072
+ // MySQL
1073
+ if (upperLine.includes('MYSQL') && !upperLine.includes('MARIADB')) {
1074
+ if (!services.find((s) => s.service === 'mysql')) {
1075
+ services.push({
1076
+ service: 'mysql',
1077
+ detected: true,
1078
+ confidence: 0.8,
1079
+ indicators: ['MYSQL_* env vars'],
1080
+ source: envFile,
1081
+ });
1082
+ }
1083
+ }
1084
+ // MariaDB
1085
+ if (upperLine.includes('MARIADB')) {
1086
+ if (!services.find((s) => s.service === 'mariadb')) {
1087
+ services.push({
1088
+ service: 'mariadb',
1089
+ detected: true,
1090
+ confidence: 0.8,
1091
+ indicators: ['MARIADB_* env vars'],
1092
+ source: envFile,
1093
+ });
1094
+ }
1095
+ }
1096
+ // MongoDB
1097
+ if (upperLine.includes('MONGODB')) {
1098
+ if (!services.find((s) => s.service === 'mongodb')) {
1099
+ services.push({
1100
+ service: 'mongodb',
1101
+ detected: true,
1102
+ confidence: 0.8,
1103
+ indicators: ['MONGODB_* env vars'],
1104
+ source: envFile,
1105
+ });
1106
+ }
1107
+ }
1108
+ // Redis
1109
+ if (upperLine.includes('REDIS')) {
1110
+ if (!services.find((s) => s.service === 'redis')) {
1111
+ services.push({
1112
+ service: 'redis',
1113
+ detected: true,
1114
+ confidence: 0.8,
1115
+ indicators: ['REDIS_* env vars'],
1116
+ source: envFile,
1117
+ });
1118
+ }
1119
+ }
1120
+ // Elasticsearch
1121
+ if (upperLine.includes('ELASTICSEARCH')) {
1122
+ if (!services.find((s) => s.service === 'elasticsearch')) {
1123
+ services.push({
1124
+ service: 'elasticsearch',
1125
+ detected: true,
1126
+ confidence: 0.8,
1127
+ indicators: ['ELASTICSEARCH_* env vars'],
1128
+ source: envFile,
1129
+ });
1130
+ }
1131
+ }
1132
+ // RabbitMQ
1133
+ if (upperLine.includes('RABBITMQ') || upperLine.includes('AMQP')) {
1134
+ if (!services.find((s) => s.service === 'rabbitmq')) {
1135
+ services.push({
1136
+ service: 'rabbitmq',
1137
+ detected: true,
1138
+ confidence: 0.8,
1139
+ indicators: ['RABBITMQ_* or AMQP_* env vars'],
1140
+ source: envFile,
1141
+ });
1142
+ }
1143
+ }
1144
+ // Kafka
1145
+ if (upperLine.includes('KAFKA')) {
1146
+ if (!services.find((s) => s.service === 'kafka')) {
1147
+ services.push({
1148
+ service: 'kafka',
1149
+ detected: true,
1150
+ confidence: 0.8,
1151
+ indicators: ['KAFKA_* env vars'],
1152
+ source: envFile,
1153
+ });
1154
+ }
1155
+ }
1156
+ // AWS S3
1157
+ if (upperLine.includes('S3_') || (upperLine.includes('AWS_') && upperLine.includes('S3'))) {
1158
+ if (!services.find((s) => s.service === 's3')) {
1159
+ services.push({
1160
+ service: 's3',
1161
+ detected: true,
1162
+ confidence: 0.7,
1163
+ indicators: ['S3_* or AWS_* env vars'],
1164
+ source: envFile,
1165
+ });
1166
+ }
1167
+ }
1168
+ // Azure Blob
1169
+ if (upperLine.includes('AZURE_STORAGE') || upperLine.includes('AZURE_BLOB')) {
1170
+ if (!services.find((s) => s.service === 'azure_blob')) {
1171
+ services.push({
1172
+ service: 'azure_blob',
1173
+ detected: true,
1174
+ confidence: 0.8,
1175
+ indicators: ['AZURE_STORAGE_* or AZURE_BLOB_* env vars'],
1176
+ source: envFile,
1177
+ });
1178
+ }
1179
+ }
1180
+ // Google Cloud Storage
1181
+ if (upperLine.includes('GCS_') || upperLine.includes('GCP_STORAGE')) {
1182
+ if (!services.find((s) => s.service === 'gcs')) {
1183
+ services.push({
1184
+ service: 'gcs',
1185
+ detected: true,
1186
+ confidence: 0.8,
1187
+ indicators: ['GCS_* or GCP_STORAGE_* env vars'],
1188
+ source: envFile,
1189
+ });
1190
+ }
1191
+ }
1192
+ // MinIO
1193
+ if (upperLine.includes('MINIO')) {
1194
+ if (!services.find((s) => s.service === 'minio')) {
1195
+ services.push({
1196
+ service: 'minio',
1197
+ detected: true,
1198
+ confidence: 0.8,
1199
+ indicators: ['MINIO_* env vars'],
1200
+ source: envFile,
1201
+ });
1202
+ }
1203
+ }
1204
+ // InfluxDB
1205
+ if (upperLine.includes('INFLUXDB')) {
1206
+ if (!services.find((s) => s.service === 'influxdb')) {
1207
+ services.push({
1208
+ service: 'influxdb',
1209
+ detected: true,
1210
+ confidence: 0.8,
1211
+ indicators: ['INFLUXDB_* env vars'],
1212
+ source: envFile,
1213
+ });
1214
+ }
1215
+ }
1216
+ // Neo4j
1217
+ if (upperLine.includes('NEO4J')) {
1218
+ if (!services.find((s) => s.service === 'neo4j')) {
1219
+ services.push({
1220
+ service: 'neo4j',
1221
+ detected: true,
1222
+ confidence: 0.8,
1223
+ indicators: ['NEO4J_* env vars'],
1224
+ source: envFile,
1225
+ });
1226
+ }
1227
+ }
1228
+ // SQL Server
1229
+ if (upperLine.includes('SQL_SERVER') || upperLine.includes('MSSQL')) {
1230
+ if (!services.find((s) => s.service === 'sqlserver')) {
1231
+ services.push({
1232
+ service: 'sqlserver',
1233
+ detected: true,
1234
+ confidence: 0.8,
1235
+ indicators: ['SQL_SERVER_* or MSSQL_* env vars'],
1236
+ source: envFile,
1237
+ });
1238
+ }
1239
+ }
1240
+ // Oracle
1241
+ if (upperLine.includes('ORACLE')) {
1242
+ if (!services.find((s) => s.service === 'oracle')) {
1243
+ services.push({
1244
+ service: 'oracle',
1245
+ detected: true,
1246
+ confidence: 0.8,
1247
+ indicators: ['ORACLE_* env vars'],
1248
+ source: envFile,
1249
+ });
1250
+ }
1251
+ }
1252
+ }
1253
+ }
1254
+ catch {
1255
+ // Ignore file read errors
1256
+ }
1257
+ }
1258
+ // Check docker-compose.yml for services
1259
+ const composeFiles = [dockerCompose, dockerComposeYaml];
1260
+ for (const composeFile of composeFiles) {
1261
+ if (await fileExists(composeFile)) {
1262
+ try {
1263
+ const composeContent = await readFile(composeFile);
1264
+ const upperContent = composeContent.toUpperCase();
1265
+ // PostgreSQL
1266
+ if (upperContent.includes('POSTGRES') &&
1267
+ !services.find((s) => s.service === 'postgresql')) {
1268
+ services.push({
1269
+ service: 'postgresql',
1270
+ detected: true,
1271
+ confidence: 0.7,
1272
+ indicators: ['docker-compose.yml postgres service'],
1273
+ source: composeFile,
1274
+ });
1275
+ }
1276
+ // MySQL
1277
+ if (upperContent.includes('MYSQL') &&
1278
+ !upperContent.includes('MARIADB') &&
1279
+ !services.find((s) => s.service === 'mysql')) {
1280
+ services.push({
1281
+ service: 'mysql',
1282
+ detected: true,
1283
+ confidence: 0.7,
1284
+ indicators: ['docker-compose.yml mysql service'],
1285
+ source: composeFile,
1286
+ });
1287
+ }
1288
+ // MariaDB
1289
+ if (upperContent.includes('MARIADB') && !services.find((s) => s.service === 'mariadb')) {
1290
+ services.push({
1291
+ service: 'mariadb',
1292
+ detected: true,
1293
+ confidence: 0.7,
1294
+ indicators: ['docker-compose.yml mariadb service'],
1295
+ source: composeFile,
1296
+ });
1297
+ }
1298
+ // MongoDB
1299
+ if (upperContent.includes('MONGO') && !services.find((s) => s.service === 'mongodb')) {
1300
+ services.push({
1301
+ service: 'mongodb',
1302
+ detected: true,
1303
+ confidence: 0.7,
1304
+ indicators: ['docker-compose.yml mongo service'],
1305
+ source: composeFile,
1306
+ });
1307
+ }
1308
+ // Redis
1309
+ if (upperContent.includes('REDIS') && !services.find((s) => s.service === 'redis')) {
1310
+ services.push({
1311
+ service: 'redis',
1312
+ detected: true,
1313
+ confidence: 0.7,
1314
+ indicators: ['docker-compose.yml redis service'],
1315
+ source: composeFile,
1316
+ });
1317
+ }
1318
+ // Memcached
1319
+ if (upperContent.includes('MEMCACHED') &&
1320
+ !services.find((s) => s.service === 'memcached')) {
1321
+ services.push({
1322
+ service: 'memcached',
1323
+ detected: true,
1324
+ confidence: 0.7,
1325
+ indicators: ['docker-compose.yml memcached service'],
1326
+ source: composeFile,
1327
+ });
1328
+ }
1329
+ // Elasticsearch
1330
+ if (upperContent.includes('ELASTICSEARCH') &&
1331
+ !services.find((s) => s.service === 'elasticsearch')) {
1332
+ services.push({
1333
+ service: 'elasticsearch',
1334
+ detected: true,
1335
+ confidence: 0.7,
1336
+ indicators: ['docker-compose.yml elasticsearch service'],
1337
+ source: composeFile,
1338
+ });
1339
+ }
1340
+ // Neo4j
1341
+ if (upperContent.includes('NEO4J') && !services.find((s) => s.service === 'neo4j')) {
1342
+ services.push({
1343
+ service: 'neo4j',
1344
+ detected: true,
1345
+ confidence: 0.7,
1346
+ indicators: ['docker-compose.yml neo4j service'],
1347
+ source: composeFile,
1348
+ });
1349
+ }
1350
+ // InfluxDB
1351
+ if (upperContent.includes('INFLUXDB') && !services.find((s) => s.service === 'influxdb')) {
1352
+ services.push({
1353
+ service: 'influxdb',
1354
+ detected: true,
1355
+ confidence: 0.7,
1356
+ indicators: ['docker-compose.yml influxdb service'],
1357
+ source: composeFile,
1358
+ });
1359
+ }
1360
+ // RabbitMQ
1361
+ if (upperContent.includes('RABBITMQ') && !services.find((s) => s.service === 'rabbitmq')) {
1362
+ services.push({
1363
+ service: 'rabbitmq',
1364
+ detected: true,
1365
+ confidence: 0.7,
1366
+ indicators: ['docker-compose.yml rabbitmq service'],
1367
+ source: composeFile,
1368
+ });
1369
+ }
1370
+ // Kafka
1371
+ if (upperContent.includes('KAFKA') && !services.find((s) => s.service === 'kafka')) {
1372
+ services.push({
1373
+ service: 'kafka',
1374
+ detected: true,
1375
+ confidence: 0.7,
1376
+ indicators: ['docker-compose.yml kafka service'],
1377
+ source: composeFile,
1378
+ });
1379
+ }
1380
+ // MinIO
1381
+ if (upperContent.includes('MINIO') && !services.find((s) => s.service === 'minio')) {
1382
+ services.push({
1383
+ service: 'minio',
1384
+ detected: true,
1385
+ confidence: 0.7,
1386
+ indicators: ['docker-compose.yml minio service'],
1387
+ source: composeFile,
1388
+ });
1389
+ }
1390
+ // SQL Server
1391
+ if ((upperContent.includes('SQLSERVER') || upperContent.includes('MSSQL')) &&
1392
+ !services.find((s) => s.service === 'sqlserver')) {
1393
+ services.push({
1394
+ service: 'sqlserver',
1395
+ detected: true,
1396
+ confidence: 0.7,
1397
+ indicators: ['docker-compose.yml sqlserver service'],
1398
+ source: composeFile,
1399
+ });
1400
+ }
1401
+ }
1402
+ catch {
1403
+ // Ignore file read errors
1404
+ }
1405
+ }
1406
+ }
1407
+ // Add undetected services (for manual selection)
1408
+ const detectedServices = new Set(services.map((s) => s.service));
1409
+ const allServices = [
1410
+ 'postgresql',
1411
+ 'mysql',
1412
+ 'mariadb',
1413
+ 'sqlserver',
1414
+ 'oracle',
1415
+ 'sqlite',
1416
+ 'mongodb',
1417
+ 'cassandra',
1418
+ 'dynamodb',
1419
+ 'redis',
1420
+ 'memcached',
1421
+ 'elasticsearch',
1422
+ 'neo4j',
1423
+ 'influxdb',
1424
+ 'rabbitmq',
1425
+ 'kafka',
1426
+ 's3',
1427
+ 'azure_blob',
1428
+ 'gcs',
1429
+ 'minio',
1430
+ ];
1431
+ for (const service of allServices) {
1432
+ if (!detectedServices.has(service)) {
1433
+ services.push({
1434
+ service,
1435
+ detected: false,
1436
+ confidence: 0,
1437
+ indicators: [],
1438
+ });
1439
+ }
1440
+ }
1441
+ return services;
1442
+ }
1443
+ //# sourceMappingURL=detector.js.map