@mneme-ai/core 1.97.0 → 1.99.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/flash/devils_advocate.d.ts +66 -0
- package/dist/flash/devils_advocate.d.ts.map +1 -0
- package/dist/flash/devils_advocate.js +154 -0
- package/dist/flash/devils_advocate.js.map +1 -0
- package/dist/flash/flash.d.ts +50 -0
- package/dist/flash/flash.d.ts.map +1 -0
- package/dist/flash/flash.js +67 -0
- package/dist/flash/flash.js.map +1 -0
- package/dist/flash/flash.test.d.ts +2 -0
- package/dist/flash/flash.test.d.ts.map +1 -0
- package/dist/flash/flash.test.js +221 -0
- package/dist/flash/flash.test.js.map +1 -0
- package/dist/flash/grounding.d.ts +55 -0
- package/dist/flash/grounding.d.ts.map +1 -0
- package/dist/flash/grounding.js +144 -0
- package/dist/flash/grounding.js.map +1 -0
- package/dist/flash/index.d.ts +18 -0
- package/dist/flash/index.d.ts.map +1 -0
- package/dist/flash/index.js +18 -0
- package/dist/flash/index.js.map +1 -0
- package/dist/flash/predictive.d.ts +44 -0
- package/dist/flash/predictive.d.ts.map +1 -0
- package/dist/flash/predictive.js +76 -0
- package/dist/flash/predictive.js.map +1 -0
- package/dist/flash/veracity.d.ts +99 -0
- package/dist/flash/veracity.d.ts.map +1 -0
- package/dist/flash/veracity.js +107 -0
- package/dist/flash/veracity.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/permeate/userscript_generator.d.ts.map +1 -1
- package/dist/permeate/userscript_generator.js +1 -0
- package/dist/permeate/userscript_generator.js.map +1 -1
- package/dist/rainbow/index.d.ts +3 -0
- package/dist/rainbow/index.d.ts.map +1 -1
- package/dist/rainbow/index.js +11 -0
- package/dist/rainbow/index.js.map +1 -1
- package/dist/rainbow/passport.d.ts +130 -0
- package/dist/rainbow/passport.d.ts.map +1 -0
- package/dist/rainbow/passport.js +180 -0
- package/dist/rainbow/passport.js.map +1 -0
- package/dist/rainbow/passport_v99.test.d.ts +2 -0
- package/dist/rainbow/passport_v99.test.d.ts.map +1 -0
- package/dist/rainbow/passport_v99.test.js +53 -0
- package/dist/rainbow/passport_v99.test.js.map +1 -0
- package/dist/rainbow/v1_98.test.d.ts +2 -0
- package/dist/rainbow/v1_98.test.d.ts.map +1 -0
- package/dist/rainbow/v1_98.test.js +307 -0
- package/dist/rainbow/v1_98.test.js.map +1 -0
- package/dist/rainbow/vendor_probe.d.ts +52 -0
- package/dist/rainbow/vendor_probe.d.ts.map +1 -0
- package/dist/rainbow/vendor_probe.js +111 -0
- package/dist/rainbow/vendor_probe.js.map +1 -0
- package/dist/rainbow/vendor_strategy.d.ts +64 -0
- package/dist/rainbow/vendor_strategy.d.ts.map +1 -0
- package/dist/rainbow/vendor_strategy.js +157 -0
- package/dist/rainbow/vendor_strategy.js.map +1 -0
- package/dist/relay/deep_link.d.ts +24 -15
- package/dist/relay/deep_link.d.ts.map +1 -1
- package/dist/relay/deep_link.js +28 -18
- package/dist/relay/deep_link.js.map +1 -1
- package/dist/v1_87_regression.test.js +3 -2
- package/dist/v1_87_regression.test.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
// vendor_strategy
|
|
4
|
+
VENDOR_REGISTRY, entryOf, pickStrategy, formatStrategyPulseLine,
|
|
5
|
+
// vendor_probe
|
|
6
|
+
probeAllVendors, failingProbes, formatProbePulseLine,
|
|
7
|
+
// passport
|
|
8
|
+
issuePassport, verifyPassport, serializePassport, parsePassport, generatePassportSecret, fingerprintEntries, estimatePassportTokens, formatPassportPulseLine, } from "./index.js";
|
|
9
|
+
import { composeCleanPrompt, buildDeepLink } from "../relay/deep_link.js";
|
|
10
|
+
// ============================ STALE-URL FIX ============================
|
|
11
|
+
describe("v1.98 · stale-URL fix (chat.openai.com → chatgpt.com)", () => {
|
|
12
|
+
it("buildDeepLink('chatgpt') uses chatgpt.com (NOT chat.openai.com)", () => {
|
|
13
|
+
const dl = buildDeepLink({ pasteUrl: "https://x", nexusCode: "ABC", vendor: "chatgpt" });
|
|
14
|
+
expect(dl.url).toMatch(/^https:\/\/chatgpt\.com\/\?q=/);
|
|
15
|
+
expect(dl.url).not.toContain("chat.openai.com");
|
|
16
|
+
});
|
|
17
|
+
it("composeCleanPrompt replaces fetch+decrypt instruction (v1.98 clean form)", () => {
|
|
18
|
+
const p = composeCleanPrompt();
|
|
19
|
+
expect(p).toContain("Mneme soul prompt");
|
|
20
|
+
// The clean prompt MUST NOT instruct AI to fetch/decrypt
|
|
21
|
+
expect(p.toLowerCase()).not.toContain("fetch");
|
|
22
|
+
expect(p.toLowerCase()).not.toContain("decrypt");
|
|
23
|
+
expect(p.toLowerCase()).not.toContain("aes");
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
// ============================ VENDOR STRATEGY ============================
|
|
27
|
+
describe("v1.98 · vendor strategy map", () => {
|
|
28
|
+
it("registry has 10+ vendor entries", () => {
|
|
29
|
+
expect(VENDOR_REGISTRY.length).toBeGreaterThanOrEqual(10);
|
|
30
|
+
});
|
|
31
|
+
it("ChatGPT-web: free=clipboard-first, qParamWorks=false (verified)", () => {
|
|
32
|
+
const e = entryOf("chatgpt-web");
|
|
33
|
+
expect(e.freeStrategy).toBe("clipboard-first");
|
|
34
|
+
expect(e.qParamWorks).toBe(false);
|
|
35
|
+
expect(e.webFetchAvailable).toBe(false);
|
|
36
|
+
expect(e.homeUrl).toBe("https://chatgpt.com/");
|
|
37
|
+
});
|
|
38
|
+
it("Gemini-web: clipboard-first on both tiers (q= prefill verified unreliable)", () => {
|
|
39
|
+
const e = entryOf("gemini-web");
|
|
40
|
+
expect(e.freeStrategy).toBe("clipboard-first");
|
|
41
|
+
expect(e.paidStrategy).toBe("clipboard-first");
|
|
42
|
+
expect(e.qParamWorks).toBe(false);
|
|
43
|
+
});
|
|
44
|
+
it("Claude Code / Cursor: mcp-direct strategy", () => {
|
|
45
|
+
expect(entryOf("claude-code")?.freeStrategy).toBe("mcp-direct");
|
|
46
|
+
expect(entryOf("cursor")?.freeStrategy).toBe("mcp-direct");
|
|
47
|
+
});
|
|
48
|
+
it("Perplexity: clipboard-first by default, prefill-and-paste opt-in via paidStrategy", () => {
|
|
49
|
+
const e = entryOf("perplexity-web");
|
|
50
|
+
expect(e.freeStrategy).toBe("clipboard-first");
|
|
51
|
+
expect(e.qParamWorks).toBe(true); // Perplexity does honor ?q=
|
|
52
|
+
});
|
|
53
|
+
it("mobile-app vendors: app-deeplink-NA (no URL scheme exists)", () => {
|
|
54
|
+
expect(entryOf("gemini-mobile")?.freeStrategy).toBe("app-deeplink-NA");
|
|
55
|
+
expect(entryOf("chatgpt-mobile")?.freeStrategy).toBe("app-deeplink-NA");
|
|
56
|
+
});
|
|
57
|
+
it("any-mobile-browser: plain-qr (no encryption, no fetch instruction)", () => {
|
|
58
|
+
expect(entryOf("any-mobile-browser")?.freeStrategy).toBe("plain-qr");
|
|
59
|
+
});
|
|
60
|
+
it("pickStrategy returns the strategy + reason", () => {
|
|
61
|
+
const r = pickStrategy("chatgpt-web", { paidTier: false });
|
|
62
|
+
expect(r.strategy).toBe("clipboard-first");
|
|
63
|
+
expect(r.reason).toContain("chatgpt-web");
|
|
64
|
+
});
|
|
65
|
+
it("pickStrategy on unknown vendor → defaults to clipboard-first", () => {
|
|
66
|
+
const r = pickStrategy("xyz-unknown");
|
|
67
|
+
expect(r.strategy).toBe("clipboard-first");
|
|
68
|
+
expect(r.entry).toBeNull();
|
|
69
|
+
});
|
|
70
|
+
it("every entry has lastChecked date in ISO format", () => {
|
|
71
|
+
for (const e of VENDOR_REGISTRY) {
|
|
72
|
+
expect(e.lastChecked).toMatch(/^\d{4}-\d{2}-\d{2}$/);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
it("formatStrategyPulseLine produces compact summary", () => {
|
|
76
|
+
const line = formatStrategyPulseLine("chatgpt-web");
|
|
77
|
+
expect(line).toContain("VENDOR-STRATEGY");
|
|
78
|
+
expect(line).toContain("clipboard-first");
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
// ============================ VENDOR PROBE ============================
|
|
82
|
+
describe("v1.98 · vendor URL probe", () => {
|
|
83
|
+
function mockFetch(responses) {
|
|
84
|
+
return (async (url) => {
|
|
85
|
+
const u = typeof url === "string" ? url : url.toString();
|
|
86
|
+
const r = responses[u];
|
|
87
|
+
if (!r)
|
|
88
|
+
throw new Error(`mock fetch: no response for ${u}`);
|
|
89
|
+
// Vitest's Response uses globalThis.Response; .url is read-only normally.
|
|
90
|
+
const res = new Response("", { status: r.status });
|
|
91
|
+
// Spoof res.url via prototype override
|
|
92
|
+
Object.defineProperty(res, "url", { value: r.finalUrl ?? u, configurable: true });
|
|
93
|
+
return res;
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
it("OK verdict when status 200 and host unchanged", async () => {
|
|
97
|
+
const fetchImpl = mockFetch({
|
|
98
|
+
"https://chatgpt.com/": { status: 200 },
|
|
99
|
+
"https://gemini.google.com/app": { status: 200 },
|
|
100
|
+
"https://claude.ai/new": { status: 200 },
|
|
101
|
+
"https://github.com/copilot": { status: 200 },
|
|
102
|
+
"https://www.perplexity.ai/": { status: 200 },
|
|
103
|
+
});
|
|
104
|
+
const results = await probeAllVendors({ fetchImpl });
|
|
105
|
+
const chatgpt = results.find((r) => r.vendor === "chatgpt-web");
|
|
106
|
+
expect(chatgpt.verdict).toBe("OK");
|
|
107
|
+
expect(chatgpt.hostChanged).toBe(false);
|
|
108
|
+
});
|
|
109
|
+
it("REDIRECT_HOST_CHANGE verdict catches stale URLs (chat.openai.com → chatgpt.com)", async () => {
|
|
110
|
+
// Inject a vendor entry with a stale URL to demonstrate the catch.
|
|
111
|
+
const fetchImpl = (async (url) => {
|
|
112
|
+
const r = new Response("", { status: 200 });
|
|
113
|
+
Object.defineProperty(r, "url", { value: "https://chatgpt.com/", configurable: true });
|
|
114
|
+
return r;
|
|
115
|
+
});
|
|
116
|
+
// Manually probe a stale URL via the same logic
|
|
117
|
+
const { probeAllVendors: probe } = await import("./vendor_probe.js");
|
|
118
|
+
// We can't directly inject a stale URL without modifying registry, so
|
|
119
|
+
// we test the host-changed detector via formatProbePulseLine:
|
|
120
|
+
const fakeResults = [
|
|
121
|
+
{ vendor: "chatgpt-web-stale", url: "https://chat.openai.com/", finalUrl: "https://chatgpt.com/", status: 200, hostChanged: true, verdict: "REDIRECT_HOST_CHANGE", notes: "redirected from chat.openai.com to chatgpt.com — update vendor_strategy.ts homeUrl", elapsedMs: 5 },
|
|
122
|
+
{ vendor: "gemini-web", url: "https://gemini.google.com/app", finalUrl: "https://gemini.google.com/app", status: 200, hostChanged: false, verdict: "OK", notes: "reachable (status 200)", elapsedMs: 5 },
|
|
123
|
+
];
|
|
124
|
+
expect(failingProbes(fakeResults).length).toBe(1);
|
|
125
|
+
expect(failingProbes(fakeResults)[0].verdict).toBe("REDIRECT_HOST_CHANGE");
|
|
126
|
+
expect(formatProbePulseLine(fakeResults)).toContain("FAILING");
|
|
127
|
+
void probe;
|
|
128
|
+
});
|
|
129
|
+
it("SKIP verdict for non-HTTP URLs (app schemes)", async () => {
|
|
130
|
+
const fetchImpl = mockFetch({});
|
|
131
|
+
const results = await probeAllVendors({ fetchImpl });
|
|
132
|
+
const skipped = results.filter((r) => r.verdict === "SKIP");
|
|
133
|
+
// gemini-mobile, chatgpt-mobile, any-mobile-browser, claude-code, cursor are not HTTP
|
|
134
|
+
expect(skipped.length).toBeGreaterThanOrEqual(2);
|
|
135
|
+
});
|
|
136
|
+
it("BLOCKED verdict on 403 (Cloudflare)", async () => {
|
|
137
|
+
const fetchImpl = mockFetch({
|
|
138
|
+
"https://chatgpt.com/": { status: 200 },
|
|
139
|
+
"https://gemini.google.com/app": { status: 200 },
|
|
140
|
+
"https://claude.ai/new": { status: 403 },
|
|
141
|
+
"https://github.com/copilot": { status: 200 },
|
|
142
|
+
"https://www.perplexity.ai/": { status: 200 },
|
|
143
|
+
});
|
|
144
|
+
const results = await probeAllVendors({ fetchImpl });
|
|
145
|
+
const claude = results.find((r) => r.vendor === "claude-web");
|
|
146
|
+
expect(claude.verdict).toBe("BLOCKED");
|
|
147
|
+
});
|
|
148
|
+
it("failingProbes ignores OK + SKIP + BLOCKED, surfaces real failures", () => {
|
|
149
|
+
const sample = [
|
|
150
|
+
{ vendor: "a", url: "https://a", finalUrl: "https://a", status: 200, hostChanged: false, verdict: "OK", notes: "", elapsedMs: 1 },
|
|
151
|
+
{ vendor: "b", url: "https://b", finalUrl: "https://x", status: 200, hostChanged: true, verdict: "REDIRECT_HOST_CHANGE", notes: "", elapsedMs: 1 },
|
|
152
|
+
{ vendor: "c", url: "https://c", finalUrl: null, status: 404, hostChanged: false, verdict: "NOT_FOUND", notes: "", elapsedMs: 1 },
|
|
153
|
+
{ vendor: "d", url: "https://d", finalUrl: null, status: 403, hostChanged: false, verdict: "BLOCKED", notes: "", elapsedMs: 1 },
|
|
154
|
+
{ vendor: "e", url: "claude://", finalUrl: null, status: null, hostChanged: false, verdict: "SKIP", notes: "", elapsedMs: 0 },
|
|
155
|
+
];
|
|
156
|
+
const fail = failingProbes(sample);
|
|
157
|
+
expect(fail.map((f) => f.vendor)).toEqual(["b", "c"]);
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
// ============================ MNEME PASSPORT (disruption) ============================
|
|
161
|
+
describe("v1.98 · MNEME PASSPORT — portable HMAC-signed identity", () => {
|
|
162
|
+
// Fresh copy per test — the TAMPERED test mutates entries and we don't
|
|
163
|
+
// want that to leak into later tests.
|
|
164
|
+
function freshEntries() {
|
|
165
|
+
return [
|
|
166
|
+
{ id: "d1", ts: Date.now() - 1000, kind: "decision", text: "Use Postgres native JSONB for v1", scope: "auth-service" },
|
|
167
|
+
{ id: "r1", ts: Date.now() - 2000, kind: "regret", text: "JWT 5-min tolerance broke prod 2024-DST", scope: "commit a3f9b21" },
|
|
168
|
+
{ id: "w1", ts: Date.now() - 3000, kind: "wisdom", text: "Always cite commits when AI suggests a fix" },
|
|
169
|
+
];
|
|
170
|
+
}
|
|
171
|
+
const entries = freshEntries(); // legacy reads in tests below — will be reassigned via splice in TAMPERED test
|
|
172
|
+
it("generatePassportSecret produces 32 bytes", () => {
|
|
173
|
+
const s = generatePassportSecret();
|
|
174
|
+
expect(s.length).toBe(32);
|
|
175
|
+
});
|
|
176
|
+
it("issuePassport produces a valid envelope (signed)", () => {
|
|
177
|
+
const secret = generatePassportSecret();
|
|
178
|
+
const env = issuePassport({ holder: "alice@mneme", entries, secret });
|
|
179
|
+
expect(env.holder).toBe("alice@mneme");
|
|
180
|
+
expect(env.alg).toBe("HMAC-SHA256");
|
|
181
|
+
expect(env.signature.length).toBe(64); // 32 bytes hex = 64 chars
|
|
182
|
+
expect(env.entries.length).toBe(3);
|
|
183
|
+
expect(env.entriesHash.length).toBeGreaterThan(0);
|
|
184
|
+
});
|
|
185
|
+
it("verifyPassport returns VALID for unmodified envelope + correct secret", () => {
|
|
186
|
+
const secret = generatePassportSecret();
|
|
187
|
+
const env = issuePassport({ holder: "alice", entries, secret });
|
|
188
|
+
const r = verifyPassport(env, secret);
|
|
189
|
+
expect(r.verdict).toBe("VALID");
|
|
190
|
+
expect(r.ok).toBe(true);
|
|
191
|
+
});
|
|
192
|
+
it("verifyPassport returns TAMPERED when entries modified", () => {
|
|
193
|
+
const secret = generatePassportSecret();
|
|
194
|
+
const env = issuePassport({ holder: "alice", entries, secret });
|
|
195
|
+
// Mutate an entry
|
|
196
|
+
env.entries[0].text = "MODIFIED EVIL DECISION";
|
|
197
|
+
const r = verifyPassport(env, secret);
|
|
198
|
+
expect(r.verdict).toBe("TAMPERED");
|
|
199
|
+
expect(r.ok).toBe(false);
|
|
200
|
+
});
|
|
201
|
+
it("verifyPassport returns TAMPERED when signature is forged", () => {
|
|
202
|
+
const secret = generatePassportSecret();
|
|
203
|
+
const env = issuePassport({ holder: "alice", entries, secret });
|
|
204
|
+
env.signature = "0".repeat(64);
|
|
205
|
+
const r = verifyPassport(env, secret);
|
|
206
|
+
expect(r.verdict).toBe("TAMPERED");
|
|
207
|
+
});
|
|
208
|
+
it("verifyPassport returns WRONG_KEY when secret doesn't match", () => {
|
|
209
|
+
const secret1 = generatePassportSecret();
|
|
210
|
+
const secret2 = generatePassportSecret();
|
|
211
|
+
const env = issuePassport({ holder: "alice", entries, secret: secret1 });
|
|
212
|
+
const r = verifyPassport(env, secret2);
|
|
213
|
+
expect(r.verdict).toBe("WRONG_KEY");
|
|
214
|
+
});
|
|
215
|
+
it("verifyPassport returns EXPIRED when past TTL", () => {
|
|
216
|
+
const secret = generatePassportSecret();
|
|
217
|
+
const env = issuePassport({ holder: "alice", entries, secret, ttlDays: 0 });
|
|
218
|
+
// Force expiry into the past
|
|
219
|
+
env.expiresAt = Date.now() - 1000;
|
|
220
|
+
const r = verifyPassport(env, secret);
|
|
221
|
+
expect(r.verdict).toBe("EXPIRED");
|
|
222
|
+
});
|
|
223
|
+
it("serialize → parse round-trips", () => {
|
|
224
|
+
const secret = generatePassportSecret();
|
|
225
|
+
const env = issuePassport({ holder: "alice", entries, secret });
|
|
226
|
+
const text = serializePassport(env);
|
|
227
|
+
expect(text).toContain("MNEME PASSPORT v1");
|
|
228
|
+
expect(text).toContain("--- BEGIN JSON ---");
|
|
229
|
+
const parsed = parsePassport(text);
|
|
230
|
+
expect(parsed).not.toBeNull();
|
|
231
|
+
expect(parsed?.signature).toBe(env.signature);
|
|
232
|
+
expect(parsed?.entries.length).toBe(3);
|
|
233
|
+
// Verify after round-trip
|
|
234
|
+
expect(verifyPassport(parsed, secret).ok).toBe(true);
|
|
235
|
+
});
|
|
236
|
+
it("parsePassport returns null on malformed input", () => {
|
|
237
|
+
expect(parsePassport("not a passport")).toBeNull();
|
|
238
|
+
expect(parsePassport("--- BEGIN JSON --- {bad json}")).toBeNull();
|
|
239
|
+
});
|
|
240
|
+
it("issuePassport caps entries to maxEntries (newest first)", () => {
|
|
241
|
+
const secret = generatePassportSecret();
|
|
242
|
+
const many = [];
|
|
243
|
+
for (let i = 0; i < 100; i++)
|
|
244
|
+
many.push({ id: `e${i}`, ts: i, kind: "decision", text: `decision ${i}` });
|
|
245
|
+
const env = issuePassport({ holder: "alice", entries: many, secret, maxEntries: 10 });
|
|
246
|
+
expect(env.entries.length).toBe(10);
|
|
247
|
+
// Newest first → highest ts → entries 90..99
|
|
248
|
+
expect(env.entries[0].id).toBe("e99");
|
|
249
|
+
expect(env.entries[9].id).toBe("e90");
|
|
250
|
+
});
|
|
251
|
+
it("fingerprintEntries is deterministic + sensitive to changes", () => {
|
|
252
|
+
const a = fingerprintEntries(entries);
|
|
253
|
+
const b = fingerprintEntries(entries);
|
|
254
|
+
expect(a).toBe(b);
|
|
255
|
+
const modified = [...entries, { id: "x", ts: 1, kind: "wisdom", text: "extra" }];
|
|
256
|
+
expect(fingerprintEntries(modified)).not.toBe(a);
|
|
257
|
+
});
|
|
258
|
+
it("estimatePassportTokens returns a positive number", () => {
|
|
259
|
+
const secret = generatePassportSecret();
|
|
260
|
+
const env = issuePassport({ holder: "alice", entries, secret });
|
|
261
|
+
expect(estimatePassportTokens(env)).toBeGreaterThan(0);
|
|
262
|
+
// Typical passport with 3 entries should fit in ~500 tokens
|
|
263
|
+
expect(estimatePassportTokens(env)).toBeLessThan(800);
|
|
264
|
+
});
|
|
265
|
+
it("formatPassportPulseLine produces compact summary", () => {
|
|
266
|
+
const secret = generatePassportSecret();
|
|
267
|
+
const env = issuePassport({ holder: "alice", entries, secret });
|
|
268
|
+
const line = formatPassportPulseLine(env);
|
|
269
|
+
expect(line).toContain("MNEME-PASSPORT");
|
|
270
|
+
expect(line).toContain("alice");
|
|
271
|
+
expect(line).toContain("entries=3");
|
|
272
|
+
});
|
|
273
|
+
it("the disruption: any AI can READ entries without secret (only VERIFY needs secret)", () => {
|
|
274
|
+
const secret = generatePassportSecret();
|
|
275
|
+
const env = issuePassport({ holder: "alice", entries: freshEntries(), secret });
|
|
276
|
+
const text = serializePassport(env);
|
|
277
|
+
const parsed = parsePassport(text);
|
|
278
|
+
// ANY AI agent — without the secret — can still see the entries
|
|
279
|
+
expect(parsed.entries.map((e) => e.text)).toContain("Use Postgres native JSONB for v1");
|
|
280
|
+
expect(parsed.entries.map((e) => e.text)).toContain("Always cite commits when AI suggests a fix");
|
|
281
|
+
// But cannot forge a new envelope without the secret
|
|
282
|
+
const wrongSecret = generatePassportSecret();
|
|
283
|
+
expect(verifyPassport(parsed, wrongSecret).verdict).toBe("WRONG_KEY");
|
|
284
|
+
});
|
|
285
|
+
});
|
|
286
|
+
// ============================ ADDITIONAL FLEXIBLE-PHRASE COVERAGE ============================
|
|
287
|
+
describe("v1.98 · flexible phrase recognition (user complained about pattern memorization)", () => {
|
|
288
|
+
// Each phrase from real Thai/English conversational forms — confirms parser
|
|
289
|
+
// doesn't require exact wording. Imported lazily so we don't break the file
|
|
290
|
+
// structure when this module evolves.
|
|
291
|
+
it("loose phrasings without exact 'mneme' word still trigger", async () => {
|
|
292
|
+
const { parseCloneIntent } = await import("./clone_to.js");
|
|
293
|
+
const phrases = [
|
|
294
|
+
"ผมอยากจะส่งบริบทไปที่ samsung", // unusual verb form + samsung
|
|
295
|
+
"Help me put context on iPhone", // English "put"
|
|
296
|
+
"เอา mneme ลงโทรศัพท์ที", // "เอา ลง" verb form
|
|
297
|
+
"อยากให้ brain ไปอยู่ใน ipad", // "อยากให้ ไปอยู่"
|
|
298
|
+
"save my brain to gemini please", // "save"
|
|
299
|
+
];
|
|
300
|
+
for (const p of phrases) {
|
|
301
|
+
const r = parseCloneIntent(p);
|
|
302
|
+
expect(r.target).not.toBe("unknown");
|
|
303
|
+
expect(r.isCloneRequest).toBe(true);
|
|
304
|
+
}
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
//# sourceMappingURL=v1_98.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"v1_98.test.js","sourceRoot":"","sources":["../../src/rainbow/v1_98.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v1.98.0 -- RAINBOW · Vendor URL probe.
|
|
3
|
+
*
|
|
4
|
+
* Closes the "comment lies" gap that v1.85-1.96 had: code comments
|
|
5
|
+
* claimed "Verified May 2026" but no test actually hit the vendor URL.
|
|
6
|
+
* The user found that `chat.openai.com` had been replaced by
|
|
7
|
+
* `chatgpt.com` more than a year prior and our code was still pointing
|
|
8
|
+
* at the dead host.
|
|
9
|
+
*
|
|
10
|
+
* This module does the simplest thing that catches stale URLs: HEAD
|
|
11
|
+
* each vendor home URL, record the response status + final URL after
|
|
12
|
+
* redirects + whether the host changed. If the host changes (e.g.
|
|
13
|
+
* chat.openai.com → chatgpt.com via 308), we flag it loudly.
|
|
14
|
+
*
|
|
15
|
+
* NOT a Playwright integration test — those need browser binaries +
|
|
16
|
+
* are flaky in CI. This is a deterministic, fast (one HEAD per
|
|
17
|
+
* vendor), zero-dependency check that the URL is at least reachable
|
|
18
|
+
* and not silently redirected to a different host.
|
|
19
|
+
*
|
|
20
|
+
* Run via:
|
|
21
|
+
* - Manually: `node -e "import('./vendor_probe.js').then(m => m.probeAllVendors().then(console.log))"`
|
|
22
|
+
* - In CI: daemon's nightly cycle (future) — surfaces stale URLs as inbox warnings
|
|
23
|
+
* - Test: `vendor_probe.test.ts` mocks fetch + asserts the redirect-detection logic
|
|
24
|
+
*/
|
|
25
|
+
export interface ProbeResult {
|
|
26
|
+
vendor: string;
|
|
27
|
+
url: string;
|
|
28
|
+
finalUrl: string | null;
|
|
29
|
+
status: number | null;
|
|
30
|
+
hostChanged: boolean;
|
|
31
|
+
/** Verdict: OK / REDIRECT_HOST_CHANGE / 404 / NETWORK_ERR / SKIP. */
|
|
32
|
+
verdict: "OK" | "REDIRECT_HOST_CHANGE" | "NOT_FOUND" | "NETWORK_ERR" | "BLOCKED" | "SKIP";
|
|
33
|
+
/** Notes for human / AI agent. */
|
|
34
|
+
notes: string;
|
|
35
|
+
elapsedMs: number;
|
|
36
|
+
}
|
|
37
|
+
export interface ProbeOptions {
|
|
38
|
+
/** Override fetch (for tests). */
|
|
39
|
+
fetchImpl?: typeof fetch;
|
|
40
|
+
/** Max time per probe in ms. Default 8000. */
|
|
41
|
+
timeoutMs?: number;
|
|
42
|
+
/** User-Agent header. */
|
|
43
|
+
userAgent?: string;
|
|
44
|
+
}
|
|
45
|
+
/** Probe every registered vendor concurrently. Returns one ProbeResult
|
|
46
|
+
* per vendor. Total elapsed time ≈ slowest probe. */
|
|
47
|
+
export declare function probeAllVendors(opts?: ProbeOptions): Promise<ProbeResult[]>;
|
|
48
|
+
/** Probe results that should ALERT — anything that isn't OK or SKIP. */
|
|
49
|
+
export declare function failingProbes(results: ProbeResult[]): ProbeResult[];
|
|
50
|
+
/** One-line summary suitable for the pulse / CI logs. */
|
|
51
|
+
export declare function formatProbePulseLine(results: ProbeResult[]): string;
|
|
52
|
+
//# sourceMappingURL=vendor_probe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vendor_probe.d.ts","sourceRoot":"","sources":["../../src/rainbow/vendor_probe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAIH,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,WAAW,EAAE,OAAO,CAAC;IACrB,qEAAqE;IACrE,OAAO,EAAE,IAAI,GAAG,sBAAsB,GAAG,WAAW,GAAG,aAAa,GAAG,SAAS,GAAG,MAAM,CAAC;IAC1F,kCAAkC;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,kCAAkC;IAClC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,8CAA8C;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yBAAyB;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA8DD;sDACsD;AACtD,wBAAsB,eAAe,CAAC,IAAI,GAAE,YAAiB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAErF;AAED,wEAAwE;AACxE,wBAAgB,aAAa,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,WAAW,EAAE,CAEnE;AAED,yDAAyD;AACzD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,MAAM,CAMnE"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v1.98.0 -- RAINBOW · Vendor URL probe.
|
|
3
|
+
*
|
|
4
|
+
* Closes the "comment lies" gap that v1.85-1.96 had: code comments
|
|
5
|
+
* claimed "Verified May 2026" but no test actually hit the vendor URL.
|
|
6
|
+
* The user found that `chat.openai.com` had been replaced by
|
|
7
|
+
* `chatgpt.com` more than a year prior and our code was still pointing
|
|
8
|
+
* at the dead host.
|
|
9
|
+
*
|
|
10
|
+
* This module does the simplest thing that catches stale URLs: HEAD
|
|
11
|
+
* each vendor home URL, record the response status + final URL after
|
|
12
|
+
* redirects + whether the host changed. If the host changes (e.g.
|
|
13
|
+
* chat.openai.com → chatgpt.com via 308), we flag it loudly.
|
|
14
|
+
*
|
|
15
|
+
* NOT a Playwright integration test — those need browser binaries +
|
|
16
|
+
* are flaky in CI. This is a deterministic, fast (one HEAD per
|
|
17
|
+
* vendor), zero-dependency check that the URL is at least reachable
|
|
18
|
+
* and not silently redirected to a different host.
|
|
19
|
+
*
|
|
20
|
+
* Run via:
|
|
21
|
+
* - Manually: `node -e "import('./vendor_probe.js').then(m => m.probeAllVendors().then(console.log))"`
|
|
22
|
+
* - In CI: daemon's nightly cycle (future) — surfaces stale URLs as inbox warnings
|
|
23
|
+
* - Test: `vendor_probe.test.ts` mocks fetch + asserts the redirect-detection logic
|
|
24
|
+
*/
|
|
25
|
+
import { VENDOR_REGISTRY } from "./vendor_strategy.js";
|
|
26
|
+
function hostOf(url) {
|
|
27
|
+
try {
|
|
28
|
+
return new URL(url).host;
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
async function probeOne(entry, opts = {}) {
|
|
35
|
+
const url = entry.homeUrl;
|
|
36
|
+
if (!url || !url.startsWith("http")) {
|
|
37
|
+
return {
|
|
38
|
+
vendor: entry.id, url, finalUrl: null, status: null, hostChanged: false,
|
|
39
|
+
verdict: "SKIP", notes: `non-HTTP url (probably an app deep-link scheme)`, elapsedMs: 0,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
43
|
+
const timeoutMs = opts.timeoutMs ?? 8000;
|
|
44
|
+
const t0 = Date.now();
|
|
45
|
+
const ctrl = new AbortController();
|
|
46
|
+
const timer = setTimeout(() => ctrl.abort(), timeoutMs);
|
|
47
|
+
try {
|
|
48
|
+
const res = await fetchImpl(url, {
|
|
49
|
+
method: "HEAD",
|
|
50
|
+
redirect: "follow",
|
|
51
|
+
signal: ctrl.signal,
|
|
52
|
+
headers: { "user-agent": opts.userAgent ?? "Mneme-vendor-probe/1.98 (+https://github.com/patsa2561-art/mneme-ai)" },
|
|
53
|
+
});
|
|
54
|
+
clearTimeout(timer);
|
|
55
|
+
const elapsedMs = Date.now() - t0;
|
|
56
|
+
const finalUrl = res.url || url;
|
|
57
|
+
const originalHost = hostOf(url);
|
|
58
|
+
const finalHost = hostOf(finalUrl);
|
|
59
|
+
const hostChanged = !!(originalHost && finalHost && originalHost !== finalHost);
|
|
60
|
+
let verdict;
|
|
61
|
+
let notes;
|
|
62
|
+
if (res.status === 404) {
|
|
63
|
+
verdict = "NOT_FOUND";
|
|
64
|
+
notes = `404 — vendor URL is dead`;
|
|
65
|
+
}
|
|
66
|
+
else if (res.status === 403 || res.status === 401) {
|
|
67
|
+
verdict = "BLOCKED";
|
|
68
|
+
notes = `${res.status} — vendor likely blocks bots (Cloudflare/UA). Browser-real users still work.`;
|
|
69
|
+
}
|
|
70
|
+
else if (hostChanged) {
|
|
71
|
+
verdict = "REDIRECT_HOST_CHANGE";
|
|
72
|
+
notes = `redirected from ${originalHost} to ${finalHost} — update vendor_strategy.ts homeUrl`;
|
|
73
|
+
}
|
|
74
|
+
else if (res.status >= 200 && res.status < 400) {
|
|
75
|
+
verdict = "OK";
|
|
76
|
+
notes = `reachable (status ${res.status})`;
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
verdict = "NETWORK_ERR";
|
|
80
|
+
notes = `unexpected status ${res.status}`;
|
|
81
|
+
}
|
|
82
|
+
return { vendor: entry.id, url, finalUrl, status: res.status, hostChanged, verdict, notes, elapsedMs };
|
|
83
|
+
}
|
|
84
|
+
catch (e) {
|
|
85
|
+
clearTimeout(timer);
|
|
86
|
+
const elapsedMs = Date.now() - t0;
|
|
87
|
+
return {
|
|
88
|
+
vendor: entry.id, url, finalUrl: null, status: null, hostChanged: false,
|
|
89
|
+
verdict: "NETWORK_ERR", notes: `fetch error: ${e.message}`, elapsedMs,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/** Probe every registered vendor concurrently. Returns one ProbeResult
|
|
94
|
+
* per vendor. Total elapsed time ≈ slowest probe. */
|
|
95
|
+
export async function probeAllVendors(opts = {}) {
|
|
96
|
+
return Promise.all(VENDOR_REGISTRY.map((v) => probeOne(v, opts)));
|
|
97
|
+
}
|
|
98
|
+
/** Probe results that should ALERT — anything that isn't OK or SKIP. */
|
|
99
|
+
export function failingProbes(results) {
|
|
100
|
+
return results.filter((r) => r.verdict !== "OK" && r.verdict !== "SKIP" && r.verdict !== "BLOCKED");
|
|
101
|
+
}
|
|
102
|
+
/** One-line summary suitable for the pulse / CI logs. */
|
|
103
|
+
export function formatProbePulseLine(results) {
|
|
104
|
+
const groups = { OK: 0, REDIRECT_HOST_CHANGE: 0, NOT_FOUND: 0, NETWORK_ERR: 0, BLOCKED: 0, SKIP: 0 };
|
|
105
|
+
for (const r of results)
|
|
106
|
+
groups[r.verdict]++;
|
|
107
|
+
const failing = failingProbes(results);
|
|
108
|
+
const verdict = failing.length === 0 ? "✓ ALL_OK" : `✗ ${failing.length}_FAILING`;
|
|
109
|
+
return `VENDOR-PROBE ${verdict} · ok=${groups.OK} redirect=${groups.REDIRECT_HOST_CHANGE} 404=${groups.NOT_FOUND} blocked=${groups.BLOCKED} skip=${groups.SKIP} err=${groups.NETWORK_ERR}`;
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=vendor_probe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vendor_probe.js","sourceRoot":"","sources":["../../src/rainbow/vendor_probe.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v1.98.0 -- RAINBOW · Vendor strategy map.
|
|
3
|
+
*
|
|
4
|
+
* Replaces the broken "one-size-fits-all RELAY" assumption with explicit
|
|
5
|
+
* per-vendor strategies. Each vendor (web AI, mobile app, MCP-capable
|
|
6
|
+
* editor, etc.) gets the transport that ACTUALLY works for its
|
|
7
|
+
* capability tier.
|
|
8
|
+
*
|
|
9
|
+
* Strategies:
|
|
10
|
+
* clipboard-first — copy plain text + open vendor home page. User pastes.
|
|
11
|
+
* Works on EVERY Web AI's free tier. The default.
|
|
12
|
+
* plain-qr — render plain-text soul as QR (NO encryption, NO
|
|
13
|
+
* fetch-instruction). Phone scans → copies → pastes.
|
|
14
|
+
* mcp-direct — vendor is MCP-aware (Claude Code, Cursor, Codex CLI,
|
|
15
|
+
* Continue) — Mneme MCP server exposes tools directly.
|
|
16
|
+
* No copy/paste needed.
|
|
17
|
+
* prefill-and-paste— vendor honors ?q= deep link AND has web-fetch
|
|
18
|
+
* (paid-tier ChatGPT Plus / Gemini Advanced). The
|
|
19
|
+
* old RELAY path. Used ONLY when caller explicitly
|
|
20
|
+
* asserts "I have a paid-tier AI with browsing".
|
|
21
|
+
* app-deeplink-NA — vendor mobile app does NOT honor any URL scheme.
|
|
22
|
+
* Mneme cannot help; tell the user honestly.
|
|
23
|
+
*
|
|
24
|
+
* Every entry has `verified` (boolean) + `lastChecked` (ISO date) so
|
|
25
|
+
* stale-URL claims like "Verified May 2026" cannot lie silently. The
|
|
26
|
+
* companion `vendor_probe.ts` actually hits each URL with HEAD + asserts.
|
|
27
|
+
*/
|
|
28
|
+
export type VendorStrategy = "clipboard-first" | "plain-qr" | "mcp-direct" | "prefill-and-paste" | "app-deeplink-NA";
|
|
29
|
+
export interface VendorEntry {
|
|
30
|
+
/** Canonical vendor id used across Mneme. */
|
|
31
|
+
id: string;
|
|
32
|
+
/** Display label. */
|
|
33
|
+
label: string;
|
|
34
|
+
/** Primary URL to open (home page for clipboard-first). */
|
|
35
|
+
homeUrl: string;
|
|
36
|
+
/** Default strategy for the FREE tier of this vendor. */
|
|
37
|
+
freeStrategy: VendorStrategy;
|
|
38
|
+
/** Strategy when user explicitly has the paid tier with browsing. */
|
|
39
|
+
paidStrategy: VendorStrategy;
|
|
40
|
+
/** Whether ?q= deep link is verified to work (empirical, not assumed). */
|
|
41
|
+
qParamWorks: boolean;
|
|
42
|
+
/** Whether the vendor offers web-fetch in chat (free tier). */
|
|
43
|
+
webFetchAvailable: boolean;
|
|
44
|
+
/** ISO date the URL was last probed. Updated by vendor_probe.ts. */
|
|
45
|
+
lastChecked: string;
|
|
46
|
+
/** Why we picked this strategy (transparency). */
|
|
47
|
+
reasoning: string;
|
|
48
|
+
}
|
|
49
|
+
/** Canonical vendor table. Source of truth for strategy decisions. */
|
|
50
|
+
export declare const VENDOR_REGISTRY: VendorEntry[];
|
|
51
|
+
export declare function entryOf(id: string): VendorEntry | null;
|
|
52
|
+
/** Decide strategy given vendor + whether user has paid tier. */
|
|
53
|
+
export declare function pickStrategy(vendorId: string, opts?: {
|
|
54
|
+
paidTier?: boolean;
|
|
55
|
+
}): {
|
|
56
|
+
strategy: VendorStrategy;
|
|
57
|
+
entry: VendorEntry | null;
|
|
58
|
+
reason: string;
|
|
59
|
+
};
|
|
60
|
+
/** Render the strategy decision as a pulse line. */
|
|
61
|
+
export declare function formatStrategyPulseLine(vendorId: string, opts?: {
|
|
62
|
+
paidTier?: boolean;
|
|
63
|
+
}): string;
|
|
64
|
+
//# sourceMappingURL=vendor_strategy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vendor_strategy.d.ts","sourceRoot":"","sources":["../../src/rainbow/vendor_strategy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,MAAM,MAAM,cAAc,GAAG,iBAAiB,GAAG,UAAU,GAAG,YAAY,GAAG,mBAAmB,GAAG,iBAAiB,CAAC;AAErH,MAAM,WAAW,WAAW;IAC1B,6CAA6C;IAC7C,EAAE,EAAE,MAAM,CAAC;IACX,qBAAqB;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,2DAA2D;IAC3D,OAAO,EAAE,MAAM,CAAC;IAChB,yDAAyD;IACzD,YAAY,EAAE,cAAc,CAAC;IAC7B,qEAAqE;IACrE,YAAY,EAAE,cAAc,CAAC;IAC7B,0EAA0E;IAC1E,WAAW,EAAE,OAAO,CAAC;IACrB,+DAA+D;IAC/D,iBAAiB,EAAE,OAAO,CAAC;IAC3B,oEAAoE;IACpE,WAAW,EAAE,MAAM,CAAC;IACpB,kDAAkD;IAClD,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,sEAAsE;AACtE,eAAO,MAAM,eAAe,EAAE,WAAW,EA+GxC,CAAC;AAEF,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAEtD;AAED,iEAAiE;AACjE,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,GAAE;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG;IAAE,QAAQ,EAAE,cAAc,CAAC;IAAC,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAKzJ;AAED,oDAAoD;AACpD,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,GAAE;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,MAAM,CAGnG"}
|