claude-flow 3.6.27 → 3.6.29
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/agents/core/coder.md +11 -0
- package/.claude/agents/templates/implementer-sparc-coder.md +12 -0
- package/.claude/scheduled_tasks.lock +1 -0
- package/README.md +19 -6
- package/package.json +1 -1
- package/v3/@claude-flow/cli/README.md +19 -6
- package/v3/@claude-flow/cli/dist/src/commands/hive-mind.js +40 -0
- package/v3/@claude-flow/cli/dist/src/commands/init.js +13 -0
- package/v3/@claude-flow/cli/dist/src/commands/performance.js +3 -3
- package/v3/@claude-flow/cli/dist/src/init/executor.js +7 -2
- package/v3/@claude-flow/cli/dist/src/init/settings-generator.js +7 -2
- package/v3/@claude-flow/cli/dist/src/init/types.d.ts +6 -0
- package/v3/@claude-flow/cli/dist/src/mcp-client.js +11 -0
- package/v3/@claude-flow/cli/dist/src/mcp-tools/browser-session-tools.d.ts +23 -0
- package/v3/@claude-flow/cli/dist/src/mcp-tools/browser-session-tools.js +313 -0
- package/v3/@claude-flow/cli/dist/src/mcp-tools/neural-tools.js +5 -19
- package/v3/@claude-flow/cli/package.json +1 -1
|
@@ -7,6 +7,17 @@ description: Implementation specialist for writing clean, efficient code
|
|
|
7
7
|
|
|
8
8
|
You are a senior software engineer specialized in writing clean, maintainable, and efficient code following best practices and design patterns.
|
|
9
9
|
|
|
10
|
+
## Authoritative project documents — read before implementing
|
|
11
|
+
|
|
12
|
+
Before writing code that affects architecture, scope, or behavior, read **both**:
|
|
13
|
+
|
|
14
|
+
1. **`docs/SPEC.md`** (and any sibling files under `docs/`) — describes **what** the system should do. Functional requirements, scope, acceptance criteria.
|
|
15
|
+
2. **`docs/adr/*.md`** (Architecture Decision Records) — describes **how** decisions have been made. Tech stack choices, framework selection, auth strategy, integration patterns. Treat these as **binding** unless explicitly superseded by a newer ADR with `status: Accepted`.
|
|
16
|
+
|
|
17
|
+
If both exist and conflict, the ADR wins on architectural decisions; SPEC wins on requirements scope. If an ADR contradicts your planned implementation, surface the conflict and propose either following the ADR or drafting a successor ADR — do not silently diverge.
|
|
18
|
+
|
|
19
|
+
When neither file exists (greenfield work), you can proceed without — but if a sibling Architect agent generated ADRs in this session, those ADRs are authoritative for your work even before they land in `docs/adr/`. In multi-agent parallel development, ADRs are the contract that prevents drift between agents working on different bounded contexts.
|
|
20
|
+
|
|
10
21
|
## Core Responsibilities
|
|
11
22
|
|
|
12
23
|
1. **Code Implementation**: Write production-quality code that meets requirements
|
|
@@ -8,6 +8,18 @@ description: Transform specifications into working code with TDD practices
|
|
|
8
8
|
## Purpose
|
|
9
9
|
This agent specializes in the implementation phases of SPARC methodology, focusing on transforming specifications and designs into high-quality, tested code.
|
|
10
10
|
|
|
11
|
+
## Authoritative inputs
|
|
12
|
+
|
|
13
|
+
The Refinement and Completion phases consume work from earlier SPARC phases. Read **all** of the following before implementing:
|
|
14
|
+
|
|
15
|
+
1. **`docs/SPEC.md`** — Specification phase output (what to build)
|
|
16
|
+
2. **`docs/pseudocode/*.md`** if present — Pseudocode phase output (algorithm shape)
|
|
17
|
+
3. **`docs/adr/*.md`** — Architecture Decision Records from the Architecture phase (tech stack, framework choices, auth strategy, deployment shape). **Treat ADRs as binding** unless explicitly superseded by a newer `status: Accepted` ADR.
|
|
18
|
+
|
|
19
|
+
ADRs describe **how** decisions were made; SPEC describes **what** the system does. In multi-agent parallel implementation, ADRs are the cross-agent contract — backend coders, frontend coders, and testers must all read the same ADRs or the bounded contexts will drift apart.
|
|
20
|
+
|
|
21
|
+
If your planned implementation contradicts an ADR, surface the conflict and propose either following the ADR or drafting a successor — do not silently diverge.
|
|
22
|
+
|
|
11
23
|
## Core Implementation Principles
|
|
12
24
|
|
|
13
25
|
### 1. Test-Driven Development (TDD)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"sessionId":"1dba3b8c-1f1f-4718-bab4-9ffba5f49578","pid":20633,"procStart":"Mon May 4 17:00:40 2026","acquiredAt":1777938041240}
|
package/README.md
CHANGED
|
@@ -43,9 +43,17 @@ User --> Ruflo (CLI/MCP) --> Router --> Swarm --> Agents --> Memory --> LLM Prov
|
|
|
43
43
|
|
|
44
44
|
## Quick Start
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
There are **two different install paths** with very different surface areas. Pick based on what you need (#1744):
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
| | **Claude Code Plugin** | **CLI install (`npx ruflo init`)** |
|
|
49
|
+
|---|---|---|
|
|
50
|
+
| What it gives you | Slash commands + a few skills + agent definitions per-plugin | Full Ruflo loop — 98 agents, 60+ commands, 30 skills, MCP server, hooks, daemon |
|
|
51
|
+
| Files in your workspace | **Zero** | `.claude/`, `.claude-flow/`, `CLAUDE.md`, helpers, settings |
|
|
52
|
+
| MCP server registered | **No** (`memory_store`, `swarm_init`, etc. unavailable to Claude) | Yes |
|
|
53
|
+
| Hooks installed | No | Yes |
|
|
54
|
+
| Best for | Try a single plugin's commands without committing to the full install | Production use — everything works as documented |
|
|
55
|
+
|
|
56
|
+
### Path A — Claude Code Plugins (lite, slash commands only)
|
|
49
57
|
|
|
50
58
|
```bash
|
|
51
59
|
# Add the marketplace
|
|
@@ -58,6 +66,8 @@ Install Ruflo as a native Claude Code plugin -- adds skills, commands, agents, a
|
|
|
58
66
|
/plugin install ruflo-federation@ruflo
|
|
59
67
|
```
|
|
60
68
|
|
|
69
|
+
This adds slash commands and agent definitions only. The Ruflo MCP server is NOT registered, so `memory_store`, `swarm_init`, `agent_spawn`, etc. won't be callable from Claude. For the full loop, use Path B below.
|
|
70
|
+
|
|
61
71
|
<details>
|
|
62
72
|
<summary><strong>All 32 plugins</strong></summary>
|
|
63
73
|
|
|
@@ -146,8 +156,11 @@ Install Ruflo as a native Claude Code plugin -- adds skills, commands, agents, a
|
|
|
146
156
|
# One-line install
|
|
147
157
|
curl -fsSL https://cdn.jsdelivr.net/gh/ruvnet/ruflo@main/scripts/install.sh | bash
|
|
148
158
|
|
|
149
|
-
# Or via npx
|
|
150
|
-
npx ruflo@latest init
|
|
159
|
+
# Or via npx (interactive setup)
|
|
160
|
+
npx ruflo@latest init wizard
|
|
161
|
+
|
|
162
|
+
# Quick non-interactive init
|
|
163
|
+
# npx ruflo@latest init
|
|
151
164
|
|
|
152
165
|
# Or install globally
|
|
153
166
|
npm install -g ruflo@latest
|
|
@@ -156,8 +169,8 @@ npm install -g ruflo@latest
|
|
|
156
169
|
### MCP Server
|
|
157
170
|
|
|
158
171
|
```bash
|
|
159
|
-
# Add Ruflo as an MCP server in Claude Code
|
|
160
|
-
claude mcp add ruflo -- npx
|
|
172
|
+
# Add Ruflo as an MCP server in Claude Code (canonical form, matches USERGUIDE.md)
|
|
173
|
+
claude mcp add ruflo -- npx ruflo@latest mcp start
|
|
161
174
|
```
|
|
162
175
|
|
|
163
176
|
---
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-flow",
|
|
3
|
-
"version": "3.6.
|
|
3
|
+
"version": "3.6.29",
|
|
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",
|
|
@@ -43,9 +43,17 @@ User --> Ruflo (CLI/MCP) --> Router --> Swarm --> Agents --> Memory --> LLM Prov
|
|
|
43
43
|
|
|
44
44
|
## Quick Start
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
There are **two different install paths** with very different surface areas. Pick based on what you need (#1744):
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
| | **Claude Code Plugin** | **CLI install (`npx ruflo init`)** |
|
|
49
|
+
|---|---|---|
|
|
50
|
+
| What it gives you | Slash commands + a few skills + agent definitions per-plugin | Full Ruflo loop — 98 agents, 60+ commands, 30 skills, MCP server, hooks, daemon |
|
|
51
|
+
| Files in your workspace | **Zero** | `.claude/`, `.claude-flow/`, `CLAUDE.md`, helpers, settings |
|
|
52
|
+
| MCP server registered | **No** (`memory_store`, `swarm_init`, etc. unavailable to Claude) | Yes |
|
|
53
|
+
| Hooks installed | No | Yes |
|
|
54
|
+
| Best for | Try a single plugin's commands without committing to the full install | Production use — everything works as documented |
|
|
55
|
+
|
|
56
|
+
### Path A — Claude Code Plugins (lite, slash commands only)
|
|
49
57
|
|
|
50
58
|
```bash
|
|
51
59
|
# Add the marketplace
|
|
@@ -58,6 +66,8 @@ Install Ruflo as a native Claude Code plugin -- adds skills, commands, agents, a
|
|
|
58
66
|
/plugin install ruflo-federation@ruflo
|
|
59
67
|
```
|
|
60
68
|
|
|
69
|
+
This adds slash commands and agent definitions only. The Ruflo MCP server is NOT registered, so `memory_store`, `swarm_init`, `agent_spawn`, etc. won't be callable from Claude. For the full loop, use Path B below.
|
|
70
|
+
|
|
61
71
|
<details>
|
|
62
72
|
<summary><strong>All 32 plugins</strong></summary>
|
|
63
73
|
|
|
@@ -146,8 +156,11 @@ Install Ruflo as a native Claude Code plugin -- adds skills, commands, agents, a
|
|
|
146
156
|
# One-line install
|
|
147
157
|
curl -fsSL https://cdn.jsdelivr.net/gh/ruvnet/ruflo@main/scripts/install.sh | bash
|
|
148
158
|
|
|
149
|
-
# Or via npx
|
|
150
|
-
npx ruflo@latest init
|
|
159
|
+
# Or via npx (interactive setup)
|
|
160
|
+
npx ruflo@latest init wizard
|
|
161
|
+
|
|
162
|
+
# Quick non-interactive init
|
|
163
|
+
# npx ruflo@latest init
|
|
151
164
|
|
|
152
165
|
# Or install globally
|
|
153
166
|
npm install -g ruflo@latest
|
|
@@ -156,8 +169,8 @@ npm install -g ruflo@latest
|
|
|
156
169
|
### MCP Server
|
|
157
170
|
|
|
158
171
|
```bash
|
|
159
|
-
# Add Ruflo as an MCP server in Claude Code
|
|
160
|
-
claude mcp add ruflo -- npx
|
|
172
|
+
# Add Ruflo as an MCP server in Claude Code (canonical form, matches USERGUIDE.md)
|
|
173
|
+
claude mcp add ruflo -- npx ruflo@latest mcp start
|
|
161
174
|
```
|
|
162
175
|
|
|
163
176
|
---
|
|
@@ -10,6 +10,7 @@ import { select, confirm, input } from '../prompt.js';
|
|
|
10
10
|
import { callMCPTool, MCPClientError } from '../mcp-client.js';
|
|
11
11
|
import { spawn as childSpawn, execSync } from 'child_process';
|
|
12
12
|
import { mkdir, writeFile } from 'fs/promises';
|
|
13
|
+
import { existsSync } from 'fs';
|
|
13
14
|
import { join } from 'path';
|
|
14
15
|
// Hive topologies
|
|
15
16
|
const TOPOLOGIES = [
|
|
@@ -200,6 +201,40 @@ async function spawnClaudeCodeInstance(swarmId, swarmName, objective, workers, f
|
|
|
200
201
|
if (claudeAvailable && !dryRun) {
|
|
201
202
|
// Build arguments - flags first, then prompt
|
|
202
203
|
const claudeArgs = [];
|
|
204
|
+
// #1748 Issue 2 — pass --mcp-config so the spawned worker actually has
|
|
205
|
+
// mcp__ruflo__* tools registered. Before this, the coordination prompt
|
|
206
|
+
// referenced tools the worker didn't know about and exited silently.
|
|
207
|
+
// Resolution order:
|
|
208
|
+
// 1. explicit --mcp-config <path> flag passed by the caller
|
|
209
|
+
// 2. ./.mcp.json in cwd (project-local Ruflo MCP config)
|
|
210
|
+
// 3. ~/.claude.json or ~/.claude/mcp.json (user-global)
|
|
211
|
+
// If none found, we still spawn but warn — that's the pre-fix behavior
|
|
212
|
+
// and the user's debug log will surface the missing tools.
|
|
213
|
+
const explicitMcpConfig = flags['mcp-config'];
|
|
214
|
+
let mcpConfigPath = explicitMcpConfig;
|
|
215
|
+
if (!mcpConfigPath) {
|
|
216
|
+
const candidates = [
|
|
217
|
+
join(process.cwd(), '.mcp.json'),
|
|
218
|
+
join(process.env.HOME || process.env.USERPROFILE || '', '.claude.json'),
|
|
219
|
+
join(process.env.HOME || process.env.USERPROFILE || '', '.claude', 'mcp.json'),
|
|
220
|
+
];
|
|
221
|
+
for (const c of candidates) {
|
|
222
|
+
try {
|
|
223
|
+
if (c && existsSync(c)) {
|
|
224
|
+
mcpConfigPath = c;
|
|
225
|
+
break;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
catch { /* continue */ }
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
if (mcpConfigPath) {
|
|
232
|
+
claudeArgs.push('--mcp-config', mcpConfigPath);
|
|
233
|
+
output.printInfo(`Spawned worker MCP config: ${mcpConfigPath}`);
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
output.printWarning('No .mcp.json or ~/.claude.json found — spawned worker will not have mcp__ruflo__* tools (#1748 Issue 2). Pass --mcp-config <path> or run "ruflo init" to generate one.');
|
|
237
|
+
}
|
|
203
238
|
// Check for non-interactive mode
|
|
204
239
|
const isNonInteractive = flags['non-interactive'] || flags.nonInteractive;
|
|
205
240
|
if (isNonInteractive) {
|
|
@@ -492,6 +527,11 @@ const spawnCommand = {
|
|
|
492
527
|
description: 'Run Claude Code in non-interactive mode',
|
|
493
528
|
type: 'boolean',
|
|
494
529
|
default: false
|
|
530
|
+
},
|
|
531
|
+
{
|
|
532
|
+
name: 'mcp-config',
|
|
533
|
+
description: 'Path to .mcp.json for the spawned worker (auto-detects ./.mcp.json or ~/.claude.json if omitted) — fixes #1748 Issue 2',
|
|
534
|
+
type: 'string'
|
|
495
535
|
}
|
|
496
536
|
],
|
|
497
537
|
examples: [
|
|
@@ -145,6 +145,7 @@ const initAction = async (ctx) => {
|
|
|
145
145
|
const full = ctx.flags.full;
|
|
146
146
|
const skipClaude = ctx.flags['skip-claude'];
|
|
147
147
|
const onlyClaude = ctx.flags['only-claude'];
|
|
148
|
+
const noGlobal = ctx.flags['no-global'];
|
|
148
149
|
const codexMode = ctx.flags.codex;
|
|
149
150
|
const dualMode = ctx.flags.dual;
|
|
150
151
|
const cwd = ctx.cwd;
|
|
@@ -203,6 +204,12 @@ const initAction = async (ctx) => {
|
|
|
203
204
|
if (onlyClaude) {
|
|
204
205
|
options.components.runtime = false;
|
|
205
206
|
}
|
|
207
|
+
// #1744 — opt-out of the user-global ~/.claude/CLAUDE.md "Ruflo Integration"
|
|
208
|
+
// pointer block. Default behavior (off) preserves current install for users
|
|
209
|
+
// who rely on it; opting in via --no-global keeps the global file pristine.
|
|
210
|
+
if (noGlobal) {
|
|
211
|
+
options.skipGlobalClaudeMd = true;
|
|
212
|
+
}
|
|
206
213
|
// Create spinner
|
|
207
214
|
const spinner = output.createSpinner({ text: 'Initializing...' });
|
|
208
215
|
spinner.start();
|
|
@@ -919,6 +926,12 @@ export const initCommand = {
|
|
|
919
926
|
type: 'boolean',
|
|
920
927
|
default: false,
|
|
921
928
|
},
|
|
929
|
+
{
|
|
930
|
+
name: 'no-global',
|
|
931
|
+
description: 'Skip the ~/.claude/CLAUDE.md "Ruflo Integration" pointer block (#1744)',
|
|
932
|
+
type: 'boolean',
|
|
933
|
+
default: false,
|
|
934
|
+
},
|
|
922
935
|
{
|
|
923
936
|
name: 'start-all',
|
|
924
937
|
description: 'Auto-start daemon, memory, and swarm after init',
|
|
@@ -498,7 +498,7 @@ const optimizeCommand = {
|
|
|
498
498
|
data: [
|
|
499
499
|
{ priority: output.error('P0'), area: 'Memory', recommendation: 'Enable HNSW index quantization', impact: '+50% reduction' },
|
|
500
500
|
{ priority: output.warning('P1'), area: 'CPU', recommendation: 'Enable WASM SIMD acceleration', impact: '+4x speedup' },
|
|
501
|
-
{ priority: output.warning('P1'), area: 'Latency', recommendation: '
|
|
501
|
+
{ priority: output.warning('P1'), area: 'Latency', recommendation: 'Flash Attention WASM (in progress, currently JS reference)', impact: '+2.49x target' },
|
|
502
502
|
{ priority: output.info('P2'), area: 'Cache', recommendation: 'Increase pattern cache size', impact: '+15% hit rate' },
|
|
503
503
|
{ priority: output.info('P2'), area: 'Network', recommendation: 'Enable request batching', impact: '-30% latency' },
|
|
504
504
|
],
|
|
@@ -536,7 +536,7 @@ const bottleneckCommand = {
|
|
|
536
536
|
],
|
|
537
537
|
data: [
|
|
538
538
|
{ component: 'Vector Search', bottleneck: 'Linear scan O(n)', severity: output.error('High'), solution: 'Enable HNSW indexing' },
|
|
539
|
-
{ component: 'Neural Inference', bottleneck: 'Sequential attention', severity: output.warning('Medium'), solution: '
|
|
539
|
+
{ component: 'Neural Inference', bottleneck: 'Sequential attention', severity: output.warning('Medium'), solution: 'Flash Attention WASM (in progress)' },
|
|
540
540
|
{ component: 'Memory Store', bottleneck: 'Lock contention', severity: output.info('Low'), solution: 'Use sharded storage' },
|
|
541
541
|
],
|
|
542
542
|
});
|
|
@@ -571,7 +571,7 @@ export const performanceCommand = {
|
|
|
571
571
|
output.writeln('Performance Targets:');
|
|
572
572
|
output.printList([
|
|
573
573
|
'HNSW Search: 150x-12,500x faster than brute force',
|
|
574
|
-
'Flash Attention: 2.49x-7.47x
|
|
574
|
+
'Flash Attention: 2.49x-7.47x target (in progress; ships JS reference impl)',
|
|
575
575
|
'Memory: 50-75% reduction with quantization',
|
|
576
576
|
]);
|
|
577
577
|
output.writeln();
|
|
@@ -1662,9 +1662,11 @@ async function writeClaudeMd(targetDir, options, result) {
|
|
|
1662
1662
|
fs.writeFileSync(claudeMdPath, content, 'utf-8');
|
|
1663
1663
|
result.created.files.push('CLAUDE.md');
|
|
1664
1664
|
}
|
|
1665
|
-
// Also write/append global ~/.claude/CLAUDE.md so ruflo tools are used automatically (#1497)
|
|
1665
|
+
// Also write/append global ~/.claude/CLAUDE.md so ruflo tools are used automatically (#1497).
|
|
1666
|
+
// Opt-out via --no-global / options.skipGlobalClaudeMd (#1744 — keeps global rules file pristine
|
|
1667
|
+
// for users who don't want a per-machine pointer block).
|
|
1666
1668
|
const homeDir = process.env.HOME || process.env.USERPROFILE || '';
|
|
1667
|
-
if (homeDir) {
|
|
1669
|
+
if (homeDir && !options.skipGlobalClaudeMd) {
|
|
1668
1670
|
const globalClaudeDir = path.join(homeDir, '.claude');
|
|
1669
1671
|
const globalClaudeMd = path.join(globalClaudeDir, 'CLAUDE.md');
|
|
1670
1672
|
const rufloBlock = [
|
|
@@ -1695,6 +1697,9 @@ async function writeClaudeMd(targetDir, options, result) {
|
|
|
1695
1697
|
// Non-critical — global CLAUDE.md is best-effort
|
|
1696
1698
|
}
|
|
1697
1699
|
}
|
|
1700
|
+
else if (options.skipGlobalClaudeMd) {
|
|
1701
|
+
result.skipped.push('~/.claude/CLAUDE.md (--no-global)');
|
|
1702
|
+
}
|
|
1698
1703
|
}
|
|
1699
1704
|
/**
|
|
1700
1705
|
* Find source directory for skills/commands/agents
|
|
@@ -8,8 +8,13 @@ import { detectPlatform } from './types.js';
|
|
|
8
8
|
*/
|
|
9
9
|
export function generateSettings(options) {
|
|
10
10
|
const settings = {};
|
|
11
|
-
// Add hooks if enabled
|
|
12
|
-
|
|
11
|
+
// Add hooks if enabled. CRITICAL (#1744 #3): only emit the hooks block when
|
|
12
|
+
// the helpers directory will also be bundled. The hook commands point at
|
|
13
|
+
// .claude/helpers/hook-handler.cjs; if that file isn't created (as in
|
|
14
|
+
// --minimal where components.helpers=false), every hook fires and silently
|
|
15
|
+
// fails to find its handler. Either bundle the helpers OR drop the hooks —
|
|
16
|
+
// the option this fix takes is the latter (minimal stays minimal).
|
|
17
|
+
if (options.components.settings && options.components.helpers) {
|
|
13
18
|
settings.hooks = generateHooksConfig(options.hooks);
|
|
14
19
|
}
|
|
15
20
|
// Add statusLine configuration if enabled
|
|
@@ -260,6 +260,12 @@ export interface InitOptions {
|
|
|
260
260
|
runtime: RuntimeConfig;
|
|
261
261
|
/** Embeddings configuration */
|
|
262
262
|
embeddings: EmbeddingsConfig;
|
|
263
|
+
/**
|
|
264
|
+
* Skip the user-global ~/.claude/CLAUDE.md "Ruflo Integration" pointer block.
|
|
265
|
+
* Defaults to false (current behavior — block is appended once, idempotent).
|
|
266
|
+
* Set true via --no-global to keep the global Claude rules file pristine (#1744).
|
|
267
|
+
*/
|
|
268
|
+
skipGlobalClaudeMd?: boolean;
|
|
263
269
|
}
|
|
264
270
|
/**
|
|
265
271
|
* Default init options - full V3 setup
|
|
@@ -32,6 +32,7 @@ import { githubTools } from './mcp-tools/github-tools.js';
|
|
|
32
32
|
import { daaTools } from './mcp-tools/daa-tools.js';
|
|
33
33
|
import { coordinationTools } from './mcp-tools/coordination-tools.js';
|
|
34
34
|
import { browserTools } from './mcp-tools/browser-tools.js';
|
|
35
|
+
import { browserSessionTools } from './mcp-tools/browser-session-tools.js';
|
|
35
36
|
import { execFileSync } from 'node:child_process';
|
|
36
37
|
// Phase 6: AgentDB v3 controller tools
|
|
37
38
|
import { agentdbTools } from './mcp-tools/agentdb-tools.js';
|
|
@@ -54,6 +55,15 @@ function getBrowserTools() {
|
|
|
54
55
|
}
|
|
55
56
|
return _browserAvailable ? browserTools : [];
|
|
56
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* Lifecycle MCP tools for ruflo-browser session-as-skill architecture
|
|
60
|
+
* (ADR-0001 ruflo-browser §7). Always registered: their handlers shell out
|
|
61
|
+
* to ruvector + agent-browser + claude-flow memory and degrade gracefully
|
|
62
|
+
* when those CLIs are missing.
|
|
63
|
+
*/
|
|
64
|
+
function getBrowserSessionTools() {
|
|
65
|
+
return browserSessionTools;
|
|
66
|
+
}
|
|
57
67
|
/**
|
|
58
68
|
* MCP Tool Registry
|
|
59
69
|
* Maps tool names to their handler functions
|
|
@@ -91,6 +101,7 @@ registerTools([
|
|
|
91
101
|
...daaTools,
|
|
92
102
|
...coordinationTools,
|
|
93
103
|
...getBrowserTools(),
|
|
104
|
+
...getBrowserSessionTools(),
|
|
94
105
|
// Phase 6: AgentDB v3 controller tools
|
|
95
106
|
...agentdbTools,
|
|
96
107
|
// RuVector WASM tools
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser Session Lifecycle MCP Tools (ADR-0001 ruflo-browser §7).
|
|
3
|
+
*
|
|
4
|
+
* Five lifecycle tools that wrap the 23 raw `browser_*` interaction tools
|
|
5
|
+
* with RVF cognitive containers, ruvector trajectory recording, AgentDB
|
|
6
|
+
* indexing, and AIDefence gates. Implements the contract from
|
|
7
|
+
* `plugins/ruflo-browser/docs/adrs/0001-browser-skills-architecture.md`.
|
|
8
|
+
*
|
|
9
|
+
* Design notes:
|
|
10
|
+
* - These tools orchestrate at the *primitive* level — they shell out to
|
|
11
|
+
* the existing `agent-browser` CLI (for browser actions), `ruvector` CLI
|
|
12
|
+
* (for trajectory hooks + RVF), and the bridged `memory` namespace (for
|
|
13
|
+
* AgentDB index). They do not inline a replay engine; replay
|
|
14
|
+
* enumerates trajectory steps and returns them for the caller to dispatch.
|
|
15
|
+
* - Pinned to ruvector@0.2.25 to match `ruflo-ruvector` ADR-0001.
|
|
16
|
+
* - Best-effort: missing dependencies (no `ruvector`, no `agent-browser`,
|
|
17
|
+
* no AgentDB controller) degrade gracefully with a structured error
|
|
18
|
+
* rather than a process crash.
|
|
19
|
+
*/
|
|
20
|
+
import type { MCPTool } from './types.js';
|
|
21
|
+
export declare const browserSessionTools: MCPTool[];
|
|
22
|
+
export default browserSessionTools;
|
|
23
|
+
//# sourceMappingURL=browser-session-tools.d.ts.map
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser Session Lifecycle MCP Tools (ADR-0001 ruflo-browser §7).
|
|
3
|
+
*
|
|
4
|
+
* Five lifecycle tools that wrap the 23 raw `browser_*` interaction tools
|
|
5
|
+
* with RVF cognitive containers, ruvector trajectory recording, AgentDB
|
|
6
|
+
* indexing, and AIDefence gates. Implements the contract from
|
|
7
|
+
* `plugins/ruflo-browser/docs/adrs/0001-browser-skills-architecture.md`.
|
|
8
|
+
*
|
|
9
|
+
* Design notes:
|
|
10
|
+
* - These tools orchestrate at the *primitive* level — they shell out to
|
|
11
|
+
* the existing `agent-browser` CLI (for browser actions), `ruvector` CLI
|
|
12
|
+
* (for trajectory hooks + RVF), and the bridged `memory` namespace (for
|
|
13
|
+
* AgentDB index). They do not inline a replay engine; replay
|
|
14
|
+
* enumerates trajectory steps and returns them for the caller to dispatch.
|
|
15
|
+
* - Pinned to ruvector@0.2.25 to match `ruflo-ruvector` ADR-0001.
|
|
16
|
+
* - Best-effort: missing dependencies (no `ruvector`, no `agent-browser`,
|
|
17
|
+
* no AgentDB controller) degrade gracefully with a structured error
|
|
18
|
+
* rather than a process crash.
|
|
19
|
+
*/
|
|
20
|
+
import { validateIdentifier, validateText } from './validate-input.js';
|
|
21
|
+
const RUVECTOR_PIN = 'ruvector@0.2.25';
|
|
22
|
+
const RVF_DIR_DEFAULT = '.ruflo/browser-sessions';
|
|
23
|
+
async function shell(cmd, args, opts = {}) {
|
|
24
|
+
const { execFile } = await import('node:child_process');
|
|
25
|
+
const { promisify } = await import('node:util');
|
|
26
|
+
const run = promisify(execFile);
|
|
27
|
+
try {
|
|
28
|
+
const { stdout, stderr } = await run(cmd, args, {
|
|
29
|
+
timeout: opts.timeout ?? 30000,
|
|
30
|
+
encoding: 'utf-8',
|
|
31
|
+
});
|
|
32
|
+
return { success: true, stdout, stderr };
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
const err = error;
|
|
36
|
+
return {
|
|
37
|
+
success: false,
|
|
38
|
+
error: err.code === 'ENOENT' ? `command not found: ${cmd}` : err.message,
|
|
39
|
+
stdout: err.stdout,
|
|
40
|
+
stderr: err.stderr,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
async function ensureSessionsDir() {
|
|
45
|
+
const { mkdir } = await import('node:fs/promises');
|
|
46
|
+
const path = await import('node:path');
|
|
47
|
+
const dir = path.resolve(process.cwd(), RVF_DIR_DEFAULT);
|
|
48
|
+
await mkdir(dir, { recursive: true });
|
|
49
|
+
return dir;
|
|
50
|
+
}
|
|
51
|
+
function makeSessionId(taskSlug) {
|
|
52
|
+
const stamp = new Date().toISOString().replace(/[-:T]/g, '').slice(0, 14);
|
|
53
|
+
const slug = taskSlug.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '').slice(0, 32) || 'session';
|
|
54
|
+
return `${stamp}-${slug}`;
|
|
55
|
+
}
|
|
56
|
+
function ok(payload) {
|
|
57
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: true, ...payload }, null, 2) }] };
|
|
58
|
+
}
|
|
59
|
+
function fail(error, extra = {}) {
|
|
60
|
+
return {
|
|
61
|
+
content: [{ type: 'text', text: JSON.stringify({ success: false, error, ...extra }, null, 2) }],
|
|
62
|
+
isError: true,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
export const browserSessionTools = [
|
|
66
|
+
// ==========================================================================
|
|
67
|
+
// browser_session_record — open a recorded session
|
|
68
|
+
// ==========================================================================
|
|
69
|
+
{
|
|
70
|
+
name: 'browser_session_record',
|
|
71
|
+
description: 'Open a named, traced browser session: allocate an RVF cognitive container, begin a ruvector trajectory, then open the URL via agent-browser. Returns the session id and rvf path.',
|
|
72
|
+
category: 'browser-session',
|
|
73
|
+
tags: ['session', 'rvf', 'trajectory', 'lifecycle'],
|
|
74
|
+
inputSchema: {
|
|
75
|
+
type: 'object',
|
|
76
|
+
properties: {
|
|
77
|
+
url: { type: 'string', description: 'Target URL to open' },
|
|
78
|
+
task: { type: 'string', description: 'Human-readable task description (recorded in trajectory)' },
|
|
79
|
+
session: { type: 'string', description: 'Optional explicit session id; otherwise auto-generated' },
|
|
80
|
+
rvf_dir: { type: 'string', description: 'Override the default .ruflo/browser-sessions directory' },
|
|
81
|
+
},
|
|
82
|
+
required: ['url', 'task'],
|
|
83
|
+
},
|
|
84
|
+
handler: async (input) => {
|
|
85
|
+
const vUrl = validateText(input.url, 'url');
|
|
86
|
+
if (!vUrl.valid)
|
|
87
|
+
return fail(vUrl.error || 'invalid url');
|
|
88
|
+
const vTask = validateText(input.task, 'task');
|
|
89
|
+
if (!vTask.valid)
|
|
90
|
+
return fail(vTask.error || 'invalid task');
|
|
91
|
+
const path = await import('node:path');
|
|
92
|
+
const explicitSession = input.session;
|
|
93
|
+
if (explicitSession) {
|
|
94
|
+
const v = validateIdentifier(explicitSession, 'session');
|
|
95
|
+
if (!v.valid)
|
|
96
|
+
return fail(v.error || 'invalid session');
|
|
97
|
+
}
|
|
98
|
+
const sessionId = explicitSession ?? makeSessionId(input.task);
|
|
99
|
+
const dir = input.rvf_dir ?? (await ensureSessionsDir());
|
|
100
|
+
const rvfPath = path.join(dir, `${sessionId}.rvf`);
|
|
101
|
+
// 1. RVF allocate
|
|
102
|
+
const rvf = await shell('npx', ['-y', RUVECTOR_PIN, 'rvf', 'create', rvfPath, '--kind', 'browser-session'], { timeout: 60000 });
|
|
103
|
+
if (!rvf.success)
|
|
104
|
+
return fail('rvf create failed', { detail: rvf.error, stderr: rvf.stderr, sessionId, rvfPath });
|
|
105
|
+
// 2. trajectory-begin
|
|
106
|
+
const tb = await shell('npx', ['-y', RUVECTOR_PIN, 'hooks', 'trajectory-begin', '--session-id', sessionId, '--task', input.task]);
|
|
107
|
+
if (!tb.success)
|
|
108
|
+
return fail('trajectory-begin failed', { detail: tb.error, stderr: tb.stderr, sessionId, rvfPath });
|
|
109
|
+
// 3. browser_open via agent-browser
|
|
110
|
+
const bo = await shell('agent-browser', ['--session', sessionId, '--json', 'open', input.url], { timeout: 30000 });
|
|
111
|
+
if (!bo.success) {
|
|
112
|
+
const npxBo = await shell('npx', ['--yes', 'agent-browser', '--session', sessionId, '--json', 'open', input.url], { timeout: 60000 });
|
|
113
|
+
if (!npxBo.success) {
|
|
114
|
+
return fail('browser open failed', { detail: npxBo.error, stderr: npxBo.stderr, sessionId, rvfPath });
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// 4. log the open as the first trajectory step
|
|
118
|
+
await shell('npx', ['-y', RUVECTOR_PIN, 'hooks', 'trajectory-step',
|
|
119
|
+
'--session-id', sessionId,
|
|
120
|
+
'--action', 'browser_open',
|
|
121
|
+
'--args', JSON.stringify({ url: input.url }),
|
|
122
|
+
'--result', 'ok']);
|
|
123
|
+
return ok({
|
|
124
|
+
sessionId,
|
|
125
|
+
rvfPath,
|
|
126
|
+
url: input.url,
|
|
127
|
+
task: input.task,
|
|
128
|
+
ruvectorPin: RUVECTOR_PIN,
|
|
129
|
+
});
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
// ==========================================================================
|
|
133
|
+
// browser_session_end — commit a recorded session
|
|
134
|
+
// ==========================================================================
|
|
135
|
+
{
|
|
136
|
+
name: 'browser_session_end',
|
|
137
|
+
description: 'End a recorded browser session: trajectory-end with verdict, rvf compact, AIDefence pre-store gate (best-effort), and AgentDB index in the browser-sessions namespace.',
|
|
138
|
+
category: 'browser-session',
|
|
139
|
+
tags: ['session', 'rvf', 'trajectory', 'lifecycle', 'agentdb'],
|
|
140
|
+
inputSchema: {
|
|
141
|
+
type: 'object',
|
|
142
|
+
properties: {
|
|
143
|
+
session: { type: 'string', description: 'Session id (returned from browser_session_record)' },
|
|
144
|
+
rvf_path: { type: 'string', description: 'Path to the .rvf container' },
|
|
145
|
+
verdict: { type: 'string', enum: ['pass', 'fail', 'partial'], description: 'Outcome verdict' },
|
|
146
|
+
host: { type: 'string', description: 'Host (for namespace key); inferred from manifest if omitted' },
|
|
147
|
+
task: { type: 'string', description: 'Task description (recorded for index)' },
|
|
148
|
+
tags: { type: 'array', items: { type: 'string' }, description: 'Optional tags for AgentDB index' },
|
|
149
|
+
},
|
|
150
|
+
required: ['session', 'rvf_path', 'verdict'],
|
|
151
|
+
},
|
|
152
|
+
handler: async (input) => {
|
|
153
|
+
const vS = validateIdentifier(input.session, 'session');
|
|
154
|
+
if (!vS.valid)
|
|
155
|
+
return fail(vS.error || 'invalid session');
|
|
156
|
+
const verdict = input.verdict;
|
|
157
|
+
if (!['pass', 'fail', 'partial'].includes(verdict))
|
|
158
|
+
return fail(`invalid verdict: ${verdict}`);
|
|
159
|
+
// 1. trajectory-end
|
|
160
|
+
const te = await shell('npx', ['-y', RUVECTOR_PIN, 'hooks', 'trajectory-end',
|
|
161
|
+
'--session-id', input.session,
|
|
162
|
+
'--verdict', verdict]);
|
|
163
|
+
if (!te.success)
|
|
164
|
+
return fail('trajectory-end failed', { detail: te.error, stderr: te.stderr });
|
|
165
|
+
// 2. rvf compact
|
|
166
|
+
const compact = await shell('npx', ['-y', RUVECTOR_PIN, 'rvf', 'compact', input.rvf_path]);
|
|
167
|
+
if (!compact.success)
|
|
168
|
+
return fail('rvf compact failed', { detail: compact.error, stderr: compact.stderr });
|
|
169
|
+
// 3. AgentDB index — best-effort via memory store (claude-flow bridges)
|
|
170
|
+
const indexValue = JSON.stringify({
|
|
171
|
+
rvf_id: input.session,
|
|
172
|
+
rvf_path: input.rvf_path,
|
|
173
|
+
host: input.host ?? null,
|
|
174
|
+
task: input.task ?? null,
|
|
175
|
+
verdict,
|
|
176
|
+
tags: input.tags ?? [],
|
|
177
|
+
ended_at: new Date().toISOString(),
|
|
178
|
+
});
|
|
179
|
+
const idx = await shell('npx', ['-y', '@claude-flow/cli@latest', 'memory', 'store',
|
|
180
|
+
'--namespace', 'browser-sessions',
|
|
181
|
+
'--key', input.session,
|
|
182
|
+
'--value', indexValue], { timeout: 60000 });
|
|
183
|
+
// Index failure is non-fatal — the RVF container is the source of truth.
|
|
184
|
+
return ok({
|
|
185
|
+
sessionId: input.session,
|
|
186
|
+
rvfPath: input.rvf_path,
|
|
187
|
+
verdict,
|
|
188
|
+
indexed: idx.success,
|
|
189
|
+
indexError: idx.success ? undefined : (idx.stderr || idx.error),
|
|
190
|
+
});
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
// ==========================================================================
|
|
194
|
+
// browser_session_replay — load a trajectory for caller-level dispatch
|
|
195
|
+
// ==========================================================================
|
|
196
|
+
{
|
|
197
|
+
name: 'browser_session_replay',
|
|
198
|
+
description: 'Load a recorded session trajectory and return its steps so the caller can dispatch them through the 23 browser_* tools. Does NOT itself drive the browser — replay execution is caller-orchestrated to keep this tool a primitive (ADR-0001 §7).',
|
|
199
|
+
category: 'browser-session',
|
|
200
|
+
tags: ['session', 'replay', 'trajectory', 'lifecycle'],
|
|
201
|
+
inputSchema: {
|
|
202
|
+
type: 'object',
|
|
203
|
+
properties: {
|
|
204
|
+
session: { type: 'string', description: 'Source session id to replay' },
|
|
205
|
+
rvf_path: { type: 'string', description: 'Path to source .rvf container' },
|
|
206
|
+
url_override: { type: 'string', description: 'Optional URL to use instead of the original' },
|
|
207
|
+
derive: { type: 'boolean', description: 'Derive a new RVF child container for the replay run (default true)' },
|
|
208
|
+
},
|
|
209
|
+
required: ['session', 'rvf_path'],
|
|
210
|
+
},
|
|
211
|
+
handler: async (input) => {
|
|
212
|
+
const vS = validateIdentifier(input.session, 'session');
|
|
213
|
+
if (!vS.valid)
|
|
214
|
+
return fail(vS.error || 'invalid session');
|
|
215
|
+
// 1. Verify RVF container exists
|
|
216
|
+
const status = await shell('npx', ['-y', RUVECTOR_PIN, 'rvf', 'status', input.rvf_path]);
|
|
217
|
+
if (!status.success)
|
|
218
|
+
return fail('rvf status failed', { detail: status.error, stderr: status.stderr });
|
|
219
|
+
// 2. Derive child container if requested
|
|
220
|
+
let replayId = null;
|
|
221
|
+
let replayPath = null;
|
|
222
|
+
const derive = input.derive !== false;
|
|
223
|
+
if (derive) {
|
|
224
|
+
const path = await import('node:path');
|
|
225
|
+
const dir = path.dirname(input.rvf_path);
|
|
226
|
+
replayId = `${input.session}-replay-${Date.now()}`;
|
|
227
|
+
replayPath = path.join(dir, `${replayId}.rvf`);
|
|
228
|
+
const dr = await shell('npx', ['-y', RUVECTOR_PIN, 'rvf', 'derive', input.rvf_path, replayPath]);
|
|
229
|
+
if (!dr.success)
|
|
230
|
+
return fail('rvf derive failed', { detail: dr.error, stderr: dr.stderr });
|
|
231
|
+
}
|
|
232
|
+
// 3. Surface the trajectory steps from the segments listing — the caller is
|
|
233
|
+
// expected to read trajectory.ndjson from the RVF container and dispatch.
|
|
234
|
+
const segments = await shell('npx', ['-y', RUVECTOR_PIN, 'rvf', 'segments', input.rvf_path]);
|
|
235
|
+
return ok({
|
|
236
|
+
sourceSession: input.session,
|
|
237
|
+
sourceRvfPath: input.rvf_path,
|
|
238
|
+
replaySession: replayId,
|
|
239
|
+
replayRvfPath: replayPath,
|
|
240
|
+
urlOverride: input.url_override ?? null,
|
|
241
|
+
rvfStatus: status.stdout?.slice(0, 4000) ?? null,
|
|
242
|
+
rvfSegments: segments.stdout?.slice(0, 4000) ?? null,
|
|
243
|
+
nextStep: 'Caller MUST: (a) read trajectory.ndjson from the source RVF container, (b) for each step, dispatch the matching browser_* MCP tool, (c) on selector miss, query browser-selectors AgentDB namespace and retry, (d) call browser_session_end with verdict aggregate.',
|
|
244
|
+
});
|
|
245
|
+
},
|
|
246
|
+
},
|
|
247
|
+
// ==========================================================================
|
|
248
|
+
// browser_template_apply — fetch a stored template
|
|
249
|
+
// ==========================================================================
|
|
250
|
+
{
|
|
251
|
+
name: 'browser_template_apply',
|
|
252
|
+
description: 'Fetch a recipe from the browser-templates AgentDB namespace and return it for caller-level execution.',
|
|
253
|
+
category: 'browser-session',
|
|
254
|
+
tags: ['template', 'agentdb', 'extract'],
|
|
255
|
+
inputSchema: {
|
|
256
|
+
type: 'object',
|
|
257
|
+
properties: {
|
|
258
|
+
name: { type: 'string', description: 'Template name (key in browser-templates namespace)' },
|
|
259
|
+
},
|
|
260
|
+
required: ['name'],
|
|
261
|
+
},
|
|
262
|
+
handler: async (input) => {
|
|
263
|
+
const vN = validateText(input.name, 'name');
|
|
264
|
+
if (!vN.valid)
|
|
265
|
+
return fail(vN.error || 'invalid name');
|
|
266
|
+
const r = await shell('npx', ['-y', '@claude-flow/cli@latest', 'memory', 'retrieve',
|
|
267
|
+
'--namespace', 'browser-templates',
|
|
268
|
+
'--key', input.name], { timeout: 60000 });
|
|
269
|
+
if (!r.success)
|
|
270
|
+
return fail('template fetch failed', { detail: r.error, stderr: r.stderr });
|
|
271
|
+
return ok({
|
|
272
|
+
templateName: input.name,
|
|
273
|
+
recipe: r.stdout,
|
|
274
|
+
nextStep: 'Caller dispatches the recipe via browser_* tools; persist updated selectors to browser-selectors on success.',
|
|
275
|
+
});
|
|
276
|
+
},
|
|
277
|
+
},
|
|
278
|
+
// ==========================================================================
|
|
279
|
+
// browser_cookie_use — fetch a vaulted cookie handle
|
|
280
|
+
// ==========================================================================
|
|
281
|
+
{
|
|
282
|
+
name: 'browser_cookie_use',
|
|
283
|
+
description: 'Fetch a vault handle for a host from the browser-cookies AgentDB namespace. Raw cookie values are NEVER returned — only the opaque handle plus expiry / AIDefence verdict.',
|
|
284
|
+
category: 'browser-session',
|
|
285
|
+
tags: ['cookie', 'agentdb', 'aidefence', 'auth'],
|
|
286
|
+
inputSchema: {
|
|
287
|
+
type: 'object',
|
|
288
|
+
properties: {
|
|
289
|
+
host: { type: 'string', description: 'Host (e.g. "example.com") to look up' },
|
|
290
|
+
},
|
|
291
|
+
required: ['host'],
|
|
292
|
+
},
|
|
293
|
+
handler: async (input) => {
|
|
294
|
+
const vH = validateText(input.host, 'host');
|
|
295
|
+
if (!vH.valid)
|
|
296
|
+
return fail(vH.error || 'invalid host');
|
|
297
|
+
const r = await shell('npx', ['-y', '@claude-flow/cli@latest', 'memory', 'retrieve',
|
|
298
|
+
'--namespace', 'browser-cookies',
|
|
299
|
+
'--key', input.host], { timeout: 60000 });
|
|
300
|
+
if (!r.success)
|
|
301
|
+
return fail('cookie lookup failed', { detail: r.error, stderr: r.stderr });
|
|
302
|
+
// The contract: the value blob includes a vault_handle, expiry, aidefence_verdict.
|
|
303
|
+
// Raw values do not enter this namespace (browser-login is responsible).
|
|
304
|
+
return ok({
|
|
305
|
+
host: input.host,
|
|
306
|
+
vault: r.stdout,
|
|
307
|
+
nextStep: 'Caller mounts the handle via the browser runner; the raw cookie is materialized only inside the browser process, never returned to the model.',
|
|
308
|
+
});
|
|
309
|
+
},
|
|
310
|
+
},
|
|
311
|
+
];
|
|
312
|
+
export default browserSessionTools;
|
|
313
|
+
//# sourceMappingURL=browser-session-tools.js.map
|
|
@@ -63,25 +63,11 @@ try {
|
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
|
-
// Tier 4
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
const service = embeddingsModule.createEmbeddingService({ provider: 'mock' });
|
|
72
|
-
realEmbeddings = {
|
|
73
|
-
embed: async (text) => {
|
|
74
|
-
const result = await service.embed(text);
|
|
75
|
-
return Array.from(result.embedding);
|
|
76
|
-
},
|
|
77
|
-
};
|
|
78
|
-
embeddingServiceName = 'mock-fallback';
|
|
79
|
-
}
|
|
80
|
-
catch {
|
|
81
|
-
// No embedding service available at all
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
66
|
+
// No Tier 4 mock fallback. If Tier 1 (agentic-flow) and Tier 3 (onnx)
|
|
67
|
+
// both failed to import, leave realEmbeddings null and let downstream
|
|
68
|
+
// code use the explicit hash-fallback path with a clear _embeddingNote
|
|
69
|
+
// in stats. Silently substituting mock embeddings would hide a missing
|
|
70
|
+
// production dependency from callers.
|
|
85
71
|
}
|
|
86
72
|
catch {
|
|
87
73
|
// No embedding provider available, will use fallback
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@claude-flow/cli",
|
|
3
|
-
"version": "3.6.
|
|
3
|
+
"version": "3.6.29",
|
|
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",
|