claude-flow 3.59.3 → 3.59.5
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.json +1 -1
- package/package.json +1 -1
- package/v3/@claude-flow/cli/catalog-manifest.json +2 -2
- package/v3/@claude-flow/cli/dist/src/commands/memory-distill.js +23 -7
- package/v3/@claude-flow/cli/dist/src/mcp-tools/hive-mind-tools.js +54 -11
- package/v3/@claude-flow/cli/dist/src/services/memory-distillation.d.ts +37 -1
- package/v3/@claude-flow/cli/dist/src/services/memory-distillation.js +82 -2
- package/v3/@claude-flow/cli/dist/src/services/worker-daemon.js +16 -3
- package/v3/@claude-flow/cli/package.json +1 -1
package/package.json
CHANGED
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
import * as fs from 'fs';
|
|
28
28
|
import * as path from 'path';
|
|
29
29
|
import { output } from '../output.js';
|
|
30
|
-
import {
|
|
30
|
+
import { runDistillationForStores, projectMemoryDbPaths, defaultMemoryDbPath, } from '../services/memory-distillation.js';
|
|
31
31
|
const DEFAULT_CONFIG = {
|
|
32
32
|
dryRun: false,
|
|
33
33
|
batchSize: 200,
|
|
@@ -139,7 +139,15 @@ const runCommand = {
|
|
|
139
139
|
'Refusing to run the LLM judge against a $0 budget.');
|
|
140
140
|
return { success: false, exitCode: 1 };
|
|
141
141
|
}
|
|
142
|
-
|
|
142
|
+
// An explicit --db remains a single-store operation. Without it, cover
|
|
143
|
+
// both stores the CLI/MCP surfaces can write (#3446): memory.db and the
|
|
144
|
+
// native AgentDB sibling. An MCP-only project often has only the latter,
|
|
145
|
+
// which is why the worker used to skip with "target table ... missing".
|
|
146
|
+
const explicitDb = typeof ctx.flags.db === 'string' && ctx.flags.db.trim()
|
|
147
|
+
? path.resolve(ctx.flags.db)
|
|
148
|
+
: undefined;
|
|
149
|
+
const dbPaths = explicitDb ? [explicitDb] : projectMemoryDbPaths(ctx.cwd || process.cwd());
|
|
150
|
+
const dbPath = explicitDb ?? dbPaths[0];
|
|
143
151
|
output.writeln();
|
|
144
152
|
output.writeln(output.bold('Memory Distillation (ADR-174)'));
|
|
145
153
|
output.writeln(output.dim('─'.repeat(55)));
|
|
@@ -148,7 +156,6 @@ const runCommand = {
|
|
|
148
156
|
const spinner = output.createSpinner({ text: 'Distilling memory_entries...', spinner: 'dots' });
|
|
149
157
|
spinner.start();
|
|
150
158
|
const distillOptions = {
|
|
151
|
-
dbPath,
|
|
152
159
|
namespaces: config.namespaces,
|
|
153
160
|
batchSize: config.batchSize,
|
|
154
161
|
maxEntries: config.maxEntries,
|
|
@@ -158,22 +165,31 @@ const runCommand = {
|
|
|
158
165
|
sinceRowid: config.sinceRowid,
|
|
159
166
|
verbose: ctx.flags.verbose === true,
|
|
160
167
|
};
|
|
161
|
-
let
|
|
168
|
+
let outcome;
|
|
162
169
|
try {
|
|
163
|
-
|
|
170
|
+
outcome = await runDistillationForStores(dbPaths, distillOptions);
|
|
164
171
|
}
|
|
165
172
|
catch (error) {
|
|
166
173
|
spinner.fail('Distillation failed');
|
|
167
174
|
output.printError(error instanceof Error ? error.message : String(error));
|
|
168
175
|
return { success: false, exitCode: 1 };
|
|
169
176
|
}
|
|
177
|
+
const report = outcome.report;
|
|
170
178
|
if (report.skipped) {
|
|
171
179
|
spinner.succeed('Distillation skipped');
|
|
172
180
|
output.writeln(output.warning(`skipped: ${report.skipped}`));
|
|
173
|
-
return { success: true, data: { dbPath, config, report } };
|
|
181
|
+
return { success: true, data: { dbPath, dbPaths, stores: outcome.stores, config, report } };
|
|
174
182
|
}
|
|
175
183
|
spinner.succeed(config.dryRun ? 'Dry-run complete' : 'Distillation complete');
|
|
176
184
|
output.writeln();
|
|
185
|
+
for (const store of outcome.stores) {
|
|
186
|
+
if (store.report.skipped) {
|
|
187
|
+
output.writeln(output.warning(`${store.dbPath}: ${store.report.skipped}`));
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
if (outcome.stores.length > 1) {
|
|
191
|
+
output.writeln(output.dim(`Stores covered: ${outcome.stores.length}`));
|
|
192
|
+
}
|
|
177
193
|
output.printTable({
|
|
178
194
|
columns: [
|
|
179
195
|
{ key: 'metric', header: 'Metric', width: 24 },
|
|
@@ -198,7 +214,7 @@ const runCommand = {
|
|
|
198
214
|
output.writeln(output.bold('By Provenance'));
|
|
199
215
|
output.printList(provenanceEntries.map(([tier, count]) => `${output.highlight(tier)}: ${count}`));
|
|
200
216
|
}
|
|
201
|
-
return { success: true, data: { dbPath, config, report } };
|
|
217
|
+
return { success: true, data: { dbPath, dbPaths, stores: outcome.stores, config, report } };
|
|
202
218
|
},
|
|
203
219
|
};
|
|
204
220
|
// ============================================================================
|
|
@@ -361,6 +361,24 @@ export const hiveMindTools = [
|
|
|
361
361
|
description: 'Consensus strategy. Default: raft (anti-drift). Use byzantine for f<n/3 fault tolerance.',
|
|
362
362
|
},
|
|
363
363
|
queenId: { type: 'string', description: 'Initial queen agent ID' },
|
|
364
|
+
maxAgents: {
|
|
365
|
+
type: 'number',
|
|
366
|
+
minimum: 1,
|
|
367
|
+
maximum: 1000,
|
|
368
|
+
default: 15,
|
|
369
|
+
description: 'Maximum number of agents the hive may contain (default: 15)',
|
|
370
|
+
},
|
|
371
|
+
memoryBackend: {
|
|
372
|
+
type: 'string',
|
|
373
|
+
enum: ['agentdb', 'sqlite', 'hybrid'],
|
|
374
|
+
default: 'hybrid',
|
|
375
|
+
description: 'Memory backend requested for this hive (default: hybrid)',
|
|
376
|
+
},
|
|
377
|
+
persist: {
|
|
378
|
+
type: 'boolean',
|
|
379
|
+
default: true,
|
|
380
|
+
description: 'Persist hive state to .claude-flow/hive-mind/state.json. Set false for an ephemeral init that writes no durable state.',
|
|
381
|
+
},
|
|
364
382
|
bootstrapSecret: { type: 'string', description: 'Operator secret (RUFLO_HIVE_BOOTSTRAP_SECRET or .claude-flow/hive-mind/bootstrap.secret). Only needed by remote/HTTP callers; local stdio/CLI callers omit it. See ADR-476.' },
|
|
365
383
|
},
|
|
366
384
|
},
|
|
@@ -372,16 +390,32 @@ export const hiveMindTools = [
|
|
|
372
390
|
if (bootstrapError) {
|
|
373
391
|
return { success: false, error: bootstrapError };
|
|
374
392
|
}
|
|
375
|
-
//
|
|
376
|
-
//
|
|
377
|
-
//
|
|
378
|
-
if (
|
|
379
|
-
|
|
393
|
+
// Validate the advertised init contract before creating any durable
|
|
394
|
+
// state (the operator secret is a filesystem write, so it must come
|
|
395
|
+
// after every input check).
|
|
396
|
+
if (input.persist !== undefined && typeof input.persist !== 'boolean') {
|
|
397
|
+
return { success: false, error: 'persist must be a boolean' };
|
|
398
|
+
}
|
|
399
|
+
const persist = input.persist !== false;
|
|
400
|
+
const maxAgents = input.maxAgents === undefined ? 15 : Number(input.maxAgents);
|
|
401
|
+
if (!Number.isInteger(maxAgents) || maxAgents < 1 || maxAgents > 1000) {
|
|
402
|
+
return { success: false, error: 'maxAgents must be an integer between 1 and 1000' };
|
|
403
|
+
}
|
|
404
|
+
const memoryBackend = input.memoryBackend === undefined ? 'hybrid' : String(input.memoryBackend);
|
|
405
|
+
if (memoryBackend !== 'agentdb' && memoryBackend !== 'sqlite' && memoryBackend !== 'hybrid') {
|
|
406
|
+
return { success: false, error: 'memoryBackend must be one of: agentdb, sqlite, hybrid' };
|
|
407
|
+
}
|
|
380
408
|
if (input.queenId) {
|
|
381
409
|
const v = validateIdentifier(input.queenId, 'queenId');
|
|
382
410
|
if (!v.valid)
|
|
383
411
|
return { success: false, error: v.error };
|
|
384
412
|
}
|
|
413
|
+
// Local first init materialises the 0600 operator secret so a later
|
|
414
|
+
// remote/HTTP deployment has something to be told out of band. The
|
|
415
|
+
// value is never returned. An ephemeral init (persist:false) must not
|
|
416
|
+
// write it either.
|
|
417
|
+
if (persist && classifyCaller(context) === 'local')
|
|
418
|
+
ensureBootstrapSecret();
|
|
385
419
|
const state = loadHiveState();
|
|
386
420
|
const hiveId = `hive-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
387
421
|
const queenId = input.queenId || `queen-${Date.now()}`;
|
|
@@ -389,6 +423,9 @@ export const hiveMindTools = [
|
|
|
389
423
|
state.initialized = true;
|
|
390
424
|
state.topology = input.topology || 'mesh';
|
|
391
425
|
state.consensusStrategy = requestedConsensus;
|
|
426
|
+
state.maxAgents = maxAgents;
|
|
427
|
+
state.memoryBackend = memoryBackend;
|
|
428
|
+
state.persist = persist;
|
|
392
429
|
state.createdAt = new Date().toISOString();
|
|
393
430
|
state.queen = {
|
|
394
431
|
agentId: queenId,
|
|
@@ -403,7 +440,8 @@ export const hiveMindTools = [
|
|
|
403
440
|
if (!state.hiveToken) {
|
|
404
441
|
state.hiveToken = randomBytes(32).toString('hex');
|
|
405
442
|
}
|
|
406
|
-
|
|
443
|
+
if (persist)
|
|
444
|
+
saveHiveState(state);
|
|
407
445
|
return {
|
|
408
446
|
success: true,
|
|
409
447
|
hiveId,
|
|
@@ -411,6 +449,7 @@ export const hiveMindTools = [
|
|
|
411
449
|
consensus: state.consensusStrategy,
|
|
412
450
|
queenId,
|
|
413
451
|
status: 'initialized',
|
|
452
|
+
persisted: persist,
|
|
414
453
|
// Deliberately NOT echoing state.hiveToken here (even though this
|
|
415
454
|
// call is itself now bootstrap-secret-gated): the CLI never reads
|
|
416
455
|
// it off this response (it uses getHiveTokenForCli()'s direct
|
|
@@ -419,9 +458,9 @@ export const hiveMindTools = [
|
|
|
419
458
|
config: {
|
|
420
459
|
topology: state.topology,
|
|
421
460
|
consensus: state.consensusStrategy,
|
|
422
|
-
maxAgents
|
|
423
|
-
persist
|
|
424
|
-
memoryBackend
|
|
461
|
+
maxAgents,
|
|
462
|
+
persist,
|
|
463
|
+
memoryBackend,
|
|
425
464
|
},
|
|
426
465
|
createdAt: state.createdAt,
|
|
427
466
|
};
|
|
@@ -468,8 +507,10 @@ export const hiveMindTools = [
|
|
|
468
507
|
hiveId: `hive-${state.createdAt ? new Date(state.createdAt).getTime() : Date.now()}`,
|
|
469
508
|
status: state.initialized ? 'active' : 'offline',
|
|
470
509
|
topology: state.topology,
|
|
471
|
-
// ADR-093 F3: surface the persisted strategy instead of a hardcoded
|
|
472
|
-
|
|
510
|
+
// ADR-093 F3: surface the persisted strategy instead of a hardcoded
|
|
511
|
+
// "byzantine". Init's documented default is raft, so legacy state
|
|
512
|
+
// without the field must not drift to a different protocol.
|
|
513
|
+
consensus: state.consensusStrategy ?? 'raft',
|
|
473
514
|
queen: state.queen ? {
|
|
474
515
|
id: state.queen.agentId,
|
|
475
516
|
agentId: state.queen.agentId,
|
|
@@ -508,6 +549,8 @@ export const hiveMindTools = [
|
|
|
508
549
|
// Additional fields
|
|
509
550
|
id: `hive-${state.createdAt ? new Date(state.createdAt).getTime() : Date.now()}`,
|
|
510
551
|
initialized: state.initialized,
|
|
552
|
+
maxAgents: state.maxAgents ?? 15,
|
|
553
|
+
memoryBackend: state.memoryBackend ?? 'hybrid',
|
|
511
554
|
workerCount: state.workers.length,
|
|
512
555
|
pendingConsensus: state.consensus.pending.length,
|
|
513
556
|
sharedMemoryKeys: Object.keys(state.sharedMemory).length,
|
|
@@ -37,6 +37,42 @@ export interface DistillReport {
|
|
|
37
37
|
* Incremental, $0, transactional, provenance-tagged.
|
|
38
38
|
*/
|
|
39
39
|
export declare function runDistillation(options: DistillOptions): Promise<DistillReport>;
|
|
40
|
-
/**
|
|
40
|
+
/**
|
|
41
|
+
* The two stores the CLI/MCP surface can write:
|
|
42
|
+
* - memory.db is the sql.js/CLI store (also used with encryption at rest);
|
|
43
|
+
* - agentdb-memory.db is the native AgentDB store the MCP bridge writes to.
|
|
44
|
+
*
|
|
45
|
+
* #3446: distillation used to default to memory.db only. In an MCP-only
|
|
46
|
+
* project that file often has no AgentDB target tables, so the daemon's
|
|
47
|
+
* consolidate worker skipped every tick while the rows accumulated in the
|
|
48
|
+
* sibling store. Keep both paths here (same root resolution as backup) so
|
|
49
|
+
* callers can cover every store without guessing which surface wrote.
|
|
50
|
+
*/
|
|
51
|
+
export declare function projectMemoryDbPaths(cwd?: string): string[];
|
|
52
|
+
/** Where the primary memory DB lives, for callers that still need one path. */
|
|
41
53
|
export declare function defaultMemoryDbPath(cwd?: string): string;
|
|
54
|
+
export interface StoreDistillResult {
|
|
55
|
+
dbPath: string;
|
|
56
|
+
report: DistillReport;
|
|
57
|
+
}
|
|
58
|
+
export interface MultiStoreDistillResult {
|
|
59
|
+
stores: StoreDistillResult[];
|
|
60
|
+
report: DistillReport;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Merge per-store reports without hiding a store's outcome. A run over both
|
|
64
|
+
* stores is only `skipped` when every store skipped; if one store distilled
|
|
65
|
+
* and the other had no schema/DB, the successful counts remain authoritative
|
|
66
|
+
* and the per-store skip stays available in `stores`.
|
|
67
|
+
*/
|
|
68
|
+
export declare function aggregateDistillReports(stores: StoreDistillResult[], dryRun?: boolean): DistillReport;
|
|
69
|
+
/**
|
|
70
|
+
* Run one distillation pass against each provided store.
|
|
71
|
+
*
|
|
72
|
+
* `runner` is injectable so callers/tests can exercise the multi-store
|
|
73
|
+
* orchestration without a native SQLite build; the default is the real
|
|
74
|
+
* service. A runner failure is converted to a per-store skip so one bad store
|
|
75
|
+
* cannot prevent the other from being distilled.
|
|
76
|
+
*/
|
|
77
|
+
export declare function runDistillationForStores(dbPaths: string[], options?: Omit<DistillOptions, 'dbPath'>, runner?: (options: DistillOptions) => Promise<DistillReport>): Promise<MultiStoreDistillResult>;
|
|
42
78
|
//# sourceMappingURL=memory-distillation.d.ts.map
|
|
@@ -28,6 +28,7 @@ import * as fs from 'fs';
|
|
|
28
28
|
import * as path from 'path';
|
|
29
29
|
import { distillTrajectoryContent, serialiseDistilled } from '../memory/structured-distill.js';
|
|
30
30
|
import { loadBetterSqlite3 } from '../memory/shared-sqlite.js';
|
|
31
|
+
import { resolveMemoryRoot } from '../memory/memory-root.js';
|
|
31
32
|
function emptyReport(dryRun, extra = {}) {
|
|
32
33
|
return {
|
|
33
34
|
processed: 0, episodes: 0, episodeEmbeddings: 0,
|
|
@@ -346,8 +347,87 @@ export async function runDistillation(options) {
|
|
|
346
347
|
}
|
|
347
348
|
return report;
|
|
348
349
|
}
|
|
349
|
-
/**
|
|
350
|
+
/**
|
|
351
|
+
* The two stores the CLI/MCP surface can write:
|
|
352
|
+
* - memory.db is the sql.js/CLI store (also used with encryption at rest);
|
|
353
|
+
* - agentdb-memory.db is the native AgentDB store the MCP bridge writes to.
|
|
354
|
+
*
|
|
355
|
+
* #3446: distillation used to default to memory.db only. In an MCP-only
|
|
356
|
+
* project that file often has no AgentDB target tables, so the daemon's
|
|
357
|
+
* consolidate worker skipped every tick while the rows accumulated in the
|
|
358
|
+
* sibling store. Keep both paths here (same root resolution as backup) so
|
|
359
|
+
* callers can cover every store without guessing which surface wrote.
|
|
360
|
+
*/
|
|
361
|
+
export function projectMemoryDbPaths(cwd = process.cwd()) {
|
|
362
|
+
// An explicit project DB pin stays a single-store operation, matching
|
|
363
|
+
// memory-backup's precedence.
|
|
364
|
+
const override = process.env.CLAUDE_FLOW_DB_PATH;
|
|
365
|
+
if (override && override.trim().length > 0)
|
|
366
|
+
return [path.resolve(cwd, override)];
|
|
367
|
+
const root = resolveMemoryRoot(cwd);
|
|
368
|
+
return [path.join(root, 'memory.db'), path.join(root, 'agentdb-memory.db')];
|
|
369
|
+
}
|
|
370
|
+
/** Where the primary memory DB lives, for callers that still need one path. */
|
|
350
371
|
export function defaultMemoryDbPath(cwd = process.cwd()) {
|
|
351
|
-
return
|
|
372
|
+
return projectMemoryDbPaths(cwd)[0];
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Merge per-store reports without hiding a store's outcome. A run over both
|
|
376
|
+
* stores is only `skipped` when every store skipped; if one store distilled
|
|
377
|
+
* and the other had no schema/DB, the successful counts remain authoritative
|
|
378
|
+
* and the per-store skip stays available in `stores`.
|
|
379
|
+
*/
|
|
380
|
+
export function aggregateDistillReports(stores, dryRun = false) {
|
|
381
|
+
const report = emptyReport(dryRun);
|
|
382
|
+
const skipped = [];
|
|
383
|
+
for (const { report: part } of stores) {
|
|
384
|
+
report.processed += part.processed;
|
|
385
|
+
report.episodes += part.episodes;
|
|
386
|
+
report.episodeEmbeddings += part.episodeEmbeddings;
|
|
387
|
+
report.patterns += part.patterns;
|
|
388
|
+
report.patternEmbeddings += part.patternEmbeddings;
|
|
389
|
+
report.causalEdges += part.causalEdges;
|
|
390
|
+
report.promoted += part.promoted;
|
|
391
|
+
report.spendUsd += part.spendUsd;
|
|
392
|
+
report.namespaces = [...new Set([...report.namespaces, ...part.namespaces])];
|
|
393
|
+
for (const [tier, count] of Object.entries(part.byProvenance)) {
|
|
394
|
+
report.byProvenance[tier] = (report.byProvenance[tier] ?? 0) + count;
|
|
395
|
+
}
|
|
396
|
+
if (part.corrupt)
|
|
397
|
+
report.corrupt = true;
|
|
398
|
+
if (part.skipped)
|
|
399
|
+
skipped.push(part.skipped);
|
|
400
|
+
}
|
|
401
|
+
if (stores.length > 0 && stores.every(store => store.report.skipped)) {
|
|
402
|
+
report.skipped = [...new Set(skipped)].join('; ');
|
|
403
|
+
}
|
|
404
|
+
return report;
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* Run one distillation pass against each provided store.
|
|
408
|
+
*
|
|
409
|
+
* `runner` is injectable so callers/tests can exercise the multi-store
|
|
410
|
+
* orchestration without a native SQLite build; the default is the real
|
|
411
|
+
* service. A runner failure is converted to a per-store skip so one bad store
|
|
412
|
+
* cannot prevent the other from being distilled.
|
|
413
|
+
*/
|
|
414
|
+
export async function runDistillationForStores(dbPaths, options = {}, runner = runDistillation) {
|
|
415
|
+
const stores = [];
|
|
416
|
+
for (const dbPath of [...new Set(dbPaths.map(p => path.resolve(p)))]) {
|
|
417
|
+
let report;
|
|
418
|
+
try {
|
|
419
|
+
report = await runner({ ...options, dbPath });
|
|
420
|
+
}
|
|
421
|
+
catch (error) {
|
|
422
|
+
report = emptyReport(options.dryRun === true, {
|
|
423
|
+
skipped: `error: ${error instanceof Error ? error.message : String(error)}`,
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
stores.push({ dbPath, report });
|
|
427
|
+
}
|
|
428
|
+
if (stores.length === 0) {
|
|
429
|
+
return { stores, report: emptyReport(options.dryRun === true, { skipped: 'no-db' }) };
|
|
430
|
+
}
|
|
431
|
+
return { stores, report: aggregateDistillReports(stores, options.dryRun === true) };
|
|
352
432
|
}
|
|
353
433
|
//# sourceMappingURL=memory-distillation.js.map
|
|
@@ -23,7 +23,7 @@ import { HeadlessWorkerExecutor, isHeadlessWorker, } from './headless-worker-exe
|
|
|
23
23
|
// service itself is owned/frozen elsewhere (memory-distillation.ts) — it is
|
|
24
24
|
// incremental (rowid cursor), non-destructive, transactional, and
|
|
25
25
|
// quick_check-gated, so it's safe to call unconditionally on every tick.
|
|
26
|
-
import {
|
|
26
|
+
import { runDistillationForStores, projectMemoryDbPaths, } from './memory-distillation.js';
|
|
27
27
|
import { backupProjectMemoryDbs } from './memory-backup.js';
|
|
28
28
|
import { resolveGitWorkspaceIdentity } from './git-workspace-identity.js';
|
|
29
29
|
import { getWorkspaceLeaseRegistry } from './workspace-lease.js';
|
|
@@ -1614,13 +1614,15 @@ export class WorkerDaemon extends EventEmitter {
|
|
|
1614
1614
|
return disabledResult;
|
|
1615
1615
|
}
|
|
1616
1616
|
let report;
|
|
1617
|
+
let stores = [];
|
|
1617
1618
|
try {
|
|
1618
|
-
|
|
1619
|
-
dbPath: defaultMemoryDbPath(this.projectRoot),
|
|
1619
|
+
const outcome = await runDistillationForStores(projectMemoryDbPaths(this.projectRoot), {
|
|
1620
1620
|
maxEntries: CONSOLIDATE_MAX_ENTRIES_PER_TICK,
|
|
1621
1621
|
batchSize: CONSOLIDATE_BATCH_SIZE,
|
|
1622
1622
|
dedupDistance: CONSOLIDATE_DEDUP_DISTANCE,
|
|
1623
1623
|
});
|
|
1624
|
+
report = outcome.report;
|
|
1625
|
+
stores = outcome.stores;
|
|
1624
1626
|
}
|
|
1625
1627
|
catch (error) {
|
|
1626
1628
|
// Defensive only — runDistillation() is internally try/catch'd and
|
|
@@ -1638,6 +1640,11 @@ export class WorkerDaemon extends EventEmitter {
|
|
|
1638
1640
|
writeFileSync(consolidateFile, JSON.stringify(errorResult, null, 2));
|
|
1639
1641
|
return errorResult;
|
|
1640
1642
|
}
|
|
1643
|
+
for (const store of stores) {
|
|
1644
|
+
if (store.report.skipped) {
|
|
1645
|
+
this.log('info', `Consolidate worker: ${store.dbPath} skipped (${store.report.skipped})`);
|
|
1646
|
+
}
|
|
1647
|
+
}
|
|
1641
1648
|
if (report.corrupt) {
|
|
1642
1649
|
this.log('warn', `Consolidate worker: memory DB reports corruption — ${report.skipped ?? 'skipped'}`);
|
|
1643
1650
|
}
|
|
@@ -1667,6 +1674,12 @@ export class WorkerDaemon extends EventEmitter {
|
|
|
1667
1674
|
dryRun: report.dryRun,
|
|
1668
1675
|
corrupt: report.corrupt ?? false,
|
|
1669
1676
|
skipped: report.skipped,
|
|
1677
|
+
stores: stores.map(({ dbPath, report: part }) => ({
|
|
1678
|
+
dbPath,
|
|
1679
|
+
processed: part.processed,
|
|
1680
|
+
patterns: part.patterns,
|
|
1681
|
+
skipped: part.skipped,
|
|
1682
|
+
})),
|
|
1670
1683
|
};
|
|
1671
1684
|
writeFileSync(consolidateFile, JSON.stringify(result, null, 2));
|
|
1672
1685
|
return result;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@claude-flow/cli",
|
|
3
|
-
"version": "3.59.
|
|
3
|
+
"version": "3.59.5",
|
|
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",
|