chainlesschain 0.132.0 → 0.145.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 (135) hide show
  1. package/package.json +1 -1
  2. package/src/commands/a2a.js +230 -0
  3. package/src/commands/activitypub.js +191 -0
  4. package/src/commands/agent.js +601 -0
  5. package/src/commands/audit.js +206 -0
  6. package/src/commands/bi.js +186 -0
  7. package/src/commands/bm25.js +162 -0
  8. package/src/commands/browse.js +225 -0
  9. package/src/commands/ccron.js +178 -0
  10. package/src/commands/chat.js +207 -0
  11. package/src/commands/compliance.js +420 -0
  12. package/src/commands/compt.js +176 -0
  13. package/src/commands/consol.js +237 -0
  14. package/src/commands/cowork.js +588 -0
  15. package/src/commands/crosschain.js +216 -0
  16. package/src/commands/dao.js +216 -0
  17. package/src/commands/dlp.js +206 -0
  18. package/src/commands/economy.js +211 -0
  19. package/src/commands/evolution.js +209 -0
  20. package/src/commands/evomap.js +216 -0
  21. package/src/commands/fflag.js +230 -0
  22. package/src/commands/git.js +185 -0
  23. package/src/commands/hardening.js +209 -0
  24. package/src/commands/hmemory.js +210 -0
  25. package/src/commands/incentive.js +209 -0
  26. package/src/commands/inference.js +178 -0
  27. package/src/commands/itbudget.js +161 -0
  28. package/src/commands/kg.js +206 -0
  29. package/src/commands/lowcode.js +201 -0
  30. package/src/commands/marketplace.js +206 -0
  31. package/src/commands/matrix.js +214 -0
  32. package/src/commands/mcpscaf.js +153 -0
  33. package/src/commands/meminj.js +153 -0
  34. package/src/commands/nostr.js +213 -0
  35. package/src/commands/orchestrate.js +217 -0
  36. package/src/commands/orchgov.js +156 -0
  37. package/src/commands/pdfp.js +160 -0
  38. package/src/commands/perf.js +176 -0
  39. package/src/commands/perm.js +156 -0
  40. package/src/commands/pipeline.js +211 -0
  41. package/src/commands/planmode.js +154 -0
  42. package/src/commands/privacy.js +203 -0
  43. package/src/commands/promcomp.js +166 -0
  44. package/src/commands/recommend.js +185 -0
  45. package/src/commands/reputation.js +208 -0
  46. package/src/commands/sandbox.js +206 -0
  47. package/src/commands/seshhook.js +153 -0
  48. package/src/commands/seshsearch.js +149 -0
  49. package/src/commands/seshtail.js +152 -0
  50. package/src/commands/seshu.js +160 -0
  51. package/src/commands/sganal.js +172 -0
  52. package/src/commands/siem.js +207 -0
  53. package/src/commands/sla.js +212 -0
  54. package/src/commands/slotfill.js +154 -0
  55. package/src/commands/social.js +159 -0
  56. package/src/commands/stress.js +206 -0
  57. package/src/commands/svccont.js +157 -0
  58. package/src/commands/terraform.js +206 -0
  59. package/src/commands/tms.js +183 -0
  60. package/src/commands/topiccls.js +158 -0
  61. package/src/commands/uprof.js +154 -0
  62. package/src/commands/vcheck.js +172 -0
  63. package/src/commands/webfetch.js +150 -0
  64. package/src/commands/zkp.js +218 -0
  65. package/src/harness/prompt-compressor.js +331 -0
  66. package/src/index.js +101 -1
  67. package/src/lib/a2a-protocol.js +373 -0
  68. package/src/lib/activitypub-bridge.js +343 -0
  69. package/src/lib/agent-economy.js +358 -0
  70. package/src/lib/app-builder.js +338 -0
  71. package/src/lib/audit-logger.js +321 -0
  72. package/src/lib/autonomous-agent.js +341 -0
  73. package/src/lib/bi-engine.js +339 -0
  74. package/src/lib/bm25-search.js +333 -0
  75. package/src/lib/browser-automation.js +352 -0
  76. package/src/lib/chat-core.js +336 -0
  77. package/src/lib/claude-code-bridge.js +341 -0
  78. package/src/lib/compliance-framework-reporter.js +359 -0
  79. package/src/lib/compliance-manager.js +330 -0
  80. package/src/lib/compression-telemetry.js +333 -0
  81. package/src/lib/content-recommender.js +370 -0
  82. package/src/lib/cowork-cron.js +330 -0
  83. package/src/lib/cowork-learning.js +333 -0
  84. package/src/lib/cowork-task-runner.js +362 -0
  85. package/src/lib/cowork-workflow.js +327 -0
  86. package/src/lib/cross-chain.js +365 -0
  87. package/src/lib/dao-governance.js +339 -0
  88. package/src/lib/dlp-engine.js +343 -0
  89. package/src/lib/evolution-system.js +336 -0
  90. package/src/lib/evomap-manager.js +339 -0
  91. package/src/lib/execution-backend.js +351 -0
  92. package/src/lib/feature-flags.js +330 -0
  93. package/src/lib/git-integration.js +343 -0
  94. package/src/lib/hardening-manager.js +341 -0
  95. package/src/lib/hierarchical-memory.js +341 -0
  96. package/src/lib/inference-network.js +362 -0
  97. package/src/lib/iteration-budget.js +357 -0
  98. package/src/lib/knowledge-graph.js +333 -0
  99. package/src/lib/matrix-bridge.js +339 -0
  100. package/src/lib/mcp-scaffold.js +345 -0
  101. package/src/lib/memory-injection.js +320 -0
  102. package/src/lib/nostr-bridge.js +342 -0
  103. package/src/lib/orchestrator.js +350 -0
  104. package/src/lib/pdf-parser.js +330 -0
  105. package/src/lib/perf-tuning.js +364 -0
  106. package/src/lib/permission-engine.js +319 -0
  107. package/src/lib/pipeline-orchestrator.js +345 -0
  108. package/src/lib/plan-mode.js +328 -0
  109. package/src/lib/privacy-computing.js +335 -0
  110. package/src/lib/prompt-compressor.js +1 -10
  111. package/src/lib/reputation-optimizer.js +340 -0
  112. package/src/lib/sandbox-v2.js +327 -0
  113. package/src/lib/service-container.js +342 -0
  114. package/src/lib/session-consolidator.js +352 -0
  115. package/src/lib/session-hooks.js +340 -0
  116. package/src/lib/session-search.js +334 -0
  117. package/src/lib/session-tail.js +320 -0
  118. package/src/lib/session-usage.js +329 -0
  119. package/src/lib/siem-exporter.js +352 -0
  120. package/src/lib/skill-marketplace.js +345 -0
  121. package/src/lib/sla-manager.js +341 -0
  122. package/src/lib/slot-filler.js +333 -0
  123. package/src/lib/social-graph-analytics.js +327 -0
  124. package/src/lib/social-graph.js +304 -0
  125. package/src/lib/stress-tester.js +342 -0
  126. package/src/lib/sub-agent-registry.js +359 -0
  127. package/src/lib/task-model-selector.js +333 -0
  128. package/src/lib/terraform-manager.js +333 -0
  129. package/src/lib/todo-manager.js +339 -0
  130. package/src/lib/token-incentive.js +341 -0
  131. package/src/lib/topic-classifier.js +353 -0
  132. package/src/lib/user-profile.js +325 -0
  133. package/src/lib/version-checker.js +335 -0
  134. package/src/lib/web-fetch.js +322 -0
  135. package/src/lib/zkp-engine.js +342 -0
@@ -164,3 +164,332 @@ export function allSessionsUsage({ limit = 1000 } = {}) {
164
164
  ),
165
165
  };
166
166
  }
167
+
168
+ // ===== V2 Surface: Session Usage governance overlay (CLI v0.142.0) =====
169
+ export const SUSE_BUDGET_MATURITY_V2 = Object.freeze({
170
+ PENDING: "pending",
171
+ ACTIVE: "active",
172
+ EXHAUSTED: "exhausted",
173
+ ARCHIVED: "archived",
174
+ });
175
+ export const SUSE_RECORD_LIFECYCLE_V2 = Object.freeze({
176
+ QUEUED: "queued",
177
+ RECORDING: "recording",
178
+ RECORDED: "recorded",
179
+ REJECTED: "rejected",
180
+ CANCELLED: "cancelled",
181
+ });
182
+ const _suseBTrans = new Map([
183
+ [
184
+ SUSE_BUDGET_MATURITY_V2.PENDING,
185
+ new Set([SUSE_BUDGET_MATURITY_V2.ACTIVE, SUSE_BUDGET_MATURITY_V2.ARCHIVED]),
186
+ ],
187
+ [
188
+ SUSE_BUDGET_MATURITY_V2.ACTIVE,
189
+ new Set([
190
+ SUSE_BUDGET_MATURITY_V2.EXHAUSTED,
191
+ SUSE_BUDGET_MATURITY_V2.ARCHIVED,
192
+ ]),
193
+ ],
194
+ [
195
+ SUSE_BUDGET_MATURITY_V2.EXHAUSTED,
196
+ new Set([SUSE_BUDGET_MATURITY_V2.ACTIVE, SUSE_BUDGET_MATURITY_V2.ARCHIVED]),
197
+ ],
198
+ [SUSE_BUDGET_MATURITY_V2.ARCHIVED, new Set()],
199
+ ]);
200
+ const _suseBTerminal = new Set([SUSE_BUDGET_MATURITY_V2.ARCHIVED]);
201
+ const _suseRTrans = new Map([
202
+ [
203
+ SUSE_RECORD_LIFECYCLE_V2.QUEUED,
204
+ new Set([
205
+ SUSE_RECORD_LIFECYCLE_V2.RECORDING,
206
+ SUSE_RECORD_LIFECYCLE_V2.CANCELLED,
207
+ ]),
208
+ ],
209
+ [
210
+ SUSE_RECORD_LIFECYCLE_V2.RECORDING,
211
+ new Set([
212
+ SUSE_RECORD_LIFECYCLE_V2.RECORDED,
213
+ SUSE_RECORD_LIFECYCLE_V2.REJECTED,
214
+ SUSE_RECORD_LIFECYCLE_V2.CANCELLED,
215
+ ]),
216
+ ],
217
+ [SUSE_RECORD_LIFECYCLE_V2.RECORDED, new Set()],
218
+ [SUSE_RECORD_LIFECYCLE_V2.REJECTED, new Set()],
219
+ [SUSE_RECORD_LIFECYCLE_V2.CANCELLED, new Set()],
220
+ ]);
221
+ const _suseBsV2 = new Map();
222
+ const _suseRsV2 = new Map();
223
+ let _suseMaxActive = 5,
224
+ _suseMaxPending = 50,
225
+ _suseIdleMs = 30 * 24 * 60 * 60 * 1000,
226
+ _suseStuckMs = 30 * 1000;
227
+ function _susePos(n, label) {
228
+ const v = Math.floor(Number(n));
229
+ if (!Number.isFinite(v) || v <= 0)
230
+ throw new Error(`${label} must be positive integer`);
231
+ return v;
232
+ }
233
+ function _suseCheckB(from, to) {
234
+ const a = _suseBTrans.get(from);
235
+ if (!a || !a.has(to))
236
+ throw new Error(`invalid suse budget transition ${from} → ${to}`);
237
+ }
238
+ function _suseCheckR(from, to) {
239
+ const a = _suseRTrans.get(from);
240
+ if (!a || !a.has(to))
241
+ throw new Error(`invalid suse record transition ${from} → ${to}`);
242
+ }
243
+ export function setMaxActiveSuseBudgetsPerOwnerV2(n) {
244
+ _suseMaxActive = _susePos(n, "maxActiveSuseBudgetsPerOwner");
245
+ }
246
+ export function getMaxActiveSuseBudgetsPerOwnerV2() {
247
+ return _suseMaxActive;
248
+ }
249
+ export function setMaxPendingSuseRecordsPerBudgetV2(n) {
250
+ _suseMaxPending = _susePos(n, "maxPendingSuseRecordsPerBudget");
251
+ }
252
+ export function getMaxPendingSuseRecordsPerBudgetV2() {
253
+ return _suseMaxPending;
254
+ }
255
+ export function setSuseBudgetIdleMsV2(n) {
256
+ _suseIdleMs = _susePos(n, "suseBudgetIdleMs");
257
+ }
258
+ export function getSuseBudgetIdleMsV2() {
259
+ return _suseIdleMs;
260
+ }
261
+ export function setSuseRecordStuckMsV2(n) {
262
+ _suseStuckMs = _susePos(n, "suseRecordStuckMs");
263
+ }
264
+ export function getSuseRecordStuckMsV2() {
265
+ return _suseStuckMs;
266
+ }
267
+ export function _resetStateSessionUsageV2() {
268
+ _suseBsV2.clear();
269
+ _suseRsV2.clear();
270
+ _suseMaxActive = 5;
271
+ _suseMaxPending = 50;
272
+ _suseIdleMs = 30 * 24 * 60 * 60 * 1000;
273
+ _suseStuckMs = 30 * 1000;
274
+ }
275
+ export function registerSuseBudgetV2({ id, owner, limit, metadata } = {}) {
276
+ if (!id) throw new Error("suse budget id required");
277
+ if (!owner) throw new Error("suse budget owner required");
278
+ if (_suseBsV2.has(id))
279
+ throw new Error(`suse budget ${id} already registered`);
280
+ const now = Date.now();
281
+ const lim =
282
+ limit == null ? 1000 : Math.max(1, Math.floor(Number(limit)) || 1);
283
+ const b = {
284
+ id,
285
+ owner,
286
+ limit: lim,
287
+ status: SUSE_BUDGET_MATURITY_V2.PENDING,
288
+ createdAt: now,
289
+ updatedAt: now,
290
+ activatedAt: null,
291
+ archivedAt: null,
292
+ lastTouchedAt: now,
293
+ metadata: { ...(metadata || {}) },
294
+ };
295
+ _suseBsV2.set(id, b);
296
+ return { ...b, metadata: { ...b.metadata } };
297
+ }
298
+ function _suseCountActive(owner) {
299
+ let n = 0;
300
+ for (const b of _suseBsV2.values())
301
+ if (b.owner === owner && b.status === SUSE_BUDGET_MATURITY_V2.ACTIVE) n++;
302
+ return n;
303
+ }
304
+ export function activateSuseBudgetV2(id) {
305
+ const b = _suseBsV2.get(id);
306
+ if (!b) throw new Error(`suse budget ${id} not found`);
307
+ _suseCheckB(b.status, SUSE_BUDGET_MATURITY_V2.ACTIVE);
308
+ const recovery = b.status === SUSE_BUDGET_MATURITY_V2.EXHAUSTED;
309
+ if (!recovery && _suseCountActive(b.owner) >= _suseMaxActive)
310
+ throw new Error(`max active suse budgets for owner ${b.owner} reached`);
311
+ const now = Date.now();
312
+ b.status = SUSE_BUDGET_MATURITY_V2.ACTIVE;
313
+ b.updatedAt = now;
314
+ b.lastTouchedAt = now;
315
+ if (!b.activatedAt) b.activatedAt = now;
316
+ return { ...b, metadata: { ...b.metadata } };
317
+ }
318
+ export function exhaustSuseBudgetV2(id) {
319
+ const b = _suseBsV2.get(id);
320
+ if (!b) throw new Error(`suse budget ${id} not found`);
321
+ _suseCheckB(b.status, SUSE_BUDGET_MATURITY_V2.EXHAUSTED);
322
+ b.status = SUSE_BUDGET_MATURITY_V2.EXHAUSTED;
323
+ b.updatedAt = Date.now();
324
+ return { ...b, metadata: { ...b.metadata } };
325
+ }
326
+ export function archiveSuseBudgetV2(id) {
327
+ const b = _suseBsV2.get(id);
328
+ if (!b) throw new Error(`suse budget ${id} not found`);
329
+ _suseCheckB(b.status, SUSE_BUDGET_MATURITY_V2.ARCHIVED);
330
+ const now = Date.now();
331
+ b.status = SUSE_BUDGET_MATURITY_V2.ARCHIVED;
332
+ b.updatedAt = now;
333
+ if (!b.archivedAt) b.archivedAt = now;
334
+ return { ...b, metadata: { ...b.metadata } };
335
+ }
336
+ export function touchSuseBudgetV2(id) {
337
+ const b = _suseBsV2.get(id);
338
+ if (!b) throw new Error(`suse budget ${id} not found`);
339
+ if (_suseBTerminal.has(b.status))
340
+ throw new Error(`cannot touch terminal suse budget ${id}`);
341
+ const now = Date.now();
342
+ b.lastTouchedAt = now;
343
+ b.updatedAt = now;
344
+ return { ...b, metadata: { ...b.metadata } };
345
+ }
346
+ export function getSuseBudgetV2(id) {
347
+ const b = _suseBsV2.get(id);
348
+ if (!b) return null;
349
+ return { ...b, metadata: { ...b.metadata } };
350
+ }
351
+ export function listSuseBudgetsV2() {
352
+ return [..._suseBsV2.values()].map((b) => ({
353
+ ...b,
354
+ metadata: { ...b.metadata },
355
+ }));
356
+ }
357
+ function _suseCountPending(budgetId) {
358
+ let n = 0;
359
+ for (const r of _suseRsV2.values())
360
+ if (
361
+ r.budgetId === budgetId &&
362
+ (r.status === SUSE_RECORD_LIFECYCLE_V2.QUEUED ||
363
+ r.status === SUSE_RECORD_LIFECYCLE_V2.RECORDING)
364
+ )
365
+ n++;
366
+ return n;
367
+ }
368
+ export function createSuseRecordV2({ id, budgetId, amount, metadata } = {}) {
369
+ if (!id) throw new Error("suse record id required");
370
+ if (!budgetId) throw new Error("suse record budgetId required");
371
+ if (_suseRsV2.has(id)) throw new Error(`suse record ${id} already exists`);
372
+ if (!_suseBsV2.has(budgetId))
373
+ throw new Error(`suse budget ${budgetId} not found`);
374
+ if (_suseCountPending(budgetId) >= _suseMaxPending)
375
+ throw new Error(`max pending suse records for budget ${budgetId} reached`);
376
+ const now = Date.now();
377
+ const amt = amount == null ? 0 : Math.max(0, Number(amount) || 0);
378
+ const r = {
379
+ id,
380
+ budgetId,
381
+ amount: amt,
382
+ status: SUSE_RECORD_LIFECYCLE_V2.QUEUED,
383
+ createdAt: now,
384
+ updatedAt: now,
385
+ startedAt: null,
386
+ settledAt: null,
387
+ metadata: { ...(metadata || {}) },
388
+ };
389
+ _suseRsV2.set(id, r);
390
+ return { ...r, metadata: { ...r.metadata } };
391
+ }
392
+ export function recordingSuseRecordV2(id) {
393
+ const r = _suseRsV2.get(id);
394
+ if (!r) throw new Error(`suse record ${id} not found`);
395
+ _suseCheckR(r.status, SUSE_RECORD_LIFECYCLE_V2.RECORDING);
396
+ const now = Date.now();
397
+ r.status = SUSE_RECORD_LIFECYCLE_V2.RECORDING;
398
+ r.updatedAt = now;
399
+ if (!r.startedAt) r.startedAt = now;
400
+ return { ...r, metadata: { ...r.metadata } };
401
+ }
402
+ export function recordSuseRecordV2(id) {
403
+ const r = _suseRsV2.get(id);
404
+ if (!r) throw new Error(`suse record ${id} not found`);
405
+ _suseCheckR(r.status, SUSE_RECORD_LIFECYCLE_V2.RECORDED);
406
+ const now = Date.now();
407
+ r.status = SUSE_RECORD_LIFECYCLE_V2.RECORDED;
408
+ r.updatedAt = now;
409
+ if (!r.settledAt) r.settledAt = now;
410
+ return { ...r, metadata: { ...r.metadata } };
411
+ }
412
+ export function rejectSuseRecordV2(id, reason) {
413
+ const r = _suseRsV2.get(id);
414
+ if (!r) throw new Error(`suse record ${id} not found`);
415
+ _suseCheckR(r.status, SUSE_RECORD_LIFECYCLE_V2.REJECTED);
416
+ const now = Date.now();
417
+ r.status = SUSE_RECORD_LIFECYCLE_V2.REJECTED;
418
+ r.updatedAt = now;
419
+ if (!r.settledAt) r.settledAt = now;
420
+ if (reason) r.metadata.rejectReason = String(reason);
421
+ return { ...r, metadata: { ...r.metadata } };
422
+ }
423
+ export function cancelSuseRecordV2(id, reason) {
424
+ const r = _suseRsV2.get(id);
425
+ if (!r) throw new Error(`suse record ${id} not found`);
426
+ _suseCheckR(r.status, SUSE_RECORD_LIFECYCLE_V2.CANCELLED);
427
+ const now = Date.now();
428
+ r.status = SUSE_RECORD_LIFECYCLE_V2.CANCELLED;
429
+ r.updatedAt = now;
430
+ if (!r.settledAt) r.settledAt = now;
431
+ if (reason) r.metadata.cancelReason = String(reason);
432
+ return { ...r, metadata: { ...r.metadata } };
433
+ }
434
+ export function getSuseRecordV2(id) {
435
+ const r = _suseRsV2.get(id);
436
+ if (!r) return null;
437
+ return { ...r, metadata: { ...r.metadata } };
438
+ }
439
+ export function listSuseRecordsV2() {
440
+ return [..._suseRsV2.values()].map((r) => ({
441
+ ...r,
442
+ metadata: { ...r.metadata },
443
+ }));
444
+ }
445
+ export function autoExhaustIdleSuseBudgetsV2({ now } = {}) {
446
+ const t = now ?? Date.now();
447
+ const flipped = [];
448
+ for (const b of _suseBsV2.values())
449
+ if (
450
+ b.status === SUSE_BUDGET_MATURITY_V2.ACTIVE &&
451
+ t - b.lastTouchedAt >= _suseIdleMs
452
+ ) {
453
+ b.status = SUSE_BUDGET_MATURITY_V2.EXHAUSTED;
454
+ b.updatedAt = t;
455
+ flipped.push(b.id);
456
+ }
457
+ return { flipped, count: flipped.length };
458
+ }
459
+ export function autoRejectStuckSuseRecordsV2({ now } = {}) {
460
+ const t = now ?? Date.now();
461
+ const flipped = [];
462
+ for (const r of _suseRsV2.values())
463
+ if (
464
+ r.status === SUSE_RECORD_LIFECYCLE_V2.RECORDING &&
465
+ r.startedAt != null &&
466
+ t - r.startedAt >= _suseStuckMs
467
+ ) {
468
+ r.status = SUSE_RECORD_LIFECYCLE_V2.REJECTED;
469
+ r.updatedAt = t;
470
+ if (!r.settledAt) r.settledAt = t;
471
+ r.metadata.rejectReason = "auto-reject-stuck";
472
+ flipped.push(r.id);
473
+ }
474
+ return { flipped, count: flipped.length };
475
+ }
476
+ export function getSessionUsageGovStatsV2() {
477
+ const budgetsByStatus = {};
478
+ for (const v of Object.values(SUSE_BUDGET_MATURITY_V2))
479
+ budgetsByStatus[v] = 0;
480
+ for (const b of _suseBsV2.values()) budgetsByStatus[b.status]++;
481
+ const recordsByStatus = {};
482
+ for (const v of Object.values(SUSE_RECORD_LIFECYCLE_V2))
483
+ recordsByStatus[v] = 0;
484
+ for (const r of _suseRsV2.values()) recordsByStatus[r.status]++;
485
+ return {
486
+ totalSuseBudgetsV2: _suseBsV2.size,
487
+ totalSuseRecordsV2: _suseRsV2.size,
488
+ maxActiveSuseBudgetsPerOwner: _suseMaxActive,
489
+ maxPendingSuseRecordsPerBudget: _suseMaxPending,
490
+ suseBudgetIdleMs: _suseIdleMs,
491
+ suseRecordStuckMs: _suseStuckMs,
492
+ budgetsByStatus,
493
+ recordsByStatus,
494
+ };
495
+ }
@@ -468,3 +468,355 @@ export function listTargetsByStatus(status) {
468
468
  }
469
469
 
470
470
  export { _severityCEF, _allowedTargetTransitions };
471
+
472
+ // ===== V2 Surface: SIEM Exporter governance overlay (CLI v0.138.0) =====
473
+ export const SIEM_TARGET_MATURITY_V2 = Object.freeze({
474
+ PENDING: "pending",
475
+ ACTIVE: "active",
476
+ DEGRADED: "degraded",
477
+ RETIRED: "retired",
478
+ });
479
+ export const SIEM_EXPORT_LIFECYCLE_V2 = Object.freeze({
480
+ QUEUED: "queued",
481
+ SENDING: "sending",
482
+ DELIVERED: "delivered",
483
+ FAILED: "failed",
484
+ CANCELLED: "cancelled",
485
+ });
486
+
487
+ const _siemTargetTrans = new Map([
488
+ [
489
+ SIEM_TARGET_MATURITY_V2.PENDING,
490
+ new Set([SIEM_TARGET_MATURITY_V2.ACTIVE, SIEM_TARGET_MATURITY_V2.RETIRED]),
491
+ ],
492
+ [
493
+ SIEM_TARGET_MATURITY_V2.ACTIVE,
494
+ new Set([
495
+ SIEM_TARGET_MATURITY_V2.DEGRADED,
496
+ SIEM_TARGET_MATURITY_V2.RETIRED,
497
+ ]),
498
+ ],
499
+ [
500
+ SIEM_TARGET_MATURITY_V2.DEGRADED,
501
+ new Set([SIEM_TARGET_MATURITY_V2.ACTIVE, SIEM_TARGET_MATURITY_V2.RETIRED]),
502
+ ],
503
+ [SIEM_TARGET_MATURITY_V2.RETIRED, new Set()],
504
+ ]);
505
+ const _siemTargetTerminal = new Set([SIEM_TARGET_MATURITY_V2.RETIRED]);
506
+ const _siemExportTrans = new Map([
507
+ [
508
+ SIEM_EXPORT_LIFECYCLE_V2.QUEUED,
509
+ new Set([
510
+ SIEM_EXPORT_LIFECYCLE_V2.SENDING,
511
+ SIEM_EXPORT_LIFECYCLE_V2.CANCELLED,
512
+ ]),
513
+ ],
514
+ [
515
+ SIEM_EXPORT_LIFECYCLE_V2.SENDING,
516
+ new Set([
517
+ SIEM_EXPORT_LIFECYCLE_V2.DELIVERED,
518
+ SIEM_EXPORT_LIFECYCLE_V2.FAILED,
519
+ SIEM_EXPORT_LIFECYCLE_V2.CANCELLED,
520
+ ]),
521
+ ],
522
+ [SIEM_EXPORT_LIFECYCLE_V2.DELIVERED, new Set()],
523
+ [SIEM_EXPORT_LIFECYCLE_V2.FAILED, new Set()],
524
+ [SIEM_EXPORT_LIFECYCLE_V2.CANCELLED, new Set()],
525
+ ]);
526
+
527
+ const _siemTargets = new Map();
528
+ const _siemExportJobs = new Map();
529
+ let _siemMaxActivePerOperator = 8;
530
+ let _siemMaxPendingExportsPerTarget = 50;
531
+ let _siemTargetIdleMs = 24 * 60 * 60 * 1000;
532
+ let _siemExportStuckMs = 5 * 60 * 1000;
533
+
534
+ function _siemPos(n, lbl) {
535
+ const v = Math.floor(Number(n));
536
+ if (!Number.isFinite(v) || v <= 0)
537
+ throw new Error(`${lbl} must be positive integer`);
538
+ return v;
539
+ }
540
+
541
+ export function setMaxActiveSiemTargetsPerOperatorV2(n) {
542
+ _siemMaxActivePerOperator = _siemPos(n, "maxActiveSiemTargetsPerOperator");
543
+ }
544
+ export function getMaxActiveSiemTargetsPerOperatorV2() {
545
+ return _siemMaxActivePerOperator;
546
+ }
547
+ export function setMaxPendingSiemExportsPerTargetV2(n) {
548
+ _siemMaxPendingExportsPerTarget = _siemPos(
549
+ n,
550
+ "maxPendingSiemExportsPerTarget",
551
+ );
552
+ }
553
+ export function getMaxPendingSiemExportsPerTargetV2() {
554
+ return _siemMaxPendingExportsPerTarget;
555
+ }
556
+ export function setSiemTargetIdleMsV2(n) {
557
+ _siemTargetIdleMs = _siemPos(n, "siemTargetIdleMs");
558
+ }
559
+ export function getSiemTargetIdleMsV2() {
560
+ return _siemTargetIdleMs;
561
+ }
562
+ export function setSiemExportStuckMsV2(n) {
563
+ _siemExportStuckMs = _siemPos(n, "siemExportStuckMs");
564
+ }
565
+ export function getSiemExportStuckMsV2() {
566
+ return _siemExportStuckMs;
567
+ }
568
+
569
+ export function _resetStateSiemExporterV2() {
570
+ _siemTargets.clear();
571
+ _siemExportJobs.clear();
572
+ _siemMaxActivePerOperator = 8;
573
+ _siemMaxPendingExportsPerTarget = 50;
574
+ _siemTargetIdleMs = 24 * 60 * 60 * 1000;
575
+ _siemExportStuckMs = 5 * 60 * 1000;
576
+ }
577
+
578
+ export function registerSiemTargetV2({ id, operator, kind, metadata } = {}) {
579
+ if (!id || typeof id !== "string") throw new Error("id is required");
580
+ if (!operator || typeof operator !== "string")
581
+ throw new Error("operator is required");
582
+ if (_siemTargets.has(id))
583
+ throw new Error(`siem target ${id} already registered`);
584
+ const now = Date.now();
585
+ const t = {
586
+ id,
587
+ operator,
588
+ kind: kind || "splunk_hec",
589
+ status: SIEM_TARGET_MATURITY_V2.PENDING,
590
+ createdAt: now,
591
+ updatedAt: now,
592
+ activatedAt: null,
593
+ retiredAt: null,
594
+ lastTouchedAt: now,
595
+ metadata: { ...(metadata || {}) },
596
+ };
597
+ _siemTargets.set(id, t);
598
+ return { ...t, metadata: { ...t.metadata } };
599
+ }
600
+ function _siemCheckT(from, to) {
601
+ const a = _siemTargetTrans.get(from);
602
+ if (!a || !a.has(to))
603
+ throw new Error(`invalid siem target transition ${from} → ${to}`);
604
+ }
605
+ function _siemCountActive(operator) {
606
+ let n = 0;
607
+ for (const t of _siemTargets.values())
608
+ if (t.operator === operator && t.status === SIEM_TARGET_MATURITY_V2.ACTIVE)
609
+ n++;
610
+ return n;
611
+ }
612
+
613
+ export function activateSiemTargetV2(id) {
614
+ const t = _siemTargets.get(id);
615
+ if (!t) throw new Error(`siem target ${id} not found`);
616
+ _siemCheckT(t.status, SIEM_TARGET_MATURITY_V2.ACTIVE);
617
+ const recovery = t.status === SIEM_TARGET_MATURITY_V2.DEGRADED;
618
+ if (!recovery) {
619
+ const c = _siemCountActive(t.operator);
620
+ if (c >= _siemMaxActivePerOperator)
621
+ throw new Error(
622
+ `max active siem targets per operator (${_siemMaxActivePerOperator}) reached for ${t.operator}`,
623
+ );
624
+ }
625
+ const now = Date.now();
626
+ t.status = SIEM_TARGET_MATURITY_V2.ACTIVE;
627
+ t.updatedAt = now;
628
+ t.lastTouchedAt = now;
629
+ if (!t.activatedAt) t.activatedAt = now;
630
+ return { ...t, metadata: { ...t.metadata } };
631
+ }
632
+ export function degradeSiemTargetV2(id) {
633
+ const t = _siemTargets.get(id);
634
+ if (!t) throw new Error(`siem target ${id} not found`);
635
+ _siemCheckT(t.status, SIEM_TARGET_MATURITY_V2.DEGRADED);
636
+ t.status = SIEM_TARGET_MATURITY_V2.DEGRADED;
637
+ t.updatedAt = Date.now();
638
+ return { ...t, metadata: { ...t.metadata } };
639
+ }
640
+ export function retireSiemTargetV2(id) {
641
+ const t = _siemTargets.get(id);
642
+ if (!t) throw new Error(`siem target ${id} not found`);
643
+ _siemCheckT(t.status, SIEM_TARGET_MATURITY_V2.RETIRED);
644
+ const now = Date.now();
645
+ t.status = SIEM_TARGET_MATURITY_V2.RETIRED;
646
+ t.updatedAt = now;
647
+ if (!t.retiredAt) t.retiredAt = now;
648
+ return { ...t, metadata: { ...t.metadata } };
649
+ }
650
+ export function touchSiemTargetV2(id) {
651
+ const t = _siemTargets.get(id);
652
+ if (!t) throw new Error(`siem target ${id} not found`);
653
+ if (_siemTargetTerminal.has(t.status))
654
+ throw new Error(`cannot touch terminal siem target ${id}`);
655
+ const now = Date.now();
656
+ t.lastTouchedAt = now;
657
+ t.updatedAt = now;
658
+ return { ...t, metadata: { ...t.metadata } };
659
+ }
660
+ export function getSiemTargetV2(id) {
661
+ const t = _siemTargets.get(id);
662
+ if (!t) return null;
663
+ return { ...t, metadata: { ...t.metadata } };
664
+ }
665
+ export function listSiemTargetsV2() {
666
+ return [..._siemTargets.values()].map((t) => ({
667
+ ...t,
668
+ metadata: { ...t.metadata },
669
+ }));
670
+ }
671
+
672
+ function _siemCountPendingExports(tid) {
673
+ let n = 0;
674
+ for (const e of _siemExportJobs.values())
675
+ if (
676
+ e.targetId === tid &&
677
+ (e.status === SIEM_EXPORT_LIFECYCLE_V2.QUEUED ||
678
+ e.status === SIEM_EXPORT_LIFECYCLE_V2.SENDING)
679
+ )
680
+ n++;
681
+ return n;
682
+ }
683
+
684
+ export function createSiemExportV2({ id, targetId, format, metadata } = {}) {
685
+ if (!id || typeof id !== "string") throw new Error("id is required");
686
+ if (!targetId || typeof targetId !== "string")
687
+ throw new Error("targetId is required");
688
+ if (_siemExportJobs.has(id))
689
+ throw new Error(`siem export ${id} already exists`);
690
+ if (!_siemTargets.has(targetId))
691
+ throw new Error(`siem target ${targetId} not found`);
692
+ const pending = _siemCountPendingExports(targetId);
693
+ if (pending >= _siemMaxPendingExportsPerTarget)
694
+ throw new Error(
695
+ `max pending siem exports per target (${_siemMaxPendingExportsPerTarget}) reached for ${targetId}`,
696
+ );
697
+ const now = Date.now();
698
+ const e = {
699
+ id,
700
+ targetId,
701
+ format: format || "json",
702
+ status: SIEM_EXPORT_LIFECYCLE_V2.QUEUED,
703
+ createdAt: now,
704
+ updatedAt: now,
705
+ startedAt: null,
706
+ settledAt: null,
707
+ metadata: { ...(metadata || {}) },
708
+ };
709
+ _siemExportJobs.set(id, e);
710
+ return { ...e, metadata: { ...e.metadata } };
711
+ }
712
+ function _siemCheckE(from, to) {
713
+ const a = _siemExportTrans.get(from);
714
+ if (!a || !a.has(to))
715
+ throw new Error(`invalid siem export transition ${from} → ${to}`);
716
+ }
717
+ export function startSiemExportV2(id) {
718
+ const e = _siemExportJobs.get(id);
719
+ if (!e) throw new Error(`siem export ${id} not found`);
720
+ _siemCheckE(e.status, SIEM_EXPORT_LIFECYCLE_V2.SENDING);
721
+ const now = Date.now();
722
+ e.status = SIEM_EXPORT_LIFECYCLE_V2.SENDING;
723
+ e.updatedAt = now;
724
+ if (!e.startedAt) e.startedAt = now;
725
+ return { ...e, metadata: { ...e.metadata } };
726
+ }
727
+ export function deliverSiemExportV2(id) {
728
+ const e = _siemExportJobs.get(id);
729
+ if (!e) throw new Error(`siem export ${id} not found`);
730
+ _siemCheckE(e.status, SIEM_EXPORT_LIFECYCLE_V2.DELIVERED);
731
+ const now = Date.now();
732
+ e.status = SIEM_EXPORT_LIFECYCLE_V2.DELIVERED;
733
+ e.updatedAt = now;
734
+ if (!e.settledAt) e.settledAt = now;
735
+ return { ...e, metadata: { ...e.metadata } };
736
+ }
737
+ export function failSiemExportV2(id, reason) {
738
+ const e = _siemExportJobs.get(id);
739
+ if (!e) throw new Error(`siem export ${id} not found`);
740
+ _siemCheckE(e.status, SIEM_EXPORT_LIFECYCLE_V2.FAILED);
741
+ const now = Date.now();
742
+ e.status = SIEM_EXPORT_LIFECYCLE_V2.FAILED;
743
+ e.updatedAt = now;
744
+ if (!e.settledAt) e.settledAt = now;
745
+ if (reason) e.metadata.failReason = String(reason);
746
+ return { ...e, metadata: { ...e.metadata } };
747
+ }
748
+ export function cancelSiemExportV2(id, reason) {
749
+ const e = _siemExportJobs.get(id);
750
+ if (!e) throw new Error(`siem export ${id} not found`);
751
+ _siemCheckE(e.status, SIEM_EXPORT_LIFECYCLE_V2.CANCELLED);
752
+ const now = Date.now();
753
+ e.status = SIEM_EXPORT_LIFECYCLE_V2.CANCELLED;
754
+ e.updatedAt = now;
755
+ if (!e.settledAt) e.settledAt = now;
756
+ if (reason) e.metadata.cancelReason = String(reason);
757
+ return { ...e, metadata: { ...e.metadata } };
758
+ }
759
+ export function getSiemExportV2(id) {
760
+ const e = _siemExportJobs.get(id);
761
+ if (!e) return null;
762
+ return { ...e, metadata: { ...e.metadata } };
763
+ }
764
+ export function listSiemExportsV2() {
765
+ return [..._siemExportJobs.values()].map((e) => ({
766
+ ...e,
767
+ metadata: { ...e.metadata },
768
+ }));
769
+ }
770
+
771
+ export function autoDegradeIdleSiemTargetsV2({ now } = {}) {
772
+ const t = now ?? Date.now();
773
+ const flipped = [];
774
+ for (const tgt of _siemTargets.values())
775
+ if (
776
+ tgt.status === SIEM_TARGET_MATURITY_V2.ACTIVE &&
777
+ t - tgt.lastTouchedAt >= _siemTargetIdleMs
778
+ ) {
779
+ tgt.status = SIEM_TARGET_MATURITY_V2.DEGRADED;
780
+ tgt.updatedAt = t;
781
+ flipped.push(tgt.id);
782
+ }
783
+ return { flipped, count: flipped.length };
784
+ }
785
+ export function autoFailStuckSiemExportsV2({ now } = {}) {
786
+ const t = now ?? Date.now();
787
+ const flipped = [];
788
+ for (const e of _siemExportJobs.values())
789
+ if (
790
+ e.status === SIEM_EXPORT_LIFECYCLE_V2.SENDING &&
791
+ e.startedAt != null &&
792
+ t - e.startedAt >= _siemExportStuckMs
793
+ ) {
794
+ e.status = SIEM_EXPORT_LIFECYCLE_V2.FAILED;
795
+ e.updatedAt = t;
796
+ if (!e.settledAt) e.settledAt = t;
797
+ e.metadata.failReason = "auto-fail-stuck";
798
+ flipped.push(e.id);
799
+ }
800
+ return { flipped, count: flipped.length };
801
+ }
802
+
803
+ export function getSiemExporterGovStatsV2() {
804
+ const targetsByStatus = {};
805
+ for (const s of Object.values(SIEM_TARGET_MATURITY_V2))
806
+ targetsByStatus[s] = 0;
807
+ for (const t of _siemTargets.values()) targetsByStatus[t.status]++;
808
+ const exportsByStatus = {};
809
+ for (const s of Object.values(SIEM_EXPORT_LIFECYCLE_V2))
810
+ exportsByStatus[s] = 0;
811
+ for (const e of _siemExportJobs.values()) exportsByStatus[e.status]++;
812
+ return {
813
+ totalSiemTargetsV2: _siemTargets.size,
814
+ totalSiemExportsV2: _siemExportJobs.size,
815
+ maxActiveSiemTargetsPerOperator: _siemMaxActivePerOperator,
816
+ maxPendingSiemExportsPerTarget: _siemMaxPendingExportsPerTarget,
817
+ siemTargetIdleMs: _siemTargetIdleMs,
818
+ siemExportStuckMs: _siemExportStuckMs,
819
+ targetsByStatus,
820
+ exportsByStatus,
821
+ };
822
+ }