@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,1843 @@
1
+ import { RestClient, type RestClientOptions } from './rest-client';
2
+ import { ServiceURLs } from './service-discovery';
3
+
4
+ /**
5
+ * Unified Tools Client for MCP Tools Services
6
+ * Provides a single interface to interact with all tool services
7
+ */
8
+ export class ToolsClient {
9
+ private gitClient: RestClient;
10
+ private fsClient: RestClient;
11
+ private terraformClient: RestClient;
12
+ private k8sClient: RestClient;
13
+ private helmClient: RestClient;
14
+ private awsClient: RestClient;
15
+ private githubClient: RestClient;
16
+ private gcpClient: RestClient;
17
+ private azureClient: RestClient;
18
+
19
+ constructor(options: RestClientOptions = {}) {
20
+ this.gitClient = new RestClient(ServiceURLs.GIT_TOOLS, options);
21
+ this.fsClient = new RestClient(ServiceURLs.FS_TOOLS, options);
22
+ this.terraformClient = new RestClient(ServiceURLs.TERRAFORM_TOOLS, options);
23
+ this.k8sClient = new RestClient(ServiceURLs.K8S_TOOLS, options);
24
+ this.helmClient = new RestClient(ServiceURLs.HELM_TOOLS, options);
25
+ this.awsClient = new RestClient(ServiceURLs.AWS_TOOLS, options);
26
+ this.githubClient = new RestClient(ServiceURLs.GITHUB_TOOLS, options);
27
+ this.gcpClient = new RestClient(ServiceURLs.GCP_TOOLS, options);
28
+ this.azureClient = new RestClient(ServiceURLs.AZURE_TOOLS, options);
29
+ }
30
+
31
+ // ==================== Git Operations ====================
32
+
33
+ git = {
34
+ clone: async (url: string, path: string, options?: { branch?: string; depth?: number }) => {
35
+ return this.gitClient.post('/api/git/clone', { url, path, ...options });
36
+ },
37
+
38
+ status: async (path?: string) => {
39
+ const query = path ? `?path=${encodeURIComponent(path)}` : '';
40
+ return this.gitClient.get(`/api/git/status${query}`);
41
+ },
42
+
43
+ add: async (files?: string | string[], path?: string) => {
44
+ return this.gitClient.post('/api/git/add', { files, path });
45
+ },
46
+
47
+ commit: async (
48
+ message: string,
49
+ options?: { path?: string; amend?: boolean; allowEmpty?: boolean }
50
+ ) => {
51
+ return this.gitClient.post('/api/git/commit', { message, ...options });
52
+ },
53
+
54
+ push: async (options?: {
55
+ path?: string;
56
+ remote?: string;
57
+ branch?: string;
58
+ force?: boolean;
59
+ setUpstream?: boolean;
60
+ }) => {
61
+ return this.gitClient.post('/api/git/push', options);
62
+ },
63
+
64
+ pull: async (options?: {
65
+ path?: string;
66
+ remote?: string;
67
+ branch?: string;
68
+ rebase?: boolean;
69
+ }) => {
70
+ return this.gitClient.post('/api/git/pull', options);
71
+ },
72
+
73
+ createBranch: async (
74
+ name: string,
75
+ options?: { path?: string; checkout?: boolean; startPoint?: string }
76
+ ) => {
77
+ return this.gitClient.post('/api/git/branch', { name, ...options });
78
+ },
79
+
80
+ listBranches: async (path?: string, showRemote?: boolean) => {
81
+ const params = new URLSearchParams();
82
+ if (path) {
83
+ params.set('path', path);
84
+ }
85
+ if (showRemote) {
86
+ params.set('remote', 'true');
87
+ }
88
+ const query = params.toString() ? `?${params.toString()}` : '';
89
+ return this.gitClient.get(`/api/git/branches${query}`);
90
+ },
91
+
92
+ checkout: async (target: string, options?: { path?: string; create?: boolean }) => {
93
+ return this.gitClient.post('/api/git/checkout', { target, ...options });
94
+ },
95
+
96
+ diff: async (options?: {
97
+ path?: string;
98
+ cached?: boolean;
99
+ nameOnly?: boolean;
100
+ from?: string;
101
+ to?: string;
102
+ }) => {
103
+ const params = new URLSearchParams();
104
+ if (options?.path) {
105
+ params.set('path', options.path);
106
+ }
107
+ if (options?.cached) {
108
+ params.set('cached', 'true');
109
+ }
110
+ if (options?.nameOnly) {
111
+ params.set('nameOnly', 'true');
112
+ }
113
+ if (options?.from) {
114
+ params.set('from', options.from);
115
+ }
116
+ if (options?.to) {
117
+ params.set('to', options.to);
118
+ }
119
+ const query = params.toString() ? `?${params.toString()}` : '';
120
+ return this.gitClient.get(`/api/git/diff${query}`);
121
+ },
122
+
123
+ log: async (options?: {
124
+ path?: string;
125
+ maxCount?: number;
126
+ from?: string;
127
+ to?: string;
128
+ file?: string;
129
+ }) => {
130
+ const params = new URLSearchParams();
131
+ if (options?.path) {
132
+ params.set('path', options.path);
133
+ }
134
+ if (options?.maxCount) {
135
+ params.set('maxCount', options.maxCount.toString());
136
+ }
137
+ if (options?.from) {
138
+ params.set('from', options.from);
139
+ }
140
+ if (options?.to) {
141
+ params.set('to', options.to);
142
+ }
143
+ if (options?.file) {
144
+ params.set('file', options.file);
145
+ }
146
+ const query = params.toString() ? `?${params.toString()}` : '';
147
+ return this.gitClient.get(`/api/git/log${query}`);
148
+ },
149
+
150
+ merge: async (
151
+ branch: string,
152
+ options?: { path?: string; noFf?: boolean; squash?: boolean; message?: string }
153
+ ) => {
154
+ return this.gitClient.post('/api/git/merge', { branch, ...options });
155
+ },
156
+
157
+ stash: async (
158
+ command: 'push' | 'pop' | 'list' | 'drop' | 'apply' | 'clear',
159
+ options?: { path?: string; message?: string; index?: number }
160
+ ) => {
161
+ return this.gitClient.post('/api/git/stash', { command, ...options });
162
+ },
163
+
164
+ fetch: async (options?: { path?: string; remote?: string; prune?: boolean }) => {
165
+ return this.gitClient.post('/api/git/fetch', options);
166
+ },
167
+
168
+ reset: async (
169
+ target: string,
170
+ options?: { path?: string; mode?: 'soft' | 'mixed' | 'hard' }
171
+ ) => {
172
+ return this.gitClient.post('/api/git/reset', { target, ...options });
173
+ },
174
+
175
+ init: async (options?: { path?: string; bare?: boolean }) => {
176
+ return this.gitClient.post('/api/git/init', options);
177
+ },
178
+
179
+ remote: async (options?: { path?: string; name?: string }) => {
180
+ const params = new URLSearchParams();
181
+ if (options?.path) {
182
+ params.set('path', options.path);
183
+ }
184
+ if (options?.name) {
185
+ params.set('name', options.name);
186
+ }
187
+ const query = params.toString() ? `?${params.toString()}` : '';
188
+ return this.gitClient.get(`/api/git/remote${query}`);
189
+ },
190
+
191
+ revert: async (
192
+ commit: string,
193
+ options?: { cwd?: string; noCommit?: boolean; noEdit?: boolean }
194
+ ) => {
195
+ return this.gitClient.post('/api/git/revert', { commit, ...options });
196
+ },
197
+
198
+ cherryPick: async (
199
+ commit: string,
200
+ options?: {
201
+ path?: string;
202
+ noCommit?: boolean;
203
+ edit?: boolean;
204
+ signoff?: boolean;
205
+ strategy?: string;
206
+ }
207
+ ) => {
208
+ return this.gitClient.post('/api/git/cherry-pick', { commit, ...options });
209
+ },
210
+
211
+ cherryPickAbort: async (options?: { path?: string }) => {
212
+ return this.gitClient.post('/api/git/cherry-pick/abort', options || {});
213
+ },
214
+
215
+ cherryPickContinue: async (options?: { path?: string }) => {
216
+ return this.gitClient.post('/api/git/cherry-pick/continue', options || {});
217
+ },
218
+
219
+ tag: async (
220
+ name: string,
221
+ options?: {
222
+ path?: string;
223
+ message?: string;
224
+ annotated?: boolean;
225
+ force?: boolean;
226
+ commit?: string;
227
+ }
228
+ ) => {
229
+ return this.gitClient.post('/api/git/tag', { name, ...options });
230
+ },
231
+
232
+ deleteTag: async (name: string, options?: { path?: string; remote?: string }) => {
233
+ const params = new URLSearchParams();
234
+ params.set('name', name);
235
+ if (options?.path) {
236
+ params.set('path', options.path);
237
+ }
238
+ if (options?.remote) {
239
+ params.set('remote', options.remote);
240
+ }
241
+ return this.gitClient.delete(`/api/git/tag?${params.toString()}`);
242
+ },
243
+
244
+ listTags: async (options?: { path?: string; pattern?: string }) => {
245
+ const params = new URLSearchParams();
246
+ if (options?.path) {
247
+ params.set('path', options.path);
248
+ }
249
+ if (options?.pattern) {
250
+ params.set('pattern', options.pattern);
251
+ }
252
+ const query = params.toString() ? `?${params.toString()}` : '';
253
+ return this.gitClient.get(`/api/git/tags${query}`);
254
+ },
255
+
256
+ pushTags: async (options?: { path?: string; remote?: string; tagName?: string }) => {
257
+ return this.gitClient.post('/api/git/tag/push', options || {});
258
+ },
259
+
260
+ showTag: async (name: string, options?: { path?: string }) => {
261
+ const params = new URLSearchParams();
262
+ params.set('name', name);
263
+ if (options?.path) {
264
+ params.set('path', options.path);
265
+ }
266
+ return this.gitClient.get(`/api/git/tag/show?${params.toString()}`);
267
+ },
268
+
269
+ blame: async (
270
+ file: string,
271
+ options?: { path?: string; startLine?: number; endLine?: number }
272
+ ) => {
273
+ const params = new URLSearchParams();
274
+ params.set('file', file);
275
+ if (options?.path) {
276
+ params.set('path', options.path);
277
+ }
278
+ if (options?.startLine) {
279
+ params.set('startLine', options.startLine.toString());
280
+ }
281
+ if (options?.endLine) {
282
+ params.set('endLine', options.endLine.toString());
283
+ }
284
+ return this.gitClient.get(`/api/git/blame?${params.toString()}`);
285
+ },
286
+ };
287
+
288
+ // ==================== File System Operations ====================
289
+
290
+ fs = {
291
+ read: async (filePath: string, options?: { basePath?: string; encoding?: string }) => {
292
+ const params = new URLSearchParams();
293
+ params.set('path', filePath);
294
+ if (options?.basePath) {
295
+ params.set('basePath', options.basePath);
296
+ }
297
+ if (options?.encoding) {
298
+ params.set('encoding', options.encoding);
299
+ }
300
+ return this.fsClient.get(`/api/fs/read?${params.toString()}`);
301
+ },
302
+
303
+ write: async (
304
+ filePath: string,
305
+ content: string,
306
+ options?: { basePath?: string; encoding?: string; createDirs?: boolean }
307
+ ) => {
308
+ return this.fsClient.post('/api/fs/write', { path: filePath, content, ...options });
309
+ },
310
+
311
+ list: async (
312
+ dirPath: string,
313
+ options?: { basePath?: string; recursive?: boolean; pattern?: string }
314
+ ) => {
315
+ const params = new URLSearchParams();
316
+ params.set('path', dirPath);
317
+ if (options?.basePath) {
318
+ params.set('basePath', options.basePath);
319
+ }
320
+ if (options?.recursive) {
321
+ params.set('recursive', 'true');
322
+ }
323
+ if (options?.pattern) {
324
+ params.set('pattern', options.pattern);
325
+ }
326
+ return this.fsClient.get(`/api/fs/list?${params.toString()}`);
327
+ },
328
+
329
+ search: async (
330
+ pattern: string,
331
+ options?: { basePath?: string; path?: string; type?: string; maxResults?: number }
332
+ ) => {
333
+ const params = new URLSearchParams();
334
+ params.set('pattern', pattern);
335
+ if (options?.basePath) {
336
+ params.set('basePath', options.basePath);
337
+ }
338
+ if (options?.path) {
339
+ params.set('path', options.path);
340
+ }
341
+ if (options?.type) {
342
+ params.set('type', options.type);
343
+ }
344
+ if (options?.maxResults) {
345
+ params.set('maxResults', options.maxResults.toString());
346
+ }
347
+ return this.fsClient.get(`/api/fs/search?${params.toString()}`);
348
+ },
349
+
350
+ delete: async (filePath: string, options?: { basePath?: string; recursive?: boolean }) => {
351
+ return this.fsClient.post('/api/fs/delete', { path: filePath, ...options });
352
+ },
353
+
354
+ copy: async (
355
+ source: string,
356
+ destination: string,
357
+ options?: { basePath?: string; overwrite?: boolean }
358
+ ) => {
359
+ return this.fsClient.post('/api/fs/copy', { source, destination, ...options });
360
+ },
361
+
362
+ move: async (
363
+ source: string,
364
+ destination: string,
365
+ options?: { basePath?: string; overwrite?: boolean }
366
+ ) => {
367
+ return this.fsClient.post('/api/fs/move', { source, destination, ...options });
368
+ },
369
+
370
+ tree: async (
371
+ directory: string,
372
+ options?: { maxDepth?: number; includeHidden?: boolean; includeFiles?: boolean }
373
+ ) => {
374
+ return this.fsClient.post('/api/fs/tree', { directory, ...options });
375
+ },
376
+
377
+ mkdir: async (dirPath: string, options?: { basePath?: string; recursive?: boolean }) => {
378
+ return this.fsClient.post('/api/fs/mkdir', { path: dirPath, ...options });
379
+ },
380
+
381
+ exists: async (filePath: string, basePath?: string) => {
382
+ const params = new URLSearchParams();
383
+ params.set('path', filePath);
384
+ if (basePath) {
385
+ params.set('basePath', basePath);
386
+ }
387
+ return this.fsClient.get(`/api/fs/exists?${params.toString()}`);
388
+ },
389
+
390
+ stat: async (filePath: string, basePath?: string) => {
391
+ const params = new URLSearchParams();
392
+ params.set('path', filePath);
393
+ if (basePath) {
394
+ params.set('basePath', basePath);
395
+ }
396
+ return this.fsClient.get(`/api/fs/stat?${params.toString()}`);
397
+ },
398
+ };
399
+
400
+ // ==================== Terraform Operations ====================
401
+
402
+ terraform = {
403
+ init: async (
404
+ workingDir?: string,
405
+ options?: { backend?: boolean; upgrade?: boolean; reconfigure?: boolean }
406
+ ) => {
407
+ return this.terraformClient.post('/api/terraform/init', { workingDir, ...options });
408
+ },
409
+
410
+ plan: async (options?: {
411
+ workingDir?: string;
412
+ out?: string;
413
+ vars?: Record<string, string>;
414
+ varFiles?: string[];
415
+ target?: string[];
416
+ destroy?: boolean;
417
+ }) => {
418
+ return this.terraformClient.post('/api/terraform/plan', options);
419
+ },
420
+
421
+ apply: async (options?: {
422
+ workingDir?: string;
423
+ planFile?: string;
424
+ vars?: Record<string, string>;
425
+ varFiles?: string[];
426
+ target?: string[];
427
+ autoApprove?: boolean;
428
+ }) => {
429
+ return this.terraformClient.post('/api/terraform/apply', options);
430
+ },
431
+
432
+ destroy: async (options?: {
433
+ workingDir?: string;
434
+ vars?: Record<string, string>;
435
+ varFiles?: string[];
436
+ target?: string[];
437
+ autoApprove?: boolean;
438
+ }) => {
439
+ return this.terraformClient.post('/api/terraform/destroy', options);
440
+ },
441
+
442
+ output: async (workingDir?: string, name?: string) => {
443
+ const params = new URLSearchParams();
444
+ if (workingDir) {
445
+ params.set('workingDir', workingDir);
446
+ }
447
+ if (name) {
448
+ params.set('name', name);
449
+ }
450
+ const query = params.toString() ? `?${params.toString()}` : '';
451
+ return this.terraformClient.get(`/api/terraform/output${query}`);
452
+ },
453
+
454
+ show: async (options?: { workingDir?: string; planFile?: string; address?: string }) => {
455
+ const params = new URLSearchParams();
456
+ if (options?.workingDir) {
457
+ params.set('workingDir', options.workingDir);
458
+ }
459
+ if (options?.planFile) {
460
+ params.set('planFile', options.planFile);
461
+ }
462
+ if (options?.address) {
463
+ params.set('address', options.address);
464
+ }
465
+ const query = params.toString() ? `?${params.toString()}` : '';
466
+ return this.terraformClient.get(`/api/terraform/show${query}`);
467
+ },
468
+
469
+ validate: async (workingDir?: string) => {
470
+ return this.terraformClient.post('/api/terraform/validate', { workingDir });
471
+ },
472
+
473
+ fmt: async (options?: {
474
+ workingDir?: string;
475
+ check?: boolean;
476
+ recursive?: boolean;
477
+ diff?: boolean;
478
+ }) => {
479
+ return this.terraformClient.post('/api/terraform/fmt', options);
480
+ },
481
+
482
+ workspace: {
483
+ list: async (workingDir?: string) => {
484
+ const params = new URLSearchParams();
485
+ if (workingDir) {
486
+ params.set('workingDir', workingDir);
487
+ }
488
+ const query = params.toString() ? `?${params.toString()}` : '';
489
+ return this.terraformClient.get(`/api/terraform/workspace/list${query}`);
490
+ },
491
+ select: async (name: string, workingDir?: string) => {
492
+ return this.terraformClient.post('/api/terraform/workspace/select', { name, workingDir });
493
+ },
494
+ new: async (name: string, workingDir?: string) => {
495
+ return this.terraformClient.post('/api/terraform/workspace/new', { name, workingDir });
496
+ },
497
+ delete: async (name: string, workingDir?: string) => {
498
+ return this.terraformClient.post('/api/terraform/workspace/delete', { name, workingDir });
499
+ },
500
+ },
501
+
502
+ state: {
503
+ list: async (workingDir?: string) => {
504
+ const params = new URLSearchParams();
505
+ if (workingDir) {
506
+ params.set('workingDir', workingDir);
507
+ }
508
+ const query = params.toString() ? `?${params.toString()}` : '';
509
+ return this.terraformClient.get(`/api/terraform/state/list${query}`);
510
+ },
511
+ show: async (address: string, workingDir?: string) => {
512
+ const params = new URLSearchParams();
513
+ params.set('address', address);
514
+ if (workingDir) {
515
+ params.set('workingDir', workingDir);
516
+ }
517
+ return this.terraformClient.get(`/api/terraform/state/show?${params.toString()}`);
518
+ },
519
+ mv: async (directory: string, source: string, destination: string) => {
520
+ return this.terraformClient.post('/api/terraform/state/mv', {
521
+ directory,
522
+ source,
523
+ destination,
524
+ });
525
+ },
526
+ pull: async (directory: string) => {
527
+ const params = new URLSearchParams();
528
+ params.set('directory', directory);
529
+ return this.terraformClient.get(`/api/terraform/state/pull?${params.toString()}`);
530
+ },
531
+ push: async (directory: string, options?: { stateFile?: string; force?: boolean }) => {
532
+ return this.terraformClient.post('/api/terraform/state/push', { directory, ...options });
533
+ },
534
+ },
535
+
536
+ taint: async (directory: string, address: string) => {
537
+ return this.terraformClient.post('/api/terraform/taint', { directory, address });
538
+ },
539
+
540
+ untaint: async (directory: string, address: string) => {
541
+ return this.terraformClient.post('/api/terraform/untaint', { directory, address });
542
+ },
543
+
544
+ graph: async (directory: string, options?: { type?: 'plan' | 'apply' }) => {
545
+ const params = new URLSearchParams();
546
+ params.set('directory', directory);
547
+ if (options?.type) {
548
+ params.set('type', options.type);
549
+ }
550
+ return this.terraformClient.get(`/api/terraform/graph?${params.toString()}`);
551
+ },
552
+
553
+ forceUnlock: async (directory: string, lockId: string) => {
554
+ return this.terraformClient.post('/api/terraform/force-unlock', { directory, lockId });
555
+ },
556
+
557
+ refresh: async (directory: string, options?: { varFile?: string }) => {
558
+ return this.terraformClient.post('/api/terraform/refresh', { directory, ...options });
559
+ },
560
+ };
561
+
562
+ // ==================== Kubernetes Operations ====================
563
+
564
+ k8s = {
565
+ get: async (
566
+ resource: string,
567
+ options?: {
568
+ name?: string;
569
+ namespace?: string;
570
+ selector?: string;
571
+ allNamespaces?: boolean;
572
+ output?: 'json' | 'yaml' | 'wide' | 'name';
573
+ kubeconfig?: string;
574
+ context?: string;
575
+ }
576
+ ) => {
577
+ const params = new URLSearchParams();
578
+ params.set('resource', resource);
579
+ if (options?.name) {
580
+ params.set('name', options.name);
581
+ }
582
+ if (options?.namespace) {
583
+ params.set('namespace', options.namespace);
584
+ }
585
+ if (options?.selector) {
586
+ params.set('selector', options.selector);
587
+ }
588
+ if (options?.allNamespaces) {
589
+ params.set('allNamespaces', 'true');
590
+ }
591
+ if (options?.output) {
592
+ params.set('output', options.output);
593
+ }
594
+ if (options?.kubeconfig) {
595
+ params.set('kubeconfig', options.kubeconfig);
596
+ }
597
+ if (options?.context) {
598
+ params.set('context', options.context);
599
+ }
600
+ return this.k8sClient.get(`/api/k8s/resources?${params.toString()}`);
601
+ },
602
+
603
+ apply: async (
604
+ manifest: string,
605
+ options?: {
606
+ namespace?: string;
607
+ dryRun?: boolean;
608
+ force?: boolean;
609
+ serverSide?: boolean;
610
+ kubeconfig?: string;
611
+ context?: string;
612
+ }
613
+ ) => {
614
+ return this.k8sClient.post('/api/k8s/apply', { manifest, ...options });
615
+ },
616
+
617
+ delete: async (
618
+ resource: string,
619
+ options?: {
620
+ name?: string;
621
+ namespace?: string;
622
+ selector?: string;
623
+ force?: boolean;
624
+ gracePeriod?: number;
625
+ kubeconfig?: string;
626
+ context?: string;
627
+ }
628
+ ) => {
629
+ return this.k8sClient.post('/api/k8s/delete', { resource, ...options });
630
+ },
631
+
632
+ logs: async (
633
+ pod: string,
634
+ options?: {
635
+ namespace?: string;
636
+ container?: string;
637
+ tail?: number;
638
+ previous?: boolean;
639
+ since?: string;
640
+ timestamps?: boolean;
641
+ kubeconfig?: string;
642
+ context?: string;
643
+ }
644
+ ) => {
645
+ const params = new URLSearchParams();
646
+ params.set('pod', pod);
647
+ if (options?.namespace) {
648
+ params.set('namespace', options.namespace);
649
+ }
650
+ if (options?.container) {
651
+ params.set('container', options.container);
652
+ }
653
+ if (options?.tail) {
654
+ params.set('tail', options.tail.toString());
655
+ }
656
+ if (options?.previous) {
657
+ params.set('previous', 'true');
658
+ }
659
+ if (options?.since) {
660
+ params.set('since', options.since);
661
+ }
662
+ if (options?.timestamps) {
663
+ params.set('timestamps', 'true');
664
+ }
665
+ if (options?.kubeconfig) {
666
+ params.set('kubeconfig', options.kubeconfig);
667
+ }
668
+ if (options?.context) {
669
+ params.set('context', options.context);
670
+ }
671
+ return this.k8sClient.get(`/api/k8s/logs?${params.toString()}`);
672
+ },
673
+
674
+ exec: async (
675
+ pod: string,
676
+ command: string[],
677
+ options?: { namespace?: string; container?: string; kubeconfig?: string; context?: string }
678
+ ) => {
679
+ return this.k8sClient.post('/api/k8s/exec', { pod, command, ...options });
680
+ },
681
+
682
+ describe: async (
683
+ resource: string,
684
+ options?: {
685
+ name?: string;
686
+ namespace?: string;
687
+ selector?: string;
688
+ allNamespaces?: boolean;
689
+ kubeconfig?: string;
690
+ context?: string;
691
+ }
692
+ ) => {
693
+ const params = new URLSearchParams();
694
+ params.set('resource', resource);
695
+ if (options?.name) {
696
+ params.set('name', options.name);
697
+ }
698
+ if (options?.namespace) {
699
+ params.set('namespace', options.namespace);
700
+ }
701
+ if (options?.selector) {
702
+ params.set('selector', options.selector);
703
+ }
704
+ if (options?.allNamespaces) {
705
+ params.set('allNamespaces', 'true');
706
+ }
707
+ if (options?.kubeconfig) {
708
+ params.set('kubeconfig', options.kubeconfig);
709
+ }
710
+ if (options?.context) {
711
+ params.set('context', options.context);
712
+ }
713
+ return this.k8sClient.get(`/api/k8s/describe?${params.toString()}`);
714
+ },
715
+
716
+ scale: async (
717
+ resource: string,
718
+ name: string,
719
+ replicas: number,
720
+ options?: { namespace?: string; kubeconfig?: string; context?: string }
721
+ ) => {
722
+ return this.k8sClient.post('/api/k8s/scale', { resource, name, replicas, ...options });
723
+ },
724
+
725
+ rollout: async (
726
+ resource: string,
727
+ name: string,
728
+ action: 'status' | 'history' | 'restart' | 'undo' | 'pause' | 'resume',
729
+ options?: { namespace?: string; revision?: number; kubeconfig?: string; context?: string }
730
+ ) => {
731
+ return this.k8sClient.post('/api/k8s/rollout', { resource, name, action, ...options });
732
+ },
733
+
734
+ contexts: async (kubeconfig?: string) => {
735
+ const params = new URLSearchParams();
736
+ if (kubeconfig) {
737
+ params.set('kubeconfig', kubeconfig);
738
+ }
739
+ const query = params.toString() ? `?${params.toString()}` : '';
740
+ return this.k8sClient.get(`/api/k8s/contexts${query}`);
741
+ },
742
+
743
+ namespaces: async (kubeconfig?: string, context?: string) => {
744
+ const params = new URLSearchParams();
745
+ if (kubeconfig) {
746
+ params.set('kubeconfig', kubeconfig);
747
+ }
748
+ if (context) {
749
+ params.set('context', context);
750
+ }
751
+ const query = params.toString() ? `?${params.toString()}` : '';
752
+ return this.k8sClient.get(`/api/k8s/namespaces${query}`);
753
+ },
754
+
755
+ createNamespace: async (name: string, options?: { kubeconfig?: string; context?: string }) => {
756
+ return this.k8sClient.post('/api/k8s/namespace', { name, ...options });
757
+ },
758
+
759
+ deleteNamespace: async (name: string, options?: { kubeconfig?: string; context?: string }) => {
760
+ return this.k8sClient.post('/api/k8s/namespace/delete', { name, ...options });
761
+ },
762
+
763
+ portForward: async (
764
+ pod: string,
765
+ ports: string,
766
+ options?: { namespace?: string; kubeconfig?: string; context?: string }
767
+ ) => {
768
+ return this.k8sClient.post('/api/k8s/port-forward', { pod, ports, ...options });
769
+ },
770
+
771
+ top: async (
772
+ resourceType: 'pods' | 'nodes',
773
+ options?: { namespace?: string; kubeconfig?: string; context?: string }
774
+ ) => {
775
+ const params = new URLSearchParams();
776
+ if (options?.namespace) {
777
+ params.set('namespace', options.namespace);
778
+ }
779
+ if (options?.kubeconfig) {
780
+ params.set('kubeconfig', options.kubeconfig);
781
+ }
782
+ if (options?.context) {
783
+ params.set('context', options.context);
784
+ }
785
+ const query = params.toString() ? `?${params.toString()}` : '';
786
+ return this.k8sClient.get(`/api/k8s/top/${resourceType}${query}`);
787
+ },
788
+
789
+ patch: async (
790
+ resource: string,
791
+ name: string,
792
+ patch: string,
793
+ options?: {
794
+ namespace?: string;
795
+ type?: 'strategic' | 'merge' | 'json';
796
+ kubeconfig?: string;
797
+ context?: string;
798
+ }
799
+ ) => {
800
+ return this.k8sClient.post('/api/k8s/patch', { resource, name, patch, ...options });
801
+ },
802
+
803
+ label: async (
804
+ resource: string,
805
+ name: string,
806
+ labels: Record<string, string>,
807
+ options?: { namespace?: string; overwrite?: boolean; kubeconfig?: string; context?: string }
808
+ ) => {
809
+ return this.k8sClient.post('/api/k8s/label', { resource, name, labels, ...options });
810
+ },
811
+
812
+ annotate: async (
813
+ resource: string,
814
+ name: string,
815
+ annotations: Record<string, string>,
816
+ options?: { namespace?: string; overwrite?: boolean; kubeconfig?: string; context?: string }
817
+ ) => {
818
+ return this.k8sClient.post('/api/k8s/annotate', { resource, name, annotations, ...options });
819
+ },
820
+ };
821
+
822
+ // ==================== Helm Operations ====================
823
+
824
+ helm = {
825
+ install: async (
826
+ name: string,
827
+ chart: string,
828
+ options?: {
829
+ namespace?: string;
830
+ values?: string;
831
+ valuesFiles?: string[];
832
+ set?: Record<string, string>;
833
+ version?: string;
834
+ createNamespace?: boolean;
835
+ dryRun?: boolean;
836
+ wait?: boolean;
837
+ timeout?: string;
838
+ atomic?: boolean;
839
+ kubeconfig?: string;
840
+ kubeContext?: string;
841
+ }
842
+ ) => {
843
+ return this.helmClient.post('/api/helm/install', { name, chart, ...options });
844
+ },
845
+
846
+ upgrade: async (
847
+ name: string,
848
+ chart: string,
849
+ options?: {
850
+ namespace?: string;
851
+ values?: string;
852
+ valuesFiles?: string[];
853
+ set?: Record<string, string>;
854
+ version?: string;
855
+ install?: boolean;
856
+ createNamespace?: boolean;
857
+ dryRun?: boolean;
858
+ wait?: boolean;
859
+ timeout?: string;
860
+ atomic?: boolean;
861
+ reuseValues?: boolean;
862
+ kubeconfig?: string;
863
+ kubeContext?: string;
864
+ }
865
+ ) => {
866
+ return this.helmClient.post('/api/helm/upgrade', { name, chart, ...options });
867
+ },
868
+
869
+ uninstall: async (
870
+ name: string,
871
+ options?: {
872
+ namespace?: string;
873
+ keepHistory?: boolean;
874
+ dryRun?: boolean;
875
+ wait?: boolean;
876
+ timeout?: string;
877
+ kubeconfig?: string;
878
+ kubeContext?: string;
879
+ }
880
+ ) => {
881
+ return this.helmClient.post('/api/helm/uninstall', { name, ...options });
882
+ },
883
+
884
+ list: async (options?: {
885
+ namespace?: string;
886
+ allNamespaces?: boolean;
887
+ filter?: string;
888
+ maxResults?: number;
889
+ kubeconfig?: string;
890
+ kubeContext?: string;
891
+ }) => {
892
+ const params = new URLSearchParams();
893
+ if (options?.namespace) {
894
+ params.set('namespace', options.namespace);
895
+ }
896
+ if (options?.allNamespaces) {
897
+ params.set('allNamespaces', 'true');
898
+ }
899
+ if (options?.filter) {
900
+ params.set('filter', options.filter);
901
+ }
902
+ if (options?.maxResults) {
903
+ params.set('maxResults', options.maxResults.toString());
904
+ }
905
+ if (options?.kubeconfig) {
906
+ params.set('kubeconfig', options.kubeconfig);
907
+ }
908
+ if (options?.kubeContext) {
909
+ params.set('kubeContext', options.kubeContext);
910
+ }
911
+ const query = params.toString() ? `?${params.toString()}` : '';
912
+ return this.helmClient.get(`/api/helm/list${query}`);
913
+ },
914
+
915
+ rollback: async (
916
+ name: string,
917
+ revision: number,
918
+ options?: {
919
+ namespace?: string;
920
+ dryRun?: boolean;
921
+ wait?: boolean;
922
+ timeout?: string;
923
+ force?: boolean;
924
+ kubeconfig?: string;
925
+ kubeContext?: string;
926
+ }
927
+ ) => {
928
+ return this.helmClient.post('/api/helm/rollback', { name, revision, ...options });
929
+ },
930
+
931
+ getValues: async (
932
+ name: string,
933
+ options?: {
934
+ namespace?: string;
935
+ allValues?: boolean;
936
+ revision?: number;
937
+ kubeconfig?: string;
938
+ kubeContext?: string;
939
+ }
940
+ ) => {
941
+ const params = new URLSearchParams();
942
+ params.set('name', name);
943
+ if (options?.namespace) {
944
+ params.set('namespace', options.namespace);
945
+ }
946
+ if (options?.allValues) {
947
+ params.set('allValues', 'true');
948
+ }
949
+ if (options?.revision) {
950
+ params.set('revision', options.revision.toString());
951
+ }
952
+ if (options?.kubeconfig) {
953
+ params.set('kubeconfig', options.kubeconfig);
954
+ }
955
+ if (options?.kubeContext) {
956
+ params.set('kubeContext', options.kubeContext);
957
+ }
958
+ return this.helmClient.get(`/api/helm/values?${params.toString()}`);
959
+ },
960
+
961
+ history: async (
962
+ name: string,
963
+ options?: {
964
+ namespace?: string;
965
+ maxResults?: number;
966
+ kubeconfig?: string;
967
+ kubeContext?: string;
968
+ }
969
+ ) => {
970
+ const params = new URLSearchParams();
971
+ params.set('name', name);
972
+ if (options?.namespace) {
973
+ params.set('namespace', options.namespace);
974
+ }
975
+ if (options?.maxResults) {
976
+ params.set('maxResults', options.maxResults.toString());
977
+ }
978
+ if (options?.kubeconfig) {
979
+ params.set('kubeconfig', options.kubeconfig);
980
+ }
981
+ if (options?.kubeContext) {
982
+ params.set('kubeContext', options.kubeContext);
983
+ }
984
+ return this.helmClient.get(`/api/helm/history?${params.toString()}`);
985
+ },
986
+
987
+ repo: {
988
+ add: async (
989
+ name: string,
990
+ url: string,
991
+ options?: {
992
+ username?: string;
993
+ password?: string;
994
+ kubeconfig?: string;
995
+ kubeContext?: string;
996
+ }
997
+ ) => {
998
+ return this.helmClient.post('/api/helm/repo', { action: 'add', name, url, ...options });
999
+ },
1000
+ remove: async (name: string) => {
1001
+ return this.helmClient.post('/api/helm/repo', { action: 'remove', name });
1002
+ },
1003
+ list: async () => {
1004
+ return this.helmClient.post('/api/helm/repo', { action: 'list' });
1005
+ },
1006
+ update: async () => {
1007
+ return this.helmClient.post('/api/helm/repo', { action: 'update' });
1008
+ },
1009
+ },
1010
+
1011
+ search: async (
1012
+ keyword: string,
1013
+ options?: {
1014
+ version?: string;
1015
+ versions?: boolean;
1016
+ hub?: boolean;
1017
+ maxResults?: number;
1018
+ kubeconfig?: string;
1019
+ kubeContext?: string;
1020
+ }
1021
+ ) => {
1022
+ const params = new URLSearchParams();
1023
+ params.set('keyword', keyword);
1024
+ if (options?.version) {
1025
+ params.set('version', options.version);
1026
+ }
1027
+ if (options?.versions) {
1028
+ params.set('versions', 'true');
1029
+ }
1030
+ if (options?.hub) {
1031
+ params.set('hub', 'true');
1032
+ }
1033
+ if (options?.maxResults) {
1034
+ params.set('maxResults', options.maxResults.toString());
1035
+ }
1036
+ if (options?.kubeconfig) {
1037
+ params.set('kubeconfig', options.kubeconfig);
1038
+ }
1039
+ if (options?.kubeContext) {
1040
+ params.set('kubeContext', options.kubeContext);
1041
+ }
1042
+ return this.helmClient.get(`/api/helm/search?${params.toString()}`);
1043
+ },
1044
+
1045
+ template: async (
1046
+ name: string,
1047
+ chart: string,
1048
+ options?: {
1049
+ namespace?: string;
1050
+ values?: string;
1051
+ valuesFiles?: string[];
1052
+ set?: Record<string, string>;
1053
+ version?: string;
1054
+ kubeconfig?: string;
1055
+ kubeContext?: string;
1056
+ }
1057
+ ) => {
1058
+ return this.helmClient.post('/api/helm/template', { name, chart, ...options });
1059
+ },
1060
+
1061
+ show: async (
1062
+ chart: string,
1063
+ options?: { subcommand?: 'all' | 'chart' | 'readme' | 'values' | 'crds'; version?: string }
1064
+ ) => {
1065
+ const params = new URLSearchParams();
1066
+ params.set('chart', chart);
1067
+ if (options?.subcommand) {
1068
+ params.set('subcommand', options.subcommand);
1069
+ }
1070
+ if (options?.version) {
1071
+ params.set('version', options.version);
1072
+ }
1073
+ return this.helmClient.get(`/api/helm/show?${params.toString()}`);
1074
+ },
1075
+
1076
+ lint: async (
1077
+ chartPath: string,
1078
+ options?: { strict?: boolean; valuesFiles?: string[]; namespace?: string }
1079
+ ) => {
1080
+ return this.helmClient.post('/api/helm/lint', { chartPath, ...options });
1081
+ },
1082
+ };
1083
+
1084
+ // ==================== GitHub Operations ====================
1085
+
1086
+ github = {
1087
+ /**
1088
+ * Set authorization token for GitHub API requests
1089
+ */
1090
+ setToken: (token: string) => {
1091
+ this.githubClient = new RestClient(ServiceURLs.GITHUB_TOOLS, {
1092
+ headers: { Authorization: `Bearer ${token}` },
1093
+ });
1094
+ },
1095
+
1096
+ // Pull Request Operations
1097
+ prs: {
1098
+ list: async (
1099
+ owner: string,
1100
+ repo: string,
1101
+ options?: { state?: 'open' | 'closed' | 'all'; perPage?: number }
1102
+ ) => {
1103
+ const params = new URLSearchParams();
1104
+ params.set('owner', owner);
1105
+ params.set('repo', repo);
1106
+ if (options?.state) {
1107
+ params.set('state', options.state);
1108
+ }
1109
+ if (options?.perPage) {
1110
+ params.set('per_page', options.perPage.toString());
1111
+ }
1112
+ return this.githubClient.get(`/api/github/prs?${params.toString()}`);
1113
+ },
1114
+
1115
+ get: async (owner: string, repo: string, prNumber: number) => {
1116
+ const params = new URLSearchParams();
1117
+ params.set('owner', owner);
1118
+ params.set('repo', repo);
1119
+ return this.githubClient.get(`/api/github/prs/${prNumber}?${params.toString()}`);
1120
+ },
1121
+
1122
+ create: async (
1123
+ owner: string,
1124
+ repo: string,
1125
+ params: { title: string; head: string; base: string; body?: string; draft?: boolean }
1126
+ ) => {
1127
+ return this.githubClient.post('/api/github/prs', { owner, repo, ...params });
1128
+ },
1129
+
1130
+ merge: async (
1131
+ owner: string,
1132
+ repo: string,
1133
+ prNumber: number,
1134
+ options?: {
1135
+ commitTitle?: string;
1136
+ commitMessage?: string;
1137
+ mergeMethod?: 'merge' | 'squash' | 'rebase';
1138
+ }
1139
+ ) => {
1140
+ return this.githubClient.post(`/api/github/prs/${prNumber}/merge`, {
1141
+ owner,
1142
+ repo,
1143
+ commit_title: options?.commitTitle,
1144
+ commit_message: options?.commitMessage,
1145
+ merge_method: options?.mergeMethod,
1146
+ });
1147
+ },
1148
+ },
1149
+
1150
+ // Issue Operations
1151
+ issues: {
1152
+ list: async (
1153
+ owner: string,
1154
+ repo: string,
1155
+ options?: { state?: 'open' | 'closed' | 'all'; perPage?: number }
1156
+ ) => {
1157
+ const params = new URLSearchParams();
1158
+ params.set('owner', owner);
1159
+ params.set('repo', repo);
1160
+ if (options?.state) {
1161
+ params.set('state', options.state);
1162
+ }
1163
+ if (options?.perPage) {
1164
+ params.set('per_page', options.perPage.toString());
1165
+ }
1166
+ return this.githubClient.get(`/api/github/issues?${params.toString()}`);
1167
+ },
1168
+
1169
+ get: async (owner: string, repo: string, issueNumber: number) => {
1170
+ const params = new URLSearchParams();
1171
+ params.set('owner', owner);
1172
+ params.set('repo', repo);
1173
+ return this.githubClient.get(`/api/github/issues/${issueNumber}?${params.toString()}`);
1174
+ },
1175
+
1176
+ create: async (
1177
+ owner: string,
1178
+ repo: string,
1179
+ params: { title: string; body?: string; labels?: string[]; assignees?: string[] }
1180
+ ) => {
1181
+ return this.githubClient.post('/api/github/issues', { owner, repo, ...params });
1182
+ },
1183
+
1184
+ close: async (owner: string, repo: string, issueNumber: number) => {
1185
+ const params = new URLSearchParams();
1186
+ params.set('owner', owner);
1187
+ params.set('repo', repo);
1188
+ return this.githubClient.put(
1189
+ `/api/github/issues/${issueNumber}/close?${params.toString()}`,
1190
+ {}
1191
+ );
1192
+ },
1193
+
1194
+ addComment: async (owner: string, repo: string, issueNumber: number, body: string) => {
1195
+ return this.githubClient.post(`/api/github/issues/${issueNumber}/comments`, {
1196
+ owner,
1197
+ repo,
1198
+ body,
1199
+ });
1200
+ },
1201
+ },
1202
+
1203
+ // Repository Operations
1204
+ repos: {
1205
+ get: async (owner: string, repo: string) => {
1206
+ const params = new URLSearchParams();
1207
+ params.set('owner', owner);
1208
+ params.set('repo', repo);
1209
+ return this.githubClient.get(`/api/github/repos?${params.toString()}`);
1210
+ },
1211
+
1212
+ listBranches: async (owner: string, repo: string, options?: { perPage?: number }) => {
1213
+ const params = new URLSearchParams();
1214
+ params.set('owner', owner);
1215
+ params.set('repo', repo);
1216
+ if (options?.perPage) {
1217
+ params.set('per_page', options.perPage.toString());
1218
+ }
1219
+ return this.githubClient.get(`/api/github/repos/branches?${params.toString()}`);
1220
+ },
1221
+
1222
+ createBranch: async (owner: string, repo: string, branch: string, sha: string) => {
1223
+ return this.githubClient.post('/api/github/repos/branches', { owner, repo, branch, sha });
1224
+ },
1225
+
1226
+ deleteBranch: async (owner: string, repo: string, branch: string) => {
1227
+ const params = new URLSearchParams();
1228
+ params.set('owner', owner);
1229
+ params.set('repo', repo);
1230
+ params.set('branch', branch);
1231
+ return this.githubClient.delete(`/api/github/repos/branches?${params.toString()}`);
1232
+ },
1233
+ },
1234
+
1235
+ // User Operations
1236
+ user: {
1237
+ get: async () => {
1238
+ return this.githubClient.get('/api/github/user');
1239
+ },
1240
+ },
1241
+ };
1242
+
1243
+ // ==================== AWS Operations ====================
1244
+
1245
+ aws = {
1246
+ ec2: {
1247
+ listInstances: async (options?: {
1248
+ instanceIds?: string[];
1249
+ maxResults?: number;
1250
+ nextToken?: string;
1251
+ region?: string;
1252
+ }) => {
1253
+ const params = new URLSearchParams();
1254
+ if (options?.instanceIds) {
1255
+ params.set('instanceIds', options.instanceIds.join(','));
1256
+ }
1257
+ if (options?.maxResults) {
1258
+ params.set('maxResults', options.maxResults.toString());
1259
+ }
1260
+ if (options?.nextToken) {
1261
+ params.set('nextToken', options.nextToken);
1262
+ }
1263
+ if (options?.region) {
1264
+ params.set('region', options.region);
1265
+ }
1266
+ const query = params.toString() ? `?${params.toString()}` : '';
1267
+ return this.awsClient.get(`/api/aws/ec2/instances${query}`);
1268
+ },
1269
+
1270
+ startInstances: async (instanceIds: string[], region?: string) => {
1271
+ return this.awsClient.post('/api/aws/ec2/instances/start', { instanceIds, region });
1272
+ },
1273
+
1274
+ stopInstances: async (
1275
+ instanceIds: string[],
1276
+ options?: { force?: boolean; region?: string }
1277
+ ) => {
1278
+ return this.awsClient.post('/api/aws/ec2/instances/stop', { instanceIds, ...options });
1279
+ },
1280
+
1281
+ rebootInstances: async (instanceIds: string[], region?: string) => {
1282
+ return this.awsClient.post('/api/aws/ec2/instances/reboot', { instanceIds, region });
1283
+ },
1284
+
1285
+ terminateInstances: async (instanceIds: string[], region?: string) => {
1286
+ return this.awsClient.post('/api/aws/ec2/instances/terminate', { instanceIds, region });
1287
+ },
1288
+
1289
+ runInstances: async (
1290
+ imageId: string,
1291
+ instanceType: string,
1292
+ options?: {
1293
+ minCount?: number;
1294
+ maxCount?: number;
1295
+ keyName?: string;
1296
+ securityGroupIds?: string[];
1297
+ subnetId?: string;
1298
+ userData?: string;
1299
+ tags?: Record<string, string>;
1300
+ region?: string;
1301
+ }
1302
+ ) => {
1303
+ return this.awsClient.post('/api/aws/ec2/instances/run', {
1304
+ imageId,
1305
+ instanceType,
1306
+ ...options,
1307
+ });
1308
+ },
1309
+
1310
+ listRegions: async (region?: string) => {
1311
+ const query = region ? `?region=${encodeURIComponent(region)}` : '';
1312
+ return this.awsClient.get(`/api/aws/ec2/regions${query}`);
1313
+ },
1314
+
1315
+ listVpcs: async (region?: string) => {
1316
+ const query = region ? `?region=${encodeURIComponent(region)}` : '';
1317
+ return this.awsClient.get(`/api/aws/ec2/vpcs${query}`);
1318
+ },
1319
+
1320
+ listSubnets: async (options?: { vpcId?: string; region?: string }) => {
1321
+ const params = new URLSearchParams();
1322
+ if (options?.vpcId) {
1323
+ params.set('vpcId', options.vpcId);
1324
+ }
1325
+ if (options?.region) {
1326
+ params.set('region', options.region);
1327
+ }
1328
+ const query = params.toString() ? `?${params.toString()}` : '';
1329
+ return this.awsClient.get(`/api/aws/ec2/subnets${query}`);
1330
+ },
1331
+
1332
+ listSecurityGroups: async (options?: { vpcId?: string; region?: string }) => {
1333
+ const params = new URLSearchParams();
1334
+ if (options?.vpcId) {
1335
+ params.set('vpcId', options.vpcId);
1336
+ }
1337
+ if (options?.region) {
1338
+ params.set('region', options.region);
1339
+ }
1340
+ const query = params.toString() ? `?${params.toString()}` : '';
1341
+ return this.awsClient.get(`/api/aws/ec2/security-groups${query}`);
1342
+ },
1343
+ },
1344
+
1345
+ s3: {
1346
+ listBuckets: async (region?: string) => {
1347
+ const query = region ? `?region=${encodeURIComponent(region)}` : '';
1348
+ return this.awsClient.get(`/api/aws/s3/buckets${query}`);
1349
+ },
1350
+
1351
+ listObjects: async (
1352
+ bucket: string,
1353
+ options?: {
1354
+ prefix?: string;
1355
+ delimiter?: string;
1356
+ maxKeys?: number;
1357
+ continuationToken?: string;
1358
+ region?: string;
1359
+ }
1360
+ ) => {
1361
+ const params = new URLSearchParams();
1362
+ params.set('bucket', bucket);
1363
+ if (options?.prefix) {
1364
+ params.set('prefix', options.prefix);
1365
+ }
1366
+ if (options?.delimiter) {
1367
+ params.set('delimiter', options.delimiter);
1368
+ }
1369
+ if (options?.maxKeys) {
1370
+ params.set('maxKeys', options.maxKeys.toString());
1371
+ }
1372
+ if (options?.continuationToken) {
1373
+ params.set('continuationToken', options.continuationToken);
1374
+ }
1375
+ if (options?.region) {
1376
+ params.set('region', options.region);
1377
+ }
1378
+ return this.awsClient.get(`/api/aws/s3/objects?${params.toString()}`);
1379
+ },
1380
+
1381
+ getObject: async (bucket: string, key: string, region?: string) => {
1382
+ const params = new URLSearchParams();
1383
+ params.set('bucket', bucket);
1384
+ params.set('key', key);
1385
+ if (region) {
1386
+ params.set('region', region);
1387
+ }
1388
+ return this.awsClient.get(`/api/aws/s3/object?${params.toString()}`);
1389
+ },
1390
+
1391
+ putObject: async (
1392
+ bucket: string,
1393
+ key: string,
1394
+ body: string,
1395
+ options?: {
1396
+ contentType?: string;
1397
+ metadata?: Record<string, string>;
1398
+ tags?: Record<string, string>;
1399
+ region?: string;
1400
+ }
1401
+ ) => {
1402
+ return this.awsClient.post('/api/aws/s3/object', { bucket, key, body, ...options });
1403
+ },
1404
+
1405
+ deleteObject: async (bucket: string, key: string, region?: string) => {
1406
+ const params = new URLSearchParams();
1407
+ params.set('bucket', bucket);
1408
+ params.set('key', key);
1409
+ if (region) {
1410
+ params.set('region', region);
1411
+ }
1412
+ return this.awsClient.delete(`/api/aws/s3/object?${params.toString()}`);
1413
+ },
1414
+
1415
+ createBucket: async (bucket: string, region?: string) => {
1416
+ return this.awsClient.post('/api/aws/s3/bucket', { bucket, region });
1417
+ },
1418
+
1419
+ deleteBucket: async (bucket: string, region?: string) => {
1420
+ const params = new URLSearchParams();
1421
+ params.set('bucket', bucket);
1422
+ if (region) {
1423
+ params.set('region', region);
1424
+ }
1425
+ return this.awsClient.delete(`/api/aws/s3/bucket?${params.toString()}`);
1426
+ },
1427
+ },
1428
+
1429
+ iam: {
1430
+ listUsers: async (options?: {
1431
+ maxItems?: number;
1432
+ marker?: string;
1433
+ pathPrefix?: string;
1434
+ region?: string;
1435
+ }) => {
1436
+ const params = new URLSearchParams();
1437
+ if (options?.maxItems) {
1438
+ params.set('maxItems', options.maxItems.toString());
1439
+ }
1440
+ if (options?.marker) {
1441
+ params.set('marker', options.marker);
1442
+ }
1443
+ if (options?.pathPrefix) {
1444
+ params.set('pathPrefix', options.pathPrefix);
1445
+ }
1446
+ if (options?.region) {
1447
+ params.set('region', options.region);
1448
+ }
1449
+ const query = params.toString() ? `?${params.toString()}` : '';
1450
+ return this.awsClient.get(`/api/aws/iam/users${query}`);
1451
+ },
1452
+
1453
+ getUser: async (userName: string, region?: string) => {
1454
+ const params = new URLSearchParams();
1455
+ params.set('userName', userName);
1456
+ if (region) {
1457
+ params.set('region', region);
1458
+ }
1459
+ return this.awsClient.get(`/api/aws/iam/user?${params.toString()}`);
1460
+ },
1461
+
1462
+ createUser: async (
1463
+ userName: string,
1464
+ options?: { path?: string; tags?: Record<string, string>; region?: string }
1465
+ ) => {
1466
+ return this.awsClient.post('/api/aws/iam/user', { userName, ...options });
1467
+ },
1468
+
1469
+ deleteUser: async (userName: string, region?: string) => {
1470
+ const params = new URLSearchParams();
1471
+ params.set('userName', userName);
1472
+ if (region) {
1473
+ params.set('region', region);
1474
+ }
1475
+ return this.awsClient.delete(`/api/aws/iam/user?${params.toString()}`);
1476
+ },
1477
+
1478
+ listRoles: async (options?: {
1479
+ maxItems?: number;
1480
+ marker?: string;
1481
+ pathPrefix?: string;
1482
+ region?: string;
1483
+ }) => {
1484
+ const params = new URLSearchParams();
1485
+ if (options?.maxItems) {
1486
+ params.set('maxItems', options.maxItems.toString());
1487
+ }
1488
+ if (options?.marker) {
1489
+ params.set('marker', options.marker);
1490
+ }
1491
+ if (options?.pathPrefix) {
1492
+ params.set('pathPrefix', options.pathPrefix);
1493
+ }
1494
+ if (options?.region) {
1495
+ params.set('region', options.region);
1496
+ }
1497
+ const query = params.toString() ? `?${params.toString()}` : '';
1498
+ return this.awsClient.get(`/api/aws/iam/roles${query}`);
1499
+ },
1500
+
1501
+ getRole: async (roleName: string, region?: string) => {
1502
+ const params = new URLSearchParams();
1503
+ params.set('roleName', roleName);
1504
+ if (region) {
1505
+ params.set('region', region);
1506
+ }
1507
+ return this.awsClient.get(`/api/aws/iam/role?${params.toString()}`);
1508
+ },
1509
+
1510
+ listPolicies: async (options?: {
1511
+ maxItems?: number;
1512
+ marker?: string;
1513
+ scope?: 'All' | 'AWS' | 'Local';
1514
+ onlyAttached?: boolean;
1515
+ region?: string;
1516
+ }) => {
1517
+ const params = new URLSearchParams();
1518
+ if (options?.maxItems) {
1519
+ params.set('maxItems', options.maxItems.toString());
1520
+ }
1521
+ if (options?.marker) {
1522
+ params.set('marker', options.marker);
1523
+ }
1524
+ if (options?.scope) {
1525
+ params.set('scope', options.scope);
1526
+ }
1527
+ if (options?.onlyAttached) {
1528
+ params.set('onlyAttached', 'true');
1529
+ }
1530
+ if (options?.region) {
1531
+ params.set('region', options.region);
1532
+ }
1533
+ const query = params.toString() ? `?${params.toString()}` : '';
1534
+ return this.awsClient.get(`/api/aws/iam/policies${query}`);
1535
+ },
1536
+
1537
+ listGroups: async (options?: {
1538
+ maxItems?: number;
1539
+ marker?: string;
1540
+ pathPrefix?: string;
1541
+ region?: string;
1542
+ }) => {
1543
+ const params = new URLSearchParams();
1544
+ if (options?.maxItems) {
1545
+ params.set('maxItems', options.maxItems.toString());
1546
+ }
1547
+ if (options?.marker) {
1548
+ params.set('marker', options.marker);
1549
+ }
1550
+ if (options?.pathPrefix) {
1551
+ params.set('pathPrefix', options.pathPrefix);
1552
+ }
1553
+ if (options?.region) {
1554
+ params.set('region', options.region);
1555
+ }
1556
+ const query = params.toString() ? `?${params.toString()}` : '';
1557
+ return this.awsClient.get(`/api/aws/iam/groups${query}`);
1558
+ },
1559
+ },
1560
+ };
1561
+
1562
+ // ==================== GCP Operations ====================
1563
+
1564
+ gcp = {
1565
+ compute: {
1566
+ listInstances: async (options?: {
1567
+ project?: string;
1568
+ zone?: string;
1569
+ maxResults?: number;
1570
+ pageToken?: string;
1571
+ }) => {
1572
+ const params = new URLSearchParams();
1573
+ if (options?.project) {
1574
+ params.set('project', options.project);
1575
+ }
1576
+ if (options?.zone) {
1577
+ params.set('zone', options.zone);
1578
+ }
1579
+ if (options?.maxResults) {
1580
+ params.set('maxResults', options.maxResults.toString());
1581
+ }
1582
+ if (options?.pageToken) {
1583
+ params.set('pageToken', options.pageToken);
1584
+ }
1585
+ const query = params.toString() ? `?${params.toString()}` : '';
1586
+ return this.gcpClient.get(`/api/gcp/compute/instances${query}`);
1587
+ },
1588
+
1589
+ startInstance: async (instance: string, options?: { project?: string; zone?: string }) => {
1590
+ return this.gcpClient.post('/api/gcp/compute/instances/start', { instance, ...options });
1591
+ },
1592
+
1593
+ stopInstance: async (instance: string, options?: { project?: string; zone?: string }) => {
1594
+ return this.gcpClient.post('/api/gcp/compute/instances/stop', { instance, ...options });
1595
+ },
1596
+ },
1597
+
1598
+ storage: {
1599
+ listBuckets: async (options?: {
1600
+ project?: string;
1601
+ maxResults?: number;
1602
+ pageToken?: string;
1603
+ }) => {
1604
+ const params = new URLSearchParams();
1605
+ if (options?.project) {
1606
+ params.set('project', options.project);
1607
+ }
1608
+ if (options?.maxResults) {
1609
+ params.set('maxResults', options.maxResults.toString());
1610
+ }
1611
+ if (options?.pageToken) {
1612
+ params.set('pageToken', options.pageToken);
1613
+ }
1614
+ const query = params.toString() ? `?${params.toString()}` : '';
1615
+ return this.gcpClient.get(`/api/gcp/storage/buckets${query}`);
1616
+ },
1617
+ },
1618
+
1619
+ gke: {
1620
+ listClusters: async (options?: { project?: string; zone?: string }) => {
1621
+ const params = new URLSearchParams();
1622
+ if (options?.project) {
1623
+ params.set('project', options.project);
1624
+ }
1625
+ if (options?.zone) {
1626
+ params.set('zone', options.zone);
1627
+ }
1628
+ const query = params.toString() ? `?${params.toString()}` : '';
1629
+ return this.gcpClient.get(`/api/gcp/gke/clusters${query}`);
1630
+ },
1631
+ },
1632
+
1633
+ iam: {
1634
+ listServiceAccounts: async (options?: {
1635
+ project?: string;
1636
+ maxResults?: number;
1637
+ pageToken?: string;
1638
+ }) => {
1639
+ const params = new URLSearchParams();
1640
+ if (options?.project) {
1641
+ params.set('project', options.project);
1642
+ }
1643
+ if (options?.maxResults) {
1644
+ params.set('maxResults', options.maxResults.toString());
1645
+ }
1646
+ if (options?.pageToken) {
1647
+ params.set('pageToken', options.pageToken);
1648
+ }
1649
+ const query = params.toString() ? `?${params.toString()}` : '';
1650
+ return this.gcpClient.get(`/api/gcp/iam/service-accounts${query}`);
1651
+ },
1652
+
1653
+ listRoles: async (options?: {
1654
+ project?: string;
1655
+ maxResults?: number;
1656
+ pageToken?: string;
1657
+ }) => {
1658
+ const params = new URLSearchParams();
1659
+ if (options?.project) {
1660
+ params.set('project', options.project);
1661
+ }
1662
+ if (options?.maxResults) {
1663
+ params.set('maxResults', options.maxResults.toString());
1664
+ }
1665
+ if (options?.pageToken) {
1666
+ params.set('pageToken', options.pageToken);
1667
+ }
1668
+ const query = params.toString() ? `?${params.toString()}` : '';
1669
+ return this.gcpClient.get(`/api/gcp/iam/roles${query}`);
1670
+ },
1671
+ },
1672
+
1673
+ discover: {
1674
+ startDiscovery: async (options?: { project?: string; regions?: string[] }) => {
1675
+ return this.gcpClient.post('/api/gcp/discover/start', options);
1676
+ },
1677
+
1678
+ getSession: async (sessionId: string) => {
1679
+ return this.gcpClient.get(`/api/gcp/discover/session/${sessionId}`);
1680
+ },
1681
+ },
1682
+
1683
+ terraform: {
1684
+ generate: async (options?: {
1685
+ project?: string;
1686
+ resources?: string[];
1687
+ outputDir?: string;
1688
+ }) => {
1689
+ return this.gcpClient.post('/api/gcp/terraform/generate', options);
1690
+ },
1691
+ },
1692
+ };
1693
+
1694
+ // ==================== Azure Operations ====================
1695
+
1696
+ azure = {
1697
+ compute: {
1698
+ listVMs: async (options?: {
1699
+ subscriptionId?: string;
1700
+ resourceGroup?: string;
1701
+ maxResults?: number;
1702
+ }) => {
1703
+ const params = new URLSearchParams();
1704
+ if (options?.subscriptionId) {
1705
+ params.set('subscriptionId', options.subscriptionId);
1706
+ }
1707
+ if (options?.resourceGroup) {
1708
+ params.set('resourceGroup', options.resourceGroup);
1709
+ }
1710
+ if (options?.maxResults) {
1711
+ params.set('maxResults', options.maxResults.toString());
1712
+ }
1713
+ const query = params.toString() ? `?${params.toString()}` : '';
1714
+ return this.azureClient.get(`/api/azure/compute/vms${query}`);
1715
+ },
1716
+
1717
+ startVM: async (
1718
+ vmName: string,
1719
+ options?: { subscriptionId?: string; resourceGroup?: string }
1720
+ ) => {
1721
+ return this.azureClient.post('/api/azure/compute/vms/start', { vmName, ...options });
1722
+ },
1723
+
1724
+ stopVM: async (
1725
+ vmName: string,
1726
+ options?: { subscriptionId?: string; resourceGroup?: string; deallocate?: boolean }
1727
+ ) => {
1728
+ return this.azureClient.post('/api/azure/compute/vms/stop', { vmName, ...options });
1729
+ },
1730
+ },
1731
+
1732
+ storage: {
1733
+ listAccounts: async (options?: { subscriptionId?: string; resourceGroup?: string }) => {
1734
+ const params = new URLSearchParams();
1735
+ if (options?.subscriptionId) {
1736
+ params.set('subscriptionId', options.subscriptionId);
1737
+ }
1738
+ if (options?.resourceGroup) {
1739
+ params.set('resourceGroup', options.resourceGroup);
1740
+ }
1741
+ const query = params.toString() ? `?${params.toString()}` : '';
1742
+ return this.azureClient.get(`/api/azure/storage/accounts${query}`);
1743
+ },
1744
+ },
1745
+
1746
+ aks: {
1747
+ listClusters: async (options?: { subscriptionId?: string; resourceGroup?: string }) => {
1748
+ const params = new URLSearchParams();
1749
+ if (options?.subscriptionId) {
1750
+ params.set('subscriptionId', options.subscriptionId);
1751
+ }
1752
+ if (options?.resourceGroup) {
1753
+ params.set('resourceGroup', options.resourceGroup);
1754
+ }
1755
+ const query = params.toString() ? `?${params.toString()}` : '';
1756
+ return this.azureClient.get(`/api/azure/aks/clusters${query}`);
1757
+ },
1758
+ },
1759
+
1760
+ iam: {
1761
+ listRoleAssignments: async (options?: {
1762
+ subscriptionId?: string;
1763
+ resourceGroup?: string;
1764
+ scope?: string;
1765
+ }) => {
1766
+ const params = new URLSearchParams();
1767
+ if (options?.subscriptionId) {
1768
+ params.set('subscriptionId', options.subscriptionId);
1769
+ }
1770
+ if (options?.resourceGroup) {
1771
+ params.set('resourceGroup', options.resourceGroup);
1772
+ }
1773
+ if (options?.scope) {
1774
+ params.set('scope', options.scope);
1775
+ }
1776
+ const query = params.toString() ? `?${params.toString()}` : '';
1777
+ return this.azureClient.get(`/api/azure/iam/role-assignments${query}`);
1778
+ },
1779
+ },
1780
+
1781
+ discover: {
1782
+ startDiscovery: async (options?: { subscriptionId?: string; resourceGroups?: string[] }) => {
1783
+ return this.azureClient.post('/api/azure/discover/start', options);
1784
+ },
1785
+
1786
+ getSession: async (sessionId: string) => {
1787
+ return this.azureClient.get(`/api/azure/discover/session/${sessionId}`);
1788
+ },
1789
+ },
1790
+
1791
+ terraform: {
1792
+ generate: async (options?: {
1793
+ subscriptionId?: string;
1794
+ resources?: string[];
1795
+ outputDir?: string;
1796
+ }) => {
1797
+ return this.azureClient.post('/api/azure/terraform/generate', options);
1798
+ },
1799
+ },
1800
+ };
1801
+
1802
+ // ==================== Health Checks ====================
1803
+
1804
+ /**
1805
+ * Check health of all tool services
1806
+ */
1807
+ async healthCheck(): Promise<Record<string, boolean>> {
1808
+ const [git, fs, terraform, k8s, helm, aws, github, gcp, azure] = await Promise.all([
1809
+ this.gitClient.healthCheck(),
1810
+ this.fsClient.healthCheck(),
1811
+ this.terraformClient.healthCheck(),
1812
+ this.k8sClient.healthCheck(),
1813
+ this.helmClient.healthCheck(),
1814
+ this.awsClient.healthCheck(),
1815
+ this.githubClient.healthCheck(),
1816
+ this.gcpClient.healthCheck(),
1817
+ this.azureClient.healthCheck(),
1818
+ ]);
1819
+
1820
+ return { git, fs, terraform, k8s, helm, aws, github, gcp, azure };
1821
+ }
1822
+
1823
+ /**
1824
+ * Check health of a specific service
1825
+ */
1826
+ async healthCheckService(
1827
+ service: 'git' | 'fs' | 'terraform' | 'k8s' | 'helm' | 'aws' | 'github' | 'gcp' | 'azure'
1828
+ ): Promise<boolean> {
1829
+ const clients: Record<string, RestClient> = {
1830
+ git: this.gitClient,
1831
+ fs: this.fsClient,
1832
+ terraform: this.terraformClient,
1833
+ k8s: this.k8sClient,
1834
+ helm: this.helmClient,
1835
+ aws: this.awsClient,
1836
+ github: this.githubClient,
1837
+ gcp: this.gcpClient,
1838
+ azure: this.azureClient,
1839
+ };
1840
+
1841
+ return clients[service].healthCheck();
1842
+ }
1843
+ }