chainlesschain 0.81.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 (209) hide show
  1. package/bin/chainlesschain.js +0 -0
  2. package/package.json +1 -1
  3. package/src/commands/a2a.js +62 -0
  4. package/src/commands/activitypub.js +61 -0
  5. package/src/commands/agent-network.js +254 -1
  6. package/src/commands/agent.js +117 -0
  7. package/src/commands/audit.js +302 -0
  8. package/src/commands/automation.js +271 -1
  9. package/src/commands/bi.js +61 -0
  10. package/src/commands/bm25.js +78 -0
  11. package/src/commands/browse.js +64 -0
  12. package/src/commands/ccron.js +78 -0
  13. package/src/commands/codegen.js +224 -0
  14. package/src/commands/collab.js +341 -0
  15. package/src/commands/compliance.js +1075 -0
  16. package/src/commands/compt.js +78 -0
  17. package/src/commands/consol.js +231 -0
  18. package/src/commands/cowork.js +263 -0
  19. package/src/commands/crosschain.js +62 -0
  20. package/src/commands/dao.js +62 -0
  21. package/src/commands/dbevo.js +284 -0
  22. package/src/commands/dev.js +252 -0
  23. package/src/commands/did.js +358 -0
  24. package/src/commands/dlp.js +61 -0
  25. package/src/commands/economy.js +56 -0
  26. package/src/commands/encrypt.js +341 -0
  27. package/src/commands/evolution.js +56 -0
  28. package/src/commands/evomap.js +61 -0
  29. package/src/commands/export.js +256 -1
  30. package/src/commands/fflag.js +178 -0
  31. package/src/commands/fusion.js +258 -0
  32. package/src/commands/git.js +45 -0
  33. package/src/commands/governance.js +325 -0
  34. package/src/commands/hardening.js +411 -0
  35. package/src/commands/hmemory.js +56 -0
  36. package/src/commands/hook.js +148 -0
  37. package/src/commands/import.js +252 -0
  38. package/src/commands/incentive.js +322 -0
  39. package/src/commands/inference.js +42 -0
  40. package/src/commands/infra.js +244 -0
  41. package/src/commands/instinct.js +260 -0
  42. package/src/commands/ipfs.js +318 -0
  43. package/src/commands/itbudget.js +45 -0
  44. package/src/commands/kg.js +387 -0
  45. package/src/commands/llm.js +263 -0
  46. package/src/commands/lowcode.js +44 -0
  47. package/src/commands/matrix.js +62 -0
  48. package/src/commands/mcp.js +221 -0
  49. package/src/commands/mcpscaf.js +41 -0
  50. package/src/commands/meminj.js +41 -0
  51. package/src/commands/memory.js +248 -0
  52. package/src/commands/multimodal.js +296 -0
  53. package/src/commands/nlprog.js +356 -0
  54. package/src/commands/nostr.js +62 -0
  55. package/src/commands/note.js +244 -0
  56. package/src/commands/ops.js +354 -0
  57. package/src/commands/orchestrate.js +166 -0
  58. package/src/commands/orchgov.js +45 -0
  59. package/src/commands/org.js +277 -0
  60. package/src/commands/p2p.js +390 -0
  61. package/src/commands/pdfp.js +78 -0
  62. package/src/commands/perception.js +290 -0
  63. package/src/commands/perf.js +39 -0
  64. package/src/commands/perm.js +45 -0
  65. package/src/commands/permmem.js +251 -0
  66. package/src/commands/pipeline.js +57 -1
  67. package/src/commands/planmode.js +45 -0
  68. package/src/commands/plugin-ecosystem.js +273 -0
  69. package/src/commands/pqc.js +393 -0
  70. package/src/commands/promcomp.js +82 -0
  71. package/src/commands/quantization.js +351 -0
  72. package/src/commands/rcache.js +271 -0
  73. package/src/commands/recommend.js +382 -0
  74. package/src/commands/runtime.js +307 -0
  75. package/src/commands/scim.js +262 -0
  76. package/src/commands/seshhook.js +41 -0
  77. package/src/commands/seshsearch.js +41 -0
  78. package/src/commands/seshtail.js +41 -0
  79. package/src/commands/seshu.js +41 -0
  80. package/src/commands/session.js +258 -0
  81. package/src/commands/sganal.js +78 -0
  82. package/src/commands/siem.js +40 -0
  83. package/src/commands/skill.js +267 -1
  84. package/src/commands/slotfill.js +41 -0
  85. package/src/commands/social.js +290 -0
  86. package/src/commands/sso.js +186 -1
  87. package/src/commands/svccont.js +45 -0
  88. package/src/commands/sync.js +256 -0
  89. package/src/commands/tech.js +338 -0
  90. package/src/commands/tenant.js +351 -0
  91. package/src/commands/tms.js +45 -0
  92. package/src/commands/tokens.js +269 -0
  93. package/src/commands/topiccls.js +45 -0
  94. package/src/commands/trust.js +249 -0
  95. package/src/commands/uprof.js +45 -0
  96. package/src/commands/vcheck.js +78 -0
  97. package/src/commands/wallet.js +277 -0
  98. package/src/commands/webfetch.js +41 -0
  99. package/src/commands/workflow.js +171 -0
  100. package/src/commands/zkp.js +62 -0
  101. package/src/harness/prompt-compressor.js +331 -0
  102. package/src/index.js +65 -1
  103. package/src/lib/a2a-protocol.js +105 -0
  104. package/src/lib/activitypub-bridge.js +105 -0
  105. package/src/lib/agent-coordinator.js +325 -0
  106. package/src/lib/agent-economy.js +105 -0
  107. package/src/lib/agent-network.js +387 -0
  108. package/src/lib/agent-router.js +395 -0
  109. package/src/lib/aiops.js +478 -0
  110. package/src/lib/app-builder.js +105 -0
  111. package/src/lib/audit-logger.js +379 -0
  112. package/src/lib/automation-engine.js +330 -0
  113. package/src/lib/autonomous-agent.js +105 -0
  114. package/src/lib/autonomous-developer.js +350 -0
  115. package/src/lib/bi-engine.js +105 -0
  116. package/src/lib/bm25-search.js +81 -0
  117. package/src/lib/browser-automation.js +105 -0
  118. package/src/lib/code-agent.js +323 -0
  119. package/src/lib/collaboration-governance.js +364 -0
  120. package/src/lib/community-governance.js +436 -0
  121. package/src/lib/compliance-framework-reporter.js +105 -0
  122. package/src/lib/compliance-manager.js +434 -0
  123. package/src/lib/compression-telemetry.js +81 -0
  124. package/src/lib/content-recommendation.js +469 -0
  125. package/src/lib/content-recommender.js +105 -0
  126. package/src/lib/cowork-cron.js +81 -0
  127. package/src/lib/cowork-task-runner.js +105 -0
  128. package/src/lib/cross-chain.js +105 -0
  129. package/src/lib/crypto-manager.js +350 -0
  130. package/src/lib/dao-governance.js +105 -0
  131. package/src/lib/dbevo.js +338 -0
  132. package/src/lib/decentral-infra.js +340 -0
  133. package/src/lib/did-manager.js +367 -0
  134. package/src/lib/dlp-engine.js +105 -0
  135. package/src/lib/evolution-system.js +105 -0
  136. package/src/lib/evomap-manager.js +105 -0
  137. package/src/lib/execution-backend.js +105 -0
  138. package/src/lib/feature-flags.js +85 -0
  139. package/src/lib/git-integration.js +105 -0
  140. package/src/lib/hardening-manager.js +348 -0
  141. package/src/lib/hierarchical-memory.js +105 -0
  142. package/src/lib/hook-manager.js +380 -0
  143. package/src/lib/inference-network.js +105 -0
  144. package/src/lib/instinct-manager.js +332 -0
  145. package/src/lib/ipfs-storage.js +334 -0
  146. package/src/lib/iteration-budget.js +105 -0
  147. package/src/lib/knowledge-exporter.js +381 -0
  148. package/src/lib/knowledge-graph.js +432 -0
  149. package/src/lib/knowledge-importer.js +379 -0
  150. package/src/lib/llm-providers.js +391 -0
  151. package/src/lib/matrix-bridge.js +105 -0
  152. package/src/lib/mcp-registry.js +333 -0
  153. package/src/lib/mcp-scaffold.js +81 -0
  154. package/src/lib/memory-injection.js +81 -0
  155. package/src/lib/memory-manager.js +330 -0
  156. package/src/lib/multimodal.js +346 -0
  157. package/src/lib/nl-programming.js +343 -0
  158. package/src/lib/nostr-bridge.js +105 -0
  159. package/src/lib/note-versioning.js +327 -0
  160. package/src/lib/orchestrator.js +105 -0
  161. package/src/lib/org-manager.js +323 -0
  162. package/src/lib/p2p-manager.js +387 -0
  163. package/src/lib/pdf-parser.js +81 -0
  164. package/src/lib/perception.js +346 -0
  165. package/src/lib/perf-tuning.js +109 -1
  166. package/src/lib/permanent-memory.js +320 -0
  167. package/src/lib/permission-engine.js +81 -0
  168. package/src/lib/pipeline-orchestrator.js +105 -0
  169. package/src/lib/plan-mode.js +81 -0
  170. package/src/lib/plugin-ecosystem.js +377 -0
  171. package/src/lib/pqc-manager.js +368 -0
  172. package/src/lib/prompt-compressor.js +1 -10
  173. package/src/lib/protocol-fusion.js +417 -0
  174. package/src/lib/quantization.js +325 -0
  175. package/src/lib/response-cache.js +327 -0
  176. package/src/lib/scim-manager.js +329 -0
  177. package/src/lib/service-container.js +81 -0
  178. package/src/lib/session-consolidator.js +105 -0
  179. package/src/lib/session-hooks.js +81 -0
  180. package/src/lib/session-manager.js +329 -0
  181. package/src/lib/session-search.js +81 -0
  182. package/src/lib/session-tail.js +81 -0
  183. package/src/lib/session-usage.js +83 -0
  184. package/src/lib/siem-exporter.js +105 -0
  185. package/src/lib/skill-loader.js +377 -0
  186. package/src/lib/slot-filler.js +81 -0
  187. package/src/lib/social-graph-analytics.js +81 -0
  188. package/src/lib/social-graph.js +81 -0
  189. package/src/lib/social-manager.js +326 -0
  190. package/src/lib/sso-manager.js +332 -0
  191. package/src/lib/sub-agent-registry.js +110 -0
  192. package/src/lib/sync-manager.js +326 -0
  193. package/src/lib/task-model-selector.js +81 -0
  194. package/src/lib/tech-learning-engine.js +369 -0
  195. package/src/lib/tenant-saas.js +460 -0
  196. package/src/lib/threat-intel.js +335 -0
  197. package/src/lib/todo-manager.js +105 -0
  198. package/src/lib/token-incentive.js +293 -0
  199. package/src/lib/token-tracker.js +329 -0
  200. package/src/lib/topic-classifier.js +105 -0
  201. package/src/lib/trust-security.js +390 -0
  202. package/src/lib/ueba.js +389 -0
  203. package/src/lib/universal-runtime.js +325 -0
  204. package/src/lib/user-profile.js +81 -0
  205. package/src/lib/version-checker.js +81 -0
  206. package/src/lib/wallet-manager.js +326 -0
  207. package/src/lib/web-fetch.js +81 -0
  208. package/src/lib/workflow-engine.js +322 -0
  209. package/src/lib/zkp-engine.js +105 -0
@@ -210,3 +210,332 @@ export function _resetState() {
210
210
  _connectors.clear();
211
211
  _syncLog.length = 0;
212
212
  }
213
+
214
+ /* ═══════════════════════════════════════════════════════════════
215
+ * V2 Surface — SCIM provisioning lifecycle layer.
216
+ * Tracks identities and sync-job lifecycle independent of legacy
217
+ * createUser/syncProvision flows above.
218
+ * ═══════════════════════════════════════════════════════════════ */
219
+
220
+ export const IDENTITY_LIFECYCLE_V2 = Object.freeze({
221
+ PENDING: "pending",
222
+ PROVISIONED: "provisioned",
223
+ SUSPENDED: "suspended",
224
+ DEPROVISIONED: "deprovisioned",
225
+ });
226
+
227
+ export const SYNC_JOB_V2 = Object.freeze({
228
+ QUEUED: "queued",
229
+ RUNNING: "running",
230
+ SUCCEEDED: "succeeded",
231
+ FAILED: "failed",
232
+ CANCELLED: "cancelled",
233
+ });
234
+
235
+ const IDENTITY_TRANSITIONS_V2 = new Map([
236
+ ["pending", new Set(["provisioned", "deprovisioned"])],
237
+ ["provisioned", new Set(["suspended", "deprovisioned"])],
238
+ ["suspended", new Set(["provisioned", "deprovisioned"])],
239
+ ["deprovisioned", new Set()],
240
+ ]);
241
+ const IDENTITY_TERMINALS_V2 = new Set(["deprovisioned"]);
242
+
243
+ const SYNC_TRANSITIONS_V2 = new Map([
244
+ ["queued", new Set(["running", "cancelled"])],
245
+ ["running", new Set(["succeeded", "failed", "cancelled"])],
246
+ ["succeeded", new Set()],
247
+ ["failed", new Set()],
248
+ ["cancelled", new Set()],
249
+ ]);
250
+ const SYNC_TERMINALS_V2 = new Set(["succeeded", "failed", "cancelled"]);
251
+
252
+ export const SCIM_DEFAULT_MAX_PROVISIONED_PER_CONNECTOR = 1000;
253
+ export const SCIM_DEFAULT_MAX_RUNNING_SYNC_PER_CONNECTOR = 2;
254
+ export const SCIM_DEFAULT_IDENTITY_IDLE_MS = 1000 * 60 * 60 * 24 * 90; // 90 days
255
+ export const SCIM_DEFAULT_SYNC_STUCK_MS = 1000 * 60 * 30; // 30 min
256
+
257
+ const _identitiesV2 = new Map();
258
+ const _syncJobsV2 = new Map();
259
+ let _maxProvisionedPerConnectorV2 = SCIM_DEFAULT_MAX_PROVISIONED_PER_CONNECTOR;
260
+ let _maxRunningSyncPerConnectorV2 = SCIM_DEFAULT_MAX_RUNNING_SYNC_PER_CONNECTOR;
261
+ let _identityIdleMsV2 = SCIM_DEFAULT_IDENTITY_IDLE_MS;
262
+ let _syncStuckMsV2 = SCIM_DEFAULT_SYNC_STUCK_MS;
263
+
264
+ function _posIntScimV2(n, label) {
265
+ const v = Math.floor(Number(n));
266
+ if (!Number.isFinite(v) || v <= 0)
267
+ throw new Error(`${label} must be a positive integer`);
268
+ return v;
269
+ }
270
+
271
+ export function getMaxProvisionedPerConnectorV2() {
272
+ return _maxProvisionedPerConnectorV2;
273
+ }
274
+ export function setMaxProvisionedPerConnectorV2(n) {
275
+ _maxProvisionedPerConnectorV2 = _posIntScimV2(
276
+ n,
277
+ "maxProvisionedPerConnector",
278
+ );
279
+ }
280
+ export function getMaxRunningSyncPerConnectorV2() {
281
+ return _maxRunningSyncPerConnectorV2;
282
+ }
283
+ export function setMaxRunningSyncPerConnectorV2(n) {
284
+ _maxRunningSyncPerConnectorV2 = _posIntScimV2(
285
+ n,
286
+ "maxRunningSyncPerConnector",
287
+ );
288
+ }
289
+ export function getIdentityIdleMsV2() {
290
+ return _identityIdleMsV2;
291
+ }
292
+ export function setIdentityIdleMsV2(n) {
293
+ _identityIdleMsV2 = _posIntScimV2(n, "identityIdleMs");
294
+ }
295
+ export function getSyncStuckMsV2() {
296
+ return _syncStuckMsV2;
297
+ }
298
+ export function setSyncStuckMsV2(n) {
299
+ _syncStuckMsV2 = _posIntScimV2(n, "syncStuckMs");
300
+ }
301
+
302
+ export function getProvisionedCountV2(connectorId) {
303
+ let n = 0;
304
+ for (const i of _identitiesV2.values()) {
305
+ if (i.connectorId === connectorId && i.status === "provisioned") n += 1;
306
+ }
307
+ return n;
308
+ }
309
+
310
+ export function getRunningSyncCountV2(connectorId) {
311
+ let n = 0;
312
+ for (const j of _syncJobsV2.values()) {
313
+ if (j.connectorId === connectorId && j.status === "running") n += 1;
314
+ }
315
+ return n;
316
+ }
317
+
318
+ function _copyIdentityV2(i) {
319
+ return { ...i, metadata: { ...i.metadata } };
320
+ }
321
+ function _copySyncV2(j) {
322
+ return { ...j, metadata: { ...j.metadata } };
323
+ }
324
+
325
+ export function registerIdentityV2(
326
+ id,
327
+ { connectorId, externalId, metadata = {}, now = Date.now() } = {},
328
+ ) {
329
+ if (!id || typeof id !== "string") throw new Error("id must be a string");
330
+ if (!connectorId || typeof connectorId !== "string")
331
+ throw new Error("connectorId must be a string");
332
+ if (!externalId || typeof externalId !== "string")
333
+ throw new Error("externalId must be a string");
334
+ if (_identitiesV2.has(id)) throw new Error(`identity ${id} already exists`);
335
+ const i = {
336
+ id,
337
+ connectorId,
338
+ externalId,
339
+ status: "pending",
340
+ createdAt: now,
341
+ lastSeenAt: now,
342
+ provisionedAt: null,
343
+ deprovisionedAt: null,
344
+ metadata: { ...metadata },
345
+ };
346
+ _identitiesV2.set(id, i);
347
+ return _copyIdentityV2(i);
348
+ }
349
+
350
+ export function getIdentityV2(id) {
351
+ const i = _identitiesV2.get(id);
352
+ return i ? _copyIdentityV2(i) : null;
353
+ }
354
+
355
+ export function listIdentitiesV2({ connectorId, status } = {}) {
356
+ const out = [];
357
+ for (const i of _identitiesV2.values()) {
358
+ if (connectorId && i.connectorId !== connectorId) continue;
359
+ if (status && i.status !== status) continue;
360
+ out.push(_copyIdentityV2(i));
361
+ }
362
+ return out;
363
+ }
364
+
365
+ export function setIdentityStatusV2(id, next, { now = Date.now() } = {}) {
366
+ const i = _identitiesV2.get(id);
367
+ if (!i) throw new Error(`identity ${id} not found`);
368
+ if (!IDENTITY_TRANSITIONS_V2.has(next))
369
+ throw new Error(`unknown identity status: ${next}`);
370
+ if (IDENTITY_TERMINALS_V2.has(i.status))
371
+ throw new Error(`identity ${id} is in terminal state ${i.status}`);
372
+ const allowed = IDENTITY_TRANSITIONS_V2.get(i.status);
373
+ if (!allowed.has(next))
374
+ throw new Error(`cannot transition identity from ${i.status} to ${next}`);
375
+ if (next === "provisioned") {
376
+ if (i.status === "pending") {
377
+ const count = getProvisionedCountV2(i.connectorId);
378
+ if (count >= _maxProvisionedPerConnectorV2)
379
+ throw new Error(
380
+ `connector ${i.connectorId} already at provisioned cap (${_maxProvisionedPerConnectorV2})`,
381
+ );
382
+ }
383
+ if (!i.provisionedAt) i.provisionedAt = now;
384
+ }
385
+ if (next === "deprovisioned" && !i.deprovisionedAt) i.deprovisionedAt = now;
386
+ i.status = next;
387
+ i.lastSeenAt = now;
388
+ return _copyIdentityV2(i);
389
+ }
390
+
391
+ export function provisionIdentityV2(id, opts) {
392
+ return setIdentityStatusV2(id, "provisioned", opts);
393
+ }
394
+ export function suspendIdentityV2(id, opts) {
395
+ return setIdentityStatusV2(id, "suspended", opts);
396
+ }
397
+ export function deprovisionIdentityV2(id, opts) {
398
+ return setIdentityStatusV2(id, "deprovisioned", opts);
399
+ }
400
+
401
+ export function touchIdentityV2(id, { now = Date.now() } = {}) {
402
+ const i = _identitiesV2.get(id);
403
+ if (!i) throw new Error(`identity ${id} not found`);
404
+ i.lastSeenAt = now;
405
+ return _copyIdentityV2(i);
406
+ }
407
+
408
+ export function createSyncJobV2(
409
+ id,
410
+ { connectorId, kind = "full", metadata = {}, now = Date.now() } = {},
411
+ ) {
412
+ if (!id || typeof id !== "string") throw new Error("id must be a string");
413
+ if (!connectorId || typeof connectorId !== "string")
414
+ throw new Error("connectorId must be a string");
415
+ if (_syncJobsV2.has(id)) throw new Error(`syncJob ${id} already exists`);
416
+ const j = {
417
+ id,
418
+ connectorId,
419
+ kind,
420
+ status: "queued",
421
+ createdAt: now,
422
+ lastSeenAt: now,
423
+ startedAt: null,
424
+ finishedAt: null,
425
+ metadata: { ...metadata },
426
+ };
427
+ _syncJobsV2.set(id, j);
428
+ return _copySyncV2(j);
429
+ }
430
+
431
+ export function getSyncJobV2(id) {
432
+ const j = _syncJobsV2.get(id);
433
+ return j ? _copySyncV2(j) : null;
434
+ }
435
+
436
+ export function listSyncJobsV2({ connectorId, status } = {}) {
437
+ const out = [];
438
+ for (const j of _syncJobsV2.values()) {
439
+ if (connectorId && j.connectorId !== connectorId) continue;
440
+ if (status && j.status !== status) continue;
441
+ out.push(_copySyncV2(j));
442
+ }
443
+ return out;
444
+ }
445
+
446
+ export function setSyncJobStatusV2(id, next, { now = Date.now() } = {}) {
447
+ const j = _syncJobsV2.get(id);
448
+ if (!j) throw new Error(`syncJob ${id} not found`);
449
+ if (!SYNC_TRANSITIONS_V2.has(next))
450
+ throw new Error(`unknown syncJob status: ${next}`);
451
+ if (SYNC_TERMINALS_V2.has(j.status))
452
+ throw new Error(`syncJob ${id} is in terminal state ${j.status}`);
453
+ const allowed = SYNC_TRANSITIONS_V2.get(j.status);
454
+ if (!allowed.has(next))
455
+ throw new Error(`cannot transition syncJob from ${j.status} to ${next}`);
456
+ if (next === "running" && j.status === "queued") {
457
+ const count = getRunningSyncCountV2(j.connectorId);
458
+ if (count >= _maxRunningSyncPerConnectorV2)
459
+ throw new Error(
460
+ `connector ${j.connectorId} already at running-sync cap (${_maxRunningSyncPerConnectorV2})`,
461
+ );
462
+ if (!j.startedAt) j.startedAt = now;
463
+ }
464
+ if (SYNC_TERMINALS_V2.has(next) && !j.finishedAt) j.finishedAt = now;
465
+ j.status = next;
466
+ j.lastSeenAt = now;
467
+ return _copySyncV2(j);
468
+ }
469
+
470
+ export function startSyncJobV2(id, opts) {
471
+ return setSyncJobStatusV2(id, "running", opts);
472
+ }
473
+ export function succeedSyncJobV2(id, opts) {
474
+ return setSyncJobStatusV2(id, "succeeded", opts);
475
+ }
476
+ export function failSyncJobV2(id, opts) {
477
+ return setSyncJobStatusV2(id, "failed", opts);
478
+ }
479
+ export function cancelSyncJobV2(id, opts) {
480
+ return setSyncJobStatusV2(id, "cancelled", opts);
481
+ }
482
+
483
+ export function autoDeprovisionIdleIdentitiesV2({ now = Date.now() } = {}) {
484
+ const flipped = [];
485
+ for (const i of _identitiesV2.values()) {
486
+ if (i.status === "deprovisioned" || i.status === "pending") continue;
487
+ if (now - i.lastSeenAt > _identityIdleMsV2) {
488
+ i.status = "deprovisioned";
489
+ i.lastSeenAt = now;
490
+ if (!i.deprovisionedAt) i.deprovisionedAt = now;
491
+ flipped.push(_copyIdentityV2(i));
492
+ }
493
+ }
494
+ return flipped;
495
+ }
496
+
497
+ export function autoFailStuckSyncJobsV2({ now = Date.now() } = {}) {
498
+ const flipped = [];
499
+ for (const j of _syncJobsV2.values()) {
500
+ if (j.status !== "running") continue;
501
+ const ref = j.startedAt ?? j.lastSeenAt;
502
+ if (now - ref > _syncStuckMsV2) {
503
+ j.status = "failed";
504
+ j.lastSeenAt = now;
505
+ if (!j.finishedAt) j.finishedAt = now;
506
+ flipped.push(_copySyncV2(j));
507
+ }
508
+ }
509
+ return flipped;
510
+ }
511
+
512
+ export function getScimManagerStatsV2() {
513
+ const identitiesByStatus = {};
514
+ for (const v of Object.values(IDENTITY_LIFECYCLE_V2))
515
+ identitiesByStatus[v] = 0;
516
+ for (const i of _identitiesV2.values()) identitiesByStatus[i.status] += 1;
517
+
518
+ const syncJobsByStatus = {};
519
+ for (const v of Object.values(SYNC_JOB_V2)) syncJobsByStatus[v] = 0;
520
+ for (const j of _syncJobsV2.values()) syncJobsByStatus[j.status] += 1;
521
+
522
+ return {
523
+ totalIdentitiesV2: _identitiesV2.size,
524
+ totalSyncJobsV2: _syncJobsV2.size,
525
+ maxProvisionedPerConnector: _maxProvisionedPerConnectorV2,
526
+ maxRunningSyncPerConnector: _maxRunningSyncPerConnectorV2,
527
+ identityIdleMs: _identityIdleMsV2,
528
+ syncStuckMs: _syncStuckMsV2,
529
+ identitiesByStatus,
530
+ syncJobsByStatus,
531
+ };
532
+ }
533
+
534
+ export function _resetStateScimManagerV2() {
535
+ _identitiesV2.clear();
536
+ _syncJobsV2.clear();
537
+ _maxProvisionedPerConnectorV2 = SCIM_DEFAULT_MAX_PROVISIONED_PER_CONNECTOR;
538
+ _maxRunningSyncPerConnectorV2 = SCIM_DEFAULT_MAX_RUNNING_SYNC_PER_CONNECTOR;
539
+ _identityIdleMsV2 = SCIM_DEFAULT_IDENTITY_IDLE_MS;
540
+ _syncStuckMsV2 = SCIM_DEFAULT_SYNC_STUCK_MS;
541
+ }
@@ -181,3 +181,84 @@ export class ServiceContainer {
181
181
  export function createServiceContainer() {
182
182
  return new ServiceContainer();
183
183
  }
184
+
185
+ // ===== V2 Surface: Service Container governance overlay (CLI v0.141.0) =====
186
+ export const SVC_CONTAINER_MATURITY_V2 = Object.freeze({
187
+ PENDING: "pending", ACTIVE: "active", DEGRADED: "degraded", DECOMMISSIONED: "decommissioned",
188
+ });
189
+ export const SVC_RESOLUTION_LIFECYCLE_V2 = Object.freeze({
190
+ QUEUED: "queued", RESOLVING: "resolving", RESOLVED: "resolved", FAILED: "failed", CANCELLED: "cancelled",
191
+ });
192
+ const _svcCTrans = new Map([
193
+ [SVC_CONTAINER_MATURITY_V2.PENDING, new Set([SVC_CONTAINER_MATURITY_V2.ACTIVE, SVC_CONTAINER_MATURITY_V2.DECOMMISSIONED])],
194
+ [SVC_CONTAINER_MATURITY_V2.ACTIVE, new Set([SVC_CONTAINER_MATURITY_V2.DEGRADED, SVC_CONTAINER_MATURITY_V2.DECOMMISSIONED])],
195
+ [SVC_CONTAINER_MATURITY_V2.DEGRADED, new Set([SVC_CONTAINER_MATURITY_V2.ACTIVE, SVC_CONTAINER_MATURITY_V2.DECOMMISSIONED])],
196
+ [SVC_CONTAINER_MATURITY_V2.DECOMMISSIONED, new Set()],
197
+ ]);
198
+ const _svcCTerminal = new Set([SVC_CONTAINER_MATURITY_V2.DECOMMISSIONED]);
199
+ const _svcRTrans = new Map([
200
+ [SVC_RESOLUTION_LIFECYCLE_V2.QUEUED, new Set([SVC_RESOLUTION_LIFECYCLE_V2.RESOLVING, SVC_RESOLUTION_LIFECYCLE_V2.CANCELLED])],
201
+ [SVC_RESOLUTION_LIFECYCLE_V2.RESOLVING, new Set([SVC_RESOLUTION_LIFECYCLE_V2.RESOLVED, SVC_RESOLUTION_LIFECYCLE_V2.FAILED, SVC_RESOLUTION_LIFECYCLE_V2.CANCELLED])],
202
+ [SVC_RESOLUTION_LIFECYCLE_V2.RESOLVED, new Set()],
203
+ [SVC_RESOLUTION_LIFECYCLE_V2.FAILED, new Set()],
204
+ [SVC_RESOLUTION_LIFECYCLE_V2.CANCELLED, new Set()],
205
+ ]);
206
+ const _svcCsV2 = new Map();
207
+ const _svcRsV2 = new Map();
208
+ let _svcMaxActivePerOwner = 8, _svcMaxPendingResPerContainer = 25, _svcIdleMs = 60 * 60 * 1000, _svcStuckMs = 30 * 1000;
209
+ function _svcPos(n, label) { const v = Math.floor(Number(n)); if (!Number.isFinite(v) || v <= 0) throw new Error(`${label} must be positive integer`); return v; }
210
+ function _svcCheckC(from, to) { const a = _svcCTrans.get(from); if (!a || !a.has(to)) throw new Error(`invalid svc container transition ${from} → ${to}`); }
211
+ function _svcCheckR(from, to) { const a = _svcRTrans.get(from); if (!a || !a.has(to)) throw new Error(`invalid svc resolution transition ${from} → ${to}`); }
212
+ export function setMaxActiveSvcContainersPerOwnerV2(n) { _svcMaxActivePerOwner = _svcPos(n, "maxActiveSvcContainersPerOwner"); }
213
+ export function getMaxActiveSvcContainersPerOwnerV2() { return _svcMaxActivePerOwner; }
214
+ export function setMaxPendingSvcResolutionsPerContainerV2(n) { _svcMaxPendingResPerContainer = _svcPos(n, "maxPendingSvcResolutionsPerContainer"); }
215
+ export function getMaxPendingSvcResolutionsPerContainerV2() { return _svcMaxPendingResPerContainer; }
216
+ export function setSvcContainerIdleMsV2(n) { _svcIdleMs = _svcPos(n, "svcContainerIdleMs"); }
217
+ export function getSvcContainerIdleMsV2() { return _svcIdleMs; }
218
+ export function setSvcResolutionStuckMsV2(n) { _svcStuckMs = _svcPos(n, "svcResolutionStuckMs"); }
219
+ export function getSvcResolutionStuckMsV2() { return _svcStuckMs; }
220
+ export function _resetStateServiceContainerV2() { _svcCsV2.clear(); _svcRsV2.clear(); _svcMaxActivePerOwner = 8; _svcMaxPendingResPerContainer = 25; _svcIdleMs = 60 * 60 * 1000; _svcStuckMs = 30 * 1000; }
221
+ export function registerSvcContainerV2({ id, owner, scope, metadata } = {}) {
222
+ if (!id) throw new Error("svc container id required"); if (!owner) throw new Error("svc container owner required");
223
+ if (_svcCsV2.has(id)) throw new Error(`svc container ${id} already registered`);
224
+ const now = Date.now();
225
+ const c = { id, owner, scope: scope || "default", status: SVC_CONTAINER_MATURITY_V2.PENDING, createdAt: now, updatedAt: now, activatedAt: null, decommissionedAt: null, lastTouchedAt: now, metadata: { ...(metadata || {}) } };
226
+ _svcCsV2.set(id, c); return { ...c, metadata: { ...c.metadata } };
227
+ }
228
+ function _svcCountActive(owner) { let n = 0; for (const c of _svcCsV2.values()) if (c.owner === owner && c.status === SVC_CONTAINER_MATURITY_V2.ACTIVE) n++; return n; }
229
+ export function activateSvcContainerV2(id) {
230
+ const c = _svcCsV2.get(id); if (!c) throw new Error(`svc container ${id} not found`);
231
+ _svcCheckC(c.status, SVC_CONTAINER_MATURITY_V2.ACTIVE);
232
+ const recovery = c.status === SVC_CONTAINER_MATURITY_V2.DEGRADED;
233
+ if (!recovery && _svcCountActive(c.owner) >= _svcMaxActivePerOwner) throw new Error(`max active svc containers for owner ${c.owner} reached`);
234
+ const now = Date.now(); c.status = SVC_CONTAINER_MATURITY_V2.ACTIVE; c.updatedAt = now; c.lastTouchedAt = now; if (!c.activatedAt) c.activatedAt = now;
235
+ return { ...c, metadata: { ...c.metadata } };
236
+ }
237
+ export function degradeSvcContainerV2(id) { const c = _svcCsV2.get(id); if (!c) throw new Error(`svc container ${id} not found`); _svcCheckC(c.status, SVC_CONTAINER_MATURITY_V2.DEGRADED); c.status = SVC_CONTAINER_MATURITY_V2.DEGRADED; c.updatedAt = Date.now(); return { ...c, metadata: { ...c.metadata } }; }
238
+ export function decommissionSvcContainerV2(id) { const c = _svcCsV2.get(id); if (!c) throw new Error(`svc container ${id} not found`); _svcCheckC(c.status, SVC_CONTAINER_MATURITY_V2.DECOMMISSIONED); const now = Date.now(); c.status = SVC_CONTAINER_MATURITY_V2.DECOMMISSIONED; c.updatedAt = now; if (!c.decommissionedAt) c.decommissionedAt = now; return { ...c, metadata: { ...c.metadata } }; }
239
+ export function touchSvcContainerV2(id) { const c = _svcCsV2.get(id); if (!c) throw new Error(`svc container ${id} not found`); if (_svcCTerminal.has(c.status)) throw new Error(`cannot touch terminal svc container ${id}`); const now = Date.now(); c.lastTouchedAt = now; c.updatedAt = now; return { ...c, metadata: { ...c.metadata } }; }
240
+ export function getSvcContainerV2(id) { const c = _svcCsV2.get(id); if (!c) return null; return { ...c, metadata: { ...c.metadata } }; }
241
+ export function listSvcContainersV2() { return [..._svcCsV2.values()].map((c) => ({ ...c, metadata: { ...c.metadata } })); }
242
+ function _svcCountPending(containerId) { let n = 0; for (const r of _svcRsV2.values()) if (r.containerId === containerId && (r.status === SVC_RESOLUTION_LIFECYCLE_V2.QUEUED || r.status === SVC_RESOLUTION_LIFECYCLE_V2.RESOLVING)) n++; return n; }
243
+ export function createSvcResolutionV2({ id, containerId, token, metadata } = {}) {
244
+ if (!id) throw new Error("svc resolution id required"); if (!containerId) throw new Error("svc resolution containerId required");
245
+ if (_svcRsV2.has(id)) throw new Error(`svc resolution ${id} already exists`);
246
+ if (!_svcCsV2.has(containerId)) throw new Error(`svc container ${containerId} not found`);
247
+ if (_svcCountPending(containerId) >= _svcMaxPendingResPerContainer) throw new Error(`max pending svc resolutions for container ${containerId} reached`);
248
+ const now = Date.now();
249
+ const r = { id, containerId, token: token || "", status: SVC_RESOLUTION_LIFECYCLE_V2.QUEUED, createdAt: now, updatedAt: now, startedAt: null, settledAt: null, metadata: { ...(metadata || {}) } };
250
+ _svcRsV2.set(id, r); return { ...r, metadata: { ...r.metadata } };
251
+ }
252
+ export function resolvingSvcResolutionV2(id) { const r = _svcRsV2.get(id); if (!r) throw new Error(`svc resolution ${id} not found`); _svcCheckR(r.status, SVC_RESOLUTION_LIFECYCLE_V2.RESOLVING); const now = Date.now(); r.status = SVC_RESOLUTION_LIFECYCLE_V2.RESOLVING; r.updatedAt = now; if (!r.startedAt) r.startedAt = now; return { ...r, metadata: { ...r.metadata } }; }
253
+ export function resolveSvcResolutionV2(id) { const r = _svcRsV2.get(id); if (!r) throw new Error(`svc resolution ${id} not found`); _svcCheckR(r.status, SVC_RESOLUTION_LIFECYCLE_V2.RESOLVED); const now = Date.now(); r.status = SVC_RESOLUTION_LIFECYCLE_V2.RESOLVED; r.updatedAt = now; if (!r.settledAt) r.settledAt = now; return { ...r, metadata: { ...r.metadata } }; }
254
+ export function failSvcResolutionV2(id, reason) { const r = _svcRsV2.get(id); if (!r) throw new Error(`svc resolution ${id} not found`); _svcCheckR(r.status, SVC_RESOLUTION_LIFECYCLE_V2.FAILED); const now = Date.now(); r.status = SVC_RESOLUTION_LIFECYCLE_V2.FAILED; r.updatedAt = now; if (!r.settledAt) r.settledAt = now; if (reason) r.metadata.failReason = String(reason); return { ...r, metadata: { ...r.metadata } }; }
255
+ export function cancelSvcResolutionV2(id, reason) { const r = _svcRsV2.get(id); if (!r) throw new Error(`svc resolution ${id} not found`); _svcCheckR(r.status, SVC_RESOLUTION_LIFECYCLE_V2.CANCELLED); const now = Date.now(); r.status = SVC_RESOLUTION_LIFECYCLE_V2.CANCELLED; r.updatedAt = now; if (!r.settledAt) r.settledAt = now; if (reason) r.metadata.cancelReason = String(reason); return { ...r, metadata: { ...r.metadata } }; }
256
+ export function getSvcResolutionV2(id) { const r = _svcRsV2.get(id); if (!r) return null; return { ...r, metadata: { ...r.metadata } }; }
257
+ export function listSvcResolutionsV2() { return [..._svcRsV2.values()].map((r) => ({ ...r, metadata: { ...r.metadata } })); }
258
+ export function autoDegradeIdleSvcContainersV2({ now } = {}) { const t = now ?? Date.now(); const flipped = []; for (const c of _svcCsV2.values()) if (c.status === SVC_CONTAINER_MATURITY_V2.ACTIVE && (t - c.lastTouchedAt) >= _svcIdleMs) { c.status = SVC_CONTAINER_MATURITY_V2.DEGRADED; c.updatedAt = t; flipped.push(c.id); } return { flipped, count: flipped.length }; }
259
+ export function autoFailStuckSvcResolutionsV2({ now } = {}) { const t = now ?? Date.now(); const flipped = []; for (const r of _svcRsV2.values()) if (r.status === SVC_RESOLUTION_LIFECYCLE_V2.RESOLVING && r.startedAt != null && (t - r.startedAt) >= _svcStuckMs) { r.status = SVC_RESOLUTION_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 }; }
260
+ export function getServiceContainerGovStatsV2() {
261
+ const containersByStatus = {}; for (const v of Object.values(SVC_CONTAINER_MATURITY_V2)) containersByStatus[v] = 0; for (const c of _svcCsV2.values()) containersByStatus[c.status]++;
262
+ const resolutionsByStatus = {}; for (const v of Object.values(SVC_RESOLUTION_LIFECYCLE_V2)) resolutionsByStatus[v] = 0; for (const r of _svcRsV2.values()) resolutionsByStatus[r.status]++;
263
+ return { totalSvcContainersV2: _svcCsV2.size, totalSvcResolutionsV2: _svcRsV2.size, maxActiveSvcContainersPerOwner: _svcMaxActivePerOwner, maxPendingSvcResolutionsPerContainer: _svcMaxPendingResPerContainer, svcContainerIdleMs: _svcIdleMs, svcResolutionStuckMs: _svcStuckMs, containersByStatus, resolutionsByStatus };
264
+ }
@@ -123,3 +123,108 @@ export async function consolidateJsonlSession(sessionId, options = {}) {
123
123
  },
124
124
  );
125
125
  }
126
+
127
+
128
+ // ===== V2 Surface: Session Consolidator governance overlay (CLI v0.134.0) =====
129
+ export const CONSOL_PROFILE_MATURITY_V2 = Object.freeze({
130
+ PENDING: "pending", ACTIVE: "active", PAUSED: "paused", ARCHIVED: "archived",
131
+ });
132
+ export const CONSOL_JOB_LIFECYCLE_V2 = Object.freeze({
133
+ QUEUED: "queued", RUNNING: "running", COMPLETED: "completed", FAILED: "failed", CANCELLED: "cancelled",
134
+ });
135
+
136
+ const _scProfTrans = new Map([
137
+ [CONSOL_PROFILE_MATURITY_V2.PENDING, new Set([CONSOL_PROFILE_MATURITY_V2.ACTIVE, CONSOL_PROFILE_MATURITY_V2.ARCHIVED])],
138
+ [CONSOL_PROFILE_MATURITY_V2.ACTIVE, new Set([CONSOL_PROFILE_MATURITY_V2.PAUSED, CONSOL_PROFILE_MATURITY_V2.ARCHIVED])],
139
+ [CONSOL_PROFILE_MATURITY_V2.PAUSED, new Set([CONSOL_PROFILE_MATURITY_V2.ACTIVE, CONSOL_PROFILE_MATURITY_V2.ARCHIVED])],
140
+ [CONSOL_PROFILE_MATURITY_V2.ARCHIVED, new Set()],
141
+ ]);
142
+ const _scProfTerminal = new Set([CONSOL_PROFILE_MATURITY_V2.ARCHIVED]);
143
+ const _scJobTrans = new Map([
144
+ [CONSOL_JOB_LIFECYCLE_V2.QUEUED, new Set([CONSOL_JOB_LIFECYCLE_V2.RUNNING, CONSOL_JOB_LIFECYCLE_V2.CANCELLED])],
145
+ [CONSOL_JOB_LIFECYCLE_V2.RUNNING, new Set([CONSOL_JOB_LIFECYCLE_V2.COMPLETED, CONSOL_JOB_LIFECYCLE_V2.FAILED, CONSOL_JOB_LIFECYCLE_V2.CANCELLED])],
146
+ [CONSOL_JOB_LIFECYCLE_V2.COMPLETED, new Set()],
147
+ [CONSOL_JOB_LIFECYCLE_V2.FAILED, new Set()],
148
+ [CONSOL_JOB_LIFECYCLE_V2.CANCELLED, new Set()],
149
+ ]);
150
+
151
+ const _scProfiles = new Map();
152
+ const _scJobs = new Map();
153
+ let _scMaxActivePerOwner = 8;
154
+ let _scMaxPendingPerProfile = 12;
155
+ let _scProfileIdleMs = 7 * 24 * 60 * 60 * 1000;
156
+ let _scJobStuckMs = 10 * 60 * 1000;
157
+
158
+ function _scPos(n, lbl) { const v = Math.floor(Number(n)); if (!Number.isFinite(v) || v <= 0) throw new Error(`${lbl} must be positive integer`); return v; }
159
+
160
+ export function setMaxActiveConsolProfilesPerOwnerV2(n) { _scMaxActivePerOwner = _scPos(n, "maxActiveConsolProfilesPerOwner"); }
161
+ export function getMaxActiveConsolProfilesPerOwnerV2() { return _scMaxActivePerOwner; }
162
+ export function setMaxPendingConsolJobsPerProfileV2(n) { _scMaxPendingPerProfile = _scPos(n, "maxPendingConsolJobsPerProfile"); }
163
+ export function getMaxPendingConsolJobsPerProfileV2() { return _scMaxPendingPerProfile; }
164
+ export function setConsolProfileIdleMsV2(n) { _scProfileIdleMs = _scPos(n, "consolProfileIdleMs"); }
165
+ export function getConsolProfileIdleMsV2() { return _scProfileIdleMs; }
166
+ export function setConsolJobStuckMsV2(n) { _scJobStuckMs = _scPos(n, "consolJobStuckMs"); }
167
+ export function getConsolJobStuckMsV2() { return _scJobStuckMs; }
168
+
169
+ export function _resetStateSessionConsolidatorV2() {
170
+ _scProfiles.clear(); _scJobs.clear();
171
+ _scMaxActivePerOwner = 8; _scMaxPendingPerProfile = 12;
172
+ _scProfileIdleMs = 7 * 24 * 60 * 60 * 1000; _scJobStuckMs = 10 * 60 * 1000;
173
+ }
174
+
175
+ export function registerConsolProfileV2({ id, owner, scope, metadata } = {}) {
176
+ if (!id || typeof id !== "string") throw new Error("id is required");
177
+ if (!owner || typeof owner !== "string") throw new Error("owner is required");
178
+ if (_scProfiles.has(id)) throw new Error(`consol profile ${id} already registered`);
179
+ const now = Date.now();
180
+ const p = { id, owner, scope: scope || "agent", status: CONSOL_PROFILE_MATURITY_V2.PENDING, createdAt: now, updatedAt: now, activatedAt: null, archivedAt: null, lastTouchedAt: now, metadata: { ...(metadata || {}) } };
181
+ _scProfiles.set(id, p);
182
+ return { ...p, metadata: { ...p.metadata } };
183
+ }
184
+ function _scCheckP(from, to) { const a = _scProfTrans.get(from); if (!a || !a.has(to)) throw new Error(`invalid consol profile transition ${from} → ${to}`); }
185
+ function _scCountActive(owner) { let n = 0; for (const p of _scProfiles.values()) if (p.owner === owner && p.status === CONSOL_PROFILE_MATURITY_V2.ACTIVE) n++; return n; }
186
+
187
+ export function activateConsolProfileV2(id) {
188
+ const p = _scProfiles.get(id); if (!p) throw new Error(`consol profile ${id} not found`);
189
+ _scCheckP(p.status, CONSOL_PROFILE_MATURITY_V2.ACTIVE);
190
+ const recovery = p.status === CONSOL_PROFILE_MATURITY_V2.PAUSED;
191
+ if (!recovery) { const a = _scCountActive(p.owner); if (a >= _scMaxActivePerOwner) throw new Error(`max active consol profiles per owner (${_scMaxActivePerOwner}) reached for ${p.owner}`); }
192
+ const now = Date.now(); p.status = CONSOL_PROFILE_MATURITY_V2.ACTIVE; p.updatedAt = now; p.lastTouchedAt = now; if (!p.activatedAt) p.activatedAt = now;
193
+ return { ...p, metadata: { ...p.metadata } };
194
+ }
195
+ export function pauseConsolProfileV2(id) { const p = _scProfiles.get(id); if (!p) throw new Error(`consol profile ${id} not found`); _scCheckP(p.status, CONSOL_PROFILE_MATURITY_V2.PAUSED); p.status = CONSOL_PROFILE_MATURITY_V2.PAUSED; p.updatedAt = Date.now(); return { ...p, metadata: { ...p.metadata } }; }
196
+ export function archiveConsolProfileV2(id) { const p = _scProfiles.get(id); if (!p) throw new Error(`consol profile ${id} not found`); _scCheckP(p.status, CONSOL_PROFILE_MATURITY_V2.ARCHIVED); const now = Date.now(); p.status = CONSOL_PROFILE_MATURITY_V2.ARCHIVED; p.updatedAt = now; if (!p.archivedAt) p.archivedAt = now; return { ...p, metadata: { ...p.metadata } }; }
197
+ export function touchConsolProfileV2(id) { const p = _scProfiles.get(id); if (!p) throw new Error(`consol profile ${id} not found`); if (_scProfTerminal.has(p.status)) throw new Error(`cannot touch terminal consol profile ${id}`); const now = Date.now(); p.lastTouchedAt = now; p.updatedAt = now; return { ...p, metadata: { ...p.metadata } }; }
198
+ export function getConsolProfileV2(id) { const p = _scProfiles.get(id); if (!p) return null; return { ...p, metadata: { ...p.metadata } }; }
199
+ export function listConsolProfilesV2() { return [..._scProfiles.values()].map((p) => ({ ...p, metadata: { ...p.metadata } })); }
200
+
201
+ function _scCountPending(pid) { let n = 0; for (const j of _scJobs.values()) if (j.profileId === pid && (j.status === CONSOL_JOB_LIFECYCLE_V2.QUEUED || j.status === CONSOL_JOB_LIFECYCLE_V2.RUNNING)) n++; return n; }
202
+
203
+ export function createConsolJobV2({ id, profileId, sessionId, metadata } = {}) {
204
+ if (!id || typeof id !== "string") throw new Error("id is required");
205
+ if (!profileId || typeof profileId !== "string") throw new Error("profileId is required");
206
+ if (_scJobs.has(id)) throw new Error(`consol job ${id} already exists`);
207
+ if (!_scProfiles.has(profileId)) throw new Error(`consol profile ${profileId} not found`);
208
+ const pending = _scCountPending(profileId);
209
+ if (pending >= _scMaxPendingPerProfile) throw new Error(`max pending consol jobs per profile (${_scMaxPendingPerProfile}) reached for ${profileId}`);
210
+ const now = Date.now();
211
+ const j = { id, profileId, sessionId: sessionId || null, status: CONSOL_JOB_LIFECYCLE_V2.QUEUED, createdAt: now, updatedAt: now, startedAt: null, settledAt: null, metadata: { ...(metadata || {}) } };
212
+ _scJobs.set(id, j);
213
+ return { ...j, metadata: { ...j.metadata } };
214
+ }
215
+ function _scCheckJ(from, to) { const a = _scJobTrans.get(from); if (!a || !a.has(to)) throw new Error(`invalid consol job transition ${from} → ${to}`); }
216
+ export function startConsolJobV2(id) { const j = _scJobs.get(id); if (!j) throw new Error(`consol job ${id} not found`); _scCheckJ(j.status, CONSOL_JOB_LIFECYCLE_V2.RUNNING); const now = Date.now(); j.status = CONSOL_JOB_LIFECYCLE_V2.RUNNING; j.updatedAt = now; if (!j.startedAt) j.startedAt = now; return { ...j, metadata: { ...j.metadata } }; }
217
+ export function completeConsolJobV2(id) { const j = _scJobs.get(id); if (!j) throw new Error(`consol job ${id} not found`); _scCheckJ(j.status, CONSOL_JOB_LIFECYCLE_V2.COMPLETED); const now = Date.now(); j.status = CONSOL_JOB_LIFECYCLE_V2.COMPLETED; j.updatedAt = now; if (!j.settledAt) j.settledAt = now; return { ...j, metadata: { ...j.metadata } }; }
218
+ export function failConsolJobV2(id, reason) { const j = _scJobs.get(id); if (!j) throw new Error(`consol job ${id} not found`); _scCheckJ(j.status, CONSOL_JOB_LIFECYCLE_V2.FAILED); const now = Date.now(); j.status = CONSOL_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 } }; }
219
+ export function cancelConsolJobV2(id, reason) { const j = _scJobs.get(id); if (!j) throw new Error(`consol job ${id} not found`); _scCheckJ(j.status, CONSOL_JOB_LIFECYCLE_V2.CANCELLED); const now = Date.now(); j.status = CONSOL_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 } }; }
220
+ export function getConsolJobV2(id) { const j = _scJobs.get(id); if (!j) return null; return { ...j, metadata: { ...j.metadata } }; }
221
+ export function listConsolJobsV2() { return [..._scJobs.values()].map((j) => ({ ...j, metadata: { ...j.metadata } })); }
222
+
223
+ export function autoPauseIdleConsolProfilesV2({ now } = {}) { const t = now ?? Date.now(); const flipped = []; for (const p of _scProfiles.values()) if (p.status === CONSOL_PROFILE_MATURITY_V2.ACTIVE && (t - p.lastTouchedAt) >= _scProfileIdleMs) { p.status = CONSOL_PROFILE_MATURITY_V2.PAUSED; p.updatedAt = t; flipped.push(p.id); } return { flipped, count: flipped.length }; }
224
+ export function autoFailStuckConsolJobsV2({ now } = {}) { const t = now ?? Date.now(); const flipped = []; for (const j of _scJobs.values()) if (j.status === CONSOL_JOB_LIFECYCLE_V2.RUNNING && j.startedAt != null && (t - j.startedAt) >= _scJobStuckMs) { j.status = CONSOL_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 }; }
225
+
226
+ export function getSessionConsolidatorStatsV2() {
227
+ const profilesByStatus = {}; for (const s of Object.values(CONSOL_PROFILE_MATURITY_V2)) profilesByStatus[s] = 0; for (const p of _scProfiles.values()) profilesByStatus[p.status]++;
228
+ const jobsByStatus = {}; for (const s of Object.values(CONSOL_JOB_LIFECYCLE_V2)) jobsByStatus[s] = 0; for (const j of _scJobs.values()) jobsByStatus[j.status]++;
229
+ return { totalProfilesV2: _scProfiles.size, totalJobsV2: _scJobs.size, maxActiveConsolProfilesPerOwner: _scMaxActivePerOwner, maxPendingConsolJobsPerProfile: _scMaxPendingPerProfile, consolProfileIdleMs: _scProfileIdleMs, consolJobStuckMs: _scJobStuckMs, profilesByStatus, jobsByStatus };
230
+ }
@@ -229,3 +229,84 @@ function withTimeout(promise, ms, label) {
229
229
  });
230
230
  return Promise.race([promise, timeout]).finally(() => clearTimeout(t));
231
231
  }
232
+
233
+ // ===== V2 Surface: Session Hooks governance overlay (CLI v0.142.0) =====
234
+ export const SHOK_PROFILE_MATURITY_V2 = Object.freeze({
235
+ PENDING: "pending", ACTIVE: "active", DISABLED: "disabled", RETIRED: "retired",
236
+ });
237
+ export const SHOK_INVOCATION_LIFECYCLE_V2 = Object.freeze({
238
+ QUEUED: "queued", RUNNING: "running", COMPLETED: "completed", FAILED: "failed", CANCELLED: "cancelled",
239
+ });
240
+ const _shokPTrans = new Map([
241
+ [SHOK_PROFILE_MATURITY_V2.PENDING, new Set([SHOK_PROFILE_MATURITY_V2.ACTIVE, SHOK_PROFILE_MATURITY_V2.RETIRED])],
242
+ [SHOK_PROFILE_MATURITY_V2.ACTIVE, new Set([SHOK_PROFILE_MATURITY_V2.DISABLED, SHOK_PROFILE_MATURITY_V2.RETIRED])],
243
+ [SHOK_PROFILE_MATURITY_V2.DISABLED, new Set([SHOK_PROFILE_MATURITY_V2.ACTIVE, SHOK_PROFILE_MATURITY_V2.RETIRED])],
244
+ [SHOK_PROFILE_MATURITY_V2.RETIRED, new Set()],
245
+ ]);
246
+ const _shokPTerminal = new Set([SHOK_PROFILE_MATURITY_V2.RETIRED]);
247
+ const _shokITrans = new Map([
248
+ [SHOK_INVOCATION_LIFECYCLE_V2.QUEUED, new Set([SHOK_INVOCATION_LIFECYCLE_V2.RUNNING, SHOK_INVOCATION_LIFECYCLE_V2.CANCELLED])],
249
+ [SHOK_INVOCATION_LIFECYCLE_V2.RUNNING, new Set([SHOK_INVOCATION_LIFECYCLE_V2.COMPLETED, SHOK_INVOCATION_LIFECYCLE_V2.FAILED, SHOK_INVOCATION_LIFECYCLE_V2.CANCELLED])],
250
+ [SHOK_INVOCATION_LIFECYCLE_V2.COMPLETED, new Set()],
251
+ [SHOK_INVOCATION_LIFECYCLE_V2.FAILED, new Set()],
252
+ [SHOK_INVOCATION_LIFECYCLE_V2.CANCELLED, new Set()],
253
+ ]);
254
+ const _shokPsV2 = new Map();
255
+ const _shokIsV2 = new Map();
256
+ let _shokMaxActive = 12, _shokMaxPending = 25, _shokIdleMs = 30 * 24 * 60 * 60 * 1000, _shokStuckMs = 30 * 1000;
257
+ function _shokPos(n, label) { const v = Math.floor(Number(n)); if (!Number.isFinite(v) || v <= 0) throw new Error(`${label} must be positive integer`); return v; }
258
+ function _shokCheckP(from, to) { const a = _shokPTrans.get(from); if (!a || !a.has(to)) throw new Error(`invalid shok profile transition ${from} → ${to}`); }
259
+ function _shokCheckI(from, to) { const a = _shokITrans.get(from); if (!a || !a.has(to)) throw new Error(`invalid shok invocation transition ${from} → ${to}`); }
260
+ export function setMaxActiveShokProfilesPerOwnerV2(n) { _shokMaxActive = _shokPos(n, "maxActiveShokProfilesPerOwner"); }
261
+ export function getMaxActiveShokProfilesPerOwnerV2() { return _shokMaxActive; }
262
+ export function setMaxPendingShokInvocationsPerProfileV2(n) { _shokMaxPending = _shokPos(n, "maxPendingShokInvocationsPerProfile"); }
263
+ export function getMaxPendingShokInvocationsPerProfileV2() { return _shokMaxPending; }
264
+ export function setShokProfileIdleMsV2(n) { _shokIdleMs = _shokPos(n, "shokProfileIdleMs"); }
265
+ export function getShokProfileIdleMsV2() { return _shokIdleMs; }
266
+ export function setShokInvocationStuckMsV2(n) { _shokStuckMs = _shokPos(n, "shokInvocationStuckMs"); }
267
+ export function getShokInvocationStuckMsV2() { return _shokStuckMs; }
268
+ export function _resetStateSessionHooksV2() { _shokPsV2.clear(); _shokIsV2.clear(); _shokMaxActive = 12; _shokMaxPending = 25; _shokIdleMs = 30 * 24 * 60 * 60 * 1000; _shokStuckMs = 30 * 1000; }
269
+ export function registerShokProfileV2({ id, owner, event, metadata } = {}) {
270
+ if (!id) throw new Error("shok profile id required"); if (!owner) throw new Error("shok profile owner required");
271
+ if (_shokPsV2.has(id)) throw new Error(`shok profile ${id} already registered`);
272
+ const now = Date.now();
273
+ const p = { id, owner, event: event || "preTurn", status: SHOK_PROFILE_MATURITY_V2.PENDING, createdAt: now, updatedAt: now, activatedAt: null, retiredAt: null, lastTouchedAt: now, metadata: { ...(metadata || {}) } };
274
+ _shokPsV2.set(id, p); return { ...p, metadata: { ...p.metadata } };
275
+ }
276
+ function _shokCountActive(owner) { let n = 0; for (const p of _shokPsV2.values()) if (p.owner === owner && p.status === SHOK_PROFILE_MATURITY_V2.ACTIVE) n++; return n; }
277
+ export function activateShokProfileV2(id) {
278
+ const p = _shokPsV2.get(id); if (!p) throw new Error(`shok profile ${id} not found`);
279
+ _shokCheckP(p.status, SHOK_PROFILE_MATURITY_V2.ACTIVE);
280
+ const recovery = p.status === SHOK_PROFILE_MATURITY_V2.DISABLED;
281
+ if (!recovery && _shokCountActive(p.owner) >= _shokMaxActive) throw new Error(`max active shok profiles for owner ${p.owner} reached`);
282
+ const now = Date.now(); p.status = SHOK_PROFILE_MATURITY_V2.ACTIVE; p.updatedAt = now; p.lastTouchedAt = now; if (!p.activatedAt) p.activatedAt = now;
283
+ return { ...p, metadata: { ...p.metadata } };
284
+ }
285
+ export function disableShokProfileV2(id) { const p = _shokPsV2.get(id); if (!p) throw new Error(`shok profile ${id} not found`); _shokCheckP(p.status, SHOK_PROFILE_MATURITY_V2.DISABLED); p.status = SHOK_PROFILE_MATURITY_V2.DISABLED; p.updatedAt = Date.now(); return { ...p, metadata: { ...p.metadata } }; }
286
+ export function retireShokProfileV2(id) { const p = _shokPsV2.get(id); if (!p) throw new Error(`shok profile ${id} not found`); _shokCheckP(p.status, SHOK_PROFILE_MATURITY_V2.RETIRED); const now = Date.now(); p.status = SHOK_PROFILE_MATURITY_V2.RETIRED; p.updatedAt = now; if (!p.retiredAt) p.retiredAt = now; return { ...p, metadata: { ...p.metadata } }; }
287
+ export function touchShokProfileV2(id) { const p = _shokPsV2.get(id); if (!p) throw new Error(`shok profile ${id} not found`); if (_shokPTerminal.has(p.status)) throw new Error(`cannot touch terminal shok profile ${id}`); const now = Date.now(); p.lastTouchedAt = now; p.updatedAt = now; return { ...p, metadata: { ...p.metadata } }; }
288
+ export function getShokProfileV2(id) { const p = _shokPsV2.get(id); if (!p) return null; return { ...p, metadata: { ...p.metadata } }; }
289
+ export function listShokProfilesV2() { return [..._shokPsV2.values()].map((p) => ({ ...p, metadata: { ...p.metadata } })); }
290
+ function _shokCountPending(profileId) { let n = 0; for (const i of _shokIsV2.values()) if (i.profileId === profileId && (i.status === SHOK_INVOCATION_LIFECYCLE_V2.QUEUED || i.status === SHOK_INVOCATION_LIFECYCLE_V2.RUNNING)) n++; return n; }
291
+ export function createShokInvocationV2({ id, profileId, payload, metadata } = {}) {
292
+ if (!id) throw new Error("shok invocation id required"); if (!profileId) throw new Error("shok invocation profileId required");
293
+ if (_shokIsV2.has(id)) throw new Error(`shok invocation ${id} already exists`);
294
+ if (!_shokPsV2.has(profileId)) throw new Error(`shok profile ${profileId} not found`);
295
+ if (_shokCountPending(profileId) >= _shokMaxPending) throw new Error(`max pending shok invocations for profile ${profileId} reached`);
296
+ const now = Date.now();
297
+ const i = { id, profileId, payload: payload || "", status: SHOK_INVOCATION_LIFECYCLE_V2.QUEUED, createdAt: now, updatedAt: now, startedAt: null, settledAt: null, metadata: { ...(metadata || {}) } };
298
+ _shokIsV2.set(id, i); return { ...i, metadata: { ...i.metadata } };
299
+ }
300
+ export function runningShokInvocationV2(id) { const i = _shokIsV2.get(id); if (!i) throw new Error(`shok invocation ${id} not found`); _shokCheckI(i.status, SHOK_INVOCATION_LIFECYCLE_V2.RUNNING); const now = Date.now(); i.status = SHOK_INVOCATION_LIFECYCLE_V2.RUNNING; i.updatedAt = now; if (!i.startedAt) i.startedAt = now; return { ...i, metadata: { ...i.metadata } }; }
301
+ export function completeShokInvocationV2(id) { const i = _shokIsV2.get(id); if (!i) throw new Error(`shok invocation ${id} not found`); _shokCheckI(i.status, SHOK_INVOCATION_LIFECYCLE_V2.COMPLETED); const now = Date.now(); i.status = SHOK_INVOCATION_LIFECYCLE_V2.COMPLETED; i.updatedAt = now; if (!i.settledAt) i.settledAt = now; return { ...i, metadata: { ...i.metadata } }; }
302
+ export function failShokInvocationV2(id, reason) { const i = _shokIsV2.get(id); if (!i) throw new Error(`shok invocation ${id} not found`); _shokCheckI(i.status, SHOK_INVOCATION_LIFECYCLE_V2.FAILED); const now = Date.now(); i.status = SHOK_INVOCATION_LIFECYCLE_V2.FAILED; i.updatedAt = now; if (!i.settledAt) i.settledAt = now; if (reason) i.metadata.failReason = String(reason); return { ...i, metadata: { ...i.metadata } }; }
303
+ export function cancelShokInvocationV2(id, reason) { const i = _shokIsV2.get(id); if (!i) throw new Error(`shok invocation ${id} not found`); _shokCheckI(i.status, SHOK_INVOCATION_LIFECYCLE_V2.CANCELLED); const now = Date.now(); i.status = SHOK_INVOCATION_LIFECYCLE_V2.CANCELLED; i.updatedAt = now; if (!i.settledAt) i.settledAt = now; if (reason) i.metadata.cancelReason = String(reason); return { ...i, metadata: { ...i.metadata } }; }
304
+ export function getShokInvocationV2(id) { const i = _shokIsV2.get(id); if (!i) return null; return { ...i, metadata: { ...i.metadata } }; }
305
+ export function listShokInvocationsV2() { return [..._shokIsV2.values()].map((i) => ({ ...i, metadata: { ...i.metadata } })); }
306
+ export function autoDisableIdleShokProfilesV2({ now } = {}) { const t = now ?? Date.now(); const flipped = []; for (const p of _shokPsV2.values()) if (p.status === SHOK_PROFILE_MATURITY_V2.ACTIVE && (t - p.lastTouchedAt) >= _shokIdleMs) { p.status = SHOK_PROFILE_MATURITY_V2.DISABLED; p.updatedAt = t; flipped.push(p.id); } return { flipped, count: flipped.length }; }
307
+ export function autoFailStuckShokInvocationsV2({ now } = {}) { const t = now ?? Date.now(); const flipped = []; for (const i of _shokIsV2.values()) if (i.status === SHOK_INVOCATION_LIFECYCLE_V2.RUNNING && i.startedAt != null && (t - i.startedAt) >= _shokStuckMs) { i.status = SHOK_INVOCATION_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 }; }
308
+ export function getSessionHooksGovStatsV2() {
309
+ const profilesByStatus = {}; for (const v of Object.values(SHOK_PROFILE_MATURITY_V2)) profilesByStatus[v] = 0; for (const p of _shokPsV2.values()) profilesByStatus[p.status]++;
310
+ const invocationsByStatus = {}; for (const v of Object.values(SHOK_INVOCATION_LIFECYCLE_V2)) invocationsByStatus[v] = 0; for (const i of _shokIsV2.values()) invocationsByStatus[i.status]++;
311
+ return { totalShokProfilesV2: _shokPsV2.size, totalShokInvocationsV2: _shokIsV2.size, maxActiveShokProfilesPerOwner: _shokMaxActive, maxPendingShokInvocationsPerProfile: _shokMaxPending, shokProfileIdleMs: _shokIdleMs, shokInvocationStuckMs: _shokStuckMs, profilesByStatus, invocationsByStatus };
312
+ }