moflo 4.7.7 → 4.8.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 (61) hide show
  1. package/.claude/helpers/statusline.cjs +34 -26
  2. package/.claude/settings.json +2 -2
  3. package/README.md +1 -1
  4. package/bin/hooks.mjs +33 -3
  5. package/bin/session-start-launcher.mjs +88 -3
  6. package/package.json +3 -5
  7. package/src/@claude-flow/cli/README.md +1 -1
  8. package/src/@claude-flow/cli/dist/src/commands/daemon.js +42 -95
  9. package/src/@claude-flow/cli/dist/src/commands/doctor.js +11 -5
  10. package/src/@claude-flow/cli/dist/src/commands/init.js +0 -145
  11. package/src/@claude-flow/cli/dist/src/config/moflo-config.d.ts +5 -0
  12. package/src/@claude-flow/cli/dist/src/config/moflo-config.js +16 -0
  13. package/src/@claude-flow/cli/dist/src/config-adapter.d.ts +1 -1
  14. package/src/@claude-flow/cli/dist/src/init/executor.js +74 -7
  15. package/src/@claude-flow/cli/dist/src/init/mcp-generator.d.ts +3 -4
  16. package/src/@claude-flow/cli/dist/src/init/mcp-generator.js +65 -22
  17. package/src/@claude-flow/cli/dist/src/init/types.d.ts +0 -4
  18. package/src/@claude-flow/cli/dist/src/init/types.js +0 -5
  19. package/src/@claude-flow/cli/dist/src/mcp-server.js +36 -0
  20. package/src/@claude-flow/cli/dist/src/memory/memory-bridge.d.ts +6 -0
  21. package/src/@claude-flow/cli/dist/src/memory/memory-bridge.js +66 -0
  22. package/src/@claude-flow/cli/dist/src/memory/memory-initializer.js +52 -1
  23. package/src/@claude-flow/cli/dist/src/services/daemon-lock.d.ts +39 -0
  24. package/src/@claude-flow/cli/dist/src/services/daemon-lock.js +213 -0
  25. package/src/@claude-flow/cli/package.json +2 -6
  26. package/.claude/helpers/README.md +0 -97
  27. package/.claude/helpers/adr-compliance.sh +0 -186
  28. package/.claude/helpers/aggressive-microcompact.mjs +0 -36
  29. package/.claude/helpers/auto-commit.sh +0 -178
  30. package/.claude/helpers/checkpoint-manager.sh +0 -251
  31. package/.claude/helpers/context-persistence-hook.mjs +0 -1979
  32. package/.claude/helpers/daemon-manager.sh +0 -252
  33. package/.claude/helpers/ddd-tracker.sh +0 -144
  34. package/.claude/helpers/github-safe.js +0 -106
  35. package/.claude/helpers/github-setup.sh +0 -28
  36. package/.claude/helpers/guidance-hook.sh +0 -13
  37. package/.claude/helpers/guidance-hooks.sh +0 -102
  38. package/.claude/helpers/health-monitor.sh +0 -108
  39. package/.claude/helpers/learning-hooks.sh +0 -329
  40. package/.claude/helpers/learning-optimizer.sh +0 -127
  41. package/.claude/helpers/learning-service.mjs +0 -1211
  42. package/.claude/helpers/memory.cjs +0 -84
  43. package/.claude/helpers/metrics-db.mjs +0 -492
  44. package/.claude/helpers/patch-aggressive-prune.mjs +0 -184
  45. package/.claude/helpers/pattern-consolidator.sh +0 -86
  46. package/.claude/helpers/perf-worker.sh +0 -160
  47. package/.claude/helpers/quick-start.sh +0 -19
  48. package/.claude/helpers/router.cjs +0 -62
  49. package/.claude/helpers/security-scanner.sh +0 -127
  50. package/.claude/helpers/session.cjs +0 -125
  51. package/.claude/helpers/setup-mcp.sh +0 -18
  52. package/.claude/helpers/standard-checkpoint-hooks.sh +0 -189
  53. package/.claude/helpers/swarm-comms.sh +0 -353
  54. package/.claude/helpers/swarm-hooks.sh +0 -761
  55. package/.claude/helpers/swarm-monitor.sh +0 -211
  56. package/.claude/helpers/sync-v3-metrics.sh +0 -245
  57. package/.claude/helpers/update-v3-progress.sh +0 -166
  58. package/.claude/helpers/v3-quick-status.sh +0 -58
  59. package/.claude/helpers/v3.sh +0 -111
  60. package/.claude/helpers/validate-v3-config.sh +0 -216
  61. package/.claude/helpers/worker-manager.sh +0 -170
@@ -7,129 +7,6 @@ import { confirm, select, multiSelect, input } from '../prompt.js';
7
7
  import * as fs from 'fs';
8
8
  import * as path from 'path';
9
9
  import { executeInit, executeUpgrade, executeUpgradeWithMissing, DEFAULT_INIT_OPTIONS, MINIMAL_INIT_OPTIONS, FULL_INIT_OPTIONS, } from '../init/index.js';
10
- // Codex initialization action
11
- async function initCodexAction(ctx, options) {
12
- const { force, minimal, full, dualMode } = options;
13
- output.writeln();
14
- output.writeln(output.bold('Initializing MoFlo V4 for OpenAI Codex'));
15
- output.writeln();
16
- // Determine template
17
- const template = minimal ? 'minimal' : full ? 'full' : 'default';
18
- const spinner = output.createSpinner({ text: 'Initializing Codex project...' });
19
- spinner.start();
20
- try {
21
- // Dynamic import of the Codex initializer with lazy loading fallback
22
- let CodexInitializer;
23
- // Try multiple resolution strategies for the @claude-flow/codex package
24
- // Use a variable to prevent TypeScript from statically resolving the optional module
25
- const codexModuleId = '@claude-flow/codex';
26
- const resolutionStrategies = [
27
- // Strategy 1: Direct import (works if installed as CLI dependency)
28
- async () => (await import(codexModuleId)).CodexInitializer,
29
- // Strategy 2: Project node_modules (works if installed in user's project)
30
- async () => {
31
- const projectPath = path.join(ctx.cwd, 'node_modules', '@claude-flow', 'codex', 'dist', 'index.js');
32
- if (fs.existsSync(projectPath)) {
33
- const mod = await import(`file://${projectPath}`);
34
- return mod.CodexInitializer;
35
- }
36
- throw new Error('Not found in project');
37
- },
38
- // Strategy 3: Global node_modules
39
- async () => {
40
- const { execSync } = await import('child_process');
41
- const globalPath = execSync('npm root -g', { encoding: 'utf-8', windowsHide: true }).trim();
42
- const codexPath = path.join(globalPath, '@claude-flow', 'codex', 'dist', 'index.js');
43
- if (fs.existsSync(codexPath)) {
44
- const mod = await import(`file://${codexPath}`);
45
- return mod.CodexInitializer;
46
- }
47
- throw new Error('Not found globally');
48
- },
49
- ];
50
- for (const strategy of resolutionStrategies) {
51
- try {
52
- CodexInitializer = await strategy();
53
- if (CodexInitializer)
54
- break;
55
- }
56
- catch {
57
- // Try next strategy
58
- }
59
- }
60
- if (!CodexInitializer) {
61
- throw new Error('Cannot find module @claude-flow/codex');
62
- }
63
- const initializer = new CodexInitializer();
64
- const result = await initializer.initialize({
65
- projectPath: ctx.cwd,
66
- template: template,
67
- force,
68
- dual: dualMode,
69
- });
70
- if (!result.success) {
71
- spinner.fail('Codex initialization failed');
72
- if (result.errors) {
73
- for (const error of result.errors) {
74
- output.printError(error);
75
- }
76
- }
77
- return { success: false, exitCode: 1 };
78
- }
79
- spinner.succeed('Codex project initialized successfully!');
80
- output.writeln();
81
- // Display summary
82
- const summary = [];
83
- summary.push(`Files: ${result.filesCreated.length} created`);
84
- summary.push(`Skills: ${result.skillsGenerated.length} installed`);
85
- output.printBox(summary.join('\n'), 'Summary');
86
- output.writeln();
87
- // Show what was created
88
- output.printBox([
89
- `AGENTS.md: Main project instructions`,
90
- `.agents/config.toml: Project configuration`,
91
- `.agents/skills/: ${result.skillsGenerated.length} skills`,
92
- `.codex/: Local overrides (gitignored)`,
93
- dualMode ? `CLAUDE.md: Claude Code compatibility` : '',
94
- ].filter(Boolean).join('\n'), 'OpenAI Codex Integration');
95
- output.writeln();
96
- // Warnings
97
- if (result.warnings && result.warnings.length > 0) {
98
- output.printWarning('Warnings:');
99
- for (const warning of result.warnings.slice(0, 5)) {
100
- output.printInfo(` • ${warning}`);
101
- }
102
- if (result.warnings.length > 5) {
103
- output.printInfo(` ... and ${result.warnings.length - 5} more`);
104
- }
105
- output.writeln();
106
- }
107
- // Next steps
108
- output.writeln(output.bold('Next steps:'));
109
- output.printList([
110
- `Review ${output.highlight('AGENTS.md')} for project instructions`,
111
- `Add skills with ${output.highlight('$skill-name')} syntax`,
112
- `Configure ${output.highlight('.agents/config.toml')} for your project`,
113
- dualMode ? `Claude Code users can use ${output.highlight('CLAUDE.md')}` : '',
114
- ].filter(Boolean));
115
- return { success: true, data: result };
116
- }
117
- catch (error) {
118
- spinner.fail('Codex initialization failed');
119
- const errorMessage = error instanceof Error ? error.message : String(error);
120
- // Handle module not found error gracefully
121
- if (errorMessage.includes('Cannot find module') || errorMessage.includes('@claude-flow/codex')) {
122
- output.printError('The @claude-flow/codex package is not installed.');
123
- output.printInfo('Install it with: npm install @claude-flow/codex');
124
- output.writeln();
125
- output.printInfo('Alternatively, copy skills manually from .claude/skills/ to .agents/skills/');
126
- }
127
- else {
128
- output.printError(`Failed to initialize: ${errorMessage}`);
129
- }
130
- return { success: false, exitCode: 1 };
131
- }
132
- }
133
10
  // Check if project is already initialized
134
11
  function isInitialized(cwd) {
135
12
  const claudePath = path.join(cwd, '.claude', 'settings.json');
@@ -146,13 +23,7 @@ const initAction = async (ctx) => {
146
23
  const full = ctx.flags.full;
147
24
  const skipClaude = ctx.flags['skip-claude'];
148
25
  const onlyClaude = ctx.flags['only-claude'];
149
- const codexMode = ctx.flags.codex;
150
- const dualMode = ctx.flags.dual;
151
26
  const cwd = ctx.cwd;
152
- // If codex mode, use the Codex initializer
153
- if (codexMode || dualMode) {
154
- return initCodexAction(ctx, { codexMode, dualMode, force, minimal, full });
155
- }
156
27
  // ── MoFlo Project Setup ────────────────────────────────────────────
157
28
  // Always run MoFlo init to ensure moflo.yaml, hooks, skill, and
158
29
  // CLAUDE.md are set up, regardless of other init options.
@@ -708,7 +579,6 @@ const skillsCommand = {
708
579
  flowNexus: false,
709
580
  browser: false,
710
581
  v3: ctx.flags.v3,
711
- dualMode: false,
712
582
  },
713
583
  };
714
584
  const spinner = output.createSpinner({ text: 'Installing skills...' });
@@ -971,18 +841,6 @@ export const initCommand = {
971
841
  default: 'all-MiniLM-L6-v2',
972
842
  choices: ['all-MiniLM-L6-v2', 'all-mpnet-base-v2'],
973
843
  },
974
- {
975
- name: 'codex',
976
- description: 'Initialize for OpenAI Codex CLI (creates AGENTS.md, .agents/)',
977
- type: 'boolean',
978
- default: false,
979
- },
980
- {
981
- name: 'dual',
982
- description: 'Initialize for both Claude Code and OpenAI Codex',
983
- type: 'boolean',
984
- default: false,
985
- },
986
844
  ],
987
845
  examples: [
988
846
  { command: 'claude-flow init', description: 'Initialize with default configuration' },
@@ -1001,9 +859,6 @@ export const initCommand = {
1001
859
  { command: 'claude-flow init upgrade', description: 'Update helpers while preserving data' },
1002
860
  { command: 'claude-flow init upgrade --settings', description: 'Update helpers and merge new settings (Agent Teams)' },
1003
861
  { command: 'claude-flow init upgrade --verbose', description: 'Show detailed upgrade info' },
1004
- { command: 'claude-flow init --codex', description: 'Initialize for OpenAI Codex (AGENTS.md)' },
1005
- { command: 'claude-flow init --codex --full', description: 'Codex init with all 137+ skills' },
1006
- { command: 'claude-flow init --dual', description: 'Initialize for both Claude Code and Codex' },
1007
862
  ],
1008
863
  action: initAction,
1009
864
  };
@@ -50,6 +50,11 @@ export interface MofloConfig {
50
50
  circuit_breaker: boolean;
51
51
  agent_overrides: Record<string, string>;
52
52
  };
53
+ auto_update: {
54
+ enabled: boolean;
55
+ scripts: boolean;
56
+ helpers: boolean;
57
+ };
53
58
  status_line: {
54
59
  enabled: boolean;
55
60
  branding: string;
@@ -69,6 +69,11 @@ const DEFAULT_CONFIG = {
69
69
  circuit_breaker: true,
70
70
  agent_overrides: {},
71
71
  },
72
+ auto_update: {
73
+ enabled: true,
74
+ scripts: true,
75
+ helpers: true,
76
+ },
72
77
  status_line: {
73
78
  enabled: true,
74
79
  branding: 'Moflo V4',
@@ -159,6 +164,11 @@ function mergeConfig(raw, root) {
159
164
  circuit_breaker: raw.model_routing?.circuit_breaker ?? raw.modelRouting?.circuitBreaker ?? DEFAULT_CONFIG.model_routing.circuit_breaker,
160
165
  agent_overrides: raw.model_routing?.agent_overrides ?? raw.modelRouting?.agentOverrides ?? DEFAULT_CONFIG.model_routing.agent_overrides,
161
166
  },
167
+ auto_update: {
168
+ enabled: raw.auto_update?.enabled ?? raw.autoUpdate?.enabled ?? DEFAULT_CONFIG.auto_update.enabled,
169
+ scripts: raw.auto_update?.scripts ?? raw.autoUpdate?.scripts ?? DEFAULT_CONFIG.auto_update.scripts,
170
+ helpers: raw.auto_update?.helpers ?? raw.autoUpdate?.helpers ?? DEFAULT_CONFIG.auto_update.helpers,
171
+ },
162
172
  status_line: {
163
173
  enabled: raw.status_line?.enabled ?? raw.statusLine?.enabled ?? DEFAULT_CONFIG.status_line.enabled,
164
174
  branding: raw.status_line?.branding ?? raw.statusLine?.branding ?? DEFAULT_CONFIG.status_line.branding,
@@ -314,6 +324,12 @@ model_routing:
314
324
  # security-architect: opus # Always use opus for security
315
325
  # researcher: sonnet # Pin research to sonnet
316
326
 
327
+ # Auto-update on session start (syncs scripts and helpers when moflo version changes)
328
+ auto_update:
329
+ enabled: true # Master toggle for version-change auto-sync
330
+ scripts: true # Sync .claude/scripts/ from moflo bin/
331
+ helpers: true # Sync .claude/helpers/ from moflo source
332
+
317
333
  # Status line items (show/hide individual sections)
318
334
  status_line:
319
335
  enabled: true
@@ -2,7 +2,7 @@
2
2
  * Configuration Adapter
3
3
  * Converts between SystemConfig and V3Config types
4
4
  */
5
- import type { SystemConfig } from '@claude-flow/shared';
5
+ import type { SystemConfig } from '../../shared/src/index.js';
6
6
  import type { V3Config } from './types.js';
7
7
  /**
8
8
  * Convert SystemConfig to V3Config (CLI-specific format)
@@ -31,7 +31,6 @@ const SKILLS_MAP = {
31
31
  'skill-builder',
32
32
  ],
33
33
  browser: ['browser'], // agent-browser integration
34
- dualMode: ['dual-mode'], // Claude Code + Codex hybrid execution
35
34
  agentdb: [
36
35
  'agentdb-advanced',
37
36
  'agentdb-learning',
@@ -89,7 +88,6 @@ const AGENTS_MAP = {
89
88
  sparc: ['sparc'],
90
89
  swarm: ['swarm'],
91
90
  browser: ['browser'], // agent-browser integration
92
- dualMode: ['dual-mode'], // Claude Code + Codex hybrid execution
93
91
  // V3-specific agents
94
92
  v3: ['v3'],
95
93
  optimization: ['optimization'],
@@ -425,6 +423,46 @@ export async function executeUpgrade(targetDir, upgradeSettings = false) {
425
423
  };
426
424
  fs.writeFileSync(statuslinePath, generateStatuslineScript(upgradeOptions), 'utf-8');
427
425
  }
426
+ // 1b. ALWAYS sync .claude/scripts/ from moflo bin/ (derived files, not user-edited)
427
+ // Scripts contain critical daemon guards, hook logic, etc. that must stay in sync.
428
+ const scriptsDir = path.join(targetDir, '.claude', 'scripts');
429
+ if (!fs.existsSync(scriptsDir)) {
430
+ fs.mkdirSync(scriptsDir, { recursive: true });
431
+ }
432
+ const UPGRADE_SCRIPT_MAP = {
433
+ 'hooks.mjs': 'hooks.mjs',
434
+ 'session-start-launcher.mjs': 'session-start-launcher.mjs',
435
+ 'index-guidance.mjs': 'index-guidance.mjs',
436
+ 'build-embeddings.mjs': 'build-embeddings.mjs',
437
+ 'generate-code-map.mjs': 'generate-code-map.mjs',
438
+ 'semantic-search.mjs': 'semantic-search.mjs',
439
+ };
440
+ const binDir = findMofloBinDir();
441
+ if (binDir) {
442
+ for (const [destName, srcName] of Object.entries(UPGRADE_SCRIPT_MAP)) {
443
+ const srcPath = path.join(binDir, srcName);
444
+ const destPath = path.join(scriptsDir, destName);
445
+ if (!fs.existsSync(srcPath))
446
+ continue;
447
+ try {
448
+ const srcStat = fs.statSync(srcPath);
449
+ const destExists = fs.existsSync(destPath);
450
+ // Always overwrite if source is newer or dest doesn't exist
451
+ if (!destExists || srcStat.mtimeMs > fs.statSync(destPath).mtimeMs) {
452
+ fs.copyFileSync(srcPath, destPath);
453
+ if (destExists) {
454
+ result.updated.push(`.claude/scripts/${destName}`);
455
+ }
456
+ else {
457
+ result.created.push(`.claude/scripts/${destName}`);
458
+ }
459
+ }
460
+ }
461
+ catch {
462
+ // Non-fatal — skip individual script on error
463
+ }
464
+ }
465
+ }
428
466
  // 2. Create MISSING metrics files only (preserve existing data)
429
467
  const metricsDir = path.join(targetDir, '.claude-flow', 'metrics');
430
468
  const securityDir = path.join(targetDir, '.claude-flow', 'security');
@@ -711,8 +749,6 @@ async function copySkills(targetDir, options, result) {
711
749
  skillsToCopy.push(...SKILLS_MAP.browser);
712
750
  if (skillsConfig.v3)
713
751
  skillsToCopy.push(...SKILLS_MAP.v3);
714
- if (skillsConfig.dualMode)
715
- skillsToCopy.push(...SKILLS_MAP.dualMode);
716
752
  }
717
753
  // Find source skills directory
718
754
  const sourceSkillsDir = findSourceDir('skills', options.sourceBaseDir);
@@ -825,9 +861,6 @@ async function copyAgents(targetDir, options, result) {
825
861
  agentsToCopy.push(...(AGENTS_MAP.optimization || []));
826
862
  if (agentsConfig.testing)
827
863
  agentsToCopy.push(...(AGENTS_MAP.testing || []));
828
- // Dual-mode agents (Claude Code + Codex hybrid)
829
- if (agentsConfig.dualMode)
830
- agentsToCopy.push(...(AGENTS_MAP.dualMode || []));
831
864
  }
832
865
  // Find source agents directory
833
866
  const sourceAgentsDir = findSourceDir('agents', options.sourceBaseDir);
@@ -905,6 +938,40 @@ function findSourceHelpersDir(sourceBaseDir) {
905
938
  }
906
939
  return null;
907
940
  }
941
+ /**
942
+ * Find the moflo bin/ directory (source of truth for .claude/scripts/).
943
+ * Uses the same resolution strategies as findSourceHelpersDir.
944
+ */
945
+ function findMofloBinDir() {
946
+ const possiblePaths = [];
947
+ const SENTINEL_FILE = 'hooks.mjs'; // Must exist in valid bin/
948
+ // Strategy 1: require.resolve
949
+ try {
950
+ const esmRequire = createRequire(import.meta.url);
951
+ const pkgJsonPath = esmRequire.resolve('moflo/package.json');
952
+ possiblePaths.push(path.join(path.dirname(pkgJsonPath), 'bin'));
953
+ }
954
+ catch { /* not installed as package */ }
955
+ // Strategy 2: __dirname-based (dist/src/init -> package root -> bin)
956
+ possiblePaths.push(path.resolve(__dirname, '..', '..', '..', 'bin'));
957
+ // Strategy 3: Walk up from __dirname
958
+ let currentDir = __dirname;
959
+ for (let i = 0; i < 10; i++) {
960
+ const parentDir = path.dirname(currentDir);
961
+ if (parentDir === currentDir)
962
+ break;
963
+ possiblePaths.push(path.join(parentDir, 'bin'));
964
+ currentDir = parentDir;
965
+ }
966
+ // Strategy 4: cwd-relative (node_modules/moflo/bin)
967
+ possiblePaths.push(path.join(process.cwd(), 'node_modules', 'moflo', 'bin'));
968
+ for (const p of possiblePaths) {
969
+ if (fs.existsSync(p) && fs.existsSync(path.join(p, SENTINEL_FILE))) {
970
+ return p;
971
+ }
972
+ }
973
+ return null;
974
+ }
908
975
  /**
909
976
  * Write helper scripts
910
977
  */
@@ -2,10 +2,9 @@
2
2
  * MCP Configuration Generator
3
3
  * Creates .mcp.json for Claude Code MCP server integration
4
4
  *
5
- * Note: Claude Code spawns MCP servers as child processes using the
6
- * command/args from .mcp.json. On all platforms (including Windows),
7
- * using `npx` directly works correctly. The previous `cmd /c` wrapper
8
- * on Windows caused MCP servers to fail to start.
5
+ * Uses direct `node` invocation when moflo is locally installed to avoid
6
+ * npx overhead (package resolution, registry checks). Falls back to `npx`
7
+ * for external packages (ruv-swarm, flow-nexus) that may not be installed.
9
8
  */
10
9
  import type { InitOptions } from './types.js';
11
10
  /**
@@ -2,17 +2,16 @@
2
2
  * MCP Configuration Generator
3
3
  * Creates .mcp.json for Claude Code MCP server integration
4
4
  *
5
- * Note: Claude Code spawns MCP servers as child processes using the
6
- * command/args from .mcp.json. On all platforms (including Windows),
7
- * using `npx` directly works correctly. The previous `cmd /c` wrapper
8
- * on Windows caused MCP servers to fail to start.
5
+ * Uses direct `node` invocation when moflo is locally installed to avoid
6
+ * npx overhead (package resolution, registry checks). Falls back to `npx`
7
+ * for external packages (ruv-swarm, flow-nexus) that may not be installed.
9
8
  */
9
+ import { existsSync } from 'fs';
10
+ import { join } from 'path';
10
11
  /**
11
- * Generate MCP server entry
12
- * Uses `npx` directly on all platforms — Claude Code handles process
13
- * spawning correctly without needing a cmd.exe wrapper.
12
+ * Generate MCP server entry using npx (for external packages)
14
13
  */
15
- function createMCPServerEntry(npxArgs, env, additionalProps = {}) {
14
+ function createNpxServerEntry(npxArgs, env, additionalProps = {}) {
16
15
  return {
17
16
  command: 'npx',
18
17
  args: ['-y', ...npxArgs],
@@ -20,6 +19,35 @@ function createMCPServerEntry(npxArgs, env, additionalProps = {}) {
20
19
  ...additionalProps,
21
20
  };
22
21
  }
22
+ /**
23
+ * Generate MCP server entry using direct node invocation (for local moflo).
24
+ * Avoids npx overhead — faster startup, fewer intermediate processes.
25
+ */
26
+ function createDirectServerEntry(cliPath, cliArgs, env, additionalProps = {}) {
27
+ return {
28
+ command: 'node',
29
+ args: [cliPath, ...cliArgs],
30
+ env,
31
+ ...additionalProps,
32
+ };
33
+ }
34
+ /**
35
+ * Find the moflo CLI entry point relative to the project root.
36
+ * Returns the path if found, null otherwise.
37
+ */
38
+ function findMofloCli(projectRoot) {
39
+ const candidates = [
40
+ // Installed as dependency
41
+ join(projectRoot, 'node_modules', 'moflo', 'bin', 'cli.js'),
42
+ // Running from moflo repo itself
43
+ join(projectRoot, 'bin', 'cli.js'),
44
+ ];
45
+ for (const candidate of candidates) {
46
+ if (existsSync(candidate))
47
+ return candidate;
48
+ }
49
+ return null;
50
+ }
23
51
  /**
24
52
  * Generate MCP configuration
25
53
  */
@@ -32,24 +60,32 @@ export function generateMCPConfig(options) {
32
60
  // When toolDefer is true, emit "deferred" so Claude Code loads schemas on
33
61
  // demand via ToolSearch instead of putting 150+ schemas into context at startup.
34
62
  const deferProps = config.toolDefer ? { toolDefer: 'deferred' } : {};
35
- // Claude Flow MCP server (core)
63
+ const mcpEnv = {
64
+ ...npmEnv,
65
+ CLAUDE_FLOW_MODE: 'v3',
66
+ CLAUDE_FLOW_HOOKS_ENABLED: 'true',
67
+ CLAUDE_FLOW_TOPOLOGY: options.runtime.topology,
68
+ CLAUDE_FLOW_MAX_AGENTS: String(options.runtime.maxAgents),
69
+ CLAUDE_FLOW_MEMORY_BACKEND: options.runtime.memoryBackend,
70
+ };
71
+ // Claude Flow MCP server (core) — use direct node when locally installed
36
72
  if (config.claudeFlow) {
37
- mcpServers['claude-flow'] = createMCPServerEntry(['moflo', 'mcp', 'start'], {
38
- ...npmEnv,
39
- CLAUDE_FLOW_MODE: 'v3',
40
- CLAUDE_FLOW_HOOKS_ENABLED: 'true',
41
- CLAUDE_FLOW_TOPOLOGY: options.runtime.topology,
42
- CLAUDE_FLOW_MAX_AGENTS: String(options.runtime.maxAgents),
43
- CLAUDE_FLOW_MEMORY_BACKEND: options.runtime.memoryBackend,
44
- }, { autoStart: config.autoStart, ...deferProps });
73
+ const projectRoot = options.targetDir ?? process.cwd();
74
+ const localCli = findMofloCli(projectRoot);
75
+ if (localCli) {
76
+ mcpServers['claude-flow'] = createDirectServerEntry(localCli, ['mcp', 'start'], mcpEnv, { autoStart: config.autoStart, ...deferProps });
77
+ }
78
+ else {
79
+ mcpServers['claude-flow'] = createNpxServerEntry(['moflo', 'mcp', 'start'], mcpEnv, { autoStart: config.autoStart, ...deferProps });
80
+ }
45
81
  }
46
- // Ruv-Swarm MCP server (enhanced coordination)
82
+ // Ruv-Swarm MCP server (enhanced coordination) — always npx (external package)
47
83
  if (config.ruvSwarm) {
48
- mcpServers['ruv-swarm'] = createMCPServerEntry(['ruv-swarm', 'mcp', 'start'], { ...npmEnv }, { optional: true, ...deferProps });
84
+ mcpServers['ruv-swarm'] = createNpxServerEntry(['ruv-swarm', 'mcp', 'start'], { ...npmEnv }, { optional: true, ...deferProps });
49
85
  }
50
- // Flow Nexus MCP server (cloud features)
86
+ // Flow Nexus MCP server (cloud features) — always npx (external package)
51
87
  if (config.flowNexus) {
52
- mcpServers['flow-nexus'] = createMCPServerEntry(['flow-nexus@latest', 'mcp', 'start'], { ...npmEnv }, { optional: true, requiresAuth: true, ...deferProps });
88
+ mcpServers['flow-nexus'] = createNpxServerEntry(['flow-nexus@latest', 'mcp', 'start'], { ...npmEnv }, { optional: true, requiresAuth: true, ...deferProps });
53
89
  }
54
90
  return { mcpServers };
55
91
  }
@@ -67,7 +103,14 @@ export function generateMCPCommands(options) {
67
103
  const commands = [];
68
104
  const config = options.mcp;
69
105
  if (config.claudeFlow) {
70
- commands.push('claude mcp add claude-flow -- npx -y moflo mcp start');
106
+ const projectRoot = options.targetDir ?? process.cwd();
107
+ const localCli = findMofloCli(projectRoot);
108
+ if (localCli) {
109
+ commands.push(`claude mcp add claude-flow -- node ${localCli} mcp start`);
110
+ }
111
+ else {
112
+ commands.push('claude mcp add claude-flow -- npx -y moflo mcp start');
113
+ }
71
114
  }
72
115
  if (config.ruvSwarm) {
73
116
  commands.push('claude mcp add ruv-swarm -- npx -y ruv-swarm mcp start');
@@ -66,8 +66,6 @@ export interface SkillsConfig {
66
66
  browser: boolean;
67
67
  /** Include V3 implementation skills */
68
68
  v3: boolean;
69
- /** Include dual-mode skills (Claude Code + Codex hybrid) */
70
- dualMode: boolean;
71
69
  /** Include all available skills */
72
70
  all: boolean;
73
71
  }
@@ -118,8 +116,6 @@ export interface AgentsConfig {
118
116
  optimization: boolean;
119
117
  /** Include testing agents */
120
118
  testing: boolean;
121
- /** Include dual-mode agents (Claude Code + Codex hybrid) */
122
- dualMode: boolean;
123
119
  /** Include all agents */
124
120
  all: boolean;
125
121
  }
@@ -75,7 +75,6 @@ export const DEFAULT_INIT_OPTIONS = {
75
75
  flowNexus: false,
76
76
  browser: true,
77
77
  v3: true,
78
- dualMode: false, // Optional: enable with --dual flag
79
78
  all: false,
80
79
  },
81
80
  commands: {
@@ -100,7 +99,6 @@ export const DEFAULT_INIT_OPTIONS = {
100
99
  v3: true,
101
100
  optimization: true,
102
101
  testing: true,
103
- dualMode: false, // Optional: enable with --dual flag
104
102
  all: true,
105
103
  },
106
104
  statusline: {
@@ -169,7 +167,6 @@ export const MINIMAL_INIT_OPTIONS = {
169
167
  flowNexus: false,
170
168
  browser: false,
171
169
  v3: false,
172
- dualMode: false,
173
170
  all: false,
174
171
  },
175
172
  agents: {
@@ -183,7 +180,6 @@ export const MINIMAL_INIT_OPTIONS = {
183
180
  v3: false,
184
181
  optimization: false,
185
182
  testing: false,
186
- dualMode: false,
187
183
  all: false,
188
184
  },
189
185
  runtime: {
@@ -229,7 +225,6 @@ export const FULL_INIT_OPTIONS = {
229
225
  flowNexus: true,
230
226
  browser: true,
231
227
  v3: true,
232
- dualMode: true, // Include in full init
233
228
  all: true,
234
229
  },
235
230
  commands: {
@@ -319,13 +319,49 @@ export class MCPServerManager extends EventEmitter {
319
319
  console.error(`[${new Date().toISOString()}] INFO [claude-flow-mcp] (${sessionId}) stdin closed, shutting down...`);
320
320
  process.exit(0);
321
321
  });
322
+ process.stdin.on('error', () => {
323
+ // stdin pipe broken — parent disconnected
324
+ process.exit(0);
325
+ });
326
+ // Orphan watchdog: on Windows, stdin 'end' doesn't always fire when the
327
+ // parent process disconnects. Poll the parent PID to detect orphaning and
328
+ // self-terminate. Also tracks stdin inactivity as a secondary signal.
329
+ const parentPid = process.ppid;
330
+ let lastStdinActivity = Date.now();
331
+ const WATCHDOG_INTERVAL_MS = 10_000; // Check every 10s
332
+ const STDIN_IDLE_TIMEOUT_MS = 5 * 60_000; // 5 min with no stdin = likely orphaned
333
+ // Track stdin activity
334
+ process.stdin.on('data', () => { lastStdinActivity = Date.now(); });
335
+ const watchdog = setInterval(() => {
336
+ // Check 1: Is parent process still alive?
337
+ if (parentPid) {
338
+ try {
339
+ process.kill(parentPid, 0); // signal 0 = existence check
340
+ }
341
+ catch {
342
+ // Parent is gone — we're orphaned
343
+ console.error(`[${new Date().toISOString()}] INFO [claude-flow-mcp] (${sessionId}) Parent (PID ${parentPid}) gone, shutting down...`);
344
+ clearInterval(watchdog);
345
+ process.exit(0);
346
+ }
347
+ }
348
+ // Check 2: Has stdin been idle too long?
349
+ if (Date.now() - lastStdinActivity > STDIN_IDLE_TIMEOUT_MS) {
350
+ console.error(`[${new Date().toISOString()}] INFO [claude-flow-mcp] (${sessionId}) No stdin activity for ${STDIN_IDLE_TIMEOUT_MS / 1000}s, shutting down...`);
351
+ clearInterval(watchdog);
352
+ process.exit(0);
353
+ }
354
+ }, WATCHDOG_INTERVAL_MS);
355
+ watchdog.unref(); // Don't keep process alive just for watchdog
322
356
  // Handle process termination
323
357
  process.on('SIGINT', () => {
324
358
  console.error(`[${new Date().toISOString()}] INFO [claude-flow-mcp] (${sessionId}) Received SIGINT, shutting down...`);
359
+ clearInterval(watchdog);
325
360
  process.exit(0);
326
361
  });
327
362
  process.on('SIGTERM', () => {
328
363
  console.error(`[${new Date().toISOString()}] INFO [claude-flow-mcp] (${sessionId}) Received SIGTERM, shutting down...`);
364
+ clearInterval(watchdog);
329
365
  process.exit(0);
330
366
  });
331
367
  // Mark as ready immediately for stdio
@@ -404,4 +404,10 @@ export declare function bridgeContextSynthesize(params: {
404
404
  export declare function bridgeSemanticRoute(params: {
405
405
  input: string;
406
406
  }): Promise<any>;
407
+ /**
408
+ * Write vector-stats.json cache file used by the statusline.
409
+ * Synchronous — safe to call from short-lived CLI commands.
410
+ * Uses the already-initialized registry; no-ops if registry isn't loaded.
411
+ */
412
+ export declare function refreshVectorStatsCache(dbPathOverride?: string): void;
407
413
  //# sourceMappingURL=memory-bridge.d.ts.map