@mfjjs/ruflo-setup 0.2.6 → 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 +7 -0
- package/README.md +70 -36
- package/package.json +1 -1
- package/src/cli.js +9 -1
- package/src/setup.js +68 -0
- package/src/status.js +4 -11
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
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
|
+
|
|
5
12
|
### [0.2.6](///compare/v0.2.5...v0.2.6) (2026-03-20)
|
|
6
13
|
|
|
7
14
|
|
package/README.md
CHANGED
|
@@ -11,6 +11,20 @@ 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>
|
|
@@ -41,43 +55,50 @@ corepack prepare pnpm@latest --activate
|
|
|
41
55
|
|
|
42
56
|
## 📦 Installation
|
|
43
57
|
|
|
44
|
-
|
|
58
|
+
Install the CLI globally once:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
45
61
|
pnpm add -g @mfjjs/ruflo-setup
|
|
46
|
-
ruflo-setup cleanup
|
|
47
62
|
```
|
|
48
63
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
## 💡 Why You Need This
|
|
64
|
+
## 🚀 Usage
|
|
52
65
|
|
|
53
|
-
|
|
66
|
+
### Setup
|
|
54
67
|
|
|
55
|
-
|
|
56
|
-
* A brand‑new project that hasn’t been set up with RuFlow yet,
|
|
68
|
+
**First, change to your project directory**, then run:
|
|
57
69
|
|
|
58
|
-
|
|
70
|
+
```bash
|
|
71
|
+
ruflo-setup
|
|
72
|
+
```
|
|
59
73
|
|
|
60
|
-
|
|
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
|
|
61
79
|
|
|
62
|
-
|
|
80
|
+
Additional options:
|
|
63
81
|
|
|
64
|
-
|
|
82
|
+
```bash
|
|
83
|
+
# non-interactive (skip all prompts)
|
|
84
|
+
ruflo-setup --yes
|
|
65
85
|
|
|
66
|
-
|
|
67
|
-
|
|
86
|
+
# preview what would happen without making any changes
|
|
87
|
+
ruflo-setup --dry-run
|
|
68
88
|
|
|
69
|
-
|
|
70
|
-
ruflo-setup
|
|
71
|
-
```
|
|
89
|
+
# skip the ruflo global install step
|
|
90
|
+
ruflo-setup --skip-init
|
|
72
91
|
|
|
73
|
-
|
|
92
|
+
# skip global hook installation
|
|
93
|
+
ruflo-setup --no-hooks
|
|
74
94
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
ruflo-setup
|
|
95
|
+
# hook operations
|
|
96
|
+
ruflo-setup hooks install
|
|
97
|
+
ruflo-setup hooks status
|
|
78
98
|
```
|
|
79
99
|
|
|
80
100
|
### Status
|
|
101
|
+
|
|
81
102
|
Check whether all Ruflo feature layers (0–8) are enabled in the current project:
|
|
82
103
|
|
|
83
104
|
```bash
|
|
@@ -87,7 +108,8 @@ ruflo-setup status
|
|
|
87
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.
|
|
88
109
|
|
|
89
110
|
### Bootstrap
|
|
90
|
-
|
|
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.
|
|
91
113
|
|
|
92
114
|
```bash
|
|
93
115
|
ruflo-setup hooks init
|
|
@@ -95,27 +117,34 @@ ruflo-setup hooks init
|
|
|
95
117
|
|
|
96
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.
|
|
97
119
|
|
|
98
|
-
###
|
|
99
|
-
Use these commands when you want to run the setup directly from a shell.
|
|
120
|
+
### Update
|
|
100
121
|
|
|
101
|
-
|
|
122
|
+
Update `@mfjjs/ruflo-setup` itself to the latest published version:
|
|
102
123
|
|
|
103
124
|
```bash
|
|
104
|
-
|
|
105
|
-
|
|
125
|
+
ruflo-setup update
|
|
126
|
+
```
|
|
106
127
|
|
|
107
|
-
|
|
108
|
-
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.
|
|
109
129
|
|
|
110
|
-
|
|
111
|
-
|
|
130
|
+
```bash
|
|
131
|
+
# preview without making changes
|
|
132
|
+
ruflo-setup update --dry-run
|
|
133
|
+
```
|
|
112
134
|
|
|
113
|
-
|
|
114
|
-
ruflo-setup --no-hooks
|
|
135
|
+
### Cleanup
|
|
115
136
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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
|
|
119
148
|
```
|
|
120
149
|
|
|
121
150
|
## 🗂️ Project structure
|
|
@@ -154,6 +183,7 @@ Flow:
|
|
|
154
183
|
3. `bin/ruflo-setup.js` forwards args to `runCli(...)`.
|
|
155
184
|
4. `src/cli.js` parses command and flags.
|
|
156
185
|
5. `src/setup.js` runs setup steps:
|
|
186
|
+
- checks for a newer version of itself and prompts to update
|
|
157
187
|
- optional `pnpm add -g ruflo@latest` then `ruflo init --full`
|
|
158
188
|
- writes platform-aware `.mcp.json`
|
|
159
189
|
- copies `templates/CLAUDE.md`
|
|
@@ -161,6 +191,10 @@ Flow:
|
|
|
161
191
|
|
|
162
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.
|
|
163
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
|
+
|
|
164
198
|
## 🛠️ Local development with pnpm
|
|
165
199
|
|
|
166
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, runCleanup } 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,7 @@ function printHelp() {
|
|
|
19
19
|
Usage:
|
|
20
20
|
ruflo-setup [options]
|
|
21
21
|
ruflo-setup status
|
|
22
|
+
ruflo-setup update [--dry-run]
|
|
22
23
|
ruflo-setup cleanup [--dry-run]
|
|
23
24
|
ruflo-setup hooks install [options]
|
|
24
25
|
ruflo-setup hooks status
|
|
@@ -33,11 +34,13 @@ Options:
|
|
|
33
34
|
--verbose Extra output
|
|
34
35
|
|
|
35
36
|
Commands:
|
|
37
|
+
update Update @mfjjs/ruflo-setup itself to the latest published version
|
|
36
38
|
cleanup Remove all Ruflo packages from the npm global registry
|
|
37
39
|
(ruflo, @mfjjs/ruflo-setup, claude-flow, @claude-flow/cli, ruv-swarm)
|
|
38
40
|
|
|
39
41
|
Examples:
|
|
40
42
|
ruflo-setup
|
|
43
|
+
ruflo-setup update
|
|
41
44
|
ruflo-setup status
|
|
42
45
|
ruflo-setup cleanup
|
|
43
46
|
ruflo-setup cleanup --dry-run
|
|
@@ -100,6 +103,11 @@ export async function runCli(argv, cwd) {
|
|
|
100
103
|
return 1;
|
|
101
104
|
}
|
|
102
105
|
|
|
106
|
+
if (flags.command === 'update') {
|
|
107
|
+
runUpdate({ dryRun: flags.dryRun });
|
|
108
|
+
return 0;
|
|
109
|
+
}
|
|
110
|
+
|
|
103
111
|
if (flags.command === 'cleanup') {
|
|
104
112
|
if (!flags.dryRun && !flags.yes) {
|
|
105
113
|
const { confirm } = await import('./utils.js');
|
package/src/setup.js
CHANGED
|
@@ -171,6 +171,29 @@ function isAlreadyConfigured(cwd) {
|
|
|
171
171
|
return pathExists(path.join(cwd, '.mcp.json')) || pathExists(path.join(cwd, '.claude', 'settings.json'));
|
|
172
172
|
}
|
|
173
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
|
+
|
|
174
197
|
export async function runSetup({
|
|
175
198
|
cwd,
|
|
176
199
|
packageRoot,
|
|
@@ -189,6 +212,24 @@ export async function runSetup({
|
|
|
189
212
|
}
|
|
190
213
|
logLine('');
|
|
191
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
|
+
|
|
192
233
|
logLine('Preflight: Syncing global /ruflo-setup command template ...');
|
|
193
234
|
const preflightCommandResult = syncGlobalCommandTemplate({ packageRoot, dryRun });
|
|
194
235
|
if (preflightCommandResult.changed) {
|
|
@@ -310,3 +351,30 @@ export function runCleanup({ dryRun = false } = {}) {
|
|
|
310
351
|
logLine('');
|
|
311
352
|
logLine('Cleanup complete.');
|
|
312
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) },
|