chainlesschain 0.81.0 → 0.143.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/chainlesschain.js +0 -0
- package/package.json +1 -1
- package/src/commands/a2a.js +62 -0
- package/src/commands/activitypub.js +61 -0
- package/src/commands/agent-network.js +254 -1
- package/src/commands/agent.js +117 -0
- package/src/commands/audit.js +302 -0
- package/src/commands/automation.js +271 -1
- package/src/commands/bi.js +61 -0
- package/src/commands/bm25.js +78 -0
- package/src/commands/browse.js +64 -0
- package/src/commands/ccron.js +78 -0
- package/src/commands/codegen.js +224 -0
- package/src/commands/collab.js +341 -0
- package/src/commands/compliance.js +1075 -0
- package/src/commands/compt.js +78 -0
- package/src/commands/consol.js +231 -0
- package/src/commands/cowork.js +263 -0
- package/src/commands/crosschain.js +62 -0
- package/src/commands/dao.js +62 -0
- package/src/commands/dbevo.js +284 -0
- package/src/commands/dev.js +252 -0
- package/src/commands/did.js +358 -0
- package/src/commands/dlp.js +61 -0
- package/src/commands/economy.js +56 -0
- package/src/commands/encrypt.js +341 -0
- package/src/commands/evolution.js +56 -0
- package/src/commands/evomap.js +61 -0
- package/src/commands/export.js +256 -1
- package/src/commands/fflag.js +178 -0
- package/src/commands/fusion.js +258 -0
- package/src/commands/git.js +45 -0
- package/src/commands/governance.js +325 -0
- package/src/commands/hardening.js +411 -0
- package/src/commands/hmemory.js +56 -0
- package/src/commands/hook.js +148 -0
- package/src/commands/import.js +252 -0
- package/src/commands/incentive.js +322 -0
- package/src/commands/inference.js +42 -0
- package/src/commands/infra.js +244 -0
- package/src/commands/instinct.js +260 -0
- package/src/commands/ipfs.js +318 -0
- package/src/commands/itbudget.js +45 -0
- package/src/commands/kg.js +387 -0
- package/src/commands/llm.js +263 -0
- package/src/commands/lowcode.js +44 -0
- package/src/commands/matrix.js +62 -0
- package/src/commands/mcp.js +221 -0
- package/src/commands/mcpscaf.js +41 -0
- package/src/commands/meminj.js +41 -0
- package/src/commands/memory.js +248 -0
- package/src/commands/multimodal.js +296 -0
- package/src/commands/nlprog.js +356 -0
- package/src/commands/nostr.js +62 -0
- package/src/commands/note.js +244 -0
- package/src/commands/ops.js +354 -0
- package/src/commands/orchestrate.js +166 -0
- package/src/commands/orchgov.js +45 -0
- package/src/commands/org.js +277 -0
- package/src/commands/p2p.js +390 -0
- package/src/commands/pdfp.js +78 -0
- package/src/commands/perception.js +290 -0
- package/src/commands/perf.js +39 -0
- package/src/commands/perm.js +45 -0
- package/src/commands/permmem.js +251 -0
- package/src/commands/pipeline.js +57 -1
- package/src/commands/planmode.js +45 -0
- package/src/commands/plugin-ecosystem.js +273 -0
- package/src/commands/pqc.js +393 -0
- package/src/commands/promcomp.js +82 -0
- package/src/commands/quantization.js +351 -0
- package/src/commands/rcache.js +271 -0
- package/src/commands/recommend.js +382 -0
- package/src/commands/runtime.js +307 -0
- package/src/commands/scim.js +262 -0
- package/src/commands/seshhook.js +41 -0
- package/src/commands/seshsearch.js +41 -0
- package/src/commands/seshtail.js +41 -0
- package/src/commands/seshu.js +41 -0
- package/src/commands/session.js +258 -0
- package/src/commands/sganal.js +78 -0
- package/src/commands/siem.js +40 -0
- package/src/commands/skill.js +267 -1
- package/src/commands/slotfill.js +41 -0
- package/src/commands/social.js +290 -0
- package/src/commands/sso.js +186 -1
- package/src/commands/svccont.js +45 -0
- package/src/commands/sync.js +256 -0
- package/src/commands/tech.js +338 -0
- package/src/commands/tenant.js +351 -0
- package/src/commands/tms.js +45 -0
- package/src/commands/tokens.js +269 -0
- package/src/commands/topiccls.js +45 -0
- package/src/commands/trust.js +249 -0
- package/src/commands/uprof.js +45 -0
- package/src/commands/vcheck.js +78 -0
- package/src/commands/wallet.js +277 -0
- package/src/commands/webfetch.js +41 -0
- package/src/commands/workflow.js +171 -0
- package/src/commands/zkp.js +62 -0
- package/src/harness/prompt-compressor.js +331 -0
- package/src/index.js +65 -1
- package/src/lib/a2a-protocol.js +105 -0
- package/src/lib/activitypub-bridge.js +105 -0
- package/src/lib/agent-coordinator.js +325 -0
- package/src/lib/agent-economy.js +105 -0
- package/src/lib/agent-network.js +387 -0
- package/src/lib/agent-router.js +395 -0
- package/src/lib/aiops.js +478 -0
- package/src/lib/app-builder.js +105 -0
- package/src/lib/audit-logger.js +379 -0
- package/src/lib/automation-engine.js +330 -0
- package/src/lib/autonomous-agent.js +105 -0
- package/src/lib/autonomous-developer.js +350 -0
- package/src/lib/bi-engine.js +105 -0
- package/src/lib/bm25-search.js +81 -0
- package/src/lib/browser-automation.js +105 -0
- package/src/lib/code-agent.js +323 -0
- package/src/lib/collaboration-governance.js +364 -0
- package/src/lib/community-governance.js +436 -0
- package/src/lib/compliance-framework-reporter.js +105 -0
- package/src/lib/compliance-manager.js +434 -0
- package/src/lib/compression-telemetry.js +81 -0
- package/src/lib/content-recommendation.js +469 -0
- package/src/lib/content-recommender.js +105 -0
- package/src/lib/cowork-cron.js +81 -0
- package/src/lib/cowork-task-runner.js +105 -0
- package/src/lib/cross-chain.js +105 -0
- package/src/lib/crypto-manager.js +350 -0
- package/src/lib/dao-governance.js +105 -0
- package/src/lib/dbevo.js +338 -0
- package/src/lib/decentral-infra.js +340 -0
- package/src/lib/did-manager.js +367 -0
- package/src/lib/dlp-engine.js +105 -0
- package/src/lib/evolution-system.js +105 -0
- package/src/lib/evomap-manager.js +105 -0
- package/src/lib/execution-backend.js +105 -0
- package/src/lib/feature-flags.js +85 -0
- package/src/lib/git-integration.js +105 -0
- package/src/lib/hardening-manager.js +348 -0
- package/src/lib/hierarchical-memory.js +105 -0
- package/src/lib/hook-manager.js +380 -0
- package/src/lib/inference-network.js +105 -0
- package/src/lib/instinct-manager.js +332 -0
- package/src/lib/ipfs-storage.js +334 -0
- package/src/lib/iteration-budget.js +105 -0
- package/src/lib/knowledge-exporter.js +381 -0
- package/src/lib/knowledge-graph.js +432 -0
- package/src/lib/knowledge-importer.js +379 -0
- package/src/lib/llm-providers.js +391 -0
- package/src/lib/matrix-bridge.js +105 -0
- package/src/lib/mcp-registry.js +333 -0
- package/src/lib/mcp-scaffold.js +81 -0
- package/src/lib/memory-injection.js +81 -0
- package/src/lib/memory-manager.js +330 -0
- package/src/lib/multimodal.js +346 -0
- package/src/lib/nl-programming.js +343 -0
- package/src/lib/nostr-bridge.js +105 -0
- package/src/lib/note-versioning.js +327 -0
- package/src/lib/orchestrator.js +105 -0
- package/src/lib/org-manager.js +323 -0
- package/src/lib/p2p-manager.js +387 -0
- package/src/lib/pdf-parser.js +81 -0
- package/src/lib/perception.js +346 -0
- package/src/lib/perf-tuning.js +109 -1
- package/src/lib/permanent-memory.js +320 -0
- package/src/lib/permission-engine.js +81 -0
- package/src/lib/pipeline-orchestrator.js +105 -0
- package/src/lib/plan-mode.js +81 -0
- package/src/lib/plugin-ecosystem.js +377 -0
- package/src/lib/pqc-manager.js +368 -0
- package/src/lib/prompt-compressor.js +1 -10
- package/src/lib/protocol-fusion.js +417 -0
- package/src/lib/quantization.js +325 -0
- package/src/lib/response-cache.js +327 -0
- package/src/lib/scim-manager.js +329 -0
- package/src/lib/service-container.js +81 -0
- package/src/lib/session-consolidator.js +105 -0
- package/src/lib/session-hooks.js +81 -0
- package/src/lib/session-manager.js +329 -0
- package/src/lib/session-search.js +81 -0
- package/src/lib/session-tail.js +81 -0
- package/src/lib/session-usage.js +83 -0
- package/src/lib/siem-exporter.js +105 -0
- package/src/lib/skill-loader.js +377 -0
- package/src/lib/slot-filler.js +81 -0
- package/src/lib/social-graph-analytics.js +81 -0
- package/src/lib/social-graph.js +81 -0
- package/src/lib/social-manager.js +326 -0
- package/src/lib/sso-manager.js +332 -0
- package/src/lib/sub-agent-registry.js +110 -0
- package/src/lib/sync-manager.js +326 -0
- package/src/lib/task-model-selector.js +81 -0
- package/src/lib/tech-learning-engine.js +369 -0
- package/src/lib/tenant-saas.js +460 -0
- package/src/lib/threat-intel.js +335 -0
- package/src/lib/todo-manager.js +105 -0
- package/src/lib/token-incentive.js +293 -0
- package/src/lib/token-tracker.js +329 -0
- package/src/lib/topic-classifier.js +105 -0
- package/src/lib/trust-security.js +390 -0
- package/src/lib/ueba.js +389 -0
- package/src/lib/universal-runtime.js +325 -0
- package/src/lib/user-profile.js +81 -0
- package/src/lib/version-checker.js +81 -0
- package/src/lib/wallet-manager.js +326 -0
- package/src/lib/web-fetch.js +81 -0
- package/src/lib/workflow-engine.js +322 -0
- package/src/lib/zkp-engine.js +105 -0
|
@@ -528,3 +528,435 @@ export function _resetState() {
|
|
|
528
528
|
_inEdges.clear();
|
|
529
529
|
_seq = 0;
|
|
530
530
|
}
|
|
531
|
+
|
|
532
|
+
/* ═══════════════════════════════════════════════════════════════
|
|
533
|
+
* V2 SURFACE — Phase 94 lifecycle state machines
|
|
534
|
+
* ═══════════════════════════════════════════════════════════════
|
|
535
|
+
*
|
|
536
|
+
* V2 adds two parallel lifecycles on top of the legacy entity/relation
|
|
537
|
+
* store. Nothing above is modified.
|
|
538
|
+
*
|
|
539
|
+
* Entity maturity: active → { deprecated, archived }
|
|
540
|
+
* deprecated → { active, archived, removed }
|
|
541
|
+
* archived → { active, removed }
|
|
542
|
+
* Terminal: removed
|
|
543
|
+
*
|
|
544
|
+
* Relation status: active → { deprecated, removed }
|
|
545
|
+
* deprecated → { active, removed }
|
|
546
|
+
* Terminal: removed
|
|
547
|
+
*
|
|
548
|
+
* Caps: per-owner active-entity count + per-source-entity active-relation
|
|
549
|
+
* count.
|
|
550
|
+
*
|
|
551
|
+
* Auto-flip: stale-entity auto-archive + stale-relation auto-remove.
|
|
552
|
+
*
|
|
553
|
+
* Stats: all enum keys zero-initialized for stable CI regression shape.
|
|
554
|
+
* ═════════════════════════════════════════════════════════════ */
|
|
555
|
+
|
|
556
|
+
export const ENTITY_STATUS_V2 = Object.freeze({
|
|
557
|
+
ACTIVE: "active",
|
|
558
|
+
DEPRECATED: "deprecated",
|
|
559
|
+
ARCHIVED: "archived",
|
|
560
|
+
REMOVED: "removed",
|
|
561
|
+
});
|
|
562
|
+
|
|
563
|
+
export const RELATION_STATUS_V2 = Object.freeze({
|
|
564
|
+
ACTIVE: "active",
|
|
565
|
+
DEPRECATED: "deprecated",
|
|
566
|
+
REMOVED: "removed",
|
|
567
|
+
});
|
|
568
|
+
|
|
569
|
+
const ENTITY_TRANSITIONS_V2 = new Map([
|
|
570
|
+
["active", new Set(["deprecated", "archived"])],
|
|
571
|
+
["deprecated", new Set(["active", "archived", "removed"])],
|
|
572
|
+
["archived", new Set(["active", "removed"])],
|
|
573
|
+
]);
|
|
574
|
+
const ENTITY_TERMINALS_V2 = new Set(["removed"]);
|
|
575
|
+
|
|
576
|
+
const RELATION_TRANSITIONS_V2 = new Map([
|
|
577
|
+
["active", new Set(["deprecated", "removed"])],
|
|
578
|
+
["deprecated", new Set(["active", "removed"])],
|
|
579
|
+
]);
|
|
580
|
+
const RELATION_TERMINALS_V2 = new Set(["removed"]);
|
|
581
|
+
|
|
582
|
+
export const KG_DEFAULT_MAX_ACTIVE_ENTITIES_PER_OWNER = 1000;
|
|
583
|
+
export const KG_DEFAULT_MAX_RELATIONS_PER_ENTITY = 100;
|
|
584
|
+
export const KG_DEFAULT_ENTITY_STALE_MS = 180 * 86400000; // 180 days
|
|
585
|
+
export const KG_DEFAULT_RELATION_STALE_MS = 365 * 86400000; // 365 days
|
|
586
|
+
|
|
587
|
+
let _maxActiveEntitiesPerOwnerV2 = KG_DEFAULT_MAX_ACTIVE_ENTITIES_PER_OWNER;
|
|
588
|
+
let _maxRelationsPerEntityV2 = KG_DEFAULT_MAX_RELATIONS_PER_ENTITY;
|
|
589
|
+
let _entityStaleMsV2 = KG_DEFAULT_ENTITY_STALE_MS;
|
|
590
|
+
let _relationStaleMsV2 = KG_DEFAULT_RELATION_STALE_MS;
|
|
591
|
+
|
|
592
|
+
const _entityStatesV2 = new Map(); // entityId → V2 record
|
|
593
|
+
const _relationStatesV2 = new Map(); // relationId → V2 record
|
|
594
|
+
|
|
595
|
+
function _positiveIntV2(n, label) {
|
|
596
|
+
const num = Number(n);
|
|
597
|
+
if (!Number.isFinite(num) || num <= 0) {
|
|
598
|
+
throw new Error(`${label} must be a positive integer`);
|
|
599
|
+
}
|
|
600
|
+
return Math.floor(num);
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
function _validEntityStatusV2(status) {
|
|
604
|
+
return (
|
|
605
|
+
status === "active" ||
|
|
606
|
+
status === "deprecated" ||
|
|
607
|
+
status === "archived" ||
|
|
608
|
+
status === "removed"
|
|
609
|
+
);
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
function _validRelationStatusV2(status) {
|
|
613
|
+
return status === "active" || status === "deprecated" || status === "removed";
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
export function getDefaultMaxActiveEntitiesPerOwnerV2() {
|
|
617
|
+
return KG_DEFAULT_MAX_ACTIVE_ENTITIES_PER_OWNER;
|
|
618
|
+
}
|
|
619
|
+
export function getMaxActiveEntitiesPerOwnerV2() {
|
|
620
|
+
return _maxActiveEntitiesPerOwnerV2;
|
|
621
|
+
}
|
|
622
|
+
export function setMaxActiveEntitiesPerOwnerV2(n) {
|
|
623
|
+
_maxActiveEntitiesPerOwnerV2 = _positiveIntV2(n, "maxActiveEntitiesPerOwner");
|
|
624
|
+
return _maxActiveEntitiesPerOwnerV2;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
export function getDefaultMaxRelationsPerEntityV2() {
|
|
628
|
+
return KG_DEFAULT_MAX_RELATIONS_PER_ENTITY;
|
|
629
|
+
}
|
|
630
|
+
export function getMaxRelationsPerEntityV2() {
|
|
631
|
+
return _maxRelationsPerEntityV2;
|
|
632
|
+
}
|
|
633
|
+
export function setMaxRelationsPerEntityV2(n) {
|
|
634
|
+
_maxRelationsPerEntityV2 = _positiveIntV2(n, "maxRelationsPerEntity");
|
|
635
|
+
return _maxRelationsPerEntityV2;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
export function getDefaultEntityStaleMsV2() {
|
|
639
|
+
return KG_DEFAULT_ENTITY_STALE_MS;
|
|
640
|
+
}
|
|
641
|
+
export function getEntityStaleMsV2() {
|
|
642
|
+
return _entityStaleMsV2;
|
|
643
|
+
}
|
|
644
|
+
export function setEntityStaleMsV2(ms) {
|
|
645
|
+
_entityStaleMsV2 = _positiveIntV2(ms, "entityStaleMs");
|
|
646
|
+
return _entityStaleMsV2;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
export function getDefaultRelationStaleMsV2() {
|
|
650
|
+
return KG_DEFAULT_RELATION_STALE_MS;
|
|
651
|
+
}
|
|
652
|
+
export function getRelationStaleMsV2() {
|
|
653
|
+
return _relationStaleMsV2;
|
|
654
|
+
}
|
|
655
|
+
export function setRelationStaleMsV2(ms) {
|
|
656
|
+
_relationStaleMsV2 = _positiveIntV2(ms, "relationStaleMs");
|
|
657
|
+
return _relationStaleMsV2;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
/* ── Entity V2 ─────────────────────────────────────────────── */
|
|
661
|
+
|
|
662
|
+
export function registerEntityV2(db, config = {}) {
|
|
663
|
+
void db;
|
|
664
|
+
const entityId = String(config.entityId || "").trim();
|
|
665
|
+
if (!entityId) throw new Error("entityId is required");
|
|
666
|
+
const ownerId = String(config.ownerId || "").trim();
|
|
667
|
+
if (!ownerId) throw new Error("ownerId is required");
|
|
668
|
+
if (_entityStatesV2.has(entityId)) {
|
|
669
|
+
throw new Error(`Entity already registered in V2: ${entityId}`);
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
let activeCount = 0;
|
|
673
|
+
for (const rec of _entityStatesV2.values()) {
|
|
674
|
+
if (rec.ownerId === ownerId && rec.status === "active") activeCount += 1;
|
|
675
|
+
}
|
|
676
|
+
if (activeCount >= _maxActiveEntitiesPerOwnerV2) {
|
|
677
|
+
throw new Error(
|
|
678
|
+
`Max active entities per owner reached (${_maxActiveEntitiesPerOwnerV2})`,
|
|
679
|
+
);
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
const now = Number(config.now ?? Date.now());
|
|
683
|
+
const record = {
|
|
684
|
+
entityId,
|
|
685
|
+
ownerId,
|
|
686
|
+
name: config.name ? String(config.name) : null,
|
|
687
|
+
type: config.type ? String(config.type) : null,
|
|
688
|
+
status: "active",
|
|
689
|
+
metadata: config.metadata ? { ...config.metadata } : {},
|
|
690
|
+
createdAt: now,
|
|
691
|
+
updatedAt: now,
|
|
692
|
+
lastActivityAt: now,
|
|
693
|
+
reason: null,
|
|
694
|
+
};
|
|
695
|
+
_entityStatesV2.set(entityId, record);
|
|
696
|
+
return { ...record, metadata: { ...record.metadata } };
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
export function getEntityV2(entityId) {
|
|
700
|
+
const rec = _entityStatesV2.get(String(entityId || ""));
|
|
701
|
+
if (!rec) return null;
|
|
702
|
+
return { ...rec, metadata: { ...rec.metadata } };
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
export function setEntityStatusV2(db, entityId, newStatus, patch = {}) {
|
|
706
|
+
void db;
|
|
707
|
+
const id = String(entityId || "");
|
|
708
|
+
const record = _entityStatesV2.get(id);
|
|
709
|
+
if (!record) throw new Error(`Entity not registered in V2: ${id}`);
|
|
710
|
+
if (!_validEntityStatusV2(newStatus)) {
|
|
711
|
+
throw new Error(`Invalid entity status: ${newStatus}`);
|
|
712
|
+
}
|
|
713
|
+
if (ENTITY_TERMINALS_V2.has(record.status)) {
|
|
714
|
+
throw new Error(
|
|
715
|
+
`Entity is in terminal status '${record.status}' and cannot transition`,
|
|
716
|
+
);
|
|
717
|
+
}
|
|
718
|
+
const allowed = ENTITY_TRANSITIONS_V2.get(record.status);
|
|
719
|
+
if (!allowed || !allowed.has(newStatus)) {
|
|
720
|
+
throw new Error(`Invalid transition: ${record.status} → ${newStatus}`);
|
|
721
|
+
}
|
|
722
|
+
record.status = newStatus;
|
|
723
|
+
record.updatedAt = Number(patch.now ?? Date.now());
|
|
724
|
+
if (patch.reason !== undefined) record.reason = patch.reason;
|
|
725
|
+
if (patch.metadata && typeof patch.metadata === "object") {
|
|
726
|
+
record.metadata = { ...record.metadata, ...patch.metadata };
|
|
727
|
+
}
|
|
728
|
+
return { ...record, metadata: { ...record.metadata } };
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
export function deprecateEntity(db, entityId, reason) {
|
|
732
|
+
return setEntityStatusV2(db, entityId, "deprecated", { reason });
|
|
733
|
+
}
|
|
734
|
+
export function archiveEntityV2(db, entityId, reason) {
|
|
735
|
+
return setEntityStatusV2(db, entityId, "archived", { reason });
|
|
736
|
+
}
|
|
737
|
+
export function removeEntityV2(db, entityId, reason) {
|
|
738
|
+
return setEntityStatusV2(db, entityId, "removed", { reason });
|
|
739
|
+
}
|
|
740
|
+
export function reviveEntity(db, entityId, reason) {
|
|
741
|
+
return setEntityStatusV2(db, entityId, "active", { reason });
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
export function touchEntityActivity(entityId) {
|
|
745
|
+
const rec = _entityStatesV2.get(String(entityId || ""));
|
|
746
|
+
if (!rec) throw new Error(`Entity not registered in V2: ${entityId}`);
|
|
747
|
+
rec.lastActivityAt = Date.now();
|
|
748
|
+
return { ...rec, metadata: { ...rec.metadata } };
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
/* ── Relation V2 ───────────────────────────────────────────── */
|
|
752
|
+
|
|
753
|
+
export function registerRelationV2(db, config = {}) {
|
|
754
|
+
void db;
|
|
755
|
+
const relationId = String(config.relationId || "").trim();
|
|
756
|
+
if (!relationId) throw new Error("relationId is required");
|
|
757
|
+
const sourceEntityId = String(config.sourceEntityId || "").trim();
|
|
758
|
+
if (!sourceEntityId) throw new Error("sourceEntityId is required");
|
|
759
|
+
const targetEntityId = String(config.targetEntityId || "").trim();
|
|
760
|
+
if (!targetEntityId) throw new Error("targetEntityId is required");
|
|
761
|
+
const relationType = String(config.relationType || "").trim();
|
|
762
|
+
if (!relationType) throw new Error("relationType is required");
|
|
763
|
+
|
|
764
|
+
if (sourceEntityId === targetEntityId) {
|
|
765
|
+
throw new Error("Cannot create self-referencing relation");
|
|
766
|
+
}
|
|
767
|
+
if (_relationStatesV2.has(relationId)) {
|
|
768
|
+
throw new Error(`Relation already registered in V2: ${relationId}`);
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
const src = _entityStatesV2.get(sourceEntityId);
|
|
772
|
+
if (!src) {
|
|
773
|
+
throw new Error(`Source entity not registered in V2: ${sourceEntityId}`);
|
|
774
|
+
}
|
|
775
|
+
if (src.status !== "active" && src.status !== "deprecated") {
|
|
776
|
+
throw new Error(`Source entity is ${src.status}, cannot create relation`);
|
|
777
|
+
}
|
|
778
|
+
const tgt = _entityStatesV2.get(targetEntityId);
|
|
779
|
+
if (!tgt) {
|
|
780
|
+
throw new Error(`Target entity not registered in V2: ${targetEntityId}`);
|
|
781
|
+
}
|
|
782
|
+
if (tgt.status !== "active" && tgt.status !== "deprecated") {
|
|
783
|
+
throw new Error(`Target entity is ${tgt.status}, cannot create relation`);
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
let sourceCount = 0;
|
|
787
|
+
for (const rel of _relationStatesV2.values()) {
|
|
788
|
+
if (rel.sourceEntityId === sourceEntityId && rel.status === "active") {
|
|
789
|
+
sourceCount += 1;
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
if (sourceCount >= _maxRelationsPerEntityV2) {
|
|
793
|
+
throw new Error(
|
|
794
|
+
`Max active relations per entity reached (${_maxRelationsPerEntityV2})`,
|
|
795
|
+
);
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
const now = Number(config.now ?? Date.now());
|
|
799
|
+
const record = {
|
|
800
|
+
relationId,
|
|
801
|
+
sourceEntityId,
|
|
802
|
+
targetEntityId,
|
|
803
|
+
relationType,
|
|
804
|
+
status: "active",
|
|
805
|
+
metadata: config.metadata ? { ...config.metadata } : {},
|
|
806
|
+
createdAt: now,
|
|
807
|
+
updatedAt: now,
|
|
808
|
+
reason: null,
|
|
809
|
+
};
|
|
810
|
+
_relationStatesV2.set(relationId, record);
|
|
811
|
+
return { ...record, metadata: { ...record.metadata } };
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
export function getRelationV2(relationId) {
|
|
815
|
+
const rec = _relationStatesV2.get(String(relationId || ""));
|
|
816
|
+
if (!rec) return null;
|
|
817
|
+
return { ...rec, metadata: { ...rec.metadata } };
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
export function setRelationStatusV2(db, relationId, newStatus, patch = {}) {
|
|
821
|
+
void db;
|
|
822
|
+
const id = String(relationId || "");
|
|
823
|
+
const record = _relationStatesV2.get(id);
|
|
824
|
+
if (!record) throw new Error(`Relation not registered in V2: ${id}`);
|
|
825
|
+
if (!_validRelationStatusV2(newStatus)) {
|
|
826
|
+
throw new Error(`Invalid relation status: ${newStatus}`);
|
|
827
|
+
}
|
|
828
|
+
if (RELATION_TERMINALS_V2.has(record.status)) {
|
|
829
|
+
throw new Error(
|
|
830
|
+
`Relation is in terminal status '${record.status}' and cannot transition`,
|
|
831
|
+
);
|
|
832
|
+
}
|
|
833
|
+
const allowed = RELATION_TRANSITIONS_V2.get(record.status);
|
|
834
|
+
if (!allowed || !allowed.has(newStatus)) {
|
|
835
|
+
throw new Error(`Invalid transition: ${record.status} → ${newStatus}`);
|
|
836
|
+
}
|
|
837
|
+
record.status = newStatus;
|
|
838
|
+
record.updatedAt = Number(patch.now ?? Date.now());
|
|
839
|
+
if (patch.reason !== undefined) record.reason = patch.reason;
|
|
840
|
+
if (patch.metadata && typeof patch.metadata === "object") {
|
|
841
|
+
record.metadata = { ...record.metadata, ...patch.metadata };
|
|
842
|
+
}
|
|
843
|
+
return { ...record, metadata: { ...record.metadata } };
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
export function deprecateRelation(db, relationId, reason) {
|
|
847
|
+
return setRelationStatusV2(db, relationId, "deprecated", { reason });
|
|
848
|
+
}
|
|
849
|
+
export function removeRelationV2(db, relationId, reason) {
|
|
850
|
+
return setRelationStatusV2(db, relationId, "removed", { reason });
|
|
851
|
+
}
|
|
852
|
+
export function reviveRelation(db, relationId, reason) {
|
|
853
|
+
return setRelationStatusV2(db, relationId, "active", { reason });
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
/* ── Counts ────────────────────────────────────────────────── */
|
|
857
|
+
|
|
858
|
+
export function getActiveEntityCount(ownerId) {
|
|
859
|
+
let n = 0;
|
|
860
|
+
for (const rec of _entityStatesV2.values()) {
|
|
861
|
+
if (rec.status !== "active") continue;
|
|
862
|
+
if (ownerId !== undefined && rec.ownerId !== String(ownerId)) continue;
|
|
863
|
+
n += 1;
|
|
864
|
+
}
|
|
865
|
+
return n;
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
export function getActiveRelationCount(sourceEntityId) {
|
|
869
|
+
let n = 0;
|
|
870
|
+
for (const rel of _relationStatesV2.values()) {
|
|
871
|
+
if (rel.status !== "active") continue;
|
|
872
|
+
if (
|
|
873
|
+
sourceEntityId !== undefined &&
|
|
874
|
+
rel.sourceEntityId !== String(sourceEntityId)
|
|
875
|
+
) {
|
|
876
|
+
continue;
|
|
877
|
+
}
|
|
878
|
+
n += 1;
|
|
879
|
+
}
|
|
880
|
+
return n;
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
/* ── Auto-flip Bulk Ops ────────────────────────────────────── */
|
|
884
|
+
|
|
885
|
+
export function autoArchiveStaleEntities(db, nowMs) {
|
|
886
|
+
void db;
|
|
887
|
+
const now = Number(nowMs ?? Date.now());
|
|
888
|
+
const flipped = [];
|
|
889
|
+
for (const rec of _entityStatesV2.values()) {
|
|
890
|
+
if (rec.status !== "active") continue;
|
|
891
|
+
if (now - rec.lastActivityAt > _entityStaleMsV2) {
|
|
892
|
+
rec.status = "archived";
|
|
893
|
+
rec.updatedAt = now;
|
|
894
|
+
rec.reason = "stale";
|
|
895
|
+
flipped.push(rec.entityId);
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
return flipped;
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
export function autoRemoveStaleRelations(db, nowMs) {
|
|
902
|
+
void db;
|
|
903
|
+
const now = Number(nowMs ?? Date.now());
|
|
904
|
+
const flipped = [];
|
|
905
|
+
for (const rel of _relationStatesV2.values()) {
|
|
906
|
+
if (rel.status === "removed") continue;
|
|
907
|
+
if (now - rel.updatedAt > _relationStaleMsV2) {
|
|
908
|
+
rel.status = "removed";
|
|
909
|
+
rel.updatedAt = now;
|
|
910
|
+
rel.reason = "stale";
|
|
911
|
+
flipped.push(rel.relationId);
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
return flipped;
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
/* ── Stats V2 ──────────────────────────────────────────────── */
|
|
918
|
+
|
|
919
|
+
export function getKnowledgeGraphStatsV2() {
|
|
920
|
+
const entitiesByStatus = {
|
|
921
|
+
active: 0,
|
|
922
|
+
deprecated: 0,
|
|
923
|
+
archived: 0,
|
|
924
|
+
removed: 0,
|
|
925
|
+
};
|
|
926
|
+
const relationsByStatus = {
|
|
927
|
+
active: 0,
|
|
928
|
+
deprecated: 0,
|
|
929
|
+
removed: 0,
|
|
930
|
+
};
|
|
931
|
+
for (const rec of _entityStatesV2.values()) {
|
|
932
|
+
if (entitiesByStatus[rec.status] !== undefined) {
|
|
933
|
+
entitiesByStatus[rec.status] += 1;
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
for (const rel of _relationStatesV2.values()) {
|
|
937
|
+
if (relationsByStatus[rel.status] !== undefined) {
|
|
938
|
+
relationsByStatus[rel.status] += 1;
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
return {
|
|
942
|
+
totalEntitiesV2: _entityStatesV2.size,
|
|
943
|
+
totalRelationsV2: _relationStatesV2.size,
|
|
944
|
+
maxActiveEntitiesPerOwner: _maxActiveEntitiesPerOwnerV2,
|
|
945
|
+
maxRelationsPerEntity: _maxRelationsPerEntityV2,
|
|
946
|
+
entityStaleMs: _entityStaleMsV2,
|
|
947
|
+
relationStaleMs: _relationStaleMsV2,
|
|
948
|
+
entitiesByStatus,
|
|
949
|
+
relationsByStatus,
|
|
950
|
+
};
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
/* ── Reset V2 (tests) ──────────────────────────────────────── */
|
|
954
|
+
|
|
955
|
+
export function _resetStateV2() {
|
|
956
|
+
_entityStatesV2.clear();
|
|
957
|
+
_relationStatesV2.clear();
|
|
958
|
+
_maxActiveEntitiesPerOwnerV2 = KG_DEFAULT_MAX_ACTIVE_ENTITIES_PER_OWNER;
|
|
959
|
+
_maxRelationsPerEntityV2 = KG_DEFAULT_MAX_RELATIONS_PER_ENTITY;
|
|
960
|
+
_entityStaleMsV2 = KG_DEFAULT_ENTITY_STALE_MS;
|
|
961
|
+
_relationStaleMsV2 = KG_DEFAULT_RELATION_STALE_MS;
|
|
962
|
+
}
|