chainlesschain 0.66.0 → 0.132.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 (143) hide show
  1. package/bin/chainlesschain.js +0 -0
  2. package/package.json +1 -1
  3. package/src/commands/a2a.js +380 -0
  4. package/src/commands/agent-network.js +254 -1
  5. package/src/commands/audit.js +302 -0
  6. package/src/commands/automation.js +271 -1
  7. package/src/commands/bi.js +348 -0
  8. package/src/commands/codegen.js +224 -0
  9. package/src/commands/collab.js +341 -0
  10. package/src/commands/compliance.js +1035 -0
  11. package/src/commands/cowork.js +221 -0
  12. package/src/commands/crosschain.js +218 -0
  13. package/src/commands/dbevo.js +284 -0
  14. package/src/commands/dev.js +252 -0
  15. package/src/commands/did.js +358 -0
  16. package/src/commands/dlp.js +341 -0
  17. package/src/commands/encrypt.js +341 -0
  18. package/src/commands/evomap.js +394 -0
  19. package/src/commands/export.js +256 -1
  20. package/src/commands/federation.js +283 -0
  21. package/src/commands/fusion.js +258 -0
  22. package/src/commands/governance.js +325 -0
  23. package/src/commands/hardening.js +411 -0
  24. package/src/commands/hook.js +148 -0
  25. package/src/commands/import.js +252 -0
  26. package/src/commands/incentive.js +322 -0
  27. package/src/commands/inference.js +318 -0
  28. package/src/commands/infra.js +244 -0
  29. package/src/commands/instinct.js +260 -0
  30. package/src/commands/ipfs.js +318 -0
  31. package/src/commands/kg.js +387 -0
  32. package/src/commands/llm.js +263 -0
  33. package/src/commands/lowcode.js +356 -0
  34. package/src/commands/marketplace.js +256 -0
  35. package/src/commands/mcp.js +221 -0
  36. package/src/commands/memory.js +248 -0
  37. package/src/commands/multimodal.js +296 -0
  38. package/src/commands/nlprog.js +356 -0
  39. package/src/commands/note.js +244 -0
  40. package/src/commands/ops.js +354 -0
  41. package/src/commands/orchestrate.js +166 -0
  42. package/src/commands/org.js +277 -0
  43. package/src/commands/p2p.js +390 -0
  44. package/src/commands/perception.js +290 -0
  45. package/src/commands/permmem.js +251 -0
  46. package/src/commands/plugin-ecosystem.js +273 -0
  47. package/src/commands/pqc.js +393 -0
  48. package/src/commands/privacy.js +321 -0
  49. package/src/commands/quantization.js +351 -0
  50. package/src/commands/rcache.js +271 -0
  51. package/src/commands/recommend.js +340 -0
  52. package/src/commands/reputation.js +261 -0
  53. package/src/commands/runtime.js +307 -0
  54. package/src/commands/scim.js +262 -0
  55. package/src/commands/session.js +258 -0
  56. package/src/commands/siem.js +246 -0
  57. package/src/commands/skill.js +267 -1
  58. package/src/commands/sla.js +259 -0
  59. package/src/commands/social.js +256 -0
  60. package/src/commands/sso.js +186 -1
  61. package/src/commands/stress.js +230 -0
  62. package/src/commands/sync.js +256 -0
  63. package/src/commands/tech.js +338 -0
  64. package/src/commands/tenant.js +351 -0
  65. package/src/commands/terraform.js +245 -0
  66. package/src/commands/tokens.js +269 -0
  67. package/src/commands/trust.js +249 -0
  68. package/src/commands/wallet.js +277 -0
  69. package/src/commands/workflow.js +171 -0
  70. package/src/commands/zkp.js +335 -0
  71. package/src/index.js +4 -0
  72. package/src/lib/a2a-protocol.js +451 -0
  73. package/src/lib/agent-coordinator.js +325 -0
  74. package/src/lib/agent-network.js +387 -0
  75. package/src/lib/agent-router.js +395 -0
  76. package/src/lib/aiops.js +478 -0
  77. package/src/lib/app-builder.js +239 -0
  78. package/src/lib/audit-logger.js +379 -0
  79. package/src/lib/automation-engine.js +330 -0
  80. package/src/lib/autonomous-developer.js +350 -0
  81. package/src/lib/bi-engine.js +338 -0
  82. package/src/lib/code-agent.js +323 -0
  83. package/src/lib/collaboration-governance.js +364 -0
  84. package/src/lib/community-governance.js +436 -0
  85. package/src/lib/compliance-manager.js +434 -0
  86. package/src/lib/content-recommendation.js +469 -0
  87. package/src/lib/cross-chain.js +345 -0
  88. package/src/lib/crypto-manager.js +350 -0
  89. package/src/lib/dbevo.js +338 -0
  90. package/src/lib/decentral-infra.js +340 -0
  91. package/src/lib/did-manager.js +367 -0
  92. package/src/lib/dlp-engine.js +389 -0
  93. package/src/lib/evomap-federation.js +177 -0
  94. package/src/lib/evomap-governance.js +276 -0
  95. package/src/lib/federation-hardening.js +259 -0
  96. package/src/lib/hardening-manager.js +348 -0
  97. package/src/lib/hook-manager.js +380 -0
  98. package/src/lib/inference-network.js +330 -0
  99. package/src/lib/instinct-manager.js +332 -0
  100. package/src/lib/ipfs-storage.js +334 -0
  101. package/src/lib/knowledge-exporter.js +381 -0
  102. package/src/lib/knowledge-graph.js +432 -0
  103. package/src/lib/knowledge-importer.js +379 -0
  104. package/src/lib/llm-providers.js +391 -0
  105. package/src/lib/mcp-registry.js +333 -0
  106. package/src/lib/memory-manager.js +330 -0
  107. package/src/lib/multimodal.js +346 -0
  108. package/src/lib/nl-programming.js +343 -0
  109. package/src/lib/note-versioning.js +327 -0
  110. package/src/lib/org-manager.js +323 -0
  111. package/src/lib/p2p-manager.js +387 -0
  112. package/src/lib/perception.js +346 -0
  113. package/src/lib/perf-tuning.js +4 -1
  114. package/src/lib/permanent-memory.js +320 -0
  115. package/src/lib/plugin-ecosystem.js +377 -0
  116. package/src/lib/pqc-manager.js +368 -0
  117. package/src/lib/privacy-computing.js +427 -0
  118. package/src/lib/protocol-fusion.js +417 -0
  119. package/src/lib/quantization.js +325 -0
  120. package/src/lib/reputation-optimizer.js +299 -0
  121. package/src/lib/response-cache.js +327 -0
  122. package/src/lib/scim-manager.js +329 -0
  123. package/src/lib/session-manager.js +329 -0
  124. package/src/lib/siem-exporter.js +333 -0
  125. package/src/lib/skill-loader.js +377 -0
  126. package/src/lib/skill-marketplace.js +325 -0
  127. package/src/lib/sla-manager.js +275 -0
  128. package/src/lib/social-manager.js +326 -0
  129. package/src/lib/sso-manager.js +332 -0
  130. package/src/lib/stress-tester.js +330 -0
  131. package/src/lib/sync-manager.js +326 -0
  132. package/src/lib/tech-learning-engine.js +369 -0
  133. package/src/lib/tenant-saas.js +460 -0
  134. package/src/lib/terraform-manager.js +363 -0
  135. package/src/lib/threat-intel.js +335 -0
  136. package/src/lib/token-incentive.js +293 -0
  137. package/src/lib/token-tracker.js +329 -0
  138. package/src/lib/trust-security.js +390 -0
  139. package/src/lib/ueba.js +389 -0
  140. package/src/lib/universal-runtime.js +325 -0
  141. package/src/lib/wallet-manager.js +326 -0
  142. package/src/lib/workflow-engine.js +322 -0
  143. package/src/lib/zkp-engine.js +274 -0
package/src/lib/aiops.js CHANGED
@@ -521,3 +521,481 @@ export function _resetState() {
521
521
  _playbooks.clear();
522
522
  _baselines.clear();
523
523
  }
524
+
525
+ /* ═══════════════════════════════════════════════════════════════
526
+ * V2 SURFACE — Phase 25 AIOps lifecycle state machines
527
+ * ═══════════════════════════════════════════════════════════════
528
+ *
529
+ * V2 adds two parallel lifecycles on top of the legacy incident/playbook
530
+ * store. Nothing above is modified.
531
+ *
532
+ * Playbook maturity: draft → { active, retired }
533
+ * active → { deprecated, retired }
534
+ * deprecated → { active, retired }
535
+ * Terminal: retired
536
+ *
537
+ * Remediation exec: pending → { executing, aborted }
538
+ * executing → { succeeded, failed, aborted }
539
+ * Terminals: succeeded, failed, aborted
540
+ *
541
+ * Caps: per-owner active-playbook count + per-owner in-flight
542
+ * remediation count.
543
+ *
544
+ * Auto-flip: stale-playbook auto-retire + stuck-remediation auto-timeout.
545
+ *
546
+ * Stats: all enum keys zero-initialized for stable CI regression shape.
547
+ * ═════════════════════════════════════════════════════════════ */
548
+
549
+ export const PLAYBOOK_MATURITY_V2 = Object.freeze({
550
+ DRAFT: "draft",
551
+ ACTIVE: "active",
552
+ DEPRECATED: "deprecated",
553
+ RETIRED: "retired",
554
+ });
555
+
556
+ export const REMEDIATION_LIFECYCLE_V2 = Object.freeze({
557
+ PENDING: "pending",
558
+ EXECUTING: "executing",
559
+ SUCCEEDED: "succeeded",
560
+ FAILED: "failed",
561
+ ABORTED: "aborted",
562
+ });
563
+
564
+ const PLAYBOOK_TRANSITIONS_V2 = new Map([
565
+ ["draft", new Set(["active", "retired"])],
566
+ ["active", new Set(["deprecated", "retired"])],
567
+ ["deprecated", new Set(["active", "retired"])],
568
+ ]);
569
+ const PLAYBOOK_TERMINALS_V2 = new Set(["retired"]);
570
+
571
+ const REMEDIATION_TRANSITIONS_V2 = new Map([
572
+ ["pending", new Set(["executing", "aborted"])],
573
+ ["executing", new Set(["succeeded", "failed", "aborted"])],
574
+ ]);
575
+ const REMEDIATION_TERMINALS_V2 = new Set(["succeeded", "failed", "aborted"]);
576
+
577
+ export const AIOPS_DEFAULT_MAX_ACTIVE_PLAYBOOKS_PER_OWNER = 50;
578
+ export const AIOPS_DEFAULT_MAX_PENDING_REMEDIATIONS_PER_OWNER = 10;
579
+ export const AIOPS_DEFAULT_PLAYBOOK_STALE_MS = 90 * 86400000; // 90 days
580
+ export const AIOPS_DEFAULT_REMEDIATION_TIMEOUT_MS = 30 * 60 * 1000; // 30 min
581
+
582
+ let _maxActivePlaybooksPerOwnerV2 =
583
+ AIOPS_DEFAULT_MAX_ACTIVE_PLAYBOOKS_PER_OWNER;
584
+ let _maxPendingRemediationsPerOwnerV2 =
585
+ AIOPS_DEFAULT_MAX_PENDING_REMEDIATIONS_PER_OWNER;
586
+ let _playbookStaleMsV2 = AIOPS_DEFAULT_PLAYBOOK_STALE_MS;
587
+ let _remediationTimeoutMsV2 = AIOPS_DEFAULT_REMEDIATION_TIMEOUT_MS;
588
+
589
+ const _playbookStatesV2 = new Map(); // playbookId → V2 record
590
+ const _remediationStatesV2 = new Map(); // remediationId → V2 record
591
+
592
+ function _positiveIntV2(n, label) {
593
+ const num = Number(n);
594
+ if (!Number.isFinite(num) || num <= 0) {
595
+ throw new Error(`${label} must be a positive integer`);
596
+ }
597
+ return Math.floor(num);
598
+ }
599
+
600
+ function _validPlaybookStatusV2(status) {
601
+ return (
602
+ status === "draft" ||
603
+ status === "active" ||
604
+ status === "deprecated" ||
605
+ status === "retired"
606
+ );
607
+ }
608
+
609
+ function _validRemediationStatusV2(status) {
610
+ return (
611
+ status === "pending" ||
612
+ status === "executing" ||
613
+ status === "succeeded" ||
614
+ status === "failed" ||
615
+ status === "aborted"
616
+ );
617
+ }
618
+
619
+ export function getDefaultMaxActivePlaybooksPerOwnerV2() {
620
+ return AIOPS_DEFAULT_MAX_ACTIVE_PLAYBOOKS_PER_OWNER;
621
+ }
622
+ export function getMaxActivePlaybooksPerOwnerV2() {
623
+ return _maxActivePlaybooksPerOwnerV2;
624
+ }
625
+ export function setMaxActivePlaybooksPerOwnerV2(n) {
626
+ _maxActivePlaybooksPerOwnerV2 = _positiveIntV2(
627
+ n,
628
+ "maxActivePlaybooksPerOwner",
629
+ );
630
+ return _maxActivePlaybooksPerOwnerV2;
631
+ }
632
+
633
+ export function getDefaultMaxPendingRemediationsPerOwnerV2() {
634
+ return AIOPS_DEFAULT_MAX_PENDING_REMEDIATIONS_PER_OWNER;
635
+ }
636
+ export function getMaxPendingRemediationsPerOwnerV2() {
637
+ return _maxPendingRemediationsPerOwnerV2;
638
+ }
639
+ export function setMaxPendingRemediationsPerOwnerV2(n) {
640
+ _maxPendingRemediationsPerOwnerV2 = _positiveIntV2(
641
+ n,
642
+ "maxPendingRemediationsPerOwner",
643
+ );
644
+ return _maxPendingRemediationsPerOwnerV2;
645
+ }
646
+
647
+ export function getDefaultPlaybookStaleMsV2() {
648
+ return AIOPS_DEFAULT_PLAYBOOK_STALE_MS;
649
+ }
650
+ export function getPlaybookStaleMsV2() {
651
+ return _playbookStaleMsV2;
652
+ }
653
+ export function setPlaybookStaleMsV2(ms) {
654
+ _playbookStaleMsV2 = _positiveIntV2(ms, "playbookStaleMs");
655
+ return _playbookStaleMsV2;
656
+ }
657
+
658
+ export function getDefaultRemediationTimeoutMsV2() {
659
+ return AIOPS_DEFAULT_REMEDIATION_TIMEOUT_MS;
660
+ }
661
+ export function getRemediationTimeoutMsV2() {
662
+ return _remediationTimeoutMsV2;
663
+ }
664
+ export function setRemediationTimeoutMsV2(ms) {
665
+ _remediationTimeoutMsV2 = _positiveIntV2(ms, "remediationTimeoutMs");
666
+ return _remediationTimeoutMsV2;
667
+ }
668
+
669
+ /* ── Playbook V2 ─────────────────────────────────────────── */
670
+
671
+ export function registerPlaybookV2(db, config = {}) {
672
+ void db;
673
+ const playbookId = String(config.playbookId || "").trim();
674
+ if (!playbookId) throw new Error("playbookId is required");
675
+ const ownerId = String(config.ownerId || "").trim();
676
+ if (!ownerId) throw new Error("ownerId is required");
677
+ if (_playbookStatesV2.has(playbookId)) {
678
+ throw new Error(`Playbook already registered in V2: ${playbookId}`);
679
+ }
680
+
681
+ const now = Number(config.now ?? Date.now());
682
+ const initialStatus = config.initialStatus || "draft";
683
+ if (!_validPlaybookStatusV2(initialStatus)) {
684
+ throw new Error(`Invalid initial status: ${initialStatus}`);
685
+ }
686
+ if (initialStatus === "retired") {
687
+ throw new Error("Cannot register playbook in terminal status 'retired'");
688
+ }
689
+
690
+ if (initialStatus === "active") {
691
+ let activeCount = 0;
692
+ for (const rec of _playbookStatesV2.values()) {
693
+ if (rec.ownerId === ownerId && rec.status === "active") activeCount += 1;
694
+ }
695
+ if (activeCount >= _maxActivePlaybooksPerOwnerV2) {
696
+ throw new Error(
697
+ `Max active playbooks per owner reached (${_maxActivePlaybooksPerOwnerV2})`,
698
+ );
699
+ }
700
+ }
701
+
702
+ const record = {
703
+ playbookId,
704
+ ownerId,
705
+ name: config.name ? String(config.name) : null,
706
+ status: initialStatus,
707
+ metadata: config.metadata ? { ...config.metadata } : {},
708
+ createdAt: now,
709
+ updatedAt: now,
710
+ lastUsedAt: now,
711
+ reason: null,
712
+ };
713
+ _playbookStatesV2.set(playbookId, record);
714
+ return { ...record, metadata: { ...record.metadata } };
715
+ }
716
+
717
+ export function getPlaybookV2(playbookId) {
718
+ const rec = _playbookStatesV2.get(String(playbookId || ""));
719
+ if (!rec) return null;
720
+ return { ...rec, metadata: { ...rec.metadata } };
721
+ }
722
+
723
+ export function setPlaybookMaturityV2(db, playbookId, newStatus, patch = {}) {
724
+ void db;
725
+ const id = String(playbookId || "");
726
+ const record = _playbookStatesV2.get(id);
727
+ if (!record) throw new Error(`Playbook not registered in V2: ${id}`);
728
+ if (!_validPlaybookStatusV2(newStatus)) {
729
+ throw new Error(`Invalid playbook status: ${newStatus}`);
730
+ }
731
+ if (PLAYBOOK_TERMINALS_V2.has(record.status)) {
732
+ throw new Error(
733
+ `Playbook is in terminal status '${record.status}' and cannot transition`,
734
+ );
735
+ }
736
+ const allowed = PLAYBOOK_TRANSITIONS_V2.get(record.status);
737
+ if (!allowed || !allowed.has(newStatus)) {
738
+ throw new Error(`Invalid transition: ${record.status} → ${newStatus}`);
739
+ }
740
+
741
+ if (newStatus === "active" && record.status !== "active") {
742
+ let activeCount = 0;
743
+ for (const rec of _playbookStatesV2.values()) {
744
+ if (rec.ownerId === record.ownerId && rec.status === "active")
745
+ activeCount += 1;
746
+ }
747
+ if (activeCount >= _maxActivePlaybooksPerOwnerV2) {
748
+ throw new Error(
749
+ `Max active playbooks per owner reached (${_maxActivePlaybooksPerOwnerV2})`,
750
+ );
751
+ }
752
+ }
753
+
754
+ record.status = newStatus;
755
+ record.updatedAt = Number(patch.now ?? Date.now());
756
+ if (patch.reason !== undefined) record.reason = patch.reason;
757
+ if (patch.metadata && typeof patch.metadata === "object") {
758
+ record.metadata = { ...record.metadata, ...patch.metadata };
759
+ }
760
+ return { ...record, metadata: { ...record.metadata } };
761
+ }
762
+
763
+ export function activatePlaybook(db, playbookId, reason) {
764
+ return setPlaybookMaturityV2(db, playbookId, "active", { reason });
765
+ }
766
+ export function deprecatePlaybookV2(db, playbookId, reason) {
767
+ return setPlaybookMaturityV2(db, playbookId, "deprecated", { reason });
768
+ }
769
+ export function retirePlaybook(db, playbookId, reason) {
770
+ return setPlaybookMaturityV2(db, playbookId, "retired", { reason });
771
+ }
772
+
773
+ export function touchPlaybookActivity(playbookId) {
774
+ const rec = _playbookStatesV2.get(String(playbookId || ""));
775
+ if (!rec) throw new Error(`Playbook not registered in V2: ${playbookId}`);
776
+ rec.lastUsedAt = Date.now();
777
+ return { ...rec, metadata: { ...rec.metadata } };
778
+ }
779
+
780
+ /* ── Remediation V2 ──────────────────────────────────────── */
781
+
782
+ export function submitRemediationV2(db, config = {}) {
783
+ void db;
784
+ const remediationId = String(config.remediationId || "").trim();
785
+ if (!remediationId) throw new Error("remediationId is required");
786
+ const ownerId = String(config.ownerId || "").trim();
787
+ if (!ownerId) throw new Error("ownerId is required");
788
+ const playbookId = String(config.playbookId || "").trim();
789
+ if (!playbookId) throw new Error("playbookId is required");
790
+
791
+ if (_remediationStatesV2.has(remediationId)) {
792
+ throw new Error(`Remediation already registered in V2: ${remediationId}`);
793
+ }
794
+
795
+ const playbook = _playbookStatesV2.get(playbookId);
796
+ if (!playbook) {
797
+ throw new Error(`Playbook not registered in V2: ${playbookId}`);
798
+ }
799
+ if (playbook.status !== "active" && playbook.status !== "deprecated") {
800
+ throw new Error(
801
+ `Playbook is ${playbook.status}, cannot submit remediation`,
802
+ );
803
+ }
804
+
805
+ let inflightCount = 0;
806
+ for (const rec of _remediationStatesV2.values()) {
807
+ if (
808
+ rec.ownerId === ownerId &&
809
+ (rec.status === "pending" || rec.status === "executing")
810
+ ) {
811
+ inflightCount += 1;
812
+ }
813
+ }
814
+ if (inflightCount >= _maxPendingRemediationsPerOwnerV2) {
815
+ throw new Error(
816
+ `Max pending remediations per owner reached (${_maxPendingRemediationsPerOwnerV2})`,
817
+ );
818
+ }
819
+
820
+ const now = Number(config.now ?? Date.now());
821
+ const record = {
822
+ remediationId,
823
+ ownerId,
824
+ playbookId,
825
+ incidentId: config.incidentId ? String(config.incidentId) : null,
826
+ status: "pending",
827
+ metadata: config.metadata ? { ...config.metadata } : {},
828
+ createdAt: now,
829
+ updatedAt: now,
830
+ startedAt: null,
831
+ completedAt: null,
832
+ reason: null,
833
+ };
834
+ _remediationStatesV2.set(remediationId, record);
835
+ return { ...record, metadata: { ...record.metadata } };
836
+ }
837
+
838
+ export function getRemediationV2(remediationId) {
839
+ const rec = _remediationStatesV2.get(String(remediationId || ""));
840
+ if (!rec) return null;
841
+ return { ...rec, metadata: { ...rec.metadata } };
842
+ }
843
+
844
+ export function setRemediationStatusV2(
845
+ db,
846
+ remediationId,
847
+ newStatus,
848
+ patch = {},
849
+ ) {
850
+ void db;
851
+ const id = String(remediationId || "");
852
+ const record = _remediationStatesV2.get(id);
853
+ if (!record) throw new Error(`Remediation not registered in V2: ${id}`);
854
+ if (!_validRemediationStatusV2(newStatus)) {
855
+ throw new Error(`Invalid remediation status: ${newStatus}`);
856
+ }
857
+ if (REMEDIATION_TERMINALS_V2.has(record.status)) {
858
+ throw new Error(
859
+ `Remediation is in terminal status '${record.status}' and cannot transition`,
860
+ );
861
+ }
862
+ const allowed = REMEDIATION_TRANSITIONS_V2.get(record.status);
863
+ if (!allowed || !allowed.has(newStatus)) {
864
+ throw new Error(`Invalid transition: ${record.status} → ${newStatus}`);
865
+ }
866
+ const now = Number(patch.now ?? Date.now());
867
+ record.status = newStatus;
868
+ record.updatedAt = now;
869
+ if (newStatus === "executing" && record.startedAt === null) {
870
+ record.startedAt = now;
871
+ }
872
+ if (REMEDIATION_TERMINALS_V2.has(newStatus)) {
873
+ record.completedAt = now;
874
+ }
875
+ if (patch.reason !== undefined) record.reason = patch.reason;
876
+ if (patch.metadata && typeof patch.metadata === "object") {
877
+ record.metadata = { ...record.metadata, ...patch.metadata };
878
+ }
879
+ return { ...record, metadata: { ...record.metadata } };
880
+ }
881
+
882
+ export function startRemediation(db, remediationId, reason) {
883
+ return setRemediationStatusV2(db, remediationId, "executing", { reason });
884
+ }
885
+ export function completeRemediation(db, remediationId, reason) {
886
+ return setRemediationStatusV2(db, remediationId, "succeeded", { reason });
887
+ }
888
+ export function failRemediation(db, remediationId, reason) {
889
+ return setRemediationStatusV2(db, remediationId, "failed", { reason });
890
+ }
891
+ export function abortRemediation(db, remediationId, reason) {
892
+ return setRemediationStatusV2(db, remediationId, "aborted", { reason });
893
+ }
894
+
895
+ /* ── Counts ──────────────────────────────────────────────── */
896
+
897
+ export function getActivePlaybookCount(ownerId) {
898
+ let n = 0;
899
+ for (const rec of _playbookStatesV2.values()) {
900
+ if (rec.status !== "active") continue;
901
+ if (ownerId !== undefined && rec.ownerId !== String(ownerId)) continue;
902
+ n += 1;
903
+ }
904
+ return n;
905
+ }
906
+
907
+ export function getPendingRemediationCount(ownerId) {
908
+ let n = 0;
909
+ for (const rec of _remediationStatesV2.values()) {
910
+ if (rec.status !== "pending" && rec.status !== "executing") continue;
911
+ if (ownerId !== undefined && rec.ownerId !== String(ownerId)) continue;
912
+ n += 1;
913
+ }
914
+ return n;
915
+ }
916
+
917
+ /* ── Auto-flip Bulk Ops ──────────────────────────────────── */
918
+
919
+ export function autoRetireStalePlaybooks(db, nowMs) {
920
+ void db;
921
+ const now = Number(nowMs ?? Date.now());
922
+ const flipped = [];
923
+ for (const rec of _playbookStatesV2.values()) {
924
+ if (PLAYBOOK_TERMINALS_V2.has(rec.status)) continue;
925
+ if (now - rec.lastUsedAt > _playbookStaleMsV2) {
926
+ rec.status = "retired";
927
+ rec.updatedAt = now;
928
+ rec.reason = "stale";
929
+ flipped.push(rec.playbookId);
930
+ }
931
+ }
932
+ return flipped;
933
+ }
934
+
935
+ export function autoTimeoutStuckRemediations(db, nowMs) {
936
+ void db;
937
+ const now = Number(nowMs ?? Date.now());
938
+ const flipped = [];
939
+ for (const rec of _remediationStatesV2.values()) {
940
+ if (rec.status !== "executing") continue;
941
+ const startedAt = rec.startedAt ?? rec.createdAt;
942
+ if (now - startedAt > _remediationTimeoutMsV2) {
943
+ rec.status = "failed";
944
+ rec.updatedAt = now;
945
+ rec.completedAt = now;
946
+ rec.reason = "timeout";
947
+ flipped.push(rec.remediationId);
948
+ }
949
+ }
950
+ return flipped;
951
+ }
952
+
953
+ /* ── Stats V2 ────────────────────────────────────────────── */
954
+
955
+ export function getAiOpsStatsV2() {
956
+ const playbooksByStatus = {
957
+ draft: 0,
958
+ active: 0,
959
+ deprecated: 0,
960
+ retired: 0,
961
+ };
962
+ const remediationsByStatus = {
963
+ pending: 0,
964
+ executing: 0,
965
+ succeeded: 0,
966
+ failed: 0,
967
+ aborted: 0,
968
+ };
969
+ for (const rec of _playbookStatesV2.values()) {
970
+ if (playbooksByStatus[rec.status] !== undefined) {
971
+ playbooksByStatus[rec.status] += 1;
972
+ }
973
+ }
974
+ for (const rec of _remediationStatesV2.values()) {
975
+ if (remediationsByStatus[rec.status] !== undefined) {
976
+ remediationsByStatus[rec.status] += 1;
977
+ }
978
+ }
979
+ return {
980
+ totalPlaybooksV2: _playbookStatesV2.size,
981
+ totalRemediationsV2: _remediationStatesV2.size,
982
+ maxActivePlaybooksPerOwner: _maxActivePlaybooksPerOwnerV2,
983
+ maxPendingRemediationsPerOwner: _maxPendingRemediationsPerOwnerV2,
984
+ playbookStaleMs: _playbookStaleMsV2,
985
+ remediationTimeoutMs: _remediationTimeoutMsV2,
986
+ playbooksByStatus,
987
+ remediationsByStatus,
988
+ };
989
+ }
990
+
991
+ /* ── Reset V2 (tests) ────────────────────────────────────── */
992
+
993
+ export function _resetStateV2() {
994
+ _playbookStatesV2.clear();
995
+ _remediationStatesV2.clear();
996
+ _maxActivePlaybooksPerOwnerV2 = AIOPS_DEFAULT_MAX_ACTIVE_PLAYBOOKS_PER_OWNER;
997
+ _maxPendingRemediationsPerOwnerV2 =
998
+ AIOPS_DEFAULT_MAX_PENDING_REMEDIATIONS_PER_OWNER;
999
+ _playbookStaleMsV2 = AIOPS_DEFAULT_PLAYBOOK_STALE_MS;
1000
+ _remediationTimeoutMsV2 = AIOPS_DEFAULT_REMEDIATION_TIMEOUT_MS;
1001
+ }