@claude-flow/cli 3.63.0 → 3.63.2
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/.claude/helpers/helpers.manifest.json +2 -2
- package/README.md +1 -1
- package/catalog-manifest.json +2 -2
- package/dist/src/mcp-tools/agentbbs-tools.js +7 -2
- package/dist/src/mcp-tools/http-fetch-tools.js +36 -8
- package/dist/src/mcp-tools/managed-agent-tools.js +3 -0
- package/dist/src/services/flywheel-transaction.js +5 -0
- package/package.json +1 -1
- package/plugins/ruflo-console/dist/tui.mjs +166 -162
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"manifest": {
|
|
3
|
-
"version": "3.63.
|
|
3
|
+
"version": "3.63.2",
|
|
4
4
|
"files": {
|
|
5
5
|
"auto-memory-hook.mjs": "631fac9d518835e2852a406888316bbbddddb49e7ed8e406d2e971f46833df9a",
|
|
6
6
|
"hook-handler.cjs": "24502a3bcb78770971147940515c992e35b6736ae14ee2dc54e07d4cdef6a1d8",
|
|
@@ -9,6 +9,6 @@
|
|
|
9
9
|
"router.cjs": "16648b3c0d73b6681ac2d8d13def6a68286c57f5a11004de5b19a0fa088c833d"
|
|
10
10
|
}
|
|
11
11
|
},
|
|
12
|
-
"signature": "
|
|
12
|
+
"signature": "6+Obx8HZs73gmcPZ6JJH6sBZf3OGb1DC5p5p0K8QhMAAr1QwhKu2uNPv36NmjpsbOTJ0MpidudSRt4fP/ToVBA==",
|
|
13
13
|
"algorithm": "ed25519"
|
|
14
14
|
}
|
package/README.md
CHANGED
|
@@ -244,7 +244,7 @@ This adds slash commands and agent definitions. `ruflo-core` (installed above) d
|
|
|
244
244
|
| [**ruflo-browser**](plugins/ruflo-browser/README.md) | Automate browser testing with Playwright |
|
|
245
245
|
| [**ruflo-jujutsu**](plugins/ruflo-jujutsu/README.md) | Analyze git diffs, score risk, suggest reviewers |
|
|
246
246
|
| [**ruflo-docs**](plugins/ruflo-docs/README.md) | Generate and maintain documentation automatically |
|
|
247
|
-
| [**agentic-qe-fleet**](https://github.com/proffesor-for-testing/agentic-qe/tree/v3.15.
|
|
247
|
+
| [**agentic-qe-fleet**](https://github.com/proffesor-for-testing/agentic-qe/tree/v3.15.13/plugins/agentic-qe-fleet) | External, maintained by [Agentic QE](https://github.com/proffesor-for-testing/agentic-qe): 11 QE agents, test generation, coverage, chaos and TDD skills, the `agentic-qe` MCP server, and a guard for AQE learning data (`/plugin install agentic-qe-fleet@ruflo`). Install it from one marketplace only, `agentic-qe` or `ruflo`: enabled from both, its mod and commands load twice |
|
|
248
248
|
|
|
249
249
|
#### Security & Compliance
|
|
250
250
|
|
package/catalog-manifest.json
CHANGED
|
@@ -441,14 +441,19 @@ export const agentbbsTools = [
|
|
|
441
441
|
const logPath = roomLogPath(basePath, roomId);
|
|
442
442
|
const all = readEnvelopes(logPath);
|
|
443
443
|
let slice = all;
|
|
444
|
+
let resuming = false;
|
|
444
445
|
if (sinceEnvelopeId) {
|
|
445
446
|
const idx = all.findIndex(e => e.envelopeId === sinceEnvelopeId);
|
|
446
|
-
|
|
447
|
+
resuming = idx >= 0;
|
|
448
|
+
slice = resuming ? all.slice(idx + 1) : all;
|
|
447
449
|
}
|
|
448
450
|
// Dedup by envelopeId before applying the limit — a relay replay or a
|
|
449
451
|
// double-append must not surface the same envelope twice to a watcher.
|
|
450
452
|
const deduped = dedupEnvelopes(slice);
|
|
451
|
-
|
|
453
|
+
// A watcher resuming after sinceEnvelopeId gets the oldest envelopes
|
|
454
|
+
// first, so passing the last returned id pages through the rest when
|
|
455
|
+
// hasMore is set. Without a cursor, it gets the most recent window.
|
|
456
|
+
const envelopes = resuming ? deduped.slice(0, limit) : deduped.slice(-limit);
|
|
452
457
|
return {
|
|
453
458
|
success: true,
|
|
454
459
|
roomId,
|
|
@@ -61,11 +61,33 @@ export function validateUrl(rawUrl) {
|
|
|
61
61
|
function isPrivateOrLoopback(host) {
|
|
62
62
|
if (host === 'localhost' || host === 'localhost.localdomain')
|
|
63
63
|
return true;
|
|
64
|
-
// IPv6
|
|
65
|
-
|
|
66
|
-
|
|
64
|
+
// Node's URL parser keeps brackets in `.hostname` for every IPv6 literal
|
|
65
|
+
// (e.g. "[::1]", "[fc00::1]", "[::ffff:7f00:1]"). Strip them once so every
|
|
66
|
+
// check below operates on the bare address — without this, the fc00::/7
|
|
67
|
+
// and fe80::/10 checks further down never match anything (they test
|
|
68
|
+
// `startsWith('fc'/'fe80:')` against a string starting with "["), and an
|
|
69
|
+
// IPv4-mapped-IPv6 literal (`::ffff:a.b.c.d`, which Node normalizes to a
|
|
70
|
+
// canonical `::ffff:xxxx:yyyy` hex form) sails through both the IPv4 and
|
|
71
|
+
// IPv6 branches untested — a live SSRF bypass (e.g. `::ffff:127.0.0.1` or
|
|
72
|
+
// `::ffff:169.254.169.254` reaching loopback / cloud-metadata targets).
|
|
73
|
+
const bare = host.startsWith('[') && host.endsWith(']') ? host.slice(1, -1) : host;
|
|
74
|
+
if (bare === '::1')
|
|
75
|
+
return true; // IPv6 loopback
|
|
76
|
+
// IPv4-mapped IPv6 — decode back to dotted-decimal and recurse into the
|
|
77
|
+
// IPv4 check below so it inherits every existing private/loopback/
|
|
78
|
+
// link-local/CGNAT rule instead of needing its own copy.
|
|
79
|
+
const mappedHex = bare.match(/^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/);
|
|
80
|
+
if (mappedHex) {
|
|
81
|
+
const hi = parseInt(mappedHex[1], 16);
|
|
82
|
+
const lo = parseInt(mappedHex[2], 16);
|
|
83
|
+
const decoded = `${(hi >> 8) & 0xff}.${hi & 0xff}.${(lo >> 8) & 0xff}.${lo & 0xff}`;
|
|
84
|
+
return isPrivateOrLoopback(decoded);
|
|
85
|
+
}
|
|
86
|
+
const mappedDecimal = bare.match(/^::ffff:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/);
|
|
87
|
+
if (mappedDecimal)
|
|
88
|
+
return isPrivateOrLoopback(mappedDecimal[1]);
|
|
67
89
|
// IPv4 numeric checks
|
|
68
|
-
const m =
|
|
90
|
+
const m = bare.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/);
|
|
69
91
|
if (m) {
|
|
70
92
|
const a = Number(m[1]);
|
|
71
93
|
const b = Number(m[2]);
|
|
@@ -85,12 +107,18 @@ function isPrivateOrLoopback(host) {
|
|
|
85
107
|
return true; // CGNAT
|
|
86
108
|
return false;
|
|
87
109
|
}
|
|
88
|
-
// IPv6
|
|
89
|
-
//
|
|
90
|
-
if (
|
|
110
|
+
// IPv6 special forms — be conservative and accept only public-looking
|
|
111
|
+
// literals. Reject obvious private/local forms.
|
|
112
|
+
if (bare.startsWith('fc') || bare.startsWith('fd'))
|
|
91
113
|
return true; // fc00::/7 ULA
|
|
92
|
-
if (
|
|
114
|
+
if (bare.startsWith('fe80:'))
|
|
93
115
|
return true; // link-local
|
|
116
|
+
// KNOWN LIMITATION (pre-existing, not introduced by the bracket-stripping /
|
|
117
|
+
// IPv4-mapped-IPv6 fix above; flagged by an independent adversarial review):
|
|
118
|
+
// `::` (IPv6 unspecified/"any", the analog of 0.0.0.0, which the IPv4 branch
|
|
119
|
+
// above does block), IPv6 multicast (ff00::/8), and NAT64 (64:ff9b::/96) are
|
|
120
|
+
// not covered. Left as a follow-up hardening item rather than scope-creeping
|
|
121
|
+
// this patch.
|
|
94
122
|
return false;
|
|
95
123
|
}
|
|
96
124
|
export function validateHeaders(headers) {
|
|
@@ -54,6 +54,9 @@ async function maRequest(method, path, body, timeoutMs = 30_000) {
|
|
|
54
54
|
const key = apiKey();
|
|
55
55
|
if (!key)
|
|
56
56
|
return { ok: false, status: 0, error: NEEDS_KEY.error };
|
|
57
|
+
// encodeURIComponent leaves '.' and '..' alone, so an id of '..' would walk up the API path (/v1/sessions/.. is /v1/).
|
|
58
|
+
if (path.split('?')[0].split('/').some(segment => segment === '.' || segment === '..'))
|
|
59
|
+
return { ok: false, status: 0, error: 'Invalid managed resource id' };
|
|
57
60
|
try {
|
|
58
61
|
const res = await fetch(`${apiBase()}/v1${path}`, {
|
|
59
62
|
method, headers: headers(key), redirect: 'error',
|
|
@@ -91,6 +91,11 @@ function atomicWriteJson(file, value) {
|
|
|
91
91
|
fs.closeSync(fd);
|
|
92
92
|
}
|
|
93
93
|
fs.renameSync(tmp, file);
|
|
94
|
+
// Windows cannot flush a directory handle (FlushFileBuffers fails with EPERM on NTFS), and there the journaled rename needs no such step.
|
|
95
|
+
// Skipping it there is the same rule policy-runtime's syncDirectory follows (#3398). On POSIX a failure here means the rename may not be
|
|
96
|
+
// durable, so it still reaches the caller (#4492).
|
|
97
|
+
if (process.platform === 'win32')
|
|
98
|
+
return;
|
|
94
99
|
const dirFd = fs.openSync(path.dirname(file), fs.constants.O_RDONLY);
|
|
95
100
|
try {
|
|
96
101
|
fs.fsyncSync(dirFd);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@claude-flow/cli",
|
|
3
|
-
"version": "3.63.
|
|
3
|
+
"version": "3.63.2",
|
|
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",
|