@xelth/eck-snapshot 5.9.0 → 6.4.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.

Potentially problematic release.


This version of @xelth/eck-snapshot might be problematic. Click here for more details.

Files changed (35) hide show
  1. package/README.md +267 -190
  2. package/package.json +15 -2
  3. package/scripts/mcp-eck-core.js +61 -13
  4. package/setup.json +114 -80
  5. package/src/cli/cli.js +235 -385
  6. package/src/cli/commands/createSnapshot.js +336 -122
  7. package/src/cli/commands/recon.js +244 -0
  8. package/src/cli/commands/setupMcp.js +278 -19
  9. package/src/cli/commands/trainTokens.js +42 -32
  10. package/src/cli/commands/updateSnapshot.js +128 -76
  11. package/src/core/depthConfig.js +54 -0
  12. package/src/core/skeletonizer.js +71 -18
  13. package/src/templates/architect-prompt.template.md +34 -0
  14. package/src/templates/multiAgent.md +18 -10
  15. package/src/templates/opencode/coder.template.md +44 -17
  16. package/src/templates/opencode/junior-architect.template.md +45 -15
  17. package/src/templates/skeleton-instruction.md +1 -1
  18. package/src/utils/aiHeader.js +57 -27
  19. package/src/utils/claudeMdGenerator.js +136 -78
  20. package/src/utils/fileUtils.js +1011 -1016
  21. package/src/utils/gitUtils.js +12 -8
  22. package/src/utils/opencodeAgentsGenerator.js +8 -2
  23. package/src/utils/projectDetector.js +66 -21
  24. package/src/utils/tokenEstimator.js +11 -7
  25. package/src/cli/commands/consilium.js +0 -86
  26. package/src/cli/commands/detectProfiles.js +0 -98
  27. package/src/cli/commands/envSync.js +0 -319
  28. package/src/cli/commands/generateProfileGuide.js +0 -144
  29. package/src/cli/commands/pruneSnapshot.js +0 -106
  30. package/src/cli/commands/restoreSnapshot.js +0 -173
  31. package/src/cli/commands/setupGemini.js +0 -149
  32. package/src/cli/commands/setupGemini.test.js +0 -115
  33. package/src/cli/commands/showFile.js +0 -39
  34. package/src/services/claudeCliService.js +0 -626
  35. package/src/services/claudeCliService.test.js +0 -267
@@ -1,267 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
- import { askClaude } from './claudeCliService.js';
3
-
4
- // Mock execa
5
- vi.mock('execa', () => ({
6
- execa: vi.fn()
7
- }));
8
-
9
- // Mock p-retry to control retry behavior in tests
10
- vi.mock('p-retry', () => ({
11
- default: async (fn, options) => {
12
- // For tests, we'll execute the function directly without retries
13
- return await fn();
14
- }
15
- }));
16
-
17
- describe('claudeCliService', () => {
18
- let mockExeca;
19
-
20
- beforeEach(async () => {
21
- const { execa } = await import('execa');
22
- mockExeca = execa;
23
- vi.clearAllMocks();
24
- });
25
-
26
- afterEach(() => {
27
- vi.resetAllMocks();
28
- });
29
-
30
- describe('askClaude', () => {
31
- it('should successfully execute gemini-cli claude command', async () => {
32
- const mockResponse = {
33
- stdout: '{"result": "test response", "success": true}',
34
- stderr: '',
35
- exitCode: 0
36
- };
37
-
38
- mockExeca.mockResolvedValue(mockResponse);
39
-
40
- const result = await askClaude('test prompt');
41
-
42
- expect(mockExeca).toHaveBeenCalledWith('gemini-cli', ['claude', 'test prompt'], {
43
- timeout: 120000
44
- });
45
- expect(result).toEqual({
46
- stdout: mockResponse.stdout,
47
- stderr: mockResponse.stderr,
48
- success: true,
49
- mcp_feedback: null
50
- });
51
- });
52
-
53
- it('should handle non-transient errors without retry', async () => {
54
- const mockError = new Error('EACCES: permission denied');
55
- mockError.code = 'EACCES';
56
- mockError.stdout = '';
57
- mockError.stderr = 'permission denied';
58
-
59
- mockExeca.mockRejectedValue(mockError);
60
-
61
- const result = await askClaude('test prompt');
62
-
63
- expect(result).toEqual({
64
- stdout: '',
65
- stderr: 'permission denied',
66
- success: false,
67
- error: 'EACCES: permission denied'
68
- });
69
- });
70
-
71
- it('should identify transient network errors', async () => {
72
- const mockError = new Error('Connection timeout');
73
- mockError.stdout = '';
74
- mockError.stderr = 'network timeout occurred';
75
-
76
- const { isTransientError } = await import('./claudeCliService.js');
77
-
78
- expect(isTransientError(mockError)).toBe(true);
79
- });
80
-
81
-
82
- it('should handle JSON parsing in gemini-cli response', async () => {
83
- const complexJsonResponse = {
84
- stdout: JSON.stringify({
85
- type: 'result',
86
- data: {
87
- analysis: 'test analysis',
88
- metrics: { tokens: 100, cost: 0.05 }
89
- },
90
- timestamp: new Date().toISOString()
91
- }),
92
- stderr: '',
93
- exitCode: 0
94
- };
95
-
96
- mockExeca.mockResolvedValue(complexJsonResponse);
97
-
98
- const result = await askClaude('analyze this code');
99
-
100
- expect(result.success).toBe(true);
101
- expect(result.stdout).toContain('test analysis');
102
- expect(result.stdout).toContain('tokens');
103
- });
104
-
105
- it('should handle empty responses gracefully', async () => {
106
- const mockResponse = {
107
- stdout: '',
108
- stderr: '',
109
- exitCode: 0
110
- };
111
-
112
- mockExeca.mockResolvedValue(mockResponse);
113
-
114
- const result = await askClaude('test prompt');
115
-
116
- expect(result).toEqual({
117
- stdout: '',
118
- stderr: '',
119
- success: true,
120
- mcp_feedback: null
121
- });
122
- });
123
-
124
- it('should handle stderr warnings without failing', async () => {
125
- const mockResponse = {
126
- stdout: '{"result": "success"}',
127
- stderr: 'Warning: deprecated feature used',
128
- exitCode: 0
129
- };
130
-
131
- mockExeca.mockResolvedValue(mockResponse);
132
-
133
- const result = await askClaude('test prompt');
134
-
135
- expect(result.success).toBe(true);
136
- expect(result.stderr).toContain('deprecated feature');
137
- });
138
-
139
- it('should respect timeout configuration', async () => {
140
- mockExeca.mockResolvedValue({
141
- stdout: 'response',
142
- stderr: '',
143
- exitCode: 0
144
- });
145
-
146
- await askClaude('test prompt');
147
-
148
- expect(mockExeca).toHaveBeenCalledWith(
149
- 'gemini-cli',
150
- ['claude', 'test prompt'],
151
- { timeout: 120000 }
152
- );
153
- });
154
-
155
- it('should parse mcp_feedback from JSON prompt', async () => {
156
- const mockResponse = {
157
- stdout: 'success',
158
- stderr: '',
159
- exitCode: 0
160
- };
161
-
162
- mockExeca.mockResolvedValue(mockResponse);
163
-
164
- const promptWithFeedback = JSON.stringify({
165
- payload: {
166
- post_execution_steps: {
167
- mcp_feedback: {
168
- success: true,
169
- errors: [],
170
- mcp_version: '1.0'
171
- }
172
- }
173
- }
174
- });
175
-
176
- const result = await askClaude(promptWithFeedback);
177
-
178
- expect(result.mcp_feedback).toEqual({
179
- success: true,
180
- errors: [],
181
- mcp_version: '1.0'
182
- });
183
- });
184
-
185
- it('should log warning when mcp_feedback contains errors', async () => {
186
- const consoleSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
187
-
188
- const mockResponse = {
189
- stdout: 'success',
190
- stderr: '',
191
- exitCode: 0
192
- };
193
-
194
- mockExeca.mockResolvedValue(mockResponse);
195
-
196
- const promptWithErrors = JSON.stringify({
197
- payload: {
198
- post_execution_steps: {
199
- mcp_feedback: {
200
- success: false,
201
- errors: ['Error 1', 'Error 2'],
202
- mcp_version: '1.0'
203
- }
204
- }
205
- }
206
- });
207
-
208
- await askClaude(promptWithErrors);
209
-
210
- expect(consoleSpy).toHaveBeenCalledWith('MCP feedback contains errors:', ['Error 1', 'Error 2']);
211
-
212
- consoleSpy.mockRestore();
213
- });
214
- });
215
-
216
- describe('transient error detection', () => {
217
- it('should treat network errors as transient', async () => {
218
- const { isTransientError } = await import('./claudeCliService.js');
219
-
220
- const networkErrors = [
221
- 'network error',
222
- 'timeout',
223
- 'connection refused',
224
- 'ECONNRESET',
225
- 'ENOTFOUND',
226
- 'socket hang up'
227
- ];
228
-
229
- networkErrors.forEach(errorMsg => {
230
- const error = new Error(errorMsg);
231
- expect(isTransientError(error)).toBe(true);
232
- });
233
- });
234
-
235
- it('should treat quota errors as transient', async () => {
236
- const { isTransientError } = await import('./claudeCliService.js');
237
-
238
- const quotaErrors = [
239
- 'quota exceeded',
240
- 'rate limit',
241
- 'too many requests',
242
- '429',
243
- '503'
244
- ];
245
-
246
- quotaErrors.forEach(errorMsg => {
247
- const error = new Error(errorMsg);
248
- expect(isTransientError(error)).toBe(true);
249
- });
250
- });
251
-
252
- it('should not treat permission errors as transient', async () => {
253
- const { isTransientError } = await import('./claudeCliService.js');
254
-
255
- const permanentErrors = [
256
- 'EACCES: permission denied',
257
- 'Invalid API key',
258
- 'Authentication failed'
259
- ];
260
-
261
- permanentErrors.forEach(errorMsg => {
262
- const error = new Error(errorMsg);
263
- expect(isTransientError(error)).toBe(false);
264
- });
265
- });
266
- });
267
- });