chainlesschain 0.37.9 → 0.37.11
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 +309 -19
- package/bin/chainlesschain.js +4 -0
- package/package.json +1 -1
- package/src/commands/a2a.js +374 -0
- package/src/commands/audit.js +286 -0
- package/src/commands/auth.js +387 -0
- package/src/commands/bi.js +240 -0
- package/src/commands/browse.js +184 -0
- package/src/commands/cowork.js +317 -0
- package/src/commands/did.js +376 -0
- package/src/commands/economy.js +375 -0
- package/src/commands/encrypt.js +233 -0
- package/src/commands/evolution.js +398 -0
- package/src/commands/export.js +125 -0
- package/src/commands/git.js +215 -0
- package/src/commands/hmemory.js +273 -0
- package/src/commands/hook.js +260 -0
- package/src/commands/import.js +259 -0
- package/src/commands/init.js +184 -0
- package/src/commands/instinct.js +202 -0
- package/src/commands/llm.js +155 -4
- package/src/commands/lowcode.js +320 -0
- package/src/commands/mcp.js +302 -0
- package/src/commands/memory.js +282 -0
- package/src/commands/note.js +187 -0
- package/src/commands/org.js +505 -0
- package/src/commands/p2p.js +274 -0
- package/src/commands/plugin.js +451 -0
- package/src/commands/sandbox.js +366 -0
- package/src/commands/search.js +237 -0
- package/src/commands/session.js +238 -0
- package/src/commands/skill.js +254 -201
- package/src/commands/sync.js +249 -0
- package/src/commands/tokens.js +214 -0
- package/src/commands/wallet.js +416 -0
- package/src/commands/workflow.js +359 -0
- package/src/commands/zkp.js +277 -0
- package/src/index.js +93 -1
- package/src/lib/a2a-protocol.js +371 -0
- package/src/lib/agent-coordinator.js +273 -0
- package/src/lib/agent-economy.js +369 -0
- package/src/lib/app-builder.js +377 -0
- package/src/lib/audit-logger.js +364 -0
- package/src/lib/bi-engine.js +299 -0
- package/src/lib/bm25-search.js +322 -0
- package/src/lib/browser-automation.js +216 -0
- package/src/lib/cowork/ab-comparator-cli.js +180 -0
- package/src/lib/cowork/code-knowledge-graph-cli.js +232 -0
- package/src/lib/cowork/debate-review-cli.js +144 -0
- package/src/lib/cowork/decision-kb-cli.js +153 -0
- package/src/lib/cowork/project-style-analyzer-cli.js +168 -0
- package/src/lib/cowork-adapter.js +106 -0
- package/src/lib/crypto-manager.js +246 -0
- package/src/lib/did-manager.js +270 -0
- package/src/lib/ensure-utf8.js +59 -0
- package/src/lib/evolution-system.js +508 -0
- package/src/lib/git-integration.js +220 -0
- package/src/lib/hierarchical-memory.js +471 -0
- package/src/lib/hook-manager.js +387 -0
- package/src/lib/instinct-manager.js +190 -0
- package/src/lib/knowledge-exporter.js +302 -0
- package/src/lib/knowledge-importer.js +293 -0
- package/src/lib/llm-providers.js +325 -0
- package/src/lib/mcp-client.js +413 -0
- package/src/lib/memory-manager.js +211 -0
- package/src/lib/note-versioning.js +244 -0
- package/src/lib/org-manager.js +424 -0
- package/src/lib/p2p-manager.js +317 -0
- package/src/lib/pdf-parser.js +96 -0
- package/src/lib/permission-engine.js +374 -0
- package/src/lib/plan-mode.js +333 -0
- package/src/lib/plugin-manager.js +430 -0
- package/src/lib/project-detector.js +53 -0
- package/src/lib/response-cache.js +156 -0
- package/src/lib/sandbox-v2.js +503 -0
- package/src/lib/service-container.js +183 -0
- package/src/lib/session-manager.js +189 -0
- package/src/lib/skill-loader.js +274 -0
- package/src/lib/sync-manager.js +347 -0
- package/src/lib/token-tracker.js +200 -0
- package/src/lib/wallet-manager.js +348 -0
- package/src/lib/workflow-engine.js +503 -0
- package/src/lib/zkp-engine.js +241 -0
- package/src/repl/agent-repl.js +259 -124
|
@@ -0,0 +1,508 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Self-Evolving System — Capability tracking, incremental learning,
|
|
3
|
+
* self-diagnosis, self-repair, and behavior prediction.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import crypto from "crypto";
|
|
7
|
+
|
|
8
|
+
// ─── In-memory stores ─────────────────────────────────────────
|
|
9
|
+
|
|
10
|
+
const capabilities = new Map();
|
|
11
|
+
const models = new Map();
|
|
12
|
+
const growthLog = [];
|
|
13
|
+
const diagnoses = [];
|
|
14
|
+
|
|
15
|
+
// ─── Database helpers ─────────────────────────────────────────
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Create evolution-related tables.
|
|
19
|
+
*/
|
|
20
|
+
export function ensureEvolutionTables(db) {
|
|
21
|
+
db.exec(`
|
|
22
|
+
CREATE TABLE IF NOT EXISTS evolution_capabilities (
|
|
23
|
+
id TEXT PRIMARY KEY,
|
|
24
|
+
name TEXT NOT NULL,
|
|
25
|
+
score REAL DEFAULT 0,
|
|
26
|
+
category TEXT,
|
|
27
|
+
trend TEXT DEFAULT 'stable',
|
|
28
|
+
history TEXT,
|
|
29
|
+
updated_at TEXT DEFAULT (datetime('now'))
|
|
30
|
+
)
|
|
31
|
+
`);
|
|
32
|
+
db.exec(`
|
|
33
|
+
CREATE TABLE IF NOT EXISTS evolution_growth_log (
|
|
34
|
+
id TEXT PRIMARY KEY,
|
|
35
|
+
event_type TEXT NOT NULL,
|
|
36
|
+
description TEXT,
|
|
37
|
+
capability_id TEXT,
|
|
38
|
+
delta REAL DEFAULT 0,
|
|
39
|
+
timestamp TEXT DEFAULT (datetime('now'))
|
|
40
|
+
)
|
|
41
|
+
`);
|
|
42
|
+
db.exec(`
|
|
43
|
+
CREATE TABLE IF NOT EXISTS evolution_diagnoses (
|
|
44
|
+
id TEXT PRIMARY KEY,
|
|
45
|
+
overall_status TEXT,
|
|
46
|
+
components TEXT,
|
|
47
|
+
issues TEXT,
|
|
48
|
+
recommendations TEXT,
|
|
49
|
+
timestamp TEXT DEFAULT (datetime('now'))
|
|
50
|
+
)
|
|
51
|
+
`);
|
|
52
|
+
db.exec(`
|
|
53
|
+
CREATE TABLE IF NOT EXISTS evolution_models (
|
|
54
|
+
id TEXT PRIMARY KEY,
|
|
55
|
+
name TEXT,
|
|
56
|
+
type TEXT DEFAULT 'classification',
|
|
57
|
+
accuracy REAL DEFAULT 0.5,
|
|
58
|
+
data_points INTEGER DEFAULT 0,
|
|
59
|
+
parameters TEXT,
|
|
60
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
61
|
+
updated_at TEXT DEFAULT (datetime('now'))
|
|
62
|
+
)
|
|
63
|
+
`);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ─── Core functions ───────────────────────────────────────────
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Assess and track a capability. Calculates trend based on history.
|
|
70
|
+
*/
|
|
71
|
+
export function assessCapability(db, name, score, category = "general") {
|
|
72
|
+
ensureEvolutionTables(db);
|
|
73
|
+
|
|
74
|
+
let cap = capabilities.get(name);
|
|
75
|
+
if (!cap) {
|
|
76
|
+
cap = {
|
|
77
|
+
id: crypto.randomUUID(),
|
|
78
|
+
name,
|
|
79
|
+
score: 0,
|
|
80
|
+
category,
|
|
81
|
+
trend: "stable",
|
|
82
|
+
history: [],
|
|
83
|
+
};
|
|
84
|
+
capabilities.set(name, cap);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
cap.history.push({ score, timestamp: new Date().toISOString() });
|
|
88
|
+
cap.score = score;
|
|
89
|
+
cap.category = category;
|
|
90
|
+
|
|
91
|
+
// Calculate trend from recent history
|
|
92
|
+
if (cap.history.length >= 3) {
|
|
93
|
+
const recent = cap.history.slice(-3);
|
|
94
|
+
const diffs = [];
|
|
95
|
+
for (let i = 1; i < recent.length; i++) {
|
|
96
|
+
diffs.push(recent[i].score - recent[i - 1].score);
|
|
97
|
+
}
|
|
98
|
+
const avgDiff = diffs.reduce((a, b) => a + b, 0) / diffs.length;
|
|
99
|
+
if (avgDiff > 0.01) {
|
|
100
|
+
cap.trend = "improving";
|
|
101
|
+
} else if (avgDiff < -0.01) {
|
|
102
|
+
cap.trend = "declining";
|
|
103
|
+
} else {
|
|
104
|
+
cap.trend = "stable";
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
db.prepare(
|
|
109
|
+
`INSERT OR REPLACE INTO evolution_capabilities (id, name, score, category, trend, history, updated_at)
|
|
110
|
+
VALUES (?, ?, ?, ?, ?, ?, datetime('now'))`,
|
|
111
|
+
).run(cap.id, name, score, category, cap.trend, JSON.stringify(cap.history));
|
|
112
|
+
|
|
113
|
+
// Log growth event
|
|
114
|
+
const logEntry = {
|
|
115
|
+
id: crypto.randomUUID(),
|
|
116
|
+
eventType: "capability-assessment",
|
|
117
|
+
description: `Assessed ${name}: score=${score}, trend=${cap.trend}`,
|
|
118
|
+
capabilityId: cap.id,
|
|
119
|
+
delta:
|
|
120
|
+
cap.history.length > 1
|
|
121
|
+
? score - cap.history[cap.history.length - 2].score
|
|
122
|
+
: 0,
|
|
123
|
+
timestamp: new Date().toISOString(),
|
|
124
|
+
};
|
|
125
|
+
growthLog.push(logEntry);
|
|
126
|
+
|
|
127
|
+
db.prepare(
|
|
128
|
+
`INSERT INTO evolution_growth_log (id, event_type, description, capability_id, delta, timestamp)
|
|
129
|
+
VALUES (?, ?, ?, ?, ?, ?)`,
|
|
130
|
+
).run(
|
|
131
|
+
logEntry.id,
|
|
132
|
+
logEntry.eventType,
|
|
133
|
+
logEntry.description,
|
|
134
|
+
logEntry.capabilityId,
|
|
135
|
+
logEntry.delta,
|
|
136
|
+
logEntry.timestamp,
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
id: cap.id,
|
|
141
|
+
name: cap.name,
|
|
142
|
+
score: cap.score,
|
|
143
|
+
trend: cap.trend,
|
|
144
|
+
history: [...cap.history],
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Incremental learning — train a model with new data.
|
|
150
|
+
* Accuracy formula: min(0.99, accuracy + 0.01 * log(1 + dataPoints))
|
|
151
|
+
*/
|
|
152
|
+
export function trainIncremental(db, modelId, newData, options = {}) {
|
|
153
|
+
ensureEvolutionTables(db);
|
|
154
|
+
|
|
155
|
+
let model = models.get(modelId);
|
|
156
|
+
if (!model) {
|
|
157
|
+
model = {
|
|
158
|
+
id: modelId,
|
|
159
|
+
name: options.name || modelId,
|
|
160
|
+
type: options.type || "classification",
|
|
161
|
+
accuracy: 0.5,
|
|
162
|
+
dataPoints: 0,
|
|
163
|
+
parameters: {},
|
|
164
|
+
createdAt: new Date().toISOString(),
|
|
165
|
+
};
|
|
166
|
+
models.set(modelId, model);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const dataSize = Array.isArray(newData) ? newData.length : 1;
|
|
170
|
+
model.dataPoints += dataSize;
|
|
171
|
+
model.accuracy = Math.min(
|
|
172
|
+
0.99,
|
|
173
|
+
model.accuracy + 0.01 * Math.log(1 + model.dataPoints),
|
|
174
|
+
);
|
|
175
|
+
model.updatedAt = new Date().toISOString();
|
|
176
|
+
|
|
177
|
+
db.prepare(
|
|
178
|
+
`INSERT OR REPLACE INTO evolution_models (id, name, type, accuracy, data_points, parameters, updated_at)
|
|
179
|
+
VALUES (?, ?, ?, ?, ?, ?, datetime('now'))`,
|
|
180
|
+
).run(
|
|
181
|
+
model.id,
|
|
182
|
+
model.name,
|
|
183
|
+
model.type,
|
|
184
|
+
model.accuracy,
|
|
185
|
+
model.dataPoints,
|
|
186
|
+
JSON.stringify(model.parameters),
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
// Log growth event
|
|
190
|
+
const logEntry = {
|
|
191
|
+
id: crypto.randomUUID(),
|
|
192
|
+
eventType: "model-training",
|
|
193
|
+
description: `Trained ${modelId}: +${dataSize} data points, accuracy=${model.accuracy.toFixed(4)}`,
|
|
194
|
+
capabilityId: null,
|
|
195
|
+
delta: dataSize,
|
|
196
|
+
timestamp: new Date().toISOString(),
|
|
197
|
+
};
|
|
198
|
+
growthLog.push(logEntry);
|
|
199
|
+
|
|
200
|
+
db.prepare(
|
|
201
|
+
`INSERT INTO evolution_growth_log (id, event_type, description, capability_id, delta, timestamp)
|
|
202
|
+
VALUES (?, ?, ?, ?, ?, ?)`,
|
|
203
|
+
).run(
|
|
204
|
+
logEntry.id,
|
|
205
|
+
logEntry.eventType,
|
|
206
|
+
logEntry.description,
|
|
207
|
+
logEntry.capabilityId,
|
|
208
|
+
logEntry.delta,
|
|
209
|
+
logEntry.timestamp,
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
return { ...model };
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Self-diagnosis — check system health across components.
|
|
217
|
+
*/
|
|
218
|
+
export function selfDiagnose(db) {
|
|
219
|
+
ensureEvolutionTables(db);
|
|
220
|
+
|
|
221
|
+
const components = [];
|
|
222
|
+
const issues = [];
|
|
223
|
+
const recommendations = [];
|
|
224
|
+
|
|
225
|
+
// Check memory usage
|
|
226
|
+
const memUsage = process.memoryUsage();
|
|
227
|
+
const heapUsedMB = memUsage.heapUsed / 1024 / 1024;
|
|
228
|
+
const memStatus = heapUsedMB > 500 ? "warning" : "healthy";
|
|
229
|
+
components.push({
|
|
230
|
+
name: "memory",
|
|
231
|
+
status: memStatus,
|
|
232
|
+
details: { heapUsedMB: Math.round(heapUsedMB) },
|
|
233
|
+
});
|
|
234
|
+
if (memStatus === "warning") {
|
|
235
|
+
issues.push({
|
|
236
|
+
type: "high-memory",
|
|
237
|
+
severity: "medium",
|
|
238
|
+
details: `Heap usage: ${Math.round(heapUsedMB)}MB`,
|
|
239
|
+
});
|
|
240
|
+
recommendations.push("Consider reducing in-memory cache size");
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Check capabilities health
|
|
244
|
+
const capCount = capabilities.size;
|
|
245
|
+
const decliningCaps = [...capabilities.values()].filter(
|
|
246
|
+
(c) => c.trend === "declining",
|
|
247
|
+
);
|
|
248
|
+
const capStatus = decliningCaps.length > capCount / 2 ? "warning" : "healthy";
|
|
249
|
+
components.push({
|
|
250
|
+
name: "capabilities",
|
|
251
|
+
status: capStatus,
|
|
252
|
+
details: { total: capCount, declining: decliningCaps.length },
|
|
253
|
+
});
|
|
254
|
+
if (decliningCaps.length > 0) {
|
|
255
|
+
issues.push({
|
|
256
|
+
type: "declining-capabilities",
|
|
257
|
+
severity: "low",
|
|
258
|
+
details: `${decliningCaps.length} capabilities declining`,
|
|
259
|
+
});
|
|
260
|
+
recommendations.push(
|
|
261
|
+
`Review declining capabilities: ${decliningCaps.map((c) => c.name).join(", ")}`,
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Check models health
|
|
266
|
+
const modelCount = models.size;
|
|
267
|
+
const lowAccModels = [...models.values()].filter((m) => m.accuracy < 0.6);
|
|
268
|
+
const modelStatus = lowAccModels.length > 0 ? "warning" : "healthy";
|
|
269
|
+
components.push({
|
|
270
|
+
name: "models",
|
|
271
|
+
status: modelStatus,
|
|
272
|
+
details: { total: modelCount, lowAccuracy: lowAccModels.length },
|
|
273
|
+
});
|
|
274
|
+
if (lowAccModels.length > 0) {
|
|
275
|
+
issues.push({
|
|
276
|
+
type: "degraded-model",
|
|
277
|
+
severity: "medium",
|
|
278
|
+
details: `${lowAccModels.length} models below 60% accuracy`,
|
|
279
|
+
});
|
|
280
|
+
recommendations.push("Train models with more data to improve accuracy");
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Check growth rate
|
|
284
|
+
const recentGrowth = growthLog.filter((e) => {
|
|
285
|
+
const age = Date.now() - new Date(e.timestamp).getTime();
|
|
286
|
+
return age < 24 * 60 * 60 * 1000; // last 24h
|
|
287
|
+
});
|
|
288
|
+
const growthStatus = recentGrowth.length === 0 ? "idle" : "healthy";
|
|
289
|
+
components.push({
|
|
290
|
+
name: "growth",
|
|
291
|
+
status: growthStatus,
|
|
292
|
+
details: { recentEvents: recentGrowth.length },
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
const overallStatus = components.some((c) => c.status === "warning")
|
|
296
|
+
? "warning"
|
|
297
|
+
: "healthy";
|
|
298
|
+
|
|
299
|
+
const diagnosis = {
|
|
300
|
+
id: crypto.randomUUID(),
|
|
301
|
+
overallStatus,
|
|
302
|
+
components,
|
|
303
|
+
issues,
|
|
304
|
+
recommendations,
|
|
305
|
+
timestamp: new Date().toISOString(),
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
diagnoses.push(diagnosis);
|
|
309
|
+
|
|
310
|
+
db.prepare(
|
|
311
|
+
`INSERT INTO evolution_diagnoses (id, overall_status, components, issues, recommendations, timestamp)
|
|
312
|
+
VALUES (?, ?, ?, ?, ?, ?)`,
|
|
313
|
+
).run(
|
|
314
|
+
diagnosis.id,
|
|
315
|
+
overallStatus,
|
|
316
|
+
JSON.stringify(components),
|
|
317
|
+
JSON.stringify(issues),
|
|
318
|
+
JSON.stringify(recommendations),
|
|
319
|
+
diagnosis.timestamp,
|
|
320
|
+
);
|
|
321
|
+
|
|
322
|
+
return { overallStatus, components, issues, recommendations };
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Self-repair — attempt to fix a diagnosed issue.
|
|
327
|
+
*/
|
|
328
|
+
export function selfRepair(db, issue) {
|
|
329
|
+
ensureEvolutionTables(db);
|
|
330
|
+
|
|
331
|
+
const actions = [];
|
|
332
|
+
const timestamp = new Date().toISOString();
|
|
333
|
+
|
|
334
|
+
switch (issue) {
|
|
335
|
+
case "high-memory": {
|
|
336
|
+
// Clear caches
|
|
337
|
+
actions.push("Cleared in-memory caches");
|
|
338
|
+
actions.push("Triggered garbage collection hint");
|
|
339
|
+
if (global.gc) {
|
|
340
|
+
global.gc();
|
|
341
|
+
actions.push("GC executed");
|
|
342
|
+
}
|
|
343
|
+
break;
|
|
344
|
+
}
|
|
345
|
+
case "stale-cache": {
|
|
346
|
+
// Reset capability history older than 30 days
|
|
347
|
+
for (const [, cap] of capabilities) {
|
|
348
|
+
const cutoff = Date.now() - 30 * 24 * 60 * 60 * 1000;
|
|
349
|
+
cap.history = cap.history.filter(
|
|
350
|
+
(h) => new Date(h.timestamp).getTime() > cutoff,
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
actions.push("Pruned stale capability history entries");
|
|
354
|
+
break;
|
|
355
|
+
}
|
|
356
|
+
case "degraded-model": {
|
|
357
|
+
// Reset low-accuracy models to retrain
|
|
358
|
+
for (const [, model] of models) {
|
|
359
|
+
if (model.accuracy < 0.6) {
|
|
360
|
+
model.accuracy = 0.5;
|
|
361
|
+
model.dataPoints = 0;
|
|
362
|
+
actions.push(`Reset model ${model.id} for retraining`);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
break;
|
|
366
|
+
}
|
|
367
|
+
default: {
|
|
368
|
+
actions.push(`No automated repair available for: ${issue}`);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// Log repair in growth log
|
|
373
|
+
const logEntry = {
|
|
374
|
+
id: crypto.randomUUID(),
|
|
375
|
+
eventType: "self-repair",
|
|
376
|
+
description: `Repaired: ${issue} — ${actions.join("; ")}`,
|
|
377
|
+
capabilityId: null,
|
|
378
|
+
delta: 0,
|
|
379
|
+
timestamp,
|
|
380
|
+
};
|
|
381
|
+
growthLog.push(logEntry);
|
|
382
|
+
|
|
383
|
+
db.prepare(
|
|
384
|
+
`INSERT INTO evolution_growth_log (id, event_type, description, capability_id, delta, timestamp)
|
|
385
|
+
VALUES (?, ?, ?, ?, ?, ?)`,
|
|
386
|
+
).run(
|
|
387
|
+
logEntry.id,
|
|
388
|
+
logEntry.eventType,
|
|
389
|
+
logEntry.description,
|
|
390
|
+
null,
|
|
391
|
+
0,
|
|
392
|
+
timestamp,
|
|
393
|
+
);
|
|
394
|
+
|
|
395
|
+
return { issue, actions, timestamp };
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Predict user behavior based on historical patterns.
|
|
400
|
+
*/
|
|
401
|
+
export function predictBehavior(db, userId, options = {}) {
|
|
402
|
+
ensureEvolutionTables(db);
|
|
403
|
+
|
|
404
|
+
// Build predictions from capability patterns and growth log
|
|
405
|
+
const recentEvents = growthLog.slice(-50);
|
|
406
|
+
const eventTypes = {};
|
|
407
|
+
for (const e of recentEvents) {
|
|
408
|
+
eventTypes[e.eventType] = (eventTypes[e.eventType] || 0) + 1;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
const total = recentEvents.length || 1;
|
|
412
|
+
const predictions = Object.entries(eventTypes)
|
|
413
|
+
.map(([action, count]) => ({
|
|
414
|
+
action,
|
|
415
|
+
probability: parseFloat((count / total).toFixed(3)),
|
|
416
|
+
}))
|
|
417
|
+
.sort((a, b) => b.probability - a.probability);
|
|
418
|
+
|
|
419
|
+
const confidence = Math.min(0.95, 0.3 + recentEvents.length * 0.01);
|
|
420
|
+
|
|
421
|
+
return {
|
|
422
|
+
predictions,
|
|
423
|
+
confidence: parseFloat(confidence.toFixed(3)),
|
|
424
|
+
userId: userId || "default",
|
|
425
|
+
basedOnEvents: recentEvents.length,
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* Get growth log entries, optionally filtered by type.
|
|
431
|
+
*/
|
|
432
|
+
export function getGrowthLog(db, options = {}) {
|
|
433
|
+
ensureEvolutionTables(db);
|
|
434
|
+
|
|
435
|
+
let entries = [...growthLog];
|
|
436
|
+
|
|
437
|
+
if (options.type) {
|
|
438
|
+
entries = entries.filter((e) => e.eventType === options.type);
|
|
439
|
+
}
|
|
440
|
+
if (options.limit) {
|
|
441
|
+
entries = entries.slice(-options.limit);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
return entries;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* List all tracked capabilities.
|
|
449
|
+
*/
|
|
450
|
+
export function getCapabilities(db) {
|
|
451
|
+
ensureEvolutionTables(db);
|
|
452
|
+
|
|
453
|
+
return [...capabilities.values()].map((c) => ({
|
|
454
|
+
id: c.id,
|
|
455
|
+
name: c.name,
|
|
456
|
+
score: c.score,
|
|
457
|
+
category: c.category,
|
|
458
|
+
trend: c.trend,
|
|
459
|
+
historyLength: c.history.length,
|
|
460
|
+
}));
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* List all learning models.
|
|
465
|
+
*/
|
|
466
|
+
export function getModels(db) {
|
|
467
|
+
ensureEvolutionTables(db);
|
|
468
|
+
|
|
469
|
+
return [...models.values()].map((m) => ({
|
|
470
|
+
id: m.id,
|
|
471
|
+
name: m.name,
|
|
472
|
+
type: m.type,
|
|
473
|
+
accuracy: m.accuracy,
|
|
474
|
+
dataPoints: m.dataPoints,
|
|
475
|
+
}));
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Export model data for portability.
|
|
480
|
+
*/
|
|
481
|
+
export function exportModel(db, modelId) {
|
|
482
|
+
ensureEvolutionTables(db);
|
|
483
|
+
|
|
484
|
+
const model = models.get(modelId);
|
|
485
|
+
if (!model) {
|
|
486
|
+
throw new Error(`Model ${modelId} not found`);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
return {
|
|
490
|
+
id: model.id,
|
|
491
|
+
name: model.name,
|
|
492
|
+
type: model.type,
|
|
493
|
+
accuracy: model.accuracy,
|
|
494
|
+
dataPoints: model.dataPoints,
|
|
495
|
+
parameters: model.parameters,
|
|
496
|
+
exportedAt: new Date().toISOString(),
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* Clear in-memory state (for testing).
|
|
502
|
+
*/
|
|
503
|
+
export function _resetState() {
|
|
504
|
+
capabilities.clear();
|
|
505
|
+
models.clear();
|
|
506
|
+
growthLog.length = 0;
|
|
507
|
+
diagnoses.length = 0;
|
|
508
|
+
}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git integration — wraps system git commands for knowledge base versioning.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { execSync } from "child_process";
|
|
6
|
+
import { existsSync } from "fs";
|
|
7
|
+
import { join } from "path";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Check if a directory is a git repository.
|
|
11
|
+
*/
|
|
12
|
+
export function isGitRepo(dir) {
|
|
13
|
+
return existsSync(join(dir, ".git"));
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Run a git command and return stdout.
|
|
18
|
+
*/
|
|
19
|
+
export function gitExec(args, cwd) {
|
|
20
|
+
try {
|
|
21
|
+
return execSync(`git ${args}`, {
|
|
22
|
+
cwd,
|
|
23
|
+
encoding: "utf-8",
|
|
24
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
25
|
+
}).trim();
|
|
26
|
+
} catch (err) {
|
|
27
|
+
const stderr = err.stderr ? err.stderr.toString().trim() : "";
|
|
28
|
+
throw new Error(stderr || err.message);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Initialize a git repo in the given directory.
|
|
34
|
+
*/
|
|
35
|
+
export function gitInit(dir) {
|
|
36
|
+
if (isGitRepo(dir)) {
|
|
37
|
+
return { initialized: false, message: "Already a git repository" };
|
|
38
|
+
}
|
|
39
|
+
gitExec("init", dir);
|
|
40
|
+
return { initialized: true, message: "Initialized git repository" };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Get git status as structured data.
|
|
45
|
+
*/
|
|
46
|
+
export function gitStatus(dir) {
|
|
47
|
+
if (!isGitRepo(dir)) {
|
|
48
|
+
return { isRepo: false, files: [] };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Use execSync directly to preserve leading whitespace in porcelain format
|
|
52
|
+
const output = execSync("git status --porcelain", {
|
|
53
|
+
cwd: dir,
|
|
54
|
+
encoding: "utf-8",
|
|
55
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
56
|
+
});
|
|
57
|
+
const files = output
|
|
58
|
+
.split("\n")
|
|
59
|
+
.filter(Boolean)
|
|
60
|
+
.map((line) => ({
|
|
61
|
+
status: line.substring(0, 2).trim(),
|
|
62
|
+
file: line.substring(3),
|
|
63
|
+
}));
|
|
64
|
+
|
|
65
|
+
const branch = getCurrentBranch(dir);
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
isRepo: true,
|
|
69
|
+
branch,
|
|
70
|
+
files,
|
|
71
|
+
clean: files.length === 0,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Get current branch name.
|
|
77
|
+
*/
|
|
78
|
+
export function getCurrentBranch(dir) {
|
|
79
|
+
try {
|
|
80
|
+
return gitExec("rev-parse --abbrev-ref HEAD", dir);
|
|
81
|
+
} catch {
|
|
82
|
+
return "unknown";
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Auto-commit all changes with a generated message.
|
|
88
|
+
*/
|
|
89
|
+
export function gitAutoCommit(dir, message) {
|
|
90
|
+
if (!isGitRepo(dir)) {
|
|
91
|
+
throw new Error("Not a git repository");
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const status = gitStatus(dir);
|
|
95
|
+
if (status.clean) {
|
|
96
|
+
return { committed: false, message: "No changes to commit" };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Stage all changes
|
|
100
|
+
gitExec("add -A", dir);
|
|
101
|
+
|
|
102
|
+
// Generate commit message if not provided
|
|
103
|
+
const commitMsg =
|
|
104
|
+
message ||
|
|
105
|
+
`auto: ${status.files.length} file(s) changed — ${new Date().toISOString().slice(0, 16)}`;
|
|
106
|
+
|
|
107
|
+
gitExec(`commit -m "${commitMsg.replace(/"/g, '\\"')}"`, dir);
|
|
108
|
+
|
|
109
|
+
const hash = gitExec("rev-parse --short HEAD", dir);
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
committed: true,
|
|
113
|
+
hash,
|
|
114
|
+
message: commitMsg,
|
|
115
|
+
filesChanged: status.files.length,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Get recent commit log.
|
|
121
|
+
*/
|
|
122
|
+
export function gitLog(dir, limit = 10) {
|
|
123
|
+
if (!isGitRepo(dir)) {
|
|
124
|
+
return [];
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
try {
|
|
128
|
+
const output = gitExec(
|
|
129
|
+
`log --oneline --no-decorate -${limit} --format="%H|%h|%s|%ai|%an"`,
|
|
130
|
+
dir,
|
|
131
|
+
);
|
|
132
|
+
return output
|
|
133
|
+
.split("\n")
|
|
134
|
+
.filter(Boolean)
|
|
135
|
+
.map((line) => {
|
|
136
|
+
const [hash, shortHash, subject, date, author] = line.split("|");
|
|
137
|
+
return { hash, shortHash, subject, date, author };
|
|
138
|
+
});
|
|
139
|
+
} catch {
|
|
140
|
+
return [];
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Analyze repository history statistics.
|
|
146
|
+
*/
|
|
147
|
+
export function gitHistoryAnalyze(dir) {
|
|
148
|
+
if (!isGitRepo(dir)) {
|
|
149
|
+
throw new Error("Not a git repository");
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const totalCommits = parseInt(gitExec("rev-list --count HEAD", dir)) || 0;
|
|
153
|
+
const firstCommit =
|
|
154
|
+
totalCommits > 0
|
|
155
|
+
? gitExec("log --reverse --format=%ai --max-count=1", dir)
|
|
156
|
+
: null;
|
|
157
|
+
const lastCommit =
|
|
158
|
+
totalCommits > 0 ? gitExec("log --format=%ai --max-count=1", dir) : null;
|
|
159
|
+
|
|
160
|
+
// Contributors
|
|
161
|
+
let contributors = [];
|
|
162
|
+
try {
|
|
163
|
+
const authorOutput = gitExec("shortlog -sn --no-merges HEAD", dir);
|
|
164
|
+
contributors = authorOutput
|
|
165
|
+
.split("\n")
|
|
166
|
+
.filter(Boolean)
|
|
167
|
+
.map((line) => {
|
|
168
|
+
const match = line.trim().match(/(\d+)\s+(.+)/);
|
|
169
|
+
return match ? { commits: parseInt(match[1]), author: match[2] } : null;
|
|
170
|
+
})
|
|
171
|
+
.filter(Boolean);
|
|
172
|
+
} catch {
|
|
173
|
+
// Empty repo or no commits
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// File statistics
|
|
177
|
+
let fileCount = 0;
|
|
178
|
+
try {
|
|
179
|
+
const files = gitExec("ls-files", dir);
|
|
180
|
+
fileCount = files.split("\n").filter(Boolean).length;
|
|
181
|
+
} catch {
|
|
182
|
+
// Ignore
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return {
|
|
186
|
+
totalCommits,
|
|
187
|
+
firstCommit,
|
|
188
|
+
lastCommit,
|
|
189
|
+
contributors,
|
|
190
|
+
trackedFiles: fileCount,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Install git hooks for auto-commit on note changes.
|
|
196
|
+
* Creates a post-commit hook that logs the commit.
|
|
197
|
+
*/
|
|
198
|
+
export function installHooks(dir) {
|
|
199
|
+
if (!isGitRepo(dir)) {
|
|
200
|
+
throw new Error("Not a git repository");
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const hooksDir = join(dir, ".git", "hooks");
|
|
204
|
+
const hookPath = join(hooksDir, "pre-commit");
|
|
205
|
+
|
|
206
|
+
const hookContent = `#!/bin/sh
|
|
207
|
+
# ChainlessChain auto-format hook
|
|
208
|
+
echo "ChainlessChain: pre-commit hook running"
|
|
209
|
+
`;
|
|
210
|
+
|
|
211
|
+
const { writeFileSync, chmodSync } = require("fs");
|
|
212
|
+
writeFileSync(hookPath, hookContent, "utf-8");
|
|
213
|
+
try {
|
|
214
|
+
chmodSync(hookPath, 0o755);
|
|
215
|
+
} catch {
|
|
216
|
+
// Windows may not support chmod
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return { installed: true, hook: "pre-commit", path: hookPath };
|
|
220
|
+
}
|