@claude-flow/cli 3.34.0 → 3.35.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/.claude/.proven-config-version +1 -0
- package/.claude/helpers/.helpers-version +1 -1
- package/.claude/helpers/helpers.manifest.json +2 -2
- package/.claude/helpers/statusline.cjs +0 -0
- package/.claude/proven-config.json +42 -0
- package/catalog-manifest.json +2 -2
- package/dist/src/commands/daemon.js +12 -7
- package/dist/src/commands/doctor.js +72 -1
- package/dist/src/commands/metaharness.js +37 -2
- package/dist/src/commands/neural.js +1 -1
- package/dist/src/log-filters.d.ts +3 -3
- package/dist/src/mcp-tools/metaharness-tools.js +35 -2
- package/dist/src/memory/memory-bridge.d.ts +25 -0
- package/dist/src/memory/memory-bridge.js +61 -8
- package/dist/src/memory/memory-initializer.d.ts +9 -3
- package/dist/src/memory/memory-initializer.js +344 -277
- package/dist/src/services/daemon-autostart.d.ts +31 -3
- package/dist/src/services/daemon-autostart.js +45 -3
- package/dist/src/services/distill-oracle.d.ts +1 -1
- package/dist/src/services/distill-oracle.js +2 -2
- package/dist/src/services/evolve-proof.d.ts +40 -1
- package/dist/src/services/evolve-proof.js +76 -14
- package/dist/src/services/flywheel-receipt.d.ts +15 -0
- package/dist/src/services/flywheel-receipt.js +22 -0
- package/dist/src/services/flywheel-sequential-evidence.d.ts +102 -0
- package/dist/src/services/flywheel-sequential-evidence.js +148 -0
- package/dist/src/services/flywheel-transaction.d.ts +71 -0
- package/dist/src/services/flywheel-transaction.js +121 -0
- package/dist/src/services/harness-flywheel-generations.d.ts +14 -0
- package/dist/src/services/harness-flywheel-generations.js +76 -4
- package/dist/src/services/harness-flywheel.d.ts +13 -0
- package/dist/src/services/harness-flywheel.js +31 -1
- 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 +6 -10
- package/plugins/ruflo-metaharness/scripts/smoke.sh +4 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
sha256:6141a8ea990c5063b77e090ae8f37f9c539d8aa8f58dcceb30f3a82f97e57319
|
|
@@ -1 +1 @@
|
|
|
1
|
-
3.
|
|
1
|
+
3.33.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"manifest": {
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.35.1",
|
|
4
4
|
"files": {
|
|
5
5
|
"auto-memory-hook.mjs": "68be7e9a9eba7bf9c4e8a230db7bf61a243b965639f8504842799d6c6ca28762",
|
|
6
6
|
"hook-handler.cjs": "dae295fb9ae2626b89899c19a20cc911541af82b52d2eeb9b214d618b96e9a86",
|
|
@@ -8,6 +8,6 @@
|
|
|
8
8
|
"statusline.cjs": "0457fe53f8cd2c56458ff178392536a5868efd1a573665fa43bc01d2d95ca677"
|
|
9
9
|
}
|
|
10
10
|
},
|
|
11
|
-
"signature": "
|
|
11
|
+
"signature": "bjvJQiP4EazGeoyS7D/vq+6pXbceHVukE7u0SGme06aFRtrPVjc9pi/PFxZ5Zl9x+o4ECex6lyXtONvBVklzDA==",
|
|
12
12
|
"algorithm": "ed25519"
|
|
13
13
|
}
|
|
File without changes
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"adoptedAt": 1785208363552,
|
|
3
|
+
"championId": "sha256:6141a8ea990c5063b77e090ae8f37f9c539d8aa8f58dcceb30f3a82f97e57319",
|
|
4
|
+
"manifest": {
|
|
5
|
+
"schema": "ruflo.proven-config/v1",
|
|
6
|
+
"policy": {
|
|
7
|
+
"ref": "sha256:6141a8ea990c5063b77e090ae8f37f9c539d8aa8f58dcceb30f3a82f97e57319",
|
|
8
|
+
"value": {
|
|
9
|
+
"alpha": 0.3,
|
|
10
|
+
"subjectWeight": 1,
|
|
11
|
+
"mmrLambda": 0.5,
|
|
12
|
+
"bodyWeight": 1.5,
|
|
13
|
+
"typePenaltyFactor": 0.5
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"layer": "framework/node-cli",
|
|
17
|
+
"compatibility": {
|
|
18
|
+
"ruflo": ">=3.24.0"
|
|
19
|
+
},
|
|
20
|
+
"benchmark": {
|
|
21
|
+
"corpus": "ADR-081-labelled-v1",
|
|
22
|
+
"corpusHash": "sha256:2f700b5c363e20a3bd88ce2bc9b87bbbbaa61732c6177894c6ec37890f888982"
|
|
23
|
+
},
|
|
24
|
+
"receipt": {
|
|
25
|
+
"heldOutDelta": 0.07381404928570845,
|
|
26
|
+
"redblue": "PASS",
|
|
27
|
+
"drift": 0,
|
|
28
|
+
"canary": {
|
|
29
|
+
"rollbackRate": 0,
|
|
30
|
+
"latencyP95": 244.612458000076,
|
|
31
|
+
"costPerTask": 0
|
|
32
|
+
},
|
|
33
|
+
"receiptCoverage": 1
|
|
34
|
+
},
|
|
35
|
+
"platform": [
|
|
36
|
+
"linux",
|
|
37
|
+
"macOS",
|
|
38
|
+
"windows"
|
|
39
|
+
]
|
|
40
|
+
},
|
|
41
|
+
"previous": ""
|
|
42
|
+
}
|
package/catalog-manifest.json
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { output } from '../output.js';
|
|
6
6
|
import { getDaemon, startDaemon, stopDaemon } from '../services/worker-daemon.js';
|
|
7
|
+
import { resolveDaemonProjectRoot } from '../services/daemon-autostart.js';
|
|
7
8
|
import { fork } from 'child_process';
|
|
8
9
|
import { fileURLToPath } from 'url';
|
|
9
10
|
import { dirname, join, resolve } from 'path';
|
|
@@ -61,7 +62,11 @@ const startCommand = {
|
|
|
61
62
|
}
|
|
62
63
|
// #1914: a forked daemon child receives --workspace <root>; the launcher
|
|
63
64
|
// and interactive invocations have no flag and fall back to cwd.
|
|
64
|
-
|
|
65
|
+
// #2877: that cwd fallback is normalized to the owning project root, so
|
|
66
|
+
// `daemon start` from a subdirectory contends for the SAME lock/PID file
|
|
67
|
+
// as one from the root instead of silently keying its own pair.
|
|
68
|
+
const projectRoot = resolveWorkspaceFlag(ctx.flags.workspace)
|
|
69
|
+
?? resolveDaemonProjectRoot(process.cwd());
|
|
65
70
|
const isDaemonProcess = process.env.CLAUDE_FLOW_DAEMON === '1';
|
|
66
71
|
// Parse resource threshold overrides from CLI flags
|
|
67
72
|
const config = {};
|
|
@@ -605,7 +610,7 @@ const stopCommand = {
|
|
|
605
610
|
],
|
|
606
611
|
action: async (ctx) => {
|
|
607
612
|
const quiet = ctx.flags.quiet;
|
|
608
|
-
const projectRoot = process.cwd();
|
|
613
|
+
const projectRoot = resolveDaemonProjectRoot(process.cwd());
|
|
609
614
|
// #2661: `stop --all` — the containment lever for daemon fanout across
|
|
610
615
|
// Git worktrees. Only processes positively identified as ruflo daemons
|
|
611
616
|
// (via their self-identifying argv) are touched; each receives SIGTERM
|
|
@@ -657,7 +662,7 @@ async function stopAllDaemons(quiet) {
|
|
|
657
662
|
await stopDaemon();
|
|
658
663
|
}
|
|
659
664
|
catch { /* not running in-process */ }
|
|
660
|
-
await killBackgroundDaemon(process.cwd());
|
|
665
|
+
await killBackgroundDaemon(resolveDaemonProjectRoot(process.cwd()));
|
|
661
666
|
const daemons = await scanRunningDaemons();
|
|
662
667
|
if (daemons.length === 0) {
|
|
663
668
|
if (!quiet) {
|
|
@@ -1160,7 +1165,7 @@ const statusCommand = {
|
|
|
1160
1165
|
if (ctx.flags.all) {
|
|
1161
1166
|
return renderAllDaemonsStatus();
|
|
1162
1167
|
}
|
|
1163
|
-
const projectRoot = process.cwd();
|
|
1168
|
+
const projectRoot = resolveDaemonProjectRoot(process.cwd());
|
|
1164
1169
|
try {
|
|
1165
1170
|
const daemon = getDaemon(projectRoot);
|
|
1166
1171
|
const status = daemon.getStatus();
|
|
@@ -1304,7 +1309,7 @@ const triggerCommand = {
|
|
|
1304
1309
|
// #2661: an explicit `trigger --headless` is user consent for AI
|
|
1305
1310
|
// execution of THIS run (still governed by the global AI budget).
|
|
1306
1311
|
// Without the flag, config.json / env opt-in still applies.
|
|
1307
|
-
const daemon = getDaemon(process.cwd(), ctx.flags.headless === true ? { aiWorkersEnabled: true } : undefined);
|
|
1312
|
+
const daemon = getDaemon(resolveDaemonProjectRoot(process.cwd()), ctx.flags.headless === true ? { aiWorkersEnabled: true } : undefined);
|
|
1308
1313
|
const spinner = output.createSpinner({ text: `Running ${workerType} worker...`, spinner: 'dots' });
|
|
1309
1314
|
spinner.start();
|
|
1310
1315
|
const result = await daemon.triggerWorker(workerType);
|
|
@@ -1347,7 +1352,7 @@ const enableCommand = {
|
|
|
1347
1352
|
return { success: false, exitCode: 1 };
|
|
1348
1353
|
}
|
|
1349
1354
|
try {
|
|
1350
|
-
const daemon = getDaemon(process.cwd());
|
|
1355
|
+
const daemon = getDaemon(resolveDaemonProjectRoot(process.cwd()));
|
|
1351
1356
|
daemon.setWorkerEnabled(workerType, !disable);
|
|
1352
1357
|
output.printSuccess(`Worker ${workerType} ${disable ? 'disabled' : 'enabled'}`);
|
|
1353
1358
|
return { success: true };
|
|
@@ -1402,7 +1407,7 @@ const installSupervisorCommand = {
|
|
|
1402
1407
|
const force = ctx.flags.force === true;
|
|
1403
1408
|
const load = ctx.flags.load !== false;
|
|
1404
1409
|
const dryRun = ctx.flags['dry-run'] === true || ctx.flags.dryRun === true;
|
|
1405
|
-
const projectRoot = process.cwd();
|
|
1410
|
+
const projectRoot = resolveDaemonProjectRoot(process.cwd());
|
|
1406
1411
|
const platform = process.platform;
|
|
1407
1412
|
if (platform === 'win32') {
|
|
1408
1413
|
output.printError('Windows scheduled-task installer is not yet implemented.');
|
|
@@ -1766,6 +1766,76 @@ async function checkMetaharnessIntegration() {
|
|
|
1766
1766
|
};
|
|
1767
1767
|
}
|
|
1768
1768
|
}
|
|
1769
|
+
/**
|
|
1770
|
+
* Dependency-contract check: every `@metaharness/*` package this CLI DECLARES
|
|
1771
|
+
* in its own optionalDependencies must actually resolve at runtime. Declared
|
|
1772
|
+
* packages are advertised integration surfaces (`ruflo metaharness evolve`,
|
|
1773
|
+
* flywheel receipt interop, radio coordination) — a declared-but-absent
|
|
1774
|
+
* package means the install dropped an optional dep (or the declaration
|
|
1775
|
+
* regressed to peer-only), so the advertised integration silently degrades.
|
|
1776
|
+
* That is a FAIL, not a warn: warn is reserved for surfaces that were never
|
|
1777
|
+
* advertised as installed (the `npx metaharness` umbrella path above).
|
|
1778
|
+
*/
|
|
1779
|
+
async function checkMetaharnessDeclaredPackages() {
|
|
1780
|
+
const NAME = 'MetaHarness declared packages (ADR-150)';
|
|
1781
|
+
try {
|
|
1782
|
+
// Walk up from this module to the CLI package root (works for npx cache,
|
|
1783
|
+
// global install, project-local install, and monorepo dev alike).
|
|
1784
|
+
let root = null;
|
|
1785
|
+
let q = dirname(fileURLToPath(import.meta.url));
|
|
1786
|
+
for (let i = 0; i < 8; i++) {
|
|
1787
|
+
const pj = join(q, 'package.json');
|
|
1788
|
+
if (existsSync(pj)) {
|
|
1789
|
+
try {
|
|
1790
|
+
if (JSON.parse(readFileSync(pj, 'utf-8')).name === '@claude-flow/cli') {
|
|
1791
|
+
root = q;
|
|
1792
|
+
break;
|
|
1793
|
+
}
|
|
1794
|
+
}
|
|
1795
|
+
catch { /* keep walking */ }
|
|
1796
|
+
}
|
|
1797
|
+
q = dirname(q);
|
|
1798
|
+
}
|
|
1799
|
+
if (!root)
|
|
1800
|
+
return { name: NAME, status: 'warn', message: 'could not locate the @claude-flow/cli package root' };
|
|
1801
|
+
const pkg = JSON.parse(readFileSync(join(root, 'package.json'), 'utf-8'));
|
|
1802
|
+
const declared = Object.keys(pkg.optionalDependencies ?? {}).filter((n) => n === 'metaharness' || n.startsWith('@metaharness/'));
|
|
1803
|
+
if (declared.length === 0) {
|
|
1804
|
+
return {
|
|
1805
|
+
name: NAME,
|
|
1806
|
+
status: 'fail',
|
|
1807
|
+
message: 'no @metaharness/* packages declared in optionalDependencies — the dependency contract regressed (peer-only declarations are never installed)',
|
|
1808
|
+
fix: 'Restore @metaharness/darwin, @metaharness/flywheel, @metaharness/radio, @metaharness/turn-credit to optionalDependencies in @claude-flow/cli',
|
|
1809
|
+
};
|
|
1810
|
+
}
|
|
1811
|
+
// Node resolution: nearest node_modules wins, walking upward from the CLI root.
|
|
1812
|
+
const resolves = (name) => {
|
|
1813
|
+
let d = root;
|
|
1814
|
+
for (let i = 0; i < 10; i++) {
|
|
1815
|
+
if (existsSync(join(d, 'node_modules', name, 'package.json')))
|
|
1816
|
+
return true;
|
|
1817
|
+
const parent = dirname(d);
|
|
1818
|
+
if (parent === d)
|
|
1819
|
+
break;
|
|
1820
|
+
d = parent;
|
|
1821
|
+
}
|
|
1822
|
+
return false;
|
|
1823
|
+
};
|
|
1824
|
+
const missing = declared.filter((n) => !resolves(n));
|
|
1825
|
+
if (missing.length > 0) {
|
|
1826
|
+
return {
|
|
1827
|
+
name: NAME,
|
|
1828
|
+
status: 'fail',
|
|
1829
|
+
message: `declared but not installed: ${missing.join(', ')} — advertised MetaHarness surfaces are degraded`,
|
|
1830
|
+
fix: 'npm install --include=optional # optional deps were skipped or pruned',
|
|
1831
|
+
};
|
|
1832
|
+
}
|
|
1833
|
+
return { name: NAME, status: 'pass', message: `${declared.length} declared package(s) resolve: ${declared.join(', ')}` };
|
|
1834
|
+
}
|
|
1835
|
+
catch (err) {
|
|
1836
|
+
return { name: NAME, status: 'warn', message: `check failed: ${err instanceof Error ? err.message : String(err)}` };
|
|
1837
|
+
}
|
|
1838
|
+
}
|
|
1769
1839
|
async function checkMetaharness() {
|
|
1770
1840
|
try {
|
|
1771
1841
|
const version = await runCommand('npx -y metaharness@latest --version 2>&1', 15000);
|
|
@@ -2116,6 +2186,7 @@ export const doctorCommand = {
|
|
|
2116
2186
|
checkEncryptionAtRest, // ADR-096 Phase 5
|
|
2117
2187
|
checkFederationBreaker, // ADR-097 Phase 4
|
|
2118
2188
|
checkMetaharness, // ADR-150 — MetaHarness upstream package
|
|
2189
|
+
checkMetaharnessDeclaredPackages, // dependency contract — declared optional deps must resolve
|
|
2119
2190
|
checkMetaharnessIntegration, // iter 45 — ruflo-side integration layer
|
|
2120
2191
|
checkFunnel, // ADR-305 — effective funnel state + deciding precedence source
|
|
2121
2192
|
checkProxySponsoredConsent, // ADR-313 — Meta LLM Proxy sponsored-downtime health
|
|
@@ -2158,7 +2229,7 @@ export const doctorCommand = {
|
|
|
2158
2229
|
'agentic-flow': checkAgenticFlow,
|
|
2159
2230
|
'encryption': checkEncryptionAtRest, // ADR-096 Phase 5
|
|
2160
2231
|
'federation': checkFederationBreaker, // ADR-097 Phase 4
|
|
2161
|
-
'metaharness': checkMetaharness, // ADR-150 — upstream
|
|
2232
|
+
'metaharness': [checkMetaharness, checkMetaharnessDeclaredPackages, checkMetaharnessIntegration], // ADR-150 — upstream + declared deps + ruflo-side
|
|
2162
2233
|
'metaharness-integration': checkMetaharnessIntegration, // iter 45 — ruflo-side
|
|
2163
2234
|
'funnel': checkFunnel, // ADR-305
|
|
2164
2235
|
// ADR-307 — deep-dive array, same pattern as 'memory' above: the cheap
|
|
@@ -39,7 +39,7 @@ import { existsSync, readFileSync } from 'fs';
|
|
|
39
39
|
import { join, dirname, resolve } from 'path';
|
|
40
40
|
import { fileURLToPath } from 'url';
|
|
41
41
|
import { runFlywheelWorker } from '../services/harness-flywheel-runtime.js';
|
|
42
|
-
import { listFlywheelReceipts, promoteFlywheelCandidate, readFlywheelTransactionState, verifyFlywheelLedger, } from '../services/flywheel-transaction.js';
|
|
42
|
+
import { listFlywheelReceipts, promoteFlywheelCandidate, readFlywheelTransactionState, resetSequentialEvidence, verifyFlywheelLedger, } from '../services/flywheel-transaction.js';
|
|
43
43
|
import { evaluatePolicyRequest } from '../services/policy-runtime.js';
|
|
44
44
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
45
45
|
// Subcommand → plugin script filename
|
|
@@ -124,6 +124,37 @@ async function dispatchFlywheel(operation, positional, flags) {
|
|
|
124
124
|
const state = readFlywheelTransactionState(projectRoot);
|
|
125
125
|
data = { ledgerHead: state.ledgerHead, commits: state.commits };
|
|
126
126
|
}
|
|
127
|
+
else if (operation === 'evidence-reset') {
|
|
128
|
+
// ADR-381 §2 — start a new evidence epoch. Same policy gate as promote:
|
|
129
|
+
// this reopens the family-wise alpha budget, so it is a governance action.
|
|
130
|
+
const reason = String(flywheelFlag(flags, 'reason', '')).trim();
|
|
131
|
+
if (!reason) {
|
|
132
|
+
data = { success: false, reason: 'evidence-reset requires --reason "<why>" — the reset audit trail records intent' };
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
const policy = await evaluatePolicyRequest({
|
|
136
|
+
identity: { id: process.env.CLAUDE_FLOW_PRINCIPAL_ID ?? 'metaharness-local', type: 'agent', roles: ['optimizer'] },
|
|
137
|
+
action: {
|
|
138
|
+
type: 'metaharness.evidence.reset',
|
|
139
|
+
resource: projectRoot,
|
|
140
|
+
environment: 'production',
|
|
141
|
+
destructive: true,
|
|
142
|
+
},
|
|
143
|
+
context: {
|
|
144
|
+
approvalIds: String(flywheelFlag(flags, 'approvalId', '')).split(',').filter(Boolean),
|
|
145
|
+
},
|
|
146
|
+
}, projectRoot);
|
|
147
|
+
if (policy.enforcedOutcome !== 'allowed') {
|
|
148
|
+
data = { success: false, reason: `policy-${policy.enforcedOutcome}:${policy.reason}`, policyReceiptId: policy.receiptId };
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
data = await resetSequentialEvidence(projectRoot, {
|
|
152
|
+
confirm: flywheelFlag(flags, 'confirm', false) === true,
|
|
153
|
+
reason,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
127
158
|
else if (operation === 'promote') {
|
|
128
159
|
const receiptId = positional[0];
|
|
129
160
|
const publicKeyPath = flywheelFlag(flags, 'publicKey');
|
|
@@ -151,6 +182,10 @@ async function dispatchFlywheel(operation, positional, flags) {
|
|
|
151
182
|
data = await promoteFlywheelCandidate(projectRoot, receiptId, {
|
|
152
183
|
confirm: flywheelFlag(flags, 'confirm', false) === true,
|
|
153
184
|
trustedPublicKeys: new Set([publicKey]),
|
|
185
|
+
// --allow-aggregate-evidence: explicit migration escape hatch for
|
|
186
|
+
// pre-upgrade receipts without task-level pairedOutcomes. Default
|
|
187
|
+
// is strict — aggregate-only evidence is refused.
|
|
188
|
+
requirePairedEvidence: flywheelFlag(flags, 'allowAggregateEvidence', false) !== true,
|
|
154
189
|
});
|
|
155
190
|
}
|
|
156
191
|
}
|
|
@@ -288,7 +323,7 @@ export const metaharnessCommand = {
|
|
|
288
323
|
output.writeln(' redblue adversarial red/blue LLM testing (init|run|patch|attack|report)');
|
|
289
324
|
output.writeln(' evolve Darwin candidate evolution');
|
|
290
325
|
output.writeln(' bench create or verify a stable benchmark suite');
|
|
291
|
-
output.writeln(' flywheel receipt loop: run | status | receipts | history | promote');
|
|
326
|
+
output.writeln(' flywheel receipt loop: run | status | receipts | history | promote | evidence-reset');
|
|
292
327
|
output.writeln('');
|
|
293
328
|
output.writeln('Each subcommand accepts --format json|table and --help.');
|
|
294
329
|
output.writeln('');
|
|
@@ -1715,7 +1715,7 @@ const routerTrainCommand = {
|
|
|
1715
1715
|
mh = await import(metaharnessRouterPkg);
|
|
1716
1716
|
}
|
|
1717
1717
|
catch {
|
|
1718
|
-
output.printError('@metaharness/router is not installed. `npm install @metaharness/router@^0.
|
|
1718
|
+
output.printError('@metaharness/router is not installed. `npm install @metaharness/router@^0.4.0` then re-run.');
|
|
1719
1719
|
return { success: false, exitCode: 1 };
|
|
1720
1720
|
}
|
|
1721
1721
|
const { neuralRouterStatus } = await import('../ruvector/neural-router.js');
|
|
@@ -40,7 +40,7 @@ declare const STDERR_REDIRECT_PREFIXES: string[];
|
|
|
40
40
|
declare const AGENTDB_MOCK_FALLBACK_DROP_PREFIXES: string[];
|
|
41
41
|
declare const shouldRedirectToStderr: (msg: unknown) => boolean;
|
|
42
42
|
declare const isAgentdbMockFallbackNoise: (msg: unknown) => boolean;
|
|
43
|
-
declare const origWarn: (
|
|
44
|
-
declare const origLog: (
|
|
45
|
-
declare const origError: (
|
|
43
|
+
declare const origWarn: (...data: any[]) => void;
|
|
44
|
+
declare const origLog: (...data: any[]) => void;
|
|
45
|
+
declare const origError: (...data: any[]) => void;
|
|
46
46
|
//# sourceMappingURL=log-filters.d.ts.map
|
|
@@ -53,7 +53,7 @@ import { join, dirname, resolve } from 'node:path';
|
|
|
53
53
|
import { fileURLToPath } from 'node:url';
|
|
54
54
|
import { runFlywheelWorker } from '../services/harness-flywheel-runtime.js';
|
|
55
55
|
import { evaluatePolicyRequest } from '../services/policy-runtime.js';
|
|
56
|
-
import { listFlywheelReceipts, promoteFlywheelCandidate, readFlywheelTransactionState, verifyFlywheelLedger, } from '../services/flywheel-transaction.js';
|
|
56
|
+
import { listFlywheelReceipts, promoteFlywheelCandidate, readFlywheelTransactionState, resetSequentialEvidence, verifyFlywheelLedger, } from '../services/flywheel-transaction.js';
|
|
57
57
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
58
58
|
/**
|
|
59
59
|
* Walk up from this module to find plugins/ruflo-metaharness/scripts/.
|
|
@@ -690,7 +690,7 @@ export const metaharnessTools = [
|
|
|
690
690
|
inputSchema: {
|
|
691
691
|
type: 'object',
|
|
692
692
|
properties: {
|
|
693
|
-
operation: { type: 'string', enum: ['run', 'status', 'receipts', 'history', 'promote'], description: 'Flywheel operation', default: 'status' },
|
|
693
|
+
operation: { type: 'string', enum: ['run', 'status', 'receipts', 'history', 'promote', 'evidence-reset'], description: 'Flywheel operation', default: 'status' },
|
|
694
694
|
projectRoot: { type: 'string', description: 'Target project root (default: active project cwd)' },
|
|
695
695
|
receiptId: { type: 'string', description: 'Receipt content ID for promote' },
|
|
696
696
|
sample: { type: 'number', description: 'Maximum harvested evaluation sample', default: 40 },
|
|
@@ -704,6 +704,8 @@ export const metaharnessTools = [
|
|
|
704
704
|
anchorHash: { type: 'string', description: 'Pinned sha256 of canonical anchor tasks; requires anchorPath' },
|
|
705
705
|
anchorManifestPath: { type: 'string', description: 'Project-contained anchor manifest path (default .claude/eval/flywheel-anchor.manifest.json)' },
|
|
706
706
|
approvalIds: { type: 'array', items: { type: 'string' }, description: 'Scoped ADR-324 approval IDs for privileged promotion' },
|
|
707
|
+
allowAggregateEvidence: { type: 'boolean', description: 'Migration escape hatch: accept a pre-upgrade receipt without task-level pairedOutcomes. Default false — aggregate-only evidence is refused by the strict sequential-evidence gate.', default: false },
|
|
708
|
+
reason: { type: 'string', description: 'Required for evidence-reset (ADR-381): the human intent recorded in the append-only reset audit trail.' },
|
|
707
709
|
},
|
|
708
710
|
required: ['operation'],
|
|
709
711
|
},
|
|
@@ -758,6 +760,36 @@ export const metaharnessTools = [
|
|
|
758
760
|
});
|
|
759
761
|
return { success: data.ran, data, degraded: false, exitCode: data.ran ? 0 : 1 };
|
|
760
762
|
}
|
|
763
|
+
if (operation === 'evidence-reset') {
|
|
764
|
+
// ADR-381 §2 — reopens the family-wise alpha budget; same policy
|
|
765
|
+
// gate as promote, plus a mandatory recorded reason.
|
|
766
|
+
const reason = String(input.reason ?? '').trim();
|
|
767
|
+
if (!reason) {
|
|
768
|
+
return { success: false, data: { reason: 'evidence-reset requires a non-empty reason — the reset audit trail records intent' }, degraded: false, exitCode: 2 };
|
|
769
|
+
}
|
|
770
|
+
const policy = await evaluatePolicyRequest({
|
|
771
|
+
identity: { id: 'metaharness-mcp', type: 'agent', roles: ['optimizer'] },
|
|
772
|
+
action: {
|
|
773
|
+
type: 'metaharness.evidence.reset',
|
|
774
|
+
resource: projectRoot,
|
|
775
|
+
environment: 'production',
|
|
776
|
+
destructive: true,
|
|
777
|
+
},
|
|
778
|
+
context: {
|
|
779
|
+
approvalIds: Array.isArray(input.approvalIds) ? input.approvalIds.map(String) : undefined,
|
|
780
|
+
},
|
|
781
|
+
}, projectRoot);
|
|
782
|
+
if (policy.enforcedOutcome !== 'allowed') {
|
|
783
|
+
return {
|
|
784
|
+
success: false,
|
|
785
|
+
data: { reason: `policy-${policy.enforcedOutcome}:${policy.reason}`, policyReceiptId: policy.receiptId },
|
|
786
|
+
degraded: false,
|
|
787
|
+
exitCode: 1,
|
|
788
|
+
};
|
|
789
|
+
}
|
|
790
|
+
const data = await resetSequentialEvidence(projectRoot, { confirm: input.confirm === true, reason });
|
|
791
|
+
return { success: data.success, data, degraded: false, exitCode: data.success ? 0 : 1 };
|
|
792
|
+
}
|
|
761
793
|
if (operation === 'promote') {
|
|
762
794
|
if (!input.receiptId || !input.publicKeyPath) {
|
|
763
795
|
return { success: false, data: { reason: 'receiptId and publicKeyPath are required' }, degraded: false, exitCode: 2 };
|
|
@@ -786,6 +818,7 @@ export const metaharnessTools = [
|
|
|
786
818
|
const data = await promoteFlywheelCandidate(projectRoot, String(input.receiptId), {
|
|
787
819
|
confirm: input.confirm === true,
|
|
788
820
|
trustedPublicKeys: new Set([publicKey]),
|
|
821
|
+
requirePairedEvidence: input.allowAggregateEvidence !== true,
|
|
789
822
|
});
|
|
790
823
|
return { success: data.success, data, degraded: false, exitCode: data.success ? 0 : 1 };
|
|
791
824
|
}
|
|
@@ -487,6 +487,14 @@ export declare function bridgeHealthCheck(dbPath?: string): Promise<{
|
|
|
487
487
|
hits: number;
|
|
488
488
|
misses: number;
|
|
489
489
|
};
|
|
490
|
+
hierarchicalMemory?: {
|
|
491
|
+
controller: string;
|
|
492
|
+
durable: boolean;
|
|
493
|
+
persistence: string;
|
|
494
|
+
/** Real row count in the backing table — null when nothing is on disk. */
|
|
495
|
+
persistedRows: number | null;
|
|
496
|
+
fallbackFrom?: string;
|
|
497
|
+
};
|
|
490
498
|
} | null>;
|
|
491
499
|
/**
|
|
492
500
|
* Store to hierarchical memory with tier.
|
|
@@ -506,6 +514,23 @@ export declare function bridgeHealthCheck(dbPath?: string): Promise<{
|
|
|
506
514
|
* temporal fields are stored in metadata, and supersede is reported as
|
|
507
515
|
* unsupported (no public update API) rather than silently dropped.
|
|
508
516
|
*/
|
|
517
|
+
/**
|
|
518
|
+
* Describe which store `agentdb_hierarchical-*` actually landed on and
|
|
519
|
+
* whether its writes survive the process (#2887).
|
|
520
|
+
*
|
|
521
|
+
* agentdb removed its `HierarchicalMemory` export at 3.0.0-alpha.17, so the
|
|
522
|
+
* @claude-flow/memory TieredMemoryStore fallback is the live path. It is only
|
|
523
|
+
* durable when it was handed a SQLite connection — callers must not report a
|
|
524
|
+
* volatile write as a success.
|
|
525
|
+
*/
|
|
526
|
+
export declare function describeHierarchicalStore(hm: any, fallback: {
|
|
527
|
+
reason: string;
|
|
528
|
+
} | null): {
|
|
529
|
+
controller: string;
|
|
530
|
+
fallbackFrom?: string;
|
|
531
|
+
durable: boolean;
|
|
532
|
+
persistence: string;
|
|
533
|
+
};
|
|
509
534
|
export declare function bridgeHierarchicalStore(params: {
|
|
510
535
|
key: string;
|
|
511
536
|
value: string;
|
|
@@ -2392,7 +2392,18 @@ export async function bridgeHealthCheck(dbPath) {
|
|
|
2392
2392
|
const s = cache.stats();
|
|
2393
2393
|
cacheStats = { size: s.size ?? 0, hits: s.hits ?? 0, misses: s.misses ?? 0 };
|
|
2394
2394
|
}
|
|
2395
|
-
|
|
2395
|
+
// #2887: cacheStats alone let a "successful" hierarchical-store coexist
|
|
2396
|
+
// with an empty store. Report the backing table's real row count so the
|
|
2397
|
+
// inconsistency is visible instead of inferred.
|
|
2398
|
+
let hierarchicalMemory;
|
|
2399
|
+
const hm = registry.get('hierarchicalMemory');
|
|
2400
|
+
if (hm) {
|
|
2401
|
+
hierarchicalMemory = {
|
|
2402
|
+
...describeHierarchicalStore(hm, getHierarchicalFallback(registry)),
|
|
2403
|
+
persistedRows: typeof hm.countPersisted === 'function' ? hm.countPersisted() : null,
|
|
2404
|
+
};
|
|
2405
|
+
}
|
|
2406
|
+
return { available: true, controllers, attestationCount, cacheStats, hierarchicalMemory };
|
|
2396
2407
|
}
|
|
2397
2408
|
catch {
|
|
2398
2409
|
return null;
|
|
@@ -2417,6 +2428,34 @@ export async function bridgeHealthCheck(dbPath) {
|
|
|
2417
2428
|
* temporal fields are stored in metadata, and supersede is reported as
|
|
2418
2429
|
* unsupported (no public update API) rather than silently dropped.
|
|
2419
2430
|
*/
|
|
2431
|
+
/**
|
|
2432
|
+
* Describe which store `agentdb_hierarchical-*` actually landed on and
|
|
2433
|
+
* whether its writes survive the process (#2887).
|
|
2434
|
+
*
|
|
2435
|
+
* agentdb removed its `HierarchicalMemory` export at 3.0.0-alpha.17, so the
|
|
2436
|
+
* @claude-flow/memory TieredMemoryStore fallback is the live path. It is only
|
|
2437
|
+
* durable when it was handed a SQLite connection — callers must not report a
|
|
2438
|
+
* volatile write as a success.
|
|
2439
|
+
*/
|
|
2440
|
+
export function describeHierarchicalStore(hm, fallback) {
|
|
2441
|
+
// Only the tiered fallback exposes isDurable(); the native controller
|
|
2442
|
+
// (should agentdb reintroduce it) writes to agentdb's own tables.
|
|
2443
|
+
if (typeof hm?.isDurable !== 'function') {
|
|
2444
|
+
return { controller: 'hierarchicalMemory', durable: true, persistence: 'agentdb' };
|
|
2445
|
+
}
|
|
2446
|
+
return {
|
|
2447
|
+
controller: 'tieredMemoryStore',
|
|
2448
|
+
fallbackFrom: fallback?.reason ?? 'hierarchicalMemory',
|
|
2449
|
+
durable: hm.isDurable() === true,
|
|
2450
|
+
persistence: typeof hm.getPersistence === 'function' ? hm.getPersistence() : 'unknown',
|
|
2451
|
+
};
|
|
2452
|
+
}
|
|
2453
|
+
/** Read `getHierarchicalFallback()` off a registry that may predate it. */
|
|
2454
|
+
function getHierarchicalFallback(registry) {
|
|
2455
|
+
return typeof registry?.getHierarchicalFallback === 'function'
|
|
2456
|
+
? registry.getHierarchicalFallback()
|
|
2457
|
+
: null;
|
|
2458
|
+
}
|
|
2420
2459
|
export async function bridgeHierarchicalStore(params) {
|
|
2421
2460
|
const registry = await getRegistry();
|
|
2422
2461
|
if (!registry)
|
|
@@ -2439,7 +2478,10 @@ export async function bridgeHierarchicalStore(params) {
|
|
|
2439
2478
|
metadata,
|
|
2440
2479
|
tags: [params.key],
|
|
2441
2480
|
});
|
|
2442
|
-
const result = {
|
|
2481
|
+
const result = {
|
|
2482
|
+
success: true, id, key: params.key, tier,
|
|
2483
|
+
controller: 'hierarchicalMemory', durable: true, persistence: 'agentdb',
|
|
2484
|
+
};
|
|
2443
2485
|
if (params.supersedes) {
|
|
2444
2486
|
// No public update/invalidate API on agentdb HierarchicalMemory —
|
|
2445
2487
|
// surface the limitation honestly instead of silently dropping it.
|
|
@@ -2448,17 +2490,28 @@ export async function bridgeHierarchicalStore(params) {
|
|
|
2448
2490
|
}
|
|
2449
2491
|
return result;
|
|
2450
2492
|
}
|
|
2451
|
-
// TieredMemoryStore fallback (temporal-aware) / legacy stub
|
|
2493
|
+
// TieredMemoryStore fallback (temporal-aware) / legacy stub.
|
|
2494
|
+
// agentdb dropped its HierarchicalMemory export at 3.0.0-alpha.17, so
|
|
2495
|
+
// this is the live path — and it is only trustworthy when the store is
|
|
2496
|
+
// backed by SQLite. A volatile write must NOT report success (#2887).
|
|
2452
2497
|
const storeResult = hm.store(params.key, params.value, tier, {
|
|
2453
2498
|
validFrom: params.validFrom,
|
|
2454
2499
|
validUntil: params.validUntil,
|
|
2455
2500
|
supersedes: params.supersedes,
|
|
2456
2501
|
});
|
|
2457
|
-
|
|
2458
|
-
|
|
2502
|
+
const info = describeHierarchicalStore(hm, getHierarchicalFallback(registry));
|
|
2503
|
+
const base = {
|
|
2504
|
+
...info,
|
|
2505
|
+
...(storeResult && typeof storeResult === 'object' ? storeResult : { key: params.key, tier }),
|
|
2506
|
+
};
|
|
2507
|
+
if (!info.durable) {
|
|
2508
|
+
return {
|
|
2509
|
+
...base,
|
|
2510
|
+
success: false,
|
|
2511
|
+
error: `hierarchical-store is running on the ${info.persistence} tiered fallback (${info.fallbackFrom}); the entry is NOT persisted to disk and will be lost when this process exits. Use memory_store for durable key-value persistence.`,
|
|
2512
|
+
};
|
|
2459
2513
|
}
|
|
2460
|
-
|
|
2461
|
-
return { success: true, key: params.key, tier };
|
|
2514
|
+
return { success: true, ...base };
|
|
2462
2515
|
}
|
|
2463
2516
|
catch (e) {
|
|
2464
2517
|
return { success: false, error: e.message };
|
|
@@ -2523,7 +2576,7 @@ export async function bridgeHierarchicalRecall(params) {
|
|
|
2523
2576
|
const filtered = params.tier
|
|
2524
2577
|
? results.filter((r) => r.tier === params.tier)
|
|
2525
2578
|
: results;
|
|
2526
|
-
return { results: filtered,
|
|
2579
|
+
return { results: filtered, ...describeHierarchicalStore(hm, getHierarchicalFallback(registry)) };
|
|
2527
2580
|
}
|
|
2528
2581
|
catch (e) {
|
|
2529
2582
|
return { results: [], error: e.message };
|
|
@@ -547,9 +547,15 @@ export declare function deleteEntry(options: {
|
|
|
547
547
|
}>;
|
|
548
548
|
/**
|
|
549
549
|
* Advisory O_EXCL lock scoped to a single memory.db file (`<dbPath>.lock`),
|
|
550
|
-
* same stale-takeover pattern as services/global-ai-budget.ts.
|
|
551
|
-
*
|
|
552
|
-
*
|
|
550
|
+
* same stale-takeover pattern as services/global-ai-budget.ts.
|
|
551
|
+
*
|
|
552
|
+
* #2878: sql.js persists by rewriting the whole database image, so every
|
|
553
|
+
* `load → mutate → export → write` sequence is a read-modify-write that a
|
|
554
|
+
* concurrent writer can clobber — both callers report success and the loser's
|
|
555
|
+
* rows vanish, with `PRAGMA integrity_check` still clean. Every such sequence
|
|
556
|
+
* in this module now runs inside this lock. It is advisory, so it still
|
|
557
|
+
* cannot coordinate against a writer that bypasses this module entirely
|
|
558
|
+
* (a native WAL connection — see hasNativeWalSidecars).
|
|
553
559
|
*/
|
|
554
560
|
export declare function withMemoryDbLock<T>(dbPath: string, fn: () => Promise<T> | T): Promise<T>;
|
|
555
561
|
export declare function purgeNamespace(options: {
|