@xelth/eck-snapshot 5.8.6 ā 6.0.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.
- package/README.md +46 -165
- package/package.json +2 -2
- package/scripts/mcp-eck-core.js +61 -13
- package/setup.json +64 -60
- package/src/cli/cli.js +25 -3
- package/src/cli/commands/createSnapshot.js +104 -99
- package/src/cli/commands/updateSnapshot.js +131 -72
- package/src/templates/opencode/coder.template.md +25 -9
- package/src/templates/opencode/junior-architect.template.md +47 -51
- package/src/utils/aiHeader.js +23 -22
- package/src/utils/claudeMdGenerator.js +142 -153
- package/src/utils/fileUtils.js +154 -89
- package/src/utils/gitUtils.js +12 -8
- package/src/utils/opencodeAgentsGenerator.js +29 -226
- package/src/utils/telemetry.js +98 -0
- package/src/utils/tokenEstimator.js +69 -23
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
|
|
5
|
+
const TELEMETRY_URL = 'https://xelth.com/T/report';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Parses the AnswerToSA.md file to extract telemetry data.
|
|
9
|
+
* @param {string} content The markdown content
|
|
10
|
+
* @returns {object|null} The parsed telemetry data or null if invalid
|
|
11
|
+
*/
|
|
12
|
+
export function parseAgentReport(content) {
|
|
13
|
+
if (!content) return null;
|
|
14
|
+
|
|
15
|
+
const data = {
|
|
16
|
+
model_name: 'Unknown',
|
|
17
|
+
agent_role: 'Coder',
|
|
18
|
+
task_scope: 'general',
|
|
19
|
+
status: 'UNKNOWN',
|
|
20
|
+
duration_sec: null,
|
|
21
|
+
error_summary: null
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// Extract Executor (Model Name)
|
|
25
|
+
const executorMatch = content.match(/\*\*Executor:\*\*\s*(.+)/i);
|
|
26
|
+
if (executorMatch) {
|
|
27
|
+
data.model_name = executorMatch[1].trim();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Extract Status
|
|
31
|
+
const statusMatch = content.match(/\*\*Status:\*\*\s*\[?(SUCCESS|FAILED|BLOCKED)\]?/i);
|
|
32
|
+
if (statusMatch) {
|
|
33
|
+
data.status = statusMatch[1].toUpperCase();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Extract Task Name / Scope
|
|
37
|
+
const titleMatch = content.match(/#\s*Report:\s*(.+)/i);
|
|
38
|
+
if (titleMatch) {
|
|
39
|
+
data.task_scope = titleMatch[1].trim().substring(0, 100);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// If failed/blocked, capture next few lines as error summary
|
|
43
|
+
if (data.status === 'FAILED' || data.status === 'BLOCKED') {
|
|
44
|
+
const lines = content.split('\n');
|
|
45
|
+
const statusIndex = lines.findIndex(l => l.match(/\*\*Status:\*\*/i));
|
|
46
|
+
if (statusIndex !== -1 && statusIndex + 1 < lines.length) {
|
|
47
|
+
data.error_summary = lines.slice(statusIndex + 1, statusIndex + 4).join(' ').trim().substring(0, 500);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return data;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Reads the latest report and pushes it to the telemetry server.
|
|
56
|
+
* @param {string} repoPath
|
|
57
|
+
* @param {boolean} silent If true, suppresses console output (for automated runs)
|
|
58
|
+
*/
|
|
59
|
+
export async function pushTelemetry(repoPath, silent = false) {
|
|
60
|
+
const reportPath = path.join(repoPath, '.eck', 'lastsnapshot', 'AnswerToSA.md');
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
const content = await fs.readFile(reportPath, 'utf-8');
|
|
64
|
+
|
|
65
|
+
// Don't push if already pushed
|
|
66
|
+
if (content.includes('[TELEMETRY: PUSHED]')) {
|
|
67
|
+
if (!silent) console.log(chalk.yellow('i Telemetry already pushed for this report.'));
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const payload = parseAgentReport(content);
|
|
72
|
+
if (!payload || payload.status === 'UNKNOWN') {
|
|
73
|
+
if (!silent) console.log(chalk.yellow('i Could not parse a valid agent report for telemetry.'));
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const response = await fetch(TELEMETRY_URL, {
|
|
78
|
+
method: 'POST',
|
|
79
|
+
headers: { 'Content-Type': 'application/json' },
|
|
80
|
+
body: JSON.stringify(payload)
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
if (response.ok) {
|
|
84
|
+
if (!silent) console.log(chalk.green(`Telemetry pushed successfully for ${payload.model_name} (${payload.status})`));
|
|
85
|
+
await fs.appendFile(reportPath, '\n\n[TELEMETRY: PUSHED]\n', 'utf-8');
|
|
86
|
+
} else {
|
|
87
|
+
if (!silent) console.log(chalk.red(`Telemetry push failed: ${response.statusText}`));
|
|
88
|
+
}
|
|
89
|
+
} catch (error) {
|
|
90
|
+
if (!silent) {
|
|
91
|
+
if (error.code === 'ENOENT') {
|
|
92
|
+
console.log(chalk.yellow('i No AnswerToSA.md found. Nothing to push.'));
|
|
93
|
+
} else {
|
|
94
|
+
console.log(chalk.red(`Telemetry error: ${error.message}`));
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -117,8 +117,50 @@ export async function addTrainingPoint(projectType, fileSizeInBytes, estimatedTo
|
|
|
117
117
|
console.log(` Estimated: ${estimatedTokens} tokens`);
|
|
118
118
|
console.log(` Actual: ${actualTokens} tokens`);
|
|
119
119
|
console.log(` Error: ${Math.abs(actualTokens - estimatedTokens)} tokens (${Math.round(Math.abs(actualTokens - estimatedTokens) / actualTokens * 100)}%)`);
|
|
120
|
+
|
|
121
|
+
// Push training point to Telemetry Hub
|
|
122
|
+
try {
|
|
123
|
+
const res = await fetch('https://xelth.com/T/tokens/train', {
|
|
124
|
+
method: 'POST',
|
|
125
|
+
headers: { 'Content-Type': 'application/json' },
|
|
126
|
+
body: JSON.stringify({
|
|
127
|
+
project_type: projectType,
|
|
128
|
+
file_size_bytes: fileSizeInBytes,
|
|
129
|
+
actual_tokens: actualTokens
|
|
130
|
+
})
|
|
131
|
+
});
|
|
132
|
+
if (res.ok) {
|
|
133
|
+
console.log(' Training point pushed to Telemetry Hub');
|
|
134
|
+
}
|
|
135
|
+
} catch (e) {
|
|
136
|
+
// Fail silently, network might be down
|
|
137
|
+
}
|
|
120
138
|
}
|
|
121
139
|
|
|
140
|
+
/**
|
|
141
|
+
* Fetch global token weights from Telemetry Hub and merge them into local training data
|
|
142
|
+
*/
|
|
143
|
+
export async function syncTokenWeights(silent = false) {
|
|
144
|
+
try {
|
|
145
|
+
if (!silent) console.log('Fetching global token weights from Telemetry Hub...');
|
|
146
|
+
const res = await fetch('https://xelth.com/T/tokens/weights');
|
|
147
|
+
if (!res.ok) throw new Error(res.statusText);
|
|
148
|
+
const data = await res.json();
|
|
149
|
+
|
|
150
|
+
if (data && data.coefficients && Object.keys(data.coefficients).length > 0) {
|
|
151
|
+
const localData = await loadTrainingData();
|
|
152
|
+
// Global coefficients override local ones
|
|
153
|
+
localData.coefficients = { ...localData.coefficients, ...data.coefficients };
|
|
154
|
+
await saveTrainingData(localData);
|
|
155
|
+
if (!silent) console.log('Global token weights synchronized successfully.');
|
|
156
|
+
} else {
|
|
157
|
+
if (!silent) console.log('No global weights available yet.');
|
|
158
|
+
}
|
|
159
|
+
} catch (e) {
|
|
160
|
+
if (!silent) console.log('Failed to sync token weights: ' + e.message);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
122
164
|
/**
|
|
123
165
|
* Update polynomial coefficients using least squares fitting
|
|
124
166
|
* For now, we'll use a simple adaptive approach
|
|
@@ -175,27 +217,31 @@ function updateCoefficients(data, projectType) {
|
|
|
175
217
|
];
|
|
176
218
|
}
|
|
177
219
|
|
|
178
|
-
/**
|
|
179
|
-
* Show current estimation statistics
|
|
180
|
-
*/
|
|
181
|
-
export async function showEstimationStats() {
|
|
182
|
-
const data = await loadTrainingData();
|
|
183
|
-
|
|
184
|
-
console.log('\nš Token Estimation Statistics:');
|
|
185
|
-
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
186
|
-
|
|
187
|
-
for (const [projectType, coefficients] of Object.entries(data.coefficients)) {
|
|
188
|
-
const points = data.trainingPoints[projectType] || [];
|
|
189
|
-
console.log(`\nšø ${projectType}:`);
|
|
190
|
-
console.log(` Coefficients: [${coefficients.map(c => c.toFixed(6)).join(', ')}]`);
|
|
191
|
-
console.log(` Training points: ${points.length}`);
|
|
192
|
-
|
|
193
|
-
if (points.length > 0) {
|
|
194
|
-
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
220
|
+
/**
|
|
221
|
+
* Show current estimation statistics
|
|
222
|
+
*/
|
|
223
|
+
export async function showEstimationStats() {
|
|
224
|
+
const data = await loadTrainingData();
|
|
225
|
+
|
|
226
|
+
console.log('\nš Token Estimation Statistics:');
|
|
227
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
228
|
+
|
|
229
|
+
for (const [projectType, coefficients] of Object.entries(data.coefficients)) {
|
|
230
|
+
const points = data.trainingPoints[projectType] || [];
|
|
231
|
+
console.log(`\nšø ${projectType}:`);
|
|
232
|
+
console.log(` Coefficients: [${coefficients.map(c => c.toFixed(6)).join(', ')}]`);
|
|
233
|
+
console.log(` Training points: ${points.length}`);
|
|
234
|
+
|
|
235
|
+
if (points.length > 0) {
|
|
236
|
+
// Recalculate error against current coefficients, ignoring old stored estimate
|
|
237
|
+
const errors = points.map(p => {
|
|
238
|
+
const currentEstimate = evaluatePolynomial(coefficients, p.fileSizeInBytes);
|
|
239
|
+
return Math.abs(p.actualTokens - currentEstimate);
|
|
240
|
+
});
|
|
241
|
+
const avgError = errors.reduce((a, b) => a + b, 0) / errors.length;
|
|
242
|
+
console.log(` Average error: ${Math.round(avgError)} tokens`);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
201
247
|
}
|