chainlesschain 0.81.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 (110) hide show
  1. package/bin/chainlesschain.js +0 -0
  2. package/package.json +1 -1
  3. package/src/commands/agent-network.js +254 -1
  4. package/src/commands/audit.js +302 -0
  5. package/src/commands/automation.js +271 -1
  6. package/src/commands/codegen.js +224 -0
  7. package/src/commands/collab.js +341 -0
  8. package/src/commands/compliance.js +1035 -0
  9. package/src/commands/cowork.js +221 -0
  10. package/src/commands/dbevo.js +284 -0
  11. package/src/commands/dev.js +252 -0
  12. package/src/commands/did.js +358 -0
  13. package/src/commands/encrypt.js +341 -0
  14. package/src/commands/export.js +256 -1
  15. package/src/commands/fusion.js +258 -0
  16. package/src/commands/governance.js +325 -0
  17. package/src/commands/hardening.js +411 -0
  18. package/src/commands/hook.js +148 -0
  19. package/src/commands/import.js +252 -0
  20. package/src/commands/incentive.js +322 -0
  21. package/src/commands/infra.js +244 -0
  22. package/src/commands/instinct.js +260 -0
  23. package/src/commands/ipfs.js +318 -0
  24. package/src/commands/kg.js +387 -0
  25. package/src/commands/llm.js +263 -0
  26. package/src/commands/mcp.js +221 -0
  27. package/src/commands/memory.js +248 -0
  28. package/src/commands/multimodal.js +296 -0
  29. package/src/commands/nlprog.js +356 -0
  30. package/src/commands/note.js +244 -0
  31. package/src/commands/ops.js +354 -0
  32. package/src/commands/orchestrate.js +166 -0
  33. package/src/commands/org.js +277 -0
  34. package/src/commands/p2p.js +390 -0
  35. package/src/commands/perception.js +290 -0
  36. package/src/commands/permmem.js +251 -0
  37. package/src/commands/plugin-ecosystem.js +273 -0
  38. package/src/commands/pqc.js +393 -0
  39. package/src/commands/quantization.js +351 -0
  40. package/src/commands/rcache.js +271 -0
  41. package/src/commands/recommend.js +340 -0
  42. package/src/commands/runtime.js +307 -0
  43. package/src/commands/scim.js +262 -0
  44. package/src/commands/session.js +258 -0
  45. package/src/commands/skill.js +267 -1
  46. package/src/commands/social.js +256 -0
  47. package/src/commands/sso.js +186 -1
  48. package/src/commands/sync.js +256 -0
  49. package/src/commands/tech.js +338 -0
  50. package/src/commands/tenant.js +351 -0
  51. package/src/commands/tokens.js +269 -0
  52. package/src/commands/trust.js +249 -0
  53. package/src/commands/wallet.js +277 -0
  54. package/src/commands/workflow.js +171 -0
  55. package/src/index.js +4 -0
  56. package/src/lib/agent-coordinator.js +325 -0
  57. package/src/lib/agent-network.js +387 -0
  58. package/src/lib/agent-router.js +395 -0
  59. package/src/lib/aiops.js +478 -0
  60. package/src/lib/audit-logger.js +379 -0
  61. package/src/lib/automation-engine.js +330 -0
  62. package/src/lib/autonomous-developer.js +350 -0
  63. package/src/lib/code-agent.js +323 -0
  64. package/src/lib/collaboration-governance.js +364 -0
  65. package/src/lib/community-governance.js +436 -0
  66. package/src/lib/compliance-manager.js +434 -0
  67. package/src/lib/content-recommendation.js +469 -0
  68. package/src/lib/crypto-manager.js +350 -0
  69. package/src/lib/dbevo.js +338 -0
  70. package/src/lib/decentral-infra.js +340 -0
  71. package/src/lib/did-manager.js +367 -0
  72. package/src/lib/hardening-manager.js +348 -0
  73. package/src/lib/hook-manager.js +380 -0
  74. package/src/lib/instinct-manager.js +332 -0
  75. package/src/lib/ipfs-storage.js +334 -0
  76. package/src/lib/knowledge-exporter.js +381 -0
  77. package/src/lib/knowledge-graph.js +432 -0
  78. package/src/lib/knowledge-importer.js +379 -0
  79. package/src/lib/llm-providers.js +391 -0
  80. package/src/lib/mcp-registry.js +333 -0
  81. package/src/lib/memory-manager.js +330 -0
  82. package/src/lib/multimodal.js +346 -0
  83. package/src/lib/nl-programming.js +343 -0
  84. package/src/lib/note-versioning.js +327 -0
  85. package/src/lib/org-manager.js +323 -0
  86. package/src/lib/p2p-manager.js +387 -0
  87. package/src/lib/perception.js +346 -0
  88. package/src/lib/perf-tuning.js +4 -1
  89. package/src/lib/permanent-memory.js +320 -0
  90. package/src/lib/plugin-ecosystem.js +377 -0
  91. package/src/lib/pqc-manager.js +368 -0
  92. package/src/lib/protocol-fusion.js +417 -0
  93. package/src/lib/quantization.js +325 -0
  94. package/src/lib/response-cache.js +327 -0
  95. package/src/lib/scim-manager.js +329 -0
  96. package/src/lib/session-manager.js +329 -0
  97. package/src/lib/skill-loader.js +377 -0
  98. package/src/lib/social-manager.js +326 -0
  99. package/src/lib/sso-manager.js +332 -0
  100. package/src/lib/sync-manager.js +326 -0
  101. package/src/lib/tech-learning-engine.js +369 -0
  102. package/src/lib/tenant-saas.js +460 -0
  103. package/src/lib/threat-intel.js +335 -0
  104. package/src/lib/token-incentive.js +293 -0
  105. package/src/lib/token-tracker.js +329 -0
  106. package/src/lib/trust-security.js +390 -0
  107. package/src/lib/ueba.js +389 -0
  108. package/src/lib/universal-runtime.js +325 -0
  109. package/src/lib/wallet-manager.js +326 -0
  110. package/src/lib/workflow-engine.js +322 -0
@@ -723,3 +723,349 @@ export function getMultimodalStats(db) {
723
723
  export function _resetState() {
724
724
  _contextCache.clear();
725
725
  }
726
+
727
+ /* ═════════════════════════════════════════════════════════ *
728
+ * Phase 27 V2 — Session Maturity + Artifact Lifecycle
729
+ * ═════════════════════════════════════════════════════════ */
730
+
731
+ export const SESSION_MATURITY_V2 = Object.freeze({
732
+ ONBOARDING: "onboarding",
733
+ ACTIVE: "active",
734
+ PAUSED: "paused",
735
+ COMPLETED: "completed",
736
+ ARCHIVED: "archived",
737
+ });
738
+
739
+ export const ARTIFACT_LIFECYCLE_V2 = Object.freeze({
740
+ PENDING: "pending",
741
+ READY: "ready",
742
+ PURGED: "purged",
743
+ });
744
+
745
+ const SESSION_TRANSITIONS_V2 = new Map([
746
+ ["onboarding", new Set(["active", "archived"])],
747
+ ["active", new Set(["paused", "completed", "archived"])],
748
+ ["paused", new Set(["active", "completed", "archived"])],
749
+ ["completed", new Set(["archived"])],
750
+ ]);
751
+ const SESSION_TERMINALS_V2 = new Set(["archived"]);
752
+
753
+ const ARTIFACT_TRANSITIONS_V2 = new Map([
754
+ ["pending", new Set(["ready", "purged"])],
755
+ ["ready", new Set(["purged"])],
756
+ ]);
757
+ const ARTIFACT_TERMINALS_V2 = new Set(["purged"]);
758
+
759
+ export const MM_DEFAULT_MAX_ACTIVE_SESSIONS_PER_OWNER = 50;
760
+ export const MM_DEFAULT_MAX_ARTIFACTS_PER_SESSION = 200;
761
+ export const MM_DEFAULT_SESSION_IDLE_MS = 30 * 86400000;
762
+ export const MM_DEFAULT_ARTIFACT_STALE_MS = 14 * 86400000;
763
+
764
+ let _maxActiveSessionsPerOwnerV2 = MM_DEFAULT_MAX_ACTIVE_SESSIONS_PER_OWNER;
765
+ let _maxArtifactsPerSessionV2 = MM_DEFAULT_MAX_ARTIFACTS_PER_SESSION;
766
+ let _sessionIdleMsV2 = MM_DEFAULT_SESSION_IDLE_MS;
767
+ let _artifactStaleMsV2 = MM_DEFAULT_ARTIFACT_STALE_MS;
768
+
769
+ function _positiveIntV2(n, label) {
770
+ const v = Math.floor(Number(n));
771
+ if (!Number.isFinite(v) || v <= 0)
772
+ throw new Error(`${label} must be a positive integer`);
773
+ return v;
774
+ }
775
+
776
+ export function getDefaultMaxActiveSessionsPerOwnerV2() {
777
+ return MM_DEFAULT_MAX_ACTIVE_SESSIONS_PER_OWNER;
778
+ }
779
+ export function getMaxActiveSessionsPerOwnerV2() {
780
+ return _maxActiveSessionsPerOwnerV2;
781
+ }
782
+ export function setMaxActiveSessionsPerOwnerV2(n) {
783
+ return (_maxActiveSessionsPerOwnerV2 = _positiveIntV2(
784
+ n,
785
+ "maxActiveSessionsPerOwner",
786
+ ));
787
+ }
788
+ export function getDefaultMaxArtifactsPerSessionV2() {
789
+ return MM_DEFAULT_MAX_ARTIFACTS_PER_SESSION;
790
+ }
791
+ export function getMaxArtifactsPerSessionV2() {
792
+ return _maxArtifactsPerSessionV2;
793
+ }
794
+ export function setMaxArtifactsPerSessionV2(n) {
795
+ return (_maxArtifactsPerSessionV2 = _positiveIntV2(
796
+ n,
797
+ "maxArtifactsPerSession",
798
+ ));
799
+ }
800
+ export function getDefaultSessionIdleMsV2() {
801
+ return MM_DEFAULT_SESSION_IDLE_MS;
802
+ }
803
+ export function getSessionIdleMsV2() {
804
+ return _sessionIdleMsV2;
805
+ }
806
+ export function setSessionIdleMsV2(ms) {
807
+ return (_sessionIdleMsV2 = _positiveIntV2(ms, "sessionIdleMs"));
808
+ }
809
+ export function getDefaultArtifactStaleMsV2() {
810
+ return MM_DEFAULT_ARTIFACT_STALE_MS;
811
+ }
812
+ export function getArtifactStaleMsV2() {
813
+ return _artifactStaleMsV2;
814
+ }
815
+ export function setArtifactStaleMsV2(ms) {
816
+ return (_artifactStaleMsV2 = _positiveIntV2(ms, "artifactStaleMs"));
817
+ }
818
+
819
+ const _sessionsV2 = new Map();
820
+ const _artifactsV2 = new Map();
821
+
822
+ export function registerSessionV2(
823
+ _db,
824
+ { sessionId, ownerId, title, initialStatus, metadata } = {},
825
+ ) {
826
+ if (!sessionId) throw new Error("sessionId is required");
827
+ if (!ownerId) throw new Error("ownerId is required");
828
+ if (_sessionsV2.has(sessionId))
829
+ throw new Error(`Session ${sessionId} already exists`);
830
+ const status = initialStatus || SESSION_MATURITY_V2.ONBOARDING;
831
+ if (!Object.values(SESSION_MATURITY_V2).includes(status))
832
+ throw new Error(`Invalid initial status: ${status}`);
833
+ if (SESSION_TERMINALS_V2.has(status))
834
+ throw new Error(`Cannot register in terminal status: ${status}`);
835
+ if (status === SESSION_MATURITY_V2.ACTIVE) {
836
+ if (getActiveSessionCount(ownerId) >= _maxActiveSessionsPerOwnerV2)
837
+ throw new Error(
838
+ `Owner ${ownerId} reached active-session cap (${_maxActiveSessionsPerOwnerV2})`,
839
+ );
840
+ }
841
+ const now = Date.now();
842
+ const record = {
843
+ sessionId,
844
+ ownerId,
845
+ title: title || "",
846
+ status,
847
+ metadata: metadata || {},
848
+ createdAt: now,
849
+ updatedAt: now,
850
+ lastActivityAt: now,
851
+ };
852
+ _sessionsV2.set(sessionId, record);
853
+ return { ...record, metadata: { ...record.metadata } };
854
+ }
855
+
856
+ export function getSessionV2(sessionId) {
857
+ const r = _sessionsV2.get(sessionId);
858
+ return r ? { ...r, metadata: { ...r.metadata } } : null;
859
+ }
860
+
861
+ export function setSessionMaturityV2(_db, sessionId, newStatus, patch = {}) {
862
+ const record = _sessionsV2.get(sessionId);
863
+ if (!record) throw new Error(`Unknown session: ${sessionId}`);
864
+ if (!Object.values(SESSION_MATURITY_V2).includes(newStatus))
865
+ throw new Error(`Invalid status: ${newStatus}`);
866
+ const allowed = SESSION_TRANSITIONS_V2.get(record.status) || new Set();
867
+ if (!allowed.has(newStatus))
868
+ throw new Error(`Invalid transition: ${record.status} -> ${newStatus}`);
869
+ if (newStatus === SESSION_MATURITY_V2.ACTIVE) {
870
+ if (getActiveSessionCount(record.ownerId) >= _maxActiveSessionsPerOwnerV2)
871
+ throw new Error(
872
+ `Owner ${record.ownerId} reached active-session cap (${_maxActiveSessionsPerOwnerV2})`,
873
+ );
874
+ }
875
+ record.status = newStatus;
876
+ record.updatedAt = Date.now();
877
+ if (patch.reason !== undefined) record.lastReason = patch.reason;
878
+ if (patch.metadata)
879
+ record.metadata = { ...record.metadata, ...patch.metadata };
880
+ return { ...record, metadata: { ...record.metadata } };
881
+ }
882
+
883
+ export function activateSession(db, sessionId, reason) {
884
+ return setSessionMaturityV2(db, sessionId, SESSION_MATURITY_V2.ACTIVE, {
885
+ reason,
886
+ });
887
+ }
888
+ export function pauseSession(db, sessionId, reason) {
889
+ return setSessionMaturityV2(db, sessionId, SESSION_MATURITY_V2.PAUSED, {
890
+ reason,
891
+ });
892
+ }
893
+ export function completeSessionV2(db, sessionId, reason) {
894
+ return setSessionMaturityV2(db, sessionId, SESSION_MATURITY_V2.COMPLETED, {
895
+ reason,
896
+ });
897
+ }
898
+ export function archiveSession(db, sessionId, reason) {
899
+ return setSessionMaturityV2(db, sessionId, SESSION_MATURITY_V2.ARCHIVED, {
900
+ reason,
901
+ });
902
+ }
903
+
904
+ export function touchSessionActivity(sessionId) {
905
+ const record = _sessionsV2.get(sessionId);
906
+ if (!record) throw new Error(`Unknown session: ${sessionId}`);
907
+ record.lastActivityAt = Date.now();
908
+ record.updatedAt = record.lastActivityAt;
909
+ return { ...record, metadata: { ...record.metadata } };
910
+ }
911
+
912
+ export function registerArtifactV2(
913
+ _db,
914
+ { artifactId, sessionId, modality, size, initialStatus, metadata } = {},
915
+ ) {
916
+ if (!artifactId) throw new Error("artifactId is required");
917
+ if (!sessionId) throw new Error("sessionId is required");
918
+ if (!modality) throw new Error("modality is required");
919
+ if (!MODALITIES.includes(modality))
920
+ throw new Error(`Invalid modality: ${modality}`);
921
+ if (_artifactsV2.has(artifactId))
922
+ throw new Error(`Artifact ${artifactId} already exists`);
923
+ const status = initialStatus || ARTIFACT_LIFECYCLE_V2.PENDING;
924
+ if (!Object.values(ARTIFACT_LIFECYCLE_V2).includes(status))
925
+ throw new Error(`Invalid initial status: ${status}`);
926
+ if (ARTIFACT_TERMINALS_V2.has(status))
927
+ throw new Error(`Cannot register in terminal status: ${status}`);
928
+ if (getArtifactCount(sessionId) >= _maxArtifactsPerSessionV2)
929
+ throw new Error(
930
+ `Session ${sessionId} reached artifact cap (${_maxArtifactsPerSessionV2})`,
931
+ );
932
+ const now = Date.now();
933
+ const record = {
934
+ artifactId,
935
+ sessionId,
936
+ modality,
937
+ size: size || 0,
938
+ status,
939
+ metadata: metadata || {},
940
+ createdAt: now,
941
+ updatedAt: now,
942
+ lastAccessAt: now,
943
+ };
944
+ _artifactsV2.set(artifactId, record);
945
+ return { ...record, metadata: { ...record.metadata } };
946
+ }
947
+
948
+ export function getArtifactV2(artifactId) {
949
+ const r = _artifactsV2.get(artifactId);
950
+ return r ? { ...r, metadata: { ...r.metadata } } : null;
951
+ }
952
+
953
+ export function setArtifactStatusV2(_db, artifactId, newStatus, patch = {}) {
954
+ const record = _artifactsV2.get(artifactId);
955
+ if (!record) throw new Error(`Unknown artifact: ${artifactId}`);
956
+ if (!Object.values(ARTIFACT_LIFECYCLE_V2).includes(newStatus))
957
+ throw new Error(`Invalid status: ${newStatus}`);
958
+ const allowed = ARTIFACT_TRANSITIONS_V2.get(record.status) || new Set();
959
+ if (!allowed.has(newStatus))
960
+ throw new Error(`Invalid transition: ${record.status} -> ${newStatus}`);
961
+ record.status = newStatus;
962
+ record.updatedAt = Date.now();
963
+ if (patch.reason !== undefined) record.lastReason = patch.reason;
964
+ if (patch.metadata)
965
+ record.metadata = { ...record.metadata, ...patch.metadata };
966
+ return { ...record, metadata: { ...record.metadata } };
967
+ }
968
+
969
+ export function markArtifactReady(db, artifactId, reason) {
970
+ return setArtifactStatusV2(db, artifactId, ARTIFACT_LIFECYCLE_V2.READY, {
971
+ reason,
972
+ });
973
+ }
974
+ export function purgeArtifact(db, artifactId, reason) {
975
+ return setArtifactStatusV2(db, artifactId, ARTIFACT_LIFECYCLE_V2.PURGED, {
976
+ reason,
977
+ });
978
+ }
979
+
980
+ export function touchArtifactAccess(artifactId) {
981
+ const record = _artifactsV2.get(artifactId);
982
+ if (!record) throw new Error(`Unknown artifact: ${artifactId}`);
983
+ record.lastAccessAt = Date.now();
984
+ record.updatedAt = record.lastAccessAt;
985
+ return { ...record, metadata: { ...record.metadata } };
986
+ }
987
+
988
+ export function getActiveSessionCount(ownerId) {
989
+ let n = 0;
990
+ for (const r of _sessionsV2.values()) {
991
+ if (r.status !== SESSION_MATURITY_V2.ACTIVE) continue;
992
+ if (ownerId && r.ownerId !== ownerId) continue;
993
+ n++;
994
+ }
995
+ return n;
996
+ }
997
+
998
+ export function getArtifactCount(sessionId) {
999
+ let n = 0;
1000
+ for (const r of _artifactsV2.values()) {
1001
+ if (ARTIFACT_TERMINALS_V2.has(r.status)) continue;
1002
+ if (sessionId && r.sessionId !== sessionId) continue;
1003
+ n++;
1004
+ }
1005
+ return n;
1006
+ }
1007
+
1008
+ export function autoArchiveIdleSessions(_db, nowMs) {
1009
+ const now = nowMs ?? Date.now();
1010
+ const flipped = [];
1011
+ for (const r of _sessionsV2.values()) {
1012
+ if (
1013
+ r.status === SESSION_MATURITY_V2.ACTIVE ||
1014
+ r.status === SESSION_MATURITY_V2.PAUSED ||
1015
+ r.status === SESSION_MATURITY_V2.COMPLETED
1016
+ ) {
1017
+ if (now - r.lastActivityAt > _sessionIdleMsV2) {
1018
+ r.status = SESSION_MATURITY_V2.ARCHIVED;
1019
+ r.updatedAt = now;
1020
+ r.lastReason = "idle";
1021
+ flipped.push(r.sessionId);
1022
+ }
1023
+ }
1024
+ }
1025
+ return { flipped, count: flipped.length };
1026
+ }
1027
+
1028
+ export function autoPurgeStaleArtifacts(_db, nowMs) {
1029
+ const now = nowMs ?? Date.now();
1030
+ const flipped = [];
1031
+ for (const r of _artifactsV2.values()) {
1032
+ if (r.status === ARTIFACT_LIFECYCLE_V2.READY) {
1033
+ if (now - r.lastAccessAt > _artifactStaleMsV2) {
1034
+ r.status = ARTIFACT_LIFECYCLE_V2.PURGED;
1035
+ r.updatedAt = now;
1036
+ r.lastReason = "stale";
1037
+ flipped.push(r.artifactId);
1038
+ }
1039
+ }
1040
+ }
1041
+ return { flipped, count: flipped.length };
1042
+ }
1043
+
1044
+ export function getMultimodalStatsV2() {
1045
+ const sessionsByStatus = {};
1046
+ for (const s of Object.values(SESSION_MATURITY_V2)) sessionsByStatus[s] = 0;
1047
+ const artifactsByStatus = {};
1048
+ for (const s of Object.values(ARTIFACT_LIFECYCLE_V2))
1049
+ artifactsByStatus[s] = 0;
1050
+ for (const r of _sessionsV2.values()) sessionsByStatus[r.status]++;
1051
+ for (const r of _artifactsV2.values()) artifactsByStatus[r.status]++;
1052
+ return {
1053
+ totalSessionsV2: _sessionsV2.size,
1054
+ totalArtifactsV2: _artifactsV2.size,
1055
+ maxActiveSessionsPerOwner: _maxActiveSessionsPerOwnerV2,
1056
+ maxArtifactsPerSession: _maxArtifactsPerSessionV2,
1057
+ sessionIdleMs: _sessionIdleMsV2,
1058
+ artifactStaleMs: _artifactStaleMsV2,
1059
+ sessionsByStatus,
1060
+ artifactsByStatus,
1061
+ };
1062
+ }
1063
+
1064
+ export function _resetStateV2() {
1065
+ _maxActiveSessionsPerOwnerV2 = MM_DEFAULT_MAX_ACTIVE_SESSIONS_PER_OWNER;
1066
+ _maxArtifactsPerSessionV2 = MM_DEFAULT_MAX_ARTIFACTS_PER_SESSION;
1067
+ _sessionIdleMsV2 = MM_DEFAULT_SESSION_IDLE_MS;
1068
+ _artifactStaleMsV2 = MM_DEFAULT_ARTIFACT_STALE_MS;
1069
+ _sessionsV2.clear();
1070
+ _artifactsV2.clear();
1071
+ }
@@ -593,3 +593,346 @@ export function _resetState() {
593
593
  _translations.clear();
594
594
  _conventions.clear();
595
595
  }
596
+
597
+ /* ═════════════════════════════════════════════════════════ *
598
+ * Phase 28 V2 — Spec Maturity + Dialogue Lifecycle
599
+ * ═════════════════════════════════════════════════════════ */
600
+
601
+ export const SPEC_MATURITY_V2 = Object.freeze({
602
+ DRAFT: "draft",
603
+ REFINING: "refining",
604
+ APPROVED: "approved",
605
+ IMPLEMENTED: "implemented",
606
+ ARCHIVED: "archived",
607
+ });
608
+
609
+ export const DIALOGUE_TURN_V2 = Object.freeze({
610
+ PENDING: "pending",
611
+ ANSWERED: "answered",
612
+ DISMISSED: "dismissed",
613
+ ESCALATED: "escalated",
614
+ });
615
+
616
+ const SPEC_TRANSITIONS_V2 = new Map([
617
+ ["draft", new Set(["refining", "approved", "archived"])],
618
+ ["refining", new Set(["draft", "approved", "archived"])],
619
+ ["approved", new Set(["refining", "implemented", "archived"])],
620
+ ["implemented", new Set(["archived"])],
621
+ ]);
622
+ const SPEC_TERMINALS_V2 = new Set(["archived"]);
623
+
624
+ const DIALOGUE_TRANSITIONS_V2 = new Map([
625
+ ["pending", new Set(["answered", "dismissed", "escalated"])],
626
+ ["escalated", new Set(["answered", "dismissed"])],
627
+ ]);
628
+ const DIALOGUE_TERMINALS_V2 = new Set(["answered", "dismissed"]);
629
+
630
+ export const NLPROG_DEFAULT_MAX_ACTIVE_SPECS_PER_AUTHOR = 30;
631
+ export const NLPROG_DEFAULT_MAX_PENDING_TURNS_PER_SPEC = 20;
632
+ export const NLPROG_DEFAULT_SPEC_IDLE_MS = 45 * 86400000; // 45d
633
+ export const NLPROG_DEFAULT_TURN_PENDING_MS = 7 * 86400000; // 7d
634
+
635
+ let _maxActiveSpecsPerAuthorV2 = NLPROG_DEFAULT_MAX_ACTIVE_SPECS_PER_AUTHOR;
636
+ let _maxPendingTurnsPerSpecV2 = NLPROG_DEFAULT_MAX_PENDING_TURNS_PER_SPEC;
637
+ let _specIdleMsV2 = NLPROG_DEFAULT_SPEC_IDLE_MS;
638
+ let _turnPendingMsV2 = NLPROG_DEFAULT_TURN_PENDING_MS;
639
+
640
+ function _positiveIntV2(n, label) {
641
+ const v = Math.floor(Number(n));
642
+ if (!Number.isFinite(v) || v <= 0)
643
+ throw new Error(`${label} must be a positive integer`);
644
+ return v;
645
+ }
646
+
647
+ export function getDefaultMaxActiveSpecsPerAuthorV2() {
648
+ return NLPROG_DEFAULT_MAX_ACTIVE_SPECS_PER_AUTHOR;
649
+ }
650
+ export function getMaxActiveSpecsPerAuthorV2() {
651
+ return _maxActiveSpecsPerAuthorV2;
652
+ }
653
+ export function setMaxActiveSpecsPerAuthorV2(n) {
654
+ return (_maxActiveSpecsPerAuthorV2 = _positiveIntV2(
655
+ n,
656
+ "maxActiveSpecsPerAuthor",
657
+ ));
658
+ }
659
+ export function getDefaultMaxPendingTurnsPerSpecV2() {
660
+ return NLPROG_DEFAULT_MAX_PENDING_TURNS_PER_SPEC;
661
+ }
662
+ export function getMaxPendingTurnsPerSpecV2() {
663
+ return _maxPendingTurnsPerSpecV2;
664
+ }
665
+ export function setMaxPendingTurnsPerSpecV2(n) {
666
+ return (_maxPendingTurnsPerSpecV2 = _positiveIntV2(
667
+ n,
668
+ "maxPendingTurnsPerSpec",
669
+ ));
670
+ }
671
+ export function getDefaultSpecIdleMsV2() {
672
+ return NLPROG_DEFAULT_SPEC_IDLE_MS;
673
+ }
674
+ export function getSpecIdleMsV2() {
675
+ return _specIdleMsV2;
676
+ }
677
+ export function setSpecIdleMsV2(ms) {
678
+ return (_specIdleMsV2 = _positiveIntV2(ms, "specIdleMs"));
679
+ }
680
+ export function getDefaultTurnPendingMsV2() {
681
+ return NLPROG_DEFAULT_TURN_PENDING_MS;
682
+ }
683
+ export function getTurnPendingMsV2() {
684
+ return _turnPendingMsV2;
685
+ }
686
+ export function setTurnPendingMsV2(ms) {
687
+ return (_turnPendingMsV2 = _positiveIntV2(ms, "turnPendingMs"));
688
+ }
689
+
690
+ const _specsV2 = new Map();
691
+ const _turnsV2 = new Map();
692
+
693
+ function _isActiveSpec(s) {
694
+ return (
695
+ s === SPEC_MATURITY_V2.DRAFT ||
696
+ s === SPEC_MATURITY_V2.REFINING ||
697
+ s === SPEC_MATURITY_V2.APPROVED
698
+ );
699
+ }
700
+
701
+ export function registerSpecV2(
702
+ _db,
703
+ { specId, authorId, title, initialStatus, metadata } = {},
704
+ ) {
705
+ if (!specId) throw new Error("specId is required");
706
+ if (!authorId) throw new Error("authorId is required");
707
+ if (_specsV2.has(specId)) throw new Error(`Spec ${specId} already exists`);
708
+ const status = initialStatus || SPEC_MATURITY_V2.DRAFT;
709
+ if (!Object.values(SPEC_MATURITY_V2).includes(status))
710
+ throw new Error(`Invalid initial status: ${status}`);
711
+ if (SPEC_TERMINALS_V2.has(status))
712
+ throw new Error(`Cannot register in terminal status: ${status}`);
713
+ if (_isActiveSpec(status)) {
714
+ if (getActiveSpecCount(authorId) >= _maxActiveSpecsPerAuthorV2)
715
+ throw new Error(
716
+ `Author ${authorId} reached active-spec cap (${_maxActiveSpecsPerAuthorV2})`,
717
+ );
718
+ }
719
+ const now = _now();
720
+ const record = {
721
+ specId,
722
+ authorId,
723
+ title: title || "",
724
+ status,
725
+ metadata: metadata || {},
726
+ createdAt: now,
727
+ updatedAt: now,
728
+ lastActivityAt: now,
729
+ };
730
+ _specsV2.set(specId, record);
731
+ return { ...record, metadata: { ...record.metadata } };
732
+ }
733
+
734
+ export function getSpecV2(specId) {
735
+ const r = _specsV2.get(specId);
736
+ return r ? { ...r, metadata: { ...r.metadata } } : null;
737
+ }
738
+
739
+ export function setSpecMaturityV2(_db, specId, newStatus, patch = {}) {
740
+ const record = _specsV2.get(specId);
741
+ if (!record) throw new Error(`Unknown spec: ${specId}`);
742
+ if (!Object.values(SPEC_MATURITY_V2).includes(newStatus))
743
+ throw new Error(`Invalid status: ${newStatus}`);
744
+ const allowed = SPEC_TRANSITIONS_V2.get(record.status) || new Set();
745
+ if (!allowed.has(newStatus))
746
+ throw new Error(`Invalid transition: ${record.status} -> ${newStatus}`);
747
+ if (_isActiveSpec(newStatus) && !_isActiveSpec(record.status)) {
748
+ if (getActiveSpecCount(record.authorId) >= _maxActiveSpecsPerAuthorV2)
749
+ throw new Error(
750
+ `Author ${record.authorId} reached active-spec cap (${_maxActiveSpecsPerAuthorV2})`,
751
+ );
752
+ }
753
+ record.status = newStatus;
754
+ record.updatedAt = _now();
755
+ if (patch.reason !== undefined) record.lastReason = patch.reason;
756
+ if (patch.metadata)
757
+ record.metadata = { ...record.metadata, ...patch.metadata };
758
+ return { ...record, metadata: { ...record.metadata } };
759
+ }
760
+
761
+ export function refineSpec(db, id, reason) {
762
+ return setSpecMaturityV2(db, id, SPEC_MATURITY_V2.REFINING, { reason });
763
+ }
764
+ export function approveSpec(db, id, reason) {
765
+ return setSpecMaturityV2(db, id, SPEC_MATURITY_V2.APPROVED, { reason });
766
+ }
767
+ export function implementSpec(db, id, reason) {
768
+ return setSpecMaturityV2(db, id, SPEC_MATURITY_V2.IMPLEMENTED, { reason });
769
+ }
770
+ export function archiveSpec(db, id, reason) {
771
+ return setSpecMaturityV2(db, id, SPEC_MATURITY_V2.ARCHIVED, { reason });
772
+ }
773
+
774
+ export function touchSpecActivity(specId) {
775
+ const record = _specsV2.get(specId);
776
+ if (!record) throw new Error(`Unknown spec: ${specId}`);
777
+ record.lastActivityAt = _now();
778
+ record.updatedAt = record.lastActivityAt;
779
+ return { ...record, metadata: { ...record.metadata } };
780
+ }
781
+
782
+ export function registerDialogueTurnV2(
783
+ _db,
784
+ { turnId, specId, role, question, initialStatus, metadata } = {},
785
+ ) {
786
+ if (!turnId) throw new Error("turnId is required");
787
+ if (!specId) throw new Error("specId is required");
788
+ if (!_specsV2.has(specId)) throw new Error(`Unknown spec: ${specId}`);
789
+ if (_turnsV2.has(turnId)) throw new Error(`Turn ${turnId} already exists`);
790
+ const status = initialStatus || DIALOGUE_TURN_V2.PENDING;
791
+ if (!Object.values(DIALOGUE_TURN_V2).includes(status))
792
+ throw new Error(`Invalid initial status: ${status}`);
793
+ if (DIALOGUE_TERMINALS_V2.has(status))
794
+ throw new Error(`Cannot register in terminal status: ${status}`);
795
+ if (status === DIALOGUE_TURN_V2.PENDING) {
796
+ if (getPendingTurnCount(specId) >= _maxPendingTurnsPerSpecV2)
797
+ throw new Error(
798
+ `Spec ${specId} reached pending-turn cap (${_maxPendingTurnsPerSpecV2})`,
799
+ );
800
+ }
801
+ const now = _now();
802
+ const record = {
803
+ turnId,
804
+ specId,
805
+ role: role || "user",
806
+ question: question || "",
807
+ status,
808
+ metadata: metadata || {},
809
+ createdAt: now,
810
+ updatedAt: now,
811
+ };
812
+ _turnsV2.set(turnId, record);
813
+ return { ...record, metadata: { ...record.metadata } };
814
+ }
815
+
816
+ export function getDialogueTurnV2(turnId) {
817
+ const r = _turnsV2.get(turnId);
818
+ return r ? { ...r, metadata: { ...r.metadata } } : null;
819
+ }
820
+
821
+ export function setDialogueTurnStatusV2(_db, turnId, newStatus, patch = {}) {
822
+ const record = _turnsV2.get(turnId);
823
+ if (!record) throw new Error(`Unknown turn: ${turnId}`);
824
+ if (!Object.values(DIALOGUE_TURN_V2).includes(newStatus))
825
+ throw new Error(`Invalid status: ${newStatus}`);
826
+ const allowed = DIALOGUE_TRANSITIONS_V2.get(record.status) || new Set();
827
+ if (!allowed.has(newStatus))
828
+ throw new Error(`Invalid transition: ${record.status} -> ${newStatus}`);
829
+ record.status = newStatus;
830
+ record.updatedAt = _now();
831
+ if (patch.answer !== undefined) record.answer = patch.answer;
832
+ if (patch.reason !== undefined) record.lastReason = patch.reason;
833
+ if (patch.metadata)
834
+ record.metadata = { ...record.metadata, ...patch.metadata };
835
+ return { ...record, metadata: { ...record.metadata } };
836
+ }
837
+
838
+ export function answerTurn(db, id, answer, reason) {
839
+ return setDialogueTurnStatusV2(db, id, DIALOGUE_TURN_V2.ANSWERED, {
840
+ answer,
841
+ reason,
842
+ });
843
+ }
844
+ export function dismissTurn(db, id, reason) {
845
+ return setDialogueTurnStatusV2(db, id, DIALOGUE_TURN_V2.DISMISSED, {
846
+ reason,
847
+ });
848
+ }
849
+ export function escalateTurn(db, id, reason) {
850
+ return setDialogueTurnStatusV2(db, id, DIALOGUE_TURN_V2.ESCALATED, {
851
+ reason,
852
+ });
853
+ }
854
+
855
+ export function getActiveSpecCount(authorId) {
856
+ let n = 0;
857
+ for (const r of _specsV2.values()) {
858
+ if (!_isActiveSpec(r.status)) continue;
859
+ if (authorId && r.authorId !== authorId) continue;
860
+ n++;
861
+ }
862
+ return n;
863
+ }
864
+
865
+ export function getPendingTurnCount(specId) {
866
+ let n = 0;
867
+ for (const r of _turnsV2.values()) {
868
+ if (r.status !== DIALOGUE_TURN_V2.PENDING) continue;
869
+ if (specId && r.specId !== specId) continue;
870
+ n++;
871
+ }
872
+ return n;
873
+ }
874
+
875
+ export function autoArchiveIdleSpecs(_db, nowMs) {
876
+ const now = nowMs ?? _now();
877
+ const flipped = [];
878
+ for (const r of _specsV2.values()) {
879
+ if (
880
+ r.status === SPEC_MATURITY_V2.DRAFT ||
881
+ r.status === SPEC_MATURITY_V2.REFINING ||
882
+ r.status === SPEC_MATURITY_V2.APPROVED ||
883
+ r.status === SPEC_MATURITY_V2.IMPLEMENTED
884
+ ) {
885
+ if (now - r.lastActivityAt > _specIdleMsV2) {
886
+ r.status = SPEC_MATURITY_V2.ARCHIVED;
887
+ r.updatedAt = now;
888
+ r.lastReason = "idle";
889
+ flipped.push(r.specId);
890
+ }
891
+ }
892
+ }
893
+ return { flipped, count: flipped.length };
894
+ }
895
+
896
+ export function autoDismissStalePendingTurns(_db, nowMs) {
897
+ const now = nowMs ?? _now();
898
+ const flipped = [];
899
+ for (const r of _turnsV2.values()) {
900
+ if (r.status === DIALOGUE_TURN_V2.PENDING) {
901
+ if (now - r.createdAt > _turnPendingMsV2) {
902
+ r.status = DIALOGUE_TURN_V2.DISMISSED;
903
+ r.updatedAt = now;
904
+ r.lastReason = "pending_timeout";
905
+ flipped.push(r.turnId);
906
+ }
907
+ }
908
+ }
909
+ return { flipped, count: flipped.length };
910
+ }
911
+
912
+ export function getNlProgrammingStatsV2() {
913
+ const specsByStatus = {};
914
+ for (const s of Object.values(SPEC_MATURITY_V2)) specsByStatus[s] = 0;
915
+ const turnsByStatus = {};
916
+ for (const s of Object.values(DIALOGUE_TURN_V2)) turnsByStatus[s] = 0;
917
+ for (const r of _specsV2.values()) specsByStatus[r.status]++;
918
+ for (const r of _turnsV2.values()) turnsByStatus[r.status]++;
919
+ return {
920
+ totalSpecsV2: _specsV2.size,
921
+ totalTurnsV2: _turnsV2.size,
922
+ maxActiveSpecsPerAuthor: _maxActiveSpecsPerAuthorV2,
923
+ maxPendingTurnsPerSpec: _maxPendingTurnsPerSpecV2,
924
+ specIdleMs: _specIdleMsV2,
925
+ turnPendingMs: _turnPendingMsV2,
926
+ specsByStatus,
927
+ turnsByStatus,
928
+ };
929
+ }
930
+
931
+ export function _resetStateV2() {
932
+ _maxActiveSpecsPerAuthorV2 = NLPROG_DEFAULT_MAX_ACTIVE_SPECS_PER_AUTHOR;
933
+ _maxPendingTurnsPerSpecV2 = NLPROG_DEFAULT_MAX_PENDING_TURNS_PER_SPEC;
934
+ _specIdleMsV2 = NLPROG_DEFAULT_SPEC_IDLE_MS;
935
+ _turnPendingMsV2 = NLPROG_DEFAULT_TURN_PENDING_MS;
936
+ _specsV2.clear();
937
+ _turnsV2.clear();
938
+ }