@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,625 @@
1
+ /**
2
+ * GCP Operations — Embedded tool (stripped HTTP wrappers)
3
+ *
4
+ * Merged from services/gcp-tools-service/src/gcp/compute.ts, iam.ts, storage.ts, gke.ts, vpc.ts
5
+ * Uses lazy imports for GCP SDK to keep binary size small.
6
+ */
7
+
8
+ import { logger } from '../utils';
9
+
10
+ // ==========================================
11
+ // Shared Types
12
+ // ==========================================
13
+
14
+ export interface OperationResult<T = any> {
15
+ success: boolean;
16
+ data?: T;
17
+ error?: string;
18
+ }
19
+
20
+ export interface GcpConfig {
21
+ projectId?: string;
22
+ }
23
+
24
+ /**
25
+ * Unified GCP Operations class merging Compute, Storage, GKE, IAM, and VPC operations.
26
+ * All GCP SDK imports are lazy to minimize binary size.
27
+ */
28
+ export class GcpOperations {
29
+ private projectId: string;
30
+
31
+ constructor(config: GcpConfig = {}) {
32
+ this.projectId =
33
+ config.projectId || process.env.GOOGLE_CLOUD_PROJECT || process.env.GCLOUD_PROJECT || '';
34
+ }
35
+
36
+ // ==========================================
37
+ // Compute Engine Operations
38
+ // ==========================================
39
+
40
+ /**
41
+ * List Compute Engine instances
42
+ */
43
+ async listInstances(options: { project?: string; zone?: string } = {}): Promise<OperationResult> {
44
+ try {
45
+ const project = options.project || this.projectId;
46
+ if (!project) {
47
+ return {
48
+ success: false,
49
+ error: 'No project specified. Set GOOGLE_CLOUD_PROJECT or pass project parameter.',
50
+ };
51
+ }
52
+
53
+ // Pre-check: verify credentials are available
54
+ try {
55
+ const { GoogleAuth } = await import('google-auth-library');
56
+ const auth = new GoogleAuth({
57
+ scopes: ['https://www.googleapis.com/auth/compute.readonly'],
58
+ });
59
+ await auth.getClient();
60
+ } catch (authErr: any) {
61
+ return { success: false, error: authErr.message || 'GCP credentials not available' };
62
+ }
63
+
64
+ const { InstancesClient } = await import('@google-cloud/compute');
65
+ const instancesClient = new InstancesClient();
66
+ const instances: any[] = [];
67
+
68
+ if (options.zone) {
69
+ const [response] = await instancesClient.list({ project, zone: options.zone });
70
+ for (const instance of response || []) {
71
+ instances.push(this.mapComputeInstance(instance, options.zone));
72
+ }
73
+ } else {
74
+ const aggListRequest = instancesClient.aggregatedListAsync({ project });
75
+ for await (const [zone, scopedList] of aggListRequest) {
76
+ if (scopedList.instances) {
77
+ const zoneName = zone.replace('zones/', '');
78
+ for (const instance of scopedList.instances) {
79
+ instances.push(this.mapComputeInstance(instance, zoneName));
80
+ }
81
+ }
82
+ }
83
+ }
84
+
85
+ return { success: true, data: { instances } };
86
+ } catch (error: any) {
87
+ logger.error('Failed to list compute instances', error);
88
+ return { success: false, error: error.message };
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Start a Compute Engine instance
94
+ */
95
+ async startInstance(project: string, zone: string, instance: string): Promise<OperationResult> {
96
+ try {
97
+ const effectiveProject = project || this.projectId;
98
+ if (!effectiveProject) {
99
+ return { success: false, error: 'No project specified.' };
100
+ }
101
+
102
+ const { InstancesClient, ZoneOperationsClient } = await import('@google-cloud/compute');
103
+ const instancesClient = new InstancesClient();
104
+ const [operation] = await instancesClient.start({
105
+ project: effectiveProject,
106
+ zone,
107
+ instance,
108
+ });
109
+
110
+ const operationsClient = new ZoneOperationsClient();
111
+ await operationsClient.wait({ operation: operation.name, project: effectiveProject, zone });
112
+
113
+ return {
114
+ success: true,
115
+ data: { message: `Instance ${instance} started successfully in zone ${zone}` },
116
+ };
117
+ } catch (error: any) {
118
+ logger.error('Failed to start instance', error);
119
+ return { success: false, error: error.message };
120
+ }
121
+ }
122
+
123
+ /**
124
+ * Stop a Compute Engine instance
125
+ */
126
+ async stopInstance(project: string, zone: string, instance: string): Promise<OperationResult> {
127
+ try {
128
+ const effectiveProject = project || this.projectId;
129
+ if (!effectiveProject) {
130
+ return { success: false, error: 'No project specified.' };
131
+ }
132
+
133
+ const { InstancesClient, ZoneOperationsClient } = await import('@google-cloud/compute');
134
+ const instancesClient = new InstancesClient();
135
+ const [operation] = await instancesClient.stop({ project: effectiveProject, zone, instance });
136
+
137
+ const operationsClient = new ZoneOperationsClient();
138
+ await operationsClient.wait({ operation: operation.name, project: effectiveProject, zone });
139
+
140
+ return {
141
+ success: true,
142
+ data: { message: `Instance ${instance} stopped successfully in zone ${zone}` },
143
+ };
144
+ } catch (error: any) {
145
+ logger.error('Failed to stop instance', error);
146
+ return { success: false, error: error.message };
147
+ }
148
+ }
149
+
150
+ /**
151
+ * Map raw instance data to a clean object
152
+ */
153
+ private mapComputeInstance(instance: any, zone: string): Record<string, unknown> {
154
+ return {
155
+ id: instance.id,
156
+ name: instance.name,
157
+ selfLink: instance.selfLink,
158
+ status: instance.status,
159
+ zone,
160
+ machineType: instance.machineType?.split('/').pop(),
161
+ networkInterfaces: instance.networkInterfaces?.map((ni: any) => ({
162
+ network: ni.network?.split('/').pop(),
163
+ subnetwork: ni.subnetwork?.split('/').pop(),
164
+ networkIP: ni.networkIP,
165
+ accessConfigs: ni.accessConfigs?.map((ac: any) => ({
166
+ name: ac.name,
167
+ natIP: ac.natIP,
168
+ type: ac.type,
169
+ })),
170
+ })),
171
+ disks: instance.disks?.map((d: any) => ({
172
+ source: d.source?.split('/').pop(),
173
+ boot: d.boot,
174
+ autoDelete: d.autoDelete,
175
+ type: d.type,
176
+ diskSizeGb: d.diskSizeGb,
177
+ })),
178
+ labels: instance.labels || {},
179
+ tags: instance.tags?.items || [],
180
+ creationTimestamp: instance.creationTimestamp,
181
+ serviceAccounts: instance.serviceAccounts?.map((sa: any) => ({
182
+ email: sa.email,
183
+ scopes: sa.scopes,
184
+ })),
185
+ metadata: instance.metadata?.items?.reduce((acc: Record<string, string>, item: any) => {
186
+ acc[item.key] = item.value;
187
+ return acc;
188
+ }, {}),
189
+ };
190
+ }
191
+
192
+ // ==========================================
193
+ // Cloud Storage Operations
194
+ // ==========================================
195
+
196
+ /**
197
+ * List Cloud Storage buckets
198
+ */
199
+ async listBuckets(project?: string): Promise<OperationResult> {
200
+ try {
201
+ const effectiveProject = project || this.projectId;
202
+ if (!effectiveProject) {
203
+ return {
204
+ success: false,
205
+ error: 'No project specified. Set GOOGLE_CLOUD_PROJECT or pass project parameter.',
206
+ };
207
+ }
208
+
209
+ const { Storage } = await import('@google-cloud/storage');
210
+ const storage = new Storage({ projectId: effectiveProject });
211
+
212
+ const [buckets] = await storage.getBuckets({ project: effectiveProject });
213
+
214
+ const mappedBuckets = buckets.map((bucket: any) => ({
215
+ name: bucket.name,
216
+ selfLink: bucket.metadata?.selfLink,
217
+ location: bucket.metadata?.location,
218
+ storageClass: bucket.metadata?.storageClass,
219
+ timeCreated: bucket.metadata?.timeCreated,
220
+ updated: bucket.metadata?.updated,
221
+ versioning: bucket.metadata?.versioning?.enabled || false,
222
+ labels: bucket.metadata?.labels || {},
223
+ iamConfiguration: {
224
+ uniformBucketLevelAccess:
225
+ bucket.metadata?.iamConfiguration?.uniformBucketLevelAccess?.enabled || false,
226
+ },
227
+ lifecycle: bucket.metadata?.lifecycle?.rule || [],
228
+ encryption: bucket.metadata?.encryption || null,
229
+ retentionPolicy: bucket.metadata?.retentionPolicy || null,
230
+ }));
231
+
232
+ return { success: true, data: { buckets: mappedBuckets } };
233
+ } catch (error: any) {
234
+ logger.error('Failed to list buckets', error);
235
+ return { success: false, error: error.message };
236
+ }
237
+ }
238
+
239
+ /**
240
+ * List objects in a Cloud Storage bucket
241
+ */
242
+ async listObjects(
243
+ bucket: string,
244
+ options: { prefix?: string; maxResults?: number } = {}
245
+ ): Promise<OperationResult> {
246
+ try {
247
+ if (!bucket) {
248
+ return { success: false, error: 'Missing required parameter: bucket' };
249
+ }
250
+
251
+ const { Storage } = await import('@google-cloud/storage');
252
+ const storage = new Storage({ projectId: this.projectId || undefined });
253
+
254
+ const queryOptions: any = {};
255
+ if (options.prefix) {
256
+ queryOptions.prefix = options.prefix;
257
+ }
258
+ if (options.maxResults) {
259
+ queryOptions.maxResults = options.maxResults;
260
+ }
261
+
262
+ const [files] = await storage.bucket(bucket).getFiles(queryOptions);
263
+
264
+ const objects = files.map((file: any) => ({
265
+ name: file.name,
266
+ selfLink: file.metadata?.selfLink,
267
+ bucket: file.metadata?.bucket,
268
+ size: file.metadata?.size,
269
+ contentType: file.metadata?.contentType,
270
+ timeCreated: file.metadata?.timeCreated,
271
+ updated: file.metadata?.updated,
272
+ storageClass: file.metadata?.storageClass,
273
+ md5Hash: file.metadata?.md5Hash,
274
+ metadata: file.metadata?.metadata || {},
275
+ }));
276
+
277
+ return { success: true, data: { objects, bucket } };
278
+ } catch (error: any) {
279
+ logger.error('Failed to list objects', error);
280
+ return { success: false, error: error.message };
281
+ }
282
+ }
283
+
284
+ // ==========================================
285
+ // GKE (Google Kubernetes Engine) Operations
286
+ // ==========================================
287
+
288
+ /**
289
+ * List GKE clusters
290
+ */
291
+ async listClusters(project?: string, location?: string): Promise<OperationResult> {
292
+ try {
293
+ const effectiveProject = project || this.projectId;
294
+ if (!effectiveProject) {
295
+ return {
296
+ success: false,
297
+ error: 'No project specified. Set GOOGLE_CLOUD_PROJECT or pass project parameter.',
298
+ };
299
+ }
300
+
301
+ const { ClusterManagerClient } = await import('@google-cloud/container');
302
+ const clusterManagerClient = new ClusterManagerClient();
303
+ const parent = location
304
+ ? `projects/${effectiveProject}/locations/${location}`
305
+ : `projects/${effectiveProject}/locations/-`;
306
+
307
+ const [response] = await clusterManagerClient.listClusters({ parent });
308
+
309
+ const clusters = (response.clusters || []).map((cluster: any) => ({
310
+ name: cluster.name,
311
+ selfLink: cluster.selfLink,
312
+ location: cluster.location,
313
+ zone: cluster.zone,
314
+ status: cluster.status,
315
+ statusMessage: cluster.statusMessage,
316
+ currentMasterVersion: cluster.currentMasterVersion,
317
+ currentNodeVersion: cluster.currentNodeVersion,
318
+ currentNodeCount: cluster.currentNodeCount,
319
+ endpoint: cluster.endpoint,
320
+ initialClusterVersion: cluster.initialClusterVersion,
321
+ createTime: cluster.createTime,
322
+ network: cluster.network,
323
+ subnetwork: cluster.subnetwork,
324
+ clusterIpv4Cidr: cluster.clusterIpv4Cidr,
325
+ servicesIpv4Cidr: cluster.servicesIpv4Cidr,
326
+ labels: cluster.resourceLabels || {},
327
+ nodePools: (cluster.nodePools || []).map((pool: any) => ({
328
+ name: pool.name,
329
+ status: pool.status,
330
+ initialNodeCount: pool.initialNodeCount,
331
+ autoscaling: pool.autoscaling
332
+ ? {
333
+ enabled: pool.autoscaling.enabled,
334
+ minNodeCount: pool.autoscaling.minNodeCount,
335
+ maxNodeCount: pool.autoscaling.maxNodeCount,
336
+ }
337
+ : null,
338
+ config: pool.config
339
+ ? {
340
+ machineType: pool.config.machineType,
341
+ diskSizeGb: pool.config.diskSizeGb,
342
+ diskType: pool.config.diskType,
343
+ }
344
+ : null,
345
+ })),
346
+ }));
347
+
348
+ return { success: true, data: { clusters } };
349
+ } catch (error: any) {
350
+ logger.error('Failed to list GKE clusters', error);
351
+ return { success: false, error: error.message };
352
+ }
353
+ }
354
+
355
+ /**
356
+ * Get details of a specific GKE cluster
357
+ */
358
+ async describeCluster(
359
+ project: string,
360
+ location: string,
361
+ cluster: string
362
+ ): Promise<OperationResult> {
363
+ try {
364
+ const effectiveProject = project || this.projectId;
365
+ if (!effectiveProject) {
366
+ return { success: false, error: 'No project specified.' };
367
+ }
368
+
369
+ const { ClusterManagerClient } = await import('@google-cloud/container');
370
+ const clusterManagerClient = new ClusterManagerClient();
371
+ const name = `projects/${effectiveProject}/locations/${location}/clusters/${cluster}`;
372
+
373
+ const [response] = await clusterManagerClient.getCluster({ name });
374
+
375
+ return {
376
+ success: true,
377
+ data: {
378
+ cluster: {
379
+ name: response.name,
380
+ selfLink: response.selfLink,
381
+ location: response.location,
382
+ zone: response.zone,
383
+ status: response.status,
384
+ currentMasterVersion: response.currentMasterVersion,
385
+ currentNodeVersion: response.currentNodeVersion,
386
+ currentNodeCount: response.currentNodeCount,
387
+ endpoint: response.endpoint,
388
+ network: response.network,
389
+ subnetwork: response.subnetwork,
390
+ clusterIpv4Cidr: response.clusterIpv4Cidr,
391
+ servicesIpv4Cidr: response.servicesIpv4Cidr,
392
+ labels: response.resourceLabels || {},
393
+ createTime: response.createTime,
394
+ nodePools: (response.nodePools || []).map((pool: any) => ({
395
+ name: pool.name,
396
+ status: pool.status,
397
+ initialNodeCount: pool.initialNodeCount,
398
+ autoscaling: pool.autoscaling,
399
+ config: pool.config
400
+ ? {
401
+ machineType: pool.config.machineType,
402
+ diskSizeGb: pool.config.diskSizeGb,
403
+ diskType: pool.config.diskType,
404
+ imageType: pool.config.imageType,
405
+ }
406
+ : null,
407
+ version: pool.version,
408
+ })),
409
+ },
410
+ },
411
+ };
412
+ } catch (error: any) {
413
+ logger.error('Failed to describe GKE cluster', error);
414
+ return { success: false, error: error.message };
415
+ }
416
+ }
417
+
418
+ // ==========================================
419
+ // IAM Operations
420
+ // ==========================================
421
+
422
+ /**
423
+ * List IAM service accounts for a project
424
+ */
425
+ async listServiceAccounts(project?: string): Promise<OperationResult> {
426
+ try {
427
+ const effectiveProject = project || this.projectId;
428
+ if (!effectiveProject) {
429
+ return {
430
+ success: false,
431
+ error: 'No project specified. Set GOOGLE_CLOUD_PROJECT or pass project parameter.',
432
+ };
433
+ }
434
+
435
+ const iamMod = await import('@google-cloud/iam');
436
+ const iamClient = new (iamMod as any).IAMClient();
437
+ const request = { name: `projects/${effectiveProject}` };
438
+
439
+ const serviceAccounts: any[] = [];
440
+ const iterable = iamClient.listServiceAccountsAsync(request);
441
+
442
+ for await (const account of iterable) {
443
+ serviceAccounts.push({
444
+ name: account.name,
445
+ email: account.email,
446
+ uniqueId: account.uniqueId,
447
+ displayName: account.displayName,
448
+ description: account.description,
449
+ disabled: account.disabled || false,
450
+ projectId: account.projectId,
451
+ oauth2ClientId: account.oauth2ClientId,
452
+ });
453
+ }
454
+
455
+ return { success: true, data: { serviceAccounts } };
456
+ } catch (error: any) {
457
+ logger.error('Failed to list service accounts', error);
458
+ return { success: false, error: error.message };
459
+ }
460
+ }
461
+
462
+ /**
463
+ * List IAM roles
464
+ */
465
+ async listRoles(project?: string): Promise<OperationResult> {
466
+ try {
467
+ const iamMod = await import('@google-cloud/iam');
468
+ const iamClient = new (iamMod as any).IAMClient();
469
+ const roles: any[] = [];
470
+
471
+ if (project || this.projectId) {
472
+ const effectiveProject = project || this.projectId;
473
+ const request = { parent: `projects/${effectiveProject}`, view: 'BASIC' };
474
+ const iterable = iamClient.listRolesAsync(request);
475
+ for await (const role of iterable) {
476
+ roles.push({
477
+ name: role.name,
478
+ title: role.title,
479
+ description: role.description,
480
+ stage: role.stage,
481
+ deleted: role.deleted || false,
482
+ includedPermissions: role.includedPermissions || [],
483
+ etag: role.etag,
484
+ });
485
+ }
486
+ } else {
487
+ const request = { view: 'BASIC' };
488
+ const iterable = iamClient.listRolesAsync(request);
489
+ for await (const role of iterable) {
490
+ roles.push({
491
+ name: role.name,
492
+ title: role.title,
493
+ description: role.description,
494
+ stage: role.stage,
495
+ deleted: role.deleted || false,
496
+ });
497
+ }
498
+ }
499
+
500
+ return { success: true, data: { roles } };
501
+ } catch (error: any) {
502
+ logger.error('Failed to list roles', error);
503
+ return { success: false, error: error.message };
504
+ }
505
+ }
506
+
507
+ // ==========================================
508
+ // VPC Operations
509
+ // ==========================================
510
+
511
+ /**
512
+ * List VPC networks
513
+ */
514
+ async listNetworks(project?: string): Promise<OperationResult> {
515
+ try {
516
+ const effectiveProject = project || this.projectId;
517
+ if (!effectiveProject) {
518
+ return {
519
+ success: false,
520
+ error: 'No project specified. Set GOOGLE_CLOUD_PROJECT or pass project parameter.',
521
+ };
522
+ }
523
+
524
+ const { NetworksClient } = await import('@google-cloud/compute');
525
+ const networksClient = new NetworksClient();
526
+ const [networks] = await networksClient.list({ project: effectiveProject });
527
+
528
+ const mappedNetworks = (networks || []).map((network: any) => ({
529
+ id: network.id,
530
+ name: network.name,
531
+ selfLink: network.selfLink,
532
+ description: network.description,
533
+ autoCreateSubnetworks: network.autoCreateSubnetworks,
534
+ routingConfig: network.routingConfig
535
+ ? {
536
+ routingMode: network.routingConfig.routingMode,
537
+ }
538
+ : null,
539
+ subnetworks: network.subnetworks || [],
540
+ peerings: (network.peerings || []).map((peering: any) => ({
541
+ name: peering.name,
542
+ network: peering.network,
543
+ state: peering.state,
544
+ autoCreateRoutes: peering.autoCreateRoutes,
545
+ exportCustomRoutes: peering.exportCustomRoutes,
546
+ importCustomRoutes: peering.importCustomRoutes,
547
+ })),
548
+ mtu: network.mtu,
549
+ creationTimestamp: network.creationTimestamp,
550
+ }));
551
+
552
+ return { success: true, data: { networks: mappedNetworks } };
553
+ } catch (error: any) {
554
+ logger.error('Failed to list VPC networks', error);
555
+ return { success: false, error: error.message };
556
+ }
557
+ }
558
+
559
+ /**
560
+ * List VPC subnetworks
561
+ */
562
+ async listSubnets(project?: string, region?: string): Promise<OperationResult> {
563
+ try {
564
+ const effectiveProject = project || this.projectId;
565
+ if (!effectiveProject) {
566
+ return {
567
+ success: false,
568
+ error: 'No project specified. Set GOOGLE_CLOUD_PROJECT or pass project parameter.',
569
+ };
570
+ }
571
+
572
+ const { SubnetworksClient } = await import('@google-cloud/compute');
573
+ const subnetworksClient = new SubnetworksClient();
574
+ const subnets: any[] = [];
575
+
576
+ if (region) {
577
+ const [response] = await subnetworksClient.list({ project: effectiveProject, region });
578
+ for (const subnet of response || []) {
579
+ subnets.push(this.mapSubnet(subnet));
580
+ }
581
+ } else {
582
+ const aggListRequest = subnetworksClient.aggregatedListAsync({ project: effectiveProject });
583
+ for await (const [_regionKey, scopedList] of aggListRequest) {
584
+ if (scopedList.subnetworks) {
585
+ for (const subnet of scopedList.subnetworks) {
586
+ subnets.push(this.mapSubnet(subnet));
587
+ }
588
+ }
589
+ }
590
+ }
591
+
592
+ return { success: true, data: { subnets } };
593
+ } catch (error: any) {
594
+ logger.error('Failed to list subnets', error);
595
+ return { success: false, error: error.message };
596
+ }
597
+ }
598
+
599
+ /**
600
+ * Map a subnet to a clean object
601
+ */
602
+ private mapSubnet(subnet: any): Record<string, unknown> {
603
+ return {
604
+ id: subnet.id,
605
+ name: subnet.name,
606
+ selfLink: subnet.selfLink,
607
+ description: subnet.description,
608
+ network: subnet.network?.split('/').pop(),
609
+ region: subnet.region?.split('/').pop(),
610
+ ipCidrRange: subnet.ipCidrRange,
611
+ gatewayAddress: subnet.gatewayAddress,
612
+ privateIpGoogleAccess: subnet.privateIpGoogleAccess,
613
+ purpose: subnet.purpose,
614
+ role: subnet.role,
615
+ state: subnet.state,
616
+ logConfig: subnet.logConfig || null,
617
+ secondaryIpRanges: (subnet.secondaryIpRanges || []).map((range: any) => ({
618
+ rangeName: range.rangeName,
619
+ ipCidrRange: range.ipCidrRange,
620
+ })),
621
+ stackType: subnet.stackType,
622
+ creationTimestamp: subnet.creationTimestamp,
623
+ };
624
+ }
625
+ }