@vfarcic/dot-ai 0.195.0 → 1.0.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 (114) hide show
  1. package/README.md +2 -7
  2. package/dist/core/capability-scan-workflow.d.ts +4 -3
  3. package/dist/core/capability-scan-workflow.d.ts.map +1 -1
  4. package/dist/core/capability-scan-workflow.js +34 -39
  5. package/dist/core/circuit-breaker.d.ts +1 -0
  6. package/dist/core/circuit-breaker.d.ts.map +1 -1
  7. package/dist/core/circuit-breaker.js +11 -3
  8. package/dist/core/command-executor.d.ts +10 -1
  9. package/dist/core/command-executor.d.ts.map +1 -1
  10. package/dist/core/command-executor.js +63 -48
  11. package/dist/core/crd-availability.d.ts +6 -1
  12. package/dist/core/crd-availability.d.ts.map +1 -1
  13. package/dist/core/crd-availability.js +59 -49
  14. package/dist/core/deploy-operation.d.ts +17 -3
  15. package/dist/core/deploy-operation.d.ts.map +1 -1
  16. package/dist/core/deploy-operation.js +72 -21
  17. package/dist/core/discovery.d.ts +16 -43
  18. package/dist/core/discovery.d.ts.map +1 -1
  19. package/dist/core/discovery.js +128 -277
  20. package/dist/core/index.d.ts +10 -2
  21. package/dist/core/index.d.ts.map +1 -1
  22. package/dist/core/index.js +20 -9
  23. package/dist/core/pattern-operations.d.ts +3 -1
  24. package/dist/core/pattern-operations.d.ts.map +1 -1
  25. package/dist/core/pattern-operations.js +3 -2
  26. package/dist/core/plugin-client.d.ts +53 -0
  27. package/dist/core/plugin-client.d.ts.map +1 -0
  28. package/dist/core/plugin-client.js +148 -0
  29. package/dist/core/plugin-manager.d.ts +119 -0
  30. package/dist/core/plugin-manager.d.ts.map +1 -0
  31. package/dist/core/plugin-manager.js +366 -0
  32. package/dist/core/plugin-types.d.ts +100 -0
  33. package/dist/core/plugin-types.d.ts.map +1 -0
  34. package/dist/core/plugin-types.js +10 -0
  35. package/dist/core/policy-operations.d.ts +15 -7
  36. package/dist/core/policy-operations.d.ts.map +1 -1
  37. package/dist/core/policy-operations.js +59 -31
  38. package/dist/core/resource-tools.d.ts +2 -90
  39. package/dist/core/resource-tools.d.ts.map +1 -1
  40. package/dist/core/resource-tools.js +4 -178
  41. package/dist/core/schema.d.ts +18 -2
  42. package/dist/core/schema.d.ts.map +1 -1
  43. package/dist/core/schema.js +118 -16
  44. package/dist/core/telemetry/client.d.ts +7 -0
  45. package/dist/core/telemetry/client.d.ts.map +1 -1
  46. package/dist/core/telemetry/client.js +51 -51
  47. package/dist/core/telemetry/index.d.ts +1 -1
  48. package/dist/core/telemetry/index.d.ts.map +1 -1
  49. package/dist/core/telemetry/index.js +2 -1
  50. package/dist/core/telemetry/types.d.ts +1 -3
  51. package/dist/core/telemetry/types.d.ts.map +1 -1
  52. package/dist/core/tracing/index.d.ts +0 -1
  53. package/dist/core/tracing/index.d.ts.map +1 -1
  54. package/dist/core/tracing/index.js +1 -4
  55. package/dist/core/unified-creation-session.d.ts +6 -1
  56. package/dist/core/unified-creation-session.d.ts.map +1 -1
  57. package/dist/core/unified-creation-session.js +19 -11
  58. package/dist/interfaces/mcp.d.ts +8 -2
  59. package/dist/interfaces/mcp.d.ts.map +1 -1
  60. package/dist/interfaces/mcp.js +85 -34
  61. package/dist/interfaces/resource-sync-handler.d.ts.map +1 -1
  62. package/dist/interfaces/resource-sync-handler.js +37 -17
  63. package/dist/interfaces/rest-api.d.ts +4 -1
  64. package/dist/interfaces/rest-api.d.ts.map +1 -1
  65. package/dist/interfaces/rest-api.js +172 -49
  66. package/dist/mcp/server.js +39 -54
  67. package/dist/tools/deploy-manifests.d.ts +3 -1
  68. package/dist/tools/deploy-manifests.d.ts.map +1 -1
  69. package/dist/tools/deploy-manifests.js +112 -13
  70. package/dist/tools/generate-manifests.d.ts +3 -1
  71. package/dist/tools/generate-manifests.d.ts.map +1 -1
  72. package/dist/tools/generate-manifests.js +107 -33
  73. package/dist/tools/operate-analysis.d.ts +5 -1
  74. package/dist/tools/operate-analysis.d.ts.map +1 -1
  75. package/dist/tools/operate-analysis.js +37 -7
  76. package/dist/tools/operate-execution.d.ts +3 -1
  77. package/dist/tools/operate-execution.d.ts.map +1 -1
  78. package/dist/tools/operate-execution.js +6 -4
  79. package/dist/tools/operate.d.ts +7 -2
  80. package/dist/tools/operate.d.ts.map +1 -1
  81. package/dist/tools/operate.js +10 -6
  82. package/dist/tools/organizational-data.d.ts +3 -2
  83. package/dist/tools/organizational-data.d.ts.map +1 -1
  84. package/dist/tools/organizational-data.js +15 -13
  85. package/dist/tools/query.d.ts +5 -1
  86. package/dist/tools/query.d.ts.map +1 -1
  87. package/dist/tools/query.js +26 -18
  88. package/dist/tools/recommend.d.ts +3 -1
  89. package/dist/tools/recommend.d.ts.map +1 -1
  90. package/dist/tools/recommend.js +7 -7
  91. package/dist/tools/remediate.d.ts +5 -2
  92. package/dist/tools/remediate.d.ts.map +1 -1
  93. package/dist/tools/remediate.js +69 -20
  94. package/dist/tools/version.d.ts +20 -5
  95. package/dist/tools/version.d.ts.map +1 -1
  96. package/dist/tools/version.js +169 -161
  97. package/package.json +1 -1
  98. package/prompts/helm-generation.md +9 -0
  99. package/dist/core/cluster-utils.d.ts +0 -12
  100. package/dist/core/cluster-utils.d.ts.map +0 -1
  101. package/dist/core/cluster-utils.js +0 -27
  102. package/dist/core/helm-utils.d.ts +0 -66
  103. package/dist/core/helm-utils.d.ts.map +0 -1
  104. package/dist/core/helm-utils.js +0 -196
  105. package/dist/core/kubectl-tools.d.ts +0 -71
  106. package/dist/core/kubectl-tools.d.ts.map +0 -1
  107. package/dist/core/kubectl-tools.js +0 -546
  108. package/dist/core/kubernetes-utils.d.ts +0 -38
  109. package/dist/core/kubernetes-utils.d.ts.map +0 -1
  110. package/dist/core/kubernetes-utils.js +0 -288
  111. package/dist/core/tracing/k8s-tracing.d.ts +0 -57
  112. package/dist/core/tracing/k8s-tracing.d.ts.map +0 -1
  113. package/dist/core/tracing/k8s-tracing.js +0 -155
  114. package/scripts/toolhive.nu +0 -21
@@ -1,288 +0,0 @@
1
- "use strict";
2
- /**
3
- * Shared Kubernetes Utilities
4
- *
5
- * Common functions for interacting with Kubernetes clusters
6
- */
7
- Object.defineProperty(exports, "__esModule", { value: true });
8
- exports.ErrorClassifier = void 0;
9
- exports.executeKubectl = executeKubectl;
10
- exports.buildKubectlCommand = buildKubectlCommand;
11
- const child_process_1 = require("child_process");
12
- const util_1 = require("util");
13
- const tracing_1 = require("./tracing");
14
- const constants_1 = require("./constants");
15
- const execAsync = (0, util_1.promisify)(child_process_1.exec);
16
- /**
17
- * Simple semaphore to limit concurrent kubectl executions
18
- * Prevents overwhelming the Kubernetes API with too many parallel requests
19
- */
20
- class KubectlSemaphore {
21
- maxConcurrent;
22
- currentCount = 0;
23
- waitQueue = [];
24
- constructor(maxConcurrent = 10) {
25
- this.maxConcurrent = maxConcurrent;
26
- }
27
- async acquire() {
28
- if (this.currentCount < this.maxConcurrent) {
29
- this.currentCount++;
30
- return;
31
- }
32
- // Wait for a slot to become available
33
- return new Promise((resolve) => {
34
- this.waitQueue.push(resolve);
35
- });
36
- }
37
- release() {
38
- if (this.waitQueue.length > 0) {
39
- // Give slot to next waiting request
40
- const next = this.waitQueue.shift();
41
- next();
42
- }
43
- else {
44
- this.currentCount--;
45
- }
46
- }
47
- }
48
- // Limit to 10 concurrent kubectl calls to prevent K8s API rate limiting
49
- const kubectlSemaphore = new KubectlSemaphore(10);
50
- /**
51
- * Execute kubectl command with proper configuration
52
- * Automatically traced with OpenTelemetry
53
- * Uses semaphore to limit concurrent executions and prevent K8s API rate limiting
54
- */
55
- async function executeKubectl(args, config) {
56
- // Acquire semaphore slot before executing
57
- await kubectlSemaphore.acquire();
58
- try {
59
- // Wrap entire execution with tracing
60
- return await (0, tracing_1.withKubectlTracing)(args, config, async () => {
61
- const command = buildKubectlCommand(args, config);
62
- const timeout = config?.timeout || 30000;
63
- try {
64
- // If stdin is provided, use spawn for proper stdin piping
65
- if (config?.stdin) {
66
- const { spawn } = require('child_process');
67
- return new Promise((resolve, reject) => {
68
- let stdout = '';
69
- let stderr = '';
70
- const proc = spawn('sh', ['-c', command], {
71
- timeout,
72
- maxBuffer: 100 * 1024 * 1024
73
- });
74
- proc.stdout.on('data', (data) => { stdout += data.toString(); });
75
- proc.stderr.on('data', (data) => { stderr += data.toString(); });
76
- proc.on('error', (error) => reject(error));
77
- proc.on('close', (code) => {
78
- if (code !== 0) {
79
- reject(new Error(`kubectl command failed: ${stderr || stdout}`));
80
- }
81
- else if (stderr && !stderr.includes('Warning') && !stderr.includes('No resources found')) {
82
- reject(new Error(`kubectl command failed: ${stderr}`));
83
- }
84
- else {
85
- resolve(stdout.trim());
86
- }
87
- });
88
- // Write stdin and close
89
- proc.stdin.write(config.stdin);
90
- proc.stdin.end();
91
- });
92
- }
93
- // No stdin - use regular execAsync
94
- const { stdout, stderr } = await execAsync(command, {
95
- timeout,
96
- maxBuffer: 100 * 1024 * 1024 // 100MB buffer for large clusters with 1000+ CRDs
97
- });
98
- if (stderr && !stderr.includes('Warning') && !stderr.includes('No resources found')) {
99
- throw new Error(`kubectl command failed: ${stderr}`);
100
- }
101
- return stdout.trim();
102
- }
103
- catch (error) {
104
- if (error.code === 'ENOENT') {
105
- throw new Error('kubectl binary not found. Please install kubectl and ensure it\'s in your PATH.');
106
- }
107
- // Use error classification for better error messages
108
- const classified = ErrorClassifier.classifyError(error);
109
- throw new Error(classified.enhancedMessage);
110
- }
111
- });
112
- }
113
- finally {
114
- // Always release the semaphore slot
115
- kubectlSemaphore.release();
116
- }
117
- }
118
- /**
119
- * Build kubectl command string with proper flags
120
- */
121
- /**
122
- * Safely escape shell arguments to prevent command injection
123
- */
124
- function escapeShellArg(arg) {
125
- if (!arg || typeof arg !== 'string') {
126
- return '""';
127
- }
128
- // If the argument contains only safe characters, return as-is
129
- if (/^[a-zA-Z0-9._/-]+$/.test(arg)) {
130
- return arg;
131
- }
132
- // Otherwise, quote and escape
133
- return `"${arg.replace(/["\\]/g, '\\$&')}"`;
134
- }
135
- function buildKubectlCommand(args, config) {
136
- const cmdParts = ['kubectl'];
137
- if (config?.kubeconfig) {
138
- cmdParts.push('--kubeconfig', escapeShellArg(config.kubeconfig));
139
- }
140
- if (config?.context) {
141
- cmdParts.push('--context', escapeShellArg(config.context));
142
- }
143
- if (config?.namespace) {
144
- cmdParts.push('--namespace', escapeShellArg(config.namespace));
145
- }
146
- // Safely add all arguments
147
- args.forEach(arg => cmdParts.push(escapeShellArg(arg)));
148
- return cmdParts.join(' ');
149
- }
150
- // Enhanced Error Classification System
151
- class ErrorClassifier {
152
- static classifyError(error) {
153
- const originalMessage = error.message;
154
- // Connection and Network Errors
155
- if (this.isNetworkError(originalMessage)) {
156
- return {
157
- type: 'network',
158
- enhancedMessage: this.enhanceNetworkError(originalMessage)
159
- };
160
- }
161
- // Authentication Errors
162
- if (this.isAuthenticationError(originalMessage)) {
163
- return {
164
- type: 'authentication',
165
- enhancedMessage: this.enhanceAuthenticationError(originalMessage)
166
- };
167
- }
168
- // Authorization/RBAC Errors
169
- if (this.isAuthorizationError(originalMessage)) {
170
- return {
171
- type: 'authorization',
172
- enhancedMessage: this.enhanceAuthorizationError(originalMessage)
173
- };
174
- }
175
- // API Availability Errors
176
- if (this.isAPIAvailabilityError(originalMessage)) {
177
- return {
178
- type: 'api-availability',
179
- enhancedMessage: this.enhanceAPIAvailabilityError(originalMessage)
180
- };
181
- }
182
- // Kubeconfig Validation Errors
183
- if (this.isKubeconfigError(originalMessage)) {
184
- return {
185
- type: 'kubeconfig',
186
- enhancedMessage: this.enhanceKubeconfigError(originalMessage)
187
- };
188
- }
189
- // Version Compatibility Errors
190
- if (this.isVersionCompatibilityError(originalMessage)) {
191
- return {
192
- type: 'version',
193
- enhancedMessage: this.enhanceVersionCompatibilityError(originalMessage)
194
- };
195
- }
196
- // Default: return original message with basic enhancement
197
- return {
198
- type: 'unknown',
199
- enhancedMessage: `${originalMessage}\n\nTroubleshooting steps:\n- Run 'kubectl cluster-info' to verify cluster connectivity\n- Check your kubeconfig with 'kubectl config view'\n- Verify cluster endpoint accessibility`
200
- };
201
- }
202
- static isNetworkError(message) {
203
- // Fixed: Avoid catastrophic backtracking by using non-overlapping alternation
204
- const networkPatterns = [
205
- 'getaddrinfo ENOTFOUND',
206
- 'timeout',
207
- 'ECONNREFUSED',
208
- 'ENOTFOUND',
209
- 'network',
210
- 'unreachable'
211
- ];
212
- return networkPatterns.some(pattern => message.toLowerCase().includes(pattern.toLowerCase()));
213
- }
214
- static isAuthenticationError(message) {
215
- // Fixed: Avoid catastrophic backtracking by using non-overlapping alternation
216
- const authPatterns = [
217
- 'unauthorized',
218
- 'invalid bearer token',
219
- 'certificate',
220
- 'auth',
221
- 'authentication'
222
- ];
223
- return authPatterns.some(pattern => message.toLowerCase().includes(pattern.toLowerCase()));
224
- }
225
- static isAuthorizationError(message) {
226
- return /forbidden|cannot list|cannot get|cannot create|RBAC|permission denied/i.test(message);
227
- }
228
- static isAPIAvailabilityError(message) {
229
- return /server could not find|resource type.*not found|doesn't have a resource type|no matches for kind/i.test(message);
230
- }
231
- static isKubeconfigError(message) {
232
- // Be more specific - don't match "path does not exist" errors which are about manifest files
233
- return /context.*does not exist|kubeconfig.*not found|invalid.*kubeconfig|config.*not found|no Auth Provider/i.test(message) &&
234
- !/the path.*does not exist/.test(message);
235
- }
236
- static isVersionCompatibilityError(message) {
237
- return /server version|version.*old|unsupported.*version|api.*version/i.test(message);
238
- }
239
- static enhanceNetworkError(message) {
240
- if (message.includes('getaddrinfo ENOTFOUND')) {
241
- return `DNS resolution failed: Cannot resolve cluster endpoint hostname.\n\nTroubleshooting steps:\n- Check cluster endpoint in kubeconfig: kubectl config view\n- Verify network connectivity and DNS settings\n- Confirm cluster is running and accessible\n- Check VPN connection if using private cluster\n\nOriginal error: ${message}`;
242
- }
243
- if (message.includes('timeout')) {
244
- return `Connection timeout: Unable to reach cluster within timeout period.\n\nTroubleshooting steps:\n- Check network latency to cluster endpoint\n- Increase timeout value if needed\n- Verify cluster is responsive: kubectl get nodes\n- Check firewall and proxy settings\n\nOriginal error: ${message}`;
245
- }
246
- return `Network connectivity issue detected.\n\nTroubleshooting steps:\n- Verify cluster endpoint accessibility\n- Run 'kubectl cluster-info' to test connectivity\n- Check network and firewall settings\n- Confirm cluster is running\n\nOriginal error: ${message}`;
247
- }
248
- static enhanceAuthenticationError(message) {
249
- if (message.includes('invalid bearer token')) {
250
- return constants_1.KUBERNETES_ERROR_TEMPLATES.AUTHENTICATION.INVALID_TOKEN(message);
251
- }
252
- if (message.includes('certificate')) {
253
- return constants_1.KUBERNETES_ERROR_TEMPLATES.AUTHENTICATION.CERTIFICATE_FAILED(message);
254
- }
255
- if (message.includes('no Auth Provider found')) {
256
- return constants_1.KUBERNETES_ERROR_TEMPLATES.AUTHENTICATION.PROVIDER_MISSING(message);
257
- }
258
- return constants_1.KUBERNETES_ERROR_TEMPLATES.AUTHENTICATION.GENERIC_FAILED(message);
259
- }
260
- static enhanceAuthorizationError(message) {
261
- if (message.includes('customresourcedefinitions')) {
262
- return constants_1.KUBERNETES_ERROR_TEMPLATES.AUTHORIZATION.CRD_PERMISSIONS(message);
263
- }
264
- if (message.includes('forbidden')) {
265
- return constants_1.KUBERNETES_ERROR_TEMPLATES.AUTHORIZATION.FORBIDDEN(message);
266
- }
267
- return constants_1.KUBERNETES_ERROR_TEMPLATES.AUTHORIZATION.PERMISSION_DENIED(message);
268
- }
269
- static enhanceAPIAvailabilityError(message) {
270
- if (message.includes('apps/v1beta1')) {
271
- return constants_1.KUBERNETES_ERROR_TEMPLATES.API.VERSION_UNSUPPORTED(message);
272
- }
273
- return constants_1.KUBERNETES_ERROR_TEMPLATES.API.RESOURCE_UNAVAILABLE(message);
274
- }
275
- static enhanceKubeconfigError(message) {
276
- if (message.includes('context') && message.includes('does not exist')) {
277
- return constants_1.KUBERNETES_ERROR_TEMPLATES.KUBECONFIG.CONTEXT_NOT_FOUND(message);
278
- }
279
- if (message.includes('not found')) {
280
- return constants_1.KUBERNETES_ERROR_TEMPLATES.KUBECONFIG.FILE_NOT_FOUND(message);
281
- }
282
- return constants_1.KUBERNETES_ERROR_TEMPLATES.KUBECONFIG.INVALID_FORMAT(message);
283
- }
284
- static enhanceVersionCompatibilityError(message) {
285
- return constants_1.KUBERNETES_ERROR_TEMPLATES.VERSION_COMPATIBILITY(message);
286
- }
287
- }
288
- exports.ErrorClassifier = ErrorClassifier;
@@ -1,57 +0,0 @@
1
- /**
2
- * Kubernetes Client Tracing Utilities
3
- *
4
- * Generic tracing wrappers for Kubernetes operations:
5
- * 1. Transparent proxy for @kubernetes/client-node API clients
6
- * 2. Wrapper for kubectl CLI command execution
7
- *
8
- * Uses CLIENT span kind with k8s.* semantic conventions
9
- */
10
- /**
11
- * Configuration for kubectl command tracing
12
- */
13
- export interface KubectlConfig {
14
- context?: string;
15
- namespace?: string;
16
- kubeconfig?: string;
17
- timeout?: number;
18
- stdin?: string;
19
- }
20
- /**
21
- * Create traced Kubernetes API client using JavaScript Proxy
22
- *
23
- * Transparently wraps ANY Kubernetes API client method with tracing.
24
- * No code changes needed in calling code - just wrap the client once.
25
- *
26
- * @param apiClient Original K8s API client instance
27
- * @param apiType API client type (e.g., 'CoreV1Api', 'AppsV1Api')
28
- * @returns Proxied client with automatic tracing for all methods
29
- *
30
- * @example
31
- * const coreApi = createTracedK8sClient(
32
- * kc.makeApiClient(k8s.CoreV1Api),
33
- * 'CoreV1Api'
34
- * );
35
- * await coreApi.listNamespace(); // Automatically traced as "k8s.listNamespace"
36
- */
37
- export declare function createTracedK8sClient<T extends object>(apiClient: T, apiType: string): T;
38
- /**
39
- * Tracing wrapper for kubectl CLI command execution
40
- *
41
- * Wraps kubectl command execution with OpenTelemetry tracing spans.
42
- * Captures command details, operation type, and execution results.
43
- *
44
- * @param args kubectl command arguments (e.g., ['get', 'pods', '-n', 'default'])
45
- * @param config kubectl execution configuration
46
- * @param handler Function that executes the actual kubectl command
47
- * @returns kubectl command output
48
- *
49
- * @example
50
- * const output = await withKubectlTracing(
51
- * ['get', 'crd', '-o', 'json'],
52
- * { kubeconfig: '/path/to/config' },
53
- * async () => execAsync('kubectl get crd -o json')
54
- * );
55
- */
56
- export declare function withKubectlTracing(args: string[], config: KubectlConfig | undefined, handler: () => Promise<string>): Promise<string>;
57
- //# sourceMappingURL=k8s-tracing.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"k8s-tracing.d.ts","sourceRoot":"","sources":["../../../src/core/tracing/k8s-tracing.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,SAAS,MAAM,EACpD,SAAS,EAAE,CAAC,EACZ,OAAO,EAAE,MAAM,GACd,CAAC,CAoEH;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,MAAM,EAAE,EACd,MAAM,EAAE,aAAa,GAAG,SAAS,EACjC,OAAO,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,GAC7B,OAAO,CAAC,MAAM,CAAC,CAgEjB"}
@@ -1,155 +0,0 @@
1
- "use strict";
2
- /**
3
- * Kubernetes Client Tracing Utilities
4
- *
5
- * Generic tracing wrappers for Kubernetes operations:
6
- * 1. Transparent proxy for @kubernetes/client-node API clients
7
- * 2. Wrapper for kubectl CLI command execution
8
- *
9
- * Uses CLIENT span kind with k8s.* semantic conventions
10
- */
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.createTracedK8sClient = createTracedK8sClient;
13
- exports.withKubectlTracing = withKubectlTracing;
14
- const api_1 = require("@opentelemetry/api");
15
- /**
16
- * Create traced Kubernetes API client using JavaScript Proxy
17
- *
18
- * Transparently wraps ANY Kubernetes API client method with tracing.
19
- * No code changes needed in calling code - just wrap the client once.
20
- *
21
- * @param apiClient Original K8s API client instance
22
- * @param apiType API client type (e.g., 'CoreV1Api', 'AppsV1Api')
23
- * @returns Proxied client with automatic tracing for all methods
24
- *
25
- * @example
26
- * const coreApi = createTracedK8sClient(
27
- * kc.makeApiClient(k8s.CoreV1Api),
28
- * 'CoreV1Api'
29
- * );
30
- * await coreApi.listNamespace(); // Automatically traced as "k8s.listNamespace"
31
- */
32
- function createTracedK8sClient(apiClient, apiType) {
33
- const tracer = api_1.trace.getTracer('dot-ai-mcp');
34
- return new Proxy(apiClient, {
35
- get(target, prop, receiver) {
36
- const original = Reflect.get(target, prop, receiver);
37
- // Only wrap functions (API methods), not properties
38
- if (typeof original !== 'function') {
39
- return original;
40
- }
41
- // Return wrapped function with tracing
42
- return function (...args) {
43
- const methodName = String(prop);
44
- const spanName = `k8s.${methodName}`;
45
- return tracer.startActiveSpan(spanName, {
46
- kind: api_1.SpanKind.CLIENT,
47
- attributes: {
48
- 'k8s.client': 'kubernetes-client-node',
49
- 'k8s.api': apiType,
50
- 'k8s.method': methodName,
51
- },
52
- }, async (span) => {
53
- try {
54
- // Execute the original K8s API method
55
- const result = await original.apply(target, args);
56
- // Add response metadata if available
57
- if (result?.response?.statusCode) {
58
- span.setAttribute('http.response.status_code', result.response.statusCode);
59
- }
60
- span.setStatus({ code: api_1.SpanStatusCode.OK });
61
- return result;
62
- }
63
- catch (error) {
64
- // Record K8s API error
65
- span.recordException(error);
66
- span.setStatus({
67
- code: api_1.SpanStatusCode.ERROR,
68
- message: error instanceof Error ? error.message : String(error),
69
- });
70
- // Add K8s-specific error attributes
71
- if (error instanceof Error && 'statusCode' in error) {
72
- span.setAttribute('k8s.error.status_code', error.statusCode);
73
- }
74
- throw error;
75
- }
76
- finally {
77
- span.end();
78
- }
79
- });
80
- };
81
- },
82
- });
83
- }
84
- /**
85
- * Tracing wrapper for kubectl CLI command execution
86
- *
87
- * Wraps kubectl command execution with OpenTelemetry tracing spans.
88
- * Captures command details, operation type, and execution results.
89
- *
90
- * @param args kubectl command arguments (e.g., ['get', 'pods', '-n', 'default'])
91
- * @param config kubectl execution configuration
92
- * @param handler Function that executes the actual kubectl command
93
- * @returns kubectl command output
94
- *
95
- * @example
96
- * const output = await withKubectlTracing(
97
- * ['get', 'crd', '-o', 'json'],
98
- * { kubeconfig: '/path/to/config' },
99
- * async () => execAsync('kubectl get crd -o json')
100
- * );
101
- */
102
- async function withKubectlTracing(args, config, handler) {
103
- const tracer = api_1.trace.getTracer('dot-ai-mcp');
104
- // Parse operation and resource from args
105
- const operation = args[0] || 'unknown'; // 'get', 'apply', 'delete', etc.
106
- const resource = args[1] || 'unknown'; // 'pods', 'crd', 'deployments', etc.
107
- const spanName = `kubectl ${operation} ${resource}`;
108
- return await tracer.startActiveSpan(spanName, {
109
- kind: api_1.SpanKind.CLIENT,
110
- attributes: {
111
- 'k8s.client': 'kubectl',
112
- 'k8s.command': 'kubectl',
113
- 'k8s.operation': operation,
114
- 'k8s.resource': resource,
115
- 'k8s.args': args.join(' '),
116
- ...(config?.namespace && { 'k8s.namespace': config.namespace }),
117
- ...(config?.context && { 'k8s.context': config.context }),
118
- ...(config?.kubeconfig && { 'k8s.kubeconfig': config.kubeconfig }),
119
- },
120
- }, async (span) => {
121
- const startTime = Date.now();
122
- try {
123
- // Execute the kubectl command
124
- const result = await api_1.context.with(api_1.trace.setSpan(api_1.context.active(), span), handler);
125
- // Add execution metrics
126
- span.setAttribute('k8s.duration_ms', Date.now() - startTime);
127
- span.setAttribute('k8s.output_size_bytes', result.length);
128
- span.setStatus({ code: api_1.SpanStatusCode.OK });
129
- return result;
130
- }
131
- catch (error) {
132
- // Record kubectl error with details
133
- span.recordException(error);
134
- span.setStatus({
135
- code: api_1.SpanStatusCode.ERROR,
136
- message: error instanceof Error ? error.message : String(error),
137
- });
138
- // Parse kubectl error for additional context
139
- const errorMessage = error instanceof Error ? error.message : String(error);
140
- if (errorMessage.includes('not found')) {
141
- span.setAttribute('k8s.error.type', 'NotFound');
142
- }
143
- else if (errorMessage.includes('forbidden')) {
144
- span.setAttribute('k8s.error.type', 'Forbidden');
145
- }
146
- else if (errorMessage.includes('timeout')) {
147
- span.setAttribute('k8s.error.type', 'Timeout');
148
- }
149
- throw error;
150
- }
151
- finally {
152
- span.end();
153
- }
154
- });
155
- }
@@ -1,21 +0,0 @@
1
- #!/usr/bin/env nu
2
-
3
- # Installs Stacklock Toolhive
4
- #
5
- # Examples:
6
- # > main apply toolhive
7
- def "main apply toolhive" [] {
8
-
9
- (
10
- helm upgrade --install toolhive-operator-crds
11
- oci://ghcr.io/stacklok/toolhive/toolhive-operator-crds
12
- )
13
-
14
- (
15
- helm upgrade --install toolhive-operator
16
- oci://ghcr.io/stacklok/toolhive/toolhive-operator
17
- --namespace toolhive-system --create-namespace
18
- --wait
19
- )
20
-
21
- }