claude-flow 3.6.27 → 3.6.28
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/scheduled_tasks.lock +1 -0
- package/README.md +12 -2
- package/package.json +1 -1
- package/v3/@claude-flow/cli/README.md +12 -2
- 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
|
@@ -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
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-flow",
|
|
3
|
-
"version": "3.6.
|
|
3
|
+
"version": "3.6.28",
|
|
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
|
|
|
@@ -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.28",
|
|
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",
|