mneme-ai 2.51.0 → 2.53.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.
@@ -1 +1 @@
1
- {"version":3,"file":"v236_commands.d.ts","sourceRoot":"","sources":["../../src/commands/v236_commands.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQzC;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAwE5D;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAiH5D;AAED;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA+EjE;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAoG3D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA6I3D;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAqM7D"}
1
+ {"version":3,"file":"v236_commands.d.ts","sourceRoot":"","sources":["../../src/commands/v236_commands.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQzC;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAwE5D;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAiH5D;AAED;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA+EjE;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAoG3D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA6I3D;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAmlB7D"}
@@ -767,6 +767,456 @@ export function registerNemesisCommand(program) {
767
767
  // v2.46.0 — relocated `mneme nemesis` engineering-friction-detector
768
768
  // (was top-level in v2.45) into `nemesis pairs` subcommand so the
769
769
  // parent `nemesis` namespace hosts both legacy + new functionality.
770
+ // ──────────────────────────────────────────────────────────────────
771
+ // v2.52.0 — Million Dollar Secret diamonds (1-6)
772
+ // Each diamond inspired by the Netflix identity-deception show:
773
+ // contestants who hide their identity vs. behavioral-fingerprint
774
+ // detection. NEMESIS turned into a competitive primitive game.
775
+ // ──────────────────────────────────────────────────────────────────
776
+ // Diamond 1 — STEALTH SCORE + anonymity-credit ledger
777
+ n.command("stealth_score")
778
+ .description("💎1 STEALTH SCORE — inverse of fingerprint confidence. 0=obvious, 1=ghost. Pair with anonymity-credit ledger for tamper-evident anonymity budget. Use --stdin with JSON {diff, prDescription, commitMessages}.")
779
+ .option("--stdin", "Read fixture JSON from stdin")
780
+ .option("--earn", "Earn anonymity credits when band ≥ stealth")
781
+ .option("--context <ref>", "Context ref for ledger row (commit sha / file path)", "stealth_score-cli")
782
+ .action(async (opts) => {
783
+ try {
784
+ const core = await import("@mneme-ai/core");
785
+ const f = opts.stdin ? await readStdinJson() : null;
786
+ if (!f) {
787
+ writeJson({ ok: false, error: "pass --stdin with JSON fixture {diff, prDescription, commitMessages}" });
788
+ process.exitCode = 1;
789
+ return;
790
+ }
791
+ const verdict = core.nemesis.computeStealthScore({ diff: f.diff ?? "", prDescription: f.prDescription ?? "", commitMessages: f.commitMessages ?? [] });
792
+ const out = { ok: true, verdict };
793
+ if (opts.earn) {
794
+ const earn = core.nemesis.earnAnonymityCredits(process.cwd(), verdict, opts.context ?? "cli");
795
+ out.earned = earn;
796
+ }
797
+ writeJson(out);
798
+ }
799
+ catch (e) {
800
+ writeJson({ ok: false, error: e.message });
801
+ process.exitCode = 1;
802
+ }
803
+ });
804
+ n.command("stealth_spend")
805
+ .description("💎1 STEALTH SCORE — spend anonymity credits to record an anonymization action. Refuses on insufficient balance.")
806
+ .requiredOption("--amount <n>", "Credits to spend", (v) => Number(v))
807
+ .requiredOption("--context <ref>", "What you spent it on (commit sha / disclosure)")
808
+ .action(async (opts) => {
809
+ try {
810
+ const core = await import("@mneme-ai/core");
811
+ const out = core.nemesis.spendAnonymityCredits(process.cwd(), opts.amount, opts.context);
812
+ writeJson({ ok: !out.rejected, ...out });
813
+ if (out.rejected)
814
+ process.exitCode = 1;
815
+ }
816
+ catch (e) {
817
+ writeJson({ ok: false, error: e.message });
818
+ process.exitCode = 1;
819
+ }
820
+ });
821
+ n.command("stealth_status")
822
+ .description("💎1 STEALTH SCORE — current anonymity-credit balance + total earned/spent + last 10 ledger rows.")
823
+ .action(async () => {
824
+ try {
825
+ const core = await import("@mneme-ai/core");
826
+ const out = core.nemesis.stealthCreditStatus(process.cwd());
827
+ const chain = core.nemesis.verifyStealthLedger(process.cwd());
828
+ writeJson({ ok: chain.ok, ...out, chain });
829
+ }
830
+ catch (e) {
831
+ writeJson({ ok: false, error: e.message });
832
+ process.exitCode = 1;
833
+ }
834
+ });
835
+ // Diamond 2 — CAPILLARY micro-tell fingerprinter
836
+ n.command("capillary")
837
+ .description("💎2 CAPILLARY — extract 50+ MICRO style tells (whitespace / quote / naming / comma / brace) from a diff. Spoof-resistant: vendors must mimic all 50+ tells coherently to fake another vendor. Use --stdin with JSON {diff}.")
838
+ .option("--stdin", "Read JSON {diff} from stdin")
839
+ .option("--top <n>", "Show top-N non-zero features", (v) => Number(v), 15)
840
+ .action(async (opts) => {
841
+ try {
842
+ const core = await import("@mneme-ai/core");
843
+ const f = opts.stdin ? await readStdinJson() : null;
844
+ if (!f) {
845
+ writeJson({ ok: false, error: "pass --stdin with JSON {diff: '...'}" });
846
+ process.exitCode = 1;
847
+ return;
848
+ }
849
+ const profile = core.nemesis.extractMicroProfile(f.diff ?? "");
850
+ const entries = Object.entries(profile.features).filter(([, v]) => v !== 0).sort((a, b) => Math.abs(b[1]) - Math.abs(a[1]));
851
+ const top = entries.slice(0, opts.top ?? 15);
852
+ writeJson({ ok: true, language: profile.language, totalLines: profile.totalLines, totalFeatures: Object.keys(profile.features).length, nonZeroFeatures: entries.length, top: Object.fromEntries(top), allFeatures: profile.features });
853
+ }
854
+ catch (e) {
855
+ writeJson({ ok: false, error: e.message });
856
+ process.exitCode = 1;
857
+ }
858
+ });
859
+ n.command("anti_capillary")
860
+ .description("💎2 ANTI-CAPILLARY — given current diff + target vendor profile, suggest rewrites to mask source vendor's micro-tells (privacy primitive). Use --stdin with JSON {current: {diff}, target: {diff}}.")
861
+ .option("--stdin", "Read JSON from stdin")
862
+ .option("--max <n>", "Max hints to return", (v) => Number(v), 10)
863
+ .action(async (opts) => {
864
+ try {
865
+ const core = await import("@mneme-ai/core");
866
+ const f = opts.stdin ? await readStdinJson() : null;
867
+ if (!f) {
868
+ writeJson({ ok: false, error: "pass --stdin with JSON {current: {diff}, target: {diff}}" });
869
+ process.exitCode = 1;
870
+ return;
871
+ }
872
+ const cur = core.nemesis.extractMicroProfile(f.current?.diff ?? "");
873
+ const tgt = core.nemesis.extractMicroProfile(f.target?.diff ?? "");
874
+ const distance = core.nemesis.microDistance(cur, tgt);
875
+ const hints = core.nemesis.suggestAntiCapillary(cur, tgt, { maxHints: opts.max ?? 10 });
876
+ writeJson({ ok: true, distance, hintsCount: hints.length, hints });
877
+ }
878
+ catch (e) {
879
+ writeJson({ ok: false, error: e.message });
880
+ process.exitCode = 1;
881
+ }
882
+ });
883
+ // Diamond 3 — COLOSSEUM auto-tournament + 3-axis leaderboard
884
+ n.command("colosseum")
885
+ .description("💎3 COLOSSEUM — auto-tournament: each contender wears every other vendor's disguise + NEMESIS classifies. ELO + 3-axis (deception/detectability/mimicry) HMAC leaderboard. Use --stdin with JSON {contenders: [{realVendor, alias?, fixture: {diff, prDescription, commitMessages}}, ...]}.")
886
+ .option("--stdin", "Read contenders JSON from stdin")
887
+ .option("--no-persist", "Run dry; do not write to .mneme/nemesis/colosseum/")
888
+ .option("--tournament-id <id>", "Override tournament id")
889
+ .action(async (opts) => {
890
+ try {
891
+ const core = await import("@mneme-ai/core");
892
+ const f = opts.stdin ? await readStdinJson() : null;
893
+ if (!f) {
894
+ writeJson({ ok: false, error: "pass --stdin with JSON {contenders: [{realVendor, alias?, fixture:{...}}]}" });
895
+ process.exitCode = 1;
896
+ return;
897
+ }
898
+ const contenders = f.contenders;
899
+ if (!Array.isArray(contenders) || contenders.length < 2) {
900
+ writeJson({ ok: false, error: "contenders must be an array of ≥ 2" });
901
+ process.exitCode = 1;
902
+ return;
903
+ }
904
+ const result = core.nemesis.runTournament(process.cwd(), contenders, { tournamentId: opts.tournamentId, persist: opts.persist !== false });
905
+ writeJson({ ok: true, tournamentId: result.tournamentId, rounds: result.rounds, champion: result.champion, leaderboard: result.leaderboard, hmac: result.hmac, eventCount: result.events.length });
906
+ }
907
+ catch (e) {
908
+ writeJson({ ok: false, error: e.message });
909
+ process.exitCode = 1;
910
+ }
911
+ });
912
+ n.command("colosseum_board")
913
+ .description("💎3 COLOSSEUM — read current leaderboard (signed) + total events.")
914
+ .action(async () => {
915
+ try {
916
+ const core = await import("@mneme-ai/core");
917
+ const b = core.nemesis.readColosseumLeaderboard(process.cwd());
918
+ const chain = core.nemesis.verifyColosseumChain(process.cwd());
919
+ writeJson({ ok: chain.ok, ...b, chain });
920
+ }
921
+ catch (e) {
922
+ writeJson({ ok: false, error: e.message });
923
+ process.exitCode = 1;
924
+ }
925
+ });
926
+ n.command("colosseum_replay")
927
+ .description("💎3 COLOSSEUM — spectator mode: replay last N events from the tournament chain.")
928
+ .option("--n <n>", "Number of events to replay", (v) => Number(v), 20)
929
+ .action(async (opts) => {
930
+ try {
931
+ const core = await import("@mneme-ai/core");
932
+ const events = core.nemesis.spectatorReplay(process.cwd(), opts.n ?? 20);
933
+ writeJson({ ok: true, eventCount: events.length, events });
934
+ }
935
+ catch (e) {
936
+ writeJson({ ok: false, error: e.message });
937
+ process.exitCode = 1;
938
+ }
939
+ });
940
+ // Diamond 4 — MOLT silent model-rotation detector
941
+ n.command("molt")
942
+ .description("💎4 MOLT — silent-model-rotation detector. Reads drift-<vendor>.jsonl ledger, splits into prior/post windows, surfaces dominant Welch-style feature shifts (z≥3.0). HMAC-signed forensic verdict. Use --vendor + (optional) --since-ms / --min-z.")
943
+ .requiredOption("--vendor <id>", "Vendor to inspect (e.g. cursor, claude-code)")
944
+ .option("--since-ms <ms>", "Filter entries newer than this epoch ms", (v) => Number(v))
945
+ .option("--min-z <n>", "Minimum z-score for shift to be dominant", (v) => Number(v), 3.0)
946
+ .option("--webhook <url>", "POST signed verdict JSON to this URL on molt detected")
947
+ .action(async (opts) => {
948
+ try {
949
+ const core = await import("@mneme-ai/core");
950
+ const v = core.nemesis.detectMolt(process.cwd(), opts.vendor, {
951
+ sinceMs: opts.sinceMs,
952
+ minZ: opts.minZ ?? 3.0,
953
+ });
954
+ const out = { ok: true, verdict: v };
955
+ if (opts.webhook && v.molted) {
956
+ const w = await core.nemesis.emitMoltWebhook(v, opts.webhook);
957
+ out.webhook = w;
958
+ }
959
+ writeJson(out);
960
+ }
961
+ catch (e) {
962
+ writeJson({ ok: false, error: e.message });
963
+ process.exitCode = 1;
964
+ }
965
+ });
966
+ n.command("molt_verify")
967
+ .description("💎4 MOLT — verify the HMAC on a MoltVerdict JSON. Use --stdin with a verdict body.")
968
+ .option("--stdin", "Read MoltVerdict JSON from stdin")
969
+ .action(async (opts) => {
970
+ try {
971
+ const core = await import("@mneme-ai/core");
972
+ const v = opts.stdin ? await readStdinJson() : null;
973
+ if (!v) {
974
+ writeJson({ ok: false, error: "pass --stdin with MoltVerdict JSON" });
975
+ process.exitCode = 1;
976
+ return;
977
+ }
978
+ const valid = core.nemesis.verifyMoltVerdict(v);
979
+ writeJson({ ok: valid, valid });
980
+ if (!valid)
981
+ process.exitCode = 1;
982
+ }
983
+ catch (e) {
984
+ writeJson({ ok: false, error: e.message });
985
+ process.exitCode = 1;
986
+ }
987
+ });
988
+ // Diamond 5 — THEMIS alibi verifier
989
+ n.command("themis")
990
+ .description("💎5 THEMIS — alibi verifier: prove a fixture is NOT vendor X. Returns star-rated evidence + HMAC-signed ALIBI_CONFIRMED/DENIED/INCONCLUSIVE. EU AI Act compliance defense primitive. Use --stdin with JSON {notVendor, fixture}.")
991
+ .option("--stdin", "Read JSON {notVendor, fixture:{diff, prDescription, commitMessages}} from stdin")
992
+ .option("--not-vendor <id>", "Override: vendor you are denying (if not via stdin)")
993
+ .option("--min-stars <n>", "Minimum stars to include feature in evidence", (v) => Number(v), 3)
994
+ .action(async (opts) => {
995
+ try {
996
+ const core = await import("@mneme-ai/core");
997
+ const j = opts.stdin ? await readStdinJson() : null;
998
+ const notVendor = opts.notVendor ?? j?.notVendor;
999
+ if (!notVendor) {
1000
+ writeJson({ ok: false, error: "missing notVendor (pass --not-vendor or via --stdin JSON)" });
1001
+ process.exitCode = 1;
1002
+ return;
1003
+ }
1004
+ const fixture = j?.fixture;
1005
+ if (!fixture) {
1006
+ writeJson({ ok: false, error: "missing fixture (pass via --stdin JSON)" });
1007
+ process.exitCode = 1;
1008
+ return;
1009
+ }
1010
+ const r = core.nemesis.verifyAlibi({
1011
+ notVendor,
1012
+ fixture: { diff: fixture.diff ?? "", prDescription: fixture.prDescription ?? "", commitMessages: fixture.commitMessages ?? [] },
1013
+ minStars: opts.minStars,
1014
+ });
1015
+ writeJson({ ok: true, result: r });
1016
+ }
1017
+ catch (e) {
1018
+ writeJson({ ok: false, error: e.message });
1019
+ process.exitCode = 1;
1020
+ }
1021
+ });
1022
+ n.command("themis_verify")
1023
+ .description("💎5 THEMIS — verify HMAC on a ThemisResult JSON. Use --stdin.")
1024
+ .option("--stdin", "Read ThemisResult JSON from stdin")
1025
+ .action(async (opts) => {
1026
+ try {
1027
+ const core = await import("@mneme-ai/core");
1028
+ const j = opts.stdin ? await readStdinJson() : null;
1029
+ if (!j) {
1030
+ writeJson({ ok: false, error: "pass --stdin with ThemisResult JSON" });
1031
+ process.exitCode = 1;
1032
+ return;
1033
+ }
1034
+ const valid = core.nemesis.verifyAlibiSignature(j);
1035
+ writeJson({ ok: valid, valid });
1036
+ if (!valid)
1037
+ process.exitCode = 1;
1038
+ }
1039
+ catch (e) {
1040
+ writeJson({ ok: false, error: e.message });
1041
+ process.exitCode = 1;
1042
+ }
1043
+ });
1044
+ // Diamond 6 — SIBYL ZK identity commitment
1045
+ n.command("sibyl_commit")
1046
+ .description("💎6 SIBYL — commit identity at session start (hash-commitment: SHA-256(identity||nonce||sessionId)). Returns commitment + nonce (save it; needed to reveal). Supports nested commits via --no-* flags.")
1047
+ .requiredOption("--vendor <id>", "Vendor identity to commit")
1048
+ .option("--model <name>", "Optional model identity to nest in commit")
1049
+ .option("--version <v>", "Optional version identity to nest in commit")
1050
+ .option("--session-id <id>", "Override session id (default auto)")
1051
+ .option("--no-persist", "Do not persist commitment to .mneme/nemesis/sibyl/")
1052
+ .action(async (opts) => {
1053
+ try {
1054
+ const core = await import("@mneme-ai/core");
1055
+ const r = core.nemesis.commitIdentity(process.cwd(), {
1056
+ identity: { vendor: opts.vendor, model: opts.model, version: opts.version },
1057
+ sessionId: opts.sessionId,
1058
+ persist: opts.persist !== false,
1059
+ });
1060
+ writeJson({ ok: true, commitment: r.commitment, nonce: r.nonce, identitySnapshot: r.identitySnapshot, hint: "SAVE the nonce — it is required at reveal time and is NOT recoverable." });
1061
+ }
1062
+ catch (e) {
1063
+ writeJson({ ok: false, error: e.message });
1064
+ process.exitCode = 1;
1065
+ }
1066
+ });
1067
+ n.command("sibyl_reveal")
1068
+ .description("💎6 SIBYL — reveal identity at session end. Recomputes commitment hash from (identity, nonce, sessionId) and verifies it matches the original. Use --stdin with JSON {sessionId, identity, nonce}.")
1069
+ .option("--stdin", "Read reveal JSON from stdin")
1070
+ .option("--no-persist", "Do not persist the reveal to chain")
1071
+ .action(async (opts) => {
1072
+ try {
1073
+ const core = await import("@mneme-ai/core");
1074
+ const j = opts.stdin ? await readStdinJson() : null;
1075
+ if (!j) {
1076
+ writeJson({ ok: false, error: "pass --stdin with JSON {sessionId, identity:{vendor[,model][,version]}, nonce}" });
1077
+ process.exitCode = 1;
1078
+ return;
1079
+ }
1080
+ const payload = j;
1081
+ if (!payload.sessionId || !payload.identity || !payload.nonce) {
1082
+ writeJson({ ok: false, error: "sessionId / identity / nonce all required" });
1083
+ process.exitCode = 1;
1084
+ return;
1085
+ }
1086
+ const r = core.nemesis.revealIdentity(process.cwd(), {
1087
+ sessionId: payload.sessionId,
1088
+ identity: { vendor: payload.identity.vendor ?? "", model: payload.identity.model, version: payload.identity.version },
1089
+ nonce: payload.nonce,
1090
+ persist: opts.persist !== false,
1091
+ });
1092
+ writeJson({ ok: r.matches, ...r });
1093
+ if (!r.matches)
1094
+ process.exitCode = 1;
1095
+ }
1096
+ catch (e) {
1097
+ writeJson({ ok: false, error: e.message });
1098
+ process.exitCode = 1;
1099
+ }
1100
+ });
1101
+ n.command("sibyl_chain")
1102
+ .description("💎6 SIBYL — verify HMAC chain on commitments + reveals; list open (un-revealed) commitments.")
1103
+ .action(async () => {
1104
+ try {
1105
+ const core = await import("@mneme-ai/core");
1106
+ const chain = core.nemesis.verifySibylChain(process.cwd());
1107
+ const open = core.nemesis.listOpenCommitments(process.cwd());
1108
+ writeJson({ ok: chain.ok, chain, openCommitments: open });
1109
+ }
1110
+ catch (e) {
1111
+ writeJson({ ok: false, error: e.message });
1112
+ process.exitCode = 1;
1113
+ }
1114
+ });
1115
+ // ──────────────────────────────────────────────────────────────────
1116
+ // v2.53.0 — PATCH OPEN WOUNDS (P0/P1)
1117
+ // Adds key wizard, augmented-corpus accuracy probe, JANUS organ,
1118
+ // release-gate threshold knob, wiring-lag gate, catalog count.
1119
+ // ──────────────────────────────────────────────────────────────────
1120
+ n.command("key_setup")
1121
+ .description("v2.53 P0-1 HMAC key wizard — generate a 64-char hex key in .mneme/nemesis/hmac.key (mode 0600) OR ~/.mneme/nemesis/hmac.key. Idempotent (skips if env var already set or key already present).")
1122
+ .option("--target <where>", "Where to write: 'repo' (default) or 'user'", (v) => v, "repo")
1123
+ .option("--force", "Overwrite existing key (dangerous — invalidates past receipts)", false)
1124
+ .option("--dry-run", "Compute path + key length without writing", false)
1125
+ .action(async (opts) => {
1126
+ try {
1127
+ const core = await import("@mneme-ai/core");
1128
+ const r = core.nemesis.runKeyWizard({
1129
+ repoRoot: process.cwd(),
1130
+ target: opts.target ?? "repo",
1131
+ force: opts.force ?? false,
1132
+ dryRun: opts.dryRun ?? false,
1133
+ });
1134
+ writeJson(r);
1135
+ if (!r.ok)
1136
+ process.exitCode = 1;
1137
+ }
1138
+ catch (e) {
1139
+ writeJson({ ok: false, error: e.message });
1140
+ process.exitCode = 1;
1141
+ }
1142
+ });
1143
+ n.command("key_check")
1144
+ .description("v2.53 P0-1 — verify HMAC key permissions + STRICT mode status.")
1145
+ .action(async () => {
1146
+ try {
1147
+ const core = await import("@mneme-ai/core");
1148
+ const perms = core.nemesis.checkKeyPermissions(process.cwd());
1149
+ let strict;
1150
+ try {
1151
+ strict = core.nemesis.strictKeyCheck(process.cwd());
1152
+ }
1153
+ catch (e) {
1154
+ strict = { error: e.message };
1155
+ }
1156
+ writeJson({ ok: perms.ok, permissions: perms, strict });
1157
+ }
1158
+ catch (e) {
1159
+ writeJson({ ok: false, error: e.message });
1160
+ process.exitCode = 1;
1161
+ }
1162
+ });
1163
+ n.command("classify_augmented")
1164
+ .description("v2.53 P1-2 — evaluate calibrated classifier on 6x-augmented corpus (header-less + naturalistic + sparse + dense + whitespace noise). Reports per-kind accuracy + sample failures.")
1165
+ .option("--max-failing <n>", "Max failures to surface", (v) => Number(v), 10)
1166
+ .action(async (opts) => {
1167
+ try {
1168
+ const core = await import("@mneme-ai/core");
1169
+ const r = core.nemesis.evaluateAugmentedAccuracy({ maxFailing: opts.maxFailing ?? 10 });
1170
+ writeJson({ ok: r.accuracy >= 0.85, ...r });
1171
+ }
1172
+ catch (e) {
1173
+ writeJson({ ok: false, error: e.message });
1174
+ process.exitCode = 1;
1175
+ }
1176
+ });
1177
+ n.command("janus_observe")
1178
+ .description("v2.53 P1-3 JANUS — locate which vendor cluster a fixture's fingerprint sits in (basin + margin to second-nearest). Use --stdin with JSON {diff, prDescription, commitMessages}.")
1179
+ .option("--stdin", "Read fixture from stdin")
1180
+ .action(async (opts) => {
1181
+ try {
1182
+ const core = await import("@mneme-ai/core");
1183
+ const f = opts.stdin ? await readStdinJson() : null;
1184
+ if (!f) {
1185
+ writeJson({ ok: false, error: "pass --stdin with JSON fixture" });
1186
+ process.exitCode = 1;
1187
+ return;
1188
+ }
1189
+ const obs = core.nemesis.observe({ diff: f.diff ?? "", prDescription: f.prDescription ?? "", commitMessages: f.commitMessages ?? [] });
1190
+ writeJson({ ok: true, observation: obs });
1191
+ }
1192
+ catch (e) {
1193
+ writeJson({ ok: false, error: e.message });
1194
+ process.exitCode = 1;
1195
+ }
1196
+ });
1197
+ n.command("janus_swap")
1198
+ .description("v2.53 P1-3 JANUS — given a SEQUENCE of fixtures (JSON array), detect cross-cluster boundary transitions ('Eve started looking like Codex mid-session'). HMAC-signed verdict.")
1199
+ .option("--stdin", "Read JSON {fixtures: [{diff, prDescription, commitMessages}, ...]} from stdin")
1200
+ .option("--min-margin <n>", "Minimum margin to second-nearest for swap to count", (v) => Number(v), 0.5)
1201
+ .action(async (opts) => {
1202
+ try {
1203
+ const core = await import("@mneme-ai/core");
1204
+ const f = opts.stdin ? await readStdinJson() : null;
1205
+ const fixtures = f?.fixtures;
1206
+ if (!Array.isArray(fixtures) || fixtures.length < 2) {
1207
+ writeJson({ ok: false, error: "fixtures array of ≥2 required" });
1208
+ process.exitCode = 1;
1209
+ return;
1210
+ }
1211
+ const obs = fixtures.map((fx) => core.nemesis.observe({ diff: fx.diff ?? "", prDescription: fx.prDescription ?? "", commitMessages: fx.commitMessages ?? [] }));
1212
+ const r = core.nemesis.detectIdentitySwap(obs, { minMargin: opts.minMargin });
1213
+ writeJson({ ok: true, swap: r });
1214
+ }
1215
+ catch (e) {
1216
+ writeJson({ ok: false, error: e.message });
1217
+ process.exitCode = 1;
1218
+ }
1219
+ });
770
1220
  n.command("cleanse_ledger")
771
1221
  .description("v2.50.0 — RETROACTIVE LEDGER CLEANSE: coerce historical embedder-leak rows in .mneme/cli-activity.jsonl to vendor:'unknown' + re-chain HMACs + back up original to .pre-v50.bak. Idempotent.")
772
1222
  .option("--dry-run", "Compute the plan without writing.", false)