@claude-flow/cli 3.10.10 → 3.10.12

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 (44) hide show
  1. package/dist/src/commands/hooks.d.ts.map +1 -1
  2. package/dist/src/commands/hooks.js +10 -8
  3. package/dist/src/commands/hooks.js.map +1 -1
  4. package/dist/src/commands/mcp.d.ts.map +1 -1
  5. package/dist/src/commands/mcp.js +14 -0
  6. package/dist/src/commands/mcp.js.map +1 -1
  7. package/dist/src/init/settings-generator.js +1 -1
  8. package/dist/src/init/statusline-generator.js +2 -2
  9. package/dist/src/mcp-tools/agent-execute-core.d.ts +2 -2
  10. package/dist/src/mcp-tools/agent-execute-core.d.ts.map +1 -1
  11. package/dist/src/mcp-tools/agent-execute-core.js +8 -5
  12. package/dist/src/mcp-tools/agent-execute-core.js.map +1 -1
  13. package/dist/src/mcp-tools/agent-tools.js +14 -14
  14. package/dist/src/mcp-tools/agent-tools.js.map +1 -1
  15. package/dist/src/mcp-tools/hooks-tools.d.ts +1 -0
  16. package/dist/src/mcp-tools/hooks-tools.d.ts.map +1 -1
  17. package/dist/src/mcp-tools/hooks-tools.js +176 -7
  18. package/dist/src/mcp-tools/hooks-tools.js.map +1 -1
  19. package/dist/src/mcp-tools/system-tools.d.ts.map +1 -1
  20. package/dist/src/mcp-tools/system-tools.js +5 -2
  21. package/dist/src/mcp-tools/system-tools.js.map +1 -1
  22. package/dist/src/runtime/parent-death-watchdog.d.ts +42 -0
  23. package/dist/src/runtime/parent-death-watchdog.d.ts.map +1 -0
  24. package/dist/src/runtime/parent-death-watchdog.js +70 -0
  25. package/dist/src/runtime/parent-death-watchdog.js.map +1 -0
  26. package/dist/src/ruvector/codemods/engine.d.ts +45 -0
  27. package/dist/src/ruvector/codemods/engine.d.ts.map +1 -0
  28. package/dist/src/ruvector/codemods/engine.js +291 -0
  29. package/dist/src/ruvector/codemods/engine.js.map +1 -0
  30. package/dist/src/ruvector/codemods/scope-analysis.d.ts +29 -0
  31. package/dist/src/ruvector/codemods/scope-analysis.d.ts.map +1 -0
  32. package/dist/src/ruvector/codemods/scope-analysis.js +162 -0
  33. package/dist/src/ruvector/codemods/scope-analysis.js.map +1 -0
  34. package/dist/src/ruvector/enhanced-model-router.d.ts +29 -8
  35. package/dist/src/ruvector/enhanced-model-router.d.ts.map +1 -1
  36. package/dist/src/ruvector/enhanced-model-router.js +104 -81
  37. package/dist/src/ruvector/enhanced-model-router.js.map +1 -1
  38. package/dist/src/ruvector/q-learning-router.d.ts +14 -1
  39. package/dist/src/ruvector/q-learning-router.d.ts.map +1 -1
  40. package/dist/src/ruvector/q-learning-router.js +36 -8
  41. package/dist/src/ruvector/q-learning-router.js.map +1 -1
  42. package/dist/tsconfig.tsbuildinfo +1 -1
  43. package/package.json +2 -2
  44. package/scripts/benchmark-codemods.mjs +127 -0
@@ -3,6 +3,7 @@
3
3
  * Provides intelligent hooks functionality via MCP protocol
4
4
  */
5
5
  import { mkdirSync, writeFileSync, existsSync, readFileSync, statSync, unlinkSync, readdirSync } from 'fs';
6
+ import * as nodeFs from 'fs';
6
7
  import { dirname, join, resolve } from 'path';
7
8
  import { getProjectCwd } from './types.js';
8
9
  import { validateIdentifier, validateText, validatePath } from './validate-input.js';
@@ -793,7 +794,7 @@ export const hooksPostCommand = {
793
794
  };
794
795
  export const hooksRoute = {
795
796
  name: 'hooks_route',
796
- description: 'Get a 3-tier routing recommendation for a task: Tier 1 (Agent Booster, 0ms / $0 — for var-to-const, add-types, etc.), Tier 2 (Haiku — simple), Tier 3 (Sonnet/Opus — complex). Use this BEFORE spawning an agent to avoid sending simple transforms to Sonnet. Native tools have no equivalent — Claude Code does not introspect its own model-selection cost. Returns the recommended model + a `[AGENT_BOOSTER_AVAILABLE]` literal when the WASM bypass applies. Use when native Bash hooks (via Claude Code\'s settings.json) are wrong because you need Ruflo-side state — pattern persistence, neural training signals, model-routing learning, cost tracking, audit chain. For one-off shell commands, plain Bash hooks are fine.',
797
+ description: 'Get a 3-tier routing recommendation for a task: Tier 1 (deterministic codemod, ~0ms / $0 — for var-to-const, remove-console, add-logging), Tier 2 (Haiku — simple), Tier 3 (Sonnet/Opus — complex). Use this BEFORE spawning an agent to avoid sending simple transforms to Sonnet. Native tools have no equivalent — Claude Code does not introspect its own model-selection cost. Returns the recommended model + a `[CODEMOD_AVAILABLE]` literal when a deterministic codemod can fully apply the edit (then call hooks_codemod). Use when native Bash hooks (via Claude Code\'s settings.json) are wrong because you need Ruflo-side state — pattern persistence, neural training signals, model-routing learning, cost tracking, audit chain. For one-off shell commands, plain Bash hooks are fine.',
797
798
  inputSchema: {
798
799
  type: 'object',
799
800
  properties: {
@@ -1118,24 +1119,26 @@ export const hooksPreTask = {
1118
1119
  : descLower.includes('simple') || descLower.includes('fix') || description.length < 50
1119
1120
  ? 'low'
1120
1121
  : 'medium';
1121
- // Enhanced model routing with Agent Booster AST (ADR-026)
1122
+ // Enhanced model routing with deterministic Tier-1 codemods (ADR-026, ADR-143)
1122
1123
  let modelRouting;
1123
1124
  try {
1124
1125
  const { getEnhancedModelRouter } = await import('../ruvector/enhanced-model-router.js');
1125
1126
  const router = getEnhancedModelRouter();
1126
1127
  const routeResult = await router.route(description, { filePath });
1127
1128
  if (routeResult.tier === 1) {
1128
- // Agent Booster can handle this task
1129
+ // Deterministic codemod can apply this edit with $0 / no LLM (ADR-143)
1130
+ const intentType = routeResult.codemodIntent?.type ?? routeResult.agentBoosterIntent?.type;
1129
1131
  modelRouting = {
1130
1132
  tier: 1,
1131
- handler: 'agent-booster',
1133
+ handler: 'codemod',
1132
1134
  canSkipLLM: true,
1133
- agentBoosterIntent: routeResult.agentBoosterIntent?.type,
1134
- intentDescription: routeResult.agentBoosterIntent?.description,
1135
+ deterministic: true,
1136
+ codemodIntent: intentType,
1137
+ intentDescription: routeResult.codemodIntent?.description ?? routeResult.agentBoosterIntent?.description,
1135
1138
  confidence: routeResult.confidence,
1136
1139
  estimatedLatencyMs: routeResult.estimatedLatencyMs,
1137
1140
  estimatedCost: routeResult.estimatedCost,
1138
- recommendation: `[AGENT_BOOSTER_AVAILABLE] Skip LLM - use Agent Booster for "${routeResult.agentBoosterIntent?.type}"`,
1141
+ recommendation: `[CODEMOD_AVAILABLE] Skip LLM call hooks_codemod with intent="${intentType}" (deterministic, $0)`,
1139
1142
  };
1140
1143
  }
1141
1144
  else {
@@ -3896,6 +3899,170 @@ export const hooksModelStats = {
3896
3899
  };
3897
3900
  },
3898
3901
  };
3902
+ // Supported source extensions for codemods.
3903
+ const CODEMOD_EXTENSIONS = new Set(['.js', '.jsx', '.ts', '.tsx', '.mjs', '.cjs', '.mts', '.cts']);
3904
+ const CODEMOD_MAX_FILES = 2000;
3905
+ function codemodLangForExt(abs) {
3906
+ const ext = abs.slice(abs.lastIndexOf('.')).toLowerCase();
3907
+ if (ext === '.tsx')
3908
+ return 'tsx';
3909
+ if (ext === '.jsx')
3910
+ return 'jsx';
3911
+ if (ext === '.js' || ext === '.mjs' || ext === '.cjs')
3912
+ return 'javascript';
3913
+ return 'typescript';
3914
+ }
3915
+ // Deterministic codemod execution — the real Tier-1 path (ADR-143)
3916
+ export const hooksCodemod = {
3917
+ name: 'hooks_codemod',
3918
+ description: 'Apply a deterministic, $0 (no-LLM) code transform — the real Tier-1 execution path (ADR-143). Supported intents: var-to-const, remove-console, add-logging. Uses the TypeScript compiler with formatting-preserving edits (comments/whitespace survive). Targets: raw `code` (returns transformed text, writes nothing) | a single `file` | a `files` array | a `glob` pattern (batch — applies the intent across every match in one $0 call). Files are rewritten in place unless `dryRun`. Intents that need reasoning — add-types, add-error-handling, async-await — are NOT supported here; route those to a model via hooks_model-route. Use when hooks_pre-task / hooks_route returned [CODEMOD_AVAILABLE].',
3919
+ inputSchema: {
3920
+ type: 'object',
3921
+ properties: {
3922
+ intent: { type: 'string', enum: ['var-to-const', 'remove-console', 'add-logging'], description: 'Deterministic codemod to apply' },
3923
+ file: { type: 'string', description: 'Path to a single existing source file to transform in place' },
3924
+ files: { type: 'array', items: { type: 'string' }, description: 'Multiple file paths to transform in one batch call' },
3925
+ glob: { type: 'string', description: 'Glob pattern (relative to project root, e.g. "src/**/*.ts") — applies the intent to every matching source file' },
3926
+ code: { type: 'string', description: 'Raw source to transform instead of files (returns transformed code, writes nothing)' },
3927
+ language: { type: 'string', enum: ['javascript', 'typescript', 'jsx', 'tsx'], description: 'Language hint for raw code (default typescript; inferred from extension for files)' },
3928
+ dryRun: { type: 'boolean', description: 'Report what would change without writing files' },
3929
+ },
3930
+ required: ['intent'],
3931
+ },
3932
+ handler: async (params) => {
3933
+ const intent = params.intent;
3934
+ const file = params.file;
3935
+ const files = Array.isArray(params.files) ? params.files : undefined;
3936
+ const glob = params.glob;
3937
+ const rawCode = params.code;
3938
+ const dryRun = params.dryRun === true;
3939
+ const langParam = params.language;
3940
+ const { applyCodemod, isDeterministicCodemod } = await import('../ruvector/codemods/engine.js');
3941
+ if (!isDeterministicCodemod(intent)) {
3942
+ return {
3943
+ success: false,
3944
+ error: `"${intent}" is not a deterministic codemod. Route it to a model via hooks_model-route (Tier 2/3).`,
3945
+ };
3946
+ }
3947
+ // Mode A: transform raw code (never touches disk)
3948
+ if (typeof rawCode === 'string') {
3949
+ const language = langParam ?? 'typescript';
3950
+ const r = applyCodemod(intent, rawCode, { language });
3951
+ return {
3952
+ success: r.success, intent, mode: 'code', changed: r.changed, edits: r.edits,
3953
+ output: r.output, language: r.language, reason: r.reason, cost: 0, tier: 1,
3954
+ };
3955
+ }
3956
+ const cwd = getProjectCwd();
3957
+ // Resolve the target file set (single / array / glob), with path containment.
3958
+ const resolveTargets = () => {
3959
+ const out = new Set();
3960
+ const addRaw = (p) => {
3961
+ const v = validatePath(p, 'path');
3962
+ if (!v.valid)
3963
+ return v.error;
3964
+ const abs = resolve(cwd, v.sanitized);
3965
+ if (!abs.startsWith(cwd))
3966
+ return `path escapes project root: ${p}`;
3967
+ out.add(abs);
3968
+ return undefined;
3969
+ };
3970
+ if (file) {
3971
+ const e = addRaw(file);
3972
+ if (e)
3973
+ return { abs: [], truncated: false, error: e };
3974
+ }
3975
+ if (files)
3976
+ for (const p of files) {
3977
+ const e = addRaw(p);
3978
+ if (e)
3979
+ return { abs: [], truncated: false, error: e };
3980
+ }
3981
+ if (glob) {
3982
+ if (glob.includes('..'))
3983
+ return { abs: [], truncated: false, error: 'glob must not contain ".."' };
3984
+ // fs.globSync is Node 22+; @types/node here predates it, so type it locally.
3985
+ const globSync = nodeFs.globSync;
3986
+ if (typeof globSync !== 'function') {
3987
+ return { abs: [], truncated: false, error: 'glob requires Node 22+ (fs.globSync unavailable); pass `files[]` instead' };
3988
+ }
3989
+ let matches = [];
3990
+ try {
3991
+ matches = globSync(glob, { cwd });
3992
+ }
3993
+ catch (err) {
3994
+ return { abs: [], truncated: false, error: `glob failed: ${err.message}` };
3995
+ }
3996
+ for (const m of matches) {
3997
+ const abs = resolve(cwd, m);
3998
+ if (abs.startsWith(cwd) && CODEMOD_EXTENSIONS.has(abs.slice(abs.lastIndexOf('.')).toLowerCase())) {
3999
+ out.add(abs);
4000
+ }
4001
+ }
4002
+ }
4003
+ const all = [...out];
4004
+ const truncated = all.length > CODEMOD_MAX_FILES;
4005
+ return { abs: truncated ? all.slice(0, CODEMOD_MAX_FILES) : all, truncated };
4006
+ };
4007
+ const targets = resolveTargets();
4008
+ if (targets.error)
4009
+ return { success: false, error: targets.error };
4010
+ if (targets.abs.length === 0) {
4011
+ return { success: false, error: 'No target files. Provide `code`, `file`, `files[]`, or a matching `glob`.' };
4012
+ }
4013
+ // Apply to each file.
4014
+ const results = [];
4015
+ let filesChanged = 0, totalEdits = 0, failures = 0, skipped = 0;
4016
+ for (const abs of targets.abs) {
4017
+ const rel = abs.startsWith(cwd) ? abs.slice(cwd.length).replace(/^[/\\]/, '') : abs;
4018
+ if (!existsSync(abs)) {
4019
+ results.push({ file: rel, success: false, reason: 'not found' });
4020
+ failures++;
4021
+ continue;
4022
+ }
4023
+ if (!CODEMOD_EXTENSIONS.has(abs.slice(abs.lastIndexOf('.')).toLowerCase())) {
4024
+ results.push({ file: rel, success: false, reason: 'unsupported extension' });
4025
+ skipped++;
4026
+ continue;
4027
+ }
4028
+ const before = readFileSync(abs, 'utf-8');
4029
+ const r = applyCodemod(intent, before, { language: codemodLangForExt(abs) });
4030
+ if (!r.success) {
4031
+ results.push({ file: rel, success: false, changed: false, reason: r.reason });
4032
+ failures++;
4033
+ continue;
4034
+ }
4035
+ const written = r.changed && !dryRun;
4036
+ if (written)
4037
+ writeFileSync(abs, r.output, 'utf-8');
4038
+ if (r.changed) {
4039
+ filesChanged++;
4040
+ totalEdits += r.edits;
4041
+ }
4042
+ results.push({ file: rel, success: true, changed: r.changed, edits: r.edits, written });
4043
+ }
4044
+ const single = targets.abs.length === 1 && !files && !glob;
4045
+ return {
4046
+ success: failures === 0,
4047
+ intent,
4048
+ mode: single ? (dryRun ? 'dry-run' : 'file') : (dryRun ? 'batch-dry-run' : 'batch'),
4049
+ summary: {
4050
+ filesScanned: targets.abs.length,
4051
+ filesChanged,
4052
+ filesUnchanged: targets.abs.length - filesChanged - failures - skipped,
4053
+ totalEdits,
4054
+ failures,
4055
+ skipped,
4056
+ truncatedAt: targets.truncated ? CODEMOD_MAX_FILES : undefined,
4057
+ },
4058
+ results: results.slice(0, 500),
4059
+ resultsTruncated: results.length > 500,
4060
+ cost: 0,
4061
+ tier: 1,
4062
+ timestamp: new Date().toISOString(),
4063
+ };
4064
+ },
4065
+ };
3899
4066
  // Simple fallback complexity analyzer
3900
4067
  function analyzeComplexityFallback(task) {
3901
4068
  const taskLower = task.toLowerCase();
@@ -4053,6 +4220,8 @@ export const hooksTools = [
4053
4220
  hooksModelRoute,
4054
4221
  hooksModelOutcome,
4055
4222
  hooksModelStats,
4223
+ // Deterministic Tier-1 codemod execution (ADR-143)
4224
+ hooksCodemod,
4056
4225
  ];
4057
4226
  export default hooksTools;
4058
4227
  //# sourceMappingURL=hooks-tools.js.map