mumpix 1.0.19 → 1.1.3

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 (38) hide show
  1. package/CHANGELOG.md +82 -11
  2. package/README.md +278 -8
  3. package/bin/mumpix.js +1 -405
  4. package/examples/agent-memory.js +1 -1
  5. package/examples/basic.js +1 -1
  6. package/examples/behavioral-primitives.js +50 -0
  7. package/examples/recall-quality-suite.js +156 -0
  8. package/examples/verified-mode.js +1 -1
  9. package/package.json +24 -13
  10. package/scripts/bench-semantic.cjs +76 -0
  11. package/scripts/test-license-modes.cjs +87 -0
  12. package/scripts/test-phase0.cjs +137 -0
  13. package/scripts/test-semantic.cjs +411 -0
  14. package/src/brp/index.js +1 -0
  15. package/src/collapse/index.js +1 -0
  16. package/src/core/MumpixDB.js +264 -323
  17. package/src/core/audit.js +1 -173
  18. package/src/core/auth.js +1 -232
  19. package/src/core/inverted-index.js +249 -0
  20. package/src/core/license.js +1 -267
  21. package/src/core/ml-dsa.mjs +1 -25
  22. package/src/core/ml-kem.mjs +1 -32
  23. package/src/core/recall.js +226 -112
  24. package/src/core/semantic-sidecar.js +312 -0
  25. package/src/core/store.js +365 -288
  26. package/src/core/wal-writer.js +83 -0
  27. package/src/index.js +20 -34
  28. package/src/integrations/developer-sdk.js +1 -165
  29. package/src/integrations/langchain-official.js +1 -0
  30. package/src/integrations/langchain.js +1 -131
  31. package/src/integrations/llamaindex-official.js +1 -0
  32. package/src/integrations/llamaindex.js +1 -86
  33. package/src/integrations/vector-sidecar.js +325 -0
  34. package/src/rlp/index.js +1 -0
  35. package/src/temporal/engine.js +1 -1894
  36. package/src/temporal/indexes.js +1 -178
  37. package/src/temporal/operators.js +1 -186
  38. package/scripts/postinstall-auth.js +0 -101
package/bin/mumpix.js CHANGED
@@ -1,406 +1,2 @@
1
1
  #!/usr/bin/env node
2
- 'use strict';
3
-
4
- /**
5
- * mumpix CLI
6
- *
7
- * Usage:
8
- * mumpix remember ./agent.mumpix "User prefers TypeScript"
9
- * mumpix recall ./agent.mumpix "what language?"
10
- * mumpix list ./agent.mumpix
11
- * mumpix clear ./agent.mumpix
12
- * mumpix stats ./agent.mumpix
13
- * mumpix audit ./agent.mumpix
14
- * mumpix shell ./agent.mumpix # interactive REPL
15
- */
16
-
17
- const path = require('path');
18
- const readline = require('readline');
19
- const { Mumpix } = require('../src/index');
20
- const {
21
- loadAuthState,
22
- clearAuthState,
23
- upsertStoredLicense,
24
- exchangeTokenForLicense,
25
- loginWithDeviceFlow,
26
- authStatePath,
27
- configDir,
28
- } = require('../src/core/auth');
29
-
30
- const USAGE = `
31
- mumpix — SQLite for AI
32
-
33
- Usage:
34
- mumpix <command> <file> [args...]
35
-
36
- Commands:
37
- remember <file> "<text>" Store a memory
38
- recall <file> "<query>" Recall the best match
39
- search <file> "<query>" [k] Recall top-k matches
40
- list <file> List all memories
41
- clear <file> Clear all memories
42
- stats <file> Show database stats
43
- audit <file> Show audit log (verified mode)
44
- shell <file> Start interactive REPL
45
- auth <subcommand> Account login/logout/status
46
- help Show this message
47
-
48
- Options (append to any command):
49
- --consistency=eventual|strict|verified (default: eventual)
50
-
51
- Examples:
52
- mumpix remember ./agent.mumpix "User prefers TypeScript"
53
- mumpix recall ./agent.mumpix "what language?" --consistency=strict
54
- mumpix search ./agent.mumpix "TypeScript" 3
55
- mumpix shell ./agent.mumpix --consistency=verified
56
- mumpix auth status
57
- mumpix auth login --token=<account-token>
58
- mumpix auth login --license=<signed-license-key>
59
- `.trim();
60
-
61
- function parseArgs(argv) {
62
- const args = [];
63
- const flags = {};
64
- for (const arg of argv) {
65
- if (arg.startsWith('--')) {
66
- const [k, v] = arg.slice(2).split('=');
67
- flags[k] = v !== undefined ? v : true;
68
- } else {
69
- args.push(arg);
70
- }
71
- }
72
- return { args, flags };
73
- }
74
-
75
- function fmt(val) {
76
- if (val === null) return 'null';
77
- if (typeof val === 'string') return val;
78
- return JSON.stringify(val, null, 2);
79
- }
80
-
81
- function colorize(text, code) {
82
- if (!process.stdout.isTTY) return text;
83
- return `\x1b[${code}m${text}\x1b[0m`;
84
- }
85
-
86
- const dim = t => colorize(t, '2');
87
- const cyan = t => colorize(t, '36');
88
- const green = t => colorize(t, '32');
89
- const yellow = t => colorize(t, '33');
90
- const red = t => colorize(t, '31');
91
- const bold = t => colorize(t, '1');
92
-
93
- function fmtExpiry(ts) {
94
- if (!ts) return '-';
95
- const d = new Date(Number(ts));
96
- if (Number.isNaN(d.getTime())) return '-';
97
- return d.toISOString();
98
- }
99
-
100
- function mask(value, keep = 6) {
101
- const s = String(value || '');
102
- if (s.length <= keep) return s;
103
- return `${s.slice(0, keep)}…`;
104
- }
105
-
106
- async function runAuth(parts, flags) {
107
- const sub = String(parts[0] || 'status').toLowerCase();
108
-
109
- if (sub === 'status') {
110
- const s = loadAuthState();
111
- if (!s || !s.license || !s.license.key) {
112
- console.log(dim('Not logged in.'));
113
- console.log(dim(`Config dir: ${configDir()}`));
114
- return;
115
- }
116
- console.log(bold('Mumpix auth status'));
117
- console.log(` account_id: ${s.account && s.account.id ? s.account.id : '-'}`);
118
- console.log(` tier: ${s.license.tier || (s.account && s.account.tier) || '-'}`);
119
- console.log(` issued_at: ${fmtExpiry(s.license.iat)}`);
120
- console.log(` expires_at: ${fmtExpiry(s.license.exp)}`);
121
- console.log(` license: ${green(mask(s.license.key, 18))}`);
122
- console.log(` state: ${authStatePath()}`);
123
- return;
124
- }
125
-
126
- if (sub === 'logout') {
127
- clearAuthState();
128
- console.log(green('✓') + ' Logged out. Local license removed.');
129
- return;
130
- }
131
-
132
- if (sub === 'login') {
133
- const directLicense = flags.license || flags['license-key'] || null;
134
- if (directLicense) {
135
- const state = upsertStoredLicense(String(directLicense));
136
- console.log(green('✓') + ' License saved.');
137
- console.log(` tier: ${state.license.tier || '-'}`);
138
- console.log(` expires_at: ${fmtExpiry(state.license.exp)}`);
139
- console.log(` state: ${authStatePath()}`);
140
- return;
141
- }
142
-
143
- const token = flags.token || process.env.MUMPIX_AUTH_TOKEN || '';
144
- if (token) {
145
- const state = await exchangeTokenForLicense(String(token).trim(), {});
146
- console.log(green('✓') + ' Account linked and license saved.');
147
- console.log(` account_id: ${state.account.id || '-'}`);
148
- console.log(` tier: ${state.license.tier || state.account.tier || '-'}`);
149
- console.log(` expires_at: ${fmtExpiry(state.license.exp)}`);
150
- console.log(` state: ${authStatePath()}`);
151
- return;
152
- }
153
-
154
- const state = await loginWithDeviceFlow({
155
- onPrompt: ({ userCode, verifyUrl, expiresInSec, intervalSec }) => {
156
- console.log(bold('Mumpix device login'));
157
- console.log(` 1) Open: ${verifyUrl}`);
158
- console.log(` 2) Enter code: ${cyan(userCode)}`);
159
- console.log(` 3) Waiting for approval... (expires in ${expiresInSec}s, polling ${intervalSec}s)`);
160
- }
161
- });
162
- console.log(green('✓') + ' Account linked and license saved.');
163
- console.log(` account_id: ${state.account.id || '-'}`);
164
- console.log(` tier: ${state.license.tier || state.account.tier || '-'}`);
165
- console.log(` expires_at: ${fmtExpiry(state.license.exp)}`);
166
- console.log(` state: ${authStatePath()}`);
167
- return;
168
- }
169
-
170
- console.error(red(`Unknown auth subcommand: ${sub}`));
171
- console.log('Usage: mumpix auth <status|login|logout> [--token=...] [--license=...]');
172
- process.exit(1);
173
- }
174
-
175
- async function main() {
176
- const { args, flags } = parseArgs(process.argv.slice(2));
177
- const [command, arg1, ...rest] = args;
178
-
179
- if (!command || command === 'help' || command === '--help' || command === '-h') {
180
- console.log(USAGE);
181
- process.exit(0);
182
- }
183
-
184
- if (command === 'auth') {
185
- await runAuth([arg1, ...rest], flags);
186
- return;
187
- }
188
-
189
- const filePath = arg1;
190
- if (!filePath && command !== 'help') {
191
- console.error(red('Error: file path required'));
192
- console.log(USAGE);
193
- process.exit(1);
194
- }
195
-
196
- const consistency = flags.consistency || 'eventual';
197
- let db;
198
-
199
- try {
200
- db = await Mumpix.open(filePath, { consistency });
201
- } catch (err) {
202
- console.error(red(`Error opening ${filePath}: ${err.message}`));
203
- process.exit(1);
204
- }
205
-
206
- try {
207
- switch (command) {
208
-
209
- case 'remember': {
210
- const text = rest.join(' ').replace(/^["']|["']$/g, '');
211
- if (!text) { console.error(red('Error: provide text to remember')); process.exit(1); }
212
- const result = await db.remember(text);
213
- console.log(green('✓') + ` Stored as #${result.id} (${result.consistency})`);
214
- break;
215
- }
216
-
217
- case 'recall': {
218
- const query = rest.join(' ').replace(/^["']|["']$/g, '');
219
- if (!query) { console.error(red('Error: provide a query')); process.exit(1); }
220
- const result = await db.recall(query);
221
- if (result === null) {
222
- console.log(dim('No memories found.'));
223
- } else {
224
- console.log(green('→') + ' ' + result);
225
- }
226
- break;
227
- }
228
-
229
- case 'search': {
230
- const k = parseInt(rest[rest.length - 1], 10);
231
- const limit = Number.isInteger(k) && k > 0 ? k : 5;
232
- const queryParts = Number.isInteger(k) ? rest.slice(0, -1) : rest;
233
- const query = queryParts.join(' ').replace(/^["']|["']$/g, '');
234
- if (!query) { console.error(red('Error: provide a query')); process.exit(1); }
235
- const results = await db.recallMany(query, limit);
236
- if (!results.length) {
237
- console.log(dim('No memories found.'));
238
- } else {
239
- results.forEach((r, i) => {
240
- const score = r.score !== undefined ? dim(` (${(r.score * 100).toFixed(1)}%)`) : '';
241
- console.log(`${cyan(`#${r.id}`)} ${r.content}${score}`);
242
- });
243
- }
244
- break;
245
- }
246
-
247
- case 'list': {
248
- const memories = await db.list();
249
- if (!memories.length) {
250
- console.log(dim('No memories stored.'));
251
- } else {
252
- memories.forEach(m => {
253
- const ts = new Date(m.ts).toLocaleString();
254
- console.log(`${cyan(`#${m.id}`)} ${m.content} ${dim(ts)}`);
255
- });
256
- console.log(dim(`\n${memories.length} total`));
257
- }
258
- break;
259
- }
260
-
261
- case 'clear': {
262
- const { count } = await db.clear();
263
- console.log(yellow('⚠') + ` Cleared ${count} ${count === 1 ? 'memory' : 'memories'}`);
264
- break;
265
- }
266
-
267
- case 'stats': {
268
- const s = await db.stats();
269
- console.log(bold('Mumpix stats'));
270
- console.log(` path: ${s.path}`);
271
- console.log(` consistency: ${cyan(s.consistency)}`);
272
- console.log(` records: ${s.records}`);
273
- console.log(` size: ${(s.sizeBytes / 1024).toFixed(2)} KB`);
274
- console.log(` created: ${new Date(s.created).toLocaleString()}`);
275
- console.log(` version: v${s.version}`);
276
- break;
277
- }
278
-
279
- case 'audit': {
280
- let entries;
281
- try {
282
- entries = await db.audit();
283
- } catch (err) {
284
- console.error(red('Error: ') + err.message);
285
- process.exit(1);
286
- }
287
- if (!entries.length) {
288
- console.log(dim('Audit log is empty.'));
289
- } else {
290
- entries.forEach(e => {
291
- const ts = new Date(e.ts).toISOString();
292
- const type = e._type.padEnd(12);
293
- const detail = e._type === 'write' ? `id=${e.id} hash=${e.hash}`
294
- : e._type === 'recall' ? `queryHash=${e.queryHash} resultId=${e.resultId ?? 'null'} latency=${e.latencyMs}ms`
295
- : e._type === 'clear' ? `count=${e.count}`
296
- : '';
297
- console.log(`${dim(ts)} ${yellow(type)} ${detail}`);
298
- });
299
- console.log(dim(`\n${entries.length} entries`));
300
- }
301
- break;
302
- }
303
-
304
- case 'shell': {
305
- await runShell(db, filePath, consistency);
306
- break;
307
- }
308
-
309
- default:
310
- console.error(red(`Unknown command: ${command}`));
311
- console.log(USAGE);
312
- process.exit(1);
313
- }
314
- } finally {
315
- if (command !== 'shell') await db.close();
316
- }
317
- }
318
-
319
- async function runShell(db, filePath, consistency) {
320
- const rl = readline.createInterface({
321
- input: process.stdin,
322
- output: process.stdout,
323
- prompt: cyan('mumpix') + dim(' › '),
324
- historySize: 100,
325
- });
326
-
327
- console.log(bold('Mumpix interactive shell'));
328
- console.log(dim(` file: ${filePath} consistency: ${consistency}`));
329
- console.log(dim(' Commands: remember("…"), recall("…"), list(), clear(), stats(), audit(), exit\n'));
330
-
331
- rl.prompt();
332
-
333
- rl.on('line', async (line) => {
334
- const raw = line.trim();
335
- if (!raw) { rl.prompt(); return; }
336
- if (raw === 'exit' || raw === 'quit' || raw === '.exit') {
337
- console.log(dim('bye'));
338
- rl.close();
339
- await db.close();
340
- process.exit(0);
341
- }
342
-
343
- const match = raw.match(/^(\w+)\s*\((.*)?\)$/s);
344
- if (!match) {
345
- console.log(red('Syntax error') + dim(' — try: remember("…") or recall("…")'));
346
- rl.prompt();
347
- return;
348
- }
349
-
350
- const [, fn, argsRaw] = match;
351
- const strArg = (s => {
352
- const m = (s || '').trim().match(/^["'`]([\s\S]*)["'`]$/);
353
- return m ? m[1] : null;
354
- })(argsRaw);
355
-
356
- try {
357
- let result;
358
- switch (fn) {
359
- case 'remember':
360
- if (strArg === null) throw new Error('remember() expects a string');
361
- result = await db.remember(strArg);
362
- console.log(green('←') + ' ' + JSON.stringify(result));
363
- break;
364
- case 'recall':
365
- if (strArg === null) throw new Error('recall() expects a string');
366
- result = await db.recall(strArg);
367
- console.log(green('←') + ' ' + (result === null ? dim('null') : JSON.stringify(result)));
368
- break;
369
- case 'list':
370
- result = await db.list();
371
- if (!result.length) console.log(dim('[]'));
372
- else result.forEach(m => console.log(` ${cyan(`#${m.id}`)} ${m.content}`));
373
- break;
374
- case 'clear':
375
- result = await db.clear();
376
- console.log(green('←') + ' ' + JSON.stringify(result));
377
- break;
378
- case 'stats':
379
- result = await db.stats();
380
- console.log(green('←') + ' ' + JSON.stringify(result, null, 2));
381
- break;
382
- case 'audit':
383
- result = await db.audit();
384
- if (!result.length) console.log(dim('[]'));
385
- else result.forEach(e => console.log(' ' + JSON.stringify(e)));
386
- break;
387
- default:
388
- console.log(red(`Unknown: db.${fn}`));
389
- }
390
- } catch (err) {
391
- console.log(red('Error: ') + err.message);
392
- }
393
-
394
- rl.prompt();
395
- });
396
-
397
- rl.on('close', async () => {
398
- await db.close();
399
- process.exit(0);
400
- });
401
- }
402
-
403
- main().catch(err => {
404
- console.error(err.message);
405
- process.exit(1);
406
- });
2
+ "use strict";require("path");const e=require("readline"),{Mumpix:o}=require("../src/index"),{loadAuthState:t,clearAuthState:n,upsertStoredLicense:s,exchangeTokenForLicense:c,loginWithDeviceFlow:l,authStatePath:r,configDir:i}=require("../src/core/auth"),{LicenseManager:a}=require("../src/core/license"),g='\nmumpix \u2014 SQLite for AI\n\nUsage:\n mumpix <command> <file> [args...]\n\nCommands:\n remember <file> "<text>" Store a memory\n recall <file> "<query>" Recall the best match\n search <file> "<query>" [k] Recall top-k matches\n list <file> List all memories\n clear <file> Clear all memories\n stats <file> Show database stats\n audit <file> Show audit log (verified mode)\n shell <file> Start interactive REPL\n auth <subcommand> Account login/logout/status\n help Show this message\n\nOptions (append to any command):\n --consistency=eventual|strict|verified (default: eventual)\n\nExamples:\n mumpix remember ./agent.mumpix "User prefers TypeScript"\n mumpix recall ./agent.mumpix "what language?" --consistency=strict\n mumpix search ./agent.mumpix "TypeScript" 3\n mumpix shell ./agent.mumpix --consistency=verified\n mumpix auth status\n mumpix auth device-id\n mumpix auth login --token=<account-token>\n mumpix auth login --license=<signed-license-key>\n'.trim();function u(e,o){return process.stdout.isTTY?`\x1b[${o}m${e}\x1b[0m`:e}const m=e=>u(e,"2"),p=e=>u(e,"36"),d=e=>u(e,"32"),h=e=>u(e,"33"),$=e=>u(e,"31"),f=e=>u(e,"1");function y(e){if(!e)return"-";const o=new Date(Number(e));return Number.isNaN(o.getTime())?"-":o.toISOString()}async function x(e,o){const g=String(e[0]||"status").toLowerCase();if("status"===g){const e=t();return e&&e.license&&e.license.key?(console.log(f("Mumpix auth status")),console.log(` account_id: ${e.account&&e.account.id?e.account.id:"-"}`),console.log(` tier: ${e.license.tier||e.account&&e.account.tier||"-"}`),console.log(` issued_at: ${y(e.license.iat)}`),console.log(` expires_at: ${y(e.license.exp)}`),console.log(` license: ${d(function(e,o=6){const t=String(e||"");return t.length<=o?t:`${t.slice(0,o)}\u2026`}(e.license.key,18))}`),void console.log(` state: ${r()}`)):(console.log(m("Not logged in.")),void console.log(m(`Config dir: ${i()}`)))}if("logout"===g)return n(),void console.log(d("\u2713")+" Logged out. Local license removed.");if("device-id"===g||"device"===g||"fingerprint"===g){const e=new a,o=await e.deviceIdentityInfo();return console.log(f("Mumpix device identity")),console.log(` algorithm: ${o.algorithm}`),console.log(` fingerprint: ${d(o.publicKeyFingerprint)}`),console.log(` public_key: ${o.publicKeyB64}`),void console.log(` state: ${o.path}`)}if("login"===g){const e=o.license||o["license-key"]||null;if(e){const o=s(String(e));return console.log(d("\u2713")+" License saved."),console.log(` tier: ${o.license.tier||"-"}`),console.log(` expires_at: ${y(o.license.exp)}`),void console.log(` state: ${r()}`)}const t=o.token||process.env.MUMPIX_AUTH_TOKEN||"";if(t){const e=await c(String(t).trim(),{});return console.log(d("\u2713")+" Account linked and license saved."),console.log(` account_id: ${e.account.id||"-"}`),console.log(` tier: ${e.license.tier||e.account.tier||"-"}`),console.log(` expires_at: ${y(e.license.exp)}`),void console.log(` state: ${r()}`)}const n=await l({onPrompt:({userCode:e,verifyUrl:o,expiresInSec:t,intervalSec:n})=>{console.log(f("Mumpix device login")),console.log(` 1) Open: ${o}`),console.log(` 2) Enter code: ${p(e)}`),console.log(` 3) Waiting for approval... (expires in ${t}s, polling ${n}s)`)}});return console.log(d("\u2713")+" Account linked and license saved."),console.log(` account_id: ${n.account.id||"-"}`),console.log(` tier: ${n.license.tier||n.account.tier||"-"}`),console.log(` expires_at: ${y(n.license.exp)}`),void console.log(` state: ${r()}`)}console.error($(`Unknown auth subcommand: ${g}`)),console.log("Usage: mumpix auth <status|login|logout|device-id> [--token=...] [--license=...]"),process.exit(1)}(async function(){const{args:t,flags:n}=function(e){const o=[],t={};for(const n of e)if(n.startsWith("--")){const[e,o]=n.slice(2).split("=");t[e]=void 0===o||o}else o.push(n);return{args:o,flags:t}}(process.argv.slice(2)),[s,c,...l]=t;if(s&&"help"!==s&&"--help"!==s&&"-h"!==s||(console.log(g),process.exit(0)),"auth"===s)return void await x([c,...l],n);const r=c;r||"help"===s||(console.error($("Error: file path required")),console.log(g),process.exit(1));const i=n.consistency||"eventual";let a;try{a=await o.open(r,{consistency:i})}catch(e){console.error($(`Error opening ${r}: ${e.message}`)),process.exit(1)}try{switch(s){case"remember":{const e=l.join(" ").replace(/^["']|["']$/g,"");e||(console.error($("Error: provide text to remember")),process.exit(1));const o=await a.remember(e);console.log(d("\u2713")+` Stored as #${o.id} (${o.consistency})`);break}case"recall":{const e=l.join(" ").replace(/^["']|["']$/g,"");e||(console.error($("Error: provide a query")),process.exit(1));const o=await a.recall(e);null===o?console.log(m("No memories found.")):console.log(d("\u2192")+" "+o);break}case"search":{const e=parseInt(l[l.length-1],10),o=Number.isInteger(e)&&e>0?e:5,t=(Number.isInteger(e)?l.slice(0,-1):l).join(" ").replace(/^["']|["']$/g,"");t||(console.error($("Error: provide a query")),process.exit(1));const n=await a.recallMany(t,o);n.length?n.forEach((e,o)=>{const t=void 0!==e.score?m(` (${(100*e.score).toFixed(1)}%)`):"";console.log(`${p(`#${e.id}`)} ${e.content}${t}`)}):console.log(m("No memories found."));break}case"list":{const e=await a.list();e.length?(e.forEach(e=>{const o=new Date(e.ts).toLocaleString();console.log(`${p(`#${e.id}`)} ${e.content} ${m(o)}`)}),console.log(m(`\n${e.length} total`))):console.log(m("No memories stored."));break}case"clear":{const{count:e}=await a.clear();console.log(h("\u26a0")+` Cleared ${e} ${1===e?"memory":"memories"}`);break}case"stats":{const e=await a.stats();console.log(f("Mumpix stats")),console.log(` path: ${e.path}`),console.log(` consistency: ${p(e.consistency)}`),console.log(` records: ${e.records}`),console.log(` size: ${(e.sizeBytes/1024).toFixed(2)} KB`),console.log(` created: ${new Date(e.created).toLocaleString()}`),console.log(` version: v${e.version}`);break}case"audit":{let e;try{e=await a.audit()}catch(e){console.error($("Error: ")+e.message),process.exit(1)}e.length?(e.forEach(e=>{const o=new Date(e.ts).toISOString(),t=e._type.padEnd(12),n="write"===e._type?`id=${e.id} hash=${e.hash}`:"recall"===e._type?`queryHash=${e.queryHash} resultId=${e.resultId??"null"} latency=${e.latencyMs}ms`:"clear"===e._type?`count=${e.count}`:"";console.log(`${m(o)} ${h(t)} ${n}`)}),console.log(m(`\n${e.length} entries`))):console.log(m("Audit log is empty."));break}case"shell":await async function(o,t,n){const s=e.createInterface({input:process.stdin,output:process.stdout,prompt:p("mumpix")+m(" \u203a "),historySize:100});console.log(f("Mumpix interactive shell")),console.log(m(` file: ${t} consistency: ${n}`)),console.log(m(' Commands: remember("\u2026"), recall("\u2026"), list(), clear(), stats(), audit(), exit\n')),s.prompt(),s.on("line",async e=>{const t=e.trim();if(!t)return void s.prompt();"exit"!==t&&"quit"!==t&&".exit"!==t||(console.log(m("bye")),s.close(),await o.close(),process.exit(0));const n=t.match(/^(\w+)\s*\((.*)?\)$/s);if(!n)return console.log($("Syntax error")+m(' \u2014 try: remember("\u2026") or recall("\u2026")')),void s.prompt();const[,c,l]=n,r=(e=>{const o=(e||"").trim().match(/^["'`]([\s\S]*)["'`]$/);return o?o[1]:null})(l);try{let e;switch(c){case"remember":if(null===r)throw new Error("remember() expects a string");e=await o.remember(r),console.log(d("\u2190")+" "+JSON.stringify(e));break;case"recall":if(null===r)throw new Error("recall() expects a string");e=await o.recall(r),console.log(d("\u2190")+" "+(null===e?m("null"):JSON.stringify(e)));break;case"list":e=await o.list(),e.length?e.forEach(e=>console.log(` ${p(`#${e.id}`)} ${e.content}`)):console.log(m("[]"));break;case"clear":e=await o.clear(),console.log(d("\u2190")+" "+JSON.stringify(e));break;case"stats":e=await o.stats(),console.log(d("\u2190")+" "+JSON.stringify(e,null,2));break;case"audit":e=await o.audit(),e.length?e.forEach(e=>console.log(" "+JSON.stringify(e))):console.log(m("[]"));break;default:console.log($(`Unknown: db.${c}`))}}catch(e){console.log($("Error: ")+e.message)}s.prompt()}),s.on("close",async()=>{await o.close(),process.exit(0)})}(a,r,i);break;default:console.error($(`Unknown command: ${s}`)),console.log(g),process.exit(1)}}finally{"shell"!==s&&await a.close()}})().catch(e=>{console.error(e.message),process.exit(1)});
@@ -17,7 +17,7 @@ const path = require('path');
17
17
  const DB_PATH = path.join(__dirname, 'agent-memory.mumpix');
18
18
 
19
19
  ;(async () => {
20
- const db = Mumpix.open(DB_PATH, { consistency: 'strict' });
20
+ const db = await Mumpix.open(DB_PATH, { consistency: 'eventual' });
21
21
  const { records } = await db.stats();
22
22
 
23
23
  if (records === 0) {
package/examples/basic.js CHANGED
@@ -13,7 +13,7 @@ const path = require('path');
13
13
 
14
14
  ;(async () => {
15
15
  const dbPath = path.join(os.tmpdir(), 'mumpix-basic-demo.mumpix');
16
- const db = Mumpix.open(dbPath, { consistency: 'strict' });
16
+ const db = await Mumpix.open(dbPath, { consistency: 'eventual' });
17
17
 
18
18
  // Store memories
19
19
  await db.remember('User prefers TypeScript over JavaScript');
@@ -0,0 +1,50 @@
1
+ 'use strict';
2
+
3
+ const { brp, rlp, collapse } = require('../src');
4
+
5
+ const gene = brp.normalizeBRP({
6
+ domain: 'browser',
7
+ trigger_signature: 'login page asks for workspace slug',
8
+ executable_payload: {
9
+ intent: 'DO',
10
+ sequence: [
11
+ { verb: 'input-text', args: { selector: '#workspace', value: 'acme' } },
12
+ { verb: 'click-element', args: { selector: 'button[type=submit]' } },
13
+ ],
14
+ },
15
+ });
16
+
17
+ const updated = brp.updateSplitConfidence(gene, {
18
+ triggerMatched: true,
19
+ sequenceExecuted: true,
20
+ breakEvenThreshold: 3,
21
+ });
22
+
23
+ const match = brp.twoStageMatch([updated], {
24
+ domain: 'browser',
25
+ text: 'workspace login form',
26
+ payload_type: 'DO',
27
+ });
28
+
29
+ const actionBoundary = rlp.validateActionBoundary(updated);
30
+
31
+ const economics = collapse.analyzeCollapse({
32
+ stages: [
33
+ { name: 'INDEX', token_cost: 200 },
34
+ { name: 'SCAN', token_cost: 2400 },
35
+ { name: 'DEBATE', token_cost: 7200 },
36
+ { name: 'EXECUTE', token_cost: 2050 },
37
+ ],
38
+ retrievalCost: 150,
39
+ promotionCost: 35550,
40
+ hits: 3,
41
+ });
42
+
43
+ console.log({
44
+ brp_id: updated.brp_id,
45
+ payload_type: updated.payload_type,
46
+ action_ok: actionBoundary.ok,
47
+ top_match: match[0] && match[0].brp.brp_id,
48
+ savings_per_hit: economics.savingsPerHit,
49
+ break_even_crossed: economics.breakEvenCrossed,
50
+ });
@@ -0,0 +1,156 @@
1
+ "use strict";
2
+
3
+ const fs = require("fs");
4
+ const os = require("os");
5
+ const path = require("path");
6
+ const { Mumpix } = require("../src/index");
7
+
8
+ const DEFAULT_BASE_URL = "http://127.0.0.1:11434/v1";
9
+ const DEFAULT_MODEL = "nomic-embed-text";
10
+
11
+ class OpenAIEmbeddingEmbedder {
12
+ constructor({ baseUrl, model, apiKey, dim }) {
13
+ this.baseUrl = baseUrl.replace(/\/+$/, "");
14
+ this.model = model;
15
+ this.apiKey = apiKey;
16
+ this.dim = dim;
17
+ this.id = `openai-compatible:${this.model}:dim${this.dim}`;
18
+ }
19
+
20
+ static async create() {
21
+ const baseUrl = process.env.MUMPIX_EMBED_BASE_URL || DEFAULT_BASE_URL;
22
+ const model = process.env.MUMPIX_EMBED_MODEL || DEFAULT_MODEL;
23
+ const apiKey = process.env.MUMPIX_EMBED_API_KEY || process.env.OPENAI_API_KEY || "";
24
+ const probe = new OpenAIEmbeddingEmbedder({ baseUrl, model, apiKey, dim: 1 });
25
+ const [vector] = await probe.embed(["dimension probe"]);
26
+ return new OpenAIEmbeddingEmbedder({
27
+ baseUrl,
28
+ model,
29
+ apiKey,
30
+ dim: vector.length,
31
+ });
32
+ }
33
+
34
+ async embed(texts) {
35
+ const response = await fetch(`${this.baseUrl}/embeddings`, {
36
+ method: "POST",
37
+ headers: {
38
+ "content-type": "application/json",
39
+ ...(this.apiKey ? { authorization: `Bearer ${this.apiKey}` } : {}),
40
+ },
41
+ body: JSON.stringify({
42
+ model: this.model,
43
+ input: texts,
44
+ }),
45
+ });
46
+
47
+ if (!response.ok) {
48
+ const body = await response.text().catch(() => "");
49
+ throw new Error(
50
+ `Embedding request failed (${response.status}) for ${this.baseUrl}/embeddings model ${this.model}: ${body}`
51
+ );
52
+ }
53
+
54
+ const json = await response.json();
55
+ if (!json || !Array.isArray(json.data) || json.data.length !== texts.length) {
56
+ throw new Error("Embedding response did not include one vector per input.");
57
+ }
58
+
59
+ return json.data
60
+ .sort((left, right) => left.index - right.index)
61
+ .map((item) => normalize(item.embedding));
62
+ }
63
+ }
64
+
65
+ function normalize(values) {
66
+ if (!Array.isArray(values) || values.length === 0) {
67
+ throw new Error("Embedding response included an invalid vector.");
68
+ }
69
+ const vector = Float32Array.from(values, Number);
70
+ const norm = Math.hypot(...vector);
71
+ if (!Number.isFinite(norm) || norm === 0) {
72
+ throw new Error("Embedding response included a zero or non-finite vector.");
73
+ }
74
+ for (let i = 0; i < vector.length; i += 1) vector[i] /= norm;
75
+ return vector;
76
+ }
77
+
78
+ const MEMORIES = [
79
+ "websocket upgrade requests bypass express middleware auth",
80
+ "the promotion gate blocked because the human review was missing",
81
+ "duration getters returned undefined for units absent from the input object",
82
+ "the stale lock file was removed and the store reopened after SIGKILL",
83
+ "route selection injected irrelevant genes and degraded a passing fix",
84
+ ];
85
+
86
+ const PARAPHRASES = [
87
+ "realtime socket connections skip the login check",
88
+ "promotion halted, approval signoff absent",
89
+ "timespan accessor gives null for fields not provided",
90
+ "store recovery after the process was killed",
91
+ "memory retrieval added noise that broke working code",
92
+ ];
93
+
94
+ function clean(filePath) {
95
+ for (const suffix of ["", ".wal", ".lock", ".idx", ".vectors.json", ".vectors.jsonl"]) {
96
+ fs.rmSync(`${filePath}${suffix}`, { force: true, recursive: true });
97
+ }
98
+ }
99
+
100
+ (async () => {
101
+ const embedder = await OpenAIEmbeddingEmbedder.create();
102
+ const semanticFloor = Number(process.env.MUMPIX_SEMANTIC_FLOOR || 0.5);
103
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), "mumpix-recall-quality-"));
104
+ const beforePath = path.join(dir, "before.mumpix");
105
+ const afterPath = path.join(dir, "after.mumpix");
106
+ clean(beforePath);
107
+ clean(afterPath);
108
+
109
+ console.log(`embedder: ${embedder.id}`);
110
+ console.log(`transport: ${embedder.baseUrl}`);
111
+ console.log(`semanticFloor: ${semanticFloor}`);
112
+
113
+ const before = await Mumpix.open(beforePath);
114
+ const after = await Mumpix.open(afterPath, {
115
+ recall: "semantic",
116
+ embedder,
117
+ semanticFloor,
118
+ });
119
+
120
+ try {
121
+ for (const memory of MEMORIES) {
122
+ await before.remember(memory);
123
+ await after.remember(memory);
124
+ }
125
+
126
+ let beforeHits = 0;
127
+ let afterHits = 0;
128
+ for (let i = 0; i < PARAPHRASES.length; i += 1) {
129
+ const query = PARAPHRASES[i];
130
+ const lexical = await before.recall(query);
131
+ const semantic = await after.recall(query);
132
+ const semanticOk = semantic === MEMORIES[i];
133
+ if (lexical) beforeHits += 1;
134
+ if (semanticOk) afterHits += 1;
135
+ console.log(`Q${i + 1}: ${query}`);
136
+ console.log(` before: ${lexical ? "HIT" : "null"}`);
137
+ console.log(` after: ${semanticOk ? "HIT" : semantic ? `WRONG: ${semantic}` : "null"}`);
138
+ }
139
+
140
+ const control = await after.recall("purple elephant tax return kazoo");
141
+ console.log(`control: ${control === null ? "null" : `FIRED: ${control}`}`);
142
+ console.log(`before: ${beforeHits}/5`);
143
+ console.log(`after: ${afterHits}/5`);
144
+ } finally {
145
+ await before.close();
146
+ await after.close();
147
+ fs.rmSync(dir, { force: true, recursive: true });
148
+ }
149
+ })().catch((err) => {
150
+ console.error(err && err.stack ? err.stack : err);
151
+ console.error("");
152
+ console.error("This recall quality suite requires a real OpenAI-compatible embedding endpoint.");
153
+ console.error(`Default local setup: ollama pull ${DEFAULT_MODEL}`);
154
+ console.error(`Then run: MUMPIX_EMBED_BASE_URL=${DEFAULT_BASE_URL} MUMPIX_EMBED_MODEL=${DEFAULT_MODEL} npm run bench:recall`);
155
+ process.exit(1);
156
+ });
@@ -27,7 +27,7 @@ const DB_PATH = path.join(os.tmpdir(), 'mumpix-verified-demo.mumpix');
27
27
  });
28
28
 
29
29
  console.log('Opening Mumpix in Verified mode...\n');
30
- const db = Mumpix.open(DB_PATH, { consistency: 'verified' });
30
+ const db = await Mumpix.open(DB_PATH, { consistency: 'verified' });
31
31
 
32
32
  // Simulate a compliance-relevant workflow
33
33
  await db.remember('Loan application #4821 approved — credit score: 742');