@build-astron-co/nimbus 0.2.0 → 0.4.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 (469) hide show
  1. package/bin/nimbus +26 -10
  2. package/bin/nimbus.cmd +41 -0
  3. package/bin/nimbus.mjs +70 -0
  4. package/completions/nimbus.bash +38 -0
  5. package/completions/nimbus.fish +48 -0
  6. package/completions/nimbus.zsh +81 -0
  7. package/dist/src/agent/compaction-agent.js +215 -0
  8. package/dist/src/agent/context-manager.js +385 -0
  9. package/dist/src/agent/context.js +322 -0
  10. package/dist/src/agent/deploy-preview.js +395 -0
  11. package/dist/src/agent/expand-files.js +95 -0
  12. package/dist/src/agent/index.js +18 -0
  13. package/dist/src/agent/loop.js +1535 -0
  14. package/dist/src/agent/modes.js +347 -0
  15. package/dist/src/agent/permissions.js +396 -0
  16. package/dist/src/agent/subagents/base.js +67 -0
  17. package/dist/src/agent/subagents/cost.js +45 -0
  18. package/dist/src/agent/subagents/explore.js +36 -0
  19. package/dist/src/agent/subagents/general.js +41 -0
  20. package/dist/src/agent/subagents/index.js +88 -0
  21. package/dist/src/agent/subagents/infra.js +52 -0
  22. package/dist/src/agent/subagents/security.js +60 -0
  23. package/dist/src/agent/system-prompt.js +860 -0
  24. package/dist/src/app.js +152 -0
  25. package/dist/src/audit/activity-log.js +209 -0
  26. package/dist/src/audit/compliance-checker.js +419 -0
  27. package/dist/src/audit/cost-tracker.js +231 -0
  28. package/dist/src/audit/index.js +10 -0
  29. package/dist/src/audit/security-scanner.js +490 -0
  30. package/dist/src/auth/guard.js +64 -0
  31. package/dist/src/auth/index.js +19 -0
  32. package/dist/src/auth/keychain.js +79 -0
  33. package/dist/src/auth/oauth.js +389 -0
  34. package/dist/src/auth/providers.js +415 -0
  35. package/dist/src/auth/sso.js +87 -0
  36. package/dist/src/auth/store.js +424 -0
  37. package/dist/src/auth/types.js +5 -0
  38. package/dist/src/cli/index.js +8 -0
  39. package/dist/src/cli/init.js +1048 -0
  40. package/dist/src/cli/openapi-spec.js +346 -0
  41. package/dist/src/cli/run.js +505 -0
  42. package/dist/src/cli/serve-auth.js +56 -0
  43. package/dist/src/cli/serve.js +432 -0
  44. package/dist/src/cli/web.js +50 -0
  45. package/dist/src/cli.js +1574 -0
  46. package/dist/src/clients/core-engine-client.js +156 -0
  47. package/dist/src/clients/enterprise-client.js +246 -0
  48. package/dist/src/clients/generator-client.js +219 -0
  49. package/dist/src/clients/git-client.js +367 -0
  50. package/dist/src/clients/github-client.js +229 -0
  51. package/dist/src/clients/helm-client.js +299 -0
  52. package/dist/src/clients/index.js +18 -0
  53. package/dist/src/clients/k8s-client.js +270 -0
  54. package/dist/src/clients/llm-client.js +119 -0
  55. package/dist/src/clients/rest-client.js +104 -0
  56. package/dist/src/clients/service-discovery.js +35 -0
  57. package/dist/src/clients/terraform-client.js +302 -0
  58. package/dist/src/clients/tools-client.js +1227 -0
  59. package/dist/src/clients/ws-client.js +93 -0
  60. package/dist/src/commands/alias.js +91 -0
  61. package/dist/src/commands/analyze/index.js +313 -0
  62. package/dist/src/commands/apply/helm.js +375 -0
  63. package/dist/src/commands/apply/index.js +176 -0
  64. package/dist/src/commands/apply/k8s.js +350 -0
  65. package/dist/src/commands/apply/terraform.js +465 -0
  66. package/dist/src/commands/ask.js +137 -0
  67. package/dist/src/commands/audit/index.js +322 -0
  68. package/dist/src/commands/auth-cloud.js +345 -0
  69. package/dist/src/commands/auth-list.js +112 -0
  70. package/dist/src/commands/auth-profile.js +104 -0
  71. package/dist/src/commands/auth-refresh.js +161 -0
  72. package/dist/src/commands/auth-status.js +122 -0
  73. package/dist/src/commands/aws/ec2.js +402 -0
  74. package/dist/src/commands/aws/iam.js +304 -0
  75. package/dist/src/commands/aws/index.js +108 -0
  76. package/dist/src/commands/aws/lambda.js +317 -0
  77. package/dist/src/commands/aws/rds.js +345 -0
  78. package/dist/src/commands/aws/s3.js +346 -0
  79. package/dist/src/commands/aws/vpc.js +302 -0
  80. package/dist/src/commands/aws-discover.js +413 -0
  81. package/dist/src/commands/aws-terraform.js +618 -0
  82. package/dist/src/commands/azure/aks.js +305 -0
  83. package/dist/src/commands/azure/functions.js +200 -0
  84. package/dist/src/commands/azure/index.js +93 -0
  85. package/dist/src/commands/azure/storage.js +378 -0
  86. package/dist/src/commands/azure/vm.js +291 -0
  87. package/dist/src/commands/billing/index.js +224 -0
  88. package/dist/src/commands/chat.js +259 -0
  89. package/dist/src/commands/completions.js +255 -0
  90. package/dist/src/commands/config.js +291 -0
  91. package/dist/src/commands/cost/cloud-cost-estimator.js +211 -0
  92. package/dist/src/commands/cost/estimator.js +73 -0
  93. package/dist/src/commands/cost/index.js +625 -0
  94. package/dist/src/commands/cost/parsers/terraform.js +234 -0
  95. package/dist/src/commands/cost/parsers/types.js +4 -0
  96. package/dist/src/commands/cost/pricing/aws.js +501 -0
  97. package/dist/src/commands/cost/pricing/azure.js +462 -0
  98. package/dist/src/commands/cost/pricing/gcp.js +359 -0
  99. package/dist/src/commands/cost/pricing/index.js +24 -0
  100. package/dist/src/commands/demo.js +196 -0
  101. package/dist/src/commands/deploy.js +215 -0
  102. package/dist/src/commands/doctor.js +1291 -0
  103. package/dist/src/commands/drift/index.js +674 -0
  104. package/dist/src/commands/explain.js +235 -0
  105. package/dist/src/commands/export.js +120 -0
  106. package/dist/src/commands/feedback.js +319 -0
  107. package/dist/src/commands/fix.js +263 -0
  108. package/dist/src/commands/fs/index.js +338 -0
  109. package/dist/src/commands/gcp/compute.js +266 -0
  110. package/dist/src/commands/gcp/functions.js +221 -0
  111. package/dist/src/commands/gcp/gke.js +357 -0
  112. package/dist/src/commands/gcp/iam.js +295 -0
  113. package/dist/src/commands/gcp/index.js +105 -0
  114. package/dist/src/commands/gcp/storage.js +232 -0
  115. package/dist/src/commands/generate-helm.js +1026 -0
  116. package/dist/src/commands/generate-k8s.js +1263 -0
  117. package/dist/src/commands/generate-terraform.js +1058 -0
  118. package/dist/src/commands/gh/index.js +663 -0
  119. package/dist/src/commands/git/index.js +1208 -0
  120. package/dist/src/commands/helm/index.js +985 -0
  121. package/dist/src/commands/help.js +639 -0
  122. package/dist/src/commands/history.js +120 -0
  123. package/dist/src/commands/import.js +782 -0
  124. package/dist/src/commands/incident.js +144 -0
  125. package/dist/src/commands/index.js +109 -0
  126. package/dist/src/commands/init.js +955 -0
  127. package/dist/src/commands/k8s/index.js +979 -0
  128. package/dist/src/commands/login.js +588 -0
  129. package/dist/src/commands/logout.js +61 -0
  130. package/dist/src/commands/logs.js +160 -0
  131. package/dist/src/commands/onboarding.js +382 -0
  132. package/dist/src/commands/pipeline.js +153 -0
  133. package/dist/src/commands/plan/display.js +216 -0
  134. package/dist/src/commands/plan/index.js +525 -0
  135. package/dist/src/commands/plugin.js +325 -0
  136. package/dist/src/commands/preview.js +356 -0
  137. package/dist/src/commands/profile.js +297 -0
  138. package/dist/src/commands/questionnaire.js +1021 -0
  139. package/dist/src/commands/resume.js +35 -0
  140. package/dist/src/commands/rollback.js +259 -0
  141. package/dist/src/commands/rollout.js +74 -0
  142. package/dist/src/commands/runbook.js +307 -0
  143. package/dist/src/commands/schedule.js +202 -0
  144. package/dist/src/commands/status.js +213 -0
  145. package/dist/src/commands/team/index.js +309 -0
  146. package/dist/src/commands/team-context.js +200 -0
  147. package/dist/src/commands/template.js +204 -0
  148. package/dist/src/commands/tf/index.js +989 -0
  149. package/dist/src/commands/upgrade.js +515 -0
  150. package/dist/src/commands/usage/index.js +118 -0
  151. package/dist/src/commands/version.js +145 -0
  152. package/dist/src/commands/watch.js +127 -0
  153. package/dist/src/compat/index.js +2 -0
  154. package/dist/src/compat/runtime.js +10 -0
  155. package/dist/src/compat/sqlite.js +144 -0
  156. package/dist/src/config/index.js +6 -0
  157. package/dist/src/config/manager.js +469 -0
  158. package/dist/src/config/mode-store.js +57 -0
  159. package/dist/src/config/profiles.js +66 -0
  160. package/dist/src/config/safety-policy.js +251 -0
  161. package/dist/src/config/schema.js +107 -0
  162. package/dist/src/config/types.js +311 -0
  163. package/dist/src/config/workspace-state.js +38 -0
  164. package/dist/src/context/context-db.js +138 -0
  165. package/dist/src/demo/index.js +295 -0
  166. package/dist/src/demo/scenarios/full-journey.js +226 -0
  167. package/dist/src/demo/scenarios/getting-started.js +124 -0
  168. package/dist/src/demo/scenarios/helm-release.js +334 -0
  169. package/dist/src/demo/scenarios/k8s-deployment.js +190 -0
  170. package/dist/src/demo/scenarios/terraform-vpc.js +167 -0
  171. package/dist/src/demo/types.js +6 -0
  172. package/dist/src/engine/cost-estimator.js +334 -0
  173. package/dist/src/engine/diagram-generator.js +192 -0
  174. package/dist/src/engine/drift-detector.js +688 -0
  175. package/dist/src/engine/executor.js +832 -0
  176. package/dist/src/engine/index.js +39 -0
  177. package/dist/src/engine/orchestrator.js +436 -0
  178. package/dist/src/engine/planner.js +616 -0
  179. package/dist/src/engine/safety.js +609 -0
  180. package/dist/src/engine/verifier.js +664 -0
  181. package/dist/src/enterprise/audit.js +241 -0
  182. package/dist/src/enterprise/auth.js +189 -0
  183. package/dist/src/enterprise/billing.js +512 -0
  184. package/dist/src/enterprise/index.js +16 -0
  185. package/dist/src/enterprise/teams.js +315 -0
  186. package/dist/src/generator/best-practices.js +1375 -0
  187. package/dist/src/generator/helm.js +495 -0
  188. package/dist/src/generator/index.js +11 -0
  189. package/dist/src/generator/intent-parser.js +420 -0
  190. package/dist/src/generator/kubernetes.js +773 -0
  191. package/dist/src/generator/terraform.js +1472 -0
  192. package/dist/src/history/index.js +6 -0
  193. package/dist/src/history/manager.js +199 -0
  194. package/dist/src/history/types.js +6 -0
  195. package/dist/src/hooks/config.js +318 -0
  196. package/dist/src/hooks/engine.js +317 -0
  197. package/dist/src/hooks/index.js +2 -0
  198. package/dist/src/llm/auth-bridge.js +157 -0
  199. package/dist/src/llm/circuit-breaker.js +116 -0
  200. package/dist/src/llm/config-loader.js +172 -0
  201. package/dist/src/llm/cost-calculator.js +137 -0
  202. package/dist/src/llm/index.js +7 -0
  203. package/dist/src/llm/model-aliases.js +99 -0
  204. package/dist/src/llm/provider-registry.js +57 -0
  205. package/dist/src/llm/providers/anthropic.js +430 -0
  206. package/dist/src/llm/providers/bedrock.js +409 -0
  207. package/dist/src/llm/providers/google.js +344 -0
  208. package/dist/src/llm/providers/ollama.js +661 -0
  209. package/dist/src/llm/providers/openai-compatible.js +289 -0
  210. package/dist/src/llm/providers/openai.js +284 -0
  211. package/dist/src/llm/providers/openrouter.js +293 -0
  212. package/dist/src/llm/router.js +844 -0
  213. package/dist/src/llm/types.js +69 -0
  214. package/dist/src/lsp/client.js +239 -0
  215. package/dist/src/lsp/languages.js +95 -0
  216. package/dist/src/lsp/manager.js +243 -0
  217. package/dist/src/mcp/client.js +289 -0
  218. package/dist/src/mcp/index.js +5 -0
  219. package/dist/src/mcp/manager.js +113 -0
  220. package/dist/src/nimbus.js +212 -0
  221. package/dist/src/plugins/index.js +13 -0
  222. package/dist/src/plugins/loader.js +280 -0
  223. package/dist/src/plugins/manager.js +282 -0
  224. package/dist/src/plugins/types.js +23 -0
  225. package/dist/src/scanners/cicd-scanner.js +230 -0
  226. package/dist/src/scanners/cloud-scanner.js +415 -0
  227. package/dist/src/scanners/framework-scanner.js +430 -0
  228. package/dist/src/scanners/iac-scanner.js +350 -0
  229. package/dist/src/scanners/index.js +454 -0
  230. package/dist/src/scanners/language-scanner.js +258 -0
  231. package/dist/src/scanners/package-manager-scanner.js +252 -0
  232. package/dist/src/scanners/types.js +6 -0
  233. package/dist/src/sessions/manager.js +395 -0
  234. package/dist/src/sessions/types.js +4 -0
  235. package/dist/src/sharing/sync.js +238 -0
  236. package/dist/src/sharing/viewer.js +131 -0
  237. package/dist/src/snapshots/index.js +1 -0
  238. package/dist/src/snapshots/manager.js +432 -0
  239. package/dist/src/state/artifacts.js +94 -0
  240. package/dist/src/state/audit.js +73 -0
  241. package/dist/src/state/billing.js +126 -0
  242. package/dist/src/state/checkpoints.js +81 -0
  243. package/dist/src/state/config.js +58 -0
  244. package/dist/src/state/conversations.js +7 -0
  245. package/dist/src/state/credentials.js +96 -0
  246. package/dist/src/state/db.js +53 -0
  247. package/dist/src/state/index.js +23 -0
  248. package/dist/src/state/messages.js +76 -0
  249. package/dist/src/state/projects.js +92 -0
  250. package/dist/src/state/schema.js +233 -0
  251. package/dist/src/state/sessions.js +79 -0
  252. package/dist/src/state/teams.js +131 -0
  253. package/dist/src/telemetry.js +91 -0
  254. package/dist/src/tools/aws-ops.js +747 -0
  255. package/dist/src/tools/azure-ops.js +491 -0
  256. package/dist/src/tools/file-ops.js +451 -0
  257. package/dist/src/tools/gcp-ops.js +559 -0
  258. package/dist/src/tools/git-ops.js +557 -0
  259. package/dist/src/tools/github-ops.js +460 -0
  260. package/dist/src/tools/helm-ops.js +634 -0
  261. package/dist/src/tools/index.js +16 -0
  262. package/dist/src/tools/k8s-ops.js +579 -0
  263. package/dist/src/tools/schemas/converter.js +129 -0
  264. package/dist/src/tools/schemas/devops.js +3319 -0
  265. package/dist/src/tools/schemas/index.js +19 -0
  266. package/dist/src/tools/schemas/standard.js +966 -0
  267. package/dist/src/tools/schemas/types.js +409 -0
  268. package/dist/src/tools/spawn-exec.js +109 -0
  269. package/dist/src/tools/terraform-ops.js +627 -0
  270. package/dist/src/types/config.js +1 -0
  271. package/dist/src/types/drift.js +4 -0
  272. package/dist/src/types/enterprise.js +5 -0
  273. package/dist/src/types/index.js +14 -0
  274. package/dist/src/types/plan.js +1 -0
  275. package/dist/src/types/request.js +1 -0
  276. package/dist/src/types/response.js +1 -0
  277. package/dist/src/types/service.js +1 -0
  278. package/dist/src/ui/App.js +1672 -0
  279. package/dist/src/ui/DeployPreview.js +60 -0
  280. package/dist/src/ui/FileDiffModal.js +108 -0
  281. package/dist/src/ui/Header.js +46 -0
  282. package/dist/src/ui/HelpModal.js +9 -0
  283. package/dist/src/ui/InputBox.js +408 -0
  284. package/dist/src/ui/MessageList.js +795 -0
  285. package/dist/src/ui/PermissionPrompt.js +72 -0
  286. package/dist/src/ui/StatusBar.js +109 -0
  287. package/dist/src/ui/TerminalPane.js +31 -0
  288. package/dist/src/ui/ToolCallDisplay.js +303 -0
  289. package/dist/src/ui/TreePane.js +83 -0
  290. package/dist/src/ui/chat-ui.js +721 -0
  291. package/dist/src/ui/index.js +11 -0
  292. package/dist/src/ui/ink/index.js +1325 -0
  293. package/dist/src/ui/streaming.js +137 -0
  294. package/dist/src/ui/theme.js +78 -0
  295. package/dist/src/ui/types.js +7 -0
  296. package/dist/src/utils/analytics.js +61 -0
  297. package/dist/src/utils/cost-warning.js +25 -0
  298. package/dist/src/utils/env.js +42 -0
  299. package/dist/src/utils/errors.js +54 -0
  300. package/dist/src/utils/event-bus.js +22 -0
  301. package/dist/src/utils/index.js +16 -0
  302. package/dist/src/utils/logger.js +150 -0
  303. package/dist/src/utils/rate-limiter.js +90 -0
  304. package/dist/src/utils/service-auth.js +36 -0
  305. package/dist/src/utils/validation.js +39 -0
  306. package/dist/src/version.js +3 -0
  307. package/dist/src/watcher/index.js +192 -0
  308. package/dist/src/wizard/approval.js +275 -0
  309. package/dist/src/wizard/index.js +13 -0
  310. package/dist/src/wizard/prompts.js +273 -0
  311. package/dist/src/wizard/types.js +4 -0
  312. package/dist/src/wizard/ui.js +453 -0
  313. package/dist/src/wizard/wizard.js +227 -0
  314. package/package.json +31 -23
  315. package/src/__tests__/alias.test.ts +133 -0
  316. package/src/__tests__/app.test.ts +1 -1
  317. package/src/__tests__/audit.test.ts +1 -1
  318. package/src/__tests__/circuit-breaker.test.ts +1 -1
  319. package/src/__tests__/cli-run.test.ts +237 -1
  320. package/src/__tests__/compat-sqlite.test.ts +68 -0
  321. package/src/__tests__/context-manager.test.ts +131 -1
  322. package/src/__tests__/context.test.ts +1 -1
  323. package/src/__tests__/devops-terminal-gaps.test.ts +718 -0
  324. package/src/__tests__/doctor.test.ts +48 -0
  325. package/src/__tests__/enterprise.test.ts +1 -1
  326. package/src/__tests__/export.test.ts +236 -0
  327. package/src/__tests__/gap-11-18-20.test.ts +958 -0
  328. package/src/__tests__/generator.test.ts +1 -1
  329. package/src/__tests__/helm-streaming.test.ts +127 -0
  330. package/src/__tests__/hooks.test.ts +1 -1
  331. package/src/__tests__/incident.test.ts +179 -0
  332. package/src/__tests__/init.test.ts +55 -4
  333. package/src/__tests__/intent-parser.test.ts +1 -1
  334. package/src/__tests__/llm-router.test.ts +1 -1
  335. package/src/__tests__/logs.test.ts +107 -0
  336. package/src/__tests__/loop-errors.test.ts +244 -0
  337. package/src/__tests__/lsp.test.ts +1 -1
  338. package/src/__tests__/modes.test.ts +1 -1
  339. package/src/__tests__/perf-optimizations.test.ts +847 -0
  340. package/src/__tests__/permissions.test.ts +1 -1
  341. package/src/__tests__/pipeline.test.ts +50 -0
  342. package/src/__tests__/polish-phase3.test.ts +340 -0
  343. package/src/__tests__/profile.test.ts +237 -0
  344. package/src/__tests__/rollback.test.ts +83 -0
  345. package/src/__tests__/runbook.test.ts +219 -0
  346. package/src/__tests__/schedule.test.ts +206 -0
  347. package/src/__tests__/serve.test.ts +1 -1
  348. package/src/__tests__/sessions.test.ts +96 -1
  349. package/src/__tests__/sharing.test.ts +53 -1
  350. package/src/__tests__/snapshots.test.ts +1 -1
  351. package/src/__tests__/standalone-migration.test.ts +199 -0
  352. package/src/__tests__/state-db.test.ts +1 -1
  353. package/src/__tests__/status.test.ts +158 -0
  354. package/src/__tests__/stream-with-tools.test.ts +71 -25
  355. package/src/__tests__/subagents.test.ts +1 -1
  356. package/src/__tests__/system-prompt.test.ts +82 -3
  357. package/src/__tests__/terminal-gap-v2.test.ts +395 -0
  358. package/src/__tests__/terminal-parity.test.ts +393 -0
  359. package/src/__tests__/tf-apply.test.ts +187 -0
  360. package/src/__tests__/tool-converter.test.ts +1 -1
  361. package/src/__tests__/tool-schemas.test.ts +209 -4
  362. package/src/__tests__/tools.test.ts +4 -3
  363. package/src/__tests__/version-json.test.ts +184 -0
  364. package/src/__tests__/version.test.ts +1 -1
  365. package/src/__tests__/watch.test.ts +129 -0
  366. package/src/agent/compaction-agent.ts +40 -1
  367. package/src/agent/context-manager.ts +67 -3
  368. package/src/agent/deploy-preview.ts +62 -1
  369. package/src/agent/expand-files.ts +108 -0
  370. package/src/agent/loop.ts +1312 -31
  371. package/src/agent/permissions.ts +51 -4
  372. package/src/agent/system-prompt.ts +573 -19
  373. package/src/app.ts +58 -0
  374. package/src/audit/security-scanner.ts +45 -0
  375. package/src/auth/keychain.ts +82 -0
  376. package/src/auth/oauth.ts +15 -5
  377. package/src/cli/init.ts +378 -5
  378. package/src/cli/run.ts +407 -16
  379. package/src/cli/serve.ts +78 -1
  380. package/src/cli/web.ts +10 -6
  381. package/src/cli.ts +312 -1
  382. package/src/clients/service-discovery.ts +30 -25
  383. package/src/commands/alias.ts +100 -0
  384. package/src/commands/audit/index.ts +121 -2
  385. package/src/commands/auth-cloud.ts +113 -0
  386. package/src/commands/auth-refresh.ts +187 -0
  387. package/src/commands/aws-discover.ts +144 -251
  388. package/src/commands/aws-terraform.ts +68 -118
  389. package/src/commands/chat.ts +9 -3
  390. package/src/commands/completions.ts +268 -0
  391. package/src/commands/config.ts +26 -0
  392. package/src/commands/cost/index.ts +218 -2
  393. package/src/commands/deploy.ts +260 -0
  394. package/src/commands/doctor.ts +744 -152
  395. package/src/commands/drift/index.ts +371 -23
  396. package/src/commands/export.ts +146 -0
  397. package/src/commands/generate-k8s.ts +9 -61
  398. package/src/commands/generate-terraform.ts +191 -449
  399. package/src/commands/help.ts +212 -36
  400. package/src/commands/history.ts +8 -1
  401. package/src/commands/incident.ts +166 -0
  402. package/src/commands/init.ts +5 -0
  403. package/src/commands/login.ts +86 -1
  404. package/src/commands/logs.ts +167 -0
  405. package/src/commands/onboarding.ts +211 -34
  406. package/src/commands/pipeline.ts +186 -0
  407. package/src/commands/plugin.ts +398 -0
  408. package/src/commands/profile.ts +342 -0
  409. package/src/commands/questionnaire.ts +0 -98
  410. package/src/commands/resume.ts +26 -34
  411. package/src/commands/rollback.ts +315 -0
  412. package/src/commands/rollout.ts +88 -0
  413. package/src/commands/runbook.ts +346 -0
  414. package/src/commands/schedule.ts +236 -0
  415. package/src/commands/status.ts +252 -0
  416. package/src/commands/team-context.ts +220 -0
  417. package/src/commands/template.ts +58 -57
  418. package/src/commands/tf/index.ts +70 -11
  419. package/src/commands/upgrade.ts +57 -0
  420. package/src/commands/version.ts +54 -50
  421. package/src/commands/watch.ts +153 -0
  422. package/src/compat/runtime.ts +1 -1
  423. package/src/compat/sqlite.ts +75 -5
  424. package/src/config/mode-store.ts +62 -0
  425. package/src/config/profiles.ts +84 -0
  426. package/src/config/types.ts +83 -1
  427. package/src/config/workspace-state.ts +53 -0
  428. package/src/engine/cost-estimator.ts +52 -10
  429. package/src/engine/executor.ts +33 -2
  430. package/src/engine/planner.ts +68 -1
  431. package/src/generator/terraform.ts +8 -0
  432. package/src/history/manager.ts +2 -74
  433. package/src/hooks/engine.ts +5 -4
  434. package/src/llm/cost-calculator.ts +2 -2
  435. package/src/llm/providers/anthropic.ts +50 -21
  436. package/src/llm/router.ts +76 -7
  437. package/src/lsp/languages.ts +3 -0
  438. package/src/lsp/manager.ts +21 -5
  439. package/src/nimbus.ts +37 -18
  440. package/src/sessions/manager.ts +108 -1
  441. package/src/sharing/sync.ts +4 -0
  442. package/src/sharing/viewer.ts +66 -0
  443. package/src/tools/file-ops.ts +22 -0
  444. package/src/tools/schemas/devops.ts +3007 -117
  445. package/src/tools/schemas/standard.ts +5 -1
  446. package/src/tools/schemas/types.ts +31 -1
  447. package/src/tools/spawn-exec.ts +148 -0
  448. package/src/ui/App.tsx +1183 -66
  449. package/src/ui/DeployPreview.tsx +62 -57
  450. package/src/ui/FileDiffModal.tsx +162 -0
  451. package/src/ui/Header.tsx +87 -24
  452. package/src/ui/HelpModal.tsx +57 -0
  453. package/src/ui/InputBox.tsx +163 -10
  454. package/src/ui/MessageList.tsx +487 -40
  455. package/src/ui/PermissionPrompt.tsx +17 -5
  456. package/src/ui/StatusBar.tsx +122 -3
  457. package/src/ui/TerminalPane.tsx +84 -0
  458. package/src/ui/ToolCallDisplay.tsx +252 -18
  459. package/src/ui/TreePane.tsx +132 -0
  460. package/src/ui/chat-ui.ts +41 -44
  461. package/src/ui/ink/index.ts +771 -38
  462. package/src/ui/streaming.ts +1 -1
  463. package/src/ui/theme.ts +104 -0
  464. package/src/ui/types.ts +18 -0
  465. package/src/version.ts +1 -1
  466. package/src/watcher/index.ts +66 -15
  467. package/src/wizard/types.ts +1 -0
  468. package/src/wizard/ui.ts +1 -1
  469. package/tsconfig.json +2 -2
@@ -0,0 +1,1026 @@
1
+ /**
2
+ * Generate Helm Values Command
3
+ *
4
+ * Interactive wizard for generating Helm values files
5
+ *
6
+ * Usage: nimbus generate helm [options]
7
+ */
8
+ import { logger } from '../utils';
9
+ import { createWizard, ui, select, confirm, input, pathInput, } from '../wizard';
10
+ import { helmClient } from '../clients';
11
+ /**
12
+ * Popular Helm charts with their repos
13
+ */
14
+ const POPULAR_CHARTS = [
15
+ {
16
+ name: 'nginx',
17
+ repo: 'bitnami',
18
+ url: 'https://charts.bitnami.com/bitnami',
19
+ description: 'NGINX web server',
20
+ },
21
+ {
22
+ name: 'postgresql',
23
+ repo: 'bitnami',
24
+ url: 'https://charts.bitnami.com/bitnami',
25
+ description: 'PostgreSQL database',
26
+ },
27
+ {
28
+ name: 'redis',
29
+ repo: 'bitnami',
30
+ url: 'https://charts.bitnami.com/bitnami',
31
+ description: 'Redis cache',
32
+ },
33
+ {
34
+ name: 'mysql',
35
+ repo: 'bitnami',
36
+ url: 'https://charts.bitnami.com/bitnami',
37
+ description: 'MySQL database',
38
+ },
39
+ {
40
+ name: 'mongodb',
41
+ repo: 'bitnami',
42
+ url: 'https://charts.bitnami.com/bitnami',
43
+ description: 'MongoDB database',
44
+ },
45
+ {
46
+ name: 'kafka',
47
+ repo: 'bitnami',
48
+ url: 'https://charts.bitnami.com/bitnami',
49
+ description: 'Apache Kafka',
50
+ },
51
+ {
52
+ name: 'rabbitmq',
53
+ repo: 'bitnami',
54
+ url: 'https://charts.bitnami.com/bitnami',
55
+ description: 'RabbitMQ message broker',
56
+ },
57
+ {
58
+ name: 'elasticsearch',
59
+ repo: 'elastic',
60
+ url: 'https://helm.elastic.co',
61
+ description: 'Elasticsearch search engine',
62
+ },
63
+ {
64
+ name: 'prometheus',
65
+ repo: 'prometheus-community',
66
+ url: 'https://prometheus-community.github.io/helm-charts',
67
+ description: 'Prometheus monitoring',
68
+ },
69
+ {
70
+ name: 'grafana',
71
+ repo: 'grafana',
72
+ url: 'https://grafana.github.io/helm-charts',
73
+ description: 'Grafana dashboards',
74
+ },
75
+ ];
76
+ /**
77
+ * Run the generate helm command
78
+ */
79
+ export async function generateHelmCommand(options = {}) {
80
+ logger.info('Starting Helm values generation wizard');
81
+ // Non-interactive mode
82
+ if (options.nonInteractive) {
83
+ await runNonInteractive(options);
84
+ return;
85
+ }
86
+ // Interactive wizard mode
87
+ const wizard = createWizard({
88
+ title: 'nimbus generate helm',
89
+ description: 'Generate Helm values files for your deployment',
90
+ initialContext: {
91
+ chart: options.chart,
92
+ releaseName: options.releaseName,
93
+ namespace: options.namespace,
94
+ environment: options.environment,
95
+ includeSecrets: options.includeSecrets,
96
+ outputPath: options.output,
97
+ chartVersion: options.version,
98
+ },
99
+ steps: createWizardSteps(),
100
+ onEvent: event => {
101
+ logger.debug('Wizard event', { type: event.type });
102
+ },
103
+ });
104
+ const result = await wizard.run();
105
+ if (result.success) {
106
+ ui.newLine();
107
+ ui.box({
108
+ title: 'Complete!',
109
+ content: [
110
+ 'Your Helm values have been generated.',
111
+ '',
112
+ 'Generated files:',
113
+ ...(result.context.generatedFiles?.map(f => ` - ${f}`) || [' - values.yaml']),
114
+ '',
115
+ 'Next steps:',
116
+ ` 1. Review the generated files in ${result.context.outputPath}`,
117
+ ' 2. Customize values as needed for your environment',
118
+ ` 3. Run "helm install ${result.context.releaseName} ${result.context.chart} -f <values-file>"`,
119
+ ' or use "nimbus apply helm"',
120
+ ],
121
+ style: 'rounded',
122
+ borderColor: 'green',
123
+ padding: 1,
124
+ });
125
+ }
126
+ else {
127
+ ui.error(`Wizard failed: ${result.error?.message || 'Unknown error'}`);
128
+ process.exit(1);
129
+ }
130
+ }
131
+ /**
132
+ * Create wizard steps
133
+ */
134
+ function createWizardSteps() {
135
+ return [
136
+ // Step 1: Chart Selection
137
+ {
138
+ id: 'chart-selection',
139
+ title: 'Chart Selection',
140
+ description: 'Select a Helm chart to configure',
141
+ execute: chartSelectionStep,
142
+ },
143
+ // Step 2: Release Configuration
144
+ {
145
+ id: 'release-config',
146
+ title: 'Release Configuration',
147
+ description: 'Configure release name and namespace',
148
+ execute: releaseConfigStep,
149
+ },
150
+ // Step 3: Environment Selection
151
+ {
152
+ id: 'environment',
153
+ title: 'Environment Selection',
154
+ description: 'Select target environment',
155
+ execute: environmentStep,
156
+ },
157
+ // Step 4: Image Configuration
158
+ {
159
+ id: 'image-config',
160
+ title: 'Image Configuration',
161
+ description: 'Configure container image settings',
162
+ execute: imageConfigStep,
163
+ },
164
+ // Step 5: Resource Configuration
165
+ {
166
+ id: 'resources',
167
+ title: 'Resource Configuration',
168
+ description: 'Configure replicas and resource limits',
169
+ execute: resourceConfigStep,
170
+ },
171
+ // Step 6: Service Configuration
172
+ {
173
+ id: 'service-config',
174
+ title: 'Service Configuration',
175
+ description: 'Configure service exposure',
176
+ execute: serviceConfigStep,
177
+ },
178
+ // Step 7: Ingress Configuration
179
+ {
180
+ id: 'ingress-config',
181
+ title: 'Ingress Configuration',
182
+ description: 'Configure ingress settings',
183
+ execute: ingressConfigStep,
184
+ },
185
+ // Step 8: Secrets Configuration
186
+ {
187
+ id: 'secrets-config',
188
+ title: 'Secrets Configuration',
189
+ description: 'Configure secret values',
190
+ execute: secretsConfigStep,
191
+ },
192
+ // Step 9: Output Configuration
193
+ {
194
+ id: 'output',
195
+ title: 'Output Configuration',
196
+ description: 'Configure where to save the values files',
197
+ execute: outputConfigStep,
198
+ },
199
+ // Step 10: Generate
200
+ {
201
+ id: 'generate',
202
+ title: 'Generate Values',
203
+ description: 'Generating your Helm values files...',
204
+ execute: generateStep,
205
+ },
206
+ ];
207
+ }
208
+ /**
209
+ * Step 1: Chart Selection
210
+ */
211
+ async function chartSelectionStep(ctx) {
212
+ // Chart source selection
213
+ const chartSource = await select({
214
+ message: 'How would you like to select a chart?',
215
+ options: [
216
+ {
217
+ value: 'popular',
218
+ label: 'Popular charts',
219
+ description: 'Choose from commonly used Helm charts',
220
+ },
221
+ {
222
+ value: 'repo',
223
+ label: 'From repository',
224
+ description: 'Specify a chart from a Helm repository',
225
+ },
226
+ {
227
+ value: 'local',
228
+ label: 'Local chart',
229
+ description: 'Use a local chart directory',
230
+ },
231
+ ],
232
+ });
233
+ if (!chartSource) {
234
+ return { success: false, error: 'No chart source selected' };
235
+ }
236
+ let chart;
237
+ let repoName;
238
+ let repoUrl;
239
+ let localPath;
240
+ let chartVersion;
241
+ if (chartSource === 'popular') {
242
+ // Show popular charts
243
+ ui.newLine();
244
+ const selectedChart = await select({
245
+ message: 'Select a popular chart:',
246
+ options: POPULAR_CHARTS.map(c => ({
247
+ value: c.name,
248
+ label: `${c.repo}/${c.name}`,
249
+ description: c.description,
250
+ })),
251
+ });
252
+ if (!selectedChart) {
253
+ return { success: false, error: 'No chart selected' };
254
+ }
255
+ const chartInfo = POPULAR_CHARTS.find(c => c.name === selectedChart);
256
+ chart = `${chartInfo.repo}/${chartInfo.name}`;
257
+ repoName = chartInfo.repo;
258
+ repoUrl = chartInfo.url;
259
+ }
260
+ else if (chartSource === 'repo') {
261
+ // Manual chart specification
262
+ ui.newLine();
263
+ repoName = await input({
264
+ message: 'Repository name (e.g., bitnami):',
265
+ defaultValue: ctx.repoName,
266
+ });
267
+ repoUrl = await input({
268
+ message: 'Repository URL:',
269
+ defaultValue: ctx.repoUrl,
270
+ });
271
+ const chartName = await input({
272
+ message: 'Chart name:',
273
+ defaultValue: ctx.chart?.split('/')[1],
274
+ });
275
+ if (!chartName) {
276
+ return { success: false, error: 'Chart name is required' };
277
+ }
278
+ chart = repoName ? `${repoName}/${chartName}` : chartName;
279
+ }
280
+ else {
281
+ // Local chart
282
+ ui.newLine();
283
+ localPath = await pathInput('Path to local chart:', ctx.localPath || './chart');
284
+ if (!localPath) {
285
+ return { success: false, error: 'Chart path is required' };
286
+ }
287
+ chart = localPath;
288
+ }
289
+ // Version selection
290
+ if (chartSource !== 'local') {
291
+ ui.newLine();
292
+ const specifyVersion = await confirm({
293
+ message: 'Specify a chart version?',
294
+ defaultValue: false,
295
+ });
296
+ if (specifyVersion) {
297
+ chartVersion = await input({
298
+ message: 'Chart version:',
299
+ defaultValue: ctx.chartVersion,
300
+ });
301
+ }
302
+ }
303
+ return {
304
+ success: true,
305
+ data: {
306
+ chartSource: chartSource === 'popular' ? 'repo' : chartSource,
307
+ chart,
308
+ repoName,
309
+ repoUrl,
310
+ localPath,
311
+ chartVersion,
312
+ },
313
+ };
314
+ }
315
+ /**
316
+ * Step 2: Release Configuration
317
+ */
318
+ async function releaseConfigStep(ctx) {
319
+ // Extract chart name for default release name
320
+ const chartName = ctx.chart?.split('/').pop() || 'release';
321
+ const releaseName = await input({
322
+ message: 'Release name:',
323
+ defaultValue: ctx.releaseName || chartName,
324
+ validate: value => {
325
+ if (!value) {
326
+ return 'Release name is required';
327
+ }
328
+ if (!/^[a-z0-9]([-a-z0-9]*[a-z0-9])?$/.test(value)) {
329
+ return 'Release name must be lowercase alphanumeric with dashes only';
330
+ }
331
+ return true;
332
+ },
333
+ });
334
+ if (!releaseName) {
335
+ return { success: false, error: 'Release name is required' };
336
+ }
337
+ ui.newLine();
338
+ const namespace = await input({
339
+ message: 'Namespace:',
340
+ defaultValue: ctx.namespace || 'default',
341
+ validate: value => {
342
+ if (!value) {
343
+ return 'Namespace is required';
344
+ }
345
+ if (!/^[a-z0-9]([-a-z0-9]*[a-z0-9])?$/.test(value)) {
346
+ return 'Namespace must be lowercase alphanumeric with dashes only';
347
+ }
348
+ return true;
349
+ },
350
+ });
351
+ if (!namespace) {
352
+ return { success: false, error: 'Namespace is required' };
353
+ }
354
+ return {
355
+ success: true,
356
+ data: { releaseName, namespace },
357
+ };
358
+ }
359
+ /**
360
+ * Step 3: Environment Selection
361
+ */
362
+ async function environmentStep(ctx) {
363
+ const environment = await select({
364
+ message: 'Target environment:',
365
+ options: [
366
+ {
367
+ value: 'dev',
368
+ label: 'Development',
369
+ description: 'Local development settings (minimal resources)',
370
+ },
371
+ {
372
+ value: 'staging',
373
+ label: 'Staging',
374
+ description: 'Pre-production testing environment',
375
+ },
376
+ {
377
+ value: 'production',
378
+ label: 'Production',
379
+ description: 'Production-ready settings (HA, security hardening)',
380
+ },
381
+ ],
382
+ defaultValue: ctx.environment || 'dev',
383
+ });
384
+ if (!environment) {
385
+ return { success: false, error: 'No environment selected' };
386
+ }
387
+ return {
388
+ success: true,
389
+ data: { environment },
390
+ };
391
+ }
392
+ /**
393
+ * Step 4: Image Configuration
394
+ */
395
+ async function imageConfigStep(ctx) {
396
+ const customizeImage = await confirm({
397
+ message: 'Customize container image settings?',
398
+ defaultValue: false,
399
+ });
400
+ if (!customizeImage) {
401
+ return { success: true, data: {} };
402
+ }
403
+ ui.newLine();
404
+ const imageRepository = await input({
405
+ message: 'Image repository (leave empty for chart default):',
406
+ defaultValue: ctx.imageRepository,
407
+ });
408
+ const imageTag = await input({
409
+ message: 'Image tag (leave empty for chart default):',
410
+ defaultValue: ctx.imageTag,
411
+ });
412
+ return {
413
+ success: true,
414
+ data: {
415
+ imageRepository: imageRepository || undefined,
416
+ imageTag: imageTag || undefined,
417
+ },
418
+ };
419
+ }
420
+ /**
421
+ * Step 5: Resource Configuration
422
+ */
423
+ async function resourceConfigStep(ctx) {
424
+ // Replicas
425
+ const replicasInput = await input({
426
+ message: 'Number of replicas:',
427
+ defaultValue: String(ctx.replicas || getDefaultReplicas(ctx.environment)),
428
+ validate: value => {
429
+ const num = parseInt(value, 10);
430
+ if (isNaN(num) || num < 1) {
431
+ return 'Must be a positive number';
432
+ }
433
+ return true;
434
+ },
435
+ });
436
+ const replicas = parseInt(replicasInput || '1', 10);
437
+ // Resource limits
438
+ ui.newLine();
439
+ const setResources = await confirm({
440
+ message: 'Configure resource requests and limits?',
441
+ defaultValue: ctx.environment === 'production',
442
+ });
443
+ let cpuRequest;
444
+ let cpuLimit;
445
+ let memoryRequest;
446
+ let memoryLimit;
447
+ if (setResources) {
448
+ const defaults = getDefaultResources(ctx.environment);
449
+ ui.newLine();
450
+ ui.info('Resource requests (guaranteed resources):');
451
+ cpuRequest = await input({
452
+ message: 'CPU request:',
453
+ defaultValue: ctx.cpuRequest || defaults.cpuRequest,
454
+ });
455
+ memoryRequest = await input({
456
+ message: 'Memory request:',
457
+ defaultValue: ctx.memoryRequest || defaults.memoryRequest,
458
+ });
459
+ ui.newLine();
460
+ ui.info('Resource limits (maximum allowed):');
461
+ cpuLimit = await input({
462
+ message: 'CPU limit:',
463
+ defaultValue: ctx.cpuLimit || defaults.cpuLimit,
464
+ });
465
+ memoryLimit = await input({
466
+ message: 'Memory limit:',
467
+ defaultValue: ctx.memoryLimit || defaults.memoryLimit,
468
+ });
469
+ }
470
+ return {
471
+ success: true,
472
+ data: {
473
+ replicas,
474
+ cpuRequest,
475
+ cpuLimit,
476
+ memoryRequest,
477
+ memoryLimit,
478
+ },
479
+ };
480
+ }
481
+ /**
482
+ * Step 6: Service Configuration
483
+ */
484
+ async function serviceConfigStep(ctx) {
485
+ const serviceType = await select({
486
+ message: 'Service type:',
487
+ options: [
488
+ {
489
+ value: 'ClusterIP',
490
+ label: 'ClusterIP',
491
+ description: 'Internal cluster access only (default)',
492
+ },
493
+ {
494
+ value: 'NodePort',
495
+ label: 'NodePort',
496
+ description: "Expose on each node's IP at a static port",
497
+ },
498
+ {
499
+ value: 'LoadBalancer',
500
+ label: 'LoadBalancer',
501
+ description: 'External load balancer (cloud provider)',
502
+ },
503
+ ],
504
+ defaultValue: ctx.serviceType || 'ClusterIP',
505
+ });
506
+ const servicePortInput = await input({
507
+ message: 'Service port:',
508
+ defaultValue: String(ctx.servicePort || 80),
509
+ validate: value => {
510
+ const num = parseInt(value, 10);
511
+ if (isNaN(num) || num < 1 || num > 65535) {
512
+ return 'Must be between 1 and 65535';
513
+ }
514
+ return true;
515
+ },
516
+ });
517
+ const servicePort = parseInt(servicePortInput || '80', 10);
518
+ return {
519
+ success: true,
520
+ data: { serviceType, servicePort },
521
+ };
522
+ }
523
+ /**
524
+ * Step 7: Ingress Configuration
525
+ */
526
+ async function ingressConfigStep(ctx) {
527
+ const ingressEnabled = await confirm({
528
+ message: 'Enable Ingress?',
529
+ defaultValue: ctx.ingressEnabled ?? ctx.environment === 'production',
530
+ });
531
+ if (!ingressEnabled) {
532
+ return { success: true, data: { ingressEnabled: false } };
533
+ }
534
+ ui.newLine();
535
+ const ingressHost = await input({
536
+ message: 'Hostname (e.g., app.example.com):',
537
+ defaultValue: ctx.ingressHost || `${ctx.releaseName}.example.com`,
538
+ validate: value => {
539
+ if (!value) {
540
+ return 'Hostname is required for Ingress';
541
+ }
542
+ return true;
543
+ },
544
+ });
545
+ const ingressTls = await confirm({
546
+ message: 'Enable TLS?',
547
+ defaultValue: ctx.ingressTls ?? ctx.environment === 'production',
548
+ });
549
+ return {
550
+ success: true,
551
+ data: { ingressEnabled, ingressHost, ingressTls },
552
+ };
553
+ }
554
+ /**
555
+ * Step 8: Secrets Configuration
556
+ */
557
+ async function secretsConfigStep(ctx) {
558
+ const includeSecrets = ctx.includeSecrets ??
559
+ (await confirm({
560
+ message: 'Generate a separate secrets values file?',
561
+ defaultValue: true,
562
+ }));
563
+ if (!includeSecrets) {
564
+ return { success: true, data: { includeSecrets: false } };
565
+ }
566
+ ui.newLine();
567
+ ui.info('You can add secret values below. Press Enter to skip.');
568
+ ui.info('(Actual secret values should be added later or managed by a secrets tool)');
569
+ const secretValues = {};
570
+ // Common secret keys based on chart
571
+ const chartName = ctx.chart?.split('/').pop() || '';
572
+ const suggestedKeys = getSuggestedSecretKeys(chartName);
573
+ for (const key of suggestedKeys) {
574
+ const value = await input({
575
+ message: `${key}:`,
576
+ defaultValue: '',
577
+ });
578
+ if (value) {
579
+ secretValues[key] = value;
580
+ }
581
+ }
582
+ // Allow adding custom secret keys
583
+ let addMore = Object.keys(secretValues).length === 0 ||
584
+ (await confirm({
585
+ message: 'Add custom secret keys?',
586
+ defaultValue: false,
587
+ }));
588
+ while (addMore) {
589
+ const key = await input({
590
+ message: 'Secret key (or press Enter to finish):',
591
+ });
592
+ if (!key) {
593
+ break;
594
+ }
595
+ const value = await input({
596
+ message: `Value for ${key}:`,
597
+ });
598
+ if (value) {
599
+ secretValues[key] = value;
600
+ }
601
+ addMore = await confirm({
602
+ message: 'Add another secret?',
603
+ defaultValue: false,
604
+ });
605
+ }
606
+ return {
607
+ success: true,
608
+ data: {
609
+ includeSecrets,
610
+ secretValues: Object.keys(secretValues).length > 0 ? secretValues : undefined,
611
+ },
612
+ };
613
+ }
614
+ /**
615
+ * Step 9: Output Configuration
616
+ */
617
+ async function outputConfigStep(ctx) {
618
+ const outputPath = await pathInput('Output directory:', ctx.outputPath || `./${ctx.releaseName}-helm`);
619
+ if (!outputPath) {
620
+ return { success: false, error: 'Output path is required' };
621
+ }
622
+ return {
623
+ success: true,
624
+ data: { outputPath },
625
+ };
626
+ }
627
+ /**
628
+ * Step 10: Generate Values Files
629
+ */
630
+ async function generateStep(ctx) {
631
+ ui.startSpinner({ message: 'Generating Helm values files...' });
632
+ try {
633
+ // Fetch default values from chart if available
634
+ if (ctx.chartSource === 'repo' && ctx.chart) {
635
+ try {
636
+ const valuesResult = await helmClient.showValues(ctx.chart, {
637
+ version: ctx.chartVersion,
638
+ });
639
+ if (valuesResult.success) {
640
+ ctx.defaultValues = valuesResult.values;
641
+ }
642
+ }
643
+ catch {
644
+ // Continue without default values
645
+ }
646
+ }
647
+ // Generate values files
648
+ const files = generateValuesFiles(ctx);
649
+ await writeFilesToDisk(files, ctx.outputPath);
650
+ ui.stopSpinnerSuccess(`Generated ${files.length} values file(s)`);
651
+ return {
652
+ success: true,
653
+ data: {
654
+ generatedFiles: files.map(f => f.path),
655
+ },
656
+ };
657
+ }
658
+ catch (error) {
659
+ ui.stopSpinnerFail('Generation failed');
660
+ return {
661
+ success: false,
662
+ error: error.message,
663
+ };
664
+ }
665
+ }
666
+ /**
667
+ * Generate values files
668
+ */
669
+ function generateValuesFiles(ctx) {
670
+ const files = [];
671
+ // Main values file
672
+ const mainValues = generateMainValues(ctx);
673
+ const envSuffix = ctx.environment !== 'dev' ? `-${ctx.environment}` : '';
674
+ files.push({
675
+ name: `values${envSuffix}.yaml`,
676
+ content: mainValues,
677
+ path: `${ctx.outputPath}/values${envSuffix}.yaml`,
678
+ });
679
+ // Secrets values file
680
+ if (ctx.includeSecrets) {
681
+ const secretsValues = generateSecretsValues(ctx);
682
+ files.push({
683
+ name: `secrets${envSuffix}.yaml`,
684
+ content: secretsValues,
685
+ path: `${ctx.outputPath}/secrets${envSuffix}.yaml`,
686
+ });
687
+ }
688
+ // README
689
+ files.push({
690
+ name: 'README.md',
691
+ content: generateReadme(ctx),
692
+ path: `${ctx.outputPath}/README.md`,
693
+ });
694
+ return files;
695
+ }
696
+ /**
697
+ * Generate main values content
698
+ */
699
+ function generateMainValues(ctx) {
700
+ const lines = [
701
+ `# Helm values for ${ctx.releaseName}`,
702
+ `# Environment: ${ctx.environment}`,
703
+ `# Generated by Nimbus CLI`,
704
+ `# Chart: ${ctx.chart}`,
705
+ '',
706
+ ];
707
+ // Replicas
708
+ lines.push(`replicaCount: ${ctx.replicas}`);
709
+ lines.push('');
710
+ // Image configuration
711
+ if (ctx.imageRepository || ctx.imageTag) {
712
+ lines.push('image:');
713
+ if (ctx.imageRepository) {
714
+ lines.push(` repository: ${ctx.imageRepository}`);
715
+ }
716
+ if (ctx.imageTag) {
717
+ lines.push(` tag: "${ctx.imageTag}"`);
718
+ }
719
+ lines.push('');
720
+ }
721
+ // Service configuration
722
+ lines.push('service:');
723
+ lines.push(` type: ${ctx.serviceType}`);
724
+ lines.push(` port: ${ctx.servicePort}`);
725
+ lines.push('');
726
+ // Ingress configuration
727
+ lines.push('ingress:');
728
+ lines.push(` enabled: ${ctx.ingressEnabled}`);
729
+ if (ctx.ingressEnabled) {
730
+ lines.push(' annotations:');
731
+ lines.push(' kubernetes.io/ingress.class: nginx');
732
+ lines.push(' hosts:');
733
+ lines.push(` - host: ${ctx.ingressHost}`);
734
+ lines.push(' paths:');
735
+ lines.push(' - path: /');
736
+ lines.push(' pathType: Prefix');
737
+ if (ctx.ingressTls) {
738
+ lines.push(' tls:');
739
+ lines.push(` - secretName: ${ctx.releaseName}-tls`);
740
+ lines.push(' hosts:');
741
+ lines.push(` - ${ctx.ingressHost}`);
742
+ }
743
+ }
744
+ lines.push('');
745
+ // Resource configuration
746
+ if (ctx.cpuRequest || ctx.memoryRequest || ctx.cpuLimit || ctx.memoryLimit) {
747
+ lines.push('resources:');
748
+ if (ctx.cpuRequest || ctx.memoryRequest) {
749
+ lines.push(' requests:');
750
+ if (ctx.cpuRequest) {
751
+ lines.push(` cpu: ${ctx.cpuRequest}`);
752
+ }
753
+ if (ctx.memoryRequest) {
754
+ lines.push(` memory: ${ctx.memoryRequest}`);
755
+ }
756
+ }
757
+ if (ctx.cpuLimit || ctx.memoryLimit) {
758
+ lines.push(' limits:');
759
+ if (ctx.cpuLimit) {
760
+ lines.push(` cpu: ${ctx.cpuLimit}`);
761
+ }
762
+ if (ctx.memoryLimit) {
763
+ lines.push(` memory: ${ctx.memoryLimit}`);
764
+ }
765
+ }
766
+ lines.push('');
767
+ }
768
+ // Environment-specific settings
769
+ if (ctx.environment === 'production') {
770
+ lines.push('# Production settings');
771
+ lines.push('podDisruptionBudget:');
772
+ lines.push(' enabled: true');
773
+ lines.push(' minAvailable: 1');
774
+ lines.push('');
775
+ lines.push('autoscaling:');
776
+ lines.push(' enabled: true');
777
+ lines.push(` minReplicas: ${ctx.replicas}`);
778
+ lines.push(` maxReplicas: ${(ctx.replicas || 1) * 3}`);
779
+ lines.push(' targetCPUUtilizationPercentage: 70');
780
+ lines.push('');
781
+ }
782
+ // Node selector / tolerations placeholder
783
+ lines.push('nodeSelector: {}');
784
+ lines.push('');
785
+ lines.push('tolerations: []');
786
+ lines.push('');
787
+ lines.push('affinity: {}');
788
+ return lines.join('\n');
789
+ }
790
+ /**
791
+ * Generate secrets values content
792
+ */
793
+ function generateSecretsValues(ctx) {
794
+ const lines = [
795
+ `# Helm secrets for ${ctx.releaseName}`,
796
+ `# Environment: ${ctx.environment}`,
797
+ '# IMPORTANT: Do not commit this file to version control!',
798
+ '# Consider using tools like SOPS, sealed-secrets, or external-secrets',
799
+ '',
800
+ ];
801
+ if (ctx.secretValues && Object.keys(ctx.secretValues).length > 0) {
802
+ lines.push('secrets:');
803
+ for (const [key, value] of Object.entries(ctx.secretValues)) {
804
+ // Mask actual values in generated file with placeholders
805
+ const placeholder = value || Buffer.from('REPLACE_ME').toString('base64');
806
+ lines.push(` ${key}: "${placeholder}" # base64-encoded value — replace with: echo -n 'your-value' | base64`);
807
+ }
808
+ }
809
+ else {
810
+ lines.push('# Add your secret values here');
811
+ lines.push('# Example:');
812
+ lines.push('# secrets:');
813
+ lines.push('# databasePassword: "<YOUR_PASSWORD>"');
814
+ lines.push('# apiKey: "<YOUR_API_KEY>"');
815
+ }
816
+ return lines.join('\n');
817
+ }
818
+ /**
819
+ * Generate README content
820
+ */
821
+ function generateReadme(ctx) {
822
+ const envSuffix = ctx.environment !== 'dev' ? `-${ctx.environment}` : '';
823
+ return `# ${ctx.releaseName} Helm Values
824
+
825
+ Generated by Nimbus CLI
826
+
827
+ ## Chart Information
828
+
829
+ - **Chart:** ${ctx.chart}
830
+ - **Release Name:** ${ctx.releaseName}
831
+ - **Namespace:** ${ctx.namespace}
832
+ - **Environment:** ${ctx.environment}
833
+
834
+ ## Installation
835
+
836
+ \`\`\`bash
837
+ # Add repository (if using a repo chart)
838
+ ${ctx.repoName && ctx.repoUrl ? `helm repo add ${ctx.repoName} ${ctx.repoUrl}` : '# helm repo add <repo-name> <repo-url>'}
839
+ helm repo update
840
+
841
+ # Install the chart
842
+ helm install ${ctx.releaseName} ${ctx.chart} \\
843
+ --namespace ${ctx.namespace} \\
844
+ --create-namespace \\
845
+ -f values${envSuffix}.yaml${ctx.includeSecrets
846
+ ? ` \\
847
+ -f secrets${envSuffix}.yaml`
848
+ : ''}
849
+ \`\`\`
850
+
851
+ ## Upgrade
852
+
853
+ \`\`\`bash
854
+ helm upgrade ${ctx.releaseName} ${ctx.chart} \\
855
+ --namespace ${ctx.namespace} \\
856
+ -f values${envSuffix}.yaml${ctx.includeSecrets
857
+ ? ` \\
858
+ -f secrets${envSuffix}.yaml`
859
+ : ''}
860
+ \`\`\`
861
+
862
+ ## Uninstall
863
+
864
+ \`\`\`bash
865
+ helm uninstall ${ctx.releaseName} --namespace ${ctx.namespace}
866
+ \`\`\`
867
+
868
+ ## Files
869
+
870
+ - \`values${envSuffix}.yaml\` - Main configuration values
871
+ ${ctx.includeSecrets ? `- \`secrets${envSuffix}.yaml\` - Secret values (DO NOT commit to git!)` : ''}
872
+
873
+ ## Security Notes
874
+
875
+ ${ctx.includeSecrets
876
+ ? `- The \`secrets${envSuffix}.yaml\` file contains sensitive data
877
+ - Add it to \`.gitignore\` to prevent accidental commits
878
+ - Consider using:
879
+ - [SOPS](https://github.com/mozilla/sops) for encrypted secrets in git
880
+ - [Sealed Secrets](https://github.com/bitnami-labs/sealed-secrets) for Kubernetes-native encryption
881
+ - [External Secrets](https://external-secrets.io/) for external secret managers`
882
+ : '- No secrets file generated'}
883
+
884
+ ## Customization
885
+
886
+ Edit the values files to customize your deployment. Common modifications:
887
+
888
+ - Increase/decrease replicas
889
+ - Adjust resource limits
890
+ - Configure ingress hosts
891
+ - Add environment variables
892
+ - Configure persistence
893
+ `;
894
+ }
895
+ /**
896
+ * Get default replicas based on environment
897
+ */
898
+ function getDefaultReplicas(environment) {
899
+ switch (environment) {
900
+ case 'production':
901
+ return 3;
902
+ case 'staging':
903
+ return 2;
904
+ default:
905
+ return 1;
906
+ }
907
+ }
908
+ /**
909
+ * Get default resources based on environment
910
+ */
911
+ function getDefaultResources(environment) {
912
+ switch (environment) {
913
+ case 'production':
914
+ return {
915
+ cpuRequest: '250m',
916
+ cpuLimit: '1000m',
917
+ memoryRequest: '256Mi',
918
+ memoryLimit: '512Mi',
919
+ };
920
+ case 'staging':
921
+ return {
922
+ cpuRequest: '100m',
923
+ cpuLimit: '500m',
924
+ memoryRequest: '128Mi',
925
+ memoryLimit: '256Mi',
926
+ };
927
+ default:
928
+ return {
929
+ cpuRequest: '50m',
930
+ cpuLimit: '200m',
931
+ memoryRequest: '64Mi',
932
+ memoryLimit: '128Mi',
933
+ };
934
+ }
935
+ }
936
+ /**
937
+ * Get suggested secret keys based on chart name
938
+ */
939
+ function getSuggestedSecretKeys(chartName) {
940
+ const chartSecrets = {
941
+ postgresql: ['postgresql-password', 'postgresql-postgres-password', 'replication-password'],
942
+ mysql: ['mysql-root-password', 'mysql-password'],
943
+ mongodb: ['mongodb-root-password', 'mongodb-password'],
944
+ redis: ['redis-password'],
945
+ rabbitmq: ['rabbitmq-password', 'rabbitmq-erlang-cookie'],
946
+ kafka: ['kafka-password'],
947
+ elasticsearch: ['elasticsearch-password'],
948
+ };
949
+ return chartSecrets[chartName.toLowerCase()] || ['secret-key'];
950
+ }
951
+ /**
952
+ * Write files to disk
953
+ */
954
+ async function writeFilesToDisk(files, outputPath) {
955
+ const fs = await import('fs/promises');
956
+ const path = await import('path');
957
+ // Create output directory
958
+ await fs.mkdir(outputPath, { recursive: true });
959
+ // Write each file
960
+ for (const file of files) {
961
+ const filePath = path.join(outputPath, file.name);
962
+ await fs.writeFile(filePath, file.content, 'utf-8');
963
+ }
964
+ // Create .gitignore for secrets
965
+ const gitignorePath = path.join(outputPath, '.gitignore');
966
+ await fs.writeFile(gitignorePath, 'secrets*.yaml\n', 'utf-8');
967
+ }
968
+ /**
969
+ * Run in non-interactive mode
970
+ */
971
+ async function runNonInteractive(options) {
972
+ ui.header('nimbus generate helm', 'Non-interactive mode');
973
+ // Validate required options
974
+ if (!options.chart) {
975
+ ui.error('Chart is required in non-interactive mode (--chart)');
976
+ process.exit(1);
977
+ }
978
+ if (!options.releaseName) {
979
+ ui.error('Release name is required in non-interactive mode (--release)');
980
+ process.exit(1);
981
+ }
982
+ ui.info(`Chart: ${options.chart}`);
983
+ ui.info(`Release: ${options.releaseName}`);
984
+ ui.info(`Namespace: ${options.namespace || 'default'}`);
985
+ ui.info(`Environment: ${options.environment || 'dev'}`);
986
+ ui.info(`Output: ${options.output || `./${options.releaseName}-helm`}`);
987
+ // Build context from options
988
+ const ctx = {
989
+ chartSource: 'repo',
990
+ chart: options.chart,
991
+ releaseName: options.releaseName,
992
+ namespace: options.namespace || 'default',
993
+ environment: options.environment || 'dev',
994
+ replicas: getDefaultReplicas(options.environment),
995
+ serviceType: 'ClusterIP',
996
+ servicePort: 80,
997
+ ingressEnabled: false,
998
+ includeSecrets: options.includeSecrets ?? true,
999
+ outputPath: options.output || `./${options.releaseName}-helm`,
1000
+ };
1001
+ ui.newLine();
1002
+ ui.startSpinner({ message: 'Generating values files...' });
1003
+ try {
1004
+ const files = generateValuesFiles(ctx);
1005
+ await writeFilesToDisk(files, ctx.outputPath);
1006
+ ui.stopSpinnerSuccess(`Generated ${files.length} file(s)`);
1007
+ ui.newLine();
1008
+ ui.box({
1009
+ title: 'Complete!',
1010
+ content: [
1011
+ `Generated ${files.length} file(s) in ${ctx.outputPath}:`,
1012
+ ...files.map(f => ` - ${f.name}`),
1013
+ ],
1014
+ style: 'rounded',
1015
+ borderColor: 'green',
1016
+ padding: 1,
1017
+ });
1018
+ }
1019
+ catch (error) {
1020
+ ui.stopSpinnerFail('Generation failed');
1021
+ ui.error(error.message);
1022
+ process.exit(1);
1023
+ }
1024
+ }
1025
+ // Export as default command
1026
+ export default generateHelmCommand;