@vfarcic/dot-ai 0.5.0 → 0.5.1

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 (145) hide show
  1. package/.claude/commands/context-load.md +11 -0
  2. package/.claude/commands/context-save.md +16 -0
  3. package/.claude/commands/prd-done.md +115 -0
  4. package/.claude/commands/prd-get.md +25 -0
  5. package/.claude/commands/prd-start.md +87 -0
  6. package/.claude/commands/task-done.md +77 -0
  7. package/.claude/commands/tests-reminder.md +32 -0
  8. package/.claude/settings.local.json +20 -0
  9. package/.eslintrc.json +25 -0
  10. package/.github/workflows/ci.yml +170 -0
  11. package/.prettierrc.json +10 -0
  12. package/.teller.yml +8 -0
  13. package/CLAUDE.md +162 -0
  14. package/assets/images/logo.png +0 -0
  15. package/bin/dot-ai.ts +47 -0
  16. package/destroy.sh +45 -0
  17. package/devbox.json +13 -0
  18. package/devbox.lock +225 -0
  19. package/docs/API.md +449 -0
  20. package/docs/CONTEXT.md +49 -0
  21. package/docs/DEVELOPMENT.md +203 -0
  22. package/docs/NEXT_STEPS.md +97 -0
  23. package/docs/STAGE_BASED_API.md +97 -0
  24. package/docs/cli-guide.md +798 -0
  25. package/docs/design.md +750 -0
  26. package/docs/discovery-engine.md +515 -0
  27. package/docs/error-handling.md +429 -0
  28. package/docs/function-registration.md +157 -0
  29. package/docs/mcp-guide.md +416 -0
  30. package/package.json +2 -121
  31. package/renovate.json +51 -0
  32. package/setup.sh +111 -0
  33. package/{dist/cli.js → src/cli.ts} +26 -19
  34. package/src/core/claude.ts +280 -0
  35. package/src/core/deploy-operation.ts +127 -0
  36. package/src/core/discovery.ts +900 -0
  37. package/src/core/error-handling.ts +562 -0
  38. package/src/core/index.ts +143 -0
  39. package/src/core/kubernetes-utils.ts +218 -0
  40. package/src/core/memory.ts +148 -0
  41. package/src/core/schema.ts +830 -0
  42. package/src/core/session-utils.ts +97 -0
  43. package/src/core/workflow.ts +234 -0
  44. package/src/index.ts +18 -0
  45. package/src/interfaces/cli.ts +872 -0
  46. package/src/interfaces/mcp.ts +183 -0
  47. package/src/mcp/server.ts +131 -0
  48. package/src/tools/answer-question.ts +807 -0
  49. package/src/tools/choose-solution.ts +169 -0
  50. package/src/tools/deploy-manifests.ts +94 -0
  51. package/src/tools/generate-manifests.ts +502 -0
  52. package/src/tools/index.ts +41 -0
  53. package/src/tools/recommend.ts +370 -0
  54. package/tests/__mocks__/@kubernetes/client-node.ts +106 -0
  55. package/tests/build-system.test.ts +345 -0
  56. package/tests/configuration.test.ts +226 -0
  57. package/tests/core/deploy-operation.test.ts +38 -0
  58. package/tests/core/discovery.test.ts +1648 -0
  59. package/tests/core/error-handling.test.ts +632 -0
  60. package/tests/core/schema.test.ts +1658 -0
  61. package/tests/core/session-utils.test.ts +245 -0
  62. package/tests/core.test.ts +439 -0
  63. package/tests/fixtures/configmap-no-labels.yaml +8 -0
  64. package/tests/fixtures/crossplane-app-configuration.yaml +6 -0
  65. package/tests/fixtures/crossplane-providers.yaml +45 -0
  66. package/tests/fixtures/crossplane-rbac.yaml +48 -0
  67. package/tests/fixtures/invalid-configmap.yaml +8 -0
  68. package/tests/fixtures/invalid-deployment.yaml +17 -0
  69. package/tests/fixtures/test-deployment.yaml +28 -0
  70. package/tests/fixtures/valid-configmap.yaml +15 -0
  71. package/tests/infrastructure.test.ts +426 -0
  72. package/tests/interfaces/cli.test.ts +1036 -0
  73. package/tests/interfaces/mcp.test.ts +139 -0
  74. package/tests/kubernetes-utils.test.ts +200 -0
  75. package/tests/mcp/server.test.ts +126 -0
  76. package/tests/setup.ts +31 -0
  77. package/tests/tools/answer-question.test.ts +367 -0
  78. package/tests/tools/choose-solution.test.ts +481 -0
  79. package/tests/tools/deploy-manifests.test.ts +185 -0
  80. package/tests/tools/generate-manifests.test.ts +441 -0
  81. package/tests/tools/index.test.ts +111 -0
  82. package/tests/tools/recommend.test.ts +180 -0
  83. package/tsconfig.json +34 -0
  84. package/dist/cli.d.ts +0 -3
  85. package/dist/cli.d.ts.map +0 -1
  86. package/dist/core/claude.d.ts +0 -42
  87. package/dist/core/claude.d.ts.map +0 -1
  88. package/dist/core/claude.js +0 -229
  89. package/dist/core/deploy-operation.d.ts +0 -38
  90. package/dist/core/deploy-operation.d.ts.map +0 -1
  91. package/dist/core/deploy-operation.js +0 -101
  92. package/dist/core/discovery.d.ts +0 -162
  93. package/dist/core/discovery.d.ts.map +0 -1
  94. package/dist/core/discovery.js +0 -758
  95. package/dist/core/error-handling.d.ts +0 -167
  96. package/dist/core/error-handling.d.ts.map +0 -1
  97. package/dist/core/error-handling.js +0 -399
  98. package/dist/core/index.d.ts +0 -42
  99. package/dist/core/index.d.ts.map +0 -1
  100. package/dist/core/index.js +0 -123
  101. package/dist/core/kubernetes-utils.d.ts +0 -38
  102. package/dist/core/kubernetes-utils.d.ts.map +0 -1
  103. package/dist/core/kubernetes-utils.js +0 -177
  104. package/dist/core/memory.d.ts +0 -45
  105. package/dist/core/memory.d.ts.map +0 -1
  106. package/dist/core/memory.js +0 -113
  107. package/dist/core/schema.d.ts +0 -187
  108. package/dist/core/schema.d.ts.map +0 -1
  109. package/dist/core/schema.js +0 -655
  110. package/dist/core/session-utils.d.ts +0 -29
  111. package/dist/core/session-utils.d.ts.map +0 -1
  112. package/dist/core/session-utils.js +0 -121
  113. package/dist/core/workflow.d.ts +0 -70
  114. package/dist/core/workflow.d.ts.map +0 -1
  115. package/dist/core/workflow.js +0 -161
  116. package/dist/index.d.ts +0 -15
  117. package/dist/index.d.ts.map +0 -1
  118. package/dist/index.js +0 -32
  119. package/dist/interfaces/cli.d.ts +0 -74
  120. package/dist/interfaces/cli.d.ts.map +0 -1
  121. package/dist/interfaces/cli.js +0 -769
  122. package/dist/interfaces/mcp.d.ts +0 -30
  123. package/dist/interfaces/mcp.d.ts.map +0 -1
  124. package/dist/interfaces/mcp.js +0 -105
  125. package/dist/mcp/server.d.ts +0 -9
  126. package/dist/mcp/server.d.ts.map +0 -1
  127. package/dist/mcp/server.js +0 -151
  128. package/dist/tools/answer-question.d.ts +0 -27
  129. package/dist/tools/answer-question.d.ts.map +0 -1
  130. package/dist/tools/answer-question.js +0 -696
  131. package/dist/tools/choose-solution.d.ts +0 -23
  132. package/dist/tools/choose-solution.d.ts.map +0 -1
  133. package/dist/tools/choose-solution.js +0 -171
  134. package/dist/tools/deploy-manifests.d.ts +0 -25
  135. package/dist/tools/deploy-manifests.d.ts.map +0 -1
  136. package/dist/tools/deploy-manifests.js +0 -74
  137. package/dist/tools/generate-manifests.d.ts +0 -23
  138. package/dist/tools/generate-manifests.d.ts.map +0 -1
  139. package/dist/tools/generate-manifests.js +0 -424
  140. package/dist/tools/index.d.ts +0 -11
  141. package/dist/tools/index.d.ts.map +0 -1
  142. package/dist/tools/index.js +0 -34
  143. package/dist/tools/recommend.d.ts +0 -23
  144. package/dist/tools/recommend.d.ts.map +0 -1
  145. package/dist/tools/recommend.js +0 -332
@@ -0,0 +1,345 @@
1
+ /**
2
+ * Build System Tests (TDD Implementation)
3
+ *
4
+ * Tests written FIRST to define requirements for production-ready build system
5
+ * Supporting both CLI binary and MCP server from unified TypeScript package
6
+ */
7
+
8
+ import * as fs from 'fs';
9
+ import * as path from 'path';
10
+ import { execSync } from 'child_process';
11
+
12
+ describe('Build System Validation (TDD)', () => {
13
+ const projectRoot = process.cwd();
14
+ const distDir = path.join(projectRoot, 'dist');
15
+ const packageJsonPath = path.join(projectRoot, 'package.json');
16
+
17
+ beforeAll(() => {
18
+ // Ensure clean build for testing
19
+ if (fs.existsSync(distDir)) {
20
+ fs.rmSync(distDir, { recursive: true });
21
+ }
22
+ });
23
+
24
+ describe('TypeScript Compilation Requirements', () => {
25
+ test('should compile TypeScript without errors', () => {
26
+ expect(() => {
27
+ execSync('npx tsc --noEmit', { cwd: projectRoot, stdio: 'pipe' });
28
+ }).not.toThrow();
29
+ });
30
+
31
+ test('should generate clean JavaScript output', () => {
32
+ execSync('npm run build', { cwd: projectRoot, stdio: 'pipe' });
33
+
34
+ expect(fs.existsSync(distDir)).toBe(true);
35
+ expect(fs.existsSync(path.join(distDir, 'core', 'index.js'))).toBe(true);
36
+ expect(fs.existsSync(path.join(distDir, 'interfaces', 'cli.js'))).toBe(true);
37
+ expect(fs.existsSync(path.join(distDir, 'interfaces', 'mcp.js'))).toBe(true);
38
+ });
39
+
40
+ test('should preserve module structure in output', () => {
41
+ const coreDir = path.join(distDir, 'core');
42
+ const interfacesDir = path.join(distDir, 'interfaces');
43
+
44
+ expect(fs.existsSync(coreDir)).toBe(true);
45
+ expect(fs.existsSync(interfacesDir)).toBe(true);
46
+
47
+ // Check core modules
48
+ const coreModules = ['index.js', 'discovery.js', 'memory.js', 'workflow.js', 'claude.js'];
49
+ coreModules.forEach(module => {
50
+ expect(fs.existsSync(path.join(coreDir, module))).toBe(true);
51
+ });
52
+
53
+ // Check interface modules
54
+ const interfaceModules = ['cli.js', 'mcp.js'];
55
+ interfaceModules.forEach(module => {
56
+ expect(fs.existsSync(path.join(interfacesDir, module))).toBe(true);
57
+ });
58
+ });
59
+
60
+ test('should generate TypeScript declaration files', () => {
61
+ expect(fs.existsSync(path.join(distDir, 'core', 'index.d.ts'))).toBe(true);
62
+ expect(fs.existsSync(path.join(distDir, 'interfaces', 'cli.d.ts'))).toBe(true);
63
+ expect(fs.existsSync(path.join(distDir, 'interfaces', 'mcp.d.ts'))).toBe(true);
64
+ });
65
+ });
66
+
67
+ describe('CLI Binary Build Requirements', () => {
68
+ test('should create executable CLI binary', () => {
69
+ const cliBinary = path.join(projectRoot, 'bin', 'dot-ai.ts');
70
+ expect(fs.existsSync(cliBinary)).toBe(true);
71
+
72
+ // Check that binary is executable
73
+ const stats = fs.statSync(cliBinary);
74
+ expect(stats.mode & parseInt('111', 8)).toBeGreaterThan(0);
75
+ });
76
+
77
+ test('should allow CLI binary to run without errors', () => {
78
+ expect(() => {
79
+ const projectKubeconfig = path.join(projectRoot, 'kubeconfig.yaml');
80
+ // Use the compiled JavaScript version for CI compatibility
81
+ const output = execSync(`node dist/cli.js --kubeconfig "${projectKubeconfig}" --help`, {
82
+ cwd: projectRoot,
83
+ stdio: 'pipe'
84
+ });
85
+ expect(output.toString()).toContain('dot-ai');
86
+ }).not.toThrow();
87
+ });
88
+
89
+ test('should include all required dependencies in CLI build', () => {
90
+ const projectKubeconfig = path.join(projectRoot, 'kubeconfig.yaml');
91
+ // Use the compiled JavaScript version for CI compatibility
92
+ const output = execSync(`node dist/cli.js --kubeconfig "${projectKubeconfig}" --version`, {
93
+ cwd: projectRoot,
94
+ stdio: 'pipe'
95
+ });
96
+ expect(output.toString().trim()).toMatch(/\d+\.\d+\.\d+/);
97
+ });
98
+ });
99
+
100
+ describe('MCP Server Build Requirements', () => {
101
+ test('should build MCP server without errors', () => {
102
+ const mcpServer = path.join(distDir, 'interfaces', 'mcp.js');
103
+ expect(fs.existsSync(mcpServer)).toBe(true);
104
+
105
+ // Test that MCP server can be imported
106
+ expect(() => {
107
+ const mcpModule = require(mcpServer);
108
+ expect(mcpModule.MCPServer).toBeDefined();
109
+ }).not.toThrow();
110
+ });
111
+
112
+ test('should include MCP server startup script', () => {
113
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
114
+ expect(packageJson.scripts).toHaveProperty('start:mcp');
115
+ expect(packageJson.scripts['start:mcp']).toContain('mcp');
116
+ });
117
+
118
+ test('should validate MCP server dependencies are available', () => {
119
+ const mcpServer = require(path.join(distDir, 'interfaces', 'mcp.js'));
120
+ const { DotAI } = require(path.join(distDir, 'core', 'index.js'));
121
+
122
+ expect(() => {
123
+ // Use project's working kubeconfig.yaml for integration tests
124
+ const projectKubeconfig = path.join(process.cwd(), 'kubeconfig.yaml');
125
+ const dotAI = new DotAI({ kubernetesConfig: projectKubeconfig });
126
+ const config = { name: 'test', version: '1.0.0', description: 'Test' };
127
+ const server = new mcpServer.MCPServer(dotAI, config);
128
+ expect(server).toBeDefined();
129
+ expect(server.isReady()).toBe(false); // Should not be ready until initialized
130
+ }).not.toThrow();
131
+ });
132
+ });
133
+
134
+ describe('Bundle Size and Performance Requirements', () => {
135
+ test('should keep core module bundle size reasonable', () => {
136
+ const coreIndexPath = path.join(distDir, 'core', 'index.js');
137
+ const stats = fs.statSync(coreIndexPath);
138
+
139
+ // Core module should be under 100KB
140
+ expect(stats.size).toBeLessThan(100 * 1024);
141
+ });
142
+
143
+ test('should keep CLI interface bundle size reasonable', () => {
144
+ const cliPath = path.join(distDir, 'interfaces', 'cli.js');
145
+ const stats = fs.statSync(cliPath);
146
+
147
+ // CLI interface should be under 50KB
148
+ expect(stats.size).toBeLessThan(50 * 1024);
149
+ });
150
+
151
+ test('should keep MCP interface bundle size reasonable', () => {
152
+ const mcpPath = path.join(distDir, 'interfaces', 'mcp.js');
153
+ const stats = fs.statSync(mcpPath);
154
+
155
+ // MCP interface should be under 50KB
156
+ expect(stats.size).toBeLessThan(50 * 1024);
157
+ });
158
+
159
+ test('should not include unnecessary files in dist', () => {
160
+ const distContents = fs.readdirSync(distDir);
161
+
162
+ // Should not contain test files
163
+ expect(distContents.some(file => file.includes('.test.'))).toBe(false);
164
+ expect(distContents.some(file => file.includes('.spec.'))).toBe(false);
165
+
166
+ // Should not contain source maps in production build
167
+ const jsFiles = distContents.filter(file => file.endsWith('.js'));
168
+ jsFiles.forEach(file => {
169
+ const filePath = path.join(distDir, file);
170
+ const content = fs.readFileSync(filePath, 'utf8');
171
+ expect(content).not.toContain('//# sourceMappingURL=');
172
+ });
173
+ });
174
+ });
175
+
176
+ describe('Cross-Platform Compatibility Requirements', () => {
177
+ test('should use cross-platform path handling', () => {
178
+ const coreFiles = fs.readdirSync(path.join(distDir, 'core'));
179
+
180
+ coreFiles.forEach(file => {
181
+ if (file.endsWith('.js')) {
182
+ const filePath = path.join(distDir, 'core', file);
183
+ const content = fs.readFileSync(filePath, 'utf8');
184
+
185
+ // Should not contain problematic hardcoded Unix paths (allow standard ones like .kube)
186
+ expect(content).not.toMatch(/\/usr\/local\/|\/opt\/|\/tmp\/[^\/\s"']+\/|\/var\/[^\/\s"']+\//g);
187
+
188
+ // Note: Files may contain the word "path" in error messages, variable names, etc.
189
+ // without needing path.join/resolve. The important check is avoiding hardcoded Unix paths above.
190
+ }
191
+ });
192
+ });
193
+
194
+ test('should handle different node environments', () => {
195
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
196
+
197
+ // Should specify node engine requirements
198
+ expect(packageJson.engines).toBeDefined();
199
+ expect(packageJson.engines.node).toBeDefined();
200
+
201
+ // Should use compatible module target (CommonJS for broader compatibility)
202
+ const tsconfigPath = path.join(projectRoot, 'tsconfig.json');
203
+ const tsconfig = JSON.parse(fs.readFileSync(tsconfigPath, 'utf8'));
204
+ expect(tsconfig.compilerOptions.target).toBe('ES2022');
205
+ expect(['commonjs', 'ESNext']).toContain(tsconfig.compilerOptions.module);
206
+ });
207
+
208
+ test('should work with different package managers', () => {
209
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
210
+
211
+ // Should not have package-lock.json dependencies in scripts
212
+ Object.values(packageJson.scripts || {}).forEach(script => {
213
+ expect(script).not.toContain('package-lock.json');
214
+ expect(script).not.toContain('yarn.lock');
215
+ });
216
+ });
217
+ });
218
+
219
+ describe('Production Build Optimization Requirements', () => {
220
+ test('should minify JavaScript output for production', () => {
221
+ // Run production build if available
222
+ try {
223
+ execSync('npm run build:prod', { cwd: projectRoot, stdio: 'pipe' });
224
+ } catch {
225
+ // Production build script may not exist yet, skip for now
226
+ return;
227
+ }
228
+
229
+ const coreIndexPath = path.join(distDir, 'core', 'index.js');
230
+ const content = fs.readFileSync(coreIndexPath, 'utf8');
231
+
232
+ // Production build should have minimal whitespace
233
+ const lines = content.split('\n');
234
+ const nonEmptyLines = lines.filter(line => line.trim().length > 0);
235
+ expect(nonEmptyLines.length / lines.length).toBeGreaterThan(0.8);
236
+ });
237
+
238
+ test('should tree-shake unused dependencies', () => {
239
+ const mcpPath = path.join(distDir, 'interfaces', 'mcp.js');
240
+ const content = fs.readFileSync(mcpPath, 'utf8');
241
+
242
+ // Should not include unused imports
243
+ expect(content).not.toContain('import * as');
244
+
245
+ // Should use specific imports
246
+ if (content.includes('require(')) {
247
+ const requireStatements = content.match(/require\(['"][^'"]+['"]\)/g) || [];
248
+ requireStatements.forEach(stmt => {
249
+ expect(stmt).not.toContain('*');
250
+ });
251
+ }
252
+ });
253
+
254
+ test('should validate all imports resolve correctly', () => {
255
+ const interfaceFiles = ['cli.js', 'mcp.js'];
256
+
257
+ interfaceFiles.forEach(file => {
258
+ const filePath = path.join(distDir, 'interfaces', file);
259
+ expect(() => {
260
+ require(filePath);
261
+ }).not.toThrow();
262
+ });
263
+ });
264
+ });
265
+
266
+ describe('Package Distribution Requirements', () => {
267
+ test('should include all necessary files for npm distribution', () => {
268
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
269
+
270
+ // Should have proper main entry point
271
+ expect(packageJson.main).toBeDefined();
272
+ expect(fs.existsSync(path.join(projectRoot, packageJson.main))).toBe(true);
273
+
274
+ // Should have types definition
275
+ expect(packageJson.types).toBeDefined();
276
+ expect(fs.existsSync(path.join(projectRoot, packageJson.types))).toBe(true);
277
+
278
+ // Should have bin entry for CLI
279
+ expect(packageJson.bin).toBeDefined();
280
+ expect(typeof packageJson.bin === 'object' || typeof packageJson.bin === 'string').toBe(true);
281
+ });
282
+
283
+ test('should have proper files field for npm publishing', () => {
284
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
285
+
286
+ if (packageJson.files) {
287
+ expect(Array.isArray(packageJson.files)).toBe(true);
288
+ expect(packageJson.files).toContain('dist');
289
+ expect(packageJson.files).toContain('prompts');
290
+ }
291
+ });
292
+
293
+ test('should validate package.json completeness', () => {
294
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
295
+
296
+ // Essential package.json fields
297
+ expect(packageJson.name).toBeDefined();
298
+ expect(packageJson.version).toBeDefined();
299
+ expect(packageJson.description).toBeDefined();
300
+ expect(packageJson.license).toBeDefined();
301
+ expect(packageJson.repository).toBeDefined();
302
+ expect(packageJson.keywords).toBeDefined();
303
+ expect(Array.isArray(packageJson.keywords)).toBe(true);
304
+ });
305
+ });
306
+
307
+ describe('Build Script Integration Requirements', () => {
308
+ test('should have all required build scripts', () => {
309
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
310
+ const scripts = packageJson.scripts;
311
+
312
+ expect(scripts).toHaveProperty('build');
313
+ expect(scripts).toHaveProperty('build:cli');
314
+ expect(scripts).toHaveProperty('build:mcp');
315
+ expect(scripts).toHaveProperty('build:watch');
316
+ });
317
+
318
+ test('should have development and production build modes', () => {
319
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
320
+ const scripts = packageJson.scripts;
321
+
322
+ // Should have development build
323
+ expect(scripts.build).toBeDefined();
324
+
325
+ // Should have watch mode for development
326
+ expect(scripts['build:watch']).toBeDefined();
327
+ expect(scripts['build:watch']).toContain('watch');
328
+ });
329
+
330
+ test('should clean build directory before building', () => {
331
+ // Create a test file in dist to verify it gets cleaned
332
+ if (!fs.existsSync(distDir)) {
333
+ fs.mkdirSync(distDir, { recursive: true });
334
+ }
335
+
336
+ const testFile = path.join(distDir, 'test-cleanup.txt');
337
+ fs.writeFileSync(testFile, 'should be removed');
338
+
339
+ execSync('npm run build', { cwd: projectRoot, stdio: 'pipe' });
340
+
341
+ // Test file should be gone after build
342
+ expect(fs.existsSync(testFile)).toBe(false);
343
+ });
344
+ });
345
+ });
@@ -0,0 +1,226 @@
1
+ /**
2
+ * Configuration Validation Tests
3
+ *
4
+ * These tests define the requirements for our package.json and TypeScript configuration
5
+ * Following TDD approach - these tests define what we SHOULD have before we implement it
6
+ */
7
+
8
+ import fs from 'fs';
9
+ import path from 'path';
10
+
11
+ describe('Package.json Configuration', () => {
12
+ let packageJson: any;
13
+
14
+ beforeAll(() => {
15
+ packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8'));
16
+ });
17
+
18
+ describe('Basic Package Information', () => {
19
+ test('should have correct package metadata', () => {
20
+ expect(packageJson.name).toBe('@vfarcic/dot-ai');
21
+ expect(packageJson.version).toMatch(/^\d+\.\d+\.\d+$/);
22
+ expect(packageJson.description).toContain('Kubernetes');
23
+ expect(packageJson.description).toContain('CLI');
24
+ expect(packageJson.description).toContain('MCP');
25
+ expect(packageJson.license).toBe('MIT');
26
+ expect(packageJson.author).toBeDefined();
27
+ });
28
+
29
+ test('should have proper keywords for discoverability', () => {
30
+ expect(packageJson.keywords).toContain('kubernetes');
31
+ expect(packageJson.keywords).toContain('cli');
32
+ expect(packageJson.keywords).toContain('mcp');
33
+ expect(packageJson.keywords).toContain('deployment');
34
+ });
35
+ });
36
+
37
+ describe('Entry Points and Exports', () => {
38
+ test('should support both CLI and MCP entry points', () => {
39
+ expect(packageJson.main).toBe('dist/index.js');
40
+ expect(packageJson.bin).toHaveProperty('dot-ai');
41
+ expect(packageJson.exports['.']).toBe('./dist/index.js');
42
+ expect(packageJson.exports['./mcp']).toBe('./dist/mcp/server.js');
43
+ });
44
+
45
+ test('should have TypeScript declaration files', () => {
46
+ expect(packageJson.types || packageJson.typings).toBeDefined();
47
+ });
48
+ });
49
+
50
+ describe('Scripts', () => {
51
+ test('should have comprehensive build scripts', () => {
52
+ expect(packageJson.scripts.build).toBeDefined();
53
+ expect(packageJson.scripts['build:watch']).toBeDefined();
54
+ expect(packageJson.scripts.test).toBeDefined();
55
+ expect(packageJson.scripts['test:watch']).toBeDefined();
56
+ expect(packageJson.scripts['test:coverage']).toBeDefined();
57
+ });
58
+
59
+ test('should have development scripts', () => {
60
+ expect(packageJson.scripts.dev).toBeDefined();
61
+ expect(packageJson.scripts.lint).toBeDefined();
62
+ expect(packageJson.scripts.format).toBeDefined();
63
+ });
64
+
65
+ test('should have CLI and MCP specific scripts', () => {
66
+ expect(packageJson.scripts['start:cli']).toBeDefined();
67
+ expect(packageJson.scripts['start:mcp']).toBeDefined();
68
+ expect(packageJson.scripts['build:cli']).toBeDefined();
69
+ expect(packageJson.scripts['build:mcp']).toBeDefined();
70
+ });
71
+ });
72
+
73
+ describe('Dependencies', () => {
74
+ test('should have required runtime dependencies', () => {
75
+ expect(packageJson.dependencies['@kubernetes/client-node']).toBeDefined();
76
+ expect(packageJson.dependencies['commander']).toBeDefined();
77
+ expect(packageJson.dependencies['@anthropic-ai/sdk']).toBeDefined();
78
+ });
79
+
80
+ test('should have proper dev dependencies', () => {
81
+ expect(packageJson.devDependencies['@types/jest']).toBeDefined();
82
+ expect(packageJson.devDependencies['@types/node']).toBeDefined();
83
+ expect(packageJson.devDependencies['typescript']).toBeDefined();
84
+ expect(packageJson.devDependencies['jest']).toBeDefined();
85
+ expect(packageJson.devDependencies['ts-jest']).toBeDefined();
86
+ });
87
+
88
+ test('should have code quality dependencies', () => {
89
+ expect(packageJson.devDependencies['eslint']).toBeDefined();
90
+ expect(packageJson.devDependencies['prettier']).toBeDefined();
91
+ expect(packageJson.devDependencies['@typescript-eslint/eslint-plugin']).toBeDefined();
92
+ expect(packageJson.devDependencies['@typescript-eslint/parser']).toBeDefined();
93
+ });
94
+ });
95
+
96
+ describe('Jest Configuration', () => {
97
+ test('should have comprehensive Jest setup', () => {
98
+ expect(packageJson.jest.preset).toBe('ts-jest');
99
+ expect(packageJson.jest.testEnvironment).toBe('node');
100
+ expect(packageJson.jest.roots).toContain('<rootDir>/src');
101
+ expect(packageJson.jest.roots).toContain('<rootDir>/tests');
102
+ });
103
+
104
+ test('should have proper coverage configuration', () => {
105
+ expect(packageJson.jest.collectCoverageFrom).toContain('src/**/*.ts');
106
+ expect(packageJson.jest.coverageDirectory).toBe('coverage');
107
+ expect(packageJson.jest.coverageReporters).toContain('text');
108
+ expect(packageJson.jest.coverageReporters).toContain('lcov');
109
+ });
110
+ });
111
+ });
112
+
113
+ describe('TypeScript Configuration', () => {
114
+ let tsConfig: any;
115
+
116
+ beforeAll(() => {
117
+ tsConfig = JSON.parse(fs.readFileSync('tsconfig.json', 'utf8'));
118
+ });
119
+
120
+ describe('Compiler Options', () => {
121
+ test('should have strict TypeScript settings', () => {
122
+ expect(tsConfig.compilerOptions.strict).toBe(true);
123
+ expect(tsConfig.compilerOptions.noImplicitAny).toBe(true);
124
+ expect(tsConfig.compilerOptions.strictNullChecks).toBe(true);
125
+ expect(tsConfig.compilerOptions.noImplicitReturns).toBe(true);
126
+ });
127
+
128
+ test('should target appropriate JavaScript version', () => {
129
+ expect(tsConfig.compilerOptions.target).toBe('ES2022');
130
+ expect(tsConfig.compilerOptions.lib).toContain('ES2022');
131
+ expect(tsConfig.compilerOptions.module).toBe('commonjs');
132
+ });
133
+
134
+ test('should have proper output configuration', () => {
135
+ expect(tsConfig.compilerOptions.outDir).toBe('./dist');
136
+ expect(tsConfig.compilerOptions.rootDir).toBe('./src');
137
+ expect(tsConfig.compilerOptions.declaration).toBe(true);
138
+ expect(tsConfig.compilerOptions.sourceMap).toBe(true);
139
+ });
140
+
141
+ test('should support module resolution', () => {
142
+ expect(tsConfig.compilerOptions.moduleResolution).toBe('node');
143
+ expect(tsConfig.compilerOptions.esModuleInterop).toBe(true);
144
+ expect(tsConfig.compilerOptions.resolveJsonModule).toBe(true);
145
+ });
146
+ });
147
+
148
+ describe('Path Resolution', () => {
149
+ test('should have proper include/exclude patterns', () => {
150
+ expect(tsConfig.include).toContain('src/**/*');
151
+ expect(tsConfig.exclude).toContain('node_modules');
152
+ expect(tsConfig.exclude).toContain('dist');
153
+ expect(tsConfig.exclude).toContain('**/*.test.ts');
154
+ });
155
+
156
+ test('should support path mapping for core modules', () => {
157
+ if (tsConfig.compilerOptions.paths) {
158
+ expect(tsConfig.compilerOptions.paths['@core/*']).toBeDefined();
159
+ expect(tsConfig.compilerOptions.paths['@interfaces/*']).toBeDefined();
160
+ }
161
+ });
162
+ });
163
+ });
164
+
165
+ describe('Build Configuration', () => {
166
+ test('should be able to compile TypeScript successfully', async () => {
167
+ // This test validates that our TypeScript configuration actually works
168
+ const { exec } = require('child_process');
169
+ const { promisify } = require('util');
170
+ const execAsync = promisify(exec);
171
+
172
+ try {
173
+ await execAsync('npx tsc --noEmit');
174
+ // If we reach here, TypeScript compilation succeeded
175
+ expect(true).toBe(true);
176
+ } catch (error) {
177
+ // If TypeScript compilation fails, we'll get details in the error
178
+ throw new Error(`TypeScript compilation failed: ${error}`);
179
+ }
180
+ });
181
+
182
+ test('should have working linting configuration', async () => {
183
+ // Test that our linting setup works
184
+ expect(fs.existsSync('.eslintrc.js') || fs.existsSync('.eslintrc.json')).toBe(true);
185
+ });
186
+
187
+ test('should have working prettier configuration', async () => {
188
+ // Test that prettier is properly configured
189
+ const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8'));
190
+ expect(
191
+ fs.existsSync('.prettierrc') ||
192
+ fs.existsSync('.prettierrc.json') ||
193
+ fs.existsSync('prettier.config.js') ||
194
+ packageJson.prettier
195
+ ).toBe(true);
196
+ });
197
+ });
198
+
199
+ describe('Module Resolution Tests', () => {
200
+ test('should be able to resolve core modules', () => {
201
+ // Test that our module paths will work
202
+ const corePath = path.resolve('src/core');
203
+ const interfacesPath = path.resolve('src/interfaces');
204
+
205
+ expect(fs.existsSync(corePath)).toBe(true);
206
+ expect(fs.existsSync(interfacesPath)).toBe(true);
207
+ });
208
+
209
+ test('should support importing from planned modules', () => {
210
+ // This validates our module structure expectations
211
+ const expectedModules = [
212
+ 'src/core/index.ts',
213
+ 'src/core/discovery.ts',
214
+ 'src/core/memory.ts',
215
+ 'src/core/workflow.ts',
216
+ 'src/interfaces/cli.ts',
217
+ 'src/interfaces/mcp.ts'
218
+ ];
219
+
220
+ expectedModules.forEach(modulePath => {
221
+ const dir = path.dirname(modulePath);
222
+ expect(fs.existsSync(dir)).toBe(true);
223
+ });
224
+ });
225
+ });
226
+
@@ -0,0 +1,38 @@
1
+ import { DeployOperation } from '../../src/core/deploy-operation';
2
+
3
+ // Mock the entire deploy-operation module to avoid complex async mocking
4
+ jest.mock('child_process', () => ({
5
+ exec: jest.fn()
6
+ }));
7
+
8
+ jest.mock('fs/promises', () => ({
9
+ access: jest.fn()
10
+ }));
11
+
12
+ jest.mock('util', () => ({
13
+ promisify: jest.fn(() => jest.fn())
14
+ }));
15
+
16
+ describe('DeployOperation', () => {
17
+ let deployOp: DeployOperation;
18
+
19
+ beforeEach(() => {
20
+ deployOp = new DeployOperation();
21
+ jest.clearAllMocks();
22
+ });
23
+
24
+ describe('constructor', () => {
25
+ it('should create DeployOperation instance', () => {
26
+ expect(deployOp).toBeInstanceOf(DeployOperation);
27
+ });
28
+ });
29
+
30
+ describe('deploy method exists', () => {
31
+ it('should have deploy method', () => {
32
+ expect(typeof deployOp.deploy).toBe('function');
33
+ });
34
+ });
35
+
36
+ // Note: Full integration testing of deploy() is done via CLI manual testing
37
+ // to avoid complex async mocking that could cause test timeouts
38
+ });