@vfarcic/dot-ai 0.82.0 → 0.83.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.
package/README.md CHANGED
@@ -342,4 +342,4 @@ MIT License - see [LICENSE](LICENSE) file for details.
342
342
 
343
343
  ---
344
344
 
345
- **DevOps AI Toolkit** - AI-powered development productivity platform for enhanced software development workflows.
345
+ **DevOps AI Toolkit** - AI-powered development productivity platform for enhanced software development workflows.
@@ -3,6 +3,7 @@
3
3
  *
4
4
  * Handles cluster connection, resource discovery, and capability detection
5
5
  */
6
+ import * as k8s from '@kubernetes/client-node';
6
7
  import { KubectlConfig } from './kubernetes-utils';
7
8
  export interface ClusterInfo {
8
9
  type: string;
@@ -103,6 +104,29 @@ export declare class KubernetesDiscovery {
103
104
  * Set a new kubeconfig path (will require reconnection)
104
105
  */
105
106
  setKubeconfigPath(newPath: string): void;
107
+ /**
108
+ * Get connection status and configuration info for diagnostics
109
+ */
110
+ getConnectionInfo(): {
111
+ connected: boolean;
112
+ kubeconfig: string;
113
+ mode: 'file' | 'in-cluster' | 'default';
114
+ server?: string;
115
+ context?: string;
116
+ };
117
+ /**
118
+ * Test connection to the cluster with detailed result
119
+ */
120
+ testConnection(): Promise<{
121
+ connected: boolean;
122
+ version?: string;
123
+ error?: string;
124
+ errorType?: string;
125
+ }>;
126
+ /**
127
+ * Get the Kubernetes client for direct API access (used by other tools)
128
+ */
129
+ getClient(): k8s.KubeConfig;
106
130
  connect(): Promise<void>;
107
131
  isConnected(): boolean;
108
132
  getClusterInfo(): Promise<ClusterInfo>;
@@ -1 +1 @@
1
- {"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../src/core/discovery.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EAEL,aAAa,EAEd,MAAM,oBAAoB,CAAC;AAE5B,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,gBAAgB,EAAE,CAAC;IAC9B,MAAM,EAAE,WAAW,EAAE,CAAC;CACvB;AAKD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,YAAY,GAAG,SAAS,CAAC;IAChC,QAAQ,EAAE,KAAK,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,OAAO,CAAC;QAChB,OAAO,EAAE,OAAO,CAAC;QACjB,MAAM,CAAC,EAAE,GAAG,CAAC;KACd,CAAC,CAAC;IACH,MAAM,CAAC,EAAE,GAAG,CAAC;CACd;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,OAAO,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,KAAK,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,OAAO,CAAC;KACnB,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,QAAQ,EAAE;QACR,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,EAAE,MAAM,CAAC;QACnB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,UAAU,EAAE;QACV,GAAG,EAAE,MAAM,CAAC;QACZ,aAAa,EAAE,MAAM,CAAC;QACtB,SAAS,EAAE,MAAM,CAAC;QAClB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,QAAQ,EAAE;QACR,WAAW,EAAE,OAAO,CAAC;QACrB,iBAAiB,EAAE,OAAO,CAAC;QAC3B,eAAe,EAAE,OAAO,CAAC;QACzB,oBAAoB,EAAE,MAAM,EAAE,CAAC;KAChC,CAAC;IACF,OAAO,EAAE;QACP,cAAc,EAAE,MAAM,EAAE,CAAC;QACzB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,UAAU,EAAE,MAAM,EAAE,CAAC;KACtB,CAAC;CACH;AAED,MAAM,WAAW,yBAAyB;IACxC,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,EAAE,CAAiB;IAC3B,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,cAAc,CAAS;gBAEnB,MAAM,CAAC,EAAE,yBAAyB;IAK9C;;;;;OAKG;IACH,OAAO,CAAC,qBAAqB;IAmB7B;;OAEG;IACH,iBAAiB,IAAI,MAAM;IAI3B;;OAEG;IACH,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAKlC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAiC9B,WAAW,IAAI,OAAO;IAIhB,cAAc,IAAI,OAAO,CAAC,WAAW,CAAC;IAkB5C,OAAO,CAAC,iBAAiB;YAiCX,kBAAkB;IAuD1B,iBAAiB,IAAI,OAAO,CAAC,WAAW,CAAC;IA+B/C;;OAEG;IACH;;;OAGG;IACG,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC;IAMvE,YAAY,CAAC,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAkDlE,eAAe,CAAC,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAuD1E,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IAoBhF,kBAAkB,IAAI,OAAO,CAAC,kBAAkB,CAAC;YA2FzC,iBAAiB;YAwBjB,iBAAiB;YAwBjB,eAAe;YA8Bf,cAAc;IAwB5B,OAAO,CAAC,aAAa;IAWf,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAiBnE,aAAa,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAalC,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAS1D;;OAEG;YACW,uBAAuB;IAsDrC;;OAEG;YACW,8BAA8B;IAkB5C;;OAEG;YACW,8BAA8B;IAiE5C;;OAEG;IACH,OAAO,CAAC,wBAAwB;CAgBjC"}
1
+ {"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../src/core/discovery.ts"],"names":[],"mappings":"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"}
@@ -71,7 +71,11 @@ class KubernetesDiscovery {
71
71
  // Resolve relative paths against process.cwd()
72
72
  return path.isAbsolute(kubeconfigPath) ? kubeconfigPath : path.resolve(kubeconfigPath);
73
73
  }
74
- // Priority 3: Default location
74
+ // Priority 3: Default location (only when not in cluster)
75
+ // When KUBERNETES_SERVICE_HOST is set, we should use in-cluster config instead
76
+ if (process.env.KUBERNETES_SERVICE_HOST) {
77
+ return ''; // Empty string indicates in-cluster should be used
78
+ }
75
79
  return path.join(os.homedir(), '.kube', 'config');
76
80
  }
77
81
  /**
@@ -87,17 +91,100 @@ class KubernetesDiscovery {
87
91
  this.kubeconfigPath = newPath;
88
92
  this.connected = false; // Force reconnection with new path
89
93
  }
94
+ /**
95
+ * Get connection status and configuration info for diagnostics
96
+ */
97
+ getConnectionInfo() {
98
+ const isInCluster = process.env.KUBERNETES_SERVICE_HOST && (!this.kubeconfigPath || this.kubeconfigPath === '');
99
+ if (isInCluster) {
100
+ return {
101
+ connected: this.connected,
102
+ kubeconfig: 'in-cluster',
103
+ mode: 'in-cluster',
104
+ server: `https://${process.env.KUBERNETES_SERVICE_HOST}:${process.env.KUBERNETES_SERVICE_PORT}`,
105
+ context: 'in-cluster'
106
+ };
107
+ }
108
+ // For file-based or default configs
109
+ const mode = this.kubeconfigPath ? 'file' : 'default';
110
+ const kubeconfig = this.kubeconfigPath || '~/.kube/config';
111
+ let server;
112
+ let context;
113
+ if (this.connected && this.kc) {
114
+ try {
115
+ context = this.kc.getCurrentContext();
116
+ const cluster = this.kc.getCurrentCluster();
117
+ server = cluster?.server;
118
+ }
119
+ catch (error) {
120
+ // Ignore errors getting context/cluster info
121
+ }
122
+ }
123
+ return {
124
+ connected: this.connected,
125
+ kubeconfig,
126
+ mode,
127
+ server,
128
+ context
129
+ };
130
+ }
131
+ /**
132
+ * Test connection to the cluster with detailed result
133
+ */
134
+ async testConnection() {
135
+ if (!this.connected || !this.k8sApi) {
136
+ return { connected: false, error: 'No connection established' };
137
+ }
138
+ try {
139
+ // Simple API call to test connectivity
140
+ await this.k8sApi.listNamespace();
141
+ // Try to get server version
142
+ let version;
143
+ try {
144
+ const versionClient = this.kc.makeApiClient(k8s.VersionApi);
145
+ const versionResponse = await versionClient.getCode();
146
+ version = versionResponse.gitVersion;
147
+ }
148
+ catch (error) {
149
+ // Version is optional
150
+ }
151
+ return { connected: true, version };
152
+ }
153
+ catch (error) {
154
+ const errorMessage = error instanceof Error ? error.message : String(error);
155
+ const classified = kubernetes_utils_1.ErrorClassifier.classifyError(error);
156
+ return {
157
+ connected: false,
158
+ error: errorMessage,
159
+ errorType: classified.type
160
+ };
161
+ }
162
+ }
163
+ /**
164
+ * Get the Kubernetes client for direct API access (used by other tools)
165
+ */
166
+ getClient() {
167
+ if (!this.kc) {
168
+ throw new Error('Kubernetes client not initialized. Call connect() first.');
169
+ }
170
+ return this.kc;
171
+ }
90
172
  async connect() {
91
173
  try {
92
174
  this.kc = new k8s.KubeConfig();
93
175
  if (this.kubeconfigPath) {
94
- // Check if the kubeconfig file exists before trying to load it
176
+ // Priority 1: Explicit kubeconfig file (constructor param or KUBECONFIG env)
95
177
  if (!require('fs').existsSync(this.kubeconfigPath)) {
96
178
  throw new Error(`Kubeconfig file not found: ${this.kubeconfigPath}`);
97
179
  }
98
180
  this.kc.loadFromFile(this.kubeconfigPath);
99
181
  }
182
+ else if (process.env.KUBERNETES_SERVICE_HOST) {
183
+ // Priority 2: In-cluster configuration (when KUBERNETES_SERVICE_HOST is set by k8s)
184
+ this.kc.loadFromCluster();
185
+ }
100
186
  else {
187
+ // Priority 3: Default kubeconfig location
101
188
  this.kc.loadFromDefault();
102
189
  }
103
190
  // Create API clients
@@ -260,7 +347,12 @@ class KubernetesDiscovery {
260
347
  * Delegates to shared utility function
261
348
  */
262
349
  async executeKubectl(args, config) {
263
- return (0, kubernetes_utils_1.executeKubectl)(args, { ...config, kubeconfig: this.kubeconfigPath });
350
+ // Don't pass kubeconfig if it's empty (in-cluster configuration)
351
+ const kubectlConfig = { ...config };
352
+ if (this.kubeconfigPath && this.kubeconfigPath !== '') {
353
+ kubectlConfig.kubeconfig = this.kubeconfigPath;
354
+ }
355
+ return (0, kubernetes_utils_1.executeKubectl)(args, kubectlConfig);
264
356
  }
265
357
  async discoverCRDs(options) {
266
358
  if (!this.connected) {
package/dist/index.d.ts CHANGED
@@ -4,11 +4,11 @@
4
4
  * Universal Kubernetes application deployment agent with MCP interface
5
5
  */
6
6
  export * from './core';
7
- export declare const version = "0.1.0";
8
- export declare const name = "dot-ai";
7
+ export declare const version: any;
8
+ export declare const name: any;
9
9
  declare const _default: {
10
- version: string;
11
- name: string;
10
+ version: any;
11
+ name: any;
12
12
  };
13
13
  export default _default;
14
14
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,QAAQ,CAAC;AAGvB,eAAO,MAAM,OAAO,UAAU,CAAC;AAC/B,eAAO,MAAM,IAAI,WAAW,CAAC;;;;;AAG7B,wBAGE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,QAAQ,CAAC;AAOvB,eAAO,MAAM,OAAO,KAAsB,CAAC;AAC3C,eAAO,MAAM,IAAI,KAA4C,CAAC;;;;;AAG9D,wBAGE"}
package/dist/index.js CHANGED
@@ -21,9 +21,12 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
21
21
  Object.defineProperty(exports, "__esModule", { value: true });
22
22
  exports.name = exports.version = void 0;
23
23
  __exportStar(require("./core"), exports);
24
- // Version information
25
- exports.version = '0.1.0';
26
- exports.name = 'dot-ai';
24
+ // Version information - loaded dynamically from package.json
25
+ const fs_1 = require("fs");
26
+ const path_1 = require("path");
27
+ const packageJson = JSON.parse((0, fs_1.readFileSync)((0, path_1.join)(__dirname, '../package.json'), 'utf8'));
28
+ exports.version = packageJson.version;
29
+ exports.name = packageJson.name.replace('@vfarcic/', '');
27
30
  // Default export for convenience
28
31
  exports.default = {
29
32
  version: exports.version,
@@ -10,6 +10,10 @@ export interface MCPServerConfig {
10
10
  version: string;
11
11
  description: string;
12
12
  author?: string;
13
+ transport?: 'stdio' | 'http';
14
+ port?: number;
15
+ host?: string;
16
+ sessionMode?: 'stateful' | 'stateless';
13
17
  }
14
18
  export declare class MCPServer {
15
19
  private server;
@@ -17,6 +21,9 @@ export declare class MCPServer {
17
21
  private initialized;
18
22
  private logger;
19
23
  private requestIdCounter;
24
+ private config;
25
+ private httpServer?;
26
+ private httpTransport?;
20
27
  constructor(dotAI: DotAI, config: MCPServerConfig);
21
28
  /**
22
29
  * Register all tools with McpServer
@@ -28,6 +35,9 @@ export declare class MCPServer {
28
35
  private registerPrompts;
29
36
  private generateRequestId;
30
37
  start(): Promise<void>;
38
+ private startStdioTransport;
39
+ private startHttpTransport;
40
+ private parseRequestBody;
31
41
  stop(): Promise<void>;
32
42
  isReady(): boolean;
33
43
  }
@@ -1 +1 @@
1
- {"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../../src/interfaces/mcp.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAwDtC,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,gBAAgB,CAAa;gBAEzB,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe;IA6BjD;;OAEG;IACH,OAAO,CAAC,aAAa;IAmKrB;;OAEG;IACH,OAAO,CAAC,eAAe;IAqCvB,OAAO,CAAC,iBAAiB;IAInB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAMtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAK3B,OAAO,IAAI,OAAO;CAGnB"}
1
+ {"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../../src/interfaces/mcp.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAWH,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAwDtC,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,UAAU,GAAG,WAAW,CAAC;CACxC;AAED,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,gBAAgB,CAAa;IACrC,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,UAAU,CAAC,CAAkC;IACrD,OAAO,CAAC,aAAa,CAAC,CAAgC;gBAE1C,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe;IA8BjD;;OAEG;IACH,OAAO,CAAC,aAAa;IAmKrB;;OAEG;IACH,OAAO,CAAC,eAAe;IAqCvB,OAAO,CAAC,iBAAiB;IAInB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAkBd,mBAAmB;YAMnB,kBAAkB;YAiElB,gBAAgB;IAexB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAgB3B,OAAO,IAAI,OAAO;CAGnB"}
@@ -9,6 +9,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.MCPServer = void 0;
10
10
  const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
11
11
  const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
12
+ const streamableHttp_js_1 = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
13
+ const node_http_1 = require("node:http");
14
+ const node_crypto_1 = require("node:crypto");
12
15
  const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
13
16
  const error_handling_1 = require("../core/error-handling");
14
17
  const recommend_1 = require("../tools/recommend");
@@ -26,8 +29,12 @@ class MCPServer {
26
29
  initialized = false;
27
30
  logger;
28
31
  requestIdCounter = 0;
32
+ config;
33
+ httpServer;
34
+ httpTransport;
29
35
  constructor(dotAI, config) {
30
36
  this.dotAI = dotAI;
37
+ this.config = config;
31
38
  this.logger = new error_handling_1.ConsoleLogger('MCPServer');
32
39
  // Create McpServer instance
33
40
  this.server = new mcp_js_1.McpServer({
@@ -147,12 +154,107 @@ class MCPServer {
147
154
  return `mcp_${Date.now()}_${++this.requestIdCounter}`;
148
155
  }
149
156
  async start() {
157
+ // Get transport type from environment or config
158
+ const transportType = process.env.TRANSPORT_TYPE || this.config.transport || 'stdio';
159
+ this.logger.info('Starting MCP Server', {
160
+ transportType,
161
+ sessionMode: this.config.sessionMode || 'stateful'
162
+ });
163
+ if (transportType === 'http') {
164
+ await this.startHttpTransport();
165
+ }
166
+ else {
167
+ await this.startStdioTransport();
168
+ }
169
+ this.initialized = true;
170
+ }
171
+ async startStdioTransport() {
172
+ this.logger.info('Using STDIO transport');
150
173
  const transport = new stdio_js_1.StdioServerTransport();
151
174
  await this.server.connect(transport);
152
- this.initialized = true;
175
+ }
176
+ async startHttpTransport() {
177
+ const port = parseInt(process.env.PORT || '') || this.config.port || 3456;
178
+ const host = process.env.HOST || this.config.host || '0.0.0.0';
179
+ const sessionMode = process.env.SESSION_MODE || this.config.sessionMode || 'stateful';
180
+ this.logger.info('Using HTTP/SSE transport', { port, host, sessionMode });
181
+ // Create HTTP transport with session management
182
+ this.httpTransport = new streamableHttp_js_1.StreamableHTTPServerTransport({
183
+ sessionIdGenerator: sessionMode === 'stateful' ? () => (0, node_crypto_1.randomUUID)() : undefined,
184
+ enableJsonResponse: false, // Use SSE for streaming
185
+ onsessioninitialized: (sessionId) => {
186
+ this.logger.info('Session initialized', { sessionId });
187
+ }
188
+ });
189
+ // Connect MCP server to transport
190
+ await this.server.connect(this.httpTransport);
191
+ // Create HTTP server
192
+ this.httpServer = (0, node_http_1.createServer)(async (req, res) => {
193
+ this.logger.debug('HTTP request received', {
194
+ method: req.method,
195
+ url: req.url,
196
+ headers: req.headers
197
+ });
198
+ // Handle CORS for browser-based clients
199
+ res.setHeader('Access-Control-Allow-Origin', '*');
200
+ res.setHeader('Access-Control-Allow-Methods', 'GET, POST, DELETE, OPTIONS');
201
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type, X-Session-Id');
202
+ if (req.method === 'OPTIONS') {
203
+ res.writeHead(204);
204
+ res.end();
205
+ return;
206
+ }
207
+ // Parse request body for POST requests
208
+ let body = undefined;
209
+ if (req.method === 'POST') {
210
+ body = await this.parseRequestBody(req);
211
+ }
212
+ // Handle the request using the transport
213
+ try {
214
+ await this.httpTransport.handleRequest(req, res, body);
215
+ }
216
+ catch (error) {
217
+ this.logger.error('Error handling HTTP request', error);
218
+ if (!res.headersSent) {
219
+ res.writeHead(500, { 'Content-Type': 'application/json' });
220
+ res.end(JSON.stringify({ error: 'Internal server error' }));
221
+ }
222
+ }
223
+ });
224
+ // Start listening
225
+ await new Promise((resolve, reject) => {
226
+ this.httpServer.listen(port, host, () => {
227
+ this.logger.info(`HTTP server listening on ${host}:${port}`);
228
+ resolve();
229
+ }).on('error', reject);
230
+ });
231
+ }
232
+ async parseRequestBody(req) {
233
+ return new Promise((resolve, reject) => {
234
+ let body = '';
235
+ req.on('data', chunk => body += chunk.toString());
236
+ req.on('end', () => {
237
+ try {
238
+ resolve(body ? JSON.parse(body) : undefined);
239
+ }
240
+ catch (error) {
241
+ reject(error);
242
+ }
243
+ });
244
+ req.on('error', reject);
245
+ });
153
246
  }
154
247
  async stop() {
155
248
  await this.server.close();
249
+ // Stop HTTP server if running
250
+ if (this.httpServer) {
251
+ await new Promise((resolve) => {
252
+ this.httpServer.close(() => {
253
+ this.logger.info('HTTP server stopped');
254
+ resolve();
255
+ });
256
+ });
257
+ }
156
258
  this.initialized = false;
157
259
  }
158
260
  isReady() {
@@ -39,22 +39,24 @@ var __importStar = (this && this.__importStar) || (function () {
39
39
  return result;
40
40
  };
41
41
  })();
42
+ var __importDefault = (this && this.__importDefault) || function (mod) {
43
+ return (mod && mod.__esModule) ? mod : { "default": mod };
44
+ };
42
45
  Object.defineProperty(exports, "__esModule", { value: true });
43
46
  const mcp_js_1 = require("../interfaces/mcp.js");
44
47
  const index_js_1 = require("../core/index.js");
48
+ const fs_1 = require("fs");
49
+ const path_1 = __importDefault(require("path"));
45
50
  async function main() {
46
51
  try {
47
52
  // Validate required environment variables
48
53
  process.stderr.write('Validating MCP server configuration...\n');
49
54
  // Check session directory configuration
50
- const sessionDir = process.env.DOT_AI_SESSION_DIR;
51
- if (!sessionDir) {
52
- process.stderr.write('FATAL: DOT_AI_SESSION_DIR environment variable is required\n');
53
- process.stderr.write('Configuration:\n');
54
- process.stderr.write('- Set DOT_AI_SESSION_DIR in .mcp.json env section\n');
55
- process.stderr.write('- Example: "DOT_AI_SESSION_DIR": "/tmp/dot-ai-sessions"\n');
56
- process.stderr.write('- Ensure the directory exists and is writable\n');
57
- process.exit(1);
55
+ const sessionDir = process.env.DOT_AI_SESSION_DIR || '/app/sessions';
56
+ process.stderr.write(`Using session directory: ${sessionDir}\n`);
57
+ if (!process.env.DOT_AI_SESSION_DIR) {
58
+ process.stderr.write('INFO: DOT_AI_SESSION_DIR not set, using default: /app/sessions\n');
59
+ process.stderr.write('For custom session directory, set DOT_AI_SESSION_DIR environment variable\n');
58
60
  }
59
61
  // Validate session directory exists and is writable
60
62
  try {
@@ -103,15 +105,18 @@ async function main() {
103
105
  process.stderr.write(`FATAL: Failed to initialize DevOps AI Toolkit: ${initError}\n`);
104
106
  process.exit(1);
105
107
  }
108
+ // Load version dynamically from package.json
109
+ const packageJson = JSON.parse((0, fs_1.readFileSync)(path_1.default.join(__dirname, '../../package.json'), 'utf8'));
106
110
  // Create and configure MCP server
107
111
  const mcpServer = new mcp_js_1.MCPServer(dotAI, {
108
112
  name: 'dot-ai',
109
- version: '0.1.0',
113
+ version: packageJson.version,
110
114
  description: 'Universal Kubernetes application deployment agent with AI-powered orchestration',
111
115
  author: 'Viktor Farcic'
112
116
  });
113
117
  // Start the MCP server
114
- process.stderr.write('Starting DevOps AI Toolkit MCP server...\n');
118
+ const transportType = process.env.TRANSPORT_TYPE || 'stdio';
119
+ process.stderr.write(`Starting DevOps AI Toolkit MCP server with ${transportType} transport...\n`);
115
120
  await mcpServer.start();
116
121
  process.stderr.write('DevOps AI Toolkit MCP server started successfully\n');
117
122
  // Handle graceful shutdown
@@ -125,6 +130,18 @@ async function main() {
125
130
  await mcpServer.stop();
126
131
  process.exit(0);
127
132
  });
133
+ // Keep the process alive for HTTP transport
134
+ if (transportType === 'http') {
135
+ process.stderr.write('HTTP transport active - server will run until terminated\n');
136
+ // Keep the process running indefinitely for HTTP server
137
+ const keepAlive = () => {
138
+ setTimeout(keepAlive, 24 * 60 * 60 * 1000); // Check every 24 hours
139
+ };
140
+ keepAlive();
141
+ }
142
+ else {
143
+ process.stderr.write('STDIO transport active - waiting for client connection\n');
144
+ }
128
145
  }
129
146
  catch (error) {
130
147
  process.stderr.write(`Failed to start DevOps AI Toolkit MCP server: ${error}\n`);
@@ -80,7 +80,7 @@ export interface SystemStatus {
80
80
  };
81
81
  }
82
82
  /**
83
- * Test Kyverno installation and readiness for policy generation
83
+ * Test Kyverno installation and readiness for policy generation using shared client
84
84
  */
85
85
  export declare function getKyvernoStatus(): Promise<SystemStatus['kyverno']>;
86
86
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../src/tools/version.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../src/tools/version.ts"],"names":[],"mappings":"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"}
@@ -45,7 +45,9 @@ exports.getVersionInfo = getVersionInfo;
45
45
  exports.handleVersionTool = handleVersionTool;
46
46
  const fs_1 = require("fs");
47
47
  const path_1 = require("path");
48
+ const k8s = __importStar(require("@kubernetes/client-node"));
48
49
  const index_1 = require("../core/index");
50
+ const discovery_1 = require("../core/discovery");
49
51
  const kubernetes_utils_1 = require("../core/kubernetes-utils");
50
52
  exports.VERSION_TOOL_NAME = 'version';
51
53
  exports.VERSION_TOOL_DESCRIPTION = 'Get comprehensive system status including version information, Vector DB connection status, embedding service capabilities, Anthropic API connectivity, Kubernetes cluster connectivity, Kyverno policy engine status, and pattern management health check';
@@ -242,16 +244,24 @@ async function getCapabilityStatus() {
242
244
  }
243
245
  }
244
246
  /**
245
- * Test Kyverno installation and readiness for policy generation
247
+ * Test Kyverno installation and readiness for policy generation using shared client
246
248
  */
247
249
  async function getKyvernoStatus() {
248
- const kubeconfig = process.env.KUBECONFIG || '~/.kube/config';
249
250
  try {
250
- // Check if Kyverno CRDs are installed
251
- const crdOutput = await (0, kubernetes_utils_1.executeKubectl)(['get', 'crd', '--no-headers'], {
252
- kubeconfig: kubeconfig,
253
- timeout: 10000
254
- });
251
+ // Create discovery instance and establish connection
252
+ const discovery = new discovery_1.KubernetesDiscovery({});
253
+ await discovery.connect();
254
+ // First test if we can connect to Kubernetes at all
255
+ const testResult = await discovery.testConnection();
256
+ if (!testResult.connected) {
257
+ return {
258
+ installed: false,
259
+ policyGenerationReady: false,
260
+ error: 'Cannot detect Kyverno - Kubernetes cluster is not accessible'
261
+ };
262
+ }
263
+ // Check if Kyverno CRDs are installed using the original approach
264
+ const crdOutput = await discovery.executeKubectl(['get', 'crd', '--no-headers']);
255
265
  const kyvernoCRDs = crdOutput.split('\n').filter(line => line.includes('kyverno.io') && (line.includes('clusterpolicies') ||
256
266
  line.includes('policies') ||
257
267
  line.includes('policyreports')));
@@ -262,23 +272,33 @@ async function getKyvernoStatus() {
262
272
  reason: 'Kyverno CRDs not found in cluster - Kyverno is not installed'
263
273
  };
264
274
  }
265
- // Check if Kyverno deployment is ready
275
+ // Check if Kyverno deployment is ready using the client
266
276
  let deploymentReady = false;
267
277
  let webhookReady = false;
268
278
  let version;
269
279
  try {
270
- const deploymentOutput = await (0, kubernetes_utils_1.executeKubectl)([
271
- 'get', 'deployment', '-n', 'kyverno', '--no-headers'
272
- ], { kubeconfig, timeout: 5000 });
273
- // Check if kyverno deployment exists and is ready
274
- const kyvernoDeployment = deploymentOutput.split('\n').find(line => line.trim().startsWith('kyverno'));
275
- if (kyvernoDeployment) {
276
- // Parse deployment status (format: NAME READY UP-TO-DATE AVAILABLE AGE)
277
- const parts = kyvernoDeployment.trim().split(/\s+/);
278
- const ready = parts[1]; // e.g., "1/1", "0/1"
279
- if (ready && ready.includes('/')) {
280
- const [current, desired] = ready.split('/');
281
- deploymentReady = current === desired && current !== '0';
280
+ // Get client and check deployment status
281
+ const client = discovery.getClient();
282
+ const appsV1Api = client.makeApiClient(k8s.AppsV1Api);
283
+ const deploymentResponse = await appsV1Api.listNamespacedDeployment({
284
+ namespace: 'kyverno'
285
+ });
286
+ const kyvernoDeployments = deploymentResponse.items.filter((deployment) => deployment.metadata?.name?.startsWith('kyverno-'));
287
+ if (kyvernoDeployments.length > 0) {
288
+ // Check if all Kyverno deployments are ready
289
+ deploymentReady = kyvernoDeployments.every((deployment) => {
290
+ const readyReplicas = deployment.status?.readyReplicas || 0;
291
+ const replicas = deployment.status?.replicas || 0;
292
+ return readyReplicas > 0 && readyReplicas === replicas;
293
+ });
294
+ // Try to get version from image tag of the first deployment (usually admission controller)
295
+ const firstDeployment = kyvernoDeployments[0];
296
+ const container = firstDeployment.spec?.template.spec?.containers?.[0];
297
+ if (container?.image) {
298
+ const imageMatch = container.image.match(/:v?([0-9]+\.[0-9]+\.[0-9]+)/);
299
+ if (imageMatch) {
300
+ version = imageMatch[1];
301
+ }
282
302
  }
283
303
  }
284
304
  }
@@ -288,36 +308,14 @@ async function getKyvernoStatus() {
288
308
  }
289
309
  // Check admission controller webhook
290
310
  try {
291
- const webhookOutput = await (0, kubernetes_utils_1.executeKubectl)([
292
- 'get', 'validatingwebhookconfigurations', '--no-headers'
293
- ], { kubeconfig, timeout: 5000 });
294
- webhookReady = webhookOutput.includes('kyverno-');
311
+ const client = discovery.getClient();
312
+ const admissionApi = client.makeApiClient(k8s.AdmissionregistrationV1Api);
313
+ const webhookResponse = await admissionApi.listValidatingWebhookConfiguration();
314
+ webhookReady = webhookResponse.items.some((webhook) => webhook.metadata?.name?.includes('kyverno'));
295
315
  }
296
316
  catch (error) {
297
317
  webhookReady = false;
298
318
  }
299
- // Try to get version from deployment labels or image
300
- try {
301
- const deploymentDetails = await (0, kubernetes_utils_1.executeKubectl)([
302
- 'get', 'deployment', 'kyverno', '-n', 'kyverno', '-o', 'jsonpath={.metadata.labels.version}'
303
- ], { kubeconfig, timeout: 5000 });
304
- if (deploymentDetails && deploymentDetails.trim()) {
305
- version = deploymentDetails.trim();
306
- }
307
- else {
308
- // Fallback: try to get version from image tag
309
- const imageOutput = await (0, kubernetes_utils_1.executeKubectl)([
310
- 'get', 'deployment', 'kyverno', '-n', 'kyverno', '-o', 'jsonpath={.spec.template.spec.containers[0].image}'
311
- ], { kubeconfig, timeout: 5000 });
312
- const imageMatch = imageOutput.match(/:v?([0-9]+\.[0-9]+\.[0-9]+)/);
313
- if (imageMatch) {
314
- version = imageMatch[1];
315
- }
316
- }
317
- }
318
- catch (error) {
319
- // Version detection is optional
320
- }
321
319
  // Determine if policy generation is ready
322
320
  const policyGenerationReady = deploymentReady && webhookReady;
323
321
  if (!policyGenerationReady) {
@@ -348,14 +346,6 @@ async function getKyvernoStatus() {
348
346
  }
349
347
  catch (error) {
350
348
  const errorMessage = error instanceof Error ? error.message : String(error);
351
- // If Kubernetes is not available, we can't detect Kyverno
352
- if (errorMessage.includes('ECONNREFUSED') || errorMessage.includes('connection refused')) {
353
- return {
354
- installed: false,
355
- policyGenerationReady: false,
356
- error: 'Cannot detect Kyverno - Kubernetes cluster is not accessible'
357
- };
358
- }
359
349
  return {
360
350
  installed: false,
361
351
  policyGenerationReady: false,
@@ -364,55 +354,42 @@ async function getKyvernoStatus() {
364
354
  }
365
355
  }
366
356
  /**
367
- * Test Kubernetes cluster connectivity
357
+ * Test Kubernetes cluster connectivity using shared client
368
358
  */
369
359
  async function getKubernetesStatus() {
370
- const kubeconfig = process.env.KUBECONFIG || '~/.kube/config';
371
360
  try {
372
- // Test basic connectivity with cluster-info
373
- const clusterInfo = await (0, kubernetes_utils_1.executeKubectl)(['cluster-info'], {
374
- kubeconfig: kubeconfig,
375
- timeout: 10000 // 10 second timeout
376
- });
377
- // Parse cluster info to extract endpoint
378
- const endpointMatch = clusterInfo.match(/Kubernetes control plane is running at (https?:\/\/[^\s]+)/);
379
- const endpoint = endpointMatch ? endpointMatch[1] : undefined;
380
- // Get current context
381
- let context;
382
- try {
383
- context = await (0, kubernetes_utils_1.executeKubectl)(['config', 'current-context'], { kubeconfig });
384
- }
385
- catch (error) {
386
- // Context retrieval is optional
387
- context = undefined;
388
- }
389
- // Get server version
390
- let version;
391
- try {
392
- const versionInfo = await (0, kubernetes_utils_1.executeKubectl)(['version', '--short'], { kubeconfig, timeout: 5000 });
393
- const serverMatch = versionInfo.match(/Server Version: (.+)/);
394
- version = serverMatch ? serverMatch[1] : undefined;
361
+ // Create discovery instance and establish connection
362
+ const discovery = new discovery_1.KubernetesDiscovery({});
363
+ await discovery.connect();
364
+ // Get connection info using the shared approach
365
+ const connectionInfo = discovery.getConnectionInfo();
366
+ const testResult = await discovery.testConnection();
367
+ if (testResult.connected) {
368
+ return {
369
+ connected: true,
370
+ clusterInfo: {
371
+ endpoint: connectionInfo.server,
372
+ version: testResult.version,
373
+ context: connectionInfo.context
374
+ },
375
+ kubeconfig: connectionInfo.kubeconfig
376
+ };
395
377
  }
396
- catch (error) {
397
- // Version retrieval is optional
398
- version = undefined;
378
+ else {
379
+ return {
380
+ connected: false,
381
+ kubeconfig: connectionInfo.kubeconfig,
382
+ error: testResult.error,
383
+ errorType: testResult.errorType
384
+ };
399
385
  }
400
- return {
401
- connected: true,
402
- clusterInfo: {
403
- endpoint,
404
- version,
405
- context
406
- },
407
- kubeconfig
408
- };
409
386
  }
410
387
  catch (error) {
411
388
  const errorMessage = error instanceof Error ? error.message : String(error);
412
389
  const classified = kubernetes_utils_1.ErrorClassifier.classifyError(error);
413
390
  return {
414
391
  connected: false,
415
- kubeconfig,
392
+ kubeconfig: process.env.KUBECONFIG || '~/.kube/config',
416
393
  error: errorMessage,
417
394
  errorType: classified.type
418
395
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vfarcic/dot-ai",
3
- "version": "0.82.0",
3
+ "version": "0.83.0",
4
4
  "description": "AI-powered development productivity platform that enhances software development workflows through intelligent automation and AI-driven assistance",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -83,11 +83,11 @@
83
83
  "typescript": "^5.0.0"
84
84
  },
85
85
  "dependencies": {
86
- "@anthropic-ai/sdk": "^0.60.0",
86
+ "@anthropic-ai/sdk": "^0.61.0",
87
87
  "@kubernetes/client-node": "^1.3.0",
88
88
  "@modelcontextprotocol/sdk": "^1.13.2",
89
89
  "@qdrant/js-client-rest": "^1.15.0",
90
- "@vfarcic/dot-ai": "^0.73.0",
90
+ "@vfarcic/dot-ai": "^0.82.0",
91
91
  "glob": "^11.0.3",
92
92
  "openai": "^5.11.0",
93
93
  "yaml": "^2.8.0"
@@ -59,9 +59,10 @@ Complete the PRD implementation workflow including branch management, pull reque
59
59
  - [ ] **Check ongoing processes**: Use `gh pr checks [pr-number]` to check for any ongoing CI/CD, security analysis, or automated reviews (CodeRabbit, CodeQL, etc.)
60
60
  - [ ] **Check PR details**: Use `gh pr view [pr-number]` to check for human review comments and PR metadata
61
61
  - [ ] **Review all automated feedback**: Check PR comments section for automated code review feedback (bots, linters, analyzers)
62
- - Look for actionable suggestions about code quality, security, performance, or maintainability
63
- - Check for recommendations about test coverage, error handling, or architectural improvements
64
- - Review suggestions for refactoring, type safety, or code organization
62
+ - **Use multiple methods to capture all feedback**:
63
+ - CLI commands: `gh pr view [pr-number]`, `gh pr checks [pr-number]`, `gh api repos/owner/repo/pulls/[pr-number]/comments`
64
+ - **Web interface inspection**: Fetch the PR URL directly to capture all comments, including inline code suggestions that CLI tools may miss
65
+ - Look for comments from automated tools (usernames ending in 'ai', 'bot', or known review tools)
65
66
  - [ ] **Present code review findings**: ALWAYS summarize automated review feedback for the user (unless there are no findings)
66
67
  - **Categorize findings**: Critical, Important, Optional based on impact
67
68
  - **Provide specific examples**: Quote actual suggestions and their locations