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.
- package/package.json +1 -1
- package/src/commands/a2a.js +230 -0
- package/src/commands/activitypub.js +191 -0
- package/src/commands/agent.js +601 -0
- package/src/commands/audit.js +206 -0
- package/src/commands/bi.js +186 -0
- package/src/commands/bm25.js +162 -0
- package/src/commands/browse.js +225 -0
- package/src/commands/ccron.js +178 -0
- package/src/commands/chat.js +207 -0
- package/src/commands/compliance.js +420 -0
- package/src/commands/compt.js +176 -0
- package/src/commands/consol.js +237 -0
- package/src/commands/cowork.js +588 -0
- package/src/commands/crosschain.js +216 -0
- package/src/commands/dao.js +216 -0
- package/src/commands/dlp.js +206 -0
- package/src/commands/economy.js +211 -0
- package/src/commands/evolution.js +209 -0
- package/src/commands/evomap.js +216 -0
- package/src/commands/fflag.js +230 -0
- package/src/commands/git.js +185 -0
- package/src/commands/hardening.js +209 -0
- package/src/commands/hmemory.js +210 -0
- package/src/commands/incentive.js +209 -0
- package/src/commands/inference.js +178 -0
- package/src/commands/itbudget.js +161 -0
- package/src/commands/kg.js +206 -0
- package/src/commands/lowcode.js +201 -0
- package/src/commands/marketplace.js +206 -0
- package/src/commands/matrix.js +214 -0
- package/src/commands/mcpscaf.js +153 -0
- package/src/commands/meminj.js +153 -0
- package/src/commands/nostr.js +213 -0
- package/src/commands/orchestrate.js +217 -0
- package/src/commands/orchgov.js +156 -0
- package/src/commands/pdfp.js +160 -0
- package/src/commands/perf.js +176 -0
- package/src/commands/perm.js +156 -0
- package/src/commands/pipeline.js +211 -0
- package/src/commands/planmode.js +154 -0
- package/src/commands/privacy.js +203 -0
- package/src/commands/promcomp.js +166 -0
- package/src/commands/recommend.js +185 -0
- package/src/commands/reputation.js +208 -0
- package/src/commands/sandbox.js +206 -0
- package/src/commands/seshhook.js +153 -0
- package/src/commands/seshsearch.js +149 -0
- package/src/commands/seshtail.js +152 -0
- package/src/commands/seshu.js +160 -0
- package/src/commands/sganal.js +172 -0
- package/src/commands/siem.js +207 -0
- package/src/commands/sla.js +212 -0
- package/src/commands/slotfill.js +154 -0
- package/src/commands/social.js +159 -0
- package/src/commands/stress.js +206 -0
- package/src/commands/svccont.js +157 -0
- package/src/commands/terraform.js +206 -0
- package/src/commands/tms.js +183 -0
- package/src/commands/topiccls.js +158 -0
- package/src/commands/uprof.js +154 -0
- package/src/commands/vcheck.js +172 -0
- package/src/commands/webfetch.js +150 -0
- package/src/commands/zkp.js +218 -0
- package/src/harness/prompt-compressor.js +331 -0
- package/src/index.js +101 -1
- package/src/lib/a2a-protocol.js +373 -0
- package/src/lib/activitypub-bridge.js +343 -0
- package/src/lib/agent-economy.js +358 -0
- package/src/lib/app-builder.js +338 -0
- package/src/lib/audit-logger.js +321 -0
- package/src/lib/autonomous-agent.js +341 -0
- package/src/lib/bi-engine.js +339 -0
- package/src/lib/bm25-search.js +333 -0
- package/src/lib/browser-automation.js +352 -0
- package/src/lib/chat-core.js +336 -0
- package/src/lib/claude-code-bridge.js +341 -0
- package/src/lib/compliance-framework-reporter.js +359 -0
- package/src/lib/compliance-manager.js +330 -0
- package/src/lib/compression-telemetry.js +333 -0
- package/src/lib/content-recommender.js +370 -0
- package/src/lib/cowork-cron.js +330 -0
- package/src/lib/cowork-learning.js +333 -0
- package/src/lib/cowork-task-runner.js +362 -0
- package/src/lib/cowork-workflow.js +327 -0
- package/src/lib/cross-chain.js +365 -0
- package/src/lib/dao-governance.js +339 -0
- package/src/lib/dlp-engine.js +343 -0
- package/src/lib/evolution-system.js +336 -0
- package/src/lib/evomap-manager.js +339 -0
- package/src/lib/execution-backend.js +351 -0
- package/src/lib/feature-flags.js +330 -0
- package/src/lib/git-integration.js +343 -0
- package/src/lib/hardening-manager.js +341 -0
- package/src/lib/hierarchical-memory.js +341 -0
- package/src/lib/inference-network.js +362 -0
- package/src/lib/iteration-budget.js +357 -0
- package/src/lib/knowledge-graph.js +333 -0
- package/src/lib/matrix-bridge.js +339 -0
- package/src/lib/mcp-scaffold.js +345 -0
- package/src/lib/memory-injection.js +320 -0
- package/src/lib/nostr-bridge.js +342 -0
- package/src/lib/orchestrator.js +350 -0
- package/src/lib/pdf-parser.js +330 -0
- package/src/lib/perf-tuning.js +364 -0
- package/src/lib/permission-engine.js +319 -0
- package/src/lib/pipeline-orchestrator.js +345 -0
- package/src/lib/plan-mode.js +328 -0
- package/src/lib/privacy-computing.js +335 -0
- package/src/lib/prompt-compressor.js +1 -10
- package/src/lib/reputation-optimizer.js +340 -0
- package/src/lib/sandbox-v2.js +327 -0
- package/src/lib/service-container.js +342 -0
- package/src/lib/session-consolidator.js +352 -0
- package/src/lib/session-hooks.js +340 -0
- package/src/lib/session-search.js +334 -0
- package/src/lib/session-tail.js +320 -0
- package/src/lib/session-usage.js +329 -0
- package/src/lib/siem-exporter.js +352 -0
- package/src/lib/skill-marketplace.js +345 -0
- package/src/lib/sla-manager.js +341 -0
- package/src/lib/slot-filler.js +333 -0
- package/src/lib/social-graph-analytics.js +327 -0
- package/src/lib/social-graph.js +304 -0
- package/src/lib/stress-tester.js +342 -0
- package/src/lib/sub-agent-registry.js +359 -0
- package/src/lib/task-model-selector.js +333 -0
- package/src/lib/terraform-manager.js +333 -0
- package/src/lib/todo-manager.js +339 -0
- package/src/lib/token-incentive.js +341 -0
- package/src/lib/topic-classifier.js +353 -0
- package/src/lib/user-profile.js +325 -0
- package/src/lib/version-checker.js +335 -0
- package/src/lib/web-fetch.js +322 -0
- package/src/lib/zkp-engine.js +342 -0
package/src/lib/slot-filler.js
CHANGED
|
@@ -596,3 +596,336 @@ Keep values concise (single words or short strings).`;
|
|
|
596
596
|
return Object.keys(REQUIRED_SLOTS);
|
|
597
597
|
}
|
|
598
598
|
}
|
|
599
|
+
|
|
600
|
+
// ===== V2 Surface: Slot Filler governance overlay (CLI v0.142.0) =====
|
|
601
|
+
export const SLOTF_PROFILE_MATURITY_V2 = Object.freeze({
|
|
602
|
+
PENDING: "pending",
|
|
603
|
+
ACTIVE: "active",
|
|
604
|
+
STALE: "stale",
|
|
605
|
+
ARCHIVED: "archived",
|
|
606
|
+
});
|
|
607
|
+
export const SLOTF_FILL_LIFECYCLE_V2 = Object.freeze({
|
|
608
|
+
QUEUED: "queued",
|
|
609
|
+
FILLING: "filling",
|
|
610
|
+
FILLED: "filled",
|
|
611
|
+
FAILED: "failed",
|
|
612
|
+
CANCELLED: "cancelled",
|
|
613
|
+
});
|
|
614
|
+
const _slotfPTrans = new Map([
|
|
615
|
+
[
|
|
616
|
+
SLOTF_PROFILE_MATURITY_V2.PENDING,
|
|
617
|
+
new Set([
|
|
618
|
+
SLOTF_PROFILE_MATURITY_V2.ACTIVE,
|
|
619
|
+
SLOTF_PROFILE_MATURITY_V2.ARCHIVED,
|
|
620
|
+
]),
|
|
621
|
+
],
|
|
622
|
+
[
|
|
623
|
+
SLOTF_PROFILE_MATURITY_V2.ACTIVE,
|
|
624
|
+
new Set([
|
|
625
|
+
SLOTF_PROFILE_MATURITY_V2.STALE,
|
|
626
|
+
SLOTF_PROFILE_MATURITY_V2.ARCHIVED,
|
|
627
|
+
]),
|
|
628
|
+
],
|
|
629
|
+
[
|
|
630
|
+
SLOTF_PROFILE_MATURITY_V2.STALE,
|
|
631
|
+
new Set([
|
|
632
|
+
SLOTF_PROFILE_MATURITY_V2.ACTIVE,
|
|
633
|
+
SLOTF_PROFILE_MATURITY_V2.ARCHIVED,
|
|
634
|
+
]),
|
|
635
|
+
],
|
|
636
|
+
[SLOTF_PROFILE_MATURITY_V2.ARCHIVED, new Set()],
|
|
637
|
+
]);
|
|
638
|
+
const _slotfPTerminal = new Set([SLOTF_PROFILE_MATURITY_V2.ARCHIVED]);
|
|
639
|
+
const _slotfFTrans = new Map([
|
|
640
|
+
[
|
|
641
|
+
SLOTF_FILL_LIFECYCLE_V2.QUEUED,
|
|
642
|
+
new Set([
|
|
643
|
+
SLOTF_FILL_LIFECYCLE_V2.FILLING,
|
|
644
|
+
SLOTF_FILL_LIFECYCLE_V2.CANCELLED,
|
|
645
|
+
]),
|
|
646
|
+
],
|
|
647
|
+
[
|
|
648
|
+
SLOTF_FILL_LIFECYCLE_V2.FILLING,
|
|
649
|
+
new Set([
|
|
650
|
+
SLOTF_FILL_LIFECYCLE_V2.FILLED,
|
|
651
|
+
SLOTF_FILL_LIFECYCLE_V2.FAILED,
|
|
652
|
+
SLOTF_FILL_LIFECYCLE_V2.CANCELLED,
|
|
653
|
+
]),
|
|
654
|
+
],
|
|
655
|
+
[SLOTF_FILL_LIFECYCLE_V2.FILLED, new Set()],
|
|
656
|
+
[SLOTF_FILL_LIFECYCLE_V2.FAILED, new Set()],
|
|
657
|
+
[SLOTF_FILL_LIFECYCLE_V2.CANCELLED, new Set()],
|
|
658
|
+
]);
|
|
659
|
+
const _slotfPsV2 = new Map();
|
|
660
|
+
const _slotfFsV2 = new Map();
|
|
661
|
+
let _slotfMaxActive = 10,
|
|
662
|
+
_slotfMaxPending = 20,
|
|
663
|
+
_slotfIdleMs = 30 * 24 * 60 * 60 * 1000,
|
|
664
|
+
_slotfStuckMs = 30 * 1000;
|
|
665
|
+
function _slotfPos(n, label) {
|
|
666
|
+
const v = Math.floor(Number(n));
|
|
667
|
+
if (!Number.isFinite(v) || v <= 0)
|
|
668
|
+
throw new Error(`${label} must be positive integer`);
|
|
669
|
+
return v;
|
|
670
|
+
}
|
|
671
|
+
function _slotfCheckP(from, to) {
|
|
672
|
+
const a = _slotfPTrans.get(from);
|
|
673
|
+
if (!a || !a.has(to))
|
|
674
|
+
throw new Error(`invalid slotf profile transition ${from} → ${to}`);
|
|
675
|
+
}
|
|
676
|
+
function _slotfCheckF(from, to) {
|
|
677
|
+
const a = _slotfFTrans.get(from);
|
|
678
|
+
if (!a || !a.has(to))
|
|
679
|
+
throw new Error(`invalid slotf fill transition ${from} → ${to}`);
|
|
680
|
+
}
|
|
681
|
+
export function setMaxActiveSlotfTemplatesPerOwnerV2(n) {
|
|
682
|
+
_slotfMaxActive = _slotfPos(n, "maxActiveSlotfTemplatesPerOwner");
|
|
683
|
+
}
|
|
684
|
+
export function getMaxActiveSlotfTemplatesPerOwnerV2() {
|
|
685
|
+
return _slotfMaxActive;
|
|
686
|
+
}
|
|
687
|
+
export function setMaxPendingSlotfFillsPerTemplateV2(n) {
|
|
688
|
+
_slotfMaxPending = _slotfPos(n, "maxPendingSlotfFillsPerTemplate");
|
|
689
|
+
}
|
|
690
|
+
export function getMaxPendingSlotfFillsPerTemplateV2() {
|
|
691
|
+
return _slotfMaxPending;
|
|
692
|
+
}
|
|
693
|
+
export function setSlotfTemplateIdleMsV2(n) {
|
|
694
|
+
_slotfIdleMs = _slotfPos(n, "slotfTemplateIdleMs");
|
|
695
|
+
}
|
|
696
|
+
export function getSlotfTemplateIdleMsV2() {
|
|
697
|
+
return _slotfIdleMs;
|
|
698
|
+
}
|
|
699
|
+
export function setSlotfFillStuckMsV2(n) {
|
|
700
|
+
_slotfStuckMs = _slotfPos(n, "slotfFillStuckMs");
|
|
701
|
+
}
|
|
702
|
+
export function getSlotfFillStuckMsV2() {
|
|
703
|
+
return _slotfStuckMs;
|
|
704
|
+
}
|
|
705
|
+
export function _resetStateSlotFillerV2() {
|
|
706
|
+
_slotfPsV2.clear();
|
|
707
|
+
_slotfFsV2.clear();
|
|
708
|
+
_slotfMaxActive = 10;
|
|
709
|
+
_slotfMaxPending = 20;
|
|
710
|
+
_slotfIdleMs = 30 * 24 * 60 * 60 * 1000;
|
|
711
|
+
_slotfStuckMs = 30 * 1000;
|
|
712
|
+
}
|
|
713
|
+
export function registerSlotfTemplateV2({ id, owner, schema, metadata } = {}) {
|
|
714
|
+
if (!id) throw new Error("slotf template id required");
|
|
715
|
+
if (!owner) throw new Error("slotf template owner required");
|
|
716
|
+
if (_slotfPsV2.has(id))
|
|
717
|
+
throw new Error(`slotf template ${id} already registered`);
|
|
718
|
+
const now = Date.now();
|
|
719
|
+
const p = {
|
|
720
|
+
id,
|
|
721
|
+
owner,
|
|
722
|
+
schema: schema || "{}",
|
|
723
|
+
status: SLOTF_PROFILE_MATURITY_V2.PENDING,
|
|
724
|
+
createdAt: now,
|
|
725
|
+
updatedAt: now,
|
|
726
|
+
activatedAt: null,
|
|
727
|
+
archivedAt: null,
|
|
728
|
+
lastTouchedAt: now,
|
|
729
|
+
metadata: { ...(metadata || {}) },
|
|
730
|
+
};
|
|
731
|
+
_slotfPsV2.set(id, p);
|
|
732
|
+
return { ...p, metadata: { ...p.metadata } };
|
|
733
|
+
}
|
|
734
|
+
function _slotfCountActive(owner) {
|
|
735
|
+
let n = 0;
|
|
736
|
+
for (const p of _slotfPsV2.values())
|
|
737
|
+
if (p.owner === owner && p.status === SLOTF_PROFILE_MATURITY_V2.ACTIVE) n++;
|
|
738
|
+
return n;
|
|
739
|
+
}
|
|
740
|
+
export function activateSlotfTemplateV2(id) {
|
|
741
|
+
const p = _slotfPsV2.get(id);
|
|
742
|
+
if (!p) throw new Error(`slotf template ${id} not found`);
|
|
743
|
+
_slotfCheckP(p.status, SLOTF_PROFILE_MATURITY_V2.ACTIVE);
|
|
744
|
+
const recovery = p.status === SLOTF_PROFILE_MATURITY_V2.STALE;
|
|
745
|
+
if (!recovery && _slotfCountActive(p.owner) >= _slotfMaxActive)
|
|
746
|
+
throw new Error(`max active slotf templates for owner ${p.owner} reached`);
|
|
747
|
+
const now = Date.now();
|
|
748
|
+
p.status = SLOTF_PROFILE_MATURITY_V2.ACTIVE;
|
|
749
|
+
p.updatedAt = now;
|
|
750
|
+
p.lastTouchedAt = now;
|
|
751
|
+
if (!p.activatedAt) p.activatedAt = now;
|
|
752
|
+
return { ...p, metadata: { ...p.metadata } };
|
|
753
|
+
}
|
|
754
|
+
export function staleSlotfTemplateV2(id) {
|
|
755
|
+
const p = _slotfPsV2.get(id);
|
|
756
|
+
if (!p) throw new Error(`slotf template ${id} not found`);
|
|
757
|
+
_slotfCheckP(p.status, SLOTF_PROFILE_MATURITY_V2.STALE);
|
|
758
|
+
p.status = SLOTF_PROFILE_MATURITY_V2.STALE;
|
|
759
|
+
p.updatedAt = Date.now();
|
|
760
|
+
return { ...p, metadata: { ...p.metadata } };
|
|
761
|
+
}
|
|
762
|
+
export function archiveSlotfTemplateV2(id) {
|
|
763
|
+
const p = _slotfPsV2.get(id);
|
|
764
|
+
if (!p) throw new Error(`slotf template ${id} not found`);
|
|
765
|
+
_slotfCheckP(p.status, SLOTF_PROFILE_MATURITY_V2.ARCHIVED);
|
|
766
|
+
const now = Date.now();
|
|
767
|
+
p.status = SLOTF_PROFILE_MATURITY_V2.ARCHIVED;
|
|
768
|
+
p.updatedAt = now;
|
|
769
|
+
if (!p.archivedAt) p.archivedAt = now;
|
|
770
|
+
return { ...p, metadata: { ...p.metadata } };
|
|
771
|
+
}
|
|
772
|
+
export function touchSlotfTemplateV2(id) {
|
|
773
|
+
const p = _slotfPsV2.get(id);
|
|
774
|
+
if (!p) throw new Error(`slotf template ${id} not found`);
|
|
775
|
+
if (_slotfPTerminal.has(p.status))
|
|
776
|
+
throw new Error(`cannot touch terminal slotf template ${id}`);
|
|
777
|
+
const now = Date.now();
|
|
778
|
+
p.lastTouchedAt = now;
|
|
779
|
+
p.updatedAt = now;
|
|
780
|
+
return { ...p, metadata: { ...p.metadata } };
|
|
781
|
+
}
|
|
782
|
+
export function getSlotfTemplateV2(id) {
|
|
783
|
+
const p = _slotfPsV2.get(id);
|
|
784
|
+
if (!p) return null;
|
|
785
|
+
return { ...p, metadata: { ...p.metadata } };
|
|
786
|
+
}
|
|
787
|
+
export function listSlotfTemplatesV2() {
|
|
788
|
+
return [..._slotfPsV2.values()].map((p) => ({
|
|
789
|
+
...p,
|
|
790
|
+
metadata: { ...p.metadata },
|
|
791
|
+
}));
|
|
792
|
+
}
|
|
793
|
+
function _slotfCountPending(templateId) {
|
|
794
|
+
let n = 0;
|
|
795
|
+
for (const f of _slotfFsV2.values())
|
|
796
|
+
if (
|
|
797
|
+
f.templateId === templateId &&
|
|
798
|
+
(f.status === SLOTF_FILL_LIFECYCLE_V2.QUEUED ||
|
|
799
|
+
f.status === SLOTF_FILL_LIFECYCLE_V2.FILLING)
|
|
800
|
+
)
|
|
801
|
+
n++;
|
|
802
|
+
return n;
|
|
803
|
+
}
|
|
804
|
+
export function createSlotfFillV2({ id, templateId, input, metadata } = {}) {
|
|
805
|
+
if (!id) throw new Error("slotf fill id required");
|
|
806
|
+
if (!templateId) throw new Error("slotf fill templateId required");
|
|
807
|
+
if (_slotfFsV2.has(id)) throw new Error(`slotf fill ${id} already exists`);
|
|
808
|
+
if (!_slotfPsV2.has(templateId))
|
|
809
|
+
throw new Error(`slotf template ${templateId} not found`);
|
|
810
|
+
if (_slotfCountPending(templateId) >= _slotfMaxPending)
|
|
811
|
+
throw new Error(
|
|
812
|
+
`max pending slotf fills for template ${templateId} reached`,
|
|
813
|
+
);
|
|
814
|
+
const now = Date.now();
|
|
815
|
+
const f = {
|
|
816
|
+
id,
|
|
817
|
+
templateId,
|
|
818
|
+
input: input || "",
|
|
819
|
+
status: SLOTF_FILL_LIFECYCLE_V2.QUEUED,
|
|
820
|
+
createdAt: now,
|
|
821
|
+
updatedAt: now,
|
|
822
|
+
startedAt: null,
|
|
823
|
+
settledAt: null,
|
|
824
|
+
metadata: { ...(metadata || {}) },
|
|
825
|
+
};
|
|
826
|
+
_slotfFsV2.set(id, f);
|
|
827
|
+
return { ...f, metadata: { ...f.metadata } };
|
|
828
|
+
}
|
|
829
|
+
export function fillingSlotfFillV2(id) {
|
|
830
|
+
const f = _slotfFsV2.get(id);
|
|
831
|
+
if (!f) throw new Error(`slotf fill ${id} not found`);
|
|
832
|
+
_slotfCheckF(f.status, SLOTF_FILL_LIFECYCLE_V2.FILLING);
|
|
833
|
+
const now = Date.now();
|
|
834
|
+
f.status = SLOTF_FILL_LIFECYCLE_V2.FILLING;
|
|
835
|
+
f.updatedAt = now;
|
|
836
|
+
if (!f.startedAt) f.startedAt = now;
|
|
837
|
+
return { ...f, metadata: { ...f.metadata } };
|
|
838
|
+
}
|
|
839
|
+
export function fillSlotfFillV2(id) {
|
|
840
|
+
const f = _slotfFsV2.get(id);
|
|
841
|
+
if (!f) throw new Error(`slotf fill ${id} not found`);
|
|
842
|
+
_slotfCheckF(f.status, SLOTF_FILL_LIFECYCLE_V2.FILLED);
|
|
843
|
+
const now = Date.now();
|
|
844
|
+
f.status = SLOTF_FILL_LIFECYCLE_V2.FILLED;
|
|
845
|
+
f.updatedAt = now;
|
|
846
|
+
if (!f.settledAt) f.settledAt = now;
|
|
847
|
+
return { ...f, metadata: { ...f.metadata } };
|
|
848
|
+
}
|
|
849
|
+
export function failSlotfFillV2(id, reason) {
|
|
850
|
+
const f = _slotfFsV2.get(id);
|
|
851
|
+
if (!f) throw new Error(`slotf fill ${id} not found`);
|
|
852
|
+
_slotfCheckF(f.status, SLOTF_FILL_LIFECYCLE_V2.FAILED);
|
|
853
|
+
const now = Date.now();
|
|
854
|
+
f.status = SLOTF_FILL_LIFECYCLE_V2.FAILED;
|
|
855
|
+
f.updatedAt = now;
|
|
856
|
+
if (!f.settledAt) f.settledAt = now;
|
|
857
|
+
if (reason) f.metadata.failReason = String(reason);
|
|
858
|
+
return { ...f, metadata: { ...f.metadata } };
|
|
859
|
+
}
|
|
860
|
+
export function cancelSlotfFillV2(id, reason) {
|
|
861
|
+
const f = _slotfFsV2.get(id);
|
|
862
|
+
if (!f) throw new Error(`slotf fill ${id} not found`);
|
|
863
|
+
_slotfCheckF(f.status, SLOTF_FILL_LIFECYCLE_V2.CANCELLED);
|
|
864
|
+
const now = Date.now();
|
|
865
|
+
f.status = SLOTF_FILL_LIFECYCLE_V2.CANCELLED;
|
|
866
|
+
f.updatedAt = now;
|
|
867
|
+
if (!f.settledAt) f.settledAt = now;
|
|
868
|
+
if (reason) f.metadata.cancelReason = String(reason);
|
|
869
|
+
return { ...f, metadata: { ...f.metadata } };
|
|
870
|
+
}
|
|
871
|
+
export function getSlotfFillV2(id) {
|
|
872
|
+
const f = _slotfFsV2.get(id);
|
|
873
|
+
if (!f) return null;
|
|
874
|
+
return { ...f, metadata: { ...f.metadata } };
|
|
875
|
+
}
|
|
876
|
+
export function listSlotfFillsV2() {
|
|
877
|
+
return [..._slotfFsV2.values()].map((f) => ({
|
|
878
|
+
...f,
|
|
879
|
+
metadata: { ...f.metadata },
|
|
880
|
+
}));
|
|
881
|
+
}
|
|
882
|
+
export function autoStaleIdleSlotfTemplatesV2({ now } = {}) {
|
|
883
|
+
const t = now ?? Date.now();
|
|
884
|
+
const flipped = [];
|
|
885
|
+
for (const p of _slotfPsV2.values())
|
|
886
|
+
if (
|
|
887
|
+
p.status === SLOTF_PROFILE_MATURITY_V2.ACTIVE &&
|
|
888
|
+
t - p.lastTouchedAt >= _slotfIdleMs
|
|
889
|
+
) {
|
|
890
|
+
p.status = SLOTF_PROFILE_MATURITY_V2.STALE;
|
|
891
|
+
p.updatedAt = t;
|
|
892
|
+
flipped.push(p.id);
|
|
893
|
+
}
|
|
894
|
+
return { flipped, count: flipped.length };
|
|
895
|
+
}
|
|
896
|
+
export function autoFailStuckSlotfFillsV2({ now } = {}) {
|
|
897
|
+
const t = now ?? Date.now();
|
|
898
|
+
const flipped = [];
|
|
899
|
+
for (const f of _slotfFsV2.values())
|
|
900
|
+
if (
|
|
901
|
+
f.status === SLOTF_FILL_LIFECYCLE_V2.FILLING &&
|
|
902
|
+
f.startedAt != null &&
|
|
903
|
+
t - f.startedAt >= _slotfStuckMs
|
|
904
|
+
) {
|
|
905
|
+
f.status = SLOTF_FILL_LIFECYCLE_V2.FAILED;
|
|
906
|
+
f.updatedAt = t;
|
|
907
|
+
if (!f.settledAt) f.settledAt = t;
|
|
908
|
+
f.metadata.failReason = "auto-fail-stuck";
|
|
909
|
+
flipped.push(f.id);
|
|
910
|
+
}
|
|
911
|
+
return { flipped, count: flipped.length };
|
|
912
|
+
}
|
|
913
|
+
export function getSlotFillerGovStatsV2() {
|
|
914
|
+
const templatesByStatus = {};
|
|
915
|
+
for (const v of Object.values(SLOTF_PROFILE_MATURITY_V2))
|
|
916
|
+
templatesByStatus[v] = 0;
|
|
917
|
+
for (const p of _slotfPsV2.values()) templatesByStatus[p.status]++;
|
|
918
|
+
const fillsByStatus = {};
|
|
919
|
+
for (const v of Object.values(SLOTF_FILL_LIFECYCLE_V2)) fillsByStatus[v] = 0;
|
|
920
|
+
for (const f of _slotfFsV2.values()) fillsByStatus[f.status]++;
|
|
921
|
+
return {
|
|
922
|
+
totalSlotfTemplatesV2: _slotfPsV2.size,
|
|
923
|
+
totalSlotfFillsV2: _slotfFsV2.size,
|
|
924
|
+
maxActiveSlotfTemplatesPerOwner: _slotfMaxActive,
|
|
925
|
+
maxPendingSlotfFillsPerTemplate: _slotfMaxPending,
|
|
926
|
+
slotfTemplateIdleMs: _slotfIdleMs,
|
|
927
|
+
slotfFillStuckMs: _slotfStuckMs,
|
|
928
|
+
templatesByStatus,
|
|
929
|
+
fillsByStatus,
|
|
930
|
+
};
|
|
931
|
+
}
|
|
@@ -705,3 +705,330 @@ export function analyticsStats(snapshot, opts = {}) {
|
|
|
705
705
|
generatedAt: new Date().toISOString(),
|
|
706
706
|
};
|
|
707
707
|
}
|
|
708
|
+
|
|
709
|
+
// =====================================================================
|
|
710
|
+
// Social Graph Analytics V2 governance overlay
|
|
711
|
+
// =====================================================================
|
|
712
|
+
export const SGAN_PROFILE_MATURITY_V2 = Object.freeze({
|
|
713
|
+
PENDING: "pending",
|
|
714
|
+
ACTIVE: "active",
|
|
715
|
+
STALE: "stale",
|
|
716
|
+
ARCHIVED: "archived",
|
|
717
|
+
});
|
|
718
|
+
export const SGAN_RUN_LIFECYCLE_V2 = Object.freeze({
|
|
719
|
+
QUEUED: "queued",
|
|
720
|
+
RUNNING: "running",
|
|
721
|
+
COMPLETED: "completed",
|
|
722
|
+
FAILED: "failed",
|
|
723
|
+
CANCELLED: "cancelled",
|
|
724
|
+
});
|
|
725
|
+
const _sganPTrans = new Map([
|
|
726
|
+
[
|
|
727
|
+
SGAN_PROFILE_MATURITY_V2.PENDING,
|
|
728
|
+
new Set([
|
|
729
|
+
SGAN_PROFILE_MATURITY_V2.ACTIVE,
|
|
730
|
+
SGAN_PROFILE_MATURITY_V2.ARCHIVED,
|
|
731
|
+
]),
|
|
732
|
+
],
|
|
733
|
+
[
|
|
734
|
+
SGAN_PROFILE_MATURITY_V2.ACTIVE,
|
|
735
|
+
new Set([
|
|
736
|
+
SGAN_PROFILE_MATURITY_V2.STALE,
|
|
737
|
+
SGAN_PROFILE_MATURITY_V2.ARCHIVED,
|
|
738
|
+
]),
|
|
739
|
+
],
|
|
740
|
+
[
|
|
741
|
+
SGAN_PROFILE_MATURITY_V2.STALE,
|
|
742
|
+
new Set([
|
|
743
|
+
SGAN_PROFILE_MATURITY_V2.ACTIVE,
|
|
744
|
+
SGAN_PROFILE_MATURITY_V2.ARCHIVED,
|
|
745
|
+
]),
|
|
746
|
+
],
|
|
747
|
+
[SGAN_PROFILE_MATURITY_V2.ARCHIVED, new Set()],
|
|
748
|
+
]);
|
|
749
|
+
const _sganPTerminal = new Set([SGAN_PROFILE_MATURITY_V2.ARCHIVED]);
|
|
750
|
+
const _sganJTrans = new Map([
|
|
751
|
+
[
|
|
752
|
+
SGAN_RUN_LIFECYCLE_V2.QUEUED,
|
|
753
|
+
new Set([SGAN_RUN_LIFECYCLE_V2.RUNNING, SGAN_RUN_LIFECYCLE_V2.CANCELLED]),
|
|
754
|
+
],
|
|
755
|
+
[
|
|
756
|
+
SGAN_RUN_LIFECYCLE_V2.RUNNING,
|
|
757
|
+
new Set([
|
|
758
|
+
SGAN_RUN_LIFECYCLE_V2.COMPLETED,
|
|
759
|
+
SGAN_RUN_LIFECYCLE_V2.FAILED,
|
|
760
|
+
SGAN_RUN_LIFECYCLE_V2.CANCELLED,
|
|
761
|
+
]),
|
|
762
|
+
],
|
|
763
|
+
[SGAN_RUN_LIFECYCLE_V2.COMPLETED, new Set()],
|
|
764
|
+
[SGAN_RUN_LIFECYCLE_V2.FAILED, new Set()],
|
|
765
|
+
[SGAN_RUN_LIFECYCLE_V2.CANCELLED, new Set()],
|
|
766
|
+
]);
|
|
767
|
+
const _sganPsV2 = new Map();
|
|
768
|
+
const _sganJsV2 = new Map();
|
|
769
|
+
let _sganMaxActive = 6,
|
|
770
|
+
_sganMaxPending = 12,
|
|
771
|
+
_sganIdleMs = 30 * 24 * 60 * 60 * 1000,
|
|
772
|
+
_sganStuckMs = 60 * 1000;
|
|
773
|
+
function _sganPos(n, label) {
|
|
774
|
+
const v = Math.floor(Number(n));
|
|
775
|
+
if (!Number.isFinite(v) || v <= 0)
|
|
776
|
+
throw new Error(`${label} must be positive integer`);
|
|
777
|
+
return v;
|
|
778
|
+
}
|
|
779
|
+
function _sganCheckP(from, to) {
|
|
780
|
+
const a = _sganPTrans.get(from);
|
|
781
|
+
if (!a || !a.has(to))
|
|
782
|
+
throw new Error(`invalid sgan profile transition ${from} → ${to}`);
|
|
783
|
+
}
|
|
784
|
+
function _sganCheckJ(from, to) {
|
|
785
|
+
const a = _sganJTrans.get(from);
|
|
786
|
+
if (!a || !a.has(to))
|
|
787
|
+
throw new Error(`invalid sgan run transition ${from} → ${to}`);
|
|
788
|
+
}
|
|
789
|
+
function _sganCountActive(owner) {
|
|
790
|
+
let c = 0;
|
|
791
|
+
for (const p of _sganPsV2.values())
|
|
792
|
+
if (p.owner === owner && p.status === SGAN_PROFILE_MATURITY_V2.ACTIVE) c++;
|
|
793
|
+
return c;
|
|
794
|
+
}
|
|
795
|
+
function _sganCountPending(profileId) {
|
|
796
|
+
let c = 0;
|
|
797
|
+
for (const j of _sganJsV2.values())
|
|
798
|
+
if (
|
|
799
|
+
j.profileId === profileId &&
|
|
800
|
+
(j.status === SGAN_RUN_LIFECYCLE_V2.QUEUED ||
|
|
801
|
+
j.status === SGAN_RUN_LIFECYCLE_V2.RUNNING)
|
|
802
|
+
)
|
|
803
|
+
c++;
|
|
804
|
+
return c;
|
|
805
|
+
}
|
|
806
|
+
export function setMaxActiveSganProfilesPerOwnerV2(n) {
|
|
807
|
+
_sganMaxActive = _sganPos(n, "maxActiveSganProfilesPerOwner");
|
|
808
|
+
}
|
|
809
|
+
export function getMaxActiveSganProfilesPerOwnerV2() {
|
|
810
|
+
return _sganMaxActive;
|
|
811
|
+
}
|
|
812
|
+
export function setMaxPendingSganRunsPerProfileV2(n) {
|
|
813
|
+
_sganMaxPending = _sganPos(n, "maxPendingSganRunsPerProfile");
|
|
814
|
+
}
|
|
815
|
+
export function getMaxPendingSganRunsPerProfileV2() {
|
|
816
|
+
return _sganMaxPending;
|
|
817
|
+
}
|
|
818
|
+
export function setSganProfileIdleMsV2(n) {
|
|
819
|
+
_sganIdleMs = _sganPos(n, "sganProfileIdleMs");
|
|
820
|
+
}
|
|
821
|
+
export function getSganProfileIdleMsV2() {
|
|
822
|
+
return _sganIdleMs;
|
|
823
|
+
}
|
|
824
|
+
export function setSganRunStuckMsV2(n) {
|
|
825
|
+
_sganStuckMs = _sganPos(n, "sganRunStuckMs");
|
|
826
|
+
}
|
|
827
|
+
export function getSganRunStuckMsV2() {
|
|
828
|
+
return _sganStuckMs;
|
|
829
|
+
}
|
|
830
|
+
export function _resetStateSocialGraphAnalyticsV2() {
|
|
831
|
+
_sganPsV2.clear();
|
|
832
|
+
_sganJsV2.clear();
|
|
833
|
+
_sganMaxActive = 6;
|
|
834
|
+
_sganMaxPending = 12;
|
|
835
|
+
_sganIdleMs = 30 * 24 * 60 * 60 * 1000;
|
|
836
|
+
_sganStuckMs = 60 * 1000;
|
|
837
|
+
}
|
|
838
|
+
export function registerSganProfileV2({ id, owner, algorithm, metadata } = {}) {
|
|
839
|
+
if (!id || !owner) throw new Error("id and owner required");
|
|
840
|
+
if (_sganPsV2.has(id)) throw new Error(`sgan profile ${id} already exists`);
|
|
841
|
+
const now = Date.now();
|
|
842
|
+
const p = {
|
|
843
|
+
id,
|
|
844
|
+
owner,
|
|
845
|
+
algorithm: algorithm || "centrality",
|
|
846
|
+
status: SGAN_PROFILE_MATURITY_V2.PENDING,
|
|
847
|
+
createdAt: now,
|
|
848
|
+
updatedAt: now,
|
|
849
|
+
lastTouchedAt: now,
|
|
850
|
+
activatedAt: null,
|
|
851
|
+
archivedAt: null,
|
|
852
|
+
metadata: { ...(metadata || {}) },
|
|
853
|
+
};
|
|
854
|
+
_sganPsV2.set(id, p);
|
|
855
|
+
return { ...p, metadata: { ...p.metadata } };
|
|
856
|
+
}
|
|
857
|
+
export function activateSganProfileV2(id) {
|
|
858
|
+
const p = _sganPsV2.get(id);
|
|
859
|
+
if (!p) throw new Error(`sgan profile ${id} not found`);
|
|
860
|
+
const isInitial = p.status === SGAN_PROFILE_MATURITY_V2.PENDING;
|
|
861
|
+
_sganCheckP(p.status, SGAN_PROFILE_MATURITY_V2.ACTIVE);
|
|
862
|
+
if (isInitial && _sganCountActive(p.owner) >= _sganMaxActive)
|
|
863
|
+
throw new Error(`max active sgan profiles for owner ${p.owner} reached`);
|
|
864
|
+
const now = Date.now();
|
|
865
|
+
p.status = SGAN_PROFILE_MATURITY_V2.ACTIVE;
|
|
866
|
+
p.updatedAt = now;
|
|
867
|
+
p.lastTouchedAt = now;
|
|
868
|
+
if (!p.activatedAt) p.activatedAt = now;
|
|
869
|
+
return { ...p, metadata: { ...p.metadata } };
|
|
870
|
+
}
|
|
871
|
+
export function staleSganProfileV2(id) {
|
|
872
|
+
const p = _sganPsV2.get(id);
|
|
873
|
+
if (!p) throw new Error(`sgan profile ${id} not found`);
|
|
874
|
+
_sganCheckP(p.status, SGAN_PROFILE_MATURITY_V2.STALE);
|
|
875
|
+
p.status = SGAN_PROFILE_MATURITY_V2.STALE;
|
|
876
|
+
p.updatedAt = Date.now();
|
|
877
|
+
return { ...p, metadata: { ...p.metadata } };
|
|
878
|
+
}
|
|
879
|
+
export function archiveSganProfileV2(id) {
|
|
880
|
+
const p = _sganPsV2.get(id);
|
|
881
|
+
if (!p) throw new Error(`sgan profile ${id} not found`);
|
|
882
|
+
_sganCheckP(p.status, SGAN_PROFILE_MATURITY_V2.ARCHIVED);
|
|
883
|
+
const now = Date.now();
|
|
884
|
+
p.status = SGAN_PROFILE_MATURITY_V2.ARCHIVED;
|
|
885
|
+
p.updatedAt = now;
|
|
886
|
+
if (!p.archivedAt) p.archivedAt = now;
|
|
887
|
+
return { ...p, metadata: { ...p.metadata } };
|
|
888
|
+
}
|
|
889
|
+
export function touchSganProfileV2(id) {
|
|
890
|
+
const p = _sganPsV2.get(id);
|
|
891
|
+
if (!p) throw new Error(`sgan profile ${id} not found`);
|
|
892
|
+
if (_sganPTerminal.has(p.status))
|
|
893
|
+
throw new Error(`cannot touch terminal sgan profile ${id}`);
|
|
894
|
+
const now = Date.now();
|
|
895
|
+
p.lastTouchedAt = now;
|
|
896
|
+
p.updatedAt = now;
|
|
897
|
+
return { ...p, metadata: { ...p.metadata } };
|
|
898
|
+
}
|
|
899
|
+
export function getSganProfileV2(id) {
|
|
900
|
+
const p = _sganPsV2.get(id);
|
|
901
|
+
if (!p) return null;
|
|
902
|
+
return { ...p, metadata: { ...p.metadata } };
|
|
903
|
+
}
|
|
904
|
+
export function listSganProfilesV2() {
|
|
905
|
+
return [..._sganPsV2.values()].map((p) => ({
|
|
906
|
+
...p,
|
|
907
|
+
metadata: { ...p.metadata },
|
|
908
|
+
}));
|
|
909
|
+
}
|
|
910
|
+
export function createSganRunV2({ id, profileId, snapshotId, metadata } = {}) {
|
|
911
|
+
if (!id || !profileId) throw new Error("id and profileId required");
|
|
912
|
+
if (_sganJsV2.has(id)) throw new Error(`sgan run ${id} already exists`);
|
|
913
|
+
if (!_sganPsV2.has(profileId))
|
|
914
|
+
throw new Error(`sgan profile ${profileId} not found`);
|
|
915
|
+
if (_sganCountPending(profileId) >= _sganMaxPending)
|
|
916
|
+
throw new Error(`max pending sgan runs for profile ${profileId} reached`);
|
|
917
|
+
const now = Date.now();
|
|
918
|
+
const j = {
|
|
919
|
+
id,
|
|
920
|
+
profileId,
|
|
921
|
+
snapshotId: snapshotId || "",
|
|
922
|
+
status: SGAN_RUN_LIFECYCLE_V2.QUEUED,
|
|
923
|
+
createdAt: now,
|
|
924
|
+
updatedAt: now,
|
|
925
|
+
startedAt: null,
|
|
926
|
+
settledAt: null,
|
|
927
|
+
metadata: { ...(metadata || {}) },
|
|
928
|
+
};
|
|
929
|
+
_sganJsV2.set(id, j);
|
|
930
|
+
return { ...j, metadata: { ...j.metadata } };
|
|
931
|
+
}
|
|
932
|
+
export function runningSganRunV2(id) {
|
|
933
|
+
const j = _sganJsV2.get(id);
|
|
934
|
+
if (!j) throw new Error(`sgan run ${id} not found`);
|
|
935
|
+
_sganCheckJ(j.status, SGAN_RUN_LIFECYCLE_V2.RUNNING);
|
|
936
|
+
const now = Date.now();
|
|
937
|
+
j.status = SGAN_RUN_LIFECYCLE_V2.RUNNING;
|
|
938
|
+
j.updatedAt = now;
|
|
939
|
+
if (!j.startedAt) j.startedAt = now;
|
|
940
|
+
return { ...j, metadata: { ...j.metadata } };
|
|
941
|
+
}
|
|
942
|
+
export function completeSganRunV2(id) {
|
|
943
|
+
const j = _sganJsV2.get(id);
|
|
944
|
+
if (!j) throw new Error(`sgan run ${id} not found`);
|
|
945
|
+
_sganCheckJ(j.status, SGAN_RUN_LIFECYCLE_V2.COMPLETED);
|
|
946
|
+
const now = Date.now();
|
|
947
|
+
j.status = SGAN_RUN_LIFECYCLE_V2.COMPLETED;
|
|
948
|
+
j.updatedAt = now;
|
|
949
|
+
if (!j.settledAt) j.settledAt = now;
|
|
950
|
+
return { ...j, metadata: { ...j.metadata } };
|
|
951
|
+
}
|
|
952
|
+
export function failSganRunV2(id, reason) {
|
|
953
|
+
const j = _sganJsV2.get(id);
|
|
954
|
+
if (!j) throw new Error(`sgan run ${id} not found`);
|
|
955
|
+
_sganCheckJ(j.status, SGAN_RUN_LIFECYCLE_V2.FAILED);
|
|
956
|
+
const now = Date.now();
|
|
957
|
+
j.status = SGAN_RUN_LIFECYCLE_V2.FAILED;
|
|
958
|
+
j.updatedAt = now;
|
|
959
|
+
if (!j.settledAt) j.settledAt = now;
|
|
960
|
+
if (reason) j.metadata.failReason = String(reason);
|
|
961
|
+
return { ...j, metadata: { ...j.metadata } };
|
|
962
|
+
}
|
|
963
|
+
export function cancelSganRunV2(id, reason) {
|
|
964
|
+
const j = _sganJsV2.get(id);
|
|
965
|
+
if (!j) throw new Error(`sgan run ${id} not found`);
|
|
966
|
+
_sganCheckJ(j.status, SGAN_RUN_LIFECYCLE_V2.CANCELLED);
|
|
967
|
+
const now = Date.now();
|
|
968
|
+
j.status = SGAN_RUN_LIFECYCLE_V2.CANCELLED;
|
|
969
|
+
j.updatedAt = now;
|
|
970
|
+
if (!j.settledAt) j.settledAt = now;
|
|
971
|
+
if (reason) j.metadata.cancelReason = String(reason);
|
|
972
|
+
return { ...j, metadata: { ...j.metadata } };
|
|
973
|
+
}
|
|
974
|
+
export function getSganRunV2(id) {
|
|
975
|
+
const j = _sganJsV2.get(id);
|
|
976
|
+
if (!j) return null;
|
|
977
|
+
return { ...j, metadata: { ...j.metadata } };
|
|
978
|
+
}
|
|
979
|
+
export function listSganRunsV2() {
|
|
980
|
+
return [..._sganJsV2.values()].map((j) => ({
|
|
981
|
+
...j,
|
|
982
|
+
metadata: { ...j.metadata },
|
|
983
|
+
}));
|
|
984
|
+
}
|
|
985
|
+
export function autoStaleIdleSganProfilesV2({ now } = {}) {
|
|
986
|
+
const t = now ?? Date.now();
|
|
987
|
+
const flipped = [];
|
|
988
|
+
for (const p of _sganPsV2.values())
|
|
989
|
+
if (
|
|
990
|
+
p.status === SGAN_PROFILE_MATURITY_V2.ACTIVE &&
|
|
991
|
+
t - p.lastTouchedAt >= _sganIdleMs
|
|
992
|
+
) {
|
|
993
|
+
p.status = SGAN_PROFILE_MATURITY_V2.STALE;
|
|
994
|
+
p.updatedAt = t;
|
|
995
|
+
flipped.push(p.id);
|
|
996
|
+
}
|
|
997
|
+
return { flipped, count: flipped.length };
|
|
998
|
+
}
|
|
999
|
+
export function autoFailStuckSganRunsV2({ now } = {}) {
|
|
1000
|
+
const t = now ?? Date.now();
|
|
1001
|
+
const flipped = [];
|
|
1002
|
+
for (const j of _sganJsV2.values())
|
|
1003
|
+
if (
|
|
1004
|
+
j.status === SGAN_RUN_LIFECYCLE_V2.RUNNING &&
|
|
1005
|
+
j.startedAt != null &&
|
|
1006
|
+
t - j.startedAt >= _sganStuckMs
|
|
1007
|
+
) {
|
|
1008
|
+
j.status = SGAN_RUN_LIFECYCLE_V2.FAILED;
|
|
1009
|
+
j.updatedAt = t;
|
|
1010
|
+
if (!j.settledAt) j.settledAt = t;
|
|
1011
|
+
j.metadata.failReason = "auto-fail-stuck";
|
|
1012
|
+
flipped.push(j.id);
|
|
1013
|
+
}
|
|
1014
|
+
return { flipped, count: flipped.length };
|
|
1015
|
+
}
|
|
1016
|
+
export function getSocialGraphAnalyticsGovStatsV2() {
|
|
1017
|
+
const profilesByStatus = {};
|
|
1018
|
+
for (const v of Object.values(SGAN_PROFILE_MATURITY_V2))
|
|
1019
|
+
profilesByStatus[v] = 0;
|
|
1020
|
+
for (const p of _sganPsV2.values()) profilesByStatus[p.status]++;
|
|
1021
|
+
const runsByStatus = {};
|
|
1022
|
+
for (const v of Object.values(SGAN_RUN_LIFECYCLE_V2)) runsByStatus[v] = 0;
|
|
1023
|
+
for (const j of _sganJsV2.values()) runsByStatus[j.status]++;
|
|
1024
|
+
return {
|
|
1025
|
+
totalSganProfilesV2: _sganPsV2.size,
|
|
1026
|
+
totalSganRunsV2: _sganJsV2.size,
|
|
1027
|
+
maxActiveSganProfilesPerOwner: _sganMaxActive,
|
|
1028
|
+
maxPendingSganRunsPerProfile: _sganMaxPending,
|
|
1029
|
+
sganProfileIdleMs: _sganIdleMs,
|
|
1030
|
+
sganRunStuckMs: _sganStuckMs,
|
|
1031
|
+
profilesByStatus,
|
|
1032
|
+
runsByStatus,
|
|
1033
|
+
};
|
|
1034
|
+
}
|