@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,1046 @@
1
+ /**
2
+ * Init Command
3
+ *
4
+ * Initialize a Nimbus workspace in the current directory
5
+ * Performs comprehensive project scanning to detect:
6
+ * - Languages and versions
7
+ * - Frameworks
8
+ * - Package managers
9
+ * - Infrastructure as Code (Terraform, Pulumi, CDK, etc.)
10
+ * - CI/CD platforms
11
+ * - Cloud providers
12
+ */
13
+
14
+ import * as fs from 'fs';
15
+ import * as path from 'path';
16
+ import { ui } from '../wizard/ui';
17
+ import { select, input, confirm } from '../wizard/prompts';
18
+ import {
19
+ createProjectScanner,
20
+ generateProjectYaml,
21
+ type ProjectContext,
22
+ type ScanOptions,
23
+ } from '../scanners';
24
+ import { initContextDatabase } from '../context/context-db';
25
+
26
+ export interface InitOptions {
27
+ /** Non-interactive mode */
28
+ nonInteractive?: boolean;
29
+ /** Force overwrite existing configuration */
30
+ force?: boolean;
31
+ /** Project name */
32
+ name?: string;
33
+ /** Default cloud provider */
34
+ provider?: string;
35
+ /** Output directory */
36
+ output?: string;
37
+ /** Scan depth: quick, standard, or deep */
38
+ scanDepth?: 'quick' | 'standard' | 'deep';
39
+ /** Custom project instructions */
40
+ instructions?: string;
41
+ /** Template to use: vpc, eks, full-stack, minimal */
42
+ template?: 'vpc' | 'eks' | 'full-stack' | 'minimal';
43
+ /** Import from existing IaC directory */
44
+ fromExisting?: string;
45
+ /** Maximum directory depth for project scanning */
46
+ maxDepth?: number;
47
+ }
48
+
49
+ const NIMBUS_DIR = '.nimbus';
50
+ const PROJECT_FILE = 'project.yaml';
51
+ const CONFIG_FILE = 'config.yaml';
52
+
53
+ // Template definitions
54
+ const TEMPLATES: Record<string, { description: string; files: Record<string, string> }> = {
55
+ vpc: {
56
+ description: 'AWS VPC with subnets, NAT gateway, and security groups',
57
+ files: {
58
+ 'terraform/main.tf': `# VPC Infrastructure
59
+ # Generated by Nimbus
60
+
61
+ terraform {
62
+ required_providers {
63
+ aws = {
64
+ source = "hashicorp/aws"
65
+ version = "~> 5.0"
66
+ }
67
+ }
68
+ }
69
+
70
+ provider "aws" {
71
+ region = var.aws_region
72
+ }
73
+
74
+ module "vpc" {
75
+ source = "terraform-aws-modules/vpc/aws"
76
+ version = "~> 5.0"
77
+
78
+ name = var.project_name
79
+ cidr = var.vpc_cidr
80
+
81
+ azs = var.availability_zones
82
+ private_subnets = var.private_subnet_cidrs
83
+ public_subnets = var.public_subnet_cidrs
84
+
85
+ enable_nat_gateway = true
86
+ single_nat_gateway = var.single_nat_gateway
87
+ enable_dns_hostnames = true
88
+ enable_dns_support = true
89
+
90
+ tags = var.tags
91
+ }
92
+ `,
93
+ 'terraform/variables.tf': `variable "project_name" {
94
+ description = "Name of the project"
95
+ type = string
96
+ }
97
+
98
+ variable "aws_region" {
99
+ description = "AWS region"
100
+ type = string
101
+ default = "us-east-1"
102
+ }
103
+
104
+ variable "vpc_cidr" {
105
+ description = "CIDR block for VPC"
106
+ type = string
107
+ default = "10.0.0.0/16"
108
+ }
109
+
110
+ variable "availability_zones" {
111
+ description = "Availability zones"
112
+ type = list(string)
113
+ default = ["us-east-1a", "us-east-1b", "us-east-1c"]
114
+ }
115
+
116
+ variable "private_subnet_cidrs" {
117
+ description = "CIDR blocks for private subnets"
118
+ type = list(string)
119
+ default = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
120
+ }
121
+
122
+ variable "public_subnet_cidrs" {
123
+ description = "CIDR blocks for public subnets"
124
+ type = list(string)
125
+ default = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]
126
+ }
127
+
128
+ variable "single_nat_gateway" {
129
+ description = "Use single NAT gateway for cost savings"
130
+ type = bool
131
+ default = true
132
+ }
133
+
134
+ variable "tags" {
135
+ description = "Tags to apply to resources"
136
+ type = map(string)
137
+ default = {}
138
+ }
139
+ `,
140
+ 'terraform/outputs.tf': `output "vpc_id" {
141
+ description = "VPC ID"
142
+ value = module.vpc.vpc_id
143
+ }
144
+
145
+ output "private_subnet_ids" {
146
+ description = "Private subnet IDs"
147
+ value = module.vpc.private_subnets
148
+ }
149
+
150
+ output "public_subnet_ids" {
151
+ description = "Public subnet IDs"
152
+ value = module.vpc.public_subnets
153
+ }
154
+
155
+ output "nat_gateway_ips" {
156
+ description = "NAT Gateway IPs"
157
+ value = module.vpc.nat_public_ips
158
+ }
159
+ `,
160
+ 'terraform/terraform.tfvars.example': `project_name = "my-project"
161
+ aws_region = "us-east-1"
162
+ vpc_cidr = "10.0.0.0/16"
163
+
164
+ tags = {
165
+ Environment = "dev"
166
+ ManagedBy = "terraform"
167
+ }
168
+ `,
169
+ },
170
+ },
171
+ eks: {
172
+ description: 'AWS EKS cluster with VPC and node groups',
173
+ files: {
174
+ 'terraform/main.tf': `# EKS Infrastructure
175
+ # Generated by Nimbus
176
+
177
+ terraform {
178
+ required_providers {
179
+ aws = {
180
+ source = "hashicorp/aws"
181
+ version = "~> 5.0"
182
+ }
183
+ kubernetes = {
184
+ source = "hashicorp/kubernetes"
185
+ version = "~> 2.0"
186
+ }
187
+ }
188
+ }
189
+
190
+ provider "aws" {
191
+ region = var.aws_region
192
+ }
193
+
194
+ module "vpc" {
195
+ source = "terraform-aws-modules/vpc/aws"
196
+ version = "~> 5.0"
197
+
198
+ name = "\${var.project_name}-vpc"
199
+ cidr = var.vpc_cidr
200
+
201
+ azs = var.availability_zones
202
+ private_subnets = var.private_subnet_cidrs
203
+ public_subnets = var.public_subnet_cidrs
204
+
205
+ enable_nat_gateway = true
206
+ single_nat_gateway = true
207
+ enable_dns_hostnames = true
208
+
209
+ public_subnet_tags = {
210
+ "kubernetes.io/role/elb" = 1
211
+ }
212
+
213
+ private_subnet_tags = {
214
+ "kubernetes.io/role/internal-elb" = 1
215
+ }
216
+
217
+ tags = var.tags
218
+ }
219
+
220
+ module "eks" {
221
+ source = "terraform-aws-modules/eks/aws"
222
+ version = "~> 19.0"
223
+
224
+ cluster_name = var.project_name
225
+ cluster_version = var.cluster_version
226
+
227
+ vpc_id = module.vpc.vpc_id
228
+ subnet_ids = module.vpc.private_subnets
229
+
230
+ cluster_endpoint_public_access = true
231
+
232
+ eks_managed_node_groups = {
233
+ default = {
234
+ min_size = var.node_min_size
235
+ max_size = var.node_max_size
236
+ desired_size = var.node_desired_size
237
+
238
+ instance_types = var.node_instance_types
239
+ capacity_type = "ON_DEMAND"
240
+ }
241
+ }
242
+
243
+ tags = var.tags
244
+ }
245
+ `,
246
+ 'terraform/variables.tf': `variable "project_name" {
247
+ description = "Name of the project / EKS cluster"
248
+ type = string
249
+ }
250
+
251
+ variable "aws_region" {
252
+ description = "AWS region"
253
+ type = string
254
+ default = "us-east-1"
255
+ }
256
+
257
+ variable "cluster_version" {
258
+ description = "Kubernetes version"
259
+ type = string
260
+ default = "1.28"
261
+ }
262
+
263
+ variable "vpc_cidr" {
264
+ description = "CIDR block for VPC"
265
+ type = string
266
+ default = "10.0.0.0/16"
267
+ }
268
+
269
+ variable "availability_zones" {
270
+ description = "Availability zones"
271
+ type = list(string)
272
+ default = ["us-east-1a", "us-east-1b"]
273
+ }
274
+
275
+ variable "private_subnet_cidrs" {
276
+ description = "CIDR blocks for private subnets"
277
+ type = list(string)
278
+ default = ["10.0.1.0/24", "10.0.2.0/24"]
279
+ }
280
+
281
+ variable "public_subnet_cidrs" {
282
+ description = "CIDR blocks for public subnets"
283
+ type = list(string)
284
+ default = ["10.0.101.0/24", "10.0.102.0/24"]
285
+ }
286
+
287
+ variable "node_instance_types" {
288
+ description = "Instance types for node group"
289
+ type = list(string)
290
+ default = ["t3.medium"]
291
+ }
292
+
293
+ variable "node_min_size" {
294
+ description = "Minimum number of nodes"
295
+ type = number
296
+ default = 1
297
+ }
298
+
299
+ variable "node_max_size" {
300
+ description = "Maximum number of nodes"
301
+ type = number
302
+ default = 5
303
+ }
304
+
305
+ variable "node_desired_size" {
306
+ description = "Desired number of nodes"
307
+ type = number
308
+ default = 2
309
+ }
310
+
311
+ variable "tags" {
312
+ description = "Tags to apply to resources"
313
+ type = map(string)
314
+ default = {}
315
+ }
316
+ `,
317
+ 'terraform/outputs.tf': `output "cluster_endpoint" {
318
+ description = "EKS cluster endpoint"
319
+ value = module.eks.cluster_endpoint
320
+ }
321
+
322
+ output "cluster_name" {
323
+ description = "EKS cluster name"
324
+ value = module.eks.cluster_name
325
+ }
326
+
327
+ output "cluster_certificate_authority_data" {
328
+ description = "Base64 encoded certificate data"
329
+ value = module.eks.cluster_certificate_authority_data
330
+ sensitive = true
331
+ }
332
+
333
+ output "configure_kubectl" {
334
+ description = "Configure kubectl"
335
+ value = "aws eks update-kubeconfig --region \${var.aws_region} --name \${module.eks.cluster_name}"
336
+ }
337
+ `,
338
+ },
339
+ },
340
+ 'full-stack': {
341
+ description: 'Complete AWS stack with VPC, EKS, RDS, and ElastiCache',
342
+ files: {
343
+ 'terraform/main.tf': `# Full Stack Infrastructure
344
+ # Generated by Nimbus
345
+
346
+ terraform {
347
+ required_providers {
348
+ aws = {
349
+ source = "hashicorp/aws"
350
+ version = "~> 5.0"
351
+ }
352
+ }
353
+ }
354
+
355
+ provider "aws" {
356
+ region = var.aws_region
357
+ }
358
+
359
+ # VPC
360
+ module "vpc" {
361
+ source = "terraform-aws-modules/vpc/aws"
362
+ version = "~> 5.0"
363
+
364
+ name = "\${var.project_name}-vpc"
365
+ cidr = "10.0.0.0/16"
366
+
367
+ azs = ["us-east-1a", "us-east-1b"]
368
+ private_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
369
+ public_subnets = ["10.0.101.0/24", "10.0.102.0/24"]
370
+ database_subnets = ["10.0.201.0/24", "10.0.202.0/24"]
371
+
372
+ enable_nat_gateway = true
373
+ single_nat_gateway = true
374
+ enable_dns_hostnames = true
375
+
376
+ create_database_subnet_group = true
377
+
378
+ tags = var.tags
379
+ }
380
+
381
+ # EKS Cluster
382
+ module "eks" {
383
+ source = "terraform-aws-modules/eks/aws"
384
+ version = "~> 19.0"
385
+
386
+ cluster_name = "\${var.project_name}-cluster"
387
+ cluster_version = "1.28"
388
+
389
+ vpc_id = module.vpc.vpc_id
390
+ subnet_ids = module.vpc.private_subnets
391
+
392
+ cluster_endpoint_public_access = true
393
+
394
+ eks_managed_node_groups = {
395
+ default = {
396
+ min_size = 2
397
+ max_size = 10
398
+ desired_size = 3
399
+ instance_types = ["t3.medium"]
400
+ }
401
+ }
402
+
403
+ tags = var.tags
404
+ }
405
+
406
+ # RDS PostgreSQL
407
+ module "rds" {
408
+ source = "terraform-aws-modules/rds/aws"
409
+ version = "~> 6.0"
410
+
411
+ identifier = "\${var.project_name}-db"
412
+
413
+ engine = "postgres"
414
+ engine_version = "15"
415
+ family = "postgres15"
416
+ major_engine_version = "15"
417
+ instance_class = "db.t3.micro"
418
+
419
+ allocated_storage = 20
420
+ max_allocated_storage = 100
421
+
422
+ db_name = "app"
423
+ username = "dbadmin"
424
+ port = 5432
425
+
426
+ db_subnet_group_name = module.vpc.database_subnet_group_name
427
+ vpc_security_group_ids = [aws_security_group.rds.id]
428
+
429
+ maintenance_window = "Mon:00:00-Mon:03:00"
430
+ backup_window = "03:00-06:00"
431
+ backup_retention_period = 7
432
+
433
+ tags = var.tags
434
+ }
435
+
436
+ # ElastiCache Redis
437
+ resource "aws_elasticache_subnet_group" "main" {
438
+ name = "\${var.project_name}-cache-subnet"
439
+ subnet_ids = module.vpc.private_subnets
440
+ }
441
+
442
+ resource "aws_elasticache_cluster" "main" {
443
+ cluster_id = "\${var.project_name}-cache"
444
+ engine = "redis"
445
+ node_type = "cache.t3.micro"
446
+ num_cache_nodes = 1
447
+ parameter_group_name = "default.redis7"
448
+ port = 6379
449
+ subnet_group_name = aws_elasticache_subnet_group.main.name
450
+ security_group_ids = [aws_security_group.redis.id]
451
+
452
+ tags = var.tags
453
+ }
454
+
455
+ # Security Groups
456
+ resource "aws_security_group" "rds" {
457
+ name = "\${var.project_name}-rds-sg"
458
+ description = "Allow PostgreSQL from VPC"
459
+ vpc_id = module.vpc.vpc_id
460
+
461
+ ingress {
462
+ from_port = 5432
463
+ to_port = 5432
464
+ protocol = "tcp"
465
+ cidr_blocks = [module.vpc.vpc_cidr_block]
466
+ }
467
+
468
+ tags = var.tags
469
+ }
470
+
471
+ resource "aws_security_group" "redis" {
472
+ name = "\${var.project_name}-redis-sg"
473
+ description = "Allow Redis from VPC"
474
+ vpc_id = module.vpc.vpc_id
475
+
476
+ ingress {
477
+ from_port = 6379
478
+ to_port = 6379
479
+ protocol = "tcp"
480
+ cidr_blocks = [module.vpc.vpc_cidr_block]
481
+ }
482
+
483
+ tags = var.tags
484
+ }
485
+ `,
486
+ 'terraform/variables.tf': `variable "project_name" {
487
+ description = "Name of the project"
488
+ type = string
489
+ }
490
+
491
+ variable "aws_region" {
492
+ description = "AWS region"
493
+ type = string
494
+ default = "us-east-1"
495
+ }
496
+
497
+ variable "tags" {
498
+ description = "Tags to apply to resources"
499
+ type = map(string)
500
+ default = {
501
+ ManagedBy = "terraform"
502
+ }
503
+ }
504
+ `,
505
+ 'terraform/outputs.tf': `output "vpc_id" {
506
+ value = module.vpc.vpc_id
507
+ }
508
+
509
+ output "eks_cluster_endpoint" {
510
+ value = module.eks.cluster_endpoint
511
+ }
512
+
513
+ output "rds_endpoint" {
514
+ value = module.rds.db_instance_endpoint
515
+ }
516
+
517
+ output "redis_endpoint" {
518
+ value = aws_elasticache_cluster.main.cache_nodes[0].address
519
+ }
520
+ `,
521
+ },
522
+ },
523
+ minimal: {
524
+ description: 'Minimal Terraform setup with just provider configuration',
525
+ files: {
526
+ 'terraform/main.tf': `# Minimal Terraform Configuration
527
+ # Generated by Nimbus
528
+
529
+ terraform {
530
+ required_version = ">= 1.0"
531
+
532
+ required_providers {
533
+ aws = {
534
+ source = "hashicorp/aws"
535
+ version = "~> 5.0"
536
+ }
537
+ }
538
+
539
+ # Uncomment to use S3 backend
540
+ # backend "s3" {
541
+ # bucket = "your-terraform-state-bucket"
542
+ # key = "terraform.tfstate"
543
+ # region = "us-east-1"
544
+ # }
545
+ }
546
+
547
+ provider "aws" {
548
+ region = var.aws_region
549
+
550
+ default_tags {
551
+ tags = {
552
+ ManagedBy = "terraform"
553
+ Project = var.project_name
554
+ }
555
+ }
556
+ }
557
+ `,
558
+ 'terraform/variables.tf': `variable "project_name" {
559
+ description = "Name of the project"
560
+ type = string
561
+ }
562
+
563
+ variable "aws_region" {
564
+ description = "AWS region"
565
+ type = string
566
+ default = "us-east-1"
567
+ }
568
+
569
+ variable "environment" {
570
+ description = "Environment (dev, staging, prod)"
571
+ type = string
572
+ default = "dev"
573
+ }
574
+ `,
575
+ 'terraform/outputs.tf': `# Add outputs here as you create resources
576
+ `,
577
+ 'terraform/.gitignore': `# Terraform
578
+ *.tfstate
579
+ *.tfstate.*
580
+ .terraform/
581
+ .terraform.lock.hcl
582
+ *.tfvars
583
+ !*.tfvars.example
584
+ crash.log
585
+ override.tf
586
+ override.tf.json
587
+ *_override.tf
588
+ *_override.tf.json
589
+ `,
590
+ },
591
+ },
592
+ };
593
+
594
+ /**
595
+ * Generate template files
596
+ */
597
+ function generateTemplateFiles(templateName: string, outputDir: string, projectName: string): void {
598
+ const template = TEMPLATES[templateName];
599
+ if (!template) {
600
+ return;
601
+ }
602
+
603
+ for (const [filePath, content] of Object.entries(template.files)) {
604
+ const fullPath = path.join(outputDir, filePath);
605
+ const dir = path.dirname(fullPath);
606
+
607
+ if (!fs.existsSync(dir)) {
608
+ fs.mkdirSync(dir, { recursive: true });
609
+ }
610
+
611
+ // Replace project name placeholder
612
+ const finalContent = content.replace(/\$\{var\.project_name\}/g, projectName);
613
+ fs.writeFileSync(fullPath, finalContent);
614
+ }
615
+ }
616
+
617
+ /**
618
+ * Create .gitignore entry for Nimbus
619
+ */
620
+ function createGitignoreEntry(): string {
621
+ return `
622
+ # Nimbus
623
+ .nimbus/
624
+ *.nimbus-session
625
+ `;
626
+ }
627
+
628
+ /**
629
+ * Display scan results in a summary table
630
+ */
631
+ function displayScanSummary(context: ProjectContext): void {
632
+ ui.newLine();
633
+ ui.section('Project Analysis');
634
+
635
+ // Languages
636
+ if (context.structure.languages.length > 0) {
637
+ ui.print(` ${ui.bold('Languages:')}`);
638
+ for (const lang of context.structure.languages.slice(0, 5)) {
639
+ const version = lang.version ? ` (${lang.version})` : '';
640
+ const confidence =
641
+ lang.confidence === 'high' ? ui.color('●', 'green') : ui.color('○', 'yellow');
642
+ ui.print(` ${confidence} ${lang.name}${version}`);
643
+ }
644
+ if (context.structure.languages.length > 5) {
645
+ ui.print(ui.dim(` ... and ${context.structure.languages.length - 5} more`));
646
+ }
647
+ ui.newLine();
648
+ }
649
+
650
+ // Frameworks
651
+ if (context.structure.frameworks.length > 0) {
652
+ ui.print(` ${ui.bold('Frameworks:')}`);
653
+ for (const fw of context.structure.frameworks.slice(0, 5)) {
654
+ const version = fw.version ? ` (${fw.version})` : '';
655
+ const confidence =
656
+ fw.confidence === 'high' ? ui.color('●', 'green') : ui.color('○', 'yellow');
657
+ ui.print(` ${confidence} ${fw.name}${version}`);
658
+ }
659
+ if (context.structure.frameworks.length > 5) {
660
+ ui.print(ui.dim(` ... and ${context.structure.frameworks.length - 5} more`));
661
+ }
662
+ ui.newLine();
663
+ }
664
+
665
+ // Package Managers
666
+ if (context.structure.packageManagers.length > 0) {
667
+ ui.print(` ${ui.bold('Package Managers:')}`);
668
+ const pmList = context.structure.packageManagers.map(pm => pm.name).join(', ');
669
+ ui.print(` ${pmList}`);
670
+ ui.newLine();
671
+ }
672
+
673
+ // Infrastructure
674
+ const hasInfra =
675
+ context.files.terraform.length > 0 ||
676
+ context.files.kubernetes.length > 0 ||
677
+ context.files.docker.length > 0;
678
+ if (hasInfra) {
679
+ ui.print(` ${ui.bold('Infrastructure:')}`);
680
+ if (context.files.terraform.length > 0) {
681
+ ui.print(` ${ui.color('●', 'green')} Terraform (${context.files.terraform.length} files)`);
682
+ }
683
+ if (context.files.kubernetes.length > 0) {
684
+ ui.print(
685
+ ` ${ui.color('●', 'green')} Kubernetes (${context.files.kubernetes.length} files)`
686
+ );
687
+ }
688
+ if (context.files.docker.length > 0) {
689
+ ui.print(` ${ui.color('●', 'green')} Docker (${context.files.docker.length} files)`);
690
+ }
691
+ ui.newLine();
692
+ }
693
+
694
+ // CI/CD
695
+ if (context.cicd.platform) {
696
+ ui.print(` ${ui.bold('CI/CD:')}`);
697
+ ui.print(
698
+ ` ${ui.color('●', 'green')} ${context.cicd.platform} (${context.cicd.workflows.length} workflows)`
699
+ );
700
+ ui.newLine();
701
+ }
702
+
703
+ // Cloud Providers
704
+ if (context.cloud.providers.length > 0) {
705
+ ui.print(` ${ui.bold('Cloud Providers:')}`);
706
+ for (const provider of context.cloud.providers) {
707
+ ui.print(` ${ui.color('●', 'green')} ${provider.toUpperCase()}`);
708
+ }
709
+ if (context.cloud.regions.length > 0) {
710
+ ui.print(` ${ui.dim('Regions:')} ${context.cloud.regions.slice(0, 5).join(', ')}`);
711
+ }
712
+ ui.newLine();
713
+ }
714
+
715
+ // Git Info
716
+ if (context.git.isRepo) {
717
+ ui.print(` ${ui.bold('Git:')}`);
718
+ ui.print(` Branch: ${context.git.branch}`);
719
+ if (context.git.remote) {
720
+ ui.print(` Remote: ${context.git.remote}`);
721
+ }
722
+ ui.newLine();
723
+ }
724
+
725
+ // Project Type
726
+ ui.print(` ${ui.bold('Project Type:')} ${context.structure.type}`);
727
+ ui.newLine();
728
+ }
729
+
730
+ /**
731
+ * Create workspace config.yaml
732
+ */
733
+ function createWorkspaceConfig(options: {
734
+ name: string;
735
+ provider?: string;
736
+ output?: string;
737
+ }): string {
738
+ const lines: string[] = [
739
+ '# Nimbus Workspace Configuration',
740
+ '# This file configures Nimbus for this project.',
741
+ '# See project.yaml for detected project context.',
742
+ '',
743
+ 'workspace:',
744
+ ` name: ${options.name}`,
745
+ ];
746
+
747
+ if (options.provider) {
748
+ lines.push(` defaultProvider: ${options.provider}`);
749
+ }
750
+
751
+ if (options.output) {
752
+ lines.push(` outputDirectory: ${options.output}`);
753
+ }
754
+
755
+ lines.push('');
756
+ lines.push('# Safety settings');
757
+ lines.push('safety:');
758
+ lines.push(' requireApproval: true');
759
+ lines.push(' protectedEnvironments: [production, prod]');
760
+ lines.push(' costThreshold: 500');
761
+
762
+ return `${lines.join('\n')}\n`;
763
+ }
764
+
765
+ /**
766
+ * Init command handler
767
+ */
768
+ export async function initCommand(options: InitOptions = {}): Promise<void> {
769
+ const cwd = process.cwd();
770
+ const nimbusDir = path.join(cwd, NIMBUS_DIR);
771
+ const projectPath = path.join(nimbusDir, PROJECT_FILE);
772
+ const configPath = path.join(nimbusDir, CONFIG_FILE);
773
+
774
+ // Check if already initialized
775
+ if (fs.existsSync(nimbusDir) && !options.force) {
776
+ ui.warning(`Nimbus workspace already exists at: ${nimbusDir}`);
777
+
778
+ if (!options.nonInteractive) {
779
+ const reinit = await confirm({
780
+ message: 'Reinitialize this workspace?',
781
+ defaultValue: false,
782
+ });
783
+
784
+ if (!reinit) {
785
+ ui.info('Workspace unchanged.');
786
+ return;
787
+ }
788
+ } else {
789
+ ui.info('Use --force to reinitialize.');
790
+ return;
791
+ }
792
+ }
793
+
794
+ // Start scanning
795
+ ui.newLine();
796
+ ui.header('Initialize Nimbus Workspace', cwd);
797
+
798
+ const scanDepth = options.scanDepth || 'standard';
799
+ ui.startSpinner({ message: `Scanning project (${scanDepth} mode)...` });
800
+
801
+ // Create scanner and run scan
802
+ const scanner = createProjectScanner();
803
+ const scanOptions: Partial<ScanOptions> = {
804
+ depth: scanDepth,
805
+ instructions: options.instructions,
806
+ maxDepth: options.maxDepth,
807
+ };
808
+
809
+ let context: ProjectContext;
810
+ try {
811
+ context = await scanner.scan(cwd, scanOptions);
812
+ ui.stopSpinnerSuccess('Project scan complete');
813
+ } catch (error) {
814
+ ui.stopSpinnerFail('Project scan failed');
815
+ ui.error((error as Error).message);
816
+ return;
817
+ }
818
+
819
+ // Display scan summary
820
+ displayScanSummary(context);
821
+
822
+ // Interactive configuration
823
+ let projectName = options.name || context.project.name;
824
+ let provider = options.provider;
825
+ let outputDir = options.output;
826
+
827
+ if (!options.nonInteractive) {
828
+ // Project name
829
+ projectName = await input({
830
+ message: 'Project name:',
831
+ defaultValue: context.project.name,
832
+ });
833
+
834
+ // Cloud provider - pre-select if detected
835
+ const detectedProvider = context.cloud.providers[0] || '';
836
+ const providerOptions = [
837
+ { label: 'AWS', value: 'aws', description: 'Amazon Web Services' },
838
+ { label: 'GCP', value: 'gcp', description: 'Google Cloud Platform' },
839
+ { label: 'Azure', value: 'azure', description: 'Microsoft Azure' },
840
+ { label: 'None', value: '', description: 'No default provider' },
841
+ ];
842
+
843
+ // Move detected provider to top
844
+ if (detectedProvider) {
845
+ const idx = providerOptions.findIndex(o => o.value === detectedProvider);
846
+ if (idx > 0) {
847
+ const [detected] = providerOptions.splice(idx, 1);
848
+ detected.label += ' (detected)';
849
+ providerOptions.unshift(detected);
850
+ }
851
+ }
852
+
853
+ provider = (await select({
854
+ message: 'Default cloud provider:',
855
+ options: providerOptions,
856
+ })) as string;
857
+
858
+ // Output directory
859
+ const defaultOutput = context.files.terraform.length > 0 ? './terraform' : './infrastructure';
860
+ outputDir = await input({
861
+ message: 'Output directory for generated code:',
862
+ defaultValue: defaultOutput,
863
+ });
864
+
865
+ // Update .gitignore
866
+ const gitignorePath = path.join(cwd, '.gitignore');
867
+ if (fs.existsSync(gitignorePath)) {
868
+ const gitignoreContent = fs.readFileSync(gitignorePath, 'utf-8');
869
+ if (!gitignoreContent.includes('.nimbus/')) {
870
+ const updateGitignore = await confirm({
871
+ message: 'Add .nimbus/ to .gitignore?',
872
+ defaultValue: true,
873
+ });
874
+
875
+ if (updateGitignore) {
876
+ fs.appendFileSync(gitignorePath, createGitignoreEntry());
877
+ ui.success('Updated .gitignore');
878
+ }
879
+ }
880
+ }
881
+ } else {
882
+ // Non-interactive: use detected or default values
883
+ provider = provider || context.cloud.providers[0] || '';
884
+ outputDir =
885
+ outputDir || (context.files.terraform.length > 0 ? './terraform' : './infrastructure');
886
+ }
887
+
888
+ // Update context with user-provided name
889
+ context.project.name = projectName;
890
+
891
+ // Create .nimbus directory
892
+ if (!fs.existsSync(nimbusDir)) {
893
+ fs.mkdirSync(nimbusDir, { recursive: true });
894
+ }
895
+
896
+ // Generate and write project.yaml
897
+ const projectYaml = generateProjectYaml(context);
898
+ fs.writeFileSync(projectPath, projectYaml);
899
+
900
+ // Generate and write config.yaml
901
+ const configContent = createWorkspaceConfig({
902
+ name: projectName,
903
+ provider: provider || undefined,
904
+ output: outputDir || undefined,
905
+ });
906
+ fs.writeFileSync(configPath, configContent);
907
+
908
+ // Create .gitkeep for empty directories
909
+ const gitkeepPath = path.join(nimbusDir, '.gitkeep');
910
+ if (!fs.existsSync(gitkeepPath)) {
911
+ fs.writeFileSync(gitkeepPath, '');
912
+ }
913
+
914
+ // Initialize context database
915
+ try {
916
+ const contextDb = initContextDatabase(cwd);
917
+ contextDb.recordCommand('init', `--name ${projectName}`, 'success');
918
+ contextDb.close();
919
+ } catch {
920
+ // Non-critical: context DB is optional
921
+ }
922
+
923
+ // Generate template files if specified
924
+ if (options.template) {
925
+ const template = TEMPLATES[options.template];
926
+ if (template) {
927
+ ui.startSpinner({ message: `Generating ${options.template} template...` });
928
+ generateTemplateFiles(options.template, cwd, projectName);
929
+ ui.stopSpinnerSuccess(`Generated ${options.template} template`);
930
+ }
931
+ } else if (!options.nonInteractive && context.files.terraform.length === 0) {
932
+ // Offer to generate a template if no existing Terraform
933
+ const useTemplate = await confirm({
934
+ message: 'No existing Terraform files found. Generate a starter template?',
935
+ defaultValue: true,
936
+ });
937
+
938
+ if (useTemplate) {
939
+ const templateChoice = await select({
940
+ message: 'Select a template:',
941
+ options: [
942
+ { label: 'Minimal', value: 'minimal', description: 'Basic provider setup' },
943
+ { label: 'VPC', value: 'vpc', description: 'AWS VPC with subnets and NAT' },
944
+ { label: 'EKS', value: 'eks', description: 'EKS cluster with VPC' },
945
+ { label: 'Full Stack', value: 'full-stack', description: 'VPC + EKS + RDS + Redis' },
946
+ ],
947
+ });
948
+
949
+ ui.startSpinner({ message: `Generating ${templateChoice} template...` });
950
+ generateTemplateFiles(templateChoice as string, cwd, projectName);
951
+ ui.stopSpinnerSuccess(`Generated ${templateChoice} template`);
952
+ }
953
+ }
954
+
955
+ // Prompt for telemetry opt-in
956
+ if (!options.nonInteractive) {
957
+ ui.newLine();
958
+ const enableTelemetry = await confirm({
959
+ message: 'Enable anonymous usage telemetry? (helps improve Nimbus)',
960
+ defaultValue: false,
961
+ });
962
+
963
+ if (enableTelemetry) {
964
+ try {
965
+ const { homedir } = await import('os');
966
+ const telemetryConfigPath = path.join(homedir(), '.nimbus', 'config.json');
967
+ const telemetryDir = path.join(homedir(), '.nimbus');
968
+
969
+ if (!fs.existsSync(telemetryDir)) {
970
+ fs.mkdirSync(telemetryDir, { recursive: true });
971
+ }
972
+
973
+ let telemetryConfig: any = {};
974
+ try {
975
+ if (fs.existsSync(telemetryConfigPath)) {
976
+ telemetryConfig = JSON.parse(fs.readFileSync(telemetryConfigPath, 'utf-8'));
977
+ }
978
+ } catch {
979
+ /* ignore */
980
+ }
981
+
982
+ const { randomUUID } = await import('crypto');
983
+ telemetryConfig.telemetry = {
984
+ ...telemetryConfig.telemetry,
985
+ enabled: true,
986
+ anonymousId: telemetryConfig.telemetry?.anonymousId || randomUUID(),
987
+ };
988
+ fs.writeFileSync(telemetryConfigPath, JSON.stringify(telemetryConfig, null, 2));
989
+ ui.success('Telemetry enabled');
990
+ } catch {
991
+ // Non-critical
992
+ }
993
+ }
994
+ }
995
+
996
+ ui.newLine();
997
+ ui.success(`Nimbus workspace initialized!`);
998
+ ui.newLine();
999
+ ui.print(` ${ui.dim('Project:')} ${projectName}`);
1000
+ ui.print(` ${ui.dim('Type:')} ${context.structure.type}`);
1001
+ ui.print(` ${ui.dim('Config:')} ${configPath}`);
1002
+ ui.print(` ${ui.dim('Context:')} ${projectPath}`);
1003
+ if (provider) {
1004
+ ui.print(` ${ui.dim('Provider:')} ${provider}`);
1005
+ }
1006
+ if (outputDir) {
1007
+ ui.print(` ${ui.dim('Output:')} ${outputDir}`);
1008
+ }
1009
+ ui.newLine();
1010
+
1011
+ // Show detected summary
1012
+ const summaryItems: string[] = [];
1013
+ if (context.structure.languages.length > 0) {
1014
+ summaryItems.push(`${context.structure.languages.length} languages`);
1015
+ }
1016
+ if (context.structure.frameworks.length > 0) {
1017
+ summaryItems.push(`${context.structure.frameworks.length} frameworks`);
1018
+ }
1019
+ if (context.files.terraform.length > 0) {
1020
+ summaryItems.push('Terraform');
1021
+ }
1022
+ if (context.files.kubernetes.length > 0) {
1023
+ summaryItems.push('Kubernetes');
1024
+ }
1025
+ if (context.cicd.platform) {
1026
+ summaryItems.push(context.cicd.platform);
1027
+ }
1028
+ if (summaryItems.length > 0) {
1029
+ ui.print(ui.dim(` Detected: ${summaryItems.join(', ')}`));
1030
+ ui.newLine();
1031
+ }
1032
+
1033
+ ui.print(ui.dim('Next steps:'));
1034
+ ui.print(` ${ui.dim('1.')} Run ${ui.color('nimbus login', 'cyan')} to configure authentication`);
1035
+ ui.print(` ${ui.dim('2.')} Run ${ui.color('nimbus chat', 'cyan')} to start a conversation`);
1036
+ if (context.files.terraform.length > 0) {
1037
+ ui.print(
1038
+ ` ${ui.dim('3.')} Run ${ui.color('nimbus plan terraform', 'cyan')} to preview infrastructure`
1039
+ );
1040
+ } else {
1041
+ ui.print(
1042
+ ` ${ui.dim('3.')} Run ${ui.color('nimbus generate terraform', 'cyan')} to generate infrastructure`
1043
+ );
1044
+ }
1045
+ ui.newLine();
1046
+ }