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.
- package/.claude/settings.local.json +4 -1
- package/.claude/workflow-state.json +3 -7
- package/README.md +3 -1
- package/bin/build-embeddings.mjs +59 -3
- package/bin/generate-code-map.mjs +3 -1
- package/bin/hooks.mjs +23 -20
- package/bin/index-guidance.mjs +3 -1
- package/bin/lib/moflo-resolve.mjs +14 -0
- package/bin/semantic-search.mjs +10 -5
- package/bin/session-start-launcher.mjs +116 -3
- package/package.json +6 -6
- package/src/@claude-flow/cli/dist/src/appliance/ruvllm-bridge.js +3 -7
- package/src/@claude-flow/cli/dist/src/commands/daemon.js +42 -95
- package/src/@claude-flow/cli/dist/src/commands/doctor.js +127 -6
- package/src/@claude-flow/cli/dist/src/commands/embeddings.js +4 -3
- package/src/@claude-flow/cli/dist/src/commands/hooks.js +3 -2
- package/src/@claude-flow/cli/dist/src/commands/mcp.js +38 -22
- package/src/@claude-flow/cli/dist/src/commands/memory.js +2 -1
- package/src/@claude-flow/cli/dist/src/commands/neural.js +10 -5
- package/src/@claude-flow/cli/dist/src/config/moflo-config.d.ts +5 -0
- package/src/@claude-flow/cli/dist/src/config/moflo-config.js +16 -0
- package/src/@claude-flow/cli/dist/src/index.js +12 -0
- package/src/@claude-flow/cli/dist/src/init/executor.js +74 -0
- package/src/@claude-flow/cli/dist/src/init/moflo-init.js +49 -0
- package/src/@claude-flow/cli/dist/src/mcp-tools/memory-tools.js +2 -2
- package/src/@claude-flow/cli/dist/src/mcp-tools/neural-tools.js +2 -1
- package/src/@claude-flow/cli/dist/src/memory/memory-bridge.js +5 -1
- package/src/@claude-flow/cli/dist/src/memory/memory-initializer.js +29 -24
- package/src/@claude-flow/cli/dist/src/ruvector/ast-analyzer.js +2 -1
- package/src/@claude-flow/cli/dist/src/ruvector/coverage-router.js +2 -1
- package/src/@claude-flow/cli/dist/src/ruvector/diff-classifier.js +2 -1
- package/src/@claude-flow/cli/dist/src/ruvector/enhanced-model-router.js +3 -3
- package/src/@claude-flow/cli/dist/src/ruvector/index.js +6 -13
- package/src/@claude-flow/cli/dist/src/ruvector/q-learning-router.js +4 -1
- package/src/@claude-flow/cli/dist/src/services/daemon-lock.d.ts +39 -0
- package/src/@claude-flow/cli/dist/src/services/daemon-lock.js +213 -0
- package/src/@claude-flow/cli/dist/src/services/learning-service.js +2 -1
- package/src/@claude-flow/cli/dist/src/services/moflo-require.d.ts +34 -0
- package/src/@claude-flow/cli/dist/src/services/moflo-require.js +67 -0
- package/src/@claude-flow/cli/dist/src/services/ruvector-training.js +8 -6
- package/src/@claude-flow/cli/package.json +6 -6
- package/.claude/helpers/README.md +0 -97
- package/.claude/helpers/adr-compliance.sh +0 -186
- package/.claude/helpers/aggressive-microcompact.mjs +0 -36
- package/.claude/helpers/auto-commit.sh +0 -178
- package/.claude/helpers/checkpoint-manager.sh +0 -251
- package/.claude/helpers/context-persistence-hook.mjs +0 -1979
- package/.claude/helpers/daemon-manager.sh +0 -252
- package/.claude/helpers/ddd-tracker.sh +0 -144
- package/.claude/helpers/github-safe.js +0 -106
- package/.claude/helpers/github-setup.sh +0 -28
- package/.claude/helpers/guidance-hook.sh +0 -13
- package/.claude/helpers/guidance-hooks.sh +0 -102
- package/.claude/helpers/health-monitor.sh +0 -108
- package/.claude/helpers/learning-hooks.sh +0 -329
- package/.claude/helpers/learning-optimizer.sh +0 -127
- package/.claude/helpers/learning-service.mjs +0 -1211
- package/.claude/helpers/memory.cjs +0 -84
- package/.claude/helpers/metrics-db.mjs +0 -492
- package/.claude/helpers/patch-aggressive-prune.mjs +0 -184
- package/.claude/helpers/pattern-consolidator.sh +0 -86
- package/.claude/helpers/perf-worker.sh +0 -160
- package/.claude/helpers/quick-start.sh +0 -19
- package/.claude/helpers/router.cjs +0 -62
- package/.claude/helpers/security-scanner.sh +0 -127
- package/.claude/helpers/session.cjs +0 -125
- package/.claude/helpers/setup-mcp.sh +0 -18
- package/.claude/helpers/standard-checkpoint-hooks.sh +0 -189
- package/.claude/helpers/swarm-comms.sh +0 -353
- package/.claude/helpers/swarm-hooks.sh +0 -761
- package/.claude/helpers/swarm-monitor.sh +0 -211
- package/.claude/helpers/sync-v3-metrics.sh +0 -245
- package/.claude/helpers/update-v3-progress.sh +0 -166
- package/.claude/helpers/v3-quick-status.sh +0 -58
- package/.claude/helpers/v3.sh +0 -111
- package/.claude/helpers/validate-v3-config.sh +0 -216
- 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:
|
|
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 || '
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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: '
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
436
|
-
|
|
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
|
-
|
|
41
|
-
|
|
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
|
-
|
|
53
|
-
|
|
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
|
|
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
|