@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,397 @@
1
+ /**
2
+ * AWS IAM Commands
3
+ *
4
+ * IAM user, role, and policy operations
5
+ *
6
+ * Usage:
7
+ * nimbus aws iam users
8
+ * nimbus aws iam roles
9
+ * nimbus aws iam policies
10
+ */
11
+
12
+ import { logger } from '../../utils';
13
+ import { ui } from '../../wizard/ui';
14
+ import type { AwsCommandOptions } from './index';
15
+
16
+ interface IAMUser {
17
+ UserName: string;
18
+ UserId: string;
19
+ Arn: string;
20
+ CreateDate: string;
21
+ PasswordLastUsed?: string;
22
+ }
23
+
24
+ interface IAMRole {
25
+ RoleName: string;
26
+ RoleId: string;
27
+ Arn: string;
28
+ CreateDate: string;
29
+ Description?: string;
30
+ }
31
+
32
+ interface IAMPolicy {
33
+ PolicyName: string;
34
+ PolicyId: string;
35
+ Arn: string;
36
+ CreateDate: string;
37
+ AttachmentCount: number;
38
+ }
39
+
40
+ /**
41
+ * IAM command router
42
+ */
43
+ export async function iamCommand(
44
+ action: string,
45
+ args: string[],
46
+ options: AwsCommandOptions
47
+ ): Promise<void> {
48
+ logger.info('Running IAM command', { action, args, options });
49
+
50
+ switch (action) {
51
+ case 'users':
52
+ await listUsers(options);
53
+ break;
54
+
55
+ case 'roles':
56
+ await listRoles(options);
57
+ break;
58
+
59
+ case 'policies':
60
+ await listPolicies(options);
61
+ break;
62
+
63
+ case 'user':
64
+ if (!args[0]) {
65
+ ui.error('User name is required');
66
+ ui.print('Usage: nimbus aws iam user <username>');
67
+ return;
68
+ }
69
+ await describeUser(args[0], options);
70
+ break;
71
+
72
+ case 'role':
73
+ if (!args[0]) {
74
+ ui.error('Role name is required');
75
+ ui.print('Usage: nimbus aws iam role <rolename>');
76
+ return;
77
+ }
78
+ await describeRole(args[0], options);
79
+ break;
80
+
81
+ default:
82
+ showIamHelp();
83
+ break;
84
+ }
85
+ }
86
+
87
+ /**
88
+ * List all IAM users
89
+ */
90
+ async function listUsers(options: AwsCommandOptions): Promise<void> {
91
+ ui.header('IAM Users');
92
+
93
+ ui.startSpinner({ message: 'Fetching IAM users...' });
94
+
95
+ try {
96
+ const result = await runAwsCommand<{ Users: IAMUser[] }>('iam list-users', options);
97
+
98
+ const users = result.Users || [];
99
+
100
+ ui.stopSpinnerSuccess(`Found ${users.length} user(s)`);
101
+ ui.newLine();
102
+
103
+ if (users.length === 0) {
104
+ ui.info('No IAM users found');
105
+ return;
106
+ }
107
+
108
+ // Display table
109
+ const headers = ['Username', 'User ID', 'Created', 'Last Login'];
110
+ const rows = users.map(user => [
111
+ user.UserName,
112
+ user.UserId,
113
+ new Date(user.CreateDate).toLocaleDateString(),
114
+ user.PasswordLastUsed ? new Date(user.PasswordLastUsed).toLocaleDateString() : 'Never',
115
+ ]);
116
+
117
+ displayTable(headers, rows);
118
+ } catch (error) {
119
+ ui.stopSpinnerFail('Failed to list users');
120
+ ui.error((error as Error).message);
121
+ }
122
+ }
123
+
124
+ /**
125
+ * List all IAM roles
126
+ */
127
+ async function listRoles(options: AwsCommandOptions): Promise<void> {
128
+ ui.header('IAM Roles');
129
+
130
+ ui.startSpinner({ message: 'Fetching IAM roles...' });
131
+
132
+ try {
133
+ const result = await runAwsCommand<{ Roles: IAMRole[] }>('iam list-roles', options);
134
+
135
+ const roles = result.Roles || [];
136
+
137
+ ui.stopSpinnerSuccess(`Found ${roles.length} role(s)`);
138
+ ui.newLine();
139
+
140
+ if (roles.length === 0) {
141
+ ui.info('No IAM roles found');
142
+ return;
143
+ }
144
+
145
+ // Display table (filter out AWS service roles by default)
146
+ const customRoles = roles.filter(r => !r.RoleName.startsWith('AWS'));
147
+ const headers = ['Role Name', 'Role ID', 'Created', 'Description'];
148
+ const rows = customRoles.map(role => [
149
+ role.RoleName,
150
+ role.RoleId,
151
+ new Date(role.CreateDate).toLocaleDateString(),
152
+ role.Description || '-',
153
+ ]);
154
+
155
+ displayTable(headers, rows);
156
+
157
+ if (customRoles.length < roles.length) {
158
+ ui.newLine();
159
+ ui.dim(`(${roles.length - customRoles.length} AWS service roles hidden)`);
160
+ }
161
+ } catch (error) {
162
+ ui.stopSpinnerFail('Failed to list roles');
163
+ ui.error((error as Error).message);
164
+ }
165
+ }
166
+
167
+ /**
168
+ * List all IAM policies
169
+ */
170
+ async function listPolicies(options: AwsCommandOptions): Promise<void> {
171
+ ui.header('IAM Policies');
172
+
173
+ ui.startSpinner({ message: 'Fetching IAM policies...' });
174
+
175
+ try {
176
+ const result = await runAwsCommand<{ Policies: IAMPolicy[] }>(
177
+ 'iam list-policies --scope Local',
178
+ options
179
+ );
180
+
181
+ const policies = result.Policies || [];
182
+
183
+ ui.stopSpinnerSuccess(`Found ${policies.length} custom policy(ies)`);
184
+ ui.newLine();
185
+
186
+ if (policies.length === 0) {
187
+ ui.info('No custom IAM policies found');
188
+ return;
189
+ }
190
+
191
+ // Display table
192
+ const headers = ['Policy Name', 'Policy ID', 'Attachments', 'Created'];
193
+ const rows = policies.map(policy => [
194
+ policy.PolicyName,
195
+ policy.PolicyId,
196
+ String(policy.AttachmentCount),
197
+ new Date(policy.CreateDate).toLocaleDateString(),
198
+ ]);
199
+
200
+ displayTable(headers, rows);
201
+ } catch (error) {
202
+ ui.stopSpinnerFail('Failed to list policies');
203
+ ui.error((error as Error).message);
204
+ }
205
+ }
206
+
207
+ /**
208
+ * Describe a specific IAM user
209
+ */
210
+ async function describeUser(userName: string, options: AwsCommandOptions): Promise<void> {
211
+ ui.header(`IAM User: ${userName}`);
212
+
213
+ ui.startSpinner({ message: 'Fetching user details...' });
214
+
215
+ try {
216
+ const { execFile } = await import('child_process');
217
+ const { promisify } = await import('util');
218
+ const execFileAsync = promisify(execFile);
219
+
220
+ // Get user details
221
+ const userArgs = ['iam', 'get-user', '--user-name', userName, '--output', 'json'];
222
+ if (options.profile) {
223
+ userArgs.push('--profile', options.profile);
224
+ }
225
+
226
+ const { stdout: userOutput } = await execFileAsync('aws', userArgs);
227
+ const userData = JSON.parse(userOutput);
228
+ const user = userData.User;
229
+
230
+ // Get user groups
231
+ const groupArgs = ['iam', 'list-groups-for-user', '--user-name', userName, '--output', 'json'];
232
+ if (options.profile) {
233
+ groupArgs.push('--profile', options.profile);
234
+ }
235
+
236
+ const { stdout: groupOutput } = await execFileAsync('aws', groupArgs);
237
+ const groupData = JSON.parse(groupOutput);
238
+ const groups = groupData.Groups || [];
239
+
240
+ ui.stopSpinnerSuccess('User details retrieved');
241
+ ui.newLine();
242
+
243
+ ui.print(ui.bold('User Details:'));
244
+ ui.newLine();
245
+ ui.print(` Username: ${user.UserName}`);
246
+ ui.print(` User ID: ${user.UserId}`);
247
+ ui.print(` ARN: ${user.Arn}`);
248
+ ui.print(` Created: ${new Date(user.CreateDate).toLocaleString()}`);
249
+ ui.print(
250
+ ` Last Login: ${user.PasswordLastUsed ? new Date(user.PasswordLastUsed).toLocaleString() : 'Never'}`
251
+ );
252
+
253
+ if (groups.length > 0) {
254
+ ui.newLine();
255
+ ui.print(ui.bold('Groups:'));
256
+ for (const group of groups) {
257
+ ui.print(` - ${group.GroupName}`);
258
+ }
259
+ }
260
+ } catch (error) {
261
+ ui.stopSpinnerFail('Failed to describe user');
262
+ ui.error((error as Error).message);
263
+ }
264
+ }
265
+
266
+ /**
267
+ * Describe a specific IAM role
268
+ */
269
+ async function describeRole(roleName: string, options: AwsCommandOptions): Promise<void> {
270
+ ui.header(`IAM Role: ${roleName}`);
271
+
272
+ ui.startSpinner({ message: 'Fetching role details...' });
273
+
274
+ try {
275
+ const { execFile } = await import('child_process');
276
+ const { promisify } = await import('util');
277
+ const execFileAsync = promisify(execFile);
278
+
279
+ // Get role details
280
+ const roleArgs = ['iam', 'get-role', '--role-name', roleName, '--output', 'json'];
281
+ if (options.profile) {
282
+ roleArgs.push('--profile', options.profile);
283
+ }
284
+
285
+ const { stdout: roleOutput } = await execFileAsync('aws', roleArgs);
286
+ const roleData = JSON.parse(roleOutput);
287
+ const role = roleData.Role;
288
+
289
+ // Get attached policies
290
+ const policyArgs = [
291
+ 'iam',
292
+ 'list-attached-role-policies',
293
+ '--role-name',
294
+ roleName,
295
+ '--output',
296
+ 'json',
297
+ ];
298
+ if (options.profile) {
299
+ policyArgs.push('--profile', options.profile);
300
+ }
301
+
302
+ const { stdout: policyOutput } = await execFileAsync('aws', policyArgs);
303
+ const policyData = JSON.parse(policyOutput);
304
+ const policies = policyData.AttachedPolicies || [];
305
+
306
+ ui.stopSpinnerSuccess('Role details retrieved');
307
+ ui.newLine();
308
+
309
+ ui.print(ui.bold('Role Details:'));
310
+ ui.newLine();
311
+ ui.print(` Role Name: ${role.RoleName}`);
312
+ ui.print(` Role ID: ${role.RoleId}`);
313
+ ui.print(` ARN: ${role.Arn}`);
314
+ ui.print(` Created: ${new Date(role.CreateDate).toLocaleString()}`);
315
+ if (role.Description) {
316
+ ui.print(` Description: ${role.Description}`);
317
+ }
318
+
319
+ if (policies.length > 0) {
320
+ ui.newLine();
321
+ ui.print(ui.bold('Attached Policies:'));
322
+ for (const policy of policies) {
323
+ ui.print(` - ${policy.PolicyName}`);
324
+ }
325
+ }
326
+ } catch (error) {
327
+ ui.stopSpinnerFail('Failed to describe role');
328
+ ui.error((error as Error).message);
329
+ }
330
+ }
331
+
332
+ /**
333
+ * Run AWS CLI command and parse JSON output
334
+ */
335
+ async function runAwsCommand<T>(command: string, options: AwsCommandOptions): Promise<T> {
336
+ const { execFile } = await import('child_process');
337
+ const { promisify } = await import('util');
338
+ const execFileAsync = promisify(execFile);
339
+
340
+ const args = command.split(' ');
341
+ const baseCommand = args[0];
342
+ const commandArgs = args.slice(1);
343
+
344
+ // Add common options
345
+ if (options.profile) {
346
+ commandArgs.push('--profile', options.profile);
347
+ }
348
+ commandArgs.push('--output', 'json');
349
+
350
+ const { stdout } = await execFileAsync('aws', [baseCommand, ...commandArgs]);
351
+ return JSON.parse(stdout) as T;
352
+ }
353
+
354
+ /**
355
+ * Display a table
356
+ */
357
+ function displayTable(headers: string[], rows: string[][]): void {
358
+ // Calculate column widths
359
+ const colWidths = headers.map((h, i) => {
360
+ const maxDataWidth = Math.max(...rows.map(r => (r[i] || '').length));
361
+ return Math.max(h.length, maxDataWidth);
362
+ });
363
+
364
+ // Print header
365
+ const headerRow = headers.map((h, i) => h.padEnd(colWidths[i])).join(' ');
366
+ ui.print(ui.bold(headerRow));
367
+ ui.print('-'.repeat(headerRow.length));
368
+
369
+ // Print rows
370
+ for (const row of rows) {
371
+ const formattedRow = row.map((cell, i) => (cell || '').padEnd(colWidths[i])).join(' ');
372
+ ui.print(formattedRow);
373
+ }
374
+ }
375
+
376
+ /**
377
+ * Show IAM command help
378
+ */
379
+ function showIamHelp(): void {
380
+ ui.print('Usage: nimbus aws iam <action> [args]');
381
+ ui.newLine();
382
+
383
+ ui.print(ui.bold('Actions:'));
384
+ ui.print(' users List all IAM users');
385
+ ui.print(' roles List all IAM roles');
386
+ ui.print(' policies List custom IAM policies');
387
+ ui.print(' user <name> Describe a specific user');
388
+ ui.print(' role <name> Describe a specific role');
389
+ ui.newLine();
390
+
391
+ ui.print(ui.bold('Examples:'));
392
+ ui.print(' nimbus aws iam users');
393
+ ui.print(' nimbus aws iam roles');
394
+ ui.print(' nimbus aws iam user admin');
395
+ }
396
+
397
+ export default iamCommand;
@@ -0,0 +1,133 @@
1
+ /**
2
+ * AWS CLI Commands
3
+ *
4
+ * Wrapper for AWS CLI operations with enhanced output and safety checks
5
+ *
6
+ * Usage:
7
+ * nimbus aws ec2 list
8
+ * nimbus aws s3 ls
9
+ * nimbus aws rds list
10
+ * nimbus aws lambda list
11
+ * nimbus aws iam users
12
+ * nimbus aws vpc list
13
+ */
14
+
15
+ import { logger } from '../../utils';
16
+ import { ui } from '../../wizard/ui';
17
+ import { ec2Command } from './ec2';
18
+ import { s3Command } from './s3';
19
+ import { rdsCommand } from './rds';
20
+ import { lambdaCommand } from './lambda';
21
+ import { iamCommand } from './iam';
22
+ import { vpcCommand } from './vpc';
23
+
24
+ export interface AwsCommandOptions {
25
+ profile?: string;
26
+ region?: string;
27
+ output?: 'json' | 'table' | 'text';
28
+ }
29
+
30
+ /**
31
+ * Parse common AWS options from args
32
+ */
33
+ export function parseAwsOptions(args: string[]): AwsCommandOptions {
34
+ const options: AwsCommandOptions = {};
35
+
36
+ for (let i = 0; i < args.length; i++) {
37
+ const arg = args[i];
38
+
39
+ if ((arg === '--profile' || arg === '-p') && args[i + 1]) {
40
+ options.profile = args[++i];
41
+ } else if ((arg === '--region' || arg === '-r') && args[i + 1]) {
42
+ options.region = args[++i];
43
+ } else if ((arg === '--output' || arg === '-o') && args[i + 1]) {
44
+ options.output = args[++i] as 'json' | 'table' | 'text';
45
+ }
46
+ }
47
+
48
+ return options;
49
+ }
50
+
51
+ /**
52
+ * Main AWS command router
53
+ */
54
+ export async function awsCommand(subcommand: string, args: string[]): Promise<void> {
55
+ logger.info('Running AWS command', { subcommand, args });
56
+
57
+ const options = parseAwsOptions(args);
58
+ const positionalArgs = args.filter(arg => !arg.startsWith('-') && !arg.startsWith('--'));
59
+
60
+ switch (subcommand) {
61
+ case 'ec2':
62
+ await ec2Command(positionalArgs[0], positionalArgs.slice(1), options);
63
+ break;
64
+
65
+ case 's3':
66
+ await s3Command(positionalArgs[0], positionalArgs.slice(1), options);
67
+ break;
68
+
69
+ case 'rds':
70
+ await rdsCommand(positionalArgs[0], positionalArgs.slice(1), options);
71
+ break;
72
+
73
+ case 'lambda':
74
+ await lambdaCommand(positionalArgs[0], positionalArgs.slice(1), options);
75
+ break;
76
+
77
+ case 'iam':
78
+ await iamCommand(positionalArgs[0], positionalArgs.slice(1), options);
79
+ break;
80
+
81
+ case 'vpc':
82
+ await vpcCommand(positionalArgs[0], positionalArgs.slice(1), options);
83
+ break;
84
+
85
+ default:
86
+ showAwsHelp();
87
+ break;
88
+ }
89
+ }
90
+
91
+ /**
92
+ * Show AWS command help
93
+ */
94
+ function showAwsHelp(): void {
95
+ ui.header('Nimbus AWS Commands');
96
+ ui.newLine();
97
+
98
+ ui.print('Usage: nimbus aws <service> <action> [options]');
99
+ ui.newLine();
100
+
101
+ ui.print(ui.bold('Services:'));
102
+ ui.print(' ec2 EC2 instance operations');
103
+ ui.print(' s3 S3 bucket and object operations');
104
+ ui.print(' rds RDS database operations');
105
+ ui.print(' lambda Lambda function operations');
106
+ ui.print(' iam IAM user, role, and policy operations');
107
+ ui.print(' vpc VPC and networking operations');
108
+ ui.newLine();
109
+
110
+ ui.print(ui.bold('Common Options:'));
111
+ ui.print(' --profile, -p AWS profile to use');
112
+ ui.print(' --region, -r AWS region');
113
+ ui.print(' --output, -o Output format (json, table, text)');
114
+ ui.newLine();
115
+
116
+ ui.print(ui.bold('Examples:'));
117
+ ui.print(' nimbus aws ec2 list List all EC2 instances');
118
+ ui.print(' nimbus aws ec2 describe i-1234567890 Describe specific instance');
119
+ ui.print(' nimbus aws s3 ls List all S3 buckets');
120
+ ui.print(' nimbus aws s3 ls my-bucket List objects in bucket');
121
+ ui.print(' nimbus aws rds list List all RDS instances');
122
+ ui.print(' nimbus aws lambda list List all Lambda functions');
123
+ }
124
+
125
+ // Re-export subcommands
126
+ export { ec2Command } from './ec2';
127
+ export { s3Command } from './s3';
128
+ export { rdsCommand } from './rds';
129
+ export { lambdaCommand } from './lambda';
130
+ export { iamCommand } from './iam';
131
+ export { vpcCommand } from './vpc';
132
+
133
+ export default awsCommand;