chainlesschain 0.66.0 → 0.81.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 +380 -0
- package/src/commands/bi.js +348 -0
- package/src/commands/crosschain.js +218 -0
- package/src/commands/dlp.js +341 -0
- package/src/commands/evomap.js +394 -0
- package/src/commands/federation.js +283 -0
- package/src/commands/inference.js +318 -0
- package/src/commands/lowcode.js +356 -0
- package/src/commands/marketplace.js +256 -0
- package/src/commands/privacy.js +321 -0
- package/src/commands/reputation.js +261 -0
- package/src/commands/siem.js +246 -0
- package/src/commands/sla.js +259 -0
- package/src/commands/stress.js +230 -0
- package/src/commands/terraform.js +245 -0
- package/src/commands/zkp.js +335 -0
- package/src/lib/a2a-protocol.js +451 -0
- package/src/lib/app-builder.js +239 -0
- package/src/lib/bi-engine.js +338 -0
- package/src/lib/cross-chain.js +345 -0
- package/src/lib/dlp-engine.js +389 -0
- package/src/lib/evomap-federation.js +177 -0
- package/src/lib/evomap-governance.js +276 -0
- package/src/lib/federation-hardening.js +259 -0
- package/src/lib/inference-network.js +330 -0
- package/src/lib/privacy-computing.js +427 -0
- package/src/lib/reputation-optimizer.js +299 -0
- package/src/lib/siem-exporter.js +333 -0
- package/src/lib/skill-marketplace.js +325 -0
- package/src/lib/sla-manager.js +275 -0
- package/src/lib/stress-tester.js +330 -0
- package/src/lib/terraform-manager.js +363 -0
- package/src/lib/zkp-engine.js +274 -0
package/src/commands/evomap.js
CHANGED
|
@@ -17,6 +17,14 @@ import {
|
|
|
17
17
|
getPressureReport,
|
|
18
18
|
recombineGenes,
|
|
19
19
|
getLineage,
|
|
20
|
+
HUB_STATUS_V2,
|
|
21
|
+
TRUST_TIER,
|
|
22
|
+
MUTATION_TYPE,
|
|
23
|
+
trustTier,
|
|
24
|
+
setHubStatus,
|
|
25
|
+
listHubsV2,
|
|
26
|
+
buildFederationContext,
|
|
27
|
+
getFederationStatsV2,
|
|
20
28
|
} from "../lib/evomap-federation.js";
|
|
21
29
|
import {
|
|
22
30
|
ensureEvoMapGovernanceTables,
|
|
@@ -25,6 +33,18 @@ import {
|
|
|
25
33
|
createGovernanceProposal,
|
|
26
34
|
voteOnGovernanceProposal,
|
|
27
35
|
getGovernanceDashboard,
|
|
36
|
+
PROPOSAL_STATUS_V2,
|
|
37
|
+
PROPOSAL_TYPE,
|
|
38
|
+
VOTE_DIRECTION,
|
|
39
|
+
createGovernanceProposalV2,
|
|
40
|
+
castVoteV2,
|
|
41
|
+
setProposalStatus,
|
|
42
|
+
executeProposal,
|
|
43
|
+
cancelProposal,
|
|
44
|
+
expireProposalsV2,
|
|
45
|
+
listProposalsV2,
|
|
46
|
+
traceContributions,
|
|
47
|
+
getGovernanceStatsV2,
|
|
28
48
|
} from "../lib/evomap-governance.js";
|
|
29
49
|
|
|
30
50
|
export function registerEvoMapCommand(program) {
|
|
@@ -555,4 +575,378 @@ export function registerEvoMapCommand(program) {
|
|
|
555
575
|
process.exit(1);
|
|
556
576
|
}
|
|
557
577
|
});
|
|
578
|
+
|
|
579
|
+
// ═══════════════════════════════════════════════════════════════
|
|
580
|
+
// V2 Canonical Subcommands (Phase 42)
|
|
581
|
+
// ═══════════════════════════════════════════════════════════════
|
|
582
|
+
|
|
583
|
+
federation
|
|
584
|
+
.command("hub-statuses")
|
|
585
|
+
.description("List V2 hub status values")
|
|
586
|
+
.action(() => {
|
|
587
|
+
console.log(JSON.stringify(Object.values(HUB_STATUS_V2), null, 2));
|
|
588
|
+
});
|
|
589
|
+
|
|
590
|
+
federation
|
|
591
|
+
.command("trust-tiers")
|
|
592
|
+
.description("List V2 trust tier values")
|
|
593
|
+
.action(() => {
|
|
594
|
+
console.log(JSON.stringify(Object.values(TRUST_TIER), null, 2));
|
|
595
|
+
});
|
|
596
|
+
|
|
597
|
+
federation
|
|
598
|
+
.command("mutation-types")
|
|
599
|
+
.description("List V2 mutation types")
|
|
600
|
+
.action(() => {
|
|
601
|
+
console.log(JSON.stringify(Object.values(MUTATION_TYPE), null, 2));
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
federation
|
|
605
|
+
.command("trust-tier <score>")
|
|
606
|
+
.description("Classify a trust score as low|medium|high")
|
|
607
|
+
.action((score) => {
|
|
608
|
+
try {
|
|
609
|
+
const num = Number(score);
|
|
610
|
+
console.log(JSON.stringify({ score: num, tier: trustTier(num) }));
|
|
611
|
+
} catch (err) {
|
|
612
|
+
logger.error(`Failed: ${err.message}`);
|
|
613
|
+
process.exit(1);
|
|
614
|
+
}
|
|
615
|
+
});
|
|
616
|
+
|
|
617
|
+
federation
|
|
618
|
+
.command("set-hub-status <hub-id> <status>")
|
|
619
|
+
.description("Transition a hub's status (V2 state machine)")
|
|
620
|
+
.action(async (hubId, status) => {
|
|
621
|
+
try {
|
|
622
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
623
|
+
if (!ctx.db) {
|
|
624
|
+
logger.error("Database not available");
|
|
625
|
+
process.exit(1);
|
|
626
|
+
}
|
|
627
|
+
const db = ctx.db.getDatabase();
|
|
628
|
+
ensureEvoMapFederationTables(db);
|
|
629
|
+
console.log(JSON.stringify(setHubStatus(db, hubId, status), null, 2));
|
|
630
|
+
await shutdown();
|
|
631
|
+
} catch (err) {
|
|
632
|
+
logger.error(`Failed: ${err.message}`);
|
|
633
|
+
process.exit(1);
|
|
634
|
+
}
|
|
635
|
+
});
|
|
636
|
+
|
|
637
|
+
federation
|
|
638
|
+
.command("list-hubs-v2")
|
|
639
|
+
.description("List hubs with V2 filters (trust tier, minTrust)")
|
|
640
|
+
.option("--status <status>", "Filter by hub status")
|
|
641
|
+
.option("--region <region>", "Filter by region")
|
|
642
|
+
.option("--min-trust <n>", "Minimum trust score (0-1)")
|
|
643
|
+
.option("--trust-tier <tier>", "Filter by trust tier (low|medium|high)")
|
|
644
|
+
.action(async (options) => {
|
|
645
|
+
try {
|
|
646
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
647
|
+
if (!ctx.db) {
|
|
648
|
+
logger.error("Database not available");
|
|
649
|
+
process.exit(1);
|
|
650
|
+
}
|
|
651
|
+
const db = ctx.db.getDatabase();
|
|
652
|
+
ensureEvoMapFederationTables(db);
|
|
653
|
+
const hubs = listHubsV2(db, {
|
|
654
|
+
status: options.status,
|
|
655
|
+
region: options.region,
|
|
656
|
+
minTrust: options.minTrust ? Number(options.minTrust) : undefined,
|
|
657
|
+
trustTier: options.trustTier,
|
|
658
|
+
});
|
|
659
|
+
console.log(JSON.stringify(hubs, null, 2));
|
|
660
|
+
await shutdown();
|
|
661
|
+
} catch (err) {
|
|
662
|
+
logger.error(`Failed: ${err.message}`);
|
|
663
|
+
process.exit(1);
|
|
664
|
+
}
|
|
665
|
+
});
|
|
666
|
+
|
|
667
|
+
federation
|
|
668
|
+
.command("context")
|
|
669
|
+
.description("Build federation context for LLM consumption")
|
|
670
|
+
.action(async () => {
|
|
671
|
+
try {
|
|
672
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
673
|
+
if (!ctx.db) {
|
|
674
|
+
logger.error("Database not available");
|
|
675
|
+
process.exit(1);
|
|
676
|
+
}
|
|
677
|
+
const db = ctx.db.getDatabase();
|
|
678
|
+
ensureEvoMapFederationTables(db);
|
|
679
|
+
console.log(JSON.stringify(buildFederationContext(), null, 2));
|
|
680
|
+
await shutdown();
|
|
681
|
+
} catch (err) {
|
|
682
|
+
logger.error(`Failed: ${err.message}`);
|
|
683
|
+
process.exit(1);
|
|
684
|
+
}
|
|
685
|
+
});
|
|
686
|
+
|
|
687
|
+
federation
|
|
688
|
+
.command("stats-v2")
|
|
689
|
+
.description("Show V2 federation stats (byStatus/byRegion/byTrustTier)")
|
|
690
|
+
.action(async () => {
|
|
691
|
+
try {
|
|
692
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
693
|
+
if (!ctx.db) {
|
|
694
|
+
logger.error("Database not available");
|
|
695
|
+
process.exit(1);
|
|
696
|
+
}
|
|
697
|
+
const db = ctx.db.getDatabase();
|
|
698
|
+
ensureEvoMapFederationTables(db);
|
|
699
|
+
console.log(JSON.stringify(getFederationStatsV2(), null, 2));
|
|
700
|
+
await shutdown();
|
|
701
|
+
} catch (err) {
|
|
702
|
+
logger.error(`Failed: ${err.message}`);
|
|
703
|
+
process.exit(1);
|
|
704
|
+
}
|
|
705
|
+
});
|
|
706
|
+
|
|
707
|
+
gov
|
|
708
|
+
.command("proposal-statuses")
|
|
709
|
+
.description("List V2 proposal status values")
|
|
710
|
+
.action(() => {
|
|
711
|
+
console.log(JSON.stringify(Object.values(PROPOSAL_STATUS_V2), null, 2));
|
|
712
|
+
});
|
|
713
|
+
|
|
714
|
+
gov
|
|
715
|
+
.command("proposal-types")
|
|
716
|
+
.description("List V2 proposal type values")
|
|
717
|
+
.action(() => {
|
|
718
|
+
console.log(JSON.stringify(Object.values(PROPOSAL_TYPE), null, 2));
|
|
719
|
+
});
|
|
720
|
+
|
|
721
|
+
gov
|
|
722
|
+
.command("vote-directions")
|
|
723
|
+
.description("List V2 vote direction values")
|
|
724
|
+
.action(() => {
|
|
725
|
+
console.log(JSON.stringify(Object.values(VOTE_DIRECTION), null, 2));
|
|
726
|
+
});
|
|
727
|
+
|
|
728
|
+
gov
|
|
729
|
+
.command("propose-v2")
|
|
730
|
+
.description("Create a V2 governance proposal with type/quorum/threshold")
|
|
731
|
+
.requiredOption("-t, --title <title>", "Proposal title")
|
|
732
|
+
.option("-d, --description <text>", "Proposal description")
|
|
733
|
+
.option("-p, --proposer <did>", "Proposer DID", "cli-user")
|
|
734
|
+
.option(
|
|
735
|
+
"--type <type>",
|
|
736
|
+
"Proposal type (standard|gene_standard|...)",
|
|
737
|
+
"standard",
|
|
738
|
+
)
|
|
739
|
+
.option("--quorum <n>", "Quorum (min votes)", "3")
|
|
740
|
+
.option("--threshold <n>", "Threshold (0-1)", "0.5")
|
|
741
|
+
.option("--voting-duration-ms <n>", "Voting duration in ms")
|
|
742
|
+
.action(async (options) => {
|
|
743
|
+
try {
|
|
744
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
745
|
+
if (!ctx.db) {
|
|
746
|
+
logger.error("Database not available");
|
|
747
|
+
process.exit(1);
|
|
748
|
+
}
|
|
749
|
+
const db = ctx.db.getDatabase();
|
|
750
|
+
ensureEvoMapGovernanceTables(db);
|
|
751
|
+
const p = createGovernanceProposalV2(db, {
|
|
752
|
+
title: options.title,
|
|
753
|
+
description: options.description,
|
|
754
|
+
proposerDid: options.proposer,
|
|
755
|
+
type: options.type,
|
|
756
|
+
quorum: Number(options.quorum),
|
|
757
|
+
threshold: Number(options.threshold),
|
|
758
|
+
votingDurationMs: options.votingDurationMs
|
|
759
|
+
? Number(options.votingDurationMs)
|
|
760
|
+
: undefined,
|
|
761
|
+
});
|
|
762
|
+
console.log(JSON.stringify(p, null, 2));
|
|
763
|
+
await shutdown();
|
|
764
|
+
} catch (err) {
|
|
765
|
+
logger.error(`Failed: ${err.message}`);
|
|
766
|
+
process.exit(1);
|
|
767
|
+
}
|
|
768
|
+
});
|
|
769
|
+
|
|
770
|
+
gov
|
|
771
|
+
.command("vote-v2 <proposal-id> <direction>")
|
|
772
|
+
.description("Cast a weighted V2 vote (for|against|abstain)")
|
|
773
|
+
.option("-v, --voter <did>", "Voter DID", "cli-user")
|
|
774
|
+
.option("-w, --weight <n>", "Vote weight", "1")
|
|
775
|
+
.action(async (proposalId, direction, options) => {
|
|
776
|
+
try {
|
|
777
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
778
|
+
if (!ctx.db) {
|
|
779
|
+
logger.error("Database not available");
|
|
780
|
+
process.exit(1);
|
|
781
|
+
}
|
|
782
|
+
const db = ctx.db.getDatabase();
|
|
783
|
+
ensureEvoMapGovernanceTables(db);
|
|
784
|
+
const r = castVoteV2(db, {
|
|
785
|
+
proposalId,
|
|
786
|
+
voterDid: options.voter,
|
|
787
|
+
direction,
|
|
788
|
+
weight: Number(options.weight),
|
|
789
|
+
});
|
|
790
|
+
console.log(JSON.stringify(r, null, 2));
|
|
791
|
+
await shutdown();
|
|
792
|
+
} catch (err) {
|
|
793
|
+
logger.error(`Failed: ${err.message}`);
|
|
794
|
+
process.exit(1);
|
|
795
|
+
}
|
|
796
|
+
});
|
|
797
|
+
|
|
798
|
+
gov
|
|
799
|
+
.command("set-status <proposal-id> <status>")
|
|
800
|
+
.description("Transition a proposal's status (V2 state machine)")
|
|
801
|
+
.action(async (proposalId, status) => {
|
|
802
|
+
try {
|
|
803
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
804
|
+
if (!ctx.db) {
|
|
805
|
+
logger.error("Database not available");
|
|
806
|
+
process.exit(1);
|
|
807
|
+
}
|
|
808
|
+
const db = ctx.db.getDatabase();
|
|
809
|
+
ensureEvoMapGovernanceTables(db);
|
|
810
|
+
console.log(
|
|
811
|
+
JSON.stringify(setProposalStatus(db, proposalId, status), null, 2),
|
|
812
|
+
);
|
|
813
|
+
await shutdown();
|
|
814
|
+
} catch (err) {
|
|
815
|
+
logger.error(`Failed: ${err.message}`);
|
|
816
|
+
process.exit(1);
|
|
817
|
+
}
|
|
818
|
+
});
|
|
819
|
+
|
|
820
|
+
gov
|
|
821
|
+
.command("execute <proposal-id>")
|
|
822
|
+
.description("Execute a passed proposal")
|
|
823
|
+
.action(async (proposalId) => {
|
|
824
|
+
try {
|
|
825
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
826
|
+
if (!ctx.db) {
|
|
827
|
+
logger.error("Database not available");
|
|
828
|
+
process.exit(1);
|
|
829
|
+
}
|
|
830
|
+
const db = ctx.db.getDatabase();
|
|
831
|
+
ensureEvoMapGovernanceTables(db);
|
|
832
|
+
console.log(JSON.stringify(executeProposal(db, proposalId), null, 2));
|
|
833
|
+
await shutdown();
|
|
834
|
+
} catch (err) {
|
|
835
|
+
logger.error(`Failed: ${err.message}`);
|
|
836
|
+
process.exit(1);
|
|
837
|
+
}
|
|
838
|
+
});
|
|
839
|
+
|
|
840
|
+
gov
|
|
841
|
+
.command("cancel <proposal-id>")
|
|
842
|
+
.description("Cancel a proposal")
|
|
843
|
+
.action(async (proposalId) => {
|
|
844
|
+
try {
|
|
845
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
846
|
+
if (!ctx.db) {
|
|
847
|
+
logger.error("Database not available");
|
|
848
|
+
process.exit(1);
|
|
849
|
+
}
|
|
850
|
+
const db = ctx.db.getDatabase();
|
|
851
|
+
ensureEvoMapGovernanceTables(db);
|
|
852
|
+
console.log(JSON.stringify(cancelProposal(db, proposalId), null, 2));
|
|
853
|
+
await shutdown();
|
|
854
|
+
} catch (err) {
|
|
855
|
+
logger.error(`Failed: ${err.message}`);
|
|
856
|
+
process.exit(1);
|
|
857
|
+
}
|
|
858
|
+
});
|
|
859
|
+
|
|
860
|
+
gov
|
|
861
|
+
.command("expire")
|
|
862
|
+
.description("Bulk-expire active proposals past voting deadline (V2)")
|
|
863
|
+
.action(async () => {
|
|
864
|
+
try {
|
|
865
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
866
|
+
if (!ctx.db) {
|
|
867
|
+
logger.error("Database not available");
|
|
868
|
+
process.exit(1);
|
|
869
|
+
}
|
|
870
|
+
const db = ctx.db.getDatabase();
|
|
871
|
+
ensureEvoMapGovernanceTables(db);
|
|
872
|
+
console.log(JSON.stringify(expireProposalsV2(db), null, 2));
|
|
873
|
+
await shutdown();
|
|
874
|
+
} catch (err) {
|
|
875
|
+
logger.error(`Failed: ${err.message}`);
|
|
876
|
+
process.exit(1);
|
|
877
|
+
}
|
|
878
|
+
});
|
|
879
|
+
|
|
880
|
+
gov
|
|
881
|
+
.command("list-v2")
|
|
882
|
+
.description("List proposals with V2 filters")
|
|
883
|
+
.option("--status <status>", "Filter by status")
|
|
884
|
+
.option("--type <type>", "Filter by type")
|
|
885
|
+
.option("--proposer <did>", "Filter by proposer DID")
|
|
886
|
+
.action(async (options) => {
|
|
887
|
+
try {
|
|
888
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
889
|
+
if (!ctx.db) {
|
|
890
|
+
logger.error("Database not available");
|
|
891
|
+
process.exit(1);
|
|
892
|
+
}
|
|
893
|
+
const db = ctx.db.getDatabase();
|
|
894
|
+
ensureEvoMapGovernanceTables(db);
|
|
895
|
+
console.log(
|
|
896
|
+
JSON.stringify(
|
|
897
|
+
listProposalsV2(db, {
|
|
898
|
+
status: options.status,
|
|
899
|
+
type: options.type,
|
|
900
|
+
proposerDid: options.proposer,
|
|
901
|
+
}),
|
|
902
|
+
null,
|
|
903
|
+
2,
|
|
904
|
+
),
|
|
905
|
+
);
|
|
906
|
+
await shutdown();
|
|
907
|
+
} catch (err) {
|
|
908
|
+
logger.error(`Failed: ${err.message}`);
|
|
909
|
+
process.exit(1);
|
|
910
|
+
}
|
|
911
|
+
});
|
|
912
|
+
|
|
913
|
+
gov
|
|
914
|
+
.command("contributions <gene-id>")
|
|
915
|
+
.description("Trace gene contributions (V2 alias of ownership-trace)")
|
|
916
|
+
.action(async (geneId) => {
|
|
917
|
+
try {
|
|
918
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
919
|
+
if (!ctx.db) {
|
|
920
|
+
logger.error("Database not available");
|
|
921
|
+
process.exit(1);
|
|
922
|
+
}
|
|
923
|
+
const db = ctx.db.getDatabase();
|
|
924
|
+
ensureEvoMapGovernanceTables(db);
|
|
925
|
+
console.log(JSON.stringify(traceContributions(geneId), null, 2));
|
|
926
|
+
await shutdown();
|
|
927
|
+
} catch (err) {
|
|
928
|
+
logger.error(`Failed: ${err.message}`);
|
|
929
|
+
process.exit(1);
|
|
930
|
+
}
|
|
931
|
+
});
|
|
932
|
+
|
|
933
|
+
gov
|
|
934
|
+
.command("stats-v2")
|
|
935
|
+
.description("Show V2 governance stats (byStatus/byType, weight totals)")
|
|
936
|
+
.action(async () => {
|
|
937
|
+
try {
|
|
938
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
939
|
+
if (!ctx.db) {
|
|
940
|
+
logger.error("Database not available");
|
|
941
|
+
process.exit(1);
|
|
942
|
+
}
|
|
943
|
+
const db = ctx.db.getDatabase();
|
|
944
|
+
ensureEvoMapGovernanceTables(db);
|
|
945
|
+
console.log(JSON.stringify(getGovernanceStatsV2(), null, 2));
|
|
946
|
+
await shutdown();
|
|
947
|
+
} catch (err) {
|
|
948
|
+
logger.error(`Failed: ${err.message}`);
|
|
949
|
+
process.exit(1);
|
|
950
|
+
}
|
|
951
|
+
});
|
|
558
952
|
}
|
|
@@ -29,6 +29,28 @@ import {
|
|
|
29
29
|
listPools,
|
|
30
30
|
destroyPool,
|
|
31
31
|
getFederationHardeningStats,
|
|
32
|
+
// V2 (Phase 58)
|
|
33
|
+
NODE_STATUS_V2,
|
|
34
|
+
FED_DEFAULT_FAILURE_THRESHOLD,
|
|
35
|
+
FED_DEFAULT_HALF_OPEN_COOLDOWN_MS,
|
|
36
|
+
FED_DEFAULT_UNHEALTHY_THRESHOLD,
|
|
37
|
+
FED_DEFAULT_MAX_ACTIVE_NODES,
|
|
38
|
+
setFailureThreshold,
|
|
39
|
+
getFailureThreshold,
|
|
40
|
+
setHalfOpenCooldownMs,
|
|
41
|
+
getHalfOpenCooldownMs,
|
|
42
|
+
setUnhealthyThreshold,
|
|
43
|
+
getUnhealthyThreshold,
|
|
44
|
+
setMaxActiveNodes,
|
|
45
|
+
getMaxActiveNodes,
|
|
46
|
+
getActiveNodeCount,
|
|
47
|
+
registerNodeV2,
|
|
48
|
+
getNodeStatusV2,
|
|
49
|
+
setNodeStatusV2,
|
|
50
|
+
recordHealthCheckV2,
|
|
51
|
+
tripCircuit,
|
|
52
|
+
autoIsolateUnhealthyNodes,
|
|
53
|
+
getFederationHardeningStatsV2,
|
|
32
54
|
} from "../lib/federation-hardening.js";
|
|
33
55
|
|
|
34
56
|
function _dbFromCtx(cmd) {
|
|
@@ -423,5 +445,266 @@ export function registerFederationCommand(program) {
|
|
|
423
445
|
);
|
|
424
446
|
});
|
|
425
447
|
|
|
448
|
+
/* ── V2 (Phase 58) ──────────────────────────────── */
|
|
449
|
+
|
|
450
|
+
fed
|
|
451
|
+
.command("node-statuses-v2")
|
|
452
|
+
.description("List V2 node lifecycle statuses")
|
|
453
|
+
.option("--json", "JSON output")
|
|
454
|
+
.action((opts) => {
|
|
455
|
+
const statuses = Object.values(NODE_STATUS_V2);
|
|
456
|
+
if (opts.json) return console.log(JSON.stringify(statuses, null, 2));
|
|
457
|
+
for (const s of statuses) console.log(` ${s}`);
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
fed
|
|
461
|
+
.command("default-failure-threshold")
|
|
462
|
+
.description("Default circuit-breaker failure threshold")
|
|
463
|
+
.option("--json", "JSON output")
|
|
464
|
+
.action((opts) => {
|
|
465
|
+
if (opts.json)
|
|
466
|
+
return console.log(JSON.stringify(FED_DEFAULT_FAILURE_THRESHOLD));
|
|
467
|
+
console.log(FED_DEFAULT_FAILURE_THRESHOLD);
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
fed
|
|
471
|
+
.command("failure-threshold")
|
|
472
|
+
.description("Current failure threshold")
|
|
473
|
+
.option("--json", "JSON output")
|
|
474
|
+
.action((opts) => {
|
|
475
|
+
const n = getFailureThreshold();
|
|
476
|
+
if (opts.json) return console.log(JSON.stringify(n));
|
|
477
|
+
console.log(n);
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
fed
|
|
481
|
+
.command("set-failure-threshold <n>")
|
|
482
|
+
.description("Set failure threshold (positive integer)")
|
|
483
|
+
.option("--json", "JSON output")
|
|
484
|
+
.action((n, opts) => {
|
|
485
|
+
setFailureThreshold(Number(n));
|
|
486
|
+
const out = { failureThreshold: getFailureThreshold() };
|
|
487
|
+
if (opts.json) return console.log(JSON.stringify(out, null, 2));
|
|
488
|
+
console.log(`failureThreshold = ${out.failureThreshold}`);
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
fed
|
|
492
|
+
.command("default-half-open-cooldown-ms")
|
|
493
|
+
.description("Default half-open cooldown in ms")
|
|
494
|
+
.option("--json", "JSON output")
|
|
495
|
+
.action((opts) => {
|
|
496
|
+
if (opts.json)
|
|
497
|
+
return console.log(JSON.stringify(FED_DEFAULT_HALF_OPEN_COOLDOWN_MS));
|
|
498
|
+
console.log(FED_DEFAULT_HALF_OPEN_COOLDOWN_MS);
|
|
499
|
+
});
|
|
500
|
+
|
|
501
|
+
fed
|
|
502
|
+
.command("half-open-cooldown-ms")
|
|
503
|
+
.description("Current half-open cooldown in ms")
|
|
504
|
+
.option("--json", "JSON output")
|
|
505
|
+
.action((opts) => {
|
|
506
|
+
const n = getHalfOpenCooldownMs();
|
|
507
|
+
if (opts.json) return console.log(JSON.stringify(n));
|
|
508
|
+
console.log(n);
|
|
509
|
+
});
|
|
510
|
+
|
|
511
|
+
fed
|
|
512
|
+
.command("set-half-open-cooldown-ms <ms>")
|
|
513
|
+
.description("Set half-open cooldown (positive integer ms)")
|
|
514
|
+
.option("--json", "JSON output")
|
|
515
|
+
.action((ms, opts) => {
|
|
516
|
+
setHalfOpenCooldownMs(Number(ms));
|
|
517
|
+
const out = { halfOpenCooldownMs: getHalfOpenCooldownMs() };
|
|
518
|
+
if (opts.json) return console.log(JSON.stringify(out, null, 2));
|
|
519
|
+
console.log(`halfOpenCooldownMs = ${out.halfOpenCooldownMs}`);
|
|
520
|
+
});
|
|
521
|
+
|
|
522
|
+
fed
|
|
523
|
+
.command("default-unhealthy-threshold")
|
|
524
|
+
.description("Default consecutive-unhealthy isolation threshold")
|
|
525
|
+
.option("--json", "JSON output")
|
|
526
|
+
.action((opts) => {
|
|
527
|
+
if (opts.json)
|
|
528
|
+
return console.log(JSON.stringify(FED_DEFAULT_UNHEALTHY_THRESHOLD));
|
|
529
|
+
console.log(FED_DEFAULT_UNHEALTHY_THRESHOLD);
|
|
530
|
+
});
|
|
531
|
+
|
|
532
|
+
fed
|
|
533
|
+
.command("unhealthy-threshold")
|
|
534
|
+
.description("Current consecutive-unhealthy threshold")
|
|
535
|
+
.option("--json", "JSON output")
|
|
536
|
+
.action((opts) => {
|
|
537
|
+
const n = getUnhealthyThreshold();
|
|
538
|
+
if (opts.json) return console.log(JSON.stringify(n));
|
|
539
|
+
console.log(n);
|
|
540
|
+
});
|
|
541
|
+
|
|
542
|
+
fed
|
|
543
|
+
.command("set-unhealthy-threshold <n>")
|
|
544
|
+
.description("Set consecutive-unhealthy threshold")
|
|
545
|
+
.option("--json", "JSON output")
|
|
546
|
+
.action((n, opts) => {
|
|
547
|
+
setUnhealthyThreshold(Number(n));
|
|
548
|
+
const out = { unhealthyThreshold: getUnhealthyThreshold() };
|
|
549
|
+
if (opts.json) return console.log(JSON.stringify(out, null, 2));
|
|
550
|
+
console.log(`unhealthyThreshold = ${out.unhealthyThreshold}`);
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
fed
|
|
554
|
+
.command("default-max-active-nodes")
|
|
555
|
+
.description("Default max active nodes cap")
|
|
556
|
+
.option("--json", "JSON output")
|
|
557
|
+
.action((opts) => {
|
|
558
|
+
if (opts.json)
|
|
559
|
+
return console.log(JSON.stringify(FED_DEFAULT_MAX_ACTIVE_NODES));
|
|
560
|
+
console.log(FED_DEFAULT_MAX_ACTIVE_NODES);
|
|
561
|
+
});
|
|
562
|
+
|
|
563
|
+
fed
|
|
564
|
+
.command("max-active-nodes")
|
|
565
|
+
.description("Current max active nodes cap")
|
|
566
|
+
.option("--json", "JSON output")
|
|
567
|
+
.action((opts) => {
|
|
568
|
+
const n = getMaxActiveNodes();
|
|
569
|
+
if (opts.json) return console.log(JSON.stringify(n));
|
|
570
|
+
console.log(n);
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
fed
|
|
574
|
+
.command("active-node-count")
|
|
575
|
+
.description("Number of currently ACTIVE nodes")
|
|
576
|
+
.option("--json", "JSON output")
|
|
577
|
+
.action((opts) => {
|
|
578
|
+
const n = getActiveNodeCount();
|
|
579
|
+
if (opts.json) return console.log(JSON.stringify(n));
|
|
580
|
+
console.log(n);
|
|
581
|
+
});
|
|
582
|
+
|
|
583
|
+
fed
|
|
584
|
+
.command("set-max-active-nodes <n>")
|
|
585
|
+
.description("Set max active nodes cap")
|
|
586
|
+
.option("--json", "JSON output")
|
|
587
|
+
.action((n, opts) => {
|
|
588
|
+
setMaxActiveNodes(Number(n));
|
|
589
|
+
const out = { maxActiveNodes: getMaxActiveNodes() };
|
|
590
|
+
if (opts.json) return console.log(JSON.stringify(out, null, 2));
|
|
591
|
+
console.log(`maxActiveNodes = ${out.maxActiveNodes}`);
|
|
592
|
+
});
|
|
593
|
+
|
|
594
|
+
fed
|
|
595
|
+
.command("register-v2 <node-id>")
|
|
596
|
+
.description("Register a node with V2 lifecycle tracking")
|
|
597
|
+
.option("-m, --metadata <json>", "JSON metadata")
|
|
598
|
+
.option("--json", "JSON output")
|
|
599
|
+
.action((nodeId, opts) => {
|
|
600
|
+
const db = _dbFromCtx(fed);
|
|
601
|
+
const metadata = opts.metadata ? JSON.parse(opts.metadata) : undefined;
|
|
602
|
+
const r = registerNodeV2(db, { nodeId, metadata });
|
|
603
|
+
if (opts.json) return console.log(JSON.stringify(r, null, 2));
|
|
604
|
+
console.log(`Registered ${nodeId} (status: ${r.status})`);
|
|
605
|
+
});
|
|
606
|
+
|
|
607
|
+
fed
|
|
608
|
+
.command("node-status-v2 <node-id>")
|
|
609
|
+
.description("Get V2 node status")
|
|
610
|
+
.option("--json", "JSON output")
|
|
611
|
+
.action((nodeId, opts) => {
|
|
612
|
+
const r = getNodeStatusV2(nodeId);
|
|
613
|
+
if (opts.json) return console.log(JSON.stringify(r, null, 2));
|
|
614
|
+
if (!r) return console.log("(not found)");
|
|
615
|
+
console.log(`${nodeId}: ${r.status}${r.reason ? ` — ${r.reason}` : ""}`);
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
fed
|
|
619
|
+
.command("set-node-status-v2 <node-id> <status>")
|
|
620
|
+
.description("Transition node to a new status")
|
|
621
|
+
.option("-r, --reason <reason>")
|
|
622
|
+
.option("-m, --metadata <json>")
|
|
623
|
+
.option("--json", "JSON output")
|
|
624
|
+
.action((nodeId, status, opts) => {
|
|
625
|
+
const db = _dbFromCtx(fed);
|
|
626
|
+
const patch = {};
|
|
627
|
+
if (opts.reason !== undefined) patch.reason = opts.reason;
|
|
628
|
+
if (opts.metadata !== undefined)
|
|
629
|
+
patch.metadata = JSON.parse(opts.metadata);
|
|
630
|
+
const r = setNodeStatusV2(db, nodeId, status, patch);
|
|
631
|
+
if (opts.json) return console.log(JSON.stringify(r, null, 2));
|
|
632
|
+
console.log(`${nodeId} → ${r.status}`);
|
|
633
|
+
});
|
|
634
|
+
|
|
635
|
+
fed
|
|
636
|
+
.command("record-health-v2 <node-id>")
|
|
637
|
+
.description("Record a V2 health check (throws on invalid input)")
|
|
638
|
+
.option(
|
|
639
|
+
"-t, --type <checkType>",
|
|
640
|
+
"heartbeat|latency|success_rate|cpu_usage|memory_usage",
|
|
641
|
+
"heartbeat",
|
|
642
|
+
)
|
|
643
|
+
.option(
|
|
644
|
+
"-s, --status <status>",
|
|
645
|
+
"healthy|degraded|unhealthy|unknown",
|
|
646
|
+
"healthy",
|
|
647
|
+
)
|
|
648
|
+
.option("-m, --metrics <json>", "Optional metrics JSON")
|
|
649
|
+
.option("--json", "JSON output")
|
|
650
|
+
.action((nodeId, opts) => {
|
|
651
|
+
const db = _dbFromCtx(fed);
|
|
652
|
+
const metrics = opts.metrics ? JSON.parse(opts.metrics) : undefined;
|
|
653
|
+
const r = recordHealthCheckV2(db, {
|
|
654
|
+
nodeId,
|
|
655
|
+
checkType: opts.type,
|
|
656
|
+
status: opts.status,
|
|
657
|
+
metrics,
|
|
658
|
+
});
|
|
659
|
+
if (opts.json) return console.log(JSON.stringify(r, null, 2));
|
|
660
|
+
console.log(`recorded check ${r.checkId}`);
|
|
661
|
+
});
|
|
662
|
+
|
|
663
|
+
fed
|
|
664
|
+
.command("trip-circuit <node-id>")
|
|
665
|
+
.description("Force-trip a circuit breaker (closed/half_open → open)")
|
|
666
|
+
.option("--json", "JSON output")
|
|
667
|
+
.action((nodeId, opts) => {
|
|
668
|
+
const db = _dbFromCtx(fed);
|
|
669
|
+
const r = tripCircuit(db, nodeId);
|
|
670
|
+
if (opts.json) return console.log(JSON.stringify(r, null, 2));
|
|
671
|
+
console.log(`${nodeId} circuit → ${r.state}`);
|
|
672
|
+
});
|
|
673
|
+
|
|
674
|
+
fed
|
|
675
|
+
.command("auto-isolate-unhealthy")
|
|
676
|
+
.description(
|
|
677
|
+
"Bulk-isolate ACTIVE nodes with N consecutive UNHEALTHY checks",
|
|
678
|
+
)
|
|
679
|
+
.option("--json", "JSON output")
|
|
680
|
+
.action((opts) => {
|
|
681
|
+
const db = _dbFromCtx(fed);
|
|
682
|
+
const r = autoIsolateUnhealthyNodes(db);
|
|
683
|
+
if (opts.json) return console.log(JSON.stringify(r, null, 2));
|
|
684
|
+
console.log(`Isolated ${r.length} node(s)`);
|
|
685
|
+
for (const n of r) console.log(` ${n.node_id}`);
|
|
686
|
+
});
|
|
687
|
+
|
|
688
|
+
fed
|
|
689
|
+
.command("stats-v2")
|
|
690
|
+
.description("V2 federation hardening statistics")
|
|
691
|
+
.option("--json", "JSON output")
|
|
692
|
+
.action((opts) => {
|
|
693
|
+
const db = _dbFromCtx(fed);
|
|
694
|
+
const s = getFederationHardeningStatsV2(db);
|
|
695
|
+
if (opts.json) return console.log(JSON.stringify(s, null, 2));
|
|
696
|
+
console.log(
|
|
697
|
+
`Nodes: ${s.totalNodes} (active=${s.activeNodes}, isolated=${s.isolatedNodes})`,
|
|
698
|
+
);
|
|
699
|
+
console.log(`Circuits: ${s.totalCircuits}`);
|
|
700
|
+
for (const [state, count] of Object.entries(s.circuitsByState)) {
|
|
701
|
+
if (count > 0) console.log(` ${state.padEnd(10)} ${count}`);
|
|
702
|
+
}
|
|
703
|
+
console.log(`Health checks: ${s.totalHealthChecks}`);
|
|
704
|
+
console.log(
|
|
705
|
+
`config: failureThreshold=${s.failureThreshold} halfOpenCooldownMs=${s.halfOpenCooldownMs} unhealthyThreshold=${s.unhealthyThreshold} maxActiveNodes=${s.maxActiveNodes}`,
|
|
706
|
+
);
|
|
707
|
+
});
|
|
708
|
+
|
|
426
709
|
program.addCommand(fed);
|
|
427
710
|
}
|