@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,396 @@
1
+ /**
2
+ * AWS Lambda Commands
3
+ *
4
+ * Lambda function operations
5
+ *
6
+ * Usage:
7
+ * nimbus aws lambda list
8
+ * nimbus aws lambda invoke <function-name>
9
+ * nimbus aws lambda logs <function-name>
10
+ */
11
+
12
+ import { logger } from '../../utils';
13
+ import { ui } from '../../wizard/ui';
14
+ import { confirm, input } from '../../wizard/prompts';
15
+ import type { AwsCommandOptions } from './index';
16
+
17
+ interface LambdaFunction {
18
+ FunctionName: string;
19
+ Runtime: string;
20
+ Handler: string;
21
+ CodeSize: number;
22
+ MemorySize: number;
23
+ Timeout: number;
24
+ LastModified: string;
25
+ State?: string;
26
+ }
27
+
28
+ /**
29
+ * Lambda command router
30
+ */
31
+ export async function lambdaCommand(
32
+ action: string,
33
+ args: string[],
34
+ options: AwsCommandOptions
35
+ ): Promise<void> {
36
+ logger.info('Running Lambda command', { action, args, options });
37
+
38
+ switch (action) {
39
+ case 'list':
40
+ case 'ls':
41
+ await listFunctions(options);
42
+ break;
43
+
44
+ case 'invoke':
45
+ if (!args[0]) {
46
+ ui.error('Function name is required');
47
+ ui.print('Usage: nimbus aws lambda invoke <function-name>');
48
+ return;
49
+ }
50
+ await invokeFunction(args[0], args[1], options);
51
+ break;
52
+
53
+ case 'logs':
54
+ if (!args[0]) {
55
+ ui.error('Function name is required');
56
+ ui.print('Usage: nimbus aws lambda logs <function-name>');
57
+ return;
58
+ }
59
+ await getFunctionLogs(args[0], options);
60
+ break;
61
+
62
+ default:
63
+ showLambdaHelp();
64
+ break;
65
+ }
66
+ }
67
+
68
+ /**
69
+ * List all Lambda functions
70
+ */
71
+ async function listFunctions(options: AwsCommandOptions): Promise<void> {
72
+ ui.header('Lambda Functions');
73
+
74
+ ui.startSpinner({ message: 'Fetching Lambda functions...' });
75
+
76
+ try {
77
+ const result = await runAwsCommand<{ Functions: LambdaFunction[] }>(
78
+ 'lambda list-functions',
79
+ options
80
+ );
81
+
82
+ const functions = result.Functions || [];
83
+
84
+ ui.stopSpinnerSuccess(`Found ${functions.length} function(s)`);
85
+ ui.newLine();
86
+
87
+ if (functions.length === 0) {
88
+ ui.info('No Lambda functions found');
89
+ return;
90
+ }
91
+
92
+ // Display table
93
+ displayFunctionTable(functions);
94
+ } catch (error) {
95
+ ui.stopSpinnerFail('Failed to list functions');
96
+ ui.error((error as Error).message);
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Invoke a Lambda function
102
+ */
103
+ async function invokeFunction(
104
+ functionName: string,
105
+ payload: string | undefined,
106
+ options: AwsCommandOptions
107
+ ): Promise<void> {
108
+ ui.header(`Invoke Lambda: ${functionName}`);
109
+
110
+ // Get payload if not provided
111
+ let invokePayload = payload;
112
+ if (!invokePayload) {
113
+ invokePayload = await input({
114
+ message: 'Enter payload (JSON):',
115
+ defaultValue: '{}',
116
+ });
117
+ }
118
+
119
+ // Validate JSON
120
+ try {
121
+ JSON.parse(invokePayload);
122
+ } catch {
123
+ ui.error('Invalid JSON payload');
124
+ return;
125
+ }
126
+
127
+ const proceed = await confirm({
128
+ message: `Invoke function ${functionName}?`,
129
+ defaultValue: true,
130
+ });
131
+
132
+ if (!proceed) {
133
+ ui.info('Operation cancelled');
134
+ return;
135
+ }
136
+
137
+ ui.startSpinner({ message: 'Invoking function...' });
138
+
139
+ try {
140
+ const { execFile } = await import('child_process');
141
+ const { promisify } = await import('util');
142
+ const fs = await import('fs/promises');
143
+ const os = await import('os');
144
+ const path = await import('path');
145
+ const execFileAsync = promisify(execFile);
146
+
147
+ // Write payload to temp file
148
+ const tempFile = path.join(os.tmpdir(), `lambda-payload-${Date.now()}.json`);
149
+ await fs.writeFile(tempFile, invokePayload);
150
+
151
+ // Invoke Lambda
152
+ const args = [
153
+ 'lambda',
154
+ 'invoke',
155
+ '--function-name',
156
+ functionName,
157
+ '--payload',
158
+ `file://${tempFile}`,
159
+ '--cli-binary-format',
160
+ 'raw-in-base64-out',
161
+ ];
162
+
163
+ if (options.profile) {
164
+ args.push('--profile', options.profile);
165
+ }
166
+ if (options.region) {
167
+ args.push('--region', options.region);
168
+ }
169
+
170
+ const outputFile = path.join(os.tmpdir(), `lambda-response-${Date.now()}.json`);
171
+ args.push(outputFile);
172
+
173
+ const { stdout } = await execFileAsync('aws', args);
174
+
175
+ ui.stopSpinnerSuccess('Function invoked');
176
+ ui.newLine();
177
+
178
+ // Parse invocation result
179
+ const result = JSON.parse(stdout);
180
+ ui.print(ui.bold('Invocation Result:'));
181
+ ui.print(` Status Code: ${result.StatusCode}`);
182
+ if (result.FunctionError) {
183
+ ui.print(` Error: ${ui.color(result.FunctionError, 'red')}`);
184
+ }
185
+
186
+ // Read response
187
+ try {
188
+ const response = await fs.readFile(outputFile, 'utf-8');
189
+ ui.newLine();
190
+ ui.print(ui.bold('Response:'));
191
+ ui.print(response);
192
+ } catch {
193
+ // No response file
194
+ }
195
+
196
+ // Cleanup
197
+ await fs.unlink(tempFile).catch(() => {});
198
+ await fs.unlink(outputFile).catch(() => {});
199
+ } catch (error) {
200
+ ui.stopSpinnerFail('Invocation failed');
201
+ ui.error((error as Error).message);
202
+ }
203
+ }
204
+
205
+ /**
206
+ * Get Lambda function logs
207
+ */
208
+ async function getFunctionLogs(functionName: string, options: AwsCommandOptions): Promise<void> {
209
+ ui.header(`Lambda Logs: ${functionName}`);
210
+
211
+ ui.startSpinner({ message: 'Fetching logs...' });
212
+
213
+ try {
214
+ const { execFile } = await import('child_process');
215
+ const { promisify } = await import('util');
216
+ const execFileAsync = promisify(execFile);
217
+
218
+ // Get log group name
219
+ const logGroupName = `/aws/lambda/${functionName}`;
220
+
221
+ // Fetch recent log streams
222
+ const args = [
223
+ 'logs',
224
+ 'describe-log-streams',
225
+ '--log-group-name',
226
+ logGroupName,
227
+ '--order-by',
228
+ 'LastEventTime',
229
+ '--descending',
230
+ '--limit',
231
+ '1',
232
+ '--output',
233
+ 'json',
234
+ ];
235
+
236
+ if (options.profile) {
237
+ args.push('--profile', options.profile);
238
+ }
239
+ if (options.region) {
240
+ args.push('--region', options.region);
241
+ }
242
+
243
+ const { stdout: streamsOutput } = await execFileAsync('aws', args);
244
+ const streams = JSON.parse(streamsOutput);
245
+
246
+ if (!streams.logStreams || streams.logStreams.length === 0) {
247
+ ui.stopSpinnerSuccess('');
248
+ ui.info('No log streams found');
249
+ return;
250
+ }
251
+
252
+ const latestStream = streams.logStreams[0].logStreamName;
253
+
254
+ // Fetch log events
255
+ const logArgs = [
256
+ 'logs',
257
+ 'get-log-events',
258
+ '--log-group-name',
259
+ logGroupName,
260
+ '--log-stream-name',
261
+ latestStream,
262
+ '--limit',
263
+ '50',
264
+ '--output',
265
+ 'json',
266
+ ];
267
+
268
+ if (options.profile) {
269
+ logArgs.push('--profile', options.profile);
270
+ }
271
+ if (options.region) {
272
+ logArgs.push('--region', options.region);
273
+ }
274
+
275
+ const { stdout: logsOutput } = await execFileAsync('aws', logArgs);
276
+ const logs = JSON.parse(logsOutput);
277
+
278
+ ui.stopSpinnerSuccess('Logs retrieved');
279
+ ui.newLine();
280
+
281
+ if (!logs.events || logs.events.length === 0) {
282
+ ui.info('No log events found');
283
+ return;
284
+ }
285
+
286
+ ui.print(ui.bold(`Recent logs from: ${latestStream}`));
287
+ ui.newLine();
288
+
289
+ for (const event of logs.events) {
290
+ const timestamp = new Date(event.timestamp).toISOString();
291
+ ui.print(`${ui.dim(timestamp)} ${event.message.trim()}`);
292
+ }
293
+ } catch (error) {
294
+ ui.stopSpinnerFail('Failed to fetch logs');
295
+ ui.error((error as Error).message);
296
+ }
297
+ }
298
+
299
+ /**
300
+ * Run AWS CLI command and parse JSON output
301
+ */
302
+ async function runAwsCommand<T>(command: string, options: AwsCommandOptions): Promise<T> {
303
+ const { execFile } = await import('child_process');
304
+ const { promisify } = await import('util');
305
+ const execFileAsync = promisify(execFile);
306
+
307
+ const args = command.split(' ');
308
+ const baseCommand = args[0];
309
+ const commandArgs = args.slice(1);
310
+
311
+ // Add common options
312
+ if (options.profile) {
313
+ commandArgs.push('--profile', options.profile);
314
+ }
315
+ if (options.region) {
316
+ commandArgs.push('--region', options.region);
317
+ }
318
+ commandArgs.push('--output', 'json');
319
+
320
+ const { stdout } = await execFileAsync('aws', [baseCommand, ...commandArgs]);
321
+ return JSON.parse(stdout) as T;
322
+ }
323
+
324
+ /**
325
+ * Display functions in a table format
326
+ */
327
+ function displayFunctionTable(functions: LambdaFunction[]): void {
328
+ const headers = ['Name', 'Runtime', 'Memory', 'Timeout', 'Code Size', 'Modified'];
329
+ const rows = functions.map(fn => [
330
+ fn.FunctionName,
331
+ fn.Runtime || 'N/A',
332
+ `${fn.MemorySize} MB`,
333
+ `${fn.Timeout}s`,
334
+ formatBytes(fn.CodeSize),
335
+ new Date(fn.LastModified).toLocaleDateString(),
336
+ ]);
337
+
338
+ // Print header
339
+ const headerRow = headers
340
+ .map((h, i) => {
341
+ const maxWidth = Math.max(h.length, ...rows.map(r => r[i].length));
342
+ return h.padEnd(maxWidth);
343
+ })
344
+ .join(' ');
345
+
346
+ ui.print(ui.bold(headerRow));
347
+ ui.print('-'.repeat(headerRow.length));
348
+
349
+ // Print rows
350
+ for (const row of rows) {
351
+ const formattedRow = row
352
+ .map((cell, i) => {
353
+ const maxWidth = Math.max(headers[i].length, ...rows.map(r => r[i].length));
354
+ return cell.padEnd(maxWidth);
355
+ })
356
+ .join(' ');
357
+
358
+ ui.print(formattedRow);
359
+ }
360
+ }
361
+
362
+ /**
363
+ * Format bytes to human readable
364
+ */
365
+ function formatBytes(bytes: number): string {
366
+ if (bytes === 0) {
367
+ return '0 B';
368
+ }
369
+
370
+ const k = 1024;
371
+ const sizes = ['B', 'KB', 'MB', 'GB'];
372
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
373
+
374
+ return `${(bytes / Math.pow(k, i)).toFixed(1)} ${sizes[i]}`;
375
+ }
376
+
377
+ /**
378
+ * Show Lambda command help
379
+ */
380
+ function showLambdaHelp(): void {
381
+ ui.print('Usage: nimbus aws lambda <action> [args]');
382
+ ui.newLine();
383
+
384
+ ui.print(ui.bold('Actions:'));
385
+ ui.print(' list List all Lambda functions');
386
+ ui.print(' invoke <name> Invoke a function');
387
+ ui.print(' logs <name> View function logs');
388
+ ui.newLine();
389
+
390
+ ui.print(ui.bold('Examples:'));
391
+ ui.print(' nimbus aws lambda list');
392
+ ui.print(' nimbus aws lambda invoke my-function \'{"key": "value"}\'');
393
+ ui.print(' nimbus aws lambda logs my-function');
394
+ }
395
+
396
+ export default lambdaCommand;