@mfjjs/ruflo-setup 0.2.5 → 0.2.7
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 +14 -0
- package/README.md +77 -26
- package/package.json +1 -1
- package/src/cli.js +29 -1
- package/src/setup.js +163 -18
- package/src/status.js +4 -11
- package/templates/ruflo-setup.md +38 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
### [0.2.7](///compare/v0.2.6...v0.2.7) (2026-03-20)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* **cli:** add update command to upgrade ruflo-setup to the latest version 569bc0b
|
|
11
|
+
|
|
12
|
+
### [0.2.6](///compare/v0.2.5...v0.2.6) (2026-03-20)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
* **cli:** add cleanup command to remove Ruflo packages from npm global registry. 5151c70
|
|
18
|
+
|
|
5
19
|
### [0.2.5](///compare/v0.2.4...v0.2.5) (2026-03-17)
|
|
6
20
|
|
|
7
21
|
### [0.2.4](https://gitlab.mfj.local:8022/mario/ruflo-setup/compare/v0.2.3...v0.2.4) (2026-03-17)
|
package/README.md
CHANGED
|
@@ -11,12 +11,26 @@ Cross-platform npm CLI to bootstrap a project with Ruflo on Windows and Linux.
|
|
|
11
11
|
- Package name: `@mfjjs/ruflo-setup`
|
|
12
12
|
- Command name: `ruflo-setup`
|
|
13
13
|
- Platform support: Windows and Linux (plus macOS by default)
|
|
14
|
+
|
|
15
|
+
## 💡 Why You Need This
|
|
16
|
+
|
|
17
|
+
If you're working on:
|
|
18
|
+
|
|
19
|
+
* A brownfield application that never had RuFlow configured, or
|
|
20
|
+
* A brand‑new project that hasn't been set up with RuFlow yet,
|
|
21
|
+
|
|
22
|
+
…then you currently have to configure RuFlow manually in each project. That means recreating the same structure, wiring, and boilerplate over and over.
|
|
23
|
+
|
|
24
|
+
`ruflo-setup` eliminates all of that. When you run it inside a project directory, it automatically generates the required RuFlow scaffolding — including all the files that belong in the `.claude/` folder — so every project starts from a clean, consistent baseline.
|
|
25
|
+
|
|
26
|
+
You only need to do this once per project. Just run the command and you're ready to go.
|
|
27
|
+
|
|
14
28
|
## 📋 Requirements
|
|
15
29
|
<details>
|
|
16
30
|
<summary>Click to toggle visibility</summary>
|
|
17
31
|
|
|
18
32
|
- Node.js 20+
|
|
19
|
-
- pnpm available on PATH
|
|
33
|
+
- pnpm **10.32.1 or higher** available on PATH
|
|
20
34
|
|
|
21
35
|
Quickest pnpm install by platform:
|
|
22
36
|
|
|
@@ -41,26 +55,50 @@ corepack prepare pnpm@latest --activate
|
|
|
41
55
|
|
|
42
56
|
## 📦 Installation
|
|
43
57
|
|
|
44
|
-
|
|
45
|
-
|
|
58
|
+
Install the CLI globally once:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
pnpm add -g @mfjjs/ruflo-setup
|
|
46
62
|
```
|
|
47
63
|
|
|
48
|
-
##
|
|
64
|
+
## 🚀 Usage
|
|
49
65
|
|
|
50
|
-
|
|
66
|
+
### Setup
|
|
51
67
|
|
|
52
|
-
|
|
53
|
-
* A brand‑new project that hasn’t been set up with RuFlow yet,
|
|
68
|
+
**First, change to your project directory**, then run:
|
|
54
69
|
|
|
55
|
-
|
|
70
|
+
```bash
|
|
71
|
+
ruflo-setup
|
|
72
|
+
```
|
|
56
73
|
|
|
57
|
-
|
|
74
|
+
That's it for most users. The command will:
|
|
75
|
+
1. Check for a newer version of itself and offer to update before proceeding
|
|
76
|
+
2. Install `ruflo@latest` globally and run `ruflo init --full` to scaffold your project
|
|
77
|
+
3. Write a platform-aware `.mcp.json`
|
|
78
|
+
4. Install a global Claude Code `SessionStart` hook
|
|
58
79
|
|
|
59
|
-
|
|
80
|
+
Additional options:
|
|
60
81
|
|
|
61
|
-
|
|
82
|
+
```bash
|
|
83
|
+
# non-interactive (skip all prompts)
|
|
84
|
+
ruflo-setup --yes
|
|
85
|
+
|
|
86
|
+
# preview what would happen without making any changes
|
|
87
|
+
ruflo-setup --dry-run
|
|
88
|
+
|
|
89
|
+
# skip the ruflo global install step
|
|
90
|
+
ruflo-setup --skip-init
|
|
91
|
+
|
|
92
|
+
# skip global hook installation
|
|
93
|
+
ruflo-setup --no-hooks
|
|
94
|
+
|
|
95
|
+
# hook operations
|
|
96
|
+
ruflo-setup hooks install
|
|
97
|
+
ruflo-setup hooks status
|
|
98
|
+
```
|
|
62
99
|
|
|
63
100
|
### Status
|
|
101
|
+
|
|
64
102
|
Check whether all Ruflo feature layers (0–8) are enabled in the current project:
|
|
65
103
|
|
|
66
104
|
```bash
|
|
@@ -70,7 +108,8 @@ ruflo-setup status
|
|
|
70
108
|
This prints a layer-by-layer report showing which features are active — prerequisites, global packages, optional WASM/ML packages, MCP servers, tool groups, environment variables, project scaffolding, and the Docker chat UI stack.
|
|
71
109
|
|
|
72
110
|
### Bootstrap
|
|
73
|
-
|
|
111
|
+
|
|
112
|
+
Use this once if you want Claude Code to expose the `/ruflo-setup` command globally, so you can run it from inside Claude Code chat without using the shell.
|
|
74
113
|
|
|
75
114
|
```bash
|
|
76
115
|
ruflo-setup hooks init
|
|
@@ -78,27 +117,34 @@ ruflo-setup hooks init
|
|
|
78
117
|
|
|
79
118
|
After that, when you open Claude Code in a project that does not already have Ruflo configured, you can run [**/ruflo-setup**](noop:) to start the setup flow.
|
|
80
119
|
|
|
81
|
-
###
|
|
82
|
-
Use these commands when you want to run the setup directly from a shell.
|
|
120
|
+
### Update
|
|
83
121
|
|
|
84
|
-
|
|
122
|
+
Update `@mfjjs/ruflo-setup` itself to the latest published version:
|
|
85
123
|
|
|
86
124
|
```bash
|
|
87
|
-
|
|
88
|
-
|
|
125
|
+
ruflo-setup update
|
|
126
|
+
```
|
|
89
127
|
|
|
90
|
-
|
|
91
|
-
ruflo-setup --yes
|
|
128
|
+
It is best to always have the latest version before running setup. When you run `ruflo-setup` without arguments it automatically checks for a newer version and will prompt you to update if one is found, so in most cases you will not need to run this manually.
|
|
92
129
|
|
|
93
|
-
|
|
94
|
-
|
|
130
|
+
```bash
|
|
131
|
+
# preview without making changes
|
|
132
|
+
ruflo-setup update --dry-run
|
|
133
|
+
```
|
|
95
134
|
|
|
96
|
-
|
|
97
|
-
ruflo-setup --no-hooks
|
|
135
|
+
### Cleanup
|
|
98
136
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
137
|
+
If you previously installed any Ruflo packages via `npm install -g`, those npm-global copies can shadow or conflict with the pnpm-managed versions. Run this to remove them and give yourself a clean slate:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
ruflo-setup cleanup
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
This uninstalls `ruflo`, `@mfjjs/ruflo-setup`, `ruflo-setup`, `claude-flow`, `@claude-flow/cli`, and `ruv-swarm` from the **npm** global registry only — it does not touch pnpm globals.
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
# preview what would be removed without making changes
|
|
147
|
+
ruflo-setup cleanup --dry-run
|
|
102
148
|
```
|
|
103
149
|
|
|
104
150
|
## 🗂️ Project structure
|
|
@@ -137,6 +183,7 @@ Flow:
|
|
|
137
183
|
3. `bin/ruflo-setup.js` forwards args to `runCli(...)`.
|
|
138
184
|
4. `src/cli.js` parses command and flags.
|
|
139
185
|
5. `src/setup.js` runs setup steps:
|
|
186
|
+
- checks for a newer version of itself and prompts to update
|
|
140
187
|
- optional `pnpm add -g ruflo@latest` then `ruflo init --full`
|
|
141
188
|
- writes platform-aware `.mcp.json`
|
|
142
189
|
- copies `templates/CLAUDE.md`
|
|
@@ -144,6 +191,10 @@ Flow:
|
|
|
144
191
|
|
|
145
192
|
When called as `ruflo-setup status`, step 5 dispatches to `src/status.js` which checks all layers (0–8) and prints a feature status report.
|
|
146
193
|
|
|
194
|
+
When called as `ruflo-setup update`, it runs `pnpm add -g @mfjjs/ruflo-setup@latest` to update the tool itself.
|
|
195
|
+
|
|
196
|
+
When called as `ruflo-setup cleanup`, it removes Ruflo packages from the npm global registry to eliminate conflicts with pnpm-managed versions.
|
|
197
|
+
|
|
147
198
|
## 🛠️ Local development with pnpm
|
|
148
199
|
|
|
149
200
|
From this repository root (`setup-ruflo/`):
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -2,7 +2,7 @@ import path from 'node:path';
|
|
|
2
2
|
import { fileURLToPath } from 'node:url';
|
|
3
3
|
import { createRequire } from 'node:module';
|
|
4
4
|
import { parseArgs } from './utils.js';
|
|
5
|
-
import { runSetup } from './setup.js';
|
|
5
|
+
import { runSetup, runCleanup, runUpdate } from './setup.js';
|
|
6
6
|
import { getGlobalHookStatus, installGlobalCheckRufloHook } from './hooks.js';
|
|
7
7
|
|
|
8
8
|
const require = createRequire(import.meta.url);
|
|
@@ -19,6 +19,8 @@ function printHelp() {
|
|
|
19
19
|
Usage:
|
|
20
20
|
ruflo-setup [options]
|
|
21
21
|
ruflo-setup status
|
|
22
|
+
ruflo-setup update [--dry-run]
|
|
23
|
+
ruflo-setup cleanup [--dry-run]
|
|
22
24
|
ruflo-setup hooks install [options]
|
|
23
25
|
ruflo-setup hooks status
|
|
24
26
|
|
|
@@ -31,9 +33,17 @@ Options:
|
|
|
31
33
|
--version, -v Print version and exit
|
|
32
34
|
--verbose Extra output
|
|
33
35
|
|
|
36
|
+
Commands:
|
|
37
|
+
update Update @mfjjs/ruflo-setup itself to the latest published version
|
|
38
|
+
cleanup Remove all Ruflo packages from the npm global registry
|
|
39
|
+
(ruflo, @mfjjs/ruflo-setup, claude-flow, @claude-flow/cli, ruv-swarm)
|
|
40
|
+
|
|
34
41
|
Examples:
|
|
35
42
|
ruflo-setup
|
|
43
|
+
ruflo-setup update
|
|
36
44
|
ruflo-setup status
|
|
45
|
+
ruflo-setup cleanup
|
|
46
|
+
ruflo-setup cleanup --dry-run
|
|
37
47
|
ruflo-setup --dry-run --skip-init
|
|
38
48
|
ruflo-setup hooks status
|
|
39
49
|
ruflo-setup hooks install --dry-run
|
|
@@ -93,6 +103,24 @@ export async function runCli(argv, cwd) {
|
|
|
93
103
|
return 1;
|
|
94
104
|
}
|
|
95
105
|
|
|
106
|
+
if (flags.command === 'update') {
|
|
107
|
+
runUpdate({ dryRun: flags.dryRun });
|
|
108
|
+
return 0;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (flags.command === 'cleanup') {
|
|
112
|
+
if (!flags.dryRun && !flags.yes) {
|
|
113
|
+
const { confirm } = await import('./utils.js');
|
|
114
|
+
const ok = await confirm('Remove Ruflo packages from npm global registry? [y/N] ');
|
|
115
|
+
if (!ok) {
|
|
116
|
+
process.stdout.write('Aborted. No changes made.\n');
|
|
117
|
+
return 0;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
runCleanup({ dryRun: flags.dryRun });
|
|
121
|
+
return 0;
|
|
122
|
+
}
|
|
123
|
+
|
|
96
124
|
await runSetup({
|
|
97
125
|
cwd,
|
|
98
126
|
packageRoot,
|
package/src/setup.js
CHANGED
|
@@ -33,30 +33,49 @@ function getPnpmInstallSuggestions(platform) {
|
|
|
33
33
|
];
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
const MIN_PNPM_VERSION = '10.32.1';
|
|
37
|
+
|
|
38
|
+
function parseSemver(str) {
|
|
39
|
+
const [major = 0, minor = 0, patch = 0] = str.trim().split('.').map(Number);
|
|
40
|
+
return { major, minor, patch };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function semverGte(a, b) {
|
|
44
|
+
if (a.major !== b.major) return a.major > b.major;
|
|
45
|
+
if (a.minor !== b.minor) return a.minor > b.minor;
|
|
46
|
+
return a.patch >= b.patch;
|
|
47
|
+
}
|
|
48
|
+
|
|
36
49
|
function ensurePnpmAvailable() {
|
|
37
50
|
const check = spawnSync('pnpm', ['--version'], {
|
|
38
|
-
stdio: 'ignore',
|
|
51
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
39
52
|
shell: process.platform === 'win32'
|
|
40
53
|
});
|
|
41
54
|
|
|
42
|
-
if (check.status
|
|
43
|
-
|
|
55
|
+
if (check.status !== 0 || check.error) {
|
|
56
|
+
const platformLabel = process.platform === 'win32'
|
|
57
|
+
? 'Windows'
|
|
58
|
+
: process.platform === 'darwin'
|
|
59
|
+
? 'macOS'
|
|
60
|
+
: 'Linux';
|
|
61
|
+
const suggestions = getPnpmInstallSuggestions(process.platform)
|
|
62
|
+
.map((command) => ` - ${command}`)
|
|
63
|
+
.join('\n');
|
|
64
|
+
|
|
65
|
+
throw new Error(
|
|
66
|
+
`pnpm is required but was not found in PATH.\n` +
|
|
67
|
+
`Install pnpm, then re-run ruflo-setup.\n` +
|
|
68
|
+
`Quick install options for ${platformLabel}:\n${suggestions}`
|
|
69
|
+
);
|
|
44
70
|
}
|
|
45
71
|
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
:
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
.join('\n');
|
|
54
|
-
|
|
55
|
-
throw new Error(
|
|
56
|
-
`pnpm is required but was not found in PATH.\n` +
|
|
57
|
-
`Install pnpm, then re-run ruflo-setup.\n` +
|
|
58
|
-
`Quick install options for ${platformLabel}:\n${suggestions}`
|
|
59
|
-
);
|
|
72
|
+
const version = (check.stdout || '').toString().trim();
|
|
73
|
+
if (!semverGte(parseSemver(version), parseSemver(MIN_PNPM_VERSION))) {
|
|
74
|
+
throw new Error(
|
|
75
|
+
`pnpm ${MIN_PNPM_VERSION} or higher is required, but found ${version}.\n` +
|
|
76
|
+
`Upgrade with: pnpm self-update`
|
|
77
|
+
);
|
|
78
|
+
}
|
|
60
79
|
}
|
|
61
80
|
|
|
62
81
|
function runPnpmInit({ force, cwd, dryRun }) {
|
|
@@ -67,22 +86,46 @@ function runPnpmInit({ force, cwd, dryRun }) {
|
|
|
67
86
|
|
|
68
87
|
if (dryRun) {
|
|
69
88
|
logLine(` [DRY RUN] Would run: pnpm add -g ruflo@latest`);
|
|
89
|
+
logLine(` [DRY RUN] Would run: pnpm approve-builds -g --all (if changes detected)`);
|
|
70
90
|
logLine(` [DRY RUN] Would run: ruflo ${initArgs.join(' ')}`);
|
|
71
91
|
return;
|
|
72
92
|
}
|
|
73
93
|
|
|
74
94
|
ensurePnpmAvailable();
|
|
75
95
|
|
|
96
|
+
// Capture stdout to detect whether pnpm installed/updated anything.
|
|
97
|
+
// Progress spinners go to stderr (still shown to user); stdout has the summary.
|
|
76
98
|
const install = spawnSync('pnpm', ['add', '-g', 'ruflo@latest'], {
|
|
77
99
|
cwd,
|
|
78
|
-
stdio: 'inherit',
|
|
100
|
+
stdio: ['inherit', 'pipe', 'inherit'],
|
|
79
101
|
shell: process.platform === 'win32'
|
|
80
102
|
});
|
|
81
103
|
|
|
104
|
+
const installOutput = (install.stdout || '').toString();
|
|
105
|
+
if (installOutput) {
|
|
106
|
+
process.stdout.write(installOutput);
|
|
107
|
+
}
|
|
108
|
+
|
|
82
109
|
if (install.status !== 0) {
|
|
83
110
|
throw new Error(`pnpm add -g ruflo@latest failed with exit code ${install.status}`);
|
|
84
111
|
}
|
|
85
112
|
|
|
113
|
+
// pnpm prints a "Packages:" summary line and "+ pkg version" lines when
|
|
114
|
+
// something is actually installed or updated. When already up to date the
|
|
115
|
+
// stdout is empty or contains only "Already up to date".
|
|
116
|
+
const somethingChanged = /Packages:/i.test(installOutput) || /^\+\s/m.test(installOutput);
|
|
117
|
+
if (somethingChanged) {
|
|
118
|
+
logLine(' Changes detected — running pnpm approve-builds -g --all ...');
|
|
119
|
+
const approve = spawnSync('pnpm', ['approve-builds', '-g', '--all'], {
|
|
120
|
+
cwd,
|
|
121
|
+
stdio: 'inherit',
|
|
122
|
+
shell: process.platform === 'win32'
|
|
123
|
+
});
|
|
124
|
+
if (approve.status !== 0) {
|
|
125
|
+
throw new Error(`pnpm approve-builds -g --all failed with exit code ${approve.status}`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
86
129
|
const run = spawnSync('ruflo', initArgs, {
|
|
87
130
|
cwd,
|
|
88
131
|
stdio: 'inherit',
|
|
@@ -128,6 +171,29 @@ function isAlreadyConfigured(cwd) {
|
|
|
128
171
|
return pathExists(path.join(cwd, '.mcp.json')) || pathExists(path.join(cwd, '.claude', 'settings.json'));
|
|
129
172
|
}
|
|
130
173
|
|
|
174
|
+
function getCurrentVersion(packageRoot) {
|
|
175
|
+
try {
|
|
176
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(packageRoot, 'package.json'), 'utf8'));
|
|
177
|
+
return pkg.version || '0.0.0';
|
|
178
|
+
} catch {
|
|
179
|
+
return '0.0.0';
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function getLatestVersion() {
|
|
184
|
+
try {
|
|
185
|
+
const result = spawnSync('pnpm', ['view', '@mfjjs/ruflo-setup', 'version'], {
|
|
186
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
187
|
+
shell: process.platform === 'win32',
|
|
188
|
+
timeout: 8000
|
|
189
|
+
});
|
|
190
|
+
if (result.status !== 0 || result.error) return null;
|
|
191
|
+
return (result.stdout || '').toString().trim() || null;
|
|
192
|
+
} catch {
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
131
197
|
export async function runSetup({
|
|
132
198
|
cwd,
|
|
133
199
|
packageRoot,
|
|
@@ -146,6 +212,24 @@ export async function runSetup({
|
|
|
146
212
|
}
|
|
147
213
|
logLine('');
|
|
148
214
|
|
|
215
|
+
// Check if a newer version of ruflo-setup itself is available.
|
|
216
|
+
if (!dryRun && !yes) {
|
|
217
|
+
const currentVersion = getCurrentVersion(packageRoot);
|
|
218
|
+
const latestVersion = getLatestVersion();
|
|
219
|
+
if (latestVersion && !semverGte(parseSemver(currentVersion), parseSemver(latestVersion))) {
|
|
220
|
+
logLine(`A newer version of ruflo-setup is available: ${latestVersion} (you have ${currentVersion}).`);
|
|
221
|
+
logLine('It is best to always have the latest version before running setup.');
|
|
222
|
+
const doUpdate = await confirm('Update @mfjjs/ruflo-setup now? [y/N] ');
|
|
223
|
+
if (doUpdate) {
|
|
224
|
+
runUpdate({ dryRun: false });
|
|
225
|
+
logLine('');
|
|
226
|
+
logLine('Please re-run ruflo-setup to continue with the updated version.');
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
logLine('');
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
149
233
|
logLine('Preflight: Syncing global /ruflo-setup command template ...');
|
|
150
234
|
const preflightCommandResult = syncGlobalCommandTemplate({ packageRoot, dryRun });
|
|
151
235
|
if (preflightCommandResult.changed) {
|
|
@@ -233,3 +317,64 @@ export async function runSetup({
|
|
|
233
317
|
logLine(' 2. Run: claude');
|
|
234
318
|
logLine(' 3. Verify hooks: ruflo-setup hooks status');
|
|
235
319
|
}
|
|
320
|
+
|
|
321
|
+
const CLEANUP_NPM_PACKAGES = [
|
|
322
|
+
'ruflo',
|
|
323
|
+
'@mfjjs/ruflo-setup',
|
|
324
|
+
'ruflo-setup',
|
|
325
|
+
'claude-flow',
|
|
326
|
+
'@claude-flow/cli',
|
|
327
|
+
'ruv-swarm'
|
|
328
|
+
];
|
|
329
|
+
|
|
330
|
+
export function runCleanup({ dryRun = false } = {}) {
|
|
331
|
+
logLine('');
|
|
332
|
+
logLine('Ruflo Cleanup — removing from npm global registry');
|
|
333
|
+
logLine(`Packages: ${CLEANUP_NPM_PACKAGES.join(', ')}`);
|
|
334
|
+
logLine('');
|
|
335
|
+
|
|
336
|
+
if (dryRun) {
|
|
337
|
+
logLine(` [DRY RUN] Would run: npm uninstall -g ${CLEANUP_NPM_PACKAGES.join(' ')}`);
|
|
338
|
+
logLine('');
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
const result = spawnSync('npm', ['uninstall', '-g', ...CLEANUP_NPM_PACKAGES], {
|
|
343
|
+
stdio: 'inherit',
|
|
344
|
+
shell: process.platform === 'win32'
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
if (result.status !== 0) {
|
|
348
|
+
throw new Error(`npm uninstall -g failed with exit code ${result.status}`);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
logLine('');
|
|
352
|
+
logLine('Cleanup complete.');
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
export function runUpdate({ dryRun = false } = {}) {
|
|
356
|
+
logLine('');
|
|
357
|
+
logLine('Ruflo Setup Update');
|
|
358
|
+
logLine('');
|
|
359
|
+
|
|
360
|
+
if (dryRun) {
|
|
361
|
+
logLine('[DRY RUN] Would run: pnpm add -g @mfjjs/ruflo-setup@latest');
|
|
362
|
+
logLine('');
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
ensurePnpmAvailable();
|
|
367
|
+
|
|
368
|
+
logLine('Updating @mfjjs/ruflo-setup to latest...');
|
|
369
|
+
const result = spawnSync('pnpm', ['add', '-g', '@mfjjs/ruflo-setup@latest'], {
|
|
370
|
+
stdio: 'inherit',
|
|
371
|
+
shell: process.platform === 'win32'
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
if (result.status !== 0) {
|
|
375
|
+
throw new Error(`pnpm add -g @mfjjs/ruflo-setup@latest failed with exit code ${result.status}`);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
logLine('');
|
|
379
|
+
logLine('Update complete. Re-run ruflo-setup to continue with the updated version.');
|
|
380
|
+
}
|
package/src/status.js
CHANGED
|
@@ -40,12 +40,11 @@ function fileExists(p) {
|
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
// Flatten
|
|
43
|
+
// Flatten pnpm --json list result into a name->version map (1 level deep).
|
|
44
44
|
function buildPkgMap(jsonText) {
|
|
45
45
|
const map = {};
|
|
46
46
|
try {
|
|
47
47
|
const parsed = JSON.parse(jsonText || '{}');
|
|
48
|
-
// npm list -g returns an array with one element, pnpm returns an object
|
|
49
48
|
const root = Array.isArray(parsed) ? parsed[0] : parsed;
|
|
50
49
|
const deps = root?.dependencies ?? {};
|
|
51
50
|
for (const [name, info] of Object.entries(deps)) {
|
|
@@ -60,13 +59,7 @@ function buildPkgMap(jsonText) {
|
|
|
60
59
|
return map;
|
|
61
60
|
}
|
|
62
61
|
|
|
63
|
-
// Tries npm list -g first, falls back to pnpm list -g.
|
|
64
62
|
function getGlobalPkgMap() {
|
|
65
|
-
const npmRes = spawn('npm', ['list', '-g', '--depth=1', '--json']);
|
|
66
|
-
if (npmRes.status === 0 && npmRes.stdout) {
|
|
67
|
-
const m = buildPkgMap(npmRes.stdout);
|
|
68
|
-
if (Object.keys(m).length > 0) return m;
|
|
69
|
-
}
|
|
70
63
|
const pnpmRes = spawn('pnpm', ['list', '-g', '--depth=1', '--json']);
|
|
71
64
|
if (pnpmRes.status === 0 && pnpmRes.stdout) {
|
|
72
65
|
return buildPkgMap(pnpmRes.stdout);
|
|
@@ -95,7 +88,7 @@ function checkLayer0() {
|
|
|
95
88
|
const ver = (claudeRes.stdout || '').trim();
|
|
96
89
|
lines.push(` ${OK} Claude Code CLI${ver ? ` ${ver}` : ''}`); ok += 1;
|
|
97
90
|
} else {
|
|
98
|
-
lines.push(` ${MISS} Claude Code CLI (install:
|
|
91
|
+
lines.push(` ${MISS} Claude Code CLI (install: pnpm add -g @anthropic-ai/claude-code)`);
|
|
99
92
|
}
|
|
100
93
|
|
|
101
94
|
if (process.env.ANTHROPIC_API_KEY) {
|
|
@@ -113,7 +106,7 @@ function checkLayer1(pkgMap) {
|
|
|
113
106
|
for (const name of ['ruflo', '@mfjjs/ruflo-setup']) {
|
|
114
107
|
const ver = pkgMap[name];
|
|
115
108
|
if (ver) { lines.push(` ${OK} ${name}${typeof ver === 'string' ? `@${ver}` : ''}`); ok += 1; }
|
|
116
|
-
else { lines.push(` ${MISS} ${name} (install:
|
|
109
|
+
else { lines.push(` ${MISS} ${name} (install: pnpm add -g ${name})`); }
|
|
117
110
|
}
|
|
118
111
|
return { lines, ok, total: 2 };
|
|
119
112
|
}
|
|
@@ -268,7 +261,7 @@ export async function runStatus({ cwd, packageRoot }) {
|
|
|
268
261
|
|
|
269
262
|
const layers = [
|
|
270
263
|
{ title: 'Layer 0: Prerequisites', result: checkLayer0() },
|
|
271
|
-
{ title: 'Layer 1: Global
|
|
264
|
+
{ title: 'Layer 1: Global Packages', result: checkLayer1(pkgMap) },
|
|
272
265
|
{ title: 'Layer 2: Optional Packages (WASM/ML) — enables AI features', result: checkLayer2(pkgMap) },
|
|
273
266
|
{ title: 'Layer 3: MCP Servers (.mcp.json)', result: checkLayer3(mcpJson) },
|
|
274
267
|
{ title: 'Layer 4: MCP Tool Groups', result: checkLayer4(mcpJson) },
|
package/templates/ruflo-setup.md
CHANGED
|
@@ -5,7 +5,7 @@ Set up Ruflo + Claude Flow V3 in the current project directory.
|
|
|
5
5
|
## Requirements
|
|
6
6
|
|
|
7
7
|
- Node.js 20+
|
|
8
|
-
- pnpm installed and available on PATH
|
|
8
|
+
- pnpm 10.32.1+ installed and available on PATH
|
|
9
9
|
|
|
10
10
|
Quickest pnpm install by platform:
|
|
11
11
|
|
|
@@ -41,15 +41,50 @@ Runs `pnpm add -g @mfjjs/ruflo-setup` then `ruflo-setup` which:
|
|
|
41
41
|
3. Installs a global `SessionStart` hook in `~/.claude/settings.json` that warns when Ruflo is not configured
|
|
42
42
|
4. May refresh `~/.claude/commands/ruflo-setup.md` from the latest packaged template when differences are detected
|
|
43
43
|
|
|
44
|
+
## Options
|
|
45
|
+
|
|
46
|
+
### cleanup
|
|
47
|
+
|
|
48
|
+
Removes all Ruflo-related packages from the **npm** global registry (does not touch pnpm globals).
|
|
49
|
+
|
|
50
|
+
Packages removed: `ruflo`, `@mfjjs/ruflo-setup`, `ruflo-setup`, `claude-flow`, `@claude-flow/cli`, `ruv-swarm`
|
|
51
|
+
|
|
44
52
|
## Instructions for Claude
|
|
45
53
|
|
|
46
54
|
When the user runs /ruflo-setup:
|
|
47
55
|
|
|
56
|
+
### Default (no arguments) — install
|
|
57
|
+
|
|
48
58
|
1. Confirm the current working directory with the user
|
|
49
59
|
2. Check if `.mcp.json` already exists — if so, warn and ask before overwriting
|
|
50
|
-
3.
|
|
60
|
+
3. Check pnpm version is at least 10.32.1:
|
|
61
|
+
```bash
|
|
62
|
+
pnpm --version
|
|
63
|
+
```
|
|
64
|
+
If the version is lower than 10.32.1, stop and tell the user to upgrade pnpm before continuing.
|
|
65
|
+
4. Run the setup CLI and capture output to detect whether pnpm modified anything:
|
|
51
66
|
```bash
|
|
52
67
|
pnpm add -g @mfjjs/ruflo-setup
|
|
68
|
+
pnpm add -g ruflo@latest 2>&1 | tee /tmp/ruflo-pnpm-add.log
|
|
69
|
+
```
|
|
70
|
+
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:
|
|
71
|
+
```bash
|
|
72
|
+
pnpm approve-builds -g --all
|
|
73
|
+
```
|
|
74
|
+
Skip `approve-builds` if nothing changed.
|
|
75
|
+
5. Run the setup tool:
|
|
76
|
+
```bash
|
|
53
77
|
ruflo-setup
|
|
54
78
|
```
|
|
55
|
-
|
|
79
|
+
6. Report what was installed and remind the user to restart Claude Code to load the new MCP servers
|
|
80
|
+
|
|
81
|
+
### cleanup
|
|
82
|
+
|
|
83
|
+
When the user runs `/ruflo-setup cleanup`:
|
|
84
|
+
|
|
85
|
+
1. Warn the user that this will remove Ruflo packages from the **npm** global registry and ask for confirmation
|
|
86
|
+
2. On confirmation, run:
|
|
87
|
+
```bash
|
|
88
|
+
ruflo-setup cleanup
|
|
89
|
+
```
|
|
90
|
+
3. Report which packages were removed and which were not found (not found is fine — it means they were already clean)
|