@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,273 @@
1
+ /**
2
+ * Terraform HCL Parser
3
+ *
4
+ * A simplified HCL parser that extracts resource blocks and their attributes
5
+ * from .tf files. Handles the most common HCL patterns including nested blocks,
6
+ * string/number/boolean attributes, and single-line comments.
7
+ *
8
+ * This is intentionally not a full HCL grammar parser -- it covers the patterns
9
+ * found in the vast majority of real-world Terraform configurations.
10
+ */
11
+
12
+ import * as fs from 'node:fs';
13
+ import * as path from 'node:path';
14
+ import type { TerraformResource } from './types';
15
+
16
+ export { TerraformResource };
17
+
18
+ export class TerraformParser {
19
+ /**
20
+ * Parse all .tf files in a directory (non-recursive for safety).
21
+ * Skips files that cannot be read and continues with the rest.
22
+ */
23
+ async parseDirectory(directory: string): Promise<TerraformResource[]> {
24
+ const entries = fs.readdirSync(directory);
25
+ const tfFiles = entries.filter(f => f.endsWith('.tf'));
26
+ const resources: TerraformResource[] = [];
27
+
28
+ for (const file of tfFiles) {
29
+ try {
30
+ const content = fs.readFileSync(path.join(directory, file), 'utf-8');
31
+ resources.push(...this.parseHCL(content));
32
+ } catch {
33
+ // Skip files that cannot be read (permissions, encoding, etc.)
34
+ }
35
+ }
36
+
37
+ return resources;
38
+ }
39
+
40
+ /**
41
+ * Parse HCL content and extract all resource blocks.
42
+ *
43
+ * Strategy:
44
+ * 1. Strip comments (# and //)
45
+ * 2. Find top-level `resource "type" "name"` declarations
46
+ * 3. Extract the balanced brace block body
47
+ * 4. Parse attributes (including nested blocks) from the body
48
+ */
49
+ parseHCL(content: string): TerraformResource[] {
50
+ const resources: TerraformResource[] = [];
51
+
52
+ // Strip single-line comments but preserve newlines for line-based matching
53
+ const stripped = this.stripComments(content);
54
+
55
+ // We use a manual scan to find resource blocks because regex alone
56
+ // cannot reliably match balanced braces with arbitrary nesting depth.
57
+ const resourceKeyword = 'resource';
58
+ let pos = 0;
59
+
60
+ while (pos < stripped.length) {
61
+ // Find next occurrence of the word "resource" at a word boundary
62
+ const idx = stripped.indexOf(resourceKeyword, pos);
63
+ if (idx === -1) {
64
+ break;
65
+ }
66
+
67
+ // Make sure it is a standalone keyword (not part of another word)
68
+ const before = idx > 0 ? stripped[idx - 1] : '\n';
69
+ const after = stripped[idx + resourceKeyword.length];
70
+ if (/\w/.test(before) || (after !== undefined && /[^\s"]/.test(after))) {
71
+ pos = idx + resourceKeyword.length;
72
+ continue;
73
+ }
74
+
75
+ // Parse: resource "type" "name" {
76
+ const afterKeyword = stripped.substring(idx + resourceKeyword.length);
77
+ const headerMatch = afterKeyword.match(/^\s+"([^"]+)"\s+"([^"]+)"\s*\{/);
78
+ if (!headerMatch) {
79
+ pos = idx + resourceKeyword.length;
80
+ continue;
81
+ }
82
+
83
+ const type = headerMatch[1];
84
+ const name = headerMatch[2];
85
+
86
+ // Find the balanced closing brace
87
+ const braceStart = idx + resourceKeyword.length + headerMatch[0].indexOf('{');
88
+ const body = this.extractBlock(stripped, braceStart);
89
+ if (body === null) {
90
+ pos = idx + resourceKeyword.length;
91
+ continue;
92
+ }
93
+
94
+ const attributes = this.parseAttributes(body);
95
+ const provider = this.detectProvider(type);
96
+
97
+ resources.push({ type, name, provider, attributes });
98
+
99
+ // Advance past the block we just parsed
100
+ pos = braceStart + body.length + 2; // +2 for the opening and closing braces
101
+ }
102
+
103
+ return resources;
104
+ }
105
+
106
+ // ------------------------------------------------------------------
107
+ // Private helpers
108
+ // ------------------------------------------------------------------
109
+
110
+ /**
111
+ * Strip single-line comments (# and //) and multi-line comments.
112
+ * Preserves newlines so that line-based attribute parsing still works.
113
+ */
114
+ private stripComments(content: string): string {
115
+ let result = '';
116
+ let i = 0;
117
+ let inString = false;
118
+
119
+ while (i < content.length) {
120
+ // Handle string literals -- don't strip inside them
121
+ if (content[i] === '"' && (i === 0 || content[i - 1] !== '\\')) {
122
+ inString = !inString;
123
+ result += content[i];
124
+ i++;
125
+ continue;
126
+ }
127
+
128
+ if (inString) {
129
+ result += content[i];
130
+ i++;
131
+ continue;
132
+ }
133
+
134
+ // Multi-line comment /* ... */
135
+ if (content[i] === '/' && content[i + 1] === '*') {
136
+ const end = content.indexOf('*/', i + 2);
137
+ if (end === -1) {
138
+ break;
139
+ }
140
+ // Preserve newlines
141
+ const chunk = content.substring(i, end + 2);
142
+ result += chunk.replace(/[^\n]/g, ' ');
143
+ i = end + 2;
144
+ continue;
145
+ }
146
+
147
+ // Single-line comments: # or //
148
+ if (content[i] === '#' || (content[i] === '/' && content[i + 1] === '/')) {
149
+ const nl = content.indexOf('\n', i);
150
+ if (nl === -1) {
151
+ break;
152
+ }
153
+ result += `${' '.repeat(nl - i)}\n`;
154
+ i = nl + 1;
155
+ continue;
156
+ }
157
+
158
+ result += content[i];
159
+ i++;
160
+ }
161
+
162
+ return result;
163
+ }
164
+
165
+ /**
166
+ * Extract the content between balanced braces starting at `start`.
167
+ * `start` must point to the opening '{'.
168
+ * Returns the inner content (without the outer braces), or null on failure.
169
+ */
170
+ private extractBlock(content: string, start: number): string | null {
171
+ if (content[start] !== '{') {
172
+ return null;
173
+ }
174
+ let depth = 0;
175
+ let inString = false;
176
+
177
+ for (let i = start; i < content.length; i++) {
178
+ const ch = content[i];
179
+ if (ch === '"' && (i === 0 || content[i - 1] !== '\\')) {
180
+ inString = !inString;
181
+ continue;
182
+ }
183
+ if (inString) {
184
+ continue;
185
+ }
186
+ if (ch === '{') {
187
+ depth++;
188
+ }
189
+ if (ch === '}') {
190
+ depth--;
191
+ if (depth === 0) {
192
+ return content.substring(start + 1, i);
193
+ }
194
+ }
195
+ }
196
+
197
+ return null;
198
+ }
199
+
200
+ /**
201
+ * Parse attributes from an HCL block body.
202
+ * Handles:
203
+ * - string: key = "value"
204
+ * - number: key = 123 or key = 1.5
205
+ * - boolean: key = true / false
206
+ * - nested blocks: block_label { ... } -- flattened with prefix
207
+ */
208
+ parseAttributes(body: string): Record<string, any> {
209
+ const attrs: Record<string, any> = {};
210
+
211
+ // Match simple key = "value" patterns
212
+ const stringAttrRegex = /^\s*(\w[\w.-]*)\s*=\s*"([^"]*)"$/gm;
213
+ let match: RegExpExecArray | null;
214
+ while ((match = stringAttrRegex.exec(body)) !== null) {
215
+ attrs[match[1]] = match[2];
216
+ }
217
+
218
+ // Match numeric assignments: key = 123 (or 1.5)
219
+ const numAttrRegex = /^\s*(\w[\w.-]*)\s*=\s*(\d+(?:\.\d+)?)\s*$/gm;
220
+ while ((match = numAttrRegex.exec(body)) !== null) {
221
+ attrs[match[1]] = parseFloat(match[2]);
222
+ }
223
+
224
+ // Match boolean assignments: key = true / false
225
+ const boolAttrRegex = /^\s*(\w[\w.-]*)\s*=\s*(true|false)\s*$/gm;
226
+ while ((match = boolAttrRegex.exec(body)) !== null) {
227
+ attrs[match[1]] = match[2] === 'true';
228
+ }
229
+
230
+ // Parse nested blocks and flatten with prefix
231
+ // e.g. root_block_device { volume_size = 50 } => root_block_device.volume_size = 50
232
+ const nestedBlockRegex = /(\w[\w.-]*)\s*\{/g;
233
+ let nestedMatch: RegExpExecArray | null;
234
+ while ((nestedMatch = nestedBlockRegex.exec(body)) !== null) {
235
+ const blockName = nestedMatch[1];
236
+ // Skip if this looks like an assignment (key = {) -- that is a map literal
237
+ const beforeBrace = body.substring(0, nestedMatch.index + blockName.length);
238
+ if (/=\s*$/.test(beforeBrace.substring(Math.max(0, beforeBrace.length - 10)))) {
239
+ continue;
240
+ }
241
+ const innerBody = this.extractBlock(
242
+ body,
243
+ nestedMatch.index +
244
+ blockName.length +
245
+ body.substring(nestedMatch.index + blockName.length).indexOf('{')
246
+ );
247
+ if (innerBody) {
248
+ const innerAttrs = this.parseAttributes(innerBody);
249
+ for (const [k, v] of Object.entries(innerAttrs)) {
250
+ attrs[`${blockName}.${k}`] = v;
251
+ }
252
+ }
253
+ }
254
+
255
+ return attrs;
256
+ }
257
+
258
+ /**
259
+ * Detect the cloud provider from the Terraform resource type prefix.
260
+ */
261
+ private detectProvider(type: string): 'aws' | 'gcp' | 'azure' | 'unknown' {
262
+ if (type.startsWith('aws_')) {
263
+ return 'aws';
264
+ }
265
+ if (type.startsWith('google_')) {
266
+ return 'gcp';
267
+ }
268
+ if (type.startsWith('azurerm_')) {
269
+ return 'azure';
270
+ }
271
+ return 'unknown';
272
+ }
273
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Types for Terraform resource parsing
3
+ */
4
+
5
+ export interface TerraformResource {
6
+ /** Resource type, e.g. "aws_instance", "google_compute_instance", "azurerm_virtual_machine" */
7
+ type: string;
8
+ /** Resource name as declared in HCL */
9
+ name: string;
10
+ /** Detected cloud provider */
11
+ provider: 'aws' | 'gcp' | 'azure' | 'unknown';
12
+ /** Parsed attributes from the resource block */
13
+ attributes: Record<string, any>;
14
+ }
15
+
16
+ export interface TerraformBlock {
17
+ /** Block type: "resource", "data", "module", "variable", etc. */
18
+ blockType: string;
19
+ /** Block labels, e.g. ["aws_instance", "web"] */
20
+ labels: string[];
21
+ /** Flat key-value attributes parsed from the block */
22
+ attributes: Record<string, any>;
23
+ /** Nested sub-blocks */
24
+ blocks: TerraformBlock[];
25
+ }