@mneme-ai/core 2.45.0 → 2.47.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/dist/agent_manifest.d.ts +1 -1
  2. package/dist/agent_manifest.d.ts.map +1 -1
  3. package/dist/agent_manifest.js +8 -0
  4. package/dist/agent_manifest.js.map +1 -1
  5. package/dist/index.d.ts +1 -1
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +14 -2
  8. package/dist/index.js.map +1 -1
  9. package/dist/nemesis/calibration_corpus.d.ts +40 -0
  10. package/dist/nemesis/calibration_corpus.d.ts.map +1 -0
  11. package/dist/nemesis/calibration_corpus.js +148 -0
  12. package/dist/nemesis/calibration_corpus.js.map +1 -0
  13. package/dist/nemesis/classifier.d.ts +39 -0
  14. package/dist/nemesis/classifier.d.ts.map +1 -0
  15. package/dist/nemesis/classifier.js +133 -0
  16. package/dist/nemesis/classifier.js.map +1 -0
  17. package/dist/nemesis/classifier_calibrated.d.ts +48 -0
  18. package/dist/nemesis/classifier_calibrated.d.ts.map +1 -0
  19. package/dist/nemesis/classifier_calibrated.js +166 -0
  20. package/dist/nemesis/classifier_calibrated.js.map +1 -0
  21. package/dist/nemesis/drift_timeline.d.ts +35 -0
  22. package/dist/nemesis/drift_timeline.d.ts.map +1 -0
  23. package/dist/nemesis/drift_timeline.js +98 -0
  24. package/dist/nemesis/drift_timeline.js.map +1 -0
  25. package/dist/nemesis/env_scan.d.ts +40 -0
  26. package/dist/nemesis/env_scan.d.ts.map +1 -0
  27. package/dist/nemesis/env_scan.js +74 -0
  28. package/dist/nemesis/env_scan.js.map +1 -0
  29. package/dist/nemesis/eu_ai_act_stamp.d.ts +30 -0
  30. package/dist/nemesis/eu_ai_act_stamp.d.ts.map +1 -0
  31. package/dist/nemesis/eu_ai_act_stamp.js +116 -0
  32. package/dist/nemesis/eu_ai_act_stamp.js.map +1 -0
  33. package/dist/nemesis/features.d.ts +13 -0
  34. package/dist/nemesis/features.d.ts.map +1 -0
  35. package/dist/nemesis/features.js +151 -0
  36. package/dist/nemesis/features.js.map +1 -0
  37. package/dist/nemesis/git_hook_installer.d.ts +24 -0
  38. package/dist/nemesis/git_hook_installer.d.ts.map +1 -0
  39. package/dist/nemesis/git_hook_installer.js +71 -0
  40. package/dist/nemesis/git_hook_installer.js.map +1 -0
  41. package/dist/nemesis/identity_verifier.d.ts +25 -0
  42. package/dist/nemesis/identity_verifier.d.ts.map +1 -0
  43. package/dist/nemesis/identity_verifier.js +106 -0
  44. package/dist/nemesis/identity_verifier.js.map +1 -0
  45. package/dist/nemesis/index.d.ts +30 -0
  46. package/dist/nemesis/index.d.ts.map +1 -0
  47. package/dist/nemesis/index.js +36 -0
  48. package/dist/nemesis/index.js.map +1 -0
  49. package/dist/nemesis/key_management.d.ts +30 -0
  50. package/dist/nemesis/key_management.d.ts.map +1 -0
  51. package/dist/nemesis/key_management.js +91 -0
  52. package/dist/nemesis/key_management.js.map +1 -0
  53. package/dist/nemesis/learning_loop.d.ts +45 -0
  54. package/dist/nemesis/learning_loop.d.ts.map +1 -0
  55. package/dist/nemesis/learning_loop.js +116 -0
  56. package/dist/nemesis/learning_loop.js.map +1 -0
  57. package/dist/nemesis/replay_attack.d.ts +27 -0
  58. package/dist/nemesis/replay_attack.d.ts.map +1 -0
  59. package/dist/nemesis/replay_attack.js +60 -0
  60. package/dist/nemesis/replay_attack.js.map +1 -0
  61. package/dist/nemesis/types.d.ts +160 -0
  62. package/dist/nemesis/types.d.ts.map +1 -0
  63. package/dist/nemesis/types.js +9 -0
  64. package/dist/nemesis/types.js.map +1 -0
  65. package/dist/nemesis/watermark.d.ts +32 -0
  66. package/dist/nemesis/watermark.d.ts.map +1 -0
  67. package/dist/nemesis/watermark.js +83 -0
  68. package/dist/nemesis/watermark.js.map +1 -0
  69. package/dist/truth_gate/claims.d.ts.map +1 -1
  70. package/dist/truth_gate/claims.js +10 -0
  71. package/dist/truth_gate/claims.js.map +1 -1
  72. package/dist/truth_gate/probes.d.ts.map +1 -1
  73. package/dist/truth_gate/probes.js +126 -0
  74. package/dist/truth_gate/probes.js.map +1 -1
  75. package/package.json +1 -1
@@ -0,0 +1,151 @@
1
+ /**
2
+ * v2.46.0 — NEMESIS ORGAN 1: FINGERPRINTER (41 features).
3
+ *
4
+ * Implements the 41-feature vector from arxiv 2601.17406 — pure
5
+ * deterministic extraction (no ML model needed for the EXTRACTOR; the
6
+ * CLASSIFIER applies the paper's feature weights to predict vendor).
7
+ *
8
+ * Each feature is documented in types.ts. Every value is a finite
9
+ * non-negative real. NEVER throws — empty inputs return zero-vector.
10
+ */
11
+ function safeDivide(num, den) {
12
+ return den === 0 ? 0 : num / den;
13
+ }
14
+ function shannonEntropyNormalized(counts) {
15
+ const total = counts.reduce((a, b) => a + b, 0);
16
+ if (total === 0 || counts.length === 0)
17
+ return 0;
18
+ let h = 0;
19
+ for (const c of counts) {
20
+ if (c === 0)
21
+ continue;
22
+ const p = c / total;
23
+ h += -p * Math.log2(p);
24
+ }
25
+ const maxH = Math.log2(Math.max(1, counts.length));
26
+ return maxH === 0 ? 0 : h / maxH; // ∈ [0, 1]
27
+ }
28
+ /**
29
+ * Parse a unified diff into per-file added/removed line counts +
30
+ * collected added-line text.
31
+ */
32
+ function parseDiff(diff) {
33
+ const perFile = new Map();
34
+ const addedLines = [];
35
+ const removedLines = [];
36
+ let current = null;
37
+ let currentName = "";
38
+ for (const ln of diff.split("\n")) {
39
+ const m = ln.match(/^diff --git a\/(\S+) b\/(\S+)/);
40
+ if (m) {
41
+ currentName = m[2];
42
+ current = { added: 0, removed: 0 };
43
+ perFile.set(currentName, current);
44
+ continue;
45
+ }
46
+ if (!current)
47
+ continue;
48
+ if (ln.startsWith("+") && !ln.startsWith("+++")) {
49
+ current.added++;
50
+ addedLines.push(ln.slice(1));
51
+ }
52
+ else if (ln.startsWith("-") && !ln.startsWith("---")) {
53
+ current.removed++;
54
+ removedLines.push(ln.slice(1));
55
+ }
56
+ }
57
+ return { perFile, addedLines, removedLines };
58
+ }
59
+ export function extractFingerprint(fixture) {
60
+ const diff = fixture.diff ?? "";
61
+ const prDesc = fixture.prDescription ?? "";
62
+ const commits = fixture.commitMessages ?? [];
63
+ // ── Commit shape ──
64
+ const commit_count = commits.length;
65
+ const multiline = commits.filter((c) => /\n/.test(c)).length;
66
+ const multiline_commit_ratio = safeDivide(multiline, commit_count);
67
+ const commitLineCounts = commits.map((c) => c.split("\n").length);
68
+ const mean_commit_lines = commit_count === 0 ? 0 : commitLineCounts.reduce((a, b) => a + b, 0) / commit_count;
69
+ const max_commit_chars = commits.reduce((m, c) => Math.max(m, c.length), 0);
70
+ const commit_bullet_count = commits.reduce((n, c) => n + (c.match(/^[\s>]*[-*+]\s/gm)?.length ?? 0), 0);
71
+ // ── Diff parse ──
72
+ const { perFile, addedLines, removedLines } = parseDiff(diff);
73
+ const added_lines = addedLines.length;
74
+ const removed_lines = removedLines.length;
75
+ const net_lines = added_lines - removed_lines;
76
+ const files_touched = perFile.size;
77
+ const addedJoined = addedLines.join("\n");
78
+ // Conditional / control flow
79
+ const if_count = (addedJoined.match(/\b(if|elif|else\s+if)\b/g) ?? []).length;
80
+ const switch_count = (addedJoined.match(/\b(switch|case|match)\b/g) ?? []).length;
81
+ const try_count = (addedJoined.match(/\b(try|catch|except|finally)\b/g) ?? []).length;
82
+ const conditional_density = safeDivide(if_count + switch_count + try_count, added_lines);
83
+ // ── PR description shape ──
84
+ const pr_desc_length_chars = prDesc.length;
85
+ const pr_desc_length_words = prDesc.split(/\s+/).filter(Boolean).length;
86
+ const pr_desc_length_lines = prDesc.split("\n").length;
87
+ const bullet_point_count = (prDesc.match(/^[\s>]*[-*+]\s/gm) ?? []).length;
88
+ const hyperlink_count = (prDesc.match(/\[[^\]]+\]\([^)]+\)/g) ?? []).length +
89
+ (prDesc.match(/\bhttps?:\/\/\S+/g) ?? []).length;
90
+ const heading_count = (prDesc.match(/^#{1,6}\s/gm) ?? []).length;
91
+ const code_fence_count = (prDesc.match(/```/g) ?? []).length / 2;
92
+ const inline_code_count = (prDesc.match(/`[^`\n]+`/g) ?? []).length;
93
+ // ── Change concentration ──
94
+ const perFileCounts = [...perFile.values()].map((v) => v.added + v.removed);
95
+ const distributed_changes_score = shannonEntropyNormalized(perFileCounts);
96
+ const change_concentration = 1 - distributed_changes_score;
97
+ // ── Line shape ──
98
+ const lineLengths = addedLines.map((l) => l.length);
99
+ const mean_line_length = lineLengths.length === 0 ? 0 : lineLengths.reduce((a, b) => a + b, 0) / lineLengths.length;
100
+ const max_line_length = lineLengths.reduce((m, l) => Math.max(m, l), 0);
101
+ const long_line_ratio = safeDivide(lineLengths.filter((l) => l > 100).length, lineLengths.length);
102
+ // ── Comments / blanks ──
103
+ const comment_count = addedLines.filter((l) => /^\s*(\/\/|#|\/\*|\*\s|---)/.test(l)).length;
104
+ const comment_ratio = safeDivide(comment_count, added_lines);
105
+ const blank_line_count = addedLines.filter((l) => /^\s*$/.test(l)).length;
106
+ const blank_line_ratio = safeDivide(blank_line_count, added_lines);
107
+ // ── Test / doc files ──
108
+ const filePaths = [...perFile.keys()];
109
+ const test_files_touched = filePaths.filter((p) => /\.(test|spec)\.|__tests__\/|tests?\//.test(p)).length;
110
+ const doc_files_touched = filePaths.filter((p) => /\.(md|rst|txt|adoc)$|docs?\//i.test(p)).length;
111
+ const test_file_ratio = safeDivide(test_files_touched, files_touched);
112
+ // ── Hygiene markers ──
113
+ const debug_print_count = (addedJoined.match(/\bconsole\.log\(/g) ?? []).length +
114
+ (addedJoined.match(/\bprint\(/g) ?? []).length +
115
+ (addedJoined.match(/\bdebugger\b/g) ?? []).length;
116
+ const todo_marker_count = (addedJoined.match(/\b(TODO|FIXME|XXX|HACK)\b/g) ?? []).length;
117
+ // ── Imports ──
118
+ const import_count = (addedJoined.match(/^\s*import\s/gm) ?? []).length +
119
+ (addedJoined.match(/\brequire\(/g) ?? []).length +
120
+ (addedJoined.match(/\bfrom\s+["']/g) ?? []).length;
121
+ const relative_import_count = (addedJoined.match(/from\s+["']\.{1,2}\//g) ?? []).length;
122
+ // ── Punctuation density ──
123
+ const semicolon_count = (addedJoined.match(/;/g) ?? []).length;
124
+ const semicolon_density = safeDivide(semicolon_count, added_lines);
125
+ const brace_count = (addedJoined.match(/[{}]/g) ?? []).length;
126
+ const brace_density = safeDivide(brace_count, added_lines);
127
+ const paren_count = (addedJoined.match(/[()]/g) ?? []).length;
128
+ const paren_density = safeDivide(paren_count, added_lines);
129
+ // ── Naming style ──
130
+ const identifiers = addedJoined.match(/\b[A-Za-z_][A-Za-z0-9_]{2,}\b/g) ?? [];
131
+ const camel_case_count = identifiers.filter((id) => /^[a-z][a-z0-9]*[A-Z]/.test(id)).length;
132
+ const snake_case_count = identifiers.filter((id) => /^[a-z][a-z0-9]*_[a-z]/.test(id)).length;
133
+ const mean_identifier_length = identifiers.length === 0 ? 0 : identifiers.reduce((s, i) => s + i.length, 0) / identifiers.length;
134
+ return {
135
+ multiline_commit_ratio, mean_commit_lines, max_commit_chars, commit_count,
136
+ conditional_density, if_count, switch_count, try_count,
137
+ pr_desc_length_chars, pr_desc_length_words, pr_desc_length_lines,
138
+ bullet_point_count, hyperlink_count, heading_count, code_fence_count, inline_code_count,
139
+ change_concentration, distributed_changes_score, files_touched,
140
+ added_lines, removed_lines, net_lines,
141
+ mean_line_length, max_line_length, long_line_ratio,
142
+ comment_ratio, blank_line_ratio,
143
+ test_files_touched, doc_files_touched, test_file_ratio,
144
+ debug_print_count, todo_marker_count,
145
+ import_count, relative_import_count,
146
+ semicolon_density, brace_density, paren_density,
147
+ camel_case_count, snake_case_count, mean_identifier_length,
148
+ commit_bullet_count,
149
+ };
150
+ }
151
+ //# sourceMappingURL=features.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"features.js","sourceRoot":"","sources":["../../src/nemesis/features.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * v2.46.0 — NEMESIS ORGAN 3 surface: GIT PRE-COMMIT HOOK INSTALLER.
3
+ *
4
+ * Installs a `.git/hooks/prepare-commit-msg` script that calls
5
+ * `mneme nemesis eu_stamp` for every commit and appends the Article 50
6
+ * disclosure block to the staged commit message.
7
+ *
8
+ * DRY-RUN default. Defensive: never throws.
9
+ */
10
+ export interface InstallHookInput {
11
+ repoRoot: string;
12
+ dryRun?: boolean;
13
+ }
14
+ export interface InstallHookResult {
15
+ ok: boolean;
16
+ reason?: string;
17
+ hookPath?: string;
18
+ plannedScript: string;
19
+ installed?: boolean;
20
+ /** When a hook already exists, we don't overwrite — return the existing body so the caller can merge manually. */
21
+ existing?: string;
22
+ }
23
+ export declare function installPreCommitHook(input: InstallHookInput): InstallHookResult;
24
+ //# sourceMappingURL=git_hook_installer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git_hook_installer.d.ts","sourceRoot":"","sources":["../../src/nemesis/git_hook_installer.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA8BH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,kHAAkH;IAClH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,gBAAgB,GAAG,iBAAiB,CAgC/E"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * v2.46.0 — NEMESIS ORGAN 3 surface: GIT PRE-COMMIT HOOK INSTALLER.
3
+ *
4
+ * Installs a `.git/hooks/prepare-commit-msg` script that calls
5
+ * `mneme nemesis eu_stamp` for every commit and appends the Article 50
6
+ * disclosure block to the staged commit message.
7
+ *
8
+ * DRY-RUN default. Defensive: never throws.
9
+ */
10
+ import { existsSync, mkdirSync, writeFileSync, readFileSync } from "node:fs";
11
+ import { join } from "node:path";
12
+ const HOOK_SCRIPT = `#!/bin/sh
13
+ # Mneme NEMESIS — EU AI Act Article 50 auto-stamper (v2.46.0+)
14
+ # Auto-installed by \`mneme nemesis install-hook\`.
15
+ #
16
+ # Reads the in-progress commit message, asks mneme nemesis for the
17
+ # detected vendor + confidence, and appends a machine-readable
18
+ # disclosure block. Skips if the message already contains one.
19
+ MSG_FILE="$1"
20
+ [ -z "$MSG_FILE" ] && exit 0
21
+ grep -q 'AI-GENERATED-CONTENT' "$MSG_FILE" 2>/dev/null && exit 0
22
+ # Best-effort detection via env scan (cheapest signal); fallback "unknown"
23
+ VENDOR="unknown"
24
+ [ -n "$CLAUDECODE" ] && VENDOR="claude-code"
25
+ [ -n "$CURSOR_AGENT" ] && VENDOR="cursor"
26
+ [ -n "$DEVIN_SESSION" ] && VENDOR="devin"
27
+ [ -n "$COPILOT_AGENT" ] && VENDOR="copilot"
28
+ [ -n "$CODEX_AGENT" ] && VENDOR="codex"
29
+ [ "$VENDOR" = "unknown" ] && exit 0
30
+ MSG=$(cat "$MSG_FILE")
31
+ mneme nemesis eu_stamp --message "$MSG" --vendor "$VENDOR" --json 2>/dev/null | \
32
+ node -e 'let s=""; process.stdin.on("data",d=>s+=d); process.stdin.on("end",()=>{try{const j=JSON.parse(s);if(j&&j.ok)process.stdout.write(j.stampedMessage)}catch{}})' \
33
+ > "$MSG_FILE.new" && mv "$MSG_FILE.new" "$MSG_FILE"
34
+ exit 0
35
+ `;
36
+ export function installPreCommitHook(input) {
37
+ const plannedScript = HOOK_SCRIPT;
38
+ if (!input || !input.repoRoot) {
39
+ return { ok: false, reason: "repoRoot required", plannedScript };
40
+ }
41
+ const dryRun = input.dryRun !== false; // default TRUE
42
+ const hookDir = join(input.repoRoot, ".git", "hooks");
43
+ const hookPath = join(hookDir, "prepare-commit-msg");
44
+ if (dryRun) {
45
+ return { ok: true, hookPath, plannedScript, installed: false };
46
+ }
47
+ if (!existsSync(join(input.repoRoot, ".git"))) {
48
+ return { ok: false, reason: "not a git repo (no .git directory)", hookPath, plannedScript };
49
+ }
50
+ try {
51
+ if (!existsSync(hookDir))
52
+ mkdirSync(hookDir, { recursive: true });
53
+ if (existsSync(hookPath)) {
54
+ const existing = readFileSync(hookPath, "utf8");
55
+ if (existing.includes("mneme nemesis eu_stamp")) {
56
+ return { ok: true, hookPath, plannedScript, installed: true, existing };
57
+ }
58
+ return {
59
+ ok: false,
60
+ reason: "existing prepare-commit-msg hook found; refuse to overwrite. Add the NEMESIS body manually or move the existing hook aside.",
61
+ hookPath, plannedScript, existing,
62
+ };
63
+ }
64
+ writeFileSync(hookPath, plannedScript, { mode: 0o755 });
65
+ return { ok: true, hookPath, plannedScript, installed: true };
66
+ }
67
+ catch (e) {
68
+ return { ok: false, reason: `install failed: ${e.message}`, hookPath, plannedScript };
69
+ }
70
+ }
71
+ //# sourceMappingURL=git_hook_installer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git_hook_installer.js","sourceRoot":"","sources":["../../src/nemesis/git_hook_installer.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,WAAW,GAAG;;;;;;;;;;;;;;;;;;;;;;;CAuBnB,CAAC;AAiBF,MAAM,UAAU,oBAAoB,CAAC,KAAuB;IAC1D,MAAM,aAAa,GAAG,WAAW,CAAC;IAClC,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;QAC9B,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,mBAAmB,EAAE,aAAa,EAAE,CAAC;IACnE,CAAC;IACD,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,KAAK,KAAK,CAAC,CAAC,eAAe;IACtD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IACtD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,oBAAoB,CAAC,CAAC;IACrD,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,aAAa,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IACjE,CAAC;IACD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC;QAC9C,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,oCAAoC,EAAE,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC9F,CAAC;IACD,IAAI,CAAC;QACH,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;YAAE,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAClE,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzB,MAAM,QAAQ,GAAG,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;YAChD,IAAI,QAAQ,CAAC,QAAQ,CAAC,wBAAwB,CAAC,EAAE,CAAC;gBAChD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,aAAa,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;YAC1E,CAAC;YACD,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,MAAM,EAAE,6HAA6H;gBACrI,QAAQ,EAAE,aAAa,EAAE,QAAQ;aAClC,CAAC;QACJ,CAAC;QACD,aAAa,CAAC,QAAQ,EAAE,aAAa,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACxD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,aAAa,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;IAChE,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,mBAAoB,CAAW,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,aAAa,EAAE,CAAC;IACnG,CAAC;AACH,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * v2.46.0 — NEMESIS ORGAN 2: LIE DETECTOR.
3
+ *
4
+ * Compares CLAIMED vendor (whoever the AI agent says it is) against
5
+ * DETECTED vendor (from fingerprinter + env scan). Divergence → alert.
6
+ *
7
+ * Verdict ladder:
8
+ * CONFIRMED claimed = detected with confidence ≥ 0.40
9
+ * DISPUTED different vendor but detector confidence < 0.65
10
+ * IMPOSSIBLE different vendor AND detector confidence ≥ 0.65
11
+ * INCONCLUSIVE detector returned unknown / confidence < 0.10
12
+ *
13
+ * Every verdict carries an HMAC over the canonical body so an
14
+ * external auditor can verify the verdict was actually computed
15
+ * (and not faked by the AI agent itself).
16
+ */
17
+ import type { Fixture, IdentityClaimInput, IdentityVerdict } from "./types.js";
18
+ export declare function verifyIdentityClaim(input: IdentityClaimInput): IdentityVerdict;
19
+ /**
20
+ * Verify the HMAC of a returned IdentityVerdict. Returns false if
21
+ * any field was tampered after the verdict was signed.
22
+ */
23
+ export declare function verifyIdentityHmac(v: IdentityVerdict): boolean;
24
+ export type { Fixture, IdentityClaimInput, IdentityVerdict };
25
+ //# sourceMappingURL=identity_verifier.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity_verifier.d.ts","sourceRoot":"","sources":["../../src/nemesis/identity_verifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EACV,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAC7C,MAAM,YAAY,CAAC;AA6BpB,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,kBAAkB,GAAG,eAAe,CAgD9E;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,eAAe,GAAG,OAAO,CAU9D;AAGD,YAAY,EAAE,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,CAAC"}
@@ -0,0 +1,106 @@
1
+ /**
2
+ * v2.46.0 — NEMESIS ORGAN 2: LIE DETECTOR.
3
+ *
4
+ * Compares CLAIMED vendor (whoever the AI agent says it is) against
5
+ * DETECTED vendor (from fingerprinter + env scan). Divergence → alert.
6
+ *
7
+ * Verdict ladder:
8
+ * CONFIRMED claimed = detected with confidence ≥ 0.40
9
+ * DISPUTED different vendor but detector confidence < 0.65
10
+ * IMPOSSIBLE different vendor AND detector confidence ≥ 0.65
11
+ * INCONCLUSIVE detector returned unknown / confidence < 0.10
12
+ *
13
+ * Every verdict carries an HMAC over the canonical body so an
14
+ * external auditor can verify the verdict was actually computed
15
+ * (and not faked by the AI agent itself).
16
+ */
17
+ import { createHmac } from "node:crypto";
18
+ import { extractFingerprint } from "./features.js";
19
+ import { classifyAgent } from "./classifier.js";
20
+ import { scanEnv } from "./env_scan.js";
21
+ const HMAC_KEY = process.env["MNEME_NEMESIS_KEY"] ?? "MNEME-NEMESIS-DEFAULT-KEY-v2.46";
22
+ function canonical(obj) {
23
+ const keys = Object.keys(obj).sort();
24
+ return JSON.stringify(keys.reduce((acc, k) => { acc[k] = obj[k]; return acc; }, {}));
25
+ }
26
+ function hmacOf(body) {
27
+ return createHmac("sha256", HMAC_KEY).update(canonical(body)).digest("hex").slice(0, 32);
28
+ }
29
+ function normalizeVendor(s) {
30
+ const x = (s ?? "").toLowerCase().trim();
31
+ // common aliases
32
+ const map = {
33
+ "claude": "claude-code", "claude-code": "claude-code", "claudecode": "claude-code", "anthropic-claude": "claude-code",
34
+ "codex": "codex", "openai-codex": "codex", "openai-codex-cli": "codex",
35
+ "copilot": "copilot", "github-copilot": "copilot", "gh-copilot": "copilot",
36
+ "cursor": "cursor", "cursor-agent": "cursor",
37
+ "devin": "devin", "cognition-devin": "devin",
38
+ };
39
+ return map[x] ?? x;
40
+ }
41
+ export function verifyIdentityClaim(input) {
42
+ const claimedRaw = input.claimedVendor ?? "";
43
+ const claimed = normalizeVendor(claimedRaw);
44
+ const fp = extractFingerprint(input.fixture);
45
+ const fpVerdict = classifyAgent(fp);
46
+ const envVerdict = scanEnv();
47
+ // Fuse fingerprint + env detector. Env evidence boosts confidence
48
+ // when it agrees; reduces when it disagrees.
49
+ let detected = fpVerdict.topVendor;
50
+ let confidence = fpVerdict.confidence;
51
+ if (envVerdict.vendor !== "unknown") {
52
+ if (envVerdict.vendor === fpVerdict.topVendor) {
53
+ // Agreement boost
54
+ confidence = Math.min(0.99, confidence + 0.20);
55
+ }
56
+ else if (fpVerdict.confidence < 0.40) {
57
+ // Env wins when fingerprint is weak
58
+ detected = envVerdict.vendor;
59
+ confidence = Math.min(0.95, envVerdict.confidence + fpVerdict.confidence * 0.30);
60
+ }
61
+ }
62
+ // Compute verdict.
63
+ let verdict;
64
+ let reasoning;
65
+ if (detected === "unknown" || confidence < 0.10) {
66
+ verdict = "INCONCLUSIVE";
67
+ reasoning = `detector returned ${detected} with confidence ${confidence.toFixed(2)} — cannot judge claim`;
68
+ }
69
+ else if (claimed === detected) {
70
+ verdict = "CONFIRMED";
71
+ reasoning = `claim=${claimed} matches detected=${detected} (conf ${confidence.toFixed(2)})`;
72
+ }
73
+ else if (confidence >= 0.65) {
74
+ verdict = "IMPOSSIBLE";
75
+ reasoning = `claim=${claimed} contradicts detected=${detected} with HIGH confidence ${confidence.toFixed(2)}`;
76
+ }
77
+ else {
78
+ verdict = "DISPUTED";
79
+ reasoning = `claim=${claimed} differs from detected=${detected} but detector confidence ${confidence.toFixed(2)} is below threshold`;
80
+ }
81
+ const body = {
82
+ verdict,
83
+ claimedVendor: claimed,
84
+ fingerprintTop: detected,
85
+ fingerprintConfidence: Number(confidence.toFixed(4)),
86
+ reasoning,
87
+ };
88
+ const hmac = hmacOf(body);
89
+ return { ...body, hmac };
90
+ }
91
+ /**
92
+ * Verify the HMAC of a returned IdentityVerdict. Returns false if
93
+ * any field was tampered after the verdict was signed.
94
+ */
95
+ export function verifyIdentityHmac(v) {
96
+ const body = {
97
+ verdict: v.verdict,
98
+ claimedVendor: v.claimedVendor,
99
+ fingerprintTop: v.fingerprintTop,
100
+ fingerprintConfidence: Number(v.fingerprintConfidence.toFixed(4)),
101
+ reasoning: v.reasoning,
102
+ };
103
+ const expected = hmacOf(body);
104
+ return expected === v.hmac;
105
+ }
106
+ //# sourceMappingURL=identity_verifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity_verifier.js","sourceRoot":"","sources":["../../src/nemesis/identity_verifier.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * v2.46.0 — NEMESIS public surface.
3
+ *
4
+ * The world's first Anti-Identity-Lie Engine for AI Coding Agents.
5
+ *
6
+ * ORGAN 1 FINGERPRINTER — features.ts + env_scan.ts (41-axis vector + env markers)
7
+ * ORGAN 2 LIE DETECTOR — classifier.ts + identity_verifier.ts (claim vs detected; HMAC verdict)
8
+ * ORGAN 3 ARTICLE 50 STAMP — eu_ai_act_stamp.ts + watermark.ts + git_hook_installer.ts
9
+ * ORGAN 4 DRIFT TIMELINE — drift_timeline.ts (per-vendor fingerprint history + σ-based drift)
10
+ * ORGAN 5 REPLAY DETECTOR — replay_attack.ts (stealth-upgrade/downgrade/swap)
11
+ *
12
+ * Composes: arxiv 2601.17406 fingerprinting + Mneme HMAC chain +
13
+ * EU AI Act Article 50 (Aug 2026 deadline) + HONEST MIRROR + ARGUS.
14
+ */
15
+ export type { VendorId, Fixture, Fingerprint, AgentVerdict, IdentityClaimInput, IdentityVerdict, IdentityVerdictKind, Article50StampInput, Article50Stamp, StampResult, VerifyStampResult, } from "./types.js";
16
+ export { extractFingerprint } from "./features.js";
17
+ export { scanEnv, type EnvScanResult } from "./env_scan.js";
18
+ export { classifyAgent, SIGNATURES } from "./classifier.js";
19
+ export { verifyIdentityClaim, verifyIdentityHmac } from "./identity_verifier.js";
20
+ export { stampArticle50, verifyStamp } from "./eu_ai_act_stamp.js";
21
+ export { encodeWatermark, decodeWatermark } from "./watermark.js";
22
+ export { installPreCommitHook, type InstallHookInput, type InstallHookResult } from "./git_hook_installer.js";
23
+ export { recordFingerprint, readTimeline, computeVariance, type DriftEntry, type VarianceResult } from "./drift_timeline.js";
24
+ export { detectReplayAttack, type ReplayResult } from "./replay_attack.js";
25
+ export { buildSeedCorpus, computeStats, seedStats, type CorpusEntry, type VendorStats, } from "./calibration_corpus.js";
26
+ export { classifyAgentCalibrated, evaluateSeedAccuracy, type AccuracyReport, } from "./classifier_calibrated.js";
27
+ export { appendCalibrationEntry, readCalibrationLedger, recomputeStats, calibrationStatus, type CalibrationStatus, type AppendResult, } from "./learning_loop.js";
28
+ export { resolveHmacKey, generateProductionKey, type KeyResolution, type KeySource, } from "./key_management.js";
29
+ export { generateProbes, gradeRun, recordRun, readRuns, trendFor, type Probe, type ProbeFamily, type NemesisRun, type TrendSeries, } from "./nemesis.js";
30
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/nemesis/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,YAAY,EACV,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,YAAY,EAC5C,kBAAkB,EAAE,eAAe,EAAE,mBAAmB,EACxD,mBAAmB,EAAE,cAAc,EAAE,WAAW,EAAE,iBAAiB,GACpE,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,eAAe,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AACjF,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAAE,KAAK,gBAAgB,EAAE,KAAK,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC9G,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,eAAe,EAAE,KAAK,UAAU,EAAE,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC7H,OAAO,EAAE,kBAAkB,EAAE,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAI3E,OAAO,EACL,eAAe,EAAE,YAAY,EAAE,SAAS,EACxC,KAAK,WAAW,EAAE,KAAK,WAAW,GACnC,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,uBAAuB,EAAE,oBAAoB,EAC7C,KAAK,cAAc,GACpB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,sBAAsB,EAAE,qBAAqB,EAAE,cAAc,EAAE,iBAAiB,EAChF,KAAK,iBAAiB,EAAE,KAAK,YAAY,GAC1C,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,cAAc,EAAE,qBAAqB,EACrC,KAAK,aAAa,EAAE,KAAK,SAAS,GACnC,MAAM,qBAAqB,CAAC;AAO7B,OAAO,EACL,cAAc,EACd,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,KAAK,KAAK,EACV,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,WAAW,GACjB,MAAM,cAAc,CAAC"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * v2.46.0 — NEMESIS public surface.
3
+ *
4
+ * The world's first Anti-Identity-Lie Engine for AI Coding Agents.
5
+ *
6
+ * ORGAN 1 FINGERPRINTER — features.ts + env_scan.ts (41-axis vector + env markers)
7
+ * ORGAN 2 LIE DETECTOR — classifier.ts + identity_verifier.ts (claim vs detected; HMAC verdict)
8
+ * ORGAN 3 ARTICLE 50 STAMP — eu_ai_act_stamp.ts + watermark.ts + git_hook_installer.ts
9
+ * ORGAN 4 DRIFT TIMELINE — drift_timeline.ts (per-vendor fingerprint history + σ-based drift)
10
+ * ORGAN 5 REPLAY DETECTOR — replay_attack.ts (stealth-upgrade/downgrade/swap)
11
+ *
12
+ * Composes: arxiv 2601.17406 fingerprinting + Mneme HMAC chain +
13
+ * EU AI Act Article 50 (Aug 2026 deadline) + HONEST MIRROR + ARGUS.
14
+ */
15
+ export { extractFingerprint } from "./features.js";
16
+ export { scanEnv } from "./env_scan.js";
17
+ export { classifyAgent, SIGNATURES } from "./classifier.js";
18
+ export { verifyIdentityClaim, verifyIdentityHmac } from "./identity_verifier.js";
19
+ export { stampArticle50, verifyStamp } from "./eu_ai_act_stamp.js";
20
+ export { encodeWatermark, decodeWatermark } from "./watermark.js";
21
+ export { installPreCommitHook } from "./git_hook_installer.js";
22
+ export { recordFingerprint, readTimeline, computeVariance } from "./drift_timeline.js";
23
+ export { detectReplayAttack } from "./replay_attack.js";
24
+ // v2.47.0 — CALIBRATED CLASSIFIER + SELF-CALIBRATING LEARNING LOOP +
25
+ // production-grade HMAC key management.
26
+ export { buildSeedCorpus, computeStats, seedStats, } from "./calibration_corpus.js";
27
+ export { classifyAgentCalibrated, evaluateSeedAccuracy, } from "./classifier_calibrated.js";
28
+ export { appendCalibrationEntry, readCalibrationLedger, recomputeStats, calibrationStatus, } from "./learning_loop.js";
29
+ export { resolveHmacKey, generateProductionKey, } from "./key_management.js";
30
+ // v1.61 NEMESIS PROTOCOL (Tier 5 — weekly adversarial audit) lives in
31
+ // nemesis.ts alongside the new v2.46.0 ANTI-IDENTITY-LIE ENGINE. Both
32
+ // export through this barrel so downstream consumers (MCP `nemesis.generate`
33
+ // / `nemesis.grade` / `nemesis.trend` Tier 5 tools) continue to work
34
+ // unchanged. Two distinct primitives sharing one namespace by design.
35
+ export { generateProbes, gradeRun, recordRun, readRuns, trendFor, } from "./nemesis.js";
36
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/nemesis/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAQH,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,OAAO,EAAsB,MAAM,eAAe,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AACjF,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAAiD,MAAM,yBAAyB,CAAC;AAC9G,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,eAAe,EAAwC,MAAM,qBAAqB,CAAC;AAC7H,OAAO,EAAE,kBAAkB,EAAqB,MAAM,oBAAoB,CAAC;AAE3E,qEAAqE;AACrE,wCAAwC;AACxC,OAAO,EACL,eAAe,EAAE,YAAY,EAAE,SAAS,GAEzC,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,uBAAuB,EAAE,oBAAoB,GAE9C,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,sBAAsB,EAAE,qBAAqB,EAAE,cAAc,EAAE,iBAAiB,GAEjF,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,cAAc,EAAE,qBAAqB,GAEtC,MAAM,qBAAqB,CAAC;AAE7B,sEAAsE;AACtE,sEAAsE;AACtE,6EAA6E;AAC7E,qEAAqE;AACrE,sEAAsE;AACtE,OAAO,EACL,cAAc,EACd,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,QAAQ,GAKT,MAAM,cAAc,CAAC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * v2.47.0 — NEMESIS HMAC KEY MANAGEMENT.
3
+ *
4
+ * Production-grade key resolution + WARN-LOUD on default key usage so
5
+ * users in production never accidentally rely on the public default
6
+ * (which an attacker who reads our source can forge against).
7
+ *
8
+ * Resolution order:
9
+ * 1. process.env.MNEME_NEMESIS_KEY (highest priority; production)
10
+ * 2. file: ${repoRoot}/.mneme/nemesis/hmac.key (per-repo override)
11
+ * 3. file: ~/.mneme/nemesis/hmac.key (per-user override)
12
+ * 4. DEFAULT_KEY_INSECURE (last resort; WARN logged)
13
+ *
14
+ * The result is cached for the process lifetime to avoid repeated
15
+ * filesystem reads.
16
+ */
17
+ export type KeySource = "env" | "repo-file" | "user-file" | "default-insecure";
18
+ export interface KeyResolution {
19
+ key: string;
20
+ source: KeySource;
21
+ /** True when source is default-insecure (production should override). */
22
+ insecureWarning: boolean;
23
+ /** User-facing message describing what to do for production. */
24
+ message: string;
25
+ }
26
+ export declare function resolveHmacKey(repoRoot?: string): KeyResolution;
27
+ /** Generate a fresh 32-byte hex key suitable for production use. */
28
+ export declare function generateProductionKey(): string;
29
+ export declare function __resetKeyCacheForTest(): void;
30
+ //# sourceMappingURL=key_management.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"key_management.d.ts","sourceRoot":"","sources":["../../src/nemesis/key_management.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AASH,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG,WAAW,GAAG,WAAW,GAAG,kBAAkB,CAAC;AAE/E,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,SAAS,CAAC;IAClB,yEAAyE;IACzE,eAAe,EAAE,OAAO,CAAC;IACzB,gEAAgE;IAChE,OAAO,EAAE,MAAM,CAAC;CACjB;AAKD,wBAAgB,cAAc,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,aAAa,CA2D/D;AAED,oEAAoE;AACpE,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C;AAED,wBAAgB,sBAAsB,IAAI,IAAI,CAAqC"}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * v2.47.0 — NEMESIS HMAC KEY MANAGEMENT.
3
+ *
4
+ * Production-grade key resolution + WARN-LOUD on default key usage so
5
+ * users in production never accidentally rely on the public default
6
+ * (which an attacker who reads our source can forge against).
7
+ *
8
+ * Resolution order:
9
+ * 1. process.env.MNEME_NEMESIS_KEY (highest priority; production)
10
+ * 2. file: ${repoRoot}/.mneme/nemesis/hmac.key (per-repo override)
11
+ * 3. file: ~/.mneme/nemesis/hmac.key (per-user override)
12
+ * 4. DEFAULT_KEY_INSECURE (last resort; WARN logged)
13
+ *
14
+ * The result is cached for the process lifetime to avoid repeated
15
+ * filesystem reads.
16
+ */
17
+ import { existsSync, readFileSync } from "node:fs";
18
+ import { join } from "node:path";
19
+ import { homedir } from "node:os";
20
+ import { randomBytes } from "node:crypto";
21
+ const DEFAULT_KEY_INSECURE = "MNEME-NEMESIS-DEFAULT-KEY-v2.46-INSECURE";
22
+ let _cached = null;
23
+ let _warned = false;
24
+ export function resolveHmacKey(repoRoot) {
25
+ if (_cached)
26
+ return _cached;
27
+ // 1. env var
28
+ const envKey = process.env["MNEME_NEMESIS_KEY"];
29
+ if (typeof envKey === "string" && envKey.length >= 16) {
30
+ _cached = {
31
+ key: envKey, source: "env", insecureWarning: false,
32
+ message: "HMAC key loaded from MNEME_NEMESIS_KEY env var.",
33
+ };
34
+ return _cached;
35
+ }
36
+ // 2. repo file
37
+ if (repoRoot) {
38
+ const p = join(repoRoot, ".mneme", "nemesis", "hmac.key");
39
+ if (existsSync(p)) {
40
+ try {
41
+ const k = readFileSync(p, "utf8").trim();
42
+ if (k.length >= 16) {
43
+ _cached = {
44
+ key: k, source: "repo-file", insecureWarning: false,
45
+ message: `HMAC key loaded from ${p}`,
46
+ };
47
+ return _cached;
48
+ }
49
+ }
50
+ catch { /* fall through */ }
51
+ }
52
+ }
53
+ // 3. user file
54
+ const userPath = join(homedir(), ".mneme", "nemesis", "hmac.key");
55
+ if (existsSync(userPath)) {
56
+ try {
57
+ const k = readFileSync(userPath, "utf8").trim();
58
+ if (k.length >= 16) {
59
+ _cached = {
60
+ key: k, source: "user-file", insecureWarning: false,
61
+ message: `HMAC key loaded from ${userPath}`,
62
+ };
63
+ return _cached;
64
+ }
65
+ }
66
+ catch { /* fall through */ }
67
+ }
68
+ // 4. default (INSECURE)
69
+ if (!_warned) {
70
+ _warned = true;
71
+ // Warn on stderr so dev sees it; production CI catches it.
72
+ try {
73
+ process.stderr.write("⚠ NEMESIS HMAC key falling back to public default (INSECURE).\n" +
74
+ " For production: set MNEME_NEMESIS_KEY env var (≥16 chars random) OR\n" +
75
+ " write a key to .mneme/nemesis/hmac.key (≥16 chars random).\n" +
76
+ " Generate one: node -e \"console.log(require('crypto').randomBytes(32).toString('hex'))\"\n");
77
+ }
78
+ catch { /* */ }
79
+ }
80
+ _cached = {
81
+ key: DEFAULT_KEY_INSECURE, source: "default-insecure", insecureWarning: true,
82
+ message: "HMAC key fell back to INSECURE default. Set MNEME_NEMESIS_KEY or .mneme/nemesis/hmac.key for production.",
83
+ };
84
+ return _cached;
85
+ }
86
+ /** Generate a fresh 32-byte hex key suitable for production use. */
87
+ export function generateProductionKey() {
88
+ return randomBytes(32).toString("hex");
89
+ }
90
+ export function __resetKeyCacheForTest() { _cached = null; _warned = false; }
91
+ //# sourceMappingURL=key_management.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"key_management.js","sourceRoot":"","sources":["../../src/nemesis/key_management.ts"],"names":[],"mappings":"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"}