@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,338 @@
1
+ /**
2
+ * Interactive Prompt Utilities
3
+ *
4
+ * Provides functions for user input in the CLI wizard
5
+ */
6
+
7
+ import * as readline from 'node:readline';
8
+ import type { SelectConfig, ConfirmConfig, InputConfig } from './types';
9
+ import { ui } from './ui';
10
+
11
+ /**
12
+ * Create a readline interface for user input
13
+ */
14
+ function createReadline(): readline.Interface {
15
+ return readline.createInterface({
16
+ input: process.stdin,
17
+ output: process.stdout,
18
+ });
19
+ }
20
+
21
+ /**
22
+ * Prompt for a single selection from options
23
+ */
24
+ export async function select<T = string>(config: SelectConfig): Promise<T | undefined> {
25
+ return new Promise(resolve => {
26
+ const options = config.options.filter(o => !o.disabled);
27
+ let selectedIndex = 0;
28
+
29
+ // Find default selection
30
+ if (config.defaultValue) {
31
+ const defaultIdx = options.findIndex(o => o.value === config.defaultValue);
32
+ if (defaultIdx >= 0) {
33
+ selectedIndex = defaultIdx;
34
+ }
35
+ }
36
+
37
+ // Display prompt
38
+ ui.print(` ${ui.icons.question} ${config.message}`);
39
+ ui.newLine();
40
+
41
+ // For now, use simple numbered selection (arrow key selection requires raw mode)
42
+ for (let i = 0; i < config.options.length; i++) {
43
+ const opt = config.options[i];
44
+ const num = i + 1;
45
+ let line = ` ${num}. ${opt.label}`;
46
+
47
+ if (opt.disabled) {
48
+ line = ui.dim(`${line} (${opt.disabledReason || 'unavailable'})`);
49
+ }
50
+
51
+ ui.print(line);
52
+
53
+ if (opt.description) {
54
+ ui.print(ui.dim(` ${opt.description}`));
55
+ }
56
+ }
57
+
58
+ ui.newLine();
59
+
60
+ const rl = createReadline();
61
+ const defaultNum = selectedIndex + 1;
62
+ const prompt = config.required
63
+ ? ` Enter choice (1-${config.options.length}): `
64
+ : ` Enter choice (1-${config.options.length}) [${defaultNum}]: `;
65
+
66
+ rl.question(prompt, answer => {
67
+ rl.close();
68
+
69
+ const trimmed = answer.trim();
70
+
71
+ // Use default if empty
72
+ if (!trimmed && !config.required) {
73
+ resolve(config.options[selectedIndex].value as T);
74
+ return;
75
+ }
76
+
77
+ // Parse number
78
+ const num = parseInt(trimmed, 10);
79
+ if (isNaN(num) || num < 1 || num > config.options.length) {
80
+ ui.error(
81
+ `Invalid selection. Please enter a number between 1 and ${config.options.length}.`
82
+ );
83
+ resolve(undefined);
84
+ return;
85
+ }
86
+
87
+ const selected = config.options[num - 1];
88
+ if (selected.disabled) {
89
+ ui.error(`Option "${selected.label}" is not available.`);
90
+ resolve(undefined);
91
+ return;
92
+ }
93
+
94
+ ui.newLine();
95
+ ui.print(` ${ui.icons.success} Selected: ${selected.label}`);
96
+ resolve(selected.value as T);
97
+ });
98
+ });
99
+ }
100
+
101
+ /**
102
+ * Prompt for multiple selections from options
103
+ */
104
+ export async function multiSelect<T = string>(config: SelectConfig): Promise<T[]> {
105
+ return new Promise(resolve => {
106
+ const options = config.options.filter(o => !o.disabled);
107
+
108
+ ui.print(` ${ui.icons.question} ${config.message}`);
109
+ ui.print(ui.dim(' (Enter comma-separated numbers, or "all" for all options)'));
110
+ ui.newLine();
111
+
112
+ // Display options
113
+ for (let i = 0; i < config.options.length; i++) {
114
+ const opt = config.options[i];
115
+ const num = i + 1;
116
+ let line = ` ${num}. ${opt.label}`;
117
+
118
+ if (opt.disabled) {
119
+ line = ui.dim(`${line} (${opt.disabledReason || 'unavailable'})`);
120
+ }
121
+
122
+ ui.print(line);
123
+
124
+ if (opt.description) {
125
+ ui.print(ui.dim(` ${opt.description}`));
126
+ }
127
+ }
128
+
129
+ ui.newLine();
130
+
131
+ const rl = createReadline();
132
+ const prompt = ` Enter choices: `;
133
+
134
+ rl.question(prompt, answer => {
135
+ rl.close();
136
+
137
+ const trimmed = answer.trim().toLowerCase();
138
+
139
+ // Handle "all" selection
140
+ if (trimmed === 'all') {
141
+ const allValues = options.map(o => o.value as T);
142
+ ui.newLine();
143
+ ui.print(` ${ui.icons.success} Selected: All options`);
144
+ resolve(allValues);
145
+ return;
146
+ }
147
+
148
+ // Parse comma-separated numbers
149
+ const nums = trimmed.split(',').map(s => parseInt(s.trim(), 10));
150
+ const selected: T[] = [];
151
+ const selectedLabels: string[] = [];
152
+
153
+ for (const num of nums) {
154
+ if (isNaN(num) || num < 1 || num > config.options.length) {
155
+ continue;
156
+ }
157
+
158
+ const opt = config.options[num - 1];
159
+ if (!opt.disabled) {
160
+ selected.push(opt.value as T);
161
+ selectedLabels.push(opt.label);
162
+ }
163
+ }
164
+
165
+ if (selected.length === 0 && config.required) {
166
+ ui.error('Please select at least one option.');
167
+ resolve([]);
168
+ return;
169
+ }
170
+
171
+ if (config.maxSelections && selected.length > config.maxSelections) {
172
+ ui.error(`Maximum ${config.maxSelections} selections allowed.`);
173
+ resolve([]);
174
+ return;
175
+ }
176
+
177
+ ui.newLine();
178
+ ui.print(` ${ui.icons.success} Selected: ${selectedLabels.join(', ')}`);
179
+ resolve(selected);
180
+ });
181
+ });
182
+ }
183
+
184
+ /**
185
+ * Prompt for confirmation (yes/no)
186
+ */
187
+ export async function confirm(config: ConfirmConfig): Promise<boolean> {
188
+ return new Promise(resolve => {
189
+ const defaultHint =
190
+ config.defaultValue !== undefined ? (config.defaultValue ? '[Y/n]' : '[y/N]') : '[y/n]';
191
+
192
+ const rl = createReadline();
193
+ const prompt = ` ${ui.icons.question} ${config.message} ${defaultHint} `;
194
+
195
+ rl.question(prompt, answer => {
196
+ rl.close();
197
+
198
+ const trimmed = answer.trim().toLowerCase();
199
+
200
+ // Handle empty input
201
+ if (!trimmed) {
202
+ if (config.defaultValue !== undefined) {
203
+ resolve(config.defaultValue);
204
+ return;
205
+ }
206
+ resolve(false);
207
+ return;
208
+ }
209
+
210
+ // Parse answer
211
+ if (trimmed === 'y' || trimmed === 'yes') {
212
+ resolve(true);
213
+ } else if (trimmed === 'n' || trimmed === 'no') {
214
+ resolve(false);
215
+ } else {
216
+ ui.error('Please enter "y" or "n".');
217
+ resolve(config.defaultValue ?? false);
218
+ }
219
+ });
220
+ });
221
+ }
222
+
223
+ /**
224
+ * Prompt for text input
225
+ */
226
+ export async function input(config: InputConfig): Promise<string> {
227
+ return new Promise(resolve => {
228
+ const rl = createReadline();
229
+
230
+ let prompt = ` ${ui.icons.question} ${config.message}`;
231
+ if (config.defaultValue) {
232
+ prompt += ui.dim(` [${config.defaultValue}]`);
233
+ }
234
+ prompt += ': ';
235
+
236
+ rl.question(prompt, answer => {
237
+ rl.close();
238
+
239
+ let value = answer.trim();
240
+
241
+ // Use default if empty
242
+ if (!value && config.defaultValue) {
243
+ value = config.defaultValue;
244
+ }
245
+
246
+ // Transform if specified
247
+ if (config.transform && value) {
248
+ value = config.transform(value);
249
+ }
250
+
251
+ // Validate if specified
252
+ if (config.validate && value) {
253
+ const result = config.validate(value);
254
+ if (result !== true) {
255
+ ui.error(result);
256
+ resolve('');
257
+ return;
258
+ }
259
+ }
260
+
261
+ resolve(value);
262
+ });
263
+ });
264
+ }
265
+
266
+ /**
267
+ * Prompt for a path input with validation
268
+ */
269
+ export async function pathInput(message: string, defaultValue?: string): Promise<string> {
270
+ return input({
271
+ message,
272
+ defaultValue,
273
+ validate: value => {
274
+ // Basic path validation
275
+ if (!value) {
276
+ return 'Path is required';
277
+ }
278
+ if (value.includes('\0')) {
279
+ return 'Invalid path';
280
+ }
281
+ return true;
282
+ },
283
+ });
284
+ }
285
+
286
+ /**
287
+ * Wait for user to press enter
288
+ */
289
+ export async function pressEnter(message: string = 'Press Enter to continue...'): Promise<void> {
290
+ return new Promise(resolve => {
291
+ const rl = createReadline();
292
+ rl.question(` ${message}`, () => {
293
+ rl.close();
294
+ resolve();
295
+ });
296
+ });
297
+ }
298
+
299
+ /**
300
+ * Display action options (e.g., for review)
301
+ */
302
+ export async function actionSelect(
303
+ message: string,
304
+ actions: Array<{ key: string; label: string; description?: string }>
305
+ ): Promise<string> {
306
+ return new Promise(resolve => {
307
+ ui.print(` ${message}`);
308
+ ui.newLine();
309
+
310
+ for (const action of actions) {
311
+ ui.print(` [${action.key.toUpperCase()}] ${action.label}`);
312
+ if (action.description) {
313
+ ui.print(ui.dim(` ${action.description}`));
314
+ }
315
+ }
316
+
317
+ ui.newLine();
318
+
319
+ const rl = createReadline();
320
+ const validKeys = actions.map(a => a.key.toLowerCase());
321
+
322
+ rl.question(' > ', answer => {
323
+ rl.close();
324
+
325
+ const key = answer.trim().toLowerCase();
326
+
327
+ if (!validKeys.includes(key)) {
328
+ ui.error(
329
+ `Invalid option. Please enter one of: ${actions.map(a => a.key.toUpperCase()).join(', ')}`
330
+ );
331
+ resolve('');
332
+ return;
333
+ }
334
+
335
+ resolve(key);
336
+ });
337
+ });
338
+ }
@@ -0,0 +1,171 @@
1
+ /**
2
+ * Type definitions for the Interactive Wizard Framework
3
+ */
4
+
5
+ // Wizard step types
6
+ export interface WizardStep<TContext = any> {
7
+ id: string;
8
+ title: string;
9
+ description?: string;
10
+ execute: (context: TContext) => Promise<StepResult>;
11
+ canSkip?: boolean;
12
+ condition?: (context: TContext) => boolean;
13
+ }
14
+
15
+ export interface StepResult {
16
+ success: boolean;
17
+ data?: Record<string, unknown>;
18
+ error?: string;
19
+ nextStep?: string; // Override default next step
20
+ skipRemaining?: boolean;
21
+ }
22
+
23
+ // Selection types
24
+ export interface SelectOption<T = string> {
25
+ value: T;
26
+ label: string;
27
+ description?: string;
28
+ disabled?: boolean;
29
+ disabledReason?: string;
30
+ }
31
+
32
+ export interface SelectConfig {
33
+ message: string;
34
+ options: SelectOption[];
35
+ defaultValue?: string;
36
+ allowMultiple?: boolean;
37
+ required?: boolean;
38
+ maxSelections?: number;
39
+ }
40
+
41
+ export interface ConfirmConfig {
42
+ message: string;
43
+ defaultValue?: boolean;
44
+ }
45
+
46
+ export interface InputConfig {
47
+ message: string;
48
+ defaultValue?: string;
49
+ placeholder?: string;
50
+ validate?: (value: string) => string | true;
51
+ transform?: (value: string) => string;
52
+ }
53
+
54
+ // Progress display types
55
+ export interface ProgressConfig {
56
+ message: string;
57
+ total?: number;
58
+ showPercentage?: boolean;
59
+ showETA?: boolean;
60
+ }
61
+
62
+ export interface SpinnerConfig {
63
+ message: string;
64
+ successMessage?: string;
65
+ failMessage?: string;
66
+ }
67
+
68
+ // Output types
69
+ export interface TableColumn {
70
+ key: string;
71
+ header: string;
72
+ width?: number;
73
+ align?: 'left' | 'center' | 'right';
74
+ formatter?: (value: unknown) => string;
75
+ }
76
+
77
+ export interface TableConfig {
78
+ columns: TableColumn[];
79
+ data: Record<string, unknown>[];
80
+ title?: string;
81
+ showRowNumbers?: boolean;
82
+ }
83
+
84
+ // Box types for styled output
85
+ export type BoxStyle = 'single' | 'double' | 'rounded' | 'heavy';
86
+
87
+ export interface BoxConfig {
88
+ content: string | string[];
89
+ title?: string;
90
+ style?: BoxStyle;
91
+ padding?: number;
92
+ width?: number;
93
+ borderColor?: string;
94
+ titleColor?: string;
95
+ }
96
+
97
+ // Diff display types
98
+ export interface DiffLine {
99
+ type: 'unchanged' | 'added' | 'removed' | 'modified';
100
+ content: string;
101
+ lineNumber?: number;
102
+ }
103
+
104
+ export interface DiffConfig {
105
+ original: string;
106
+ modified: string;
107
+ title?: string;
108
+ contextLines?: number;
109
+ }
110
+
111
+ // Wizard context for terraform generation
112
+ export interface TerraformWizardContext {
113
+ // Provider selection
114
+ provider?: 'aws' | 'gcp' | 'azure';
115
+
116
+ // AWS configuration
117
+ awsProfile?: string;
118
+ awsRegions?: string[];
119
+ awsAccountId?: string;
120
+ awsAccountAlias?: string;
121
+
122
+ // GCP configuration
123
+ gcpProject?: string;
124
+ gcpRegions?: string[];
125
+
126
+ // Azure configuration
127
+ azureSubscription?: string;
128
+ azureResourceGroup?: string;
129
+
130
+ // Discovery options
131
+ servicesToScan?: string[];
132
+ excludeServices?: string[];
133
+
134
+ // Generation options
135
+ outputPath?: string;
136
+ includeImports?: boolean;
137
+ importMethod?: 'blocks' | 'script' | 'both';
138
+
139
+ // Improvements
140
+ enabledCategories?: string[];
141
+ autoApplyLowRisk?: boolean;
142
+ explanationLevel?: 'simple' | 'detailed';
143
+
144
+ // Starter kit
145
+ includeReadme?: boolean;
146
+ includeGitignore?: boolean;
147
+ includeMakefile?: boolean;
148
+ includeGithubActions?: boolean;
149
+
150
+ // State
151
+ discoverySessionId?: string;
152
+ inventory?: any;
153
+ generatedFiles?: any[];
154
+ improvements?: any;
155
+
156
+ // Preferences
157
+ savePreferences?: boolean;
158
+ organizationPolicy?: string;
159
+ }
160
+
161
+ // Wizard events
162
+ export type WizardEvent =
163
+ | { type: 'step:start'; stepId: string }
164
+ | { type: 'step:complete'; stepId: string; result: StepResult }
165
+ | { type: 'step:error'; stepId: string; error: Error }
166
+ | { type: 'wizard:start' }
167
+ | { type: 'wizard:complete'; context: any }
168
+ | { type: 'wizard:cancel' }
169
+ | { type: 'wizard:error'; error: Error };
170
+
171
+ export type WizardEventHandler = (event: WizardEvent) => void;