@mfjjs/ruflo-setup 0.2.7 → 0.2.9
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/CHANGELOG.md +16 -0
- package/README.md +65 -4
- package/package.json +1 -1
- package/src/setup.js +414 -380
- package/src/utils.js +120 -120
- package/templates/ruflo-setup.md +92 -90
package/src/utils.js
CHANGED
|
@@ -1,120 +1,120 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import readline from 'node:readline';
|
|
4
|
-
|
|
5
|
-
export function pathExists(filePath) {
|
|
6
|
-
return fs.existsSync(filePath);
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export function readJsonSafe(filePath, fallbackValue = {}) {
|
|
10
|
-
if (!pathExists(filePath)) {
|
|
11
|
-
return fallbackValue;
|
|
12
|
-
}
|
|
13
|
-
try {
|
|
14
|
-
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
15
|
-
} catch {
|
|
16
|
-
return fallbackValue;
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function writeJson(filePath, value) {
|
|
21
|
-
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
22
|
-
fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`, 'utf8');
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export function copyFileSync(src, dest) {
|
|
26
|
-
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
27
|
-
fs.copyFileSync(src, dest);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export async function confirm(question) {
|
|
31
|
-
const rl = readline.createInterface({
|
|
32
|
-
input: process.stdin,
|
|
33
|
-
output: process.stdout
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
const answer = await new Promise((resolve) => {
|
|
37
|
-
rl.question(question, resolve);
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
rl.close();
|
|
41
|
-
return /^[Yy]$/.test((answer || '').trim());
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export function parseArgs(argv) {
|
|
45
|
-
const flags = {
|
|
46
|
-
force: false,
|
|
47
|
-
dryRun: false,
|
|
48
|
-
yes: false,
|
|
49
|
-
noHooks: false,
|
|
50
|
-
skipInit: false,
|
|
51
|
-
verbose: false,
|
|
52
|
-
command: 'setup'
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
const positional = [];
|
|
56
|
-
for (const item of argv) {
|
|
57
|
-
if (item === '--force' || item === '-f') flags.force = true;
|
|
58
|
-
else if (item === '--dry-run') flags.dryRun = true;
|
|
59
|
-
else if (item === '--yes' || item === '-y') flags.yes = true;
|
|
60
|
-
else if (item === '--no-hooks') flags.noHooks = true;
|
|
61
|
-
else if (item === '--skip-init') flags.skipInit = true;
|
|
62
|
-
else if (item === '--verbose') flags.verbose = true;
|
|
63
|
-
else positional.push(item);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (positional.length > 0) {
|
|
67
|
-
flags.command = positional[0];
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
return flags;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export function toPlatformMcpConfig(platform) {
|
|
74
|
-
const isWindows = platform === 'win32';
|
|
75
|
-
const command = isWindows ? 'cmd' : '
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
const makeArgs = (pkg, extraArgs) => {
|
|
79
|
-
return [...
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
return {
|
|
83
|
-
mcpServers: {
|
|
84
|
-
'claude-flow': {
|
|
85
|
-
command,
|
|
86
|
-
args: makeArgs('@claude-flow/cli@latest', ['mcp', 'start']),
|
|
87
|
-
env: {
|
|
88
|
-
npm_config_update_notifier: 'false',
|
|
89
|
-
CLAUDE_FLOW_MODE: 'v3',
|
|
90
|
-
CLAUDE_FLOW_HOOKS_ENABLED: 'true',
|
|
91
|
-
CLAUDE_FLOW_TOPOLOGY: 'hierarchical-mesh',
|
|
92
|
-
CLAUDE_FLOW_MAX_AGENTS: '15',
|
|
93
|
-
CLAUDE_FLOW_MEMORY_BACKEND: 'hybrid',
|
|
94
|
-
MCP_GROUP_SECURITY: 'true',
|
|
95
|
-
MCP_GROUP_BROWSER: 'true',
|
|
96
|
-
MCP_GROUP_NEURAL: 'true',
|
|
97
|
-
MCP_GROUP_AGENTIC_FLOW: 'true'
|
|
98
|
-
},
|
|
99
|
-
autoStart: false
|
|
100
|
-
},
|
|
101
|
-
'ruv-swarm': {
|
|
102
|
-
command,
|
|
103
|
-
args: makeArgs('ruv-swarm', ['mcp', 'start']),
|
|
104
|
-
env: {
|
|
105
|
-
npm_config_update_notifier: 'false'
|
|
106
|
-
},
|
|
107
|
-
optional: true
|
|
108
|
-
},
|
|
109
|
-
'flow-nexus': {
|
|
110
|
-
command,
|
|
111
|
-
args: makeArgs('flow-nexus@latest', ['mcp', 'start']),
|
|
112
|
-
env: {
|
|
113
|
-
npm_config_update_notifier: 'false'
|
|
114
|
-
},
|
|
115
|
-
optional: true,
|
|
116
|
-
requiresAuth: true
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
};
|
|
120
|
-
}
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import readline from 'node:readline';
|
|
4
|
+
|
|
5
|
+
export function pathExists(filePath) {
|
|
6
|
+
return fs.existsSync(filePath);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function readJsonSafe(filePath, fallbackValue = {}) {
|
|
10
|
+
if (!pathExists(filePath)) {
|
|
11
|
+
return fallbackValue;
|
|
12
|
+
}
|
|
13
|
+
try {
|
|
14
|
+
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
15
|
+
} catch {
|
|
16
|
+
return fallbackValue;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function writeJson(filePath, value) {
|
|
21
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
22
|
+
fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`, 'utf8');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function copyFileSync(src, dest) {
|
|
26
|
+
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
27
|
+
fs.copyFileSync(src, dest);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export async function confirm(question) {
|
|
31
|
+
const rl = readline.createInterface({
|
|
32
|
+
input: process.stdin,
|
|
33
|
+
output: process.stdout
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const answer = await new Promise((resolve) => {
|
|
37
|
+
rl.question(question, resolve);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
rl.close();
|
|
41
|
+
return /^[Yy]$/.test((answer || '').trim());
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function parseArgs(argv) {
|
|
45
|
+
const flags = {
|
|
46
|
+
force: false,
|
|
47
|
+
dryRun: false,
|
|
48
|
+
yes: false,
|
|
49
|
+
noHooks: false,
|
|
50
|
+
skipInit: false,
|
|
51
|
+
verbose: false,
|
|
52
|
+
command: 'setup'
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const positional = [];
|
|
56
|
+
for (const item of argv) {
|
|
57
|
+
if (item === '--force' || item === '-f') flags.force = true;
|
|
58
|
+
else if (item === '--dry-run') flags.dryRun = true;
|
|
59
|
+
else if (item === '--yes' || item === '-y') flags.yes = true;
|
|
60
|
+
else if (item === '--no-hooks') flags.noHooks = true;
|
|
61
|
+
else if (item === '--skip-init') flags.skipInit = true;
|
|
62
|
+
else if (item === '--verbose') flags.verbose = true;
|
|
63
|
+
else positional.push(item);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (positional.length > 0) {
|
|
67
|
+
flags.command = positional[0];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return flags;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function toPlatformMcpConfig(platform) {
|
|
74
|
+
const isWindows = platform === 'win32';
|
|
75
|
+
const command = isWindows ? 'cmd' : 'npx';
|
|
76
|
+
const npxArgs = isWindows ? ['/c', 'npx', '-y'] : ['-y'];
|
|
77
|
+
|
|
78
|
+
const makeArgs = (pkg, extraArgs) => {
|
|
79
|
+
return [...npxArgs, pkg, ...extraArgs];
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
mcpServers: {
|
|
84
|
+
'claude-flow': {
|
|
85
|
+
command,
|
|
86
|
+
args: makeArgs('@claude-flow/cli@latest', ['mcp', 'start']),
|
|
87
|
+
env: {
|
|
88
|
+
npm_config_update_notifier: 'false',
|
|
89
|
+
CLAUDE_FLOW_MODE: 'v3',
|
|
90
|
+
CLAUDE_FLOW_HOOKS_ENABLED: 'true',
|
|
91
|
+
CLAUDE_FLOW_TOPOLOGY: 'hierarchical-mesh',
|
|
92
|
+
CLAUDE_FLOW_MAX_AGENTS: '15',
|
|
93
|
+
CLAUDE_FLOW_MEMORY_BACKEND: 'hybrid',
|
|
94
|
+
MCP_GROUP_SECURITY: 'true',
|
|
95
|
+
MCP_GROUP_BROWSER: 'true',
|
|
96
|
+
MCP_GROUP_NEURAL: 'true',
|
|
97
|
+
MCP_GROUP_AGENTIC_FLOW: 'true'
|
|
98
|
+
},
|
|
99
|
+
autoStart: false
|
|
100
|
+
},
|
|
101
|
+
'ruv-swarm': {
|
|
102
|
+
command,
|
|
103
|
+
args: makeArgs('ruv-swarm', ['mcp', 'start']),
|
|
104
|
+
env: {
|
|
105
|
+
npm_config_update_notifier: 'false'
|
|
106
|
+
},
|
|
107
|
+
optional: true
|
|
108
|
+
},
|
|
109
|
+
'flow-nexus': {
|
|
110
|
+
command,
|
|
111
|
+
args: makeArgs('flow-nexus@latest', ['mcp', 'start']),
|
|
112
|
+
env: {
|
|
113
|
+
npm_config_update_notifier: 'false'
|
|
114
|
+
},
|
|
115
|
+
optional: true,
|
|
116
|
+
requiresAuth: true
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
}
|
package/templates/ruflo-setup.md
CHANGED
|
@@ -1,90 +1,92 @@
|
|
|
1
|
-
# /ruflo-setup
|
|
2
|
-
|
|
3
|
-
Set up Ruflo + Claude Flow V3 in the current project directory.
|
|
4
|
-
|
|
5
|
-
## Requirements
|
|
6
|
-
|
|
7
|
-
- Node.js 20+
|
|
8
|
-
- pnpm 10.32.1+ installed and available on PATH
|
|
9
|
-
|
|
10
|
-
Quickest pnpm install by platform:
|
|
11
|
-
|
|
12
|
-
```bash
|
|
13
|
-
# Windows (recommended)
|
|
14
|
-
winget install -e --id pnpm.pnpm
|
|
15
|
-
|
|
16
|
-
# macOS (recommended)
|
|
17
|
-
brew install pnpm
|
|
18
|
-
|
|
19
|
-
# Linux (recommended)
|
|
20
|
-
curl -fsSL https://get.pnpm.io/install.sh | sh -
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
Alternative (all platforms with recent Node.js):
|
|
24
|
-
|
|
25
|
-
```bash
|
|
26
|
-
corepack enable
|
|
27
|
-
corepack prepare pnpm@latest --activate
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
## What this does
|
|
31
|
-
|
|
32
|
-
Runs `pnpm add -g @mfjjs/ruflo-setup` then `ruflo-setup` which:
|
|
33
|
-
|
|
34
|
-
1. Runs `pnpm add -g ruflo@latest` then `ruflo init --full` to install:
|
|
35
|
-
- `.claude/settings.json` with hooks, permissions, and Claude Flow config
|
|
36
|
-
- `.claude/helpers/` — hook-handler, statusline, auto-memory scripts
|
|
37
|
-
- `.claude/agents/` — 120+ agent definitions
|
|
38
|
-
- `.claude/skills/` — 30+ skill definitions
|
|
39
|
-
- `.claude/commands/` — slash commands
|
|
40
|
-
2. Writes a platform-aware `.mcp.json` (MCP server registration for claude-flow, ruv-swarm, flow-nexus)
|
|
41
|
-
3.
|
|
42
|
-
4.
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
pnpm add -g
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
```
|
|
90
|
-
|
|
1
|
+
# /ruflo-setup
|
|
2
|
+
|
|
3
|
+
Set up Ruflo + Claude Flow V3 in the current project directory.
|
|
4
|
+
|
|
5
|
+
## Requirements
|
|
6
|
+
|
|
7
|
+
- Node.js 20+
|
|
8
|
+
- pnpm 10.32.1+ installed and available on PATH
|
|
9
|
+
|
|
10
|
+
Quickest pnpm install by platform:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
# Windows (recommended)
|
|
14
|
+
winget install -e --id pnpm.pnpm
|
|
15
|
+
|
|
16
|
+
# macOS (recommended)
|
|
17
|
+
brew install pnpm
|
|
18
|
+
|
|
19
|
+
# Linux (recommended)
|
|
20
|
+
curl -fsSL https://get.pnpm.io/install.sh | sh -
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Alternative (all platforms with recent Node.js):
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
corepack enable
|
|
27
|
+
corepack prepare pnpm@latest --activate
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## What this does
|
|
31
|
+
|
|
32
|
+
Runs `pnpm add -g @mfjjs/ruflo-setup` then `ruflo-setup` which:
|
|
33
|
+
|
|
34
|
+
1. Runs `pnpm add -g ruflo@latest` then `ruflo init --full` to install:
|
|
35
|
+
- `.claude/settings.json` with hooks, permissions, and Claude Flow config
|
|
36
|
+
- `.claude/helpers/` — hook-handler, statusline, auto-memory scripts
|
|
37
|
+
- `.claude/agents/` — 120+ agent definitions
|
|
38
|
+
- `.claude/skills/` — 30+ skill definitions
|
|
39
|
+
- `.claude/commands/` — slash commands
|
|
40
|
+
2. Writes a platform-aware `.mcp.json` (MCP server registration for claude-flow, ruv-swarm, flow-nexus; servers invoked via `npx` for cross-platform compatibility)
|
|
41
|
+
3. Adds `.mcp.json` and `.claude/settings.json` to the project's `.gitignore`
|
|
42
|
+
4. Installs a global `SessionStart` hook in `~/.claude/settings.json` that warns when Ruflo is not configured
|
|
43
|
+
5. May refresh `~/.claude/commands/ruflo-setup.md` from the latest packaged template when differences are detected
|
|
44
|
+
|
|
45
|
+
## Options
|
|
46
|
+
|
|
47
|
+
### cleanup
|
|
48
|
+
|
|
49
|
+
Removes all Ruflo-related packages from the **npm** global registry (does not touch pnpm globals).
|
|
50
|
+
|
|
51
|
+
Packages removed: `ruflo`, `@mfjjs/ruflo-setup`, `ruflo-setup`, `claude-flow`, `@claude-flow/cli`, `ruv-swarm`
|
|
52
|
+
|
|
53
|
+
## Instructions for Claude
|
|
54
|
+
|
|
55
|
+
When the user runs /ruflo-setup:
|
|
56
|
+
|
|
57
|
+
### Default (no arguments) — install
|
|
58
|
+
|
|
59
|
+
1. Confirm the current working directory with the user
|
|
60
|
+
2. Check if `.mcp.json` already exists — if so, warn and ask before overwriting
|
|
61
|
+
3. Check pnpm version is at least 10.32.1:
|
|
62
|
+
```bash
|
|
63
|
+
pnpm --version
|
|
64
|
+
```
|
|
65
|
+
If the version is lower than 10.32.1, stop and tell the user to upgrade pnpm before continuing.
|
|
66
|
+
4. Run the setup CLI and capture output to detect whether pnpm modified anything:
|
|
67
|
+
```bash
|
|
68
|
+
pnpm add -g @mfjjs/ruflo-setup
|
|
69
|
+
pnpm add -g ruflo@latest 2>&1 | tee /tmp/ruflo-pnpm-add.log
|
|
70
|
+
```
|
|
71
|
+
After the `pnpm add -g ruflo@latest` step, inspect the output. If pnpm installed or updated any packages (i.e. the output does NOT contain "Already up to date" or an equivalent no-change message), run:
|
|
72
|
+
```bash
|
|
73
|
+
pnpm approve-builds -g --all
|
|
74
|
+
```
|
|
75
|
+
Skip `approve-builds` if nothing changed.
|
|
76
|
+
5. Run the setup tool:
|
|
77
|
+
```bash
|
|
78
|
+
ruflo-setup
|
|
79
|
+
```
|
|
80
|
+
6. Ensure `.mcp.json` and `.claude/settings.json` are in the project's `.gitignore` (ruflo-setup does this automatically, but verify if using `--skip-init`)
|
|
81
|
+
7. Report what was installed and remind the user to restart Claude Code to load the new MCP servers
|
|
82
|
+
|
|
83
|
+
### cleanup
|
|
84
|
+
|
|
85
|
+
When the user runs `/ruflo-setup cleanup`:
|
|
86
|
+
|
|
87
|
+
1. Warn the user that this will remove Ruflo packages from the **npm** global registry and ask for confirmation
|
|
88
|
+
2. On confirmation, run:
|
|
89
|
+
```bash
|
|
90
|
+
ruflo-setup cleanup
|
|
91
|
+
```
|
|
92
|
+
3. Report which packages were removed and which were not found (not found is fine — it means they were already clean)
|