@build-astron-co/nimbus 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (313) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +628 -0
  3. package/bin/nimbus +38 -0
  4. package/package.json +80 -0
  5. package/src/__tests__/app.test.ts +76 -0
  6. package/src/__tests__/audit.test.ts +877 -0
  7. package/src/__tests__/circuit-breaker.test.ts +116 -0
  8. package/src/__tests__/cli-run.test.ts +115 -0
  9. package/src/__tests__/context-manager.test.ts +502 -0
  10. package/src/__tests__/context.test.ts +242 -0
  11. package/src/__tests__/enterprise.test.ts +401 -0
  12. package/src/__tests__/generator.test.ts +433 -0
  13. package/src/__tests__/hooks.test.ts +582 -0
  14. package/src/__tests__/init.test.ts +436 -0
  15. package/src/__tests__/intent-parser.test.ts +229 -0
  16. package/src/__tests__/llm-router.test.ts +209 -0
  17. package/src/__tests__/lsp.test.ts +293 -0
  18. package/src/__tests__/modes.test.ts +336 -0
  19. package/src/__tests__/permissions.test.ts +338 -0
  20. package/src/__tests__/serve.test.ts +275 -0
  21. package/src/__tests__/sessions.test.ts +227 -0
  22. package/src/__tests__/sharing.test.ts +288 -0
  23. package/src/__tests__/snapshots.test.ts +581 -0
  24. package/src/__tests__/state-db.test.ts +334 -0
  25. package/src/__tests__/stream-with-tools.test.ts +732 -0
  26. package/src/__tests__/subagents.test.ts +176 -0
  27. package/src/__tests__/system-prompt.test.ts +169 -0
  28. package/src/__tests__/tool-converter.test.ts +256 -0
  29. package/src/__tests__/tool-schemas.test.ts +397 -0
  30. package/src/__tests__/tools.test.ts +143 -0
  31. package/src/__tests__/version.test.ts +49 -0
  32. package/src/agent/compaction-agent.ts +227 -0
  33. package/src/agent/context-manager.ts +435 -0
  34. package/src/agent/context.ts +427 -0
  35. package/src/agent/deploy-preview.ts +426 -0
  36. package/src/agent/index.ts +68 -0
  37. package/src/agent/loop.ts +717 -0
  38. package/src/agent/modes.ts +429 -0
  39. package/src/agent/permissions.ts +466 -0
  40. package/src/agent/subagents/base.ts +116 -0
  41. package/src/agent/subagents/cost.ts +51 -0
  42. package/src/agent/subagents/explore.ts +42 -0
  43. package/src/agent/subagents/general.ts +54 -0
  44. package/src/agent/subagents/index.ts +102 -0
  45. package/src/agent/subagents/infra.ts +59 -0
  46. package/src/agent/subagents/security.ts +69 -0
  47. package/src/agent/system-prompt.ts +436 -0
  48. package/src/app.ts +122 -0
  49. package/src/audit/activity-log.ts +290 -0
  50. package/src/audit/compliance-checker.ts +540 -0
  51. package/src/audit/cost-tracker.ts +318 -0
  52. package/src/audit/index.ts +23 -0
  53. package/src/audit/security-scanner.ts +596 -0
  54. package/src/auth/guard.ts +75 -0
  55. package/src/auth/index.ts +56 -0
  56. package/src/auth/oauth.ts +455 -0
  57. package/src/auth/providers.ts +470 -0
  58. package/src/auth/sso.ts +113 -0
  59. package/src/auth/store.ts +505 -0
  60. package/src/auth/types.ts +187 -0
  61. package/src/build.ts +141 -0
  62. package/src/cli/index.ts +16 -0
  63. package/src/cli/init.ts +854 -0
  64. package/src/cli/openapi-spec.ts +356 -0
  65. package/src/cli/run.ts +237 -0
  66. package/src/cli/serve-auth.ts +80 -0
  67. package/src/cli/serve.ts +462 -0
  68. package/src/cli/web.ts +67 -0
  69. package/src/cli.ts +1417 -0
  70. package/src/clients/core-engine-client.ts +227 -0
  71. package/src/clients/enterprise-client.ts +334 -0
  72. package/src/clients/generator-client.ts +351 -0
  73. package/src/clients/git-client.ts +627 -0
  74. package/src/clients/github-client.ts +410 -0
  75. package/src/clients/helm-client.ts +504 -0
  76. package/src/clients/index.ts +80 -0
  77. package/src/clients/k8s-client.ts +497 -0
  78. package/src/clients/llm-client.ts +161 -0
  79. package/src/clients/rest-client.ts +130 -0
  80. package/src/clients/service-discovery.ts +33 -0
  81. package/src/clients/terraform-client.ts +482 -0
  82. package/src/clients/tools-client.ts +1843 -0
  83. package/src/clients/ws-client.ts +115 -0
  84. package/src/commands/analyze/index.ts +352 -0
  85. package/src/commands/apply/helm.ts +473 -0
  86. package/src/commands/apply/index.ts +213 -0
  87. package/src/commands/apply/k8s.ts +454 -0
  88. package/src/commands/apply/terraform.ts +582 -0
  89. package/src/commands/ask.ts +167 -0
  90. package/src/commands/audit/index.ts +238 -0
  91. package/src/commands/auth-cloud.ts +294 -0
  92. package/src/commands/auth-list.ts +134 -0
  93. package/src/commands/auth-profile.ts +121 -0
  94. package/src/commands/auth-status.ts +141 -0
  95. package/src/commands/aws/ec2.ts +501 -0
  96. package/src/commands/aws/iam.ts +397 -0
  97. package/src/commands/aws/index.ts +133 -0
  98. package/src/commands/aws/lambda.ts +396 -0
  99. package/src/commands/aws/rds.ts +439 -0
  100. package/src/commands/aws/s3.ts +439 -0
  101. package/src/commands/aws/vpc.ts +393 -0
  102. package/src/commands/aws-discover.ts +649 -0
  103. package/src/commands/aws-terraform.ts +805 -0
  104. package/src/commands/azure/aks.ts +376 -0
  105. package/src/commands/azure/functions.ts +253 -0
  106. package/src/commands/azure/index.ts +116 -0
  107. package/src/commands/azure/storage.ts +478 -0
  108. package/src/commands/azure/vm.ts +355 -0
  109. package/src/commands/billing/index.ts +256 -0
  110. package/src/commands/chat.ts +314 -0
  111. package/src/commands/config.ts +346 -0
  112. package/src/commands/cost/cloud-cost-estimator.ts +266 -0
  113. package/src/commands/cost/estimator.ts +79 -0
  114. package/src/commands/cost/index.ts +594 -0
  115. package/src/commands/cost/parsers/terraform.ts +273 -0
  116. package/src/commands/cost/parsers/types.ts +25 -0
  117. package/src/commands/cost/pricing/aws.ts +544 -0
  118. package/src/commands/cost/pricing/azure.ts +499 -0
  119. package/src/commands/cost/pricing/gcp.ts +396 -0
  120. package/src/commands/cost/pricing/index.ts +40 -0
  121. package/src/commands/demo.ts +250 -0
  122. package/src/commands/doctor.ts +794 -0
  123. package/src/commands/drift/index.ts +439 -0
  124. package/src/commands/explain.ts +277 -0
  125. package/src/commands/feedback.ts +389 -0
  126. package/src/commands/fix.ts +324 -0
  127. package/src/commands/fs/index.ts +402 -0
  128. package/src/commands/gcp/compute.ts +325 -0
  129. package/src/commands/gcp/functions.ts +271 -0
  130. package/src/commands/gcp/gke.ts +438 -0
  131. package/src/commands/gcp/iam.ts +344 -0
  132. package/src/commands/gcp/index.ts +129 -0
  133. package/src/commands/gcp/storage.ts +284 -0
  134. package/src/commands/generate-helm.ts +1249 -0
  135. package/src/commands/generate-k8s.ts +1560 -0
  136. package/src/commands/generate-terraform.ts +1460 -0
  137. package/src/commands/gh/index.ts +863 -0
  138. package/src/commands/git/index.ts +1343 -0
  139. package/src/commands/helm/index.ts +1126 -0
  140. package/src/commands/help.ts +539 -0
  141. package/src/commands/history.ts +142 -0
  142. package/src/commands/import.ts +868 -0
  143. package/src/commands/index.ts +367 -0
  144. package/src/commands/init.ts +1046 -0
  145. package/src/commands/k8s/index.ts +1137 -0
  146. package/src/commands/login.ts +631 -0
  147. package/src/commands/logout.ts +83 -0
  148. package/src/commands/onboarding.ts +228 -0
  149. package/src/commands/plan/display.ts +279 -0
  150. package/src/commands/plan/index.ts +599 -0
  151. package/src/commands/preview.ts +452 -0
  152. package/src/commands/questionnaire.ts +1270 -0
  153. package/src/commands/resume.ts +55 -0
  154. package/src/commands/team/index.ts +346 -0
  155. package/src/commands/template.ts +232 -0
  156. package/src/commands/tf/index.ts +1034 -0
  157. package/src/commands/upgrade.ts +550 -0
  158. package/src/commands/usage/index.ts +134 -0
  159. package/src/commands/version.ts +170 -0
  160. package/src/compat/index.ts +2 -0
  161. package/src/compat/runtime.ts +12 -0
  162. package/src/compat/sqlite.ts +107 -0
  163. package/src/config/index.ts +17 -0
  164. package/src/config/manager.ts +530 -0
  165. package/src/config/safety-policy.ts +358 -0
  166. package/src/config/schema.ts +125 -0
  167. package/src/config/types.ts +527 -0
  168. package/src/context/context-db.ts +199 -0
  169. package/src/demo/index.ts +349 -0
  170. package/src/demo/scenarios/full-journey.ts +229 -0
  171. package/src/demo/scenarios/getting-started.ts +127 -0
  172. package/src/demo/scenarios/helm-release.ts +341 -0
  173. package/src/demo/scenarios/k8s-deployment.ts +194 -0
  174. package/src/demo/scenarios/terraform-vpc.ts +170 -0
  175. package/src/demo/types.ts +92 -0
  176. package/src/engine/cost-estimator.ts +438 -0
  177. package/src/engine/diagram-generator.ts +256 -0
  178. package/src/engine/drift-detector.ts +902 -0
  179. package/src/engine/executor.ts +1035 -0
  180. package/src/engine/index.ts +76 -0
  181. package/src/engine/orchestrator.ts +636 -0
  182. package/src/engine/planner.ts +720 -0
  183. package/src/engine/safety.ts +743 -0
  184. package/src/engine/verifier.ts +770 -0
  185. package/src/enterprise/audit.ts +348 -0
  186. package/src/enterprise/auth.ts +270 -0
  187. package/src/enterprise/billing.ts +822 -0
  188. package/src/enterprise/index.ts +17 -0
  189. package/src/enterprise/teams.ts +443 -0
  190. package/src/generator/best-practices.ts +1608 -0
  191. package/src/generator/helm.ts +630 -0
  192. package/src/generator/index.ts +37 -0
  193. package/src/generator/intent-parser.ts +514 -0
  194. package/src/generator/kubernetes.ts +976 -0
  195. package/src/generator/terraform.ts +1867 -0
  196. package/src/history/index.ts +8 -0
  197. package/src/history/manager.ts +322 -0
  198. package/src/history/types.ts +34 -0
  199. package/src/hooks/config.ts +432 -0
  200. package/src/hooks/engine.ts +391 -0
  201. package/src/hooks/index.ts +4 -0
  202. package/src/llm/auth-bridge.ts +198 -0
  203. package/src/llm/circuit-breaker.ts +140 -0
  204. package/src/llm/config-loader.ts +201 -0
  205. package/src/llm/cost-calculator.ts +171 -0
  206. package/src/llm/index.ts +8 -0
  207. package/src/llm/model-aliases.ts +115 -0
  208. package/src/llm/provider-registry.ts +63 -0
  209. package/src/llm/providers/anthropic.ts +433 -0
  210. package/src/llm/providers/bedrock.ts +477 -0
  211. package/src/llm/providers/google.ts +405 -0
  212. package/src/llm/providers/ollama.ts +767 -0
  213. package/src/llm/providers/openai-compatible.ts +340 -0
  214. package/src/llm/providers/openai.ts +328 -0
  215. package/src/llm/providers/openrouter.ts +338 -0
  216. package/src/llm/router.ts +1035 -0
  217. package/src/llm/types.ts +232 -0
  218. package/src/lsp/client.ts +298 -0
  219. package/src/lsp/languages.ts +116 -0
  220. package/src/lsp/manager.ts +278 -0
  221. package/src/mcp/client.ts +402 -0
  222. package/src/mcp/index.ts +5 -0
  223. package/src/mcp/manager.ts +133 -0
  224. package/src/nimbus.ts +214 -0
  225. package/src/plugins/index.ts +27 -0
  226. package/src/plugins/loader.ts +334 -0
  227. package/src/plugins/manager.ts +376 -0
  228. package/src/plugins/types.ts +284 -0
  229. package/src/scanners/cicd-scanner.ts +258 -0
  230. package/src/scanners/cloud-scanner.ts +466 -0
  231. package/src/scanners/framework-scanner.ts +469 -0
  232. package/src/scanners/iac-scanner.ts +388 -0
  233. package/src/scanners/index.ts +539 -0
  234. package/src/scanners/language-scanner.ts +276 -0
  235. package/src/scanners/package-manager-scanner.ts +277 -0
  236. package/src/scanners/types.ts +172 -0
  237. package/src/sessions/manager.ts +365 -0
  238. package/src/sessions/types.ts +44 -0
  239. package/src/sharing/sync.ts +296 -0
  240. package/src/sharing/viewer.ts +97 -0
  241. package/src/snapshots/index.ts +2 -0
  242. package/src/snapshots/manager.ts +530 -0
  243. package/src/state/artifacts.ts +147 -0
  244. package/src/state/audit.ts +137 -0
  245. package/src/state/billing.ts +240 -0
  246. package/src/state/checkpoints.ts +117 -0
  247. package/src/state/config.ts +67 -0
  248. package/src/state/conversations.ts +14 -0
  249. package/src/state/credentials.ts +154 -0
  250. package/src/state/db.ts +58 -0
  251. package/src/state/index.ts +26 -0
  252. package/src/state/messages.ts +115 -0
  253. package/src/state/projects.ts +123 -0
  254. package/src/state/schema.ts +236 -0
  255. package/src/state/sessions.ts +147 -0
  256. package/src/state/teams.ts +200 -0
  257. package/src/telemetry.ts +108 -0
  258. package/src/tools/aws-ops.ts +952 -0
  259. package/src/tools/azure-ops.ts +579 -0
  260. package/src/tools/file-ops.ts +593 -0
  261. package/src/tools/gcp-ops.ts +625 -0
  262. package/src/tools/git-ops.ts +773 -0
  263. package/src/tools/github-ops.ts +799 -0
  264. package/src/tools/helm-ops.ts +943 -0
  265. package/src/tools/index.ts +17 -0
  266. package/src/tools/k8s-ops.ts +819 -0
  267. package/src/tools/schemas/converter.ts +184 -0
  268. package/src/tools/schemas/devops.ts +612 -0
  269. package/src/tools/schemas/index.ts +73 -0
  270. package/src/tools/schemas/standard.ts +1144 -0
  271. package/src/tools/schemas/types.ts +705 -0
  272. package/src/tools/terraform-ops.ts +862 -0
  273. package/src/types/ambient.d.ts +193 -0
  274. package/src/types/config.ts +83 -0
  275. package/src/types/drift.ts +116 -0
  276. package/src/types/enterprise.ts +335 -0
  277. package/src/types/index.ts +20 -0
  278. package/src/types/plan.ts +44 -0
  279. package/src/types/request.ts +65 -0
  280. package/src/types/response.ts +54 -0
  281. package/src/types/service.ts +51 -0
  282. package/src/ui/App.tsx +997 -0
  283. package/src/ui/DeployPreview.tsx +169 -0
  284. package/src/ui/Header.tsx +68 -0
  285. package/src/ui/InputBox.tsx +350 -0
  286. package/src/ui/MessageList.tsx +585 -0
  287. package/src/ui/PermissionPrompt.tsx +151 -0
  288. package/src/ui/StatusBar.tsx +158 -0
  289. package/src/ui/ToolCallDisplay.tsx +409 -0
  290. package/src/ui/chat-ui.ts +853 -0
  291. package/src/ui/index.ts +33 -0
  292. package/src/ui/ink/index.ts +711 -0
  293. package/src/ui/streaming.ts +176 -0
  294. package/src/ui/types.ts +57 -0
  295. package/src/utils/analytics.ts +72 -0
  296. package/src/utils/cost-warning.ts +27 -0
  297. package/src/utils/env.ts +46 -0
  298. package/src/utils/errors.ts +69 -0
  299. package/src/utils/event-bus.ts +38 -0
  300. package/src/utils/index.ts +24 -0
  301. package/src/utils/logger.ts +171 -0
  302. package/src/utils/rate-limiter.ts +121 -0
  303. package/src/utils/service-auth.ts +49 -0
  304. package/src/utils/validation.ts +53 -0
  305. package/src/version.ts +4 -0
  306. package/src/watcher/index.ts +163 -0
  307. package/src/wizard/approval.ts +383 -0
  308. package/src/wizard/index.ts +25 -0
  309. package/src/wizard/prompts.ts +338 -0
  310. package/src/wizard/types.ts +171 -0
  311. package/src/wizard/ui.ts +556 -0
  312. package/src/wizard/wizard.ts +304 -0
  313. package/tsconfig.json +24 -0
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Demo Framework Types
3
+ *
4
+ * Type definitions for the demo scenarios framework
5
+ */
6
+
7
+ /**
8
+ * A single step in a demo scenario
9
+ */
10
+ export interface DemoStep {
11
+ /** Unique identifier for this step */
12
+ id: string;
13
+ /** Title shown before executing */
14
+ title: string;
15
+ /** Description of what this step does */
16
+ description?: string;
17
+ /** Command to execute */
18
+ command: string;
19
+ /** Whether to wait for user input before proceeding */
20
+ waitForInput?: boolean;
21
+ /** Expected output pattern (regex) */
22
+ expectedOutput?: string;
23
+ /** Time to wait after step (ms) */
24
+ delay?: number;
25
+ /** Whether to show command output */
26
+ showOutput?: boolean;
27
+ /** Mock response for demo mode (when not actually executing) */
28
+ mockResponse?: string;
29
+ }
30
+
31
+ /**
32
+ * A demo scenario containing multiple steps
33
+ */
34
+ export interface DemoScenario {
35
+ /** Unique identifier */
36
+ id: string;
37
+ /** Display name */
38
+ name: string;
39
+ /** Short description */
40
+ description: string;
41
+ /** Category for grouping */
42
+ category: 'terraform' | 'kubernetes' | 'helm' | 'aws' | 'full-journey' | 'tutorial';
43
+ /** Ordered list of steps */
44
+ steps: DemoStep[];
45
+ /** Prerequisites (e.g., "aws cli installed") */
46
+ prerequisites?: string[];
47
+ /** Estimated duration in minutes */
48
+ duration?: number;
49
+ /** Tags for filtering */
50
+ tags?: string[];
51
+ }
52
+
53
+ /**
54
+ * Demo runner options
55
+ */
56
+ export interface DemoOptions {
57
+ /** Scenario ID to run */
58
+ scenario?: string;
59
+ /** List available scenarios */
60
+ list?: boolean;
61
+ /** Interactive mode (prompt for each step) */
62
+ interactive?: boolean;
63
+ /** Speed: slow, normal, fast */
64
+ speed?: 'slow' | 'normal' | 'fast';
65
+ /** Dry run - don't execute commands */
66
+ dryRun?: boolean;
67
+ /** Show all output (verbose) */
68
+ verbose?: boolean;
69
+ }
70
+
71
+ /**
72
+ * Step execution result
73
+ */
74
+ export interface StepResult {
75
+ step: DemoStep;
76
+ success: boolean;
77
+ output?: string;
78
+ error?: string;
79
+ duration: number;
80
+ }
81
+
82
+ /**
83
+ * Scenario execution result
84
+ */
85
+ export interface ScenarioResult {
86
+ scenario: DemoScenario;
87
+ steps: StepResult[];
88
+ success: boolean;
89
+ totalDuration: number;
90
+ startedAt: Date;
91
+ completedAt: Date;
92
+ }
@@ -0,0 +1,438 @@
1
+ /**
2
+ * Cost Estimator
3
+ *
4
+ * Standalone module for estimating monthly and annual infrastructure costs
5
+ * based on component type, environment, region, and usage patterns.
6
+ *
7
+ * Extracted from the cost estimation logic in verifier.ts and planner.ts,
8
+ * with expanded capabilities for detailed breakdowns and recommendations.
9
+ */
10
+
11
+ import { logger } from '../utils';
12
+
13
+ // ==========================================
14
+ // Cost Estimator Types
15
+ // ==========================================
16
+
17
+ /** Known infrastructure components with a base monthly cost. */
18
+ export type KnownComponent =
19
+ | 'vpc'
20
+ | 'eks'
21
+ | 'rds'
22
+ | 's3'
23
+ | 'ecs'
24
+ | 'lambda'
25
+ | 'cloudfront'
26
+ | 'elasticache'
27
+ | 'sqs'
28
+ | 'sns';
29
+
30
+ /** The environment tier affects cost multipliers and recommendations. */
31
+ export type EnvironmentTier = 'development' | 'staging' | 'production';
32
+
33
+ /** Cloud provider — affects regional pricing offsets. */
34
+ export type CloudProvider = 'aws' | 'gcp' | 'azure';
35
+
36
+ export interface CostEstimationInput {
37
+ /** List of infrastructure components to estimate (e.g. ['vpc', 'eks', 'rds']) */
38
+ components: string[];
39
+ /** Target environment — affects multipliers */
40
+ environment?: EnvironmentTier | string;
41
+ /** Cloud provider — affects regional pricing offsets */
42
+ provider?: CloudProvider | string;
43
+ /** AWS/GCP/Azure region — used for regional cost adjustments */
44
+ region?: string;
45
+ /** Optional explicit budget cap; used to flag over-budget estimates */
46
+ budgetLimit?: number;
47
+ /** Custom per-component overrides (monthly USD) */
48
+ customCosts?: Record<string, number>;
49
+ }
50
+
51
+ export interface ComponentCostBreakdown {
52
+ component: string;
53
+ baseMonthlyCost: number;
54
+ adjustedMonthlyCost: number;
55
+ environmentMultiplier: number;
56
+ regionalMultiplier: number;
57
+ notes: string;
58
+ }
59
+
60
+ export interface CostEstimate {
61
+ /** Total estimated monthly cost in USD */
62
+ totalMonthlyCost: number;
63
+ /** Total estimated annual cost in USD */
64
+ totalAnnualCost: number;
65
+ /** Per-component cost breakdown */
66
+ breakdown: ComponentCostBreakdown[];
67
+ /** Budget status */
68
+ withinBudget: boolean;
69
+ /** Budget limit used for comparison (if provided) */
70
+ budgetLimit?: number;
71
+ /** Cost optimisation recommendations */
72
+ recommendations: string[];
73
+ /** Environment tier used in the estimate */
74
+ environment: string;
75
+ /** Cloud provider used in the estimate */
76
+ provider: string;
77
+ /** Timestamp of estimate generation */
78
+ generatedAt: Date;
79
+ }
80
+
81
+ // ==========================================
82
+ // Constants
83
+ // ==========================================
84
+
85
+ /**
86
+ * Base monthly component costs in USD.
87
+ *
88
+ * These are intentionally conservative estimates for the most common
89
+ * instance sizes and usage patterns. Extracted directly from the
90
+ * original verifier.ts cost table and expanded for additional components.
91
+ *
92
+ * Sources:
93
+ * vpc: NAT Gateway ($0.045/h * 730h) ~= $32
94
+ * eks: Control plane only ($0.10/h * 730h) ~= $73
95
+ * rds: db.t3.micro ($0.017/h) + 20GB storage (~$2.30) ~= $15; rounded to $50 with Multi-AZ
96
+ * s3: Minimal storage estimate (< 100GB) ~= $5
97
+ */
98
+ const BASE_COMPONENT_COSTS: Record<string, number> = {
99
+ vpc: 32, // NAT Gateway
100
+ eks: 73, // Control plane
101
+ rds: 50, // db.t3.micro + storage
102
+ s3: 5, // Minimal storage
103
+ ecs: 30, // Fargate minimal
104
+ lambda: 2, // < 1M invocations/month
105
+ cloudfront: 10, // < 1TB transfer/month
106
+ elasticache: 25, // cache.t3.micro
107
+ sqs: 1, // < 1M requests/month
108
+ sns: 1, // < 1M notifications/month
109
+ };
110
+
111
+ /**
112
+ * Regional cost multipliers relative to us-east-1 (base = 1.0).
113
+ * Approximate — derived from AWS published pricing differentials.
114
+ */
115
+ const REGIONAL_MULTIPLIERS: Record<string, number> = {
116
+ 'us-east-1': 1.0,
117
+ 'us-east-2': 1.0,
118
+ 'us-west-1': 1.08,
119
+ 'us-west-2': 1.0,
120
+ 'eu-west-1': 1.06,
121
+ 'eu-west-2': 1.1,
122
+ 'eu-central-1': 1.08,
123
+ 'ap-southeast-1': 1.14,
124
+ 'ap-northeast-1': 1.16,
125
+ 'ap-south-1': 1.05,
126
+ 'sa-east-1': 1.2,
127
+ 'ca-central-1': 1.06,
128
+ // GCP regions (approximate relative costs)
129
+ 'us-central1': 1.0,
130
+ 'us-east1': 1.0,
131
+ 'europe-west1': 1.08,
132
+ 'asia-east1': 1.12,
133
+ // Azure regions
134
+ eastus: 1.0,
135
+ westus: 1.05,
136
+ westeurope: 1.1,
137
+ southeastasia: 1.12,
138
+ };
139
+
140
+ /**
141
+ * Environment multipliers.
142
+ * Production typically uses larger, HA-ready instances; dev uses minimal sizes.
143
+ */
144
+ const ENVIRONMENT_MULTIPLIERS: Record<string, number> = {
145
+ development: 0.5,
146
+ staging: 0.75,
147
+ production: 1.0,
148
+ prod: 1.0,
149
+ dev: 0.5,
150
+ staging_: 0.75,
151
+ };
152
+
153
+ /**
154
+ * Human-readable notes per component explaining the cost assumption.
155
+ */
156
+ const COMPONENT_NOTES: Record<string, string> = {
157
+ vpc: 'NAT Gateway ($0.045/h) — one AZ; add $32/mo per additional AZ',
158
+ eks: 'EKS control plane only ($0.10/h); node group EC2 costs are additive',
159
+ rds: 'db.t3.micro Multi-AZ estimated; scales significantly with instance class',
160
+ s3: 'Minimal estimate (<100GB, <1M requests); review lifecycle policies for long-term savings',
161
+ ecs: 'Fargate minimal workload; scales linearly with vCPU and memory allocation',
162
+ lambda: 'Under 1M invocations/month; free tier may apply',
163
+ cloudfront: 'Under 1TB egress/month; varies heavily with traffic patterns',
164
+ elasticache: 'cache.t3.micro; consider Reserved Nodes for >30% savings in production',
165
+ sqs: 'Under 1M requests/month; near-zero cost at small scale',
166
+ sns: 'Under 1M notifications/month; near-zero cost at small scale',
167
+ };
168
+
169
+ // ==========================================
170
+ // CostEstimator
171
+ // ==========================================
172
+
173
+ export class CostEstimator {
174
+ /**
175
+ * Estimate the monthly and annual cost for a given set of components.
176
+ */
177
+ estimate(input: CostEstimationInput): CostEstimate {
178
+ const environment = input.environment || 'production';
179
+ const provider = input.provider || 'aws';
180
+ const region = input.region || this.defaultRegion(provider);
181
+ const budgetLimit = input.budgetLimit;
182
+
183
+ logger.info(
184
+ `Estimating cost for ${input.components.length} components ` +
185
+ `(env=${environment}, provider=${provider}, region=${region})`
186
+ );
187
+
188
+ const envMultiplier = this.resolveEnvironmentMultiplier(environment);
189
+ const regionMultiplier = this.resolveRegionalMultiplier(region);
190
+
191
+ const breakdown: ComponentCostBreakdown[] = [];
192
+
193
+ for (const component of input.components) {
194
+ const baseCost = this.resolveBaseCost(component, input.customCosts);
195
+ const adjustedCost = Math.round(baseCost * envMultiplier * regionMultiplier * 100) / 100;
196
+
197
+ breakdown.push({
198
+ component,
199
+ baseMonthlyCost: baseCost,
200
+ adjustedMonthlyCost: adjustedCost,
201
+ environmentMultiplier: envMultiplier,
202
+ regionalMultiplier: regionMultiplier,
203
+ notes:
204
+ COMPONENT_NOTES[component] ||
205
+ `Estimate for ${component}; verify against provider pricing`,
206
+ });
207
+ }
208
+
209
+ const totalMonthlyCost =
210
+ Math.round(breakdown.reduce((sum, b) => sum + b.adjustedMonthlyCost, 0) * 100) / 100;
211
+
212
+ const totalAnnualCost = Math.round(totalMonthlyCost * 12 * 100) / 100;
213
+
214
+ const withinBudget = budgetLimit !== undefined ? totalMonthlyCost <= budgetLimit : true;
215
+
216
+ const recommendations = this.generateRecommendations(input, breakdown, totalMonthlyCost);
217
+
218
+ logger.info(
219
+ `Cost estimate: $${totalMonthlyCost}/mo ($${totalAnnualCost}/yr); ` +
220
+ `${withinBudget ? 'within' : 'exceeds'} budget`
221
+ );
222
+
223
+ return {
224
+ totalMonthlyCost,
225
+ totalAnnualCost,
226
+ breakdown,
227
+ withinBudget,
228
+ budgetLimit,
229
+ recommendations,
230
+ environment,
231
+ provider,
232
+ generatedAt: new Date(),
233
+ };
234
+ }
235
+
236
+ /**
237
+ * Estimate cost from a flat context object (compatible with verifier/planner usage).
238
+ *
239
+ * This is a convenience wrapper that accepts the same `context` shape used
240
+ * by the Verifier's `runCostChecks` method, allowing the CostEstimator to
241
+ * serve as a drop-in replacement.
242
+ */
243
+ estimateFromContext(context: Record<string, unknown>): number {
244
+ const components = (context.components as string[]) || [];
245
+ const result = this.estimate({
246
+ components,
247
+ environment: (context.environment as string) || 'production',
248
+ provider: (context.provider as string) || 'aws',
249
+ region: context.region as string | undefined,
250
+ budgetLimit: context.budget_limit as number | undefined,
251
+ });
252
+ return result.totalMonthlyCost;
253
+ }
254
+
255
+ /**
256
+ * Format a CostEstimate as a Markdown report.
257
+ */
258
+ formatAsMarkdown(estimate: CostEstimate): string {
259
+ const lines: string[] = [
260
+ `# Infrastructure Cost Estimate`,
261
+ ``,
262
+ `**Environment:** ${estimate.environment}`,
263
+ `**Provider:** ${estimate.provider}`,
264
+ `**Generated:** ${estimate.generatedAt.toISOString()}`,
265
+ ``,
266
+ `## Summary`,
267
+ ``,
268
+ `| Metric | Value |`,
269
+ `|--------|-------|`,
270
+ `| Monthly Cost | $${estimate.totalMonthlyCost.toFixed(2)} |`,
271
+ `| Annual Cost | $${estimate.totalAnnualCost.toFixed(2)} |`,
272
+ ];
273
+
274
+ if (estimate.budgetLimit !== undefined) {
275
+ lines.push(
276
+ `| Budget Limit | $${estimate.budgetLimit.toFixed(2)} |`,
277
+ `| Status | ${estimate.withinBudget ? 'Within Budget' : 'Over Budget'} |`
278
+ );
279
+ }
280
+
281
+ lines.push(
282
+ ``,
283
+ `## Component Breakdown`,
284
+ ``,
285
+ `| Component | Base ($/mo) | Adjusted ($/mo) | Notes |`,
286
+ `|-----------|------------|----------------|-------|`
287
+ );
288
+
289
+ for (const b of estimate.breakdown) {
290
+ lines.push(
291
+ `| ${b.component} | $${b.baseMonthlyCost.toFixed(2)} | $${b.adjustedMonthlyCost.toFixed(2)} | ${b.notes} |`
292
+ );
293
+ }
294
+
295
+ if (estimate.recommendations.length > 0) {
296
+ lines.push(``, `## Recommendations`, ``);
297
+ for (const rec of estimate.recommendations) {
298
+ lines.push(`- ${rec}`);
299
+ }
300
+ }
301
+
302
+ return lines.join('\n');
303
+ }
304
+
305
+ /**
306
+ * Generate cost optimisation recommendations based on the estimate inputs and results.
307
+ */
308
+ private generateRecommendations(
309
+ input: CostEstimationInput,
310
+ breakdown: ComponentCostBreakdown[],
311
+ totalMonthlyCost: number
312
+ ): string[] {
313
+ const recommendations: string[] = [];
314
+ const env = (input.environment || 'production').toLowerCase();
315
+ const components = input.components.map(c => c.toLowerCase());
316
+
317
+ // Production: Reserved instances
318
+ if (env === 'production' || env === 'prod') {
319
+ const hasExpensive = components.some(c => ['eks', 'rds', 'elasticache'].includes(c));
320
+ if (hasExpensive) {
321
+ recommendations.push(
322
+ 'Consider Reserved Instances or Savings Plans for EKS nodes, RDS, and ElastiCache — ' +
323
+ 'typically 30-40% savings over on-demand pricing with 1-year commitments.'
324
+ );
325
+ }
326
+ }
327
+
328
+ // Non-production: Single NAT gateway
329
+ if (env !== 'production' && env !== 'prod' && components.includes('vpc')) {
330
+ recommendations.push(
331
+ 'Use a single NAT Gateway in non-production environments to save ~$32/mo per additional AZ.'
332
+ );
333
+ }
334
+
335
+ // S3 lifecycle policies
336
+ if (components.includes('s3')) {
337
+ recommendations.push(
338
+ 'Configure S3 Lifecycle policies to transition infrequently accessed objects to ' +
339
+ 'S3 Intelligent-Tiering or Glacier; can reduce storage costs by 40-60%.'
340
+ );
341
+ }
342
+
343
+ // Development: spot instances
344
+ if (env === 'development' || env === 'dev') {
345
+ if (components.some(c => ['eks', 'ecs'].includes(c))) {
346
+ recommendations.push(
347
+ 'Use Spot Instances for development EKS node groups and ECS Fargate Spot — ' +
348
+ 'up to 90% savings with appropriate interruption handling.'
349
+ );
350
+ }
351
+ }
352
+
353
+ // High overall cost warning
354
+ if (totalMonthlyCost > 1000) {
355
+ recommendations.push(
356
+ `Total monthly cost $${totalMonthlyCost.toFixed(2)} is significant. ` +
357
+ 'Review instance types, enable autoscaling, and run AWS Cost Explorer or GCP Cost Management ' +
358
+ 'to identify unexpected spend.'
359
+ );
360
+ }
361
+
362
+ // Lambda: evaluate if replacing always-on compute
363
+ if (
364
+ components.includes('lambda') &&
365
+ !components.includes('ecs') &&
366
+ !components.includes('eks')
367
+ ) {
368
+ recommendations.push(
369
+ 'Lambda-only architecture is cost-efficient at low request volumes. ' +
370
+ 'Monitor concurrency limits and cold-start latency as traffic grows.'
371
+ );
372
+ }
373
+
374
+ // EKS without VPC
375
+ if (components.includes('eks') && !components.includes('vpc')) {
376
+ recommendations.push(
377
+ 'EKS clusters require a VPC. If using an existing VPC, ensure its NAT Gateway costs are ' +
378
+ 'accounted for separately (typically +$32/mo per AZ).'
379
+ );
380
+ }
381
+
382
+ return recommendations;
383
+ }
384
+
385
+ /**
386
+ * Resolve base cost for a component, respecting custom overrides.
387
+ */
388
+ private resolveBaseCost(component: string, customCosts?: Record<string, number>): number {
389
+ if (customCosts && component in customCosts) {
390
+ return customCosts[component];
391
+ }
392
+ return BASE_COMPONENT_COSTS[component.toLowerCase()] ?? 0;
393
+ }
394
+
395
+ /**
396
+ * Resolve environment multiplier from an environment string.
397
+ */
398
+ private resolveEnvironmentMultiplier(environment: string): number {
399
+ const key = environment.toLowerCase();
400
+ return ENVIRONMENT_MULTIPLIERS[key] ?? 1.0;
401
+ }
402
+
403
+ /**
404
+ * Resolve regional multiplier from a region string.
405
+ */
406
+ private resolveRegionalMultiplier(region: string): number {
407
+ return REGIONAL_MULTIPLIERS[region] ?? 1.0;
408
+ }
409
+
410
+ /**
411
+ * Return the default region for a given provider.
412
+ */
413
+ private defaultRegion(provider: string): string {
414
+ switch (provider.toLowerCase()) {
415
+ case 'gcp':
416
+ return 'us-central1';
417
+ case 'azure':
418
+ return 'eastus';
419
+ case 'aws':
420
+ default:
421
+ return 'us-east-1';
422
+ }
423
+ }
424
+
425
+ /**
426
+ * Get the base cost table (useful for display or testing).
427
+ */
428
+ getBaseCostTable(): Record<string, number> {
429
+ return { ...BASE_COMPONENT_COSTS };
430
+ }
431
+
432
+ /**
433
+ * Get the regional multiplier table (useful for display or testing).
434
+ */
435
+ getRegionalMultiplierTable(): Record<string, number> {
436
+ return { ...REGIONAL_MULTIPLIERS };
437
+ }
438
+ }