chainlesschain 0.66.0 → 0.81.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/package.json +1 -1
- package/src/commands/a2a.js +380 -0
- package/src/commands/bi.js +348 -0
- package/src/commands/crosschain.js +218 -0
- package/src/commands/dlp.js +341 -0
- package/src/commands/evomap.js +394 -0
- package/src/commands/federation.js +283 -0
- package/src/commands/inference.js +318 -0
- package/src/commands/lowcode.js +356 -0
- package/src/commands/marketplace.js +256 -0
- package/src/commands/privacy.js +321 -0
- package/src/commands/reputation.js +261 -0
- package/src/commands/siem.js +246 -0
- package/src/commands/sla.js +259 -0
- package/src/commands/stress.js +230 -0
- package/src/commands/terraform.js +245 -0
- package/src/commands/zkp.js +335 -0
- package/src/lib/a2a-protocol.js +451 -0
- package/src/lib/app-builder.js +239 -0
- package/src/lib/bi-engine.js +338 -0
- package/src/lib/cross-chain.js +345 -0
- package/src/lib/dlp-engine.js +389 -0
- package/src/lib/evomap-federation.js +177 -0
- package/src/lib/evomap-governance.js +276 -0
- package/src/lib/federation-hardening.js +259 -0
- package/src/lib/inference-network.js +330 -0
- package/src/lib/privacy-computing.js +427 -0
- package/src/lib/reputation-optimizer.js +299 -0
- package/src/lib/siem-exporter.js +333 -0
- package/src/lib/skill-marketplace.js +325 -0
- package/src/lib/sla-manager.js +275 -0
- package/src/lib/stress-tester.js +330 -0
- package/src/lib/terraform-manager.js +363 -0
- package/src/lib/zkp-engine.js +274 -0
|
@@ -404,4 +404,334 @@ export function getSchedulerStats(db) {
|
|
|
404
404
|
export function _resetState() {
|
|
405
405
|
_nodes.clear();
|
|
406
406
|
_tasks.clear();
|
|
407
|
+
_maxConcurrentTasksPerNode = INFERENCE_DEFAULT_MAX_CONCURRENT_TASKS_PER_NODE;
|
|
408
|
+
_heartbeatTimeoutMs = INFERENCE_DEFAULT_HEARTBEAT_TIMEOUT_MS;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/* ──────────────────────────────────────────────────────────
|
|
412
|
+
* V2 — Phase 67 surface (strictly additive)
|
|
413
|
+
* ────────────────────────────────────────────────────────── */
|
|
414
|
+
|
|
415
|
+
export const NODE_STATUS_V2 = NODE_STATUS;
|
|
416
|
+
export const TASK_STATUS_V2 = TASK_STATUS;
|
|
417
|
+
export const PRIVACY_MODE_V2 = PRIVACY_MODE;
|
|
418
|
+
|
|
419
|
+
export const INFERENCE_DEFAULT_MAX_CONCURRENT_TASKS_PER_NODE = 4;
|
|
420
|
+
export const INFERENCE_DEFAULT_HEARTBEAT_TIMEOUT_MS = 90000;
|
|
421
|
+
|
|
422
|
+
let _maxConcurrentTasksPerNode =
|
|
423
|
+
INFERENCE_DEFAULT_MAX_CONCURRENT_TASKS_PER_NODE;
|
|
424
|
+
let _heartbeatTimeoutMs = INFERENCE_DEFAULT_HEARTBEAT_TIMEOUT_MS;
|
|
425
|
+
|
|
426
|
+
const TASK_TRANSITIONS_V2 = new Map([
|
|
427
|
+
["queued", new Set(["dispatched", "failed"])],
|
|
428
|
+
["dispatched", new Set(["running", "failed"])],
|
|
429
|
+
["running", new Set(["complete", "failed"])],
|
|
430
|
+
]);
|
|
431
|
+
const TASK_TERMINALS_V2 = new Set(["complete", "failed"]);
|
|
432
|
+
|
|
433
|
+
export function setMaxConcurrentTasksPerNode(n) {
|
|
434
|
+
if (typeof n !== "number" || Number.isNaN(n) || n < 1) {
|
|
435
|
+
throw new Error("maxConcurrentTasksPerNode must be a positive integer");
|
|
436
|
+
}
|
|
437
|
+
_maxConcurrentTasksPerNode = Math.floor(n);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
export function getMaxConcurrentTasksPerNode() {
|
|
441
|
+
return _maxConcurrentTasksPerNode;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
export function setHeartbeatTimeoutMs(ms) {
|
|
445
|
+
if (typeof ms !== "number" || Number.isNaN(ms) || ms < 1) {
|
|
446
|
+
throw new Error("heartbeatTimeoutMs must be a positive integer");
|
|
447
|
+
}
|
|
448
|
+
_heartbeatTimeoutMs = Math.floor(ms);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
export function getHeartbeatTimeoutMs() {
|
|
452
|
+
return _heartbeatTimeoutMs;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
export function getActiveTasksPerNode(nodeId) {
|
|
456
|
+
if (!nodeId) return 0;
|
|
457
|
+
let count = 0;
|
|
458
|
+
for (const t of _tasks.values()) {
|
|
459
|
+
if (
|
|
460
|
+
t.assigned_node === nodeId &&
|
|
461
|
+
(t.status === "dispatched" || t.status === "running")
|
|
462
|
+
) {
|
|
463
|
+
count += 1;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
return count;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
export function submitTaskV2(db, { model, input, privacyMode, priority } = {}) {
|
|
470
|
+
if (!model) throw new Error("model is required");
|
|
471
|
+
const mode = privacyMode || DEFAULT_CONFIG.defaultPrivacyMode;
|
|
472
|
+
if (!VALID_PRIVACY_MODES.has(mode)) {
|
|
473
|
+
throw new Error(`Invalid privacy mode: ${mode}`);
|
|
474
|
+
}
|
|
475
|
+
const prio = Math.min(Math.max(priority || 5, 1), DEFAULT_CONFIG.maxPriority);
|
|
476
|
+
|
|
477
|
+
const id = _id();
|
|
478
|
+
const now = _now();
|
|
479
|
+
const task = {
|
|
480
|
+
id,
|
|
481
|
+
model,
|
|
482
|
+
input: input || null,
|
|
483
|
+
output: null,
|
|
484
|
+
privacy_mode: mode,
|
|
485
|
+
priority: prio,
|
|
486
|
+
assigned_node: null,
|
|
487
|
+
status: "queued",
|
|
488
|
+
duration_ms: null,
|
|
489
|
+
created_at: now,
|
|
490
|
+
completed_at: null,
|
|
491
|
+
started_at: null,
|
|
492
|
+
error_message: null,
|
|
493
|
+
};
|
|
494
|
+
|
|
495
|
+
db.prepare(
|
|
496
|
+
`INSERT INTO inference_tasks (id, model, input, output, privacy_mode, priority,
|
|
497
|
+
assigned_node, status, duration_ms, created_at, completed_at)
|
|
498
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
499
|
+
).run(
|
|
500
|
+
id,
|
|
501
|
+
model,
|
|
502
|
+
task.input,
|
|
503
|
+
null,
|
|
504
|
+
mode,
|
|
505
|
+
prio,
|
|
506
|
+
null,
|
|
507
|
+
"queued",
|
|
508
|
+
null,
|
|
509
|
+
now,
|
|
510
|
+
null,
|
|
511
|
+
);
|
|
512
|
+
|
|
513
|
+
_tasks.set(id, task);
|
|
514
|
+
return { ...task };
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
function _pickLeastLoadedOnline(privacyMode) {
|
|
518
|
+
let best = null;
|
|
519
|
+
let bestLoad = Infinity;
|
|
520
|
+
for (const n of _nodes.values()) {
|
|
521
|
+
if (n.status !== "online") continue;
|
|
522
|
+
const load = getActiveTasksPerNode(n.id);
|
|
523
|
+
if (load >= _maxConcurrentTasksPerNode) continue;
|
|
524
|
+
if (load < bestLoad) {
|
|
525
|
+
best = n;
|
|
526
|
+
bestLoad = load;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
return best;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
export function dispatchTaskV2(db, taskId, { nodeId } = {}) {
|
|
533
|
+
const t = _tasks.get(taskId);
|
|
534
|
+
if (!t) throw new Error(`Unknown task: ${taskId}`);
|
|
535
|
+
if (t.status !== "queued") {
|
|
536
|
+
throw new Error(
|
|
537
|
+
`Invalid transition: ${t.status} → dispatched (must be queued)`,
|
|
538
|
+
);
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
let target = null;
|
|
542
|
+
if (nodeId) {
|
|
543
|
+
target = _nodes.get(nodeId);
|
|
544
|
+
if (!target) throw new Error(`Unknown node: ${nodeId}`);
|
|
545
|
+
if (target.status !== "online") {
|
|
546
|
+
throw new Error(`Node ${nodeId} is not online (status=${target.status})`);
|
|
547
|
+
}
|
|
548
|
+
if (getActiveTasksPerNode(nodeId) >= _maxConcurrentTasksPerNode) {
|
|
549
|
+
throw new Error(`Max concurrent tasks reached for node ${nodeId}`);
|
|
550
|
+
}
|
|
551
|
+
} else {
|
|
552
|
+
target = _pickLeastLoadedOnline(t.privacy_mode);
|
|
553
|
+
if (!target) throw new Error("No eligible online nodes available");
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
t.status = "dispatched";
|
|
557
|
+
t.assigned_node = target.id;
|
|
558
|
+
target.task_count += 1;
|
|
559
|
+
|
|
560
|
+
db.prepare(
|
|
561
|
+
`UPDATE inference_tasks SET status = ?, assigned_node = ? WHERE id = ?`,
|
|
562
|
+
).run("dispatched", target.id, taskId);
|
|
563
|
+
db.prepare("UPDATE inference_nodes SET task_count = ? WHERE id = ?").run(
|
|
564
|
+
target.task_count,
|
|
565
|
+
target.id,
|
|
566
|
+
);
|
|
567
|
+
|
|
568
|
+
return { ...t };
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
export function startTask(db, taskId) {
|
|
572
|
+
const t = _tasks.get(taskId);
|
|
573
|
+
if (!t) throw new Error(`Unknown task: ${taskId}`);
|
|
574
|
+
if (t.status !== "dispatched") {
|
|
575
|
+
throw new Error(
|
|
576
|
+
`Invalid transition: ${t.status} → running (must be dispatched)`,
|
|
577
|
+
);
|
|
578
|
+
}
|
|
579
|
+
t.status = "running";
|
|
580
|
+
t.started_at = _now();
|
|
581
|
+
db.prepare("UPDATE inference_tasks SET status = ? WHERE id = ?").run(
|
|
582
|
+
"running",
|
|
583
|
+
taskId,
|
|
584
|
+
);
|
|
585
|
+
return { ...t };
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
export function completeTaskV2(db, taskId, { output, durationMs } = {}) {
|
|
589
|
+
const t = _tasks.get(taskId);
|
|
590
|
+
if (!t) throw new Error(`Unknown task: ${taskId}`);
|
|
591
|
+
if (t.status !== "running") {
|
|
592
|
+
throw new Error(
|
|
593
|
+
`Invalid transition: ${t.status} → complete (must be running)`,
|
|
594
|
+
);
|
|
595
|
+
}
|
|
596
|
+
t.status = "complete";
|
|
597
|
+
t.output = output != null ? output : null;
|
|
598
|
+
t.completed_at = _now();
|
|
599
|
+
if (durationMs != null) {
|
|
600
|
+
t.duration_ms = durationMs;
|
|
601
|
+
} else if (t.started_at) {
|
|
602
|
+
t.duration_ms = t.completed_at - t.started_at;
|
|
603
|
+
} else {
|
|
604
|
+
t.duration_ms = t.completed_at - t.created_at;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
db.prepare(
|
|
608
|
+
`UPDATE inference_tasks SET status = ?, output = ?, completed_at = ?,
|
|
609
|
+
duration_ms = ? WHERE id = ?`,
|
|
610
|
+
).run("complete", t.output, t.completed_at, t.duration_ms, taskId);
|
|
611
|
+
|
|
612
|
+
return { ...t };
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
export function failTaskV2(db, taskId, { error } = {}) {
|
|
616
|
+
const t = _tasks.get(taskId);
|
|
617
|
+
if (!t) throw new Error(`Unknown task: ${taskId}`);
|
|
618
|
+
if (!TASK_TRANSITIONS_V2.get(t.status)?.has("failed")) {
|
|
619
|
+
throw new Error(`Invalid transition: ${t.status} → failed`);
|
|
620
|
+
}
|
|
621
|
+
t.status = "failed";
|
|
622
|
+
t.error_message = error || null;
|
|
623
|
+
t.output = error || null;
|
|
624
|
+
t.completed_at = _now();
|
|
625
|
+
|
|
626
|
+
db.prepare(
|
|
627
|
+
"UPDATE inference_tasks SET status = ?, output = ?, completed_at = ? WHERE id = ?",
|
|
628
|
+
).run("failed", t.output, t.completed_at, taskId);
|
|
629
|
+
|
|
630
|
+
return { ...t };
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
export function setTaskStatus(db, taskId, newStatus, patch = {}) {
|
|
634
|
+
const t = _tasks.get(taskId);
|
|
635
|
+
if (!t) throw new Error(`Unknown task: ${taskId}`);
|
|
636
|
+
if (!Object.values(TASK_STATUS).includes(newStatus)) {
|
|
637
|
+
throw new Error(`Unknown status: ${newStatus}`);
|
|
638
|
+
}
|
|
639
|
+
const allowed = TASK_TRANSITIONS_V2.get(t.status);
|
|
640
|
+
if (!allowed || !allowed.has(newStatus)) {
|
|
641
|
+
throw new Error(`Invalid transition: ${t.status} → ${newStatus}`);
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
t.status = newStatus;
|
|
645
|
+
if (patch.output !== undefined) t.output = patch.output;
|
|
646
|
+
if (patch.errorMessage !== undefined) t.error_message = patch.errorMessage;
|
|
647
|
+
if (patch.durationMs !== undefined) t.duration_ms = patch.durationMs;
|
|
648
|
+
if (patch.startedAt !== undefined) t.started_at = patch.startedAt;
|
|
649
|
+
if (newStatus === "running" && !t.started_at) t.started_at = _now();
|
|
650
|
+
if (TASK_TERMINALS_V2.has(newStatus)) {
|
|
651
|
+
t.completed_at = t.completed_at || _now();
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
db.prepare(
|
|
655
|
+
`UPDATE inference_tasks SET status = ?, output = ?, completed_at = ?,
|
|
656
|
+
duration_ms = ? WHERE id = ?`,
|
|
657
|
+
).run(newStatus, t.output, t.completed_at, t.duration_ms, taskId);
|
|
658
|
+
|
|
659
|
+
return { ...t };
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
export function autoMarkOfflineNodes(db) {
|
|
663
|
+
const cutoff = _now() - _heartbeatTimeoutMs;
|
|
664
|
+
const offlined = [];
|
|
665
|
+
for (const n of _nodes.values()) {
|
|
666
|
+
if (n.status === "offline") continue;
|
|
667
|
+
if (n.last_heartbeat < cutoff) {
|
|
668
|
+
n.status = "offline";
|
|
669
|
+
db.prepare("UPDATE inference_nodes SET status = ? WHERE id = ?").run(
|
|
670
|
+
"offline",
|
|
671
|
+
n.id,
|
|
672
|
+
);
|
|
673
|
+
offlined.push({ ...n });
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
return offlined;
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
export function findEligibleNodes({ capability, privacyMode } = {}) {
|
|
680
|
+
const _ = privacyMode; // reserved for future mode-aware routing
|
|
681
|
+
const out = [];
|
|
682
|
+
for (const n of _nodes.values()) {
|
|
683
|
+
if (n.status !== "online") continue;
|
|
684
|
+
if (getActiveTasksPerNode(n.id) >= _maxConcurrentTasksPerNode) continue;
|
|
685
|
+
if (capability) {
|
|
686
|
+
if (
|
|
687
|
+
!Array.isArray(n.capabilities) ||
|
|
688
|
+
!n.capabilities.includes(capability)
|
|
689
|
+
) {
|
|
690
|
+
continue;
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
out.push({ ...n });
|
|
694
|
+
}
|
|
695
|
+
return out.sort(
|
|
696
|
+
(a, b) => getActiveTasksPerNode(a.id) - getActiveTasksPerNode(b.id),
|
|
697
|
+
);
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
export function getInferenceStatsV2() {
|
|
701
|
+
const nodesByStatus = {};
|
|
702
|
+
for (const s of Object.values(NODE_STATUS)) nodesByStatus[s] = 0;
|
|
703
|
+
const tasksByStatus = {};
|
|
704
|
+
for (const s of Object.values(TASK_STATUS)) tasksByStatus[s] = 0;
|
|
705
|
+
const tasksByPrivacyMode = {};
|
|
706
|
+
for (const m of Object.values(PRIVACY_MODE)) tasksByPrivacyMode[m] = 0;
|
|
707
|
+
|
|
708
|
+
const loadPerNode = {};
|
|
709
|
+
for (const n of _nodes.values()) {
|
|
710
|
+
nodesByStatus[n.status] = (nodesByStatus[n.status] || 0) + 1;
|
|
711
|
+
loadPerNode[n.id] = getActiveTasksPerNode(n.id);
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
let durSum = 0;
|
|
715
|
+
let durCount = 0;
|
|
716
|
+
for (const t of _tasks.values()) {
|
|
717
|
+
tasksByStatus[t.status] = (tasksByStatus[t.status] || 0) + 1;
|
|
718
|
+
tasksByPrivacyMode[t.privacy_mode] =
|
|
719
|
+
(tasksByPrivacyMode[t.privacy_mode] || 0) + 1;
|
|
720
|
+
if (t.status === "complete" && typeof t.duration_ms === "number") {
|
|
721
|
+
durSum += t.duration_ms;
|
|
722
|
+
durCount += 1;
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
return {
|
|
727
|
+
totalNodes: _nodes.size,
|
|
728
|
+
totalTasks: _tasks.size,
|
|
729
|
+
maxConcurrentTasksPerNode: _maxConcurrentTasksPerNode,
|
|
730
|
+
heartbeatTimeoutMs: _heartbeatTimeoutMs,
|
|
731
|
+
nodesByStatus,
|
|
732
|
+
tasksByStatus,
|
|
733
|
+
tasksByPrivacyMode,
|
|
734
|
+
loadPerNode,
|
|
735
|
+
avgDurationMs: durCount > 0 ? Math.round(durSum / durCount) : 0,
|
|
736
|
+
};
|
|
407
737
|
}
|