@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,325 @@
1
+ /**
2
+ * Plugin / Extension System (L3)
3
+ *
4
+ * Manages MCP server plugins that extend Nimbus's tool capabilities.
5
+ * Registry stored at ~/.nimbus/plugins.json
6
+ *
7
+ * Commands:
8
+ * nimbus plugin list — list installed plugins
9
+ * nimbus plugin add <name> — add a plugin from npm or git URL
10
+ * nimbus plugin remove <name> — remove a plugin
11
+ * nimbus plugin init — scaffold a minimal MCP server in CWD
12
+ */
13
+ import * as fs from 'node:fs';
14
+ import * as path from 'node:path';
15
+ import * as os from 'node:os';
16
+ import { execFileSync } from 'node:child_process';
17
+ import { ui } from '../wizard/ui';
18
+ const PLUGINS_FILE = path.join(os.homedir(), '.nimbus', 'plugins.json');
19
+ const MCP_FILE = path.join(os.homedir(), '.nimbus', 'mcp.json');
20
+ function loadMCPConfig() {
21
+ try {
22
+ const content = fs.readFileSync(MCP_FILE, 'utf-8');
23
+ return JSON.parse(content);
24
+ }
25
+ catch {
26
+ return { servers: [] };
27
+ }
28
+ }
29
+ function saveMCPConfig(config) {
30
+ const dir = path.dirname(MCP_FILE);
31
+ fs.mkdirSync(dir, { recursive: true });
32
+ fs.writeFileSync(MCP_FILE, JSON.stringify(config, null, 2), 'utf-8');
33
+ }
34
+ /**
35
+ * M5: MCP server management command.
36
+ * Subcommands: add, list, remove, test
37
+ */
38
+ export async function mcpCommand(subcommand, args) {
39
+ switch (subcommand) {
40
+ case 'list': {
41
+ const config = loadMCPConfig();
42
+ if (config.servers.length === 0) {
43
+ ui.info('No MCP servers configured. Add one with: nimbus mcp add <command-or-url>');
44
+ ui.info(`Config file: ${MCP_FILE}`);
45
+ return;
46
+ }
47
+ ui.header('Configured MCP Servers');
48
+ for (const s of config.servers) {
49
+ const cmd = s.type === 'http' ? `${s.url ?? ''}` : `${s.command} ${(s.args ?? []).join(' ')}`;
50
+ ui.print(` ${ui.color(s.name, 'cyan')} [${s.type}] ${cmd}`);
51
+ }
52
+ ui.newLine();
53
+ ui.info(`Config: ${MCP_FILE}`);
54
+ break;
55
+ }
56
+ case 'add': {
57
+ const commandOrUrl = args[0];
58
+ if (!commandOrUrl) {
59
+ ui.print('Usage: nimbus mcp add <command-or-url> [--name <name>]');
60
+ ui.print('');
61
+ ui.print('Examples:');
62
+ ui.print(' nimbus mcp add "npx -y @my/mcp-server" (npm package)');
63
+ ui.print(' nimbus mcp add "https://my-server.example.com" (HTTP)');
64
+ ui.print(' nimbus mcp add "./my-server.js" (local script)');
65
+ return;
66
+ }
67
+ // Parse optional --name flag
68
+ let serverName = commandOrUrl;
69
+ for (let i = 1; i < args.length; i++) {
70
+ if (args[i] === '--name' && args[i + 1]) {
71
+ serverName = args[++i];
72
+ }
73
+ }
74
+ const config = loadMCPConfig();
75
+ if (config.servers.find(s => s.name === serverName)) {
76
+ ui.warning(`MCP server "${serverName}" is already configured.`);
77
+ return;
78
+ }
79
+ // Determine transport type and build entry
80
+ const isHttp = commandOrUrl.startsWith('http://') || commandOrUrl.startsWith('https://');
81
+ let entry;
82
+ if (isHttp) {
83
+ entry = {
84
+ name: serverName,
85
+ command: '',
86
+ type: 'http',
87
+ url: commandOrUrl,
88
+ };
89
+ }
90
+ else {
91
+ // Parse "npx -y @my/mcp-server" into command + args
92
+ const parts = commandOrUrl.split(/\s+/);
93
+ entry = {
94
+ name: serverName,
95
+ command: parts[0] ?? commandOrUrl,
96
+ args: parts.slice(1),
97
+ type: 'stdio',
98
+ };
99
+ }
100
+ config.servers.push(entry);
101
+ saveMCPConfig(config);
102
+ ui.print(`${ui.color('✓', 'green')} MCP server "${serverName}" added.`);
103
+ ui.info(`Config saved to: ${MCP_FILE}`);
104
+ ui.info('Restart Nimbus for the server to take effect.');
105
+ break;
106
+ }
107
+ case 'remove': {
108
+ const name = args[0];
109
+ if (!name) {
110
+ ui.print('Usage: nimbus mcp remove <name>');
111
+ return;
112
+ }
113
+ const config = loadMCPConfig();
114
+ const idx = config.servers.findIndex(s => s.name === name);
115
+ if (idx === -1) {
116
+ ui.warning(`MCP server "${name}" not found.`);
117
+ ui.info('Run "nimbus mcp list" to see configured servers.');
118
+ return;
119
+ }
120
+ config.servers.splice(idx, 1);
121
+ saveMCPConfig(config);
122
+ ui.print(`${ui.color('✓', 'green')} MCP server "${name}" removed.`);
123
+ break;
124
+ }
125
+ case 'test': {
126
+ const name = args[0];
127
+ if (!name) {
128
+ ui.print('Usage: nimbus mcp test <name>');
129
+ return;
130
+ }
131
+ const config = loadMCPConfig();
132
+ const server = config.servers.find(s => s.name === name);
133
+ if (!server) {
134
+ ui.warning(`MCP server "${name}" not found.`);
135
+ ui.info('Run "nimbus mcp list" to see configured servers.');
136
+ return;
137
+ }
138
+ if (server.type === 'http') {
139
+ // HTTP: send a tools/list request via curl if available
140
+ ui.startSpinner({ message: `Testing MCP server "${name}" at ${server.url ?? ''}...` });
141
+ try {
142
+ const resp = execFileSync('curl', [
143
+ '-s', '--max-time', '5',
144
+ '-X', 'POST',
145
+ '-H', 'Content-Type: application/json',
146
+ '-d', JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'tools/list', params: {} }),
147
+ server.url ?? '',
148
+ ], { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] });
149
+ const data = JSON.parse(resp);
150
+ ui.stopSpinnerSuccess(`Server responded. Result: ${JSON.stringify(data).slice(0, 200)}`);
151
+ }
152
+ catch (err) {
153
+ ui.stopSpinnerFail(`Could not reach server: ${err instanceof Error ? err.message : String(err)}`);
154
+ }
155
+ }
156
+ else {
157
+ // stdio: spawn briefly and send a tools/list JSON-RPC message
158
+ ui.startSpinner({ message: `Testing MCP server "${name}" (stdio)...` });
159
+ try {
160
+ const testPayload = JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'tools/list', params: {} }) + '\n';
161
+ const result = execFileSync(server.command, server.args ?? [], {
162
+ input: testPayload,
163
+ encoding: 'utf-8',
164
+ timeout: 5000,
165
+ stdio: ['pipe', 'pipe', 'pipe'],
166
+ });
167
+ const parsed = JSON.parse(result);
168
+ const tools = parsed.result?.tools;
169
+ const toolCount = Array.isArray(tools) ? tools.length : '?';
170
+ ui.stopSpinnerSuccess(`Server responded with ${toolCount} tools.`);
171
+ }
172
+ catch (err) {
173
+ ui.stopSpinnerFail(`Server test failed: ${err instanceof Error ? err.message : String(err)}`);
174
+ }
175
+ }
176
+ break;
177
+ }
178
+ default:
179
+ ui.print('Usage: nimbus mcp <list|add|remove|test>');
180
+ ui.print('');
181
+ ui.print('Commands:');
182
+ ui.print(' list List configured MCP servers');
183
+ ui.print(' add <cmd-or-url> Add a new MCP server');
184
+ ui.print(' remove <name> Remove an MCP server');
185
+ ui.print(' test <name> Test that a server responds');
186
+ }
187
+ }
188
+ function loadRegistry() {
189
+ try {
190
+ const content = fs.readFileSync(PLUGINS_FILE, 'utf-8');
191
+ return JSON.parse(content);
192
+ }
193
+ catch {
194
+ return { plugins: [] };
195
+ }
196
+ }
197
+ function saveRegistry(registry) {
198
+ const dir = path.dirname(PLUGINS_FILE);
199
+ fs.mkdirSync(dir, { recursive: true });
200
+ fs.writeFileSync(PLUGINS_FILE, JSON.stringify(registry, null, 2), 'utf-8');
201
+ }
202
+ export async function pluginCommand(subcommand, args) {
203
+ switch (subcommand) {
204
+ case 'list': {
205
+ const registry = loadRegistry();
206
+ if (registry.plugins.length === 0) {
207
+ ui.info('No plugins installed. Add one with: nimbus plugin add <name>');
208
+ return;
209
+ }
210
+ ui.header('Installed Plugins');
211
+ for (const p of registry.plugins) {
212
+ ui.print(` ${ui.color(p.name, 'cyan')} — ${p.description ?? p.command}`);
213
+ if (p.args)
214
+ ui.print(` args: ${p.args.join(' ')}`);
215
+ }
216
+ break;
217
+ }
218
+ case 'add': {
219
+ const name = args[0];
220
+ if (!name) {
221
+ ui.print('Usage: nimbus plugin add <package-name-or-url>');
222
+ return;
223
+ }
224
+ const registry = loadRegistry();
225
+ if (registry.plugins.find(p => p.name === name)) {
226
+ ui.warning(`Plugin "${name}" is already installed.`);
227
+ return;
228
+ }
229
+ // Determine command: npm package → `npx <name>`, git URL → clone first
230
+ const isUrl = name.startsWith('http') || name.startsWith('git@');
231
+ const command = isUrl ? `node` : `npx`;
232
+ const pluginArgs = isUrl ? [name] : [name];
233
+ const entry = {
234
+ name,
235
+ command,
236
+ args: pluginArgs,
237
+ installedAt: new Date().toISOString(),
238
+ };
239
+ registry.plugins.push(entry);
240
+ saveRegistry(registry);
241
+ ui.print(`${ui.color('✓', 'green')} Plugin "${name}" added.`);
242
+ ui.info('Restart Nimbus for the plugin to take effect.');
243
+ break;
244
+ }
245
+ case 'remove': {
246
+ const name = args[0];
247
+ if (!name) {
248
+ ui.print('Usage: nimbus plugin remove <name>');
249
+ return;
250
+ }
251
+ const registry = loadRegistry();
252
+ const idx = registry.plugins.findIndex(p => p.name === name);
253
+ if (idx === -1) {
254
+ ui.warning(`Plugin "${name}" not found.`);
255
+ return;
256
+ }
257
+ registry.plugins.splice(idx, 1);
258
+ saveRegistry(registry);
259
+ ui.print(`${ui.color('✓', 'green')} Plugin "${name}" removed.`);
260
+ break;
261
+ }
262
+ case 'init': {
263
+ const cwd = process.cwd();
264
+ const serverFile = path.join(cwd, 'nimbus-plugin.js');
265
+ if (fs.existsSync(serverFile)) {
266
+ ui.warning(`${serverFile} already exists.`);
267
+ return;
268
+ }
269
+ const template = `#!/usr/bin/env node
270
+ /**
271
+ * Nimbus MCP Plugin Template
272
+ *
273
+ * Implement tools that extend Nimbus's capabilities.
274
+ * See: https://github.com/the-ai-project-co/nimbus
275
+ */
276
+
277
+ const readline = require('readline');
278
+
279
+ const tools = [
280
+ {
281
+ name: 'my_tool',
282
+ description: 'A custom tool for Nimbus',
283
+ inputSchema: {
284
+ type: 'object',
285
+ properties: {
286
+ input: { type: 'string', description: 'Input for the tool' },
287
+ },
288
+ required: ['input'],
289
+ },
290
+ },
291
+ ];
292
+
293
+ // MCP server — reads JSON-RPC requests from stdin, writes responses to stdout
294
+ const rl = readline.createInterface({ input: process.stdin, terminal: false });
295
+
296
+ rl.on('line', (line) => {
297
+ try {
298
+ const request = JSON.parse(line);
299
+ if (request.method === 'tools/list') {
300
+ respond(request.id, { tools });
301
+ } else if (request.method === 'tools/call') {
302
+ const { name, arguments: args } = request.params;
303
+ if (name === 'my_tool') {
304
+ respond(request.id, { content: [{ type: 'text', text: \`You called my_tool with: \${args.input}\` }] });
305
+ }
306
+ }
307
+ } catch (e) {
308
+ process.stderr.write(\`Error: \${e}\\n\`);
309
+ }
310
+ });
311
+
312
+ function respond(id, result) {
313
+ process.stdout.write(JSON.stringify({ jsonrpc: '2.0', id, result }) + '\\n');
314
+ }
315
+ `;
316
+ fs.writeFileSync(serverFile, template, 'utf-8');
317
+ fs.chmodSync(serverFile, 0o755);
318
+ ui.print(`${ui.color('✓', 'green')} Created ${serverFile}`);
319
+ ui.info('Register with: nimbus plugin add ./nimbus-plugin.js');
320
+ break;
321
+ }
322
+ default:
323
+ ui.print('Usage: nimbus plugin <list|add|remove|init>');
324
+ }
325
+ }
@@ -0,0 +1,356 @@
1
+ /**
2
+ * Preview Command
3
+ *
4
+ * Preview infrastructure changes without applying them
5
+ *
6
+ * Usage:
7
+ * nimbus preview terraform [directory]
8
+ * nimbus preview k8s [directory]
9
+ * nimbus preview helm [chart]
10
+ */
11
+ import { logger } from '../utils';
12
+ import { ui } from '../wizard/ui';
13
+ import { terraformClient, k8sClient, helmClient } from '../clients';
14
+ import { loadSafetyPolicy, evaluateSafety } from '../config/safety-policy';
15
+ import { displaySafetySummary } from '../wizard/approval';
16
+ /**
17
+ * Preview command handler
18
+ */
19
+ export async function previewCommand(options) {
20
+ logger.info('Running preview', { type: options.type });
21
+ ui.newLine();
22
+ ui.header(`Preview ${capitalize(options.type)} Changes`);
23
+ switch (options.type) {
24
+ case 'terraform':
25
+ await previewTerraform(options);
26
+ break;
27
+ case 'k8s':
28
+ await previewKubernetes(options);
29
+ break;
30
+ case 'helm':
31
+ await previewHelm(options);
32
+ break;
33
+ default:
34
+ ui.error(`Unknown preview type: ${options.type}`);
35
+ }
36
+ }
37
+ /**
38
+ * Preview Terraform changes
39
+ */
40
+ async function previewTerraform(options) {
41
+ const directory = options.directory || '.';
42
+ ui.info(`Directory: ${directory}`);
43
+ ui.newLine();
44
+ // Check if terraform client is available
45
+ const clientAvailable = await terraformClient.isAvailable();
46
+ if (clientAvailable) {
47
+ await previewTerraformWithService(options);
48
+ }
49
+ else {
50
+ await previewTerraformWithCLI(options);
51
+ }
52
+ }
53
+ /**
54
+ * Preview Terraform using service
55
+ */
56
+ async function previewTerraformWithService(options) {
57
+ const directory = options.directory || '.';
58
+ ui.startSpinner({ message: 'Creating execution plan...' });
59
+ try {
60
+ const result = await terraformClient.plan(directory, {});
61
+ ui.stopSpinnerSuccess('Plan created');
62
+ ui.newLine();
63
+ if (!result.success) {
64
+ ui.error(`Plan failed: ${result.error}`);
65
+ return;
66
+ }
67
+ // Display plan
68
+ displayTerraformPlan(result, options);
69
+ // Run safety checks if not skipped
70
+ if (!options.skipSafety) {
71
+ await runSafetyChecks('plan', 'terraform', result.output, options);
72
+ }
73
+ }
74
+ catch (error) {
75
+ ui.stopSpinnerFail('Plan failed');
76
+ ui.error(error.message);
77
+ }
78
+ }
79
+ /**
80
+ * Preview Terraform using local CLI
81
+ */
82
+ async function previewTerraformWithCLI(options) {
83
+ const { spawn } = await import('child_process');
84
+ const directory = options.directory || '.';
85
+ const args = ['plan', '-no-color'];
86
+ if (options.target) {
87
+ args.push('-target', options.target);
88
+ }
89
+ ui.info(`Running: terraform ${args.join(' ')}`);
90
+ ui.newLine();
91
+ return new Promise(resolve => {
92
+ let output = '';
93
+ const proc = spawn('terraform', args, {
94
+ cwd: directory,
95
+ stdio: ['inherit', 'pipe', 'pipe'],
96
+ });
97
+ proc.stdout?.on('data', data => {
98
+ const text = data.toString();
99
+ output += text;
100
+ process.stdout.write(text);
101
+ });
102
+ proc.stderr?.on('data', data => {
103
+ process.stderr.write(data);
104
+ });
105
+ proc.on('error', error => {
106
+ ui.error(`Failed to run terraform: ${error.message}`);
107
+ ui.info('Make sure terraform is installed and in your PATH');
108
+ resolve();
109
+ });
110
+ proc.on('close', async (code) => {
111
+ if (code === 0) {
112
+ ui.newLine();
113
+ ui.success('Plan preview complete');
114
+ // Run safety checks if not skipped
115
+ if (!options.skipSafety) {
116
+ await runSafetyChecks('plan', 'terraform', output, options);
117
+ }
118
+ }
119
+ else {
120
+ ui.newLine();
121
+ ui.error(`Terraform plan failed with exit code ${code}`);
122
+ }
123
+ resolve();
124
+ });
125
+ });
126
+ }
127
+ /**
128
+ * Display Terraform plan results
129
+ */
130
+ function displayTerraformPlan(result, options) {
131
+ if (!result.hasChanges) {
132
+ ui.success('No changes. Infrastructure is up to date.');
133
+ return;
134
+ }
135
+ if (options.format === 'json') {
136
+ console.log(JSON.stringify({ hasChanges: result.hasChanges, output: result.output }, null, 2));
137
+ return;
138
+ }
139
+ // Parse changes from output
140
+ const addMatch = result.output.match(/(\d+) to add/);
141
+ const changeMatch = result.output.match(/(\d+) to change/);
142
+ const destroyMatch = result.output.match(/(\d+) to destroy/);
143
+ const add = parseInt(addMatch?.[1] || '0', 10);
144
+ const change = parseInt(changeMatch?.[1] || '0', 10);
145
+ const destroy = parseInt(destroyMatch?.[1] || '0', 10);
146
+ // Display summary table
147
+ ui.print(ui.bold('Plan Summary:'));
148
+ ui.newLine();
149
+ if (add > 0) {
150
+ ui.print(` ${ui.color(`+ ${add} to add`, 'green')}`);
151
+ }
152
+ if (change > 0) {
153
+ ui.print(` ${ui.color(`~ ${change} to change`, 'yellow')}`);
154
+ }
155
+ if (destroy > 0) {
156
+ ui.print(` ${ui.color(`- ${destroy} to destroy`, 'red')}`);
157
+ }
158
+ // Show detailed output if verbose
159
+ if (options.verbose) {
160
+ ui.newLine();
161
+ ui.print(ui.bold('Detailed Changes:'));
162
+ ui.newLine();
163
+ ui.print(result.output);
164
+ }
165
+ }
166
+ /**
167
+ * Preview Kubernetes changes
168
+ */
169
+ async function previewKubernetes(options) {
170
+ const directory = options.directory || '.';
171
+ const namespace = options.namespace || 'default';
172
+ ui.info(`Directory: ${directory}`);
173
+ ui.info(`Namespace: ${namespace}`);
174
+ ui.newLine();
175
+ // Check if k8s client is available
176
+ const clientAvailable = await k8sClient.isAvailable();
177
+ // K8s client doesn't have a diff method, always use CLI
178
+ // If client is available, we could use dry-run apply in the future
179
+ if (clientAvailable) {
180
+ ui.info('Using kubectl diff for preview...');
181
+ }
182
+ // Use kubectl diff CLI
183
+ await previewKubernetesWithCLI(options);
184
+ }
185
+ /**
186
+ * Preview Kubernetes using kubectl
187
+ */
188
+ async function previewKubernetesWithCLI(options) {
189
+ const { spawn } = await import('child_process');
190
+ const directory = options.directory || '.';
191
+ const namespace = options.namespace || 'default';
192
+ const args = ['diff', '-f', directory, '-n', namespace];
193
+ ui.info(`Running: kubectl ${args.join(' ')}`);
194
+ ui.newLine();
195
+ return new Promise(resolve => {
196
+ const proc = spawn('kubectl', args, {
197
+ stdio: 'inherit',
198
+ });
199
+ proc.on('error', error => {
200
+ ui.error(`Failed to run kubectl: ${error.message}`);
201
+ ui.info('Make sure kubectl is installed and configured');
202
+ resolve();
203
+ });
204
+ proc.on('close', code => {
205
+ ui.newLine();
206
+ if (code === 0) {
207
+ ui.success('No changes detected');
208
+ }
209
+ else if (code === 1) {
210
+ ui.info('Changes detected (see diff above)');
211
+ }
212
+ else {
213
+ ui.error(`kubectl diff failed with exit code ${code}`);
214
+ }
215
+ resolve();
216
+ });
217
+ });
218
+ }
219
+ /**
220
+ * Display Kubernetes diff
221
+ */
222
+ function _displayK8sDiff(result, options) {
223
+ if (options.format === 'json') {
224
+ console.log(JSON.stringify(result, null, 2));
225
+ return;
226
+ }
227
+ ui.print(ui.bold('Kubernetes Diff:'));
228
+ ui.newLine();
229
+ if (result.output) {
230
+ // Color the diff output
231
+ const lines = result.output.split('\n');
232
+ for (const line of lines) {
233
+ if (line.startsWith('+')) {
234
+ ui.print(ui.color(line, 'green'));
235
+ }
236
+ else if (line.startsWith('-')) {
237
+ ui.print(ui.color(line, 'red'));
238
+ }
239
+ else if (line.startsWith('@')) {
240
+ ui.print(ui.color(line, 'cyan'));
241
+ }
242
+ else {
243
+ ui.print(line);
244
+ }
245
+ }
246
+ }
247
+ }
248
+ /**
249
+ * Preview Helm changes
250
+ */
251
+ async function previewHelm(options) {
252
+ const chart = options.directory || '.';
253
+ const release = options.release || 'preview';
254
+ const namespace = options.namespace || 'default';
255
+ ui.info(`Chart: ${chart}`);
256
+ ui.info(`Release: ${release}`);
257
+ ui.info(`Namespace: ${namespace}`);
258
+ ui.newLine();
259
+ // Check if helm client is available
260
+ const clientAvailable = await helmClient.isAvailable();
261
+ // Helm client doesn't have a diff method, always use CLI
262
+ // If client is available, we could use template comparison in the future
263
+ if (clientAvailable) {
264
+ ui.info('Using helm template for preview...');
265
+ }
266
+ // Use helm template CLI
267
+ await previewHelmWithCLI(options);
268
+ }
269
+ /**
270
+ * Preview Helm using helm CLI
271
+ */
272
+ async function previewHelmWithCLI(options) {
273
+ const { spawn } = await import('child_process');
274
+ const chart = options.directory || '.';
275
+ const release = options.release || 'preview';
276
+ const namespace = options.namespace || 'default';
277
+ // Use helm template to preview what would be generated
278
+ const args = ['template', release, chart, '-n', namespace];
279
+ if (options.valuesFile) {
280
+ args.push('-f', options.valuesFile);
281
+ }
282
+ ui.info(`Running: helm ${args.join(' ')}`);
283
+ ui.newLine();
284
+ return new Promise(resolve => {
285
+ const proc = spawn('helm', args, {
286
+ stdio: 'inherit',
287
+ });
288
+ proc.on('error', error => {
289
+ ui.error(`Failed to run helm: ${error.message}`);
290
+ ui.info('Make sure helm is installed and in your PATH');
291
+ resolve();
292
+ });
293
+ proc.on('close', code => {
294
+ ui.newLine();
295
+ if (code === 0) {
296
+ ui.success('Template preview complete');
297
+ }
298
+ else {
299
+ ui.error(`helm template failed with exit code ${code}`);
300
+ }
301
+ resolve();
302
+ });
303
+ });
304
+ }
305
+ /**
306
+ * Display Helm diff
307
+ */
308
+ function _displayHelmDiff(result, options) {
309
+ if (options.format === 'json') {
310
+ console.log(JSON.stringify(result, null, 2));
311
+ return;
312
+ }
313
+ if (!result.hasDiff) {
314
+ ui.success('No changes. Helm release is up to date.');
315
+ return;
316
+ }
317
+ ui.print(ui.bold('Helm Diff:'));
318
+ ui.newLine();
319
+ if (result.output) {
320
+ ui.print(result.output);
321
+ }
322
+ }
323
+ /**
324
+ * Run safety checks on the preview
325
+ */
326
+ async function runSafetyChecks(operation, type, output, options) {
327
+ const policy = loadSafetyPolicy();
328
+ const context = {
329
+ operation,
330
+ type,
331
+ planOutput: output,
332
+ metadata: {
333
+ directory: options.directory,
334
+ namespace: options.namespace,
335
+ },
336
+ };
337
+ const result = evaluateSafety(context, policy);
338
+ ui.newLine();
339
+ displaySafetySummary({
340
+ operation: `${type} ${operation}`,
341
+ risks: result.risks,
342
+ passed: result.passed,
343
+ });
344
+ if (result.requiresApproval) {
345
+ ui.newLine();
346
+ ui.warning('This operation will require approval when applied');
347
+ }
348
+ }
349
+ /**
350
+ * Capitalize first letter
351
+ */
352
+ function capitalize(str) {
353
+ return str.charAt(0).toUpperCase() + str.slice(1);
354
+ }
355
+ // Export as default
356
+ export default previewCommand;