claude-flow 3.56.0 → 3.56.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/node_modules/@claude-flow/codex/dist/cli.js +0 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/bin.js +0 -0
- package/package.json +1 -1
- package/v3/@claude-flow/cli/README.md +62 -158
- package/v3/@claude-flow/cli/catalog-manifest.json +5 -5
- package/v3/@claude-flow/cli/dist/src/commands/config.js +1 -1
- package/v3/@claude-flow/cli/dist/src/mcp-tools/config-tools.js +118 -13
- package/v3/@claude-flow/cli/dist/src/memory/memory-initializer.js +5 -1
- package/v3/@claude-flow/cli/dist/src/services/config-file-manager.d.ts +2 -2
- package/v3/@claude-flow/cli/dist/src/services/config-file-manager.js +22 -3
- package/v3/@claude-flow/cli/dist/src/services/policy-ledger-anchor.d.ts +8 -0
- package/v3/@claude-flow/cli/dist/src/services/policy-ledger-anchor.js +18 -3
- package/v3/@claude-flow/cli/dist/src/services/policy-runtime.js +2 -2
- package/v3/@claude-flow/cli/package.json +1 -1
|
File without changes
|
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,85 +1,22 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
**An agent meta-harness for Claude Code and Codex.**
|
|
3
|
+
[](https://cognitum.one/agentic-engineering)
|
|
6
4
|
|
|
7
5
|
<!-- Try Ruflo — the 3 badges first-time visitors actually act on -->
|
|
8
6
|
[](https://www.npmjs.com/package/ruflo)
|
|
9
7
|
[](https://opensource.org/licenses/MIT)
|
|
10
8
|
[](https://github.com/ruvnet/claude-flow)
|
|
11
9
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
</div>
|
|
20
|
-
|
|
21
|
-
<a id="start-here"></a>
|
|
22
|
-
|
|
23
|
-
## <img src="docs/assets/readme/icons/terminal.svg" width="32" height="32" alt=""> Get started with Ruflo
|
|
24
|
-
|
|
25
|
-
<img src="docs/assets/readme/icons/plugins.svg" width="28" height="28" alt=""> **Start in Claude Code** with core tools, the visual console and runtime mods. Requires Claude Code **2.1.287 or later**. Run inside Claude Code:
|
|
26
|
-
|
|
27
|
-
```text
|
|
28
|
-
/plugin marketplace add ruvnet/ruflo
|
|
29
|
-
/plugin install ruflo-core@ruflo
|
|
30
|
-
/plugin install ruflo-console@ruflo
|
|
31
|
-
/plugin install ruflo-mods@ruflo
|
|
32
|
-
/reload-plugins
|
|
33
|
-
/ruflo
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
**Core** provides foundation tools. **Console** opens the agent cockpit. **Mods** add routing and policy enforcement inside Claude Code. Mods run with your account's permissions; review their code before installing.
|
|
37
|
-
|
|
38
|
-
<img src="docs/assets/readme/icons/terminal.svg" width="28" height="28" alt=""> **Using Codex or another MCP enabled tool?** Use NPX for Ruflo project setup and connect your client to the Ruflo MCP server. Run the setup wizard in your project terminal:
|
|
39
|
-
|
|
40
|
-
```bash
|
|
41
|
-
npx ruflo@latest init wizard
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
For clients that support local stdio MCP servers, configure **command** `npx` and **arguments** `["-y", "ruflo@latest", "mcp", "start"]`. The equivalent server command is:
|
|
45
|
-
|
|
46
|
-
```bash
|
|
47
|
-
npx -y ruflo@latest mcp start
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
MCP exposes Ruflo tools to your client. The console and mods above are Claude Code integrations; hook support depends on the client.
|
|
51
|
-
|
|
52
|
-
[Compare install paths](#quick-start) · [Open the console](#console-walkthrough) · [User guide](docs/USERGUIDE.md)
|
|
53
|
-
|
|
54
|
-
<div align="center">
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
### Optional: ruOS Desktop
|
|
58
|
-
|
|
59
|
-
<a href="https://ruos.cognitum.one"><img src="ruflo/assets/ruos-animated.svg" alt="ruOS — A desktop that runs itself" width="100%"></a>
|
|
60
|
-
|
|
61
|
-
**Connect ruOS to ChatGPT or Claude via MCP:**
|
|
62
|
-
|
|
63
|
-
```text
|
|
64
|
-
https://ruos.cognitum.one/mcp
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
<!-- RuVector promo -->
|
|
70
|
-
<a href="https://github.com/ruvnet/ruvector"><img src="docs/assets/readme/ruvector-promo-depth.svg" width="100%" alt="RuVector: Give your agents memory. Local vector search, persistent context, graph relationships and feedback learning. Explore RuVector."></a>
|
|
71
|
-
|
|
72
|
-
```bash
|
|
73
|
-
npx ruvector
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
10
|
+
<!-- Ecosystem strip (collapsed visually with flat-square) -->
|
|
11
|
+
[](https://github.com/ruvnet/ruvector)
|
|
12
|
+
[](https://github.com/ruvnet/ruflo/blob/main/data/clone-data.proof.json)
|
|
13
|
+
[](https://github.com/ruvnet/ruflo/blob/main/data/clone-data.ledger.json)
|
|
14
|
+
[](https://github.com/ruvnet/claude-flow)
|
|
15
|
+
[](https://www.npmjs.com/package/@claude-flow/codex)
|
|
78
16
|
|
|
79
17
|
# Ruflo
|
|
80
18
|
|
|
81
|
-
|
|
82
|
-
|
|
19
|
+
**An agent meta-harness for Claude Code and Codex.**
|
|
83
20
|
|
|
84
21
|
[](docs/ruflo-explained.md)
|
|
85
22
|
|
|
@@ -92,16 +29,13 @@ A 14-chapter guide: from the basic idea to a first useful task, then memory, age
|
|
|
92
29
|
|
|
93
30
|
One `npx ruflo init` gives Claude Code a nervous system: agents self-organize into swarms, learn from every task, remember across sessions, and — with federation — securely talk to agents on other machines without leaking data. You keep writing code. Ruflo handles the coordination.
|
|
94
31
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
<sub>Conceptual learning loop. Local vector retrieval and contrastive updates can run without an LLM; embeddings and configured learning modules are still required. See the <a href="v3/@claude-flow/cli/src/services/ruvector-training.ts">RuVector training integration</a> and <a href="v3/@claude-flow/neural/src/modes/balanced.ts">trajectory contrastive learning</a>.</sub>
|
|
98
|
-
|
|
99
|
-
<details>
|
|
100
|
-
<summary>Architecture in text</summary>
|
|
101
|
-
|
|
102
|
-
User → Ruflo (CLI/MCP) → Router → Swarm → Agents → Memory → LLM providers. Memory feeds useful experience back into routing. This is a conceptual flow, not a live execution trace.
|
|
32
|
+
```
|
|
33
|
+
Self-Learning / Self-Optimizing Agent Architecture
|
|
103
34
|
|
|
104
|
-
|
|
35
|
+
User --> Ruflo (CLI/MCP) --> Router --> Swarm --> Agents --> Memory --> LLM Providers
|
|
36
|
+
^ |
|
|
37
|
+
+---- Learning Loop <-------+
|
|
38
|
+
```
|
|
105
39
|
|
|
106
40
|
> **New to Ruflo?** You don't need to learn 314 MCP tools or 26 CLI commands. After `init`, just use Claude Code normally — the hooks system automatically routes tasks, learns from successful patterns, and coordinates agents in the background.
|
|
107
41
|
|
|
@@ -114,50 +48,10 @@ User → Ruflo (CLI/MCP) → Router → Swarm → Agents → Memory → LLM prov
|
|
|
114
48
|
|
|
115
49
|
---
|
|
116
50
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
<p align="center"><img src="docs/assets/ruflo-console-workflows.svg" width="952" height="964" alt="An animated recording of the ruflo console inside Claude Code: the boot (the neon sign and every area checked), then the Workflows page on a sample run: phases and agents with model, tokens and time; drilling from a run into one agent's activity, log and result; search; failure triage; cost; replay and compare; the control tab with a confirm card; and the mission autopilot panel"></p>
|
|
120
|
-
|
|
121
|
-
<img src="docs/assets/readme/console-icon-workflows.svg" width="28" height="28" alt=""> **Your agent cockpit.** Track workflows, agents, models, tokens and cost beside Claude Code. The animation shows startup checks and a **sample workflow**, not a live session.
|
|
122
|
-
|
|
123
|
-
<img src="docs/assets/readme/console-icon-inspect.svg" width="28" height="28" alt=""> **Inspect any run.** Open agent logs and results, search, triage failures, replay and compare. Start with `npx ruflo init`, restart Claude Code, then `/ruflo`. [Full console tour](docs/assets/ruflo-console-walkthrough-wide.gif).
|
|
124
|
-
|
|
125
|
-
<img src="docs/assets/readme/console-icon-control.svg" width="28" height="28" alt=""> **Let Claude drive. You set the limits.** Enable **Settings → Claude control** to navigate and run console actions. Choose `read`, `write`, `manage` or `full`, with `ask` or `auto` approval. The current default is **read + ask**; raising the level is your choice. Actions above your permission level are refused, and network, spending and destructive actions require confirmation even in `auto`. Review the live action log or press **Take back control** to stop Claude control. [Details](v3/docs/adr/ADR-444-claude-controls-the-console.md).
|
|
126
|
-
|
|
127
|
-
<a id="console-walkthrough"></a>
|
|
128
|
-
|
|
129
|
-
### One task: create a mission with Claude
|
|
130
|
-
|
|
131
|
-
<img src="docs/assets/readme/console-icon-workflows.svg" width="28" height="28" alt=""> **Watch the recorded console session below.** Claude creates a mission, opens the Learning and Security pages, and reports its actions in Overview.
|
|
132
|
-
|
|
133
|
-
1. **Set the boundary.** Install the console using the commands below, open `/ruflo`, then choose **Settings → Claude control → write + ask**.
|
|
134
|
-
2. **Give a concrete request.** Try: “Create a mission to add a dark mode toggle. Show me the mission and its status.”
|
|
135
|
-
3. **Approve creation.** Claude opens Missions and sets the goal. Confirm the pending create action in the console.
|
|
136
|
-
4. **Verify the result.** Check that Missions contains the goal and Overview records the action. Creating a mission does not mean the feature has been implemented.
|
|
137
|
-
5. **Keep control.** **Take back control** pauses Claude's console tools. A later call should be refused until you restore control.
|
|
138
|
-
|
|
139
|
-
**What the recording demonstrates:** a real Claude Haiku session with `write + auto`, mission creation, page navigation, a refused swarm stop, and control being taken back. The steps above use `ask` so you approve creation yourself. The separate workflow animation uses sample data; neither is evidence of completed swarm work or memory recall.
|
|
140
|
-
|
|
141
|
-
[Implementation and recorded test findings](v3/docs/adr/ADR-444-claude-controls-the-console.md) · [Reproduction script](plugins/ruflo-console/scripts/e2e-control.sh)
|
|
142
|
-
|
|
143
|
-
<p align="center"><img src="docs/assets/ruflo-console-claude-control.gif" alt="Claude Code with the ruflo console beside it: Claude sets a mission goal, creates the mission and opens the Learning, Security and Overview pages through the console tools; the Claude control dashboard logs each action; swarm-stop is refused because it needs the full level; the person clicks Take back control and the next request is refused"></p>
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
**Install the mods from the ruflo marketplace** (Claude Code 2.1.287 or later; mods run with your account's permissions and are not sandboxed, so read the code first):
|
|
147
|
-
|
|
148
|
-
```text
|
|
149
|
-
/plugin marketplace add ruvnet/ruflo
|
|
150
|
-
/plugin install ruflo-console@ruflo
|
|
151
|
-
/plugin install ruflo-mods@ruflo
|
|
152
|
-
/reload-plugins
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
`ruflo-console` is the cockpit above, `ruflo-mods` routes prompts and enforces policy in-process, `ruflo-swarm` shows the swarm in a pane, and `ruflo-ruos` adds the ruOS status segment. Open `/plugin` to confirm they appear in the active mods line. Inside the console, `/ruflo market` is the Plugin Catalog: every ruflo plugin, mod and skill with what it ships, and buttons to install, enable, disable and update (each asks first).
|
|
51
|
+

|
|
156
52
|
|
|
157
53
|
## Quick Start
|
|
158
54
|
|
|
159
|
-
<p align="center"><img src="docs/assets/readme/quick-start.svg" alt="Start building with Ruflo" width="100%"></p>
|
|
160
|
-
|
|
161
55
|
There are **two different install paths** with very different surface areas. Pick based on what you need (#1744):
|
|
162
56
|
|
|
163
57
|
| | **Claude Code Plugin** | **CLI install (`npx ruflo init`)** |
|
|
@@ -268,7 +162,7 @@ This adds slash commands and agent definitions. `ruflo-core` (installed above) d
|
|
|
268
162
|
|
|
269
163
|
</details>
|
|
270
164
|
|
|
271
|
-
###
|
|
165
|
+
### CLI Install
|
|
272
166
|
|
|
273
167
|
**macOS / Linux / WSL / Git-Bash:**
|
|
274
168
|
|
|
@@ -292,50 +186,68 @@ npm install -g ruflo@latest
|
|
|
292
186
|
|
|
293
187
|
> 💡 **Windows users:** the `curl ... | bash` form needs a POSIX shell (Git-Bash, WSL, MSYS). The `npx ruflo@latest init wizard` line works natively in PowerShell and cmd. If you hit an `'bash' is not recognized` error, use the `npx` line instead — both end up running the same init flow.
|
|
294
188
|
|
|
295
|
-
###
|
|
189
|
+
### MCP Server
|
|
296
190
|
|
|
297
191
|
```bash
|
|
298
192
|
# Add Ruflo as an MCP server in Claude Code
|
|
299
193
|
claude mcp add claude-flow -- npx ruflo@latest mcp start
|
|
300
194
|
```
|
|
301
195
|
|
|
302
|
-
|
|
196
|
+
#### HTTP transport security
|
|
303
197
|
|
|
304
|
-
|
|
198
|
+
`ruflo mcp start -t http` exposes every registered tool over HTTP (`/rpc`, `/mcp`, `/ws`). The default `stdio` transport is not affected.
|
|
305
199
|
|
|
306
|
-
|
|
200
|
+
| Setting | Effect |
|
|
201
|
+
|---|---|
|
|
202
|
+
| `RUFLO_MCP_HTTP_TOKEN=<token>` | Require `Authorization: Bearer <token>` on every request. Failure is a bare `401`. The token is compared in constant time and is never logged. Prefer this over `--auth-token`, which is visible in `ps`. |
|
|
203
|
+
| `--auth-token-file <path>` | Read the token from a file (one line). Takes precedence over the env var. |
|
|
204
|
+
| `--auth-token <token>` | Same, on the command line (visible in argv; highest precedence). |
|
|
205
|
+
| `RUFLO_MCP_ALLOW_UNAUTHENTICATED_HTTP=1` | Allow an unauthenticated bind to a non-loopback `--host`. Only for a trusted network boundary or an authenticating reverse proxy. |
|
|
307
206
|
|
|
308
|
-
|
|
309
|
-
<tr><td width="50%"><a href="plugins/ruflo-swarm/README.md"><img src="docs/assets/readme/card-swarm.svg" width="100%" alt="Agent teams"></a></td><td width="50%"><a href="plugins/ruflo-rag-memory/README.md"><img src="docs/assets/readme/card-memory.svg" width="100%" alt="Persistent memory"></a></td></tr>
|
|
310
|
-
<tr><td width="50%"><a href="plugins/ruflo-intelligence/README.md"><img src="docs/assets/readme/card-learning.svg" width="100%" alt="Learning loops"></a></td><td width="50%"><a href="plugins/ruflo-security-audit/README.md"><img src="docs/assets/readme/card-security.svg" width="100%" alt="Security controls"></a></td></tr>
|
|
311
|
-
<tr><td width="50%"><a href="https://ruvnet.github.io/ruflo"><img src="docs/assets/readme/card-plugins.svg" width="100%" alt="Plugin marketplace"></a></td><td width="50%"><a href="plugins/ruflo-ruvllm/README.md"><img src="docs/assets/readme/card-routing.svg" width="100%" alt="Models and routing"></a></td></tr>
|
|
312
|
-
</table>
|
|
207
|
+
A token must be 16-512 printable ASCII characters (no spaces). `GET /health` stays public and returns only `{"status":"ok"}` when a token is set. Tokens are supported for `-t http` only; `-t websocket` rejects one.
|
|
313
208
|
|
|
314
|
-
|
|
|
315
|
-
|
|
316
|
-
|
|
|
317
|
-
|
|
|
318
|
-
| <img src="docs/assets/readme/icons/swarm.svg" width="28" height="28" alt=""> **Swarm Coordination** | Hierarchical, mesh, and adaptive topologies with consensus |
|
|
319
|
-
| <img src="docs/assets/readme/icons/learning.svg" width="28" height="28" alt=""> **Self-Learning** | SONA neural patterns, ReasoningBank, trajectory learning |
|
|
320
|
-
| <img src="docs/assets/readme/icons/memory.svg" width="28" height="28" alt=""> **Vector Memory** | HNSW-indexed AgentDB — measured ~1.9x faster at N=20k, ~3.2x–4.7x at N=5k vs brute force (recall@10 ~0.99); ANN wins above the crossover, ties/loses at small N. See [audit](docs/reviews/intelligence-system-audit-2026-05-29.md) + [`scripts/benchmark-intelligence.mjs`](scripts/benchmark-intelligence.mjs) |
|
|
321
|
-
| <img src="docs/assets/readme/icons/workers.svg" width="28" height="28" alt=""> **Background Workers** | 12 auto-triggered workers (audit, optimize, testgaps, etc.) |
|
|
322
|
-
| <img src="docs/assets/readme/icons/plugins.svg" width="28" height="28" alt=""> **Plugin Marketplace** | 33 native Claude Code plugins + 21 npm plugins |
|
|
323
|
-
| <img src="docs/assets/readme/icons/routing.svg" width="28" height="28" alt=""> **Multi-Provider** | Claude, GPT, Gemini, Cohere, Ollama with smart routing |
|
|
324
|
-
| <img src="docs/assets/readme/icons/security.svg" width="28" height="28" alt=""> **Security** | AIDefence, input validation, CVE remediation, path traversal prevention |
|
|
325
|
-
| <img src="docs/assets/readme/icons/federation.svg" width="28" height="28" alt=""> **Agent Federation** | Cross-installation agent collaboration with zero-trust security |
|
|
326
|
-
| <img src="docs/assets/readme/icons/audit.svg" width="28" height="28" alt=""> **[MetaHarness](docs/metaharness-user-guide.md)** | Audit your AI agent setup before you ship. Grade readiness (1-100), scan tool configs for security issues, snapshot the whole project to catch regressions over time, and find templates that match your repo. `ruflo eject` turns a ruflo project into a standalone agent toolkit with its own name. [Full guide](docs/metaharness-user-guide.md). |
|
|
209
|
+
| `--host` | no token | token set |
|
|
210
|
+
|---|---|---|
|
|
211
|
+
| `localhost`, `127.0.0.1`, `::1` | starts, **unauthenticated** | starts, token required |
|
|
212
|
+
| anything else (`0.0.0.0`, `::`, a LAN IP, `127.0.0.2`, `[::1]`, `LOCALHOST`) | **refuses to start** unless `RUFLO_MCP_ALLOW_UNAUTHENTICATED_HTTP=1` | starts, token required |
|
|
327
213
|
|
|
328
|
-
|
|
214
|
+
Without a token, a loopback server is still unauthenticated: any process on the machine, and any web page that can reach it via DNS rebinding, can call tools. Set `RUFLO_MCP_HTTP_TOKEN` whenever the HTTP transport is used.
|
|
329
215
|
|
|
330
|
-
|
|
216
|
+
**Upgrading:** binding off loopback (for example `--host 0.0.0.0` in Docker) now needs a token or the opt-out above; otherwise the server exits with an error.
|
|
331
217
|
|
|
332
|
-
|
|
218
|
+
---
|
|
333
219
|
|
|
334
|
-
|
|
220
|
+
## What You Get
|
|
335
221
|
|
|
336
|
-
|
|
222
|
+
| Capability | Description |
|
|
223
|
+
|------------|-------------|
|
|
224
|
+
| 🤖 **100+ Agents** | Specialized agents for coding, testing, security, docs, architecture |
|
|
225
|
+
| 📡 **Comms Layer** | Zero-trust federation — agents across machines/orgs discover, authenticate, and exchange work securely |
|
|
226
|
+
| 🐝 **Swarm Coordination** | Hierarchical, mesh, and adaptive topologies with consensus |
|
|
227
|
+
| 🧠 **Self-Learning** | SONA neural patterns, ReasoningBank, trajectory learning |
|
|
228
|
+
| 💾 **Vector Memory** | HNSW-indexed AgentDB — measured ~1.9x faster at N=20k, ~3.2x–4.7x at N=5k vs brute force (recall@10 ~0.99); ANN wins above the crossover, ties/loses at small N. See [audit](docs/reviews/intelligence-system-audit-2026-05-29.md) + [`scripts/benchmark-intelligence.mjs`](scripts/benchmark-intelligence.mjs) |
|
|
229
|
+
| ⚡ **Background Workers** | 12 auto-triggered workers (audit, optimize, testgaps, etc.) |
|
|
230
|
+
| 🧩 **Plugin Marketplace** | 33 native Claude Code plugins + 21 npm plugins |
|
|
231
|
+
| 🔌 **Multi-Provider** | Claude, GPT, Gemini, Cohere, Ollama with smart routing |
|
|
232
|
+
| 🛡️ **Security** | AIDefence, input validation, CVE remediation, path traversal prevention |
|
|
233
|
+
| 🌐 **Agent Federation** | Cross-installation agent collaboration with zero-trust security |
|
|
234
|
+
| 🔬 **[MetaHarness](docs/metaharness-user-guide.md)** | Audit your AI agent setup before you ship. Grade readiness (1-100), scan tool configs for security issues, snapshot the whole project to catch regressions over time, and find templates that match your repo. `ruflo eject` turns a ruflo project into a standalone agent toolkit with its own name. [Full guide](docs/metaharness-user-guide.md). |
|
|
337
235
|
|
|
338
|
-
|
|
236
|
+
### Agent Federation — Slack for Agents
|
|
237
|
+
|
|
238
|
+
```
|
|
239
|
+
Your Agent --> [ Remove secrets ] --> [ Sign message ] --> [ Encrypted channel ]
|
|
240
|
+
Emails, SSNs, Proves it came No one reads it
|
|
241
|
+
keys stripped from you in transit
|
|
242
|
+
|
|
|
243
|
+
v
|
|
244
|
+
Their Agent <-- [ Block attacks ] <-- [ Check identity ] <------+
|
|
245
|
+
Stops prompt Rejects forgeries
|
|
246
|
+
injection
|
|
247
|
+
|
|
248
|
+
Audit trail on both sides.
|
|
249
|
+
Trust builds over time. Bad behavior = instant downgrade.
|
|
250
|
+
```
|
|
339
251
|
|
|
340
252
|
Slack gave teams channels. Federation gives agents the same thing — **shared workspaces across trust boundaries**, where agents on different machines, orgs, or cloud regions can discover each other, prove who they are, and collaborate on tasks.
|
|
341
253
|
|
|
@@ -437,8 +349,6 @@ User --> Claude Code / CLI
|
|
|
437
349
|
|
|
438
350
|
## Documentation
|
|
439
351
|
|
|
440
|
-
<p align="center"><img src="docs/assets/readme/documentation.svg" alt="Guides, architecture and verification" width="100%"></p>
|
|
441
|
-
|
|
442
352
|
Four docs for four audiences:
|
|
443
353
|
|
|
444
354
|
| Doc | When to read it |
|
|
@@ -469,8 +379,6 @@ User Guide section index:
|
|
|
469
379
|
|
|
470
380
|
## Support
|
|
471
381
|
|
|
472
|
-
<p align="center"><img src="docs/assets/readme/support.svg" alt="Build with the Ruflo community" width="100%"></p>
|
|
473
|
-
|
|
474
382
|
| Resource | Link |
|
|
475
383
|
|----------|------|
|
|
476
384
|
| Documentation | [User Guide](docs/USERGUIDE.md) |
|
|
@@ -479,10 +387,6 @@ User Guide section index:
|
|
|
479
387
|
| Community | [Agentics Foundation Discord](https://discord.com/invite/dfxmpwkG2D) |
|
|
480
388
|
| Powered by | [Cognitum.one](https://cognitum.one) |
|
|
481
389
|
|
|
482
|
-
<p align="center"><img src="docs/assets/readme/signal-divider.svg" alt="Ruflo" width="100%"></p>
|
|
483
|
-
|
|
484
390
|
## License
|
|
485
391
|
|
|
486
392
|
MIT - [RuvNet](https://github.com/ruvnet)
|
|
487
|
-
|
|
488
|
-
<a href="https://cognitum.one"><img src="docs/assets/readme/cognitum-banner-v2.svg" width="100%" alt="Cognitum One: Ambient Intelligence at the edge of the Physical World. Explore cognitum.one."></a>
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"generation":
|
|
4
|
-
"generatedAt": "2026-
|
|
5
|
-
"gitSha": "
|
|
3
|
+
"generation": 6,
|
|
4
|
+
"generatedAt": "2026-09-17T21:28:47.530Z",
|
|
5
|
+
"gitSha": "702d1461",
|
|
6
6
|
"catalog": {
|
|
7
|
-
"agents":
|
|
8
|
-
"tools":
|
|
7
|
+
"agents": 167,
|
|
8
|
+
"tools": 418,
|
|
9
9
|
"skills": 34
|
|
10
10
|
},
|
|
11
11
|
"benchmark": null
|
|
@@ -309,7 +309,7 @@ const resetCommand = {
|
|
|
309
309
|
],
|
|
310
310
|
action: async (ctx) => {
|
|
311
311
|
try {
|
|
312
|
-
const configPath = configManager.reset(ctx.cwd);
|
|
312
|
+
const configPath = configManager.reset(ctx.cwd, ctx.flags.section);
|
|
313
313
|
output.writeln(`Configuration reset to defaults: ${configPath}`);
|
|
314
314
|
return { success: true };
|
|
315
315
|
}
|
|
@@ -35,12 +35,110 @@ function ensureConfigDir() {
|
|
|
35
35
|
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
|
+
// Plain CLI files and legacy MCP envelopes share the same path. Keep the
|
|
39
|
+
// original plain document so MCP writes remain readable by the CLI.
|
|
40
|
+
const plainDocuments = new WeakMap();
|
|
41
|
+
const STORE_METADATA = new Set(['scopes', 'version', 'updatedAt']);
|
|
42
|
+
function isRecord(value) {
|
|
43
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
44
|
+
}
|
|
45
|
+
function flattenValues(document) {
|
|
46
|
+
const values = {};
|
|
47
|
+
function visit(value, key) {
|
|
48
|
+
if (isRecord(value) && Object.keys(value).length > 0) {
|
|
49
|
+
for (const [child, entry] of Object.entries(value))
|
|
50
|
+
visit(entry, `${key}.${child}`);
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
Object.defineProperty(values, key, { value, enumerable: true, configurable: true, writable: true });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
for (const [key, value] of Object.entries(document)) {
|
|
57
|
+
if (!STORE_METADATA.has(key))
|
|
58
|
+
visit(value, key);
|
|
59
|
+
}
|
|
60
|
+
// CLI reads literal dotted keys before traversing nested objects.
|
|
61
|
+
for (const [key, value] of Object.entries(document)) {
|
|
62
|
+
if (key.includes('.'))
|
|
63
|
+
Object.defineProperty(values, key, { value, enumerable: true, configurable: true, writable: true });
|
|
64
|
+
}
|
|
65
|
+
return values;
|
|
66
|
+
}
|
|
67
|
+
function readDefaultValue(store, key) {
|
|
68
|
+
const document = plainDocuments.get(store);
|
|
69
|
+
if (!document)
|
|
70
|
+
return store.values[key];
|
|
71
|
+
return Object.hasOwn(document, key) ? document[key] : getNestedValue(document, key);
|
|
72
|
+
}
|
|
73
|
+
function writeDefaultValue(store, key, value) {
|
|
74
|
+
const document = plainDocuments.get(store);
|
|
75
|
+
if (!document) {
|
|
76
|
+
store.values[key] = value;
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
// Keep existing literal dotted keys; otherwise use the CLI's nested shape.
|
|
80
|
+
if (Object.hasOwn(document, key)) {
|
|
81
|
+
// Reuse the same segment validation as nested writes.
|
|
82
|
+
setNestedValue({}, key, value);
|
|
83
|
+
document[key] = value;
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
setNestedValue(document, key, value);
|
|
87
|
+
}
|
|
88
|
+
store.values = flattenValues(document);
|
|
89
|
+
}
|
|
90
|
+
function deleteDefaultValue(store, key) {
|
|
91
|
+
const document = plainDocuments.get(store);
|
|
92
|
+
if (!document)
|
|
93
|
+
return Object.hasOwn(store.values, key) && delete store.values[key];
|
|
94
|
+
let target = document;
|
|
95
|
+
let leaf = key;
|
|
96
|
+
if (!Object.hasOwn(document, key)) {
|
|
97
|
+
const parts = key.split('.');
|
|
98
|
+
leaf = parts.pop();
|
|
99
|
+
for (const part of parts) {
|
|
100
|
+
if (!Object.hasOwn(target, part) || !isRecord(target[part]))
|
|
101
|
+
return false;
|
|
102
|
+
target = target[part];
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
const deleted = Object.hasOwn(target, leaf) && delete target[leaf];
|
|
106
|
+
store.values = flattenValues(document);
|
|
107
|
+
return deleted;
|
|
108
|
+
}
|
|
109
|
+
function replaceDefaultValues(store, values) {
|
|
110
|
+
const document = plainDocuments.get(store);
|
|
111
|
+
if (!document) {
|
|
112
|
+
store.values = values;
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
for (const key of Object.keys(document)) {
|
|
116
|
+
if (!STORE_METADATA.has(key))
|
|
117
|
+
delete document[key];
|
|
118
|
+
}
|
|
119
|
+
for (const [key, value] of Object.entries(values))
|
|
120
|
+
writeDefaultValue(store, key, value);
|
|
121
|
+
}
|
|
38
122
|
function loadConfigStore() {
|
|
39
123
|
try {
|
|
40
124
|
const path = getConfigPath();
|
|
41
125
|
if (existsSync(path)) {
|
|
42
126
|
const data = readFileSync(path, 'utf-8');
|
|
43
|
-
|
|
127
|
+
const document = JSON.parse(data);
|
|
128
|
+
const isEnvelope = isRecord(document) && isRecord(document.values)
|
|
129
|
+
&& isRecord(document.scopes) && typeof document.version === 'string'
|
|
130
|
+
&& typeof document.updatedAt === 'string';
|
|
131
|
+
if (isRecord(document) && !isEnvelope) {
|
|
132
|
+
const store = {
|
|
133
|
+
values: flattenValues(document),
|
|
134
|
+
scopes: isRecord(document.scopes) ? document.scopes : {},
|
|
135
|
+
version: typeof document.version === 'string' ? document.version : '3.0.0',
|
|
136
|
+
updatedAt: typeof document.updatedAt === 'string' ? document.updatedAt : '',
|
|
137
|
+
};
|
|
138
|
+
plainDocuments.set(store, document);
|
|
139
|
+
return store;
|
|
140
|
+
}
|
|
141
|
+
return document;
|
|
44
142
|
}
|
|
45
143
|
}
|
|
46
144
|
catch {
|
|
@@ -56,13 +154,20 @@ function loadConfigStore() {
|
|
|
56
154
|
function saveConfigStore(store) {
|
|
57
155
|
ensureConfigDir();
|
|
58
156
|
store.updatedAt = new Date().toISOString();
|
|
59
|
-
|
|
157
|
+
const document = plainDocuments.get(store);
|
|
158
|
+
if (document) {
|
|
159
|
+
document.updatedAt = store.updatedAt;
|
|
160
|
+
if (Object.keys(store.scopes).length > 0 || Object.hasOwn(document, 'scopes')) {
|
|
161
|
+
document.scopes = store.scopes;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
writeFileSync(getConfigPath(), JSON.stringify(document ?? store, null, 2), 'utf-8');
|
|
60
165
|
}
|
|
61
166
|
function getNestedValue(obj, key) {
|
|
62
167
|
const parts = key.split('.');
|
|
63
168
|
let current = obj;
|
|
64
169
|
for (const part of parts) {
|
|
65
|
-
if (current && typeof current === 'object' && part
|
|
170
|
+
if (current && typeof current === 'object' && Object.hasOwn(current, part)) {
|
|
66
171
|
current = current[part];
|
|
67
172
|
}
|
|
68
173
|
else {
|
|
@@ -95,7 +200,7 @@ function setNestedValue(obj, key, value) {
|
|
|
95
200
|
let current = obj;
|
|
96
201
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
97
202
|
const part = parts[i];
|
|
98
|
-
if (!(part
|
|
203
|
+
if (!Object.hasOwn(current, part) || current[part] === null || typeof current[part] !== 'object') {
|
|
99
204
|
current[part] = {};
|
|
100
205
|
}
|
|
101
206
|
current = current[part];
|
|
@@ -134,7 +239,7 @@ export const configTools = [
|
|
|
134
239
|
value = store.scopes[scope][key];
|
|
135
240
|
}
|
|
136
241
|
if (value === undefined) {
|
|
137
|
-
value = store
|
|
242
|
+
value = readDefaultValue(store, key);
|
|
138
243
|
}
|
|
139
244
|
if (value === undefined) {
|
|
140
245
|
value = DEFAULT_CONFIG[key];
|
|
@@ -144,7 +249,7 @@ export const configTools = [
|
|
|
144
249
|
value,
|
|
145
250
|
scope,
|
|
146
251
|
exists: value !== undefined,
|
|
147
|
-
source: value !== undefined ? (store
|
|
252
|
+
source: value !== undefined ? (readDefaultValue(store, key) !== undefined ? 'stored' : 'default') : 'none',
|
|
148
253
|
};
|
|
149
254
|
},
|
|
150
255
|
},
|
|
@@ -175,9 +280,9 @@ export const configTools = [
|
|
|
175
280
|
const key = input.key;
|
|
176
281
|
const value = input.value;
|
|
177
282
|
const scope = input.scope || 'default';
|
|
178
|
-
const previousValue = store
|
|
283
|
+
const previousValue = readDefaultValue(store, key);
|
|
179
284
|
if (scope === 'default') {
|
|
180
|
-
store
|
|
285
|
+
writeDefaultValue(store, key, value);
|
|
181
286
|
}
|
|
182
287
|
else {
|
|
183
288
|
if (!store.scopes[scope]) {
|
|
@@ -289,8 +394,7 @@ export const configTools = [
|
|
|
289
394
|
if (key) {
|
|
290
395
|
// Reset specific key
|
|
291
396
|
if (scope === 'default') {
|
|
292
|
-
if (key
|
|
293
|
-
delete store.values[key];
|
|
397
|
+
if (deleteDefaultValue(store, key)) {
|
|
294
398
|
resetKeys.push(key);
|
|
295
399
|
}
|
|
296
400
|
}
|
|
@@ -303,7 +407,7 @@ export const configTools = [
|
|
|
303
407
|
// Reset all keys in scope
|
|
304
408
|
if (scope === 'default') {
|
|
305
409
|
resetKeys = Object.keys(store.values);
|
|
306
|
-
store
|
|
410
|
+
replaceDefaultValues(store, { ...DEFAULT_CONFIG });
|
|
307
411
|
}
|
|
308
412
|
else if (store.scopes[scope]) {
|
|
309
413
|
resetKeys = Object.keys(store.scopes[scope]);
|
|
@@ -385,10 +489,11 @@ export const configTools = [
|
|
|
385
489
|
const importedKeys = Object.keys(config);
|
|
386
490
|
if (scope === 'default') {
|
|
387
491
|
if (merge) {
|
|
388
|
-
Object.
|
|
492
|
+
for (const [key, value] of Object.entries(config))
|
|
493
|
+
writeDefaultValue(store, key, value);
|
|
389
494
|
}
|
|
390
495
|
else {
|
|
391
|
-
store
|
|
496
|
+
replaceDefaultValues(store, { ...DEFAULT_CONFIG, ...config });
|
|
392
497
|
}
|
|
393
498
|
}
|
|
394
499
|
else {
|
|
@@ -1235,7 +1235,11 @@ export async function ensureSchemaColumns(dbPath, options = {}) {
|
|
|
1235
1235
|
if (columnsAdded.includes('status') || existingColumns.has('status')) {
|
|
1236
1236
|
try {
|
|
1237
1237
|
db.run(`UPDATE memory_entries SET status = 'active' WHERE status IS NULL`);
|
|
1238
|
-
|
|
1238
|
+
// #3918: only a backfill that changed rows dirties the image. Setting
|
|
1239
|
+
// this unconditionally rewrote every up-to-date store on each open (and,
|
|
1240
|
+
// with encryption at rest, with a fresh nonce, so the bytes changed too).
|
|
1241
|
+
if (db.getRowsModified() > 0)
|
|
1242
|
+
modified = true;
|
|
1239
1243
|
}
|
|
1240
1244
|
catch {
|
|
1241
1245
|
/* table is read-only or doesn't exist — skip */
|
|
@@ -18,8 +18,8 @@ export declare class ConfigFileManager {
|
|
|
18
18
|
set(cwd: string, key: string, value: unknown): void;
|
|
19
19
|
/** Create a new config file with defaults */
|
|
20
20
|
create(cwd: string, overrides?: Record<string, unknown>, force?: boolean): string;
|
|
21
|
-
/** Reset
|
|
22
|
-
reset(cwd: string): string;
|
|
21
|
+
/** Reset all configuration or only the selected section to defaults. */
|
|
22
|
+
reset(cwd: string, section?: string): string;
|
|
23
23
|
/** Export config to a specific path */
|
|
24
24
|
exportTo(cwd: string, exportPath: string): void;
|
|
25
25
|
/** Import config from a specific path */
|
|
@@ -148,11 +148,30 @@ export class ConfigFileManager {
|
|
|
148
148
|
this.configPath = targetPath;
|
|
149
149
|
return targetPath;
|
|
150
150
|
}
|
|
151
|
-
/** Reset
|
|
152
|
-
reset(cwd) {
|
|
151
|
+
/** Reset all configuration or only the selected section to defaults. */
|
|
152
|
+
reset(cwd, section = 'all') {
|
|
153
|
+
if (!['agents', 'swarm', 'memory', 'mcp', 'providers', 'all'].includes(section)) {
|
|
154
|
+
throw new Error(`Unknown configuration section: ${section}`);
|
|
155
|
+
}
|
|
153
156
|
this.selectProject(cwd);
|
|
154
157
|
const targetPath = this.findConfig(cwd) ?? path.resolve(cwd, CONFIG_FILENAMES[0]);
|
|
155
|
-
const config =
|
|
158
|
+
const config = section === 'all'
|
|
159
|
+
? structuredClone(DEFAULT_CONFIG)
|
|
160
|
+
: structuredClone(this.load(cwd) ?? {});
|
|
161
|
+
if (section === 'providers') {
|
|
162
|
+
// Provider defaults are supplied by the provider command, so remove
|
|
163
|
+
// only the persisted override, as a whole reset already does.
|
|
164
|
+
delete config.providers;
|
|
165
|
+
}
|
|
166
|
+
else if (section !== 'all') {
|
|
167
|
+
config[section] = structuredClone(DEFAULT_CONFIG[section]);
|
|
168
|
+
}
|
|
169
|
+
if (section !== 'all') {
|
|
170
|
+
for (const key of Object.keys(config)) {
|
|
171
|
+
if (key.startsWith(`${section}.`))
|
|
172
|
+
delete config[key];
|
|
173
|
+
}
|
|
174
|
+
}
|
|
156
175
|
this.writeAtomic(targetPath, config);
|
|
157
176
|
this.config = config;
|
|
158
177
|
this.configPath = targetPath;
|
|
@@ -22,6 +22,14 @@ export type AnchorAssessment = {
|
|
|
22
22
|
};
|
|
23
23
|
export type AnchorWriter = (file: string, value: unknown) => Promise<void>;
|
|
24
24
|
export declare const anchorLogPath: (projectRoot: string) => string;
|
|
25
|
+
/**
|
|
26
|
+
* Directory holding per-project trust material (anchor mirror, HMAC key).
|
|
27
|
+
* Resolved from the environment at call time (#3919): $XDG_CONFIG_HOME when it
|
|
28
|
+
* is absolute, else $HOME/.config (os.homedir() honours $HOME), so a scratch
|
|
29
|
+
* HOME keeps tests and sandboxed runs out of the developer's real home. An XDG
|
|
30
|
+
* user who already has trust state under the legacy ~/.config keeps using it.
|
|
31
|
+
*/
|
|
32
|
+
export declare function policyTrustRoot(): string;
|
|
25
33
|
/**
|
|
26
34
|
* How the stored anchors relate to `state`; read-only. `rebuild` is the
|
|
27
35
|
* explicit-establish path: an unreadable log or mirror is treated as absent, but
|
|
@@ -13,14 +13,29 @@
|
|
|
13
13
|
*/
|
|
14
14
|
import { createHash } from 'node:crypto';
|
|
15
15
|
import { existsSync, mkdirSync, readFileSync, realpathSync } from 'node:fs';
|
|
16
|
-
import { dirname, join, resolve } from 'node:path';
|
|
17
|
-
import {
|
|
16
|
+
import { dirname, isAbsolute, join, resolve } from 'node:path';
|
|
17
|
+
import { homedir } from 'node:os';
|
|
18
18
|
const LOG_FILE = 'ledger-anchors.json';
|
|
19
19
|
const MIRROR_FILE = 'ledger-anchor-head.json';
|
|
20
20
|
export const anchorLogPath = (projectRoot) => join(resolve(projectRoot), '.claude-flow', 'policy', LOG_FILE);
|
|
21
|
+
/**
|
|
22
|
+
* Directory holding per-project trust material (anchor mirror, HMAC key).
|
|
23
|
+
* Resolved from the environment at call time (#3919): $XDG_CONFIG_HOME when it
|
|
24
|
+
* is absolute, else $HOME/.config (os.homedir() honours $HOME), so a scratch
|
|
25
|
+
* HOME keeps tests and sandboxed runs out of the developer's real home. An XDG
|
|
26
|
+
* user who already has trust state under the legacy ~/.config keeps using it.
|
|
27
|
+
*/
|
|
28
|
+
export function policyTrustRoot() {
|
|
29
|
+
const legacy = join(homedir(), '.config', 'ruflo', 'policy-trust');
|
|
30
|
+
const xdg = process.env.XDG_CONFIG_HOME;
|
|
31
|
+
if (!xdg || !isAbsolute(xdg))
|
|
32
|
+
return legacy;
|
|
33
|
+
const preferred = join(xdg, 'ruflo', 'policy-trust');
|
|
34
|
+
return !existsSync(preferred) && existsSync(legacy) ? legacy : preferred;
|
|
35
|
+
}
|
|
21
36
|
function mirrorPath(projectRoot) {
|
|
22
37
|
const id = createHash('sha256').update(realpathSync(projectRoot)).digest('hex');
|
|
23
|
-
return join(
|
|
38
|
+
return join(policyTrustRoot(), id, MIRROR_FILE);
|
|
24
39
|
}
|
|
25
40
|
function entryHash(entry) {
|
|
26
41
|
return createHash('sha256').update(JSON.stringify([
|
|
@@ -5,7 +5,7 @@ import { closeSync, constants as fsConstants, existsSync, fstatSync, lstatSync,
|
|
|
5
5
|
import { dirname, join, resolve } from 'node:path';
|
|
6
6
|
import { hostname, userInfo } from 'node:os';
|
|
7
7
|
import { syncPolicyProjection } from '../mods/policy-projection.js';
|
|
8
|
-
import { assessAnchors, recordAnchor } from './policy-ledger-anchor.js';
|
|
8
|
+
import { assessAnchors, policyTrustRoot, recordAnchor } from './policy-ledger-anchor.js';
|
|
9
9
|
const POLICY_DIR = join('.claude-flow', 'policy');
|
|
10
10
|
const POLICY_FILE = 'state.json';
|
|
11
11
|
const LOCK_FILE = 'state.lock';
|
|
@@ -194,7 +194,7 @@ async function writeJsonAtomic(file, value) {
|
|
|
194
194
|
}
|
|
195
195
|
}
|
|
196
196
|
function trustPaths(projectRoot) {
|
|
197
|
-
const trustRoot =
|
|
197
|
+
const trustRoot = policyTrustRoot();
|
|
198
198
|
const projectId = createHash('sha256').update(realpathSync(projectRoot)).digest('hex');
|
|
199
199
|
const dir = join(trustRoot, projectId);
|
|
200
200
|
return { key: join(dir, 'anchor.key'), anchor: join(dir, 'state.anchor.json') };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@claude-flow/cli",
|
|
3
|
-
"version": "3.56.
|
|
3
|
+
"version": "3.56.1",
|
|
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",
|