@build-astron-co/nimbus 0.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 (313) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +628 -0
  3. package/bin/nimbus +38 -0
  4. package/package.json +80 -0
  5. package/src/__tests__/app.test.ts +76 -0
  6. package/src/__tests__/audit.test.ts +877 -0
  7. package/src/__tests__/circuit-breaker.test.ts +116 -0
  8. package/src/__tests__/cli-run.test.ts +115 -0
  9. package/src/__tests__/context-manager.test.ts +502 -0
  10. package/src/__tests__/context.test.ts +242 -0
  11. package/src/__tests__/enterprise.test.ts +401 -0
  12. package/src/__tests__/generator.test.ts +433 -0
  13. package/src/__tests__/hooks.test.ts +582 -0
  14. package/src/__tests__/init.test.ts +436 -0
  15. package/src/__tests__/intent-parser.test.ts +229 -0
  16. package/src/__tests__/llm-router.test.ts +209 -0
  17. package/src/__tests__/lsp.test.ts +293 -0
  18. package/src/__tests__/modes.test.ts +336 -0
  19. package/src/__tests__/permissions.test.ts +338 -0
  20. package/src/__tests__/serve.test.ts +275 -0
  21. package/src/__tests__/sessions.test.ts +227 -0
  22. package/src/__tests__/sharing.test.ts +288 -0
  23. package/src/__tests__/snapshots.test.ts +581 -0
  24. package/src/__tests__/state-db.test.ts +334 -0
  25. package/src/__tests__/stream-with-tools.test.ts +732 -0
  26. package/src/__tests__/subagents.test.ts +176 -0
  27. package/src/__tests__/system-prompt.test.ts +169 -0
  28. package/src/__tests__/tool-converter.test.ts +256 -0
  29. package/src/__tests__/tool-schemas.test.ts +397 -0
  30. package/src/__tests__/tools.test.ts +143 -0
  31. package/src/__tests__/version.test.ts +49 -0
  32. package/src/agent/compaction-agent.ts +227 -0
  33. package/src/agent/context-manager.ts +435 -0
  34. package/src/agent/context.ts +427 -0
  35. package/src/agent/deploy-preview.ts +426 -0
  36. package/src/agent/index.ts +68 -0
  37. package/src/agent/loop.ts +717 -0
  38. package/src/agent/modes.ts +429 -0
  39. package/src/agent/permissions.ts +466 -0
  40. package/src/agent/subagents/base.ts +116 -0
  41. package/src/agent/subagents/cost.ts +51 -0
  42. package/src/agent/subagents/explore.ts +42 -0
  43. package/src/agent/subagents/general.ts +54 -0
  44. package/src/agent/subagents/index.ts +102 -0
  45. package/src/agent/subagents/infra.ts +59 -0
  46. package/src/agent/subagents/security.ts +69 -0
  47. package/src/agent/system-prompt.ts +436 -0
  48. package/src/app.ts +122 -0
  49. package/src/audit/activity-log.ts +290 -0
  50. package/src/audit/compliance-checker.ts +540 -0
  51. package/src/audit/cost-tracker.ts +318 -0
  52. package/src/audit/index.ts +23 -0
  53. package/src/audit/security-scanner.ts +596 -0
  54. package/src/auth/guard.ts +75 -0
  55. package/src/auth/index.ts +56 -0
  56. package/src/auth/oauth.ts +455 -0
  57. package/src/auth/providers.ts +470 -0
  58. package/src/auth/sso.ts +113 -0
  59. package/src/auth/store.ts +505 -0
  60. package/src/auth/types.ts +187 -0
  61. package/src/build.ts +141 -0
  62. package/src/cli/index.ts +16 -0
  63. package/src/cli/init.ts +854 -0
  64. package/src/cli/openapi-spec.ts +356 -0
  65. package/src/cli/run.ts +237 -0
  66. package/src/cli/serve-auth.ts +80 -0
  67. package/src/cli/serve.ts +462 -0
  68. package/src/cli/web.ts +67 -0
  69. package/src/cli.ts +1417 -0
  70. package/src/clients/core-engine-client.ts +227 -0
  71. package/src/clients/enterprise-client.ts +334 -0
  72. package/src/clients/generator-client.ts +351 -0
  73. package/src/clients/git-client.ts +627 -0
  74. package/src/clients/github-client.ts +410 -0
  75. package/src/clients/helm-client.ts +504 -0
  76. package/src/clients/index.ts +80 -0
  77. package/src/clients/k8s-client.ts +497 -0
  78. package/src/clients/llm-client.ts +161 -0
  79. package/src/clients/rest-client.ts +130 -0
  80. package/src/clients/service-discovery.ts +33 -0
  81. package/src/clients/terraform-client.ts +482 -0
  82. package/src/clients/tools-client.ts +1843 -0
  83. package/src/clients/ws-client.ts +115 -0
  84. package/src/commands/analyze/index.ts +352 -0
  85. package/src/commands/apply/helm.ts +473 -0
  86. package/src/commands/apply/index.ts +213 -0
  87. package/src/commands/apply/k8s.ts +454 -0
  88. package/src/commands/apply/terraform.ts +582 -0
  89. package/src/commands/ask.ts +167 -0
  90. package/src/commands/audit/index.ts +238 -0
  91. package/src/commands/auth-cloud.ts +294 -0
  92. package/src/commands/auth-list.ts +134 -0
  93. package/src/commands/auth-profile.ts +121 -0
  94. package/src/commands/auth-status.ts +141 -0
  95. package/src/commands/aws/ec2.ts +501 -0
  96. package/src/commands/aws/iam.ts +397 -0
  97. package/src/commands/aws/index.ts +133 -0
  98. package/src/commands/aws/lambda.ts +396 -0
  99. package/src/commands/aws/rds.ts +439 -0
  100. package/src/commands/aws/s3.ts +439 -0
  101. package/src/commands/aws/vpc.ts +393 -0
  102. package/src/commands/aws-discover.ts +649 -0
  103. package/src/commands/aws-terraform.ts +805 -0
  104. package/src/commands/azure/aks.ts +376 -0
  105. package/src/commands/azure/functions.ts +253 -0
  106. package/src/commands/azure/index.ts +116 -0
  107. package/src/commands/azure/storage.ts +478 -0
  108. package/src/commands/azure/vm.ts +355 -0
  109. package/src/commands/billing/index.ts +256 -0
  110. package/src/commands/chat.ts +314 -0
  111. package/src/commands/config.ts +346 -0
  112. package/src/commands/cost/cloud-cost-estimator.ts +266 -0
  113. package/src/commands/cost/estimator.ts +79 -0
  114. package/src/commands/cost/index.ts +594 -0
  115. package/src/commands/cost/parsers/terraform.ts +273 -0
  116. package/src/commands/cost/parsers/types.ts +25 -0
  117. package/src/commands/cost/pricing/aws.ts +544 -0
  118. package/src/commands/cost/pricing/azure.ts +499 -0
  119. package/src/commands/cost/pricing/gcp.ts +396 -0
  120. package/src/commands/cost/pricing/index.ts +40 -0
  121. package/src/commands/demo.ts +250 -0
  122. package/src/commands/doctor.ts +794 -0
  123. package/src/commands/drift/index.ts +439 -0
  124. package/src/commands/explain.ts +277 -0
  125. package/src/commands/feedback.ts +389 -0
  126. package/src/commands/fix.ts +324 -0
  127. package/src/commands/fs/index.ts +402 -0
  128. package/src/commands/gcp/compute.ts +325 -0
  129. package/src/commands/gcp/functions.ts +271 -0
  130. package/src/commands/gcp/gke.ts +438 -0
  131. package/src/commands/gcp/iam.ts +344 -0
  132. package/src/commands/gcp/index.ts +129 -0
  133. package/src/commands/gcp/storage.ts +284 -0
  134. package/src/commands/generate-helm.ts +1249 -0
  135. package/src/commands/generate-k8s.ts +1560 -0
  136. package/src/commands/generate-terraform.ts +1460 -0
  137. package/src/commands/gh/index.ts +863 -0
  138. package/src/commands/git/index.ts +1343 -0
  139. package/src/commands/helm/index.ts +1126 -0
  140. package/src/commands/help.ts +539 -0
  141. package/src/commands/history.ts +142 -0
  142. package/src/commands/import.ts +868 -0
  143. package/src/commands/index.ts +367 -0
  144. package/src/commands/init.ts +1046 -0
  145. package/src/commands/k8s/index.ts +1137 -0
  146. package/src/commands/login.ts +631 -0
  147. package/src/commands/logout.ts +83 -0
  148. package/src/commands/onboarding.ts +228 -0
  149. package/src/commands/plan/display.ts +279 -0
  150. package/src/commands/plan/index.ts +599 -0
  151. package/src/commands/preview.ts +452 -0
  152. package/src/commands/questionnaire.ts +1270 -0
  153. package/src/commands/resume.ts +55 -0
  154. package/src/commands/team/index.ts +346 -0
  155. package/src/commands/template.ts +232 -0
  156. package/src/commands/tf/index.ts +1034 -0
  157. package/src/commands/upgrade.ts +550 -0
  158. package/src/commands/usage/index.ts +134 -0
  159. package/src/commands/version.ts +170 -0
  160. package/src/compat/index.ts +2 -0
  161. package/src/compat/runtime.ts +12 -0
  162. package/src/compat/sqlite.ts +107 -0
  163. package/src/config/index.ts +17 -0
  164. package/src/config/manager.ts +530 -0
  165. package/src/config/safety-policy.ts +358 -0
  166. package/src/config/schema.ts +125 -0
  167. package/src/config/types.ts +527 -0
  168. package/src/context/context-db.ts +199 -0
  169. package/src/demo/index.ts +349 -0
  170. package/src/demo/scenarios/full-journey.ts +229 -0
  171. package/src/demo/scenarios/getting-started.ts +127 -0
  172. package/src/demo/scenarios/helm-release.ts +341 -0
  173. package/src/demo/scenarios/k8s-deployment.ts +194 -0
  174. package/src/demo/scenarios/terraform-vpc.ts +170 -0
  175. package/src/demo/types.ts +92 -0
  176. package/src/engine/cost-estimator.ts +438 -0
  177. package/src/engine/diagram-generator.ts +256 -0
  178. package/src/engine/drift-detector.ts +902 -0
  179. package/src/engine/executor.ts +1035 -0
  180. package/src/engine/index.ts +76 -0
  181. package/src/engine/orchestrator.ts +636 -0
  182. package/src/engine/planner.ts +720 -0
  183. package/src/engine/safety.ts +743 -0
  184. package/src/engine/verifier.ts +770 -0
  185. package/src/enterprise/audit.ts +348 -0
  186. package/src/enterprise/auth.ts +270 -0
  187. package/src/enterprise/billing.ts +822 -0
  188. package/src/enterprise/index.ts +17 -0
  189. package/src/enterprise/teams.ts +443 -0
  190. package/src/generator/best-practices.ts +1608 -0
  191. package/src/generator/helm.ts +630 -0
  192. package/src/generator/index.ts +37 -0
  193. package/src/generator/intent-parser.ts +514 -0
  194. package/src/generator/kubernetes.ts +976 -0
  195. package/src/generator/terraform.ts +1867 -0
  196. package/src/history/index.ts +8 -0
  197. package/src/history/manager.ts +322 -0
  198. package/src/history/types.ts +34 -0
  199. package/src/hooks/config.ts +432 -0
  200. package/src/hooks/engine.ts +391 -0
  201. package/src/hooks/index.ts +4 -0
  202. package/src/llm/auth-bridge.ts +198 -0
  203. package/src/llm/circuit-breaker.ts +140 -0
  204. package/src/llm/config-loader.ts +201 -0
  205. package/src/llm/cost-calculator.ts +171 -0
  206. package/src/llm/index.ts +8 -0
  207. package/src/llm/model-aliases.ts +115 -0
  208. package/src/llm/provider-registry.ts +63 -0
  209. package/src/llm/providers/anthropic.ts +433 -0
  210. package/src/llm/providers/bedrock.ts +477 -0
  211. package/src/llm/providers/google.ts +405 -0
  212. package/src/llm/providers/ollama.ts +767 -0
  213. package/src/llm/providers/openai-compatible.ts +340 -0
  214. package/src/llm/providers/openai.ts +328 -0
  215. package/src/llm/providers/openrouter.ts +338 -0
  216. package/src/llm/router.ts +1035 -0
  217. package/src/llm/types.ts +232 -0
  218. package/src/lsp/client.ts +298 -0
  219. package/src/lsp/languages.ts +116 -0
  220. package/src/lsp/manager.ts +278 -0
  221. package/src/mcp/client.ts +402 -0
  222. package/src/mcp/index.ts +5 -0
  223. package/src/mcp/manager.ts +133 -0
  224. package/src/nimbus.ts +214 -0
  225. package/src/plugins/index.ts +27 -0
  226. package/src/plugins/loader.ts +334 -0
  227. package/src/plugins/manager.ts +376 -0
  228. package/src/plugins/types.ts +284 -0
  229. package/src/scanners/cicd-scanner.ts +258 -0
  230. package/src/scanners/cloud-scanner.ts +466 -0
  231. package/src/scanners/framework-scanner.ts +469 -0
  232. package/src/scanners/iac-scanner.ts +388 -0
  233. package/src/scanners/index.ts +539 -0
  234. package/src/scanners/language-scanner.ts +276 -0
  235. package/src/scanners/package-manager-scanner.ts +277 -0
  236. package/src/scanners/types.ts +172 -0
  237. package/src/sessions/manager.ts +365 -0
  238. package/src/sessions/types.ts +44 -0
  239. package/src/sharing/sync.ts +296 -0
  240. package/src/sharing/viewer.ts +97 -0
  241. package/src/snapshots/index.ts +2 -0
  242. package/src/snapshots/manager.ts +530 -0
  243. package/src/state/artifacts.ts +147 -0
  244. package/src/state/audit.ts +137 -0
  245. package/src/state/billing.ts +240 -0
  246. package/src/state/checkpoints.ts +117 -0
  247. package/src/state/config.ts +67 -0
  248. package/src/state/conversations.ts +14 -0
  249. package/src/state/credentials.ts +154 -0
  250. package/src/state/db.ts +58 -0
  251. package/src/state/index.ts +26 -0
  252. package/src/state/messages.ts +115 -0
  253. package/src/state/projects.ts +123 -0
  254. package/src/state/schema.ts +236 -0
  255. package/src/state/sessions.ts +147 -0
  256. package/src/state/teams.ts +200 -0
  257. package/src/telemetry.ts +108 -0
  258. package/src/tools/aws-ops.ts +952 -0
  259. package/src/tools/azure-ops.ts +579 -0
  260. package/src/tools/file-ops.ts +593 -0
  261. package/src/tools/gcp-ops.ts +625 -0
  262. package/src/tools/git-ops.ts +773 -0
  263. package/src/tools/github-ops.ts +799 -0
  264. package/src/tools/helm-ops.ts +943 -0
  265. package/src/tools/index.ts +17 -0
  266. package/src/tools/k8s-ops.ts +819 -0
  267. package/src/tools/schemas/converter.ts +184 -0
  268. package/src/tools/schemas/devops.ts +612 -0
  269. package/src/tools/schemas/index.ts +73 -0
  270. package/src/tools/schemas/standard.ts +1144 -0
  271. package/src/tools/schemas/types.ts +705 -0
  272. package/src/tools/terraform-ops.ts +862 -0
  273. package/src/types/ambient.d.ts +193 -0
  274. package/src/types/config.ts +83 -0
  275. package/src/types/drift.ts +116 -0
  276. package/src/types/enterprise.ts +335 -0
  277. package/src/types/index.ts +20 -0
  278. package/src/types/plan.ts +44 -0
  279. package/src/types/request.ts +65 -0
  280. package/src/types/response.ts +54 -0
  281. package/src/types/service.ts +51 -0
  282. package/src/ui/App.tsx +997 -0
  283. package/src/ui/DeployPreview.tsx +169 -0
  284. package/src/ui/Header.tsx +68 -0
  285. package/src/ui/InputBox.tsx +350 -0
  286. package/src/ui/MessageList.tsx +585 -0
  287. package/src/ui/PermissionPrompt.tsx +151 -0
  288. package/src/ui/StatusBar.tsx +158 -0
  289. package/src/ui/ToolCallDisplay.tsx +409 -0
  290. package/src/ui/chat-ui.ts +853 -0
  291. package/src/ui/index.ts +33 -0
  292. package/src/ui/ink/index.ts +711 -0
  293. package/src/ui/streaming.ts +176 -0
  294. package/src/ui/types.ts +57 -0
  295. package/src/utils/analytics.ts +72 -0
  296. package/src/utils/cost-warning.ts +27 -0
  297. package/src/utils/env.ts +46 -0
  298. package/src/utils/errors.ts +69 -0
  299. package/src/utils/event-bus.ts +38 -0
  300. package/src/utils/index.ts +24 -0
  301. package/src/utils/logger.ts +171 -0
  302. package/src/utils/rate-limiter.ts +121 -0
  303. package/src/utils/service-auth.ts +49 -0
  304. package/src/utils/validation.ts +53 -0
  305. package/src/version.ts +4 -0
  306. package/src/watcher/index.ts +163 -0
  307. package/src/wizard/approval.ts +383 -0
  308. package/src/wizard/index.ts +25 -0
  309. package/src/wizard/prompts.ts +338 -0
  310. package/src/wizard/types.ts +171 -0
  311. package/src/wizard/ui.ts +556 -0
  312. package/src/wizard/wizard.ts +304 -0
  313. package/tsconfig.json +24 -0
@@ -0,0 +1,276 @@
1
+ /**
2
+ * Language Scanner
3
+ *
4
+ * Detects programming languages in a project
5
+ */
6
+
7
+ import * as fs from 'fs';
8
+ import * as path from 'path';
9
+ import type { Scanner, ScanResult, ScanOptions, LanguageInfo, ConfidenceLevel } from './types';
10
+
11
+ interface LanguagePattern {
12
+ name: string;
13
+ configFiles: string[];
14
+ extensions: string[];
15
+ versionExtractor?: (cwd: string) => string | undefined;
16
+ }
17
+
18
+ const LANGUAGE_PATTERNS: LanguagePattern[] = [
19
+ {
20
+ name: 'typescript',
21
+ configFiles: ['tsconfig.json', 'tsconfig.base.json'],
22
+ extensions: ['.ts', '.tsx'],
23
+ versionExtractor: (cwd: string) => {
24
+ const tsconfigPath = path.join(cwd, 'tsconfig.json');
25
+ if (fs.existsSync(tsconfigPath)) {
26
+ try {
27
+ const tsconfig = JSON.parse(fs.readFileSync(tsconfigPath, 'utf-8'));
28
+ return tsconfig.compilerOptions?.target;
29
+ } catch {
30
+ return undefined;
31
+ }
32
+ }
33
+ return undefined;
34
+ },
35
+ },
36
+ {
37
+ name: 'javascript',
38
+ configFiles: ['package.json', 'jsconfig.json'],
39
+ extensions: ['.js', '.jsx', '.mjs', '.cjs'],
40
+ },
41
+ {
42
+ name: 'python',
43
+ configFiles: ['requirements.txt', 'pyproject.toml', 'setup.py', 'Pipfile', 'setup.cfg'],
44
+ extensions: ['.py', '.pyw', '.pyi'],
45
+ versionExtractor: (cwd: string) => {
46
+ const pyprojectPath = path.join(cwd, 'pyproject.toml');
47
+ if (fs.existsSync(pyprojectPath)) {
48
+ try {
49
+ const content = fs.readFileSync(pyprojectPath, 'utf-8');
50
+ const match = content.match(/requires-python\s*=\s*["']([^"']+)["']/);
51
+ return match ? match[1] : undefined;
52
+ } catch {
53
+ return undefined;
54
+ }
55
+ }
56
+ return undefined;
57
+ },
58
+ },
59
+ {
60
+ name: 'go',
61
+ configFiles: ['go.mod', 'go.sum'],
62
+ extensions: ['.go'],
63
+ versionExtractor: (cwd: string) => {
64
+ const goModPath = path.join(cwd, 'go.mod');
65
+ if (fs.existsSync(goModPath)) {
66
+ try {
67
+ const content = fs.readFileSync(goModPath, 'utf-8');
68
+ const match = content.match(/^go\s+(\d+\.\d+)/m);
69
+ return match ? match[1] : undefined;
70
+ } catch {
71
+ return undefined;
72
+ }
73
+ }
74
+ return undefined;
75
+ },
76
+ },
77
+ {
78
+ name: 'rust',
79
+ configFiles: ['Cargo.toml', 'Cargo.lock'],
80
+ extensions: ['.rs'],
81
+ versionExtractor: (cwd: string) => {
82
+ const cargoPath = path.join(cwd, 'Cargo.toml');
83
+ if (fs.existsSync(cargoPath)) {
84
+ try {
85
+ const content = fs.readFileSync(cargoPath, 'utf-8');
86
+ const match = content.match(/rust-version\s*=\s*["']([^"']+)["']/);
87
+ return match ? match[1] : undefined;
88
+ } catch {
89
+ return undefined;
90
+ }
91
+ }
92
+ return undefined;
93
+ },
94
+ },
95
+ {
96
+ name: 'java',
97
+ configFiles: ['pom.xml', 'build.gradle', 'build.gradle.kts', 'settings.gradle'],
98
+ extensions: ['.java'],
99
+ },
100
+ {
101
+ name: 'kotlin',
102
+ configFiles: ['build.gradle.kts'],
103
+ extensions: ['.kt', '.kts'],
104
+ },
105
+ {
106
+ name: 'swift',
107
+ configFiles: ['Package.swift', '*.xcodeproj', '*.xcworkspace'],
108
+ extensions: ['.swift'],
109
+ },
110
+ {
111
+ name: 'ruby',
112
+ configFiles: ['Gemfile', 'Gemfile.lock', '*.gemspec'],
113
+ extensions: ['.rb', '.rake'],
114
+ versionExtractor: (cwd: string) => {
115
+ const rubyVersionPath = path.join(cwd, '.ruby-version');
116
+ if (fs.existsSync(rubyVersionPath)) {
117
+ try {
118
+ return fs.readFileSync(rubyVersionPath, 'utf-8').trim();
119
+ } catch {
120
+ return undefined;
121
+ }
122
+ }
123
+ return undefined;
124
+ },
125
+ },
126
+ {
127
+ name: 'php',
128
+ configFiles: ['composer.json', 'composer.lock'],
129
+ extensions: ['.php'],
130
+ versionExtractor: (cwd: string) => {
131
+ const composerPath = path.join(cwd, 'composer.json');
132
+ if (fs.existsSync(composerPath)) {
133
+ try {
134
+ const composer = JSON.parse(fs.readFileSync(composerPath, 'utf-8'));
135
+ return composer.require?.php?.replace(/[^0-9.]/g, '');
136
+ } catch {
137
+ return undefined;
138
+ }
139
+ }
140
+ return undefined;
141
+ },
142
+ },
143
+ {
144
+ name: 'csharp',
145
+ configFiles: ['*.csproj', '*.sln'],
146
+ extensions: ['.cs'],
147
+ },
148
+ {
149
+ name: 'scala',
150
+ configFiles: ['build.sbt', 'build.sc'],
151
+ extensions: ['.scala', '.sc'],
152
+ },
153
+ {
154
+ name: 'elixir',
155
+ configFiles: ['mix.exs'],
156
+ extensions: ['.ex', '.exs'],
157
+ },
158
+ {
159
+ name: 'haskell',
160
+ configFiles: ['*.cabal', 'stack.yaml'],
161
+ extensions: ['.hs', '.lhs'],
162
+ },
163
+ {
164
+ name: 'lua',
165
+ configFiles: ['.luacheckrc', 'rockspec'],
166
+ extensions: ['.lua'],
167
+ },
168
+ {
169
+ name: 'dart',
170
+ configFiles: ['pubspec.yaml'],
171
+ extensions: ['.dart'],
172
+ },
173
+ ];
174
+
175
+ export class LanguageScanner implements Scanner {
176
+ name = 'language';
177
+
178
+ async scan(cwd: string, _options?: ScanOptions): Promise<ScanResult> {
179
+ const languages = await this.detectLanguages(cwd);
180
+
181
+ return {
182
+ detected: languages.length > 0,
183
+ confidence: languages.length > 0 ? languages[0].confidence : 'low',
184
+ details: {
185
+ languages,
186
+ },
187
+ };
188
+ }
189
+
190
+ async detectLanguages(cwd: string): Promise<LanguageInfo[]> {
191
+ const detected: LanguageInfo[] = [];
192
+
193
+ for (const pattern of LANGUAGE_PATTERNS) {
194
+ const result = await this.detectLanguage(cwd, pattern);
195
+ if (result) {
196
+ detected.push(result);
197
+ }
198
+ }
199
+
200
+ // Sort by confidence
201
+ return detected.sort((a, b) => {
202
+ const order: Record<ConfidenceLevel, number> = { high: 3, medium: 2, low: 1 };
203
+ return order[b.confidence] - order[a.confidence];
204
+ });
205
+ }
206
+
207
+ private async detectLanguage(
208
+ cwd: string,
209
+ pattern: LanguagePattern
210
+ ): Promise<LanguageInfo | null> {
211
+ const foundFiles: string[] = [];
212
+ let confidence: ConfidenceLevel = 'low';
213
+
214
+ // Check for config files
215
+ for (const configFile of pattern.configFiles) {
216
+ if (configFile.includes('*')) {
217
+ // Glob pattern - simple check for directory existence
218
+ const parts = configFile.split('*');
219
+ const dir = path.join(cwd, parts[0]);
220
+ if (fs.existsSync(dir)) {
221
+ foundFiles.push(configFile);
222
+ confidence = 'high';
223
+ }
224
+ } else {
225
+ const filePath = path.join(cwd, configFile);
226
+ if (fs.existsSync(filePath)) {
227
+ foundFiles.push(configFile);
228
+ confidence = 'high';
229
+ }
230
+ }
231
+ }
232
+
233
+ // Quick extension check in common directories
234
+ const dirsToCheck = ['src', 'lib', 'app', 'pkg', 'internal', 'cmd', '.'];
235
+ for (const dir of dirsToCheck) {
236
+ const dirPath = path.join(cwd, dir);
237
+ if (fs.existsSync(dirPath) && fs.statSync(dirPath).isDirectory()) {
238
+ try {
239
+ const files = fs.readdirSync(dirPath).slice(0, 20); // Limit for performance
240
+ for (const file of files) {
241
+ const ext = path.extname(file);
242
+ if (pattern.extensions.includes(ext)) {
243
+ foundFiles.push(path.join(dir, file));
244
+ if (confidence === 'low') {
245
+ confidence = 'medium';
246
+ }
247
+ }
248
+ }
249
+ } catch {
250
+ // Ignore read errors
251
+ }
252
+ }
253
+ }
254
+
255
+ if (foundFiles.length === 0) {
256
+ return null;
257
+ }
258
+
259
+ // Extract version if available
260
+ const version = pattern.versionExtractor?.(cwd);
261
+
262
+ return {
263
+ name: pattern.name,
264
+ version,
265
+ confidence,
266
+ files: foundFiles.slice(0, 10), // Limit files reported
267
+ };
268
+ }
269
+ }
270
+
271
+ /**
272
+ * Create language scanner instance
273
+ */
274
+ export function createLanguageScanner(): LanguageScanner {
275
+ return new LanguageScanner();
276
+ }
@@ -0,0 +1,277 @@
1
+ /**
2
+ * Package Manager Scanner
3
+ *
4
+ * Detects package managers used in a project
5
+ */
6
+
7
+ import * as fs from 'fs';
8
+ import * as path from 'path';
9
+ import type {
10
+ Scanner,
11
+ ScanResult,
12
+ ScanOptions,
13
+ PackageManagerInfo,
14
+ ConfidenceLevel,
15
+ } from './types';
16
+
17
+ interface PackageManagerPattern {
18
+ name: string;
19
+ lockFiles: string[];
20
+ configFiles: string[];
21
+ language: string;
22
+ }
23
+
24
+ const PACKAGE_MANAGER_PATTERNS: PackageManagerPattern[] = [
25
+ // JavaScript/TypeScript
26
+ {
27
+ name: 'npm',
28
+ lockFiles: ['package-lock.json'],
29
+ configFiles: ['.npmrc'],
30
+ language: 'javascript',
31
+ },
32
+ {
33
+ name: 'yarn',
34
+ lockFiles: ['yarn.lock'],
35
+ configFiles: ['.yarnrc', '.yarnrc.yml'],
36
+ language: 'javascript',
37
+ },
38
+ {
39
+ name: 'pnpm',
40
+ lockFiles: ['pnpm-lock.yaml'],
41
+ configFiles: ['.pnpmrc', 'pnpm-workspace.yaml'],
42
+ language: 'javascript',
43
+ },
44
+ {
45
+ name: 'bun',
46
+ lockFiles: ['bun.lockb'],
47
+ configFiles: ['bunfig.toml'],
48
+ language: 'javascript',
49
+ },
50
+ // Python
51
+ {
52
+ name: 'pip',
53
+ lockFiles: [],
54
+ configFiles: ['requirements.txt', 'requirements-dev.txt'],
55
+ language: 'python',
56
+ },
57
+ {
58
+ name: 'pipenv',
59
+ lockFiles: ['Pipfile.lock'],
60
+ configFiles: ['Pipfile'],
61
+ language: 'python',
62
+ },
63
+ {
64
+ name: 'poetry',
65
+ lockFiles: ['poetry.lock'],
66
+ configFiles: ['pyproject.toml'],
67
+ language: 'python',
68
+ },
69
+ {
70
+ name: 'uv',
71
+ lockFiles: ['uv.lock'],
72
+ configFiles: ['pyproject.toml'],
73
+ language: 'python',
74
+ },
75
+ {
76
+ name: 'conda',
77
+ lockFiles: ['conda-lock.yml'],
78
+ configFiles: ['environment.yml', 'environment.yaml'],
79
+ language: 'python',
80
+ },
81
+ // Go
82
+ {
83
+ name: 'go-modules',
84
+ lockFiles: ['go.sum'],
85
+ configFiles: ['go.mod'],
86
+ language: 'go',
87
+ },
88
+ // Rust
89
+ {
90
+ name: 'cargo',
91
+ lockFiles: ['Cargo.lock'],
92
+ configFiles: ['Cargo.toml'],
93
+ language: 'rust',
94
+ },
95
+ // Ruby
96
+ {
97
+ name: 'bundler',
98
+ lockFiles: ['Gemfile.lock'],
99
+ configFiles: ['Gemfile'],
100
+ language: 'ruby',
101
+ },
102
+ // PHP
103
+ {
104
+ name: 'composer',
105
+ lockFiles: ['composer.lock'],
106
+ configFiles: ['composer.json'],
107
+ language: 'php',
108
+ },
109
+ // Java
110
+ {
111
+ name: 'maven',
112
+ lockFiles: [],
113
+ configFiles: ['pom.xml'],
114
+ language: 'java',
115
+ },
116
+ {
117
+ name: 'gradle',
118
+ lockFiles: ['gradle.lockfile'],
119
+ configFiles: ['build.gradle', 'build.gradle.kts', 'settings.gradle'],
120
+ language: 'java',
121
+ },
122
+ // .NET
123
+ {
124
+ name: 'nuget',
125
+ lockFiles: ['packages.lock.json'],
126
+ configFiles: ['*.csproj', 'nuget.config'],
127
+ language: 'csharp',
128
+ },
129
+ // Swift
130
+ {
131
+ name: 'swift-pm',
132
+ lockFiles: ['Package.resolved'],
133
+ configFiles: ['Package.swift'],
134
+ language: 'swift',
135
+ },
136
+ // Dart
137
+ {
138
+ name: 'pub',
139
+ lockFiles: ['pubspec.lock'],
140
+ configFiles: ['pubspec.yaml'],
141
+ language: 'dart',
142
+ },
143
+ // Elixir
144
+ {
145
+ name: 'mix',
146
+ lockFiles: ['mix.lock'],
147
+ configFiles: ['mix.exs'],
148
+ language: 'elixir',
149
+ },
150
+ // Haskell
151
+ {
152
+ name: 'stack',
153
+ lockFiles: ['stack.yaml.lock'],
154
+ configFiles: ['stack.yaml'],
155
+ language: 'haskell',
156
+ },
157
+ {
158
+ name: 'cabal',
159
+ lockFiles: ['cabal.project.freeze'],
160
+ configFiles: ['*.cabal'],
161
+ language: 'haskell',
162
+ },
163
+ ];
164
+
165
+ export class PackageManagerScanner implements Scanner {
166
+ name = 'package-manager';
167
+
168
+ async scan(cwd: string, _options?: ScanOptions): Promise<ScanResult> {
169
+ const packageManagers = await this.detectPackageManagers(cwd);
170
+
171
+ return {
172
+ detected: packageManagers.length > 0,
173
+ confidence: packageManagers.length > 0 ? packageManagers[0].confidence : 'low',
174
+ details: {
175
+ packageManagers,
176
+ },
177
+ };
178
+ }
179
+
180
+ async detectPackageManagers(cwd: string): Promise<PackageManagerInfo[]> {
181
+ const detected: PackageManagerInfo[] = [];
182
+
183
+ for (const pattern of PACKAGE_MANAGER_PATTERNS) {
184
+ const result = await this.detectPackageManager(cwd, pattern);
185
+ if (result) {
186
+ detected.push(result);
187
+ }
188
+ }
189
+
190
+ // Sort by confidence
191
+ return detected.sort((a, b) => {
192
+ const order: Record<ConfidenceLevel, number> = { high: 3, medium: 2, low: 1 };
193
+ return order[b.confidence] - order[a.confidence];
194
+ });
195
+ }
196
+
197
+ private async detectPackageManager(
198
+ cwd: string,
199
+ pattern: PackageManagerPattern
200
+ ): Promise<PackageManagerInfo | null> {
201
+ let confidence: ConfidenceLevel = 'low';
202
+ let lockFile: string | undefined;
203
+
204
+ // Check for lock files first (highest confidence)
205
+ for (const file of pattern.lockFiles) {
206
+ const filePath = path.join(cwd, file);
207
+ if (fs.existsSync(filePath)) {
208
+ confidence = 'high';
209
+ lockFile = file;
210
+ break;
211
+ }
212
+ }
213
+
214
+ // Check for config files
215
+ if (confidence !== 'high') {
216
+ for (const file of pattern.configFiles) {
217
+ if (file.includes('*')) {
218
+ // Glob pattern - simple check
219
+ const extension = file.replace('*', '');
220
+ try {
221
+ const files = fs.readdirSync(cwd);
222
+ if (files.some(f => f.endsWith(extension))) {
223
+ confidence = 'medium';
224
+ break;
225
+ }
226
+ } catch {
227
+ // Ignore errors
228
+ }
229
+ } else {
230
+ const filePath = path.join(cwd, file);
231
+ if (fs.existsSync(filePath)) {
232
+ // Special handling for pyproject.toml - need to check for poetry section
233
+ if (file === 'pyproject.toml' && pattern.name === 'poetry') {
234
+ try {
235
+ const content = fs.readFileSync(filePath, 'utf-8');
236
+ if (content.includes('[tool.poetry]')) {
237
+ confidence = 'high';
238
+ }
239
+ } catch {
240
+ // Ignore errors
241
+ }
242
+ } else if (file === 'pyproject.toml' && pattern.name === 'uv') {
243
+ try {
244
+ const content = fs.readFileSync(filePath, 'utf-8');
245
+ if (content.includes('[tool.uv]')) {
246
+ confidence = 'high';
247
+ }
248
+ } catch {
249
+ // Ignore errors
250
+ }
251
+ } else {
252
+ confidence = confidence === 'low' ? 'medium' : confidence;
253
+ }
254
+ break;
255
+ }
256
+ }
257
+ }
258
+ }
259
+
260
+ if (confidence === 'low') {
261
+ return null;
262
+ }
263
+
264
+ return {
265
+ name: pattern.name,
266
+ lockFile,
267
+ confidence,
268
+ };
269
+ }
270
+ }
271
+
272
+ /**
273
+ * Create package manager scanner instance
274
+ */
275
+ export function createPackageManagerScanner(): PackageManagerScanner {
276
+ return new PackageManagerScanner();
277
+ }
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Scanner Types
3
+ *
4
+ * Type definitions for project scanners
5
+ */
6
+
7
+ /**
8
+ * Confidence level for detection
9
+ */
10
+ export type ConfidenceLevel = 'high' | 'medium' | 'low';
11
+
12
+ /**
13
+ * Base scan result for all scanners
14
+ */
15
+ export interface ScanResult {
16
+ detected: boolean;
17
+ confidence: ConfidenceLevel;
18
+ details: Record<string, unknown>;
19
+ }
20
+
21
+ /**
22
+ * Scanner interface
23
+ */
24
+ export interface Scanner {
25
+ name: string;
26
+ scan(cwd: string, options?: ScanOptions): Promise<ScanResult>;
27
+ }
28
+
29
+ /**
30
+ * Language detection result
31
+ */
32
+ export interface LanguageInfo {
33
+ name: string;
34
+ version?: string;
35
+ confidence: ConfidenceLevel;
36
+ files: string[];
37
+ }
38
+
39
+ /**
40
+ * Framework detection result
41
+ */
42
+ export interface FrameworkInfo {
43
+ name: string;
44
+ version?: string;
45
+ confidence: ConfidenceLevel;
46
+ language: string;
47
+ }
48
+
49
+ /**
50
+ * Package manager detection result
51
+ */
52
+ export interface PackageManagerInfo {
53
+ name: string;
54
+ lockFile?: string;
55
+ confidence: ConfidenceLevel;
56
+ }
57
+
58
+ /**
59
+ * Infrastructure as Code detection result
60
+ */
61
+ export interface IaCInfo {
62
+ name: string;
63
+ type: 'terraform' | 'pulumi' | 'cdk' | 'cloudformation' | 'ansible' | 'other';
64
+ files: string[];
65
+ confidence: ConfidenceLevel;
66
+ }
67
+
68
+ /**
69
+ * CI/CD detection result
70
+ */
71
+ export interface CICDInfo {
72
+ platform: string;
73
+ workflows: string[];
74
+ confidence: ConfidenceLevel;
75
+ }
76
+
77
+ /**
78
+ * Cloud provider detection result
79
+ */
80
+ export interface CloudInfo {
81
+ provider: string;
82
+ regions: string[];
83
+ services: string[];
84
+ confidence: ConfidenceLevel;
85
+ }
86
+
87
+ /**
88
+ * Git repository info
89
+ */
90
+ export interface GitInfo {
91
+ isRepo: boolean;
92
+ remote: string | null;
93
+ branch: string;
94
+ hasUncommittedChanges: boolean;
95
+ }
96
+
97
+ /**
98
+ * Complete project context from scanning
99
+ */
100
+ export interface ProjectContext {
101
+ project: {
102
+ name: string;
103
+ path: string;
104
+ detected_at: string;
105
+ };
106
+ structure: {
107
+ type: ProjectType;
108
+ languages: LanguageInfo[];
109
+ frameworks: FrameworkInfo[];
110
+ packageManagers: PackageManagerInfo[];
111
+ };
112
+ files: {
113
+ terraform: string[];
114
+ kubernetes: string[];
115
+ docker: string[];
116
+ cicd: string[];
117
+ };
118
+ git: GitInfo;
119
+ cicd: {
120
+ platform: string | null;
121
+ workflows: string[];
122
+ };
123
+ cloud: {
124
+ providers: string[];
125
+ regions: string[];
126
+ };
127
+ instructions: string;
128
+ }
129
+
130
+ /**
131
+ * Project type classification
132
+ */
133
+ export type ProjectType =
134
+ | 'frontend'
135
+ | 'backend'
136
+ | 'fullstack'
137
+ | 'monorepo'
138
+ | 'library'
139
+ | 'infrastructure'
140
+ | 'mobile'
141
+ | 'cli'
142
+ | 'unknown';
143
+
144
+ /**
145
+ * Scan options
146
+ */
147
+ export interface ScanOptions {
148
+ /** Scan depth: quick, standard, or deep */
149
+ depth: 'quick' | 'standard' | 'deep';
150
+ /** Maximum files to scan per pattern */
151
+ maxFiles?: number;
152
+ /** Include hidden directories */
153
+ includeHidden?: boolean;
154
+ /** Custom project instructions */
155
+ instructions?: string;
156
+ /** Maximum directory depth for scanning */
157
+ maxDepth?: number;
158
+ }
159
+
160
+ /**
161
+ * Aggregate scan results from all scanners
162
+ */
163
+ export interface AggregateScanResult {
164
+ languages: LanguageInfo[];
165
+ frameworks: FrameworkInfo[];
166
+ packageManagers: PackageManagerInfo[];
167
+ iac: IaCInfo[];
168
+ cicd: CICDInfo[];
169
+ cloud: CloudInfo[];
170
+ git: GitInfo;
171
+ projectType: ProjectType;
172
+ }