@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,616 @@
1
+ import { logger } from '../utils';
2
+ import { LLMRouter } from '../llm/router';
3
+ // ==========================================
4
+ // Constants
5
+ // ==========================================
6
+ /** System prompt instructing the LLM to generate execution steps as JSON. */
7
+ const PLANNING_PROMPT = 'You are an infrastructure planning agent. Given the task context, generate an ordered array of execution steps as JSON. ' +
8
+ 'Each step has fields: id (string like step_1), name (string), description (string), type (one of: generate, validate, deploy, configure, verify), ' +
9
+ 'order (number), estimatedDuration (number in seconds). Return ONLY the JSON array, no markdown.';
10
+ /** System prompt instructing the LLM to assess risks as JSON. */
11
+ const RISK_ASSESSMENT_PROMPT = 'You are an infrastructure risk assessor. Given the task and execution steps, identify risks. ' +
12
+ 'Return a JSON array of risks with fields: id (string), severity (low|medium|high|critical), ' +
13
+ 'category (security|cost|availability|performance|compliance), description (string), mitigation (string), ' +
14
+ 'probability (0-1), impact (0-1). Return ONLY the JSON array.';
15
+ /** Valid step types for plan steps. */
16
+ const VALID_STEP_TYPES = new Set(['generate', 'validate', 'deploy', 'configure', 'verify']);
17
+ /** Valid severity levels for risks. */
18
+ const VALID_SEVERITIES = new Set(['low', 'medium', 'high', 'critical']);
19
+ /** Valid risk categories. */
20
+ const VALID_CATEGORIES = new Set(['security', 'cost', 'availability', 'performance', 'compliance']);
21
+ // ==========================================
22
+ // Planner
23
+ // ==========================================
24
+ /** Detect the primary domain of a task description. */
25
+ function detectDomain(task) {
26
+ const desc = (task.type + ' ' + JSON.stringify(task.context)).toLowerCase();
27
+ if (desc.includes('helm') || desc.includes('chart') || desc.includes('release'))
28
+ return 'helm';
29
+ if (desc.includes('kubectl') || desc.includes('kubernetes') || desc.includes('pod') || desc.includes('deployment') || desc.includes('k8s'))
30
+ return 'kubernetes';
31
+ if (desc.includes('terraform') || desc.includes('.tf') || desc.includes('infrastructure') || desc.includes('provider'))
32
+ return 'terraform';
33
+ // Default to terraform for infrastructure tasks
34
+ if (task.type === 'deploy' || task.type === 'generate')
35
+ return 'terraform';
36
+ return 'generic';
37
+ }
38
+ export class Planner {
39
+ router;
40
+ constructor() {
41
+ this.router = new LLMRouter();
42
+ }
43
+ /**
44
+ * Generate an execution plan for a task
45
+ */
46
+ async generatePlan(task) {
47
+ logger.info(`Generating plan for task: ${task.id}`);
48
+ const steps = await this.generateSteps(task);
49
+ const dependencies = this.analyzeDependencies(steps);
50
+ const risks = await this.assessRisks(task, steps);
51
+ const riskLevel = this.calculateOverallRiskLevel(risks);
52
+ const plan = {
53
+ id: this.generatePlanId(),
54
+ task_id: task.id,
55
+ status: 'draft',
56
+ created_at: new Date(),
57
+ updated_at: new Date(),
58
+ steps,
59
+ dependencies,
60
+ risks,
61
+ risk_level: riskLevel,
62
+ requires_approval: riskLevel === 'high' || riskLevel === 'critical',
63
+ };
64
+ // Estimate duration and cost
65
+ plan.estimated_duration = this.estimateDuration(steps);
66
+ plan.estimated_cost = await this.estimateCost(task, steps);
67
+ logger.info(`Generated plan ${plan.id} with ${steps.length} steps, risk level: ${riskLevel}`);
68
+ return plan;
69
+ }
70
+ /**
71
+ * Generate execution steps for a task.
72
+ * Attempts LLM-based generation first, falls back to heuristic logic.
73
+ */
74
+ async generateSteps(task) {
75
+ try {
76
+ const llmSteps = await this.generateStepsWithLLM(task);
77
+ if (llmSteps.length > 0) {
78
+ logger.info(`Using LLM-generated steps (${llmSteps.length} steps)`);
79
+ return llmSteps;
80
+ }
81
+ }
82
+ catch (error) {
83
+ logger.debug(`LLM step generation failed, falling back to heuristics: ${error.message}`);
84
+ }
85
+ return this.generateStepsHeuristic(task);
86
+ }
87
+ /**
88
+ * Generate steps using the embedded LLM router.
89
+ */
90
+ async generateStepsWithLLM(task) {
91
+ const response = await this.router.route({
92
+ messages: [
93
+ { role: 'system', content: PLANNING_PROMPT },
94
+ { role: 'user', content: JSON.stringify(task.context) },
95
+ ],
96
+ });
97
+ const content = response?.content;
98
+ if (!content) {
99
+ throw new Error('LLM response missing content');
100
+ }
101
+ const parsed = JSON.parse(content);
102
+ if (!Array.isArray(parsed) || parsed.length === 0) {
103
+ throw new Error('LLM response is not a non-empty array');
104
+ }
105
+ const steps = [];
106
+ for (const item of parsed) {
107
+ if (typeof item !== 'object' ||
108
+ item === null ||
109
+ typeof item.id !== 'string' ||
110
+ typeof item.description !== 'string' ||
111
+ !VALID_STEP_TYPES.has(item.type)) {
112
+ throw new Error('LLM response contains invalid step structure');
113
+ }
114
+ steps.push({
115
+ id: item.id,
116
+ order: typeof item.order === 'number' ? item.order : steps.length + 1,
117
+ type: item.type,
118
+ description: item.description,
119
+ action: item.type,
120
+ parameters: {},
121
+ status: 'pending',
122
+ });
123
+ }
124
+ return steps;
125
+ }
126
+ /**
127
+ * Generate execution steps using heuristic logic (fallback).
128
+ */
129
+ generateStepsHeuristic(task) {
130
+ const steps = [];
131
+ let order = 1;
132
+ // Domain-specific step generation
133
+ const domain = detectDomain(task);
134
+ if (domain === 'terraform') {
135
+ return this.generateTerraformSteps(task);
136
+ }
137
+ else if (domain === 'kubernetes') {
138
+ return this.generateKubernetesSteps(task);
139
+ }
140
+ else if (domain === 'helm') {
141
+ return this.generateHelmSteps(task);
142
+ }
143
+ // Step 1: Validate requirements
144
+ steps.push({
145
+ id: `step_${order++}`,
146
+ order: steps.length + 1,
147
+ type: 'validate',
148
+ description: 'Validate infrastructure requirements and constraints',
149
+ action: 'validate_requirements',
150
+ parameters: {
151
+ provider: task.context.provider,
152
+ components: task.context.components,
153
+ requirements: task.context.requirements,
154
+ },
155
+ status: 'pending',
156
+ });
157
+ // Step 2-N: Generate infrastructure components
158
+ for (const component of task.context.components) {
159
+ steps.push({
160
+ id: `step_${order++}`,
161
+ order: steps.length + 1,
162
+ type: 'generate',
163
+ description: `Generate ${component.toUpperCase()} configuration`,
164
+ component,
165
+ action: 'generate_component',
166
+ parameters: {
167
+ component,
168
+ provider: task.context.provider,
169
+ environment: task.context.environment,
170
+ requirements: task.context.requirements,
171
+ },
172
+ status: 'pending',
173
+ depends_on: ['step_1'], // Depends on validation
174
+ });
175
+ }
176
+ // Step: Validate generated code
177
+ steps.push({
178
+ id: `step_${order++}`,
179
+ order: steps.length + 1,
180
+ type: 'validate',
181
+ description: 'Validate generated infrastructure code',
182
+ action: 'validate_generated_code',
183
+ parameters: {
184
+ components: task.context.components,
185
+ },
186
+ status: 'pending',
187
+ depends_on: steps.slice(1, -1).map(s => s.id), // Depends on all generation steps
188
+ });
189
+ // Step: Apply best practices
190
+ steps.push({
191
+ id: `step_${order++}`,
192
+ order: steps.length + 1,
193
+ type: 'validate',
194
+ description: 'Apply security and best practices',
195
+ action: 'apply_best_practices',
196
+ parameters: {
197
+ components: task.context.components,
198
+ autofix: true,
199
+ },
200
+ status: 'pending',
201
+ depends_on: [steps[steps.length - 1].id],
202
+ });
203
+ // If deployment is requested
204
+ if (task.type === 'deploy') {
205
+ // Step: Plan deployment
206
+ steps.push({
207
+ id: `step_${order++}`,
208
+ order: steps.length + 1,
209
+ type: 'deploy',
210
+ description: 'Plan infrastructure deployment (terraform plan)',
211
+ action: 'plan_deployment',
212
+ parameters: {
213
+ provider: task.context.provider,
214
+ environment: task.context.environment,
215
+ },
216
+ status: 'pending',
217
+ depends_on: [steps[steps.length - 1].id],
218
+ });
219
+ // Step: Apply deployment
220
+ steps.push({
221
+ id: `step_${order++}`,
222
+ order: steps.length + 1,
223
+ type: 'deploy',
224
+ description: 'Apply infrastructure deployment (terraform apply)',
225
+ action: 'apply_deployment',
226
+ parameters: {
227
+ provider: task.context.provider,
228
+ environment: task.context.environment,
229
+ auto_approve: false,
230
+ },
231
+ status: 'pending',
232
+ depends_on: [steps[steps.length - 1].id],
233
+ rollback_action: `terraform_destroy:${task.context.environment ?? '.'}`,
234
+ rollback_parameters: {
235
+ provider: task.context.provider,
236
+ environment: task.context.environment,
237
+ },
238
+ });
239
+ // Step: Verify deployment
240
+ steps.push({
241
+ id: `step_${order++}`,
242
+ order: steps.length + 1,
243
+ type: 'verify',
244
+ description: 'Verify deployed infrastructure',
245
+ action: 'verify_deployment',
246
+ parameters: {
247
+ components: task.context.components,
248
+ environment: task.context.environment,
249
+ },
250
+ status: 'pending',
251
+ depends_on: [steps[steps.length - 1].id],
252
+ });
253
+ }
254
+ // Final step: Generate documentation
255
+ steps.push({
256
+ id: `step_${order++}`,
257
+ order: steps.length + 1,
258
+ type: 'generate',
259
+ description: 'Generate infrastructure documentation',
260
+ action: 'generate_documentation',
261
+ parameters: {
262
+ components: task.context.components,
263
+ include_diagrams: true,
264
+ },
265
+ status: 'pending',
266
+ depends_on: [steps[steps.length - 1].id],
267
+ });
268
+ return steps;
269
+ }
270
+ generateTerraformSteps(task) {
271
+ const steps = [];
272
+ let order = 1;
273
+ const env = task.context.environment ?? '.';
274
+ steps.push({ id: `step_${order++}`, order: steps.length + 1, type: 'validate', description: 'terraform init — initialize providers and modules', action: 'terraform_init', parameters: { workdir: env }, status: 'pending' });
275
+ steps.push({ id: `step_${order++}`, order: steps.length + 1, type: 'validate', description: 'terraform validate — check configuration syntax', action: 'terraform_validate', parameters: { workdir: env }, status: 'pending', depends_on: ['step_1'] });
276
+ steps.push({ id: `step_${order++}`, order: steps.length + 1, type: 'validate', description: 'terraform plan — preview changes', action: 'terraform_plan', parameters: { workdir: env }, status: 'pending', depends_on: ['step_2'] });
277
+ steps.push({ id: `step_${order++}`, order: steps.length + 1, type: 'validate', description: 'Review plan output with human', action: 'review_plan', parameters: { workdir: env }, status: 'pending', depends_on: ['step_3'] });
278
+ if (task.type === 'deploy') {
279
+ steps.push({ id: `step_${order++}`, order: steps.length + 1, type: 'deploy', description: 'terraform apply — apply approved changes', action: 'terraform_apply', parameters: { workdir: env }, status: 'pending', depends_on: ['step_4'], rollback_action: `terraform_destroy:${env}`, rollback_parameters: { workdir: env } });
280
+ steps.push({ id: `step_${order++}`, order: steps.length + 1, type: 'validate', description: 'terraform output — capture outputs', action: 'terraform_output', parameters: { workdir: env }, status: 'pending', depends_on: ['step_5'] });
281
+ steps.push({ id: `step_${order++}`, order: steps.length + 1, type: 'verify', description: 'Verify deployed infrastructure resources', action: 'verify_infra', parameters: { workdir: env }, status: 'pending', depends_on: ['step_6'] });
282
+ }
283
+ return steps;
284
+ }
285
+ generateKubernetesSteps(task) {
286
+ const steps = [];
287
+ let order = 1;
288
+ const env = task.context.environment ?? '.';
289
+ steps.push({ id: `step_${order++}`, order: steps.length + 1, type: 'validate', description: 'Validate Kubernetes manifests (dry-run client)', action: 'kubectl_dry_run', parameters: { workdir: env }, status: 'pending' });
290
+ steps.push({ id: `step_${order++}`, order: steps.length + 1, type: 'validate', description: 'kubectl diff — show what would change', action: 'kubectl_diff', parameters: { workdir: env }, status: 'pending', depends_on: ['step_1'] });
291
+ if (task.type === 'deploy') {
292
+ steps.push({ id: `step_${order++}`, order: steps.length + 1, type: 'deploy', description: 'kubectl apply — deploy manifests', action: 'kubectl_apply', parameters: { workdir: env }, status: 'pending', depends_on: ['step_2'], rollback_action: 'kubectl_rollout_undo:deployment/app:default' });
293
+ steps.push({ id: `step_${order++}`, order: steps.length + 1, type: 'verify', description: 'kubectl rollout status — wait for rollout', action: 'kubectl_rollout_status', parameters: { workdir: env }, status: 'pending', depends_on: ['step_3'] });
294
+ steps.push({ id: `step_${order++}`, order: steps.length + 1, type: 'verify', description: 'Verify all pods are running', action: 'verify_pods', parameters: { workdir: env }, status: 'pending', depends_on: ['step_4'] });
295
+ }
296
+ return steps;
297
+ }
298
+ generateHelmSteps(task) {
299
+ const steps = [];
300
+ let order = 1;
301
+ const release = task.context.components[0] ?? 'app';
302
+ const ns = task.context.environment ?? 'default';
303
+ steps.push({ id: `step_${order++}`, order: steps.length + 1, type: 'validate', description: 'helm lint — validate chart templates', action: 'helm_lint', parameters: { release, namespace: ns }, status: 'pending' });
304
+ steps.push({ id: `step_${order++}`, order: steps.length + 1, type: 'validate', description: 'helm template — render and preview manifests', action: 'helm_template', parameters: { release, namespace: ns }, status: 'pending', depends_on: ['step_1'] });
305
+ if (task.type === 'deploy') {
306
+ steps.push({ id: `step_${order++}`, order: steps.length + 1, type: 'validate', description: 'helm diff upgrade — show what would change', action: 'helm_diff', parameters: { release, namespace: ns }, status: 'pending', depends_on: ['step_2'] });
307
+ steps.push({ id: `step_${order++}`, order: steps.length + 1, type: 'deploy', description: 'helm upgrade --install --atomic — deploy release', action: 'helm_upgrade', parameters: { release, namespace: ns }, status: 'pending', depends_on: ['step_3'], rollback_action: `helm_rollback:${release}:0:${ns}` });
308
+ steps.push({ id: `step_${order++}`, order: steps.length + 1, type: 'verify', description: 'helm test — run chart tests', action: 'helm_test', parameters: { release, namespace: ns }, status: 'pending', depends_on: ['step_4'] });
309
+ steps.push({ id: `step_${order++}`, order: steps.length + 1, type: 'verify', description: 'Verify release is deployed and healthy', action: 'verify_release', parameters: { release, namespace: ns }, status: 'pending', depends_on: ['step_5'] });
310
+ }
311
+ return steps;
312
+ }
313
+ /**
314
+ * Analyze dependencies between steps
315
+ */
316
+ analyzeDependencies(steps) {
317
+ return steps
318
+ .filter(step => step.depends_on && step.depends_on.length > 0)
319
+ .map(step => ({
320
+ step_id: step.id,
321
+ depends_on: step.depends_on,
322
+ type: (step.depends_on.length === 1 ? 'sequential' : 'parallel'),
323
+ }));
324
+ }
325
+ /**
326
+ * Assess risks for the plan.
327
+ * Attempts LLM-based assessment first, falls back to heuristic logic.
328
+ */
329
+ async assessRisks(task, steps) {
330
+ try {
331
+ const llmRisks = await this.assessRisksWithLLM(task, steps);
332
+ if (llmRisks.length > 0) {
333
+ logger.info(`Using LLM-assessed risks (${llmRisks.length} risks)`);
334
+ return llmRisks;
335
+ }
336
+ }
337
+ catch (error) {
338
+ logger.debug(`LLM risk assessment failed, falling back to heuristics: ${error.message}`);
339
+ }
340
+ return this.assessRisksHeuristic(task, steps);
341
+ }
342
+ /**
343
+ * Assess risks using the embedded LLM router.
344
+ */
345
+ async assessRisksWithLLM(task, steps) {
346
+ const response = await this.router.route({
347
+ messages: [
348
+ { role: 'system', content: RISK_ASSESSMENT_PROMPT },
349
+ {
350
+ role: 'user',
351
+ content: JSON.stringify({
352
+ task: task.context,
353
+ steps: steps.map(s => ({ id: s.id, type: s.type, description: s.description })),
354
+ }),
355
+ },
356
+ ],
357
+ });
358
+ const content = response?.content;
359
+ if (!content) {
360
+ throw new Error('LLM response missing content');
361
+ }
362
+ const parsed = JSON.parse(content);
363
+ if (!Array.isArray(parsed) || parsed.length === 0) {
364
+ throw new Error('LLM response is not a non-empty array');
365
+ }
366
+ const risks = [];
367
+ for (const item of parsed) {
368
+ if (typeof item !== 'object' ||
369
+ item === null ||
370
+ typeof item.id !== 'string' ||
371
+ typeof item.description !== 'string' ||
372
+ !VALID_SEVERITIES.has(item.severity) ||
373
+ !VALID_CATEGORIES.has(item.category) ||
374
+ typeof item.probability !== 'number' ||
375
+ typeof item.impact !== 'number') {
376
+ throw new Error('LLM response contains invalid risk structure');
377
+ }
378
+ risks.push({
379
+ id: item.id,
380
+ severity: item.severity,
381
+ category: item.category,
382
+ description: item.description,
383
+ mitigation: typeof item.mitigation === 'string' ? item.mitigation : undefined,
384
+ probability: item.probability,
385
+ impact: item.impact,
386
+ });
387
+ }
388
+ return risks;
389
+ }
390
+ /**
391
+ * Assess risks using heuristic logic (fallback).
392
+ */
393
+ assessRisksHeuristic(task, steps) {
394
+ const risks = [];
395
+ // Security risks
396
+ if (task.context.environment === 'production') {
397
+ risks.push({
398
+ id: 'risk_prod_deploy',
399
+ severity: 'high',
400
+ category: 'availability',
401
+ description: 'Deploying to production environment',
402
+ mitigation: 'Requires approval, automated testing, and gradual rollout',
403
+ probability: 0.3,
404
+ impact: 0.8,
405
+ });
406
+ }
407
+ // Cost risks
408
+ const hasExpensiveComponents = task.context.components.some(c => ['eks', 'rds'].includes(c));
409
+ if (hasExpensiveComponents) {
410
+ risks.push({
411
+ id: 'risk_high_cost',
412
+ severity: 'medium',
413
+ category: 'cost',
414
+ description: 'Infrastructure includes high-cost components',
415
+ mitigation: 'Review instance types and enable autoscaling',
416
+ probability: 0.6,
417
+ impact: 0.5,
418
+ });
419
+ }
420
+ // Compliance risks
421
+ if (task.context.components.includes('s3')) {
422
+ risks.push({
423
+ id: 'risk_data_security',
424
+ severity: 'high',
425
+ category: 'security',
426
+ description: 'Storage component requires encryption and access controls',
427
+ mitigation: 'Enable encryption at rest and in transit, implement least privilege access',
428
+ probability: 0.4,
429
+ impact: 0.9,
430
+ });
431
+ }
432
+ // Deployment risks
433
+ const hasDeploymentSteps = steps.some(s => s.type === 'deploy');
434
+ if (hasDeploymentSteps && !task.context.requirements?.backup_enabled) {
435
+ risks.push({
436
+ id: 'risk_no_backup',
437
+ severity: 'high',
438
+ category: 'availability',
439
+ description: 'No backup strategy defined',
440
+ mitigation: 'Enable automated backups and test restoration procedures',
441
+ probability: 0.5,
442
+ impact: 0.7,
443
+ });
444
+ }
445
+ return risks;
446
+ }
447
+ /**
448
+ * Calculate overall risk level
449
+ */
450
+ calculateOverallRiskLevel(risks) {
451
+ if (risks.length === 0) {
452
+ return 'low';
453
+ }
454
+ const hasCritical = risks.some(r => r.severity === 'critical');
455
+ if (hasCritical) {
456
+ return 'critical';
457
+ }
458
+ const highRisks = risks.filter(r => r.severity === 'high');
459
+ if (highRisks.length >= 2) {
460
+ return 'high';
461
+ }
462
+ if (highRisks.length === 1) {
463
+ return 'high';
464
+ }
465
+ const mediumRisks = risks.filter(r => r.severity === 'medium');
466
+ if (mediumRisks.length >= 3) {
467
+ return 'high';
468
+ }
469
+ if (mediumRisks.length >= 1) {
470
+ return 'medium';
471
+ }
472
+ return 'low';
473
+ }
474
+ /**
475
+ * Estimate duration in seconds
476
+ */
477
+ estimateDuration(steps) {
478
+ const durations = {
479
+ validate: 30,
480
+ generate: 60,
481
+ deploy: 600, // 10 minutes for deployment
482
+ verify: 120,
483
+ };
484
+ return steps.reduce((total, step) => {
485
+ return total + (durations[step.type] || 60);
486
+ }, 0);
487
+ }
488
+ /**
489
+ * Estimate cost in USD
490
+ */
491
+ async estimateCost(task, _steps) {
492
+ let monthlyCost = 0;
493
+ const componentCosts = {
494
+ vpc: 0, // VPC itself is free, NAT gateway costs ~$32/month
495
+ eks: 73, // $0.10/hour * 730 hours
496
+ rds: 50, // t3.micro ~$15/month + storage
497
+ s3: 5, // Minimal storage estimate
498
+ };
499
+ for (const component of task.context.components) {
500
+ monthlyCost += componentCosts[component] || 0;
501
+ }
502
+ // Add NAT gateway cost if VPC is included
503
+ if (task.context.components.includes('vpc')) {
504
+ monthlyCost += 32;
505
+ }
506
+ return Math.round(monthlyCost);
507
+ }
508
+ /**
509
+ * Optimize plan for parallel execution
510
+ */
511
+ optimizePlan(plan) {
512
+ // Identify steps that can run in parallel
513
+ const optimized = { ...plan };
514
+ // Group independent generation steps
515
+ const generationSteps = plan.steps.filter(s => s.type === 'generate' && s.component);
516
+ // Mark independent steps as parallelizable
517
+ for (let i = 0; i < generationSteps.length; i++) {
518
+ const step = generationSteps[i];
519
+ // If steps don't have interdependencies, they can run in parallel
520
+ if (!this.hasInterdependency(step, generationSteps, i)) {
521
+ step.parameters.parallel_group = 'generation';
522
+ }
523
+ }
524
+ return optimized;
525
+ }
526
+ /**
527
+ * Check if step has interdependency with others
528
+ */
529
+ hasInterdependency(step, steps, _index) {
530
+ // Check if this step's output is needed by another step in the group
531
+ // Simplified: assume VPC must be created before EKS/RDS
532
+ if (step.component === 'vpc') {
533
+ return false;
534
+ }
535
+ if (step.component === 'eks' || step.component === 'rds') {
536
+ return steps.some(s => s.component === 'vpc');
537
+ }
538
+ return false;
539
+ }
540
+ /**
541
+ * Validate plan is executable
542
+ */
543
+ validatePlan(plan) {
544
+ const errors = [];
545
+ // Check for circular dependencies
546
+ if (this.hasCircularDependencies(plan)) {
547
+ errors.push('Plan contains circular dependencies');
548
+ }
549
+ // Check all dependencies exist
550
+ const stepIds = new Set(plan.steps.map(s => s.id));
551
+ for (const step of plan.steps) {
552
+ if (step.depends_on) {
553
+ for (const depId of step.depends_on) {
554
+ if (!stepIds.has(depId)) {
555
+ errors.push(`Step ${step.id} depends on non-existent step ${depId}`);
556
+ }
557
+ }
558
+ }
559
+ }
560
+ // Check step order matches dependencies
561
+ for (const step of plan.steps) {
562
+ if (step.depends_on) {
563
+ for (const depId of step.depends_on) {
564
+ const depStep = plan.steps.find(s => s.id === depId);
565
+ if (depStep && depStep.order >= step.order) {
566
+ errors.push(`Step ${step.id} has invalid order relative to dependency ${depId}`);
567
+ }
568
+ }
569
+ }
570
+ }
571
+ return {
572
+ valid: errors.length === 0,
573
+ errors,
574
+ };
575
+ }
576
+ /**
577
+ * Check for circular dependencies
578
+ */
579
+ hasCircularDependencies(plan) {
580
+ const visited = new Set();
581
+ const recursionStack = new Set();
582
+ const hasCycle = (stepId) => {
583
+ visited.add(stepId);
584
+ recursionStack.add(stepId);
585
+ const step = plan.steps.find(s => s.id === stepId);
586
+ if (step?.depends_on) {
587
+ for (const depId of step.depends_on) {
588
+ if (!visited.has(depId)) {
589
+ if (hasCycle(depId)) {
590
+ return true;
591
+ }
592
+ }
593
+ else if (recursionStack.has(depId)) {
594
+ return true;
595
+ }
596
+ }
597
+ }
598
+ recursionStack.delete(stepId);
599
+ return false;
600
+ };
601
+ for (const step of plan.steps) {
602
+ if (!visited.has(step.id)) {
603
+ if (hasCycle(step.id)) {
604
+ return true;
605
+ }
606
+ }
607
+ }
608
+ return false;
609
+ }
610
+ /**
611
+ * Generate plan ID
612
+ */
613
+ generatePlanId() {
614
+ return `plan_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
615
+ }
616
+ }