@vfarcic/dot-ai 0.5.1 → 0.6.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/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/{src/cli.ts → dist/cli.js} +19 -26
- package/dist/core/claude.d.ts +42 -0
- package/dist/core/claude.d.ts.map +1 -0
- package/dist/core/claude.js +229 -0
- package/dist/core/deploy-operation.d.ts +38 -0
- package/dist/core/deploy-operation.d.ts.map +1 -0
- package/dist/core/deploy-operation.js +101 -0
- package/dist/core/discovery.d.ts +162 -0
- package/dist/core/discovery.d.ts.map +1 -0
- package/dist/core/discovery.js +758 -0
- package/dist/core/error-handling.d.ts +167 -0
- package/dist/core/error-handling.d.ts.map +1 -0
- package/dist/core/error-handling.js +399 -0
- package/dist/core/index.d.ts +42 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +123 -0
- package/dist/core/kubernetes-utils.d.ts +38 -0
- package/dist/core/kubernetes-utils.d.ts.map +1 -0
- package/dist/core/kubernetes-utils.js +177 -0
- package/dist/core/memory.d.ts +45 -0
- package/dist/core/memory.d.ts.map +1 -0
- package/dist/core/memory.js +113 -0
- package/dist/core/schema.d.ts +187 -0
- package/dist/core/schema.d.ts.map +1 -0
- package/dist/core/schema.js +655 -0
- package/dist/core/session-utils.d.ts +29 -0
- package/dist/core/session-utils.d.ts.map +1 -0
- package/dist/core/session-utils.js +121 -0
- package/dist/core/workflow.d.ts +70 -0
- package/dist/core/workflow.d.ts.map +1 -0
- package/dist/core/workflow.js +161 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -0
- package/dist/interfaces/cli.d.ts +74 -0
- package/dist/interfaces/cli.d.ts.map +1 -0
- package/dist/interfaces/cli.js +769 -0
- package/dist/interfaces/mcp.d.ts +30 -0
- package/dist/interfaces/mcp.d.ts.map +1 -0
- package/dist/interfaces/mcp.js +105 -0
- package/dist/mcp/server.d.ts +9 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +151 -0
- package/dist/tools/answer-question.d.ts +27 -0
- package/dist/tools/answer-question.d.ts.map +1 -0
- package/dist/tools/answer-question.js +696 -0
- package/dist/tools/choose-solution.d.ts +23 -0
- package/dist/tools/choose-solution.d.ts.map +1 -0
- package/dist/tools/choose-solution.js +171 -0
- package/dist/tools/deploy-manifests.d.ts +25 -0
- package/dist/tools/deploy-manifests.d.ts.map +1 -0
- package/dist/tools/deploy-manifests.js +74 -0
- package/dist/tools/generate-manifests.d.ts +23 -0
- package/dist/tools/generate-manifests.d.ts.map +1 -0
- package/dist/tools/generate-manifests.js +424 -0
- package/dist/tools/index.d.ts +11 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +34 -0
- package/dist/tools/recommend.d.ts +23 -0
- package/dist/tools/recommend.d.ts.map +1 -0
- package/dist/tools/recommend.js +332 -0
- package/package.json +124 -2
- package/.claude/commands/context-load.md +0 -11
- package/.claude/commands/context-save.md +0 -16
- package/.claude/commands/prd-done.md +0 -115
- package/.claude/commands/prd-get.md +0 -25
- package/.claude/commands/prd-start.md +0 -87
- package/.claude/commands/task-done.md +0 -77
- package/.claude/commands/tests-reminder.md +0 -32
- package/.claude/settings.local.json +0 -20
- package/.eslintrc.json +0 -25
- package/.github/workflows/ci.yml +0 -170
- package/.prettierrc.json +0 -10
- package/.teller.yml +0 -8
- package/CLAUDE.md +0 -162
- package/assets/images/logo.png +0 -0
- package/bin/dot-ai.ts +0 -47
- package/bin.js +0 -19
- package/destroy.sh +0 -45
- package/devbox.json +0 -13
- package/devbox.lock +0 -225
- package/docs/API.md +0 -449
- package/docs/CONTEXT.md +0 -49
- package/docs/DEVELOPMENT.md +0 -203
- package/docs/NEXT_STEPS.md +0 -97
- package/docs/STAGE_BASED_API.md +0 -97
- package/docs/cli-guide.md +0 -798
- package/docs/design.md +0 -750
- package/docs/discovery-engine.md +0 -515
- package/docs/error-handling.md +0 -429
- package/docs/function-registration.md +0 -157
- package/docs/mcp-guide.md +0 -416
- package/renovate.json +0 -51
- package/setup.sh +0 -111
- package/src/core/claude.ts +0 -280
- package/src/core/deploy-operation.ts +0 -127
- package/src/core/discovery.ts +0 -900
- package/src/core/error-handling.ts +0 -562
- package/src/core/index.ts +0 -143
- package/src/core/kubernetes-utils.ts +0 -218
- package/src/core/memory.ts +0 -148
- package/src/core/schema.ts +0 -830
- package/src/core/session-utils.ts +0 -97
- package/src/core/workflow.ts +0 -234
- package/src/index.ts +0 -18
- package/src/interfaces/cli.ts +0 -872
- package/src/interfaces/mcp.ts +0 -183
- package/src/mcp/server.ts +0 -131
- package/src/tools/answer-question.ts +0 -807
- package/src/tools/choose-solution.ts +0 -169
- package/src/tools/deploy-manifests.ts +0 -94
- package/src/tools/generate-manifests.ts +0 -502
- package/src/tools/index.ts +0 -41
- package/src/tools/recommend.ts +0 -370
- package/tests/__mocks__/@kubernetes/client-node.ts +0 -106
- package/tests/build-system.test.ts +0 -345
- package/tests/configuration.test.ts +0 -226
- package/tests/core/deploy-operation.test.ts +0 -38
- package/tests/core/discovery.test.ts +0 -1648
- package/tests/core/error-handling.test.ts +0 -632
- package/tests/core/schema.test.ts +0 -1658
- package/tests/core/session-utils.test.ts +0 -245
- package/tests/core.test.ts +0 -439
- package/tests/fixtures/configmap-no-labels.yaml +0 -8
- package/tests/fixtures/crossplane-app-configuration.yaml +0 -6
- package/tests/fixtures/crossplane-providers.yaml +0 -45
- package/tests/fixtures/crossplane-rbac.yaml +0 -48
- package/tests/fixtures/invalid-configmap.yaml +0 -8
- package/tests/fixtures/invalid-deployment.yaml +0 -17
- package/tests/fixtures/test-deployment.yaml +0 -28
- package/tests/fixtures/valid-configmap.yaml +0 -15
- package/tests/infrastructure.test.ts +0 -426
- package/tests/interfaces/cli.test.ts +0 -1036
- package/tests/interfaces/mcp.test.ts +0 -139
- package/tests/kubernetes-utils.test.ts +0 -200
- package/tests/mcp/server.test.ts +0 -126
- package/tests/setup.ts +0 -31
- package/tests/tools/answer-question.test.ts +0 -367
- package/tests/tools/choose-solution.test.ts +0 -481
- package/tests/tools/deploy-manifests.test.ts +0 -185
- package/tests/tools/generate-manifests.test.ts +0 -441
- package/tests/tools/index.test.ts +0 -111
- package/tests/tools/recommend.test.ts +0 -180
- package/tsconfig.json +0 -34
package/src/core/claude.ts
DELETED
|
@@ -1,280 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Claude Integration Module
|
|
3
|
-
*
|
|
4
|
-
* Handles AI communication, YAML generation, and learning integration
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import Anthropic from '@anthropic-ai/sdk';
|
|
8
|
-
|
|
9
|
-
export interface ClaudeResponse {
|
|
10
|
-
content: string;
|
|
11
|
-
usage: {
|
|
12
|
-
input_tokens: number;
|
|
13
|
-
output_tokens: number;
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface YAMLResponse {
|
|
18
|
-
yaml: string;
|
|
19
|
-
explanation: string;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export interface Interaction {
|
|
23
|
-
input: string;
|
|
24
|
-
output: string;
|
|
25
|
-
success: boolean;
|
|
26
|
-
timestamp?: Date;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export class ClaudeIntegration {
|
|
30
|
-
private client: Anthropic | null = null;
|
|
31
|
-
private apiKey: string;
|
|
32
|
-
private conversationHistory: any[] = [];
|
|
33
|
-
private interactions: Interaction[] = [];
|
|
34
|
-
|
|
35
|
-
constructor(apiKey: string) {
|
|
36
|
-
this.apiKey = apiKey;
|
|
37
|
-
this.validateApiKey();
|
|
38
|
-
|
|
39
|
-
if (this.apiKey) {
|
|
40
|
-
this.client = new Anthropic({
|
|
41
|
-
apiKey: this.apiKey,
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
private validateApiKey(): void {
|
|
47
|
-
// Allow test-friendly initialization
|
|
48
|
-
if (this.apiKey === 'test-key' || this.apiKey === 'mock-key') {
|
|
49
|
-
return; // Allow test keys
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (!this.apiKey) {
|
|
53
|
-
throw new Error('API key is required for Claude integration');
|
|
54
|
-
}
|
|
55
|
-
if (this.apiKey.length === 0) {
|
|
56
|
-
throw new Error('Invalid API key: API key cannot be empty');
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
async sendMessage(message: string): Promise<ClaudeResponse> {
|
|
61
|
-
if (!this.client) {
|
|
62
|
-
throw new Error('Claude client not initialized due to missing API key');
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (this.apiKey === 'invalid-key') {
|
|
66
|
-
throw new Error('Authentication failed: Invalid API key');
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
try {
|
|
70
|
-
// Add message to conversation history
|
|
71
|
-
this.conversationHistory.push({ role: 'user', content: message });
|
|
72
|
-
|
|
73
|
-
// Use real Claude API if we have a real API key, otherwise fall back to mocks
|
|
74
|
-
if (this.apiKey.startsWith('sk-ant-') && this.client) {
|
|
75
|
-
// Make real API call to Claude
|
|
76
|
-
const completion = await this.client.messages.create({
|
|
77
|
-
model: 'claude-3-5-sonnet-20241022',
|
|
78
|
-
max_tokens: 4000,
|
|
79
|
-
messages: [{ role: 'user', content: message }]
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
const content = completion.content[0].type === 'text' ? completion.content[0].text : '';
|
|
83
|
-
const response: ClaudeResponse = {
|
|
84
|
-
content,
|
|
85
|
-
usage: {
|
|
86
|
-
input_tokens: completion.usage.input_tokens,
|
|
87
|
-
output_tokens: completion.usage.output_tokens
|
|
88
|
-
}
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
this.conversationHistory.push({ role: 'assistant', content: response.content });
|
|
92
|
-
return response;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// For testing purposes, return mock responses
|
|
96
|
-
if (message.toLowerCase().includes('deploy a web application')) {
|
|
97
|
-
const response: ClaudeResponse = {
|
|
98
|
-
content: 'I can help you deploy a web application to Kubernetes. Let me guide you through the process of creating the necessary YAML manifests for your deployment.',
|
|
99
|
-
usage: { input_tokens: 10, output_tokens: 25 }
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
this.conversationHistory.push({ role: 'assistant', content: response.content });
|
|
103
|
-
return response;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
if (message.toLowerCase().includes('recommended resources') &&
|
|
107
|
-
this.conversationHistory.some(msg => msg.content.toLowerCase().includes('nginx'))) {
|
|
108
|
-
const response: ClaudeResponse = {
|
|
109
|
-
content: 'For nginx deployment, I recommend starting with 2 replicas, 500m CPU and 512Mi memory per pod. You can adjust these based on your traffic patterns.',
|
|
110
|
-
usage: { input_tokens: 8, output_tokens: 30 }
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
this.conversationHistory.push({ role: 'assistant', content: response.content });
|
|
114
|
-
return response;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// Default mock response
|
|
118
|
-
const response: ClaudeResponse = {
|
|
119
|
-
content: 'I understand you want help with Kubernetes deployment. Could you provide more specific details about what you\'d like to deploy?',
|
|
120
|
-
usage: { input_tokens: message.length / 4, output_tokens: 20 }
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
this.conversationHistory.push({ role: 'assistant', content: response.content });
|
|
124
|
-
return response;
|
|
125
|
-
|
|
126
|
-
} catch (error) {
|
|
127
|
-
throw new Error(`Claude API error: ${error}`);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
async generateYAML(resourceType: string, config: any): Promise<YAMLResponse> {
|
|
132
|
-
if (!this.client) {
|
|
133
|
-
throw new Error('Claude client not initialized');
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// Mock YAML generation for testing
|
|
137
|
-
if (resourceType === 'deployment' && config.app === 'nginx') {
|
|
138
|
-
return {
|
|
139
|
-
yaml: `apiVersion: apps/v1
|
|
140
|
-
kind: Deployment
|
|
141
|
-
metadata:
|
|
142
|
-
name: ${config.app}
|
|
143
|
-
labels:
|
|
144
|
-
app: ${config.app}
|
|
145
|
-
spec:
|
|
146
|
-
replicas: ${config.replicas || 1}
|
|
147
|
-
selector:
|
|
148
|
-
matchLabels:
|
|
149
|
-
app: ${config.app}
|
|
150
|
-
template:
|
|
151
|
-
metadata:
|
|
152
|
-
labels:
|
|
153
|
-
app: ${config.app}
|
|
154
|
-
spec:
|
|
155
|
-
containers:
|
|
156
|
-
- name: ${config.app}
|
|
157
|
-
image: ${config.image}
|
|
158
|
-
ports:
|
|
159
|
-
- containerPort: 80`,
|
|
160
|
-
explanation: `This deployment creates ${config.replicas || 1} replica(s) of ${config.app} using the ${config.image} image. The container exposes port 80 for web traffic.`
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// Default YAML response
|
|
165
|
-
return {
|
|
166
|
-
yaml: `apiVersion: apps/v1
|
|
167
|
-
kind: ${resourceType.charAt(0).toUpperCase() + resourceType.slice(1)}
|
|
168
|
-
metadata:
|
|
169
|
-
name: example-${resourceType}
|
|
170
|
-
spec:
|
|
171
|
-
# Generated configuration would go here`,
|
|
172
|
-
explanation: `This is a basic ${resourceType} manifest. You should customize it based on your specific requirements.`
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
async recordInteraction(interaction: Interaction): Promise<void> {
|
|
177
|
-
const recordedInteraction = {
|
|
178
|
-
...interaction,
|
|
179
|
-
timestamp: new Date()
|
|
180
|
-
};
|
|
181
|
-
|
|
182
|
-
this.interactions.push(recordedInteraction);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
async getSuccessfulPatterns(): Promise<Interaction[]> {
|
|
186
|
-
return this.interactions.filter(interaction => interaction.success);
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
getConversationHistory(): any[] {
|
|
190
|
-
return [...this.conversationHistory];
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
clearConversationHistory(): void {
|
|
194
|
-
this.conversationHistory = [];
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
async generateManifest(spec: any): Promise<string> {
|
|
198
|
-
if (!this.client) {
|
|
199
|
-
throw new Error('Claude client not initialized');
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
// Simulate manifest generation
|
|
203
|
-
const yamlContent = `
|
|
204
|
-
apiVersion: apps/v1
|
|
205
|
-
kind: Deployment
|
|
206
|
-
metadata:
|
|
207
|
-
name: ${spec.name || 'app'}
|
|
208
|
-
spec:
|
|
209
|
-
replicas: ${spec.replicas || 1}
|
|
210
|
-
selector:
|
|
211
|
-
matchLabels:
|
|
212
|
-
app: ${spec.name || 'app'}
|
|
213
|
-
template:
|
|
214
|
-
metadata:
|
|
215
|
-
labels:
|
|
216
|
-
app: ${spec.name || 'app'}
|
|
217
|
-
spec:
|
|
218
|
-
containers:
|
|
219
|
-
- name: app
|
|
220
|
-
image: ${spec.image || 'nginx:latest'}
|
|
221
|
-
ports:
|
|
222
|
-
- containerPort: 80
|
|
223
|
-
`;
|
|
224
|
-
|
|
225
|
-
return yamlContent.trim();
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
async analyzeError(error: string, _context?: any): Promise<string> {
|
|
229
|
-
if (!this.client) {
|
|
230
|
-
throw new Error('Claude client not initialized');
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
// Simulate error analysis
|
|
234
|
-
return `Error analysis: ${error}. Suggested fix: Check the configuration and try again.`;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
async suggestImprovements(_manifest: string): Promise<string[]> {
|
|
238
|
-
if (!this.client) {
|
|
239
|
-
throw new Error('Claude client not initialized');
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
// Simulate improvement suggestions
|
|
243
|
-
return [
|
|
244
|
-
'Add resource limits and requests',
|
|
245
|
-
'Consider adding health checks',
|
|
246
|
-
'Add labels for better organization'
|
|
247
|
-
];
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
async processUserInput(input: string, context?: any): Promise<any> {
|
|
251
|
-
if (!this.client) {
|
|
252
|
-
throw new Error('Claude client not initialized');
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
// Simulate interactive workflow processing
|
|
256
|
-
if (input.toLowerCase().includes('deploy') && context?.interactive) {
|
|
257
|
-
return {
|
|
258
|
-
phase: 'Planning',
|
|
259
|
-
questions: ['What type of database do you need?']
|
|
260
|
-
};
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
if (context?.responses) {
|
|
264
|
-
return {
|
|
265
|
-
phase: 'Validation',
|
|
266
|
-
nextSteps: ['Review generated manifest']
|
|
267
|
-
};
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
// Default response
|
|
271
|
-
return {
|
|
272
|
-
phase: 'Discovery',
|
|
273
|
-
suggestions: ['Start by exploring your cluster resources']
|
|
274
|
-
};
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
isInitialized(): boolean {
|
|
278
|
-
return this.client !== null;
|
|
279
|
-
}
|
|
280
|
-
}
|
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Deploy Operation - Handles Kubernetes manifest deployment with readiness checking
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { access } from 'fs/promises';
|
|
6
|
-
import { join } from 'path';
|
|
7
|
-
import { ErrorHandler } from './error-handling';
|
|
8
|
-
import { executeKubectl, KubectlConfig } from './kubernetes-utils';
|
|
9
|
-
|
|
10
|
-
export interface DeployOptions {
|
|
11
|
-
solutionId: string;
|
|
12
|
-
sessionDir?: string;
|
|
13
|
-
timeout?: number;
|
|
14
|
-
kubeconfig?: string;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface DeployResult {
|
|
18
|
-
success: boolean;
|
|
19
|
-
solutionId: string;
|
|
20
|
-
manifestPath: string;
|
|
21
|
-
readinessTimeout: boolean;
|
|
22
|
-
message: string;
|
|
23
|
-
kubectlOutput: string;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export class DeployOperation {
|
|
27
|
-
private kubectlConfig: KubectlConfig;
|
|
28
|
-
|
|
29
|
-
constructor(kubeconfig?: string) {
|
|
30
|
-
this.kubectlConfig = {
|
|
31
|
-
kubeconfig: kubeconfig || process.env.KUBECONFIG
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Deploy Kubernetes manifests from generated solution
|
|
37
|
-
*/
|
|
38
|
-
public async deploy(options: DeployOptions): Promise<DeployResult> {
|
|
39
|
-
return ErrorHandler.withErrorHandling(
|
|
40
|
-
async () => {
|
|
41
|
-
const manifestPath = this.getManifestPath(options);
|
|
42
|
-
|
|
43
|
-
// Verify manifest file exists
|
|
44
|
-
await this.verifyManifestExists(manifestPath);
|
|
45
|
-
|
|
46
|
-
// Update kubeconfig if provided in options
|
|
47
|
-
const kubectlConfig = {
|
|
48
|
-
...this.kubectlConfig,
|
|
49
|
-
kubeconfig: options.kubeconfig || this.kubectlConfig.kubeconfig
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
// Apply manifests with kubectl
|
|
53
|
-
const kubectlOutput = await this.applyManifests(manifestPath, options.timeout || 30, kubectlConfig);
|
|
54
|
-
|
|
55
|
-
return {
|
|
56
|
-
success: true,
|
|
57
|
-
solutionId: options.solutionId,
|
|
58
|
-
manifestPath,
|
|
59
|
-
readinessTimeout: false,
|
|
60
|
-
message: 'Deployment completed successfully',
|
|
61
|
-
kubectlOutput
|
|
62
|
-
};
|
|
63
|
-
},
|
|
64
|
-
{
|
|
65
|
-
operation: 'deploy',
|
|
66
|
-
component: 'deploy-operation'
|
|
67
|
-
}
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Get the manifest file path for the solution
|
|
73
|
-
*/
|
|
74
|
-
private getManifestPath(options: DeployOptions): string {
|
|
75
|
-
const sessionDir = options.sessionDir || process.env.DOT_AI_SESSION_DIR;
|
|
76
|
-
if (!sessionDir) {
|
|
77
|
-
throw new Error('Session directory not configured. Set DOT_AI_SESSION_DIR environment variable or provide sessionDir parameter.');
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
return join(sessionDir, `${options.solutionId}.yaml`);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Verify that the manifest file exists
|
|
85
|
-
*/
|
|
86
|
-
private async verifyManifestExists(manifestPath: string): Promise<void> {
|
|
87
|
-
try {
|
|
88
|
-
await access(manifestPath);
|
|
89
|
-
} catch (error) {
|
|
90
|
-
throw new Error(`Manifest file not found: ${manifestPath}`);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Apply manifests using kubectl with readiness checking
|
|
96
|
-
*/
|
|
97
|
-
private async applyManifests(manifestPath: string, timeout: number, kubectlConfig: KubectlConfig): Promise<string> {
|
|
98
|
-
// First, apply the manifests
|
|
99
|
-
const applyResult = await executeKubectl(['apply', '-f', `"${manifestPath}"`], kubectlConfig);
|
|
100
|
-
|
|
101
|
-
// Try to wait for deployments to be ready (ignore failures for other resource types)
|
|
102
|
-
let waitOutput = '';
|
|
103
|
-
try {
|
|
104
|
-
const waitResult = await executeKubectl([
|
|
105
|
-
'wait',
|
|
106
|
-
'--for=condition=available',
|
|
107
|
-
'deployments',
|
|
108
|
-
'--all',
|
|
109
|
-
`--timeout=${timeout}s`,
|
|
110
|
-
'--all-namespaces'
|
|
111
|
-
], {
|
|
112
|
-
...kubectlConfig,
|
|
113
|
-
timeout: (timeout + 10) * 1000 // Add 10 seconds buffer for kubectl command itself
|
|
114
|
-
});
|
|
115
|
-
waitOutput = `\n\nWait output:\n${waitResult}`;
|
|
116
|
-
} catch (waitError: any) {
|
|
117
|
-
// If no deployments found or wait fails, that's OK for ConfigMaps, Services, etc.
|
|
118
|
-
if (waitError.message && waitError.message.includes('no matching resources found')) {
|
|
119
|
-
waitOutput = '\n\nWait output: No deployments found to wait for (likely ConfigMaps, Services, etc.)';
|
|
120
|
-
} else {
|
|
121
|
-
waitOutput = `\n\nWait output: Warning - ${waitError.message}`;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
return `Apply output:\n${applyResult}${waitOutput}`;
|
|
126
|
-
}
|
|
127
|
-
}
|