@claude-flow/cli 3.72.0 → 3.72.2

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 (64) hide show
  1. package/.claude/helpers/helpers.manifest.json +2 -2
  2. package/.claude/skills/fast-code-edits/SKILL.md +45 -0
  3. package/.claude/skills/graph-mincut/SKILL.md +32 -0
  4. package/.claude/skills/injection-defense/SKILL.md +36 -0
  5. package/.claude/skills/lora-learning/SKILL.md +30 -0
  6. package/.claude/skills/sublinear-solver/SKILL.md +34 -0
  7. package/.claude/skills/vector-quantization/SKILL.md +36 -0
  8. package/catalog-manifest.json +4 -4
  9. package/dist/src/appliance/ruvllm-bridge.d.ts +6 -2
  10. package/dist/src/appliance/ruvllm-bridge.js +13 -8
  11. package/dist/src/commands/init.js +2 -0
  12. package/dist/src/commands/neural.js +81 -71
  13. package/dist/src/init/executor.js +13 -0
  14. package/dist/src/init/types.d.ts +6 -0
  15. package/dist/src/init/types.js +3 -0
  16. package/dist/src/mcp-client.js +2 -0
  17. package/dist/src/mcp-tools/agentdb-tools.js +34 -2
  18. package/dist/src/mcp-tools/browser-session-tools.d.ts +2 -2
  19. package/dist/src/mcp-tools/browser-session-tools.js +4 -4
  20. package/dist/src/mcp-tools/fast-apply-tools.d.ts +4 -0
  21. package/dist/src/mcp-tools/fast-apply-tools.js +85 -0
  22. package/dist/src/mcp-tools/hooks-tools.js +19 -34
  23. package/dist/src/mcp-tools/metaharness-tools.js +1 -1
  24. package/dist/src/mcp-tools/neural-tools.js +3 -3
  25. package/dist/src/mcp-tools/realpath-containment.d.ts +3 -0
  26. package/dist/src/mcp-tools/realpath-containment.js +39 -0
  27. package/dist/src/mods/command-registry/schema.d.ts +12 -12
  28. package/dist/src/ruvector/ast-analyzer.d.ts +1 -2
  29. package/dist/src/ruvector/ast-analyzer.js +4 -12
  30. package/dist/src/ruvector/coverage-router.d.ts +1 -2
  31. package/dist/src/ruvector/coverage-router.js +4 -12
  32. package/dist/src/ruvector/diff-classifier.d.ts +1 -2
  33. package/dist/src/ruvector/diff-classifier.js +3 -12
  34. package/dist/src/ruvector/fast-apply.d.ts +46 -0
  35. package/dist/src/ruvector/fast-apply.js +73 -0
  36. package/dist/src/ruvector/graph-analyzer.d.ts +11 -1
  37. package/dist/src/ruvector/graph-analyzer.js +22 -36
  38. package/dist/src/ruvector/mincut-bridge.d.ts +70 -0
  39. package/dist/src/ruvector/mincut-bridge.js +172 -0
  40. package/dist/src/services/distill-oracle.d.ts +1 -1
  41. package/dist/src/services/distill-oracle.js +2 -2
  42. package/node_modules/@claude-flow/codex/.agents/skills/fast-code-edits/SKILL.md +42 -0
  43. package/node_modules/@claude-flow/codex/.agents/skills/graph-mincut/SKILL.md +42 -0
  44. package/node_modules/@claude-flow/codex/.agents/skills/injection-defense/SKILL.md +45 -0
  45. package/node_modules/@claude-flow/codex/.agents/skills/lora-learning/SKILL.md +39 -0
  46. package/node_modules/@claude-flow/codex/.agents/skills/sublinear-solver/SKILL.md +38 -0
  47. package/node_modules/@claude-flow/codex/.agents/skills/vector-quantization/SKILL.md +49 -0
  48. package/node_modules/@claude-flow/codex/dist/generators/skill-md.d.ts.map +1 -1
  49. package/node_modules/@claude-flow/codex/dist/generators/skill-md.js +6 -0
  50. package/node_modules/@claude-flow/codex/dist/generators/skill-md.js.map +1 -1
  51. package/node_modules/@claude-flow/codex/dist/index.d.ts +3 -3
  52. package/node_modules/@claude-flow/codex/dist/index.js +1 -1
  53. package/node_modules/@claude-flow/codex/dist/templates/index.d.ts.map +1 -1
  54. package/node_modules/@claude-flow/codex/dist/templates/index.js +37 -0
  55. package/node_modules/@claude-flow/codex/dist/templates/index.js.map +1 -1
  56. package/node_modules/@claude-flow/codex/dist/types.d.ts +1 -1
  57. package/node_modules/@claude-flow/codex/dist/types.d.ts.map +1 -1
  58. package/node_modules/@claude-flow/codex/package.json +1 -1
  59. package/package.json +12 -10
  60. package/plugins/ruflo-console/dist/tui.mjs +153 -153
  61. package/plugins/ruflo-metaharness/.claude-plugin/plugin.json +1 -1
  62. package/plugins/ruflo-metaharness/scripts/_darwin.mjs +4 -4
  63. package/plugins/ruflo-metaharness/scripts/_harness.mjs +1 -1
  64. package/plugins/ruflo-metaharness/scripts/smoke.sh +4 -4
@@ -1502,6 +1502,8 @@ export const agentdbGraphPathfinder = {
1502
1502
  }
1503
1503
  const edges = rawEdges;
1504
1504
  let paths = [];
1505
+ let mincutInfo;
1506
+ let approximation;
1505
1507
  // Check millisecond budget before heavy computation
1506
1508
  if (Date.now() - t0 > budget.maxMillis) {
1507
1509
  return { success: true, paths: [], count: 0, message: `complexityBudget.maxMillis (${budget.maxMillis}ms) exceeded before solver dispatch`, seedNodeId, algorithm, elapsedMs: Date.now() - t0 };
@@ -1557,10 +1559,38 @@ export const agentdbGraphPathfinder = {
1557
1559
  paths = witnessChain.slice(0, topK);
1558
1560
  break;
1559
1561
  }
1562
+ case 'dynamic-mincut': {
1563
+ // Exact minimum cut of the seed's depth-hop neighbourhood: the
1564
+ // weakest boundary around the seed, and the nodes on its side of it.
1565
+ // Wasm solver via ruvector (@ruvector/mincut-wasm), JS Stoer-Wagner
1566
+ // fallback for small neighbourhoods.
1567
+ const edgeTuples = edges.map(r => [String(r[0]), String(r[1]), Number(r[2]) || 1.0]);
1568
+ const { seedLocalMinCut } = await import('../ruvector/mincut-bridge.js');
1569
+ const { fallbackMinCut } = await import('../ruvector/graph-analyzer.js');
1570
+ const cut = await seedLocalMinCut(seedNodeId, edgeTuples, depth, budget.maxNodesVisited, fallbackMinCut);
1571
+ if (!cut) {
1572
+ mincutInfo = { backend: 'none', message: 'seed neighbourhood too large for the JS fallback and the wasm solver is unavailable (install ruvector)' };
1573
+ break;
1574
+ }
1575
+ paths = cut.seedSide
1576
+ .map(r => ({ nodeId: r.nodeId, score: 1 / (1 + r.depth), depth: r.depth }))
1577
+ .filter(r => r.score >= threshold)
1578
+ .slice(0, topK);
1579
+ mincutInfo = {
1580
+ backend: cut.backend,
1581
+ cutValue: cut.cutValue,
1582
+ seedSideSize: cut.seedSide.length + 1,
1583
+ otherSideSize: cut.otherSide.length,
1584
+ subgraphNodes: cut.subgraphNodes,
1585
+ cutEdges: cut.cutEdges.slice(0, 50),
1586
+ };
1587
+ break;
1588
+ }
1560
1589
  case 'connected-component-churn':
1561
- case 'dynamic-mincut':
1562
1590
  case 'spectral-sparsify': {
1563
- // Simplified implementations: return k-hop neighbors with basic score
1591
+ // Not implemented natively yet: approximated by k-hop neighbours with
1592
+ // a rank-decay score. The response says so via `implementation`.
1593
+ approximation = 'k-hop';
1564
1594
  const edgeTuples = edges.map(r => [r[0], r[1], Number(r[2]) || 1.0]);
1565
1595
  const khopResult = await agentdbGraphQuery.handler({
1566
1596
  nodeId: seedNodeId, mode: 'k-hop', depth, complexityBudget: budget,
@@ -1582,6 +1612,8 @@ export const agentdbGraphPathfinder = {
1582
1612
  count: paths.length,
1583
1613
  elapsedMs,
1584
1614
  budgetUsed: { millis: elapsedMs, nodes: rawEdges.length },
1615
+ ...(mincutInfo && { mincut: mincutInfo }),
1616
+ ...(approximation && { implementation: `${approximation} approximation` }),
1585
1617
  ...(depthWarning && { warning: depthWarning }),
1586
1618
  };
1587
1619
  }
@@ -13,9 +13,9 @@
13
13
  * AgentDB index). They do not inline a replay engine; replay
14
14
  * enumerates trajectory steps and returns them for the caller to dispatch.
15
15
  * - ruvector resolution is local-first: if a locally installed `ruvector`
16
- * package is found (the CLI already depends on ruvector@0.2.27), its bin
16
+ * package is found (the CLI depends on ruvector ^0.3.11), its bin
17
17
  * is spawned directly with `node`; otherwise we fall back to
18
- * `npx -y ruvector@0.2.27`. The previous 0.2.25 pin forced cold npx
18
+ * `npx -y ruvector@0.3.12`. The previous 0.2.25 pin forced cold npx
19
19
  * downloads of a *second* ruvector version — 4 per browser session.
20
20
  * - Best-effort: missing dependencies (no `ruvector`, no `agent-browser`,
21
21
  * no AgentDB controller) degrade gracefully with a structured error
@@ -13,9 +13,9 @@
13
13
  * AgentDB index). They do not inline a replay engine; replay
14
14
  * enumerates trajectory steps and returns them for the caller to dispatch.
15
15
  * - ruvector resolution is local-first: if a locally installed `ruvector`
16
- * package is found (the CLI already depends on ruvector@0.2.27), its bin
16
+ * package is found (the CLI depends on ruvector ^0.3.11), its bin
17
17
  * is spawned directly with `node`; otherwise we fall back to
18
- * `npx -y ruvector@0.2.27`. The previous 0.2.25 pin forced cold npx
18
+ * `npx -y ruvector@0.3.12`. The previous 0.2.25 pin forced cold npx
19
19
  * downloads of a *second* ruvector version — 4 per browser session.
20
20
  * - Best-effort: missing dependencies (no `ruvector`, no `agent-browser`,
21
21
  * no AgentDB controller) degrade gracefully with a structured error
@@ -25,9 +25,9 @@ import { validateIdentifier, validateText } from './validate-input.js';
25
25
  import { browserUrlError } from './browser-argv.js';
26
26
  // Pin matches the version in this package's own dependency tree so the npx
27
27
  // fallback never downloads a second ruvector. Subcommand surface verified
28
- // against ruvector@0.2.27 --help: `rvf create/compact/status/derive/segments`
28
+ // against ruvector@0.3.12 --help (and earlier 0.2.27): `rvf create/compact/status/derive/segments`
29
29
  // and `hooks trajectory-begin/step/end` all exist with the flags used below.
30
- const RUVECTOR_PIN = 'ruvector@0.2.27';
30
+ const RUVECTOR_PIN = 'ruvector@0.3.12';
31
31
  const RVF_DIR_DEFAULT = '.ruflo/browser-sessions';
32
32
  async function shell(cmd, args, opts = {}) {
33
33
  const { execFile } = await import('node:child_process');
@@ -0,0 +1,4 @@
1
+ import { type MCPTool } from './types.js';
2
+ export declare const hooksFastApply: MCPTool;
3
+ export declare const fastApplyTools: MCPTool[];
4
+ //# sourceMappingURL=fast-apply-tools.d.ts.map
@@ -0,0 +1,85 @@
1
+ /**
2
+ * hooks_fast-apply — merge a code snippet into a file or string with
3
+ * agent-booster (~ms, no LLM). The caller supplies the target code; for
4
+ * deterministic intents with no snippet use hooks_codemod instead.
5
+ */
6
+ import { existsSync, readFileSync, writeFileSync } from 'fs';
7
+ import { resolve, sep } from 'path';
8
+ import { getProjectCwd } from './types.js';
9
+ import { validatePath } from './validate-input.js';
10
+ import { realpathNearest, isInsideRealRoot } from './realpath-containment.js';
11
+ const MAX_INPUT_BYTES = 1_000_000;
12
+ function langForPath(p) {
13
+ const ext = p.slice(p.lastIndexOf('.') + 1).toLowerCase();
14
+ const map = {
15
+ ts: 'typescript', tsx: 'typescript', mts: 'typescript', cts: 'typescript',
16
+ js: 'javascript', jsx: 'javascript', mjs: 'javascript', cjs: 'javascript',
17
+ py: 'python', rs: 'rust', go: 'go', java: 'java', c: 'c', cpp: 'cpp', h: 'c',
18
+ };
19
+ return map[ext];
20
+ }
21
+ export const hooksFastApply = {
22
+ name: 'hooks_fast-apply',
23
+ description: 'Merge an edit SNIPPET (the rewritten code, e.g. a whole new version of one function) into a file or raw code using agent-booster — a local fast-apply engine (~1-10 ms, no LLM, $0). `edit` must be code, not an instruction: "make add typed" fails, "function add(a: number, b: number): number { return a + b; }" works. Use when you already have the replacement code and the surrounding file is large, instead of re-sending the whole file. Deterministic intents (var-to-const, remove-console, add-logging) belong to hooks_codemod. Returns confidence + strategy; below minConfidence nothing is written.',
24
+ inputSchema: {
25
+ type: 'object',
26
+ properties: {
27
+ edit: { type: 'string', description: 'Target code snippet to merge (code, not an instruction)' },
28
+ file: { type: 'string', description: 'Existing file inside the project to patch in place' },
29
+ code: { type: 'string', description: 'Raw source to patch instead of a file (returns output, writes nothing)' },
30
+ language: { type: 'string', description: 'Language hint (inferred from the file extension when omitted)' },
31
+ minConfidence: { type: 'number', description: 'Minimum merge confidence 0-1 required to apply (default 0.5)' },
32
+ dryRun: { type: 'boolean', description: 'Report the merge result without writing the file' },
33
+ },
34
+ required: ['edit'],
35
+ },
36
+ handler: async (params) => {
37
+ const edit = params.edit;
38
+ if (typeof edit !== 'string' || edit.trim() === '')
39
+ return { success: false, error: 'edit (non-empty code snippet) is required' };
40
+ if (edit.length > MAX_INPUT_BYTES)
41
+ return { success: false, error: 'edit too large' };
42
+ const minConfidence = typeof params.minConfidence === 'number'
43
+ ? Math.min(Math.max(params.minConfidence, 0), 1) : 0.5;
44
+ const dryRun = params.dryRun === true;
45
+ const { fastApply } = await import('../ruvector/fast-apply.js');
46
+ if (typeof params.code === 'string') {
47
+ if (params.code.length > MAX_INPUT_BYTES)
48
+ return { success: false, error: 'code too large' };
49
+ const r = await fastApply({ code: params.code, edit, language: params.language, minConfidence });
50
+ return { ...r, mode: 'code', cost: 0 };
51
+ }
52
+ if (typeof params.file !== 'string')
53
+ return { success: false, error: 'Provide `file` or `code`.' };
54
+ const v = validatePath(params.file, 'file');
55
+ if (!v.valid)
56
+ return { success: false, error: v.error };
57
+ const cwd = getProjectCwd();
58
+ const abs = resolve(cwd, v.sanitized);
59
+ if (abs !== cwd && !abs.startsWith(cwd + sep))
60
+ return { success: false, error: `path escapes project root: ${params.file}` };
61
+ let realRoot;
62
+ try {
63
+ realRoot = realpathNearest(cwd);
64
+ }
65
+ catch (err) {
66
+ return { success: false, error: `cannot resolve project root: ${err.message}` };
67
+ }
68
+ if (!isInsideRealRoot(realRoot, abs))
69
+ return { success: false, error: `path escapes project root via symlink: ${params.file}` };
70
+ if (!existsSync(abs))
71
+ return { success: false, error: `file not found: ${params.file}` };
72
+ const before = readFileSync(abs, 'utf-8');
73
+ if (before.length > MAX_INPUT_BYTES)
74
+ return { success: false, error: 'file too large' };
75
+ const language = params.language ?? langForPath(abs);
76
+ const r = await fastApply({ code: before, edit, language, minConfidence });
77
+ const written = r.success && !dryRun;
78
+ if (written)
79
+ writeFileSync(abs, r.output, 'utf-8');
80
+ const { output, ...meta } = r;
81
+ return { ...meta, mode: dryRun ? 'dry-run' : 'file', file: params.file, written, ...(dryRun && { output }), cost: 0 };
82
+ },
83
+ };
84
+ export const fastApplyTools = [hooksFastApply];
85
+ //# sourceMappingURL=fast-apply-tools.js.map
@@ -5,9 +5,10 @@ import { feedbackPatternsSchema, validateFeedbackPatterns } from '../memory/feed
5
5
  */
6
6
  import { mkdirSync, writeFileSync, existsSync, readFileSync, statSync, unlinkSync, readdirSync } from 'fs';
7
7
  import * as nodeFs from 'fs';
8
- import { basename, dirname, isAbsolute, join, relative, resolve, sep } from 'path';
8
+ import { dirname, join, resolve, sep } from 'path';
9
9
  import { getProjectCwd } from './types.js';
10
10
  import { validateIdentifier, validateText, validatePath } from './validate-input.js';
11
+ import { realpathNearest, isInsideRealRoot } from './realpath-containment.js';
11
12
  import { commandRecordingDisabled, redactCommandForStorage } from '../services/command-recording.js';
12
13
  import { checkCommandLoop, recordCommandOutcome } from './tool-loop-guardrail.js';
13
14
  import { buildLearnedRoutingPatterns, } from '../services/learned-routing.js';
@@ -2223,8 +2224,24 @@ export const hooksBuildAgents = {
2223
2224
  return { success: false, error: v.error };
2224
2225
  }
2225
2226
  const outputDir = resolve(getProjectCwd(), params.outputDir || './agents');
2227
+ // validatePath allows absolute paths, so keep the real output dir inside
2228
+ // the real project root (CWE-22/59): configs are only ever project files.
2229
+ let realProjectRoot;
2230
+ try {
2231
+ realProjectRoot = nodeFs.realpathSync(getProjectCwd());
2232
+ }
2233
+ catch {
2234
+ realProjectRoot = getProjectCwd();
2235
+ }
2236
+ if (!isInsideRealRoot(realProjectRoot, outputDir)) {
2237
+ return { success: false, error: 'outputDir must be inside the project directory' };
2238
+ }
2226
2239
  const focus = params.focus || 'all';
2227
- const format = params.format || 'yaml';
2240
+ // format is spliced into each file name; only the two supported formats.
2241
+ const format = params.format === undefined ? 'yaml' : params.format;
2242
+ if (format !== 'yaml' && format !== 'json') {
2243
+ return { success: false, error: 'format must be "yaml" or "json"' };
2244
+ }
2228
2245
  const persist = params.persist !== false; // Default to true
2229
2246
  const agents = [
2230
2247
  { type: 'coder', configFile: join(outputDir, `coder.${format}`), capabilities: ['code-generation', 'refactoring', 'debugging'], optimizations: ['flash-attention', 'token-reduction'] },
@@ -5126,38 +5143,6 @@ function codemodLangForExt(abs) {
5126
5143
  return 'javascript';
5127
5144
  return 'typescript';
5128
5145
  }
5129
- // Canonicalize a path that may not exist yet: realpath the nearest existing
5130
- // ancestor and re-attach the missing tail, so a symlinked parent still
5131
- // resolves to its real location (mirrors @claude-flow/security's
5132
- // canonicalizeSync, which is not exported).
5133
- function realpathNearest(p) {
5134
- try {
5135
- return nodeFs.realpathSync(p);
5136
- }
5137
- catch (err) {
5138
- if (err?.code !== 'ENOENT')
5139
- throw err;
5140
- }
5141
- const parent = dirname(p);
5142
- if (parent === p)
5143
- return p;
5144
- return join(realpathNearest(parent), basename(p));
5145
- }
5146
- // CWE-59 (#4346): containment must compare real paths on BOTH sides — a
5147
- // symlink inside the project pointing outside it must not pass, and a
5148
- // symlinked project root (e.g. macOS /var -> /private/var) must not make
5149
- // every path fail. Fails closed if canonicalization throws (ELOOP, EACCES).
5150
- function isInsideRealRoot(realRoot, abs) {
5151
- let real;
5152
- try {
5153
- real = realpathNearest(abs);
5154
- }
5155
- catch {
5156
- return false;
5157
- }
5158
- const rel = relative(realRoot, real);
5159
- return rel === '' || (rel !== '..' && !rel.startsWith('..' + sep) && !isAbsolute(rel));
5160
- }
5161
5146
  // Deterministic codemod execution — the real Tier-1 path (ADR-143)
5162
5147
  export const hooksCodemod = {
5163
5148
  name: 'hooks_codemod',
@@ -399,7 +399,7 @@ export const metaharnessTools = [
399
399
  },
400
400
  // ───────────────────────────────────────────────────────────────────────
401
401
  // ADR-153 — @metaharness/darwin integration (3 tools).
402
- // Backed by the separate `@metaharness/darwin@~0.12.0` npm package, NOT
402
+ // Backed by the separate `@metaharness/darwin@~0.13.0` npm package, NOT
403
403
  // the umbrella `metaharness`. Plugin scripts shell out via _darwin.mjs.
404
404
  // Same {success, data, degraded, exitCode} contract.
405
405
  // ───────────────────────────────────────────────────────────────────────
@@ -72,7 +72,7 @@ function activeChampionParams() {
72
72
  // command, because mcp-client statically imports this module. ensureEmbeddings()
73
73
  // keeps the exact same tier chain and degraded/fallback semantics, but only
74
74
  // pays the cost when a handler actually needs an embedding.
75
- // Tier 0 (ADR-089): ruvector@0.2.27 bundled ONNX (no sharp dep, fixes ADR-086's
75
+ // Tier 0 (ADR-089): ruvector bundled ONNX (since 0.2.27) (no sharp dep, fixes ADR-086's
76
76
  // silent-fallback bug at source; closes the chain described in ruvnet/ruvector#523).
77
77
  // Tier 1: agentic-flow v3 ReasoningBank (was Tier 1 — broken on darwin-arm64 without sharp)
78
78
  // Tier 2-3: @claude-flow/embeddings
@@ -110,7 +110,7 @@ function ensureEmbeddings() {
110
110
  }
111
111
  }
112
112
  catch { /* not configured — fall through */ }
113
- // Tier 0: ruvector@0.2.27 — bundled all-MiniLM-L6-v2 + parallel worker pool.
113
+ // Tier 0: ruvector (CLI dependency) — bundled all-MiniLM-L6-v2 + parallel worker pool.
114
114
  // Probe with isOnnxAvailable() and verify an actual embed succeeds (avoids
115
115
  // the type-load-success-but-runtime-fails trap from ADR-086). The probe now
116
116
  // runs on first embed request instead of at import time.
@@ -133,7 +133,7 @@ function ensureEmbeddings() {
133
133
  return Array.isArray(v) ? v : Array.from(v);
134
134
  },
135
135
  };
136
- embeddingServiceName = 'ruvector@0.2.27 (bundled all-MiniLM-L6-v2)';
136
+ embeddingServiceName = 'ruvector (bundled all-MiniLM-L6-v2)';
137
137
  }
138
138
  }
139
139
  catch {
@@ -0,0 +1,3 @@
1
+ export declare function realpathNearest(p: string): string;
2
+ export declare function isInsideRealRoot(realRoot: string, abs: string): boolean;
3
+ //# sourceMappingURL=realpath-containment.d.ts.map
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Project-root containment for MCP tools that read or write files.
3
+ * Shared by hooks_codemod and hooks_fast-apply (moved out of hooks-tools.ts).
4
+ */
5
+ import * as nodeFs from 'fs';
6
+ import { basename, dirname, isAbsolute, join, relative, sep } from 'path';
7
+ // Canonicalize a path that may not exist yet: realpath the nearest existing
8
+ // ancestor and re-attach the missing tail, so a symlinked parent still
9
+ // resolves to its real location (mirrors @claude-flow/security's
10
+ // canonicalizeSync, which is not exported).
11
+ export function realpathNearest(p) {
12
+ try {
13
+ return nodeFs.realpathSync(p);
14
+ }
15
+ catch (err) {
16
+ if (err?.code !== 'ENOENT')
17
+ throw err;
18
+ }
19
+ const parent = dirname(p);
20
+ if (parent === p)
21
+ return p;
22
+ return join(realpathNearest(parent), basename(p));
23
+ }
24
+ // CWE-59 (#4346): containment must compare real paths on BOTH sides — a
25
+ // symlink inside the project pointing outside it must not pass, and a
26
+ // symlinked project root (e.g. macOS /var -> /private/var) must not make
27
+ // every path fail. Fails closed if canonicalization throws (ELOOP, EACCES).
28
+ export function isInsideRealRoot(realRoot, abs) {
29
+ let real;
30
+ try {
31
+ real = realpathNearest(abs);
32
+ }
33
+ catch {
34
+ return false;
35
+ }
36
+ const rel = relative(realRoot, real);
37
+ return rel === '' || (rel !== '..' && !rel.startsWith('..' + sep) && !isAbsolute(rel));
38
+ }
39
+ //# sourceMappingURL=realpath-containment.js.map
@@ -192,8 +192,8 @@ export declare const inventorySourceSchema: z.ZodObject<{
192
192
  }, "strict", z.ZodTypeAny, {
193
193
  digest: string;
194
194
  sourcePath: string;
195
- channel: "repo-project-commands" | "cli-init-template" | "marketplace-plugin" | "source-plugin" | "mod-registration";
196
195
  package: string;
196
+ channel: "repo-project-commands" | "cli-init-template" | "marketplace-plugin" | "source-plugin" | "mod-registration";
197
197
  observedInvocation: string;
198
198
  binding: "markdown-loader" | "mod-register" | "mod-middleware-on-markdown";
199
199
  shippedIn: string[];
@@ -201,8 +201,8 @@ export declare const inventorySourceSchema: z.ZodObject<{
201
201
  }, {
202
202
  digest: string;
203
203
  sourcePath: string;
204
- channel: "repo-project-commands" | "cli-init-template" | "marketplace-plugin" | "source-plugin" | "mod-registration";
205
204
  package: string;
205
+ channel: "repo-project-commands" | "cli-init-template" | "marketplace-plugin" | "source-plugin" | "mod-registration";
206
206
  observedInvocation: string;
207
207
  binding: "markdown-loader" | "mod-register" | "mod-middleware-on-markdown";
208
208
  shippedIn: string[];
@@ -370,8 +370,8 @@ export declare const catalogEntrySchema: z.ZodObject<{
370
370
  }, "strict", z.ZodTypeAny, {
371
371
  digest: string;
372
372
  sourcePath: string;
373
- channel: "repo-project-commands" | "cli-init-template" | "marketplace-plugin" | "source-plugin" | "mod-registration";
374
373
  package: string;
374
+ channel: "repo-project-commands" | "cli-init-template" | "marketplace-plugin" | "source-plugin" | "mod-registration";
375
375
  observedInvocation: string;
376
376
  binding: "markdown-loader" | "mod-register" | "mod-middleware-on-markdown";
377
377
  shippedIn: string[];
@@ -379,8 +379,8 @@ export declare const catalogEntrySchema: z.ZodObject<{
379
379
  }, {
380
380
  digest: string;
381
381
  sourcePath: string;
382
- channel: "repo-project-commands" | "cli-init-template" | "marketplace-plugin" | "source-plugin" | "mod-registration";
383
382
  package: string;
383
+ channel: "repo-project-commands" | "cli-init-template" | "marketplace-plugin" | "source-plugin" | "mod-registration";
384
384
  observedInvocation: string;
385
385
  binding: "markdown-loader" | "mod-register" | "mod-middleware-on-markdown";
386
386
  shippedIn: string[];
@@ -391,8 +391,8 @@ export declare const catalogEntrySchema: z.ZodObject<{
391
391
  sources: {
392
392
  digest: string;
393
393
  sourcePath: string;
394
- channel: "repo-project-commands" | "cli-init-template" | "marketplace-plugin" | "source-plugin" | "mod-registration";
395
394
  package: string;
395
+ channel: "repo-project-commands" | "cli-init-template" | "marketplace-plugin" | "source-plugin" | "mod-registration";
396
396
  observedInvocation: string;
397
397
  binding: "markdown-loader" | "mod-register" | "mod-middleware-on-markdown";
398
398
  shippedIn: string[];
@@ -432,8 +432,8 @@ export declare const catalogEntrySchema: z.ZodObject<{
432
432
  sources: {
433
433
  digest: string;
434
434
  sourcePath: string;
435
- channel: "repo-project-commands" | "cli-init-template" | "marketplace-plugin" | "source-plugin" | "mod-registration";
436
435
  package: string;
436
+ channel: "repo-project-commands" | "cli-init-template" | "marketplace-plugin" | "source-plugin" | "mod-registration";
437
437
  observedInvocation: string;
438
438
  binding: "markdown-loader" | "mod-register" | "mod-middleware-on-markdown";
439
439
  shippedIn: string[];
@@ -636,8 +636,8 @@ export declare const commandCatalogSchema: z.ZodObject<{
636
636
  }, "strict", z.ZodTypeAny, {
637
637
  digest: string;
638
638
  sourcePath: string;
639
- channel: "repo-project-commands" | "cli-init-template" | "marketplace-plugin" | "source-plugin" | "mod-registration";
640
639
  package: string;
640
+ channel: "repo-project-commands" | "cli-init-template" | "marketplace-plugin" | "source-plugin" | "mod-registration";
641
641
  observedInvocation: string;
642
642
  binding: "markdown-loader" | "mod-register" | "mod-middleware-on-markdown";
643
643
  shippedIn: string[];
@@ -645,8 +645,8 @@ export declare const commandCatalogSchema: z.ZodObject<{
645
645
  }, {
646
646
  digest: string;
647
647
  sourcePath: string;
648
- channel: "repo-project-commands" | "cli-init-template" | "marketplace-plugin" | "source-plugin" | "mod-registration";
649
648
  package: string;
649
+ channel: "repo-project-commands" | "cli-init-template" | "marketplace-plugin" | "source-plugin" | "mod-registration";
650
650
  observedInvocation: string;
651
651
  binding: "markdown-loader" | "mod-register" | "mod-middleware-on-markdown";
652
652
  shippedIn: string[];
@@ -657,8 +657,8 @@ export declare const commandCatalogSchema: z.ZodObject<{
657
657
  sources: {
658
658
  digest: string;
659
659
  sourcePath: string;
660
- channel: "repo-project-commands" | "cli-init-template" | "marketplace-plugin" | "source-plugin" | "mod-registration";
661
660
  package: string;
661
+ channel: "repo-project-commands" | "cli-init-template" | "marketplace-plugin" | "source-plugin" | "mod-registration";
662
662
  observedInvocation: string;
663
663
  binding: "markdown-loader" | "mod-register" | "mod-middleware-on-markdown";
664
664
  shippedIn: string[];
@@ -698,8 +698,8 @@ export declare const commandCatalogSchema: z.ZodObject<{
698
698
  sources: {
699
699
  digest: string;
700
700
  sourcePath: string;
701
- channel: "repo-project-commands" | "cli-init-template" | "marketplace-plugin" | "source-plugin" | "mod-registration";
702
701
  package: string;
702
+ channel: "repo-project-commands" | "cli-init-template" | "marketplace-plugin" | "source-plugin" | "mod-registration";
703
703
  observedInvocation: string;
704
704
  binding: "markdown-loader" | "mod-register" | "mod-middleware-on-markdown";
705
705
  shippedIn: string[];
@@ -741,8 +741,8 @@ export declare const commandCatalogSchema: z.ZodObject<{
741
741
  sources: {
742
742
  digest: string;
743
743
  sourcePath: string;
744
- channel: "repo-project-commands" | "cli-init-template" | "marketplace-plugin" | "source-plugin" | "mod-registration";
745
744
  package: string;
745
+ channel: "repo-project-commands" | "cli-init-template" | "marketplace-plugin" | "source-plugin" | "mod-registration";
746
746
  observedInvocation: string;
747
747
  binding: "markdown-loader" | "mod-register" | "mod-middleware-on-markdown";
748
748
  shippedIn: string[];
@@ -787,8 +787,8 @@ export declare const commandCatalogSchema: z.ZodObject<{
787
787
  sources: {
788
788
  digest: string;
789
789
  sourcePath: string;
790
- channel: "repo-project-commands" | "cli-init-template" | "marketplace-plugin" | "source-plugin" | "mod-registration";
791
790
  package: string;
791
+ channel: "repo-project-commands" | "cli-init-template" | "marketplace-plugin" | "source-plugin" | "mod-registration";
792
792
  observedInvocation: string;
793
793
  binding: "markdown-loader" | "mod-register" | "mod-middleware-on-markdown";
794
794
  shippedIn: string[];
@@ -40,8 +40,7 @@ export interface ASTAnalysis {
40
40
  }
41
41
  export declare class ASTAnalyzer {
42
42
  private config;
43
- private ruvectorEngine;
44
- private useNative;
43
+ private readonly useNative;
45
44
  private analysisCache;
46
45
  constructor(config?: Partial<ASTAnalyzerConfig>);
47
46
  initialize(): Promise<void>;
@@ -22,24 +22,16 @@ const LANGUAGE_PATTERNS = {
22
22
  };
23
23
  export class ASTAnalyzer {
24
24
  config;
25
- ruvectorEngine = null;
26
25
  useNative = false;
27
26
  analysisCache = new Map();
28
27
  constructor(config = {}) {
29
28
  this.config = { ...DEFAULT_CONFIG, ...config };
30
29
  }
31
30
  async initialize() {
32
- try {
33
- // @ruvector/ast is optional - gracefully fallback if not installed
34
- const ruvector = await import('@ruvector/ast').catch(() => null);
35
- if (ruvector) {
36
- this.ruvectorEngine = ruvector.createASTAnalyzer?.(this.config);
37
- this.useNative = !!this.ruvectorEngine;
38
- }
39
- }
40
- catch {
41
- this.useNative = false;
42
- }
31
+ // Pure-JS analysis. This used to try `import('@ruvector/ast')`, a package that has
32
+ // never been published (npm 404), so it always fell through to here. ruvector@0.3's
33
+ // ASTParser needs the native tree-sitter grammars and is async-only, so it cannot
34
+ // back this synchronous analyzer.
43
35
  }
44
36
  analyze(code, filePath = 'unknown') {
45
37
  const startTime = performance.now();
@@ -63,8 +63,7 @@ export interface CoverageRouteResult {
63
63
  }
64
64
  export declare class CoverageRouter {
65
65
  private config;
66
- private ruvectorEngine;
67
- private useNative;
66
+ private readonly useNative;
68
67
  private coverageHistory;
69
68
  constructor(config?: Partial<CoverageRouterConfig>);
70
69
  initialize(): Promise<void>;
@@ -37,24 +37,16 @@ const DEFAULT_CONFIG = {
37
37
  };
38
38
  export class CoverageRouter {
39
39
  config;
40
- ruvectorEngine = null;
41
40
  useNative = false;
42
41
  coverageHistory = [];
43
42
  constructor(config = {}) {
44
43
  this.config = { ...DEFAULT_CONFIG, ...config };
45
44
  }
46
45
  async initialize() {
47
- try {
48
- // @ruvector/coverage is optional - gracefully fallback if not installed
49
- const ruvector = await import('@ruvector/coverage').catch(() => null);
50
- if (ruvector) {
51
- this.ruvectorEngine = ruvector.createCoverageRouter?.(this.config);
52
- this.useNative = !!this.ruvectorEngine;
53
- }
54
- }
55
- catch {
56
- this.useNative = false;
57
- }
46
+ // Pure-JS analysis. This used to try `import('@ruvector/coverage')`, a package that
47
+ // has never been published (npm 404), so it always fell through to here.
48
+ // ruvector@0.3's parseIstanbulCoverage is a plain-JS parser equivalent to the parsers
49
+ // below.
58
50
  }
59
51
  parseCoverage(data, format = 'json') {
60
52
  switch (format) {
@@ -49,8 +49,7 @@ export interface DiffAnalysis {
49
49
  }
50
50
  export declare class DiffClassifier {
51
51
  private config;
52
- private ruvectorEngine;
53
- private useNative;
52
+ private readonly useNative;
54
53
  private classificationCache;
55
54
  constructor(config?: Partial<DiffClassifierConfig>);
56
55
  initialize(): Promise<void>;
@@ -60,24 +60,15 @@ function isSecuritySensitivePath(path) {
60
60
  }
61
61
  export class DiffClassifier {
62
62
  config;
63
- ruvectorEngine = null;
64
63
  useNative = false;
65
64
  classificationCache = new Map();
66
65
  constructor(config = {}) {
67
66
  this.config = { ...DEFAULT_CONFIG, ...config };
68
67
  }
69
68
  async initialize() {
70
- try {
71
- // @ruvector/diff is optional - gracefully fallback if not installed
72
- const ruvector = await import('@ruvector/diff').catch(() => null);
73
- if (ruvector) {
74
- this.ruvectorEngine = ruvector.createDiffClassifier?.(this.config);
75
- this.useNative = !!this.ruvectorEngine;
76
- }
77
- }
78
- catch {
79
- this.useNative = false;
80
- }
69
+ // Pure-JS analysis. This used to try `import('@ruvector/diff')`, a package that has
70
+ // never been published (npm 404), so it always fell through to here. ruvector@0.3's
71
+ // parseDiff is a plain-JS parser equivalent to parseDiff() below.
81
72
  }
82
73
  parseDiff(diffContent) {
83
74
  const files = [];
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Fast-apply: merge an edit snippet into existing code with agent-booster.
3
+ *
4
+ * agent-booster is a Morph/Cursor-style *applier*: `apply({ code, edit })`
5
+ * expects `edit` to be the target code (e.g. the rewritten function), and it
6
+ * locates and splices it into `code` in a few milliseconds with no LLM call.
7
+ * It cannot turn a natural-language instruction into an edit — given one it
8
+ * returns `success: false, strategy: "failed"` (see ADR-143). So this is the
9
+ * path for callers that already hold a snippet (an agent's proposed rewrite),
10
+ * not a Tier-1 intent engine; deterministic intents stay in hooks_codemod.
11
+ */
12
+ export interface FastApplyRequest {
13
+ code: string;
14
+ edit: string;
15
+ language?: string;
16
+ /** Results below this confidence are reported as not applied. Default 0.5. */
17
+ minConfidence?: number;
18
+ }
19
+ export interface FastApplyResult {
20
+ success: boolean;
21
+ output: string;
22
+ confidence: number;
23
+ strategy: string;
24
+ latencyMs: number;
25
+ backend: 'agent-booster' | 'unavailable';
26
+ reason?: string;
27
+ }
28
+ interface BoosterLike {
29
+ apply(req: {
30
+ code: string;
31
+ edit: string;
32
+ language?: string;
33
+ }): Promise<{
34
+ output: string;
35
+ success: boolean;
36
+ confidence: number;
37
+ strategy: string;
38
+ }>;
39
+ }
40
+ /** Lazily construct one AgentBooster. Resolves null when it is not installed. */
41
+ export declare function loadAgentBooster(): Promise<BoosterLike | null>;
42
+ /** Test hook: forget the memoised AgentBooster. */
43
+ export declare function resetAgentBoosterLoader(): void;
44
+ export declare function fastApply(req: FastApplyRequest): Promise<FastApplyResult>;
45
+ export {};
46
+ //# sourceMappingURL=fast-apply.d.ts.map