moflo 4.6.4 → 4.6.6
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/helpers/statusline.cjs +127 -118
- package/README.md +133 -52
- package/bin/build-embeddings.mjs +19 -2
- package/bin/generate-code-map.mjs +19 -13
- package/package.json +1 -1
- package/src/@claude-flow/cli/package.json +1 -1
|
@@ -42,7 +42,7 @@ function loadStatusLineConfig() {
|
|
|
42
42
|
show_adrs: true,
|
|
43
43
|
show_agentdb: true,
|
|
44
44
|
show_tests: true,
|
|
45
|
-
mode: '
|
|
45
|
+
mode: 'compact',
|
|
46
46
|
};
|
|
47
47
|
|
|
48
48
|
// Try moflo.yaml
|
|
@@ -159,38 +159,26 @@ function getGitInfo() {
|
|
|
159
159
|
staged: 0, ahead: 0, behind: 0,
|
|
160
160
|
};
|
|
161
161
|
|
|
162
|
-
//
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
'
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
const parts = raw.split('---SEP---').map(s => s.trim());
|
|
177
|
-
if (parts.length >= 4) {
|
|
178
|
-
result.name = parts[0] || 'user';
|
|
179
|
-
result.gitBranch = parts[1] || '';
|
|
180
|
-
|
|
181
|
-
// Parse porcelain status
|
|
182
|
-
if (parts[2]) {
|
|
183
|
-
for (const line of parts[2].split('\n')) {
|
|
184
|
-
if (!line || line.length < 2) continue;
|
|
185
|
-
const x = line[0], y = line[1];
|
|
186
|
-
if (x === '?' && y === '?') { result.untracked++; continue; }
|
|
187
|
-
if (x !== ' ' && x !== '?') result.staged++;
|
|
188
|
-
if (y !== ' ' && y !== '?') result.modified++;
|
|
189
|
-
}
|
|
162
|
+
// Individual git calls (cross-platform — sh -c fails on Windows)
|
|
163
|
+
result.name = safeExec('git config user.name', 2000) || 'user';
|
|
164
|
+
result.gitBranch = safeExec('git branch --show-current', 2000) || '';
|
|
165
|
+
|
|
166
|
+
// Parse porcelain status
|
|
167
|
+
const statusRaw = safeExec('git status --porcelain', 2000);
|
|
168
|
+
if (statusRaw) {
|
|
169
|
+
for (const line of statusRaw.split('\n')) {
|
|
170
|
+
if (!line || line.length < 2) continue;
|
|
171
|
+
const x = line[0], y = line[1];
|
|
172
|
+
if (x === '?' && y === '?') { result.untracked++; continue; }
|
|
173
|
+
if (x !== ' ' && x !== '?') result.staged++;
|
|
174
|
+
if (y !== ' ' && y !== '?') result.modified++;
|
|
190
175
|
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
{
|
|
191
179
|
|
|
192
180
|
// Parse ahead/behind
|
|
193
|
-
const ab = (
|
|
181
|
+
const ab = (safeExec('git rev-list --left-right --count HEAD...@{upstream}', 2000) || '0 0').split(/\s+/);
|
|
194
182
|
result.ahead = parseInt(ab[0]) || 0;
|
|
195
183
|
result.behind = parseInt(ab[1]) || 0;
|
|
196
184
|
}
|
|
@@ -669,26 +657,16 @@ function generateStatusline() {
|
|
|
669
657
|
}
|
|
670
658
|
|
|
671
659
|
// Multi-line dashboard (for --dashboard flag)
|
|
660
|
+
// Respects show_* toggles from moflo.yaml status_line config
|
|
672
661
|
function generateDashboard() {
|
|
673
662
|
const git = getGitInfo();
|
|
674
|
-
const modelName = getModelName();
|
|
675
|
-
const progress = getV3Progress();
|
|
676
|
-
const security = getSecurityStatus();
|
|
677
|
-
const swarm = getSwarmStatus();
|
|
678
|
-
const system = getSystemMetrics();
|
|
679
|
-
const adrs = getADRStatus();
|
|
680
|
-
const hooks = getHooksStatus();
|
|
681
|
-
const agentdb = getAgentDBStats();
|
|
682
|
-
const tests = getTestStats();
|
|
683
663
|
const session = getSessionStats();
|
|
684
|
-
const integration = getIntegrationStatus();
|
|
685
664
|
const lines = [];
|
|
686
665
|
|
|
687
|
-
// Header
|
|
666
|
+
// Header: branding + git
|
|
688
667
|
let header = `${c.bold}${c.brightPurple}\u258A ${SL_CONFIG.branding}${c.reset}`;
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
header += ` ${c.dim}\u2502${c.reset} ${c.brightBlue}\u23C7 ${git.gitBranch}${c.reset}`;
|
|
668
|
+
if (SL_CONFIG.show_git && git.gitBranch) {
|
|
669
|
+
header += ` ${c.brightBlue}\u23C7 ${git.gitBranch}${c.reset}`;
|
|
692
670
|
const changes = git.modified + git.staged + git.untracked;
|
|
693
671
|
if (changes > 0) {
|
|
694
672
|
let ind = '';
|
|
@@ -700,82 +678,111 @@ function generateDashboard() {
|
|
|
700
678
|
if (git.ahead > 0) header += ` ${c.brightGreen}\u2191${git.ahead}${c.reset}`;
|
|
701
679
|
if (git.behind > 0) header += ` ${c.brightRed}\u2193${git.behind}${c.reset}`;
|
|
702
680
|
}
|
|
703
|
-
|
|
704
|
-
|
|
681
|
+
if (SL_CONFIG.show_session && session.duration) {
|
|
682
|
+
header += ` ${c.dim}\u2502${c.reset} ${c.cyan}\u23F1 ${session.duration}${c.reset}`;
|
|
683
|
+
}
|
|
705
684
|
lines.push(header);
|
|
706
685
|
|
|
707
686
|
// Separator
|
|
708
|
-
lines.push(`${c.dim}
|
|
709
|
-
|
|
710
|
-
//
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
const
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
}
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
);
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
687
|
+
lines.push(`${c.dim}${'─'.repeat(53)}${c.reset}`);
|
|
688
|
+
|
|
689
|
+
// Swarm line (if enabled)
|
|
690
|
+
if (SL_CONFIG.show_swarm) {
|
|
691
|
+
const swarm = getSwarmStatus();
|
|
692
|
+
const system = getSystemMetrics();
|
|
693
|
+
const swarmInd = swarm.coordinationActive ? `${c.brightGreen}\u25C9${c.reset}` : `${c.dim}\u25CB${c.reset}`;
|
|
694
|
+
const agentsColor = swarm.activeAgents > 0 ? c.brightGreen : c.red;
|
|
695
|
+
lines.push(
|
|
696
|
+
`${c.brightYellow}\uD83E\uDD16 Swarm${c.reset} ${swarmInd} [${agentsColor}${String(swarm.activeAgents).padStart(2)}${c.reset}/${c.brightWhite}${swarm.maxAgents}${c.reset}] ` +
|
|
697
|
+
`${c.brightPurple}\uD83D\uDC65 ${system.subAgents}${c.reset} ` +
|
|
698
|
+
`${c.brightCyan}\uD83D\uDCBE ${system.memoryMB}MB${c.reset}`
|
|
699
|
+
);
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
// AgentDB + MCP line (if either enabled)
|
|
703
|
+
if (SL_CONFIG.show_agentdb || SL_CONFIG.show_mcp) {
|
|
704
|
+
const parts = [];
|
|
705
|
+
if (SL_CONFIG.show_agentdb) {
|
|
706
|
+
const agentdb = getAgentDBStats();
|
|
707
|
+
const hnswInd = agentdb.hasHnsw ? `${c.brightGreen}\u26A1${c.reset}` : '';
|
|
708
|
+
const sizeDisp = agentdb.dbSizeKB >= 1024 ? `${(agentdb.dbSizeKB / 1024).toFixed(1)}MB` : `${agentdb.dbSizeKB}KB`;
|
|
709
|
+
const vectorColor = agentdb.vectorCount > 0 ? c.brightGreen : c.dim;
|
|
710
|
+
parts.push(`${c.cyan}Vectors${c.reset} ${vectorColor}\u25CF${agentdb.vectorCount}${hnswInd}${c.reset}`);
|
|
711
|
+
parts.push(`${c.cyan}Size${c.reset} ${c.brightWhite}${sizeDisp}${c.reset}`);
|
|
712
|
+
}
|
|
713
|
+
if (SL_CONFIG.show_mcp) {
|
|
714
|
+
const integration = getIntegrationStatus();
|
|
715
|
+
if (integration.mcpServers.total > 0) {
|
|
716
|
+
const mcpCol = integration.mcpServers.enabled === integration.mcpServers.total ? c.brightGreen :
|
|
717
|
+
integration.mcpServers.enabled > 0 ? c.brightYellow : c.red;
|
|
718
|
+
parts.push(`${c.cyan}MCP${c.reset} ${mcpCol}\u25CF${integration.mcpServers.enabled}/${integration.mcpServers.total}${c.reset}`);
|
|
719
|
+
}
|
|
720
|
+
if (integration.hasDatabase) parts.push(`${c.brightGreen}\u25C6${c.reset}DB`);
|
|
721
|
+
}
|
|
722
|
+
if (parts.length > 0) {
|
|
723
|
+
lines.push(`${c.brightCyan}\uD83D\uDCCA AgentDB${c.reset} ${parts.join(` ${c.dim}\u2502${c.reset} `)}`);
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
return lines.join('\n');
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
// Compact dashboard: header + single combined line
|
|
731
|
+
function generateCompactDashboard() {
|
|
732
|
+
const git = getGitInfo();
|
|
733
|
+
const session = getSessionStats();
|
|
734
|
+
const lines = [];
|
|
735
|
+
|
|
736
|
+
// Header: branding + git + session
|
|
737
|
+
let header = `${c.bold}${c.brightPurple}\u258A ${SL_CONFIG.branding}${c.reset}`;
|
|
738
|
+
if (SL_CONFIG.show_git && git.gitBranch) {
|
|
739
|
+
header += ` ${c.brightBlue}\u23C7 ${git.gitBranch}${c.reset}`;
|
|
740
|
+
const changes = git.modified + git.staged + git.untracked;
|
|
741
|
+
if (changes > 0) {
|
|
742
|
+
let ind = '';
|
|
743
|
+
if (git.staged > 0) ind += `${c.brightGreen}+${git.staged}${c.reset}`;
|
|
744
|
+
if (git.modified > 0) ind += `${c.brightYellow}~${git.modified}${c.reset}`;
|
|
745
|
+
if (git.untracked > 0) ind += `${c.dim}?${git.untracked}${c.reset}`;
|
|
746
|
+
header += ` ${ind}`;
|
|
747
|
+
}
|
|
748
|
+
if (git.ahead > 0) header += ` ${c.brightGreen}\u2191${git.ahead}${c.reset}`;
|
|
749
|
+
if (git.behind > 0) header += ` ${c.brightRed}\u2193${git.behind}${c.reset}`;
|
|
750
|
+
}
|
|
751
|
+
if (SL_CONFIG.show_session && session.duration) {
|
|
752
|
+
header += ` ${c.dim}\u2502${c.reset} ${c.cyan}\u23F1 ${session.duration}${c.reset}`;
|
|
753
|
+
}
|
|
754
|
+
lines.push(header);
|
|
755
|
+
|
|
756
|
+
// Combined swarm + agentdb + mcp line
|
|
757
|
+
const segments = [];
|
|
758
|
+
if (SL_CONFIG.show_swarm) {
|
|
759
|
+
const swarm = getSwarmStatus();
|
|
760
|
+
const swarmInd = swarm.coordinationActive ? `${c.brightGreen}\u25C9${c.reset}` : `${c.dim}\u25CB${c.reset}`;
|
|
761
|
+
const agentsColor = swarm.activeAgents > 0 ? c.brightGreen : c.red;
|
|
762
|
+
segments.push(
|
|
763
|
+
`${c.brightYellow}\uD83E\uDD16${c.reset} ${swarmInd}[${agentsColor}${swarm.activeAgents}${c.reset}/${c.brightWhite}${swarm.maxAgents}${c.reset}]`
|
|
764
|
+
);
|
|
765
|
+
}
|
|
766
|
+
if (SL_CONFIG.show_agentdb) {
|
|
767
|
+
const agentdb = getAgentDBStats();
|
|
768
|
+
const hnswInd = agentdb.hasHnsw ? `\u26A1` : '';
|
|
769
|
+
const sizeDisp = agentdb.dbSizeKB >= 1024 ? `${(agentdb.dbSizeKB / 1024).toFixed(1)}MB` : `${agentdb.dbSizeKB}KB`;
|
|
770
|
+
const vectorColor = agentdb.vectorCount > 0 ? c.brightGreen : c.dim;
|
|
771
|
+
segments.push(
|
|
772
|
+
`${c.brightCyan}\uD83D\uDCCA${c.reset} ${vectorColor}${agentdb.vectorCount}${hnswInd}${c.reset} ${c.dim}(${sizeDisp})${c.reset}`
|
|
773
|
+
);
|
|
774
|
+
}
|
|
775
|
+
if (SL_CONFIG.show_mcp) {
|
|
776
|
+
const integration = getIntegrationStatus();
|
|
777
|
+
if (integration.mcpServers.total > 0) {
|
|
778
|
+
const mcpCol = integration.mcpServers.enabled === integration.mcpServers.total ? c.brightGreen :
|
|
779
|
+
integration.mcpServers.enabled > 0 ? c.brightYellow : c.red;
|
|
780
|
+
segments.push(`${c.cyan}MCP${c.reset} ${mcpCol}\u25CF${integration.mcpServers.enabled}/${integration.mcpServers.total}${c.reset}`);
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
if (segments.length > 0) {
|
|
784
|
+
lines.push(segments.join(` ${c.dim}\u2502${c.reset} `));
|
|
785
|
+
}
|
|
779
786
|
|
|
780
787
|
return lines.join('\n');
|
|
781
788
|
}
|
|
@@ -801,8 +808,10 @@ function generateJSON() {
|
|
|
801
808
|
// ─── Main ───────────────────────────────────────────────────────
|
|
802
809
|
if (process.argv.includes('--json')) {
|
|
803
810
|
console.log(JSON.stringify(generateJSON(), null, 2));
|
|
804
|
-
} else if (process.argv.includes('--compact')) {
|
|
811
|
+
} else if (process.argv.includes('--json-compact')) {
|
|
805
812
|
console.log(JSON.stringify(generateJSON()));
|
|
813
|
+
} else if (process.argv.includes('--compact') || SL_CONFIG.mode === 'compact') {
|
|
814
|
+
console.log(generateCompactDashboard());
|
|
806
815
|
} else if (process.argv.includes('--dashboard') || SL_CONFIG.mode === 'dashboard') {
|
|
807
816
|
console.log(generateDashboard());
|
|
808
817
|
} else {
|
package/README.md
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
# MoFlo
|
|
6
6
|
|
|
7
|
-
**An opinionated
|
|
7
|
+
**An opinionated fork of [Ruflo/Claude Flow](https://github.com/ruvnet/ruflo), optimized for local development.**
|
|
8
8
|
|
|
9
|
-
MoFlo adds automatic code and guidance cataloging along with memory gating on top of the original Claude Flow orchestration engine. Where the upstream project provides raw building blocks, MoFlo ships opinionated defaults — workflow gates that enforce memory-first patterns, semantic indexing that runs at session start, and learned routing that improves over time — so you get a productive setup from `flo init` without manual tuning.
|
|
9
|
+
MoFlo adds automatic code and guidance cataloging along with memory gating on top of the original Ruflo/Claude Flow orchestration engine. Where the upstream project provides raw building blocks, MoFlo ships opinionated defaults — workflow gates that enforce memory-first patterns, semantic indexing that runs at session start, and learned routing that improves over time — so you get a productive setup from `flo init` without manual tuning.
|
|
10
10
|
|
|
11
11
|
Install it as a dev dependency and run `flo init`.
|
|
12
12
|
|
|
@@ -23,29 +23,82 @@ Install it as a dev dependency and run `flo init`.
|
|
|
23
23
|
| **Context Tracking** | Monitors context window usage (FRESH → MODERATE → DEPLETED → CRITICAL) and advises accordingly. |
|
|
24
24
|
| **Cross-Platform** | Works on macOS, Linux, and Windows. |
|
|
25
25
|
|
|
26
|
-
##
|
|
26
|
+
## Getting Started
|
|
27
|
+
|
|
28
|
+
### 1. Install and init
|
|
27
29
|
|
|
28
30
|
```bash
|
|
29
|
-
# Install as a dev dependency
|
|
30
31
|
npm install --save-dev moflo
|
|
31
|
-
|
|
32
|
-
# Initialize your project (generates config, hooks, skill, CLAUDE.md section)
|
|
33
32
|
npx flo init
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`flo init` automatically scans your project to find where your guidance and code live, then writes the results into `moflo.yaml`. It looks for:
|
|
36
|
+
|
|
37
|
+
| What | Directories it checks | Default if none found |
|
|
38
|
+
|------|----------------------|----------------------|
|
|
39
|
+
| **Guidance** | `.claude/guidance`, `docs/guides`, `docs`, `architecture`, `adr`, `.cursor/rules` | `.claude/guidance` |
|
|
40
|
+
| **Source code** | `src`, `packages`, `lib`, `app`, `apps`, `services`, `server`, `client` | `src` |
|
|
41
|
+
| **Languages** | Scans detected source dirs for file extensions | `.ts`, `.tsx`, `.js`, `.jsx` |
|
|
42
|
+
|
|
43
|
+
It also generates:
|
|
34
44
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
45
|
+
| Generated File | Purpose |
|
|
46
|
+
|----------------|---------|
|
|
47
|
+
| `moflo.yaml` | Project config with detected guidance/code locations |
|
|
48
|
+
| `.claude/settings.json` | Workflow gate hooks for Claude Code |
|
|
49
|
+
| `.claude/skills/flo/` | The `/flo` issue execution skill (also `/fl`) |
|
|
50
|
+
| `CLAUDE.md` section | Teaches Claude how to use MoFlo |
|
|
51
|
+
| `.gitignore` entries | Excludes MoFlo state directories |
|
|
38
52
|
|
|
39
|
-
|
|
40
|
-
|
|
53
|
+
In interactive mode (`flo init` without `--yes`), it shows what it found and lets you confirm or adjust before writing.
|
|
54
|
+
|
|
55
|
+
### 2. Review your guidance and code settings
|
|
56
|
+
|
|
57
|
+
Open `moflo.yaml` to see what init detected. The two key sections:
|
|
58
|
+
|
|
59
|
+
**Guidance** — documentation that helps Claude understand your project (conventions, architecture, domain context):
|
|
60
|
+
|
|
61
|
+
```yaml
|
|
62
|
+
guidance:
|
|
63
|
+
directories:
|
|
64
|
+
- .claude/guidance # project rules, patterns, conventions
|
|
65
|
+
- docs # general documentation
|
|
41
66
|
```
|
|
42
67
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
-
|
|
68
|
+
**Code map** — source files to index for "where does X live?" navigation:
|
|
69
|
+
|
|
70
|
+
```yaml
|
|
71
|
+
code_map:
|
|
72
|
+
directories:
|
|
73
|
+
- src # your source code
|
|
74
|
+
- packages # shared packages (monorepo)
|
|
75
|
+
extensions: [".ts", ".tsx"]
|
|
76
|
+
exclude: [node_modules, dist, .next, coverage]
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
MoFlo chunks your guidance files into semantic embeddings and indexes your code structure, so Claude searches your knowledge base before touching any files. Adjust these directories to match your project:
|
|
80
|
+
|
|
81
|
+
```yaml
|
|
82
|
+
# Monorepo with shared docs
|
|
83
|
+
guidance:
|
|
84
|
+
directories: [.claude/guidance, docs, packages/shared/docs]
|
|
85
|
+
code_map:
|
|
86
|
+
directories: [packages, apps, libs]
|
|
87
|
+
|
|
88
|
+
# Backend + frontend
|
|
89
|
+
code_map:
|
|
90
|
+
directories: [server/src, client/src]
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### 3. Index and verify
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
npx flo memory index-guidance # Index your guidance docs
|
|
97
|
+
npx flo memory code-map # Index your code structure
|
|
98
|
+
npx flo doctor # Verify everything works
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Both indexes run automatically at session start after this, so you only need to run them manually on first setup or after major structural changes.
|
|
49
102
|
|
|
50
103
|
## Commands
|
|
51
104
|
|
|
@@ -120,21 +173,22 @@ flo doctor # Health check
|
|
|
120
173
|
flo --version # Show version
|
|
121
174
|
```
|
|
122
175
|
|
|
123
|
-
## Configuration
|
|
124
176
|
|
|
125
|
-
|
|
177
|
+
## Full Configuration Reference
|
|
178
|
+
|
|
179
|
+
`flo init` generates a `moflo.yaml` at your project root. Here's the complete set of options:
|
|
126
180
|
|
|
127
181
|
```yaml
|
|
128
182
|
project:
|
|
129
183
|
name: "my-project"
|
|
130
184
|
|
|
131
185
|
guidance:
|
|
132
|
-
directories: [.claude/guidance]
|
|
186
|
+
directories: [.claude/guidance]
|
|
133
187
|
namespace: guidance
|
|
134
188
|
|
|
135
189
|
code_map:
|
|
136
|
-
directories: [src, packages]
|
|
137
|
-
extensions: [".ts", ".tsx"]
|
|
190
|
+
directories: [src, packages]
|
|
191
|
+
extensions: [".ts", ".tsx"]
|
|
138
192
|
exclude: [node_modules, dist]
|
|
139
193
|
namespace: code-map
|
|
140
194
|
|
|
@@ -147,42 +201,36 @@ auto_index:
|
|
|
147
201
|
guidance: true # Auto-index docs on session start
|
|
148
202
|
code_map: true # Auto-index code on session start
|
|
149
203
|
|
|
150
|
-
# Hook toggles (all on by default — disable to slim down)
|
|
151
204
|
hooks:
|
|
152
205
|
pre_edit: true # Track file edits for learning
|
|
153
|
-
post_edit: true # Record edit outcomes
|
|
154
|
-
pre_task: true #
|
|
206
|
+
post_edit: true # Record edit outcomes
|
|
207
|
+
pre_task: true # Agent routing before task spawn
|
|
155
208
|
post_task: true # Record task results for learning
|
|
156
209
|
gate: true # Workflow gate enforcement
|
|
157
|
-
route: true # Intelligent task routing
|
|
210
|
+
route: true # Intelligent task routing
|
|
158
211
|
stop_hook: true # Session-end persistence
|
|
159
212
|
session_restore: true # Restore session state on start
|
|
160
|
-
notification: true # Hook into Claude Code notifications
|
|
161
213
|
|
|
162
214
|
models:
|
|
163
|
-
default: opus
|
|
164
|
-
research: sonnet
|
|
165
|
-
review: opus
|
|
166
|
-
test: sonnet
|
|
215
|
+
default: opus
|
|
216
|
+
research: sonnet
|
|
217
|
+
review: opus
|
|
218
|
+
test: sonnet
|
|
167
219
|
|
|
168
|
-
# Optional: intelligent model routing (off by default)
|
|
169
220
|
model_routing:
|
|
170
|
-
enabled: false
|
|
221
|
+
enabled: false # Set to true for automatic model selection
|
|
171
222
|
confidence_threshold: 0.85
|
|
172
223
|
cost_optimization: true
|
|
173
224
|
circuit_breaker: true
|
|
174
225
|
|
|
175
|
-
# Status line display
|
|
176
226
|
status_line:
|
|
177
227
|
enabled: true
|
|
178
|
-
branding: "
|
|
179
|
-
mode:
|
|
228
|
+
branding: "MoFlo V4"
|
|
229
|
+
mode: compact # single-line, compact, or dashboard
|
|
180
230
|
show_git: true
|
|
181
|
-
show_model: true
|
|
182
231
|
show_session: true
|
|
183
|
-
show_intelligence: true
|
|
184
232
|
show_swarm: true
|
|
185
|
-
|
|
233
|
+
show_agentdb: true
|
|
186
234
|
show_mcp: true
|
|
187
235
|
```
|
|
188
236
|
|
|
@@ -228,13 +276,54 @@ MoFlo installs Claude Code hooks that run on every tool call. Together, these ga
|
|
|
228
276
|
|
|
229
277
|
All gates are configurable via `moflo.yaml` — you can disable any individual hook if it doesn't suit your workflow.
|
|
230
278
|
|
|
231
|
-
###
|
|
279
|
+
### Intelligent Agent Routing
|
|
280
|
+
|
|
281
|
+
MoFlo ships with 12 built-in task patterns that map common work to the right agent type:
|
|
282
|
+
|
|
283
|
+
| Pattern | Keywords | Primary Agent |
|
|
284
|
+
|---------|----------|---------------|
|
|
285
|
+
| security-task | auth, password, encryption, CVE | security-architect |
|
|
286
|
+
| testing-task | test, spec, coverage, e2e | tester |
|
|
287
|
+
| database-task | schema, migration, SQL, ORM | architect |
|
|
288
|
+
| feature-task | implement, add, create, build | architect → coder |
|
|
289
|
+
| bugfix-task | bug, fix, error, crash, debug | coder |
|
|
290
|
+
| api-task | endpoint, REST, route, handler | architect → coder |
|
|
291
|
+
| ... | | *(12 patterns total)* |
|
|
292
|
+
|
|
293
|
+
When you route a task (`flo hooks route --task "..."` or via MCP), MoFlo runs semantic similarity against these patterns using HNSW vector search and returns a ranked recommendation with confidence scores.
|
|
294
|
+
|
|
295
|
+
**The routing gets smarter over time.** Every time a task completes successfully, MoFlo's post-task hook records the outcome — the full task description, which agent handled it, and whether it succeeded. These learned patterns are combined with the built-in seeds on every future route call. Because learned patterns contain rich task descriptions (not just short keywords), they discriminate better as they accumulate.
|
|
232
296
|
|
|
233
|
-
|
|
297
|
+
Routing outcomes are stored in `.claude-flow/routing-outcomes.json` and persist across sessions. You can inspect them with `flo hooks patterns` or transfer them between projects with `flo hooks transfer`.
|
|
234
298
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
299
|
+
### The Two-Layer Task System
|
|
300
|
+
|
|
301
|
+
MoFlo doesn't replace your AI client's task system — it wraps it. Your client (Claude Code, Cursor, or any MCP-capable tool) handles spawning agents and running code. MoFlo adds a coordination layer on top that handles memory, routing, and learning.
|
|
302
|
+
|
|
303
|
+
```
|
|
304
|
+
┌──────────────────────────────────────────────────┐
|
|
305
|
+
│ YOUR AI CLIENT (Execution Layer) │
|
|
306
|
+
│ Spawns agents, runs code, streams output │
|
|
307
|
+
│ TaskCreate → Agent → TaskUpdate → results │
|
|
308
|
+
├──────────────────────────────────────────────────┤
|
|
309
|
+
│ MOFLO (Knowledge Layer) │
|
|
310
|
+
│ Routes tasks, gates agent spawns, stores │
|
|
311
|
+
│ patterns, learns from outcomes │
|
|
312
|
+
└──────────────────────────────────────────────────┘
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
Here's how a typical task flows through both layers:
|
|
316
|
+
|
|
317
|
+
1. **MoFlo routes** — Before work starts, MoFlo analyzes the prompt and recommends an agent type and model tier via hook or MCP tool.
|
|
318
|
+
2. **MoFlo gates** — Before an agent can spawn, MoFlo verifies that memory was searched and a task was registered. This prevents blind exploration.
|
|
319
|
+
3. **Your client executes** — The actual agent runs through your client's native task system. MoFlo doesn't manage the agent — your client handles execution, output, and completion.
|
|
320
|
+
4. **MoFlo learns** — After the agent finishes, MoFlo records what worked (or didn't) in its memory database. Successful patterns feed into future routing.
|
|
321
|
+
|
|
322
|
+
The key insight: **your client handles execution, MoFlo handles knowledge.** Your client is good at spawning agents and running code. MoFlo is good at remembering what happened, routing to the right agent, and ensuring prior knowledge is checked before exploring from scratch.
|
|
323
|
+
|
|
324
|
+
For complex work, MoFlo structures tasks into waves — a research wave discovers context, then an implementation wave acts on it — with dependencies tracked through both the client's task system and MoFlo's coordination layer. The full integration pattern is documented in `.claude/guidance/task-swarm-integration.md`.
|
|
325
|
+
|
|
326
|
+
The `/flo` skill ties both systems together for GitHub issues — driving a full workflow (research → enhance → implement → test → simplify → PR) with your client's agents for execution and MoFlo's memory for continuity.
|
|
238
327
|
|
|
239
328
|
### Memory & Knowledge Storage
|
|
240
329
|
|
|
@@ -262,18 +351,10 @@ When `flo init` runs, it appends a workflow section to your CLAUDE.md that teach
|
|
|
262
351
|
|
|
263
352
|
## Architecture
|
|
264
353
|
|
|
265
|
-
MoFlo is a maintained fork of [ruflo 3.x](https://github.com/ruvnet/ruflo) with:
|
|
266
|
-
|
|
267
|
-
- **3 patches applied to TypeScript source** (no more monkey-patching node_modules):
|
|
268
|
-
- 384-dim domain-aware embeddings for consistent CLI ↔ MCP search
|
|
269
|
-
- `windowsHide: true` on all spawn/exec calls (Windows UX)
|
|
270
|
-
- Routing learned patterns (task outcomes feed back into routing)
|
|
271
354
|
- **7 standalone bin scripts** shipped with npm: `flo-search`, `flo-embeddings`, `flo-index`, `flo-codemap`, `flo-learn`, `flo-setup`, plus the main `flo` CLI
|
|
272
355
|
- **Project config system**: `moflo.yaml` for per-project settings
|
|
273
356
|
- **One-stop init**: `flo init` generates everything needed for OOTB operation
|
|
274
357
|
|
|
275
|
-
Upstream remote preserved for cherry-picking future ruflo fixes.
|
|
276
|
-
|
|
277
358
|
## License
|
|
278
359
|
|
|
279
360
|
MIT (inherited from [upstream](https://github.com/ruvnet/ruflo))
|
package/bin/build-embeddings.mjs
CHANGED
|
@@ -282,7 +282,9 @@ function getEntriesNeedingEmbeddings(db, namespace = null, forceAll = false) {
|
|
|
282
282
|
const params = [];
|
|
283
283
|
|
|
284
284
|
if (!forceAll) {
|
|
285
|
-
|
|
285
|
+
// Include entries with no embedding OR entries with hash/fallback embeddings
|
|
286
|
+
// that should be upgraded to Xenova when available
|
|
287
|
+
sql += ` AND (embedding IS NULL OR embedding = '' OR embedding_model IN ('domain-aware-hash-v1', 'hash-fallback', 'local'))`;
|
|
286
288
|
}
|
|
287
289
|
|
|
288
290
|
if (namespace) {
|
|
@@ -408,7 +410,22 @@ async function main() {
|
|
|
408
410
|
const stats = getEmbeddingStats(db);
|
|
409
411
|
|
|
410
412
|
// Write changes back to disk (sql.js operates in-memory)
|
|
411
|
-
if (embedded > 0)
|
|
413
|
+
if (embedded > 0) {
|
|
414
|
+
saveDb(db);
|
|
415
|
+
|
|
416
|
+
// Delete stale HNSW index so the CLI rebuilds from fresh vectors
|
|
417
|
+
const hnswPaths = [
|
|
418
|
+
resolve(projectRoot, '.swarm/hnsw.index'),
|
|
419
|
+
resolve(projectRoot, '.swarm/hnsw.metadata.json'),
|
|
420
|
+
];
|
|
421
|
+
for (const p of hnswPaths) {
|
|
422
|
+
if (existsSync(p)) {
|
|
423
|
+
const { unlinkSync } = await import('fs');
|
|
424
|
+
unlinkSync(p);
|
|
425
|
+
log(`Deleted stale HNSW index: ${p}`);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
}
|
|
412
429
|
db.close();
|
|
413
430
|
|
|
414
431
|
console.log('');
|
|
@@ -665,20 +665,26 @@ async function main() {
|
|
|
665
665
|
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
666
666
|
log(`Done in ${elapsed}s — ${allChunks.length} chunks written to code-map namespace`);
|
|
667
667
|
|
|
668
|
-
// 7.
|
|
668
|
+
// 7. Generate embeddings inline (not detached — ensures Xenova runs reliably)
|
|
669
669
|
if (!skipEmbeddings) {
|
|
670
|
-
//
|
|
671
|
-
const
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
670
|
+
// Prefer moflo's own bin script, fall back to project's .claude/scripts/
|
|
671
|
+
const embedCandidates = [
|
|
672
|
+
resolve(dirname(fileURLToPath(import.meta.url)), 'build-embeddings.mjs'),
|
|
673
|
+
resolve(projectRoot, '.claude/scripts/build-embeddings.mjs'),
|
|
674
|
+
];
|
|
675
|
+
const embedScript = embedCandidates.find(p => existsSync(p));
|
|
676
|
+
if (embedScript) {
|
|
677
|
+
log('Generating embeddings for code-map...');
|
|
678
|
+
try {
|
|
679
|
+
execSync(`node "${embedScript}" --namespace code-map`, {
|
|
680
|
+
cwd: projectRoot,
|
|
681
|
+
stdio: 'inherit',
|
|
682
|
+
timeout: 120000,
|
|
683
|
+
windowsHide: true,
|
|
684
|
+
});
|
|
685
|
+
} catch (err) {
|
|
686
|
+
log(`Warning: embedding generation failed: ${err.message?.split('\n')[0]}`);
|
|
687
|
+
}
|
|
682
688
|
}
|
|
683
689
|
}
|
|
684
690
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "moflo",
|
|
3
|
-
"version": "4.6.
|
|
3
|
+
"version": "4.6.6",
|
|
4
4
|
"description": "MoFlo — AI agent orchestration for Claude Code. Forked from ruflo/claude-flow with patches applied to source, plus feature-level orchestration.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@moflo/cli",
|
|
3
|
-
"version": "4.6.
|
|
3
|
+
"version": "4.6.6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "MoFlo CLI — AI agent orchestration with specialized agents, swarm coordination, MCP server, self-learning hooks, and vector memory for Claude Code",
|
|
6
6
|
"main": "dist/src/index.js",
|