moflo 4.9.36 → 4.9.37
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/.claude/guidance/shipped/moflo-agent-rules.md +12 -0
- package/.claude/guidance/shipped/moflo-memory-protocol.md +30 -0
- package/.claude/guidance/shipped/moflo-subagents.md +4 -0
- package/.claude/helpers/gate.cjs +3 -3
- package/.claude/helpers/subagent-bootstrap.json +1 -1
- package/.claude/helpers/subagent-start.cjs +1 -1
- package/.claude/skills/eldar/SKILL.md +8 -0
- package/bin/gate.cjs +3 -3
- package/bin/index-guidance.mjs +41 -52
- package/bin/migrations/purge-doc-entries.mjs +53 -0
- package/bin/migrations/strip-context-preambles.mjs +97 -0
- package/bin/semantic-search.mjs +4 -1
- package/bin/session-start-launcher.mjs +2 -0
- package/dist/src/cli/commands/doctor-checks-memory-access.js +179 -0
- package/dist/src/cli/commands/memory.js +41 -52
- package/dist/src/cli/init/claudemd-generator.js +4 -0
- package/dist/src/cli/mcp-tools/memory-tools.js +169 -31
- package/dist/src/cli/memory/bridge-entries.js +6 -2
- package/dist/src/cli/memory/memory-initializer.js +17 -11
- package/dist/src/cli/services/subagent-bootstrap.js +1 -1
- package/dist/src/cli/version.js +1 -1
- package/package.json +2 -2
|
@@ -403,7 +403,7 @@ export async function bridgeSearchEntries(options) {
|
|
|
403
403
|
let rows;
|
|
404
404
|
try {
|
|
405
405
|
const sql = `
|
|
406
|
-
SELECT id, key, namespace, content, embedding
|
|
406
|
+
SELECT id, key, namespace, content, metadata, embedding
|
|
407
407
|
FROM memory_entries
|
|
408
408
|
WHERE status = 'active' ${nsFilter}
|
|
409
409
|
LIMIT 1000
|
|
@@ -459,6 +459,7 @@ export async function bridgeSearchEntries(options) {
|
|
|
459
459
|
const provenance = usedSemantic
|
|
460
460
|
? `semantic:${semanticScore.toFixed(3)}+bm25:${bm25ScoreVal.toFixed(3)}`
|
|
461
461
|
: `bm25:${bm25ScoreVal.toFixed(3)}`;
|
|
462
|
+
const metadataStr = row.metadata != null ? String(row.metadata) : undefined;
|
|
462
463
|
results.push({
|
|
463
464
|
id: String(row.id).substring(0, 12),
|
|
464
465
|
// The substring is a fallback id-prefix when key is missing —
|
|
@@ -468,6 +469,7 @@ export async function bridgeSearchEntries(options) {
|
|
|
468
469
|
score,
|
|
469
470
|
namespace: String(row.namespace || 'default'),
|
|
470
471
|
provenance,
|
|
472
|
+
metadata: metadataStr,
|
|
471
473
|
});
|
|
472
474
|
}
|
|
473
475
|
}
|
|
@@ -542,13 +544,14 @@ export async function bridgeGetEntry(options) {
|
|
|
542
544
|
updatedAt: cached.updatedAt || new Date().toISOString(),
|
|
543
545
|
hasEmbedding: !!cached.embedding,
|
|
544
546
|
tags: cached.tags || [],
|
|
547
|
+
metadata: cached.metadata || undefined,
|
|
545
548
|
},
|
|
546
549
|
};
|
|
547
550
|
}
|
|
548
551
|
let row;
|
|
549
552
|
try {
|
|
550
553
|
const stmt = ctx.db.prepare(`
|
|
551
|
-
SELECT id, key, namespace, content, embedding, access_count, created_at, updated_at, tags
|
|
554
|
+
SELECT id, key, namespace, content, embedding, access_count, created_at, updated_at, tags, metadata
|
|
552
555
|
FROM memory_entries
|
|
553
556
|
WHERE status = 'active' AND key = ? AND namespace = ?
|
|
554
557
|
LIMIT 1
|
|
@@ -591,6 +594,7 @@ export async function bridgeGetEntry(options) {
|
|
|
591
594
|
updatedAt: row.updated_at || new Date().toISOString(),
|
|
592
595
|
hasEmbedding: !!(row.embedding && String(row.embedding).length > 10),
|
|
593
596
|
tags,
|
|
597
|
+
metadata: row.metadata != null ? String(row.metadata) : undefined,
|
|
594
598
|
};
|
|
595
599
|
await cacheSet(registry, cacheKey, entry);
|
|
596
600
|
return { success: true, found: true, cacheHit: false, entry };
|
|
@@ -424,8 +424,8 @@ export async function getHNSWIndex(options) {
|
|
|
424
424
|
// adjacency. When the sidecar IS loaded we skip the per-row JSON.parse
|
|
425
425
|
// of the embedding column, which is the expensive part on a populated
|
|
426
426
|
// consumer DB.
|
|
427
|
-
const SELECT_WITH_EMBEDDING = `id, key, namespace, content, embedding`;
|
|
428
|
-
const SELECT_METADATA_ONLY = `id, key, namespace, content`;
|
|
427
|
+
const SELECT_WITH_EMBEDDING = `id, key, namespace, content, metadata, embedding`;
|
|
428
|
+
const SELECT_METADATA_ONLY = `id, key, namespace, content, metadata`;
|
|
429
429
|
if (fs.existsSync(dbPath)) {
|
|
430
430
|
try {
|
|
431
431
|
const initSqlJs = (await mofloImport('sql.js')).default;
|
|
@@ -442,7 +442,9 @@ export async function getHNSWIndex(options) {
|
|
|
442
442
|
let parseSkipped = 0;
|
|
443
443
|
if (result[0]?.values) {
|
|
444
444
|
for (const row of result[0].values) {
|
|
445
|
-
|
|
445
|
+
// Column order matches SELECT_WITH_EMBEDDING / SELECT_METADATA_ONLY.
|
|
446
|
+
// When sidecar is loaded, embeddingJson is undefined (column absent).
|
|
447
|
+
const [id, key, ns, content, metadataJson, embeddingJson] = row;
|
|
446
448
|
if (!sidecarLoaded) {
|
|
447
449
|
const vec = parseEmbeddingJson(embeddingJson);
|
|
448
450
|
if (!vec) {
|
|
@@ -455,7 +457,8 @@ export async function getHNSWIndex(options) {
|
|
|
455
457
|
id: String(id),
|
|
456
458
|
key: key || String(id),
|
|
457
459
|
namespace: ns || 'default',
|
|
458
|
-
content: content || ''
|
|
460
|
+
content: content || '',
|
|
461
|
+
metadata: metadataJson || undefined
|
|
459
462
|
});
|
|
460
463
|
}
|
|
461
464
|
}
|
|
@@ -545,7 +548,8 @@ export async function searchHNSWIndex(queryEmbedding, options) {
|
|
|
545
548
|
key: entry.key || entry.id.substring(0, 15),
|
|
546
549
|
content: entry.content.substring(0, 60) + (entry.content.length > 60 ? '...' : ''),
|
|
547
550
|
score,
|
|
548
|
-
namespace: entry.namespace
|
|
551
|
+
namespace: entry.namespace,
|
|
552
|
+
metadata: entry.metadata
|
|
549
553
|
});
|
|
550
554
|
if (filtered.length >= k)
|
|
551
555
|
break;
|
|
@@ -1817,7 +1821,7 @@ export async function searchEntries(options) {
|
|
|
1817
1821
|
const db = new SQL.Database(fileBuffer);
|
|
1818
1822
|
// Get entries with embeddings
|
|
1819
1823
|
const entries = db.exec(`
|
|
1820
|
-
SELECT id, key, namespace, content, embedding
|
|
1824
|
+
SELECT id, key, namespace, content, metadata, embedding
|
|
1821
1825
|
FROM memory_entries
|
|
1822
1826
|
WHERE status = 'active'
|
|
1823
1827
|
${namespace !== 'all' ? `AND namespace = '${namespace.replace(/'/g, "''")}'` : ''}
|
|
@@ -1826,7 +1830,7 @@ export async function searchEntries(options) {
|
|
|
1826
1830
|
const results = [];
|
|
1827
1831
|
if (entries[0]?.values) {
|
|
1828
1832
|
for (const row of entries[0].values) {
|
|
1829
|
-
const [id, key, ns, content, embeddingJson] = row;
|
|
1833
|
+
const [id, key, ns, content, metadataJson, embeddingJson] = row;
|
|
1830
1834
|
let score = 0;
|
|
1831
1835
|
if (embeddingJson) {
|
|
1832
1836
|
try {
|
|
@@ -1849,7 +1853,8 @@ export async function searchEntries(options) {
|
|
|
1849
1853
|
key: key || id.substring(0, 15),
|
|
1850
1854
|
content: (content || '').substring(0, 60) + ((content || '').length > 60 ? '...' : ''),
|
|
1851
1855
|
score,
|
|
1852
|
-
namespace: ns || 'default'
|
|
1856
|
+
namespace: ns || 'default',
|
|
1857
|
+
metadata: metadataJson || undefined
|
|
1853
1858
|
});
|
|
1854
1859
|
}
|
|
1855
1860
|
}
|
|
@@ -1987,7 +1992,7 @@ export async function getEntry(options) {
|
|
|
1987
1992
|
const db = new SQL.Database(fileBuffer);
|
|
1988
1993
|
// Find entry by key
|
|
1989
1994
|
const result = db.exec(`
|
|
1990
|
-
SELECT id, key, namespace, content, embedding, access_count, created_at, updated_at, tags
|
|
1995
|
+
SELECT id, key, namespace, content, embedding, access_count, created_at, updated_at, tags, metadata
|
|
1991
1996
|
FROM memory_entries
|
|
1992
1997
|
WHERE status = 'active'
|
|
1993
1998
|
AND key = '${key.replace(/'/g, "''")}'
|
|
@@ -1998,7 +2003,7 @@ export async function getEntry(options) {
|
|
|
1998
2003
|
db.close();
|
|
1999
2004
|
return { success: true, found: false };
|
|
2000
2005
|
}
|
|
2001
|
-
const [id, entryKey, ns, content, embedding, accessCount, createdAt, updatedAt, tagsJson] = result[0].values[0];
|
|
2006
|
+
const [id, entryKey, ns, content, embedding, accessCount, createdAt, updatedAt, tagsJson, metadataJson] = result[0].values[0];
|
|
2002
2007
|
// Update access count
|
|
2003
2008
|
db.run(`
|
|
2004
2009
|
UPDATE memory_entries
|
|
@@ -2028,7 +2033,8 @@ export async function getEntry(options) {
|
|
|
2028
2033
|
createdAt: createdAt || new Date().toISOString(),
|
|
2029
2034
|
updatedAt: updatedAt || new Date().toISOString(),
|
|
2030
2035
|
hasEmbedding: !!embedding && embedding.length > 10,
|
|
2031
|
-
tags
|
|
2036
|
+
tags,
|
|
2037
|
+
metadata: metadataJson || undefined
|
|
2032
2038
|
}
|
|
2033
2039
|
};
|
|
2034
2040
|
}
|
|
@@ -21,7 +21,7 @@ const BOOTSTRAP_JSON_REL = '.claude/helpers/subagent-bootstrap.json';
|
|
|
21
21
|
// Defense-in-depth copy of the canonical directive in subagent-bootstrap.json.
|
|
22
22
|
// Kept as a single-line literal so the parity test can verify it matches the
|
|
23
23
|
// JSON via plain substring containment.
|
|
24
|
-
const FALLBACK_DIRECTIVE = 'MANDATORY FIRST ACTION: Your very first tool call MUST be mcp__moflo__memory_search (any query, any namespace). The memory-first gate WILL BLOCK all Glob, Grep, and Read calls until you do this. After memory search, follow `.claude/guidance/moflo-subagents.md` protocol.';
|
|
24
|
+
const FALLBACK_DIRECTIVE = 'MANDATORY FIRST ACTION: Your very first tool call MUST be mcp__moflo__memory_search (any query, any namespace). The memory-first gate WILL BLOCK all Glob, Grep, and Read calls until you do this. After memory search, follow `.claude/guidance/moflo-subagents.md` protocol. When search returns chunk hits, traverse via mcp__moflo__memory_get_neighbors before retrieving — see `.claude/guidance/moflo-memory-protocol.md`.';
|
|
25
25
|
function loadDirective() {
|
|
26
26
|
const jsonPath = locateMofloRootPath(BOOTSTRAP_JSON_REL);
|
|
27
27
|
if (!jsonPath) {
|
package/dist/src/cli/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "moflo",
|
|
3
|
-
"version": "4.9.
|
|
3
|
+
"version": "4.9.37",
|
|
4
4
|
"description": "MoFlo — AI agent orchestration for Claude Code. A standalone, opinionated toolkit with semantic memory, learned routing, gates, spells, and the /flo issue-execution skill.",
|
|
5
5
|
"main": "dist/src/cli/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -97,7 +97,7 @@
|
|
|
97
97
|
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
|
98
98
|
"@typescript-eslint/parser": "^7.18.0",
|
|
99
99
|
"eslint": "^8.0.0",
|
|
100
|
-
"moflo": "^4.9.
|
|
100
|
+
"moflo": "^4.9.36",
|
|
101
101
|
"tsx": "^4.21.0",
|
|
102
102
|
"typescript": "^5.9.3",
|
|
103
103
|
"vitest": "^4.0.0"
|