@mneme-ai/core 1.69.0 → 1.70.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/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -1
- package/dist/precog/bayesian_priors.d.ts +49 -0
- package/dist/precog/bayesian_priors.d.ts.map +1 -0
- package/dist/precog/bayesian_priors.js +135 -0
- package/dist/precog/bayesian_priors.js.map +1 -0
- package/dist/precog/firewall.d.ts +72 -0
- package/dist/precog/firewall.d.ts.map +1 -0
- package/dist/precog/firewall.js +141 -0
- package/dist/precog/firewall.js.map +1 -0
- package/dist/precog/index.d.ts +54 -0
- package/dist/precog/index.d.ts.map +1 -0
- package/dist/precog/index.js +94 -0
- package/dist/precog/index.js.map +1 -0
- package/dist/precog/package_verifier.d.ts +45 -0
- package/dist/precog/package_verifier.d.ts.map +1 -0
- package/dist/precog/package_verifier.js +139 -0
- package/dist/precog/package_verifier.js.map +1 -0
- package/dist/precog/precog.test.d.ts +5 -0
- package/dist/precog/precog.test.d.ts.map +1 -0
- package/dist/precog/precog.test.js +224 -0
- package/dist/precog/precog.test.js.map +1 -0
- package/dist/precog/sha_version_verifier.d.ts +34 -0
- package/dist/precog/sha_version_verifier.d.ts.map +1 -0
- package/dist/precog/sha_version_verifier.js +131 -0
- package/dist/precog/sha_version_verifier.js.map +1 -0
- package/dist/precog/temporal_verifier.d.ts +45 -0
- package/dist/precog/temporal_verifier.d.ts.map +1 -0
- package/dist/precog/temporal_verifier.js +139 -0
- package/dist/precog/temporal_verifier.js.map +1 -0
- package/dist/precog/trust_certificate.d.ts +44 -0
- package/dist/precog/trust_certificate.d.ts.map +1 -0
- package/dist/precog/trust_certificate.js +103 -0
- package/dist/precog/trust_certificate.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v1.70.0 -- PRECOG P2: SHA / VERSION / EMAIL VERIFIER.
|
|
3
|
+
*
|
|
4
|
+
* Common AI fabrications:
|
|
5
|
+
* - "in commit abc1234" (commit doesn't exist)
|
|
6
|
+
* - "we shipped v9.99.0 last quarter" (no such tag)
|
|
7
|
+
* - "Alice <alice@example.com> wrote this" (no such git author)
|
|
8
|
+
*
|
|
9
|
+
* Each fact verifier shells out to git/CHANGELOG/git-log respectively:
|
|
10
|
+
* - SHA -> git rev-list / git cat-file -e
|
|
11
|
+
* - Version -> git tags + CHANGELOG.md
|
|
12
|
+
* - Email -> distinct authors from git log --format=%ae
|
|
13
|
+
*
|
|
14
|
+
* Pure read; no side effects.
|
|
15
|
+
*/
|
|
16
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
17
|
+
import { join } from "node:path";
|
|
18
|
+
import { execSync } from "node:child_process";
|
|
19
|
+
const SHA_RE = /\b([0-9a-f]{7,40})\b/gi;
|
|
20
|
+
const VERSION_RE = /\bv?(\d+\.\d+\.\d+(?:-[\w.-]+)?)\b/g;
|
|
21
|
+
const EMAIL_RE = /\b([\w.+-]+)@([\w-]+(?:\.[\w-]+)+)\b/g;
|
|
22
|
+
function gitCheckSha(repoRoot, sha) {
|
|
23
|
+
try {
|
|
24
|
+
execSync(`git -C "${repoRoot}" cat-file -e ${sha}`, { stdio: "ignore", timeout: 2000 });
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function gitListTags(repoRoot) {
|
|
32
|
+
try {
|
|
33
|
+
const r = execSync(`git -C "${repoRoot}" tag --list`, { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], timeout: 2000 });
|
|
34
|
+
return new Set(r.split("\n").map((t) => t.trim()).filter(Boolean));
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return new Set();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function gitListAuthorEmails(repoRoot) {
|
|
41
|
+
try {
|
|
42
|
+
const r = execSync(`git -C "${repoRoot}" log --format=%ae --max-count=2000`, { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], timeout: 3000 });
|
|
43
|
+
const out = new Set();
|
|
44
|
+
for (const line of r.split("\n")) {
|
|
45
|
+
const v = line.trim().toLowerCase();
|
|
46
|
+
if (v)
|
|
47
|
+
out.add(v);
|
|
48
|
+
}
|
|
49
|
+
return out;
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return new Set();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function changelogVersions(repoRoot) {
|
|
56
|
+
const p = join(repoRoot, "CHANGELOG.md");
|
|
57
|
+
if (!existsSync(p))
|
|
58
|
+
return new Set();
|
|
59
|
+
const out = new Set();
|
|
60
|
+
try {
|
|
61
|
+
const content = readFileSync(p, "utf8");
|
|
62
|
+
// Match `## [1.2.3]` / `# v1.2.3` lines.
|
|
63
|
+
for (const m of content.matchAll(/^\s*#+\s*\[?v?(\d+\.\d+\.\d+(?:-[\w.-]+)?)\]?/gm)) {
|
|
64
|
+
out.add(m[1]);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
catch { /* */ }
|
|
68
|
+
return out;
|
|
69
|
+
}
|
|
70
|
+
export function extractFactRefs(text) {
|
|
71
|
+
const out = [];
|
|
72
|
+
const seen = new Set();
|
|
73
|
+
const push = (ref) => {
|
|
74
|
+
const key = `${ref.kind}|${ref.value}`;
|
|
75
|
+
if (seen.has(key))
|
|
76
|
+
return;
|
|
77
|
+
seen.add(key);
|
|
78
|
+
out.push(ref);
|
|
79
|
+
};
|
|
80
|
+
for (const m of text.matchAll(SHA_RE)) {
|
|
81
|
+
const v = m[1];
|
|
82
|
+
if (v.length < 7)
|
|
83
|
+
continue;
|
|
84
|
+
if (!/[a-f]/.test(v))
|
|
85
|
+
continue; // pure-digit -> probably a number, not SHA
|
|
86
|
+
push({ kind: "sha", value: v.toLowerCase(), offset: m.index ?? 0 });
|
|
87
|
+
}
|
|
88
|
+
for (const m of text.matchAll(VERSION_RE)) {
|
|
89
|
+
// Use the FULL match (incl. optional "v") as the surface so hedging
|
|
90
|
+
// spans correctly; the verifier strips "v" for lookup.
|
|
91
|
+
push({ kind: "version", value: m[0], offset: m.index ?? 0 });
|
|
92
|
+
}
|
|
93
|
+
for (const m of text.matchAll(EMAIL_RE)) {
|
|
94
|
+
push({ kind: "email", value: m[0].toLowerCase(), offset: m.index ?? 0 });
|
|
95
|
+
}
|
|
96
|
+
return out;
|
|
97
|
+
}
|
|
98
|
+
export function verifyFacts(repoRoot, text) {
|
|
99
|
+
const refs = extractFactRefs(text);
|
|
100
|
+
const tags = gitListTags(repoRoot);
|
|
101
|
+
const changelog = changelogVersions(repoRoot);
|
|
102
|
+
const authors = gitListAuthorEmails(repoRoot);
|
|
103
|
+
const confirmed = [];
|
|
104
|
+
const suspects = [];
|
|
105
|
+
for (const ref of refs) {
|
|
106
|
+
if (ref.kind === "sha") {
|
|
107
|
+
if (gitCheckSha(repoRoot, ref.value))
|
|
108
|
+
confirmed.push(ref);
|
|
109
|
+
else
|
|
110
|
+
suspects.push({ ref, reason: `SHA ${ref.value} not found in git object database.`, confidence: 0.95 });
|
|
111
|
+
}
|
|
112
|
+
else if (ref.kind === "version") {
|
|
113
|
+
const numeric = ref.value.replace(/^v/i, "");
|
|
114
|
+
const inTags = tags.has(numeric) || tags.has(`v${numeric}`);
|
|
115
|
+
const inChangelog = changelog.has(numeric);
|
|
116
|
+
if (inTags || inChangelog)
|
|
117
|
+
confirmed.push(ref);
|
|
118
|
+
else
|
|
119
|
+
suspects.push({ ref, reason: `Version ${ref.value} not in git tags or CHANGELOG.md.`, confidence: 0.85 });
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
if (authors.has(ref.value))
|
|
123
|
+
confirmed.push(ref);
|
|
124
|
+
else
|
|
125
|
+
suspects.push({ ref, reason: `Author email ${ref.value} not in git log authors.`, confidence: 0.8 });
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
const headline = `${refs.length} fact ref(s); ${confirmed.length} confirmed, ${suspects.length} suspect.`;
|
|
129
|
+
return { refs, confirmed, suspects, headline };
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=sha_version_verifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sha_version_verifier.js","sourceRoot":"","sources":["../../src/precog/sha_version_verifier.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v1.70.0 -- PRECOG P3: TEMPORAL VERIFIER.
|
|
3
|
+
*
|
|
4
|
+
* Catches "we deleted X last week" / "yesterday Y was added" / "3
|
|
5
|
+
* days ago we shipped Z" -- temporal claims that need to be
|
|
6
|
+
* corroborated by `git log` within the bounded window.
|
|
7
|
+
*
|
|
8
|
+
* "last week" -> window [now-14d, now-1d]
|
|
9
|
+
* "yesterday" -> window [now-2d, now-1d]
|
|
10
|
+
* "today" -> window [now-1d, now]
|
|
11
|
+
* "3 days ago" -> window [now-4d, now-2d]
|
|
12
|
+
* "last month" -> window [now-45d, now-15d]
|
|
13
|
+
* "X days ago" -> window [now-X-1d, now-X+1d]
|
|
14
|
+
*
|
|
15
|
+
* Verifier checks:
|
|
16
|
+
* 1. Were there ANY commits in the window? (sanity)
|
|
17
|
+
* 2. If claim mentions a verb (add/delete/fix/ship), is there a
|
|
18
|
+
* commit with that verb root in subject within the window?
|
|
19
|
+
* 3. If claim names a file, does git log -- <file> show commits in window?
|
|
20
|
+
*
|
|
21
|
+
* Honest "INSUFFICIENT_EVIDENCE" verdict when window is empty.
|
|
22
|
+
*/
|
|
23
|
+
export interface TemporalReference {
|
|
24
|
+
/** The phrase that triggered the match. */
|
|
25
|
+
phrase: string;
|
|
26
|
+
/** Window start (ms since epoch). */
|
|
27
|
+
fromMs: number;
|
|
28
|
+
/** Window end (ms since epoch). */
|
|
29
|
+
toMs: number;
|
|
30
|
+
offset: number;
|
|
31
|
+
}
|
|
32
|
+
export interface TemporalSuspect {
|
|
33
|
+
ref: TemporalReference;
|
|
34
|
+
reason: string;
|
|
35
|
+
confidence: number;
|
|
36
|
+
}
|
|
37
|
+
export interface TemporalReport {
|
|
38
|
+
refs: TemporalReference[];
|
|
39
|
+
suspects: TemporalSuspect[];
|
|
40
|
+
corroborated: TemporalReference[];
|
|
41
|
+
headline: string;
|
|
42
|
+
}
|
|
43
|
+
export declare function extractTemporalRefs(text: string): TemporalReference[];
|
|
44
|
+
export declare function verifyTemporal(repoRoot: string, text: string): TemporalReport;
|
|
45
|
+
//# sourceMappingURL=temporal_verifier.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"temporal_verifier.d.ts","sourceRoot":"","sources":["../../src/precog/temporal_verifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAIH,MAAM,WAAW,iBAAiB;IAChC,2CAA2C;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,qCAAqC;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,mCAAmC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,iBAAiB,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,iBAAiB,EAAE,CAAC;IAC1B,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,YAAY,EAAE,iBAAiB,EAAE,CAAC;IAClC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAkBD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,EAAE,CA6BrE;AAmCD,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,cAAc,CA0C7E"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v1.70.0 -- PRECOG P3: TEMPORAL VERIFIER.
|
|
3
|
+
*
|
|
4
|
+
* Catches "we deleted X last week" / "yesterday Y was added" / "3
|
|
5
|
+
* days ago we shipped Z" -- temporal claims that need to be
|
|
6
|
+
* corroborated by `git log` within the bounded window.
|
|
7
|
+
*
|
|
8
|
+
* "last week" -> window [now-14d, now-1d]
|
|
9
|
+
* "yesterday" -> window [now-2d, now-1d]
|
|
10
|
+
* "today" -> window [now-1d, now]
|
|
11
|
+
* "3 days ago" -> window [now-4d, now-2d]
|
|
12
|
+
* "last month" -> window [now-45d, now-15d]
|
|
13
|
+
* "X days ago" -> window [now-X-1d, now-X+1d]
|
|
14
|
+
*
|
|
15
|
+
* Verifier checks:
|
|
16
|
+
* 1. Were there ANY commits in the window? (sanity)
|
|
17
|
+
* 2. If claim mentions a verb (add/delete/fix/ship), is there a
|
|
18
|
+
* commit with that verb root in subject within the window?
|
|
19
|
+
* 3. If claim names a file, does git log -- <file> show commits in window?
|
|
20
|
+
*
|
|
21
|
+
* Honest "INSUFFICIENT_EVIDENCE" verdict when window is empty.
|
|
22
|
+
*/
|
|
23
|
+
import { execSync } from "node:child_process";
|
|
24
|
+
const PHRASE_RES = [
|
|
25
|
+
{ pattern: /\b(today)\b/gi, days: { from: 1, to: 0 } },
|
|
26
|
+
{ pattern: /\b(yesterday)\b/gi, days: { from: 2, to: 1 } },
|
|
27
|
+
{ pattern: /\b(last\s+week)\b/gi, days: { from: 14, to: 1 } },
|
|
28
|
+
{ pattern: /\b(last\s+month)\b/gi, days: { from: 45, to: 15 } },
|
|
29
|
+
{ pattern: /\b(last\s+quarter)\b/gi, days: { from: 120, to: 45 } },
|
|
30
|
+
{ pattern: /\b(this\s+week)\b/gi, days: { from: 7, to: 0 } },
|
|
31
|
+
];
|
|
32
|
+
const N_DAYS_AGO = /\b(\d+)\s+days?\s+ago\b/gi;
|
|
33
|
+
const VERB_PATTERN = /\b(added?|deleted?|removed?|shipped?|fixed?|merged?|reverted?|deployed?|released?|refactored?)\b/gi;
|
|
34
|
+
const FILE_PATTERN = /([\w./_-]+\.(?:ts|tsx|js|mjs|cjs|jsx|json|md|sql|yml|yaml|py|rs|go))/g;
|
|
35
|
+
const DAY_MS = 86400 * 1000;
|
|
36
|
+
export function extractTemporalRefs(text) {
|
|
37
|
+
const out = [];
|
|
38
|
+
const seen = new Set();
|
|
39
|
+
const now = Date.now();
|
|
40
|
+
for (const { pattern, days } of PHRASE_RES) {
|
|
41
|
+
for (const m of text.matchAll(pattern)) {
|
|
42
|
+
const phrase = m[1].toLowerCase();
|
|
43
|
+
const key = `${phrase}|${m.index}`;
|
|
44
|
+
if (seen.has(key))
|
|
45
|
+
continue;
|
|
46
|
+
seen.add(key);
|
|
47
|
+
out.push({
|
|
48
|
+
phrase,
|
|
49
|
+
fromMs: now - days.from * DAY_MS,
|
|
50
|
+
toMs: now - days.to * DAY_MS,
|
|
51
|
+
offset: m.index ?? 0,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
for (const m of text.matchAll(N_DAYS_AGO)) {
|
|
56
|
+
const n = Number(m[1]);
|
|
57
|
+
if (!Number.isFinite(n) || n < 0)
|
|
58
|
+
continue;
|
|
59
|
+
out.push({
|
|
60
|
+
phrase: m[0].toLowerCase(),
|
|
61
|
+
fromMs: now - (n + 1) * DAY_MS,
|
|
62
|
+
toMs: now - Math.max(0, n - 1) * DAY_MS,
|
|
63
|
+
offset: m.index ?? 0,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
return out;
|
|
67
|
+
}
|
|
68
|
+
function queryGitWindow(repoRoot, ref, verbs, files) {
|
|
69
|
+
const since = new Date(ref.fromMs).toISOString();
|
|
70
|
+
const until = new Date(ref.toMs).toISOString();
|
|
71
|
+
let totalCommits = 0;
|
|
72
|
+
let subjects = "";
|
|
73
|
+
try {
|
|
74
|
+
const r = execSync(`git -C "${repoRoot}" log --since="${since}" --until="${until}" --pretty=format:%s`, { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], timeout: 3000 });
|
|
75
|
+
subjects = r;
|
|
76
|
+
totalCommits = r.split("\n").filter(Boolean).length;
|
|
77
|
+
}
|
|
78
|
+
catch { /* */ }
|
|
79
|
+
let verbMatches = 0;
|
|
80
|
+
for (const v of verbs) {
|
|
81
|
+
const re = new RegExp(`\\b${v.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\b`, "i");
|
|
82
|
+
if (re.test(subjects))
|
|
83
|
+
verbMatches += 1;
|
|
84
|
+
}
|
|
85
|
+
let fileTouches = 0;
|
|
86
|
+
for (const f of files.slice(0, 3)) {
|
|
87
|
+
try {
|
|
88
|
+
const r = execSync(`git -C "${repoRoot}" log --since="${since}" --until="${until}" --format=%H -- "${f}"`, { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], timeout: 3000 });
|
|
89
|
+
if (r.trim().split("\n").filter(Boolean).length > 0)
|
|
90
|
+
fileTouches += 1;
|
|
91
|
+
}
|
|
92
|
+
catch { /* */ }
|
|
93
|
+
}
|
|
94
|
+
return { totalCommits, verbMatches, fileTouches };
|
|
95
|
+
}
|
|
96
|
+
export function verifyTemporal(repoRoot, text) {
|
|
97
|
+
const refs = extractTemporalRefs(text);
|
|
98
|
+
if (refs.length === 0) {
|
|
99
|
+
return { refs, suspects: [], corroborated: [], headline: "No temporal claims in text." };
|
|
100
|
+
}
|
|
101
|
+
// Extract verbs + files ONCE for the whole text -- conservative: any temporal
|
|
102
|
+
// ref in the text takes context from all verbs/files in the same text.
|
|
103
|
+
const verbs = [...new Set([...text.matchAll(VERB_PATTERN)].map((m) => m[1].toLowerCase()))];
|
|
104
|
+
const files = [...new Set([...text.matchAll(FILE_PATTERN)].map((m) => m[1]))];
|
|
105
|
+
const suspects = [];
|
|
106
|
+
const corroborated = [];
|
|
107
|
+
for (const ref of refs) {
|
|
108
|
+
const result = queryGitWindow(repoRoot, ref, verbs, files);
|
|
109
|
+
if (result.totalCommits === 0) {
|
|
110
|
+
suspects.push({
|
|
111
|
+
ref,
|
|
112
|
+
reason: `No git commits in window [${new Date(ref.fromMs).toISOString().slice(0, 10)} .. ${new Date(ref.toMs).toISOString().slice(0, 10)}] for "${ref.phrase}".`,
|
|
113
|
+
confidence: 0.85,
|
|
114
|
+
});
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
// If claim names verbs or files, require corroboration.
|
|
118
|
+
if (verbs.length > 0 && result.verbMatches === 0 && files.length === 0) {
|
|
119
|
+
suspects.push({
|
|
120
|
+
ref,
|
|
121
|
+
reason: `${result.totalCommits} commit(s) in window but none match the claimed verbs (${verbs.slice(0, 3).join(", ")}).`,
|
|
122
|
+
confidence: 0.7,
|
|
123
|
+
});
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
if (files.length > 0 && result.fileTouches === 0) {
|
|
127
|
+
suspects.push({
|
|
128
|
+
ref,
|
|
129
|
+
reason: `${result.totalCommits} commit(s) in window but none touched the named file(s).`,
|
|
130
|
+
confidence: 0.8,
|
|
131
|
+
});
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
corroborated.push(ref);
|
|
135
|
+
}
|
|
136
|
+
const headline = `${refs.length} temporal claim(s); ${corroborated.length} corroborated, ${suspects.length} suspect.`;
|
|
137
|
+
return { refs, suspects, corroborated, headline };
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=temporal_verifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"temporal_verifier.js","sourceRoot":"","sources":["../../src/precog/temporal_verifier.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v1.70.0 -- PRECOG P5: TRUST CERTIFICATE.
|
|
3
|
+
*
|
|
4
|
+
* After a claim passes verification, mint an HMAC-signed certificate.
|
|
5
|
+
* Downstream consumers (apps, the user's UI, mesh peers) can verify
|
|
6
|
+
* the certificate without re-running every checker.
|
|
7
|
+
*
|
|
8
|
+
* issueCertificate(claim, verifierResults) -> { cert, signers, ts }
|
|
9
|
+
* verifyCertificate(cert) -> boolean
|
|
10
|
+
*
|
|
11
|
+
* The "SSL for AI claims" the user described.
|
|
12
|
+
*/
|
|
13
|
+
export interface VerifierResult {
|
|
14
|
+
name: string;
|
|
15
|
+
passed: boolean;
|
|
16
|
+
detail?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface TrustCertificate {
|
|
19
|
+
/** Stable id = sha256(claim || payload). */
|
|
20
|
+
id: string;
|
|
21
|
+
/** Original claim (truncated to 500 chars). */
|
|
22
|
+
claim: string;
|
|
23
|
+
/** Verifier names that passed. */
|
|
24
|
+
signers: string[];
|
|
25
|
+
/** Verifier names that flagged. */
|
|
26
|
+
flaggedBy: string[];
|
|
27
|
+
/** Verdict band. */
|
|
28
|
+
verdict: "CERTIFIED" | "CONDITIONAL" | "REVOKED";
|
|
29
|
+
/** ISO ts. */
|
|
30
|
+
issuedAt: string;
|
|
31
|
+
/** Expiry (ISO). */
|
|
32
|
+
expiresAt: string;
|
|
33
|
+
/** HMAC over canonical payload. */
|
|
34
|
+
hmac: string;
|
|
35
|
+
}
|
|
36
|
+
export interface IssueOptions {
|
|
37
|
+
/** Window during which the cert is valid (ms). Default 24h. */
|
|
38
|
+
ttlMs?: number;
|
|
39
|
+
}
|
|
40
|
+
export declare function issueCertificate(repoRoot: string, claim: string, verifierResults: VerifierResult[], opts?: IssueOptions): TrustCertificate;
|
|
41
|
+
export type VerifyVerdict = "VALID" | "INVALID_HMAC" | "EXPIRED" | "NOT_CERTIFIED";
|
|
42
|
+
export declare function verifyCertificate(repoRoot: string, cert: TrustCertificate): VerifyVerdict;
|
|
43
|
+
export declare function readCertLedger(repoRoot: string): TrustCertificate[];
|
|
44
|
+
//# sourceMappingURL=trust_certificate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trust_certificate.d.ts","sourceRoot":"","sources":["../../src/precog/trust_certificate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAUH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,4CAA4C;IAC5C,EAAE,EAAE,MAAM,CAAC;IACX,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,kCAAkC;IAClC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,mCAAmC;IACnC,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,oBAAoB;IACpB,OAAO,EAAE,WAAW,GAAG,aAAa,GAAG,SAAS,CAAC;IACjD,cAAc;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,oBAAoB;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,mCAAmC;IACnC,IAAI,EAAE,MAAM,CAAC;CACd;AAuBD,MAAM,WAAW,YAAY;IAC3B,+DAA+D;IAC/D,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,eAAe,EAAE,cAAc,EAAE,EACjC,IAAI,CAAC,EAAE,YAAY,GAClB,gBAAgB,CA2BlB;AAED,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,cAAc,GAAG,SAAS,GAAG,eAAe,CAAC;AAEnF,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,GAAG,aAAa,CAQzF;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,EAAE,CAWnE"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v1.70.0 -- PRECOG P5: TRUST CERTIFICATE.
|
|
3
|
+
*
|
|
4
|
+
* After a claim passes verification, mint an HMAC-signed certificate.
|
|
5
|
+
* Downstream consumers (apps, the user's UI, mesh peers) can verify
|
|
6
|
+
* the certificate without re-running every checker.
|
|
7
|
+
*
|
|
8
|
+
* issueCertificate(claim, verifierResults) -> { cert, signers, ts }
|
|
9
|
+
* verifyCertificate(cert) -> boolean
|
|
10
|
+
*
|
|
11
|
+
* The "SSL for AI claims" the user described.
|
|
12
|
+
*/
|
|
13
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync, appendFileSync } from "node:fs";
|
|
14
|
+
import { createHash, createHmac, randomBytes } from "node:crypto";
|
|
15
|
+
import { join } from "node:path";
|
|
16
|
+
const PRECOG_DIR = ".mneme/precog";
|
|
17
|
+
const CERT_LEDGER = ".mneme/precog/certificates.jsonl";
|
|
18
|
+
const SECRET_FILE = ".mneme/precog/cert-secret";
|
|
19
|
+
function ensureSecret(repoRoot) {
|
|
20
|
+
const path = join(repoRoot, SECRET_FILE);
|
|
21
|
+
if (existsSync(path))
|
|
22
|
+
return readFileSync(path, "utf8").trim();
|
|
23
|
+
const dir = join(repoRoot, PRECOG_DIR);
|
|
24
|
+
if (!existsSync(dir))
|
|
25
|
+
mkdirSync(dir, { recursive: true });
|
|
26
|
+
const s = randomBytes(32).toString("hex");
|
|
27
|
+
try {
|
|
28
|
+
writeFileSync(path, s, "utf8");
|
|
29
|
+
}
|
|
30
|
+
catch { /* */ }
|
|
31
|
+
return s;
|
|
32
|
+
}
|
|
33
|
+
function canonical(payload) {
|
|
34
|
+
return JSON.stringify({
|
|
35
|
+
claim: payload.claim,
|
|
36
|
+
signers: [...payload.signers].sort(),
|
|
37
|
+
flaggedBy: [...payload.flaggedBy].sort(),
|
|
38
|
+
verdict: payload.verdict,
|
|
39
|
+
issuedAt: payload.issuedAt,
|
|
40
|
+
expiresAt: payload.expiresAt,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
export function issueCertificate(repoRoot, claim, verifierResults, opts) {
|
|
44
|
+
const secret = ensureSecret(repoRoot);
|
|
45
|
+
const issuedAt = new Date().toISOString();
|
|
46
|
+
const ttlMs = opts?.ttlMs ?? 24 * 3600 * 1000;
|
|
47
|
+
const expiresAt = new Date(Date.now() + ttlMs).toISOString();
|
|
48
|
+
const signers = verifierResults.filter((v) => v.passed).map((v) => v.name);
|
|
49
|
+
const flaggedBy = verifierResults.filter((v) => !v.passed).map((v) => v.name);
|
|
50
|
+
const verdict = flaggedBy.length === 0
|
|
51
|
+
? "CERTIFIED"
|
|
52
|
+
: signers.length > flaggedBy.length
|
|
53
|
+
? "CONDITIONAL"
|
|
54
|
+
: "REVOKED";
|
|
55
|
+
const payload = {
|
|
56
|
+
claim: claim.slice(0, 500),
|
|
57
|
+
signers, flaggedBy, verdict, issuedAt, expiresAt,
|
|
58
|
+
};
|
|
59
|
+
const canon = canonical(payload);
|
|
60
|
+
const hmac = createHmac("sha256", secret).update(canon).digest("hex");
|
|
61
|
+
const id = createHash("sha256").update(canon).digest("hex").slice(0, 16);
|
|
62
|
+
const cert = { ...payload, id, hmac };
|
|
63
|
+
// Persist to ledger.
|
|
64
|
+
try {
|
|
65
|
+
const dir = join(repoRoot, PRECOG_DIR);
|
|
66
|
+
if (!existsSync(dir))
|
|
67
|
+
mkdirSync(dir, { recursive: true });
|
|
68
|
+
appendFileSync(join(repoRoot, CERT_LEDGER), JSON.stringify(cert) + "\n", "utf8");
|
|
69
|
+
}
|
|
70
|
+
catch { /* */ }
|
|
71
|
+
return cert;
|
|
72
|
+
}
|
|
73
|
+
export function verifyCertificate(repoRoot, cert) {
|
|
74
|
+
if (Date.parse(cert.expiresAt) < Date.now())
|
|
75
|
+
return "EXPIRED";
|
|
76
|
+
const secret = ensureSecret(repoRoot);
|
|
77
|
+
const canon = canonical(cert);
|
|
78
|
+
const expected = createHmac("sha256", secret).update(canon).digest("hex");
|
|
79
|
+
if (expected !== cert.hmac)
|
|
80
|
+
return "INVALID_HMAC";
|
|
81
|
+
if (cert.verdict === "REVOKED")
|
|
82
|
+
return "NOT_CERTIFIED";
|
|
83
|
+
return "VALID";
|
|
84
|
+
}
|
|
85
|
+
export function readCertLedger(repoRoot) {
|
|
86
|
+
const p = join(repoRoot, CERT_LEDGER);
|
|
87
|
+
if (!existsSync(p))
|
|
88
|
+
return [];
|
|
89
|
+
const out = [];
|
|
90
|
+
try {
|
|
91
|
+
for (const line of readFileSync(p, "utf8").split("\n")) {
|
|
92
|
+
if (!line.trim())
|
|
93
|
+
continue;
|
|
94
|
+
try {
|
|
95
|
+
out.push(JSON.parse(line));
|
|
96
|
+
}
|
|
97
|
+
catch { /* */ }
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
catch { /* */ }
|
|
101
|
+
return out;
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=trust_certificate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trust_certificate.js","sourceRoot":"","sources":["../../src/precog/trust_certificate.ts"],"names":[],"mappings":"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"}
|