claude-flow 3.20.0 → 3.21.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.
Files changed (36) hide show
  1. package/package.json +1 -1
  2. package/v3/@claude-flow/cli/dist/src/agenticow/speculative-exploration.d.ts +148 -0
  3. package/v3/@claude-flow/cli/dist/src/agenticow/speculative-exploration.js +218 -0
  4. package/v3/@claude-flow/cli/dist/src/commands/autopilot.js +45 -0
  5. package/v3/@claude-flow/cli/dist/src/commands/doctor.js +56 -0
  6. package/v3/@claude-flow/cli/dist/src/commands/neural.js +309 -1
  7. package/v3/@claude-flow/cli/dist/src/init/executor.js +17 -0
  8. package/v3/@claude-flow/cli/dist/src/init/helpers-generator.js +26 -2
  9. package/v3/@claude-flow/cli/dist/src/init/memory-package-resolver.d.ts +53 -0
  10. package/v3/@claude-flow/cli/dist/src/init/memory-package-resolver.js +118 -0
  11. package/v3/@claude-flow/cli/dist/src/mcp-client.js +6 -1
  12. package/v3/@claude-flow/cli/dist/src/mcp-tools/agent-execute-core.js +33 -0
  13. package/v3/@claude-flow/cli/dist/src/mcp-tools/agent-tools.js +47 -1
  14. package/v3/@claude-flow/cli/dist/src/mcp-tools/agenticow-loader.d.ts +59 -0
  15. package/v3/@claude-flow/cli/dist/src/mcp-tools/agenticow-loader.js +105 -0
  16. package/v3/@claude-flow/cli/dist/src/mcp-tools/agenticow-speculate-tools.d.ts +24 -0
  17. package/v3/@claude-flow/cli/dist/src/mcp-tools/agenticow-speculate-tools.js +202 -0
  18. package/v3/@claude-flow/cli/dist/src/mcp-tools/agenticow-tools.js +9 -82
  19. package/v3/@claude-flow/cli/dist/src/mcp-tools/index.d.ts +1 -0
  20. package/v3/@claude-flow/cli/dist/src/mcp-tools/index.js +2 -0
  21. package/v3/@claude-flow/cli/dist/src/memory/memory-bridge.js +49 -8
  22. package/v3/@claude-flow/cli/dist/src/ruvector/router-trajectory.d.ts +33 -0
  23. package/v3/@claude-flow/cli/dist/src/ruvector/router-trajectory.js +31 -0
  24. package/v3/@claude-flow/cli/dist/src/ruvector/run-transcript-recorder.d.ts +154 -0
  25. package/v3/@claude-flow/cli/dist/src/ruvector/run-transcript-recorder.js +209 -0
  26. package/v3/@claude-flow/cli/dist/src/services/checkpoint-gate.d.ts +140 -0
  27. package/v3/@claude-flow/cli/dist/src/services/checkpoint-gate.js +223 -0
  28. package/v3/@claude-flow/cli/dist/src/services/distill-oracle.d.ts +190 -0
  29. package/v3/@claude-flow/cli/dist/src/services/distill-oracle.js +349 -0
  30. package/v3/@claude-flow/cli/dist/src/services/fable-harness.d.ts +168 -0
  31. package/v3/@claude-flow/cli/dist/src/services/fable-harness.js +347 -0
  32. package/v3/@claude-flow/cli/dist/src/services/swarm-memory-branches.d.ts +135 -0
  33. package/v3/@claude-flow/cli/dist/src/services/swarm-memory-branches.js +213 -0
  34. package/v3/@claude-flow/cli/dist/src/services/weight-eft.d.ts +305 -0
  35. package/v3/@claude-flow/cli/dist/src/services/weight-eft.js +296 -0
  36. package/v3/@claude-flow/cli/package.json +5 -4
@@ -224,6 +224,8 @@ export const agentTools = [
224
224
  description: 'Claude model alias (haiku=fast/cheap, sonnet=balanced, opus=current Opus 4.8, opus-4.7=prior Opus pin)'
225
225
  },
226
226
  task: { type: 'string', description: 'Task description for intelligent model routing' },
227
+ memoryBase: { type: 'string', description: 'Opt-in: base .rvf memory file to fork a per-agent Copy-On-Write branch from (agenticow). When set, the agent gets an isolated ~162-byte COW branch instead of a full copy — promote on success, discard on terminate. Requires the optional `agenticow` dep; degrades to a no-op when absent or when CLAUDE_FLOW_NO_COW_MEMORY=1.' },
228
+ memoryDimension: { type: 'integer', description: 'Vector dimension for the COW base (required only when memoryBase does not exist yet)' },
227
229
  },
228
230
  required: ['agentType'],
229
231
  },
@@ -295,6 +297,31 @@ export const agentTools = [
295
297
  await addNode({ id: agentId, type: 'agent', name: agentType });
296
298
  }
297
299
  catch { /* graph-node not available */ }
300
+ // ACOW — opt-in per-agent COW memory branch. Only when the caller
301
+ // supplies `memoryBase` does the agent get an isolated 162-byte branch
302
+ // (vs a full .rvf copy). Lazy-imported so agenticow stays off the
303
+ // startup path. Non-fatal: a branch failure never blocks the spawn —
304
+ // the agent is already registered above.
305
+ let memoryBranch;
306
+ if (input.memoryBase) {
307
+ try {
308
+ const { SwarmMemoryBranches } = await import('../services/swarm-memory-branches.js');
309
+ const svc = new SwarmMemoryBranches();
310
+ const br = await svc.branchForAgent(String(input.memoryBase), agentId, {
311
+ dimension: typeof input.memoryDimension === 'number' ? input.memoryDimension : undefined,
312
+ });
313
+ if (br.branchPath) {
314
+ memoryBranch = br.branchPath;
315
+ agent.memoryBranch = br.branchPath;
316
+ agent.memoryBase = br.basePath;
317
+ store.agents[agentId] = agent;
318
+ saveAgentStore(store);
319
+ }
320
+ // else: degraded (agenticow missing / kill-switched) — agent stands
321
+ // without an isolated branch; callers see no memoryBranch field.
322
+ }
323
+ catch { /* COW branch is best-effort; agent already registered */ }
324
+ }
298
325
  // Include deterministic codemod routing info if applicable
299
326
  const response = {
300
327
  success: true,
@@ -307,6 +334,7 @@ export const agentTools = [
307
334
  ...(routingResult.openrouterModel ? { openrouterModel: routingResult.openrouterModel } : {}),
308
335
  status: 'registered',
309
336
  createdAt: agent.createdAt,
337
+ ...(memoryBranch ? { memoryBranch, memoryBase: agent.memoryBase } : {}),
310
338
  note: 'Agent registered for coordination. Three execution paths: ' +
311
339
  '(1) call agent_execute(agentId, prompt) — direct LLM call via Anthropic Messages API (requires ANTHROPIC_API_KEY); ' +
312
340
  '(2) Claude Code Task tool — spawns a real subagent; ' +
@@ -375,6 +403,7 @@ export const agentTools = [
375
403
  properties: {
376
404
  agentId: { type: 'string', description: 'ID of agent to terminate' },
377
405
  force: { type: 'boolean', description: 'Force immediate termination' },
406
+ promoteMemory: { type: 'boolean', description: 'When the agent has a per-agent COW memory branch (spawned with memoryBase), promote (merge) its edits into the shared base on terminate. Default false → discard the branch (throw its edits away). No-op when the agent has no branch.' },
378
407
  },
379
408
  required: ['agentId'],
380
409
  },
@@ -385,13 +414,30 @@ export const agentTools = [
385
414
  const store = loadAgentStore();
386
415
  const agentId = input.agentId;
387
416
  if (store.agents[agentId]) {
388
- store.agents[agentId].status = 'terminated';
417
+ const rec = store.agents[agentId];
418
+ rec.status = 'terminated';
389
419
  saveAgentStore(store);
420
+ // ACOW — resolve the agent's COW memory branch on teardown: promote
421
+ // (merge into base) when asked, else discard. Non-fatal — a failure
422
+ // here never blocks termination. Discard needs no agenticow (pure fs),
423
+ // so cleanup still works in the degraded path.
424
+ let memory;
425
+ if (rec.memoryBranch) {
426
+ try {
427
+ const { SwarmMemoryBranches } = await import('../services/swarm-memory-branches.js');
428
+ const svc = new SwarmMemoryBranches();
429
+ memory = input.promoteMemory
430
+ ? (await svc.promoteAgent(agentId))
431
+ : (await svc.discardAgent(agentId));
432
+ }
433
+ catch { /* best-effort teardown */ }
434
+ }
390
435
  return {
391
436
  success: true,
392
437
  agentId,
393
438
  terminated: true,
394
439
  terminatedAt: new Date().toISOString(),
440
+ ...(memory ? { memory } : {}),
395
441
  };
396
442
  }
397
443
  return {
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Agenticow shared loader + helpers.
3
+ *
4
+ * Extracted from `agenticow-tools.ts` so both the MCP tool surface AND the
5
+ * `SwarmMemoryBranches` service (src/services/swarm-memory-branches.ts) share
6
+ * one loader, one degradation contract, and one set of path/lineage helpers —
7
+ * rather than duplicating the optional-dep dance in two places.
8
+ *
9
+ * Architectural constraint (ADR-150, mirrors metaharness-tools.ts):
10
+ * - `agenticow` lives in `optionalDependencies` — never a hard runtime dep.
11
+ * - When the package is missing, callers get `null` from `loadAgenticow()`
12
+ * (or a `{degraded:true}` result via `degradedResult`) and MUST fall back
13
+ * gracefully — never throw a MODULE_NOT_FOUND.
14
+ *
15
+ * @module @claude-flow/cli/mcp-tools/agenticow-loader
16
+ */
17
+ export declare const PACKAGE_NAME = "agenticow";
18
+ export interface AgenticowApi {
19
+ open: (file: string, opts?: {
20
+ dimension?: number;
21
+ metric?: string;
22
+ }) => Promise<any>;
23
+ openBase?: (file: string, opts?: any) => Promise<any>;
24
+ AgenticMemory: any;
25
+ }
26
+ /**
27
+ * Lazily import `agenticow`. Returns the module on success, or `null` when the
28
+ * package is not installed (the optional-dep degraded path). Any OTHER load
29
+ * error (e.g. a corrupt install) is re-thrown so it is not silently masked.
30
+ */
31
+ export declare function loadAgenticow(): Promise<AgenticowApi | null>;
32
+ /** Reset the module-level load cache. Test-only seam. */
33
+ export declare function __resetAgenticowCache(): void;
34
+ export declare function degradedResult(reason: string): {
35
+ success: true;
36
+ degraded: true;
37
+ reason: string;
38
+ };
39
+ /**
40
+ * Resolve a user-supplied memory path against the project cwd, rejecting path
41
+ * traversal and NUL bytes (D-2 style hardening — same rule the MCP verbs use).
42
+ */
43
+ export declare function resolveMemoryPath(path: string): string;
44
+ /**
45
+ * Lineage manifest companion path. agenticow persists the COW chain
46
+ * (working → checkpoints → base) into `<file>.agenticow.json` next to the
47
+ * `.rvf` data file. Without it, forks/checkpoints are in-memory only and
48
+ * disappear when the AgenticMemory handle closes.
49
+ */
50
+ export declare function manifestFor(file: string): string;
51
+ /** Validate a COW branch/checkpoint label (alnum + a small safe symbol set). */
52
+ export declare function validateLabel(label: string): string;
53
+ /**
54
+ * Open (or create) a memory file, restoring its COW chain from the lineage
55
+ * manifest when one exists. When neither the `.rvf` nor the manifest exists,
56
+ * `dimension` is required to create a fresh base.
57
+ */
58
+ export declare function openWithLineage(api: AgenticowApi, file: string, dimension?: number): Promise<any>;
59
+ //# sourceMappingURL=agenticow-loader.d.ts.map
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Agenticow shared loader + helpers.
3
+ *
4
+ * Extracted from `agenticow-tools.ts` so both the MCP tool surface AND the
5
+ * `SwarmMemoryBranches` service (src/services/swarm-memory-branches.ts) share
6
+ * one loader, one degradation contract, and one set of path/lineage helpers —
7
+ * rather than duplicating the optional-dep dance in two places.
8
+ *
9
+ * Architectural constraint (ADR-150, mirrors metaharness-tools.ts):
10
+ * - `agenticow` lives in `optionalDependencies` — never a hard runtime dep.
11
+ * - When the package is missing, callers get `null` from `loadAgenticow()`
12
+ * (or a `{degraded:true}` result via `degradedResult`) and MUST fall back
13
+ * gracefully — never throw a MODULE_NOT_FOUND.
14
+ *
15
+ * @module @claude-flow/cli/mcp-tools/agenticow-loader
16
+ */
17
+ import { existsSync } from 'node:fs';
18
+ import { resolve, isAbsolute } from 'node:path';
19
+ import { getProjectCwd } from './types.js';
20
+ export const PACKAGE_NAME = 'agenticow';
21
+ // Cache: module load is expensive enough to amortize across handler calls.
22
+ // null = not yet attempted; false = attempted and unavailable; module = loaded.
23
+ let _agenticowMod = null;
24
+ let _loadAttempted = false;
25
+ /**
26
+ * Lazily import `agenticow`. Returns the module on success, or `null` when the
27
+ * package is not installed (the optional-dep degraded path). Any OTHER load
28
+ * error (e.g. a corrupt install) is re-thrown so it is not silently masked.
29
+ */
30
+ export async function loadAgenticow() {
31
+ if (_loadAttempted)
32
+ return _agenticowMod || null;
33
+ _loadAttempted = true;
34
+ try {
35
+ _agenticowMod = await import(PACKAGE_NAME);
36
+ return _agenticowMod;
37
+ }
38
+ catch (err) {
39
+ if (err && (err.code === 'ERR_MODULE_NOT_FOUND' || err.code === 'MODULE_NOT_FOUND' ||
40
+ /Cannot find (module|package)/i.test(String(err.message)))) {
41
+ _agenticowMod = false;
42
+ return null;
43
+ }
44
+ throw err;
45
+ }
46
+ }
47
+ /** Reset the module-level load cache. Test-only seam. */
48
+ export function __resetAgenticowCache() {
49
+ _agenticowMod = null;
50
+ _loadAttempted = false;
51
+ }
52
+ export function degradedResult(reason) {
53
+ return { success: true, degraded: true, reason };
54
+ }
55
+ /**
56
+ * Resolve a user-supplied memory path against the project cwd, rejecting path
57
+ * traversal and NUL bytes (D-2 style hardening — same rule the MCP verbs use).
58
+ */
59
+ export function resolveMemoryPath(path) {
60
+ if (!path || typeof path !== 'string')
61
+ throw new Error('memory path is required');
62
+ if (/\.\.[\\/]|\0/.test(path))
63
+ throw new Error('memory path contains disallowed characters');
64
+ return isAbsolute(path) ? path : resolve(getProjectCwd(), path);
65
+ }
66
+ /**
67
+ * Lineage manifest companion path. agenticow persists the COW chain
68
+ * (working → checkpoints → base) into `<file>.agenticow.json` next to the
69
+ * `.rvf` data file. Without it, forks/checkpoints are in-memory only and
70
+ * disappear when the AgenticMemory handle closes.
71
+ */
72
+ export function manifestFor(file) {
73
+ return `${file}.agenticow.json`;
74
+ }
75
+ /** Validate a COW branch/checkpoint label (alnum + a small safe symbol set). */
76
+ export function validateLabel(label) {
77
+ if (!label || typeof label !== 'string')
78
+ throw new Error('label is required');
79
+ if (label.length > 256)
80
+ throw new Error('label exceeds 256 chars');
81
+ if (!/^[A-Za-z0-9_.\-:/@]+$/.test(label)) {
82
+ throw new Error('label may only contain [A-Za-z0-9_.\\-:/@]');
83
+ }
84
+ return label;
85
+ }
86
+ /**
87
+ * Open (or create) a memory file, restoring its COW chain from the lineage
88
+ * manifest when one exists. When neither the `.rvf` nor the manifest exists,
89
+ * `dimension` is required to create a fresh base.
90
+ */
91
+ export async function openWithLineage(api, file, dimension) {
92
+ const manifest = manifestFor(file);
93
+ if (existsSync(manifest)) {
94
+ return api.AgenticMemory.load(manifest);
95
+ }
96
+ const opts = {};
97
+ if (typeof dimension === 'number' && Number.isInteger(dimension) && dimension > 0) {
98
+ opts.dimension = dimension;
99
+ }
100
+ else if (!existsSync(file)) {
101
+ throw new Error('dimension is required when creating a new memory file');
102
+ }
103
+ return api.open(file, opts);
104
+ }
105
+ //# sourceMappingURL=agenticow-loader.js.map
@@ -0,0 +1,24 @@
1
+ /**
2
+ * agenticow speculate — MCP surface for speculative branch-and-promote
3
+ * (agenticow step 4).
4
+ *
5
+ * Exposes the `SpeculativeExploration` module as a single MCP tool
6
+ * `agenticow_speculate` so agents can drive parallel A/B memory exploration:
7
+ * fan out N candidate ingest-sets, each on its own 162-byte COW branch of a
8
+ * shared base `.rvf`, score them by a probe query, PROMOTE the winner into
9
+ * base, and DISCARD the losers (delete their branch files).
10
+ *
11
+ * Because MCP inputs are JSON (not JS functions), candidates are DECLARATIVE:
12
+ * each candidate is a label + a set of vectors to ingest, and scoring is a
13
+ * probe query (`nearest`) or an ingest count (`count`). The generic
14
+ * `explore(base, {label, fn}[], score)` core does the real work.
15
+ *
16
+ * Optional-dep contract (mirrors agenticow-tools.ts): when `agenticow` is not
17
+ * installed the tool returns `{success:true, degraded:true,
18
+ * reason:'agenticow-not-found'}` and never throws for that reason.
19
+ *
20
+ * @module @claude-flow/cli/mcp-tools/agenticow-speculate
21
+ */
22
+ import type { MCPTool } from './types.js';
23
+ export declare const agenticowSpeculateTools: MCPTool[];
24
+ //# sourceMappingURL=agenticow-speculate-tools.d.ts.map
@@ -0,0 +1,202 @@
1
+ /**
2
+ * agenticow speculate — MCP surface for speculative branch-and-promote
3
+ * (agenticow step 4).
4
+ *
5
+ * Exposes the `SpeculativeExploration` module as a single MCP tool
6
+ * `agenticow_speculate` so agents can drive parallel A/B memory exploration:
7
+ * fan out N candidate ingest-sets, each on its own 162-byte COW branch of a
8
+ * shared base `.rvf`, score them by a probe query, PROMOTE the winner into
9
+ * base, and DISCARD the losers (delete their branch files).
10
+ *
11
+ * Because MCP inputs are JSON (not JS functions), candidates are DECLARATIVE:
12
+ * each candidate is a label + a set of vectors to ingest, and scoring is a
13
+ * probe query (`nearest`) or an ingest count (`count`). The generic
14
+ * `explore(base, {label, fn}[], score)` core does the real work.
15
+ *
16
+ * Optional-dep contract (mirrors agenticow-tools.ts): when `agenticow` is not
17
+ * installed the tool returns `{success:true, degraded:true,
18
+ * reason:'agenticow-not-found'}` and never throws for that reason.
19
+ *
20
+ * @module @claude-flow/cli/mcp-tools/agenticow-speculate
21
+ */
22
+ import { loadAgenticow, degradedResult, resolveMemoryPath, openWithLineage, manifestFor, validateLabel, } from './agenticow-loader.js';
23
+ import { explore, } from '../agenticow/speculative-exploration.js';
24
+ /** Turn a validated label into a filesystem-safe branch filename segment. */
25
+ function safeSegment(label) {
26
+ return label.replace(/[^A-Za-z0-9_-]+/g, '_').slice(0, 64) || 'branch';
27
+ }
28
+ export const agenticowSpeculateTools = [
29
+ {
30
+ name: 'agenticow_speculate',
31
+ description: "agenticow — speculative branch-and-promote for parallel A/B memory exploration. " +
32
+ "Forks a 162-byte COW branch per candidate off a shared base .rvf, ingests each candidate's " +
33
+ "vectors into its OWN isolated branch, scores every branch (probe-query 'nearest' distance or " +
34
+ "ingest 'count'), PROMOTES the winning branch's edits into base, and DISCARDS the losers by " +
35
+ "deleting their branch files. Use when you want to try N competing memory-write strategies and " +
36
+ "keep only the best — the memory-state analogue of worktree-per-agent code exploration. " +
37
+ "Copying the base per candidate is wrong (full-copy snapshots grow linearly, the 3.3 GB Darwin " +
38
+ "bloat); COW forks are constant-size and losers cost ~162 B to throw away. Optional dep — " +
39
+ "degrades to {degraded:true} when agenticow is missing.",
40
+ category: 'memory',
41
+ tags: ['agenticow', 'memory', 'cow', 'speculative', 'branch', 'promote', 'ab'],
42
+ inputSchema: {
43
+ type: 'object',
44
+ properties: {
45
+ basePath: {
46
+ type: 'string',
47
+ description: 'Path to base .rvf memory file (absolute or relative to cwd)',
48
+ },
49
+ dimension: {
50
+ type: 'integer',
51
+ description: 'Vector dimension (required only when basePath does not exist yet)',
52
+ },
53
+ candidates: {
54
+ type: 'array',
55
+ description: 'The A/B candidates. Each explores its own COW branch.',
56
+ items: {
57
+ type: 'object',
58
+ properties: {
59
+ label: { type: 'string', description: 'Branch label (alnum + _.-:/@ only)' },
60
+ ingest: {
61
+ type: 'array',
62
+ description: 'Vectors to ingest into this candidate branch',
63
+ items: {
64
+ type: 'object',
65
+ properties: {
66
+ id: { type: 'integer', description: 'Explicit vector id (auto when omitted)' },
67
+ vector: { type: 'array', items: { type: 'number' }, description: 'Dense vector' },
68
+ text: { type: 'string', description: 'Optional payload text' },
69
+ },
70
+ required: ['vector'],
71
+ },
72
+ },
73
+ branchPath: {
74
+ type: 'string',
75
+ description: 'Optional explicit path for this branch file (default: alongside base)',
76
+ },
77
+ },
78
+ required: ['label', 'ingest'],
79
+ },
80
+ },
81
+ probe: {
82
+ type: 'array',
83
+ items: { type: 'number' },
84
+ description: "Probe vector for scoreBy='nearest' (scores each branch by best-hit similarity)",
85
+ },
86
+ k: { type: 'integer', description: 'Nearest-neighbours to fetch per probe (default 1)' },
87
+ scoreBy: {
88
+ type: 'string',
89
+ enum: ['nearest', 'count'],
90
+ description: "'nearest' = closest probe distance wins; 'count' = most accepted ingests wins. Default 'nearest'.",
91
+ },
92
+ requireClearance: {
93
+ type: 'boolean',
94
+ description: 'ADR-171 fail-closed gate. When true, the top-scored winner is NOT promoted (base stays unchanged) and a provenance-tagged receipt is emitted — score alone cannot graduate work. Use when speculating over TASK outcomes rather than pure memory A/B. Default false (score-only promotion, tagged `unverified`).',
95
+ default: false,
96
+ },
97
+ },
98
+ required: ['basePath', 'candidates'],
99
+ },
100
+ handler: async (input) => {
101
+ const api = await loadAgenticow();
102
+ if (!api)
103
+ return degradedResult('agenticow-not-found');
104
+ const basePath = resolveMemoryPath(String(input.basePath));
105
+ const dimension = input.dimension;
106
+ const scoreBy = input.scoreBy === 'count' ? 'count' : 'nearest';
107
+ const k = Number.isInteger(input.k) && input.k > 0 ? input.k : 1;
108
+ const probe = Array.isArray(input.probe) ? input.probe : null;
109
+ const rawCandidates = input.candidates;
110
+ if (!Array.isArray(rawCandidates) || rawCandidates.length === 0) {
111
+ throw new Error('at least one candidate is required');
112
+ }
113
+ if (scoreBy === 'nearest' && !probe) {
114
+ throw new Error("scoreBy='nearest' requires a probe vector");
115
+ }
116
+ // Build the generic {label, fn} candidates. Each fn ingests into its own
117
+ // branch handle, then (for 'nearest') probes it so we can score.
118
+ const candidates = rawCandidates.map((c) => {
119
+ const label = validateLabel(String(c.label));
120
+ if (!Array.isArray(c.ingest) || c.ingest.length === 0) {
121
+ throw new Error(`candidate ${label} must ingest at least one vector`);
122
+ }
123
+ const records = c.ingest.map((r) => ({
124
+ ...(Number.isInteger(r.id) ? { id: r.id } : {}),
125
+ vector: r.vector,
126
+ ...(typeof r.text === 'string' ? { text: r.text } : {}),
127
+ }));
128
+ return {
129
+ label,
130
+ fn: (branch) => {
131
+ const res = branch.ingest(records);
132
+ const accepted = Number(res?.accepted ?? records.length);
133
+ let hits = [];
134
+ if (probe) {
135
+ hits = (branch.query(probe, k) || []).map((h) => ({
136
+ id: h.id,
137
+ distance: h.distance,
138
+ }));
139
+ }
140
+ const bestDistance = hits.length ? hits[0].distance : null;
141
+ return { accepted, bestDistance, hits };
142
+ },
143
+ };
144
+ });
145
+ const score = (r) => {
146
+ if (scoreBy === 'count')
147
+ return r.accepted;
148
+ // nearest: smaller distance = better. Map to a higher-is-better score.
149
+ if (r.bestDistance === null)
150
+ return -Infinity;
151
+ return 1 / (1 + Math.max(0, r.bestDistance));
152
+ };
153
+ const branchPath = (label) => {
154
+ const explicit = rawCandidates.find((c) => validateLabel(String(c.label)) === label)?.branchPath;
155
+ if (explicit)
156
+ return resolveMemoryPath(String(explicit));
157
+ return `${basePath}.spec-${safeSegment(label)}.rvf`;
158
+ };
159
+ // ADR-171 promotion gate. For pure memory A/B the `score` IS the chosen
160
+ // metric (not a proxy for task correctness), so score-only promotion is
161
+ // legitimate and stays the default (tagged `unverified`, never
162
+ // masquerading as ground truth). Callers grafting this onto TASK work
163
+ // pass requireClearance:true to fail-closed — the winner is then
164
+ // ineligible unless a real clearance mechanism graduates it.
165
+ const requireClearance = input.requireClearance === true;
166
+ const exploreOpts = { branchPath, persist: true };
167
+ if (requireClearance)
168
+ exploreOpts.requireClearance = true;
169
+ // Open base, run the speculative exploration, persist base with the winner promoted.
170
+ const base = await openWithLineage(api, basePath, dimension);
171
+ try {
172
+ const result = await explore(base, candidates, score, exploreOpts);
173
+ base.save?.(manifestFor(basePath));
174
+ return {
175
+ success: true,
176
+ basePath,
177
+ scoreBy,
178
+ winner: result.winner,
179
+ scores: result.scores,
180
+ promoted: result.promoted,
181
+ promotedBy: result.promotedBy,
182
+ promotionDecision: result.promotionDecision,
183
+ promoteStats: result.promoteStats,
184
+ discarded: result.discarded,
185
+ receipts: result.receipts,
186
+ branches: result.branches.map((b) => ({
187
+ label: b.label,
188
+ path: b.path,
189
+ score: b.score,
190
+ kept: b.kept,
191
+ accepted: b.result.accepted,
192
+ bestDistance: b.result.bestDistance,
193
+ })),
194
+ };
195
+ }
196
+ finally {
197
+ await base.close?.();
198
+ }
199
+ },
200
+ },
201
+ ];
202
+ //# sourceMappingURL=agenticow-speculate-tools.js.map
@@ -31,83 +31,10 @@
31
31
  *
32
32
  * @module @claude-flow/cli/mcp-tools/agenticow
33
33
  */
34
- import { existsSync } from 'node:fs';
35
- import { getProjectCwd } from './types.js';
36
- import { resolve, isAbsolute } from 'node:path';
37
- const PACKAGE_NAME = 'agenticow';
38
- // Cache: module load is expensive enough to amortize across handler calls.
39
- // null = not yet attempted; false = attempted and unavailable; module = loaded.
40
- let _agenticowMod = null;
41
- let _loadAttempted = false;
42
- async function loadAgenticow() {
43
- if (_loadAttempted)
44
- return _agenticowMod;
45
- _loadAttempted = true;
46
- try {
47
- _agenticowMod = await import(PACKAGE_NAME);
48
- return _agenticowMod;
49
- }
50
- catch (err) {
51
- if (err && (err.code === 'ERR_MODULE_NOT_FOUND' || err.code === 'MODULE_NOT_FOUND' ||
52
- /Cannot find (module|package)/i.test(String(err.message)))) {
53
- _agenticowMod = false;
54
- return null;
55
- }
56
- throw err;
57
- }
58
- }
59
- function degradedResult(reason) {
60
- return { success: true, degraded: true, reason };
61
- }
62
- function resolveMemoryPath(path) {
63
- if (!path || typeof path !== 'string')
64
- throw new Error('memory path is required');
65
- // D-2 style: reject path traversal in user-supplied paths
66
- if (/\.\.[\\/]|\0/.test(path))
67
- throw new Error('memory path contains disallowed characters');
68
- return isAbsolute(path) ? path : resolve(getProjectCwd(), path);
69
- }
70
- /**
71
- * Lineage manifest companion path. agenticow persists the COW chain
72
- * (working → checkpoints → base) into `<file>.agenticow.json` next to the
73
- * `.rvf` data file. Without this, checkpoints and forks are in-memory only
74
- * and disappear when the AgenticMemory handle closes. Mirrors the bin
75
- * CLI's `manifestFor(file)` helper.
76
- */
77
- function manifestFor(file) {
78
- return `${file}.agenticow.json`;
79
- }
80
- function validateLabel(label) {
81
- if (!label || typeof label !== 'string')
82
- throw new Error('label is required');
83
- if (label.length > 256)
84
- throw new Error('label exceeds 256 chars');
85
- if (!/^[A-Za-z0-9_.\-:/@]+$/.test(label)) {
86
- throw new Error('label may only contain [A-Za-z0-9_.\\-:/@]');
87
- }
88
- return label;
89
- }
90
- /**
91
- * Open (or create) a base memory file. When a lineage manifest exists at
92
- * `<file>.agenticow.json`, we load that to restore the COW chain (checkpoints,
93
- * ancestors). When only the `.rvf` exists, fresh-open it. When neither exists,
94
- * dimension is required to create. Mirrors the bin CLI's `loadMem()` helper.
95
- */
96
- async function openWithLineage(api, file, dimension) {
97
- const manifest = manifestFor(file);
98
- if (existsSync(manifest)) {
99
- // The class-level static method `load` reconstructs the full chain.
100
- return api.AgenticMemory.load(manifest);
101
- }
102
- const opts = {};
103
- if (typeof dimension === 'number' && Number.isInteger(dimension) && dimension > 0) {
104
- opts.dimension = dimension;
105
- }
106
- else if (!existsSync(file)) {
107
- throw new Error('dimension is required when creating a new memory file');
108
- }
109
- return api.open(file, opts);
110
- }
34
+ // Loader + path/lineage helpers are shared with the SwarmMemoryBranches
35
+ // service (src/services/swarm-memory-branches.ts) via one module so the
36
+ // optional-dep dance and the COW open/fork semantics live in exactly one place.
37
+ import { loadAgenticow, degradedResult, resolveMemoryPath, manifestFor, validateLabel, openWithLineage, } from './agenticow-loader.js';
111
38
  export const agenticowTools = [
112
39
  {
113
40
  name: 'agenticow_branch',
@@ -157,7 +84,7 @@ export const agenticowTools = [
157
84
  },
158
85
  {
159
86
  name: 'agenticow_ingest',
160
- description: 'agenticow — write vectors (with optional text payloads) into an .rvf memory branch or base. Records: [{id?, vector, text?}] — id auto-assigns when omitted. This is the write half that makes a branch usable: agenticow_branch creates an empty COW child, but without ingest it has nothing to read back. Use after branching to populate an agent/session-local memory. Editing the base directly is wrong when the writes are speculative — ingest into a branch, then promote only if validated. Persists via .agenticow.json lineage manifest.',
87
+ description: 'agenticow — write vectors (with optional text payloads) into an .rvf memory branch or base. Records: [{id?, vector, text?}] — id auto-assigns when omitted. This is the write half that makes a branch usable: agenticow_branch creates an empty COW child, but without ingest it has nothing to read back. Use when you have branched and must populate the branch (agenticow_branch alone leaves it empty). Editing the base directly is wrong when the writes are speculative — ingest into a branch, then promote only if validated. Persists via .agenticow.json lineage manifest.',
161
88
  category: 'memory',
162
89
  tags: ['agenticow', 'memory', 'cow', 'ingest', 'write'],
163
90
  inputSchema: {
@@ -213,7 +140,7 @@ export const agenticowTools = [
213
140
  },
214
141
  {
215
142
  name: 'agenticow_query',
216
- description: 'agenticow — k-NN read across an .rvf memory branch\'s full COW lineage (parent ∪ edits, child wins), returning {id, distance, branch, text}. Read-only (no manifest write). The `branch` field on each hit tells you which lineage node the result came from — the read-through semantics that make branching useful. Use to retrieve from an agent/session branch without materializing a full copy. Re-opening the base and manually merging edits is wrong: query already spans the chain (and uses the single-call Rust path when the branch was forked with nativeAnn).',
143
+ description: 'agenticow — k-NN read across an .rvf memory branch\'s full COW lineage (parent ∪ edits, child wins), returning {id, distance, branch, text}. Read-only (no manifest write). The `branch` field on each hit tells you which lineage node the result came from — the read-through semantics that make branching useful. Use when you need to read from an agent/session branch without materializing a full copy. Re-opening the base and manually merging edits is wrong: query already spans the chain (and uses the single-call Rust path when the branch was forked with nativeAnn).',
217
144
  category: 'memory',
218
145
  tags: ['agenticow', 'memory', 'cow', 'query', 'read', 'search'],
219
146
  inputSchema: {
@@ -251,7 +178,7 @@ export const agenticowTools = [
251
178
  },
252
179
  {
253
180
  name: 'agenticow_diff',
254
- description: 'agenticow — show what a branch changed relative to its lineage: {added, overridden, deleted} vector-id lists. Use before promote to preview the exact merge, or to audit what an agent/session branch actually wrote. Diffing by re-querying is wrong because deletions (tombstones) are invisible to a read — diff() surfaces them explicitly. Requires the branch was opened with edit tracking (default on).',
181
+ description: 'agenticow — show what a branch changed relative to its lineage: {added, overridden, deleted} vector-id lists. Use when you are about to promote and want to preview the exact merge, or when auditing what a branch actually wrote. Diffing by re-querying is wrong because deletions (tombstones) are invisible to a read — diff() surfaces them explicitly. Requires the branch was opened with edit tracking (default on).',
255
182
  category: 'memory',
256
183
  tags: ['agenticow', 'memory', 'cow', 'diff'],
257
184
  inputSchema: {
@@ -278,7 +205,7 @@ export const agenticowTools = [
278
205
  },
279
206
  {
280
207
  name: 'agenticow_lineage',
281
- description: 'agenticow — walk the COW chain of an .rvf memory file: an ordered list of nodes (role working|checkpoint|base, id, label, parent, createdAt, mutations, tombstones). Use to understand branch history, find checkpoint ids for a targeted rollback, or debug a promote. Guessing the chain from filenames is wrong — lineage is the authoritative structure the store maintains.',
208
+ description: 'agenticow — walk the COW chain of an .rvf memory file: an ordered list of nodes (role working|checkpoint|base, id, label, parent, createdAt, mutations, tombstones). Use when you need branch history — to find checkpoint ids for a targeted rollback, or to debug a promote. Guessing the chain from filenames is wrong — lineage is the authoritative structure the store maintains.',
282
209
  category: 'memory',
283
210
  tags: ['agenticow', 'memory', 'cow', 'lineage', 'history'],
284
211
  inputSchema: {
@@ -305,7 +232,7 @@ export const agenticowTools = [
305
232
  },
306
233
  {
307
234
  name: 'agenticow_status',
308
- description: 'agenticow — health/geometry of an .rvf memory file: {totalVectors, totalSegments, fileSize, currentEpoch, deadSpaceRatio, readOnly, chainDepth, dimension, metric}. Use to check vector count before/after ingest, spot compaction pressure (deadSpaceRatio), or confirm the dimension before ingesting into a shared base. Pure read.',
235
+ description: 'agenticow — health/geometry of an .rvf memory file: {totalVectors, totalSegments, fileSize, currentEpoch, deadSpaceRatio, readOnly, chainDepth, dimension, metric}. Use when you need to check vector count before/after ingest, spot compaction pressure (deadSpaceRatio), or confirm the dimension before ingesting into a shared base. Pure read.',
309
236
  category: 'memory',
310
237
  tags: ['agenticow', 'memory', 'cow', 'status'],
311
238
  inputSchema: {
@@ -27,6 +27,7 @@ export { autopilotTools } from './autopilot-tools.js';
27
27
  export { metaharnessTools } from './metaharness-tools.js';
28
28
  export { testgenTools } from './testgen-tools.js';
29
29
  export { agenticowTools } from './agenticow-tools.js';
30
+ export { agenticowSpeculateTools } from './agenticow-speculate-tools.js';
30
31
  export { agentbbsTools } from './agentbbs-tools.js';
31
32
  export { businessPodTools } from './business-pod-tools.js';
32
33
  export { httpFetchTools } from './http-fetch-tools.js';
@@ -29,6 +29,8 @@ export { metaharnessTools } from './metaharness-tools.js';
29
29
  export { testgenTools } from './testgen-tools.js';
30
30
  // agenticow@~0.2.3 — Copy-On-Write memory branching (162-byte branches)
31
31
  export { agenticowTools } from './agenticow-tools.js';
32
+ // agenticow step 4 — speculative branch-and-promote (A/B memory exploration)
33
+ export { agenticowSpeculateTools } from './agenticow-speculate-tools.js';
32
34
  // ADR-164 — AgentBBS federated business-domain BBS rooms (Phase 1)
33
35
  export { agentbbsTools } from './agentbbs-tools.js';
34
36
  // ADR-164 Phase 2 — Business-pod template validation