claude-flow 3.54.1 → 3.55.0
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/.proven-config-version +1 -0
- package/.claude/proven-config.json +42 -0
- package/node_modules/@claude-flow/mcp/dist/connection-pool.d.ts.map +1 -1
- package/node_modules/@claude-flow/mcp/dist/connection-pool.js +5 -2
- package/node_modules/@claude-flow/mcp/dist/connection-pool.js.map +1 -1
- package/node_modules/@claude-flow/mcp/dist/transport/http.d.ts +7 -1
- package/node_modules/@claude-flow/mcp/dist/transport/http.d.ts.map +1 -1
- package/node_modules/@claude-flow/mcp/dist/transport/http.js +60 -47
- package/node_modules/@claude-flow/mcp/dist/transport/http.js.map +1 -1
- package/node_modules/@claude-flow/mcp/package.json +1 -1
- package/node_modules/@claude-flow/plugin-agent-federation/dist/application/federation-coordinator.js +1 -1
- package/node_modules/@claude-flow/plugin-agent-federation/dist/application/federation-coordinator.js.map +1 -1
- package/node_modules/@claude-flow/plugin-agent-federation/dist/bin.js +0 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/services/routing-service.d.ts +3 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/services/routing-service.d.ts.map +1 -1
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/services/routing-service.js +4 -1
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/services/routing-service.js.map +1 -1
- package/node_modules/@claude-flow/plugin-agent-federation/dist/plugin.d.ts.map +1 -1
- package/node_modules/@claude-flow/plugin-agent-federation/dist/plugin.js +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/plugin.js.map +1 -1
- package/node_modules/@claude-flow/plugin-agent-federation/package.json +1 -1
- package/node_modules/@claude-flow/security/dist/policy/engine.d.ts +11 -1
- package/node_modules/@claude-flow/security/dist/policy/engine.d.ts.map +1 -1
- package/node_modules/@claude-flow/security/dist/policy/engine.js +19 -3
- package/node_modules/@claude-flow/security/dist/policy/engine.js.map +1 -1
- package/node_modules/@claude-flow/security/dist/policy/types.d.ts +4 -2
- package/node_modules/@claude-flow/security/dist/policy/types.d.ts.map +1 -1
- package/node_modules/@claude-flow/security/package.json +1 -1
- package/package.json +5 -5
- package/v3/@claude-flow/cli/bin/cli.js +1 -1
- package/v3/@claude-flow/cli/bin/mcp-server.js +1 -1
- package/v3/@claude-flow/cli/catalog-manifest.json +2 -2
- package/v3/@claude-flow/cli/dist/src/commands/autopilot.js +2 -2
- package/v3/@claude-flow/cli/dist/src/commands/daemon.js +21 -1
- package/v3/@claude-flow/cli/dist/src/commands/hive-mind.js +7 -0
- package/v3/@claude-flow/cli/dist/src/commands/mcp.js +35 -1
- package/v3/@claude-flow/cli/dist/src/commands/policy.js +10 -2
- package/v3/@claude-flow/cli/dist/src/mcp-server.d.ts +33 -0
- package/v3/@claude-flow/cli/dist/src/mcp-server.js +96 -4
- package/v3/@claude-flow/cli/dist/src/mcp-tools/hive-mind-tools.d.ts +2 -4
- package/v3/@claude-flow/cli/dist/src/mcp-tools/hive-mind-tools.js +214 -40
- package/v3/@claude-flow/cli/dist/src/missions/schemas.d.ts +125 -125
- package/v3/@claude-flow/cli/dist/src/mods/command-registry/schema.d.ts +199 -199
- package/v3/@claude-flow/cli/dist/src/parser.d.ts +3 -0
- package/v3/@claude-flow/cli/dist/src/parser.js +64 -13
- package/v3/@claude-flow/cli/dist/src/production/retry.js +1 -1
- package/v3/@claude-flow/cli/dist/src/services/bounded-worker-pool.js +3 -0
- package/v3/@claude-flow/cli/dist/src/services/config-file-manager.d.ts +3 -0
- package/v3/@claude-flow/cli/dist/src/services/config-file-manager.js +24 -7
- package/v3/@claude-flow/cli/dist/src/services/policy-ledger-anchor.d.ts +42 -0
- package/v3/@claude-flow/cli/dist/src/services/policy-ledger-anchor.js +163 -0
- package/v3/@claude-flow/cli/dist/src/services/policy-runtime.d.ts +11 -5
- package/v3/@claude-flow/cli/dist/src/services/policy-runtime.js +70 -15
- package/v3/@claude-flow/cli/dist/src/services/worker-daemon.d.ts +1 -0
- package/v3/@claude-flow/cli/dist/src/services/worker-daemon.js +12 -0
- package/v3/@claude-flow/cli/dist/src/services/worker-queue.js +11 -2
- package/v3/@claude-flow/cli/package.json +7 -7
- package/v3/@claude-flow/shared/dist/events/event-store-pagination.test.d.ts +2 -0
- package/v3/@claude-flow/shared/dist/events/event-store-pagination.test.js +32 -0
- package/v3/@claude-flow/shared/dist/events/event-store.js +6 -2
- package/v3/@claude-flow/shared/dist/mcp/connection-pool.js +5 -2
- package/v3/@claude-flow/shared/dist/resilience/bulkhead-sync-throw.test.d.ts +2 -0
- package/v3/@claude-flow/shared/dist/resilience/bulkhead-sync-throw.test.js +33 -0
- package/v3/@claude-flow/shared/dist/resilience/bulkhead.js +2 -1
- package/v3/@claude-flow/shared/dist/resilience/retry-timeout-cleanup.test.d.ts +2 -0
- package/v3/@claude-flow/shared/dist/resilience/retry-timeout-cleanup.test.js +38 -0
- package/v3/@claude-flow/shared/dist/resilience/retry.js +9 -2
- package/v3/@claude-flow/shared/package.json +1 -1
|
@@ -193,6 +193,7 @@ export class WorkerDaemon extends EventEmitter {
|
|
|
193
193
|
?? fileConfig.aiWorkersEnabled
|
|
194
194
|
?? (process.env.RUFLO_DAEMON_AI_WORKERS === '1'),
|
|
195
195
|
workers: config?.workers ?? DEFAULT_WORKERS,
|
|
196
|
+
enabledWorkers: config?.enabledWorkers,
|
|
196
197
|
};
|
|
197
198
|
// #2935 — deferred from readDaemonConfigFromFile(): this.config (and
|
|
198
199
|
// therefore this.config.logDir) doesn't exist until the assignment
|
|
@@ -700,6 +701,17 @@ export class WorkerDaemon extends EventEmitter {
|
|
|
700
701
|
// Ignore parse errors, start fresh
|
|
701
702
|
}
|
|
702
703
|
}
|
|
704
|
+
// #3547 (#1968 follow-up): an explicit `--workers` selection wins over
|
|
705
|
+
// both DEFAULT_WORKERS and whatever daemon-state.json just restored
|
|
706
|
+
// above — otherwise `daemon start --workers map,audit` always ran the
|
|
707
|
+
// full default set (or a stale saved selection) because nothing ever
|
|
708
|
+
// applied the requested list to `enabled`.
|
|
709
|
+
if (this.config.enabledWorkers) {
|
|
710
|
+
const selected = new Set(this.config.enabledWorkers);
|
|
711
|
+
for (const workerConfig of this.config.workers) {
|
|
712
|
+
workerConfig.enabled = selected.has(workerConfig.type);
|
|
713
|
+
}
|
|
714
|
+
}
|
|
703
715
|
// Initialize any missing workers
|
|
704
716
|
for (const workerConfig of this.config.workers) {
|
|
705
717
|
if (!this.workers.has(workerConfig.type)) {
|
|
@@ -233,8 +233,9 @@ export class WorkerQueue extends EventEmitter {
|
|
|
233
233
|
// Check queues in priority order
|
|
234
234
|
for (const workerType of workerTypes) {
|
|
235
235
|
const queueName = this.getQueueName(workerType);
|
|
236
|
-
|
|
237
|
-
|
|
236
|
+
let taskId;
|
|
237
|
+
// Cancelled or otherwise stale entries do not exhaust this worker type.
|
|
238
|
+
while ((taskId = this.store.popFromQueue(queueName)) !== null) {
|
|
238
239
|
const task = this.store.getTask(taskId);
|
|
239
240
|
if (task && task.status === 'pending') {
|
|
240
241
|
task.status = 'processing';
|
|
@@ -258,6 +259,10 @@ export class WorkerQueue extends EventEmitter {
|
|
|
258
259
|
this.emit('warning', { message: `Task ${taskId} not found for completion` });
|
|
259
260
|
return;
|
|
260
261
|
}
|
|
262
|
+
// Late or duplicate outcomes must not rewrite a settled task.
|
|
263
|
+
if (['completed', 'failed', 'timeout', 'cancelled'].includes(task.status)) {
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
261
266
|
task.status = 'completed';
|
|
262
267
|
task.completedAt = new Date();
|
|
263
268
|
task.result = result;
|
|
@@ -276,6 +281,10 @@ export class WorkerQueue extends EventEmitter {
|
|
|
276
281
|
this.emit('warning', { message: `Task ${taskId} not found for failure` });
|
|
277
282
|
return;
|
|
278
283
|
}
|
|
284
|
+
// Late or duplicate outcomes must not rewrite a settled task.
|
|
285
|
+
if (['completed', 'failed', 'timeout', 'cancelled'].includes(task.status)) {
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
279
288
|
this.processingTasks.delete(taskId);
|
|
280
289
|
// Check if we should retry
|
|
281
290
|
if (retryable && task.retryCount < task.maxRetries) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@claude-flow/cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.55.0",
|
|
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",
|
|
@@ -100,11 +100,11 @@
|
|
|
100
100
|
"dependencies": {
|
|
101
101
|
"@claude-flow/cli-core": "3.7.0",
|
|
102
102
|
"@claude-flow/codex": "3.0.3",
|
|
103
|
-
"@claude-flow/mcp": "3.
|
|
103
|
+
"@claude-flow/mcp": "3.1.0",
|
|
104
104
|
"@claude-flow/neural": "3.0.0",
|
|
105
|
-
"@claude-flow/plugin-agent-federation": "1.0.
|
|
106
|
-
"@claude-flow/security": "3.0.
|
|
107
|
-
"@claude-flow/shared": "3.0.
|
|
105
|
+
"@claude-flow/plugin-agent-federation": "1.0.1",
|
|
106
|
+
"@claude-flow/security": "3.0.2",
|
|
107
|
+
"@claude-flow/shared": "3.0.2",
|
|
108
108
|
"@iarna/toml": "^2.2.5",
|
|
109
109
|
"@noble/ed25519": "2.3.0",
|
|
110
110
|
"@ruvector/rabitq-wasm": "0.1.0",
|
|
@@ -125,11 +125,11 @@
|
|
|
125
125
|
"ws": "^8.21.0",
|
|
126
126
|
"yaml": "^2.8.0",
|
|
127
127
|
"zod": "^3.22.0",
|
|
128
|
-
"@claude-flow/memory": "3.0.
|
|
128
|
+
"@claude-flow/memory": "3.0.1"
|
|
129
129
|
},
|
|
130
130
|
"optionalDependencies": {
|
|
131
131
|
"@agntcy/slim-bindings": "2.0.0-alpha.5",
|
|
132
|
-
"@claude-flow/memory": "3.0.
|
|
132
|
+
"@claude-flow/memory": "3.0.1",
|
|
133
133
|
"@metaharness/darwin": "~0.10.2",
|
|
134
134
|
"@metaharness/flywheel": "~0.1.10",
|
|
135
135
|
"@metaharness/radio": "~0.1.0",
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { beforeEach, afterEach, describe, it, expect } from 'vitest';
|
|
2
|
+
import { EventStore } from './event-store.js';
|
|
3
|
+
import { createAgentSpawnedEvent } from './domain-events.js';
|
|
4
|
+
describe('SQLite event query pagination', () => {
|
|
5
|
+
let store;
|
|
6
|
+
beforeEach(async () => {
|
|
7
|
+
store = new EventStore({
|
|
8
|
+
databasePath: ':memory:',
|
|
9
|
+
autoPersistInterval: 0,
|
|
10
|
+
});
|
|
11
|
+
await store.initialize();
|
|
12
|
+
for (let i = 0; i < 3; i++) {
|
|
13
|
+
const event = createAgentSpawnedEvent(`agent-${i}`, 'coder', 'core', []);
|
|
14
|
+
event.timestamp = 100 + i;
|
|
15
|
+
await store.append(event);
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
afterEach(async () => {
|
|
19
|
+
await store.shutdown();
|
|
20
|
+
});
|
|
21
|
+
it('supports offsets without a caller-specified limit', async () => {
|
|
22
|
+
expect((await store.query({ offset: 1 })).map((event) => event.aggregateId)).toEqual(['agent-1', 'agent-2']);
|
|
23
|
+
});
|
|
24
|
+
it('returns no rows for an explicit zero limit', async () => {
|
|
25
|
+
expect(await store.query({ limit: 0 })).toEqual([]);
|
|
26
|
+
expect(await store.query({ limit: 0, offset: 1 })).toEqual([]);
|
|
27
|
+
});
|
|
28
|
+
it('retains bounded page ordering', async () => {
|
|
29
|
+
expect((await store.query({ limit: 1, offset: 1 })).map((event) => event.aggregateId)).toEqual(['agent-1']);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
//# sourceMappingURL=event-store-pagination.test.js.map
|
|
@@ -225,11 +225,15 @@ export class EventStore extends EventEmitter {
|
|
|
225
225
|
// Order by timestamp
|
|
226
226
|
sql += ' ORDER BY timestamp ASC';
|
|
227
227
|
// Pagination
|
|
228
|
-
if (filter.limit) {
|
|
228
|
+
if (filter.limit !== undefined) {
|
|
229
229
|
sql += ' LIMIT ?';
|
|
230
230
|
params.push(filter.limit);
|
|
231
231
|
}
|
|
232
|
-
if (filter.offset) {
|
|
232
|
+
else if (filter.offset !== undefined) {
|
|
233
|
+
// SQLite requires LIMIT before OFFSET; -1 means no upper bound.
|
|
234
|
+
sql += ' LIMIT -1';
|
|
235
|
+
}
|
|
236
|
+
if (filter.offset !== undefined) {
|
|
233
237
|
sql += ' OFFSET ?';
|
|
234
238
|
params.push(filter.offset);
|
|
235
239
|
}
|
|
@@ -119,9 +119,12 @@ export class ConnectionPool extends EventEmitter {
|
|
|
119
119
|
/**
|
|
120
120
|
* Create a new connection
|
|
121
121
|
*/
|
|
122
|
-
async createConnection() {
|
|
122
|
+
async createConnection(reserved = false) {
|
|
123
123
|
const id = `conn-${++this.connectionCounter}-${Date.now()}`;
|
|
124
124
|
const connection = new ManagedConnection(id, this.transportType);
|
|
125
|
+
// Reserve before exposing it in the map or yielding to another acquirer.
|
|
126
|
+
if (reserved)
|
|
127
|
+
connection.state = 'busy';
|
|
125
128
|
this.connections.set(id, connection);
|
|
126
129
|
this.stats.totalCreated++;
|
|
127
130
|
this.emit('pool:connection:created', { connectionId: id });
|
|
@@ -149,7 +152,7 @@ export class ConnectionPool extends EventEmitter {
|
|
|
149
152
|
}
|
|
150
153
|
// Create new connection if under limit
|
|
151
154
|
if (this.connections.size < this.config.maxConnections) {
|
|
152
|
-
const connection = await this.createConnection();
|
|
155
|
+
const connection = await this.createConnection(true);
|
|
153
156
|
connection.acquire();
|
|
154
157
|
this.stats.totalAcquired++;
|
|
155
158
|
this.recordAcquireTime(startTime);
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { Bulkhead } from './bulkhead.js';
|
|
3
|
+
describe('queued bulkhead failures', () => {
|
|
4
|
+
it('rejects the throwing task and preserves the previous result and remaining capacity', async () => {
|
|
5
|
+
const bulkhead = new Bulkhead({
|
|
6
|
+
name: 'test',
|
|
7
|
+
maxConcurrent: 1,
|
|
8
|
+
maxQueue: 2,
|
|
9
|
+
queueTimeout: 100,
|
|
10
|
+
});
|
|
11
|
+
let release;
|
|
12
|
+
const first = bulkhead.execute(() => new Promise((resolve) => {
|
|
13
|
+
release = resolve;
|
|
14
|
+
}));
|
|
15
|
+
const failure = new Error('synchronous callback failure');
|
|
16
|
+
const second = bulkhead.execute(() => {
|
|
17
|
+
throw failure;
|
|
18
|
+
});
|
|
19
|
+
const secondResult = second.catch((error) => error);
|
|
20
|
+
const third = bulkhead.execute(async () => 'third');
|
|
21
|
+
release('first');
|
|
22
|
+
await expect(first).resolves.toBe('first');
|
|
23
|
+
expect(await secondResult).toBe(failure);
|
|
24
|
+
await expect(third).resolves.toBe('third');
|
|
25
|
+
await Promise.resolve();
|
|
26
|
+
expect(bulkhead.getStats()).toMatchObject({
|
|
27
|
+
active: 0,
|
|
28
|
+
queued: 0,
|
|
29
|
+
completed: 2,
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
//# sourceMappingURL=bulkhead-sync-throw.test.js.map
|
|
@@ -158,7 +158,8 @@ export class Bulkhead extends EventEmitter {
|
|
|
158
158
|
// Execute the queued function
|
|
159
159
|
this.active++;
|
|
160
160
|
this.emit('acquire');
|
|
161
|
-
|
|
161
|
+
Promise.resolve()
|
|
162
|
+
.then(() => item.fn())
|
|
162
163
|
.then((result) => {
|
|
163
164
|
this.completed++;
|
|
164
165
|
item.resolve(result);
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { afterEach, describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import { retry } from './retry.js';
|
|
3
|
+
afterEach(() => vi.useRealTimers());
|
|
4
|
+
describe('retry timeout lifetime', () => {
|
|
5
|
+
it('does not keep a success timer alive after an attempt settles', async () => {
|
|
6
|
+
vi.useFakeTimers();
|
|
7
|
+
const result = await retry(async () => 42, {
|
|
8
|
+
maxAttempts: 1,
|
|
9
|
+
timeout: 30000,
|
|
10
|
+
});
|
|
11
|
+
expect(result.success).toBe(true);
|
|
12
|
+
expect(result.result).toBe(42);
|
|
13
|
+
expect(vi.getTimerCount()).toBe(0);
|
|
14
|
+
});
|
|
15
|
+
it('releases timers for rejected attempts without suppressing their errors', async () => {
|
|
16
|
+
vi.useFakeTimers();
|
|
17
|
+
const err = new Error('no');
|
|
18
|
+
const result = await retry(async () => {
|
|
19
|
+
throw err;
|
|
20
|
+
}, { maxAttempts: 1 });
|
|
21
|
+
expect(result.success).toBe(false);
|
|
22
|
+
expect(result.errors).toEqual([err]);
|
|
23
|
+
expect(vi.getTimerCount()).toBe(0);
|
|
24
|
+
});
|
|
25
|
+
it('still bounds a pending operation and reports the timeout', async () => {
|
|
26
|
+
vi.useFakeTimers();
|
|
27
|
+
const promise = retry(() => new Promise(() => { }), {
|
|
28
|
+
maxAttempts: 1,
|
|
29
|
+
timeout: 10,
|
|
30
|
+
});
|
|
31
|
+
await vi.advanceTimersByTimeAsync(10);
|
|
32
|
+
const result = await promise;
|
|
33
|
+
expect(result.success).toBe(false);
|
|
34
|
+
expect(result.errors[0].message).toContain('timed out');
|
|
35
|
+
expect(vi.getTimerCount()).toBe(0);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
//# sourceMappingURL=retry-timeout-cleanup.test.js.map
|
|
@@ -117,12 +117,19 @@ export function withRetry(fn, options = {}) {
|
|
|
117
117
|
* Execute with timeout
|
|
118
118
|
*/
|
|
119
119
|
async function withTimeout(promise, timeout, attempt) {
|
|
120
|
+
let timer;
|
|
120
121
|
const timeoutPromise = new Promise((_, reject) => {
|
|
121
|
-
setTimeout(() => {
|
|
122
|
+
timer = setTimeout(() => {
|
|
122
123
|
reject(new Error(`Attempt ${attempt} timed out after ${timeout}ms`));
|
|
123
124
|
}, timeout);
|
|
124
125
|
});
|
|
125
|
-
|
|
126
|
+
try {
|
|
127
|
+
return await Promise.race([promise, timeoutPromise]);
|
|
128
|
+
}
|
|
129
|
+
finally {
|
|
130
|
+
if (timer !== undefined)
|
|
131
|
+
clearTimeout(timer);
|
|
132
|
+
}
|
|
126
133
|
}
|
|
127
134
|
/**
|
|
128
135
|
* Sleep for specified milliseconds
|