chainlesschain 0.51.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 (39) 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/perf.js +433 -0
  16. package/src/commands/pipeline.js +449 -0
  17. package/src/commands/plugin-ecosystem.js +517 -0
  18. package/src/commands/sandbox.js +401 -0
  19. package/src/commands/social.js +311 -0
  20. package/src/commands/sso.js +798 -0
  21. package/src/commands/workflow.js +320 -0
  22. package/src/commands/zkp.js +227 -1
  23. package/src/index.js +21 -0
  24. package/src/lib/agent-economy.js +479 -0
  25. package/src/lib/agent-network.js +1121 -0
  26. package/src/lib/automation-engine.js +948 -0
  27. package/src/lib/dao-governance.js +569 -0
  28. package/src/lib/did-v2-manager.js +1127 -0
  29. package/src/lib/evolution-system.js +453 -0
  30. package/src/lib/hierarchical-memory.js +481 -0
  31. package/src/lib/perf-tuning.js +734 -0
  32. package/src/lib/pipeline-orchestrator.js +928 -0
  33. package/src/lib/plugin-ecosystem.js +1109 -0
  34. package/src/lib/sandbox-v2.js +306 -0
  35. package/src/lib/social-graph-analytics.js +707 -0
  36. package/src/lib/sso-manager.js +841 -0
  37. package/src/lib/workflow-engine.js +454 -1
  38. package/src/lib/zkp-engine.js +249 -20
  39. package/src/assets/web-panel/assets/Dashboard-BS-tzGNj.css +0 -1
@@ -695,4 +695,310 @@ export function pruneExpired(db, now = Date.now()) {
695
695
  export function _resetState() {
696
696
  activeSandboxes.clear();
697
697
  auditLog.length = 0;
698
+ _v2Isolations.length = 0;
699
+ }
700
+
701
+ // ═════════════════════════════════════════════════════════════════
702
+ // Phase 87 — Agent Security Sandbox 2.0 additions (strictly-additive)
703
+ // Frozen canonical enums + lifecycle state machine (pause/resume/
704
+ // terminate) + per-type quota + explicit enforce/check helpers +
705
+ // risk-level classification + auto-isolate + filtered audit/stats.
706
+ // ═════════════════════════════════════════════════════════════════
707
+
708
+ export const SANDBOX_STATUS = Object.freeze({
709
+ CREATING: "creating",
710
+ READY: "ready",
711
+ RUNNING: "running",
712
+ PAUSED: "paused",
713
+ TERMINATED: "terminated",
714
+ ERROR: "error",
715
+ });
716
+
717
+ export const PERMISSION_TYPE = Object.freeze({
718
+ FILESYSTEM: "filesystem",
719
+ NETWORK: "network",
720
+ SYSCALL: "syscall",
721
+ IPC: "ipc",
722
+ PROCESS: "process",
723
+ });
724
+
725
+ export const RISK_LEVEL = Object.freeze({
726
+ SAFE: "safe",
727
+ LOW: "low",
728
+ MEDIUM: "medium",
729
+ HIGH: "high",
730
+ CRITICAL: "critical",
731
+ });
732
+
733
+ export const QUOTA_TYPE = Object.freeze({
734
+ CPU_PERCENT: "cpu_percent",
735
+ MEMORY_MB: "memory_mb",
736
+ DISK_MB: "disk_mb",
737
+ NETWORK_KBPS: "network_kbps",
738
+ PROCESS_COUNT: "process_count",
739
+ });
740
+
741
+ const _PERM_TYPE_VALUES = new Set(Object.values(PERMISSION_TYPE));
742
+ const _QUOTA_TYPE_VALUES = new Set(Object.values(QUOTA_TYPE));
743
+
744
+ // V2 audit / isolation state
745
+ const _v2Isolations = [];
746
+
747
+ // QUOTA_TYPE → internal quota-field mapping (maps canonical Phase 87 names
748
+ // onto the pre-existing sandbox.quota fields).
749
+ const _QUOTA_FIELD_MAP = {
750
+ [QUOTA_TYPE.CPU_PERCENT]: "cpu",
751
+ [QUOTA_TYPE.MEMORY_MB]: "memory",
752
+ [QUOTA_TYPE.DISK_MB]: "storage",
753
+ [QUOTA_TYPE.NETWORK_KBPS]: "network",
754
+ [QUOTA_TYPE.PROCESS_COUNT]: "processCount",
755
+ };
756
+
757
+ function _requireSandbox(sandboxId) {
758
+ const s = activeSandboxes.get(sandboxId);
759
+ if (!s) throw new Error(`Sandbox not found: ${sandboxId}`);
760
+ return s;
761
+ }
762
+
763
+ /**
764
+ * Pause a sandbox: active → paused (no execution allowed while paused).
765
+ */
766
+ export function pauseSandboxV2(db, sandboxId) {
767
+ ensureSandboxTables(db);
768
+ const sandbox = _requireSandbox(sandboxId);
769
+ if (sandbox.status === SANDBOX_STATUS.PAUSED)
770
+ throw new Error("Sandbox already paused");
771
+ if (sandbox.status === SANDBOX_STATUS.TERMINATED)
772
+ throw new Error("Cannot pause terminated sandbox");
773
+ const prev = sandbox.status;
774
+ sandbox.status = SANDBOX_STATUS.PAUSED;
775
+ db.prepare(
776
+ `UPDATE sandbox_instances SET status = ?, updated_at = datetime('now') WHERE id = ?`,
777
+ ).run(SANDBOX_STATUS.PAUSED, sandboxId);
778
+ logAudit(db, sandboxId, "pause", { previousStatus: prev });
779
+ return { id: sandboxId, status: SANDBOX_STATUS.PAUSED, previousStatus: prev };
780
+ }
781
+
782
+ /**
783
+ * Resume a paused sandbox back to active.
784
+ */
785
+ export function resumeSandboxV2(db, sandboxId) {
786
+ ensureSandboxTables(db);
787
+ const sandbox = _requireSandbox(sandboxId);
788
+ if (sandbox.status !== SANDBOX_STATUS.PAUSED)
789
+ throw new Error(`Cannot resume: sandbox is ${sandbox.status}, not paused`);
790
+ sandbox.status = "active";
791
+ db.prepare(
792
+ `UPDATE sandbox_instances SET status = 'active', updated_at = datetime('now') WHERE id = ?`,
793
+ ).run(sandboxId);
794
+ logAudit(db, sandboxId, "resume", {});
795
+ return { id: sandboxId, status: "active" };
796
+ }
797
+
798
+ /**
799
+ * Terminate a sandbox (canonical name for destroy; records TERMINATED status).
800
+ */
801
+ export function terminateSandboxV2(db, sandboxId, reason = null) {
802
+ ensureSandboxTables(db);
803
+ const sandbox = _requireSandbox(sandboxId);
804
+ const prev = sandbox.status;
805
+ sandbox.status = SANDBOX_STATUS.TERMINATED;
806
+ activeSandboxes.delete(sandboxId);
807
+ db.prepare(
808
+ `UPDATE sandbox_instances SET status = ?, updated_at = datetime('now') WHERE id = ?`,
809
+ ).run(SANDBOX_STATUS.TERMINATED, sandboxId);
810
+ logAudit(db, sandboxId, "terminate", { previousStatus: prev, reason });
811
+ return {
812
+ id: sandboxId,
813
+ status: SANDBOX_STATUS.TERMINATED,
814
+ previousStatus: prev,
815
+ reason,
816
+ };
817
+ }
818
+
819
+ /**
820
+ * Set a single quota value keyed by QUOTA_TYPE. Validates type; merges into
821
+ * existing quota object instead of replacing.
822
+ */
823
+ export function setQuotaTyped(db, sandboxId, quotaType, limit) {
824
+ ensureSandboxTables(db);
825
+ if (!_QUOTA_TYPE_VALUES.has(quotaType))
826
+ throw new Error(`Invalid quotaType: ${quotaType}`);
827
+ if (!Number.isFinite(limit) || limit < 0)
828
+ throw new Error(`Invalid limit: ${limit}`);
829
+ const sandbox = _requireSandbox(sandboxId);
830
+ const field = _QUOTA_FIELD_MAP[quotaType];
831
+ const nextQuota = { ...sandbox.quota, [field]: limit };
832
+ sandbox.quota = nextQuota;
833
+ db.prepare(
834
+ `UPDATE sandbox_instances SET quota = ?, updated_at = datetime('now') WHERE id = ?`,
835
+ ).run(JSON.stringify(nextQuota), sandboxId);
836
+ logAudit(db, sandboxId, "set-quota-typed", { quotaType, limit, field });
837
+ return { id: sandboxId, quotaType, limit, quota: nextQuota };
838
+ }
839
+
840
+ /**
841
+ * Explicit permission enforcement (boolean result + optional throw on denied).
842
+ * Supports filesystem / network / syscall permission types.
843
+ */
844
+ export function enforcePermission(
845
+ sandbox,
846
+ { type, target, mode, throwOnDeny = false } = {},
847
+ ) {
848
+ if (!_PERM_TYPE_VALUES.has(type))
849
+ throw new Error(`Invalid permission type: ${type}`);
850
+ if (!sandbox || !sandbox.permissions)
851
+ throw new Error("Sandbox or permissions missing");
852
+ let allowed = false;
853
+ if (type === PERMISSION_TYPE.FILESYSTEM) {
854
+ allowed = checkFilePermission(sandbox.permissions, target, mode || "read");
855
+ } else if (type === PERMISSION_TYPE.NETWORK) {
856
+ allowed = checkNetworkPermission(sandbox.permissions, target);
857
+ } else if (type === PERMISSION_TYPE.SYSCALL) {
858
+ allowed = checkSystemCallPermission(sandbox.permissions, target);
859
+ } else {
860
+ // IPC / PROCESS — not implemented in base library; treat as denied-by-default
861
+ allowed = false;
862
+ }
863
+ if (!allowed && throwOnDeny)
864
+ throw new Error(`Permission denied: ${type} ${mode || ""} ${target}`);
865
+ return { allowed, type, target, mode: mode || null };
866
+ }
867
+
868
+ /**
869
+ * Per-type quota check. Returns {ok, current, limit, remaining}.
870
+ */
871
+ export function checkQuotaV2(sandbox, quotaType, amount = 0) {
872
+ if (!_QUOTA_TYPE_VALUES.has(quotaType))
873
+ throw new Error(`Invalid quotaType: ${quotaType}`);
874
+ if (!sandbox || !sandbox.quota) throw new Error("Sandbox or quota missing");
875
+ const field = _QUOTA_FIELD_MAP[quotaType];
876
+ const limit = sandbox.quota[field];
877
+ const current = (sandbox.resourceUsage?.[field] || 0) + amount;
878
+ const remaining = limit != null ? Math.max(0, limit - current) : Infinity;
879
+ return {
880
+ quotaType,
881
+ field,
882
+ limit: limit ?? null,
883
+ current,
884
+ remaining,
885
+ ok: limit == null || current <= limit,
886
+ };
887
+ }
888
+
889
+ /**
890
+ * Map a risk score (0..100) to a RISK_LEVEL enum value.
891
+ * safe < 20 ≤ low < 40 ≤ medium < 60 ≤ high < 80 ≤ critical
892
+ */
893
+ export function getRiskLevel(score) {
894
+ const n = Number(score) || 0;
895
+ if (n < 20) return RISK_LEVEL.SAFE;
896
+ if (n < 40) return RISK_LEVEL.LOW;
897
+ if (n < 60) return RISK_LEVEL.MEDIUM;
898
+ if (n < 80) return RISK_LEVEL.HIGH;
899
+ return RISK_LEVEL.CRITICAL;
900
+ }
901
+
902
+ /**
903
+ * Calculate risk score via monitorBehavior and classify with RISK_LEVEL.
904
+ */
905
+ export function calculateRiskScore(db, sandboxId) {
906
+ const report = monitorBehavior(db, sandboxId);
907
+ const level = getRiskLevel(report.riskScore);
908
+ return {
909
+ sandboxId,
910
+ riskScore: report.riskScore,
911
+ riskLevel: level,
912
+ patterns: report.patterns,
913
+ totalEvents: report.totalEvents,
914
+ };
915
+ }
916
+
917
+ /**
918
+ * Auto-isolate a sandbox: records an isolation entry + terminates.
919
+ * Typical trigger: risk level == CRITICAL or explicit admin call.
920
+ */
921
+ export function autoIsolate(db, sandboxId, reason = "high-risk") {
922
+ ensureSandboxTables(db);
923
+ const sandbox = _requireSandbox(sandboxId);
924
+ const entry = {
925
+ id: crypto.randomUUID(),
926
+ sandboxId,
927
+ reason,
928
+ isolatedAt: new Date().toISOString(),
929
+ agentId: sandbox.agentId,
930
+ };
931
+ _v2Isolations.push(entry);
932
+ logAudit(db, sandboxId, "auto-isolate", { reason });
933
+ try {
934
+ terminateSandboxV2(db, sandboxId, reason);
935
+ } catch (_e) {
936
+ // swallow — sandbox may already be terminated
937
+ }
938
+ return entry;
939
+ }
940
+
941
+ export function listIsolations(options = {}) {
942
+ let result = [..._v2Isolations];
943
+ if (options.sandboxId)
944
+ result = result.filter((i) => i.sandboxId === options.sandboxId);
945
+ if (options.reason)
946
+ result = result.filter((i) => i.reason === options.reason);
947
+ return result;
948
+ }
949
+
950
+ /**
951
+ * Filtered audit log — time range + event types + limit.
952
+ */
953
+ export function filterAuditLog(db, sandboxId, options = {}) {
954
+ let entries = [...auditLog];
955
+ if (sandboxId) entries = entries.filter((e) => e.sandboxId === sandboxId);
956
+ if (options.eventTypes && options.eventTypes.length > 0) {
957
+ const set = new Set(options.eventTypes);
958
+ entries = entries.filter((e) => set.has(e.action));
959
+ }
960
+ if (options.timeRange) {
961
+ const from = options.timeRange.from
962
+ ? new Date(options.timeRange.from).getTime()
963
+ : null;
964
+ const to = options.timeRange.to
965
+ ? new Date(options.timeRange.to).getTime()
966
+ : null;
967
+ entries = entries.filter((e) => {
968
+ const t = new Date(e.timestamp).getTime();
969
+ if (from != null && t < from) return false;
970
+ if (to != null && t > to) return false;
971
+ return true;
972
+ });
973
+ }
974
+ if (options.limit) entries = entries.slice(-options.limit);
975
+ return entries;
976
+ }
977
+
978
+ /**
979
+ * Extended V2 stats: per-status sandbox counts + audit summary + isolations.
980
+ */
981
+ export function getSandboxStatsV2() {
982
+ const byStatus = {};
983
+ for (const s of activeSandboxes.values()) {
984
+ const st = s.status || "unknown";
985
+ byStatus[st] = (byStatus[st] || 0) + 1;
986
+ }
987
+ const auditByAction = {};
988
+ for (const e of auditLog) {
989
+ auditByAction[e.action] = (auditByAction[e.action] || 0) + 1;
990
+ }
991
+ return {
992
+ totalSandboxes: activeSandboxes.size,
993
+ byStatus,
994
+ auditEventCount: auditLog.length,
995
+ auditByAction,
996
+ isolations: {
997
+ total: _v2Isolations.length,
998
+ byReason: _v2Isolations.reduce((acc, i) => {
999
+ acc[i.reason] = (acc[i.reason] || 0) + 1;
1000
+ return acc;
1001
+ }, {}),
1002
+ },
1003
+ };
698
1004
  }