@claude-flow/cli 3.41.0 → 3.41.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/.claude/helpers/helpers.manifest.json +2 -2
- package/catalog-manifest.json +2 -2
- package/dist/src/commands/memory.js +11 -0
- package/dist/src/memory/memory-bridge.d.ts +4 -0
- package/dist/src/memory/memory-bridge.js +66 -14
- package/dist/src/memory/sibling-store.d.ts +11 -0
- package/dist/src/memory/sibling-store.js +53 -0
- package/node_modules/@claude-flow/codex/dist/cli.js +0 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/bin.js +0 -0
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"manifest": {
|
|
3
|
-
"version": "3.41.
|
|
3
|
+
"version": "3.41.1",
|
|
4
4
|
"files": {
|
|
5
5
|
"auto-memory-hook.mjs": "85fe05c757421c52137c0bc8545a0896bab6b4714538c2a11d1d0835bfcc8c1c",
|
|
6
6
|
"hook-handler.cjs": "209d9fafe10e17d1be0866727f6f9cf9ac66f9a0793f1c793a4f58319e8e4583",
|
|
@@ -8,6 +8,6 @@
|
|
|
8
8
|
"statusline.cjs": "4a48353b4f1566fa4379b00fd0321b6676a22b6cc91fbbd8380ac5183d619468"
|
|
9
9
|
}
|
|
10
10
|
},
|
|
11
|
-
"signature": "
|
|
11
|
+
"signature": "6JrRzvJx81mt9GZLoEwVmk8GNxDCaHMrR/8YywbD947dVkjWUFnTBCemqG1LKoRbfubrOlLr5i71BX3v8W98CQ==",
|
|
12
12
|
"algorithm": "ed25519"
|
|
13
13
|
}
|
package/catalog-manifest.json
CHANGED
|
@@ -7,6 +7,8 @@ import { select, confirm, input } from '../prompt.js';
|
|
|
7
7
|
import { callMCPTool, MCPClientError } from '../mcp-client.js';
|
|
8
8
|
import { distillCommand } from './memory-distill.js';
|
|
9
9
|
import { backupCommand } from './memory-backup.js';
|
|
10
|
+
import { countSiblingStoreRows } from '../memory/sibling-store.js';
|
|
11
|
+
import { resolveDbPath } from '../memory/memory-initializer.js';
|
|
10
12
|
// Memory backends
|
|
11
13
|
const BACKENDS = [
|
|
12
14
|
{ value: 'agentdb', label: 'AgentDB', hint: 'Vector database with HNSW indexing (150x-12,500x faster)' },
|
|
@@ -760,6 +762,15 @@ const listCommand = {
|
|
|
760
762
|
});
|
|
761
763
|
output.writeln();
|
|
762
764
|
output.printInfo(`Showing ${entries.length} of ${listResult.total} entries`);
|
|
765
|
+
// #3196: AgentDB owns a sibling store next to this one. `total` counts only
|
|
766
|
+
// the file we read, so a bare count reads as "this is everything" while rows
|
|
767
|
+
// sit unreadable next door. Silence would be recoverable; a confident wrong
|
|
768
|
+
// total is not, because nothing prompts anyone to look further.
|
|
769
|
+
const unread = await countSiblingStoreRows(resolveDbPath(ctx.flags.path));
|
|
770
|
+
if (unread && unread.rows > 0) {
|
|
771
|
+
output.printWarning(`${unread.rows} more entries are in ${unread.path} and were not read here. ` +
|
|
772
|
+
`That store is written by the MCP/AgentDB path; read it with --path ${unread.path}.`);
|
|
773
|
+
}
|
|
763
774
|
return { success: true, data: listResult.entries };
|
|
764
775
|
}
|
|
765
776
|
catch (error) {
|
|
@@ -34,6 +34,10 @@ export declare function shouldDisableNativeBridge(platform?: NodeJS.Platform, en
|
|
|
34
34
|
* noise. Suppress the banners, keep the bad news.
|
|
35
35
|
*/
|
|
36
36
|
export declare function shouldSuppressInitLog(msg: string): boolean;
|
|
37
|
+
/** Test seam: forget cached registries so a test can exercise a fresh open. */
|
|
38
|
+
export declare function _resetRegistryCacheForTest(): void;
|
|
39
|
+
/** #3196: the sibling store AgentDB owns next to a given sql.js database. */
|
|
40
|
+
export declare function siblingAgentDbPath(dbPath: string): string | null;
|
|
37
41
|
/**
|
|
38
42
|
* Create/migrate the bridge's `memory_entries` table on `db`.
|
|
39
43
|
*
|
|
@@ -19,9 +19,33 @@
|
|
|
19
19
|
import * as path from 'path';
|
|
20
20
|
import * as crypto from 'crypto';
|
|
21
21
|
import { createRequire } from 'node:module';
|
|
22
|
-
// ===== Lazy
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
// ===== Lazy registry cache, keyed by database path =====
|
|
23
|
+
/**
|
|
24
|
+
* #3196: this cache is keyed by resolved database path, and that is the whole
|
|
25
|
+
* point of it.
|
|
26
|
+
*
|
|
27
|
+
* It used to be a single global instance. The first caller to touch the bridge
|
|
28
|
+
* decided which file the process would use, and every later caller's explicit
|
|
29
|
+
* `dbPath` was accepted and then silently ignored — `getRegistry()` returned the
|
|
30
|
+
* already-built instance without ever comparing paths. A `memory store --path A`
|
|
31
|
+
* following an MCP write therefore read and wrote B, reported success, and left
|
|
32
|
+
* two valid corpora that neither interface could see whole.
|
|
33
|
+
*
|
|
34
|
+
* Keying by path makes an explicit path mean what it says. Two paths in one
|
|
35
|
+
* process are two registries, which is the behaviour the CLI's `--path` flag and
|
|
36
|
+
* `CLAUDE_FLOW_DB_PATH` have always advertised.
|
|
37
|
+
*/
|
|
38
|
+
const registryPromises = new Map();
|
|
39
|
+
const registryInstances = new Map();
|
|
40
|
+
/**
|
|
41
|
+
* Test seam: when set, every path resolves to this registry.
|
|
42
|
+
*
|
|
43
|
+
* Kept separate from the path cache on purpose. A test installs a fake registry
|
|
44
|
+
* and then calls a bridge function with its own temp `dbPath`; keying the
|
|
45
|
+
* override by path would mean the seam only worked for callers that happened to
|
|
46
|
+
* pass the same path the seam guessed, which is how #2968's fixture broke.
|
|
47
|
+
*/
|
|
48
|
+
let testRegistryOverride = null;
|
|
25
49
|
let bridgeAvailable = null;
|
|
26
50
|
// #2652/#2120: rows created before the status column existed receive NULL
|
|
27
51
|
// during migration. They are live rows, not tombstones. Every user-facing
|
|
@@ -172,10 +196,18 @@ async function getRegistry(dbPath) {
|
|
|
172
196
|
: 'AgentDB native bridge disabled by CLAUDE_FLOW_DISABLE_BRIDGE=1';
|
|
173
197
|
return null;
|
|
174
198
|
}
|
|
199
|
+
if (testRegistryOverride)
|
|
200
|
+
return testRegistryOverride;
|
|
175
201
|
if (bridgeAvailable === false)
|
|
176
202
|
return null;
|
|
177
|
-
|
|
178
|
-
|
|
203
|
+
// Resolve first, then cache on the resolved value: `undefined`, a relative
|
|
204
|
+
// path and its absolute form must not become three different registries over
|
|
205
|
+
// the same file.
|
|
206
|
+
const resolvedPath = dbPath ? path.resolve(dbPath) : getAgentDbPath();
|
|
207
|
+
const cached = registryInstances.get(resolvedPath);
|
|
208
|
+
if (cached)
|
|
209
|
+
return cached;
|
|
210
|
+
let registryPromise = registryPromises.get(resolvedPath);
|
|
179
211
|
if (!registryPromise) {
|
|
180
212
|
registryPromise = (async () => {
|
|
181
213
|
try {
|
|
@@ -193,7 +225,7 @@ async function getRegistry(dbPath) {
|
|
|
193
225
|
try {
|
|
194
226
|
await registry.initialize({
|
|
195
227
|
// #2786: use agentdb-memory.db (plaintext) so native better-sqlite3 doesn't hit the encrypted memory.db.
|
|
196
|
-
dbPath:
|
|
228
|
+
dbPath: resolvedPath,
|
|
197
229
|
embeddingModel: 'Xenova/all-MiniLM-L6-v2',
|
|
198
230
|
dimension: 384,
|
|
199
231
|
vectorBackend: 'auto',
|
|
@@ -440,7 +472,7 @@ async function getRegistry(dbPath) {
|
|
|
440
472
|
catch {
|
|
441
473
|
// Top-level catch — registry stays usable even if post-init wiring fails wholesale.
|
|
442
474
|
}
|
|
443
|
-
|
|
475
|
+
registryInstances.set(resolvedPath, registry);
|
|
444
476
|
bridgeAvailable = true;
|
|
445
477
|
bridgeFailureReason = null;
|
|
446
478
|
return registry;
|
|
@@ -451,13 +483,29 @@ async function getRegistry(dbPath) {
|
|
|
451
483
|
// makes the resulting sql.js-fallback refusal undiagnosable.
|
|
452
484
|
bridgeFailureReason = err instanceof Error ? err.message : String(err);
|
|
453
485
|
bridgeAvailable = false;
|
|
454
|
-
|
|
486
|
+
registryPromises.delete(resolvedPath);
|
|
455
487
|
return null;
|
|
456
488
|
}
|
|
457
489
|
})();
|
|
490
|
+
registryPromises.set(resolvedPath, registryPromise);
|
|
458
491
|
}
|
|
459
492
|
return registryPromise;
|
|
460
493
|
}
|
|
494
|
+
/** Test seam: forget cached registries so a test can exercise a fresh open. */
|
|
495
|
+
export function _resetRegistryCacheForTest() {
|
|
496
|
+
registryPromises.clear();
|
|
497
|
+
registryInstances.clear();
|
|
498
|
+
testRegistryOverride = null;
|
|
499
|
+
bridgeAvailable = null;
|
|
500
|
+
bridgeFailureReason = null;
|
|
501
|
+
}
|
|
502
|
+
/** #3196: the sibling store AgentDB owns next to a given sql.js database. */
|
|
503
|
+
export function siblingAgentDbPath(dbPath) {
|
|
504
|
+
if (!dbPath || dbPath === ':memory:')
|
|
505
|
+
return null;
|
|
506
|
+
const sibling = path.join(path.dirname(path.resolve(dbPath)), 'agentdb-memory.db');
|
|
507
|
+
return path.resolve(dbPath) === sibling ? null : sibling;
|
|
508
|
+
}
|
|
461
509
|
// ===== Phase 2: BM25 hybrid scoring =====
|
|
462
510
|
/**
|
|
463
511
|
* BM25 scoring for keyword-based search.
|
|
@@ -1738,8 +1786,9 @@ export function getBridgeFailureReason() {
|
|
|
1738
1786
|
* independent of package build order without changing production startup.
|
|
1739
1787
|
*/
|
|
1740
1788
|
export function __setMemoryBridgeRegistryForTests(registry) {
|
|
1741
|
-
|
|
1742
|
-
|
|
1789
|
+
registryPromises.clear();
|
|
1790
|
+
registryInstances.clear();
|
|
1791
|
+
testRegistryOverride = registry;
|
|
1743
1792
|
bridgeAvailable = registry ? true : null;
|
|
1744
1793
|
bridgeFailureReason = null;
|
|
1745
1794
|
}
|
|
@@ -1753,16 +1802,19 @@ export function __setMemoryBridgeRegistryForTests(registry) {
|
|
|
1753
1802
|
* therefore had no recovery path short of a restart.
|
|
1754
1803
|
*/
|
|
1755
1804
|
export async function shutdownBridge() {
|
|
1756
|
-
|
|
1805
|
+
// #3196: every cached registry owns an open database handle, so shutting down
|
|
1806
|
+
// one of several would leave the rest holding files open.
|
|
1807
|
+
for (const registry of registryInstances.values()) {
|
|
1757
1808
|
try {
|
|
1758
|
-
await
|
|
1809
|
+
await registry.shutdown();
|
|
1759
1810
|
}
|
|
1760
1811
|
catch {
|
|
1761
1812
|
// Best-effort
|
|
1762
1813
|
}
|
|
1763
1814
|
}
|
|
1764
|
-
|
|
1765
|
-
|
|
1815
|
+
registryInstances.clear();
|
|
1816
|
+
registryPromises.clear();
|
|
1817
|
+
testRegistryOverride = null;
|
|
1766
1818
|
bridgeAvailable = null;
|
|
1767
1819
|
bridgeFailureReason = null;
|
|
1768
1820
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface SiblingStoreReport {
|
|
2
|
+
path: string;
|
|
3
|
+
rows: number;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Count rows in the sibling AgentDB store, read-only. Returns null when there
|
|
7
|
+
* is no sibling, it does not exist, or it cannot be read — an unreadable store
|
|
8
|
+
* is not evidence of an empty one, so we stay silent rather than claim zero.
|
|
9
|
+
*/
|
|
10
|
+
export declare function countSiblingStoreRows(dbPath: string): Promise<SiblingStoreReport | null>;
|
|
11
|
+
//# sourceMappingURL=sibling-store.d.ts.map
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* #3196: report the store this interface is NOT reading.
|
|
3
|
+
*
|
|
4
|
+
* `memory.db` (sql.js, encrypted at rest when enabled) and `agentdb-memory.db`
|
|
5
|
+
* (native better-sqlite3, plaintext) are deliberately separate files — see
|
|
6
|
+
* #2786; pointing native at an encrypted file fails and silently disables the
|
|
7
|
+
* learning system. Both are legitimate stores, and a read of one is not a read
|
|
8
|
+
* of the other.
|
|
9
|
+
*
|
|
10
|
+
* The danger is not the split. It is a count that describes one file as though
|
|
11
|
+
* it described the memory. This module exists so the CLI can say what it did
|
|
12
|
+
* not read, without opening, migrating or modifying that file.
|
|
13
|
+
*/
|
|
14
|
+
import { existsSync } from 'node:fs';
|
|
15
|
+
import { siblingAgentDbPath } from './memory-bridge.js';
|
|
16
|
+
/**
|
|
17
|
+
* Count rows in the sibling AgentDB store, read-only. Returns null when there
|
|
18
|
+
* is no sibling, it does not exist, or it cannot be read — an unreadable store
|
|
19
|
+
* is not evidence of an empty one, so we stay silent rather than claim zero.
|
|
20
|
+
*/
|
|
21
|
+
export async function countSiblingStoreRows(dbPath) {
|
|
22
|
+
const sibling = siblingAgentDbPath(dbPath);
|
|
23
|
+
if (!sibling || !existsSync(sibling))
|
|
24
|
+
return null;
|
|
25
|
+
try {
|
|
26
|
+
const require = (await import('node:module')).createRequire(import.meta.url);
|
|
27
|
+
// Optional native dependency: absence must degrade to silence, never throw.
|
|
28
|
+
const Database = require('better-sqlite3');
|
|
29
|
+
const db = new Database(sibling, { readonly: true, fileMustExist: true });
|
|
30
|
+
try {
|
|
31
|
+
const table = db
|
|
32
|
+
.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='memory_entries'")
|
|
33
|
+
.get();
|
|
34
|
+
if (!table)
|
|
35
|
+
return null;
|
|
36
|
+
const row = db
|
|
37
|
+
.prepare("SELECT COUNT(*) AS n FROM memory_entries WHERE (status = 'active' OR status IS NULL)")
|
|
38
|
+
.get();
|
|
39
|
+
const rows = Number(row?.n ?? 0);
|
|
40
|
+
return rows > 0 ? { path: sibling, rows } : null;
|
|
41
|
+
}
|
|
42
|
+
finally {
|
|
43
|
+
try {
|
|
44
|
+
db.close();
|
|
45
|
+
}
|
|
46
|
+
catch { /* best effort */ }
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=sibling-store.js.map
|
|
File without changes
|
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@claude-flow/cli",
|
|
3
|
-
"version": "3.41.
|
|
3
|
+
"version": "3.41.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Ruflo CLI - Enterprise AI agent orchestration with 60+ specialized agents, swarm coordination, MCP server, self-learning hooks, and vector memory for Claude Code",
|
|
6
6
|
"main": "dist/src/index.js",
|