moflo 4.7.8 → 4.8.1

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 (77) hide show
  1. package/.claude/settings.local.json +4 -1
  2. package/.claude/workflow-state.json +3 -7
  3. package/README.md +3 -1
  4. package/bin/build-embeddings.mjs +59 -3
  5. package/bin/generate-code-map.mjs +3 -1
  6. package/bin/hooks.mjs +23 -20
  7. package/bin/index-guidance.mjs +3 -1
  8. package/bin/lib/moflo-resolve.mjs +14 -0
  9. package/bin/semantic-search.mjs +10 -5
  10. package/bin/session-start-launcher.mjs +116 -3
  11. package/package.json +6 -6
  12. package/src/@claude-flow/cli/dist/src/appliance/ruvllm-bridge.js +3 -7
  13. package/src/@claude-flow/cli/dist/src/commands/daemon.js +42 -95
  14. package/src/@claude-flow/cli/dist/src/commands/doctor.js +127 -6
  15. package/src/@claude-flow/cli/dist/src/commands/embeddings.js +4 -3
  16. package/src/@claude-flow/cli/dist/src/commands/hooks.js +3 -2
  17. package/src/@claude-flow/cli/dist/src/commands/mcp.js +38 -22
  18. package/src/@claude-flow/cli/dist/src/commands/memory.js +2 -1
  19. package/src/@claude-flow/cli/dist/src/commands/neural.js +10 -5
  20. package/src/@claude-flow/cli/dist/src/config/moflo-config.d.ts +5 -0
  21. package/src/@claude-flow/cli/dist/src/config/moflo-config.js +16 -0
  22. package/src/@claude-flow/cli/dist/src/index.js +12 -0
  23. package/src/@claude-flow/cli/dist/src/init/executor.js +74 -0
  24. package/src/@claude-flow/cli/dist/src/init/moflo-init.js +49 -0
  25. package/src/@claude-flow/cli/dist/src/mcp-tools/memory-tools.js +2 -2
  26. package/src/@claude-flow/cli/dist/src/mcp-tools/neural-tools.js +2 -1
  27. package/src/@claude-flow/cli/dist/src/memory/memory-bridge.js +5 -1
  28. package/src/@claude-flow/cli/dist/src/memory/memory-initializer.js +29 -24
  29. package/src/@claude-flow/cli/dist/src/ruvector/ast-analyzer.js +2 -1
  30. package/src/@claude-flow/cli/dist/src/ruvector/coverage-router.js +2 -1
  31. package/src/@claude-flow/cli/dist/src/ruvector/diff-classifier.js +2 -1
  32. package/src/@claude-flow/cli/dist/src/ruvector/enhanced-model-router.js +3 -3
  33. package/src/@claude-flow/cli/dist/src/ruvector/index.js +6 -13
  34. package/src/@claude-flow/cli/dist/src/ruvector/q-learning-router.js +4 -1
  35. package/src/@claude-flow/cli/dist/src/services/daemon-lock.d.ts +39 -0
  36. package/src/@claude-flow/cli/dist/src/services/daemon-lock.js +213 -0
  37. package/src/@claude-flow/cli/dist/src/services/learning-service.js +2 -1
  38. package/src/@claude-flow/cli/dist/src/services/moflo-require.d.ts +34 -0
  39. package/src/@claude-flow/cli/dist/src/services/moflo-require.js +67 -0
  40. package/src/@claude-flow/cli/dist/src/services/ruvector-training.js +8 -6
  41. package/src/@claude-flow/cli/package.json +6 -6
  42. package/.claude/helpers/README.md +0 -97
  43. package/.claude/helpers/adr-compliance.sh +0 -186
  44. package/.claude/helpers/aggressive-microcompact.mjs +0 -36
  45. package/.claude/helpers/auto-commit.sh +0 -178
  46. package/.claude/helpers/checkpoint-manager.sh +0 -251
  47. package/.claude/helpers/context-persistence-hook.mjs +0 -1979
  48. package/.claude/helpers/daemon-manager.sh +0 -252
  49. package/.claude/helpers/ddd-tracker.sh +0 -144
  50. package/.claude/helpers/github-safe.js +0 -106
  51. package/.claude/helpers/github-setup.sh +0 -28
  52. package/.claude/helpers/guidance-hook.sh +0 -13
  53. package/.claude/helpers/guidance-hooks.sh +0 -102
  54. package/.claude/helpers/health-monitor.sh +0 -108
  55. package/.claude/helpers/learning-hooks.sh +0 -329
  56. package/.claude/helpers/learning-optimizer.sh +0 -127
  57. package/.claude/helpers/learning-service.mjs +0 -1211
  58. package/.claude/helpers/memory.cjs +0 -84
  59. package/.claude/helpers/metrics-db.mjs +0 -492
  60. package/.claude/helpers/patch-aggressive-prune.mjs +0 -184
  61. package/.claude/helpers/pattern-consolidator.sh +0 -86
  62. package/.claude/helpers/perf-worker.sh +0 -160
  63. package/.claude/helpers/quick-start.sh +0 -19
  64. package/.claude/helpers/router.cjs +0 -62
  65. package/.claude/helpers/security-scanner.sh +0 -127
  66. package/.claude/helpers/session.cjs +0 -125
  67. package/.claude/helpers/setup-mcp.sh +0 -18
  68. package/.claude/helpers/standard-checkpoint-hooks.sh +0 -189
  69. package/.claude/helpers/swarm-comms.sh +0 -353
  70. package/.claude/helpers/swarm-hooks.sh +0 -761
  71. package/.claude/helpers/swarm-monitor.sh +0 -211
  72. package/.claude/helpers/sync-v3-metrics.sh +0 -245
  73. package/.claude/helpers/update-v3-progress.sh +0 -166
  74. package/.claude/helpers/v3-quick-status.sh +0 -58
  75. package/.claude/helpers/v3.sh +0 -111
  76. package/.claude/helpers/validate-v3-config.sh +0 -216
  77. package/.claude/helpers/worker-manager.sh +0 -170
@@ -27,6 +27,7 @@ function getPackageVersion() {
27
27
  }
28
28
  }
29
29
  export const VERSION = getPackageVersion();
30
+ const LONG_RUNNING_COMMANDS = ['mcp', 'daemon'];
30
31
  /**
31
32
  * V3 CLI Application
32
33
  */
@@ -201,6 +202,17 @@ export class CLI {
201
202
  if (result && !result.success) {
202
203
  process.exit(result.exitCode || 1);
203
204
  }
205
+ // Explicitly exit after successful non-long-running commands to prevent
206
+ // zombie processes on Windows where open handles keep node alive.
207
+ // Skip for MCP/daemon commands that need to stay running.
208
+ // Also skip in test environments (vitest/jest) where process.exit is mocked.
209
+ const isTestEnv = 'VITEST' in process.env
210
+ || 'JEST_WORKER_ID' in process.env
211
+ || process.env.NODE_ENV === 'test';
212
+ if (!LONG_RUNNING_COMMANDS.includes(commandName) && !isTestEnv) {
213
+ // Use setImmediate to let any pending I/O flush before exit
214
+ setImmediate(() => process.exit(0));
215
+ }
204
216
  }
205
217
  else {
206
218
  // No action - show command help
@@ -423,6 +423,46 @@ export async function executeUpgrade(targetDir, upgradeSettings = false) {
423
423
  };
424
424
  fs.writeFileSync(statuslinePath, generateStatuslineScript(upgradeOptions), 'utf-8');
425
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
+ }
426
466
  // 2. Create MISSING metrics files only (preserve existing data)
427
467
  const metricsDir = path.join(targetDir, '.claude-flow', 'metrics');
428
468
  const securityDir = path.join(targetDir, '.claude-flow', 'security');
@@ -898,6 +938,40 @@ function findSourceHelpersDir(sourceBaseDir) {
898
938
  }
899
939
  return null;
900
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
+ }
901
975
  /**
902
976
  * Write helper scripts
903
977
  */
@@ -105,6 +105,8 @@ export async function initMoflo(options) {
105
105
  steps.push(syncScripts(projectRoot, force));
106
106
  // Step 6: .gitignore entries
107
107
  steps.push(updateGitignore(projectRoot));
108
+ // Step 7: .claude/guidance/moflo-bootstrap.md (subagent bootstrap protocol)
109
+ steps.push(syncBootstrapGuidance(projectRoot, force));
108
110
  return { steps };
109
111
  }
110
112
  // ============================================================================
@@ -647,4 +649,51 @@ function updateGitignore(root) {
647
649
  fs.appendFileSync(gitignorePath, '\n# MoFlo state (gitignored)\n' + toAdd.join('\n') + '\n');
648
650
  return { name: '.gitignore', status: 'updated', detail: `Added: ${toAdd.join(', ')}` };
649
651
  }
652
+ // ============================================================================
653
+ // Step 7: .claude/guidance/moflo-bootstrap.md
654
+ // Copies the agent bootstrap guidance to the project so subagents can read it
655
+ // from disk without requiring memory search.
656
+ // ============================================================================
657
+ function syncBootstrapGuidance(root, force) {
658
+ const guidanceDir = path.join(root, '.claude', 'guidance');
659
+ const targetFile = path.join(guidanceDir, 'moflo-bootstrap.md');
660
+ // Find the source bootstrap file from the moflo package
661
+ let sourceDir;
662
+ try {
663
+ sourceDir = path.dirname(fileURLToPath(import.meta.url));
664
+ }
665
+ catch {
666
+ sourceDir = typeof __dirname !== 'undefined' ? __dirname : '';
667
+ }
668
+ const candidates = [
669
+ path.join(root, 'node_modules', 'moflo', '.claude', 'guidance', 'agent-bootstrap.md'),
670
+ // When running from moflo repo itself
671
+ ...(sourceDir ? [path.join(sourceDir, '..', '..', '..', '..', '.claude', 'guidance', 'agent-bootstrap.md')] : []),
672
+ ];
673
+ const sourceFile = candidates.find(f => { try {
674
+ return fs.existsSync(f);
675
+ }
676
+ catch {
677
+ return false;
678
+ } });
679
+ if (!sourceFile) {
680
+ return { name: 'guidance/moflo-bootstrap.md', status: 'skipped', detail: 'Source bootstrap not found' };
681
+ }
682
+ // Check if target exists and is up to date
683
+ if (fs.existsSync(targetFile) && !force) {
684
+ if (!isStale(sourceFile, targetFile)) {
685
+ return { name: 'guidance/moflo-bootstrap.md', status: 'skipped', detail: 'Already up to date' };
686
+ }
687
+ }
688
+ // Read source and prepend header
689
+ const content = fs.readFileSync(sourceFile, 'utf-8');
690
+ const header = `<!-- AUTO-GENERATED by moflo init. Do not edit — changes will be overwritten on next init. -->\n<!-- Source: moflo/.claude/guidance/agent-bootstrap.md -->\n<!-- To customize, create .claude/guidance/agent-bootstrap.md for project-specific rules. -->\n\n`;
691
+ fs.mkdirSync(guidanceDir, { recursive: true });
692
+ fs.writeFileSync(targetFile, header + content, 'utf-8');
693
+ return {
694
+ name: 'guidance/moflo-bootstrap.md',
695
+ status: fs.existsSync(targetFile) ? 'updated' : 'created',
696
+ detail: 'Subagent bootstrap protocol'
697
+ };
698
+ }
650
699
  //# sourceMappingURL=moflo-init.js.map
@@ -263,7 +263,7 @@ export const memoryTools = [
263
263
  type: 'object',
264
264
  properties: {
265
265
  query: { type: 'string', description: 'Search query (semantic similarity)' },
266
- namespace: { type: 'string', description: 'Namespace to search (default: "default")' },
266
+ namespace: { type: 'string', description: 'Namespace to search (default: all namespaces)' },
267
267
  limit: { type: 'number', description: 'Maximum results (default: 10)' },
268
268
  threshold: { type: 'number', description: 'Minimum similarity threshold 0-1 (default: 0.3)' },
269
269
  },
@@ -273,7 +273,7 @@ export const memoryTools = [
273
273
  await ensureInitialized();
274
274
  const { searchEntries } = await getMemoryFunctions();
275
275
  const query = input.query;
276
- const namespace = input.namespace || 'default';
276
+ const namespace = input.namespace || 'all';
277
277
  const limit = input.limit || 10;
278
278
  const threshold = input.threshold || 0.3;
279
279
  validateMemoryInput(undefined, undefined, query);
@@ -13,12 +13,13 @@
13
13
  */
14
14
  import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
15
15
  import { join } from 'node:path';
16
+ import { mofloImport } from '../services/moflo-require.js';
16
17
  // Try to import real embeddings — prefer agentic-flow v3 ReasoningBank, then @claude-flow/embeddings
17
18
  let realEmbeddings = null;
18
19
  let embeddingServiceName = 'none';
19
20
  try {
20
21
  // Tier 1: agentic-flow v3 ReasoningBank (fastest — WASM-accelerated)
21
- const rb = await import('agentic-flow/reasoningbank').catch(() => null);
22
+ const rb = await mofloImport('agentic-flow/reasoningbank');
22
23
  if (rb?.computeEmbedding) {
23
24
  realEmbeddings = { embed: (text) => rb.computeEmbedding(text) };
24
25
  embeddingServiceName = 'agentic-flow/reasoningbank';
@@ -18,6 +18,7 @@
18
18
  */
19
19
  import * as path from 'path';
20
20
  import * as crypto from 'crypto';
21
+ import { mofloImport } from '../services/moflo-require.js';
21
22
  // ===== Project root resolution =====
22
23
  // When run via npx, CWD may be node_modules/moflo — walk up to find actual project
23
24
  import * as fs from 'fs';
@@ -59,7 +60,10 @@ async function getFallbackEmbedder() {
59
60
  if (_tfEmbedder)
60
61
  return _tfEmbedder;
61
62
  try {
62
- const { pipeline } = await import('@xenova/transformers');
63
+ const transformersModule = await mofloImport('@xenova/transformers');
64
+ if (!transformersModule)
65
+ throw new Error('@xenova/transformers not available');
66
+ const { pipeline } = transformersModule;
63
67
  _tfEmbedder = await pipeline('feature-extraction', 'Xenova/all-MiniLM-L6-v2');
64
68
  return _tfEmbedder;
65
69
  }
@@ -10,6 +10,7 @@
10
10
  */
11
11
  import * as fs from 'fs';
12
12
  import * as path from 'path';
13
+ import { mofloImport } from '../services/moflo-require.js';
13
14
  /**
14
15
  * Write vector-stats.json cache for the statusline (no subprocess needed).
15
16
  * Called after memory store/delete to keep the cache fresh.
@@ -379,7 +380,7 @@ export async function getHNSWIndex(options) {
379
380
  try {
380
381
  // Import @ruvector/core dynamically
381
382
  // Handle both ESM (default export) and CJS patterns
382
- const ruvectorModule = await import('@ruvector/core').catch(() => null);
383
+ const ruvectorModule = await mofloImport('@ruvector/core');
383
384
  if (!ruvectorModule) {
384
385
  hnswInitializing = false;
385
386
  return null; // HNSW not available
@@ -436,7 +437,7 @@ export async function getHNSWIndex(options) {
436
437
  }
437
438
  if (fs.existsSync(dbPath)) {
438
439
  try {
439
- const initSqlJs = (await import('sql.js')).default;
440
+ const initSqlJs = (await mofloImport('sql.js')).default;
440
441
  const SQL = await initSqlJs();
441
442
  const fileBuffer = fs.readFileSync(dbPath);
442
443
  const sqlDb = new SQL.Database(fileBuffer);
@@ -852,7 +853,7 @@ export async function ensureSchemaColumns(dbPath) {
852
853
  if (!fs.existsSync(dbPath)) {
853
854
  return { success: true, columnsAdded: [] };
854
855
  }
855
- const initSqlJs = (await import('sql.js')).default;
856
+ const initSqlJs = (await mofloImport('sql.js')).default;
856
857
  const SQL = await initSqlJs();
857
858
  const fileBuffer = fs.readFileSync(dbPath);
858
859
  const db = new SQL.Database(fileBuffer);
@@ -919,7 +920,7 @@ export async function checkAndMigrateLegacy(options) {
919
920
  for (const legacyPath of legacyPaths) {
920
921
  if (fs.existsSync(legacyPath) && legacyPath !== dbPath) {
921
922
  try {
922
- const initSqlJs = (await import('sql.js')).default;
923
+ const initSqlJs = (await mofloImport('sql.js')).default;
923
924
  const SQL = await initSqlJs();
924
925
  const legacyBuffer = fs.readFileSync(legacyPath);
925
926
  const legacyDb = new SQL.Database(legacyBuffer);
@@ -1038,7 +1039,7 @@ export async function initializeMemoryDatabase(options) {
1038
1039
  let usedSqlJs = false;
1039
1040
  try {
1040
1041
  // Dynamic import of sql.js
1041
- const initSqlJs = (await import('sql.js')).default;
1042
+ const initSqlJs = (await mofloImport('sql.js')).default;
1042
1043
  const SQL = await initSqlJs();
1043
1044
  // Load existing database or create new
1044
1045
  if (fs.existsSync(dbPath) && force) {
@@ -1188,7 +1189,7 @@ export async function checkMemoryInitialization(dbPath) {
1188
1189
  }
1189
1190
  try {
1190
1191
  // Try to load with sql.js
1191
- const initSqlJs = (await import('sql.js')).default;
1192
+ const initSqlJs = (await mofloImport('sql.js')).default;
1192
1193
  const SQL = await initSqlJs();
1193
1194
  const fileBuffer = fs.readFileSync(path_);
1194
1195
  const db = new SQL.Database(fileBuffer);
@@ -1233,7 +1234,7 @@ export async function applyTemporalDecay(dbPath) {
1233
1234
  const swarmDir = path.join(process.cwd(), '.swarm');
1234
1235
  const path_ = dbPath || path.join(swarmDir, 'memory.db');
1235
1236
  try {
1236
- const initSqlJs = (await import('sql.js')).default;
1237
+ const initSqlJs = (await mofloImport('sql.js')).default;
1237
1238
  const SQL = await initSqlJs();
1238
1239
  const fileBuffer = fs.readFileSync(path_);
1239
1240
  const db = new SQL.Database(fileBuffer);
@@ -1294,14 +1295,14 @@ export async function loadEmbeddingModel(options) {
1294
1295
  loaded: true,
1295
1296
  model: null, // Bridge handles embedding
1296
1297
  tokenizer: null,
1297
- dimensions: bridgeResult.dimensions
1298
+ dimensions: bridgeResult.dimensions,
1299
+ modelName: bridgeResult.modelName || 'bridge'
1298
1300
  };
1299
1301
  return bridgeResult;
1300
1302
  }
1301
1303
  }
1302
1304
  try {
1303
- // Try to import @xenova/transformers for ONNX embeddings
1304
- const transformers = await import('@xenova/transformers').catch(() => null);
1305
+ const transformers = await mofloImport('@xenova/transformers');
1305
1306
  if (transformers) {
1306
1307
  if (verbose) {
1307
1308
  console.log('Loading ONNX embedding model (all-MiniLM-L6-v2)...');
@@ -1313,7 +1314,8 @@ export async function loadEmbeddingModel(options) {
1313
1314
  loaded: true,
1314
1315
  model: embedder,
1315
1316
  tokenizer: null,
1316
- dimensions: 384 // MiniLM-L6 produces 384-dim vectors
1317
+ dimensions: 384, // MiniLM-L6 produces 384-dim vectors
1318
+ modelName: 'Xenova/all-MiniLM-L6-v2'
1317
1319
  };
1318
1320
  return {
1319
1321
  success: true,
@@ -1323,7 +1325,7 @@ export async function loadEmbeddingModel(options) {
1323
1325
  };
1324
1326
  }
1325
1327
  // Fallback: Check for agentic-flow ReasoningBank embeddings (v3)
1326
- const reasoningBank = await import('agentic-flow/reasoningbank').catch(() => null);
1328
+ const reasoningBank = await mofloImport('agentic-flow/reasoningbank');
1327
1329
  if (reasoningBank?.computeEmbedding) {
1328
1330
  if (verbose) {
1329
1331
  console.log('Loading agentic-flow ReasoningBank embedding model...');
@@ -1332,7 +1334,8 @@ export async function loadEmbeddingModel(options) {
1332
1334
  loaded: true,
1333
1335
  model: { embed: reasoningBank.computeEmbedding },
1334
1336
  tokenizer: null,
1335
- dimensions: 768
1337
+ dimensions: 768,
1338
+ modelName: 'agentic-flow/reasoningbank'
1336
1339
  };
1337
1340
  return {
1338
1341
  success: true,
@@ -1342,7 +1345,7 @@ export async function loadEmbeddingModel(options) {
1342
1345
  };
1343
1346
  }
1344
1347
  // Legacy fallback: Check for agentic-flow core embeddings
1345
- const agenticFlow = await import('agentic-flow').catch(() => null);
1348
+ const agenticFlow = await mofloImport('agentic-flow');
1346
1349
  if (agenticFlow && agenticFlow.embeddings) {
1347
1350
  if (verbose) {
1348
1351
  console.log('Loading agentic-flow embedding model...');
@@ -1351,7 +1354,8 @@ export async function loadEmbeddingModel(options) {
1351
1354
  loaded: true,
1352
1355
  model: agenticFlow.embeddings,
1353
1356
  tokenizer: null,
1354
- dimensions: 768
1357
+ dimensions: 768,
1358
+ modelName: 'agentic-flow'
1355
1359
  };
1356
1360
  return {
1357
1361
  success: true,
@@ -1365,7 +1369,8 @@ export async function loadEmbeddingModel(options) {
1365
1369
  loaded: true,
1366
1370
  model: null, // Will use domain-aware hash fallback
1367
1371
  tokenizer: null,
1368
- dimensions: 384 // Domain-aware hash embedding dimensions
1372
+ dimensions: 384, // Domain-aware hash embedding dimensions
1373
+ modelName: 'domain-aware-hash-384'
1369
1374
  };
1370
1375
  return {
1371
1376
  success: true,
@@ -1408,7 +1413,7 @@ export async function generateEmbedding(text) {
1408
1413
  return {
1409
1414
  embedding,
1410
1415
  dimensions: embedding.length,
1411
- model: 'onnx'
1416
+ model: state.modelName || 'Xenova/all-MiniLM-L6-v2'
1412
1417
  };
1413
1418
  }
1414
1419
  catch {
@@ -1420,7 +1425,7 @@ export async function generateEmbedding(text) {
1420
1425
  return {
1421
1426
  embedding,
1422
1427
  dimensions: 384,
1423
- model: 'domain-aware-hash-384'
1428
+ model: state.modelName || 'domain-aware-hash-384'
1424
1429
  };
1425
1430
  }
1426
1431
  /**
@@ -1610,7 +1615,7 @@ export async function verifyMemoryInit(dbPath, options) {
1610
1615
  const { verbose = false } = options || {};
1611
1616
  const tests = [];
1612
1617
  try {
1613
- const initSqlJs = (await import('sql.js')).default;
1618
+ const initSqlJs = (await mofloImport('sql.js')).default;
1614
1619
  const SQL = await initSqlJs();
1615
1620
  const fs = await import('fs');
1616
1621
  // Load database
@@ -1800,7 +1805,7 @@ export async function storeEntry(options) {
1800
1805
  }
1801
1806
  // Ensure schema has all required columns (migration for older DBs)
1802
1807
  await ensureSchemaColumns(dbPath);
1803
- const initSqlJs = (await import('sql.js')).default;
1808
+ const initSqlJs = (await mofloImport('sql.js')).default;
1804
1809
  const SQL = await initSqlJs();
1805
1810
  const fileBuffer = fs.readFileSync(dbPath);
1806
1811
  const db = new SQL.Database(fileBuffer);
@@ -1919,7 +1924,7 @@ export async function searchEntries(options) {
1919
1924
  };
1920
1925
  }
1921
1926
  // Fall back to brute-force SQLite search
1922
- const initSqlJs = (await import('sql.js')).default;
1927
+ const initSqlJs = (await mofloImport('sql.js')).default;
1923
1928
  const SQL = await initSqlJs();
1924
1929
  const fileBuffer = fs.readFileSync(dbPath);
1925
1930
  const db = new SQL.Database(fileBuffer);
@@ -2025,7 +2030,7 @@ export async function listEntries(options) {
2025
2030
  }
2026
2031
  // Ensure schema has all required columns (migration for older DBs)
2027
2032
  await ensureSchemaColumns(dbPath);
2028
- const initSqlJs = (await import('sql.js')).default;
2033
+ const initSqlJs = (await mofloImport('sql.js')).default;
2029
2034
  const SQL = await initSqlJs();
2030
2035
  const fileBuffer = fs.readFileSync(dbPath);
2031
2036
  const db = new SQL.Database(fileBuffer);
@@ -2094,7 +2099,7 @@ export async function getEntry(options) {
2094
2099
  }
2095
2100
  // Ensure schema has all required columns (migration for older DBs)
2096
2101
  await ensureSchemaColumns(dbPath);
2097
- const initSqlJs = (await import('sql.js')).default;
2102
+ const initSqlJs = (await mofloImport('sql.js')).default;
2098
2103
  const SQL = await initSqlJs();
2099
2104
  const fileBuffer = fs.readFileSync(dbPath);
2100
2105
  const db = new SQL.Database(fileBuffer);
@@ -2184,7 +2189,7 @@ export async function deleteEntry(options) {
2184
2189
  }
2185
2190
  // Ensure schema has all required columns (migration for older DBs)
2186
2191
  await ensureSchemaColumns(dbPath);
2187
- const initSqlJs = (await import('sql.js')).default;
2192
+ const initSqlJs = (await mofloImport('sql.js')).default;
2188
2193
  const SQL = await initSqlJs();
2189
2194
  const fileBuffer = fs.readFileSync(dbPath);
2190
2195
  const db = new SQL.Database(fileBuffer);
@@ -6,6 +6,7 @@
6
6
  *
7
7
  * @module ast-analyzer
8
8
  */
9
+ import { mofloImport } from '../services/moflo-require.js';
9
10
  const DEFAULT_CONFIG = {
10
11
  maxFileSize: 1024 * 1024,
11
12
  languages: ['typescript', 'javascript', 'python', 'rust', 'go'],
@@ -31,7 +32,7 @@ export class ASTAnalyzer {
31
32
  async initialize() {
32
33
  try {
33
34
  // @ruvector/ast is optional - gracefully fallback if not installed
34
- const ruvector = await import('@ruvector/ast').catch(() => null);
35
+ const ruvector = await mofloImport('@ruvector/ast');
35
36
  if (ruvector) {
36
37
  this.ruvectorEngine = ruvector.createASTAnalyzer?.(this.config);
37
38
  this.useNative = !!this.ruvectorEngine;
@@ -9,6 +9,7 @@
9
9
  // ============================================================================
10
10
  // Caching for Performance
11
11
  // ============================================================================
12
+ import { mofloImport } from '../services/moflo-require.js';
12
13
  /**
13
14
  * Cache for coverage data (1 minute TTL)
14
15
  */
@@ -43,7 +44,7 @@ export class CoverageRouter {
43
44
  async initialize() {
44
45
  try {
45
46
  // @ruvector/coverage is optional - gracefully fallback if not installed
46
- const ruvector = await import('@ruvector/coverage').catch(() => null);
47
+ const ruvector = await mofloImport('@ruvector/coverage');
47
48
  if (ruvector) {
48
49
  this.ruvectorEngine = ruvector.createCoverageRouter?.(this.config);
49
50
  this.useNative = !!this.ruvectorEngine;
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * Diff Classifier for Change Analysis
3
3
  */
4
+ import { mofloImport } from '../services/moflo-require.js';
4
5
  const DEFAULT_CONFIG = {
5
6
  maxDiffSize: 10000,
6
7
  classifyByImpact: true,
@@ -31,7 +32,7 @@ export class DiffClassifier {
31
32
  async initialize() {
32
33
  try {
33
34
  // @ruvector/diff is optional - gracefully fallback if not installed
34
- const ruvector = await import('@ruvector/diff').catch(() => null);
35
+ const ruvector = await mofloImport('@ruvector/diff');
35
36
  if (ruvector) {
36
37
  this.ruvectorEngine = ruvector.createDiffClassifier?.(this.config);
37
38
  this.useNative = !!this.ruvectorEngine;
@@ -11,6 +11,7 @@
11
11
  import { existsSync, readFileSync } from 'fs';
12
12
  import { extname } from 'path';
13
13
  import { getModelRouter } from './model-router.js';
14
+ import { mofloImport } from '../services/moflo-require.js';
14
15
  // ============================================================================
15
16
  // Intent Detection Patterns
16
17
  // ============================================================================
@@ -432,9 +433,8 @@ export class EnhancedModelRouter {
432
433
  const language = intent.language || 'javascript';
433
434
  // Try local agentic-flow agent-booster (v3 — no npx needed)
434
435
  // Note: agent-booster export declared but dist missing in alpha.1; use intelligence path as fallback
435
- const boosterModule = await import('agentic-flow/agent-booster')
436
- .catch(() => import(/* @vite-ignore */ 'agentic-flow/intelligence/agent-booster-enhanced'))
437
- .catch(() => null);
436
+ const boosterModule = await mofloImport('agentic-flow/agent-booster')
437
+ || await mofloImport('agentic-flow/intelligence/agent-booster-enhanced');
438
438
  if (boosterModule?.enhancedApply) {
439
439
  const result = await boosterModule.enhancedApply({
440
440
  code: originalCode,
@@ -33,28 +33,21 @@ export { FlashAttention, getFlashAttention, resetFlashAttention, computeAttentio
33
33
  export { LoRAAdapter, getLoRAAdapter, resetLoRAAdapter, createLoRAAdapter, adaptEmbedding, trainLoRA, getLoRAStats, DEFAULT_RANK, DEFAULT_ALPHA, INPUT_DIM as LORA_INPUT_DIM, OUTPUT_DIM as LORA_OUTPUT_DIM, } from './lora-adapter.js';
34
34
  export { ModelRouter, getModelRouter, resetModelRouter, createModelRouter, routeToModel, routeToModelFull, analyzeTaskComplexity, getModelRouterStats, recordModelOutcome, MODEL_CAPABILITIES, COMPLEXITY_INDICATORS, } from './model-router.js';
35
35
  export { SemanticRouter, createSemanticRouter, } from './semantic-router.js';
36
+ import { mofloImport } from '../services/moflo-require.js';
36
37
  /**
37
38
  * Check if ruvector packages are available
38
39
  */
39
40
  export async function isRuvectorAvailable() {
40
- try {
41
- await import('@ruvector/core');
42
- return true;
43
- }
44
- catch {
45
- return false;
46
- }
41
+ const mod = await mofloImport('@ruvector/core');
42
+ return mod !== null;
47
43
  }
48
44
  /**
49
45
  * Get ruvector version if available
50
46
  */
51
47
  export async function getRuvectorVersion() {
52
- try {
53
- const ruvector = await import('@ruvector/core');
54
- return ruvector.version || '1.0.0';
55
- }
56
- catch {
48
+ const ruvector = await mofloImport('@ruvector/core');
49
+ if (!ruvector)
57
50
  return null;
58
- }
51
+ return ruvector.version || '1.0.0';
59
52
  }
60
53
  //# sourceMappingURL=index.js.map
@@ -15,6 +15,7 @@
15
15
  */
16
16
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
17
17
  import { dirname } from 'path';
18
+ import { mofloImport } from '../services/moflo-require.js';
18
19
  /**
19
20
  * Default configuration
20
21
  */
@@ -110,7 +111,9 @@ export class QLearningRouter {
110
111
  */
111
112
  async initialize() {
112
113
  try {
113
- const ruvector = await import('@ruvector/core');
114
+ const ruvector = await mofloImport('@ruvector/core');
115
+ if (!ruvector)
116
+ throw new Error('not available');
114
117
  this.ruvectorEngine = ruvector.createQLearning?.(this.config);
115
118
  this.useNative = !!this.ruvectorEngine;
116
119
  }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Atomic daemon lock — prevents duplicate daemon processes.
3
+ *
4
+ * Uses fs.writeFileSync with { flag: 'wx' } (O_CREAT | O_EXCL) which is
5
+ * atomic on all platforms: the write fails immediately if the file exists,
6
+ * eliminating the TOCTOU race in the old PID-file approach.
7
+ *
8
+ * Also solves Windows PID recycling by storing a label in the lock payload
9
+ * and verifying the process command line before trusting a "live" PID.
10
+ */
11
+ export interface DaemonLockPayload {
12
+ pid: number;
13
+ startedAt: number;
14
+ label: string;
15
+ }
16
+ /** Resolve the lock file path for a project root. */
17
+ export declare function lockPath(projectRoot: string): string;
18
+ /**
19
+ * Try to acquire the daemon lock atomically.
20
+ *
21
+ * @returns `{ acquired: true }` on success,
22
+ * `{ acquired: false, holder: pid }` if another daemon owns the lock.
23
+ */
24
+ export declare function acquireDaemonLock(projectRoot: string, pid?: number): {
25
+ acquired: true;
26
+ } | {
27
+ acquired: false;
28
+ holder: number;
29
+ };
30
+ /**
31
+ * Release the daemon lock. Only removes if we own it (or force = true).
32
+ */
33
+ export declare function releaseDaemonLock(projectRoot: string, pid?: number, force?: boolean): void;
34
+ /**
35
+ * Check if the daemon lock is currently held by a live daemon.
36
+ * Returns the holder PID or null.
37
+ */
38
+ export declare function getDaemonLockHolder(projectRoot: string): number | null;
39
+ //# sourceMappingURL=daemon-lock.d.ts.map