@xelth/eck-snapshot 4.0.0 → 4.2.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/package.json +13 -3
- package/setup.json +57 -35
- package/src/cli/cli.js +81 -134
- package/src/cli/commands/autoDocs.js +1 -32
- package/src/cli/commands/createSnapshot.js +338 -198
- package/src/cli/commands/doctor.js +60 -0
- package/src/cli/commands/setupGemini.js +1 -1
- package/src/cli/commands/setupGemini.test.js +1 -1
- package/src/cli/commands/showFile.js +39 -0
- package/src/cli/commands/updateSnapshot.js +75 -0
- package/src/config.js +44 -0
- package/src/core/skeletonizer.js +201 -0
- package/src/services/claudeCliService.js +5 -0
- package/src/templates/agent-prompt.template.md +104 -7
- package/src/templates/architect-prompt.template.md +112 -23
- package/src/templates/multiAgent.md +40 -86
- package/src/templates/skeleton-instruction.md +16 -0
- package/src/templates/update-prompt.template.md +19 -0
- package/src/utils/aiHeader.js +373 -147
- package/src/utils/eckProtocolParser.js +221 -0
- package/src/utils/fileUtils.js +212 -175
- package/src/utils/gitUtils.js +44 -0
- package/src/utils/tokenEstimator.js +4 -1
- package/src/cli/commands/askGpt.js +0 -29
- package/src/services/authService.js +0 -20
- package/src/services/dispatcherService.js +0 -33
- package/src/services/gptService.js +0 -302
- package/src/services/gptService.test.js +0 -120
- package/src/templates/vectorMode.md +0 -22
|
@@ -1,302 +0,0 @@
|
|
|
1
|
-
import { execa } from 'execa';
|
|
2
|
-
import fs from 'fs/promises';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import pRetry from 'p-retry';
|
|
5
|
-
import ora from 'ora';
|
|
6
|
-
import { loadProjectEckManifest } from '../utils/fileUtils.js';
|
|
7
|
-
import { initiateLogin } from './authService.js';
|
|
8
|
-
import which from 'which';
|
|
9
|
-
|
|
10
|
-
const SYSTEM_PROMPT = 'You are a Coder agent. Apply code changes per JSON spec. Respond only in JSON: {success: bool, changes: array, errors: array, post_steps: object}';
|
|
11
|
-
|
|
12
|
-
class AuthError extends Error {
|
|
13
|
-
constructor(message) {
|
|
14
|
-
super(message);
|
|
15
|
-
this.name = 'AuthError';
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Checks if the codex CLI tool is available in the system's PATH.
|
|
21
|
-
* Throws an error if not found.
|
|
22
|
-
*/
|
|
23
|
-
async function ensureCodexCliExists() {
|
|
24
|
-
try {
|
|
25
|
-
await which('codex');
|
|
26
|
-
} catch (error) {
|
|
27
|
-
throw new Error('The `codex` CLI tool is not installed or not in your PATH. Please install it from https://github.com/openai/codex to use this command.');
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Delegates an apply_code_changes payload to the codex CLI with auto-login.
|
|
33
|
-
* @param {string|object} payload - JSON string or object payload to forward to the agent.
|
|
34
|
-
* @param {{ verbose?: boolean, model?: string, reasoning?: string }} [options]
|
|
35
|
-
* @returns {Promise<object>}
|
|
36
|
-
*/
|
|
37
|
-
export async function ask(payload, options = {}) {
|
|
38
|
-
const { verbose = false, model = 'gpt-5-codex', reasoning = 'high' } = options;
|
|
39
|
-
await ensureCodexCliExists();
|
|
40
|
-
|
|
41
|
-
const run = async () => {
|
|
42
|
-
const spinner = verbose ? null : ora('Sending payload to Codex agent...').start();
|
|
43
|
-
try {
|
|
44
|
-
const payloadObject = await parsePayload(payload);
|
|
45
|
-
const manifest = await loadProjectEckManifest(process.cwd());
|
|
46
|
-
const userPrompt = buildUserPrompt(payloadObject, manifest);
|
|
47
|
-
const promptInput = `${SYSTEM_PROMPT}\n\n${userPrompt}`;
|
|
48
|
-
|
|
49
|
-
const args = [
|
|
50
|
-
'exec',
|
|
51
|
-
// Use full-auto mode to prevent interactive prompts from the agent,
|
|
52
|
-
// as this service is designed for non-interactive delegation.
|
|
53
|
-
'--full-auto',
|
|
54
|
-
'--model', model,
|
|
55
|
-
'-c', `model_reasoning_effort=${reasoning}`
|
|
56
|
-
];
|
|
57
|
-
|
|
58
|
-
debug(verbose, `Executing: codex ${args.join(' ')} <stdin>`);
|
|
59
|
-
|
|
60
|
-
const cliResult = await execa('codex', args, {
|
|
61
|
-
cwd: process.cwd(),
|
|
62
|
-
timeout: 300000, // 5-minute timeout
|
|
63
|
-
input: promptInput // Stream large prompts via stdin to avoid argv limits
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
const output = cliResult?.stdout?.trim();
|
|
67
|
-
if (!output) {
|
|
68
|
-
throw new Error('codex CLI returned empty response');
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const parsed = extractFinalJson(output);
|
|
72
|
-
if (parsed) {
|
|
73
|
-
if (parsed.post_steps || parsed.post_execution_steps) {
|
|
74
|
-
const postSteps = parsed.post_steps || parsed.post_execution_steps;
|
|
75
|
-
await handlePostExecutionSteps(postSteps, payloadObject);
|
|
76
|
-
parsed.mcp_feedback = postSteps?.mcp_feedback || null;
|
|
77
|
-
}
|
|
78
|
-
spinner?.succeed('Codex agent completed the task.');
|
|
79
|
-
return parsed;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// If parsing fails, surface the raw response text for upstream handling.
|
|
83
|
-
spinner?.succeed('Codex agent completed the task.');
|
|
84
|
-
return { success: true, changes: [], errors: [], response_text: output };
|
|
85
|
-
|
|
86
|
-
} catch (error) {
|
|
87
|
-
spinner?.fail('Codex execution failed.');
|
|
88
|
-
handleCliError(error); // This will throw a specific error type
|
|
89
|
-
}
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
return pRetry(run, {
|
|
93
|
-
retries: 1, // Only retry once after a successful login
|
|
94
|
-
minTimeout: 0,
|
|
95
|
-
onFailedAttempt: async (error) => {
|
|
96
|
-
if (error.name === 'AuthError') {
|
|
97
|
-
await initiateLogin();
|
|
98
|
-
} else {
|
|
99
|
-
throw error; // Don't retry for other errors, fail immediately
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
async function parsePayload(payload) {
|
|
107
|
-
if (typeof payload === 'string') {
|
|
108
|
-
try {
|
|
109
|
-
return JSON.parse(payload);
|
|
110
|
-
} catch (error) {
|
|
111
|
-
throw new Error(`Failed to parse payload JSON: ${error.message}`);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
if (typeof payload === 'object' && payload !== null) {
|
|
115
|
-
return payload;
|
|
116
|
-
}
|
|
117
|
-
throw new Error('Invalid payload type. Expected JSON string or object.');
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
function buildUserPrompt(payloadObject, manifest) {
|
|
121
|
-
const payloadString = JSON.stringify(payloadObject);
|
|
122
|
-
if (!manifest) {
|
|
123
|
-
return payloadString;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
const sections = [];
|
|
127
|
-
if (manifest.context) {
|
|
128
|
-
sections.push('## .eck Context\n' + manifest.context);
|
|
129
|
-
}
|
|
130
|
-
if (manifest.operations) {
|
|
131
|
-
sections.push('## .eck Operations\n' + manifest.operations);
|
|
132
|
-
}
|
|
133
|
-
if (manifest.journal) {
|
|
134
|
-
sections.push('## .eck Journal\n' + manifest.journal);
|
|
135
|
-
}
|
|
136
|
-
if (manifest.environment && Object.keys(manifest.environment).length > 0) {
|
|
137
|
-
sections.push('## .eck Environment\n' + JSON.stringify(manifest.environment, null, 2));
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
if (sections.length === 0) {
|
|
141
|
-
return payloadString;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
return `${payloadString}\n\n# Project Context\n${sections.join('\n\n')}`;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
function debug(verbose, message) {
|
|
148
|
-
if (verbose) {
|
|
149
|
-
console.log(`[ask-gpt] ${message}`);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
function extractFinalJson(text) {
|
|
154
|
-
const trimmed = text?.trim();
|
|
155
|
-
if (!trimmed) {
|
|
156
|
-
return null;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
try {
|
|
160
|
-
return JSON.parse(trimmed);
|
|
161
|
-
} catch (error) {
|
|
162
|
-
// Continue with fallback parsing when logs precede the JSON payload.
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
const fencedMatch = trimmed.match(/```(?:json)?\s*([\s\S]*?)```/i);
|
|
166
|
-
if (fencedMatch && fencedMatch[1]) {
|
|
167
|
-
const fencedContent = fencedMatch[1].trim();
|
|
168
|
-
try {
|
|
169
|
-
return JSON.parse(fencedContent);
|
|
170
|
-
} catch (error) {
|
|
171
|
-
// Ignore and fall through to final brace search.
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
const lastBraceIndex = trimmed.lastIndexOf('{');
|
|
176
|
-
if (lastBraceIndex === -1) {
|
|
177
|
-
return null;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
const jsonCandidate = trimmed.slice(lastBraceIndex);
|
|
181
|
-
try {
|
|
182
|
-
return JSON.parse(jsonCandidate);
|
|
183
|
-
} catch (error) {
|
|
184
|
-
return null;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
function handleCliError(error) {
|
|
189
|
-
const combined = `${error?.message || ''} ${error?.stderr || ''} ${error?.stdout || ''}`.toLowerCase();
|
|
190
|
-
// Check for text that `codex` outputs when auth is missing.
|
|
191
|
-
if (combined.includes('authentication is required') || combined.includes('please run `codex login`')) {
|
|
192
|
-
const authError = new Error('Codex authentication is required. Attempting to log in.');
|
|
193
|
-
authError.name = 'AuthError';
|
|
194
|
-
throw authError;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
throw new Error(`codex CLI failed: ${error.stderr || error.message}`);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
async function handlePostExecutionSteps(postSteps, payloadObject) {
|
|
201
|
-
if (!postSteps || typeof postSteps !== 'object') {
|
|
202
|
-
return;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
if (postSteps.journal_entry) {
|
|
206
|
-
await applyJournalEntry(postSteps.journal_entry, payloadObject);
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
if (postSteps.mcp_feedback) {
|
|
210
|
-
logMcpFeedback(postSteps.mcp_feedback);
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
async function applyJournalEntry(entry, payloadObject) {
|
|
215
|
-
const journalEntry = normalizeJournalEntry(entry);
|
|
216
|
-
const journalPath = path.join(process.cwd(), '.eck', 'JOURNAL.md');
|
|
217
|
-
|
|
218
|
-
await fs.mkdir(path.dirname(journalPath), { recursive: true });
|
|
219
|
-
|
|
220
|
-
let existing = '';
|
|
221
|
-
try {
|
|
222
|
-
existing = await fs.readFile(journalPath, 'utf-8');
|
|
223
|
-
} catch (error) {
|
|
224
|
-
if (error.code !== 'ENOENT') {
|
|
225
|
-
throw new Error(`Failed to read JOURNAL.md: ${error.message}`);
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
const taskId = payloadObject?.task_id || payloadObject?.payload?.task_id || journalEntry.task_id || 'ask-gpt';
|
|
230
|
-
const isoDate = new Date().toISOString();
|
|
231
|
-
|
|
232
|
-
const frontmatter = [
|
|
233
|
-
'---',
|
|
234
|
-
`task_id: ${taskId}`,
|
|
235
|
-
`date: ${isoDate}`,
|
|
236
|
-
`type: ${journalEntry.type}`,
|
|
237
|
-
`scope: ${journalEntry.scope}`,
|
|
238
|
-
'---',
|
|
239
|
-
''
|
|
240
|
-
].join('\n');
|
|
241
|
-
|
|
242
|
-
const summary = journalEntry.summary ? `## ${journalEntry.summary}\n` : '';
|
|
243
|
-
const details = journalEntry.details ? `${journalEntry.details}\n` : '';
|
|
244
|
-
|
|
245
|
-
const entryBlock = `${frontmatter}${summary ? `${summary}\n` : ''}${details}\n`;
|
|
246
|
-
|
|
247
|
-
const existingTrimmed = existing ? existing.replace(/^\n+/, '') : '';
|
|
248
|
-
const newContent = `${entryBlock}${existingTrimmed}`.replace(/\n{3,}/g, '\n\n');
|
|
249
|
-
|
|
250
|
-
await fs.writeFile(journalPath, newContent.trimEnd() + '\n');
|
|
251
|
-
|
|
252
|
-
await stageJournal(journalPath);
|
|
253
|
-
await commitJournal(journalEntry);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
function normalizeJournalEntry(entry) {
|
|
257
|
-
return {
|
|
258
|
-
type: entry.type || 'chore',
|
|
259
|
-
scope: entry.scope || 'journal',
|
|
260
|
-
summary: entry.summary || 'Update journal entry',
|
|
261
|
-
details: entry.details || ''
|
|
262
|
-
};
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
async function stageJournal(journalPath) {
|
|
266
|
-
const relativePath = path.relative(process.cwd(), journalPath);
|
|
267
|
-
try {
|
|
268
|
-
await execa('git', ['add', relativePath], { cwd: process.cwd() });
|
|
269
|
-
} catch (error) {
|
|
270
|
-
throw new Error(`Failed to stage journal entry: ${error.message}`);
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
async function commitJournal(entry) {
|
|
275
|
-
const scopePart = entry.scope ? `(${entry.scope})` : '';
|
|
276
|
-
const summary = (entry.summary || 'Update journal entry').replace(/\s+/g, ' ').trim();
|
|
277
|
-
const commitMessage = `${entry.type}${scopePart}: ${summary}`;
|
|
278
|
-
|
|
279
|
-
try {
|
|
280
|
-
await execa('git', ['commit', '-m', commitMessage], { cwd: process.cwd() });
|
|
281
|
-
} catch (error) {
|
|
282
|
-
const text = `${error?.stderr || ''} ${error?.stdout || ''}`.toLowerCase();
|
|
283
|
-
if (text.includes('nothing to commit')) {
|
|
284
|
-
console.warn('Journal entry already committed or no changes to commit.');
|
|
285
|
-
return;
|
|
286
|
-
}
|
|
287
|
-
throw new Error(`Failed to commit journal entry: ${error.message}`);
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
function logMcpFeedback(feedback) {
|
|
292
|
-
if (!feedback) {
|
|
293
|
-
return;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
const errors = Array.isArray(feedback.errors) ? feedback.errors : [];
|
|
297
|
-
if (!feedback.success || errors.length > 0) {
|
|
298
|
-
console.warn('MCP feedback indicates issues:', errors.length > 0 ? errors : feedback);
|
|
299
|
-
} else {
|
|
300
|
-
console.log('MCP feedback:', feedback);
|
|
301
|
-
}
|
|
302
|
-
}
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
-
|
|
3
|
-
// Mock execa and which
|
|
4
|
-
vi.mock('execa', () => ({ execa: vi.fn() }));
|
|
5
|
-
vi.mock('which', () => ({ default: vi.fn() }));
|
|
6
|
-
|
|
7
|
-
// Mock fs/promises for journal entries
|
|
8
|
-
const mkdirMock = vi.fn();
|
|
9
|
-
const readFileMock = vi.fn();
|
|
10
|
-
const writeFileMock = vi.fn();
|
|
11
|
-
const loadProjectEckManifestMock = vi.fn();
|
|
12
|
-
vi.mock('fs/promises', () => ({
|
|
13
|
-
mkdir: mkdirMock,
|
|
14
|
-
readFile: readFileMock,
|
|
15
|
-
writeFile: writeFileMock
|
|
16
|
-
}));
|
|
17
|
-
vi.mock('../utils/fileUtils.js', () => ({
|
|
18
|
-
loadProjectEckManifest: loadProjectEckManifestMock
|
|
19
|
-
}));
|
|
20
|
-
|
|
21
|
-
// Mock p-retry to control retry behavior in tests
|
|
22
|
-
vi.mock('p-retry', async (importOriginal) => {
|
|
23
|
-
const actual = await importOriginal();
|
|
24
|
-
return {
|
|
25
|
-
...actual,
|
|
26
|
-
default: vi.fn(async (fn, options) => {
|
|
27
|
-
try {
|
|
28
|
-
return await fn();
|
|
29
|
-
} catch (error) {
|
|
30
|
-
if (options.onFailedAttempt) {
|
|
31
|
-
await options.onFailedAttempt(error);
|
|
32
|
-
// In a real scenario, p-retry would re-run fn. For testing, we simulate one retry.
|
|
33
|
-
if (error.name === 'AuthError') {
|
|
34
|
-
return await fn();
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
throw error;
|
|
38
|
-
}
|
|
39
|
-
})
|
|
40
|
-
};
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
// Mock the authService
|
|
44
|
-
vi.mock('./authService.js', () => ({
|
|
45
|
-
initiateLogin: vi.fn()
|
|
46
|
-
}));
|
|
47
|
-
|
|
48
|
-
describe('gptService with codex CLI', () => {
|
|
49
|
-
let ask;
|
|
50
|
-
let execaMock;
|
|
51
|
-
let whichMock;
|
|
52
|
-
let initiateLoginMock;
|
|
53
|
-
|
|
54
|
-
beforeEach(async () => {
|
|
55
|
-
vi.clearAllMocks();
|
|
56
|
-
|
|
57
|
-
({ execa: execaMock } = await import('execa'));
|
|
58
|
-
const which = (await import('which')).default;
|
|
59
|
-
whichMock = which;
|
|
60
|
-
({ initiateLogin: initiateLoginMock } = await import('./authService.js'));
|
|
61
|
-
({ ask } = await import('./gptService.js'));
|
|
62
|
-
|
|
63
|
-
whichMock.mockResolvedValue('/usr/bin/codex');
|
|
64
|
-
loadProjectEckManifestMock.mockResolvedValue(null);
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it('should call codex CLI with correct arguments and parse final JSON from noisy output', async () => {
|
|
68
|
-
const codexLogs = '[2025-10-06 20:04:22] OpenAI Codex v0.42.0\nSome setup log...\n\n{"success": true, "changes": ["change1"], "errors": []}';
|
|
69
|
-
execaMock.mockResolvedValue({ stdout: codexLogs });
|
|
70
|
-
|
|
71
|
-
const payload = { objective: 'Test' };
|
|
72
|
-
const result = await ask(payload);
|
|
73
|
-
|
|
74
|
-
expect(result).toEqual({ success: true, changes: ['change1'], errors: [] });
|
|
75
|
-
expect(execaMock).toHaveBeenCalledWith('codex', expect.arrayContaining(['exec', '--full-auto', '--model']), expect.any(Object));
|
|
76
|
-
const [, , options] = execaMock.mock.calls[0];
|
|
77
|
-
expect(options.input).toContain(JSON.stringify(payload));
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
it('should trigger login flow on authentication error and retry', async () => {
|
|
81
|
-
const authError = new Error('Authentication is required. Please run `codex login`.');
|
|
82
|
-
authError.name = 'AuthError'; // Custom error name to trigger retry
|
|
83
|
-
authError.stderr = 'Authentication is required. Please run `codex login`.';
|
|
84
|
-
|
|
85
|
-
const successResponse = {
|
|
86
|
-
id: 'task2',
|
|
87
|
-
msg: {
|
|
88
|
-
type: 'task_complete',
|
|
89
|
-
last_agent_message: '{"success": true}'
|
|
90
|
-
}
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
// First call fails, second call (retry) succeeds
|
|
94
|
-
execaMock
|
|
95
|
-
.mockRejectedValueOnce(authError)
|
|
96
|
-
.mockResolvedValueOnce({ stdout: JSON.stringify(successResponse) });
|
|
97
|
-
|
|
98
|
-
initiateLoginMock.mockResolvedValue();
|
|
99
|
-
|
|
100
|
-
const result = await ask({ objective: 'Retry test' });
|
|
101
|
-
|
|
102
|
-
expect(result).toEqual({ success: true });
|
|
103
|
-
expect(initiateLoginMock).toHaveBeenCalledTimes(1);
|
|
104
|
-
expect(execaMock).toHaveBeenCalledTimes(2); // Initial call + retry
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
it('should throw if codex CLI is not found', async () => {
|
|
108
|
-
whichMock.mockRejectedValue(new Error('not found'));
|
|
109
|
-
await expect(ask({})).rejects.toThrow('The `codex` CLI tool is not installed');
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
it('should throw non-auth errors immediately without retry', async () => {
|
|
113
|
-
const otherError = new Error('Some other CLI error');
|
|
114
|
-
otherError.stderr = 'Something else went wrong';
|
|
115
|
-
execaMock.mockRejectedValueOnce(otherError);
|
|
116
|
-
|
|
117
|
-
await expect(ask({})).rejects.toThrow('codex CLI failed: Something else went wrong');
|
|
118
|
-
expect(initiateLoginMock).not.toHaveBeenCalled();
|
|
119
|
-
});
|
|
120
|
-
});
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
# AI Instructions
|
|
2
|
-
|
|
3
|
-
## 1. How to Read This Snapshot
|
|
4
|
-
|
|
5
|
-
This document is a context-aware snapshot of the **{{repoName}}** software repository, generated by the `eck-snapshot` tool on **{{timestamp}}**. The content has been filtered based on vector similarity to your query: "{{userQuery}}"
|
|
6
|
-
|
|
7
|
-
* **Source of Truth:** Treat this snapshot as the relevant source code for your specific task.
|
|
8
|
-
* **Structure:** The file contains the full content of each relevant file, demarcated by `--- File: /path/to/file ---` headers.
|
|
9
|
-
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
## 2. Your Core Operational Workflow
|
|
13
|
-
|
|
14
|
-
You are the Project Manager and Solution Architect AI. Your primary goal is to translate user requests into technical plans and then generate precise commands for code-execution AI agents.
|
|
15
|
-
|
|
16
|
-
### PROJECT OVERVIEW
|
|
17
|
-
- **Project:** {{repoName}}
|
|
18
|
-
- **User Query:** "{{userQuery}}"
|
|
19
|
-
|
|
20
|
-
{{multiAgentSection}}
|
|
21
|
-
|
|
22
|
-
---
|