claude-flow 3.58.1 → 3.59.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.
Files changed (57) hide show
  1. package/.claude/proven-config.json +1 -1
  2. package/README.md +2 -0
  3. package/node_modules/@claude-flow/codex/dist/cli.js +0 -0
  4. package/node_modules/@claude-flow/plugin-agent-federation/dist/bin.js +0 -0
  5. package/package.json +2 -1
  6. package/v3/@claude-flow/cli/README.md +62 -174
  7. package/v3/@claude-flow/cli/bin/cli.js +19 -1
  8. package/v3/@claude-flow/cli/catalog-manifest.json +5 -5
  9. package/v3/@claude-flow/cli/dist/src/commands/harness.d.ts +40 -0
  10. package/v3/@claude-flow/cli/dist/src/commands/harness.js +142 -0
  11. package/v3/@claude-flow/cli/dist/src/commands/index.js +1 -0
  12. package/v3/@claude-flow/cli/dist/src/commands/init.js +116 -0
  13. package/v3/@claude-flow/cli/dist/src/commands/memory.js +6 -1
  14. package/v3/@claude-flow/cli/dist/src/commands/status.js +2 -2
  15. package/v3/@claude-flow/cli/dist/src/index.d.ts +3 -0
  16. package/v3/@claude-flow/cli/dist/src/index.js +12 -2
  17. package/v3/@claude-flow/cli/dist/src/init/grok-generator.d.ts +96 -0
  18. package/v3/@claude-flow/cli/dist/src/init/grok-generator.js +371 -0
  19. package/v3/@claude-flow/cli/dist/src/init/grok-templates.d.ts +11 -0
  20. package/v3/@claude-flow/cli/dist/src/init/grok-templates.js +28 -0
  21. package/v3/@claude-flow/cli/dist/src/init/index.d.ts +2 -0
  22. package/v3/@claude-flow/cli/dist/src/init/index.js +2 -0
  23. package/v3/@claude-flow/cli/dist/src/mcp-client.js +4 -0
  24. package/v3/@claude-flow/cli/dist/src/mcp-tools/agent-execute-core.js +59 -12
  25. package/v3/@claude-flow/cli/dist/src/mcp-tools/capability-brain.d.ts +1 -1
  26. package/v3/@claude-flow/cli/dist/src/mcp-tools/capability-brain.js +5 -3
  27. package/v3/@claude-flow/cli/dist/src/mcp-tools/embeddings-tools.js +11 -4
  28. package/v3/@claude-flow/cli/dist/src/mcp-tools/index.d.ts +1 -0
  29. package/v3/@claude-flow/cli/dist/src/mcp-tools/index.js +2 -0
  30. package/v3/@claude-flow/cli/dist/src/mcp-tools/memory-tools.js +42 -4
  31. package/v3/@claude-flow/cli/dist/src/mcp-tools/task-tools.js +7 -3
  32. package/v3/@claude-flow/cli/dist/src/mcp-tools/team-tools.d.ts +15 -0
  33. package/v3/@claude-flow/cli/dist/src/mcp-tools/team-tools.js +244 -0
  34. package/v3/@claude-flow/cli/dist/src/memory/memory-bridge.d.ts +19 -0
  35. package/v3/@claude-flow/cli/dist/src/memory/memory-bridge.js +163 -3
  36. package/v3/@claude-flow/cli/dist/src/memory/memory-initializer.d.ts +4 -0
  37. package/v3/@claude-flow/cli/dist/src/memory/memory-initializer.js +70 -37
  38. package/v3/@claude-flow/cli/dist/src/memory/rabitq-index.d.ts +19 -0
  39. package/v3/@claude-flow/cli/dist/src/memory/rabitq-index.js +117 -1
  40. package/v3/@claude-flow/cli/dist/src/missions/schemas.d.ts +113 -113
  41. package/v3/@claude-flow/cli/dist/src/mods/command-registry/schema.d.ts +193 -193
  42. package/v3/@claude-flow/cli/dist/src/services/live-harness.d.ts +111 -0
  43. package/v3/@claude-flow/cli/dist/src/services/live-harness.js +427 -0
  44. package/v3/@claude-flow/cli/package.json +4 -3
  45. package/v3/@claude-flow/cli/templates/grok/agents/ruflo-architect.md +35 -0
  46. package/v3/@claude-flow/cli/templates/grok/agents/ruflo-coder.md +34 -0
  47. package/v3/@claude-flow/cli/templates/grok/agents/ruflo-reviewer.md +30 -0
  48. package/v3/@claude-flow/cli/templates/grok/agents/ruflo-tester.md +26 -0
  49. package/v3/@claude-flow/cli/templates/grok/config.toml +63 -0
  50. package/v3/@claude-flow/cli/templates/grok/docs/README.md +186 -0
  51. package/v3/@claude-flow/cli/templates/grok/hooks/subagent-stop-team.json +15 -0
  52. package/v3/@claude-flow/cli/templates/grok/rules/ruflo-grok.md +132 -0
  53. package/v3/@claude-flow/cli/templates/grok/scripts/grok-subagent-stop-hook.mjs +90 -0
  54. package/v3/@claude-flow/cli/templates/grok/scripts/grok-team-bus.mjs +525 -0
  55. package/v3/@claude-flow/cli/templates/grok/scripts/grok-team-store.mjs +287 -0
  56. package/v3/@claude-flow/cli/templates/grok/scripts/host-statusline.mjs +281 -0
  57. package/v3/@claude-flow/cli/templates/grok/skills/agent-teams-grok/SKILL.md +98 -0
@@ -0,0 +1,371 @@
1
+ /**
2
+ * Grok Build host init (ADR-402).
3
+ *
4
+ * Mirrors `init --codex`: writes project-scoped `.grok/` surface + team bus scripts
5
+ * so any repo can run Ruflo Agent Teams under Grok without Claude SendMessage.
6
+ *
7
+ * Writes outside the project only with `statusLine: true` (`--grok-statusline`):
8
+ * the status row lives in the user's ~/.grok/config.toml, which is parsed and
9
+ * merged with a real TOML parser, never blindly appended to.
10
+ */
11
+ import * as fs from 'node:fs';
12
+ import * as os from 'node:os';
13
+ import * as path from 'node:path';
14
+ import * as TOML from '@iarna/toml';
15
+ import { grokPackageRoot, grokTemplatesRoot } from './grok-templates.js';
16
+ export { grokTemplatesRoot };
17
+ function packageVersion(root) {
18
+ try {
19
+ return JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf-8')).version || '0.0.0';
20
+ }
21
+ catch {
22
+ return '0.0.0';
23
+ }
24
+ }
25
+ /**
26
+ * How the project .grok/config.toml starts the Ruflo MCP server.
27
+ *
28
+ * The team_* tools ship in the same release as `init --grok`, so the server is
29
+ * pinned to the version that is running this init — never `@latest`, which can
30
+ * be an older release without them. Running from a source checkout (not under
31
+ * node_modules) points at that checkout's CLI, since its version may not be
32
+ * published yet.
33
+ */
34
+ export function rufloMcpLaunch(root = grokPackageRoot()) {
35
+ const version = packageVersion(root);
36
+ const published = root.split(path.sep).includes('node_modules');
37
+ if (!published) {
38
+ return {
39
+ command: 'node',
40
+ args: [path.join(root, 'bin', 'cli.js'), 'mcp', 'start'],
41
+ source: 'checkout',
42
+ version,
43
+ };
44
+ }
45
+ const npxArgs = ['-y', `ruflo@${version}`, 'mcp', 'start'];
46
+ return process.platform === 'win32'
47
+ ? { command: 'cmd', args: ['/c', 'npx', ...npxArgs], source: 'published', version }
48
+ : { command: 'npx', args: npxArgs, source: 'published', version };
49
+ }
50
+ /** A TOML basic string. JSON escaping is a valid subset (\\, \", \uXXXX). */
51
+ function tomlString(value) {
52
+ return JSON.stringify(value);
53
+ }
54
+ /**
55
+ * Fill the template placeholders. Every inserted value is escaped as a TOML
56
+ * string, so a Windows path such as C:\Users\x stays valid TOML.
57
+ */
58
+ export function materializeGrokConfig(template, launch, home) {
59
+ const homeInString = tomlString(home.replace(/[\\/]+$/, '')).slice(1, -1);
60
+ return template
61
+ .replaceAll('{{RUFLO_MCP_COMMAND}}', tomlString(launch.command))
62
+ .replaceAll('{{RUFLO_MCP_ARGS}}', `[${launch.args.map(tomlString).join(', ')}]`)
63
+ .replaceAll('{{HOME}}/', `${homeInString}/`);
64
+ }
65
+ // ---------------------------------------------------------------------------
66
+ // User-level status row (~/.grok/config.toml [ui.status_line])
67
+ // ---------------------------------------------------------------------------
68
+ /** Where the opt-in status row script is installed: a stable absolute path. */
69
+ export function grokStatusScriptPath(home) {
70
+ return path.join(home, '.grok', 'ruflo', 'host-statusline.mjs');
71
+ }
72
+ /** `node "<abs path>"` — no shell builtins, and never a repo-relative script. */
73
+ export function grokStatusLineCommand(home) {
74
+ return `node "${grokStatusScriptPath(home)}"`;
75
+ }
76
+ export function grokStatusLineSnippet(home) {
77
+ return TOML.stringify({
78
+ ui: { status_line: { type: 'command', command: grokStatusLineCommand(home) } },
79
+ });
80
+ }
81
+ function stableJson(value) {
82
+ return JSON.stringify(value, (_k, v) => v && typeof v === 'object' && !Array.isArray(v) && !(v instanceof Date)
83
+ ? Object.fromEntries(Object.keys(v).sort().map((k) => [k, v[k]]))
84
+ : v);
85
+ }
86
+ function statusLineOf(doc) {
87
+ const ui = doc.ui;
88
+ return ui && typeof ui === 'object' && !Array.isArray(ui) ? ui.status_line : undefined;
89
+ }
90
+ /**
91
+ * Add the status row to an existing user config without disturbing it.
92
+ *
93
+ * Any existing `ui.status_line` — header, `[ ui.status_line ]`,
94
+ * `[ui."status_line"]`, dotted keys, or an inline table — is detected by
95
+ * parsing, and left alone. Otherwise the block is appended and the result is
96
+ * re-parsed: it is written only if it parses, carries exactly our status row,
97
+ * and every other value is unchanged. Anything else (unparseable file, `ui`
98
+ * as an inline table, …) falls back to printing the snippet.
99
+ */
100
+ export function mergeGrokStatusLine(existing, home) {
101
+ let before;
102
+ try {
103
+ before = TOML.parse(existing);
104
+ }
105
+ catch (e) {
106
+ return { kind: 'unsafe', reason: `could not parse it as TOML (${e.message.split('\n')[0]})` };
107
+ }
108
+ const current = statusLineOf(before);
109
+ if (current !== undefined) {
110
+ const command = current && typeof current === 'object' ? current.command : undefined;
111
+ return { kind: 'already-set', ours: command === grokStatusLineCommand(home) };
112
+ }
113
+ const sep = existing.length === 0 || existing.endsWith('\n') ? '' : '\n';
114
+ const text = `${existing}${sep}\n# Ruflo loaded-status row (added by ruflo init --grok --grok-statusline)\n${grokStatusLineSnippet(home)}`;
115
+ let after;
116
+ try {
117
+ after = TOML.parse(text);
118
+ }
119
+ catch (e) {
120
+ return { kind: 'unsafe', reason: `appending [ui.status_line] would not parse (${e.message.split('\n')[0]})` };
121
+ }
122
+ const added = statusLineOf(after);
123
+ if (!added || added.type !== 'command' || added.command !== grokStatusLineCommand(home)) {
124
+ return { kind: 'unsafe', reason: 'the merged file did not contain the expected status row' };
125
+ }
126
+ const ui = after.ui;
127
+ delete ui.status_line;
128
+ if (before.ui === undefined && Object.keys(ui).length === 0)
129
+ delete after.ui;
130
+ if (stableJson(after) !== stableJson(before)) {
131
+ return { kind: 'unsafe', reason: 'the merge would change other settings' };
132
+ }
133
+ return { kind: 'write', text };
134
+ }
135
+ /**
136
+ * If `file` is a symlink, resolve it to what it actually points at. A rename
137
+ * onto a symlink path replaces the symlink itself with a plain file — in a
138
+ * dotfiles-managed setup where `~/.grok/config.toml` is a symlink, that
139
+ * silently destroys the symlink instead of updating the file it points to
140
+ * (ADR-402 round-2 review, minor item 1). A broken symlink (target missing)
141
+ * falls back to writing `file` itself, same as a plain non-existent path.
142
+ */
143
+ function resolveWriteTarget(file) {
144
+ try {
145
+ if (fs.lstatSync(file).isSymbolicLink()) {
146
+ return fs.realpathSync(file);
147
+ }
148
+ }
149
+ catch {
150
+ /* missing, unreadable, or a broken symlink target: write `file` itself */
151
+ }
152
+ return file;
153
+ }
154
+ function writeFileAtomic(file, text, mode) {
155
+ const target = resolveWriteTarget(file);
156
+ fs.mkdirSync(path.dirname(target), { recursive: true });
157
+ const tmp = `${target}.${process.pid}.${Date.now()}.tmp`;
158
+ fs.writeFileSync(tmp, text, { encoding: 'utf-8', mode: mode ?? 0o600 });
159
+ fs.renameSync(tmp, target);
160
+ }
161
+ function wireGrokUserStatusLine(home, dryRun, created, errors) {
162
+ const dest = path.join(home, '.grok', 'config.toml');
163
+ const snippet = grokStatusLineSnippet(home);
164
+ const script = grokStatusScriptPath(home);
165
+ const result = (action, reason) => ({
166
+ action,
167
+ path: dest,
168
+ snippet,
169
+ reason,
170
+ });
171
+ let existing = null;
172
+ try {
173
+ existing = fs.existsSync(dest) ? fs.readFileSync(dest, 'utf-8') : null;
174
+ }
175
+ catch (e) {
176
+ return result('snippet', `could not read ${dest}: ${e.message}`);
177
+ }
178
+ const outcome = existing === null
179
+ ? { kind: 'write', text: `# Ruflo loaded-status row (added by ruflo init --grok --grok-statusline)\n${snippet}` }
180
+ : mergeGrokStatusLine(existing, home);
181
+ if (outcome.kind === 'unsafe')
182
+ return result('snippet', `${dest}: ${outcome.reason}`);
183
+ if (outcome.kind === 'already-set' && !outcome.ours) {
184
+ return result('already-set', `${dest} already has its own [ui.status_line]; left it and did not install the Ruflo script`);
185
+ }
186
+ // Ours, or about to be ours: install/refresh the script it runs.
187
+ const needsConfig = outcome.kind === 'write';
188
+ if (dryRun) {
189
+ created.push(script);
190
+ if (needsConfig)
191
+ created.push(dest);
192
+ return result(needsConfig ? 'would-write' : 'already-set');
193
+ }
194
+ try {
195
+ const src = path.join(grokTemplatesRoot(), 'scripts', 'host-statusline.mjs');
196
+ writeFileAtomic(script, fs.readFileSync(src, 'utf-8'), 0o755);
197
+ created.push(script);
198
+ if (!needsConfig)
199
+ return result('already-set');
200
+ writeFileAtomic(dest, outcome.text);
201
+ created.push(dest);
202
+ return result(existing === null ? 'created' : 'merged');
203
+ }
204
+ catch (e) {
205
+ errors.push(`${dest}: ${e.message}`);
206
+ return result('snippet', e.message);
207
+ }
208
+ }
209
+ /** First `object.key` (or `[index]`) path to a BigInt value, or null. */
210
+ function findBigIntKeyPath(value, path = []) {
211
+ if (typeof value === 'bigint')
212
+ return path.length ? path.join('.') : '(root)';
213
+ if (Array.isArray(value)) {
214
+ for (let i = 0; i < value.length; i++) {
215
+ const found = findBigIntKeyPath(value[i], [...path, `[${i}]`]);
216
+ if (found)
217
+ return found;
218
+ }
219
+ return null;
220
+ }
221
+ if (value && typeof value === 'object' && !(value instanceof Date)) {
222
+ for (const [k, v] of Object.entries(value)) {
223
+ const found = findBigIntKeyPath(v, [...path, k]);
224
+ if (found)
225
+ return found;
226
+ }
227
+ }
228
+ return null;
229
+ }
230
+ /**
231
+ * Whether an existing `~/.grok/config.toml` can be safely parsed and
232
+ * serialized before init touches anything. A TOML integer literal above
233
+ * 2^53 parses to a BigInt (@iarna/toml), and `JSON.stringify` — used by
234
+ * `mergeGrokStatusLine`'s stableJson comparison — throws "Do not know how
235
+ * to serialize a BigInt" on it. That merge used to run as the LAST step of
236
+ * `executeGrokInit`, so the crash left project files already written and
237
+ * nothing to show for the failure. Checked here, first, so init either
238
+ * fully succeeds or writes nothing at all (ADR-402 round-2 review, minor
239
+ * item 2). Returns a user-facing error message naming the offending key,
240
+ * or null if the file is fine (or absent, or already unparseable as
241
+ * TOML — mergeGrokStatusLine reports that case on its own, safely).
242
+ */
243
+ function validateExistingUserConfig(dest) {
244
+ let existing;
245
+ try {
246
+ if (!fs.existsSync(dest))
247
+ return null;
248
+ existing = fs.readFileSync(dest, 'utf-8');
249
+ }
250
+ catch (e) {
251
+ return `could not read ${dest}: ${e.message}`;
252
+ }
253
+ let doc;
254
+ try {
255
+ doc = TOML.parse(existing);
256
+ }
257
+ catch {
258
+ return null;
259
+ }
260
+ // An existing status row is left as-is, so nothing in this file is
261
+ // serialized. A BigInt elsewhere must not fail init in that case
262
+ // (ADR-402 round-3 review). The status step reports already-set.
263
+ if (statusLineOf(doc) !== undefined)
264
+ return null;
265
+ try {
266
+ JSON.stringify(doc);
267
+ }
268
+ catch (e) {
269
+ const offending = findBigIntKeyPath(doc);
270
+ const where = offending ? ` at "${offending}"` : '';
271
+ return `${dest} has a value ruflo cannot serialize${where} (${e.message}) — fix or remove it before running init --grok --grok-statusline again`;
272
+ }
273
+ return null;
274
+ }
275
+ function writeProjectFile(ctx, dest, write) {
276
+ try {
277
+ if (fs.existsSync(dest) && !ctx.force) {
278
+ ctx.skipped.push(dest);
279
+ return;
280
+ }
281
+ if (!ctx.dryRun) {
282
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
283
+ write();
284
+ }
285
+ ctx.created.push(dest);
286
+ }
287
+ catch (e) {
288
+ ctx.errors.push(`${dest}: ${e.message}`);
289
+ }
290
+ }
291
+ function copyFile(ctx, src, dest) {
292
+ writeProjectFile(ctx, dest, () => {
293
+ fs.copyFileSync(src, dest);
294
+ fs.chmodSync(dest, fs.statSync(src).mode);
295
+ });
296
+ }
297
+ function walkCopy(ctx, srcDir, destDir) {
298
+ if (!fs.existsSync(srcDir)) {
299
+ ctx.errors.push(`Template directory missing: ${srcDir}`);
300
+ return;
301
+ }
302
+ for (const ent of fs.readdirSync(srcDir, { withFileTypes: true })) {
303
+ const src = path.join(srcDir, ent.name);
304
+ const dest = path.join(destDir, ent.name);
305
+ if (ent.isDirectory())
306
+ walkCopy(ctx, src, dest);
307
+ else
308
+ copyFile(ctx, src, dest);
309
+ }
310
+ }
311
+ /**
312
+ * Initialize Grok host surface in targetDir.
313
+ */
314
+ export function executeGrokInit(options) {
315
+ const { targetDir, force = false, docs = true, statusLine = false, dryRun = false } = options;
316
+ const home = options.homeDir || os.homedir();
317
+ const ctx = { force, dryRun, created: [], skipped: [], errors: [] };
318
+ const tpl = grokTemplatesRoot();
319
+ const mcp = rufloMcpLaunch();
320
+ const userConfig = {
321
+ action: 'not-requested',
322
+ path: path.join(home, '.grok', 'config.toml'),
323
+ snippet: grokStatusLineSnippet(home),
324
+ };
325
+ const done = () => ({
326
+ success: ctx.errors.length === 0,
327
+ dryRun,
328
+ filesCreated: ctx.created,
329
+ filesSkipped: ctx.skipped,
330
+ errors: ctx.errors,
331
+ mcp,
332
+ userConfig,
333
+ });
334
+ if (!fs.existsSync(path.join(tpl, 'config.toml'))) {
335
+ ctx.errors.push(`Grok templates not found at ${tpl}. Reinstall @claude-flow/cli or run from a monorepo checkout that includes templates/grok.`);
336
+ return done();
337
+ }
338
+ // Validate any existing user-level config before writing a single project
339
+ // file — see validateExistingUserConfig for why (BigInt/serialization
340
+ // failures must not leave a half-initialized project).
341
+ if (statusLine) {
342
+ const problem = validateExistingUserConfig(userConfig.path);
343
+ if (problem) {
344
+ ctx.errors.push(problem);
345
+ return done();
346
+ }
347
+ }
348
+ // .grok/config.toml — placeholders filled, then checked with a TOML parser
349
+ const config = materializeGrokConfig(fs.readFileSync(path.join(tpl, 'config.toml'), 'utf-8'), mcp, home);
350
+ try {
351
+ TOML.parse(config);
352
+ }
353
+ catch (e) {
354
+ ctx.errors.push(`.grok/config.toml would not be valid TOML: ${e.message.split('\n')[0]}`);
355
+ return done();
356
+ }
357
+ writeProjectFile(ctx, path.join(targetDir, '.grok', 'config.toml'), () => fs.writeFileSync(path.join(targetDir, '.grok', 'config.toml'), config, 'utf-8'));
358
+ for (const dir of ['rules', 'agents', 'hooks', 'skills']) {
359
+ walkCopy(ctx, path.join(tpl, dir), path.join(targetDir, '.grok', dir));
360
+ }
361
+ // scripts/ team bus (project-local CLI + SubagentStop adapter + status row)
362
+ walkCopy(ctx, path.join(tpl, 'scripts'), path.join(targetDir, 'scripts'));
363
+ if (docs) {
364
+ walkCopy(ctx, path.join(tpl, 'docs'), path.join(targetDir, 'docs', 'grok'));
365
+ }
366
+ if (statusLine) {
367
+ Object.assign(userConfig, wireGrokUserStatusLine(home, dryRun, ctx.created, ctx.errors));
368
+ }
369
+ return done();
370
+ }
371
+ //# sourceMappingURL=grok-generator.js.map
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Where the Grok host templates live (ADR-402).
3
+ *
4
+ * Kept apart from grok-generator.ts so the team_* MCP tools can find the team
5
+ * bus scripts without loading the TOML parser on every MCP client import.
6
+ */
7
+ /** Root of the installed @claude-flow/cli package (the one holding templates/grok). */
8
+ export declare function grokPackageRoot(): string;
9
+ /** templates/grok inside the installed @claude-flow/cli package. */
10
+ export declare function grokTemplatesRoot(): string;
11
+ //# sourceMappingURL=grok-templates.d.ts.map
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Where the Grok host templates live (ADR-402).
3
+ *
4
+ * Kept apart from grok-generator.ts so the team_* MCP tools can find the team
5
+ * bus scripts without loading the TOML parser on every MCP client import.
6
+ */
7
+ import * as fs from 'node:fs';
8
+ import * as path from 'node:path';
9
+ import { fileURLToPath } from 'node:url';
10
+ /** Root of the installed @claude-flow/cli package (the one holding templates/grok). */
11
+ export function grokPackageRoot() {
12
+ const here = path.dirname(fileURLToPath(import.meta.url));
13
+ const candidates = [
14
+ path.resolve(here, '../../..'), // dist/src/init → package root
15
+ path.resolve(here, '../..'), // src/init → package root
16
+ ];
17
+ for (const c of candidates) {
18
+ if (fs.existsSync(path.join(c, 'templates', 'grok', 'config.toml'))) {
19
+ return c;
20
+ }
21
+ }
22
+ return candidates[0];
23
+ }
24
+ /** templates/grok inside the installed @claude-flow/cli package. */
25
+ export function grokTemplatesRoot() {
26
+ return path.join(grokPackageRoot(), 'templates', 'grok');
27
+ }
28
+ //# sourceMappingURL=grok-templates.js.map
@@ -10,4 +10,6 @@ export { generatePreCommitHook, generatePostCommitHook, generateSessionManager,
10
10
  export { generateClaudeMd, generateMinimalClaudeMd, CLAUDE_MD_TEMPLATES, } from './claudemd-generator.js';
11
11
  export { executeInit, executeUpgrade, executeUpgradeWithMissing, default } from './executor.js';
12
12
  export type { UpgradeResult } from './executor.js';
13
+ export { executeGrokInit } from './grok-generator.js';
14
+ export type { GrokInitOptions, GrokInitResult } from './grok-generator.js';
13
15
  //# sourceMappingURL=index.d.ts.map
@@ -12,4 +12,6 @@ export { generatePreCommitHook, generatePostCommitHook, generateSessionManager,
12
12
  export { generateClaudeMd, generateMinimalClaudeMd, CLAUDE_MD_TEMPLATES, } from './claudemd-generator.js';
13
13
  // Main executor
14
14
  export { executeInit, executeUpgrade, executeUpgradeWithMissing, default } from './executor.js';
15
+ // Grok Build host (ADR-402)
16
+ export { executeGrokInit } from './grok-generator.js';
15
17
  //# sourceMappingURL=index.js.map
@@ -73,6 +73,8 @@ import { businessPodTools } from './mcp-tools/business-pod-tools.js';
73
73
  // + auth headers; opt-in via CLAUDE_FLOW_HTTP_FETCH_ALLOW_PRIVATE / _AUTH=1.
74
74
  import { httpFetchTools } from './mcp-tools/http-fetch-tools.js';
75
75
  import { missionTools } from './mcp-tools/mission-tools.js';
76
+ // ADR-402 — host-agnostic Agent Teams bus (team_create/send/inbox/spawn/…)
77
+ import { teamTools } from './mcp-tools/team-tools.js';
76
78
  // #1916: coverage-aware routing tools — defined in ruvector/coverage-tools.ts
77
79
  // but were never registered, so the `ruflo hooks coverage-*` CLI subcommands
78
80
  // failed with `Tool not found: hooks_coverage-route`.
@@ -183,6 +185,8 @@ registerTools([
183
185
  ...httpFetchTools,
184
186
  // ADR-406 — mission semantic operations (create/plan/get/events/request_action)
185
187
  ...missionTools,
188
+ // ADR-402 — host-agnostic Agent Teams (9 tools)
189
+ ...teamTools,
186
190
  ]);
187
191
  // The capability brain consumes the completed live registry. This is injected
188
192
  // after registration to keep guidance honest and avoid a registry import cycle.
@@ -152,7 +152,11 @@ export async function callAnthropicMessages(input) {
152
152
  ...input,
153
153
  apiKey: ollamaKey || persistedOllama?.apiKey || 'local',
154
154
  baseUrl: resolvedBaseUrl,
155
- model: input.model || persistedOllama?.model,
155
+ model: input.model,
156
+ // Local default for tier aliases / Anthropic ids (see
157
+ // resolveOllamaModel): OLLAMA_DEFAULT_MODEL, then the model saved by
158
+ // `providers configure -p ollama -m <tag>`.
159
+ defaultModel: process.env.OLLAMA_DEFAULT_MODEL || persistedOllama?.model,
156
160
  });
157
161
  }
158
162
  return { success: false, error: 'Ollama was selected but no API key or self-hosted endpoint is configured.' };
@@ -242,13 +246,15 @@ export async function callAnthropicMessages(input) {
242
246
  *
243
247
  * Translates the Anthropic-flavored input shape onto OpenAI chat-completions
244
248
  * and translates the response back so callers never see provider-specific
245
- * fields. Logical model names are mapped to Ollama Cloud defaults:
246
- * - 'haiku' / 'sonnet' → 'gpt-oss:120b-cloud' (sensible single default)
247
- * - 'opus' → 'gpt-oss:120b-cloud' (no opus tier on Ollama)
248
- * - explicit 'ollama:<model>' or bare provider-native name → passed through
249
+ * fields. Logical model names ('haiku' / 'sonnet' / 'opus' / a tier-routed
250
+ * `claude-*` id) resolve to the configured OLLAMA_DEFAULT_MODEL / persisted
251
+ * default; only when the endpoint is genuinely Ollama's cloud service AND no
252
+ * default is configured does this fall back to 'gpt-oss:120b-cloud' — a
253
+ * self-hosted/local endpoint with no default configured fails loudly instead
254
+ * (see resolveOllamaModel). An explicit 'ollama:<model>' or bare
255
+ * provider-native name always passes through unchanged.
249
256
  */
250
257
  async function callOllamaCompat(input) {
251
- const model = resolveOllamaModel(input.model);
252
258
  const startedAt = Date.now();
253
259
  // #2962 — input.baseUrl (resolved by the caller from persisted
254
260
  // `providers configure` config, then OLLAMA_BASE_URL) takes precedence
@@ -257,6 +263,20 @@ async function callOllamaCompat(input) {
257
263
  // Cloud. Falls back to the original OLLAMA_BASE_URL-or-cloud behavior
258
264
  // for any direct caller that doesn't pass baseUrl.
259
265
  const base = (input.baseUrl || process.env.OLLAMA_BASE_URL || 'https://ollama.com').replace(/\/+$/, '');
266
+ // Only a base URL actually pointed at Ollama's real cloud endpoint may
267
+ // fall back to a `-cloud`-suffixed default model — see resolveOllamaModel.
268
+ const isCloudEndpoint = /^https:\/\/ollama\.com\/?$/i.test(base);
269
+ let model;
270
+ try {
271
+ model = resolveOllamaModel(input.model, input.defaultModel, isCloudEndpoint);
272
+ }
273
+ catch (err) {
274
+ return {
275
+ success: false,
276
+ error: err instanceof Error ? err.message : String(err),
277
+ durationMs: Date.now() - startedAt,
278
+ };
279
+ }
260
280
  const url = `${base}/v1/chat/completions`;
261
281
  // Self-hosted endpoints typically don't need an Authorization header
262
282
  // (the daemon binds to 11434 with no auth by default), but Ollama Cloud
@@ -403,18 +423,45 @@ function resolveOpenAICompatModel(input, fallback) {
403
423
  return 'anthropic/claude-opus-4-8';
404
424
  return input;
405
425
  }
406
- function resolveOllamaModel(input) {
407
- const DEFAULT = 'gpt-oss:120b-cloud';
426
+ /**
427
+ * Resolve the model name to send to an Ollama-compatible endpoint.
428
+ *
429
+ * Self-hosted setups name their default via OLLAMA_DEFAULT_MODEL or
430
+ * `providers configure -p ollama -m <tag>` (`defaultModel`, resolved by the
431
+ * caller). When no default is configured AND the endpoint is not actually
432
+ * Ollama's real cloud service, this must NOT silently rewrite a tier-routed
433
+ * `claude-*` id (or a bare tier alias) to a `-cloud`-suffixed model name: a
434
+ * signed-in local Ollama daemon forwards any `-cloud`-suffixed model to
435
+ * Ollama's actual cloud service, so a silent rewrite would leak a prompt
436
+ * that was supposed to stay local. Fail loudly instead and tell the caller
437
+ * how to fix it — a loud, local failure beats silent cloud egress.
438
+ */
439
+ function resolveOllamaModel(input, defaultModel, isCloudEndpoint = false) {
440
+ const cloudDefault = 'gpt-oss:120b-cloud';
441
+ const resolveDefault = () => {
442
+ if (defaultModel)
443
+ return defaultModel;
444
+ if (isCloudEndpoint)
445
+ return cloudDefault;
446
+ throw new Error('No Ollama model configured for this self-hosted/local endpoint — refusing to fall back to '
447
+ + `a cloud-suffixed default ("${cloudDefault}") a local Ollama daemon would forward to Ollama `
448
+ + 'Cloud. Set OLLAMA_DEFAULT_MODEL, or run `providers configure -p ollama -m <tag>`, to pin a '
449
+ + 'real local model.');
450
+ };
408
451
  if (!input)
409
- return DEFAULT;
410
- // Logical → cloud default
452
+ return resolveDefault();
453
+ // Logical tier alias → default
411
454
  if (input === 'haiku' || input === 'sonnet' || input === 'opus' || input === 'inherit') {
412
- return DEFAULT;
455
+ return resolveDefault();
413
456
  }
414
457
  // Explicit provider prefix
415
458
  if (input.startsWith('ollama:'))
416
459
  return input.slice('ollama:'.length);
417
- // Bare name with cloud suffix (e.g. 'llama3:70b-cloud') passes through
460
+ // Anthropic model ids (what executeAgentTask sends for a tier-routed agent
461
+ // via MODEL_MAP) never exist on an Ollama endpoint → default.
462
+ if (/^claude-/i.test(input))
463
+ return resolveDefault();
464
+ // Bare name (e.g. 'qwen3-coder:30b', 'llama3:70b-cloud') passes through
418
465
  return input;
419
466
  }
420
467
  /**
@@ -97,7 +97,7 @@ export interface CapabilityBrain {
97
97
  };
98
98
  }
99
99
  /** Top-level commands from the CLI command loader. Kept as a checked manifest. */
100
- export declare const RUFLO_CLI_COMMANDS: readonly ["init", "start", "status", "task", "session", "agent", "swarm", "memory", "mcp", "config", "migrate", "hooks", "workflow", "hive-mind", "process", "daemon", "version", "neural", "security", "performance", "providers", "plugins", "deployment", "claims", "policy", "embeddings", "completions", "doctor", "verify", "analyze", "route", "progress", "issues", "update", "ruvector", "benchmark", "guidance", "appliance", "appliance-advanced", "transfer-store", "cleanup", "autopilot", "gaia-bench", "metaharness", "eject", "funnel", "settings", "auth", "proxy", "advisor", "spinner", "announcements", "tui"];
100
+ export declare const RUFLO_CLI_COMMANDS: readonly ["init", "start", "status", "task", "session", "agent", "swarm", "memory", "mcp", "config", "migrate", "hooks", "workflow", "hive-mind", "process", "daemon", "version", "neural", "security", "performance", "providers", "plugins", "deployment", "claims", "policy", "embeddings", "completions", "doctor", "verify", "analyze", "route", "progress", "issues", "update", "ruvector", "benchmark", "guidance", "appliance", "appliance-advanced", "transfer-store", "cleanup", "autopilot", "gaia-bench", "metaharness", "eject", "funnel", "settings", "auth", "proxy", "advisor", "spinner", "announcements", "tui", "harness"];
101
101
  export interface ImplementationLoopStep {
102
102
  id: string;
103
103
  name: string;
@@ -16,7 +16,7 @@ export const RUFLO_CLI_COMMANDS = [
16
16
  'ruvector', 'benchmark', 'guidance', 'appliance', 'appliance-advanced',
17
17
  'transfer-store', 'cleanup', 'autopilot', 'gaia-bench', 'metaharness',
18
18
  'eject', 'funnel', 'settings', 'auth', 'proxy', 'advisor', 'spinner',
19
- 'announcements', 'tui',
19
+ 'announcements', 'tui', 'harness',
20
20
  ];
21
21
  export const IMPLEMENTATION_LOOP = [
22
22
  {
@@ -284,9 +284,10 @@ export const CAPABILITY_DOMAINS = [
284
284
  {
285
285
  id: 'swarm-coordination',
286
286
  name: 'Swarm & Coordination',
287
- prefixes: ['swarm_', 'coordination_', 'daa_'],
287
+ // team_: host-agnostic Agent Teams bus (ADR-402)
288
+ prefixes: ['swarm_', 'coordination_', 'daa_', 'team_'],
288
289
  description: 'Topology-aware multi-agent coordination, task ownership, and collective scheduling.',
289
- taskSignals: ['swarm', 'concurrent', 'parallel', 'coordinate', 'multi-agent'],
290
+ taskSignals: ['swarm', 'concurrent', 'parallel', 'coordinate', 'multi-agent', 'agent team'],
290
291
  commands: ['swarm init', 'swarm status', 'swarm coordinate'],
291
292
  skills: ['swarm-orchestration', 'swarm-advanced'],
292
293
  agents: ['coordinator', 'coder', 'tester', 'reviewer'],
@@ -553,6 +554,7 @@ const TOOL_OWNERSHIP = [
553
554
  { prefixes: ['guidance_'], packageOwner: '@claude-flow/guidance', pluginOwner: 'ruflo-core' },
554
555
  { prefixes: ['seraphina_'], packageOwner: '@claude-flow/cli', pluginOwner: 'ruflo-core' },
555
556
  { prefixes: ['x_federation_'], packageOwner: '@claude-flow/cli', pluginOwner: 'ruflo-x-gateway' },
557
+ { prefixes: ['team_'], packageOwner: '@claude-flow/cli' },
556
558
  ];
557
559
  function ownershipForTool(toolName, definition) {
558
560
  const explicit = TOOL_OWNERSHIP.find((entry) => entry.prefixes.some((prefix) => toolName.startsWith(prefix)));
@@ -928,15 +928,22 @@ export const embeddingsTools = [
928
928
  const v = vt(params.query, 'query');
929
929
  if (!v.valid)
930
930
  return { success: false, error: v.error };
931
- const { searchRabitq } = await import('../memory/rabitq-index.js');
931
+ const { ensureRabitqIndex, searchRabitq } = await import('../memory/rabitq-index.js');
932
932
  const { generateEmbedding } = await import('../memory/memory-initializer.js');
933
933
  const queryEmb = await generateEmbedding(params.query);
934
- const results = await searchRabitq(queryEmb.embedding, {
934
+ const searchOptions = {
935
935
  k: params.k || 10,
936
936
  namespace: params.namespace,
937
- });
937
+ };
938
+ // #4203: the index is built on demand, so a search no longer requires a
939
+ // separate `embeddings_rabitq_build` call first.
940
+ let results = await searchRabitq(queryEmb.embedding, searchOptions);
941
+ if (!results) {
942
+ await ensureRabitqIndex({ dimensions: queryEmb.embedding.length });
943
+ results = await searchRabitq(queryEmb.embedding, searchOptions);
944
+ }
938
945
  if (!results) {
939
- return { success: false, error: 'RaBitQ index not built. Call embeddings_rabitq_build first.' };
946
+ return { success: false, error: 'RaBitQ index not built (needs at least 10 embedded entries). Call embeddings_rabitq_build first.' };
940
947
  }
941
948
  return {
942
949
  success: true,
@@ -39,4 +39,5 @@ export { xFederationChannelTools } from './x-federation-channels.js';
39
39
  export { businessPodTools } from './business-pod-tools.js';
40
40
  export { httpFetchTools } from './http-fetch-tools.js';
41
41
  export { missionTools, createMissionTools } from './mission-tools.js';
42
+ export { teamTools } from './team-tools.js';
42
43
  //# sourceMappingURL=index.d.ts.map
@@ -45,4 +45,6 @@ export { businessPodTools } from './business-pod-tools.js';
45
45
  export { httpFetchTools } from './http-fetch-tools.js';
46
46
  // ADR-406 — mission semantic operations
47
47
  export { missionTools, createMissionTools } from './mission-tools.js';
48
+ // ADR-402 — host-agnostic Agent Teams bus
49
+ export { teamTools } from './team-tools.js';
48
50
  //# sourceMappingURL=index.js.map