claude-flow 3.6.5 → 3.6.6
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/v3/@claude-flow/cli/dist/src/mcp-tools/browser-tools.js +86 -32
- package/v3/@claude-flow/cli/dist/src/mcp-tools/embeddings-tools.js +3 -3
- package/v3/@claude-flow/cli/dist/src/memory/memory-bridge.d.ts +15 -0
- package/v3/@claude-flow/cli/dist/src/memory/memory-bridge.js +45 -0
- package/v3/@claude-flow/cli/dist/src/memory/rabitq-index.js +45 -29
- package/v3/@claude-flow/cli/package.json +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-flow",
|
|
3
|
-
"version": "3.6.
|
|
3
|
+
"version": "3.6.6",
|
|
4
4
|
"description": "Ruflo - Enterprise AI agent orchestration for Claude Code. Deploy 60+ specialized agents in coordinated swarms with self-learning, fault-tolerant consensus, vector memory, and MCP integration",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -8,47 +8,90 @@ import { validateIdentifier, validateText } from './validate-input.js';
|
|
|
8
8
|
// Session registry for multi-session support
|
|
9
9
|
const browserSessions = new Map();
|
|
10
10
|
/**
|
|
11
|
-
* Execute agent-browser CLI command
|
|
11
|
+
* Execute agent-browser CLI command.
|
|
12
|
+
* Tries global agent-browser first, falls back to npx if ENOENT.
|
|
12
13
|
*/
|
|
13
14
|
async function execBrowserCommand(args, session = 'default') {
|
|
14
15
|
const { execFileSync } = await import('child_process');
|
|
16
|
+
const fullArgs = ['--session', session, '--json', ...args];
|
|
17
|
+
let result;
|
|
15
18
|
try {
|
|
16
|
-
|
|
17
|
-
const result = execFileSync('agent-browser', fullArgs, {
|
|
19
|
+
result = execFileSync('agent-browser', fullArgs, {
|
|
18
20
|
encoding: 'utf-8',
|
|
19
21
|
timeout: 30000,
|
|
20
22
|
});
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
const err = error;
|
|
26
|
+
if (err.code === 'ENOENT') {
|
|
27
|
+
try {
|
|
28
|
+
result = execFileSync('npx', ['--yes', 'agent-browser', ...fullArgs], {
|
|
29
|
+
encoding: 'utf-8',
|
|
30
|
+
timeout: 60000,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
catch (npxError) {
|
|
34
|
+
const npxErr = npxError;
|
|
35
|
+
return {
|
|
36
|
+
content: [{
|
|
37
|
+
type: 'text',
|
|
38
|
+
text: JSON.stringify({
|
|
39
|
+
success: false,
|
|
40
|
+
error: npxErr.code === 'ENOENT'
|
|
41
|
+
? 'Neither agent-browser nor npx found. Install with: npm i -g agent-browser'
|
|
42
|
+
: npxErr instanceof Error ? npxErr.message : String(npxError),
|
|
43
|
+
}),
|
|
44
|
+
}],
|
|
45
|
+
isError: true,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
27
48
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
49
|
+
else {
|
|
50
|
+
return {
|
|
51
|
+
content: [{
|
|
52
|
+
type: 'text',
|
|
53
|
+
text: JSON.stringify({
|
|
54
|
+
success: false,
|
|
55
|
+
error: err instanceof Error ? err.message : String(error),
|
|
56
|
+
}),
|
|
57
|
+
}],
|
|
58
|
+
isError: true,
|
|
59
|
+
};
|
|
32
60
|
}
|
|
33
|
-
return {
|
|
34
|
-
content: [{
|
|
35
|
-
type: 'text',
|
|
36
|
-
text: JSON.stringify(data, null, 2),
|
|
37
|
-
}],
|
|
38
|
-
};
|
|
39
61
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
error: error instanceof Error ? error.message : String(error),
|
|
47
|
-
}),
|
|
48
|
-
}],
|
|
49
|
-
isError: true,
|
|
50
|
-
};
|
|
62
|
+
let data;
|
|
63
|
+
try {
|
|
64
|
+
data = JSON.parse(result);
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
data = result.trim();
|
|
51
68
|
}
|
|
69
|
+
const sessionInfo = browserSessions.get(session);
|
|
70
|
+
if (sessionInfo) {
|
|
71
|
+
sessionInfo.lastActivity = new Date().toISOString();
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
content: [{
|
|
75
|
+
type: 'text',
|
|
76
|
+
text: JSON.stringify(data, null, 2),
|
|
77
|
+
}],
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Detect if Linux needs --no-sandbox for Chrome.
|
|
82
|
+
*/
|
|
83
|
+
function needsNoSandbox() {
|
|
84
|
+
try {
|
|
85
|
+
const { readFileSync, existsSync } = require('fs');
|
|
86
|
+
if (process.platform !== 'linux')
|
|
87
|
+
return false;
|
|
88
|
+
const clonePath = '/proc/sys/kernel/unprivileged_userns_clone';
|
|
89
|
+
if (existsSync(clonePath)) {
|
|
90
|
+
return readFileSync(clonePath, 'utf-8').trim() === '0';
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
catch { /* not Linux or can't read */ }
|
|
94
|
+
return false;
|
|
52
95
|
}
|
|
53
96
|
/**
|
|
54
97
|
* Browser MCP Tools
|
|
@@ -72,6 +115,11 @@ export const browserTools = [
|
|
|
72
115
|
enum: ['load', 'domcontentloaded', 'networkidle'],
|
|
73
116
|
description: 'Wait condition',
|
|
74
117
|
},
|
|
118
|
+
args: {
|
|
119
|
+
type: 'array',
|
|
120
|
+
items: { type: 'string' },
|
|
121
|
+
description: 'Additional Chrome launch args (e.g., ["--no-sandbox", "--disable-dev-shm-usage"])',
|
|
122
|
+
},
|
|
75
123
|
},
|
|
76
124
|
required: ['url'],
|
|
77
125
|
},
|
|
@@ -85,9 +133,15 @@ export const browserTools = [
|
|
|
85
133
|
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: vS.error }) }], isError: true };
|
|
86
134
|
}
|
|
87
135
|
const { url, session, waitUntil } = input;
|
|
136
|
+
const launchArgs = input.args || [];
|
|
137
|
+
if (needsNoSandbox() && !launchArgs.includes('--no-sandbox')) {
|
|
138
|
+
launchArgs.push('--no-sandbox');
|
|
139
|
+
}
|
|
88
140
|
const args = ['open', url];
|
|
89
141
|
if (waitUntil)
|
|
90
142
|
args.push('--wait-until', waitUntil);
|
|
143
|
+
for (const a of launchArgs)
|
|
144
|
+
args.push('--arg', a);
|
|
91
145
|
// Create session if new
|
|
92
146
|
const sessionId = session || 'default';
|
|
93
147
|
if (!browserSessions.has(sessionId)) {
|
|
@@ -369,13 +423,13 @@ export const browserTools = [
|
|
|
369
423
|
},
|
|
370
424
|
{
|
|
371
425
|
name: 'browser_hover',
|
|
372
|
-
description: 'Hover over an element',
|
|
426
|
+
description: 'Hover over an element using ref (@e1) or CSS selector',
|
|
373
427
|
category: 'browser',
|
|
374
428
|
tags: ['interaction'],
|
|
375
429
|
inputSchema: {
|
|
376
430
|
type: 'object',
|
|
377
431
|
properties: {
|
|
378
|
-
target: { type: 'string', description: 'Element ref or CSS selector' },
|
|
432
|
+
target: { type: 'string', description: 'Element ref (@e1) or CSS selector' },
|
|
379
433
|
session: { type: 'string', description: 'Session ID' },
|
|
380
434
|
},
|
|
381
435
|
required: ['target'],
|
|
@@ -412,7 +412,7 @@ export const embeddingsTools = [
|
|
|
412
412
|
query,
|
|
413
413
|
limit: topK,
|
|
414
414
|
threshold,
|
|
415
|
-
namespace: namespace || '
|
|
415
|
+
namespace: namespace || 'all'
|
|
416
416
|
});
|
|
417
417
|
const searchTime = (performance.now() - startTime).toFixed(2);
|
|
418
418
|
return {
|
|
@@ -428,7 +428,7 @@ export const embeddingsTools = [
|
|
|
428
428
|
model: config.model,
|
|
429
429
|
topK,
|
|
430
430
|
threshold,
|
|
431
|
-
namespace: namespace || '
|
|
431
|
+
namespace: namespace || 'all',
|
|
432
432
|
searchTime: `${searchTime}ms`,
|
|
433
433
|
indexType: config.hyperbolic.enabled ? 'HNSW (hyperbolic)' : 'HNSW (euclidean)',
|
|
434
434
|
resultCount: searchResult.results.length
|
|
@@ -446,7 +446,7 @@ export const embeddingsTools = [
|
|
|
446
446
|
model: config.model,
|
|
447
447
|
topK,
|
|
448
448
|
threshold,
|
|
449
|
-
namespace: namespace || '
|
|
449
|
+
namespace: namespace || 'all',
|
|
450
450
|
searchTime: `${searchTime}ms`,
|
|
451
451
|
indexType: config.hyperbolic.enabled ? 'HNSW (hyperbolic)' : 'HNSW (euclidean)',
|
|
452
452
|
},
|
|
@@ -405,4 +405,19 @@ export declare function bridgeContextSynthesize(params: {
|
|
|
405
405
|
export declare function bridgeSemanticRoute(params: {
|
|
406
406
|
input: string;
|
|
407
407
|
}): Promise<any>;
|
|
408
|
+
/**
|
|
409
|
+
* Export all embeddings from the bridge's better-sqlite3 connection.
|
|
410
|
+
* Used by RaBitQ to build its index from the same data that memory_store writes.
|
|
411
|
+
* Returns null if bridge is unavailable (caller falls back to sql.js).
|
|
412
|
+
*/
|
|
413
|
+
export declare function bridgeGetAllEmbeddings(options?: {
|
|
414
|
+
dimensions?: number;
|
|
415
|
+
limit?: number;
|
|
416
|
+
dbPath?: string;
|
|
417
|
+
}): Promise<Array<{
|
|
418
|
+
id: string;
|
|
419
|
+
key: string;
|
|
420
|
+
namespace: string;
|
|
421
|
+
embedding: number[];
|
|
422
|
+
}> | null>;
|
|
408
423
|
//# sourceMappingURL=memory-bridge.d.ts.map
|
|
@@ -1554,6 +1554,51 @@ export async function bridgeSemanticRoute(params) {
|
|
|
1554
1554
|
return { route: null, error: e.message };
|
|
1555
1555
|
}
|
|
1556
1556
|
}
|
|
1557
|
+
// ===== RaBitQ data export =====
|
|
1558
|
+
/**
|
|
1559
|
+
* Export all embeddings from the bridge's better-sqlite3 connection.
|
|
1560
|
+
* Used by RaBitQ to build its index from the same data that memory_store writes.
|
|
1561
|
+
* Returns null if bridge is unavailable (caller falls back to sql.js).
|
|
1562
|
+
*/
|
|
1563
|
+
export async function bridgeGetAllEmbeddings(options) {
|
|
1564
|
+
const registry = await getRegistry(options?.dbPath);
|
|
1565
|
+
if (!registry)
|
|
1566
|
+
return null;
|
|
1567
|
+
const ctx = getDb(registry);
|
|
1568
|
+
if (!ctx)
|
|
1569
|
+
return null;
|
|
1570
|
+
try {
|
|
1571
|
+
const dims = options?.dimensions ?? 384;
|
|
1572
|
+
const maxRows = options?.limit ?? 50000;
|
|
1573
|
+
const rows = ctx.db.prepare(`
|
|
1574
|
+
SELECT id, key, namespace, embedding
|
|
1575
|
+
FROM memory_entries
|
|
1576
|
+
WHERE status = 'active' AND embedding IS NOT NULL
|
|
1577
|
+
LIMIT ?
|
|
1578
|
+
`).all(maxRows);
|
|
1579
|
+
const results = [];
|
|
1580
|
+
for (const row of rows) {
|
|
1581
|
+
if (!row.embedding)
|
|
1582
|
+
continue;
|
|
1583
|
+
try {
|
|
1584
|
+
const emb = JSON.parse(row.embedding);
|
|
1585
|
+
if (emb.length !== dims)
|
|
1586
|
+
continue;
|
|
1587
|
+
results.push({
|
|
1588
|
+
id: String(row.id),
|
|
1589
|
+
key: row.key || String(row.id),
|
|
1590
|
+
namespace: row.namespace || 'default',
|
|
1591
|
+
embedding: emb,
|
|
1592
|
+
});
|
|
1593
|
+
}
|
|
1594
|
+
catch { /* skip invalid */ }
|
|
1595
|
+
}
|
|
1596
|
+
return results;
|
|
1597
|
+
}
|
|
1598
|
+
catch {
|
|
1599
|
+
return null;
|
|
1600
|
+
}
|
|
1601
|
+
}
|
|
1557
1602
|
// ===== Utility =====
|
|
1558
1603
|
function cosineSim(a, b) {
|
|
1559
1604
|
if (!a || !b || a.length === 0 || b.length === 0)
|
|
@@ -55,41 +55,57 @@ export async function buildRabitqIndex(options) {
|
|
|
55
55
|
const dimensions = options?.dimensions ?? 384;
|
|
56
56
|
const swarmDir = path.resolve(process.cwd(), '.swarm');
|
|
57
57
|
const dbPath = options?.dbPath ? path.resolve(options.dbPath) : path.join(swarmDir, 'memory.db');
|
|
58
|
-
if (!fs.existsSync(dbPath)) {
|
|
59
|
-
rabitqInitializing = false;
|
|
60
|
-
return { success: false, vectorCount: 0, dimensions, compressionRatio: 0, buildTimeMs: 0, error: 'Database not found' };
|
|
61
|
-
}
|
|
62
|
-
// Load embeddings from SQLite
|
|
63
|
-
const initSqlJs = (await import('sql.js')).default;
|
|
64
|
-
const SQL = await initSqlJs();
|
|
65
|
-
const fileBuffer = fs.readFileSync(dbPath);
|
|
66
|
-
const db = new SQL.Database(fileBuffer);
|
|
67
|
-
const result = db.exec(`
|
|
68
|
-
SELECT id, key, namespace, embedding
|
|
69
|
-
FROM memory_entries
|
|
70
|
-
WHERE status = 'active' AND embedding IS NOT NULL
|
|
71
|
-
LIMIT 50000
|
|
72
|
-
`);
|
|
73
58
|
const entries = [];
|
|
74
59
|
const vectors = [];
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
entries.push({ id: String(id), key: key || String(id), namespace: ns || 'default' });
|
|
85
|
-
vectors.push(...embedding);
|
|
60
|
+
// Try bridge first (reads via better-sqlite3, sees WAL data)
|
|
61
|
+
let usedBridge = false;
|
|
62
|
+
try {
|
|
63
|
+
const { bridgeGetAllEmbeddings } = await import('./memory-bridge.js');
|
|
64
|
+
const bridgeRows = await bridgeGetAllEmbeddings({ dimensions, dbPath: options?.dbPath });
|
|
65
|
+
if (bridgeRows && bridgeRows.length > 0) {
|
|
66
|
+
for (const row of bridgeRows) {
|
|
67
|
+
entries.push({ id: row.id, key: row.key, namespace: row.namespace });
|
|
68
|
+
vectors.push(...row.embedding);
|
|
86
69
|
}
|
|
87
|
-
|
|
88
|
-
|
|
70
|
+
usedBridge = true;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
catch { /* bridge unavailable, fall through */ }
|
|
74
|
+
// Fallback: read .swarm/memory.db via sql.js
|
|
75
|
+
if (!usedBridge) {
|
|
76
|
+
if (!fs.existsSync(dbPath)) {
|
|
77
|
+
rabitqInitializing = false;
|
|
78
|
+
return { success: false, vectorCount: 0, dimensions, compressionRatio: 0, buildTimeMs: 0, error: 'Database not found' };
|
|
79
|
+
}
|
|
80
|
+
const initSqlJs = (await import('sql.js')).default;
|
|
81
|
+
const SQL = await initSqlJs();
|
|
82
|
+
const fileBuffer = fs.readFileSync(dbPath);
|
|
83
|
+
const db = new SQL.Database(fileBuffer);
|
|
84
|
+
const result = db.exec(`
|
|
85
|
+
SELECT id, key, namespace, embedding
|
|
86
|
+
FROM memory_entries
|
|
87
|
+
WHERE status = 'active' AND embedding IS NOT NULL
|
|
88
|
+
LIMIT 50000
|
|
89
|
+
`);
|
|
90
|
+
if (result[0]?.values) {
|
|
91
|
+
for (const row of result[0].values) {
|
|
92
|
+
const [id, key, ns, embeddingJson] = row;
|
|
93
|
+
if (!embeddingJson)
|
|
94
|
+
continue;
|
|
95
|
+
try {
|
|
96
|
+
const embedding = JSON.parse(embeddingJson);
|
|
97
|
+
if (embedding.length !== dimensions)
|
|
98
|
+
continue;
|
|
99
|
+
entries.push({ id: String(id), key: key || String(id), namespace: ns || 'default' });
|
|
100
|
+
vectors.push(...embedding);
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
// skip invalid
|
|
104
|
+
}
|
|
89
105
|
}
|
|
90
106
|
}
|
|
107
|
+
db.close();
|
|
91
108
|
}
|
|
92
|
-
db.close();
|
|
93
109
|
if (entries.length < 2) {
|
|
94
110
|
rabitqInitializing = false;
|
|
95
111
|
return { success: false, vectorCount: entries.length, dimensions, compressionRatio: 0, buildTimeMs: Date.now() - startTime, error: 'Need at least 2 vectors to build RaBitQ index' };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@claude-flow/cli",
|
|
3
|
-
"version": "3.6.
|
|
3
|
+
"version": "3.6.6",
|
|
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",
|