chainlesschain 0.47.8 → 0.49.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.
Files changed (86) hide show
  1. package/bin/chainlesschain.js +0 -0
  2. package/package.json +10 -8
  3. package/src/assets/web-panel/.build-hash +1 -1
  4. package/src/assets/web-panel/assets/{AppLayout-6SPt_8Y_.js → AppLayout-Rvi759IS.js} +1 -1
  5. package/src/assets/web-panel/assets/Dashboard-BS-tzGNj.css +1 -0
  6. package/src/assets/web-panel/assets/{Dashboard-Br7kCwKJ.js → Dashboard-DBhFxXYQ.js} +2 -2
  7. package/src/assets/web-panel/assets/{index-tN-8TosE.js → index-uL0cZ8N_.js} +2 -2
  8. package/src/assets/web-panel/index.html +2 -2
  9. package/src/commands/activitypub.js +533 -0
  10. package/src/commands/codegen.js +303 -0
  11. package/src/commands/collab.js +482 -0
  12. package/src/commands/compliance.js +597 -6
  13. package/src/commands/crosschain.js +382 -0
  14. package/src/commands/dbevo.js +388 -0
  15. package/src/commands/dev.js +411 -0
  16. package/src/commands/federation.js +427 -0
  17. package/src/commands/fusion.js +332 -0
  18. package/src/commands/governance.js +505 -0
  19. package/src/commands/hardening.js +110 -0
  20. package/src/commands/incentive.js +373 -0
  21. package/src/commands/inference.js +304 -0
  22. package/src/commands/infra.js +361 -0
  23. package/src/commands/kg.js +371 -0
  24. package/src/commands/marketplace.js +326 -0
  25. package/src/commands/matrix.js +283 -0
  26. package/src/commands/mcp.js +441 -18
  27. package/src/commands/nlprog.js +329 -0
  28. package/src/commands/nostr.js +196 -7
  29. package/src/commands/ops.js +408 -0
  30. package/src/commands/perception.js +385 -0
  31. package/src/commands/pqc.js +34 -0
  32. package/src/commands/privacy.js +345 -0
  33. package/src/commands/quantization.js +280 -0
  34. package/src/commands/recommend.js +336 -0
  35. package/src/commands/reputation.js +349 -0
  36. package/src/commands/runtime.js +500 -0
  37. package/src/commands/sla.js +352 -0
  38. package/src/commands/social.js +265 -0
  39. package/src/commands/stress.js +252 -0
  40. package/src/commands/tech.js +268 -0
  41. package/src/commands/tenant.js +576 -0
  42. package/src/commands/trust.js +366 -0
  43. package/src/harness/mcp-client.js +330 -54
  44. package/src/index.js +114 -0
  45. package/src/lib/activitypub-bridge.js +623 -0
  46. package/src/lib/aiops.js +523 -0
  47. package/src/lib/autonomous-developer.js +524 -0
  48. package/src/lib/code-agent.js +442 -0
  49. package/src/lib/collaboration-governance.js +556 -0
  50. package/src/lib/community-governance.js +649 -0
  51. package/src/lib/compliance-framework-reporter.js +600 -0
  52. package/src/lib/content-recommendation.js +600 -0
  53. package/src/lib/cross-chain.js +669 -0
  54. package/src/lib/dbevo.js +669 -0
  55. package/src/lib/decentral-infra.js +445 -0
  56. package/src/lib/federation-hardening.js +587 -0
  57. package/src/lib/hardening-manager.js +409 -0
  58. package/src/lib/inference-network.js +407 -0
  59. package/src/lib/knowledge-graph.js +530 -0
  60. package/src/lib/matrix-bridge.js +252 -0
  61. package/src/lib/mcp-client.js +3 -0
  62. package/src/lib/mcp-registry.js +347 -0
  63. package/src/lib/mcp-scaffold.js +385 -0
  64. package/src/lib/multimodal.js +698 -0
  65. package/src/lib/nl-programming.js +595 -0
  66. package/src/lib/nostr-bridge.js +214 -38
  67. package/src/lib/perception.js +500 -0
  68. package/src/lib/pqc-manager.js +141 -9
  69. package/src/lib/privacy-computing.js +575 -0
  70. package/src/lib/protocol-fusion.js +535 -0
  71. package/src/lib/quantization.js +362 -0
  72. package/src/lib/reputation-optimizer.js +509 -0
  73. package/src/lib/skill-marketplace.js +397 -0
  74. package/src/lib/sla-manager.js +484 -0
  75. package/src/lib/social-graph.js +408 -0
  76. package/src/lib/stix-parser.js +167 -0
  77. package/src/lib/stress-tester.js +383 -0
  78. package/src/lib/tech-learning-engine.js +651 -0
  79. package/src/lib/tenant-saas.js +831 -0
  80. package/src/lib/threat-intel.js +268 -0
  81. package/src/lib/token-incentive.js +513 -0
  82. package/src/lib/topic-classifier.js +400 -0
  83. package/src/lib/trust-security.js +473 -0
  84. package/src/lib/ueba.js +403 -0
  85. package/src/lib/universal-runtime.js +771 -0
  86. package/src/assets/web-panel/assets/Dashboard-CKeMmCoT.css +0 -1
@@ -0,0 +1,407 @@
1
+ /**
2
+ * Inference Network — CLI port of Phase 67 去中心化推理网络
3
+ * (docs/design/modules/38_去中心化推理网络系统.md).
4
+ *
5
+ * Desktop uses InferenceNodeRegistry + InferenceScheduler with real
6
+ * P2P node discovery, GPU-aware scheduling, and privacy-mode routing.
7
+ * CLI port ships:
8
+ *
9
+ * - Node registration / heartbeat / status management
10
+ * - Task submission with priority + privacy mode
11
+ * - Simulated scheduling (round-robin to online nodes)
12
+ * - Scheduler stats (queue/completed/avg latency)
13
+ *
14
+ * What does NOT port: real P2P node discovery, GPU probe, encrypted/
15
+ * federated inference, InferenceNetworkPage.vue, Pinia store.
16
+ */
17
+
18
+ import crypto from "crypto";
19
+
20
+ /* ── Constants ─────────────────────────────────────────────── */
21
+
22
+ export const NODE_STATUS = Object.freeze({
23
+ ONLINE: "online",
24
+ OFFLINE: "offline",
25
+ BUSY: "busy",
26
+ DEGRADED: "degraded",
27
+ });
28
+
29
+ export const TASK_STATUS = Object.freeze({
30
+ QUEUED: "queued",
31
+ DISPATCHED: "dispatched",
32
+ RUNNING: "running",
33
+ COMPLETE: "complete",
34
+ FAILED: "failed",
35
+ });
36
+
37
+ export const PRIVACY_MODE = Object.freeze({
38
+ STANDARD: "standard",
39
+ ENCRYPTED: "encrypted",
40
+ FEDERATED: "federated",
41
+ });
42
+
43
+ export const DEFAULT_CONFIG = Object.freeze({
44
+ maxNodes: 100,
45
+ heartbeatIntervalMs: 30000,
46
+ defaultPrivacyMode: "standard",
47
+ maxPriority: 10,
48
+ });
49
+
50
+ /* ── State ─────────────────────────────────────────────── */
51
+
52
+ let _nodes = new Map();
53
+ let _tasks = new Map();
54
+
55
+ function _id() {
56
+ return crypto.randomUUID();
57
+ }
58
+ function _now() {
59
+ return Date.now();
60
+ }
61
+
62
+ function _strip(row) {
63
+ if (!row) return null;
64
+ const out = {};
65
+ for (const [k, v] of Object.entries(row)) {
66
+ if (k !== "_rowid_" && k !== "rowid") out[k] = v;
67
+ }
68
+ return out;
69
+ }
70
+
71
+ function _parseJson(str, fallback) {
72
+ if (!str) return fallback;
73
+ try {
74
+ return JSON.parse(str);
75
+ } catch (_e) {
76
+ return fallback;
77
+ }
78
+ }
79
+
80
+ /* ── Schema ────────────────────────────────────────────── */
81
+
82
+ export function ensureInferenceTables(db) {
83
+ db.exec(`CREATE TABLE IF NOT EXISTS inference_nodes (
84
+ id TEXT PRIMARY KEY,
85
+ node_id TEXT NOT NULL,
86
+ endpoint TEXT,
87
+ capabilities TEXT,
88
+ gpu_memory_mb INTEGER DEFAULT 0,
89
+ status TEXT DEFAULT 'online',
90
+ last_heartbeat INTEGER,
91
+ task_count INTEGER DEFAULT 0,
92
+ created_at INTEGER
93
+ )`);
94
+ db.exec(
95
+ "CREATE INDEX IF NOT EXISTS idx_infn_status ON inference_nodes(status)",
96
+ );
97
+
98
+ db.exec(`CREATE TABLE IF NOT EXISTS inference_tasks (
99
+ id TEXT PRIMARY KEY,
100
+ model TEXT NOT NULL,
101
+ input TEXT,
102
+ output TEXT,
103
+ privacy_mode TEXT DEFAULT 'standard',
104
+ priority INTEGER DEFAULT 5,
105
+ assigned_node TEXT,
106
+ status TEXT DEFAULT 'queued',
107
+ duration_ms INTEGER,
108
+ created_at INTEGER,
109
+ completed_at INTEGER
110
+ )`);
111
+ db.exec(
112
+ "CREATE INDEX IF NOT EXISTS idx_inft_status ON inference_tasks(status)",
113
+ );
114
+
115
+ _loadAll(db);
116
+ }
117
+
118
+ function _loadAll(db) {
119
+ _nodes.clear();
120
+ _tasks.clear();
121
+ try {
122
+ for (const row of db.prepare("SELECT * FROM inference_nodes").all()) {
123
+ const n = _strip(row);
124
+ n.capabilities = _parseJson(n.capabilities, []);
125
+ _nodes.set(n.id, n);
126
+ }
127
+ } catch (_e) {
128
+ /* table may not exist */
129
+ }
130
+ try {
131
+ for (const row of db.prepare("SELECT * FROM inference_tasks").all()) {
132
+ _tasks.set(row.id, _strip(row));
133
+ }
134
+ } catch (_e) {
135
+ /* table may not exist */
136
+ }
137
+ }
138
+
139
+ /* ── Node Registry ─────────────────────────────────────── */
140
+
141
+ const VALID_NODE_STATUSES = new Set(Object.values(NODE_STATUS));
142
+
143
+ export function registerNode(
144
+ db,
145
+ nodeId,
146
+ { endpoint, capabilities, gpuMemory } = {},
147
+ ) {
148
+ if (!nodeId) return { nodeId: null, reason: "missing_node_id" };
149
+
150
+ // Check for existing node with same nodeId
151
+ for (const n of _nodes.values()) {
152
+ if (n.node_id === nodeId) return { nodeId: null, reason: "duplicate_node" };
153
+ }
154
+
155
+ if (_nodes.size >= DEFAULT_CONFIG.maxNodes) {
156
+ return { nodeId: null, reason: "max_nodes_reached" };
157
+ }
158
+
159
+ const id = _id();
160
+ const now = _now();
161
+ const caps = capabilities || [];
162
+ const gpu = gpuMemory || 0;
163
+
164
+ const node = {
165
+ id,
166
+ node_id: nodeId,
167
+ endpoint: endpoint || null,
168
+ capabilities: caps,
169
+ gpu_memory_mb: gpu,
170
+ status: "online",
171
+ last_heartbeat: now,
172
+ task_count: 0,
173
+ created_at: now,
174
+ };
175
+
176
+ db.prepare(
177
+ `INSERT INTO inference_nodes (id, node_id, endpoint, capabilities, gpu_memory_mb,
178
+ status, last_heartbeat, task_count, created_at)
179
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
180
+ ).run(
181
+ id,
182
+ nodeId,
183
+ node.endpoint,
184
+ JSON.stringify(caps),
185
+ gpu,
186
+ "online",
187
+ now,
188
+ 0,
189
+ now,
190
+ );
191
+
192
+ _nodes.set(id, node);
193
+ return { nodeId: id };
194
+ }
195
+
196
+ export function unregisterNode(db, id) {
197
+ const n = _nodes.get(id);
198
+ if (!n) return { removed: false, reason: "not_found" };
199
+ db.prepare("DELETE FROM inference_nodes WHERE id = ?").run(id);
200
+ _nodes.delete(id);
201
+ return { removed: true };
202
+ }
203
+
204
+ export function heartbeat(db, id) {
205
+ const n = _nodes.get(id);
206
+ if (!n) return { updated: false, reason: "not_found" };
207
+ n.last_heartbeat = _now();
208
+ if (n.status === "offline") n.status = "online";
209
+ db.prepare(
210
+ "UPDATE inference_nodes SET last_heartbeat = ?, status = ? WHERE id = ?",
211
+ ).run(n.last_heartbeat, n.status, id);
212
+ return { updated: true, status: n.status };
213
+ }
214
+
215
+ export function updateNodeStatus(db, id, status) {
216
+ if (!VALID_NODE_STATUSES.has(status))
217
+ return { updated: false, reason: "invalid_status" };
218
+ const n = _nodes.get(id);
219
+ if (!n) return { updated: false, reason: "not_found" };
220
+ n.status = status;
221
+ db.prepare("UPDATE inference_nodes SET status = ? WHERE id = ?").run(
222
+ status,
223
+ id,
224
+ );
225
+ return { updated: true };
226
+ }
227
+
228
+ export function getNode(db, id) {
229
+ const n = _nodes.get(id);
230
+ return n ? { ...n } : null;
231
+ }
232
+
233
+ export function listNodes(db, { status, capability, limit = 50 } = {}) {
234
+ let nodes = [..._nodes.values()];
235
+ if (status) nodes = nodes.filter((n) => n.status === status);
236
+ if (capability)
237
+ nodes = nodes.filter(
238
+ (n) =>
239
+ Array.isArray(n.capabilities) && n.capabilities.includes(capability),
240
+ );
241
+ return nodes
242
+ .sort((a, b) => b.last_heartbeat - a.last_heartbeat)
243
+ .slice(0, limit)
244
+ .map((n) => ({ ...n }));
245
+ }
246
+
247
+ /* ── Task Scheduler ────────────────────────────────────── */
248
+
249
+ const VALID_PRIVACY_MODES = new Set(Object.values(PRIVACY_MODE));
250
+
251
+ export function submitTask(db, model, { input, privacyMode, priority } = {}) {
252
+ if (!model) return { taskId: null, reason: "missing_model" };
253
+
254
+ const mode = privacyMode || DEFAULT_CONFIG.defaultPrivacyMode;
255
+ if (!VALID_PRIVACY_MODES.has(mode))
256
+ return { taskId: null, reason: "invalid_privacy_mode" };
257
+
258
+ const prio = Math.min(Math.max(priority || 5, 1), DEFAULT_CONFIG.maxPriority);
259
+
260
+ const id = _id();
261
+ const now = _now();
262
+
263
+ // Simulated scheduling: pick first online node with lowest task_count
264
+ let assignedNode = null;
265
+ const onlineNodes = [..._nodes.values()]
266
+ .filter((n) => n.status === "online")
267
+ .sort((a, b) => a.task_count - b.task_count);
268
+ if (onlineNodes.length > 0) {
269
+ assignedNode = onlineNodes[0].id;
270
+ onlineNodes[0].task_count += 1;
271
+ db.prepare("UPDATE inference_nodes SET task_count = ? WHERE id = ?").run(
272
+ onlineNodes[0].task_count,
273
+ assignedNode,
274
+ );
275
+ }
276
+
277
+ const status = assignedNode ? "dispatched" : "queued";
278
+ const task = {
279
+ id,
280
+ model,
281
+ input: input || null,
282
+ output: null,
283
+ privacy_mode: mode,
284
+ priority: prio,
285
+ assigned_node: assignedNode,
286
+ status,
287
+ duration_ms: null,
288
+ created_at: now,
289
+ completed_at: null,
290
+ };
291
+
292
+ db.prepare(
293
+ `INSERT INTO inference_tasks (id, model, input, output, privacy_mode, priority,
294
+ assigned_node, status, duration_ms, created_at, completed_at)
295
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
296
+ ).run(
297
+ id,
298
+ model,
299
+ task.input,
300
+ null,
301
+ mode,
302
+ prio,
303
+ assignedNode,
304
+ status,
305
+ null,
306
+ now,
307
+ null,
308
+ );
309
+
310
+ _tasks.set(id, task);
311
+ return { taskId: id, status, assignedNode };
312
+ }
313
+
314
+ export function completeTask(db, taskId, { output, durationMs } = {}) {
315
+ const t = _tasks.get(taskId);
316
+ if (!t) return { completed: false, reason: "not_found" };
317
+ if (t.status === "complete")
318
+ return { completed: false, reason: "already_complete" };
319
+ if (t.status === "failed") return { completed: false, reason: "task_failed" };
320
+
321
+ t.status = "complete";
322
+ t.output = output || null;
323
+ t.completed_at = _now();
324
+ t.duration_ms = durationMs || t.completed_at - t.created_at;
325
+
326
+ db.prepare(
327
+ `UPDATE inference_tasks SET status = ?, output = ?, completed_at = ?,
328
+ duration_ms = ? WHERE id = ?`,
329
+ ).run("complete", t.output, t.completed_at, t.duration_ms, taskId);
330
+
331
+ return { completed: true, durationMs: t.duration_ms };
332
+ }
333
+
334
+ export function failTask(db, taskId, { error } = {}) {
335
+ const t = _tasks.get(taskId);
336
+ if (!t) return { failed: false, reason: "not_found" };
337
+ if (t.status === "complete")
338
+ return { failed: false, reason: "already_complete" };
339
+
340
+ t.status = "failed";
341
+ t.output = error || null;
342
+ t.completed_at = _now();
343
+
344
+ db.prepare(
345
+ "UPDATE inference_tasks SET status = ?, output = ?, completed_at = ? WHERE id = ?",
346
+ ).run("failed", t.output, t.completed_at, taskId);
347
+
348
+ return { failed: true };
349
+ }
350
+
351
+ export function getTask(db, taskId) {
352
+ const t = _tasks.get(taskId);
353
+ return t ? { ...t } : null;
354
+ }
355
+
356
+ export function listTasks(db, { status, model, privacyMode, limit = 50 } = {}) {
357
+ let tasks = [..._tasks.values()];
358
+ if (status) tasks = tasks.filter((t) => t.status === status);
359
+ if (model) tasks = tasks.filter((t) => t.model === model);
360
+ if (privacyMode) tasks = tasks.filter((t) => t.privacy_mode === privacyMode);
361
+ return tasks
362
+ .sort((a, b) => b.created_at - a.created_at)
363
+ .slice(0, limit)
364
+ .map((t) => ({ ...t }));
365
+ }
366
+
367
+ /* ── Stats ─────────────────────────────────────────────── */
368
+
369
+ export function getSchedulerStats(db) {
370
+ const tasks = [..._tasks.values()];
371
+ const nodes = [..._nodes.values()];
372
+
373
+ const completed = tasks.filter((t) => t.status === "complete");
374
+ const queued = tasks.filter(
375
+ (t) => t.status === "queued" || t.status === "dispatched",
376
+ );
377
+ const avgDuration =
378
+ completed.length > 0
379
+ ? Math.round(
380
+ completed.reduce((s, t) => s + (t.duration_ms || 0), 0) /
381
+ completed.length,
382
+ )
383
+ : 0;
384
+
385
+ return {
386
+ nodes: {
387
+ total: nodes.length,
388
+ online: nodes.filter((n) => n.status === "online").length,
389
+ offline: nodes.filter((n) => n.status === "offline").length,
390
+ busy: nodes.filter((n) => n.status === "busy").length,
391
+ },
392
+ tasks: {
393
+ total: tasks.length,
394
+ queued: queued.length,
395
+ completed: completed.length,
396
+ failed: tasks.filter((t) => t.status === "failed").length,
397
+ avgDurationMs: avgDuration,
398
+ },
399
+ };
400
+ }
401
+
402
+ /* ── Reset (tests) ─────────────────────────────────────── */
403
+
404
+ export function _resetState() {
405
+ _nodes.clear();
406
+ _tasks.clear();
407
+ }