@claude-flow/cli 3.72.1 → 3.73.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/helpers/helpers.manifest.json +2 -2
- package/README.md +29 -21
- package/catalog-manifest.json +2 -2
- package/dist/src/commands/agent.js +2 -0
- package/dist/src/commands/funnel.d.ts +1 -0
- package/dist/src/commands/funnel.js +37 -2
- package/dist/src/commands/hooks.js +16 -2
- package/dist/src/commands/init.js +70 -16
- package/dist/src/commands/mcp.js +15 -0
- package/dist/src/commands/neural.js +5 -3
- package/dist/src/commands/swarm.js +2 -0
- package/dist/src/funnel/activation.d.ts +30 -0
- package/dist/src/funnel/activation.js +69 -0
- package/dist/src/funnel/events.js +4 -1
- package/dist/src/funnel/index.d.ts +2 -1
- package/dist/src/funnel/index.js +2 -1
- package/dist/src/funnel/message-transport.d.ts +12 -0
- package/dist/src/funnel/message-transport.js +23 -1
- package/dist/src/funnel/types.d.ts +2 -2
- package/dist/src/init/first-win.d.ts +24 -0
- package/dist/src/init/first-win.js +97 -0
- package/dist/src/mcp-tools/agent-tools.js +2 -0
- package/dist/src/mcp-tools/browser-session-tools.d.ts +2 -2
- package/dist/src/mcp-tools/browser-session-tools.js +4 -4
- package/dist/src/mcp-tools/hooks-tools.js +17 -1
- package/dist/src/mcp-tools/neural-tools.js +3 -3
- package/dist/src/mcp-tools/swarm-tools.js +2 -0
- package/dist/src/missions/schemas.d.ts +117 -117
- package/dist/src/mods/command-registry/schema.d.ts +121 -121
- package/dist/src/transfer/store/download.d.ts +1 -1
- package/dist/src/transfer/store/download.js +22 -21
- package/dist/src/transfer/store/publish.d.ts +1 -1
- package/dist/src/transfer/store/publish.js +13 -14
- 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/node_modules/@claude-flow/plugin-agent-federation/package.json +5 -5
- package/node_modules/@claude-flow/security/dist/input-validator.d.ts +6 -6
- package/package.json +7 -7
- package/plugins/ruflo-console/dist/tui.mjs +153 -153
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The concrete result `ruflo init` ends with (adoption plan item 1): a quick,
|
|
3
|
+
* local snapshot of the user's own project, plus one prompt to paste into
|
|
4
|
+
* Claude Code. Replaces a list of commands with something about *their* repo.
|
|
5
|
+
*
|
|
6
|
+
* Local only: `git` with argument arrays (no shell), a hard timeout per call,
|
|
7
|
+
* no network. Any failure returns null and init prints nothing extra.
|
|
8
|
+
*/
|
|
9
|
+
export interface ProjectSnapshot {
|
|
10
|
+
files: number;
|
|
11
|
+
languages: string[];
|
|
12
|
+
hotFile?: {
|
|
13
|
+
path: string;
|
|
14
|
+
changes: number;
|
|
15
|
+
};
|
|
16
|
+
testCommand?: string;
|
|
17
|
+
}
|
|
18
|
+
/** Snapshot of the project at `cwd`, or null when it is not a git repo with code. */
|
|
19
|
+
export declare function snapshotProject(cwd: string, timeoutMs?: number): ProjectSnapshot | null;
|
|
20
|
+
/** The one prompt to paste into Claude Code, specific to this project. */
|
|
21
|
+
export declare function firstPrompt(s: ProjectSnapshot | null): string;
|
|
22
|
+
/** Lines for init's closing summary. Empty when there is nothing useful to say. */
|
|
23
|
+
export declare function snapshotLines(s: ProjectSnapshot | null): string[];
|
|
24
|
+
//# sourceMappingURL=first-win.d.ts.map
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The concrete result `ruflo init` ends with (adoption plan item 1): a quick,
|
|
3
|
+
* local snapshot of the user's own project, plus one prompt to paste into
|
|
4
|
+
* Claude Code. Replaces a list of commands with something about *their* repo.
|
|
5
|
+
*
|
|
6
|
+
* Local only: `git` with argument arrays (no shell), a hard timeout per call,
|
|
7
|
+
* no network. Any failure returns null and init prints nothing extra.
|
|
8
|
+
*/
|
|
9
|
+
import { spawnSync } from 'node:child_process';
|
|
10
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
11
|
+
import { extname, join } from 'node:path';
|
|
12
|
+
const LANGUAGE = {
|
|
13
|
+
'.ts': 'TypeScript', '.tsx': 'TypeScript', '.js': 'JavaScript', '.jsx': 'JavaScript', '.mjs': 'JavaScript', '.cjs': 'JavaScript',
|
|
14
|
+
'.py': 'Python', '.rs': 'Rust', '.go': 'Go', '.java': 'Java', '.kt': 'Kotlin', '.rb': 'Ruby', '.php': 'PHP',
|
|
15
|
+
'.cs': 'C#', '.cpp': 'C++', '.cc': 'C++', '.c': 'C', '.h': 'C', '.swift': 'Swift', '.scala': 'Scala',
|
|
16
|
+
'.vue': 'Vue', '.svelte': 'Svelte', '.dart': 'Dart', '.ex': 'Elixir', '.exs': 'Elixir', '.lua': 'Lua',
|
|
17
|
+
};
|
|
18
|
+
// Files a "riskiest module" suggestion should never point at.
|
|
19
|
+
const NOT_CODE = /(^|\/)(package-lock\.json|pnpm-lock\.yaml|yarn\.lock|Cargo\.lock|go\.sum|CHANGELOG[^/]*|README[^/]*|\.github\/|\.claude\/|\.claude-flow\/|dist\/|build\/|node_modules\/)/i;
|
|
20
|
+
function git(cwd, args, timeoutMs) {
|
|
21
|
+
const r = spawnSync('git', args, { cwd, encoding: 'utf8', timeout: timeoutMs, maxBuffer: 16 * 1024 * 1024, stdio: ['ignore', 'pipe', 'ignore'] });
|
|
22
|
+
return r.status === 0 && typeof r.stdout === 'string' ? r.stdout : null;
|
|
23
|
+
}
|
|
24
|
+
function testCommandFor(cwd) {
|
|
25
|
+
try {
|
|
26
|
+
const pkg = JSON.parse(readFileSync(join(cwd, 'package.json'), 'utf8'));
|
|
27
|
+
const t = pkg.scripts?.test;
|
|
28
|
+
if (t && !/no test specified/i.test(t))
|
|
29
|
+
return 'npm test';
|
|
30
|
+
}
|
|
31
|
+
catch { /* not a node project */ }
|
|
32
|
+
if (existsSync(join(cwd, 'Cargo.toml')))
|
|
33
|
+
return 'cargo test';
|
|
34
|
+
if (existsSync(join(cwd, 'go.mod')))
|
|
35
|
+
return 'go test ./...';
|
|
36
|
+
if (existsSync(join(cwd, 'pyproject.toml')) || existsSync(join(cwd, 'pytest.ini')))
|
|
37
|
+
return 'pytest';
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
/** Snapshot of the project at `cwd`, or null when it is not a git repo with code. */
|
|
41
|
+
export function snapshotProject(cwd, timeoutMs = 2000) {
|
|
42
|
+
try {
|
|
43
|
+
const listed = git(cwd, ['ls-files', '-z'], timeoutMs);
|
|
44
|
+
if (!listed)
|
|
45
|
+
return null;
|
|
46
|
+
const files = listed.split('\0').filter(Boolean);
|
|
47
|
+
if (files.length === 0)
|
|
48
|
+
return null;
|
|
49
|
+
const counts = new Map();
|
|
50
|
+
for (const f of files) {
|
|
51
|
+
const lang = LANGUAGE[extname(f).toLowerCase()];
|
|
52
|
+
if (lang)
|
|
53
|
+
counts.set(lang, (counts.get(lang) ?? 0) + 1);
|
|
54
|
+
}
|
|
55
|
+
const languages = [...counts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 3).map(([l]) => l);
|
|
56
|
+
// Most-changed code file in the last 90 days (bounded to 500 commits).
|
|
57
|
+
let hotFile;
|
|
58
|
+
const log = git(cwd, ['log', '--since=90.days', '--max-count=500', '--name-only', '--pretty=format:'], timeoutMs);
|
|
59
|
+
if (log) {
|
|
60
|
+
const tracked = new Set(files);
|
|
61
|
+
const churn = new Map();
|
|
62
|
+
for (const line of log.split('\n')) {
|
|
63
|
+
const p = line.trim();
|
|
64
|
+
if (!p || NOT_CODE.test(p) || !tracked.has(p) || !LANGUAGE[extname(p).toLowerCase()])
|
|
65
|
+
continue;
|
|
66
|
+
churn.set(p, (churn.get(p) ?? 0) + 1);
|
|
67
|
+
}
|
|
68
|
+
const top = [...churn.entries()].sort((a, b) => b[1] - a[1])[0];
|
|
69
|
+
if (top && top[1] >= 2)
|
|
70
|
+
hotFile = { path: top[0], changes: top[1] };
|
|
71
|
+
}
|
|
72
|
+
return { files: files.length, languages, hotFile, testCommand: testCommandFor(cwd) };
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/** The one prompt to paste into Claude Code, specific to this project. */
|
|
79
|
+
export function firstPrompt(s) {
|
|
80
|
+
if (s?.hotFile) {
|
|
81
|
+
const verify = s.testCommand ? ` and run \`${s.testCommand}\` to prove it` : '';
|
|
82
|
+
return `Use a ruflo swarm to review ${s.hotFile.path} (the most-changed file here): find the riskiest logic, add tests for it${verify}, and summarise what you changed.`;
|
|
83
|
+
}
|
|
84
|
+
return 'Use a ruflo swarm to review this repo: find the riskiest module, write tests for it, and summarise what you changed.';
|
|
85
|
+
}
|
|
86
|
+
/** Lines for init's closing summary. Empty when there is nothing useful to say. */
|
|
87
|
+
export function snapshotLines(s) {
|
|
88
|
+
if (!s)
|
|
89
|
+
return [];
|
|
90
|
+
const lines = [`${s.files.toLocaleString('en-US')} tracked file${s.files === 1 ? '' : 's'}${s.languages.length ? ` · ${s.languages.join(', ')}` : ''}`];
|
|
91
|
+
if (s.hotFile)
|
|
92
|
+
lines.push(`Most-changed file (90 days): ${s.hotFile.path} (${s.hotFile.changes} commits)`);
|
|
93
|
+
if (s.testCommand)
|
|
94
|
+
lines.push(`Tests: ${s.testCommand}`);
|
|
95
|
+
return lines;
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=first-win.js.map
|
|
@@ -12,6 +12,7 @@ import { validateIdentifier, validateText, validateAgentSpawn } from './validate
|
|
|
12
12
|
import { executeAgentTask } from './agent-execute-core.js';
|
|
13
13
|
import { AGENT_HEALTH_WINDOW, summarizeAgentExecutions } from './agent-health-metrics.js';
|
|
14
14
|
import { pheromoneAgentEligibility } from './swarm-tools.js';
|
|
15
|
+
import { noteFirstAgentRun } from '../funnel/activation.js';
|
|
15
16
|
// Storage paths
|
|
16
17
|
const STORAGE_DIR = '.claude-flow';
|
|
17
18
|
const AGENT_DIR = 'agents';
|
|
@@ -425,6 +426,7 @@ export const agentTools = [
|
|
|
425
426
|
catch { /* COW branch is best-effort; agent already registered */ }
|
|
426
427
|
}
|
|
427
428
|
// Include deterministic codemod routing info if applicable
|
|
429
|
+
noteFirstAgentRun('cli'); // activation funnel (opt-in; no-op without telemetry consent)
|
|
428
430
|
const response = {
|
|
429
431
|
success: true,
|
|
430
432
|
agentId,
|
|
@@ -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
|
|
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.
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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');
|
|
@@ -2224,8 +2224,24 @@ export const hooksBuildAgents = {
|
|
|
2224
2224
|
return { success: false, error: v.error };
|
|
2225
2225
|
}
|
|
2226
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
|
+
}
|
|
2227
2239
|
const focus = params.focus || 'all';
|
|
2228
|
-
|
|
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
|
+
}
|
|
2229
2245
|
const persist = params.persist !== false; // Default to true
|
|
2230
2246
|
const agents = [
|
|
2231
2247
|
{ type: 'coder', configFile: join(outputDir, `coder.${format}`), capabilities: ['code-generation', 'refactoring', 'debugging'], optimizations: ['flash-attention', 'token-reduction'] },
|
|
@@ -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
|
|
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
|
|
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
|
|
136
|
+
embeddingServiceName = 'ruvector (bundled all-MiniLM-L6-v2)';
|
|
137
137
|
}
|
|
138
138
|
}
|
|
139
139
|
catch {
|
|
@@ -9,6 +9,7 @@ import { join } from 'node:path';
|
|
|
9
9
|
import { nullPrototypeRecords, readPreservedJsonStore } from './record-store.js';
|
|
10
10
|
import { getProjectCwd } from './types.js';
|
|
11
11
|
import { validateIdentifier } from './validate-input.js';
|
|
12
|
+
import { noteFirstAgentRun } from '../funnel/activation.js';
|
|
12
13
|
import { createApscState, isApscAgentEligible, normalizeApscConfig, recordApscSignal, } from '../services/pheromone-adaptive.js';
|
|
13
14
|
// Swarm state persistence
|
|
14
15
|
const SWARM_DIR = '.claude-flow/swarm';
|
|
@@ -283,6 +284,7 @@ export const swarmTools = [
|
|
|
283
284
|
const store = loadSwarmStore();
|
|
284
285
|
store.swarms[swarmId] = swarmState;
|
|
285
286
|
saveSwarmStore(store);
|
|
287
|
+
noteFirstAgentRun('cli'); // activation funnel (opt-in; no-op without telemetry consent)
|
|
286
288
|
return {
|
|
287
289
|
success: true,
|
|
288
290
|
swarmId,
|