monomind 2.3.0 → 2.3.1
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/package.json +1 -1
- package/packages/@monomind/cli/.claude/helpers/handlers/route-handler.cjs +6 -1
- package/packages/@monomind/cli/.claude/skills/mastermind-skills/taskdev.md +2 -0
- package/packages/@monomind/cli/dist/src/commands/cleanup.js +1 -0
- package/packages/@monomind/cli/dist/src/memory/memory-bridge.js +65 -27
- package/packages/@monomind/cli/package.json +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "monomind",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.1",
|
|
4
4
|
"description": "Open-source CLI extension for Claude Code. Adds an MCP server with a codebase knowledge graph, persistent memory, multi-agent coordination, and reusable slash commands. MIT licensed, runs locally, no data leaves your machine.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -358,7 +358,12 @@ module.exports = {
|
|
|
358
358
|
if (fs.existsSync(secAuditFile) && fs.statSync(secAuditFile).size < 32768) {
|
|
359
359
|
var secData = JSON.parse(fs.readFileSync(secAuditFile, 'utf-8'));
|
|
360
360
|
if (secData && secData.findings && secData.findings.length > 0) {
|
|
361
|
-
|
|
361
|
+
var serious = secData.findings.filter(function (f) { return f && (f.severity === 'high' || f.severity === 'medium'); });
|
|
362
|
+
if (serious.length > 0) {
|
|
363
|
+
console.log('[SECURITY] ' + serious.length + ' finding(s) from background scan. Review .monomind/metrics/security-audit.json');
|
|
364
|
+
} else {
|
|
365
|
+
console.log('[AUDIT] ' + secData.findings.length + ' low-severity note(s) (architecture heuristics, not vulnerabilities) — .monomind/metrics/security-audit.json');
|
|
366
|
+
}
|
|
362
367
|
}
|
|
363
368
|
}
|
|
364
369
|
// Codebase map top files (high-centrality god nodes from monograph)
|
|
@@ -157,6 +157,8 @@ Implementer subagents report one of four statuses. Handle each appropriately:
|
|
|
157
157
|
|
|
158
158
|
**Never** ignore an escalation or force the same model to retry without changes. If the implementer said it's stuck, something needs to change.
|
|
159
159
|
|
|
160
|
+
**Async dispatches:** reviewer and implementer subagents may complete asynchronously even when dispatched synchronously. Wait for each result before acting on it — never proceed to the next gate, and never touch the files a dispatched subagent is working on, while its result is pending.
|
|
161
|
+
|
|
160
162
|
---
|
|
161
163
|
|
|
162
164
|
## Handling Reviewer ⚠️ Items
|
|
@@ -30,6 +30,7 @@ const KEEP_CONFIG_PATHS = [
|
|
|
30
30
|
join('.claude', 'settings.json'),
|
|
31
31
|
];
|
|
32
32
|
/** Scratch pruning (--scratch): taskdev handoff files and loop state. */
|
|
33
|
+
// monolean: manual flag only — upgrade path: invoke from the `cache` background worker so crashed-run scratch is pruned without anyone remembering the flag
|
|
33
34
|
const SCRATCH_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000; // taskdev scratch older than this is stale
|
|
34
35
|
const LOOP_STALE_GRACE_MS = 24 * 60 * 60 * 1000; // a live loop reschedules every <=1h; overdue by a day = abandoned
|
|
35
36
|
/**
|
|
@@ -121,6 +121,15 @@ let bridgeAvailable = null;
|
|
|
121
121
|
let _embedder = null;
|
|
122
122
|
const MAX_INIT_ATTEMPTS = 3;
|
|
123
123
|
let initAttempts = 0;
|
|
124
|
+
/** Flush after mutations: the sql.js fallback backend is in-memory WASM and
|
|
125
|
+
* only reaches disk via persist(); the CLI process is short-lived, so waiting
|
|
126
|
+
* for an auto-persist interval would lose writes. No-op on better-sqlite3. */
|
|
127
|
+
async function flushBackend(backend) {
|
|
128
|
+
try {
|
|
129
|
+
await backend?.persist?.();
|
|
130
|
+
}
|
|
131
|
+
catch { /* best effort */ }
|
|
132
|
+
}
|
|
124
133
|
async function getBackend(dbPath) {
|
|
125
134
|
if (bridgeAvailable === false)
|
|
126
135
|
return null;
|
|
@@ -134,7 +143,6 @@ async function getBackend(dbPath) {
|
|
|
134
143
|
backendPromise = (async () => {
|
|
135
144
|
try {
|
|
136
145
|
const mod = await import('@monoes/memory');
|
|
137
|
-
const { LanceDBBackend } = mod;
|
|
138
146
|
// Try to create embedding generator from HuggingFace transformers
|
|
139
147
|
let embeddingGenerator;
|
|
140
148
|
try {
|
|
@@ -152,26 +160,39 @@ async function getBackend(dbPath) {
|
|
|
152
160
|
if (process.env.DEBUG || process.env.MONOMIND_DEBUG)
|
|
153
161
|
console.error('[memory-bridge] embedding model failed to load — store and search without vectors:', e);
|
|
154
162
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
163
|
+
// Local SQLite engine (LanceDB replaced 2026-07): better-sqlite3 when its
|
|
164
|
+
// native binding loads, sql.js (pure WASM) otherwise — both persist text
|
|
165
|
+
// AND embeddings, so vectors are always recomputable/derivable data.
|
|
166
|
+
// getDbPath keeps its traversal guard and directory semantics; the SQLite
|
|
167
|
+
// file lives inside that directory.
|
|
168
|
+
const dir = getDbPath(dbPath);
|
|
169
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
170
|
+
const cfg = {
|
|
171
|
+
databasePath: path.join(dir, 'memory.db'),
|
|
172
|
+
walMode: true,
|
|
173
|
+
optimize: true,
|
|
174
|
+
defaultNamespace: 'default',
|
|
162
175
|
embeddingGenerator,
|
|
163
|
-
|
|
164
|
-
nProbes: 20,
|
|
165
|
-
});
|
|
176
|
+
};
|
|
166
177
|
const origLog = console.log;
|
|
167
178
|
console.log = (...args) => {
|
|
168
179
|
const msg = String(args[0] ?? '');
|
|
169
|
-
if (msg.includes('Transformers.js') || msg.includes('
|
|
180
|
+
if (msg.includes('Transformers.js') || msg.includes('Loading model'))
|
|
170
181
|
return;
|
|
171
182
|
origLog.apply(console, args);
|
|
172
183
|
};
|
|
184
|
+
let backend;
|
|
173
185
|
try {
|
|
174
|
-
|
|
186
|
+
try {
|
|
187
|
+
backend = new mod.SQLiteBackend(cfg);
|
|
188
|
+
await backend.initialize();
|
|
189
|
+
}
|
|
190
|
+
catch (e) {
|
|
191
|
+
if (process.env.DEBUG || process.env.MONOMIND_DEBUG)
|
|
192
|
+
console.error('[memory-bridge] better-sqlite3 unavailable — using sql.js backend:', e);
|
|
193
|
+
backend = new mod.SqlJsBackend(cfg);
|
|
194
|
+
await backend.initialize();
|
|
195
|
+
}
|
|
175
196
|
}
|
|
176
197
|
finally {
|
|
177
198
|
console.log = origLog;
|
|
@@ -256,6 +277,7 @@ export async function bridgeStoreEntry(options) {
|
|
|
256
277
|
catch { /* non-fatal — store anyway */ }
|
|
257
278
|
}
|
|
258
279
|
await backend.store(entry);
|
|
280
|
+
await flushBackend(backend);
|
|
259
281
|
return { success: true, id, embedding: embeddingInfo };
|
|
260
282
|
}
|
|
261
283
|
catch (err) {
|
|
@@ -302,20 +324,31 @@ export async function bridgeSearchEntries(options) {
|
|
|
302
324
|
namespace: namespace ?? 'default',
|
|
303
325
|
limit: 50000,
|
|
304
326
|
});
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
327
|
+
// Token-based matching, not whole-phrase substring: "semantic test" must
|
|
328
|
+
// match an entry keyed "semantic-test" (the old .includes(query) required
|
|
329
|
+
// the exact phrase — including its whitespace — to appear verbatim).
|
|
330
|
+
// Score = fraction of query tokens present in key+content.
|
|
331
|
+
const tokens = queryStr.toLowerCase().split(/[^a-z0-9]+/).filter(t => t.length > 1);
|
|
332
|
+
if (tokens.length) {
|
|
333
|
+
results = entries
|
|
334
|
+
.map((e) => {
|
|
335
|
+
const haystack = `${e.key || ''} ${e.content || ''}`.toLowerCase();
|
|
336
|
+
const hits = tokens.filter(t => haystack.includes(t)).length;
|
|
337
|
+
return { e, score: hits / tokens.length };
|
|
338
|
+
})
|
|
339
|
+
.filter((x) => x.score > 0)
|
|
340
|
+
.sort((a, b) => b.score - a.score)
|
|
341
|
+
.slice(0, limit)
|
|
342
|
+
.map(({ e, score }) => ({
|
|
343
|
+
id: e.id,
|
|
344
|
+
key: e.key,
|
|
345
|
+
content: e.content || '',
|
|
346
|
+
score: Math.min(0.9, 0.3 + score * 0.6),
|
|
347
|
+
namespace: e.namespace,
|
|
348
|
+
provenance: `keyword:${score.toFixed(2)}`,
|
|
349
|
+
_createdAt: e.createdAt || 0,
|
|
350
|
+
}));
|
|
351
|
+
}
|
|
319
352
|
searchMethod = 'keyword';
|
|
320
353
|
}
|
|
321
354
|
// Filter stale entries based on automem config — skip for knowledge
|
|
@@ -413,6 +446,8 @@ export async function bridgeDeleteEntry(options) {
|
|
|
413
446
|
if (entry)
|
|
414
447
|
deleted = await backend.delete(entry.id);
|
|
415
448
|
}
|
|
449
|
+
if (deleted)
|
|
450
|
+
await flushBackend(backend);
|
|
416
451
|
return { success: true, deleted };
|
|
417
452
|
}
|
|
418
453
|
catch {
|
|
@@ -667,6 +702,7 @@ export async function bridgeSessionEnd(options) {
|
|
|
667
702
|
}),
|
|
668
703
|
tags: ['session', 'ended'],
|
|
669
704
|
});
|
|
705
|
+
await flushBackend(backend);
|
|
670
706
|
}
|
|
671
707
|
return { success: true };
|
|
672
708
|
}
|
|
@@ -758,6 +794,8 @@ export async function bridgeConsolidate(params) {
|
|
|
758
794
|
deleted++;
|
|
759
795
|
}
|
|
760
796
|
}
|
|
797
|
+
if (deleted)
|
|
798
|
+
await flushBackend(backend);
|
|
761
799
|
return { success: true, consolidated: deleted };
|
|
762
800
|
}
|
|
763
801
|
catch {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@monoes/monomindcli",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "CLI engine for Monomind — an open-source MCP server that extends Claude Code with a codebase knowledge graph (tree-sitter + SQLite), persistent memory, multi-agent task coordination, and session hooks. MIT licensed, fully local.",
|
|
6
6
|
"main": "dist/src/index.js",
|
|
@@ -105,7 +105,7 @@
|
|
|
105
105
|
},
|
|
106
106
|
"optionalDependencies": {
|
|
107
107
|
"@huggingface/transformers": "^3.8.1",
|
|
108
|
-
"@monoes/memory": "^1.0.
|
|
108
|
+
"@monoes/memory": "^1.0.6",
|
|
109
109
|
"@monomind/hooks": "*",
|
|
110
110
|
"@monomind/mcp": "*",
|
|
111
111
|
"@monomind/routing": "*",
|