moflo 4.8.9 → 4.8.11

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 (166) hide show
  1. package/.claude/agents/core/coder.md +265 -265
  2. package/.claude/agents/core/planner.md +167 -167
  3. package/.claude/agents/core/researcher.md +189 -189
  4. package/.claude/agents/core/reviewer.md +325 -325
  5. package/.claude/agents/core/tester.md +318 -318
  6. package/.claude/agents/dual-mode/codex-coordinator.md +224 -224
  7. package/.claude/agents/dual-mode/codex-worker.md +211 -211
  8. package/.claude/agents/dual-mode/dual-orchestrator.md +291 -291
  9. package/.claude/agents/github/code-review-swarm.md +537 -537
  10. package/.claude/agents/github/github-modes.md +172 -172
  11. package/.claude/agents/github/issue-tracker.md +318 -318
  12. package/.claude/agents/github/multi-repo-swarm.md +552 -552
  13. package/.claude/agents/github/pr-manager.md +190 -190
  14. package/.claude/agents/github/project-board-sync.md +508 -508
  15. package/.claude/agents/github/release-manager.md +366 -366
  16. package/.claude/agents/github/release-swarm.md +582 -582
  17. package/.claude/agents/github/repo-architect.md +397 -397
  18. package/.claude/agents/github/swarm-issue.md +572 -572
  19. package/.claude/agents/github/swarm-pr.md +427 -427
  20. package/.claude/agents/github/sync-coordinator.md +451 -451
  21. package/.claude/agents/github/workflow-automation.md +634 -634
  22. package/.claude/agents/goal/code-goal-planner.md +445 -445
  23. package/.claude/agents/hive-mind/collective-intelligence-coordinator.md +129 -129
  24. package/.claude/agents/hive-mind/queen-coordinator.md +202 -202
  25. package/.claude/agents/hive-mind/scout-explorer.md +241 -241
  26. package/.claude/agents/hive-mind/swarm-memory-manager.md +192 -192
  27. package/.claude/agents/hive-mind/worker-specialist.md +216 -216
  28. package/.claude/agents/neural/safla-neural.md +73 -73
  29. package/.claude/agents/reasoning/goal-planner.md +72 -72
  30. package/.claude/agents/swarm/adaptive-coordinator.md +395 -395
  31. package/.claude/agents/swarm/hierarchical-coordinator.md +326 -326
  32. package/.claude/agents/swarm/mesh-coordinator.md +391 -391
  33. package/.claude/agents/templates/migration-plan.md +745 -745
  34. package/.claude/commands/agents/agent-spawning.md +28 -28
  35. package/.claude/commands/analysis/COMMAND_COMPLIANCE_REPORT.md +53 -53
  36. package/.claude/commands/analysis/bottleneck-detect.md +162 -162
  37. package/.claude/commands/analysis/performance-bottlenecks.md +58 -58
  38. package/.claude/commands/analysis/token-efficiency.md +44 -44
  39. package/.claude/commands/automation/auto-agent.md +122 -122
  40. package/.claude/commands/automation/self-healing.md +105 -105
  41. package/.claude/commands/automation/session-memory.md +89 -89
  42. package/.claude/commands/automation/smart-agents.md +72 -72
  43. package/.claude/commands/coordination/init.md +44 -44
  44. package/.claude/commands/coordination/orchestrate.md +43 -43
  45. package/.claude/commands/coordination/spawn.md +45 -45
  46. package/.claude/commands/coordination/swarm-init.md +85 -85
  47. package/.claude/commands/github/github-modes.md +146 -146
  48. package/.claude/commands/github/github-swarm.md +121 -121
  49. package/.claude/commands/github/issue-tracker.md +291 -291
  50. package/.claude/commands/github/pr-manager.md +169 -169
  51. package/.claude/commands/github/release-manager.md +337 -337
  52. package/.claude/commands/github/repo-architect.md +366 -366
  53. package/.claude/commands/github/sync-coordinator.md +300 -300
  54. package/.claude/commands/memory/neural.md +47 -47
  55. package/.claude/commands/monitoring/agents.md +44 -44
  56. package/.claude/commands/monitoring/status.md +46 -46
  57. package/.claude/commands/optimization/auto-topology.md +61 -61
  58. package/.claude/commands/optimization/parallel-execution.md +49 -49
  59. package/.claude/commands/sparc/analyzer.md +51 -51
  60. package/.claude/commands/sparc/architect.md +53 -53
  61. package/.claude/commands/sparc/ask.md +97 -97
  62. package/.claude/commands/sparc/batch-executor.md +54 -54
  63. package/.claude/commands/sparc/code.md +89 -89
  64. package/.claude/commands/sparc/coder.md +54 -54
  65. package/.claude/commands/sparc/debug.md +83 -83
  66. package/.claude/commands/sparc/debugger.md +54 -54
  67. package/.claude/commands/sparc/designer.md +53 -53
  68. package/.claude/commands/sparc/devops.md +109 -109
  69. package/.claude/commands/sparc/docs-writer.md +80 -80
  70. package/.claude/commands/sparc/documenter.md +54 -54
  71. package/.claude/commands/sparc/innovator.md +54 -54
  72. package/.claude/commands/sparc/integration.md +83 -83
  73. package/.claude/commands/sparc/mcp.md +117 -117
  74. package/.claude/commands/sparc/memory-manager.md +54 -54
  75. package/.claude/commands/sparc/optimizer.md +54 -54
  76. package/.claude/commands/sparc/orchestrator.md +131 -131
  77. package/.claude/commands/sparc/post-deployment-monitoring-mode.md +83 -83
  78. package/.claude/commands/sparc/refinement-optimization-mode.md +83 -83
  79. package/.claude/commands/sparc/researcher.md +54 -54
  80. package/.claude/commands/sparc/reviewer.md +54 -54
  81. package/.claude/commands/sparc/security-review.md +80 -80
  82. package/.claude/commands/sparc/sparc-modes.md +174 -174
  83. package/.claude/commands/sparc/sparc.md +111 -111
  84. package/.claude/commands/sparc/spec-pseudocode.md +80 -80
  85. package/.claude/commands/sparc/supabase-admin.md +348 -348
  86. package/.claude/commands/sparc/swarm-coordinator.md +54 -54
  87. package/.claude/commands/sparc/tdd.md +54 -54
  88. package/.claude/commands/sparc/tester.md +54 -54
  89. package/.claude/commands/sparc/tutorial.md +79 -79
  90. package/.claude/commands/sparc/workflow-manager.md +54 -54
  91. package/.claude/commands/sparc.md +166 -166
  92. package/.claude/commands/swarm/analysis.md +95 -95
  93. package/.claude/commands/swarm/development.md +96 -96
  94. package/.claude/commands/swarm/examples.md +168 -168
  95. package/.claude/commands/swarm/maintenance.md +102 -102
  96. package/.claude/commands/swarm/optimization.md +117 -117
  97. package/.claude/commands/swarm/research.md +136 -136
  98. package/.claude/commands/swarm/testing.md +131 -131
  99. package/.claude/commands/training/neural-patterns.md +73 -73
  100. package/.claude/commands/training/specialization.md +62 -62
  101. package/.claude/commands/workflows/development.md +77 -77
  102. package/.claude/commands/workflows/research.md +62 -62
  103. package/.claude/guidance/{agent-bootstrap.md → shipped/agent-bootstrap.md} +126 -126
  104. package/.claude/guidance/{guidance-memory-strategy.md → shipped/guidance-memory-strategy.md} +262 -262
  105. package/.claude/guidance/{memory-strategy.md → shipped/memory-strategy.md} +204 -204
  106. package/.claude/guidance/{moflo.md → shipped/moflo.md} +45 -31
  107. package/.claude/guidance/{task-swarm-integration.md → shipped/task-swarm-integration.md} +441 -348
  108. package/.claude/helpers/gate.cjs +236 -236
  109. package/.claude/helpers/hook-handler.cjs +42 -46
  110. package/.claude/settings.json +2 -2
  111. package/.claude/settings.local.json +3 -3
  112. package/.claude/skills/fl/SKILL.md +29 -23
  113. package/.claude/skills/flo/SKILL.md +29 -23
  114. package/.claude/skills/github-code-review/SKILL.md +4 -4
  115. package/.claude/skills/github-multi-repo/SKILL.md +8 -8
  116. package/.claude/skills/github-project-management/SKILL.md +6 -6
  117. package/.claude/skills/github-release-management/SKILL.md +12 -12
  118. package/.claude/skills/github-workflow-automation/SKILL.md +6 -6
  119. package/.claude/skills/hooks-automation/SKILL.md +1201 -1201
  120. package/.claude/skills/performance-analysis/SKILL.md +563 -563
  121. package/.claude/skills/sparc-methodology/SKILL.md +64 -64
  122. package/.claude/skills/swarm-advanced/SKILL.md +77 -77
  123. package/.claude-plugin/README.md +3 -3
  124. package/.claude-plugin/docs/PLUGIN_SUMMARY.md +3 -3
  125. package/.claude-plugin/docs/QUICKSTART.md +4 -4
  126. package/.claude-plugin/marketplace.json +3 -3
  127. package/.claude-plugin/plugin.json +3 -3
  128. package/.claude-plugin/scripts/install.sh +9 -9
  129. package/.claude-plugin/scripts/verify.sh +7 -7
  130. package/README.md +311 -116
  131. package/bin/gate-hook.mjs +50 -0
  132. package/bin/gate.cjs +138 -0
  133. package/bin/hook-handler.cjs +83 -0
  134. package/bin/hooks.mjs +72 -12
  135. package/bin/index-guidance.mjs +28 -34
  136. package/bin/index-tests.mjs +710 -0
  137. package/bin/lib/process-manager.mjs +243 -0
  138. package/bin/lib/registry-cleanup.cjs +41 -0
  139. package/bin/prompt-hook.mjs +72 -0
  140. package/bin/semantic-search.mjs +473 -441
  141. package/bin/session-start-launcher.mjs +81 -31
  142. package/bin/setup-project.mjs +13 -10
  143. package/package.json +4 -2
  144. package/src/@claude-flow/cli/README.md +1 -1
  145. package/src/@claude-flow/cli/bin/cli.js +175 -175
  146. package/src/@claude-flow/cli/dist/src/commands/doctor.js +1091 -736
  147. package/src/@claude-flow/cli/dist/src/commands/github.d.ts +12 -0
  148. package/src/@claude-flow/cli/dist/src/commands/github.js +505 -0
  149. package/src/@claude-flow/cli/dist/src/commands/hive-mind.js +90 -90
  150. package/src/@claude-flow/cli/dist/src/commands/index.d.ts +1 -0
  151. package/src/@claude-flow/cli/dist/src/commands/index.js +7 -0
  152. package/src/@claude-flow/cli/dist/src/config-adapter.js +1 -1
  153. package/src/@claude-flow/cli/dist/src/init/claudemd-generator.js +1 -1
  154. package/src/@claude-flow/cli/dist/src/init/executor.js +109 -5
  155. package/src/@claude-flow/cli/dist/src/init/helpers-generator.d.ts +14 -0
  156. package/src/@claude-flow/cli/dist/src/init/helpers-generator.js +156 -24
  157. package/src/@claude-flow/cli/dist/src/init/mcp-generator.js +20 -20
  158. package/src/@claude-flow/cli/dist/src/init/moflo-init.d.ts +7 -0
  159. package/src/@claude-flow/cli/dist/src/init/moflo-init.js +72 -10
  160. package/src/@claude-flow/cli/dist/src/init/settings-generator.js +23 -14
  161. package/src/@claude-flow/cli/dist/src/mcp-server.js +3 -3
  162. package/src/@claude-flow/cli/dist/src/plugins/manager.js +9 -8
  163. package/src/@claude-flow/cli/dist/src/services/worker-daemon.d.ts +1 -0
  164. package/src/@claude-flow/cli/dist/src/services/worker-daemon.js +3 -1
  165. package/src/@claude-flow/cli/dist/src/services/workflow-gate.js +10 -10
  166. package/src/@claude-flow/cli/package.json +1 -1
@@ -178,6 +178,8 @@ export function generateHelpers(options) {
178
178
  helpers['pre-commit'] = generatePreCommitHook();
179
179
  helpers['post-commit'] = generatePostCommitHook();
180
180
  helpers['gate.cjs'] = generateGateScript();
181
+ helpers['gate-hook.mjs'] = generateGateHookScript();
182
+ helpers['prompt-hook.mjs'] = generatePromptHookScript();
181
183
  helpers['hook-handler.cjs'] = generateHookHandlerScript();
182
184
  }
183
185
  if (options.components.statusline) {
@@ -197,7 +199,7 @@ export function generateGateScript() {
197
199
  var fs = require('fs');
198
200
  var path = require('path');
199
201
 
200
- var PROJECT_DIR = process.env.CLAUDE_PROJECT_DIR || process.cwd();
202
+ var PROJECT_DIR = (process.env.CLAUDE_PROJECT_DIR || process.cwd()).replace(/^\\/([a-z])\\//i, '$1:/');
201
203
  var STATE_FILE = path.join(PROJECT_DIR, '.claude', 'workflow-state.json');
202
204
 
203
205
  function readState() {
@@ -241,13 +243,15 @@ var TASK_RE = /\\b(fix|bug|error|implement|add|create|build|write|refactor|debug
241
243
  switch (command) {
242
244
  case 'check-before-agent': {
243
245
  var s = readState();
244
- if (config.task_create_first && !s.tasksCreated) {
245
- console.log('BLOCKED: Call TaskCreate before spawning agents.');
246
- process.exit(1);
246
+ // Hard gate: memory must be searched
247
+ if (config.memory_first && s.memoryRequired && !s.memorySearched) {
248
+ process.stderr.write('BLOCKED: Search memory (mcp__moflo__memory_search) before spawning agents.\\n');
249
+ process.exit(2);
247
250
  }
248
- if (config.memory_first && !s.memorySearched) {
249
- console.log('BLOCKED: Search memory before spawning agents.');
250
- process.exit(1);
251
+ // Soft gate: TaskCreate recommended but not blocking
252
+ // (TaskCreate PostToolUse doesn't fire in Claude Code, so we can't track it reliably)
253
+ if (config.task_create_first && !s.tasksCreated) {
254
+ process.stdout.write('REMINDER: Use TaskCreate before spawning agents. Task tool is blocked until then.\\n');
251
255
  }
252
256
  break;
253
257
  }
@@ -257,14 +261,8 @@ switch (command) {
257
261
  if (s.memorySearched || !s.memoryRequired) break;
258
262
  var target = (process.env.TOOL_INPUT_pattern || '') + ' ' + (process.env.TOOL_INPUT_path || '');
259
263
  if (EXEMPT.some(function(p) { return target.indexOf(p) >= 0; })) break;
260
- var now = Date.now();
261
- var last = s.lastBlockedAt ? new Date(s.lastBlockedAt).getTime() : 0;
262
- if (now - last > 2000) {
263
- s.lastBlockedAt = new Date(now).toISOString();
264
- writeState(s);
265
- console.log('BLOCKED: Search memory before exploring files.');
266
- }
267
- process.exit(1);
264
+ process.stderr.write('BLOCKED: Search memory before exploring files. Use mcp__moflo__memory_search.\\n');
265
+ process.exit(2);
268
266
  }
269
267
  case 'check-before-read': {
270
268
  if (!config.memory_first) break;
@@ -272,14 +270,8 @@ switch (command) {
272
270
  if (s.memorySearched || !s.memoryRequired) break;
273
271
  var fp = process.env.TOOL_INPUT_file_path || '';
274
272
  if (fp.indexOf('.claude/guidance/') < 0 && fp.indexOf('.claude\\\\guidance\\\\') < 0) break;
275
- var now = Date.now();
276
- var last = s.lastBlockedAt ? new Date(s.lastBlockedAt).getTime() : 0;
277
- if (now - last > 2000) {
278
- s.lastBlockedAt = new Date(now).toISOString();
279
- writeState(s);
280
- console.log('BLOCKED: Search memory before reading guidance files.');
281
- }
282
- process.exit(1);
273
+ process.stderr.write('BLOCKED: Search memory before reading guidance files. Use mcp__moflo__memory_search.\\n');
274
+ process.exit(2);
283
275
  }
284
276
  case 'record-task-created': {
285
277
  var s = readState();
@@ -325,7 +317,7 @@ switch (command) {
325
317
  var ic = s.interactionCount;
326
318
  if (ic > 30) console.log('Context: CRITICAL. Commit, store learnings, suggest new session.');
327
319
  else if (ic > 20) console.log('Context: DEPLETED. Checkpoint progress. Recommend /compact or fresh session.');
328
- else if (ic > 10) console.log('Context: MODERATE. Re-state goal before architectural decisions.');
320
+ else if (ic > 10) console.log('Context: MODERATE. Re-state goal before architectural decisions. Use agents for >300 LOC.');
329
321
  }
330
322
  break;
331
323
  }
@@ -342,6 +334,146 @@ switch (command) {
342
334
  }
343
335
  `;
344
336
  }
337
+ /**
338
+ * Generate gate-hook.mjs — ESM wrapper that reads Claude Code stdin JSON
339
+ * and passes tool_name + tool_input to gate.cjs via environment variables.
340
+ *
341
+ * Claude Code hooks receive context as JSON on stdin but don't set env vars
342
+ * for tool input. This script bridges that gap. It also translates exit code 1
343
+ * from gate.cjs into exit code 2 (which Claude Code requires to block tools).
344
+ */
345
+ export function generateGateHookScript() {
346
+ return `#!/usr/bin/env node
347
+ import { execSync } from 'child_process';
348
+ import { resolve } from 'path';
349
+
350
+ var command = process.argv[2];
351
+ if (!command) process.exit(0);
352
+
353
+ // Read stdin JSON from Claude Code
354
+ var stdinData = '';
355
+ try {
356
+ stdinData = await new Promise(function(res) {
357
+ var data = '';
358
+ var timeout = setTimeout(function() { res(data); }, 500);
359
+ process.stdin.setEncoding('utf-8');
360
+ process.stdin.on('data', function(chunk) { data += chunk; });
361
+ process.stdin.on('end', function() { clearTimeout(timeout); res(data); });
362
+ process.stdin.on('error', function() { clearTimeout(timeout); res(''); });
363
+ if (process.stdin.isTTY) { clearTimeout(timeout); res(''); }
364
+ });
365
+ } catch (e) { /* no stdin */ }
366
+
367
+ var hookContext = {};
368
+ try { if (stdinData.trim()) hookContext = JSON.parse(stdinData); } catch (e) {}
369
+
370
+ // Pass tool info as env vars for gate.cjs
371
+ var env = Object.assign({}, process.env);
372
+ if (hookContext.tool_name) env.TOOL_NAME = hookContext.tool_name;
373
+ if (hookContext.tool_input && typeof hookContext.tool_input === 'object') {
374
+ Object.keys(hookContext.tool_input).forEach(function(key) {
375
+ if (typeof hookContext.tool_input[key] === 'string') {
376
+ env['TOOL_INPUT_' + key] = hookContext.tool_input[key];
377
+ }
378
+ });
379
+ }
380
+
381
+ // Run gate.cjs with the enriched environment
382
+ var projectDir = (env.CLAUDE_PROJECT_DIR || process.cwd()).replace(/^\\/([a-z])\\//i, '$1:/');
383
+ var gateScript = resolve(projectDir, '.claude/helpers/gate.cjs');
384
+ try {
385
+ var output = execSync('node "' + gateScript + '" ' + command, {
386
+ env: env, encoding: 'utf-8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe']
387
+ });
388
+ if (output.trim()) process.stdout.write(output);
389
+ process.exit(0);
390
+ } catch (err) {
391
+ // gate.cjs exit(2) = block, exit(1) = also block attempt — translate both to exit(2)
392
+ if (err.stderr) process.stderr.write(err.stderr);
393
+ if (err.stdout) process.stderr.write(err.stdout);
394
+ process.exit(err.status === 2 || err.status === 1 ? 2 : 0);
395
+ }
396
+ `;
397
+ }
398
+ /**
399
+ * Generate prompt-hook.mjs — reads user prompt from Claude Code stdin JSON,
400
+ * runs prompt classification via gate.cjs, and appends namespace hints.
401
+ */
402
+ export function generatePromptHookScript() {
403
+ return `#!/usr/bin/env node
404
+ import { execSync } from 'child_process';
405
+ import { resolve } from 'path';
406
+
407
+ // Read stdin JSON from Claude Code
408
+ var stdinData = '';
409
+ try {
410
+ stdinData = await new Promise(function(res) {
411
+ var data = '';
412
+ var timeout = setTimeout(function() { res(data); }, 500);
413
+ process.stdin.setEncoding('utf-8');
414
+ process.stdin.on('data', function(chunk) { data += chunk; });
415
+ process.stdin.on('end', function() { clearTimeout(timeout); res(data); });
416
+ process.stdin.on('error', function() { clearTimeout(timeout); res(''); });
417
+ if (process.stdin.isTTY) { clearTimeout(timeout); res(''); }
418
+ });
419
+ } catch (e) { /* no stdin */ }
420
+
421
+ var hookContext = {};
422
+ try { if (stdinData.trim()) hookContext = JSON.parse(stdinData); } catch (e) {}
423
+
424
+ var userPrompt = hookContext.user_prompt || hookContext.prompt || '';
425
+ var env = Object.assign({}, process.env, { CLAUDE_USER_PROMPT: userPrompt });
426
+
427
+ // Run prompt-reminder via gate.cjs
428
+ var projectDir = (env.CLAUDE_PROJECT_DIR || process.cwd()).replace(/^\\/([a-z])\\//i, '$1:/');
429
+ var gateScript = resolve(projectDir, '.claude/helpers/gate.cjs');
430
+ var output = '';
431
+ try {
432
+ output = execSync('node "' + gateScript + '" prompt-reminder', {
433
+ env: env, encoding: 'utf-8', timeout: 3000, stdio: ['pipe', 'pipe', 'pipe']
434
+ });
435
+ } catch (err) { output = (err && err.stdout) || ''; }
436
+
437
+ // Classify prompt for namespace hint
438
+ var lower = userPrompt.toLowerCase();
439
+
440
+ var KNOWLEDGE_ONLY = /\\b(knowledge|remember|recall)\\b|we (decid|agree|chose|said)/;
441
+ var EXPLICIT_NS = [
442
+ { pattern: /\\b(pattern|convention|best practice|style|coding rule)\\b/, ns: 'patterns', label: 'code patterns and conventions' },
443
+ { pattern: /\\b(code.?map|file structure|project structure|directory)\\b/, ns: 'code-map', label: 'codebase navigation' },
444
+ ];
445
+ var PATTERN_HINTS = [/\\b(template|example|similar to|how do we|how should)\\b/];
446
+ var DOMAIN_HINTS = [
447
+ /\\b(guidance|guide|docs|documentation|rules|how-to)\\b/,
448
+ /\\b(architecture|design|domain|tenant|migrat|schema|deploy)/,
449
+ /\\b(rule|requirement|constraint|compliance)\\b/,
450
+ ];
451
+ var NAV_PATTERNS = [
452
+ /\\b(find|where|which file|look up|locate|endpoint|route|url|path)\\b/,
453
+ /\\b(class|function|method|component|service|entity|module)\\b/,
454
+ ];
455
+
456
+ var nsHint = '';
457
+ if (KNOWLEDGE_ONLY.test(lower)) {
458
+ nsHint = 'Memory namespace hint: use "knowledge" for user-directed project decisions.';
459
+ } else {
460
+ var found = EXPLICIT_NS.find(function(e) { return e.pattern.test(lower); });
461
+ if (found) {
462
+ nsHint = 'Memory namespace hint: use "' + found.ns + '" for ' + found.label + '.';
463
+ } else if (DOMAIN_HINTS.some(function(p) { return p.test(lower); })) {
464
+ nsHint = 'Memory namespace hint: search "guidance" and "knowledge" for domain rules and project decisions.';
465
+ } else if (PATTERN_HINTS.some(function(p) { return p.test(lower); })) {
466
+ nsHint = 'Memory namespace hint: use "patterns" for code patterns and conventions.';
467
+ } else if (NAV_PATTERNS.some(function(p) { return p.test(lower); })) {
468
+ nsHint = 'Memory namespace hint: use "code-map" for codebase navigation.';
469
+ }
470
+ }
471
+
472
+ var parts = [output.trim(), nsHint].filter(Boolean);
473
+ if (parts.length) process.stdout.write(parts.join('\\n') + '\\n');
474
+ process.exit(0);
475
+ `;
476
+ }
345
477
  /**
346
478
  * Generate lightweight hook-handler.cjs — hook dispatch without CLI bootstrap.
347
479
  * Handles routing, edit/task tracking, session lifecycle, and notifications.
@@ -8,28 +8,25 @@
8
8
  */
9
9
  import { existsSync } from 'fs';
10
10
  import { join } from 'path';
11
+ const isWindows = process.platform === 'win32';
11
12
  /**
12
- * Generate MCP server entry using npx (for external packages)
13
+ * Generate MCP server entry using npx (for external packages).
14
+ * On Windows, wraps with `cmd /c` so Claude Code can spawn the process.
13
15
  */
14
16
  function createNpxServerEntry(npxArgs, env, additionalProps = {}) {
15
- return {
16
- command: 'npx',
17
- args: ['-y', ...npxArgs],
18
- env,
19
- ...additionalProps,
20
- };
17
+ return isWindows
18
+ ? { command: 'cmd', args: ['/c', 'npx', '-y', ...npxArgs], env, ...additionalProps }
19
+ : { command: 'npx', args: ['-y', ...npxArgs], env, ...additionalProps };
21
20
  }
22
21
  /**
23
22
  * Generate MCP server entry using direct node invocation (for local moflo).
24
23
  * Avoids npx overhead — faster startup, fewer intermediate processes.
24
+ * On Windows, wraps with `cmd /c` so Claude Code can spawn the process.
25
25
  */
26
26
  function createDirectServerEntry(cliPath, cliArgs, env, additionalProps = {}) {
27
- return {
28
- command: 'node',
29
- args: [cliPath, ...cliArgs],
30
- env,
31
- ...additionalProps,
32
- };
27
+ return isWindows
28
+ ? { command: 'cmd', args: ['/c', 'node', cliPath, ...cliArgs], env, ...additionalProps }
29
+ : { command: 'node', args: [cliPath, ...cliArgs], env, ...additionalProps };
33
30
  }
34
31
  /**
35
32
  * Find the moflo CLI entry point relative to the project root.
@@ -73,10 +70,10 @@ export function generateMCPConfig(options) {
73
70
  const projectRoot = options.targetDir ?? process.cwd();
74
71
  const localCli = findMofloCli(projectRoot);
75
72
  if (localCli) {
76
- mcpServers['claude-flow'] = createDirectServerEntry(localCli, ['mcp', 'start'], mcpEnv, { autoStart: config.autoStart, ...deferProps });
73
+ mcpServers['moflo'] = createDirectServerEntry(localCli, ['mcp', 'start'], mcpEnv, { autoStart: config.autoStart, ...deferProps });
77
74
  }
78
75
  else {
79
- mcpServers['claude-flow'] = createNpxServerEntry(['moflo', 'mcp', 'start'], mcpEnv, { autoStart: config.autoStart, ...deferProps });
76
+ mcpServers['moflo'] = createNpxServerEntry(['moflo', 'mcp', 'start'], mcpEnv, { autoStart: config.autoStart, ...deferProps });
80
77
  }
81
78
  }
82
79
  // Ruv-Swarm MCP server (enhanced coordination) — always npx (external package)
@@ -102,21 +99,22 @@ export function generateMCPJson(options) {
102
99
  export function generateMCPCommands(options) {
103
100
  const commands = [];
104
101
  const config = options.mcp;
102
+ const cmdPrefix = isWindows ? 'cmd /c ' : '';
105
103
  if (config.claudeFlow) {
106
104
  const projectRoot = options.targetDir ?? process.cwd();
107
105
  const localCli = findMofloCli(projectRoot);
108
106
  if (localCli) {
109
- commands.push(`claude mcp add claude-flow -- node ${localCli} mcp start`);
107
+ commands.push(`claude mcp add moflo -- ${cmdPrefix}node ${localCli} mcp start`);
110
108
  }
111
109
  else {
112
- commands.push('claude mcp add claude-flow -- npx -y moflo mcp start');
110
+ commands.push(`claude mcp add moflo -- ${cmdPrefix}npx -y moflo mcp start`);
113
111
  }
114
112
  }
115
113
  if (config.ruvSwarm) {
116
- commands.push('claude mcp add ruv-swarm -- npx -y ruv-swarm mcp start');
114
+ commands.push(`claude mcp add ruv-swarm -- ${cmdPrefix}npx -y ruv-swarm mcp start`);
117
115
  }
118
116
  if (config.flowNexus) {
119
- commands.push('claude mcp add flow-nexus -- npx -y flow-nexus@latest mcp start');
117
+ commands.push(`claude mcp add flow-nexus -- ${cmdPrefix}npx -y flow-nexus@latest mcp start`);
120
118
  }
121
119
  return commands;
122
120
  }
@@ -129,7 +127,9 @@ export function getPlatformInstructions() {
129
127
  : process.platform === 'darwin' ? 'macOS' : 'Linux';
130
128
  return {
131
129
  platform,
132
- note: 'MCP configuration uses npx directly.',
130
+ note: isWindows
131
+ ? 'MCP configuration uses cmd /c wrapper for Windows compatibility.'
132
+ : 'MCP configuration uses npx directly.',
133
133
  };
134
134
  }
135
135
  //# sourceMappingURL=mcp-generator.js.map
@@ -10,6 +10,8 @@ export interface MofloInitAnswers {
10
10
  guidanceDirs: string[];
11
11
  codeMap: boolean;
12
12
  srcDirs: string[];
13
+ tests: boolean;
14
+ testDirs: string[];
13
15
  gates: boolean;
14
16
  stopHook: boolean;
15
17
  }
@@ -20,5 +22,10 @@ export interface MofloInitResult {
20
22
  detail?: string;
21
23
  }[];
22
24
  }
25
+ /**
26
+ * Discover test directories by checking common locations and walking for
27
+ * colocated __tests__ dirs. Returns relative paths.
28
+ */
29
+ export declare function discoverTestDirs(root: string): string[];
23
30
  export declare function initMoflo(options: MofloInitOptions): Promise<MofloInitResult>;
24
31
  //# sourceMappingURL=moflo-init.d.ts.map
@@ -53,6 +53,37 @@ function discoverGuidanceDirs(root) {
53
53
  walk('', 0);
54
54
  return found;
55
55
  }
56
+ /**
57
+ * Discover test directories by checking common locations and walking for
58
+ * colocated __tests__ dirs. Returns relative paths.
59
+ */
60
+ export function discoverTestDirs(root) {
61
+ const TOP_LEVEL = ['tests', 'test', '__tests__', 'spec', 'e2e'];
62
+ const found = TOP_LEVEL.filter(d => fs.existsSync(path.join(root, d)));
63
+ // Walk up to 3 levels deep looking for __tests__ dirs inside src
64
+ const SKIP = new Set(['node_modules', '.git', 'dist', 'build', 'coverage', '.next', '.reports', '.swarm', '.claude-flow']);
65
+ function walk(dir, depth) {
66
+ if (depth > 3)
67
+ return;
68
+ try {
69
+ const entries = fs.readdirSync(path.join(root, dir), { withFileTypes: true });
70
+ for (const entry of entries) {
71
+ if (!entry.isDirectory() || SKIP.has(entry.name))
72
+ continue;
73
+ const rel = dir ? `${dir}/${entry.name}` : entry.name;
74
+ if (entry.name === '__tests__') {
75
+ found.push(rel);
76
+ }
77
+ else {
78
+ walk(rel, depth + 1);
79
+ }
80
+ }
81
+ }
82
+ catch { /* skip unreadable directories */ }
83
+ }
84
+ walk('', 0);
85
+ return found;
86
+ }
56
87
  /**
57
88
  * Discover source directories by walking the project tree.
58
89
  * Finds directories named 'src' (or top-level 'packages', 'lib', etc.)
@@ -140,6 +171,22 @@ async function runWizard(root) {
140
171
  });
141
172
  srcDirs = answer.split(',').map((d) => d.trim()).filter(Boolean);
142
173
  }
174
+ // Detect test directories
175
+ const detectedTests = discoverTestDirs(root);
176
+ const tests = await confirm({
177
+ message: detectedTests.length > 0
178
+ ? `Found tests in ${detectedTests.join(', ')}. Enable test file indexing?`
179
+ : 'Enable test file indexing?',
180
+ default: true,
181
+ });
182
+ let testDirs = detectedTests.length > 0 ? detectedTests : ['tests'];
183
+ if (tests) {
184
+ const answer = await input({
185
+ message: 'Test directories (comma-separated):',
186
+ default: testDirs.join(', '),
187
+ });
188
+ testDirs = answer.split(',').map((d) => d.trim()).filter(Boolean);
189
+ }
143
190
  const gates = await confirm({
144
191
  message: 'Enable workflow gates (memory-first, task-create-before-agents)?',
145
192
  default: true,
@@ -148,7 +195,7 @@ async function runWizard(root) {
148
195
  message: 'Enable session-end hook (saves session state)?',
149
196
  default: true,
150
197
  });
151
- return { guidance, guidanceDirs, codeMap, srcDirs, gates, stopHook };
198
+ return { guidance, guidanceDirs, codeMap, srcDirs, tests, testDirs, gates, stopHook };
152
199
  }
153
200
  /**
154
201
  * Get default answers (--yes mode).
@@ -160,13 +207,16 @@ function defaultAnswers(root) {
160
207
  const srcDirs = discoverSrcDirs(root);
161
208
  if (srcDirs.length === 0)
162
209
  srcDirs.push('src');
163
- return { guidance: true, guidanceDirs, codeMap: true, srcDirs, gates: true, stopHook: true };
210
+ const testDirs = discoverTestDirs(root);
211
+ if (testDirs.length === 0)
212
+ testDirs.push('tests');
213
+ return { guidance: true, guidanceDirs, codeMap: true, srcDirs, tests: true, testDirs, gates: true, stopHook: true };
164
214
  }
165
215
  /**
166
216
  * Get minimal answers (--minimal mode).
167
217
  */
168
218
  function minimalAnswers() {
169
- return { guidance: false, guidanceDirs: [], codeMap: false, srcDirs: [], gates: false, stopHook: false };
219
+ return { guidance: false, guidanceDirs: [], codeMap: false, srcDirs: [], tests: false, testDirs: [], gates: false, stopHook: false };
170
220
  }
171
221
  export async function initMoflo(options) {
172
222
  const { projectRoot, force, interactive, minimal } = options;
@@ -204,6 +254,7 @@ function generateConfig(root, force, answers) {
204
254
  const projectName = path.basename(root);
205
255
  const guidanceDirs = answers?.guidanceDirs ?? ['.claude/guidance'];
206
256
  const srcDirs = answers?.srcDirs ?? ['src'];
257
+ const testDirs = answers?.testDirs ?? ['tests'];
207
258
  const gatesEnabled = answers?.gates ?? true;
208
259
  // Detect languages
209
260
  const extensions = new Set();
@@ -240,6 +291,15 @@ ${srcDirs.map(d => ` - ${d}`).join('\n')}
240
291
  exclude: [node_modules, dist, .next, coverage, build, __pycache__, target, .git]
241
292
  namespace: code-map
242
293
 
294
+ # Test file discovery and indexing
295
+ tests:
296
+ directories:
297
+ ${testDirs.map(d => ` - ${d}`).join('\n')}
298
+ patterns: ["*.test.*", "*.spec.*", "*.test-*"]
299
+ extensions: [".ts", ".tsx", ".js", ".jsx"]
300
+ exclude: [node_modules, coverage, dist]
301
+ namespace: tests
302
+
243
303
  # Workflow gates (enforced via Claude Code hooks)
244
304
  gates:
245
305
  memory_first: ${gatesEnabled}
@@ -250,6 +310,7 @@ gates:
250
310
  auto_index:
251
311
  guidance: ${answers?.guidance ?? true}
252
312
  code_map: ${answers?.codeMap ?? true}
313
+ tests: ${answers?.tests ?? true}
253
314
 
254
315
  # Memory backend
255
316
  memory:
@@ -432,7 +493,7 @@ function generateHooks(root, force, answers) {
432
493
  }]
433
494
  },
434
495
  {
435
- "matcher": "^mcp__claude-flow__memory_(search|retrieve)$",
496
+ "matcher": "^mcp__moflo__memory_(search|retrieve)$",
436
497
  "hooks": [{
437
498
  "type": "command",
438
499
  "command": "npx flo gate record-memory-searched",
@@ -590,7 +651,7 @@ This project uses [MoFlo](https://github.com/eric-cielo/moflo) for AI-assisted d
590
651
  Your first tool call for every new user prompt MUST be a memory search. Do this BEFORE Glob, Grep, Read, or any file exploration.
591
652
 
592
653
  \`\`\`
593
- mcp__claude-flow__memory_search — query: "<task description>", namespace: "guidance" or "patterns" or "knowledge" or "code-map"
654
+ mcp__moflo__memory_search — query: "<task description>", namespace: "guidance" or "patterns" or "knowledge" or "code-map"
594
655
  \`\`\`
595
656
 
596
657
  For codebase navigation, search the \`code-map\` namespace first. For patterns and domain knowledge, search \`patterns\`, \`knowledge\`, and \`guidance\`.
@@ -612,11 +673,11 @@ Research → Enhance → Implement → Test → Simplify → PR
612
673
 
613
674
  | Tool | Purpose |
614
675
  |------|---------|
615
- | \`mcp__claude-flow__memory_search\` | Semantic search across indexed knowledge |
616
- | \`mcp__claude-flow__memory_store\` | Store patterns and decisions |
617
- | \`mcp__claude-flow__hooks_route\` | Route task to optimal agent type |
618
- | \`mcp__claude-flow__hooks_pre-task\` | Record task start |
619
- | \`mcp__claude-flow__hooks_post-task\` | Record task completion for learning |
676
+ | \`mcp__moflo__memory_search\` | Semantic search across indexed knowledge |
677
+ | \`mcp__moflo__memory_store\` | Store patterns and decisions |
678
+ | \`mcp__moflo__hooks_route\` | Route task to optimal agent type |
679
+ | \`mcp__moflo__hooks_pre-task\` | Record task start |
680
+ | \`mcp__moflo__hooks_post-task\` | Record task completion for learning |
620
681
 
621
682
  ### Agent Icon Mapping
622
683
 
@@ -659,6 +720,7 @@ const SCRIPT_MAP = {
659
720
  'build-embeddings.mjs': 'build-embeddings.mjs',
660
721
  'generate-code-map.mjs': 'generate-code-map.mjs',
661
722
  'semantic-search.mjs': 'semantic-search.mjs',
723
+ 'index-tests.mjs': 'index-tests.mjs',
662
724
  };
663
725
  function syncScripts(root, force) {
664
726
  const scriptsDir = path.join(root, '.claude', 'scripts');
@@ -22,7 +22,7 @@ export function generateSettings(options) {
22
22
  'Bash(npx moflo*)',
23
23
  'Bash(npx flo*)',
24
24
  'Bash(node .claude/*)',
25
- 'mcp__claude-flow__:*',
25
+ 'mcp__moflo__:*',
26
26
  ],
27
27
  deny: [
28
28
  'Read(./.env)',
@@ -176,6 +176,14 @@ function autoMemoryCmd(subcommand) {
176
176
  function gateCmd(subcommand) {
177
177
  return hookCmd('"$CLAUDE_PROJECT_DIR/.claude/helpers/gate.cjs"', subcommand);
178
178
  }
179
+ /** Gate hook wrapper — reads stdin JSON for tool input, uses exit code 2 for blocking */
180
+ function gateHookCmd(subcommand) {
181
+ return hookCmdEsm('"$CLAUDE_PROJECT_DIR/.claude/helpers/gate-hook.mjs"', subcommand);
182
+ }
183
+ /** Prompt hook — reads stdin JSON for user prompt, classifies namespace */
184
+ function promptHookCmd() {
185
+ return `node "$CLAUDE_PROJECT_DIR/.claude/helpers/prompt-hook.mjs"`;
186
+ }
179
187
  /**
180
188
  * Generate statusLine configuration for Claude Code
181
189
  * Uses local helper script for cross-platform compatibility (no npx cold-start)
@@ -194,7 +202,7 @@ function generateStatusLineConfig(_options) {
194
202
  /**
195
203
  * Generate hooks configuration
196
204
  * All hooks use direct node invocation via lightweight helper scripts
197
- * (gate.cjs, hook-handler.cjs) instead of `npx flo` to avoid spawning
205
+ * (gate.cjs, gate-hook.mjs, hook-handler.cjs) instead of `npx flo` to avoid spawning
198
206
  * a full CLI process on every tool call.
199
207
  */
200
208
  function generateHooksConfig(config) {
@@ -208,22 +216,21 @@ function generateHooksConfig(config) {
208
216
  },
209
217
  {
210
218
  matcher: '^(Glob|Grep)$',
211
- hooks: [{ type: 'command', command: gateCmd('check-before-scan'), timeout: 3000 }],
219
+ hooks: [{ type: 'command', command: gateHookCmd('check-before-scan'), timeout: 3000 }],
212
220
  },
213
221
  {
214
222
  matcher: '^Read$',
215
- hooks: [{ type: 'command', command: gateCmd('check-before-read'), timeout: 3000 }],
223
+ hooks: [{ type: 'command', command: gateHookCmd('check-before-read'), timeout: 3000 }],
216
224
  },
217
225
  {
218
- matcher: '^Task$',
226
+ matcher: '^Agent$',
219
227
  hooks: [
220
- { type: 'command', command: gateCmd('check-before-agent'), timeout: 3000 },
221
- { type: 'command', command: hookHandlerCmd('pre-task'), timeout: 5000 },
228
+ { type: 'command', command: gateHookCmd('check-before-agent'), timeout: 3000 },
222
229
  ],
223
230
  },
224
231
  {
225
232
  matcher: '^Bash$',
226
- hooks: [{ type: 'command', command: gateCmd('check-dangerous-command'), timeout: 2000 }],
233
+ hooks: [{ type: 'command', command: gateHookCmd('check-dangerous-command'), timeout: 2000 }],
227
234
  },
228
235
  ];
229
236
  }
@@ -235,20 +242,23 @@ function generateHooksConfig(config) {
235
242
  hooks: [{ type: 'command', command: hookHandlerCmd('post-edit'), timeout: 5000 }],
236
243
  },
237
244
  {
238
- matcher: '^Task$',
245
+ matcher: '^Agent$',
239
246
  hooks: [{ type: 'command', command: hookHandlerCmd('post-task'), timeout: 5000 }],
240
247
  },
241
248
  {
249
+ // TaskCreate PostToolUse only fires in some Claude Code versions.
250
+ // The prompt-reminder and soft gate in check-before-agent handle the common case.
242
251
  matcher: '^TaskCreate$',
243
252
  hooks: [{ type: 'command', command: gateCmd('record-task-created'), timeout: 2000 }],
244
253
  },
245
254
  {
246
255
  matcher: '^Bash$',
247
- hooks: [{ type: 'command', command: gateCmd('check-bash-memory'), timeout: 2000 }],
256
+ hooks: [{ type: 'command', command: gateHookCmd('check-bash-memory'), timeout: 2000 }],
248
257
  },
249
258
  {
250
- matcher: '^mcp__claude-flow__memory_(search|retrieve)$',
251
- hooks: [{ type: 'command', command: gateCmd('record-memory-searched'), timeout: 2000 }],
259
+ // Simplified matcher — anchored regex with parens doesn't match MCP tool names reliably
260
+ matcher: 'mcp__moflo__memory_',
261
+ hooks: [{ type: 'command', command: gateCmd('record-memory-searched'), timeout: 3000 }],
252
262
  },
253
263
  ];
254
264
  }
@@ -257,8 +267,7 @@ function generateHooksConfig(config) {
257
267
  hooks.UserPromptSubmit = [
258
268
  {
259
269
  hooks: [
260
- { type: 'command', command: gateCmd('prompt-reminder'), timeout: 2000 },
261
- { type: 'command', command: hookHandlerCmd('route'), timeout: 5000 },
270
+ { type: 'command', command: promptHookCmd(), timeout: 3000 },
262
271
  ],
263
272
  },
264
273
  ];
@@ -274,7 +274,7 @@ export class MCPServerManager extends EventEmitter {
274
274
  method: 'server.initialized',
275
275
  params: {
276
276
  serverInfo: {
277
- name: 'claude-flow',
277
+ name: 'moflo',
278
278
  version: VERSION,
279
279
  capabilities: {
280
280
  tools: { listChanged: true },
@@ -388,7 +388,7 @@ export class MCPServerManager extends EventEmitter {
388
388
  id: message.id,
389
389
  result: {
390
390
  protocolVersion: '2024-11-05',
391
- serverInfo: { name: 'claude-flow', version: '3.0.0' },
391
+ serverInfo: { name: 'moflo', version: '3.0.0' },
392
392
  capabilities: {
393
393
  tools: { listChanged: true },
394
394
  resources: { subscribe: true, listChanged: true },
@@ -480,7 +480,7 @@ export class MCPServerManager extends EventEmitter {
480
480
  error: (msg, data) => this.emit('log', { level: 'error', msg, data }),
481
481
  };
482
482
  const mcpServer = createMCPServer({
483
- name: 'Claude-Flow MCP Server V3',
483
+ name: 'MoFlo MCP Server V3',
484
484
  version: '3.0.0',
485
485
  transport: this.options.transport,
486
486
  host: this.options.host,
@@ -114,10 +114,11 @@ export class PluginManager {
114
114
  if (fs.existsSync(packageJsonPath)) {
115
115
  const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
116
116
  installedVersion = pkg.version;
117
- // Check for claude-flow plugin metadata
118
- if (pkg['claude-flow']) {
119
- commands = pkg['claude-flow'].commands || [];
120
- hooks = pkg['claude-flow'].hooks || [];
117
+ // Check for moflo/claude-flow plugin metadata (backward compat)
118
+ const pluginMeta = pkg['moflo'] || pkg['claude-flow'];
119
+ if (pluginMeta) {
120
+ commands = pluginMeta.commands || [];
121
+ hooks = pluginMeta.hooks || [];
121
122
  }
122
123
  }
123
124
  // Create plugin entry
@@ -177,8 +178,8 @@ export class PluginManager {
177
178
  enabled: true,
178
179
  source: 'local',
179
180
  path: absolutePath,
180
- commands: pkg['claude-flow']?.commands || [],
181
- hooks: pkg['claude-flow']?.hooks || [],
181
+ commands: (pkg['moflo'] || pkg['claude-flow'])?.commands || [],
182
+ hooks: (pkg['moflo'] || pkg['claude-flow'])?.hooks || [],
182
183
  };
183
184
  // Save to manifest
184
185
  this.manifest.plugins[packageName] = plugin;
@@ -338,8 +339,8 @@ export class PluginManager {
338
339
  if (fs.existsSync(packageJsonPath)) {
339
340
  const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
340
341
  existing.version = pkg.version;
341
- existing.commands = pkg['claude-flow']?.commands || existing.commands;
342
- existing.hooks = pkg['claude-flow']?.hooks || existing.hooks;
342
+ existing.commands = (pkg['moflo'] || pkg['claude-flow'])?.commands || existing.commands;
343
+ existing.hooks = (pkg['moflo'] || pkg['claude-flow'])?.hooks || existing.hooks;
343
344
  }
344
345
  await this.saveManifest();
345
346
  console.log(`[PluginManager] Upgraded ${packageName} to ${existing.version}`);