@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,322 @@
1
+ /**
2
+ * Audit Commands
3
+ * Audit log viewer and export CLI commands
4
+ */
5
+ import { ui } from '../../wizard/ui';
6
+ import { auditClient } from '../../clients/enterprise-client';
7
+ import * as fs from 'node:fs';
8
+ /**
9
+ * Get current team ID from config or environment
10
+ */
11
+ function getCurrentTeamId() {
12
+ return process.env.NIMBUS_TEAM_ID || null;
13
+ }
14
+ /**
15
+ * Parse relative time string (e.g., "7d", "24h") to ISO date
16
+ */
17
+ function parseRelativeTime(timeStr) {
18
+ const now = Date.now();
19
+ const match = timeStr.match(/^(\d+)([dhwm])$/);
20
+ if (!match) {
21
+ return timeStr; // Assume it's already a valid date string
22
+ }
23
+ const value = parseInt(match[1], 10);
24
+ const unit = match[2];
25
+ let ms;
26
+ switch (unit) {
27
+ case 'h':
28
+ ms = value * 60 * 60 * 1000;
29
+ break;
30
+ case 'd':
31
+ ms = value * 24 * 60 * 60 * 1000;
32
+ break;
33
+ case 'w':
34
+ ms = value * 7 * 24 * 60 * 60 * 1000;
35
+ break;
36
+ case 'm':
37
+ ms = value * 30 * 24 * 60 * 60 * 1000;
38
+ break;
39
+ default:
40
+ return timeStr;
41
+ }
42
+ return new Date(now - ms).toISOString();
43
+ }
44
+ /**
45
+ * Parse audit list options
46
+ */
47
+ export function parseAuditListOptions(args) {
48
+ const options = {};
49
+ for (let i = 0; i < args.length; i++) {
50
+ const arg = args[i];
51
+ if (arg === '--since' && args[i + 1]) {
52
+ options.since = parseRelativeTime(args[++i]);
53
+ }
54
+ else if (arg === '--until' && args[i + 1]) {
55
+ options.until = parseRelativeTime(args[++i]);
56
+ }
57
+ else if (arg === '--action' && args[i + 1]) {
58
+ options.action = args[++i];
59
+ }
60
+ else if (arg === '--user' && args[i + 1]) {
61
+ options.userId = args[++i];
62
+ }
63
+ else if ((arg === '--limit' || arg === '-n') && args[i + 1]) {
64
+ options.limit = parseInt(args[++i], 10);
65
+ }
66
+ else if (arg === '--json') {
67
+ options.json = true;
68
+ }
69
+ else if (arg === '--non-interactive') {
70
+ options.nonInteractive = true;
71
+ }
72
+ }
73
+ return options;
74
+ }
75
+ /**
76
+ * Parse audit export options
77
+ */
78
+ export function parseAuditExportOptions(args) {
79
+ const options = {};
80
+ for (let i = 0; i < args.length; i++) {
81
+ const arg = args[i];
82
+ if (arg === '--format' && args[i + 1]) {
83
+ options.format = args[++i];
84
+ }
85
+ else if ((arg === '--output' || arg === '-o') && args[i + 1]) {
86
+ options.output = args[++i];
87
+ }
88
+ else if (arg === '--since' && args[i + 1]) {
89
+ options.since = parseRelativeTime(args[++i]);
90
+ }
91
+ else if (arg === '--until' && args[i + 1]) {
92
+ options.until = parseRelativeTime(args[++i]);
93
+ }
94
+ else if (arg === '--non-interactive') {
95
+ options.nonInteractive = true;
96
+ }
97
+ }
98
+ return options;
99
+ }
100
+ /**
101
+ * Format timestamp for display
102
+ */
103
+ function formatTimestamp(ts) {
104
+ const date = new Date(ts);
105
+ return `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`;
106
+ }
107
+ /**
108
+ * Audit list command
109
+ */
110
+ export async function auditListCommand(options) {
111
+ try {
112
+ const teamId = getCurrentTeamId();
113
+ if (!teamId) {
114
+ ui.error('No team selected. Run `nimbus team switch <team-id>` first.');
115
+ return;
116
+ }
117
+ ui.startSpinner({ message: 'Fetching audit logs...' });
118
+ const result = await auditClient.queryLogs({
119
+ teamId,
120
+ userId: options.userId,
121
+ action: options.action,
122
+ since: options.since,
123
+ until: options.until,
124
+ limit: options.limit || 50,
125
+ });
126
+ ui.stopSpinnerSuccess(`Found ${result.total} logs (showing ${result.logs.length})`);
127
+ if (options.json) {
128
+ console.log(JSON.stringify(result, null, 2));
129
+ return;
130
+ }
131
+ if (result.logs.length === 0) {
132
+ ui.info('No audit logs found');
133
+ return;
134
+ }
135
+ ui.newLine();
136
+ ui.table({
137
+ columns: [
138
+ { key: 'timestamp', header: 'Time', width: 20 },
139
+ { key: 'action', header: 'Action', width: 20 },
140
+ { key: 'user', header: 'User', width: 15 },
141
+ { key: 'status', header: 'Status', width: 10 },
142
+ { key: 'resource', header: 'Resource' },
143
+ ],
144
+ data: result.logs.map(log => ({
145
+ timestamp: formatTimestamp(log.timestamp),
146
+ action: log.action,
147
+ user: log.userId || '-',
148
+ status: log.status,
149
+ resource: log.resourceType ? `${log.resourceType}/${log.resourceId || ''}` : '-',
150
+ })),
151
+ });
152
+ if (result.total > result.logs.length) {
153
+ ui.newLine();
154
+ ui.dim(`Showing ${result.logs.length} of ${result.total} logs. Use --limit to show more.`);
155
+ }
156
+ }
157
+ catch (error) {
158
+ ui.stopSpinnerFail('Failed to fetch audit logs');
159
+ ui.error(error.message);
160
+ }
161
+ }
162
+ /**
163
+ * Audit export command
164
+ */
165
+ export async function auditExportCommand(options) {
166
+ try {
167
+ const teamId = getCurrentTeamId();
168
+ if (!teamId) {
169
+ ui.error('No team selected. Run `nimbus team switch <team-id>` first.');
170
+ return;
171
+ }
172
+ const format = options.format || 'json';
173
+ const output = options.output || `audit-logs-${new Date().toISOString().split('T')[0]}.${format}`;
174
+ ui.startSpinner({ message: `Exporting audit logs to ${output}...` });
175
+ const content = await auditClient.exportLogs(format, {
176
+ teamId,
177
+ since: options.since,
178
+ until: options.until,
179
+ });
180
+ fs.writeFileSync(output, content);
181
+ ui.stopSpinnerSuccess(`Exported to ${output}`);
182
+ const stats = fs.statSync(output);
183
+ ui.info(`File size: ${(stats.size / 1024).toFixed(1)} KB`);
184
+ }
185
+ catch (error) {
186
+ ui.stopSpinnerFail('Failed to export audit logs');
187
+ ui.error(error.message);
188
+ }
189
+ }
190
+ /**
191
+ * Parse audit scan options from CLI args
192
+ */
193
+ export function parseAuditScanOptions(args) {
194
+ const options = {};
195
+ for (let i = 0; i < args.length; i++) {
196
+ const arg = args[i];
197
+ if (arg === '--framework' && args[i + 1]) {
198
+ options.framework = args[++i];
199
+ }
200
+ else if ((arg === '--output' || arg === '-o') && args[i + 1]) {
201
+ options.output = args[++i];
202
+ }
203
+ else if ((arg === '--dir' || arg === '-d') && args[i + 1]) {
204
+ options.dir = args[++i];
205
+ }
206
+ else if (arg === '--threshold' && args[i + 1]) {
207
+ options.threshold = parseInt(args[++i], 10);
208
+ }
209
+ }
210
+ return options;
211
+ }
212
+ /**
213
+ * Audit scan subcommand — runs the local security scanner
214
+ */
215
+ export async function auditScanCommand(options) {
216
+ const { scanSecurity } = await import('../../audit/security-scanner');
217
+ const dir = options.dir ?? process.cwd();
218
+ ui.startSpinner({ message: `Scanning ${dir} for security issues...` });
219
+ let result;
220
+ try {
221
+ result = await scanSecurity({ dir });
222
+ }
223
+ catch (e) {
224
+ ui.stopSpinnerFail('Scan failed');
225
+ ui.error(e.message);
226
+ return;
227
+ }
228
+ ui.stopSpinnerSuccess(`Scan complete: ${result.findings.length} finding(s) in ${result.scannedFiles} file(s)`);
229
+ // Filter by framework if provided (maps framework to relevant finding IDs)
230
+ let findings = result.findings;
231
+ if (options.framework) {
232
+ // Each framework maps loosely to severity thresholds
233
+ const frameworkSeverityMap = {
234
+ soc2: ['CRITICAL', 'HIGH', 'MEDIUM'],
235
+ hipaa: ['CRITICAL', 'HIGH', 'MEDIUM'],
236
+ pci: ['CRITICAL', 'HIGH'],
237
+ iso27001: ['CRITICAL', 'HIGH', 'MEDIUM', 'LOW'],
238
+ };
239
+ const allowedSeverities = frameworkSeverityMap[options.framework] ?? [];
240
+ findings = findings.filter((f) => allowedSeverities.includes(f.severity));
241
+ ui.dim(`Framework filter (${options.framework}): showing ${findings.length} relevant finding(s)`);
242
+ }
243
+ if (findings.length === 0) {
244
+ ui.info('No findings. Scan clean.');
245
+ }
246
+ else {
247
+ ui.newLine();
248
+ for (const finding of findings) {
249
+ const severityColor = finding.severity === 'CRITICAL' || finding.severity === 'HIGH'
250
+ ? 'red'
251
+ : finding.severity === 'MEDIUM'
252
+ ? 'yellow'
253
+ : 'white';
254
+ ui.print(`[${ui.color(finding.severity, severityColor)}] ${finding.id}: ${finding.title}`);
255
+ if (finding.file)
256
+ ui.dim(` File: ${finding.file}${finding.line ? `:${finding.line}` : ''}`);
257
+ ui.dim(` ${finding.recommendation}`);
258
+ ui.newLine();
259
+ }
260
+ }
261
+ // Write JSON report to file if requested
262
+ if (options.output) {
263
+ const report = {
264
+ timestamp: result.timestamp.toISOString(),
265
+ scannedFiles: result.scannedFiles,
266
+ scanDuration: result.scanDuration,
267
+ framework: options.framework ?? null,
268
+ findingsCount: findings.length,
269
+ findings,
270
+ };
271
+ fs.writeFileSync(options.output, JSON.stringify(report, null, 2), 'utf-8');
272
+ ui.print(`Report written to ${options.output}`);
273
+ }
274
+ // Threshold check — exit code 1 if too many findings
275
+ if (options.threshold !== undefined && findings.length > options.threshold) {
276
+ ui.error(`Findings (${findings.length}) exceeded threshold (${options.threshold}). Exiting with code 1.`);
277
+ process.exit(1);
278
+ }
279
+ }
280
+ /**
281
+ * Main audit command dispatcher
282
+ */
283
+ export async function auditCommand(subcommand, args) {
284
+ switch (subcommand) {
285
+ case 'list':
286
+ case '':
287
+ await auditListCommand(parseAuditListOptions(args));
288
+ break;
289
+ case 'export':
290
+ await auditExportCommand(parseAuditExportOptions(args));
291
+ break;
292
+ case 'scan':
293
+ await auditScanCommand(parseAuditScanOptions(args));
294
+ break;
295
+ default:
296
+ ui.error(`Unknown audit command: ${subcommand}`);
297
+ ui.newLine();
298
+ ui.info('Available audit commands:');
299
+ ui.print(' nimbus audit - List audit logs');
300
+ ui.print(' nimbus audit list - List audit logs');
301
+ ui.print(' nimbus audit export - Export audit logs');
302
+ ui.print(' nimbus audit scan - Scan directory for security issues');
303
+ ui.newLine();
304
+ ui.info('Options (list):');
305
+ ui.print(' --since <time> Filter logs since (e.g., 7d, 24h, 2024-01-01)');
306
+ ui.print(' --until <time> Filter logs until');
307
+ ui.print(' --action <type> Filter by action type');
308
+ ui.print(' --user <id> Filter by user');
309
+ ui.print(' --limit <n> Number of logs to show');
310
+ ui.print(' --json Output as JSON');
311
+ ui.newLine();
312
+ ui.info('Options (scan):');
313
+ ui.print(' --framework <f> Compliance framework: soc2|hipaa|pci|iso27001');
314
+ ui.print(' --output <file> Write JSON report to file');
315
+ ui.print(' --dir <path> Directory to scan (default: cwd)');
316
+ ui.print(' --threshold <n> Exit code 1 if findings exceed this count');
317
+ ui.newLine();
318
+ ui.info('Export options:');
319
+ ui.print(' --format <type> Export format (csv|json)');
320
+ ui.print(' --output <file> Output file path');
321
+ }
322
+ }
@@ -0,0 +1,345 @@
1
+ /**
2
+ * Cloud Credential Management Commands
3
+ *
4
+ * Validate and display cloud provider credentials.
5
+ *
6
+ * Usage:
7
+ * nimbus auth aws [--profile <name>]
8
+ * nimbus auth gcp [--project <name>]
9
+ * nimbus auth azure [--subscription <id>]
10
+ */
11
+ import { logger } from '../utils';
12
+ import { ui } from '../wizard/ui';
13
+ /**
14
+ * Check if a CLI tool is installed
15
+ */
16
+ async function isCliInstalled(cmd) {
17
+ const { execFile } = await import('child_process');
18
+ const { promisify } = await import('util');
19
+ const execFileAsync = promisify(execFile);
20
+ try {
21
+ await execFileAsync(cmd, ['--version'], { timeout: 5000 });
22
+ return true;
23
+ }
24
+ catch {
25
+ return false;
26
+ }
27
+ }
28
+ /**
29
+ * Run a CLI command and capture output
30
+ */
31
+ async function runCommand(cmd, args) {
32
+ const { execFile } = await import('child_process');
33
+ const { promisify } = await import('util');
34
+ const execFileAsync = promisify(execFile);
35
+ try {
36
+ const { stdout } = await execFileAsync(cmd, args, { timeout: 15000 });
37
+ return { stdout: stdout.trim(), success: true };
38
+ }
39
+ catch (error) {
40
+ return { stdout: error.stdout?.trim() || error.message, success: false };
41
+ }
42
+ }
43
+ /**
44
+ * nimbus auth aws — Validate AWS credentials
45
+ */
46
+ export async function authAwsCommand(options = {}) {
47
+ logger.info('Validating AWS credentials', { options });
48
+ ui.header('AWS Credentials');
49
+ // Check if AWS CLI is installed
50
+ const installed = await isCliInstalled('aws');
51
+ if (!installed) {
52
+ ui.error('AWS CLI is not installed');
53
+ ui.newLine();
54
+ ui.print('Install the AWS CLI:');
55
+ ui.print(` ${ui.dim('brew install awscli')} (macOS)`);
56
+ ui.print(` ${ui.dim('pip install awscli')} (pip)`);
57
+ ui.print(` ${ui.dim('https://aws.amazon.com/cli/')} (official)`);
58
+ return;
59
+ }
60
+ ui.startSpinner({ message: 'Validating AWS credentials...' });
61
+ // Get caller identity
62
+ const identityArgs = ['sts', 'get-caller-identity', '--output', 'json'];
63
+ if (options.profile) {
64
+ identityArgs.push('--profile', options.profile);
65
+ }
66
+ const identity = await runCommand('aws', identityArgs);
67
+ if (!identity.success) {
68
+ ui.stopSpinnerFail('AWS credentials validation failed');
69
+ ui.newLine();
70
+ ui.error('Unable to validate AWS credentials');
71
+ ui.print(ui.dim(identity.stdout));
72
+ ui.newLine();
73
+ ui.print('Configure credentials:');
74
+ ui.print(` ${ui.dim('aws configure')}`);
75
+ ui.print(` ${ui.dim('export AWS_ACCESS_KEY_ID=...')}`);
76
+ ui.print(` ${ui.dim('export AWS_SECRET_ACCESS_KEY=...')}`);
77
+ return;
78
+ }
79
+ ui.stopSpinnerSuccess('AWS credentials valid');
80
+ ui.newLine();
81
+ // Parse identity
82
+ try {
83
+ const data = JSON.parse(identity.stdout);
84
+ ui.print(` ${ui.bold('Account:')} ${data.Account}`);
85
+ ui.print(` ${ui.bold('User ARN:')} ${data.Arn}`);
86
+ ui.print(` ${ui.bold('User ID:')} ${data.UserId}`);
87
+ }
88
+ catch {
89
+ ui.print(` ${identity.stdout}`);
90
+ }
91
+ // Get current region
92
+ const regionArgs = ['configure', 'get', 'region'];
93
+ if (options.profile) {
94
+ regionArgs.push('--profile', options.profile);
95
+ }
96
+ const region = await runCommand('aws', regionArgs);
97
+ if (region.success && region.stdout) {
98
+ ui.print(` ${ui.bold('Region:')} ${region.stdout}`);
99
+ }
100
+ if (options.profile) {
101
+ ui.print(` ${ui.bold('Profile:')} ${options.profile}`);
102
+ }
103
+ ui.newLine();
104
+ ui.success('AWS credentials are configured and valid');
105
+ }
106
+ /**
107
+ * nimbus auth gcp — Validate GCP credentials
108
+ */
109
+ export async function authGcpCommand(options = {}) {
110
+ logger.info('Validating GCP credentials', { options });
111
+ ui.header('GCP Credentials');
112
+ // Check if gcloud CLI is installed
113
+ const installed = await isCliInstalled('gcloud');
114
+ if (!installed) {
115
+ ui.error('Google Cloud SDK (gcloud) is not installed');
116
+ ui.newLine();
117
+ ui.print('Install the Google Cloud SDK:');
118
+ ui.print(` ${ui.dim('brew install google-cloud-sdk')} (macOS)`);
119
+ ui.print(` ${ui.dim('https://cloud.google.com/sdk/docs/install')} (official)`);
120
+ return;
121
+ }
122
+ ui.startSpinner({ message: 'Validating GCP credentials...' });
123
+ // Get current account
124
+ const account = await runCommand('gcloud', [
125
+ 'auth',
126
+ 'list',
127
+ '--filter=status:ACTIVE',
128
+ '--format=value(account)',
129
+ ]);
130
+ if (!account.success || !account.stdout) {
131
+ ui.stopSpinnerFail('GCP credentials validation failed');
132
+ ui.newLine();
133
+ ui.error('No active GCP credentials found');
134
+ ui.print('Configure credentials:');
135
+ ui.print(` ${ui.dim('gcloud auth login')}`);
136
+ ui.print(` ${ui.dim('gcloud auth application-default login')}`);
137
+ return;
138
+ }
139
+ ui.stopSpinnerSuccess('GCP credentials valid');
140
+ ui.newLine();
141
+ ui.print(` ${ui.bold('Account:')} ${account.stdout}`);
142
+ // Check Application Default Credentials
143
+ const adcCheck = await runCommand('gcloud', [
144
+ 'auth',
145
+ 'application-default',
146
+ 'print-access-token',
147
+ ]);
148
+ if (adcCheck.success) {
149
+ ui.print(` ${ui.bold('ADC:')} ${ui.color('configured', 'green')}`);
150
+ }
151
+ else {
152
+ ui.print(` ${ui.bold('ADC:')} ${ui.color('not configured', 'yellow')}`);
153
+ ui.print(ui.dim(' Set with: gcloud auth application-default login'));
154
+ }
155
+ // Get current project
156
+ const projectArgs = options.project
157
+ ? ['config', 'get-value', 'project', '--project', options.project]
158
+ : ['config', 'get-value', 'project'];
159
+ const project = await runCommand('gcloud', projectArgs);
160
+ if (project.success && project.stdout && project.stdout !== '(unset)') {
161
+ ui.print(` ${ui.bold('Project:')} ${project.stdout}`);
162
+ }
163
+ else if (options.project) {
164
+ ui.print(` ${ui.bold('Project:')} ${options.project}`);
165
+ }
166
+ else {
167
+ ui.print(` ${ui.bold('Project:')} ${ui.color('not set', 'yellow')}`);
168
+ ui.print(ui.dim(' Set with: gcloud config set project PROJECT_ID'));
169
+ }
170
+ // Get current region
171
+ const region = await runCommand('gcloud', ['config', 'get-value', 'compute/region']);
172
+ if (region.success && region.stdout && region.stdout !== '(unset)') {
173
+ ui.print(` ${ui.bold('Region:')} ${region.stdout}`);
174
+ }
175
+ ui.newLine();
176
+ ui.success('GCP credentials are configured and valid');
177
+ }
178
+ /**
179
+ * nimbus auth azure — Validate Azure credentials
180
+ */
181
+ export async function authAzureCommand(options = {}) {
182
+ logger.info('Validating Azure credentials', { options });
183
+ ui.header('Azure Credentials');
184
+ // Check if az CLI is installed
185
+ const installed = await isCliInstalled('az');
186
+ if (!installed) {
187
+ ui.error('Azure CLI (az) is not installed');
188
+ ui.newLine();
189
+ ui.print('Install the Azure CLI:');
190
+ ui.print(` ${ui.dim('brew install azure-cli')} (macOS)`);
191
+ ui.print(` ${ui.dim('https://learn.microsoft.com/en-us/cli/azure/install-azure-cli')} (official)`);
192
+ return;
193
+ }
194
+ ui.startSpinner({ message: 'Validating Azure credentials...' });
195
+ // Get current account
196
+ const account = await runCommand('az', ['account', 'show', '--output', 'json']);
197
+ if (!account.success) {
198
+ ui.stopSpinnerFail('Azure credentials validation failed');
199
+ ui.newLine();
200
+ ui.error('No active Azure credentials found');
201
+ ui.print('Configure credentials:');
202
+ ui.print(` ${ui.dim('az login')}`);
203
+ return;
204
+ }
205
+ ui.stopSpinnerSuccess('Azure credentials valid');
206
+ ui.newLine();
207
+ try {
208
+ const data = JSON.parse(account.stdout);
209
+ ui.print(` ${ui.bold('Subscription:')} ${data.name} (${data.id})`);
210
+ ui.print(` ${ui.bold('Tenant:')} ${data.tenantId}`);
211
+ ui.print(` ${ui.bold('State:')} ${data.state}`);
212
+ if (data.user) {
213
+ ui.print(` ${ui.bold('User:')} ${data.user.name} (${data.user.type})`);
214
+ }
215
+ }
216
+ catch {
217
+ ui.print(` ${account.stdout}`);
218
+ }
219
+ ui.newLine();
220
+ ui.success('Azure credentials are configured and valid');
221
+ }
222
+ /**
223
+ * H1: AWS SSO Login — delegates to `aws sso login` so the CLI handles the browser flow.
224
+ * spawnSync with stdio: 'inherit' so device codes / browser prompts appear in terminal.
225
+ */
226
+ export async function loginAwsCommand(options = {}) {
227
+ const installed = await isCliInstalled('aws');
228
+ if (!installed) {
229
+ ui.error('AWS CLI is not installed. Install from https://aws.amazon.com/cli/');
230
+ return;
231
+ }
232
+ ui.info('Launching AWS SSO login...');
233
+ ui.print(ui.dim('The browser (or device code) flow is handled by the AWS CLI.'));
234
+ ui.newLine();
235
+ const { spawnSync } = await import('child_process');
236
+ const args = ['sso', 'login'];
237
+ if (options.profile) {
238
+ args.push('--profile', options.profile);
239
+ }
240
+ const result = spawnSync('aws', args, { stdio: 'inherit' });
241
+ if (result.status === 0) {
242
+ ui.success('AWS SSO login completed successfully.');
243
+ }
244
+ else {
245
+ ui.error('AWS SSO login failed or was cancelled.');
246
+ }
247
+ }
248
+ /**
249
+ * H1: GCP Login — delegates to `gcloud auth login --no-launch-browser` (device code flow).
250
+ */
251
+ export async function loginGcpCommand(options = {}) {
252
+ const installed = await isCliInstalled('gcloud');
253
+ if (!installed) {
254
+ ui.error('Google Cloud SDK not installed. See https://cloud.google.com/sdk/docs/install');
255
+ return;
256
+ }
257
+ ui.info('Launching GCP device-code login...');
258
+ ui.print(ui.dim('Follow the URL and code shown below to complete authentication.'));
259
+ ui.newLine();
260
+ const { spawnSync } = await import('child_process');
261
+ const args = ['auth', 'login', '--no-launch-browser'];
262
+ if (options.project) {
263
+ args.push('--project', options.project);
264
+ }
265
+ const result = spawnSync('gcloud', args, { stdio: 'inherit' });
266
+ if (result.status === 0) {
267
+ ui.success('GCP login completed successfully.');
268
+ }
269
+ else {
270
+ ui.error('GCP login failed or was cancelled.');
271
+ }
272
+ }
273
+ /**
274
+ * H1: Azure Login — delegates to `az login --use-device-code`.
275
+ */
276
+ export async function loginAzureCommand(options = {}) {
277
+ const installed = await isCliInstalled('az');
278
+ if (!installed) {
279
+ ui.error('Azure CLI not installed. See https://learn.microsoft.com/en-us/cli/azure/install-azure-cli');
280
+ return;
281
+ }
282
+ ui.info('Launching Azure device-code login...');
283
+ ui.print(ui.dim('Follow the URL and code shown below to complete authentication.'));
284
+ ui.newLine();
285
+ const { spawnSync } = await import('child_process');
286
+ const args = ['login', '--use-device-code'];
287
+ if (options.subscription) {
288
+ args.push('--subscription', options.subscription);
289
+ }
290
+ const result = spawnSync('az', args, { stdio: 'inherit' });
291
+ if (result.status === 0) {
292
+ ui.success('Azure login completed successfully.');
293
+ }
294
+ else {
295
+ ui.error('Azure login failed or was cancelled.');
296
+ }
297
+ }
298
+ /**
299
+ * Cloud auth parent command router
300
+ */
301
+ export async function authCloudCommand(provider, options = {}) {
302
+ switch (provider) {
303
+ case 'aws':
304
+ await authAwsCommand(options);
305
+ break;
306
+ case 'gcp':
307
+ case 'google':
308
+ await authGcpCommand(options);
309
+ break;
310
+ case 'azure':
311
+ await authAzureCommand(options);
312
+ break;
313
+ default:
314
+ ui.error(`Unknown cloud provider: ${provider}`);
315
+ ui.newLine();
316
+ ui.print('Supported providers:');
317
+ ui.print(' nimbus auth aws — Validate AWS credentials');
318
+ ui.print(' nimbus auth gcp — Validate GCP credentials');
319
+ ui.print(' nimbus auth azure — Validate Azure credentials');
320
+ }
321
+ }
322
+ /**
323
+ * Cloud login command router — delegates to CLI tools for SSO/OAuth flows (H1).
324
+ */
325
+ export async function loginCloudCommand(provider, options = {}) {
326
+ switch (provider) {
327
+ case 'aws':
328
+ await loginAwsCommand(options);
329
+ break;
330
+ case 'gcp':
331
+ case 'google':
332
+ await loginGcpCommand(options);
333
+ break;
334
+ case 'azure':
335
+ await loginAzureCommand(options);
336
+ break;
337
+ default:
338
+ ui.error(`Unknown cloud provider: ${provider}`);
339
+ ui.newLine();
340
+ ui.print('Supported providers:');
341
+ ui.print(' nimbus auth login aws — AWS SSO login (browser/device code)');
342
+ ui.print(' nimbus auth login gcp — GCP device-code login');
343
+ ui.print(' nimbus auth login azure — Azure device-code login');
344
+ }
345
+ }