@build-astron-co/nimbus 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (469) hide show
  1. package/bin/nimbus +26 -10
  2. package/bin/nimbus.cmd +41 -0
  3. package/bin/nimbus.mjs +70 -0
  4. package/completions/nimbus.bash +38 -0
  5. package/completions/nimbus.fish +48 -0
  6. package/completions/nimbus.zsh +81 -0
  7. package/dist/src/agent/compaction-agent.js +215 -0
  8. package/dist/src/agent/context-manager.js +385 -0
  9. package/dist/src/agent/context.js +322 -0
  10. package/dist/src/agent/deploy-preview.js +395 -0
  11. package/dist/src/agent/expand-files.js +95 -0
  12. package/dist/src/agent/index.js +18 -0
  13. package/dist/src/agent/loop.js +1535 -0
  14. package/dist/src/agent/modes.js +347 -0
  15. package/dist/src/agent/permissions.js +396 -0
  16. package/dist/src/agent/subagents/base.js +67 -0
  17. package/dist/src/agent/subagents/cost.js +45 -0
  18. package/dist/src/agent/subagents/explore.js +36 -0
  19. package/dist/src/agent/subagents/general.js +41 -0
  20. package/dist/src/agent/subagents/index.js +88 -0
  21. package/dist/src/agent/subagents/infra.js +52 -0
  22. package/dist/src/agent/subagents/security.js +60 -0
  23. package/dist/src/agent/system-prompt.js +860 -0
  24. package/dist/src/app.js +152 -0
  25. package/dist/src/audit/activity-log.js +209 -0
  26. package/dist/src/audit/compliance-checker.js +419 -0
  27. package/dist/src/audit/cost-tracker.js +231 -0
  28. package/dist/src/audit/index.js +10 -0
  29. package/dist/src/audit/security-scanner.js +490 -0
  30. package/dist/src/auth/guard.js +64 -0
  31. package/dist/src/auth/index.js +19 -0
  32. package/dist/src/auth/keychain.js +79 -0
  33. package/dist/src/auth/oauth.js +389 -0
  34. package/dist/src/auth/providers.js +415 -0
  35. package/dist/src/auth/sso.js +87 -0
  36. package/dist/src/auth/store.js +424 -0
  37. package/dist/src/auth/types.js +5 -0
  38. package/dist/src/cli/index.js +8 -0
  39. package/dist/src/cli/init.js +1048 -0
  40. package/dist/src/cli/openapi-spec.js +346 -0
  41. package/dist/src/cli/run.js +505 -0
  42. package/dist/src/cli/serve-auth.js +56 -0
  43. package/dist/src/cli/serve.js +432 -0
  44. package/dist/src/cli/web.js +50 -0
  45. package/dist/src/cli.js +1574 -0
  46. package/dist/src/clients/core-engine-client.js +156 -0
  47. package/dist/src/clients/enterprise-client.js +246 -0
  48. package/dist/src/clients/generator-client.js +219 -0
  49. package/dist/src/clients/git-client.js +367 -0
  50. package/dist/src/clients/github-client.js +229 -0
  51. package/dist/src/clients/helm-client.js +299 -0
  52. package/dist/src/clients/index.js +18 -0
  53. package/dist/src/clients/k8s-client.js +270 -0
  54. package/dist/src/clients/llm-client.js +119 -0
  55. package/dist/src/clients/rest-client.js +104 -0
  56. package/dist/src/clients/service-discovery.js +35 -0
  57. package/dist/src/clients/terraform-client.js +302 -0
  58. package/dist/src/clients/tools-client.js +1227 -0
  59. package/dist/src/clients/ws-client.js +93 -0
  60. package/dist/src/commands/alias.js +91 -0
  61. package/dist/src/commands/analyze/index.js +313 -0
  62. package/dist/src/commands/apply/helm.js +375 -0
  63. package/dist/src/commands/apply/index.js +176 -0
  64. package/dist/src/commands/apply/k8s.js +350 -0
  65. package/dist/src/commands/apply/terraform.js +465 -0
  66. package/dist/src/commands/ask.js +137 -0
  67. package/dist/src/commands/audit/index.js +322 -0
  68. package/dist/src/commands/auth-cloud.js +345 -0
  69. package/dist/src/commands/auth-list.js +112 -0
  70. package/dist/src/commands/auth-profile.js +104 -0
  71. package/dist/src/commands/auth-refresh.js +161 -0
  72. package/dist/src/commands/auth-status.js +122 -0
  73. package/dist/src/commands/aws/ec2.js +402 -0
  74. package/dist/src/commands/aws/iam.js +304 -0
  75. package/dist/src/commands/aws/index.js +108 -0
  76. package/dist/src/commands/aws/lambda.js +317 -0
  77. package/dist/src/commands/aws/rds.js +345 -0
  78. package/dist/src/commands/aws/s3.js +346 -0
  79. package/dist/src/commands/aws/vpc.js +302 -0
  80. package/dist/src/commands/aws-discover.js +413 -0
  81. package/dist/src/commands/aws-terraform.js +618 -0
  82. package/dist/src/commands/azure/aks.js +305 -0
  83. package/dist/src/commands/azure/functions.js +200 -0
  84. package/dist/src/commands/azure/index.js +93 -0
  85. package/dist/src/commands/azure/storage.js +378 -0
  86. package/dist/src/commands/azure/vm.js +291 -0
  87. package/dist/src/commands/billing/index.js +224 -0
  88. package/dist/src/commands/chat.js +259 -0
  89. package/dist/src/commands/completions.js +255 -0
  90. package/dist/src/commands/config.js +291 -0
  91. package/dist/src/commands/cost/cloud-cost-estimator.js +211 -0
  92. package/dist/src/commands/cost/estimator.js +73 -0
  93. package/dist/src/commands/cost/index.js +625 -0
  94. package/dist/src/commands/cost/parsers/terraform.js +234 -0
  95. package/dist/src/commands/cost/parsers/types.js +4 -0
  96. package/dist/src/commands/cost/pricing/aws.js +501 -0
  97. package/dist/src/commands/cost/pricing/azure.js +462 -0
  98. package/dist/src/commands/cost/pricing/gcp.js +359 -0
  99. package/dist/src/commands/cost/pricing/index.js +24 -0
  100. package/dist/src/commands/demo.js +196 -0
  101. package/dist/src/commands/deploy.js +215 -0
  102. package/dist/src/commands/doctor.js +1291 -0
  103. package/dist/src/commands/drift/index.js +674 -0
  104. package/dist/src/commands/explain.js +235 -0
  105. package/dist/src/commands/export.js +120 -0
  106. package/dist/src/commands/feedback.js +319 -0
  107. package/dist/src/commands/fix.js +263 -0
  108. package/dist/src/commands/fs/index.js +338 -0
  109. package/dist/src/commands/gcp/compute.js +266 -0
  110. package/dist/src/commands/gcp/functions.js +221 -0
  111. package/dist/src/commands/gcp/gke.js +357 -0
  112. package/dist/src/commands/gcp/iam.js +295 -0
  113. package/dist/src/commands/gcp/index.js +105 -0
  114. package/dist/src/commands/gcp/storage.js +232 -0
  115. package/dist/src/commands/generate-helm.js +1026 -0
  116. package/dist/src/commands/generate-k8s.js +1263 -0
  117. package/dist/src/commands/generate-terraform.js +1058 -0
  118. package/dist/src/commands/gh/index.js +663 -0
  119. package/dist/src/commands/git/index.js +1208 -0
  120. package/dist/src/commands/helm/index.js +985 -0
  121. package/dist/src/commands/help.js +639 -0
  122. package/dist/src/commands/history.js +120 -0
  123. package/dist/src/commands/import.js +782 -0
  124. package/dist/src/commands/incident.js +144 -0
  125. package/dist/src/commands/index.js +109 -0
  126. package/dist/src/commands/init.js +955 -0
  127. package/dist/src/commands/k8s/index.js +979 -0
  128. package/dist/src/commands/login.js +588 -0
  129. package/dist/src/commands/logout.js +61 -0
  130. package/dist/src/commands/logs.js +160 -0
  131. package/dist/src/commands/onboarding.js +382 -0
  132. package/dist/src/commands/pipeline.js +153 -0
  133. package/dist/src/commands/plan/display.js +216 -0
  134. package/dist/src/commands/plan/index.js +525 -0
  135. package/dist/src/commands/plugin.js +325 -0
  136. package/dist/src/commands/preview.js +356 -0
  137. package/dist/src/commands/profile.js +297 -0
  138. package/dist/src/commands/questionnaire.js +1021 -0
  139. package/dist/src/commands/resume.js +35 -0
  140. package/dist/src/commands/rollback.js +259 -0
  141. package/dist/src/commands/rollout.js +74 -0
  142. package/dist/src/commands/runbook.js +307 -0
  143. package/dist/src/commands/schedule.js +202 -0
  144. package/dist/src/commands/status.js +213 -0
  145. package/dist/src/commands/team/index.js +309 -0
  146. package/dist/src/commands/team-context.js +200 -0
  147. package/dist/src/commands/template.js +204 -0
  148. package/dist/src/commands/tf/index.js +989 -0
  149. package/dist/src/commands/upgrade.js +515 -0
  150. package/dist/src/commands/usage/index.js +118 -0
  151. package/dist/src/commands/version.js +145 -0
  152. package/dist/src/commands/watch.js +127 -0
  153. package/dist/src/compat/index.js +2 -0
  154. package/dist/src/compat/runtime.js +10 -0
  155. package/dist/src/compat/sqlite.js +144 -0
  156. package/dist/src/config/index.js +6 -0
  157. package/dist/src/config/manager.js +469 -0
  158. package/dist/src/config/mode-store.js +57 -0
  159. package/dist/src/config/profiles.js +66 -0
  160. package/dist/src/config/safety-policy.js +251 -0
  161. package/dist/src/config/schema.js +107 -0
  162. package/dist/src/config/types.js +311 -0
  163. package/dist/src/config/workspace-state.js +38 -0
  164. package/dist/src/context/context-db.js +138 -0
  165. package/dist/src/demo/index.js +295 -0
  166. package/dist/src/demo/scenarios/full-journey.js +226 -0
  167. package/dist/src/demo/scenarios/getting-started.js +124 -0
  168. package/dist/src/demo/scenarios/helm-release.js +334 -0
  169. package/dist/src/demo/scenarios/k8s-deployment.js +190 -0
  170. package/dist/src/demo/scenarios/terraform-vpc.js +167 -0
  171. package/dist/src/demo/types.js +6 -0
  172. package/dist/src/engine/cost-estimator.js +334 -0
  173. package/dist/src/engine/diagram-generator.js +192 -0
  174. package/dist/src/engine/drift-detector.js +688 -0
  175. package/dist/src/engine/executor.js +832 -0
  176. package/dist/src/engine/index.js +39 -0
  177. package/dist/src/engine/orchestrator.js +436 -0
  178. package/dist/src/engine/planner.js +616 -0
  179. package/dist/src/engine/safety.js +609 -0
  180. package/dist/src/engine/verifier.js +664 -0
  181. package/dist/src/enterprise/audit.js +241 -0
  182. package/dist/src/enterprise/auth.js +189 -0
  183. package/dist/src/enterprise/billing.js +512 -0
  184. package/dist/src/enterprise/index.js +16 -0
  185. package/dist/src/enterprise/teams.js +315 -0
  186. package/dist/src/generator/best-practices.js +1375 -0
  187. package/dist/src/generator/helm.js +495 -0
  188. package/dist/src/generator/index.js +11 -0
  189. package/dist/src/generator/intent-parser.js +420 -0
  190. package/dist/src/generator/kubernetes.js +773 -0
  191. package/dist/src/generator/terraform.js +1472 -0
  192. package/dist/src/history/index.js +6 -0
  193. package/dist/src/history/manager.js +199 -0
  194. package/dist/src/history/types.js +6 -0
  195. package/dist/src/hooks/config.js +318 -0
  196. package/dist/src/hooks/engine.js +317 -0
  197. package/dist/src/hooks/index.js +2 -0
  198. package/dist/src/llm/auth-bridge.js +157 -0
  199. package/dist/src/llm/circuit-breaker.js +116 -0
  200. package/dist/src/llm/config-loader.js +172 -0
  201. package/dist/src/llm/cost-calculator.js +137 -0
  202. package/dist/src/llm/index.js +7 -0
  203. package/dist/src/llm/model-aliases.js +99 -0
  204. package/dist/src/llm/provider-registry.js +57 -0
  205. package/dist/src/llm/providers/anthropic.js +430 -0
  206. package/dist/src/llm/providers/bedrock.js +409 -0
  207. package/dist/src/llm/providers/google.js +344 -0
  208. package/dist/src/llm/providers/ollama.js +661 -0
  209. package/dist/src/llm/providers/openai-compatible.js +289 -0
  210. package/dist/src/llm/providers/openai.js +284 -0
  211. package/dist/src/llm/providers/openrouter.js +293 -0
  212. package/dist/src/llm/router.js +844 -0
  213. package/dist/src/llm/types.js +69 -0
  214. package/dist/src/lsp/client.js +239 -0
  215. package/dist/src/lsp/languages.js +95 -0
  216. package/dist/src/lsp/manager.js +243 -0
  217. package/dist/src/mcp/client.js +289 -0
  218. package/dist/src/mcp/index.js +5 -0
  219. package/dist/src/mcp/manager.js +113 -0
  220. package/dist/src/nimbus.js +212 -0
  221. package/dist/src/plugins/index.js +13 -0
  222. package/dist/src/plugins/loader.js +280 -0
  223. package/dist/src/plugins/manager.js +282 -0
  224. package/dist/src/plugins/types.js +23 -0
  225. package/dist/src/scanners/cicd-scanner.js +230 -0
  226. package/dist/src/scanners/cloud-scanner.js +415 -0
  227. package/dist/src/scanners/framework-scanner.js +430 -0
  228. package/dist/src/scanners/iac-scanner.js +350 -0
  229. package/dist/src/scanners/index.js +454 -0
  230. package/dist/src/scanners/language-scanner.js +258 -0
  231. package/dist/src/scanners/package-manager-scanner.js +252 -0
  232. package/dist/src/scanners/types.js +6 -0
  233. package/dist/src/sessions/manager.js +395 -0
  234. package/dist/src/sessions/types.js +4 -0
  235. package/dist/src/sharing/sync.js +238 -0
  236. package/dist/src/sharing/viewer.js +131 -0
  237. package/dist/src/snapshots/index.js +1 -0
  238. package/dist/src/snapshots/manager.js +432 -0
  239. package/dist/src/state/artifacts.js +94 -0
  240. package/dist/src/state/audit.js +73 -0
  241. package/dist/src/state/billing.js +126 -0
  242. package/dist/src/state/checkpoints.js +81 -0
  243. package/dist/src/state/config.js +58 -0
  244. package/dist/src/state/conversations.js +7 -0
  245. package/dist/src/state/credentials.js +96 -0
  246. package/dist/src/state/db.js +53 -0
  247. package/dist/src/state/index.js +23 -0
  248. package/dist/src/state/messages.js +76 -0
  249. package/dist/src/state/projects.js +92 -0
  250. package/dist/src/state/schema.js +233 -0
  251. package/dist/src/state/sessions.js +79 -0
  252. package/dist/src/state/teams.js +131 -0
  253. package/dist/src/telemetry.js +91 -0
  254. package/dist/src/tools/aws-ops.js +747 -0
  255. package/dist/src/tools/azure-ops.js +491 -0
  256. package/dist/src/tools/file-ops.js +451 -0
  257. package/dist/src/tools/gcp-ops.js +559 -0
  258. package/dist/src/tools/git-ops.js +557 -0
  259. package/dist/src/tools/github-ops.js +460 -0
  260. package/dist/src/tools/helm-ops.js +634 -0
  261. package/dist/src/tools/index.js +16 -0
  262. package/dist/src/tools/k8s-ops.js +579 -0
  263. package/dist/src/tools/schemas/converter.js +129 -0
  264. package/dist/src/tools/schemas/devops.js +3319 -0
  265. package/dist/src/tools/schemas/index.js +19 -0
  266. package/dist/src/tools/schemas/standard.js +966 -0
  267. package/dist/src/tools/schemas/types.js +409 -0
  268. package/dist/src/tools/spawn-exec.js +109 -0
  269. package/dist/src/tools/terraform-ops.js +627 -0
  270. package/dist/src/types/config.js +1 -0
  271. package/dist/src/types/drift.js +4 -0
  272. package/dist/src/types/enterprise.js +5 -0
  273. package/dist/src/types/index.js +14 -0
  274. package/dist/src/types/plan.js +1 -0
  275. package/dist/src/types/request.js +1 -0
  276. package/dist/src/types/response.js +1 -0
  277. package/dist/src/types/service.js +1 -0
  278. package/dist/src/ui/App.js +1672 -0
  279. package/dist/src/ui/DeployPreview.js +60 -0
  280. package/dist/src/ui/FileDiffModal.js +108 -0
  281. package/dist/src/ui/Header.js +46 -0
  282. package/dist/src/ui/HelpModal.js +9 -0
  283. package/dist/src/ui/InputBox.js +408 -0
  284. package/dist/src/ui/MessageList.js +795 -0
  285. package/dist/src/ui/PermissionPrompt.js +72 -0
  286. package/dist/src/ui/StatusBar.js +109 -0
  287. package/dist/src/ui/TerminalPane.js +31 -0
  288. package/dist/src/ui/ToolCallDisplay.js +303 -0
  289. package/dist/src/ui/TreePane.js +83 -0
  290. package/dist/src/ui/chat-ui.js +721 -0
  291. package/dist/src/ui/index.js +11 -0
  292. package/dist/src/ui/ink/index.js +1325 -0
  293. package/dist/src/ui/streaming.js +137 -0
  294. package/dist/src/ui/theme.js +78 -0
  295. package/dist/src/ui/types.js +7 -0
  296. package/dist/src/utils/analytics.js +61 -0
  297. package/dist/src/utils/cost-warning.js +25 -0
  298. package/dist/src/utils/env.js +42 -0
  299. package/dist/src/utils/errors.js +54 -0
  300. package/dist/src/utils/event-bus.js +22 -0
  301. package/dist/src/utils/index.js +16 -0
  302. package/dist/src/utils/logger.js +150 -0
  303. package/dist/src/utils/rate-limiter.js +90 -0
  304. package/dist/src/utils/service-auth.js +36 -0
  305. package/dist/src/utils/validation.js +39 -0
  306. package/dist/src/version.js +3 -0
  307. package/dist/src/watcher/index.js +192 -0
  308. package/dist/src/wizard/approval.js +275 -0
  309. package/dist/src/wizard/index.js +13 -0
  310. package/dist/src/wizard/prompts.js +273 -0
  311. package/dist/src/wizard/types.js +4 -0
  312. package/dist/src/wizard/ui.js +453 -0
  313. package/dist/src/wizard/wizard.js +227 -0
  314. package/package.json +31 -23
  315. package/src/__tests__/alias.test.ts +133 -0
  316. package/src/__tests__/app.test.ts +1 -1
  317. package/src/__tests__/audit.test.ts +1 -1
  318. package/src/__tests__/circuit-breaker.test.ts +1 -1
  319. package/src/__tests__/cli-run.test.ts +237 -1
  320. package/src/__tests__/compat-sqlite.test.ts +68 -0
  321. package/src/__tests__/context-manager.test.ts +131 -1
  322. package/src/__tests__/context.test.ts +1 -1
  323. package/src/__tests__/devops-terminal-gaps.test.ts +718 -0
  324. package/src/__tests__/doctor.test.ts +48 -0
  325. package/src/__tests__/enterprise.test.ts +1 -1
  326. package/src/__tests__/export.test.ts +236 -0
  327. package/src/__tests__/gap-11-18-20.test.ts +958 -0
  328. package/src/__tests__/generator.test.ts +1 -1
  329. package/src/__tests__/helm-streaming.test.ts +127 -0
  330. package/src/__tests__/hooks.test.ts +1 -1
  331. package/src/__tests__/incident.test.ts +179 -0
  332. package/src/__tests__/init.test.ts +55 -4
  333. package/src/__tests__/intent-parser.test.ts +1 -1
  334. package/src/__tests__/llm-router.test.ts +1 -1
  335. package/src/__tests__/logs.test.ts +107 -0
  336. package/src/__tests__/loop-errors.test.ts +244 -0
  337. package/src/__tests__/lsp.test.ts +1 -1
  338. package/src/__tests__/modes.test.ts +1 -1
  339. package/src/__tests__/perf-optimizations.test.ts +847 -0
  340. package/src/__tests__/permissions.test.ts +1 -1
  341. package/src/__tests__/pipeline.test.ts +50 -0
  342. package/src/__tests__/polish-phase3.test.ts +340 -0
  343. package/src/__tests__/profile.test.ts +237 -0
  344. package/src/__tests__/rollback.test.ts +83 -0
  345. package/src/__tests__/runbook.test.ts +219 -0
  346. package/src/__tests__/schedule.test.ts +206 -0
  347. package/src/__tests__/serve.test.ts +1 -1
  348. package/src/__tests__/sessions.test.ts +96 -1
  349. package/src/__tests__/sharing.test.ts +53 -1
  350. package/src/__tests__/snapshots.test.ts +1 -1
  351. package/src/__tests__/standalone-migration.test.ts +199 -0
  352. package/src/__tests__/state-db.test.ts +1 -1
  353. package/src/__tests__/status.test.ts +158 -0
  354. package/src/__tests__/stream-with-tools.test.ts +71 -25
  355. package/src/__tests__/subagents.test.ts +1 -1
  356. package/src/__tests__/system-prompt.test.ts +82 -3
  357. package/src/__tests__/terminal-gap-v2.test.ts +395 -0
  358. package/src/__tests__/terminal-parity.test.ts +393 -0
  359. package/src/__tests__/tf-apply.test.ts +187 -0
  360. package/src/__tests__/tool-converter.test.ts +1 -1
  361. package/src/__tests__/tool-schemas.test.ts +209 -4
  362. package/src/__tests__/tools.test.ts +4 -3
  363. package/src/__tests__/version-json.test.ts +184 -0
  364. package/src/__tests__/version.test.ts +1 -1
  365. package/src/__tests__/watch.test.ts +129 -0
  366. package/src/agent/compaction-agent.ts +40 -1
  367. package/src/agent/context-manager.ts +67 -3
  368. package/src/agent/deploy-preview.ts +62 -1
  369. package/src/agent/expand-files.ts +108 -0
  370. package/src/agent/loop.ts +1312 -31
  371. package/src/agent/permissions.ts +51 -4
  372. package/src/agent/system-prompt.ts +573 -19
  373. package/src/app.ts +58 -0
  374. package/src/audit/security-scanner.ts +45 -0
  375. package/src/auth/keychain.ts +82 -0
  376. package/src/auth/oauth.ts +15 -5
  377. package/src/cli/init.ts +378 -5
  378. package/src/cli/run.ts +407 -16
  379. package/src/cli/serve.ts +78 -1
  380. package/src/cli/web.ts +10 -6
  381. package/src/cli.ts +312 -1
  382. package/src/clients/service-discovery.ts +30 -25
  383. package/src/commands/alias.ts +100 -0
  384. package/src/commands/audit/index.ts +121 -2
  385. package/src/commands/auth-cloud.ts +113 -0
  386. package/src/commands/auth-refresh.ts +187 -0
  387. package/src/commands/aws-discover.ts +144 -251
  388. package/src/commands/aws-terraform.ts +68 -118
  389. package/src/commands/chat.ts +9 -3
  390. package/src/commands/completions.ts +268 -0
  391. package/src/commands/config.ts +26 -0
  392. package/src/commands/cost/index.ts +218 -2
  393. package/src/commands/deploy.ts +260 -0
  394. package/src/commands/doctor.ts +744 -152
  395. package/src/commands/drift/index.ts +371 -23
  396. package/src/commands/export.ts +146 -0
  397. package/src/commands/generate-k8s.ts +9 -61
  398. package/src/commands/generate-terraform.ts +191 -449
  399. package/src/commands/help.ts +212 -36
  400. package/src/commands/history.ts +8 -1
  401. package/src/commands/incident.ts +166 -0
  402. package/src/commands/init.ts +5 -0
  403. package/src/commands/login.ts +86 -1
  404. package/src/commands/logs.ts +167 -0
  405. package/src/commands/onboarding.ts +211 -34
  406. package/src/commands/pipeline.ts +186 -0
  407. package/src/commands/plugin.ts +398 -0
  408. package/src/commands/profile.ts +342 -0
  409. package/src/commands/questionnaire.ts +0 -98
  410. package/src/commands/resume.ts +26 -34
  411. package/src/commands/rollback.ts +315 -0
  412. package/src/commands/rollout.ts +88 -0
  413. package/src/commands/runbook.ts +346 -0
  414. package/src/commands/schedule.ts +236 -0
  415. package/src/commands/status.ts +252 -0
  416. package/src/commands/team-context.ts +220 -0
  417. package/src/commands/template.ts +58 -57
  418. package/src/commands/tf/index.ts +70 -11
  419. package/src/commands/upgrade.ts +57 -0
  420. package/src/commands/version.ts +54 -50
  421. package/src/commands/watch.ts +153 -0
  422. package/src/compat/runtime.ts +1 -1
  423. package/src/compat/sqlite.ts +75 -5
  424. package/src/config/mode-store.ts +62 -0
  425. package/src/config/profiles.ts +84 -0
  426. package/src/config/types.ts +83 -1
  427. package/src/config/workspace-state.ts +53 -0
  428. package/src/engine/cost-estimator.ts +52 -10
  429. package/src/engine/executor.ts +33 -2
  430. package/src/engine/planner.ts +68 -1
  431. package/src/generator/terraform.ts +8 -0
  432. package/src/history/manager.ts +2 -74
  433. package/src/hooks/engine.ts +5 -4
  434. package/src/llm/cost-calculator.ts +2 -2
  435. package/src/llm/providers/anthropic.ts +50 -21
  436. package/src/llm/router.ts +76 -7
  437. package/src/lsp/languages.ts +3 -0
  438. package/src/lsp/manager.ts +21 -5
  439. package/src/nimbus.ts +37 -18
  440. package/src/sessions/manager.ts +108 -1
  441. package/src/sharing/sync.ts +4 -0
  442. package/src/sharing/viewer.ts +66 -0
  443. package/src/tools/file-ops.ts +22 -0
  444. package/src/tools/schemas/devops.ts +3007 -117
  445. package/src/tools/schemas/standard.ts +5 -1
  446. package/src/tools/schemas/types.ts +31 -1
  447. package/src/tools/spawn-exec.ts +148 -0
  448. package/src/ui/App.tsx +1183 -66
  449. package/src/ui/DeployPreview.tsx +62 -57
  450. package/src/ui/FileDiffModal.tsx +162 -0
  451. package/src/ui/Header.tsx +87 -24
  452. package/src/ui/HelpModal.tsx +57 -0
  453. package/src/ui/InputBox.tsx +163 -10
  454. package/src/ui/MessageList.tsx +487 -40
  455. package/src/ui/PermissionPrompt.tsx +17 -5
  456. package/src/ui/StatusBar.tsx +122 -3
  457. package/src/ui/TerminalPane.tsx +84 -0
  458. package/src/ui/ToolCallDisplay.tsx +252 -18
  459. package/src/ui/TreePane.tsx +132 -0
  460. package/src/ui/chat-ui.ts +41 -44
  461. package/src/ui/ink/index.ts +771 -38
  462. package/src/ui/streaming.ts +1 -1
  463. package/src/ui/theme.ts +104 -0
  464. package/src/ui/types.ts +18 -0
  465. package/src/version.ts +1 -1
  466. package/src/watcher/index.ts +66 -15
  467. package/src/wizard/types.ts +1 -0
  468. package/src/wizard/ui.ts +1 -1
  469. package/tsconfig.json +2 -2
@@ -0,0 +1,747 @@
1
+ /**
2
+ * AWS Operations — Embedded tool (stripped HTTP wrappers)
3
+ *
4
+ * Merged from services/aws-tools-service/src/aws/ec2.ts, s3.ts, iam.ts
5
+ * Uses lazy imports for AWS SDK to keep binary size small.
6
+ */
7
+ import { logger } from '../utils';
8
+ /**
9
+ * Unified AWS Operations class merging EC2, S3, and IAM operations.
10
+ * All AWS SDK imports are lazy to minimize binary size.
11
+ */
12
+ export class AwsOperations {
13
+ config;
14
+ constructor(config = {}) {
15
+ this.config = {
16
+ region: config.region || process.env.AWS_REGION || 'us-east-1',
17
+ accessKeyId: config.accessKeyId,
18
+ secretAccessKey: config.secretAccessKey,
19
+ sessionToken: config.sessionToken,
20
+ };
21
+ }
22
+ /**
23
+ * Build common client config
24
+ */
25
+ getClientConfig() {
26
+ const clientConfig = {
27
+ region: this.config.region,
28
+ };
29
+ if (this.config.accessKeyId && this.config.secretAccessKey) {
30
+ clientConfig.credentials = {
31
+ accessKeyId: this.config.accessKeyId,
32
+ secretAccessKey: this.config.secretAccessKey,
33
+ sessionToken: this.config.sessionToken,
34
+ };
35
+ }
36
+ return clientConfig;
37
+ }
38
+ // ==========================================
39
+ // EC2 Operations
40
+ // ==========================================
41
+ /**
42
+ * List EC2 instances
43
+ */
44
+ async listInstances(options = {}) {
45
+ try {
46
+ const { EC2Client, DescribeInstancesCommand } = await import('@aws-sdk/client-ec2');
47
+ const client = new EC2Client(this.getClientConfig());
48
+ const input = {};
49
+ if (options.instanceIds && options.instanceIds.length > 0) {
50
+ input.InstanceIds = options.instanceIds;
51
+ }
52
+ if (options.filters) {
53
+ input.Filters = Object.entries(options.filters).map(([name, values]) => ({
54
+ Name: name,
55
+ Values: values,
56
+ }));
57
+ }
58
+ if (options.maxResults) {
59
+ input.MaxResults = options.maxResults;
60
+ }
61
+ if (options.nextToken) {
62
+ input.NextToken = options.nextToken;
63
+ }
64
+ const command = new DescribeInstancesCommand(input);
65
+ const response = await client.send(command);
66
+ const instances = response.Reservations?.flatMap((r) => r.Instances?.map((i) => ({
67
+ instanceId: i.InstanceId,
68
+ instanceType: i.InstanceType,
69
+ state: i.State?.Name,
70
+ publicIpAddress: i.PublicIpAddress,
71
+ privateIpAddress: i.PrivateIpAddress,
72
+ launchTime: i.LaunchTime,
73
+ availabilityZone: i.Placement?.AvailabilityZone,
74
+ vpcId: i.VpcId,
75
+ subnetId: i.SubnetId,
76
+ imageId: i.ImageId,
77
+ keyName: i.KeyName,
78
+ tags: i.Tags?.reduce((acc, tag) => {
79
+ if (tag.Key) {
80
+ acc[tag.Key] = tag.Value || '';
81
+ }
82
+ return acc;
83
+ }, {}),
84
+ })) || []);
85
+ return {
86
+ success: true,
87
+ data: {
88
+ instances: instances || [],
89
+ nextToken: response.NextToken,
90
+ },
91
+ };
92
+ }
93
+ catch (error) {
94
+ logger.error('Failed to list instances', error);
95
+ return { success: false, error: error.message };
96
+ }
97
+ }
98
+ /**
99
+ * Start EC2 instances
100
+ */
101
+ async startInstances(instanceIds) {
102
+ try {
103
+ const { EC2Client, StartInstancesCommand } = await import('@aws-sdk/client-ec2');
104
+ const client = new EC2Client(this.getClientConfig());
105
+ const command = new StartInstancesCommand({ InstanceIds: instanceIds });
106
+ const response = await client.send(command);
107
+ const results = response.StartingInstances?.map((i) => ({
108
+ instanceId: i.InstanceId,
109
+ previousState: i.PreviousState?.Name,
110
+ currentState: i.CurrentState?.Name,
111
+ }));
112
+ return { success: true, data: { instances: results || [] } };
113
+ }
114
+ catch (error) {
115
+ logger.error('Failed to start instances', error);
116
+ return { success: false, error: error.message };
117
+ }
118
+ }
119
+ /**
120
+ * Start a single instance (convenience wrapper)
121
+ */
122
+ async startInstance(instanceId) {
123
+ return this.startInstances([instanceId]);
124
+ }
125
+ /**
126
+ * Stop EC2 instances
127
+ */
128
+ async stopInstances(instanceIds, force) {
129
+ try {
130
+ const { EC2Client, StopInstancesCommand } = await import('@aws-sdk/client-ec2');
131
+ const client = new EC2Client(this.getClientConfig());
132
+ const command = new StopInstancesCommand({ InstanceIds: instanceIds, Force: force });
133
+ const response = await client.send(command);
134
+ const results = response.StoppingInstances?.map((i) => ({
135
+ instanceId: i.InstanceId,
136
+ previousState: i.PreviousState?.Name,
137
+ currentState: i.CurrentState?.Name,
138
+ }));
139
+ return { success: true, data: { instances: results || [] } };
140
+ }
141
+ catch (error) {
142
+ logger.error('Failed to stop instances', error);
143
+ return { success: false, error: error.message };
144
+ }
145
+ }
146
+ /**
147
+ * Stop a single instance (convenience wrapper)
148
+ */
149
+ async stopInstance(instanceId, force) {
150
+ return this.stopInstances([instanceId], force);
151
+ }
152
+ /**
153
+ * Reboot EC2 instances
154
+ */
155
+ async rebootInstances(instanceIds) {
156
+ try {
157
+ const { EC2Client, RebootInstancesCommand } = await import('@aws-sdk/client-ec2');
158
+ const client = new EC2Client(this.getClientConfig());
159
+ const command = new RebootInstancesCommand({ InstanceIds: instanceIds });
160
+ await client.send(command);
161
+ return {
162
+ success: true,
163
+ data: { message: `Reboot initiated for instances: ${instanceIds.join(', ')}` },
164
+ };
165
+ }
166
+ catch (error) {
167
+ logger.error('Failed to reboot instances', error);
168
+ return { success: false, error: error.message };
169
+ }
170
+ }
171
+ /**
172
+ * Terminate EC2 instances
173
+ */
174
+ async terminateInstances(instanceIds) {
175
+ try {
176
+ const { EC2Client, TerminateInstancesCommand } = await import('@aws-sdk/client-ec2');
177
+ const client = new EC2Client(this.getClientConfig());
178
+ const command = new TerminateInstancesCommand({ InstanceIds: instanceIds });
179
+ const response = await client.send(command);
180
+ const results = response.TerminatingInstances?.map((i) => ({
181
+ instanceId: i.InstanceId,
182
+ previousState: i.PreviousState?.Name,
183
+ currentState: i.CurrentState?.Name,
184
+ }));
185
+ return { success: true, data: { instances: results || [] } };
186
+ }
187
+ catch (error) {
188
+ logger.error('Failed to terminate instances', error);
189
+ return { success: false, error: error.message };
190
+ }
191
+ }
192
+ /**
193
+ * Terminate a single instance (convenience wrapper)
194
+ */
195
+ async terminateInstance(instanceId) {
196
+ return this.terminateInstances([instanceId]);
197
+ }
198
+ /**
199
+ * Describe instance status
200
+ */
201
+ async getInstanceStatus(instanceIds) {
202
+ try {
203
+ const { EC2Client, DescribeInstanceStatusCommand } = await import('@aws-sdk/client-ec2');
204
+ const client = new EC2Client(this.getClientConfig());
205
+ const command = new DescribeInstanceStatusCommand({
206
+ InstanceIds: instanceIds,
207
+ IncludeAllInstances: true,
208
+ });
209
+ const response = await client.send(command);
210
+ const statuses = response.InstanceStatuses?.map((s) => ({
211
+ instanceId: s.InstanceId,
212
+ instanceState: s.InstanceState?.Name,
213
+ instanceStatus: s.InstanceStatus?.Status,
214
+ systemStatus: s.SystemStatus?.Status,
215
+ availabilityZone: s.AvailabilityZone,
216
+ }));
217
+ return { success: true, data: { statuses: statuses || [] } };
218
+ }
219
+ catch (error) {
220
+ logger.error('Failed to get instance status', error);
221
+ return { success: false, error: error.message };
222
+ }
223
+ }
224
+ /**
225
+ * List VPCs
226
+ */
227
+ async listVpcs() {
228
+ try {
229
+ const { EC2Client, DescribeVpcsCommand } = await import('@aws-sdk/client-ec2');
230
+ const client = new EC2Client(this.getClientConfig());
231
+ const command = new DescribeVpcsCommand({});
232
+ const response = await client.send(command);
233
+ const vpcs = response.Vpcs?.map((v) => ({
234
+ vpcId: v.VpcId,
235
+ cidrBlock: v.CidrBlock,
236
+ state: v.State,
237
+ isDefault: v.IsDefault,
238
+ tags: v.Tags?.reduce((acc, tag) => {
239
+ if (tag.Key) {
240
+ acc[tag.Key] = tag.Value || '';
241
+ }
242
+ return acc;
243
+ }, {}),
244
+ }));
245
+ return { success: true, data: { vpcs: vpcs || [] } };
246
+ }
247
+ catch (error) {
248
+ logger.error('Failed to list VPCs', error);
249
+ return { success: false, error: error.message };
250
+ }
251
+ }
252
+ /**
253
+ * List subnets
254
+ */
255
+ async listSubnets(vpcId) {
256
+ try {
257
+ const { EC2Client, DescribeSubnetsCommand } = await import('@aws-sdk/client-ec2');
258
+ const client = new EC2Client(this.getClientConfig());
259
+ const input = {};
260
+ if (vpcId) {
261
+ input.Filters = [{ Name: 'vpc-id', Values: [vpcId] }];
262
+ }
263
+ const command = new DescribeSubnetsCommand(input);
264
+ const response = await client.send(command);
265
+ const subnets = response.Subnets?.map((s) => ({
266
+ subnetId: s.SubnetId,
267
+ vpcId: s.VpcId,
268
+ cidrBlock: s.CidrBlock,
269
+ availabilityZone: s.AvailabilityZone,
270
+ availableIpAddressCount: s.AvailableIpAddressCount,
271
+ defaultForAz: s.DefaultForAz,
272
+ tags: s.Tags?.reduce((acc, tag) => {
273
+ if (tag.Key) {
274
+ acc[tag.Key] = tag.Value || '';
275
+ }
276
+ return acc;
277
+ }, {}),
278
+ }));
279
+ return { success: true, data: { subnets: subnets || [] } };
280
+ }
281
+ catch (error) {
282
+ logger.error('Failed to list subnets', error);
283
+ return { success: false, error: error.message };
284
+ }
285
+ }
286
+ /**
287
+ * List security groups
288
+ */
289
+ async listSecurityGroups(vpcId) {
290
+ try {
291
+ const { EC2Client, DescribeSecurityGroupsCommand } = await import('@aws-sdk/client-ec2');
292
+ const client = new EC2Client(this.getClientConfig());
293
+ const input = {};
294
+ if (vpcId) {
295
+ input.Filters = [{ Name: 'vpc-id', Values: [vpcId] }];
296
+ }
297
+ const command = new DescribeSecurityGroupsCommand(input);
298
+ const response = await client.send(command);
299
+ const groups = response.SecurityGroups?.map((g) => ({
300
+ groupId: g.GroupId,
301
+ groupName: g.GroupName,
302
+ description: g.Description,
303
+ vpcId: g.VpcId,
304
+ }));
305
+ return { success: true, data: { securityGroups: groups || [] } };
306
+ }
307
+ catch (error) {
308
+ logger.error('Failed to list security groups', error);
309
+ return { success: false, error: error.message };
310
+ }
311
+ }
312
+ /**
313
+ * List regions
314
+ */
315
+ async listRegions() {
316
+ try {
317
+ const { EC2Client, DescribeRegionsCommand } = await import('@aws-sdk/client-ec2');
318
+ const client = new EC2Client(this.getClientConfig());
319
+ const command = new DescribeRegionsCommand({});
320
+ const response = await client.send(command);
321
+ const regions = response.Regions?.map((r) => ({
322
+ regionName: r.RegionName,
323
+ endpoint: r.Endpoint,
324
+ }));
325
+ return { success: true, data: { regions: regions || [] } };
326
+ }
327
+ catch (error) {
328
+ logger.error('Failed to list regions', error);
329
+ return { success: false, error: error.message };
330
+ }
331
+ }
332
+ // ==========================================
333
+ // S3 Operations
334
+ // ==========================================
335
+ /**
336
+ * List all S3 buckets
337
+ */
338
+ async listBuckets() {
339
+ try {
340
+ const { S3Client, ListBucketsCommand } = await import('@aws-sdk/client-s3');
341
+ const client = new S3Client(this.getClientConfig());
342
+ const command = new ListBucketsCommand({});
343
+ const response = await client.send(command);
344
+ const buckets = response.Buckets?.map((b) => ({
345
+ name: b.Name,
346
+ creationDate: b.CreationDate,
347
+ }));
348
+ return {
349
+ success: true,
350
+ data: {
351
+ buckets: buckets || [],
352
+ owner: {
353
+ id: response.Owner?.ID,
354
+ displayName: response.Owner?.DisplayName,
355
+ },
356
+ },
357
+ };
358
+ }
359
+ catch (error) {
360
+ logger.error('Failed to list buckets', error);
361
+ return { success: false, error: error.message };
362
+ }
363
+ }
364
+ /**
365
+ * List objects in a bucket
366
+ */
367
+ async listObjects(options) {
368
+ try {
369
+ const { S3Client, ListObjectsV2Command } = await import('@aws-sdk/client-s3');
370
+ const client = new S3Client(this.getClientConfig());
371
+ const input = { Bucket: options.bucket };
372
+ if (options.prefix) {
373
+ input.Prefix = options.prefix;
374
+ }
375
+ if (options.delimiter) {
376
+ input.Delimiter = options.delimiter;
377
+ }
378
+ if (options.maxKeys) {
379
+ input.MaxKeys = options.maxKeys;
380
+ }
381
+ if (options.continuationToken) {
382
+ input.ContinuationToken = options.continuationToken;
383
+ }
384
+ const command = new ListObjectsV2Command(input);
385
+ const response = await client.send(command);
386
+ const objects = response.Contents?.map((o) => ({
387
+ key: o.Key,
388
+ size: o.Size,
389
+ lastModified: o.LastModified,
390
+ etag: o.ETag,
391
+ storageClass: o.StorageClass,
392
+ }));
393
+ const commonPrefixes = response.CommonPrefixes?.map((p) => p.Prefix);
394
+ return {
395
+ success: true,
396
+ data: {
397
+ objects: objects || [],
398
+ commonPrefixes: commonPrefixes || [],
399
+ isTruncated: response.IsTruncated,
400
+ nextContinuationToken: response.NextContinuationToken,
401
+ keyCount: response.KeyCount,
402
+ },
403
+ };
404
+ }
405
+ catch (error) {
406
+ logger.error('Failed to list objects', error);
407
+ return { success: false, error: error.message };
408
+ }
409
+ }
410
+ /**
411
+ * Get object from bucket
412
+ */
413
+ async getObject(bucket, key) {
414
+ try {
415
+ const { S3Client, GetObjectCommand } = await import('@aws-sdk/client-s3');
416
+ const client = new S3Client(this.getClientConfig());
417
+ const command = new GetObjectCommand({ Bucket: bucket, Key: key });
418
+ const response = await client.send(command);
419
+ const body = await response.Body?.transformToString();
420
+ return {
421
+ success: true,
422
+ data: {
423
+ body,
424
+ contentType: response.ContentType,
425
+ contentLength: response.ContentLength,
426
+ lastModified: response.LastModified,
427
+ etag: response.ETag,
428
+ metadata: response.Metadata,
429
+ },
430
+ };
431
+ }
432
+ catch (error) {
433
+ logger.error('Failed to get object', error);
434
+ return { success: false, error: error.message };
435
+ }
436
+ }
437
+ /**
438
+ * Put object to bucket
439
+ */
440
+ async putObject(options) {
441
+ try {
442
+ const { S3Client, PutObjectCommand } = await import('@aws-sdk/client-s3');
443
+ const client = new S3Client(this.getClientConfig());
444
+ const command = new PutObjectCommand({
445
+ Bucket: options.bucket,
446
+ Key: options.key,
447
+ Body: options.body,
448
+ ContentType: options.contentType,
449
+ Metadata: options.metadata,
450
+ Tagging: options.tags
451
+ ? Object.entries(options.tags)
452
+ .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
453
+ .join('&')
454
+ : undefined,
455
+ });
456
+ const response = await client.send(command);
457
+ return {
458
+ success: true,
459
+ data: { etag: response.ETag, versionId: response.VersionId },
460
+ };
461
+ }
462
+ catch (error) {
463
+ logger.error('Failed to put object', error);
464
+ return { success: false, error: error.message };
465
+ }
466
+ }
467
+ /**
468
+ * Delete object from bucket
469
+ */
470
+ async deleteObject(bucket, key) {
471
+ try {
472
+ const { S3Client, DeleteObjectCommand } = await import('@aws-sdk/client-s3');
473
+ const client = new S3Client(this.getClientConfig());
474
+ const command = new DeleteObjectCommand({ Bucket: bucket, Key: key });
475
+ const response = await client.send(command);
476
+ return {
477
+ success: true,
478
+ data: { deleteMarker: response.DeleteMarker, versionId: response.VersionId },
479
+ };
480
+ }
481
+ catch (error) {
482
+ logger.error('Failed to delete object', error);
483
+ return { success: false, error: error.message };
484
+ }
485
+ }
486
+ /**
487
+ * Create a bucket
488
+ */
489
+ async createBucket(bucket, region) {
490
+ try {
491
+ const { S3Client, CreateBucketCommand } = await import('@aws-sdk/client-s3');
492
+ const targetRegion = region || this.config.region || 'us-east-1';
493
+ const client = new S3Client({ ...this.getClientConfig(), region: targetRegion });
494
+ const command = new CreateBucketCommand({
495
+ Bucket: bucket,
496
+ CreateBucketConfiguration: targetRegion !== 'us-east-1' ? { LocationConstraint: targetRegion } : undefined,
497
+ });
498
+ await client.send(command);
499
+ return { success: true, data: { bucket, region: targetRegion } };
500
+ }
501
+ catch (error) {
502
+ logger.error('Failed to create bucket', error);
503
+ return { success: false, error: error.message };
504
+ }
505
+ }
506
+ /**
507
+ * Delete a bucket
508
+ */
509
+ async deleteBucket(bucket) {
510
+ try {
511
+ const { S3Client, DeleteBucketCommand } = await import('@aws-sdk/client-s3');
512
+ const client = new S3Client(this.getClientConfig());
513
+ const command = new DeleteBucketCommand({ Bucket: bucket });
514
+ await client.send(command);
515
+ return { success: true, data: { message: `Bucket ${bucket} deleted` } };
516
+ }
517
+ catch (error) {
518
+ logger.error('Failed to delete bucket', error);
519
+ return { success: false, error: error.message };
520
+ }
521
+ }
522
+ // ==========================================
523
+ // IAM Operations
524
+ // ==========================================
525
+ /**
526
+ * List IAM users
527
+ */
528
+ async listUsers(options = {}) {
529
+ try {
530
+ const { IAMClient, ListUsersCommand } = await import('@aws-sdk/client-iam');
531
+ const client = new IAMClient(this.getClientConfig());
532
+ const input = {};
533
+ if (options.maxItems) {
534
+ input.MaxItems = options.maxItems;
535
+ }
536
+ if (options.marker) {
537
+ input.Marker = options.marker;
538
+ }
539
+ if (options.pathPrefix) {
540
+ input.PathPrefix = options.pathPrefix;
541
+ }
542
+ const command = new ListUsersCommand(input);
543
+ const response = await client.send(command);
544
+ const users = response.Users?.map((u) => ({
545
+ userName: u.UserName,
546
+ userId: u.UserId,
547
+ arn: u.Arn,
548
+ path: u.Path,
549
+ createDate: u.CreateDate,
550
+ passwordLastUsed: u.PasswordLastUsed,
551
+ }));
552
+ return {
553
+ success: true,
554
+ data: {
555
+ users: users || [],
556
+ isTruncated: response.IsTruncated,
557
+ marker: response.Marker,
558
+ },
559
+ };
560
+ }
561
+ catch (error) {
562
+ logger.error('Failed to list users', error);
563
+ return { success: false, error: error.message };
564
+ }
565
+ }
566
+ /**
567
+ * List IAM roles
568
+ */
569
+ async listRoles(options = {}) {
570
+ try {
571
+ const { IAMClient, ListRolesCommand } = await import('@aws-sdk/client-iam');
572
+ const client = new IAMClient(this.getClientConfig());
573
+ const input = {};
574
+ if (options.maxItems) {
575
+ input.MaxItems = options.maxItems;
576
+ }
577
+ if (options.marker) {
578
+ input.Marker = options.marker;
579
+ }
580
+ if (options.pathPrefix) {
581
+ input.PathPrefix = options.pathPrefix;
582
+ }
583
+ const command = new ListRolesCommand(input);
584
+ const response = await client.send(command);
585
+ const roles = response.Roles?.map((r) => ({
586
+ roleName: r.RoleName,
587
+ roleId: r.RoleId,
588
+ arn: r.Arn,
589
+ path: r.Path,
590
+ createDate: r.CreateDate,
591
+ description: r.Description,
592
+ maxSessionDuration: r.MaxSessionDuration,
593
+ }));
594
+ return {
595
+ success: true,
596
+ data: {
597
+ roles: roles || [],
598
+ isTruncated: response.IsTruncated,
599
+ marker: response.Marker,
600
+ },
601
+ };
602
+ }
603
+ catch (error) {
604
+ logger.error('Failed to list roles', error);
605
+ return { success: false, error: error.message };
606
+ }
607
+ }
608
+ /**
609
+ * List IAM policies
610
+ */
611
+ async listPolicies(options = {}) {
612
+ try {
613
+ const { IAMClient, ListPoliciesCommand } = await import('@aws-sdk/client-iam');
614
+ const client = new IAMClient(this.getClientConfig());
615
+ const command = new ListPoliciesCommand({
616
+ MaxItems: options.maxItems,
617
+ Marker: options.marker,
618
+ PathPrefix: options.pathPrefix,
619
+ Scope: options.scope,
620
+ OnlyAttached: options.onlyAttached,
621
+ });
622
+ const response = await client.send(command);
623
+ const policies = response.Policies?.map((p) => ({
624
+ policyName: p.PolicyName,
625
+ policyId: p.PolicyId,
626
+ arn: p.Arn,
627
+ path: p.Path,
628
+ createDate: p.CreateDate,
629
+ updateDate: p.UpdateDate,
630
+ attachmentCount: p.AttachmentCount,
631
+ isAttachable: p.IsAttachable,
632
+ description: p.Description,
633
+ }));
634
+ return {
635
+ success: true,
636
+ data: {
637
+ policies: policies || [],
638
+ isTruncated: response.IsTruncated,
639
+ marker: response.Marker,
640
+ },
641
+ };
642
+ }
643
+ catch (error) {
644
+ logger.error('Failed to list policies', error);
645
+ return { success: false, error: error.message };
646
+ }
647
+ }
648
+ /**
649
+ * List IAM groups
650
+ */
651
+ async listGroups(options = {}) {
652
+ try {
653
+ const { IAMClient, ListGroupsCommand } = await import('@aws-sdk/client-iam');
654
+ const client = new IAMClient(this.getClientConfig());
655
+ const command = new ListGroupsCommand({
656
+ MaxItems: options.maxItems,
657
+ Marker: options.marker,
658
+ PathPrefix: options.pathPrefix,
659
+ });
660
+ const response = await client.send(command);
661
+ const groups = response.Groups?.map((g) => ({
662
+ groupName: g.GroupName,
663
+ groupId: g.GroupId,
664
+ arn: g.Arn,
665
+ path: g.Path,
666
+ createDate: g.CreateDate,
667
+ }));
668
+ return {
669
+ success: true,
670
+ data: {
671
+ groups: groups || [],
672
+ isTruncated: response.IsTruncated,
673
+ marker: response.Marker,
674
+ },
675
+ };
676
+ }
677
+ catch (error) {
678
+ logger.error('Failed to list groups', error);
679
+ return { success: false, error: error.message };
680
+ }
681
+ }
682
+ /**
683
+ * Get IAM user details
684
+ */
685
+ async getUser(userName) {
686
+ try {
687
+ const { IAMClient, GetUserCommand } = await import('@aws-sdk/client-iam');
688
+ const client = new IAMClient(this.getClientConfig());
689
+ const command = new GetUserCommand(userName ? { UserName: userName } : {});
690
+ const response = await client.send(command);
691
+ const user = response.User;
692
+ return {
693
+ success: true,
694
+ data: {
695
+ userName: user?.UserName,
696
+ userId: user?.UserId,
697
+ arn: user?.Arn,
698
+ path: user?.Path,
699
+ createDate: user?.CreateDate,
700
+ passwordLastUsed: user?.PasswordLastUsed,
701
+ },
702
+ };
703
+ }
704
+ catch (error) {
705
+ logger.error('Failed to get user', error);
706
+ return { success: false, error: error.message };
707
+ }
708
+ }
709
+ /**
710
+ * Attach policy to role
711
+ */
712
+ async attachRolePolicy(roleName, policyArn) {
713
+ try {
714
+ const { IAMClient, AttachRolePolicyCommand } = await import('@aws-sdk/client-iam');
715
+ const client = new IAMClient(this.getClientConfig());
716
+ const command = new AttachRolePolicyCommand({ RoleName: roleName, PolicyArn: policyArn });
717
+ await client.send(command);
718
+ return {
719
+ success: true,
720
+ data: { message: `Policy ${policyArn} attached to role ${roleName}` },
721
+ };
722
+ }
723
+ catch (error) {
724
+ logger.error('Failed to attach role policy', error);
725
+ return { success: false, error: error.message };
726
+ }
727
+ }
728
+ /**
729
+ * Detach policy from role
730
+ */
731
+ async detachRolePolicy(roleName, policyArn) {
732
+ try {
733
+ const { IAMClient, DetachRolePolicyCommand } = await import('@aws-sdk/client-iam');
734
+ const client = new IAMClient(this.getClientConfig());
735
+ const command = new DetachRolePolicyCommand({ RoleName: roleName, PolicyArn: policyArn });
736
+ await client.send(command);
737
+ return {
738
+ success: true,
739
+ data: { message: `Policy ${policyArn} detached from role ${roleName}` },
740
+ };
741
+ }
742
+ catch (error) {
743
+ logger.error('Failed to detach role policy', error);
744
+ return { success: false, error: error.message };
745
+ }
746
+ }
747
+ }