chainlesschain 0.66.0 → 0.132.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. package/bin/chainlesschain.js +0 -0
  2. package/package.json +1 -1
  3. package/src/commands/a2a.js +380 -0
  4. package/src/commands/agent-network.js +254 -1
  5. package/src/commands/audit.js +302 -0
  6. package/src/commands/automation.js +271 -1
  7. package/src/commands/bi.js +348 -0
  8. package/src/commands/codegen.js +224 -0
  9. package/src/commands/collab.js +341 -0
  10. package/src/commands/compliance.js +1035 -0
  11. package/src/commands/cowork.js +221 -0
  12. package/src/commands/crosschain.js +218 -0
  13. package/src/commands/dbevo.js +284 -0
  14. package/src/commands/dev.js +252 -0
  15. package/src/commands/did.js +358 -0
  16. package/src/commands/dlp.js +341 -0
  17. package/src/commands/encrypt.js +341 -0
  18. package/src/commands/evomap.js +394 -0
  19. package/src/commands/export.js +256 -1
  20. package/src/commands/federation.js +283 -0
  21. package/src/commands/fusion.js +258 -0
  22. package/src/commands/governance.js +325 -0
  23. package/src/commands/hardening.js +411 -0
  24. package/src/commands/hook.js +148 -0
  25. package/src/commands/import.js +252 -0
  26. package/src/commands/incentive.js +322 -0
  27. package/src/commands/inference.js +318 -0
  28. package/src/commands/infra.js +244 -0
  29. package/src/commands/instinct.js +260 -0
  30. package/src/commands/ipfs.js +318 -0
  31. package/src/commands/kg.js +387 -0
  32. package/src/commands/llm.js +263 -0
  33. package/src/commands/lowcode.js +356 -0
  34. package/src/commands/marketplace.js +256 -0
  35. package/src/commands/mcp.js +221 -0
  36. package/src/commands/memory.js +248 -0
  37. package/src/commands/multimodal.js +296 -0
  38. package/src/commands/nlprog.js +356 -0
  39. package/src/commands/note.js +244 -0
  40. package/src/commands/ops.js +354 -0
  41. package/src/commands/orchestrate.js +166 -0
  42. package/src/commands/org.js +277 -0
  43. package/src/commands/p2p.js +390 -0
  44. package/src/commands/perception.js +290 -0
  45. package/src/commands/permmem.js +251 -0
  46. package/src/commands/plugin-ecosystem.js +273 -0
  47. package/src/commands/pqc.js +393 -0
  48. package/src/commands/privacy.js +321 -0
  49. package/src/commands/quantization.js +351 -0
  50. package/src/commands/rcache.js +271 -0
  51. package/src/commands/recommend.js +340 -0
  52. package/src/commands/reputation.js +261 -0
  53. package/src/commands/runtime.js +307 -0
  54. package/src/commands/scim.js +262 -0
  55. package/src/commands/session.js +258 -0
  56. package/src/commands/siem.js +246 -0
  57. package/src/commands/skill.js +267 -1
  58. package/src/commands/sla.js +259 -0
  59. package/src/commands/social.js +256 -0
  60. package/src/commands/sso.js +186 -1
  61. package/src/commands/stress.js +230 -0
  62. package/src/commands/sync.js +256 -0
  63. package/src/commands/tech.js +338 -0
  64. package/src/commands/tenant.js +351 -0
  65. package/src/commands/terraform.js +245 -0
  66. package/src/commands/tokens.js +269 -0
  67. package/src/commands/trust.js +249 -0
  68. package/src/commands/wallet.js +277 -0
  69. package/src/commands/workflow.js +171 -0
  70. package/src/commands/zkp.js +335 -0
  71. package/src/index.js +4 -0
  72. package/src/lib/a2a-protocol.js +451 -0
  73. package/src/lib/agent-coordinator.js +325 -0
  74. package/src/lib/agent-network.js +387 -0
  75. package/src/lib/agent-router.js +395 -0
  76. package/src/lib/aiops.js +478 -0
  77. package/src/lib/app-builder.js +239 -0
  78. package/src/lib/audit-logger.js +379 -0
  79. package/src/lib/automation-engine.js +330 -0
  80. package/src/lib/autonomous-developer.js +350 -0
  81. package/src/lib/bi-engine.js +338 -0
  82. package/src/lib/code-agent.js +323 -0
  83. package/src/lib/collaboration-governance.js +364 -0
  84. package/src/lib/community-governance.js +436 -0
  85. package/src/lib/compliance-manager.js +434 -0
  86. package/src/lib/content-recommendation.js +469 -0
  87. package/src/lib/cross-chain.js +345 -0
  88. package/src/lib/crypto-manager.js +350 -0
  89. package/src/lib/dbevo.js +338 -0
  90. package/src/lib/decentral-infra.js +340 -0
  91. package/src/lib/did-manager.js +367 -0
  92. package/src/lib/dlp-engine.js +389 -0
  93. package/src/lib/evomap-federation.js +177 -0
  94. package/src/lib/evomap-governance.js +276 -0
  95. package/src/lib/federation-hardening.js +259 -0
  96. package/src/lib/hardening-manager.js +348 -0
  97. package/src/lib/hook-manager.js +380 -0
  98. package/src/lib/inference-network.js +330 -0
  99. package/src/lib/instinct-manager.js +332 -0
  100. package/src/lib/ipfs-storage.js +334 -0
  101. package/src/lib/knowledge-exporter.js +381 -0
  102. package/src/lib/knowledge-graph.js +432 -0
  103. package/src/lib/knowledge-importer.js +379 -0
  104. package/src/lib/llm-providers.js +391 -0
  105. package/src/lib/mcp-registry.js +333 -0
  106. package/src/lib/memory-manager.js +330 -0
  107. package/src/lib/multimodal.js +346 -0
  108. package/src/lib/nl-programming.js +343 -0
  109. package/src/lib/note-versioning.js +327 -0
  110. package/src/lib/org-manager.js +323 -0
  111. package/src/lib/p2p-manager.js +387 -0
  112. package/src/lib/perception.js +346 -0
  113. package/src/lib/perf-tuning.js +4 -1
  114. package/src/lib/permanent-memory.js +320 -0
  115. package/src/lib/plugin-ecosystem.js +377 -0
  116. package/src/lib/pqc-manager.js +368 -0
  117. package/src/lib/privacy-computing.js +427 -0
  118. package/src/lib/protocol-fusion.js +417 -0
  119. package/src/lib/quantization.js +325 -0
  120. package/src/lib/reputation-optimizer.js +299 -0
  121. package/src/lib/response-cache.js +327 -0
  122. package/src/lib/scim-manager.js +329 -0
  123. package/src/lib/session-manager.js +329 -0
  124. package/src/lib/siem-exporter.js +333 -0
  125. package/src/lib/skill-loader.js +377 -0
  126. package/src/lib/skill-marketplace.js +325 -0
  127. package/src/lib/sla-manager.js +275 -0
  128. package/src/lib/social-manager.js +326 -0
  129. package/src/lib/sso-manager.js +332 -0
  130. package/src/lib/stress-tester.js +330 -0
  131. package/src/lib/sync-manager.js +326 -0
  132. package/src/lib/tech-learning-engine.js +369 -0
  133. package/src/lib/tenant-saas.js +460 -0
  134. package/src/lib/terraform-manager.js +363 -0
  135. package/src/lib/threat-intel.js +335 -0
  136. package/src/lib/token-incentive.js +293 -0
  137. package/src/lib/token-tracker.js +329 -0
  138. package/src/lib/trust-security.js +390 -0
  139. package/src/lib/ueba.js +389 -0
  140. package/src/lib/universal-runtime.js +325 -0
  141. package/src/lib/wallet-manager.js +326 -0
  142. package/src/lib/workflow-engine.js +322 -0
  143. package/src/lib/zkp-engine.js +274 -0
@@ -356,3 +356,380 @@ export class CLISkillLoader {
356
356
  this._cache = null;
357
357
  }
358
358
  }
359
+
360
+ // ─── V2 Governance Layer ────────────────────────────────────────────
361
+ //
362
+ // In-memory governance for skill registrations + execution tickets,
363
+ // independent of the file-based 4-layer CLISkillLoader (which scans
364
+ // bundled/marketplace/managed/workspace dirs). V2 tracks maturity
365
+ // transitions, per-owner active-skill caps, per-skill pending-execution
366
+ // caps, stamp-once timestamps, and bulk auto-flip routines.
367
+
368
+ export const SKILL_MATURITY_V2 = Object.freeze({
369
+ PENDING: "pending",
370
+ ACTIVE: "active",
371
+ DEPRECATED: "deprecated",
372
+ ARCHIVED: "archived",
373
+ });
374
+
375
+ export const EXECUTION_LIFECYCLE_V2 = Object.freeze({
376
+ QUEUED: "queued",
377
+ RUNNING: "running",
378
+ SUCCEEDED: "succeeded",
379
+ FAILED: "failed",
380
+ CANCELLED: "cancelled",
381
+ });
382
+
383
+ const _SKILL_TRANSITIONS_V2 = new Map([
384
+ [
385
+ SKILL_MATURITY_V2.PENDING,
386
+ new Set([SKILL_MATURITY_V2.ACTIVE, SKILL_MATURITY_V2.ARCHIVED]),
387
+ ],
388
+ [
389
+ SKILL_MATURITY_V2.ACTIVE,
390
+ new Set([SKILL_MATURITY_V2.DEPRECATED, SKILL_MATURITY_V2.ARCHIVED]),
391
+ ],
392
+ [
393
+ SKILL_MATURITY_V2.DEPRECATED,
394
+ new Set([SKILL_MATURITY_V2.ACTIVE, SKILL_MATURITY_V2.ARCHIVED]),
395
+ ],
396
+ [SKILL_MATURITY_V2.ARCHIVED, new Set()],
397
+ ]);
398
+
399
+ const _SKILL_TERMINALS_V2 = new Set([SKILL_MATURITY_V2.ARCHIVED]);
400
+
401
+ const _EXEC_TRANSITIONS_V2 = new Map([
402
+ [
403
+ EXECUTION_LIFECYCLE_V2.QUEUED,
404
+ new Set([EXECUTION_LIFECYCLE_V2.RUNNING, EXECUTION_LIFECYCLE_V2.CANCELLED]),
405
+ ],
406
+ [
407
+ EXECUTION_LIFECYCLE_V2.RUNNING,
408
+ new Set([
409
+ EXECUTION_LIFECYCLE_V2.SUCCEEDED,
410
+ EXECUTION_LIFECYCLE_V2.FAILED,
411
+ EXECUTION_LIFECYCLE_V2.CANCELLED,
412
+ ]),
413
+ ],
414
+ [EXECUTION_LIFECYCLE_V2.SUCCEEDED, new Set()],
415
+ [EXECUTION_LIFECYCLE_V2.FAILED, new Set()],
416
+ [EXECUTION_LIFECYCLE_V2.CANCELLED, new Set()],
417
+ ]);
418
+
419
+ const _EXEC_TERMINALS_V2 = new Set([
420
+ EXECUTION_LIFECYCLE_V2.SUCCEEDED,
421
+ EXECUTION_LIFECYCLE_V2.FAILED,
422
+ EXECUTION_LIFECYCLE_V2.CANCELLED,
423
+ ]);
424
+
425
+ export const SKILL_DEFAULT_MAX_ACTIVE_PER_OWNER = 30;
426
+ export const SKILL_DEFAULT_MAX_PENDING_EXECUTIONS_PER_SKILL = 5;
427
+ export const SKILL_DEFAULT_SKILL_IDLE_MS = 30 * 24 * 60 * 60 * 1000; // 30 days
428
+ export const SKILL_DEFAULT_EXEC_STUCK_MS = 15 * 60 * 1000; // 15 min
429
+
430
+ const _stateV2 = {
431
+ skills: new Map(),
432
+ executions: new Map(),
433
+ maxActiveSkillsPerOwner: SKILL_DEFAULT_MAX_ACTIVE_PER_OWNER,
434
+ maxPendingExecutionsPerSkill: SKILL_DEFAULT_MAX_PENDING_EXECUTIONS_PER_SKILL,
435
+ skillIdleMs: SKILL_DEFAULT_SKILL_IDLE_MS,
436
+ execStuckMs: SKILL_DEFAULT_EXEC_STUCK_MS,
437
+ };
438
+
439
+ function _posIntSkillV2(n, label) {
440
+ const v = Math.floor(Number(n));
441
+ if (!Number.isFinite(v) || v <= 0) {
442
+ throw new Error(`${label} must be a positive integer, got ${n}`);
443
+ }
444
+ return v;
445
+ }
446
+
447
+ export function getMaxActiveSkillsPerOwnerV2() {
448
+ return _stateV2.maxActiveSkillsPerOwner;
449
+ }
450
+
451
+ export function setMaxActiveSkillsPerOwnerV2(n) {
452
+ _stateV2.maxActiveSkillsPerOwner = _posIntSkillV2(
453
+ n,
454
+ "maxActiveSkillsPerOwner",
455
+ );
456
+ }
457
+
458
+ export function getMaxPendingExecutionsPerSkillV2() {
459
+ return _stateV2.maxPendingExecutionsPerSkill;
460
+ }
461
+
462
+ export function setMaxPendingExecutionsPerSkillV2(n) {
463
+ _stateV2.maxPendingExecutionsPerSkill = _posIntSkillV2(
464
+ n,
465
+ "maxPendingExecutionsPerSkill",
466
+ );
467
+ }
468
+
469
+ export function getSkillIdleMsV2() {
470
+ return _stateV2.skillIdleMs;
471
+ }
472
+
473
+ export function setSkillIdleMsV2(ms) {
474
+ _stateV2.skillIdleMs = _posIntSkillV2(ms, "skillIdleMs");
475
+ }
476
+
477
+ export function getExecStuckMsV2() {
478
+ return _stateV2.execStuckMs;
479
+ }
480
+
481
+ export function setExecStuckMsV2(ms) {
482
+ _stateV2.execStuckMs = _posIntSkillV2(ms, "execStuckMs");
483
+ }
484
+
485
+ function _copySkillV2(s) {
486
+ return { ...s, metadata: { ...s.metadata } };
487
+ }
488
+
489
+ function _copyExecV2(e) {
490
+ return { ...e, metadata: { ...e.metadata } };
491
+ }
492
+
493
+ export function getActiveSkillCountV2(ownerId) {
494
+ let count = 0;
495
+ for (const s of _stateV2.skills.values()) {
496
+ if (s.ownerId === ownerId && s.status === SKILL_MATURITY_V2.ACTIVE) count++;
497
+ }
498
+ return count;
499
+ }
500
+
501
+ export function getPendingExecutionCountV2(skillId) {
502
+ let count = 0;
503
+ for (const e of _stateV2.executions.values()) {
504
+ if (
505
+ e.skillId === skillId &&
506
+ (e.status === EXECUTION_LIFECYCLE_V2.QUEUED ||
507
+ e.status === EXECUTION_LIFECYCLE_V2.RUNNING)
508
+ ) {
509
+ count++;
510
+ }
511
+ }
512
+ return count;
513
+ }
514
+
515
+ export function registerSkillV2(id, { ownerId, name, layer, metadata } = {}) {
516
+ if (!id) throw new Error("skill id is required");
517
+ if (!ownerId) throw new Error("ownerId is required");
518
+ if (!name) throw new Error("name is required");
519
+ if (_stateV2.skills.has(id)) throw new Error(`skill ${id} already exists`);
520
+ const now = Date.now();
521
+ const skill = {
522
+ id,
523
+ ownerId,
524
+ name,
525
+ layer: layer || "workspace",
526
+ status: SKILL_MATURITY_V2.PENDING,
527
+ createdAt: now,
528
+ lastSeenAt: now,
529
+ activatedAt: null,
530
+ archivedAt: null,
531
+ metadata: metadata ? { ...metadata } : {},
532
+ };
533
+ _stateV2.skills.set(id, skill);
534
+ return _copySkillV2(skill);
535
+ }
536
+
537
+ export function getSkillV2(id) {
538
+ const s = _stateV2.skills.get(id);
539
+ return s ? _copySkillV2(s) : null;
540
+ }
541
+
542
+ export function listSkillsV2({ ownerId, status, layer } = {}) {
543
+ const out = [];
544
+ for (const s of _stateV2.skills.values()) {
545
+ if (ownerId && s.ownerId !== ownerId) continue;
546
+ if (status && s.status !== status) continue;
547
+ if (layer && s.layer !== layer) continue;
548
+ out.push(_copySkillV2(s));
549
+ }
550
+ return out;
551
+ }
552
+
553
+ export function setSkillStatusV2(id, next) {
554
+ const s = _stateV2.skills.get(id);
555
+ if (!s) throw new Error(`skill ${id} not found`);
556
+ const allowed = _SKILL_TRANSITIONS_V2.get(s.status);
557
+ if (!allowed || !allowed.has(next)) {
558
+ throw new Error(`invalid skill transition: ${s.status} → ${next}`);
559
+ }
560
+ if (
561
+ s.status === SKILL_MATURITY_V2.PENDING &&
562
+ next === SKILL_MATURITY_V2.ACTIVE
563
+ ) {
564
+ const count = getActiveSkillCountV2(s.ownerId);
565
+ if (count >= _stateV2.maxActiveSkillsPerOwner) {
566
+ throw new Error(
567
+ `owner ${s.ownerId} active-skill cap reached (${count}/${_stateV2.maxActiveSkillsPerOwner})`,
568
+ );
569
+ }
570
+ }
571
+ const now = Date.now();
572
+ s.status = next;
573
+ s.lastSeenAt = now;
574
+ if (next === SKILL_MATURITY_V2.ACTIVE && !s.activatedAt) s.activatedAt = now;
575
+ if (_SKILL_TERMINALS_V2.has(next) && !s.archivedAt) s.archivedAt = now;
576
+ return _copySkillV2(s);
577
+ }
578
+
579
+ export function activateSkillV2(id) {
580
+ return setSkillStatusV2(id, SKILL_MATURITY_V2.ACTIVE);
581
+ }
582
+
583
+ export function deprecateSkillV2(id) {
584
+ return setSkillStatusV2(id, SKILL_MATURITY_V2.DEPRECATED);
585
+ }
586
+
587
+ export function archiveSkillV2(id) {
588
+ return setSkillStatusV2(id, SKILL_MATURITY_V2.ARCHIVED);
589
+ }
590
+
591
+ export function touchSkillV2(id) {
592
+ const s = _stateV2.skills.get(id);
593
+ if (!s) throw new Error(`skill ${id} not found`);
594
+ s.lastSeenAt = Date.now();
595
+ return _copySkillV2(s);
596
+ }
597
+
598
+ export function createExecutionV2(id, { skillId, kind, metadata } = {}) {
599
+ if (!id) throw new Error("execution id is required");
600
+ if (!skillId) throw new Error("skillId is required");
601
+ if (_stateV2.executions.has(id))
602
+ throw new Error(`execution ${id} already exists`);
603
+ const skill = _stateV2.skills.get(skillId);
604
+ if (!skill) throw new Error(`skill ${skillId} not found`);
605
+ const pending = getPendingExecutionCountV2(skillId);
606
+ if (pending >= _stateV2.maxPendingExecutionsPerSkill) {
607
+ throw new Error(
608
+ `skill ${skillId} pending-execution cap reached (${pending}/${_stateV2.maxPendingExecutionsPerSkill})`,
609
+ );
610
+ }
611
+ const now = Date.now();
612
+ const exec = {
613
+ id,
614
+ skillId,
615
+ kind: kind || "invoke",
616
+ status: EXECUTION_LIFECYCLE_V2.QUEUED,
617
+ createdAt: now,
618
+ lastSeenAt: now,
619
+ startedAt: null,
620
+ settledAt: null,
621
+ metadata: metadata ? { ...metadata } : {},
622
+ };
623
+ _stateV2.executions.set(id, exec);
624
+ return _copyExecV2(exec);
625
+ }
626
+
627
+ export function getExecutionV2(id) {
628
+ const e = _stateV2.executions.get(id);
629
+ return e ? _copyExecV2(e) : null;
630
+ }
631
+
632
+ export function listExecutionsV2({ skillId, status } = {}) {
633
+ const out = [];
634
+ for (const e of _stateV2.executions.values()) {
635
+ if (skillId && e.skillId !== skillId) continue;
636
+ if (status && e.status !== status) continue;
637
+ out.push(_copyExecV2(e));
638
+ }
639
+ return out;
640
+ }
641
+
642
+ export function setExecutionStatusV2(id, next) {
643
+ const e = _stateV2.executions.get(id);
644
+ if (!e) throw new Error(`execution ${id} not found`);
645
+ const allowed = _EXEC_TRANSITIONS_V2.get(e.status);
646
+ if (!allowed || !allowed.has(next)) {
647
+ throw new Error(`invalid execution transition: ${e.status} → ${next}`);
648
+ }
649
+ const now = Date.now();
650
+ e.status = next;
651
+ e.lastSeenAt = now;
652
+ if (next === EXECUTION_LIFECYCLE_V2.RUNNING && !e.startedAt)
653
+ e.startedAt = now;
654
+ if (_EXEC_TERMINALS_V2.has(next) && !e.settledAt) e.settledAt = now;
655
+ return _copyExecV2(e);
656
+ }
657
+
658
+ export function startExecutionV2(id) {
659
+ return setExecutionStatusV2(id, EXECUTION_LIFECYCLE_V2.RUNNING);
660
+ }
661
+
662
+ export function succeedExecutionV2(id) {
663
+ return setExecutionStatusV2(id, EXECUTION_LIFECYCLE_V2.SUCCEEDED);
664
+ }
665
+
666
+ export function failExecutionV2(id) {
667
+ return setExecutionStatusV2(id, EXECUTION_LIFECYCLE_V2.FAILED);
668
+ }
669
+
670
+ export function cancelExecutionV2(id) {
671
+ return setExecutionStatusV2(id, EXECUTION_LIFECYCLE_V2.CANCELLED);
672
+ }
673
+
674
+ export function autoDeprecateIdleSkillsV2({ now = Date.now() } = {}) {
675
+ const flipped = [];
676
+ for (const s of _stateV2.skills.values()) {
677
+ if (
678
+ s.status === SKILL_MATURITY_V2.ACTIVE &&
679
+ now - s.lastSeenAt > _stateV2.skillIdleMs
680
+ ) {
681
+ s.status = SKILL_MATURITY_V2.DEPRECATED;
682
+ s.lastSeenAt = now;
683
+ flipped.push(_copySkillV2(s));
684
+ }
685
+ }
686
+ return flipped;
687
+ }
688
+
689
+ export function autoFailStuckExecutionsV2({ now = Date.now() } = {}) {
690
+ const flipped = [];
691
+ for (const e of _stateV2.executions.values()) {
692
+ if (
693
+ e.status === EXECUTION_LIFECYCLE_V2.RUNNING &&
694
+ now - e.lastSeenAt > _stateV2.execStuckMs
695
+ ) {
696
+ e.status = EXECUTION_LIFECYCLE_V2.FAILED;
697
+ e.lastSeenAt = now;
698
+ if (!e.settledAt) e.settledAt = now;
699
+ flipped.push(_copyExecV2(e));
700
+ }
701
+ }
702
+ return flipped;
703
+ }
704
+
705
+ export function getSkillLoaderStatsV2() {
706
+ const skillsByStatus = {};
707
+ for (const v of Object.values(SKILL_MATURITY_V2)) skillsByStatus[v] = 0;
708
+ for (const s of _stateV2.skills.values()) skillsByStatus[s.status]++;
709
+
710
+ const executionsByStatus = {};
711
+ for (const v of Object.values(EXECUTION_LIFECYCLE_V2))
712
+ executionsByStatus[v] = 0;
713
+ for (const e of _stateV2.executions.values()) executionsByStatus[e.status]++;
714
+
715
+ return {
716
+ totalSkillsV2: _stateV2.skills.size,
717
+ totalExecutionsV2: _stateV2.executions.size,
718
+ maxActiveSkillsPerOwner: _stateV2.maxActiveSkillsPerOwner,
719
+ maxPendingExecutionsPerSkill: _stateV2.maxPendingExecutionsPerSkill,
720
+ skillIdleMs: _stateV2.skillIdleMs,
721
+ execStuckMs: _stateV2.execStuckMs,
722
+ skillsByStatus,
723
+ executionsByStatus,
724
+ };
725
+ }
726
+
727
+ export function _resetStateSkillLoaderV2() {
728
+ _stateV2.skills.clear();
729
+ _stateV2.executions.clear();
730
+ _stateV2.maxActiveSkillsPerOwner = SKILL_DEFAULT_MAX_ACTIVE_PER_OWNER;
731
+ _stateV2.maxPendingExecutionsPerSkill =
732
+ SKILL_DEFAULT_MAX_PENDING_EXECUTIONS_PER_SKILL;
733
+ _stateV2.skillIdleMs = SKILL_DEFAULT_SKILL_IDLE_MS;
734
+ _stateV2.execStuckMs = SKILL_DEFAULT_EXEC_STUCK_MS;
735
+ }
@@ -394,4 +394,329 @@ export function _resetState() {
394
394
  _services.clear();
395
395
  _invocations.clear();
396
396
  _seq = 0;
397
+ _maxConcurrentInvocationsPerService =
398
+ DEFAULT_MAX_CONCURRENT_INVOCATIONS_PER_SERVICE;
399
+ }
400
+
401
+ /* ═══════════════════════════════════════════════════════════════
402
+ * V2 (Phase 65) — Frozen enums + async invocation lifecycle +
403
+ * per-service concurrency cap + patch-merged setInvocationStatus +
404
+ * stats-v2. Strictly additive on top of the legacy surface above.
405
+ * ═══════════════════════════════════════════════════════════════ */
406
+
407
+ export const SERVICE_STATUS_V2 = Object.freeze({
408
+ DRAFT: "draft",
409
+ PUBLISHED: "published",
410
+ DEPRECATED: "deprecated",
411
+ SUSPENDED: "suspended",
412
+ });
413
+
414
+ export const INVOCATION_STATUS_V2 = Object.freeze({
415
+ PENDING: "pending",
416
+ RUNNING: "running",
417
+ SUCCESS: "success",
418
+ FAILED: "failed",
419
+ TIMEOUT: "timeout",
420
+ });
421
+
422
+ export const PRICING_MODEL_V2 = Object.freeze({
423
+ FREE: "free",
424
+ PAY_PER_CALL: "pay_per_call",
425
+ SUBSCRIPTION: "subscription",
426
+ TIERED: "tiered",
427
+ });
428
+
429
+ const DEFAULT_MAX_CONCURRENT_INVOCATIONS_PER_SERVICE = 10;
430
+ let _maxConcurrentInvocationsPerService =
431
+ DEFAULT_MAX_CONCURRENT_INVOCATIONS_PER_SERVICE;
432
+ export const MARKETPLACE_DEFAULT_MAX_CONCURRENT_INVOCATIONS =
433
+ DEFAULT_MAX_CONCURRENT_INVOCATIONS_PER_SERVICE;
434
+
435
+ export function setMaxConcurrentInvocations(n) {
436
+ if (typeof n !== "number" || !Number.isFinite(n) || n < 1) {
437
+ throw new Error("maxConcurrentInvocations must be a positive integer");
438
+ }
439
+ _maxConcurrentInvocationsPerService = Math.floor(n);
440
+ return _maxConcurrentInvocationsPerService;
441
+ }
442
+
443
+ export function getMaxConcurrentInvocations() {
444
+ return _maxConcurrentInvocationsPerService;
445
+ }
446
+
447
+ export function getActiveInvocationCount(serviceId) {
448
+ let count = 0;
449
+ for (const inv of _invocations.values()) {
450
+ if (
451
+ (serviceId == null || inv.serviceId === serviceId) &&
452
+ (inv.status === INVOCATION_STATUS_V2.PENDING ||
453
+ inv.status === INVOCATION_STATUS_V2.RUNNING)
454
+ ) {
455
+ count++;
456
+ }
457
+ }
458
+ return count;
459
+ }
460
+
461
+ // Invocation state machine:
462
+ // pending → { running, failed, timeout }
463
+ // running → { success, failed, timeout }
464
+ // success/failed/timeout are terminal.
465
+ const _invocationTerminal = new Set([
466
+ INVOCATION_STATUS_V2.SUCCESS,
467
+ INVOCATION_STATUS_V2.FAILED,
468
+ INVOCATION_STATUS_V2.TIMEOUT,
469
+ ]);
470
+ const _invocationAllowed = new Map([
471
+ [
472
+ INVOCATION_STATUS_V2.PENDING,
473
+ new Set([
474
+ INVOCATION_STATUS_V2.RUNNING,
475
+ INVOCATION_STATUS_V2.FAILED,
476
+ INVOCATION_STATUS_V2.TIMEOUT,
477
+ ]),
478
+ ],
479
+ [
480
+ INVOCATION_STATUS_V2.RUNNING,
481
+ new Set([
482
+ INVOCATION_STATUS_V2.SUCCESS,
483
+ INVOCATION_STATUS_V2.FAILED,
484
+ INVOCATION_STATUS_V2.TIMEOUT,
485
+ ]),
486
+ ],
487
+ [INVOCATION_STATUS_V2.SUCCESS, new Set([])],
488
+ [INVOCATION_STATUS_V2.FAILED, new Set([])],
489
+ [INVOCATION_STATUS_V2.TIMEOUT, new Set([])],
490
+ ]);
491
+
492
+ /**
493
+ * beginInvocationV2 — creates a PENDING invocation row (no output/duration).
494
+ * Caller drives the transition via startInvocation (→ RUNNING),
495
+ * completeInvocation (→ SUCCESS), failInvocation / timeoutInvocation,
496
+ * or the generic setInvocationStatus.
497
+ */
498
+ export function beginInvocationV2(db, config = {}) {
499
+ const serviceId = String(config.serviceId || "").trim();
500
+ if (!serviceId) throw new Error("serviceId is required");
501
+ const service = _mustGetService(serviceId);
502
+ if (service.status !== SERVICE_STATUS_V2.PUBLISHED) {
503
+ throw new Error(
504
+ `Cannot invoke non-published service (status=${service.status})`,
505
+ );
506
+ }
507
+
508
+ const activeCount = getActiveInvocationCount(serviceId);
509
+ if (activeCount >= _maxConcurrentInvocationsPerService) {
510
+ throw new Error(
511
+ `Max concurrent invocations reached: ${activeCount}/${_maxConcurrentInvocationsPerService}`,
512
+ );
513
+ }
514
+
515
+ const callerId = config.callerId ? String(config.callerId).trim() : null;
516
+ const input = config.input ?? null;
517
+ const now = Number(config.now ?? Date.now());
518
+ const id = config.id || crypto.randomUUID();
519
+
520
+ const invocation = {
521
+ id,
522
+ serviceId,
523
+ callerId,
524
+ input,
525
+ output: null,
526
+ status: INVOCATION_STATUS_V2.PENDING,
527
+ durationMs: null,
528
+ error: null,
529
+ startedAt: null,
530
+ completedAt: null,
531
+ createdAt: now,
532
+ _seq: ++_seq,
533
+ };
534
+ _invocations.set(id, invocation);
535
+
536
+ if (db) {
537
+ db.prepare(
538
+ `INSERT INTO skill_invocations (id, service_id, caller_id, input, output, status, duration_ms, error, created_at)
539
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
540
+ ).run(
541
+ id,
542
+ serviceId,
543
+ callerId,
544
+ input == null ? null : JSON.stringify(input),
545
+ null,
546
+ INVOCATION_STATUS_V2.PENDING,
547
+ null,
548
+ null,
549
+ now,
550
+ );
551
+ }
552
+
553
+ return _strip(invocation);
554
+ }
555
+
556
+ function _mustGetInvocation(invocationId) {
557
+ const inv = _invocations.get(invocationId);
558
+ if (!inv) throw new Error(`Invocation not found: ${invocationId}`);
559
+ return inv;
560
+ }
561
+
562
+ function _persistInvocation(db, invocationId, fields) {
563
+ if (!db) return;
564
+ const setClauses = Object.keys(fields)
565
+ .map((k) => `${k} = ?`)
566
+ .join(", ");
567
+ const values = Object.values(fields).map((v) =>
568
+ v && typeof v === "object" ? JSON.stringify(v) : v,
569
+ );
570
+ db.prepare(`UPDATE skill_invocations SET ${setClauses} WHERE id = ?`).run(
571
+ ...values,
572
+ invocationId,
573
+ );
574
+ }
575
+
576
+ export function startInvocation(db, invocationId, opts = {}) {
577
+ return setInvocationStatus(db, invocationId, INVOCATION_STATUS_V2.RUNNING, {
578
+ startedAt: Number(opts.now ?? Date.now()),
579
+ });
580
+ }
581
+
582
+ export function completeInvocationV2(db, invocationId, opts = {}) {
583
+ return setInvocationStatus(db, invocationId, INVOCATION_STATUS_V2.SUCCESS, {
584
+ output: opts.output ?? null,
585
+ durationMs: opts.durationMs == null ? null : Number(opts.durationMs),
586
+ });
587
+ }
588
+
589
+ export function failInvocationV2(db, invocationId, errorMessage, opts = {}) {
590
+ return setInvocationStatus(db, invocationId, INVOCATION_STATUS_V2.FAILED, {
591
+ error: errorMessage ? String(errorMessage) : null,
592
+ durationMs: opts.durationMs == null ? null : Number(opts.durationMs),
593
+ });
594
+ }
595
+
596
+ export function timeoutInvocationV2(db, invocationId, opts = {}) {
597
+ return setInvocationStatus(db, invocationId, INVOCATION_STATUS_V2.TIMEOUT, {
598
+ error: opts.error ? String(opts.error) : "timeout",
599
+ durationMs: opts.durationMs == null ? null : Number(opts.durationMs),
600
+ });
601
+ }
602
+
603
+ export function setInvocationStatus(db, invocationId, newStatus, patch = {}) {
604
+ const inv = _mustGetInvocation(invocationId);
605
+
606
+ if (!Object.values(INVOCATION_STATUS_V2).includes(newStatus)) {
607
+ throw new Error(`Unknown invocation status: ${newStatus}`);
608
+ }
609
+
610
+ const allowed = _invocationAllowed.get(inv.status);
611
+ if (!allowed || !allowed.has(newStatus)) {
612
+ throw new Error(
613
+ `Invalid invocation status transition: ${inv.status} → ${newStatus}`,
614
+ );
615
+ }
616
+
617
+ const now = Date.now();
618
+ inv.status = newStatus;
619
+
620
+ const dbFields = { status: newStatus };
621
+
622
+ if (patch.output !== undefined) {
623
+ inv.output = patch.output;
624
+ dbFields.output =
625
+ patch.output == null ? null : JSON.stringify(patch.output);
626
+ }
627
+ if (patch.error !== undefined) {
628
+ inv.error = patch.error;
629
+ dbFields.error = patch.error;
630
+ }
631
+ if (patch.durationMs !== undefined) {
632
+ const d = patch.durationMs == null ? null : Number(patch.durationMs);
633
+ if (d != null && (Number.isNaN(d) || d < 0)) {
634
+ throw new Error(`Invalid durationMs: ${patch.durationMs}`);
635
+ }
636
+ inv.durationMs = d;
637
+ dbFields.duration_ms = d;
638
+ }
639
+ if (patch.startedAt !== undefined) {
640
+ inv.startedAt = patch.startedAt;
641
+ }
642
+
643
+ if (_invocationTerminal.has(newStatus) && inv.completedAt == null) {
644
+ inv.completedAt = now;
645
+ // Bump the service's invocation counter once on terminal.
646
+ const service = _services.get(inv.serviceId);
647
+ if (service) {
648
+ service.invocationCount = (service.invocationCount || 0) + 1;
649
+ service.updatedAt = now;
650
+ _persistService(db, inv.serviceId, {
651
+ invocation_count: service.invocationCount,
652
+ updated_at: now,
653
+ });
654
+ }
655
+ }
656
+
657
+ _persistInvocation(db, invocationId, dbFields);
658
+
659
+ return _strip(inv);
660
+ }
661
+
662
+ export function getMarketplaceStatsV2() {
663
+ const services = [..._services.values()];
664
+ const invocations = [..._invocations.values()];
665
+
666
+ const servicesByStatus = {};
667
+ for (const s of Object.values(SERVICE_STATUS_V2)) servicesByStatus[s] = 0;
668
+ for (const s of services)
669
+ servicesByStatus[s.status] = (servicesByStatus[s.status] || 0) + 1;
670
+
671
+ const invocationsByStatus = {};
672
+ for (const s of Object.values(INVOCATION_STATUS_V2))
673
+ invocationsByStatus[s] = 0;
674
+ for (const inv of invocations)
675
+ invocationsByStatus[inv.status] =
676
+ (invocationsByStatus[inv.status] || 0) + 1;
677
+
678
+ const servicesByPricing = {};
679
+ for (const p of Object.values(PRICING_MODEL_V2)) servicesByPricing[p] = 0;
680
+ for (const s of services) {
681
+ const model =
682
+ s.pricing && typeof s.pricing === "object" && s.pricing.model
683
+ ? String(s.pricing.model)
684
+ : PRICING_MODEL_V2.FREE;
685
+ if (servicesByPricing[model] == null) servicesByPricing[model] = 0;
686
+ servicesByPricing[model]++;
687
+ }
688
+
689
+ let totalDuration = 0;
690
+ let durationSamples = 0;
691
+ for (const inv of invocations) {
692
+ if (inv.durationMs != null && inv.status === INVOCATION_STATUS_V2.SUCCESS) {
693
+ totalDuration += inv.durationMs;
694
+ durationSamples++;
695
+ }
696
+ }
697
+ const avgDurationMs =
698
+ durationSamples > 0
699
+ ? Number((totalDuration / durationSamples).toFixed(1))
700
+ : 0;
701
+ const successRate =
702
+ invocations.length > 0
703
+ ? Number(
704
+ (
705
+ invocationsByStatus[INVOCATION_STATUS_V2.SUCCESS] /
706
+ invocations.length
707
+ ).toFixed(3),
708
+ )
709
+ : 0;
710
+
711
+ return {
712
+ totalServices: services.length,
713
+ totalInvocations: invocations.length,
714
+ activeInvocations: getActiveInvocationCount(),
715
+ maxConcurrentInvocations: _maxConcurrentInvocationsPerService,
716
+ servicesByStatus,
717
+ invocationsByStatus,
718
+ servicesByPricing,
719
+ avgDurationMs,
720
+ successRate,
721
+ };
397
722
  }