claude-flow 3.21.0 → 3.22.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/package.json +1 -1
- package/v3/@claude-flow/cli/dist/src/commands/daemon.js +23 -2
- package/v3/@claude-flow/cli/dist/src/commands/doctor.js +56 -0
- package/v3/@claude-flow/cli/dist/src/commands/memory-distill.d.ts +27 -0
- package/v3/@claude-flow/cli/dist/src/commands/memory-distill.js +374 -0
- package/v3/@claude-flow/cli/dist/src/commands/memory.js +4 -2
- package/v3/@claude-flow/cli/dist/src/index.d.ts +1 -1
- package/v3/@claude-flow/cli/dist/src/index.js +22 -1
- package/v3/@claude-flow/cli/dist/src/init/executor.js +37 -0
- package/v3/@claude-flow/cli/dist/src/init/helper-refresh.d.ts +19 -0
- package/v3/@claude-flow/cli/dist/src/init/helper-refresh.js +175 -0
- package/v3/@claude-flow/cli/dist/src/init/helper-signing.d.ts +30 -0
- package/v3/@claude-flow/cli/dist/src/init/helper-signing.js +60 -0
- package/v3/@claude-flow/cli/dist/src/init/helpers-generator.d.ts +16 -0
- package/v3/@claude-flow/cli/dist/src/init/helpers-generator.js +89 -8
- package/v3/@claude-flow/cli/dist/src/init/memory-package-resolver.d.ts +53 -0
- package/v3/@claude-flow/cli/dist/src/init/memory-package-resolver.js +118 -0
- package/v3/@claude-flow/cli/dist/src/init/statusline-generator.js +18 -7
- package/v3/@claude-flow/cli/dist/src/mcp-client.js +13 -0
- package/v3/@claude-flow/cli/dist/src/mcp-tools/agenticow-speculate-tools.js +9 -2
- package/v3/@claude-flow/cli/dist/src/mcp-tools/browser-intent-tools.d.ts +162 -0
- package/v3/@claude-flow/cli/dist/src/mcp-tools/browser-intent-tools.js +548 -0
- package/v3/@claude-flow/cli/dist/src/mcp-tools/browser-tools.d.ts +9 -1
- package/v3/@claude-flow/cli/dist/src/mcp-tools/browser-tools.js +4 -1
- package/v3/@claude-flow/cli/dist/src/memory/memory-bridge.js +115 -54
- package/v3/@claude-flow/cli/dist/src/memory/memory-initializer.d.ts +71 -0
- package/v3/@claude-flow/cli/dist/src/memory/memory-initializer.js +330 -2
- package/v3/@claude-flow/cli/dist/src/services/distill-tuning.d.ts +111 -0
- package/v3/@claude-flow/cli/dist/src/services/distill-tuning.js +510 -0
- package/v3/@claude-flow/cli/dist/src/services/memory-distillation.d.ts +41 -0
- package/v3/@claude-flow/cli/dist/src/services/memory-distillation.js +277 -0
- package/v3/@claude-flow/cli/dist/src/services/worker-daemon.d.ts +22 -1
- package/v3/@claude-flow/cli/dist/src/services/worker-daemon.js +117 -6
- package/v3/@claude-flow/cli/package.json +5 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-flow",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.22.0",
|
|
4
4
|
"description": "Ruflo - Enterprise AI agent orchestration for Claude Code. Deploy 60+ specialized agents in coordinated swarms with self-learning, fault-tolerant consensus, vector memory, and MCP integration",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -14,6 +14,12 @@ const startCommand = {
|
|
|
14
14
|
description: 'Start the worker daemon with all enabled background workers',
|
|
15
15
|
options: [
|
|
16
16
|
{ name: 'workers', short: 'w', type: 'string', description: 'Comma-separated list of workers to enable (default: map,audit,optimize,consolidate,testgaps)' },
|
|
17
|
+
// ADR-174 M3: consolidate now runs a real memory-distillation pass
|
|
18
|
+
// (memory_entries -> episodes/reasoning_patterns/causal_edges) instead of
|
|
19
|
+
// a no-op stub. This opt-out skips just that pass for the life of this
|
|
20
|
+
// daemon process, without touching persisted worker-enabled state — for
|
|
21
|
+
// permanently disabling the worker use `daemon enable -w consolidate --disable`.
|
|
22
|
+
{ name: 'no-distill', type: 'boolean', description: 'Disable the consolidate worker\'s memory-distillation pass (ADR-174)' },
|
|
17
23
|
{ name: 'quiet', short: 'Q', type: 'boolean', description: 'Suppress output' },
|
|
18
24
|
{ name: 'background', short: 'b', type: 'boolean', description: 'Run daemon in background (detached process)', default: true },
|
|
19
25
|
{ name: 'foreground', short: 'f', type: 'boolean', description: 'Run daemon in foreground (blocks terminal)' },
|
|
@@ -35,10 +41,19 @@ const startCommand = {
|
|
|
35
41
|
{ command: 'claude-flow daemon start --foreground', description: 'Start in foreground (blocks terminal)' },
|
|
36
42
|
{ command: 'claude-flow daemon start -w map,audit,optimize', description: 'Start with specific workers' },
|
|
37
43
|
{ command: 'claude-flow daemon start --headless --sandbox strict', description: 'Start with headless workers in strict sandbox' },
|
|
44
|
+
{ command: 'claude-flow daemon start --no-distill', description: 'Start with the consolidate worker\'s distillation pass disabled' },
|
|
38
45
|
],
|
|
39
46
|
action: async (ctx) => {
|
|
40
47
|
const quiet = ctx.flags.quiet;
|
|
41
48
|
const foreground = ctx.flags.foreground;
|
|
49
|
+
const noDistill = ctx.flags['no-distill'];
|
|
50
|
+
// ADR-174 M3: honored by WorkerDaemon's consolidate worker directly via
|
|
51
|
+
// process.env — set it now so the foreground path (which runs in this
|
|
52
|
+
// same process) picks it up too; the background path forwards it to the
|
|
53
|
+
// forked child's env explicitly (see startBackgroundDaemon below).
|
|
54
|
+
if (noDistill) {
|
|
55
|
+
process.env.RUFLO_DAEMON_NO_DISTILL = '1';
|
|
56
|
+
}
|
|
42
57
|
// #1914: a forked daemon child receives --workspace <root>; the launcher
|
|
43
58
|
// and interactive invocations have no flag and fall back to cwd.
|
|
44
59
|
const projectRoot = resolveWorkspaceFlag(ctx.flags.workspace) ?? process.cwd();
|
|
@@ -208,6 +223,7 @@ const startCommand = {
|
|
|
208
223
|
headless: ctx.flags.headless,
|
|
209
224
|
sandbox: ctx.flags.sandbox,
|
|
210
225
|
ttl: rawTtl,
|
|
226
|
+
noDistill,
|
|
211
227
|
});
|
|
212
228
|
}
|
|
213
229
|
finally {
|
|
@@ -404,7 +420,7 @@ export function extractWorkspaceFromDaemonLine(commandLine) {
|
|
|
404
420
|
return ws.length > 0 ? ws : null;
|
|
405
421
|
}
|
|
406
422
|
async function startBackgroundDaemon(projectRoot, quiet, forwarded = {}) {
|
|
407
|
-
const { maxCpuLoad, minFreeMemory, workers, headless, sandbox, ttl } = forwarded;
|
|
423
|
+
const { maxCpuLoad, minFreeMemory, workers, headless, sandbox, ttl, noDistill } = forwarded;
|
|
408
424
|
// Validate and resolve project root
|
|
409
425
|
const resolvedRoot = resolve(projectRoot);
|
|
410
426
|
validatePath(resolvedRoot, 'Project root');
|
|
@@ -493,6 +509,11 @@ async function startBackgroundDaemon(projectRoot, quiet, forwarded = {}) {
|
|
|
493
509
|
if (typeof sandbox === 'string' && (sandbox === 'strict' || sandbox === 'permissive' || sandbox === 'disabled')) {
|
|
494
510
|
forkArgs.push('--sandbox', sandbox);
|
|
495
511
|
}
|
|
512
|
+
// ADR-174 M3: forward the distillation opt-out to the forked foreground
|
|
513
|
+
// child; its own `start` action sets RUFLO_DAEMON_NO_DISTILL from this flag.
|
|
514
|
+
if (noDistill === true) {
|
|
515
|
+
forkArgs.push('--no-distill');
|
|
516
|
+
}
|
|
496
517
|
// #1914: stamp the workspace into argv (kept LAST) so the foreground daemon
|
|
497
518
|
// process is self-identifying and `killStaleDaemons` only reaps daemons
|
|
498
519
|
// belonging to this workspace. resolvedRoot was validatePath()'d above.
|
|
@@ -1352,7 +1373,7 @@ export const daemonCommand = {
|
|
|
1352
1373
|
`${output.highlight('map')} - Codebase mapping (5 min interval)`,
|
|
1353
1374
|
`${output.highlight('audit')} - Security analysis (10 min interval)`,
|
|
1354
1375
|
`${output.highlight('optimize')} - Performance optimization (15 min interval)`,
|
|
1355
|
-
`${output.highlight('consolidate')} - Memory
|
|
1376
|
+
`${output.highlight('consolidate')} - Memory distillation: memory_entries -> episodes/reasoning_patterns/causal_edges (30 min interval, ADR-174; --no-distill to disable)`,
|
|
1356
1377
|
`${output.highlight('testgaps')} - Test coverage analysis (20 min interval)`,
|
|
1357
1378
|
`${output.highlight('predict')} - Predictive preloading (2 min, disabled by default)`,
|
|
1358
1379
|
`${output.highlight('document')} - Auto-documentation (60 min, disabled by default)`,
|
|
@@ -13,6 +13,7 @@ import { execSync, exec } from 'child_process';
|
|
|
13
13
|
import { promisify } from 'util';
|
|
14
14
|
import { decodeKey, isEncryptionEnabled } from '../encryption/vault.js';
|
|
15
15
|
import { isEncryptedBlob } from '../encryption/vault.js';
|
|
16
|
+
import { resolveMemoryPackageFromProject, readMemoryPackageVersion, recordMemoryPackagePath, } from '../init/memory-package-resolver.js';
|
|
16
17
|
// Promisified exec with proper shell and env inheritance for cross-platform support
|
|
17
18
|
const execAsync = promisify(exec);
|
|
18
19
|
/**
|
|
@@ -244,6 +245,37 @@ async function checkMemoryDatabase() {
|
|
|
244
245
|
}
|
|
245
246
|
return { name: 'Memory Database', status: 'warn', message: 'Not initialized', fix: 'claude-flow memory configure --backend hybrid' };
|
|
246
247
|
}
|
|
248
|
+
// #2545: Check that the self-learning bridge can actually load @claude-flow/memory
|
|
249
|
+
// the SAME way the SessionStart auto-memory hook does. On the documented `npx ruflo`
|
|
250
|
+
// path the package lands in the npx cache — unreachable from the project — so the
|
|
251
|
+
// hook silently no-op'd with no signal anywhere. This surfaces it.
|
|
252
|
+
async function checkLearningBridge() {
|
|
253
|
+
const cwd = process.cwd();
|
|
254
|
+
const hookPath = join(cwd, '.claude', 'helpers', 'auto-memory-hook.mjs');
|
|
255
|
+
// Only relevant once init has deployed the hook; otherwise stay quiet.
|
|
256
|
+
if (!existsSync(hookPath)) {
|
|
257
|
+
return {
|
|
258
|
+
name: 'Learning Bridge',
|
|
259
|
+
status: 'pass',
|
|
260
|
+
message: 'auto-memory hook not installed (run: npx ruflo@latest init)',
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
const distPath = resolveMemoryPackageFromProject(cwd);
|
|
264
|
+
if (distPath) {
|
|
265
|
+
const version = readMemoryPackageVersion(distPath);
|
|
266
|
+
return {
|
|
267
|
+
name: 'Learning Bridge',
|
|
268
|
+
status: 'pass',
|
|
269
|
+
message: `@claude-flow/memory resolvable${version ? ` (v${version})` : ''}`,
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
return {
|
|
273
|
+
name: 'Learning Bridge',
|
|
274
|
+
status: 'fail',
|
|
275
|
+
message: '@claude-flow/memory NOT resolvable — SessionStart self-learning imports are a silent no-op',
|
|
276
|
+
fix: 'npx ruflo@latest doctor --fix (records resolver sidecar) — or: npm i -D @claude-flow/memory',
|
|
277
|
+
};
|
|
278
|
+
}
|
|
247
279
|
// Check API keys
|
|
248
280
|
async function checkApiKeys() {
|
|
249
281
|
const keys = ['ANTHROPIC_API_KEY', 'CLAUDE_API_KEY', 'OPENAI_API_KEY'];
|
|
@@ -1036,6 +1068,7 @@ export const doctorCommand = {
|
|
|
1036
1068
|
checkStaleSettingsNpx, // #2448 — runaway `npx @latest` in statusLine/hooks
|
|
1037
1069
|
checkDaemonStatus,
|
|
1038
1070
|
checkMemoryDatabase,
|
|
1071
|
+
checkLearningBridge, // #2545 — can the auto-memory hook actually load @claude-flow/memory?
|
|
1039
1072
|
checkApiKeys,
|
|
1040
1073
|
checkMcpServers,
|
|
1041
1074
|
checkAIDefence, // #1807
|
|
@@ -1057,6 +1090,8 @@ export const doctorCommand = {
|
|
|
1057
1090
|
'stale-settings': checkStaleSettingsNpx, // #2448
|
|
1058
1091
|
'daemon': checkDaemonStatus,
|
|
1059
1092
|
'memory': checkMemoryDatabase,
|
|
1093
|
+
'learning': checkLearningBridge, // #2545
|
|
1094
|
+
'learning-bridge': checkLearningBridge, // #2545
|
|
1060
1095
|
'api': checkApiKeys,
|
|
1061
1096
|
'git': checkGit,
|
|
1062
1097
|
'mcp': checkMcpServers,
|
|
@@ -1107,6 +1142,27 @@ export const doctorCommand = {
|
|
|
1107
1142
|
spinner.stop();
|
|
1108
1143
|
output.writeln(output.error('Failed to run health checks'));
|
|
1109
1144
|
}
|
|
1145
|
+
// #2545: --fix / --install can actually repair the Learning Bridge by
|
|
1146
|
+
// recording the resolver sidecar. When doctor runs via `npx ruflo`, the CLI
|
|
1147
|
+
// CAN resolve its optional @claude-flow/memory dep (it is in the same npx
|
|
1148
|
+
// cache), so writing the sidecar makes the SessionStart hook find it.
|
|
1149
|
+
if ((showFix || autoInstall)) {
|
|
1150
|
+
const lbResult = results.find(r => r.name === 'Learning Bridge');
|
|
1151
|
+
if (lbResult && lbResult.status === 'fail') {
|
|
1152
|
+
const record = recordMemoryPackagePath(process.cwd(), 'doctor');
|
|
1153
|
+
if (record) {
|
|
1154
|
+
const newCheck = await checkLearningBridge();
|
|
1155
|
+
const idx = results.findIndex(r => r.name === 'Learning Bridge');
|
|
1156
|
+
if (idx !== -1)
|
|
1157
|
+
results[idx] = newCheck;
|
|
1158
|
+
const fixIdx = fixes.findIndex(f => f.startsWith('Learning Bridge:'));
|
|
1159
|
+
if (fixIdx !== -1 && newCheck.status === 'pass')
|
|
1160
|
+
fixes.splice(fixIdx, 1);
|
|
1161
|
+
output.writeln(output.success(`Repaired Learning Bridge — wrote .claude-flow/memory-package.json → ${record.distPath}`));
|
|
1162
|
+
output.writeln(formatCheck(newCheck));
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1110
1166
|
// Auto-install missing dependencies if requested
|
|
1111
1167
|
if (autoInstall) {
|
|
1112
1168
|
const claudeCodeResult = results.find(r => r.name === 'Claude Code CLI');
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Command, CommandContext } from '../types.js';
|
|
2
|
+
export interface DistillCliConfig {
|
|
3
|
+
dryRun: boolean;
|
|
4
|
+
namespaces?: string[];
|
|
5
|
+
batchSize: number;
|
|
6
|
+
dedupDistance: number;
|
|
7
|
+
maxEntries?: number;
|
|
8
|
+
sinceRowid?: number;
|
|
9
|
+
budgetUsd: number;
|
|
10
|
+
judge: 'structural' | 'fable';
|
|
11
|
+
}
|
|
12
|
+
type ResolveResult = {
|
|
13
|
+
ok: true;
|
|
14
|
+
config: DistillCliConfig;
|
|
15
|
+
} | {
|
|
16
|
+
ok: false;
|
|
17
|
+
error: string;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Resolve the effective distill config from: built-in defaults, an optional
|
|
21
|
+
* `--config <path>` JSON file, an `--aggressive`/`--conservative` preset, and
|
|
22
|
+
* finally explicit CLI flags (highest precedence).
|
|
23
|
+
*/
|
|
24
|
+
export declare function resolveDistillConfig(ctx: CommandContext): ResolveResult;
|
|
25
|
+
export declare const distillCommand: Command;
|
|
26
|
+
export default distillCommand;
|
|
27
|
+
//# sourceMappingURL=memory-distill.d.ts.map
|
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* V3 CLI `memory distill` Command Family (ADR-174 Milestone 2)
|
|
3
|
+
*
|
|
4
|
+
* CLI surface over the frozen M1 service (`../services/memory-distillation.js`
|
|
5
|
+
* — `runDistillation` / `defaultMemoryDbPath`). This file does not implement
|
|
6
|
+
* any distillation logic itself; it only resolves flags/config/presets into
|
|
7
|
+
* `DistillOptions`, calls the service, and formats the report.
|
|
8
|
+
*
|
|
9
|
+
* memory distill run — run (or dry-run) a distillation pass
|
|
10
|
+
* memory distill status — read-only report on the target tables + cursor
|
|
11
|
+
* memory distill config — print the effective resolved config as JSON
|
|
12
|
+
*
|
|
13
|
+
* Design notes:
|
|
14
|
+
* - `--judge fable` requires `--budget-usd > 0` (ADR-172 cost-bounded advisor
|
|
15
|
+
* gate). This is enforced here, client-side, as a fail-fast — the service
|
|
16
|
+
* itself also refuses (`skipped: 'judge:fable requires ...'`) but failing
|
|
17
|
+
* fast in the CLI gives a clearer, non-zero-exit error.
|
|
18
|
+
* - `--aggressive` / `--conservative` are preset bundles (ADR-174 param
|
|
19
|
+
* table). Precedence, low to high: built-in defaults < `--config` file <
|
|
20
|
+
* preset < explicit `--batch-size`/`--dedup-distance` flags.
|
|
21
|
+
* - `status` opens the DB read-only via the same "variable-specifier"
|
|
22
|
+
* optional-import pattern used by `../memory/graph-edge-writer.ts` so the
|
|
23
|
+
* TypeScript compiler never statically requires `better-sqlite3` types,
|
|
24
|
+
* and degrades gracefully (no throw) when the DB, tables, or the native
|
|
25
|
+
* module are absent.
|
|
26
|
+
*/
|
|
27
|
+
import * as fs from 'fs';
|
|
28
|
+
import * as path from 'path';
|
|
29
|
+
import { output } from '../output.js';
|
|
30
|
+
import { runDistillation, defaultMemoryDbPath, } from '../services/memory-distillation.js';
|
|
31
|
+
const DEFAULT_CONFIG = {
|
|
32
|
+
dryRun: false,
|
|
33
|
+
batchSize: 200,
|
|
34
|
+
dedupDistance: 0.2, // ADR-174 M4-tuned platform default (~37% fewer patterns, retrieval-neutral)
|
|
35
|
+
budgetUsd: 0,
|
|
36
|
+
judge: 'structural',
|
|
37
|
+
};
|
|
38
|
+
// ADR-174 preset bundles — distinct extremes around the 0.2 tuned default.
|
|
39
|
+
const AGGRESSIVE_PRESET = { dedupDistance: 0.3, batchSize: 500 }; // more clustering → fewer, coarser patterns
|
|
40
|
+
const CONSERVATIVE_PRESET = { dedupDistance: 0.1, batchSize: 100 }; // less clustering → more, granular patterns
|
|
41
|
+
const DB_OPTION = {
|
|
42
|
+
name: 'db',
|
|
43
|
+
description: 'Path to the memory DB (default: cwd/.swarm/memory.db)',
|
|
44
|
+
type: 'string',
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Resolve the effective distill config from: built-in defaults, an optional
|
|
48
|
+
* `--config <path>` JSON file, an `--aggressive`/`--conservative` preset, and
|
|
49
|
+
* finally explicit CLI flags (highest precedence).
|
|
50
|
+
*/
|
|
51
|
+
export function resolveDistillConfig(ctx) {
|
|
52
|
+
let cfg = { ...DEFAULT_CONFIG };
|
|
53
|
+
const configPath = ctx.flags.config;
|
|
54
|
+
if (configPath) {
|
|
55
|
+
try {
|
|
56
|
+
const raw = fs.readFileSync(path.resolve(configPath), 'utf8');
|
|
57
|
+
const parsed = JSON.parse(raw);
|
|
58
|
+
if (parsed && typeof parsed === 'object') {
|
|
59
|
+
cfg = { ...cfg, ...parsed };
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
return { ok: false, error: `Failed to load --config ${configPath}: ${error instanceof Error ? error.message : String(error)}` };
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
const aggressive = ctx.flags.aggressive === true;
|
|
67
|
+
const conservative = ctx.flags.conservative === true;
|
|
68
|
+
if (aggressive && conservative) {
|
|
69
|
+
return { ok: false, error: '--aggressive and --conservative are mutually exclusive' };
|
|
70
|
+
}
|
|
71
|
+
if (aggressive)
|
|
72
|
+
cfg = { ...cfg, ...AGGRESSIVE_PRESET };
|
|
73
|
+
if (conservative)
|
|
74
|
+
cfg = { ...cfg, ...CONSERVATIVE_PRESET };
|
|
75
|
+
// Explicit CLI flags win over the config file and presets.
|
|
76
|
+
if (ctx.flags.dryRun === true)
|
|
77
|
+
cfg.dryRun = true;
|
|
78
|
+
if (typeof ctx.flags.namespace === 'string' && ctx.flags.namespace.length > 0) {
|
|
79
|
+
cfg.namespaces = ctx.flags.namespace.split(',').map((s) => s.trim()).filter(Boolean);
|
|
80
|
+
}
|
|
81
|
+
if (ctx.flags.batchSize !== undefined)
|
|
82
|
+
cfg.batchSize = Number(ctx.flags.batchSize);
|
|
83
|
+
if (ctx.flags.dedupDistance !== undefined)
|
|
84
|
+
cfg.dedupDistance = Number(ctx.flags.dedupDistance);
|
|
85
|
+
if (ctx.flags.maxEntries !== undefined)
|
|
86
|
+
cfg.maxEntries = Number(ctx.flags.maxEntries);
|
|
87
|
+
if (ctx.flags.since !== undefined)
|
|
88
|
+
cfg.sinceRowid = Number(ctx.flags.since);
|
|
89
|
+
if (ctx.flags.budgetUsd !== undefined)
|
|
90
|
+
cfg.budgetUsd = Number(ctx.flags.budgetUsd);
|
|
91
|
+
if (ctx.flags.judge !== undefined) {
|
|
92
|
+
if (ctx.flags.judge !== 'structural' && ctx.flags.judge !== 'fable') {
|
|
93
|
+
return { ok: false, error: `--judge must be 'structural' or 'fable' (got '${String(ctx.flags.judge)}')` };
|
|
94
|
+
}
|
|
95
|
+
cfg.judge = ctx.flags.judge;
|
|
96
|
+
}
|
|
97
|
+
return { ok: true, config: cfg };
|
|
98
|
+
}
|
|
99
|
+
function resolveDbPath(ctx) {
|
|
100
|
+
return ctx.flags.db || defaultMemoryDbPath(ctx.cwd || process.cwd());
|
|
101
|
+
}
|
|
102
|
+
// ============================================================================
|
|
103
|
+
// `memory distill run`
|
|
104
|
+
// ============================================================================
|
|
105
|
+
const runCommand = {
|
|
106
|
+
name: 'run',
|
|
107
|
+
description: 'Distill memory_entries into episodes/reasoning_patterns/pattern_embeddings/causal_edges (ADR-174)',
|
|
108
|
+
options: [
|
|
109
|
+
{ name: 'dry-run', description: 'Report counts, write nothing', type: 'boolean', default: false },
|
|
110
|
+
{ name: 'namespace', description: 'Comma-separated namespace scope (default: all embedded namespaces)', type: 'string' },
|
|
111
|
+
{ name: 'batch-size', description: 'Rows per transaction (default 200)', type: 'number', default: 200 },
|
|
112
|
+
{ name: 'dedup-distance', description: 'Cosine distance for pattern clustering (default 0.12)', type: 'number', default: 0.12 },
|
|
113
|
+
{ name: 'max-entries', description: 'Per-invocation work cap (default unbounded)', type: 'number' },
|
|
114
|
+
{ name: 'since', description: 'Override the incremental cursor and rescan from this rowid', type: 'number' },
|
|
115
|
+
{ name: 'budget-usd', description: '$0 by default; >0 required to unlock --judge fable (ADR-172)', type: 'number', default: 0 },
|
|
116
|
+
{ name: 'judge', description: "'structural' (default, $0) or 'fable' (requires --budget-usd > 0)", type: 'string', default: 'structural', choices: ['structural', 'fable'] },
|
|
117
|
+
{ name: 'aggressive', description: 'Preset: dedup-distance 0.2, batch-size 500', type: 'boolean' },
|
|
118
|
+
{ name: 'conservative', description: 'Preset: dedup-distance 0.08, batch-size 100', type: 'boolean' },
|
|
119
|
+
{ name: 'config', description: 'Load options from a JSON config file (see: memory distill config)', type: 'string' },
|
|
120
|
+
{ ...DB_OPTION },
|
|
121
|
+
{ name: 'verbose', short: 'v', description: 'Verbose service logging', type: 'boolean' },
|
|
122
|
+
],
|
|
123
|
+
examples: [
|
|
124
|
+
{ command: 'claude-flow memory distill run --dry-run', description: 'Preview counts without writing anything' },
|
|
125
|
+
{ command: 'claude-flow memory distill run --namespace feedback,commands', description: 'Scope the run to specific namespaces' },
|
|
126
|
+
{ command: 'claude-flow memory distill run --aggressive', description: 'Larger batches, looser dedup clustering' },
|
|
127
|
+
{ command: 'claude-flow memory distill run --judge fable --budget-usd 2', description: 'Opt into the cost-bounded Fable judge (ADR-172)' },
|
|
128
|
+
],
|
|
129
|
+
action: async (ctx) => {
|
|
130
|
+
const resolved = resolveDistillConfig(ctx);
|
|
131
|
+
if (!resolved.ok) {
|
|
132
|
+
output.printError(resolved.error);
|
|
133
|
+
return { success: false, exitCode: 1 };
|
|
134
|
+
}
|
|
135
|
+
const config = resolved.config;
|
|
136
|
+
// Fail-fast ADR-172 gate: the Fable judge is cost-bounded and opt-in only.
|
|
137
|
+
if (config.judge === 'fable' && !(config.budgetUsd > 0)) {
|
|
138
|
+
output.printError('--judge fable requires --budget-usd > 0 (ADR-172 cost-bounded advisor path). ' +
|
|
139
|
+
'Refusing to run the LLM judge against a $0 budget.');
|
|
140
|
+
return { success: false, exitCode: 1 };
|
|
141
|
+
}
|
|
142
|
+
const dbPath = resolveDbPath(ctx);
|
|
143
|
+
output.writeln();
|
|
144
|
+
output.writeln(output.bold('Memory Distillation (ADR-174)'));
|
|
145
|
+
output.writeln(output.dim('─'.repeat(55)));
|
|
146
|
+
if (config.dryRun)
|
|
147
|
+
output.writeln(output.warning('DRY RUN — no writes will be made'));
|
|
148
|
+
const spinner = output.createSpinner({ text: 'Distilling memory_entries...', spinner: 'dots' });
|
|
149
|
+
spinner.start();
|
|
150
|
+
const distillOptions = {
|
|
151
|
+
dbPath,
|
|
152
|
+
namespaces: config.namespaces,
|
|
153
|
+
batchSize: config.batchSize,
|
|
154
|
+
maxEntries: config.maxEntries,
|
|
155
|
+
dedupDistance: config.dedupDistance,
|
|
156
|
+
dryRun: config.dryRun,
|
|
157
|
+
judge: config.judge,
|
|
158
|
+
sinceRowid: config.sinceRowid,
|
|
159
|
+
verbose: ctx.flags.verbose === true,
|
|
160
|
+
};
|
|
161
|
+
let report;
|
|
162
|
+
try {
|
|
163
|
+
report = await runDistillation(distillOptions);
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
spinner.fail('Distillation failed');
|
|
167
|
+
output.printError(error instanceof Error ? error.message : String(error));
|
|
168
|
+
return { success: false, exitCode: 1 };
|
|
169
|
+
}
|
|
170
|
+
if (report.skipped) {
|
|
171
|
+
spinner.succeed('Distillation skipped');
|
|
172
|
+
output.writeln(output.warning(`skipped: ${report.skipped}`));
|
|
173
|
+
return { success: true, data: { dbPath, config, report } };
|
|
174
|
+
}
|
|
175
|
+
spinner.succeed(config.dryRun ? 'Dry-run complete' : 'Distillation complete');
|
|
176
|
+
output.writeln();
|
|
177
|
+
output.printTable({
|
|
178
|
+
columns: [
|
|
179
|
+
{ key: 'metric', header: 'Metric', width: 24 },
|
|
180
|
+
{ key: 'value', header: 'Value', width: 20 },
|
|
181
|
+
],
|
|
182
|
+
data: [
|
|
183
|
+
{ metric: 'Processed', value: String(report.processed) },
|
|
184
|
+
{ metric: 'Episodes', value: String(report.episodes) },
|
|
185
|
+
{ metric: 'Patterns', value: String(report.patterns) },
|
|
186
|
+
{ metric: 'Pattern Embeddings', value: String(report.patternEmbeddings) },
|
|
187
|
+
{ metric: 'Causal Edges', value: String(report.causalEdges) },
|
|
188
|
+
{ metric: 'Promoted (ADR-171)', value: String(report.promoted) },
|
|
189
|
+
{ metric: 'Namespaces', value: report.namespaces.join(', ') || '(none)' },
|
|
190
|
+
{ metric: 'Spend', value: `$${report.spendUsd.toFixed(4)}` },
|
|
191
|
+
{ metric: 'Dry Run', value: report.dryRun ? 'yes' : 'no' },
|
|
192
|
+
],
|
|
193
|
+
});
|
|
194
|
+
const provenanceEntries = Object.entries(report.byProvenance);
|
|
195
|
+
if (provenanceEntries.length > 0) {
|
|
196
|
+
output.writeln();
|
|
197
|
+
output.writeln(output.bold('By Provenance'));
|
|
198
|
+
output.printList(provenanceEntries.map(([tier, count]) => `${output.highlight(tier)}: ${count}`));
|
|
199
|
+
}
|
|
200
|
+
return { success: true, data: { dbPath, config, report } };
|
|
201
|
+
},
|
|
202
|
+
};
|
|
203
|
+
// ============================================================================
|
|
204
|
+
// `memory distill status`
|
|
205
|
+
// ============================================================================
|
|
206
|
+
const statusCommand = {
|
|
207
|
+
name: 'status',
|
|
208
|
+
description: 'Read-only report: target table row counts, per-namespace distill_state cursor, promoted vs proxy breakdown',
|
|
209
|
+
options: [{ ...DB_OPTION }],
|
|
210
|
+
examples: [
|
|
211
|
+
{ command: 'claude-flow memory distill status', description: 'Show distillation state for the default DB' },
|
|
212
|
+
{ command: 'claude-flow memory distill status --db ./copy.db', description: 'Inspect a specific DB copy' },
|
|
213
|
+
],
|
|
214
|
+
action: async (ctx) => {
|
|
215
|
+
const dbPath = resolveDbPath(ctx);
|
|
216
|
+
output.writeln();
|
|
217
|
+
output.writeln(output.bold('Memory Distillation Status'));
|
|
218
|
+
output.writeln(output.dim('─'.repeat(55)));
|
|
219
|
+
if (!fs.existsSync(dbPath)) {
|
|
220
|
+
output.writeln(output.warning(`No memory DB found at ${dbPath}`));
|
|
221
|
+
return { success: true, data: { available: false, dbPath, reason: 'no-db' } };
|
|
222
|
+
}
|
|
223
|
+
// Optional native dep — hidden behind a variable specifier so the
|
|
224
|
+
// compiler never statically requires `better-sqlite3` types (same
|
|
225
|
+
// pattern as ../memory/graph-edge-writer.ts).
|
|
226
|
+
let Database;
|
|
227
|
+
try {
|
|
228
|
+
const mod = 'better-sqlite3';
|
|
229
|
+
Database = (await import(mod)).default;
|
|
230
|
+
}
|
|
231
|
+
catch {
|
|
232
|
+
output.writeln(output.warning('better-sqlite3 native module unavailable — cannot read distillation state.'));
|
|
233
|
+
return { success: true, data: { available: false, dbPath, reason: 'better-sqlite3 unavailable' } };
|
|
234
|
+
}
|
|
235
|
+
let db;
|
|
236
|
+
try {
|
|
237
|
+
db = new Database(dbPath, { readonly: true, fileMustExist: true });
|
|
238
|
+
}
|
|
239
|
+
catch (error) {
|
|
240
|
+
output.printError(`Failed to open ${dbPath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
241
|
+
return { success: true, data: { available: false, dbPath, reason: 'open-failed' } };
|
|
242
|
+
}
|
|
243
|
+
try {
|
|
244
|
+
const tableExists = (name) => (db.prepare("SELECT COUNT(*) AS c FROM sqlite_master WHERE type='table' AND name=?").get(name)?.c ?? 0) > 0;
|
|
245
|
+
const targetTables = ['episodes', 'reasoning_patterns', 'pattern_embeddings', 'causal_edges'];
|
|
246
|
+
const presence = {};
|
|
247
|
+
for (const t of [...targetTables, 'distill_state'])
|
|
248
|
+
presence[t] = tableExists(t);
|
|
249
|
+
const counts = {};
|
|
250
|
+
for (const t of targetTables) {
|
|
251
|
+
counts[t] = presence[t] ? (db.prepare(`SELECT COUNT(*) AS c FROM ${t}`).get()?.c ?? 0) : 0;
|
|
252
|
+
}
|
|
253
|
+
let cursors = [];
|
|
254
|
+
if (presence.distill_state) {
|
|
255
|
+
cursors = db.prepare('SELECT namespace AS namespace, last_rowid AS lastRowid, last_run_at AS lastRunAt FROM distill_state ORDER BY namespace').all();
|
|
256
|
+
}
|
|
257
|
+
let promoted = 0;
|
|
258
|
+
let proxy = 0;
|
|
259
|
+
if (presence.reasoning_patterns) {
|
|
260
|
+
promoted = db.prepare("SELECT COUNT(*) AS c FROM reasoning_patterns WHERE json_extract(metadata,'$.promoted')=1").get()?.c ?? 0;
|
|
261
|
+
proxy = db.prepare("SELECT COUNT(*) AS c FROM reasoning_patterns WHERE json_extract(metadata,'$.provenance')='proxy:structural'").get()?.c ?? 0;
|
|
262
|
+
}
|
|
263
|
+
db.close();
|
|
264
|
+
output.printTable({
|
|
265
|
+
columns: [
|
|
266
|
+
{ key: 'table', header: 'Table', width: 22 },
|
|
267
|
+
{ key: 'rows', header: 'Rows', width: 10 },
|
|
268
|
+
],
|
|
269
|
+
data: targetTables.map((t) => ({ table: t, rows: String(counts[t]) })),
|
|
270
|
+
});
|
|
271
|
+
output.writeln();
|
|
272
|
+
output.writeln(output.bold('Promote gate (ADR-171)'));
|
|
273
|
+
output.writeln(` promoted: ${promoted} proxy (never promoted): ${proxy} total patterns: ${counts.reasoning_patterns}`);
|
|
274
|
+
if (cursors.length > 0) {
|
|
275
|
+
output.writeln();
|
|
276
|
+
output.writeln(output.bold('distill_state cursor'));
|
|
277
|
+
output.printTable({
|
|
278
|
+
columns: [
|
|
279
|
+
{ key: 'namespace', header: 'Namespace', width: 20 },
|
|
280
|
+
{ key: 'lastRowid', header: 'Last Rowid', width: 12 },
|
|
281
|
+
{ key: 'lastRunAt', header: 'Last Run', width: 26 },
|
|
282
|
+
],
|
|
283
|
+
data: cursors.map((c) => ({
|
|
284
|
+
namespace: c.namespace,
|
|
285
|
+
lastRowid: String(c.lastRowid),
|
|
286
|
+
lastRunAt: c.lastRunAt ? new Date(c.lastRunAt).toISOString() : 'never',
|
|
287
|
+
})),
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
else {
|
|
291
|
+
output.writeln();
|
|
292
|
+
output.writeln(output.dim('No distill_state cursor rows yet (run `memory distill run` first).'));
|
|
293
|
+
}
|
|
294
|
+
if (!presence.reasoning_patterns) {
|
|
295
|
+
output.writeln();
|
|
296
|
+
output.writeln(output.dim('Target tables not present — agentdb schema not initialised, or distillation never run.'));
|
|
297
|
+
}
|
|
298
|
+
return {
|
|
299
|
+
success: true,
|
|
300
|
+
data: { available: true, dbPath, counts, cursors, promoted, proxy, tablesPresent: presence },
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
catch (error) {
|
|
304
|
+
try {
|
|
305
|
+
db?.close();
|
|
306
|
+
}
|
|
307
|
+
catch { /* best-effort */ }
|
|
308
|
+
output.printError(error instanceof Error ? error.message : String(error));
|
|
309
|
+
return { success: true, data: { available: false, dbPath, reason: 'error' } };
|
|
310
|
+
}
|
|
311
|
+
},
|
|
312
|
+
};
|
|
313
|
+
// ============================================================================
|
|
314
|
+
// `memory distill config`
|
|
315
|
+
// ============================================================================
|
|
316
|
+
const configCommand = {
|
|
317
|
+
name: 'config',
|
|
318
|
+
description: 'Print the effective distill config (defaults + --config file + preset + explicit flags) as JSON',
|
|
319
|
+
options: [
|
|
320
|
+
{ name: 'config', description: 'Load options from a JSON config file', type: 'string' },
|
|
321
|
+
{ name: 'aggressive', description: 'Preset: dedup-distance 0.2, batch-size 500', type: 'boolean' },
|
|
322
|
+
{ name: 'conservative', description: 'Preset: dedup-distance 0.08, batch-size 100', type: 'boolean' },
|
|
323
|
+
{ name: 'namespace', description: 'Comma-separated namespace scope', type: 'string' },
|
|
324
|
+
{ name: 'batch-size', description: 'Rows per transaction', type: 'number' },
|
|
325
|
+
{ name: 'dedup-distance', description: 'Cosine distance for pattern clustering', type: 'number' },
|
|
326
|
+
{ name: 'max-entries', description: 'Per-invocation work cap', type: 'number' },
|
|
327
|
+
{ name: 'since', description: 'Override incremental cursor start (rowid)', type: 'number' },
|
|
328
|
+
{ name: 'budget-usd', description: '$0 by default', type: 'number' },
|
|
329
|
+
{ name: 'judge', description: "'structural' | 'fable'", type: 'string' },
|
|
330
|
+
{ ...DB_OPTION },
|
|
331
|
+
],
|
|
332
|
+
examples: [
|
|
333
|
+
{ command: 'claude-flow memory distill config', description: 'Print the platform-default config' },
|
|
334
|
+
{ command: 'claude-flow memory distill config --aggressive', description: 'Print the effective config with the aggressive preset applied' },
|
|
335
|
+
],
|
|
336
|
+
action: async (ctx) => {
|
|
337
|
+
const resolved = resolveDistillConfig(ctx);
|
|
338
|
+
if (!resolved.ok) {
|
|
339
|
+
output.printError(resolved.error);
|
|
340
|
+
return { success: false, exitCode: 1 };
|
|
341
|
+
}
|
|
342
|
+
const dbPath = resolveDbPath(ctx);
|
|
343
|
+
const payload = { dbPath, ...resolved.config };
|
|
344
|
+
output.writeln(JSON.stringify(payload, null, 2));
|
|
345
|
+
return { success: true, data: payload };
|
|
346
|
+
},
|
|
347
|
+
};
|
|
348
|
+
// ============================================================================
|
|
349
|
+
// `memory distill` (parent)
|
|
350
|
+
// ============================================================================
|
|
351
|
+
export const distillCommand = {
|
|
352
|
+
name: 'distill',
|
|
353
|
+
description: 'Memory distillation (ADR-174): mine memory_entries into reasoning_patterns/episodes/causal_edges',
|
|
354
|
+
subcommands: [runCommand, statusCommand, configCommand],
|
|
355
|
+
examples: [
|
|
356
|
+
{ command: 'claude-flow memory distill run --dry-run', description: 'Preview a distillation pass' },
|
|
357
|
+
{ command: 'claude-flow memory distill status', description: 'Show distilled table counts + cursor' },
|
|
358
|
+
{ command: 'claude-flow memory distill config --conservative', description: 'Print the effective conservative-preset config' },
|
|
359
|
+
],
|
|
360
|
+
action: async () => {
|
|
361
|
+
output.writeln();
|
|
362
|
+
output.writeln(output.bold('Memory Distillation (ADR-174)'));
|
|
363
|
+
output.writeln('Usage: claude-flow memory distill <run|status|config> [options]');
|
|
364
|
+
output.writeln();
|
|
365
|
+
output.printList([
|
|
366
|
+
`${output.highlight('run')} - Distill memory_entries into the structured intelligence tables`,
|
|
367
|
+
`${output.highlight('status')} - Report target table counts, cursor, and promote-gate breakdown`,
|
|
368
|
+
`${output.highlight('config')} - Print the effective resolved config as JSON`,
|
|
369
|
+
]);
|
|
370
|
+
return { success: true };
|
|
371
|
+
},
|
|
372
|
+
};
|
|
373
|
+
export default distillCommand;
|
|
374
|
+
//# sourceMappingURL=memory-distill.js.map
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import { output } from '../output.js';
|
|
6
6
|
import { select, confirm, input } from '../prompt.js';
|
|
7
7
|
import { callMCPTool, MCPClientError } from '../mcp-client.js';
|
|
8
|
+
import { distillCommand } from './memory-distill.js';
|
|
8
9
|
// Memory backends
|
|
9
10
|
const BACKENDS = [
|
|
10
11
|
{ value: 'agentdb', label: 'AgentDB', hint: 'Vector database with HNSW indexing (150x-12,500x faster)' },
|
|
@@ -1471,7 +1472,7 @@ const initMemoryCommand = {
|
|
|
1471
1472
|
export const memoryCommand = {
|
|
1472
1473
|
name: 'memory',
|
|
1473
1474
|
description: 'Memory management commands',
|
|
1474
|
-
subcommands: [initMemoryCommand, storeCommand, retrieveCommand, searchCommand, listCommand, deleteCommand, statsCommand, configureCommand, cleanupCommand, compressCommand, exportCommand, importCommand],
|
|
1475
|
+
subcommands: [initMemoryCommand, storeCommand, retrieveCommand, searchCommand, listCommand, deleteCommand, statsCommand, configureCommand, cleanupCommand, compressCommand, exportCommand, importCommand, distillCommand],
|
|
1475
1476
|
options: [],
|
|
1476
1477
|
examples: [
|
|
1477
1478
|
{ command: 'claude-flow memory store -k "key" -v "value"', description: 'Store data' },
|
|
@@ -1497,7 +1498,8 @@ export const memoryCommand = {
|
|
|
1497
1498
|
`${output.highlight('cleanup')} - Clean expired entries`,
|
|
1498
1499
|
`${output.highlight('compress')} - Compress database`,
|
|
1499
1500
|
`${output.highlight('export')} - Export memory to file`,
|
|
1500
|
-
`${output.highlight('import')} - Import from file
|
|
1501
|
+
`${output.highlight('import')} - Import from file`,
|
|
1502
|
+
`${output.highlight('distill')} - Distill memory_entries into structured intelligence (ADR-174)`
|
|
1501
1503
|
]);
|
|
1502
1504
|
return { success: true };
|
|
1503
1505
|
}
|
|
@@ -63,7 +63,7 @@ export { OutputFormatter, output, Progress, Spinner, type VerbosityLevel } from
|
|
|
63
63
|
export * from './prompt.js';
|
|
64
64
|
export * from './commands/index.js';
|
|
65
65
|
export { MCPServerManager, createMCPServerManager, getServerManager, startMCPServer, stopMCPServer, getMCPServerStatus, type MCPServerOptions, type MCPServerStatus, } from './mcp-server.js';
|
|
66
|
-
export { initializeMemoryDatabase, generateEmbedding, generateBatchEmbeddings, storeEntry, searchEntries, getHNSWIndex, addToHNSWIndex, searchHNSWIndex, getHNSWStatus, clearHNSWIndex, quantizeInt8, dequantizeInt8, quantizedCosineSim, getQuantizationStats, batchCosineSim, softmaxAttention, topKIndices, flashAttentionSearch, type MemoryInitResult, } from './memory/memory-initializer.js';
|
|
66
|
+
export { initializeMemoryDatabase, repairVectorIndexes, recoverMemoryDatabase, generateEmbedding, generateBatchEmbeddings, storeEntry, searchEntries, getHNSWIndex, addToHNSWIndex, searchHNSWIndex, getHNSWStatus, clearHNSWIndex, quantizeInt8, dequantizeInt8, quantizedCosineSim, getQuantizationStats, batchCosineSim, softmaxAttention, topKIndices, flashAttentionSearch, type MemoryInitResult, } from './memory/memory-initializer.js';
|
|
67
67
|
export { initializeIntelligence, recordStep, recordTrajectory, findSimilarPatterns, getIntelligenceStats, getSonaCoordinator, getReasoningBank, clearIntelligence, benchmarkAdaptation, endTrajectoryWithVerdict, distillLearning, getAllPatterns, getPatternsByType, flushPatterns, deletePattern, clearAllPatterns, getNeuralDataDir, getPersistenceStatus, type SonaConfig, type TrajectoryStep, type Pattern, type IntelligenceStats, } from './memory/intelligence.js';
|
|
68
68
|
export { EWCConsolidator, getEWCConsolidator, resetEWCConsolidator, consolidatePatterns, recordPatternOutcome, getEWCStats, type PatternWeights, type EWCConfig, type ConsolidationResult, type EWCStats, } from './memory/ewc-consolidation.js';
|
|
69
69
|
export { SONAOptimizer, getSONAOptimizer, resetSONAOptimizer, processTrajectory, getSuggestion, getSONAStats, type TrajectoryOutcome, type LearnedPattern, type RoutingSuggestion, type SONAStats, } from './memory/sona-optimizer.js';
|
|
@@ -113,6 +113,27 @@ export class CLI {
|
|
|
113
113
|
if (!flags.noUpdate && commandPath[0] !== 'update') {
|
|
114
114
|
this.checkForUpdatesOnStartup().catch(() => { });
|
|
115
115
|
}
|
|
116
|
+
// Version-stamped helper auto-refresh — propagate hook fixes to an already
|
|
117
|
+
// initialized project without a manual re-init. Skip for init/upgrade
|
|
118
|
+
// (they refresh explicitly). AWAITED (not fire-and-forget) so a fast
|
|
119
|
+
// command can't exit before the copy lands; the fast path is a single
|
|
120
|
+
// stamp read + string compare (sub-ms), and the copy runs at most once per
|
|
121
|
+
// version bump. Best-effort + silent — never blocks or fails a command.
|
|
122
|
+
if (commandPath[0] !== 'init' && commandPath[0] !== 'update') {
|
|
123
|
+
try {
|
|
124
|
+
const { autoRefreshHelpersIfStale } = await import('./init/helper-refresh.js');
|
|
125
|
+
const r = await autoRefreshHelpersIfStale(process.cwd());
|
|
126
|
+
if (r.blocked) {
|
|
127
|
+
// Integrity failure = potential on-disk tampering of hook code. Warn
|
|
128
|
+
// loudly (not silent) — the existing project helpers were left intact.
|
|
129
|
+
this.output.printWarning(`Skipped helper auto-refresh — ${r.blocked}. Reinstall @claude-flow/cli from a trusted source.`);
|
|
130
|
+
}
|
|
131
|
+
else if (r.refreshed && this.output.isVerbose()) {
|
|
132
|
+
this.output.printDebug(`Refreshed .claude/helpers (${r.from} → ${r.to})`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
catch { /* silent */ }
|
|
136
|
+
}
|
|
116
137
|
// Handle lazy-loaded commands that weren't recognized by the parser
|
|
117
138
|
// If commandPath is empty but positional has a command name, check if it's lazy-loadable
|
|
118
139
|
if (commandPath.length === 0 && positional.length > 0 && !positional[0].startsWith('-')) {
|
|
@@ -515,7 +536,7 @@ export * from './commands/index.js';
|
|
|
515
536
|
// MCP Server management
|
|
516
537
|
export { MCPServerManager, createMCPServerManager, getServerManager, startMCPServer, stopMCPServer, getMCPServerStatus, } from './mcp-server.js';
|
|
517
538
|
// Memory & Intelligence (V3 Performance Features)
|
|
518
|
-
export { initializeMemoryDatabase, generateEmbedding, generateBatchEmbeddings, storeEntry, searchEntries, getHNSWIndex, addToHNSWIndex, searchHNSWIndex, getHNSWStatus, clearHNSWIndex, quantizeInt8, dequantizeInt8, quantizedCosineSim, getQuantizationStats,
|
|
539
|
+
export { initializeMemoryDatabase, repairVectorIndexes, recoverMemoryDatabase, generateEmbedding, generateBatchEmbeddings, storeEntry, searchEntries, getHNSWIndex, addToHNSWIndex, searchHNSWIndex, getHNSWStatus, clearHNSWIndex, quantizeInt8, dequantizeInt8, quantizedCosineSim, getQuantizationStats,
|
|
519
540
|
// Flash Attention-style batch operations
|
|
520
541
|
batchCosineSim, softmaxAttention, topKIndices, flashAttentionSearch, } from './memory/memory-initializer.js';
|
|
521
542
|
export { initializeIntelligence, recordStep, recordTrajectory, findSimilarPatterns, getIntelligenceStats, getSonaCoordinator, getReasoningBank, clearIntelligence, benchmarkAdaptation,
|