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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-flow",
3
- "version": "3.6.5",
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
- const fullArgs = ['--session', session, '--json', ...args];
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
- let data;
22
- try {
23
- data = JSON.parse(result);
24
- }
25
- catch {
26
- data = result.trim();
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
- // Update session activity
29
- const sessionInfo = browserSessions.get(session);
30
- if (sessionInfo) {
31
- sessionInfo.lastActivity = new Date().toISOString();
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
- catch (error) {
41
- return {
42
- content: [{
43
- type: 'text',
44
- text: JSON.stringify({
45
- success: false,
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 || 'default'
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 || 'default',
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 || 'default',
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
- if (result[0]?.values) {
76
- for (const row of result[0].values) {
77
- const [id, key, ns, embeddingJson] = row;
78
- if (!embeddingJson)
79
- continue;
80
- try {
81
- const embedding = JSON.parse(embeddingJson);
82
- if (embedding.length !== dimensions)
83
- continue;
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
- catch {
88
- // skip invalid
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.5",
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",