@xelth/eck-snapshot 5.9.0 ā 6.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/README.md +321 -190
- package/index.js +1 -1
- package/package.json +15 -2
- package/scripts/mcp-eck-core.js +143 -13
- package/setup.json +119 -81
- package/src/cli/cli.js +256 -385
- package/src/cli/commands/createSnapshot.js +391 -175
- package/src/cli/commands/recon.js +308 -0
- package/src/cli/commands/setupMcp.js +280 -19
- package/src/cli/commands/trainTokens.js +42 -32
- package/src/cli/commands/updateSnapshot.js +136 -43
- package/src/core/depthConfig.js +54 -0
- package/src/core/skeletonizer.js +280 -21
- package/src/templates/architect-prompt.template.md +34 -0
- package/src/templates/multiAgent.md +68 -15
- package/src/templates/opencode/coder.template.md +53 -17
- package/src/templates/opencode/junior-architect.template.md +54 -15
- package/src/templates/skeleton-instruction.md +1 -1
- package/src/templates/update-prompt.template.md +2 -0
- package/src/utils/aiHeader.js +57 -27
- package/src/utils/claudeMdGenerator.js +182 -88
- package/src/utils/fileUtils.js +217 -149
- package/src/utils/gitUtils.js +12 -8
- package/src/utils/opencodeAgentsGenerator.js +8 -2
- package/src/utils/projectDetector.js +66 -21
- package/src/utils/tokenEstimator.js +11 -7
- package/src/cli/commands/consilium.js +0 -86
- package/src/cli/commands/detectProfiles.js +0 -98
- package/src/cli/commands/envSync.js +0 -319
- package/src/cli/commands/generateProfileGuide.js +0 -144
- package/src/cli/commands/pruneSnapshot.js +0 -106
- package/src/cli/commands/restoreSnapshot.js +0 -173
- package/src/cli/commands/setupGemini.js +0 -149
- package/src/cli/commands/setupGemini.test.js +0 -115
- package/src/cli/commands/showFile.js +0 -39
- package/src/services/claudeCliService.js +0 -626
- package/src/services/claudeCliService.test.js +0 -267
|
@@ -1,27 +1,49 @@
|
|
|
1
1
|
import fs from 'fs/promises';
|
|
2
|
+
import fsSync from 'fs';
|
|
2
3
|
import path from 'path';
|
|
3
4
|
import chalk from 'chalk';
|
|
4
5
|
import ora from 'ora';
|
|
5
6
|
import os from 'os';
|
|
6
7
|
import { execa } from 'execa';
|
|
7
8
|
import { fileURLToPath } from 'url';
|
|
9
|
+
import { ensureSnapshotsInGitignore } from '../../utils/fileUtils.js';
|
|
8
10
|
|
|
9
11
|
const __filename = fileURLToPath(import.meta.url);
|
|
10
12
|
const __dirname = path.dirname(__filename);
|
|
11
13
|
|
|
12
14
|
/**
|
|
13
|
-
*
|
|
15
|
+
* Walk up from cwd to find the project root (directory containing .git or package.json).
|
|
16
|
+
* Falls back to cwd if no marker is found.
|
|
17
|
+
*/
|
|
18
|
+
function findProjectRoot() {
|
|
19
|
+
let dir = process.cwd();
|
|
20
|
+
const root = path.parse(dir).root;
|
|
21
|
+
while (dir !== root) {
|
|
22
|
+
try {
|
|
23
|
+
const entries = fsSync.readdirSync(dir);
|
|
24
|
+
if (entries.includes('.git') || entries.includes('package.json')) {
|
|
25
|
+
return dir;
|
|
26
|
+
}
|
|
27
|
+
} catch { /* unreadable dir, keep going */ }
|
|
28
|
+
dir = path.dirname(dir);
|
|
29
|
+
}
|
|
30
|
+
return process.cwd();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Setup / Restore MCP servers for Claude Code, OpenCode, and Codex.
|
|
14
35
|
* Registers:
|
|
15
36
|
* 1. eck-core (eck_finish_task) - commit + snapshot
|
|
16
37
|
* 2. glm-zai (glm_zai_*) - GLM-4.7 coding workers
|
|
17
38
|
*
|
|
18
39
|
* Usage:
|
|
19
|
-
* eck-snapshot setup-mcp # Auto-detect and register for Claude Code
|
|
40
|
+
* eck-snapshot setup-mcp # Auto-detect and register for Claude Code & Codex
|
|
20
41
|
* eck-snapshot setup-mcp --opencode # Register for OpenCode
|
|
21
|
-
* eck-snapshot setup-mcp --both # Register for
|
|
42
|
+
* eck-snapshot setup-mcp --both # Register for all
|
|
22
43
|
*/
|
|
23
44
|
export async function setupMcp(options = {}) {
|
|
24
45
|
const packageRoot = path.resolve(__dirname, '../../..');
|
|
46
|
+
const projectRoot = findProjectRoot();
|
|
25
47
|
const eckCorePath = path.join(packageRoot, 'scripts', 'mcp-eck-core.js');
|
|
26
48
|
const glmZaiPath = path.join(packageRoot, 'scripts', 'mcp-glm-zai-worker.mjs');
|
|
27
49
|
const targets = [];
|
|
@@ -34,15 +56,30 @@ export async function setupMcp(options = {}) {
|
|
|
34
56
|
}
|
|
35
57
|
|
|
36
58
|
console.log(chalk.blue.bold('\nš§ EckSnapshot MCP Setup\n'));
|
|
59
|
+
if (projectRoot !== process.cwd()) {
|
|
60
|
+
console.log(chalk.gray(` Project root: ${projectRoot}\n`));
|
|
61
|
+
}
|
|
37
62
|
|
|
38
63
|
for (const target of targets) {
|
|
39
64
|
if (target === 'claude') {
|
|
40
|
-
await setupForClaude(packageRoot, eckCorePath, glmZaiPath, options);
|
|
65
|
+
await setupForClaude(packageRoot, eckCorePath, glmZaiPath, options, projectRoot);
|
|
41
66
|
} else {
|
|
42
|
-
await setupForOpenCode(packageRoot, eckCorePath, glmZaiPath, options);
|
|
67
|
+
await setupForOpenCode(packageRoot, eckCorePath, glmZaiPath, options, projectRoot);
|
|
43
68
|
}
|
|
44
69
|
}
|
|
45
70
|
|
|
71
|
+
// Auto-detect Codex
|
|
72
|
+
const codexDir = path.join(projectRoot, '.codex');
|
|
73
|
+
let hasCodex = false;
|
|
74
|
+
try {
|
|
75
|
+
await fs.access(codexDir);
|
|
76
|
+
hasCodex = true;
|
|
77
|
+
} catch {}
|
|
78
|
+
|
|
79
|
+
if (hasCodex) {
|
|
80
|
+
await setupForCodex(packageRoot, eckCorePath, glmZaiPath, options, projectRoot);
|
|
81
|
+
}
|
|
82
|
+
|
|
46
83
|
// Print summary
|
|
47
84
|
console.log(chalk.green.bold('\nā
MCP Setup Complete!\n'));
|
|
48
85
|
console.log(chalk.white('Registered MCP servers:'));
|
|
@@ -54,16 +91,15 @@ export async function setupMcp(options = {}) {
|
|
|
54
91
|
console.log(chalk.white(' ⢠Get your key at https://z.ai'));
|
|
55
92
|
console.log('');
|
|
56
93
|
console.log(chalk.yellow('Next steps:'));
|
|
57
|
-
console.log(chalk.white(' 1. Restart your AI coding tool
|
|
94
|
+
console.log(chalk.white(' 1. Restart your AI coding tool'));
|
|
58
95
|
console.log(chalk.white(' 2. The tools will be available automatically'));
|
|
59
|
-
console.log(chalk.white(' 3. Use --jas or --jao flags to generate CLAUDE.md with delegation protocol'));
|
|
60
96
|
console.log('');
|
|
61
97
|
}
|
|
62
98
|
|
|
63
99
|
/**
|
|
64
100
|
* Register MCP servers for Claude Code using `claude mcp add`
|
|
65
101
|
*/
|
|
66
|
-
async function setupForClaude(packageRoot, eckCorePath, glmZaiPath, options) {
|
|
102
|
+
async function setupForClaude(packageRoot, eckCorePath, glmZaiPath, options, projectRoot) {
|
|
67
103
|
const spinner = ora();
|
|
68
104
|
|
|
69
105
|
console.log(chalk.blue('š¦ Setting up for Claude Code...\n'));
|
|
@@ -173,7 +209,7 @@ async function setupForClaude(packageRoot, eckCorePath, glmZaiPath, options) {
|
|
|
173
209
|
spinner.succeed(`Config saved: ${chalk.cyan(claudeConfigPath)}`);
|
|
174
210
|
|
|
175
211
|
// Also update the local .eck/claude-mcp-config.json
|
|
176
|
-
const localConfigPath = path.join(
|
|
212
|
+
const localConfigPath = path.join(projectRoot, '.eck', 'claude-mcp-config.json');
|
|
177
213
|
const localConfig = {
|
|
178
214
|
mcpServers: {
|
|
179
215
|
'eck-core': config.mcpServers['eck-core'],
|
|
@@ -183,6 +219,7 @@ async function setupForClaude(packageRoot, eckCorePath, glmZaiPath, options) {
|
|
|
183
219
|
|
|
184
220
|
try {
|
|
185
221
|
await fs.mkdir(path.dirname(localConfigPath), { recursive: true });
|
|
222
|
+
await ensureSnapshotsInGitignore(projectRoot);
|
|
186
223
|
await fs.writeFile(localConfigPath, JSON.stringify(localConfig, null, 2));
|
|
187
224
|
spinner.succeed(`Local config updated: ${chalk.cyan(localConfigPath)}`);
|
|
188
225
|
} catch (e) {
|
|
@@ -196,12 +233,12 @@ async function setupForClaude(packageRoot, eckCorePath, glmZaiPath, options) {
|
|
|
196
233
|
* { "mcp": { "name": { "type": "local", "command": [...], "enabled": true } } }
|
|
197
234
|
* The CLI (`opencode mcp add`) is interactive (TUI), so we write the config directly.
|
|
198
235
|
*/
|
|
199
|
-
async function setupForOpenCode(packageRoot, eckCorePath, glmZaiPath, options) {
|
|
236
|
+
async function setupForOpenCode(packageRoot, eckCorePath, glmZaiPath, options, projectRoot) {
|
|
200
237
|
const spinner = ora();
|
|
201
238
|
|
|
202
239
|
console.log(chalk.blue('š¦ Setting up for OpenCode...\n'));
|
|
203
240
|
|
|
204
|
-
const configPath = path.join(
|
|
241
|
+
const configPath = path.join(projectRoot, 'opencode.json');
|
|
205
242
|
|
|
206
243
|
spinner.start('Updating OpenCode config (opencode.json)...');
|
|
207
244
|
|
|
@@ -236,19 +273,38 @@ async function setupForOpenCode(packageRoot, eckCorePath, glmZaiPath, options) {
|
|
|
236
273
|
timeout: 120000,
|
|
237
274
|
};
|
|
238
275
|
|
|
239
|
-
// Preserve ZAI_API_KEY in environment if it was set before
|
|
240
|
-
if (process.env.ZAI_API_KEY) {
|
|
241
|
-
config.mcp['glm-zai'].environment = {
|
|
242
|
-
ZAI_API_KEY: process.env.ZAI_API_KEY,
|
|
243
|
-
};
|
|
244
|
-
}
|
|
245
|
-
|
|
246
276
|
// Remove old minimax entries if present
|
|
247
277
|
if (config.mcp['minimax-worker']) {
|
|
248
278
|
delete config.mcp['minimax-worker'];
|
|
249
279
|
console.log(chalk.gray(' Removed old minimax-worker from opencode.json'));
|
|
250
280
|
}
|
|
251
281
|
|
|
282
|
+
// Add permissions only if not already configured
|
|
283
|
+
// List all tools explicitly with "allow", then "*" as fallback for future tools
|
|
284
|
+
// Order matters: last matching rule wins, so users can override specific tools
|
|
285
|
+
if (!config.permission) {
|
|
286
|
+
config.permission = {
|
|
287
|
+
"read": "allow",
|
|
288
|
+
"edit": "allow",
|
|
289
|
+
"glob": "allow",
|
|
290
|
+
"grep": "allow",
|
|
291
|
+
"list": "allow",
|
|
292
|
+
"bash": "allow",
|
|
293
|
+
"task": "allow",
|
|
294
|
+
"skill": "allow",
|
|
295
|
+
"lsp": "allow",
|
|
296
|
+
"todoread": "allow",
|
|
297
|
+
"todowrite": "allow",
|
|
298
|
+
"webfetch": "allow",
|
|
299
|
+
"websearch": "allow",
|
|
300
|
+
"codesearch": "allow",
|
|
301
|
+
"external_directory": "allow",
|
|
302
|
+
"doom_loop": "allow",
|
|
303
|
+
"*": "allow"
|
|
304
|
+
};
|
|
305
|
+
console.log(chalk.gray(' Added default permissions (allow all) - modify in opencode.json to restrict'));
|
|
306
|
+
}
|
|
307
|
+
|
|
252
308
|
// Ensure AGENTS.md is in instructions
|
|
253
309
|
if (!config.instructions) {
|
|
254
310
|
config.instructions = ['AGENTS.md'];
|
|
@@ -260,5 +316,210 @@ async function setupForOpenCode(packageRoot, eckCorePath, glmZaiPath, options) {
|
|
|
260
316
|
spinner.succeed(`OpenCode config updated: ${chalk.cyan(configPath)}`);
|
|
261
317
|
|
|
262
318
|
console.log(chalk.gray('\n OpenCode will read MCP servers from opencode.json on next start.'));
|
|
263
|
-
console.log(chalk.gray(' Use `eck-snapshot
|
|
319
|
+
console.log(chalk.gray(' Use `eck-snapshot \'{"name": "eck_snapshot", "arguments": {"jas": true}}\'` to generate AGENTS.md.\n'));
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Register MCP servers for Codex by appending to .codex/config.toml
|
|
324
|
+
*/
|
|
325
|
+
async function setupForCodex(packageRoot, eckCorePath, glmZaiPath, options, projectRoot) {
|
|
326
|
+
const spinner = ora();
|
|
327
|
+
console.log(chalk.blue('š¦ Setting up for Codex...\n'));
|
|
328
|
+
spinner.start('Updating Codex config (.codex/config.toml)...');
|
|
329
|
+
|
|
330
|
+
try {
|
|
331
|
+
const updated = await ensureProjectCodexConfig(projectRoot);
|
|
332
|
+
if (updated) {
|
|
333
|
+
spinner.succeed(`Codex config updated: ${chalk.cyan('.codex/config.toml')}`);
|
|
334
|
+
} else {
|
|
335
|
+
spinner.info(`Codex config already up to date: ${chalk.cyan('.codex/config.toml')}`);
|
|
336
|
+
}
|
|
337
|
+
} catch (error) {
|
|
338
|
+
spinner.fail(`Failed to update Codex config: ${error.message}`);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Silently ensure .codex/config.toml exists in target project root with eck-core configured.
|
|
344
|
+
* Called automatically during snapshot creation so any Codex session
|
|
345
|
+
* in that project will have eck_finish_task / eck_fail_task available.
|
|
346
|
+
*
|
|
347
|
+
* @param {string} repoPath - Target project root
|
|
348
|
+
* @returns {boolean} true if config was created/updated, false if already OK
|
|
349
|
+
*/
|
|
350
|
+
export async function ensureProjectCodexConfig(repoPath) {
|
|
351
|
+
const codexDir = path.join(repoPath, '.codex');
|
|
352
|
+
try {
|
|
353
|
+
await fs.access(codexDir);
|
|
354
|
+
} catch {
|
|
355
|
+
return false; // No .codex directory, do nothing
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
const packageRoot = path.resolve(__dirname, '../../..');
|
|
359
|
+
const eckCorePath = path.join(packageRoot, 'scripts', 'mcp-eck-core.js');
|
|
360
|
+
const glmZaiPath = path.join(packageRoot, 'scripts', 'mcp-glm-zai-worker.mjs');
|
|
361
|
+
const configPath = path.join(codexDir, 'config.toml');
|
|
362
|
+
|
|
363
|
+
let content = '';
|
|
364
|
+
try {
|
|
365
|
+
content = await fs.readFile(configPath, 'utf-8');
|
|
366
|
+
} catch { /* file might not exist yet */ }
|
|
367
|
+
|
|
368
|
+
let updated = false;
|
|
369
|
+
|
|
370
|
+
// Simple string inclusion check (safe enough for TOML injection)
|
|
371
|
+
if (!content.includes('[mcp_servers.eck-core]')) {
|
|
372
|
+
content += `\n\n[mcp_servers.eck-core]\ncommand = "node"\nargs = ["${eckCorePath.replace(/\\/g, '\\\\')}"]\n`;
|
|
373
|
+
updated = true;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
if (!content.includes('[mcp_servers.glm-zai]')) {
|
|
377
|
+
content += `\n\n[mcp_servers.glm-zai]\ncommand = "node"\nargs = ["${glmZaiPath.replace(/\\/g, '\\\\')}"]\n`;
|
|
378
|
+
updated = true;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
if (updated) {
|
|
382
|
+
await fs.writeFile(configPath, content.trim() + '\n', 'utf-8');
|
|
383
|
+
return true;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
return false;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Silently ensure .mcp.json exists in target project root with eck-core configured.
|
|
391
|
+
* Called automatically during snapshot creation so any Claude Code session
|
|
392
|
+
* in that project will have eck_finish_task / eck_fail_task available.
|
|
393
|
+
*
|
|
394
|
+
* @param {string} repoPath - Target project root
|
|
395
|
+
* @returns {boolean} true if file was created/updated, false if already OK
|
|
396
|
+
*/
|
|
397
|
+
export async function ensureProjectMcpConfig(repoPath) {
|
|
398
|
+
const packageRoot = path.resolve(__dirname, '../../..');
|
|
399
|
+
const eckCorePath = path.join(packageRoot, 'scripts', 'mcp-eck-core.js');
|
|
400
|
+
const mcpJsonPath = path.join(repoPath, '.mcp.json');
|
|
401
|
+
|
|
402
|
+
// Read existing .mcp.json if present
|
|
403
|
+
let config = {};
|
|
404
|
+
try {
|
|
405
|
+
const content = await fs.readFile(mcpJsonPath, 'utf-8');
|
|
406
|
+
config = JSON.parse(content);
|
|
407
|
+
} catch { /* doesn't exist yet */ }
|
|
408
|
+
|
|
409
|
+
// Ensure root mcpServers key exists (required by Claude Code schema)
|
|
410
|
+
if (!config.mcpServers) {
|
|
411
|
+
config.mcpServers = {};
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// Check if eck-core is already configured with correct path
|
|
415
|
+
if (config.mcpServers['eck-core'] &&
|
|
416
|
+
config.mcpServers['eck-core'].command === 'node' &&
|
|
417
|
+
config.mcpServers['eck-core'].args?.[0] === eckCorePath) {
|
|
418
|
+
return false; // Already up to date
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// Add/update eck-core inside mcpServers
|
|
422
|
+
config.mcpServers['eck-core'] = {
|
|
423
|
+
command: 'node',
|
|
424
|
+
args: [eckCorePath]
|
|
425
|
+
};
|
|
426
|
+
|
|
427
|
+
await fs.writeFile(mcpJsonPath, JSON.stringify(config, null, 2) + '\n', 'utf-8');
|
|
428
|
+
|
|
429
|
+
// Ensure .mcp.json is in .gitignore (it contains absolute paths)
|
|
430
|
+
try {
|
|
431
|
+
const gitignorePath = path.join(repoPath, '.gitignore');
|
|
432
|
+
let gitignore = '';
|
|
433
|
+
try {
|
|
434
|
+
gitignore = await fs.readFile(gitignorePath, 'utf-8');
|
|
435
|
+
} catch { /* no .gitignore */ }
|
|
436
|
+
|
|
437
|
+
if (!gitignore.includes('.mcp.json')) {
|
|
438
|
+
const suffix = gitignore.endsWith('\n') || gitignore === '' ? '' : '\n';
|
|
439
|
+
await fs.writeFile(gitignorePath, gitignore + suffix + '.mcp.json\n', 'utf-8');
|
|
440
|
+
}
|
|
441
|
+
} catch { /* non-critical */ }
|
|
442
|
+
|
|
443
|
+
return true;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Silently ensure local opencode.json exists in target project root with eck-core configured.
|
|
448
|
+
* Called automatically during snapshot creation so any OpenCode session
|
|
449
|
+
* in that project will have eck_finish_task / eck_fail_task available.
|
|
450
|
+
*
|
|
451
|
+
* @param {string} repoPath - Target project root
|
|
452
|
+
* @returns {boolean} true if config was created/updated, false if already OK
|
|
453
|
+
*/
|
|
454
|
+
export async function ensureProjectOpenCodeConfig(repoPath) {
|
|
455
|
+
const packageRoot = path.resolve(__dirname, '../../..');
|
|
456
|
+
const eckCorePath = path.join(packageRoot, 'scripts', 'mcp-eck-core.js');
|
|
457
|
+
const configPath = path.join(repoPath, 'opencode.json');
|
|
458
|
+
|
|
459
|
+
// Read existing config or create new
|
|
460
|
+
let config = {};
|
|
461
|
+
try {
|
|
462
|
+
const content = await fs.readFile(configPath, 'utf-8');
|
|
463
|
+
config = JSON.parse(content);
|
|
464
|
+
} catch { /* new config */ }
|
|
465
|
+
|
|
466
|
+
// Ensure mcp key exists
|
|
467
|
+
if (!config.mcp) {
|
|
468
|
+
config.mcp = {};
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// Check if eck-core is already configured with correct path
|
|
472
|
+
if (config.mcp['eck-core'] &&
|
|
473
|
+
config.mcp['eck-core'].type === 'local' &&
|
|
474
|
+
config.mcp['eck-core'].command?.[0] === 'node' &&
|
|
475
|
+
config.mcp['eck-core'].command?.[1] === eckCorePath) {
|
|
476
|
+
// Still need to check instructions
|
|
477
|
+
if (config.instructions && config.instructions.includes('AGENTS.md')) {
|
|
478
|
+
return false; // Already up to date
|
|
479
|
+
}
|
|
480
|
+
} else {
|
|
481
|
+
// Add/update eck-core
|
|
482
|
+
config.mcp['eck-core'] = {
|
|
483
|
+
type: 'local',
|
|
484
|
+
command: ['node', eckCorePath],
|
|
485
|
+
enabled: true,
|
|
486
|
+
timeout: 30000,
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// Ensure AGENTS.md is in instructions
|
|
491
|
+
if (!config.instructions) {
|
|
492
|
+
config.instructions = ['AGENTS.md'];
|
|
493
|
+
} else if (!config.instructions.includes('AGENTS.md')) {
|
|
494
|
+
config.instructions.push('AGENTS.md');
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// Add permissions only if not already configured
|
|
498
|
+
// List all tools explicitly with "allow", then "*" as fallback for future tools
|
|
499
|
+
// Order matters: last matching rule wins, so users can override specific tools
|
|
500
|
+
if (!config.permission) {
|
|
501
|
+
config.permission = {
|
|
502
|
+
"read": "allow",
|
|
503
|
+
"edit": "allow",
|
|
504
|
+
"glob": "allow",
|
|
505
|
+
"grep": "allow",
|
|
506
|
+
"list": "allow",
|
|
507
|
+
"bash": "allow",
|
|
508
|
+
"task": "allow",
|
|
509
|
+
"skill": "allow",
|
|
510
|
+
"lsp": "allow",
|
|
511
|
+
"todoread": "allow",
|
|
512
|
+
"todowrite": "allow",
|
|
513
|
+
"webfetch": "allow",
|
|
514
|
+
"websearch": "allow",
|
|
515
|
+
"codesearch": "allow",
|
|
516
|
+
"external_directory": "allow",
|
|
517
|
+
"doom_loop": "allow",
|
|
518
|
+
"*": "allow"
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
await fs.writeFile(configPath, JSON.stringify(config, null, 2) + '\n', 'utf-8');
|
|
523
|
+
|
|
524
|
+
return true;
|
|
264
525
|
}
|
|
@@ -1,38 +1,48 @@
|
|
|
1
|
-
import
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import ora from 'ora';
|
|
3
|
+
import { addTrainingPoint, showEstimationStats, syncTokenWeights } from '../../utils/tokenEstimator.js';
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
export async function runTokenTools(payload) {
|
|
6
|
+
const toolName = payload.name;
|
|
7
|
+
const args = payload.arguments || {};
|
|
8
|
+
|
|
9
|
+
if (toolName === 'eck_train_tokens') {
|
|
10
|
+
await handleTrainTokens(args);
|
|
11
|
+
} else if (toolName === 'eck_token_stats') {
|
|
12
|
+
await handleTokenStats();
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async function handleTrainTokens(args) {
|
|
17
|
+
const { projectType, fileSizeBytes, estimatedTokens, actualTokens } = args;
|
|
18
|
+
|
|
19
|
+
if (!projectType || fileSizeBytes === undefined || estimatedTokens === undefined || actualTokens === undefined) {
|
|
20
|
+
console.log(chalk.red('ā Error: Missing required arguments for eck_train_tokens.'));
|
|
21
|
+
console.log(chalk.yellow('Expected: { projectType, fileSizeBytes, estimatedTokens, actualTokens }'));
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const spinner = ora('Calibrating token estimation polynomial...').start();
|
|
11
26
|
try {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
throw new Error('Invalid numeric values provided');
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
await addTrainingPoint(projectType, fileSizeInBytes, estimatedTokens, actualTokens);
|
|
23
|
-
|
|
24
|
-
console.log('\nš Updated polynomial coefficients for improved estimation.');
|
|
25
|
-
|
|
27
|
+
await addTrainingPoint(
|
|
28
|
+
projectType,
|
|
29
|
+
Number(fileSizeBytes),
|
|
30
|
+
Number(estimatedTokens),
|
|
31
|
+
Number(actualTokens)
|
|
32
|
+
);
|
|
33
|
+
spinner.succeed('Token estimation calibrated successfully.');
|
|
26
34
|
} catch (error) {
|
|
27
|
-
|
|
28
|
-
console.error('Usage: eck-snapshot train-tokens <project-type> <file-size-bytes> <estimated-tokens> <actual-tokens>');
|
|
29
|
-
process.exit(1);
|
|
35
|
+
spinner.fail(`Calibration failed: ${error.message}`);
|
|
30
36
|
}
|
|
31
37
|
}
|
|
32
38
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
async function handleTokenStats() {
|
|
40
|
+
const spinner = ora('Fetching latest token statistics and weights...').start();
|
|
41
|
+
try {
|
|
42
|
+
await syncTokenWeights(true);
|
|
43
|
+
spinner.stop();
|
|
44
|
+
await showEstimationStats();
|
|
45
|
+
} catch (error) {
|
|
46
|
+
spinner.fail(`Failed to fetch statistics: ${error.message}`);
|
|
47
|
+
}
|
|
48
|
+
}
|