chainlesschain 0.49.0 → 0.66.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 (43) hide show
  1. package/package.json +1 -1
  2. package/src/assets/web-panel/.build-hash +1 -1
  3. package/src/assets/web-panel/assets/{AppLayout-Rvi759IS.js → AppLayout-6SPt_8Y_.js} +1 -1
  4. package/src/assets/web-panel/assets/{Dashboard-DBhFxXYQ.js → Dashboard-Br7kCwKJ.js} +2 -2
  5. package/src/assets/web-panel/assets/Dashboard-CKeMmCoT.css +1 -0
  6. package/src/assets/web-panel/assets/{index-uL0cZ8N_.js → index-tN-8TosE.js} +2 -2
  7. package/src/assets/web-panel/index.html +2 -2
  8. package/src/commands/agent-network.js +785 -0
  9. package/src/commands/automation.js +654 -0
  10. package/src/commands/dao.js +565 -0
  11. package/src/commands/did-v2.js +620 -0
  12. package/src/commands/economy.js +578 -0
  13. package/src/commands/evolution.js +391 -0
  14. package/src/commands/hmemory.js +442 -0
  15. package/src/commands/ipfs.js +392 -0
  16. package/src/commands/multimodal.js +404 -0
  17. package/src/commands/perf.js +433 -0
  18. package/src/commands/pipeline.js +449 -0
  19. package/src/commands/plugin-ecosystem.js +517 -0
  20. package/src/commands/sandbox.js +401 -0
  21. package/src/commands/social.js +311 -0
  22. package/src/commands/sso.js +798 -0
  23. package/src/commands/workflow.js +320 -0
  24. package/src/commands/zkp.js +227 -1
  25. package/src/index.js +27 -0
  26. package/src/lib/agent-economy.js +479 -0
  27. package/src/lib/agent-network.js +1121 -0
  28. package/src/lib/automation-engine.js +948 -0
  29. package/src/lib/dao-governance.js +569 -0
  30. package/src/lib/did-v2-manager.js +1127 -0
  31. package/src/lib/evolution-system.js +453 -0
  32. package/src/lib/hierarchical-memory.js +481 -0
  33. package/src/lib/ipfs-storage.js +575 -0
  34. package/src/lib/multimodal.js +39 -12
  35. package/src/lib/perf-tuning.js +734 -0
  36. package/src/lib/pipeline-orchestrator.js +928 -0
  37. package/src/lib/plugin-ecosystem.js +1109 -0
  38. package/src/lib/sandbox-v2.js +306 -0
  39. package/src/lib/social-graph-analytics.js +707 -0
  40. package/src/lib/sso-manager.js +841 -0
  41. package/src/lib/workflow-engine.js +454 -1
  42. package/src/lib/zkp-engine.js +249 -20
  43. package/src/assets/web-panel/assets/Dashboard-BS-tzGNj.css +0 -1
@@ -1,10 +1,42 @@
1
1
  /**
2
2
  * Workflow Engine — DAG-based workflow creation, execution, and management.
3
- * Supports stages with action/approval types, pause/resume, rollback, and built-in templates.
3
+ * Supports stages with action/approval types, pause/resume, rollback, built-in templates,
4
+ * breakpoint debugging, checkpoint snapshots, and JSON import/export (Phase 82 port).
4
5
  */
5
6
 
6
7
  import crypto from "crypto";
7
8
 
9
+ // ─── Frozen enums (Phase 82 spec) ─────────────────────────────
10
+
11
+ export const WORKFLOW_STATUS = Object.freeze({
12
+ CREATED: "created",
13
+ ACTIVE: "active",
14
+ RUNNING: "running",
15
+ PAUSED: "paused",
16
+ COMPLETED: "completed",
17
+ FAILED: "failed",
18
+ ROLLING_BACK: "rolling_back",
19
+ ROLLED_BACK: "rolled_back",
20
+ ARCHIVED: "archived",
21
+ });
22
+
23
+ export const NODE_STATUS = Object.freeze({
24
+ PENDING: "pending",
25
+ RUNNING: "running",
26
+ COMPLETED: "completed",
27
+ FAILED: "failed",
28
+ SKIPPED: "skipped",
29
+ WAITING_APPROVAL: "waiting_approval",
30
+ });
31
+
32
+ export const TEMPLATE_TYPE = Object.freeze({
33
+ CI_CD: "ci_cd",
34
+ DATA_PIPELINE: "data_pipeline",
35
+ CODE_REVIEW: "code_review",
36
+ DEPLOYMENT: "deployment",
37
+ TEST_SUITE: "test_suite",
38
+ });
39
+
8
40
  /**
9
41
  * Ensure workflow tables exist in the database.
10
42
  */
@@ -34,6 +66,26 @@ export function ensureWorkflowTables(db) {
34
66
  updated_at TEXT DEFAULT (datetime('now'))
35
67
  )
36
68
  `);
69
+ db.exec(`
70
+ CREATE TABLE IF NOT EXISTS workflow_checkpoints (
71
+ id TEXT PRIMARY KEY,
72
+ execution_id TEXT NOT NULL,
73
+ workflow_id TEXT NOT NULL,
74
+ state_snapshot TEXT,
75
+ node_states TEXT,
76
+ created_at TEXT DEFAULT (datetime('now'))
77
+ )
78
+ `);
79
+ db.exec(`
80
+ CREATE TABLE IF NOT EXISTS workflow_breakpoints (
81
+ id TEXT PRIMARY KEY,
82
+ workflow_id TEXT NOT NULL,
83
+ node_id TEXT NOT NULL,
84
+ condition TEXT,
85
+ enabled INTEGER DEFAULT 1,
86
+ created_at TEXT DEFAULT (datetime('now'))
87
+ )
88
+ `);
37
89
  }
38
90
 
39
91
  /**
@@ -501,3 +553,404 @@ export function getTemplates() {
501
553
  },
502
554
  ];
503
555
  }
556
+
557
+ // ─── Canonical Phase 82 templates (keyed by TEMPLATE_TYPE) ────
558
+
559
+ /**
560
+ * Return the 5 canonical Phase 82 templates keyed by TEMPLATE_TYPE.
561
+ * These are distinct from `getTemplates()` which returns human-friendly slugs.
562
+ */
563
+ export function listTemplates() {
564
+ return [
565
+ {
566
+ id: TEMPLATE_TYPE.CI_CD,
567
+ name: "CI/CD Pipeline",
568
+ description: "Lint → test → build → deploy with human gate before deploy",
569
+ stages: [
570
+ { id: "lint", type: "action", name: "Lint", next: ["test"] },
571
+ { id: "test", type: "action", name: "Test", next: ["build"] },
572
+ { id: "build", type: "action", name: "Build", next: ["approve"] },
573
+ {
574
+ id: "approve",
575
+ type: "approval",
576
+ name: "Deploy Approval",
577
+ next: ["deploy"],
578
+ },
579
+ { id: "deploy", type: "action", name: "Deploy", next: [] },
580
+ ],
581
+ },
582
+ {
583
+ id: TEMPLATE_TYPE.DATA_PIPELINE,
584
+ name: "Data Pipeline",
585
+ description: "Extract → transform → validate → load",
586
+ stages: [
587
+ {
588
+ id: "extract",
589
+ type: "action",
590
+ name: "Extract",
591
+ next: ["transform"],
592
+ },
593
+ {
594
+ id: "transform",
595
+ type: "action",
596
+ name: "Transform",
597
+ next: ["validate"],
598
+ },
599
+ { id: "validate", type: "action", name: "Validate", next: ["load"] },
600
+ { id: "load", type: "action", name: "Load", next: [] },
601
+ ],
602
+ },
603
+ {
604
+ id: TEMPLATE_TYPE.CODE_REVIEW,
605
+ name: "Code Review",
606
+ description: "Lint + tests gated by human review before merge",
607
+ stages: [
608
+ { id: "lint", type: "action", name: "Lint Check", next: ["test"] },
609
+ { id: "test", type: "action", name: "Run Tests", next: ["review"] },
610
+ {
611
+ id: "review",
612
+ type: "approval",
613
+ name: "Human Review",
614
+ next: ["merge"],
615
+ },
616
+ { id: "merge", type: "action", name: "Merge to Main", next: [] },
617
+ ],
618
+ },
619
+ {
620
+ id: TEMPLATE_TYPE.DEPLOYMENT,
621
+ name: "Deployment",
622
+ description: "Pre-check → deploy → smoke-test → finalize",
623
+ stages: [
624
+ {
625
+ id: "precheck",
626
+ type: "action",
627
+ name: "Pre-deploy Check",
628
+ next: ["deploy"],
629
+ },
630
+ { id: "deploy", type: "action", name: "Deploy", next: ["smoke"] },
631
+ {
632
+ id: "smoke",
633
+ type: "action",
634
+ name: "Smoke Test",
635
+ next: ["finalize"],
636
+ },
637
+ {
638
+ id: "finalize",
639
+ type: "approval",
640
+ name: "Finalize Release",
641
+ next: [],
642
+ },
643
+ ],
644
+ },
645
+ {
646
+ id: TEMPLATE_TYPE.TEST_SUITE,
647
+ name: "Test Suite",
648
+ description: "Unit → integration → e2e → report",
649
+ stages: [
650
+ {
651
+ id: "unit",
652
+ type: "action",
653
+ name: "Unit Tests",
654
+ next: ["integration"],
655
+ },
656
+ {
657
+ id: "integration",
658
+ type: "action",
659
+ name: "Integration Tests",
660
+ next: ["e2e"],
661
+ },
662
+ { id: "e2e", type: "action", name: "E2E Tests", next: ["report"] },
663
+ { id: "report", type: "action", name: "Generate Report", next: [] },
664
+ ],
665
+ },
666
+ ];
667
+ }
668
+
669
+ // ─── Checkpoints ──────────────────────────────────────────────
670
+
671
+ /**
672
+ * Create a checkpoint snapshot of an execution's current state.
673
+ */
674
+ export function createCheckpoint(db, executionId) {
675
+ ensureWorkflowTables(db);
676
+ const exec = db
677
+ .prepare("SELECT * FROM workflow_executions WHERE id = ?")
678
+ .get(executionId);
679
+ if (!exec) {
680
+ throw new Error(`Execution not found: ${executionId}`);
681
+ }
682
+
683
+ const id = `cp-${crypto.randomBytes(8).toString("hex")}`;
684
+ const snapshot = {
685
+ executionId,
686
+ workflowId: exec.workflow_id,
687
+ status: exec.status,
688
+ currentStage: exec.current_stage,
689
+ capturedAt: new Date().toISOString(),
690
+ };
691
+ const nodeStates = JSON.parse(exec.log || "[]");
692
+
693
+ db.prepare(
694
+ `INSERT INTO workflow_checkpoints (id, execution_id, workflow_id, state_snapshot, node_states, created_at)
695
+ VALUES (?, ?, ?, ?, ?, datetime('now'))`,
696
+ ).run(
697
+ id,
698
+ executionId,
699
+ exec.workflow_id,
700
+ JSON.stringify(snapshot),
701
+ JSON.stringify(nodeStates),
702
+ );
703
+
704
+ db.prepare(
705
+ "UPDATE workflow_executions SET updated_at = datetime('now') WHERE id = ?",
706
+ ).run(executionId);
707
+
708
+ return { id, executionId, workflowId: exec.workflow_id, snapshot };
709
+ }
710
+
711
+ /**
712
+ * List checkpoints for an execution (newest first).
713
+ */
714
+ export function listCheckpoints(db, executionId) {
715
+ ensureWorkflowTables(db);
716
+ const rows = db
717
+ .prepare(
718
+ "SELECT * FROM workflow_checkpoints WHERE execution_id = ? ORDER BY created_at DESC",
719
+ )
720
+ .all(executionId);
721
+ return rows.map((row) => ({
722
+ id: row.id,
723
+ executionId: row.execution_id,
724
+ workflowId: row.workflow_id,
725
+ snapshot: JSON.parse(row.state_snapshot || "{}"),
726
+ nodeStates: JSON.parse(row.node_states || "[]"),
727
+ createdAt: row.created_at,
728
+ }));
729
+ }
730
+
731
+ /**
732
+ * Rollback an execution to a specific checkpoint, restoring log & status.
733
+ */
734
+ export function rollbackToCheckpoint(db, executionId, checkpointId) {
735
+ ensureWorkflowTables(db);
736
+ const cp = db
737
+ .prepare(
738
+ "SELECT * FROM workflow_checkpoints WHERE id = ? AND execution_id = ?",
739
+ )
740
+ .get(checkpointId, executionId);
741
+ if (!cp) {
742
+ throw new Error(
743
+ `Checkpoint ${checkpointId} not found for execution ${executionId}`,
744
+ );
745
+ }
746
+ const exec = db
747
+ .prepare("SELECT * FROM workflow_executions WHERE id = ?")
748
+ .get(executionId);
749
+ if (!exec) {
750
+ throw new Error(`Execution not found: ${executionId}`);
751
+ }
752
+
753
+ const snapshot = JSON.parse(cp.state_snapshot || "{}");
754
+ const nodeStates = JSON.parse(cp.node_states || "[]");
755
+
756
+ const restoredLog = [
757
+ ...nodeStates,
758
+ {
759
+ action: "rolled_back_to_checkpoint",
760
+ checkpointId,
761
+ timestamp: new Date().toISOString(),
762
+ },
763
+ ];
764
+
765
+ db.prepare(
766
+ "UPDATE workflow_executions SET status = ?, current_stage = ?, log = ?, updated_at = datetime('now') WHERE id = ?",
767
+ ).run(
768
+ WORKFLOW_STATUS.ROLLED_BACK,
769
+ snapshot.currentStage || null,
770
+ JSON.stringify(restoredLog),
771
+ executionId,
772
+ );
773
+
774
+ return {
775
+ id: executionId,
776
+ checkpointId,
777
+ status: WORKFLOW_STATUS.ROLLED_BACK,
778
+ restoredStage: snapshot.currentStage || null,
779
+ };
780
+ }
781
+
782
+ // ─── Breakpoints ──────────────────────────────────────────────
783
+
784
+ /**
785
+ * Set a breakpoint on a workflow node, optionally with a condition.
786
+ * Condition is a simple expression like `input.priority > 5` evaluated
787
+ * against the execution's input object (NO eval — regex-safe parse).
788
+ */
789
+ export function setBreakpoint(db, workflowId, nodeId, condition = null) {
790
+ ensureWorkflowTables(db);
791
+ const workflow = getWorkflow(db, workflowId);
792
+ if (!workflow) {
793
+ throw new Error(`Workflow not found: ${workflowId}`);
794
+ }
795
+ const nodeExists = workflow.dag.some((s) => s.id === nodeId);
796
+ if (!nodeExists) {
797
+ throw new Error(`Node ${nodeId} not in workflow ${workflowId}`);
798
+ }
799
+ if (condition !== null && condition !== undefined) {
800
+ if (!_isValidCondition(condition)) {
801
+ throw new Error(`Invalid breakpoint condition: ${condition}`);
802
+ }
803
+ }
804
+
805
+ const id = `bp-${crypto.randomBytes(8).toString("hex")}`;
806
+ db.prepare(
807
+ `INSERT INTO workflow_breakpoints (id, workflow_id, node_id, condition, enabled, created_at)
808
+ VALUES (?, ?, ?, ?, 1, datetime('now'))`,
809
+ ).run(id, workflowId, nodeId, condition || null);
810
+
811
+ return { id, workflowId, nodeId, condition: condition || null };
812
+ }
813
+
814
+ /**
815
+ * List breakpoints for a workflow.
816
+ */
817
+ export function listBreakpoints(db, workflowId) {
818
+ ensureWorkflowTables(db);
819
+ const rows = db
820
+ .prepare(
821
+ "SELECT * FROM workflow_breakpoints WHERE workflow_id = ? ORDER BY created_at ASC",
822
+ )
823
+ .all(workflowId);
824
+ return rows.map((row) => ({
825
+ id: row.id,
826
+ workflowId: row.workflow_id,
827
+ nodeId: row.node_id,
828
+ condition: row.condition,
829
+ enabled: row.enabled === 1,
830
+ }));
831
+ }
832
+
833
+ /**
834
+ * Remove a breakpoint.
835
+ */
836
+ export function removeBreakpoint(db, breakpointId) {
837
+ ensureWorkflowTables(db);
838
+ const result = db
839
+ .prepare("DELETE FROM workflow_breakpoints WHERE id = ?")
840
+ .run(breakpointId);
841
+ return { removed: result.changes > 0 };
842
+ }
843
+
844
+ /**
845
+ * Determine whether a breakpoint should trigger for a given node and input.
846
+ * Unconditional breakpoints always trigger; conditional ones evaluate safely.
847
+ */
848
+ export function shouldBreakpointTrigger(breakpoint, input = {}) {
849
+ if (!breakpoint || breakpoint.enabled === false) return false;
850
+ if (!breakpoint.condition) return true;
851
+ return _evaluateCondition(breakpoint.condition, input);
852
+ }
853
+
854
+ /**
855
+ * Validate a condition string is parseable (no arbitrary eval).
856
+ * Accepts: `input.<path> OP <literal>` where OP ∈ {==, !=, <, <=, >, >=}.
857
+ */
858
+ function _isValidCondition(expr) {
859
+ if (typeof expr !== "string") return false;
860
+ const trimmed = expr.trim();
861
+ if (!trimmed) return false;
862
+ return /^input(?:\.[a-zA-Z_][\w]*)+\s*(==|!=|<=|>=|<|>)\s*(.+)$/.test(
863
+ trimmed,
864
+ );
865
+ }
866
+
867
+ function _evaluateCondition(expr, input) {
868
+ const m = expr
869
+ .trim()
870
+ .match(/^input((?:\.[a-zA-Z_][\w]*)+)\s*(==|!=|<=|>=|<|>)\s*(.+)$/);
871
+ if (!m) return false;
872
+ const path = m[1].slice(1).split(".");
873
+ const op = m[2];
874
+ let rhs = m[3].trim();
875
+
876
+ let lhs = input;
877
+ for (const key of path) {
878
+ if (lhs == null) return false;
879
+ lhs = lhs[key];
880
+ }
881
+
882
+ let rhsParsed;
883
+ if (/^-?\d+(\.\d+)?$/.test(rhs)) {
884
+ rhsParsed = Number(rhs);
885
+ } else if (rhs === "true") {
886
+ rhsParsed = true;
887
+ } else if (rhs === "false") {
888
+ rhsParsed = false;
889
+ } else if (rhs === "null") {
890
+ rhsParsed = null;
891
+ } else if (
892
+ (rhs.startsWith('"') && rhs.endsWith('"')) ||
893
+ (rhs.startsWith("'") && rhs.endsWith("'"))
894
+ ) {
895
+ rhsParsed = rhs.slice(1, -1);
896
+ } else {
897
+ rhsParsed = rhs;
898
+ }
899
+
900
+ switch (op) {
901
+ case "==":
902
+ return lhs === rhsParsed;
903
+ case "!=":
904
+ return lhs !== rhsParsed;
905
+ case "<":
906
+ return lhs < rhsParsed;
907
+ case "<=":
908
+ return lhs <= rhsParsed;
909
+ case ">":
910
+ return lhs > rhsParsed;
911
+ case ">=":
912
+ return lhs >= rhsParsed;
913
+ default:
914
+ return false;
915
+ }
916
+ }
917
+
918
+ // ─── Import / Export ──────────────────────────────────────────
919
+
920
+ /**
921
+ * Export a workflow as a portable JSON definition.
922
+ */
923
+ export function exportWorkflow(db, workflowId) {
924
+ const workflow = getWorkflow(db, workflowId);
925
+ if (!workflow) {
926
+ throw new Error(`Workflow not found: ${workflowId}`);
927
+ }
928
+ return {
929
+ name: workflow.name,
930
+ description: workflow.description || "",
931
+ stages: workflow.dag,
932
+ exportedAt: new Date().toISOString(),
933
+ schemaVersion: 1,
934
+ };
935
+ }
936
+
937
+ /**
938
+ * Import a workflow from an exported JSON definition.
939
+ * Creates a new workflow row with fresh ID.
940
+ */
941
+ export function importWorkflow(db, definition) {
942
+ if (!definition || typeof definition !== "object") {
943
+ throw new Error("Definition must be an object");
944
+ }
945
+ if (!definition.name) {
946
+ throw new Error("Definition missing name");
947
+ }
948
+ if (!Array.isArray(definition.stages) || definition.stages.length === 0) {
949
+ throw new Error("Definition must include non-empty stages array");
950
+ }
951
+ return createWorkflow(db, {
952
+ name: definition.name,
953
+ description: definition.description || "",
954
+ stages: definition.stages,
955
+ });
956
+ }