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.
Files changed (84) hide show
  1. package/README.md +309 -19
  2. package/bin/chainlesschain.js +4 -0
  3. package/package.json +1 -1
  4. package/src/commands/a2a.js +374 -0
  5. package/src/commands/audit.js +286 -0
  6. package/src/commands/auth.js +387 -0
  7. package/src/commands/bi.js +240 -0
  8. package/src/commands/browse.js +184 -0
  9. package/src/commands/cowork.js +317 -0
  10. package/src/commands/did.js +376 -0
  11. package/src/commands/economy.js +375 -0
  12. package/src/commands/encrypt.js +233 -0
  13. package/src/commands/evolution.js +398 -0
  14. package/src/commands/export.js +125 -0
  15. package/src/commands/git.js +215 -0
  16. package/src/commands/hmemory.js +273 -0
  17. package/src/commands/hook.js +260 -0
  18. package/src/commands/import.js +259 -0
  19. package/src/commands/init.js +184 -0
  20. package/src/commands/instinct.js +202 -0
  21. package/src/commands/llm.js +155 -4
  22. package/src/commands/lowcode.js +320 -0
  23. package/src/commands/mcp.js +302 -0
  24. package/src/commands/memory.js +282 -0
  25. package/src/commands/note.js +187 -0
  26. package/src/commands/org.js +505 -0
  27. package/src/commands/p2p.js +274 -0
  28. package/src/commands/plugin.js +451 -0
  29. package/src/commands/sandbox.js +366 -0
  30. package/src/commands/search.js +237 -0
  31. package/src/commands/session.js +238 -0
  32. package/src/commands/skill.js +254 -201
  33. package/src/commands/sync.js +249 -0
  34. package/src/commands/tokens.js +214 -0
  35. package/src/commands/wallet.js +416 -0
  36. package/src/commands/workflow.js +359 -0
  37. package/src/commands/zkp.js +277 -0
  38. package/src/index.js +93 -1
  39. package/src/lib/a2a-protocol.js +371 -0
  40. package/src/lib/agent-coordinator.js +273 -0
  41. package/src/lib/agent-economy.js +369 -0
  42. package/src/lib/app-builder.js +377 -0
  43. package/src/lib/audit-logger.js +364 -0
  44. package/src/lib/bi-engine.js +299 -0
  45. package/src/lib/bm25-search.js +322 -0
  46. package/src/lib/browser-automation.js +216 -0
  47. package/src/lib/cowork/ab-comparator-cli.js +180 -0
  48. package/src/lib/cowork/code-knowledge-graph-cli.js +232 -0
  49. package/src/lib/cowork/debate-review-cli.js +144 -0
  50. package/src/lib/cowork/decision-kb-cli.js +153 -0
  51. package/src/lib/cowork/project-style-analyzer-cli.js +168 -0
  52. package/src/lib/cowork-adapter.js +106 -0
  53. package/src/lib/crypto-manager.js +246 -0
  54. package/src/lib/did-manager.js +270 -0
  55. package/src/lib/ensure-utf8.js +59 -0
  56. package/src/lib/evolution-system.js +508 -0
  57. package/src/lib/git-integration.js +220 -0
  58. package/src/lib/hierarchical-memory.js +471 -0
  59. package/src/lib/hook-manager.js +387 -0
  60. package/src/lib/instinct-manager.js +190 -0
  61. package/src/lib/knowledge-exporter.js +302 -0
  62. package/src/lib/knowledge-importer.js +293 -0
  63. package/src/lib/llm-providers.js +325 -0
  64. package/src/lib/mcp-client.js +413 -0
  65. package/src/lib/memory-manager.js +211 -0
  66. package/src/lib/note-versioning.js +244 -0
  67. package/src/lib/org-manager.js +424 -0
  68. package/src/lib/p2p-manager.js +317 -0
  69. package/src/lib/pdf-parser.js +96 -0
  70. package/src/lib/permission-engine.js +374 -0
  71. package/src/lib/plan-mode.js +333 -0
  72. package/src/lib/plugin-manager.js +430 -0
  73. package/src/lib/project-detector.js +53 -0
  74. package/src/lib/response-cache.js +156 -0
  75. package/src/lib/sandbox-v2.js +503 -0
  76. package/src/lib/service-container.js +183 -0
  77. package/src/lib/session-manager.js +189 -0
  78. package/src/lib/skill-loader.js +274 -0
  79. package/src/lib/sync-manager.js +347 -0
  80. package/src/lib/token-tracker.js +200 -0
  81. package/src/lib/wallet-manager.js +348 -0
  82. package/src/lib/workflow-engine.js +503 -0
  83. package/src/lib/zkp-engine.js +241 -0
  84. package/src/repl/agent-repl.js +259 -124
@@ -0,0 +1,347 @@
1
+ /**
2
+ * Sync Manager — File and knowledge synchronization for CLI.
3
+ * Manages sync state, conflict resolution, and push/pull operations.
4
+ */
5
+
6
+ import crypto from "crypto";
7
+ import fs from "fs";
8
+ import path from "path";
9
+
10
+ /**
11
+ * Ensure sync tables exist.
12
+ */
13
+ export function ensureSyncTables(db) {
14
+ db.exec(`
15
+ CREATE TABLE IF NOT EXISTS sync_state (
16
+ id TEXT PRIMARY KEY,
17
+ resource_type TEXT NOT NULL,
18
+ resource_id TEXT NOT NULL,
19
+ local_version INTEGER DEFAULT 1,
20
+ remote_version INTEGER DEFAULT 0,
21
+ checksum TEXT,
22
+ status TEXT DEFAULT 'pending',
23
+ last_synced TEXT,
24
+ created_at TEXT DEFAULT (datetime('now')),
25
+ updated_at TEXT DEFAULT (datetime('now'))
26
+ )
27
+ `);
28
+ db.exec(`
29
+ CREATE TABLE IF NOT EXISTS sync_conflicts (
30
+ id TEXT PRIMARY KEY,
31
+ resource_type TEXT NOT NULL,
32
+ resource_id TEXT NOT NULL,
33
+ local_data TEXT,
34
+ remote_data TEXT,
35
+ resolution TEXT,
36
+ resolved_at TEXT,
37
+ created_at TEXT DEFAULT (datetime('now'))
38
+ )
39
+ `);
40
+ db.exec(`
41
+ CREATE TABLE IF NOT EXISTS sync_log (
42
+ id TEXT PRIMARY KEY,
43
+ operation TEXT NOT NULL,
44
+ resource_type TEXT,
45
+ resource_id TEXT,
46
+ status TEXT DEFAULT 'success',
47
+ details TEXT,
48
+ created_at TEXT DEFAULT (datetime('now'))
49
+ )
50
+ `);
51
+ }
52
+
53
+ /**
54
+ * Compute file checksum (SHA-256).
55
+ */
56
+ export function computeChecksum(content) {
57
+ return crypto.createHash("sha256").update(content).digest("hex");
58
+ }
59
+
60
+ /**
61
+ * Register a resource for syncing.
62
+ */
63
+ export function registerResource(db, resourceType, resourceId, checksum) {
64
+ ensureSyncTables(db);
65
+ const id = `sync-${crypto.randomBytes(8).toString("hex")}`;
66
+
67
+ db.prepare(
68
+ `INSERT OR REPLACE INTO sync_state (id, resource_type, resource_id, checksum, status)
69
+ VALUES (?, ?, ?, ?, ?)`,
70
+ ).run(id, resourceType, resourceId, checksum || null, "pending");
71
+
72
+ return { id, resourceType, resourceId, checksum, status: "pending" };
73
+ }
74
+
75
+ /**
76
+ * Get sync state for a resource.
77
+ */
78
+ export function getSyncState(db, resourceType, resourceId) {
79
+ ensureSyncTables(db);
80
+ return db
81
+ .prepare(
82
+ "SELECT * FROM sync_state WHERE resource_type = ? AND resource_id = ?",
83
+ )
84
+ .get(resourceType, resourceId);
85
+ }
86
+
87
+ /**
88
+ * Get all sync states.
89
+ */
90
+ export function getAllSyncStates(db, options = {}) {
91
+ ensureSyncTables(db);
92
+ const { status, resourceType } = options;
93
+
94
+ let sql = "SELECT * FROM sync_state WHERE 1=1";
95
+ const params = [];
96
+
97
+ if (status) {
98
+ sql += " AND status = ?";
99
+ params.push(status);
100
+ }
101
+ if (resourceType) {
102
+ sql += " AND resource_type = ?";
103
+ params.push(resourceType);
104
+ }
105
+
106
+ sql += " ORDER BY updated_at DESC";
107
+ return db.prepare(sql).all(...params);
108
+ }
109
+
110
+ /**
111
+ * Update sync state after push or pull.
112
+ */
113
+ export function updateSyncState(db, id, updates) {
114
+ ensureSyncTables(db);
115
+ const { localVersion, remoteVersion, checksum, status, lastSynced } = updates;
116
+
117
+ if (status) {
118
+ db.prepare("UPDATE sync_state SET status = ? WHERE id = ?").run(status, id);
119
+ }
120
+ if (localVersion !== undefined) {
121
+ db.prepare("UPDATE sync_state SET local_version = ? WHERE id = ?").run(
122
+ localVersion,
123
+ id,
124
+ );
125
+ }
126
+ if (remoteVersion !== undefined) {
127
+ db.prepare("UPDATE sync_state SET remote_version = ? WHERE id = ?").run(
128
+ remoteVersion,
129
+ id,
130
+ );
131
+ }
132
+ if (checksum) {
133
+ db.prepare("UPDATE sync_state SET checksum = ? WHERE id = ?").run(
134
+ checksum,
135
+ id,
136
+ );
137
+ }
138
+ if (lastSynced) {
139
+ db.prepare("UPDATE sync_state SET last_synced = ? WHERE id = ?").run(
140
+ lastSynced,
141
+ id,
142
+ );
143
+ }
144
+
145
+ return true;
146
+ }
147
+
148
+ /**
149
+ * Create a sync conflict record.
150
+ */
151
+ export function createConflict(
152
+ db,
153
+ resourceType,
154
+ resourceId,
155
+ localData,
156
+ remoteData,
157
+ ) {
158
+ ensureSyncTables(db);
159
+ const id = `conflict-${crypto.randomBytes(8).toString("hex")}`;
160
+
161
+ db.prepare(
162
+ `INSERT INTO sync_conflicts (id, resource_type, resource_id, local_data, remote_data)
163
+ VALUES (?, ?, ?, ?, ?)`,
164
+ ).run(
165
+ id,
166
+ resourceType,
167
+ resourceId,
168
+ typeof localData === "string" ? localData : JSON.stringify(localData),
169
+ typeof remoteData === "string" ? remoteData : JSON.stringify(remoteData),
170
+ );
171
+
172
+ return { id, resourceType, resourceId, status: "unresolved" };
173
+ }
174
+
175
+ /**
176
+ * Get unresolved conflicts.
177
+ */
178
+ export function getConflicts(db, options = {}) {
179
+ ensureSyncTables(db);
180
+ const { resolved = false } = options;
181
+
182
+ if (resolved) {
183
+ return db
184
+ .prepare("SELECT * FROM sync_conflicts ORDER BY created_at DESC")
185
+ .all();
186
+ }
187
+ return db
188
+ .prepare(
189
+ "SELECT * FROM sync_conflicts WHERE resolution IS NULL ORDER BY created_at DESC",
190
+ )
191
+ .all();
192
+ }
193
+
194
+ /**
195
+ * Resolve a conflict.
196
+ */
197
+ export function resolveConflict(db, conflictId, resolution) {
198
+ ensureSyncTables(db);
199
+ const result = db
200
+ .prepare(
201
+ "UPDATE sync_conflicts SET resolution = ?, resolved_at = datetime('now') WHERE id = ?",
202
+ )
203
+ .run(resolution, conflictId);
204
+ return result.changes > 0;
205
+ }
206
+
207
+ /**
208
+ * Log a sync operation.
209
+ */
210
+ export function logSyncOperation(
211
+ db,
212
+ operation,
213
+ resourceType,
214
+ resourceId,
215
+ status,
216
+ details,
217
+ ) {
218
+ ensureSyncTables(db);
219
+ const id = `slog-${crypto.randomBytes(8).toString("hex")}`;
220
+
221
+ db.prepare(
222
+ `INSERT INTO sync_log (id, operation, resource_type, resource_id, status, details)
223
+ VALUES (?, ?, ?, ?, ?, ?)`,
224
+ ).run(
225
+ id,
226
+ operation,
227
+ resourceType || null,
228
+ resourceId || null,
229
+ status,
230
+ details || null,
231
+ );
232
+
233
+ return { id, operation, status };
234
+ }
235
+
236
+ /**
237
+ * Get sync log entries.
238
+ */
239
+ export function getSyncLog(db, options = {}) {
240
+ ensureSyncTables(db);
241
+ const { limit = 50, operation } = options;
242
+
243
+ let sql = "SELECT * FROM sync_log";
244
+ const params = [];
245
+
246
+ if (operation) {
247
+ sql += " WHERE operation = ?";
248
+ params.push(operation);
249
+ }
250
+
251
+ sql += " ORDER BY created_at DESC LIMIT ?";
252
+ params.push(limit);
253
+
254
+ return db.prepare(sql).all(...params);
255
+ }
256
+
257
+ /**
258
+ * Get sync status summary.
259
+ */
260
+ export function getSyncStatus(db) {
261
+ ensureSyncTables(db);
262
+ const total = db.prepare("SELECT COUNT(*) as c FROM sync_state").get();
263
+ const pending = db
264
+ .prepare("SELECT COUNT(*) as c FROM sync_state WHERE status = ?")
265
+ .get("pending");
266
+ const synced = db
267
+ .prepare("SELECT COUNT(*) as c FROM sync_state WHERE status = ?")
268
+ .get("synced");
269
+ const conflicts = db
270
+ .prepare(
271
+ "SELECT COUNT(*) as c FROM sync_conflicts WHERE resolution IS NULL",
272
+ )
273
+ .get();
274
+
275
+ return {
276
+ totalResources: total?.c || 0,
277
+ pending: pending?.c || 0,
278
+ synced: synced?.c || 0,
279
+ conflicts: conflicts?.c || 0,
280
+ };
281
+ }
282
+
283
+ /**
284
+ * Perform a push operation (mark resources as synced).
285
+ */
286
+ export function pushResources(db, resourceType) {
287
+ ensureSyncTables(db);
288
+ let sql = "SELECT * FROM sync_state WHERE status = ?";
289
+ const params = ["pending"];
290
+
291
+ if (resourceType) {
292
+ sql += " AND resource_type = ?";
293
+ params.push(resourceType);
294
+ }
295
+
296
+ const pending = db.prepare(sql).all(...params);
297
+ let pushed = 0;
298
+
299
+ for (const resource of pending) {
300
+ updateSyncState(db, resource.id, {
301
+ status: "synced",
302
+ remoteVersion: resource.local_version,
303
+ lastSynced: new Date().toISOString(),
304
+ });
305
+ logSyncOperation(
306
+ db,
307
+ "push",
308
+ resource.resource_type,
309
+ resource.resource_id,
310
+ "success",
311
+ );
312
+ pushed++;
313
+ }
314
+
315
+ return { pushed, total: pending.length };
316
+ }
317
+
318
+ /**
319
+ * Perform a pull operation (check for remote updates).
320
+ */
321
+ export function pullResources(db, resourceType) {
322
+ ensureSyncTables(db);
323
+ // In standalone CLI mode, pull simulates checking for remote updates
324
+ const synced = getAllSyncStates(db, { status: "synced", resourceType });
325
+
326
+ logSyncOperation(
327
+ db,
328
+ "pull",
329
+ resourceType || null,
330
+ null,
331
+ "success",
332
+ `Checked ${synced.length} resources`,
333
+ );
334
+
335
+ return { checked: synced.length, updated: 0 };
336
+ }
337
+
338
+ /**
339
+ * Clear all sync data.
340
+ */
341
+ export function clearSyncData(db) {
342
+ ensureSyncTables(db);
343
+ db.prepare("DELETE FROM sync_state").run();
344
+ db.prepare("DELETE FROM sync_conflicts").run();
345
+ db.prepare("DELETE FROM sync_log").run();
346
+ return true;
347
+ }
@@ -0,0 +1,200 @@
1
+ /**
2
+ * Token usage tracker for CLI
3
+ *
4
+ * Tracks LLM API call token counts and costs.
5
+ * Lightweight port of desktop-app-vue/src/main/llm/token-tracker.js
6
+ */
7
+
8
+ import { createHash } from "crypto";
9
+
10
+ /**
11
+ * Pricing data per million tokens (USD)
12
+ */
13
+ const PRICING = {
14
+ ollama: { input: 0, output: 0 },
15
+ openai: {
16
+ "gpt-4o": { input: 2.5, output: 10 },
17
+ "gpt-4o-mini": { input: 0.15, output: 0.6 },
18
+ "gpt-4-turbo": { input: 10, output: 30 },
19
+ "gpt-3.5-turbo": { input: 0.5, output: 1.5 },
20
+ o1: { input: 15, output: 60 },
21
+ _default: { input: 2.5, output: 10 },
22
+ },
23
+ anthropic: {
24
+ "claude-sonnet-4-6": { input: 3, output: 15 },
25
+ "claude-opus-4-6": { input: 15, output: 75 },
26
+ "claude-haiku-4-5-20251001": { input: 0.8, output: 4 },
27
+ _default: { input: 3, output: 15 },
28
+ },
29
+ deepseek: {
30
+ "deepseek-chat": { input: 0.14, output: 0.28 },
31
+ _default: { input: 0.14, output: 0.28 },
32
+ },
33
+ dashscope: {
34
+ "qwen-turbo": { input: 0.3, output: 0.6 },
35
+ "qwen-plus": { input: 0.8, output: 2 },
36
+ _default: { input: 0.3, output: 0.6 },
37
+ },
38
+ };
39
+
40
+ function ensureTokenTable(db) {
41
+ db.exec(`
42
+ CREATE TABLE IF NOT EXISTS llm_usage_log (
43
+ id TEXT PRIMARY KEY,
44
+ provider TEXT NOT NULL,
45
+ model TEXT NOT NULL,
46
+ input_tokens INTEGER DEFAULT 0,
47
+ output_tokens INTEGER DEFAULT 0,
48
+ total_tokens INTEGER DEFAULT 0,
49
+ cost_usd REAL DEFAULT 0,
50
+ response_time_ms INTEGER DEFAULT 0,
51
+ endpoint TEXT DEFAULT '',
52
+ created_at TEXT DEFAULT (datetime('now'))
53
+ )
54
+ `);
55
+ }
56
+
57
+ /**
58
+ * Calculate cost for a given usage
59
+ */
60
+ export function calculateCost(provider, model, inputTokens, outputTokens) {
61
+ const providerPricing = PRICING[provider];
62
+ if (!providerPricing) return 0;
63
+
64
+ // Ollama is free
65
+ if (provider === "ollama") return 0;
66
+
67
+ const modelPricing = providerPricing[model] || providerPricing._default;
68
+ if (!modelPricing) return 0;
69
+
70
+ const inputCost = (inputTokens / 1_000_000) * modelPricing.input;
71
+ const outputCost = (outputTokens / 1_000_000) * modelPricing.output;
72
+ return inputCost + outputCost;
73
+ }
74
+
75
+ /**
76
+ * Record a token usage event
77
+ */
78
+ export function recordUsage(db, params) {
79
+ ensureTokenTable(db);
80
+
81
+ const {
82
+ provider,
83
+ model,
84
+ inputTokens = 0,
85
+ outputTokens = 0,
86
+ responseTimeMs = 0,
87
+ endpoint = "",
88
+ } = params;
89
+
90
+ const totalTokens = inputTokens + outputTokens;
91
+ const costUsd = calculateCost(provider, model, inputTokens, outputTokens);
92
+
93
+ const id = createHash("sha256")
94
+ .update(`${Date.now()}-${Math.random()}`)
95
+ .digest("hex")
96
+ .slice(0, 16);
97
+
98
+ db.prepare(
99
+ `INSERT INTO llm_usage_log (id, provider, model, input_tokens, output_tokens, total_tokens, cost_usd, response_time_ms, endpoint)
100
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
101
+ ).run(
102
+ id,
103
+ provider,
104
+ model,
105
+ inputTokens,
106
+ outputTokens,
107
+ totalTokens,
108
+ costUsd,
109
+ responseTimeMs,
110
+ endpoint,
111
+ );
112
+
113
+ return { id, totalTokens, costUsd };
114
+ }
115
+
116
+ /**
117
+ * Get usage stats with optional date filtering
118
+ */
119
+ export function getUsageStats(db, options = {}) {
120
+ ensureTokenTable(db);
121
+
122
+ const { startDate, endDate, provider, model } = options;
123
+ let sql = `SELECT
124
+ COUNT(*) as total_calls,
125
+ COALESCE(SUM(input_tokens), 0) as total_input_tokens,
126
+ COALESCE(SUM(output_tokens), 0) as total_output_tokens,
127
+ COALESCE(SUM(total_tokens), 0) as total_tokens,
128
+ COALESCE(SUM(cost_usd), 0) as total_cost_usd,
129
+ COALESCE(AVG(response_time_ms), 0) as avg_response_time_ms
130
+ FROM llm_usage_log WHERE 1=1`;
131
+
132
+ const params = [];
133
+ if (startDate) {
134
+ sql += " AND created_at >= ?";
135
+ params.push(startDate);
136
+ }
137
+ if (endDate) {
138
+ sql += " AND created_at <= ?";
139
+ params.push(endDate);
140
+ }
141
+ if (provider) {
142
+ sql += " AND provider = ?";
143
+ params.push(provider);
144
+ }
145
+ if (model) {
146
+ sql += " AND model = ?";
147
+ params.push(model);
148
+ }
149
+
150
+ const result = db.prepare(sql).get(...params);
151
+ return {
152
+ total_calls: result?.total_calls || 0,
153
+ total_input_tokens: result?.total_input_tokens || 0,
154
+ total_output_tokens: result?.total_output_tokens || 0,
155
+ total_tokens: result?.total_tokens || 0,
156
+ total_cost_usd: result?.total_cost_usd || 0,
157
+ avg_response_time_ms: result?.avg_response_time_ms || 0,
158
+ };
159
+ }
160
+
161
+ /**
162
+ * Get cost breakdown by provider
163
+ */
164
+ export function getCostBreakdown(db) {
165
+ ensureTokenTable(db);
166
+
167
+ return db
168
+ .prepare(
169
+ `SELECT provider, model,
170
+ COUNT(*) as calls,
171
+ SUM(input_tokens) as input_tokens,
172
+ SUM(output_tokens) as output_tokens,
173
+ SUM(total_tokens) as total_tokens,
174
+ SUM(cost_usd) as cost_usd
175
+ FROM llm_usage_log
176
+ GROUP BY provider, model
177
+ ORDER BY cost_usd DESC`,
178
+ )
179
+ .all();
180
+ }
181
+
182
+ /**
183
+ * Get recent usage entries
184
+ */
185
+ export function getRecentUsage(db, limit = 20) {
186
+ ensureTokenTable(db);
187
+
188
+ return db
189
+ .prepare(`SELECT * FROM llm_usage_log ORDER BY created_at DESC LIMIT ?`)
190
+ .all(limit);
191
+ }
192
+
193
+ /**
194
+ * Get today's stats
195
+ */
196
+ export function getTodayStats(db) {
197
+ return getUsageStats(db, {
198
+ startDate: new Date().toISOString().slice(0, 10),
199
+ });
200
+ }