chainlesschain 0.132.0 → 0.143.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 (106) hide show
  1. package/package.json +1 -1
  2. package/src/commands/a2a.js +62 -0
  3. package/src/commands/activitypub.js +61 -0
  4. package/src/commands/agent.js +117 -0
  5. package/src/commands/bi.js +61 -0
  6. package/src/commands/bm25.js +78 -0
  7. package/src/commands/browse.js +64 -0
  8. package/src/commands/ccron.js +78 -0
  9. package/src/commands/compliance.js +40 -0
  10. package/src/commands/compt.js +78 -0
  11. package/src/commands/consol.js +231 -0
  12. package/src/commands/cowork.js +42 -0
  13. package/src/commands/crosschain.js +62 -0
  14. package/src/commands/dao.js +62 -0
  15. package/src/commands/dlp.js +61 -0
  16. package/src/commands/economy.js +56 -0
  17. package/src/commands/evolution.js +56 -0
  18. package/src/commands/evomap.js +61 -0
  19. package/src/commands/fflag.js +178 -0
  20. package/src/commands/git.js +45 -0
  21. package/src/commands/hmemory.js +56 -0
  22. package/src/commands/inference.js +42 -0
  23. package/src/commands/itbudget.js +45 -0
  24. package/src/commands/lowcode.js +44 -0
  25. package/src/commands/matrix.js +62 -0
  26. package/src/commands/mcpscaf.js +41 -0
  27. package/src/commands/meminj.js +41 -0
  28. package/src/commands/nostr.js +62 -0
  29. package/src/commands/orchgov.js +45 -0
  30. package/src/commands/pdfp.js +78 -0
  31. package/src/commands/perf.js +39 -0
  32. package/src/commands/perm.js +45 -0
  33. package/src/commands/pipeline.js +57 -1
  34. package/src/commands/planmode.js +45 -0
  35. package/src/commands/promcomp.js +82 -0
  36. package/src/commands/recommend.js +42 -0
  37. package/src/commands/seshhook.js +41 -0
  38. package/src/commands/seshsearch.js +41 -0
  39. package/src/commands/seshtail.js +41 -0
  40. package/src/commands/seshu.js +41 -0
  41. package/src/commands/sganal.js +78 -0
  42. package/src/commands/siem.js +40 -0
  43. package/src/commands/slotfill.js +41 -0
  44. package/src/commands/social.js +34 -0
  45. package/src/commands/svccont.js +45 -0
  46. package/src/commands/tms.js +45 -0
  47. package/src/commands/topiccls.js +45 -0
  48. package/src/commands/uprof.js +45 -0
  49. package/src/commands/vcheck.js +78 -0
  50. package/src/commands/webfetch.js +41 -0
  51. package/src/commands/zkp.js +62 -0
  52. package/src/harness/prompt-compressor.js +331 -0
  53. package/src/index.js +61 -1
  54. package/src/lib/a2a-protocol.js +105 -0
  55. package/src/lib/activitypub-bridge.js +105 -0
  56. package/src/lib/agent-economy.js +105 -0
  57. package/src/lib/app-builder.js +105 -0
  58. package/src/lib/autonomous-agent.js +105 -0
  59. package/src/lib/bi-engine.js +105 -0
  60. package/src/lib/bm25-search.js +81 -0
  61. package/src/lib/browser-automation.js +105 -0
  62. package/src/lib/compliance-framework-reporter.js +105 -0
  63. package/src/lib/compression-telemetry.js +81 -0
  64. package/src/lib/content-recommender.js +105 -0
  65. package/src/lib/cowork-cron.js +81 -0
  66. package/src/lib/cowork-task-runner.js +105 -0
  67. package/src/lib/cross-chain.js +105 -0
  68. package/src/lib/dao-governance.js +105 -0
  69. package/src/lib/dlp-engine.js +105 -0
  70. package/src/lib/evolution-system.js +105 -0
  71. package/src/lib/evomap-manager.js +105 -0
  72. package/src/lib/execution-backend.js +105 -0
  73. package/src/lib/feature-flags.js +85 -0
  74. package/src/lib/git-integration.js +105 -0
  75. package/src/lib/hierarchical-memory.js +105 -0
  76. package/src/lib/inference-network.js +105 -0
  77. package/src/lib/iteration-budget.js +105 -0
  78. package/src/lib/matrix-bridge.js +105 -0
  79. package/src/lib/mcp-scaffold.js +81 -0
  80. package/src/lib/memory-injection.js +81 -0
  81. package/src/lib/nostr-bridge.js +105 -0
  82. package/src/lib/orchestrator.js +105 -0
  83. package/src/lib/pdf-parser.js +81 -0
  84. package/src/lib/perf-tuning.js +105 -0
  85. package/src/lib/permission-engine.js +81 -0
  86. package/src/lib/pipeline-orchestrator.js +105 -0
  87. package/src/lib/plan-mode.js +81 -0
  88. package/src/lib/prompt-compressor.js +1 -10
  89. package/src/lib/service-container.js +81 -0
  90. package/src/lib/session-consolidator.js +105 -0
  91. package/src/lib/session-hooks.js +81 -0
  92. package/src/lib/session-search.js +81 -0
  93. package/src/lib/session-tail.js +81 -0
  94. package/src/lib/session-usage.js +83 -0
  95. package/src/lib/siem-exporter.js +105 -0
  96. package/src/lib/slot-filler.js +81 -0
  97. package/src/lib/social-graph-analytics.js +81 -0
  98. package/src/lib/social-graph.js +81 -0
  99. package/src/lib/sub-agent-registry.js +110 -0
  100. package/src/lib/task-model-selector.js +81 -0
  101. package/src/lib/todo-manager.js +105 -0
  102. package/src/lib/topic-classifier.js +105 -0
  103. package/src/lib/user-profile.js +81 -0
  104. package/src/lib/version-checker.js +81 -0
  105. package/src/lib/web-fetch.js +81 -0
  106. package/src/lib/zkp-engine.js +105 -0
@@ -735,3 +735,108 @@ export function getInferenceStatsV2() {
735
735
  avgDurationMs: durCount > 0 ? Math.round(durSum / durCount) : 0,
736
736
  };
737
737
  }
738
+
739
+
740
+ // ===== V2 Surface: Inference Network governance overlay (CLI v0.139.0) =====
741
+ export const INFERENCE_NODE_MATURITY_V2 = Object.freeze({
742
+ PENDING: "pending", ACTIVE: "active", DEGRADED: "degraded", DECOMMISSIONED: "decommissioned",
743
+ });
744
+ export const INFERENCE_JOB_LIFECYCLE_V2 = Object.freeze({
745
+ QUEUED: "queued", RUNNING: "running", COMPLETED: "completed", FAILED: "failed", CANCELLED: "cancelled",
746
+ });
747
+
748
+ const _inTrans = new Map([
749
+ [INFERENCE_NODE_MATURITY_V2.PENDING, new Set([INFERENCE_NODE_MATURITY_V2.ACTIVE, INFERENCE_NODE_MATURITY_V2.DECOMMISSIONED])],
750
+ [INFERENCE_NODE_MATURITY_V2.ACTIVE, new Set([INFERENCE_NODE_MATURITY_V2.DEGRADED, INFERENCE_NODE_MATURITY_V2.DECOMMISSIONED])],
751
+ [INFERENCE_NODE_MATURITY_V2.DEGRADED, new Set([INFERENCE_NODE_MATURITY_V2.ACTIVE, INFERENCE_NODE_MATURITY_V2.DECOMMISSIONED])],
752
+ [INFERENCE_NODE_MATURITY_V2.DECOMMISSIONED, new Set()],
753
+ ]);
754
+ const _inTerminal = new Set([INFERENCE_NODE_MATURITY_V2.DECOMMISSIONED]);
755
+ const _ijTrans = new Map([
756
+ [INFERENCE_JOB_LIFECYCLE_V2.QUEUED, new Set([INFERENCE_JOB_LIFECYCLE_V2.RUNNING, INFERENCE_JOB_LIFECYCLE_V2.CANCELLED])],
757
+ [INFERENCE_JOB_LIFECYCLE_V2.RUNNING, new Set([INFERENCE_JOB_LIFECYCLE_V2.COMPLETED, INFERENCE_JOB_LIFECYCLE_V2.FAILED, INFERENCE_JOB_LIFECYCLE_V2.CANCELLED])],
758
+ [INFERENCE_JOB_LIFECYCLE_V2.COMPLETED, new Set()],
759
+ [INFERENCE_JOB_LIFECYCLE_V2.FAILED, new Set()],
760
+ [INFERENCE_JOB_LIFECYCLE_V2.CANCELLED, new Set()],
761
+ ]);
762
+
763
+ const _innV2 = new Map();
764
+ const _ijsV2 = new Map();
765
+ let _inMaxActivePerOperator = 12;
766
+ let _inMaxPendingJobsPerNode = 25;
767
+ let _inIdleMs = 24 * 60 * 60 * 1000;
768
+ let _ijStuckMs = 10 * 60 * 1000;
769
+
770
+ function _inPos(n, lbl) { const v = Math.floor(Number(n)); if (!Number.isFinite(v) || v <= 0) throw new Error(`${lbl} must be positive integer`); return v; }
771
+
772
+ export function setMaxActiveInferenceNodesPerOperatorV2(n) { _inMaxActivePerOperator = _inPos(n, "maxActiveInferenceNodesPerOperator"); }
773
+ export function getMaxActiveInferenceNodesPerOperatorV2() { return _inMaxActivePerOperator; }
774
+ export function setMaxPendingInferenceJobsPerNodeV2(n) { _inMaxPendingJobsPerNode = _inPos(n, "maxPendingInferenceJobsPerNode"); }
775
+ export function getMaxPendingInferenceJobsPerNodeV2() { return _inMaxPendingJobsPerNode; }
776
+ export function setInferenceNodeIdleMsV2(n) { _inIdleMs = _inPos(n, "inferenceNodeIdleMs"); }
777
+ export function getInferenceNodeIdleMsV2() { return _inIdleMs; }
778
+ export function setInferenceJobStuckMsV2(n) { _ijStuckMs = _inPos(n, "inferenceJobStuckMs"); }
779
+ export function getInferenceJobStuckMsV2() { return _ijStuckMs; }
780
+
781
+ export function _resetStateInferenceNetworkV2() {
782
+ _innV2.clear(); _ijsV2.clear();
783
+ _inMaxActivePerOperator = 12; _inMaxPendingJobsPerNode = 25;
784
+ _inIdleMs = 24 * 60 * 60 * 1000; _ijStuckMs = 10 * 60 * 1000;
785
+ }
786
+
787
+ export function registerInferenceNodeV2({ id, operator, model, metadata } = {}) {
788
+ if (!id || typeof id !== "string") throw new Error("id is required");
789
+ if (!operator || typeof operator !== "string") throw new Error("operator is required");
790
+ if (_innV2.has(id)) throw new Error(`inference node ${id} already registered`);
791
+ const now = Date.now();
792
+ const n = { id, operator, model: model || "default", status: INFERENCE_NODE_MATURITY_V2.PENDING, createdAt: now, updatedAt: now, activatedAt: null, decommissionedAt: null, lastTouchedAt: now, metadata: { ...(metadata || {}) } };
793
+ _innV2.set(id, n);
794
+ return { ...n, metadata: { ...n.metadata } };
795
+ }
796
+ function _inCheckN(from, to) { const a = _inTrans.get(from); if (!a || !a.has(to)) throw new Error(`invalid inference node transition ${from} → ${to}`); }
797
+ function _inCountActive(operator) { let n = 0; for (const x of _innV2.values()) if (x.operator === operator && x.status === INFERENCE_NODE_MATURITY_V2.ACTIVE) n++; return n; }
798
+
799
+ export function activateInferenceNodeV2(id) {
800
+ const n = _innV2.get(id); if (!n) throw new Error(`inference node ${id} not found`);
801
+ _inCheckN(n.status, INFERENCE_NODE_MATURITY_V2.ACTIVE);
802
+ const recovery = n.status === INFERENCE_NODE_MATURITY_V2.DEGRADED;
803
+ if (!recovery) { const c = _inCountActive(n.operator); if (c >= _inMaxActivePerOperator) throw new Error(`max active inference nodes per operator (${_inMaxActivePerOperator}) reached for ${n.operator}`); }
804
+ const now = Date.now(); n.status = INFERENCE_NODE_MATURITY_V2.ACTIVE; n.updatedAt = now; n.lastTouchedAt = now; if (!n.activatedAt) n.activatedAt = now;
805
+ return { ...n, metadata: { ...n.metadata } };
806
+ }
807
+ export function degradeInferenceNodeV2(id) { const n = _innV2.get(id); if (!n) throw new Error(`inference node ${id} not found`); _inCheckN(n.status, INFERENCE_NODE_MATURITY_V2.DEGRADED); n.status = INFERENCE_NODE_MATURITY_V2.DEGRADED; n.updatedAt = Date.now(); return { ...n, metadata: { ...n.metadata } }; }
808
+ export function decommissionInferenceNodeV2(id) { const n = _innV2.get(id); if (!n) throw new Error(`inference node ${id} not found`); _inCheckN(n.status, INFERENCE_NODE_MATURITY_V2.DECOMMISSIONED); const now = Date.now(); n.status = INFERENCE_NODE_MATURITY_V2.DECOMMISSIONED; n.updatedAt = now; if (!n.decommissionedAt) n.decommissionedAt = now; return { ...n, metadata: { ...n.metadata } }; }
809
+ export function touchInferenceNodeV2(id) { const n = _innV2.get(id); if (!n) throw new Error(`inference node ${id} not found`); if (_inTerminal.has(n.status)) throw new Error(`cannot touch terminal inference node ${id}`); const now = Date.now(); n.lastTouchedAt = now; n.updatedAt = now; return { ...n, metadata: { ...n.metadata } }; }
810
+ export function getInferenceNodeV2(id) { const n = _innV2.get(id); if (!n) return null; return { ...n, metadata: { ...n.metadata } }; }
811
+ export function listInferenceNodesV2() { return [..._innV2.values()].map((n) => ({ ...n, metadata: { ...n.metadata } })); }
812
+
813
+ function _ijCountPending(nodeId) { let n = 0; for (const j of _ijsV2.values()) if (j.nodeId === nodeId && (j.status === INFERENCE_JOB_LIFECYCLE_V2.QUEUED || j.status === INFERENCE_JOB_LIFECYCLE_V2.RUNNING)) n++; return n; }
814
+
815
+ export function createInferenceJobV2({ id, nodeId, prompt, metadata } = {}) {
816
+ if (!id || typeof id !== "string") throw new Error("id is required");
817
+ if (!nodeId || typeof nodeId !== "string") throw new Error("nodeId is required");
818
+ if (_ijsV2.has(id)) throw new Error(`inference job ${id} already exists`);
819
+ if (!_innV2.has(nodeId)) throw new Error(`inference node ${nodeId} not found`);
820
+ const pending = _ijCountPending(nodeId);
821
+ if (pending >= _inMaxPendingJobsPerNode) throw new Error(`max pending inference jobs per node (${_inMaxPendingJobsPerNode}) reached for ${nodeId}`);
822
+ const now = Date.now();
823
+ const j = { id, nodeId, prompt: prompt || "", status: INFERENCE_JOB_LIFECYCLE_V2.QUEUED, createdAt: now, updatedAt: now, startedAt: null, settledAt: null, metadata: { ...(metadata || {}) } };
824
+ _ijsV2.set(id, j);
825
+ return { ...j, metadata: { ...j.metadata } };
826
+ }
827
+ function _ijCheckJ(from, to) { const a = _ijTrans.get(from); if (!a || !a.has(to)) throw new Error(`invalid inference job transition ${from} → ${to}`); }
828
+ export function startInferenceJobV2(id) { const j = _ijsV2.get(id); if (!j) throw new Error(`inference job ${id} not found`); _ijCheckJ(j.status, INFERENCE_JOB_LIFECYCLE_V2.RUNNING); const now = Date.now(); j.status = INFERENCE_JOB_LIFECYCLE_V2.RUNNING; j.updatedAt = now; if (!j.startedAt) j.startedAt = now; return { ...j, metadata: { ...j.metadata } }; }
829
+ export function completeInferenceJobV2(id) { const j = _ijsV2.get(id); if (!j) throw new Error(`inference job ${id} not found`); _ijCheckJ(j.status, INFERENCE_JOB_LIFECYCLE_V2.COMPLETED); const now = Date.now(); j.status = INFERENCE_JOB_LIFECYCLE_V2.COMPLETED; j.updatedAt = now; if (!j.settledAt) j.settledAt = now; return { ...j, metadata: { ...j.metadata } }; }
830
+ export function failInferenceJobV2(id, reason) { const j = _ijsV2.get(id); if (!j) throw new Error(`inference job ${id} not found`); _ijCheckJ(j.status, INFERENCE_JOB_LIFECYCLE_V2.FAILED); const now = Date.now(); j.status = INFERENCE_JOB_LIFECYCLE_V2.FAILED; j.updatedAt = now; if (!j.settledAt) j.settledAt = now; if (reason) j.metadata.failReason = String(reason); return { ...j, metadata: { ...j.metadata } }; }
831
+ export function cancelInferenceJobV2(id, reason) { const j = _ijsV2.get(id); if (!j) throw new Error(`inference job ${id} not found`); _ijCheckJ(j.status, INFERENCE_JOB_LIFECYCLE_V2.CANCELLED); const now = Date.now(); j.status = INFERENCE_JOB_LIFECYCLE_V2.CANCELLED; j.updatedAt = now; if (!j.settledAt) j.settledAt = now; if (reason) j.metadata.cancelReason = String(reason); return { ...j, metadata: { ...j.metadata } }; }
832
+ export function getInferenceJobV2(id) { const j = _ijsV2.get(id); if (!j) return null; return { ...j, metadata: { ...j.metadata } }; }
833
+ export function listInferenceJobsV2() { return [..._ijsV2.values()].map((j) => ({ ...j, metadata: { ...j.metadata } })); }
834
+
835
+ export function autoDegradeIdleInferenceNodesV2({ now } = {}) { const t = now ?? Date.now(); const flipped = []; for (const n of _innV2.values()) if (n.status === INFERENCE_NODE_MATURITY_V2.ACTIVE && (t - n.lastTouchedAt) >= _inIdleMs) { n.status = INFERENCE_NODE_MATURITY_V2.DEGRADED; n.updatedAt = t; flipped.push(n.id); } return { flipped, count: flipped.length }; }
836
+ export function autoFailStuckInferenceJobsV2({ now } = {}) { const t = now ?? Date.now(); const flipped = []; for (const j of _ijsV2.values()) if (j.status === INFERENCE_JOB_LIFECYCLE_V2.RUNNING && j.startedAt != null && (t - j.startedAt) >= _ijStuckMs) { j.status = INFERENCE_JOB_LIFECYCLE_V2.FAILED; j.updatedAt = t; if (!j.settledAt) j.settledAt = t; j.metadata.failReason = "auto-fail-stuck"; flipped.push(j.id); } return { flipped, count: flipped.length }; }
837
+
838
+ export function getInferenceNetworkGovStatsV2() {
839
+ const nodesByStatus = {}; for (const s of Object.values(INFERENCE_NODE_MATURITY_V2)) nodesByStatus[s] = 0; for (const n of _innV2.values()) nodesByStatus[n.status]++;
840
+ const jobsByStatus = {}; for (const s of Object.values(INFERENCE_JOB_LIFECYCLE_V2)) jobsByStatus[s] = 0; for (const j of _ijsV2.values()) jobsByStatus[j.status]++;
841
+ return { totalInferenceNodesV2: _innV2.size, totalInferenceJobsV2: _ijsV2.size, maxActiveInferenceNodesPerOperator: _inMaxActivePerOperator, maxPendingInferenceJobsPerNode: _inMaxPendingJobsPerNode, inferenceNodeIdleMs: _inIdleMs, inferenceJobStuckMs: _ijStuckMs, nodesByStatus, jobsByStatus };
842
+ }
@@ -173,3 +173,108 @@ export class IterationBudget {
173
173
  export const DEFAULT_ITERATION_BUDGET = DEFAULT_BUDGET;
174
174
  export const BUDGET_WARNING_THRESHOLD = WARNING_THRESHOLD;
175
175
  export const BUDGET_WRAPPING_UP_THRESHOLD = WRAPPING_UP_THRESHOLD;
176
+
177
+
178
+ // ===== V2 Surface: Iteration Budget governance overlay (CLI v0.140.0) =====
179
+ export const ITER_BUDGET_PROFILE_MATURITY_V2 = Object.freeze({
180
+ PENDING: "pending", ACTIVE: "active", PAUSED: "paused", EXHAUSTED: "exhausted",
181
+ });
182
+ export const ITER_RUN_LIFECYCLE_V2 = Object.freeze({
183
+ QUEUED: "queued", RUNNING: "running", COMPLETED: "completed", FAILED: "failed", CANCELLED: "cancelled",
184
+ });
185
+
186
+ const _ibpTrans = new Map([
187
+ [ITER_BUDGET_PROFILE_MATURITY_V2.PENDING, new Set([ITER_BUDGET_PROFILE_MATURITY_V2.ACTIVE, ITER_BUDGET_PROFILE_MATURITY_V2.EXHAUSTED])],
188
+ [ITER_BUDGET_PROFILE_MATURITY_V2.ACTIVE, new Set([ITER_BUDGET_PROFILE_MATURITY_V2.PAUSED, ITER_BUDGET_PROFILE_MATURITY_V2.EXHAUSTED])],
189
+ [ITER_BUDGET_PROFILE_MATURITY_V2.PAUSED, new Set([ITER_BUDGET_PROFILE_MATURITY_V2.ACTIVE, ITER_BUDGET_PROFILE_MATURITY_V2.EXHAUSTED])],
190
+ [ITER_BUDGET_PROFILE_MATURITY_V2.EXHAUSTED, new Set()],
191
+ ]);
192
+ const _ibpTerminal = new Set([ITER_BUDGET_PROFILE_MATURITY_V2.EXHAUSTED]);
193
+ const _irTrans = new Map([
194
+ [ITER_RUN_LIFECYCLE_V2.QUEUED, new Set([ITER_RUN_LIFECYCLE_V2.RUNNING, ITER_RUN_LIFECYCLE_V2.CANCELLED])],
195
+ [ITER_RUN_LIFECYCLE_V2.RUNNING, new Set([ITER_RUN_LIFECYCLE_V2.COMPLETED, ITER_RUN_LIFECYCLE_V2.FAILED, ITER_RUN_LIFECYCLE_V2.CANCELLED])],
196
+ [ITER_RUN_LIFECYCLE_V2.COMPLETED, new Set()],
197
+ [ITER_RUN_LIFECYCLE_V2.FAILED, new Set()],
198
+ [ITER_RUN_LIFECYCLE_V2.CANCELLED, new Set()],
199
+ ]);
200
+
201
+ const _ibpsV2 = new Map();
202
+ const _irsV2 = new Map();
203
+ let _ibpMaxActivePerOwner = 4;
204
+ let _ibpMaxPendingRunsPerProfile = 8;
205
+ let _ibpIdleMs = 24 * 60 * 60 * 1000;
206
+ let _irStuckMs = 60 * 60 * 1000;
207
+
208
+ function _ibpPos(n, lbl) { const v = Math.floor(Number(n)); if (!Number.isFinite(v) || v <= 0) throw new Error(`${lbl} must be positive integer`); return v; }
209
+
210
+ export function setMaxActiveIterBudgetProfilesPerOwnerV2(n) { _ibpMaxActivePerOwner = _ibpPos(n, "maxActiveIterBudgetProfilesPerOwner"); }
211
+ export function getMaxActiveIterBudgetProfilesPerOwnerV2() { return _ibpMaxActivePerOwner; }
212
+ export function setMaxPendingIterRunsPerProfileV2(n) { _ibpMaxPendingRunsPerProfile = _ibpPos(n, "maxPendingIterRunsPerProfile"); }
213
+ export function getMaxPendingIterRunsPerProfileV2() { return _ibpMaxPendingRunsPerProfile; }
214
+ export function setIterBudgetProfileIdleMsV2(n) { _ibpIdleMs = _ibpPos(n, "iterBudgetProfileIdleMs"); }
215
+ export function getIterBudgetProfileIdleMsV2() { return _ibpIdleMs; }
216
+ export function setIterRunStuckMsV2(n) { _irStuckMs = _ibpPos(n, "iterRunStuckMs"); }
217
+ export function getIterRunStuckMsV2() { return _irStuckMs; }
218
+
219
+ export function _resetStateIterationBudgetV2() {
220
+ _ibpsV2.clear(); _irsV2.clear();
221
+ _ibpMaxActivePerOwner = 4; _ibpMaxPendingRunsPerProfile = 8;
222
+ _ibpIdleMs = 24 * 60 * 60 * 1000; _irStuckMs = 60 * 60 * 1000;
223
+ }
224
+
225
+ export function registerIterBudgetProfileV2({ id, owner, budget, metadata } = {}) {
226
+ if (!id || typeof id !== "string") throw new Error("id is required");
227
+ if (!owner || typeof owner !== "string") throw new Error("owner is required");
228
+ if (_ibpsV2.has(id)) throw new Error(`iter budget profile ${id} already registered`);
229
+ const now = Date.now();
230
+ const p = { id, owner, budget: budget || 50, status: ITER_BUDGET_PROFILE_MATURITY_V2.PENDING, createdAt: now, updatedAt: now, activatedAt: null, exhaustedAt: null, lastTouchedAt: now, metadata: { ...(metadata || {}) } };
231
+ _ibpsV2.set(id, p);
232
+ return { ...p, metadata: { ...p.metadata } };
233
+ }
234
+ function _ibpCheckP(from, to) { const a = _ibpTrans.get(from); if (!a || !a.has(to)) throw new Error(`invalid iter budget profile transition ${from} → ${to}`); }
235
+ function _ibpCountActive(owner) { let n = 0; for (const p of _ibpsV2.values()) if (p.owner === owner && p.status === ITER_BUDGET_PROFILE_MATURITY_V2.ACTIVE) n++; return n; }
236
+
237
+ export function activateIterBudgetProfileV2(id) {
238
+ const p = _ibpsV2.get(id); if (!p) throw new Error(`iter budget profile ${id} not found`);
239
+ _ibpCheckP(p.status, ITER_BUDGET_PROFILE_MATURITY_V2.ACTIVE);
240
+ const recovery = p.status === ITER_BUDGET_PROFILE_MATURITY_V2.PAUSED;
241
+ if (!recovery) { const c = _ibpCountActive(p.owner); if (c >= _ibpMaxActivePerOwner) throw new Error(`max active iter budget profiles per owner (${_ibpMaxActivePerOwner}) reached for ${p.owner}`); }
242
+ const now = Date.now(); p.status = ITER_BUDGET_PROFILE_MATURITY_V2.ACTIVE; p.updatedAt = now; p.lastTouchedAt = now; if (!p.activatedAt) p.activatedAt = now;
243
+ return { ...p, metadata: { ...p.metadata } };
244
+ }
245
+ export function pauseIterBudgetProfileV2(id) { const p = _ibpsV2.get(id); if (!p) throw new Error(`iter budget profile ${id} not found`); _ibpCheckP(p.status, ITER_BUDGET_PROFILE_MATURITY_V2.PAUSED); p.status = ITER_BUDGET_PROFILE_MATURITY_V2.PAUSED; p.updatedAt = Date.now(); return { ...p, metadata: { ...p.metadata } }; }
246
+ export function exhaustIterBudgetProfileV2(id) { const p = _ibpsV2.get(id); if (!p) throw new Error(`iter budget profile ${id} not found`); _ibpCheckP(p.status, ITER_BUDGET_PROFILE_MATURITY_V2.EXHAUSTED); const now = Date.now(); p.status = ITER_BUDGET_PROFILE_MATURITY_V2.EXHAUSTED; p.updatedAt = now; if (!p.exhaustedAt) p.exhaustedAt = now; return { ...p, metadata: { ...p.metadata } }; }
247
+ export function touchIterBudgetProfileV2(id) { const p = _ibpsV2.get(id); if (!p) throw new Error(`iter budget profile ${id} not found`); if (_ibpTerminal.has(p.status)) throw new Error(`cannot touch terminal iter budget profile ${id}`); const now = Date.now(); p.lastTouchedAt = now; p.updatedAt = now; return { ...p, metadata: { ...p.metadata } }; }
248
+ export function getIterBudgetProfileV2(id) { const p = _ibpsV2.get(id); if (!p) return null; return { ...p, metadata: { ...p.metadata } }; }
249
+ export function listIterBudgetProfilesV2() { return [..._ibpsV2.values()].map((p) => ({ ...p, metadata: { ...p.metadata } })); }
250
+
251
+ function _irCountPending(profileId) { let n = 0; for (const r of _irsV2.values()) if (r.profileId === profileId && (r.status === ITER_RUN_LIFECYCLE_V2.QUEUED || r.status === ITER_RUN_LIFECYCLE_V2.RUNNING)) n++; return n; }
252
+
253
+ export function createIterRunV2({ id, profileId, goal, metadata } = {}) {
254
+ if (!id || typeof id !== "string") throw new Error("id is required");
255
+ if (!profileId || typeof profileId !== "string") throw new Error("profileId is required");
256
+ if (_irsV2.has(id)) throw new Error(`iter run ${id} already exists`);
257
+ if (!_ibpsV2.has(profileId)) throw new Error(`iter budget profile ${profileId} not found`);
258
+ const pending = _irCountPending(profileId);
259
+ if (pending >= _ibpMaxPendingRunsPerProfile) throw new Error(`max pending iter runs per profile (${_ibpMaxPendingRunsPerProfile}) reached for ${profileId}`);
260
+ const now = Date.now();
261
+ const r = { id, profileId, goal: goal || "", status: ITER_RUN_LIFECYCLE_V2.QUEUED, createdAt: now, updatedAt: now, startedAt: null, settledAt: null, metadata: { ...(metadata || {}) } };
262
+ _irsV2.set(id, r);
263
+ return { ...r, metadata: { ...r.metadata } };
264
+ }
265
+ function _irCheckR(from, to) { const a = _irTrans.get(from); if (!a || !a.has(to)) throw new Error(`invalid iter run transition ${from} → ${to}`); }
266
+ export function startIterRunV2(id) { const r = _irsV2.get(id); if (!r) throw new Error(`iter run ${id} not found`); _irCheckR(r.status, ITER_RUN_LIFECYCLE_V2.RUNNING); const now = Date.now(); r.status = ITER_RUN_LIFECYCLE_V2.RUNNING; r.updatedAt = now; if (!r.startedAt) r.startedAt = now; return { ...r, metadata: { ...r.metadata } }; }
267
+ export function completeIterRunV2(id) { const r = _irsV2.get(id); if (!r) throw new Error(`iter run ${id} not found`); _irCheckR(r.status, ITER_RUN_LIFECYCLE_V2.COMPLETED); const now = Date.now(); r.status = ITER_RUN_LIFECYCLE_V2.COMPLETED; r.updatedAt = now; if (!r.settledAt) r.settledAt = now; return { ...r, metadata: { ...r.metadata } }; }
268
+ export function failIterRunV2(id, reason) { const r = _irsV2.get(id); if (!r) throw new Error(`iter run ${id} not found`); _irCheckR(r.status, ITER_RUN_LIFECYCLE_V2.FAILED); const now = Date.now(); r.status = ITER_RUN_LIFECYCLE_V2.FAILED; r.updatedAt = now; if (!r.settledAt) r.settledAt = now; if (reason) r.metadata.failReason = String(reason); return { ...r, metadata: { ...r.metadata } }; }
269
+ export function cancelIterRunV2(id, reason) { const r = _irsV2.get(id); if (!r) throw new Error(`iter run ${id} not found`); _irCheckR(r.status, ITER_RUN_LIFECYCLE_V2.CANCELLED); const now = Date.now(); r.status = ITER_RUN_LIFECYCLE_V2.CANCELLED; r.updatedAt = now; if (!r.settledAt) r.settledAt = now; if (reason) r.metadata.cancelReason = String(reason); return { ...r, metadata: { ...r.metadata } }; }
270
+ export function getIterRunV2(id) { const r = _irsV2.get(id); if (!r) return null; return { ...r, metadata: { ...r.metadata } }; }
271
+ export function listIterRunsV2() { return [..._irsV2.values()].map((r) => ({ ...r, metadata: { ...r.metadata } })); }
272
+
273
+ export function autoPauseIdleIterBudgetProfilesV2({ now } = {}) { const t = now ?? Date.now(); const flipped = []; for (const p of _ibpsV2.values()) if (p.status === ITER_BUDGET_PROFILE_MATURITY_V2.ACTIVE && (t - p.lastTouchedAt) >= _ibpIdleMs) { p.status = ITER_BUDGET_PROFILE_MATURITY_V2.PAUSED; p.updatedAt = t; flipped.push(p.id); } return { flipped, count: flipped.length }; }
274
+ export function autoFailStuckIterRunsV2({ now } = {}) { const t = now ?? Date.now(); const flipped = []; for (const r of _irsV2.values()) if (r.status === ITER_RUN_LIFECYCLE_V2.RUNNING && r.startedAt != null && (t - r.startedAt) >= _irStuckMs) { r.status = ITER_RUN_LIFECYCLE_V2.FAILED; r.updatedAt = t; if (!r.settledAt) r.settledAt = t; r.metadata.failReason = "auto-fail-stuck"; flipped.push(r.id); } return { flipped, count: flipped.length }; }
275
+
276
+ export function getIterationBudgetGovStatsV2() {
277
+ const profilesByStatus = {}; for (const s of Object.values(ITER_BUDGET_PROFILE_MATURITY_V2)) profilesByStatus[s] = 0; for (const p of _ibpsV2.values()) profilesByStatus[p.status]++;
278
+ const runsByStatus = {}; for (const s of Object.values(ITER_RUN_LIFECYCLE_V2)) runsByStatus[s] = 0; for (const r of _irsV2.values()) runsByStatus[r.status]++;
279
+ return { totalIterBudgetProfilesV2: _ibpsV2.size, totalIterRunsV2: _irsV2.size, maxActiveIterBudgetProfilesPerOwner: _ibpMaxActivePerOwner, maxPendingIterRunsPerProfile: _ibpMaxPendingRunsPerProfile, iterBudgetProfileIdleMs: _ibpIdleMs, iterRunStuckMs: _irStuckMs, profilesByStatus, runsByStatus };
280
+ }
@@ -446,3 +446,108 @@ export function _resetState() {
446
446
  e2eeEnabled: true,
447
447
  };
448
448
  }
449
+
450
+
451
+ // ===== V2 Surface: Matrix Bridge governance overlay (CLI v0.134.0) =====
452
+ export const MX_ROOM_MATURITY_V2 = Object.freeze({
453
+ PENDING: "pending", ACTIVE: "active", MUTED: "muted", ARCHIVED: "archived",
454
+ });
455
+ export const MX_MESSAGE_LIFECYCLE_V2 = Object.freeze({
456
+ QUEUED: "queued", SENDING: "sending", DELIVERED: "delivered", FAILED: "failed", CANCELLED: "cancelled",
457
+ });
458
+
459
+ const _mxRoomTrans = new Map([
460
+ [MX_ROOM_MATURITY_V2.PENDING, new Set([MX_ROOM_MATURITY_V2.ACTIVE, MX_ROOM_MATURITY_V2.ARCHIVED])],
461
+ [MX_ROOM_MATURITY_V2.ACTIVE, new Set([MX_ROOM_MATURITY_V2.MUTED, MX_ROOM_MATURITY_V2.ARCHIVED])],
462
+ [MX_ROOM_MATURITY_V2.MUTED, new Set([MX_ROOM_MATURITY_V2.ACTIVE, MX_ROOM_MATURITY_V2.ARCHIVED])],
463
+ [MX_ROOM_MATURITY_V2.ARCHIVED, new Set()],
464
+ ]);
465
+ const _mxRoomTerminal = new Set([MX_ROOM_MATURITY_V2.ARCHIVED]);
466
+ const _mxMsgTrans = new Map([
467
+ [MX_MESSAGE_LIFECYCLE_V2.QUEUED, new Set([MX_MESSAGE_LIFECYCLE_V2.SENDING, MX_MESSAGE_LIFECYCLE_V2.CANCELLED])],
468
+ [MX_MESSAGE_LIFECYCLE_V2.SENDING, new Set([MX_MESSAGE_LIFECYCLE_V2.DELIVERED, MX_MESSAGE_LIFECYCLE_V2.FAILED, MX_MESSAGE_LIFECYCLE_V2.CANCELLED])],
469
+ [MX_MESSAGE_LIFECYCLE_V2.DELIVERED, new Set()],
470
+ [MX_MESSAGE_LIFECYCLE_V2.FAILED, new Set()],
471
+ [MX_MESSAGE_LIFECYCLE_V2.CANCELLED, new Set()],
472
+ ]);
473
+
474
+ const _mxRooms = new Map();
475
+ const _mxMsgs = new Map();
476
+ let _mxMaxActivePerOwner = 20;
477
+ let _mxMaxPendingPerRoom = 40;
478
+ let _mxRoomIdleMs = 24 * 60 * 60 * 1000;
479
+ let _mxMsgStuckMs = 3 * 60 * 1000;
480
+
481
+ function _mxPos(n, lbl) { const v = Math.floor(Number(n)); if (!Number.isFinite(v) || v <= 0) throw new Error(`${lbl} must be positive integer`); return v; }
482
+
483
+ export function setMaxActiveMatrixRoomsPerOwnerV2(n) { _mxMaxActivePerOwner = _mxPos(n, "maxActiveMatrixRoomsPerOwner"); }
484
+ export function getMaxActiveMatrixRoomsPerOwnerV2() { return _mxMaxActivePerOwner; }
485
+ export function setMaxPendingMatrixMessagesPerRoomV2(n) { _mxMaxPendingPerRoom = _mxPos(n, "maxPendingMatrixMessagesPerRoom"); }
486
+ export function getMaxPendingMatrixMessagesPerRoomV2() { return _mxMaxPendingPerRoom; }
487
+ export function setMatrixRoomIdleMsV2(n) { _mxRoomIdleMs = _mxPos(n, "matrixRoomIdleMs"); }
488
+ export function getMatrixRoomIdleMsV2() { return _mxRoomIdleMs; }
489
+ export function setMatrixMessageStuckMsV2(n) { _mxMsgStuckMs = _mxPos(n, "matrixMessageStuckMs"); }
490
+ export function getMatrixMessageStuckMsV2() { return _mxMsgStuckMs; }
491
+
492
+ export function _resetStateMatrixBridgeV2() {
493
+ _mxRooms.clear(); _mxMsgs.clear();
494
+ _mxMaxActivePerOwner = 20; _mxMaxPendingPerRoom = 40;
495
+ _mxRoomIdleMs = 24 * 60 * 60 * 1000; _mxMsgStuckMs = 3 * 60 * 1000;
496
+ }
497
+
498
+ export function registerMatrixRoomV2({ id, owner, alias, metadata } = {}) {
499
+ if (!id || typeof id !== "string") throw new Error("id is required");
500
+ if (!owner || typeof owner !== "string") throw new Error("owner is required");
501
+ if (_mxRooms.has(id)) throw new Error(`matrix room ${id} already registered`);
502
+ const now = Date.now();
503
+ const r = { id, owner, alias: alias || id, status: MX_ROOM_MATURITY_V2.PENDING, createdAt: now, updatedAt: now, activatedAt: null, archivedAt: null, lastTouchedAt: now, metadata: { ...(metadata || {}) } };
504
+ _mxRooms.set(id, r);
505
+ return { ...r, metadata: { ...r.metadata } };
506
+ }
507
+ function _mxCheckR(from, to) { const a = _mxRoomTrans.get(from); if (!a || !a.has(to)) throw new Error(`invalid matrix room transition ${from} → ${to}`); }
508
+ function _mxCountActive(owner) { let n = 0; for (const r of _mxRooms.values()) if (r.owner === owner && r.status === MX_ROOM_MATURITY_V2.ACTIVE) n++; return n; }
509
+
510
+ export function activateMatrixRoomV2(id) {
511
+ const r = _mxRooms.get(id); if (!r) throw new Error(`matrix room ${id} not found`);
512
+ _mxCheckR(r.status, MX_ROOM_MATURITY_V2.ACTIVE);
513
+ const recovery = r.status === MX_ROOM_MATURITY_V2.MUTED;
514
+ if (!recovery) { const a = _mxCountActive(r.owner); if (a >= _mxMaxActivePerOwner) throw new Error(`max active matrix rooms per owner (${_mxMaxActivePerOwner}) reached for ${r.owner}`); }
515
+ const now = Date.now(); r.status = MX_ROOM_MATURITY_V2.ACTIVE; r.updatedAt = now; r.lastTouchedAt = now; if (!r.activatedAt) r.activatedAt = now;
516
+ return { ...r, metadata: { ...r.metadata } };
517
+ }
518
+ export function muteMatrixRoomV2(id) { const r = _mxRooms.get(id); if (!r) throw new Error(`matrix room ${id} not found`); _mxCheckR(r.status, MX_ROOM_MATURITY_V2.MUTED); r.status = MX_ROOM_MATURITY_V2.MUTED; r.updatedAt = Date.now(); return { ...r, metadata: { ...r.metadata } }; }
519
+ export function archiveMatrixRoomV2(id) { const r = _mxRooms.get(id); if (!r) throw new Error(`matrix room ${id} not found`); _mxCheckR(r.status, MX_ROOM_MATURITY_V2.ARCHIVED); const now = Date.now(); r.status = MX_ROOM_MATURITY_V2.ARCHIVED; r.updatedAt = now; if (!r.archivedAt) r.archivedAt = now; return { ...r, metadata: { ...r.metadata } }; }
520
+ export function touchMatrixRoomV2(id) { const r = _mxRooms.get(id); if (!r) throw new Error(`matrix room ${id} not found`); if (_mxRoomTerminal.has(r.status)) throw new Error(`cannot touch terminal matrix room ${id}`); const now = Date.now(); r.lastTouchedAt = now; r.updatedAt = now; return { ...r, metadata: { ...r.metadata } }; }
521
+ export function getMatrixRoomV2(id) { const r = _mxRooms.get(id); if (!r) return null; return { ...r, metadata: { ...r.metadata } }; }
522
+ export function listMatrixRoomsV2() { return [..._mxRooms.values()].map((r) => ({ ...r, metadata: { ...r.metadata } })); }
523
+
524
+ function _mxCountPending(rid) { let n = 0; for (const m of _mxMsgs.values()) if (m.roomId === rid && (m.status === MX_MESSAGE_LIFECYCLE_V2.QUEUED || m.status === MX_MESSAGE_LIFECYCLE_V2.SENDING)) n++; return n; }
525
+
526
+ export function createMatrixMessageV2({ id, roomId, body, metadata } = {}) {
527
+ if (!id || typeof id !== "string") throw new Error("id is required");
528
+ if (!roomId || typeof roomId !== "string") throw new Error("roomId is required");
529
+ if (_mxMsgs.has(id)) throw new Error(`matrix message ${id} already exists`);
530
+ if (!_mxRooms.has(roomId)) throw new Error(`matrix room ${roomId} not found`);
531
+ const pending = _mxCountPending(roomId);
532
+ if (pending >= _mxMaxPendingPerRoom) throw new Error(`max pending matrix messages per room (${_mxMaxPendingPerRoom}) reached for ${roomId}`);
533
+ const now = Date.now();
534
+ const m = { id, roomId, body: body || "", status: MX_MESSAGE_LIFECYCLE_V2.QUEUED, createdAt: now, updatedAt: now, startedAt: null, settledAt: null, metadata: { ...(metadata || {}) } };
535
+ _mxMsgs.set(id, m);
536
+ return { ...m, metadata: { ...m.metadata } };
537
+ }
538
+ function _mxCheckM(from, to) { const a = _mxMsgTrans.get(from); if (!a || !a.has(to)) throw new Error(`invalid matrix message transition ${from} → ${to}`); }
539
+ export function startMatrixMessageV2(id) { const m = _mxMsgs.get(id); if (!m) throw new Error(`matrix message ${id} not found`); _mxCheckM(m.status, MX_MESSAGE_LIFECYCLE_V2.SENDING); const now = Date.now(); m.status = MX_MESSAGE_LIFECYCLE_V2.SENDING; m.updatedAt = now; if (!m.startedAt) m.startedAt = now; return { ...m, metadata: { ...m.metadata } }; }
540
+ export function deliverMatrixMessageV2(id) { const m = _mxMsgs.get(id); if (!m) throw new Error(`matrix message ${id} not found`); _mxCheckM(m.status, MX_MESSAGE_LIFECYCLE_V2.DELIVERED); const now = Date.now(); m.status = MX_MESSAGE_LIFECYCLE_V2.DELIVERED; m.updatedAt = now; if (!m.settledAt) m.settledAt = now; return { ...m, metadata: { ...m.metadata } }; }
541
+ export function failMatrixMessageV2(id, reason) { const m = _mxMsgs.get(id); if (!m) throw new Error(`matrix message ${id} not found`); _mxCheckM(m.status, MX_MESSAGE_LIFECYCLE_V2.FAILED); const now = Date.now(); m.status = MX_MESSAGE_LIFECYCLE_V2.FAILED; m.updatedAt = now; if (!m.settledAt) m.settledAt = now; if (reason) m.metadata.failReason = String(reason); return { ...m, metadata: { ...m.metadata } }; }
542
+ export function cancelMatrixMessageV2(id, reason) { const m = _mxMsgs.get(id); if (!m) throw new Error(`matrix message ${id} not found`); _mxCheckM(m.status, MX_MESSAGE_LIFECYCLE_V2.CANCELLED); const now = Date.now(); m.status = MX_MESSAGE_LIFECYCLE_V2.CANCELLED; m.updatedAt = now; if (!m.settledAt) m.settledAt = now; if (reason) m.metadata.cancelReason = String(reason); return { ...m, metadata: { ...m.metadata } }; }
543
+ export function getMatrixMessageV2(id) { const m = _mxMsgs.get(id); if (!m) return null; return { ...m, metadata: { ...m.metadata } }; }
544
+ export function listMatrixMessagesV2() { return [..._mxMsgs.values()].map((m) => ({ ...m, metadata: { ...m.metadata } })); }
545
+
546
+ export function autoMuteIdleMatrixRoomsV2({ now } = {}) { const t = now ?? Date.now(); const flipped = []; for (const r of _mxRooms.values()) if (r.status === MX_ROOM_MATURITY_V2.ACTIVE && (t - r.lastTouchedAt) >= _mxRoomIdleMs) { r.status = MX_ROOM_MATURITY_V2.MUTED; r.updatedAt = t; flipped.push(r.id); } return { flipped, count: flipped.length }; }
547
+ export function autoFailStuckMatrixMessagesV2({ now } = {}) { const t = now ?? Date.now(); const flipped = []; for (const m of _mxMsgs.values()) if (m.status === MX_MESSAGE_LIFECYCLE_V2.SENDING && m.startedAt != null && (t - m.startedAt) >= _mxMsgStuckMs) { m.status = MX_MESSAGE_LIFECYCLE_V2.FAILED; m.updatedAt = t; if (!m.settledAt) m.settledAt = t; m.metadata.failReason = "auto-fail-stuck"; flipped.push(m.id); } return { flipped, count: flipped.length }; }
548
+
549
+ export function getMatrixBridgeStatsV2() {
550
+ const roomsByStatus = {}; for (const s of Object.values(MX_ROOM_MATURITY_V2)) roomsByStatus[s] = 0; for (const r of _mxRooms.values()) roomsByStatus[r.status]++;
551
+ const msgsByStatus = {}; for (const s of Object.values(MX_MESSAGE_LIFECYCLE_V2)) msgsByStatus[s] = 0; for (const m of _mxMsgs.values()) msgsByStatus[m.status]++;
552
+ return { totalRoomsV2: _mxRooms.size, totalMessagesV2: _mxMsgs.size, maxActiveMatrixRoomsPerOwner: _mxMaxActivePerOwner, maxPendingMatrixMessagesPerRoom: _mxMaxPendingPerRoom, matrixRoomIdleMs: _mxRoomIdleMs, matrixMessageStuckMs: _mxMsgStuckMs, roomsByStatus, msgsByStatus };
553
+ }
@@ -383,3 +383,84 @@ function renderGitignore() {
383
383
  !.env.example
384
384
  `;
385
385
  }
386
+
387
+ // ===== V2 Surface: MCP Scaffold governance overlay (CLI v0.142.0) =====
388
+ export const MSCAF_PROFILE_MATURITY_V2 = Object.freeze({
389
+ PENDING: "pending", ACTIVE: "active", STALE: "stale", ARCHIVED: "archived",
390
+ });
391
+ export const MSCAF_GENERATION_LIFECYCLE_V2 = Object.freeze({
392
+ QUEUED: "queued", GENERATING: "generating", GENERATED: "generated", FAILED: "failed", CANCELLED: "cancelled",
393
+ });
394
+ const _mscafPTrans = new Map([
395
+ [MSCAF_PROFILE_MATURITY_V2.PENDING, new Set([MSCAF_PROFILE_MATURITY_V2.ACTIVE, MSCAF_PROFILE_MATURITY_V2.ARCHIVED])],
396
+ [MSCAF_PROFILE_MATURITY_V2.ACTIVE, new Set([MSCAF_PROFILE_MATURITY_V2.STALE, MSCAF_PROFILE_MATURITY_V2.ARCHIVED])],
397
+ [MSCAF_PROFILE_MATURITY_V2.STALE, new Set([MSCAF_PROFILE_MATURITY_V2.ACTIVE, MSCAF_PROFILE_MATURITY_V2.ARCHIVED])],
398
+ [MSCAF_PROFILE_MATURITY_V2.ARCHIVED, new Set()],
399
+ ]);
400
+ const _mscafPTerminal = new Set([MSCAF_PROFILE_MATURITY_V2.ARCHIVED]);
401
+ const _mscafGTrans = new Map([
402
+ [MSCAF_GENERATION_LIFECYCLE_V2.QUEUED, new Set([MSCAF_GENERATION_LIFECYCLE_V2.GENERATING, MSCAF_GENERATION_LIFECYCLE_V2.CANCELLED])],
403
+ [MSCAF_GENERATION_LIFECYCLE_V2.GENERATING, new Set([MSCAF_GENERATION_LIFECYCLE_V2.GENERATED, MSCAF_GENERATION_LIFECYCLE_V2.FAILED, MSCAF_GENERATION_LIFECYCLE_V2.CANCELLED])],
404
+ [MSCAF_GENERATION_LIFECYCLE_V2.GENERATED, new Set()],
405
+ [MSCAF_GENERATION_LIFECYCLE_V2.FAILED, new Set()],
406
+ [MSCAF_GENERATION_LIFECYCLE_V2.CANCELLED, new Set()],
407
+ ]);
408
+ const _mscafPsV2 = new Map();
409
+ const _mscafGsV2 = new Map();
410
+ let _mscafMaxActive = 6, _mscafMaxPending = 15, _mscafIdleMs = 30 * 24 * 60 * 60 * 1000, _mscafStuckMs = 60 * 1000;
411
+ function _mscafPos(n, label) { const v = Math.floor(Number(n)); if (!Number.isFinite(v) || v <= 0) throw new Error(`${label} must be positive integer`); return v; }
412
+ function _mscafCheckP(from, to) { const a = _mscafPTrans.get(from); if (!a || !a.has(to)) throw new Error(`invalid mscaf profile transition ${from} → ${to}`); }
413
+ function _mscafCheckG(from, to) { const a = _mscafGTrans.get(from); if (!a || !a.has(to)) throw new Error(`invalid mscaf generation transition ${from} → ${to}`); }
414
+ export function setMaxActiveMscafProfilesPerOwnerV2(n) { _mscafMaxActive = _mscafPos(n, "maxActiveMscafProfilesPerOwner"); }
415
+ export function getMaxActiveMscafProfilesPerOwnerV2() { return _mscafMaxActive; }
416
+ export function setMaxPendingMscafGenerationsPerProfileV2(n) { _mscafMaxPending = _mscafPos(n, "maxPendingMscafGenerationsPerProfile"); }
417
+ export function getMaxPendingMscafGenerationsPerProfileV2() { return _mscafMaxPending; }
418
+ export function setMscafProfileIdleMsV2(n) { _mscafIdleMs = _mscafPos(n, "mscafProfileIdleMs"); }
419
+ export function getMscafProfileIdleMsV2() { return _mscafIdleMs; }
420
+ export function setMscafGenerationStuckMsV2(n) { _mscafStuckMs = _mscafPos(n, "mscafGenerationStuckMs"); }
421
+ export function getMscafGenerationStuckMsV2() { return _mscafStuckMs; }
422
+ export function _resetStateMcpScaffoldV2() { _mscafPsV2.clear(); _mscafGsV2.clear(); _mscafMaxActive = 6; _mscafMaxPending = 15; _mscafIdleMs = 30 * 24 * 60 * 60 * 1000; _mscafStuckMs = 60 * 1000; }
423
+ export function registerMscafProfileV2({ id, owner, transport, metadata } = {}) {
424
+ if (!id) throw new Error("mscaf profile id required"); if (!owner) throw new Error("mscaf profile owner required");
425
+ if (_mscafPsV2.has(id)) throw new Error(`mscaf profile ${id} already registered`);
426
+ const now = Date.now();
427
+ const p = { id, owner, transport: transport || "stdio", status: MSCAF_PROFILE_MATURITY_V2.PENDING, createdAt: now, updatedAt: now, activatedAt: null, archivedAt: null, lastTouchedAt: now, metadata: { ...(metadata || {}) } };
428
+ _mscafPsV2.set(id, p); return { ...p, metadata: { ...p.metadata } };
429
+ }
430
+ function _mscafCountActive(owner) { let n = 0; for (const p of _mscafPsV2.values()) if (p.owner === owner && p.status === MSCAF_PROFILE_MATURITY_V2.ACTIVE) n++; return n; }
431
+ export function activateMscafProfileV2(id) {
432
+ const p = _mscafPsV2.get(id); if (!p) throw new Error(`mscaf profile ${id} not found`);
433
+ _mscafCheckP(p.status, MSCAF_PROFILE_MATURITY_V2.ACTIVE);
434
+ const recovery = p.status === MSCAF_PROFILE_MATURITY_V2.STALE;
435
+ if (!recovery && _mscafCountActive(p.owner) >= _mscafMaxActive) throw new Error(`max active mscaf profiles for owner ${p.owner} reached`);
436
+ const now = Date.now(); p.status = MSCAF_PROFILE_MATURITY_V2.ACTIVE; p.updatedAt = now; p.lastTouchedAt = now; if (!p.activatedAt) p.activatedAt = now;
437
+ return { ...p, metadata: { ...p.metadata } };
438
+ }
439
+ export function staleMscafProfileV2(id) { const p = _mscafPsV2.get(id); if (!p) throw new Error(`mscaf profile ${id} not found`); _mscafCheckP(p.status, MSCAF_PROFILE_MATURITY_V2.STALE); p.status = MSCAF_PROFILE_MATURITY_V2.STALE; p.updatedAt = Date.now(); return { ...p, metadata: { ...p.metadata } }; }
440
+ export function archiveMscafProfileV2(id) { const p = _mscafPsV2.get(id); if (!p) throw new Error(`mscaf profile ${id} not found`); _mscafCheckP(p.status, MSCAF_PROFILE_MATURITY_V2.ARCHIVED); const now = Date.now(); p.status = MSCAF_PROFILE_MATURITY_V2.ARCHIVED; p.updatedAt = now; if (!p.archivedAt) p.archivedAt = now; return { ...p, metadata: { ...p.metadata } }; }
441
+ export function touchMscafProfileV2(id) { const p = _mscafPsV2.get(id); if (!p) throw new Error(`mscaf profile ${id} not found`); if (_mscafPTerminal.has(p.status)) throw new Error(`cannot touch terminal mscaf profile ${id}`); const now = Date.now(); p.lastTouchedAt = now; p.updatedAt = now; return { ...p, metadata: { ...p.metadata } }; }
442
+ export function getMscafProfileV2(id) { const p = _mscafPsV2.get(id); if (!p) return null; return { ...p, metadata: { ...p.metadata } }; }
443
+ export function listMscafProfilesV2() { return [..._mscafPsV2.values()].map((p) => ({ ...p, metadata: { ...p.metadata } })); }
444
+ function _mscafCountPending(profileId) { let n = 0; for (const g of _mscafGsV2.values()) if (g.profileId === profileId && (g.status === MSCAF_GENERATION_LIFECYCLE_V2.QUEUED || g.status === MSCAF_GENERATION_LIFECYCLE_V2.GENERATING)) n++; return n; }
445
+ export function createMscafGenerationV2({ id, profileId, target, metadata } = {}) {
446
+ if (!id) throw new Error("mscaf generation id required"); if (!profileId) throw new Error("mscaf generation profileId required");
447
+ if (_mscafGsV2.has(id)) throw new Error(`mscaf generation ${id} already exists`);
448
+ if (!_mscafPsV2.has(profileId)) throw new Error(`mscaf profile ${profileId} not found`);
449
+ if (_mscafCountPending(profileId) >= _mscafMaxPending) throw new Error(`max pending mscaf generations for profile ${profileId} reached`);
450
+ const now = Date.now();
451
+ const g = { id, profileId, target: target || "", status: MSCAF_GENERATION_LIFECYCLE_V2.QUEUED, createdAt: now, updatedAt: now, startedAt: null, settledAt: null, metadata: { ...(metadata || {}) } };
452
+ _mscafGsV2.set(id, g); return { ...g, metadata: { ...g.metadata } };
453
+ }
454
+ export function generatingMscafGenerationV2(id) { const g = _mscafGsV2.get(id); if (!g) throw new Error(`mscaf generation ${id} not found`); _mscafCheckG(g.status, MSCAF_GENERATION_LIFECYCLE_V2.GENERATING); const now = Date.now(); g.status = MSCAF_GENERATION_LIFECYCLE_V2.GENERATING; g.updatedAt = now; if (!g.startedAt) g.startedAt = now; return { ...g, metadata: { ...g.metadata } }; }
455
+ export function generateMscafGenerationV2(id) { const g = _mscafGsV2.get(id); if (!g) throw new Error(`mscaf generation ${id} not found`); _mscafCheckG(g.status, MSCAF_GENERATION_LIFECYCLE_V2.GENERATED); const now = Date.now(); g.status = MSCAF_GENERATION_LIFECYCLE_V2.GENERATED; g.updatedAt = now; if (!g.settledAt) g.settledAt = now; return { ...g, metadata: { ...g.metadata } }; }
456
+ export function failMscafGenerationV2(id, reason) { const g = _mscafGsV2.get(id); if (!g) throw new Error(`mscaf generation ${id} not found`); _mscafCheckG(g.status, MSCAF_GENERATION_LIFECYCLE_V2.FAILED); const now = Date.now(); g.status = MSCAF_GENERATION_LIFECYCLE_V2.FAILED; g.updatedAt = now; if (!g.settledAt) g.settledAt = now; if (reason) g.metadata.failReason = String(reason); return { ...g, metadata: { ...g.metadata } }; }
457
+ export function cancelMscafGenerationV2(id, reason) { const g = _mscafGsV2.get(id); if (!g) throw new Error(`mscaf generation ${id} not found`); _mscafCheckG(g.status, MSCAF_GENERATION_LIFECYCLE_V2.CANCELLED); const now = Date.now(); g.status = MSCAF_GENERATION_LIFECYCLE_V2.CANCELLED; g.updatedAt = now; if (!g.settledAt) g.settledAt = now; if (reason) g.metadata.cancelReason = String(reason); return { ...g, metadata: { ...g.metadata } }; }
458
+ export function getMscafGenerationV2(id) { const g = _mscafGsV2.get(id); if (!g) return null; return { ...g, metadata: { ...g.metadata } }; }
459
+ export function listMscafGenerationsV2() { return [..._mscafGsV2.values()].map((g) => ({ ...g, metadata: { ...g.metadata } })); }
460
+ export function autoStaleIdleMscafProfilesV2({ now } = {}) { const t = now ?? Date.now(); const flipped = []; for (const p of _mscafPsV2.values()) if (p.status === MSCAF_PROFILE_MATURITY_V2.ACTIVE && (t - p.lastTouchedAt) >= _mscafIdleMs) { p.status = MSCAF_PROFILE_MATURITY_V2.STALE; p.updatedAt = t; flipped.push(p.id); } return { flipped, count: flipped.length }; }
461
+ export function autoFailStuckMscafGenerationsV2({ now } = {}) { const t = now ?? Date.now(); const flipped = []; for (const g of _mscafGsV2.values()) if (g.status === MSCAF_GENERATION_LIFECYCLE_V2.GENERATING && g.startedAt != null && (t - g.startedAt) >= _mscafStuckMs) { g.status = MSCAF_GENERATION_LIFECYCLE_V2.FAILED; g.updatedAt = t; if (!g.settledAt) g.settledAt = t; g.metadata.failReason = "auto-fail-stuck"; flipped.push(g.id); } return { flipped, count: flipped.length }; }
462
+ export function getMcpScaffoldGovStatsV2() {
463
+ const profilesByStatus = {}; for (const v of Object.values(MSCAF_PROFILE_MATURITY_V2)) profilesByStatus[v] = 0; for (const p of _mscafPsV2.values()) profilesByStatus[p.status]++;
464
+ const generationsByStatus = {}; for (const v of Object.values(MSCAF_GENERATION_LIFECYCLE_V2)) generationsByStatus[v] = 0; for (const g of _mscafGsV2.values()) generationsByStatus[g.status]++;
465
+ return { totalMscafProfilesV2: _mscafPsV2.size, totalMscafGenerationsV2: _mscafGsV2.size, maxActiveMscafProfilesPerOwner: _mscafMaxActive, maxPendingMscafGenerationsPerProfile: _mscafMaxPending, mscafProfileIdleMs: _mscafIdleMs, mscafGenerationStuckMs: _mscafStuckMs, profilesByStatus, generationsByStatus };
466
+ }
@@ -88,3 +88,84 @@ export function buildMemoryInjection(options = {}) {
88
88
  });
89
89
  return content ? { role: "system", content, count: memories.length } : null;
90
90
  }
91
+
92
+ // ===== V2 Surface: Memory Injection governance overlay (CLI v0.142.0) =====
93
+ export const MINJ_RULE_MATURITY_V2 = Object.freeze({
94
+ PENDING: "pending", ACTIVE: "active", PAUSED: "paused", ARCHIVED: "archived",
95
+ });
96
+ export const MINJ_INJECTION_LIFECYCLE_V2 = Object.freeze({
97
+ QUEUED: "queued", INJECTING: "injecting", APPLIED: "applied", FAILED: "failed", CANCELLED: "cancelled",
98
+ });
99
+ const _minjRTrans = new Map([
100
+ [MINJ_RULE_MATURITY_V2.PENDING, new Set([MINJ_RULE_MATURITY_V2.ACTIVE, MINJ_RULE_MATURITY_V2.ARCHIVED])],
101
+ [MINJ_RULE_MATURITY_V2.ACTIVE, new Set([MINJ_RULE_MATURITY_V2.PAUSED, MINJ_RULE_MATURITY_V2.ARCHIVED])],
102
+ [MINJ_RULE_MATURITY_V2.PAUSED, new Set([MINJ_RULE_MATURITY_V2.ACTIVE, MINJ_RULE_MATURITY_V2.ARCHIVED])],
103
+ [MINJ_RULE_MATURITY_V2.ARCHIVED, new Set()],
104
+ ]);
105
+ const _minjRTerminal = new Set([MINJ_RULE_MATURITY_V2.ARCHIVED]);
106
+ const _minjITrans = new Map([
107
+ [MINJ_INJECTION_LIFECYCLE_V2.QUEUED, new Set([MINJ_INJECTION_LIFECYCLE_V2.INJECTING, MINJ_INJECTION_LIFECYCLE_V2.CANCELLED])],
108
+ [MINJ_INJECTION_LIFECYCLE_V2.INJECTING, new Set([MINJ_INJECTION_LIFECYCLE_V2.APPLIED, MINJ_INJECTION_LIFECYCLE_V2.FAILED, MINJ_INJECTION_LIFECYCLE_V2.CANCELLED])],
109
+ [MINJ_INJECTION_LIFECYCLE_V2.APPLIED, new Set()],
110
+ [MINJ_INJECTION_LIFECYCLE_V2.FAILED, new Set()],
111
+ [MINJ_INJECTION_LIFECYCLE_V2.CANCELLED, new Set()],
112
+ ]);
113
+ const _minjRsV2 = new Map();
114
+ const _minjIsV2 = new Map();
115
+ let _minjMaxActive = 10, _minjMaxPending = 25, _minjIdleMs = 30 * 24 * 60 * 60 * 1000, _minjStuckMs = 30 * 1000;
116
+ function _minjPos(n, label) { const v = Math.floor(Number(n)); if (!Number.isFinite(v) || v <= 0) throw new Error(`${label} must be positive integer`); return v; }
117
+ function _minjCheckR(from, to) { const a = _minjRTrans.get(from); if (!a || !a.has(to)) throw new Error(`invalid minj rule transition ${from} → ${to}`); }
118
+ function _minjCheckI(from, to) { const a = _minjITrans.get(from); if (!a || !a.has(to)) throw new Error(`invalid minj injection transition ${from} → ${to}`); }
119
+ export function setMaxActiveMinjRulesPerOwnerV2(n) { _minjMaxActive = _minjPos(n, "maxActiveMinjRulesPerOwner"); }
120
+ export function getMaxActiveMinjRulesPerOwnerV2() { return _minjMaxActive; }
121
+ export function setMaxPendingMinjInjectionsPerRuleV2(n) { _minjMaxPending = _minjPos(n, "maxPendingMinjInjectionsPerRule"); }
122
+ export function getMaxPendingMinjInjectionsPerRuleV2() { return _minjMaxPending; }
123
+ export function setMinjRuleIdleMsV2(n) { _minjIdleMs = _minjPos(n, "minjRuleIdleMs"); }
124
+ export function getMinjRuleIdleMsV2() { return _minjIdleMs; }
125
+ export function setMinjInjectionStuckMsV2(n) { _minjStuckMs = _minjPos(n, "minjInjectionStuckMs"); }
126
+ export function getMinjInjectionStuckMsV2() { return _minjStuckMs; }
127
+ export function _resetStateMemoryInjectionV2() { _minjRsV2.clear(); _minjIsV2.clear(); _minjMaxActive = 10; _minjMaxPending = 25; _minjIdleMs = 30 * 24 * 60 * 60 * 1000; _minjStuckMs = 30 * 1000; }
128
+ export function registerMinjRuleV2({ id, owner, scope, metadata } = {}) {
129
+ if (!id) throw new Error("minj rule id required"); if (!owner) throw new Error("minj rule owner required");
130
+ if (_minjRsV2.has(id)) throw new Error(`minj rule ${id} already registered`);
131
+ const now = Date.now();
132
+ const r = { id, owner, scope: scope || "*", status: MINJ_RULE_MATURITY_V2.PENDING, createdAt: now, updatedAt: now, activatedAt: null, archivedAt: null, lastTouchedAt: now, metadata: { ...(metadata || {}) } };
133
+ _minjRsV2.set(id, r); return { ...r, metadata: { ...r.metadata } };
134
+ }
135
+ function _minjCountActive(owner) { let n = 0; for (const r of _minjRsV2.values()) if (r.owner === owner && r.status === MINJ_RULE_MATURITY_V2.ACTIVE) n++; return n; }
136
+ export function activateMinjRuleV2(id) {
137
+ const r = _minjRsV2.get(id); if (!r) throw new Error(`minj rule ${id} not found`);
138
+ _minjCheckR(r.status, MINJ_RULE_MATURITY_V2.ACTIVE);
139
+ const recovery = r.status === MINJ_RULE_MATURITY_V2.PAUSED;
140
+ if (!recovery && _minjCountActive(r.owner) >= _minjMaxActive) throw new Error(`max active minj rules for owner ${r.owner} reached`);
141
+ const now = Date.now(); r.status = MINJ_RULE_MATURITY_V2.ACTIVE; r.updatedAt = now; r.lastTouchedAt = now; if (!r.activatedAt) r.activatedAt = now;
142
+ return { ...r, metadata: { ...r.metadata } };
143
+ }
144
+ export function pauseMinjRuleV2(id) { const r = _minjRsV2.get(id); if (!r) throw new Error(`minj rule ${id} not found`); _minjCheckR(r.status, MINJ_RULE_MATURITY_V2.PAUSED); r.status = MINJ_RULE_MATURITY_V2.PAUSED; r.updatedAt = Date.now(); return { ...r, metadata: { ...r.metadata } }; }
145
+ export function archiveMinjRuleV2(id) { const r = _minjRsV2.get(id); if (!r) throw new Error(`minj rule ${id} not found`); _minjCheckR(r.status, MINJ_RULE_MATURITY_V2.ARCHIVED); const now = Date.now(); r.status = MINJ_RULE_MATURITY_V2.ARCHIVED; r.updatedAt = now; if (!r.archivedAt) r.archivedAt = now; return { ...r, metadata: { ...r.metadata } }; }
146
+ export function touchMinjRuleV2(id) { const r = _minjRsV2.get(id); if (!r) throw new Error(`minj rule ${id} not found`); if (_minjRTerminal.has(r.status)) throw new Error(`cannot touch terminal minj rule ${id}`); const now = Date.now(); r.lastTouchedAt = now; r.updatedAt = now; return { ...r, metadata: { ...r.metadata } }; }
147
+ export function getMinjRuleV2(id) { const r = _minjRsV2.get(id); if (!r) return null; return { ...r, metadata: { ...r.metadata } }; }
148
+ export function listMinjRulesV2() { return [..._minjRsV2.values()].map((r) => ({ ...r, metadata: { ...r.metadata } })); }
149
+ function _minjCountPending(ruleId) { let n = 0; for (const i of _minjIsV2.values()) if (i.ruleId === ruleId && (i.status === MINJ_INJECTION_LIFECYCLE_V2.QUEUED || i.status === MINJ_INJECTION_LIFECYCLE_V2.INJECTING)) n++; return n; }
150
+ export function createMinjInjectionV2({ id, ruleId, payload, metadata } = {}) {
151
+ if (!id) throw new Error("minj injection id required"); if (!ruleId) throw new Error("minj injection ruleId required");
152
+ if (_minjIsV2.has(id)) throw new Error(`minj injection ${id} already exists`);
153
+ if (!_minjRsV2.has(ruleId)) throw new Error(`minj rule ${ruleId} not found`);
154
+ if (_minjCountPending(ruleId) >= _minjMaxPending) throw new Error(`max pending minj injections for rule ${ruleId} reached`);
155
+ const now = Date.now();
156
+ const i = { id, ruleId, payload: payload || "", status: MINJ_INJECTION_LIFECYCLE_V2.QUEUED, createdAt: now, updatedAt: now, startedAt: null, settledAt: null, metadata: { ...(metadata || {}) } };
157
+ _minjIsV2.set(id, i); return { ...i, metadata: { ...i.metadata } };
158
+ }
159
+ export function injectingMinjInjectionV2(id) { const i = _minjIsV2.get(id); if (!i) throw new Error(`minj injection ${id} not found`); _minjCheckI(i.status, MINJ_INJECTION_LIFECYCLE_V2.INJECTING); const now = Date.now(); i.status = MINJ_INJECTION_LIFECYCLE_V2.INJECTING; i.updatedAt = now; if (!i.startedAt) i.startedAt = now; return { ...i, metadata: { ...i.metadata } }; }
160
+ export function applyMinjInjectionV2(id) { const i = _minjIsV2.get(id); if (!i) throw new Error(`minj injection ${id} not found`); _minjCheckI(i.status, MINJ_INJECTION_LIFECYCLE_V2.APPLIED); const now = Date.now(); i.status = MINJ_INJECTION_LIFECYCLE_V2.APPLIED; i.updatedAt = now; if (!i.settledAt) i.settledAt = now; return { ...i, metadata: { ...i.metadata } }; }
161
+ export function failMinjInjectionV2(id, reason) { const i = _minjIsV2.get(id); if (!i) throw new Error(`minj injection ${id} not found`); _minjCheckI(i.status, MINJ_INJECTION_LIFECYCLE_V2.FAILED); const now = Date.now(); i.status = MINJ_INJECTION_LIFECYCLE_V2.FAILED; i.updatedAt = now; if (!i.settledAt) i.settledAt = now; if (reason) i.metadata.failReason = String(reason); return { ...i, metadata: { ...i.metadata } }; }
162
+ export function cancelMinjInjectionV2(id, reason) { const i = _minjIsV2.get(id); if (!i) throw new Error(`minj injection ${id} not found`); _minjCheckI(i.status, MINJ_INJECTION_LIFECYCLE_V2.CANCELLED); const now = Date.now(); i.status = MINJ_INJECTION_LIFECYCLE_V2.CANCELLED; i.updatedAt = now; if (!i.settledAt) i.settledAt = now; if (reason) i.metadata.cancelReason = String(reason); return { ...i, metadata: { ...i.metadata } }; }
163
+ export function getMinjInjectionV2(id) { const i = _minjIsV2.get(id); if (!i) return null; return { ...i, metadata: { ...i.metadata } }; }
164
+ export function listMinjInjectionsV2() { return [..._minjIsV2.values()].map((i) => ({ ...i, metadata: { ...i.metadata } })); }
165
+ export function autoPauseIdleMinjRulesV2({ now } = {}) { const t = now ?? Date.now(); const flipped = []; for (const r of _minjRsV2.values()) if (r.status === MINJ_RULE_MATURITY_V2.ACTIVE && (t - r.lastTouchedAt) >= _minjIdleMs) { r.status = MINJ_RULE_MATURITY_V2.PAUSED; r.updatedAt = t; flipped.push(r.id); } return { flipped, count: flipped.length }; }
166
+ export function autoFailStuckMinjInjectionsV2({ now } = {}) { const t = now ?? Date.now(); const flipped = []; for (const i of _minjIsV2.values()) if (i.status === MINJ_INJECTION_LIFECYCLE_V2.INJECTING && i.startedAt != null && (t - i.startedAt) >= _minjStuckMs) { i.status = MINJ_INJECTION_LIFECYCLE_V2.FAILED; i.updatedAt = t; if (!i.settledAt) i.settledAt = t; i.metadata.failReason = "auto-fail-stuck"; flipped.push(i.id); } return { flipped, count: flipped.length }; }
167
+ export function getMemoryInjectionGovStatsV2() {
168
+ const rulesByStatus = {}; for (const v of Object.values(MINJ_RULE_MATURITY_V2)) rulesByStatus[v] = 0; for (const r of _minjRsV2.values()) rulesByStatus[r.status]++;
169
+ const injectionsByStatus = {}; for (const v of Object.values(MINJ_INJECTION_LIFECYCLE_V2)) injectionsByStatus[v] = 0; for (const i of _minjIsV2.values()) injectionsByStatus[i.status]++;
170
+ return { totalMinjRulesV2: _minjRsV2.size, totalMinjInjectionsV2: _minjIsV2.size, maxActiveMinjRulesPerOwner: _minjMaxActive, maxPendingMinjInjectionsPerRule: _minjMaxPending, minjRuleIdleMs: _minjIdleMs, minjInjectionStuckMs: _minjStuckMs, rulesByStatus, injectionsByStatus };
171
+ }