@mfjjs/ruflo-setup 0.1.9 β 0.2.1
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 +22 -0
- package/README.md +14 -0
- package/package.json +1 -1
- package/src/cli.js +8 -0
- package/src/status.js +303 -0
- package/src/utils.js +5 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,28 @@
|
|
|
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.1](https://gitlab.mfj.local:8022/mario/ruflo-setup/compare/v0.2.0...v0.2.1) (2026-03-14)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* **docs:** update usage section by moving status command first ([e98f473](https://gitlab.mfj.local:8022/mario/ruflo-setup/commit/e98f473f25f53031d8cf08cf8d6bd3bfedcae949))
|
|
11
|
+
|
|
12
|
+
## [0.2.0](https://gitlab.mfj.local:8022/mario/ruflo-setup/compare/v0.1.9...v0.2.0) (2026-03-14)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### β BREAKING CHANGES
|
|
16
|
+
|
|
17
|
+
* **cli:** The CLI now includes a new command which may affect existing scripts that rely on the previous command structure.
|
|
18
|
+
|
|
19
|
+
### Features
|
|
20
|
+
|
|
21
|
+
* **cli:** add 'status' command to check feature status ([d551664](https://gitlab.mfj.local:8022/mario/ruflo-setup/commit/d551664619635e7efbbc9a9810266ecfe2212d1c))
|
|
22
|
+
* **docs:** add detailed agents and skills sections to Ruflo benefit documentation ([c66d212](https://gitlab.mfj.local:8022/mario/ruflo-setup/commit/c66d212f4ee25390ab139e43131ecb548b7bcb5c))
|
|
23
|
+
* **docs:** add link to ruflo-benefits.md and renamed to plural ([2820aeb](https://gitlab.mfj.local:8022/mario/ruflo-setup/commit/2820aeb5cebbfad0ac7b568291aa55a49076c6c3))
|
|
24
|
+
* **docs:** update Ruflo benefit documentation with agents and skills sections ([8feb883](https://gitlab.mfj.local:8022/mario/ruflo-setup/commit/8feb8836c88ec5096a907eb4c842b0b3b4c55b4c))
|
|
25
|
+
* **status:** enhance directory checks to display count of agents and skills ([3ade22b](https://gitlab.mfj.local:8022/mario/ruflo-setup/commit/3ade22b10ba1840f405b8f239f2a723f6d4089d7))
|
|
26
|
+
|
|
5
27
|
### [0.1.9](https://gitlab.mfj.local:8022/mario/ruflo-setup/compare/v0.1.8...v0.1.9) (2026-03-13)
|
|
6
28
|
|
|
7
29
|
### [0.1.8](https://gitlab.mfj.local:8022/mario/ruflo-setup/compare/v0.1.7...v0.1.8) (2026-03-13)
|
package/README.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Cross-platform npm CLI to bootstrap a project with Ruflo on Windows and Linux.
|
|
4
4
|
|
|
5
|
+
> **Deep dive:** [`docs/ruflo-benefits.md`](docs/ruflo-benefits.md) is a comprehensive reference (~900 lines) covering every feature layer, the MinCut/RuVector/RVF internals, all 80+ agents, 33 skills, 65 slash commands, and how agents and skills are invoked. Not a quick read.
|
|
6
|
+
|
|
5
7
|
## π What this project is
|
|
6
8
|
|
|
7
9
|
`@mfjjs/ruflo-setup` implements the setup with a Node-based CLI command:
|
|
@@ -58,6 +60,15 @@ You only need to do this once in each folder. Just run the command and youβre
|
|
|
58
60
|
|
|
59
61
|
## π Usage
|
|
60
62
|
|
|
63
|
+
### Status
|
|
64
|
+
Check whether all Ruflo feature layers (0β8) are enabled in the current project:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
ruflo-setup status
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
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
|
+
|
|
61
72
|
### Bootstrap
|
|
62
73
|
Use this once if you want Claude Code to expose the `/ruflo-setup` command globally.
|
|
63
74
|
|
|
@@ -96,6 +107,7 @@ ruflo-setup hooks status
|
|
|
96
107
|
- `bin/ruflo-setup.js`: executable entry file the shell runs
|
|
97
108
|
- `src/cli.js`: command router and argument handling
|
|
98
109
|
- `src/setup.js`: setup workflow (`init`, `.mcp.json`, template copy)
|
|
110
|
+
- `src/status.js`: layer-by-layer feature status checker (Layers 0β8)
|
|
99
111
|
- `src/hooks.js`: global `check-ruflo` hook install/status
|
|
100
112
|
- `src/utils.js`: reusable filesystem and argument helpers
|
|
101
113
|
- `templates/CLAUDE.md`: bundled template copied into target project
|
|
@@ -130,6 +142,8 @@ Flow:
|
|
|
130
142
|
- copies `templates/CLAUDE.md`
|
|
131
143
|
- installs global SessionStart hook (unless skipped)
|
|
132
144
|
|
|
145
|
+
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
|
+
|
|
133
147
|
## π οΈ Local development with pnpm
|
|
134
148
|
|
|
135
149
|
From this repository root (`setup-ruflo/`):
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -18,6 +18,7 @@ function printHelp() {
|
|
|
18
18
|
|
|
19
19
|
Usage:
|
|
20
20
|
ruflo-setup [options]
|
|
21
|
+
ruflo-setup status
|
|
21
22
|
ruflo-setup hooks install [options]
|
|
22
23
|
ruflo-setup hooks status
|
|
23
24
|
|
|
@@ -32,6 +33,7 @@ Options:
|
|
|
32
33
|
|
|
33
34
|
Examples:
|
|
34
35
|
ruflo-setup
|
|
36
|
+
ruflo-setup status
|
|
35
37
|
ruflo-setup --dry-run --skip-init
|
|
36
38
|
ruflo-setup hooks status
|
|
37
39
|
ruflo-setup hooks install --dry-run
|
|
@@ -58,6 +60,12 @@ export async function runCli(argv, cwd) {
|
|
|
58
60
|
const packageRoot = packageRootFromModule();
|
|
59
61
|
const flags = parseArgs(argv);
|
|
60
62
|
|
|
63
|
+
if (flags.command === 'status') {
|
|
64
|
+
const { runStatus } = await import('./status.js');
|
|
65
|
+
await runStatus({ cwd, packageRoot });
|
|
66
|
+
return 0;
|
|
67
|
+
}
|
|
68
|
+
|
|
61
69
|
if (flags.command === 'hooks') {
|
|
62
70
|
const subcommand = argv[1] || 'status';
|
|
63
71
|
if (subcommand === 'status') {
|
package/src/status.js
ADDED
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import { spawnSync } from 'node:child_process';
|
|
5
|
+
import { createRequire } from 'node:module';
|
|
6
|
+
import { readJsonSafe } from './utils.js';
|
|
7
|
+
import { getGlobalHookStatus } from './hooks.js';
|
|
8
|
+
|
|
9
|
+
const require = createRequire(import.meta.url);
|
|
10
|
+
const OK = '[OK]';
|
|
11
|
+
const MISS = '[--]';
|
|
12
|
+
const ERR = '[!!]';
|
|
13
|
+
const IS_WIN = process.platform === 'win32';
|
|
14
|
+
|
|
15
|
+
function spawn(cmd, args) {
|
|
16
|
+
try {
|
|
17
|
+
return spawnSync(cmd, args, {
|
|
18
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
19
|
+
encoding: 'utf8',
|
|
20
|
+
shell: IS_WIN
|
|
21
|
+
});
|
|
22
|
+
} catch {
|
|
23
|
+
return { status: 1, stdout: '' };
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function dirExists(p) {
|
|
28
|
+
try {
|
|
29
|
+
return fs.statSync(p).isDirectory();
|
|
30
|
+
} catch {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function fileExists(p) {
|
|
36
|
+
try {
|
|
37
|
+
return fs.statSync(p).isFile();
|
|
38
|
+
} catch {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Flatten npm/pnpm --json list result into a name->version map (1 level deep).
|
|
44
|
+
function buildPkgMap(jsonText) {
|
|
45
|
+
const map = {};
|
|
46
|
+
try {
|
|
47
|
+
const parsed = JSON.parse(jsonText || '{}');
|
|
48
|
+
// npm list -g returns an array with one element, pnpm returns an object
|
|
49
|
+
const root = Array.isArray(parsed) ? parsed[0] : parsed;
|
|
50
|
+
const deps = root?.dependencies ?? {};
|
|
51
|
+
for (const [name, info] of Object.entries(deps)) {
|
|
52
|
+
map[name] = info?.version ?? true;
|
|
53
|
+
for (const [nname, ninfo] of Object.entries(info?.dependencies ?? {})) {
|
|
54
|
+
if (!(nname in map)) map[nname] = ninfo?.version ?? true;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
} catch {
|
|
58
|
+
// ignore parse errors
|
|
59
|
+
}
|
|
60
|
+
return map;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Tries npm list -g first, falls back to pnpm list -g.
|
|
64
|
+
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
|
+
const pnpmRes = spawn('pnpm', ['list', '-g', '--depth=1', '--json']);
|
|
71
|
+
if (pnpmRes.status === 0 && pnpmRes.stdout) {
|
|
72
|
+
return buildPkgMap(pnpmRes.stdout);
|
|
73
|
+
}
|
|
74
|
+
return {};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Each checkLayer* returns { lines: string[], ok: number, total: number }
|
|
78
|
+
|
|
79
|
+
function checkLayer0() {
|
|
80
|
+
const lines = [];
|
|
81
|
+
let ok = 0;
|
|
82
|
+
const nodeMajor = parseInt(process.version.slice(1), 10);
|
|
83
|
+
if (nodeMajor >= 20) { lines.push(` ${OK} Node.js ${process.version} (>=20 required)`); ok += 1; }
|
|
84
|
+
else { lines.push(` ${ERR} Node.js ${process.version} (>=20 required β upgrade Node.js)`); }
|
|
85
|
+
|
|
86
|
+
const pnpmRes = spawn('pnpm', ['--version']);
|
|
87
|
+
if (pnpmRes.status === 0 && pnpmRes.stdout.trim()) {
|
|
88
|
+
lines.push(` ${OK} pnpm ${pnpmRes.stdout.trim()}`); ok += 1;
|
|
89
|
+
} else {
|
|
90
|
+
lines.push(` ${MISS} pnpm (install: npm install -g pnpm)`);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const claudeRes = spawn('claude', ['--version']);
|
|
94
|
+
if (claudeRes.status === 0) {
|
|
95
|
+
const ver = (claudeRes.stdout || '').trim();
|
|
96
|
+
lines.push(` ${OK} Claude Code CLI${ver ? ` ${ver}` : ''}`); ok += 1;
|
|
97
|
+
} else {
|
|
98
|
+
lines.push(` ${MISS} Claude Code CLI (install: npm install -g @anthropic-ai/claude-code)`);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (process.env.ANTHROPIC_API_KEY) {
|
|
102
|
+
lines.push(` ${OK} ANTHROPIC_API_KEY set`); ok += 1;
|
|
103
|
+
} else {
|
|
104
|
+
lines.push(` ${ERR} ANTHROPIC_API_KEY not set (required for LLM calls)`);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return { lines, ok, total: 4 };
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function checkLayer1(pkgMap) {
|
|
111
|
+
const lines = [];
|
|
112
|
+
let ok = 0;
|
|
113
|
+
for (const name of ['ruflo', '@mfjjs/ruflo-setup']) {
|
|
114
|
+
const ver = pkgMap[name];
|
|
115
|
+
if (ver) { lines.push(` ${OK} ${name}${typeof ver === 'string' ? `@${ver}` : ''}`); ok += 1; }
|
|
116
|
+
else { lines.push(` ${MISS} ${name} (install: npm install -g ${name})`); }
|
|
117
|
+
}
|
|
118
|
+
return { lines, ok, total: 2 };
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function checkLayer2(pkgMap) {
|
|
122
|
+
const lines = [];
|
|
123
|
+
let ok = 0;
|
|
124
|
+
const ATTENTION_WIN_NOTE = '(Windows: requires Windows 11 SDK for NAPI; WASM fallback available)';
|
|
125
|
+
const pkgs = [
|
|
126
|
+
'@claude-flow/memory', '@ruvector/attention', '@claude-flow/aidefence', 'agentic-flow',
|
|
127
|
+
'@ruvector/sona', '@ruvector/router', '@ruvector/learning-wasm',
|
|
128
|
+
'@claude-flow/embeddings', '@claude-flow/guidance', '@claude-flow/codex'
|
|
129
|
+
];
|
|
130
|
+
for (const name of pkgs) {
|
|
131
|
+
const ver = pkgMap[name];
|
|
132
|
+
if (ver) { lines.push(` ${OK} ${name}${typeof ver === 'string' ? `@${ver}` : ''}`); ok += 1; }
|
|
133
|
+
else {
|
|
134
|
+
const note = (name === '@ruvector/attention' && IS_WIN) ? ` ${ATTENTION_WIN_NOTE}` : '';
|
|
135
|
+
lines.push(` ${MISS} ${name}${note}`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return { lines, ok, total: pkgs.length };
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function checkLayer3(mcpJson) {
|
|
142
|
+
const lines = [];
|
|
143
|
+
let ok = 0;
|
|
144
|
+
const servers = mcpJson?.mcpServers ?? {};
|
|
145
|
+
|
|
146
|
+
if (servers['claude-flow']) {
|
|
147
|
+
const args = servers['claude-flow']?.args ?? [];
|
|
148
|
+
const pkgArg = args.find((a) => typeof a === 'string' && a.includes('@claude-flow/cli')) ?? '@claude-flow/cli@latest';
|
|
149
|
+
lines.push(` ${OK} claude-flow (${pkgArg})`); ok += 1;
|
|
150
|
+
} else {
|
|
151
|
+
lines.push(` ${MISS} claude-flow (run ruflo-setup to configure)`);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (servers['ruv-swarm']) { lines.push(` ${OK} ruv-swarm (optional)`); ok += 1; }
|
|
155
|
+
else { lines.push(` ${MISS} ruv-swarm (optional)`); }
|
|
156
|
+
|
|
157
|
+
if (servers['flow-nexus']) { lines.push(` ${OK} flow-nexus (optional)`); ok += 1; }
|
|
158
|
+
else { lines.push(` ${MISS} flow-nexus (optional β needs Cognitum.One account)`); }
|
|
159
|
+
|
|
160
|
+
return { lines, ok, total: 3 };
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function checkLayer4(mcpJson) {
|
|
164
|
+
const lines = [];
|
|
165
|
+
let ok = 0;
|
|
166
|
+
const cfEnv = mcpJson?.mcpServers?.['claude-flow']?.env ?? {};
|
|
167
|
+
const resolve = (k) => { const v = cfEnv[k] ?? process.env[k]; return v === undefined ? null : String(v).toLowerCase(); };
|
|
168
|
+
|
|
169
|
+
for (const g of ['INTELLIGENCE', 'AGENTS', 'MEMORY', 'DEVTOOLS']) {
|
|
170
|
+
if (resolve(`MCP_GROUP_${g}`) === 'false') { lines.push(` ${MISS} ${g} (disabled via MCP_GROUP_${g}=false)`); }
|
|
171
|
+
else { lines.push(` ${OK} ${g} (default on)`); ok += 1; }
|
|
172
|
+
}
|
|
173
|
+
for (const g of ['SECURITY', 'BROWSER', 'NEURAL', 'AGENTIC_FLOW']) {
|
|
174
|
+
if (resolve(`MCP_GROUP_${g}`) === 'true') { lines.push(` ${OK} ${g} (enabled)`); ok += 1; }
|
|
175
|
+
else { lines.push(` ${MISS} ${g} (set MCP_GROUP_${g}=true in .mcp.json env)`); }
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return { lines, ok, total: 8 };
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function checkLayer5() {
|
|
182
|
+
const lines = [];
|
|
183
|
+
let ok = 0;
|
|
184
|
+
const checks = [
|
|
185
|
+
{ key: 'ANTHROPIC_API_KEY', req: true, note: '' },
|
|
186
|
+
{ key: 'OPENAI_API_KEY', req: false, note: '(optional β enables GPT + Codex)' },
|
|
187
|
+
{ key: 'GOOGLE_API_KEY', req: false, note: '(optional β enables Gemini)' },
|
|
188
|
+
{ key: 'OPENROUTER_API_KEY', req: false, note: '(optional β multi-provider proxy)' }
|
|
189
|
+
];
|
|
190
|
+
for (const { key, req, note } of checks) {
|
|
191
|
+
if (process.env[key]) { lines.push(` ${OK} ${key}`); ok += 1; }
|
|
192
|
+
else if (req) { lines.push(` ${ERR} ${key} not set (required for LLM calls)`); }
|
|
193
|
+
else { lines.push(` ${MISS} ${key} ${note}`); }
|
|
194
|
+
}
|
|
195
|
+
return { lines, ok, total: checks.length };
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function checkLayer6(packageRoot) {
|
|
199
|
+
const lines = [];
|
|
200
|
+
let ok = 0;
|
|
201
|
+
const homeDir = os.homedir();
|
|
202
|
+
|
|
203
|
+
try {
|
|
204
|
+
const hs = getGlobalHookStatus({ packageRoot });
|
|
205
|
+
const sp = hs.settingsPath ?? path.join(homeDir, '.claude', 'settings.json');
|
|
206
|
+
if (hs.installed) { lines.push(` ${OK} SessionStart hook (${sp})`); ok += 1; }
|
|
207
|
+
else { lines.push(` ${MISS} SessionStart hook (${sp})`); }
|
|
208
|
+
} catch {
|
|
209
|
+
lines.push(` ${MISS} SessionStart hook (could not read ~/.claude/settings.json)`);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const commandFile = path.join(homeDir, '.claude', 'commands', 'ruflo-setup.md');
|
|
213
|
+
if (fileExists(commandFile)) { lines.push(` ${OK} /ruflo-setup command (${commandFile})`); ok += 1; }
|
|
214
|
+
else { lines.push(` ${MISS} /ruflo-setup command (${commandFile})`); }
|
|
215
|
+
|
|
216
|
+
return { lines, ok, total: 2 };
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function checkLayer7(cwd) {
|
|
220
|
+
const lines = [];
|
|
221
|
+
let ok = 0;
|
|
222
|
+
const files = ['.mcp.json', 'CLAUDE.md', path.join('.claude', 'settings.json')];
|
|
223
|
+
const dirs = [
|
|
224
|
+
{ rel: path.join('.claude', 'agents'), hint: 'run: ruflo init --full' },
|
|
225
|
+
{ rel: path.join('.claude', 'skills'), hint: null },
|
|
226
|
+
{ rel: path.join('.claude', 'commands'), hint: null },
|
|
227
|
+
{ rel: '.claude-flow', hint: null }
|
|
228
|
+
];
|
|
229
|
+
|
|
230
|
+
for (const rel of files) {
|
|
231
|
+
if (fileExists(path.join(cwd, rel))) { lines.push(` ${OK} ${rel}`); ok += 1; }
|
|
232
|
+
else { lines.push(` ${MISS} ${rel}`); }
|
|
233
|
+
}
|
|
234
|
+
for (const { rel, hint } of dirs) {
|
|
235
|
+
const disp = `${rel}/`.replace(/\\/g, '/');
|
|
236
|
+
const full = path.join(cwd, rel);
|
|
237
|
+
if (dirExists(full)) {
|
|
238
|
+
let count = '';
|
|
239
|
+
if (rel.endsWith('agents') || rel.endsWith('skills')) {
|
|
240
|
+
try {
|
|
241
|
+
const n = fs.readdirSync(full).length;
|
|
242
|
+
const label = rel.endsWith('agents') ? 'agents' : 'skills';
|
|
243
|
+
count = ` (${n} ${label})`;
|
|
244
|
+
} catch { /* ignore */ }
|
|
245
|
+
}
|
|
246
|
+
lines.push(` ${OK} ${disp}${count}`); ok += 1;
|
|
247
|
+
} else {
|
|
248
|
+
lines.push(` ${MISS} ${disp}${hint ? ` (${hint})` : ''}`);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return { lines, ok, total: files.length + dirs.length };
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function checkLayer8() {
|
|
256
|
+
const res = spawn('docker', ['--version']);
|
|
257
|
+
if (res.status === 0 && res.stdout.trim()) {
|
|
258
|
+
return { lines: [` ${OK} Docker ${res.stdout.trim()}`], ok: 1, total: 1 };
|
|
259
|
+
}
|
|
260
|
+
return { lines: [` ${MISS} Docker not detected (optional β needed for ruvocal chat UI)`], ok: 0, total: 1 };
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
export async function runStatus({ cwd, packageRoot }) {
|
|
264
|
+
try {
|
|
265
|
+
const { version } = require('../package.json');
|
|
266
|
+
const mcpJson = readJsonSafe(path.join(cwd, '.mcp.json'), {});
|
|
267
|
+
const pkgMap = getGlobalPkgMap();
|
|
268
|
+
|
|
269
|
+
const layers = [
|
|
270
|
+
{ title: 'Layer 0: Prerequisites', result: checkLayer0() },
|
|
271
|
+
{ title: 'Layer 1: Global npm Packages', result: checkLayer1(pkgMap) },
|
|
272
|
+
{ title: 'Layer 2: Optional Packages (WASM/ML) β enables AI features', result: checkLayer2(pkgMap) },
|
|
273
|
+
{ title: 'Layer 3: MCP Servers (.mcp.json)', result: checkLayer3(mcpJson) },
|
|
274
|
+
{ title: 'Layer 4: MCP Tool Groups', result: checkLayer4(mcpJson) },
|
|
275
|
+
{ title: 'Layer 5: Environment Variables', result: checkLayer5() },
|
|
276
|
+
{ title: 'Layer 6: Claude Code Hooks', result: checkLayer6(packageRoot) },
|
|
277
|
+
{ title: 'Layer 7: Project Scaffolding', result: checkLayer7(cwd) },
|
|
278
|
+
{ title: 'Layer 8: Docker Chat UI (optional)', result: checkLayer8() }
|
|
279
|
+
];
|
|
280
|
+
|
|
281
|
+
let totalOk = 0;
|
|
282
|
+
let totalChecks = 0;
|
|
283
|
+
|
|
284
|
+
process.stdout.write(`\nRuflo Feature Status (ruflo-setup v${version})\n`);
|
|
285
|
+
process.stdout.write(`Target: ${cwd}\n`);
|
|
286
|
+
|
|
287
|
+
for (const { title, result } of layers) {
|
|
288
|
+
process.stdout.write(`\n${title}\n`);
|
|
289
|
+
for (const line of result.lines) process.stdout.write(`${line}\n`);
|
|
290
|
+
totalOk += result.ok;
|
|
291
|
+
totalChecks += result.total;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
process.stdout.write(`\nSummary: ${totalOk}/${totalChecks} features enabled\n`);
|
|
295
|
+
process.stdout.write(`For agents, skills, and slash commands reference: docs/ruflo-benefit.md\n`);
|
|
296
|
+
|
|
297
|
+
const hasRequiredMissing = parseInt(process.version.slice(1), 10) < 20 || !process.env.ANTHROPIC_API_KEY;
|
|
298
|
+
if (hasRequiredMissing) process.stdout.write(`Run 'ruflo-setup' to configure missing required features.\n`);
|
|
299
|
+
process.stdout.write('\n');
|
|
300
|
+
} catch (error) {
|
|
301
|
+
process.stderr.write(`status error: ${error.message}\n`);
|
|
302
|
+
}
|
|
303
|
+
}
|
package/src/utils.js
CHANGED
|
@@ -90,7 +90,11 @@ export function toPlatformMcpConfig(platform) {
|
|
|
90
90
|
CLAUDE_FLOW_HOOKS_ENABLED: 'true',
|
|
91
91
|
CLAUDE_FLOW_TOPOLOGY: 'hierarchical-mesh',
|
|
92
92
|
CLAUDE_FLOW_MAX_AGENTS: '15',
|
|
93
|
-
CLAUDE_FLOW_MEMORY_BACKEND: 'hybrid'
|
|
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'
|
|
94
98
|
},
|
|
95
99
|
autoStart: false
|
|
96
100
|
},
|