moflo 4.3.1 → 4.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/guidance/agent-bootstrap.md +2 -2
- package/.claude/guidance/guidance-memory-strategy.md +262 -0
- package/.claude/guidance/memory-strategy.md +204 -0
- package/.claude/guidance/moflo.md +594 -0
- package/.claude/guidance/task-swarm-integration.md +348 -0
- package/.claude/helpers/hook-handler.cjs +83 -1
- package/.claude/helpers/metrics-db.mjs +492 -488
- package/.claude/helpers/statusline.cjs +85 -16
- package/.claude/settings.json +10 -25
- package/.claude/settings.local.json +14 -0
- package/README.md +279 -181
- package/bin/build-embeddings.mjs +2 -2
- package/bin/generate-code-map.mjs +1 -1
- package/bin/index-guidance.mjs +85 -15
- package/bin/semantic-search.mjs +6 -6
- package/bin/setup-project.mjs +9 -9
- package/package.json +8 -7
- package/src/@claude-flow/cli/dist/src/commands/config.js +2 -2
- package/src/@claude-flow/cli/dist/src/commands/gate.d.ts +8 -8
- package/src/@claude-flow/cli/dist/src/commands/gate.js +13 -13
- package/src/@claude-flow/cli/dist/src/commands/orc.d.ts +4 -4
- package/src/@claude-flow/cli/dist/src/commands/orc.js +13 -13
- package/src/@claude-flow/cli/dist/src/init/moflo-init.js +180 -179
- package/src/@claude-flow/memory/package.json +44 -42
package/README.md
CHANGED
|
@@ -1,181 +1,279 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
|
16
|
-
|
|
17
|
-
| **
|
|
18
|
-
| **
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
#
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/eric-cielo/moflo/main/docs/moflo.png" alt="MoFlo" width="480" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
# MoFlo
|
|
6
|
+
|
|
7
|
+
**An opinionated, maintained fork of [Ruflo/Claude Flow](https://github.com/ruvnet/ruflo) that just works.**
|
|
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.
|
|
10
|
+
|
|
11
|
+
Install it as a dev dependency and run `flo init`.
|
|
12
|
+
|
|
13
|
+
## Features
|
|
14
|
+
|
|
15
|
+
| Feature | What It Does |
|
|
16
|
+
|---------|-------------|
|
|
17
|
+
| **Semantic Memory** | 384-dim domain-aware embeddings. Store knowledge, search it instantly. |
|
|
18
|
+
| **Code Navigation** | Indexes your codebase structure so Claude can answer "where does X live?" without Glob/Grep. |
|
|
19
|
+
| **Guidance Indexing** | Chunks your project docs (`.claude/guidance/`, `docs/`) and makes them searchable. |
|
|
20
|
+
| **Workflow Gates** | Enforces memory-first and task-creation patterns via Claude Code hooks. Prevents Claude from skipping steps. |
|
|
21
|
+
| **Learned Routing** | Routes tasks to the right agent type. Learns from outcomes — gets better over time. |
|
|
22
|
+
| **`/flo` Skill** | Execute GitHub issues through a full workflow: research → enhance → implement → test → simplify → PR. (Also available as `/fl`.) |
|
|
23
|
+
| **Context Tracking** | Monitors context window usage (FRESH → MODERATE → DEPLETED → CRITICAL) and advises accordingly. |
|
|
24
|
+
| **Cross-Platform** | Works on macOS, Linux, and Windows. |
|
|
25
|
+
|
|
26
|
+
## Quick Start
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# Install as a dev dependency
|
|
30
|
+
npm install --save-dev moflo
|
|
31
|
+
|
|
32
|
+
# Initialize your project (generates config, hooks, skill, CLAUDE.md section)
|
|
33
|
+
npx flo init
|
|
34
|
+
|
|
35
|
+
# Index your project's knowledge base
|
|
36
|
+
npx flo memory index-guidance
|
|
37
|
+
npx flo memory code-map
|
|
38
|
+
|
|
39
|
+
# Verify everything works
|
|
40
|
+
npx flo doctor
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
That's it. `flo init` sets up everything:
|
|
44
|
+
- `moflo.yaml` — project config (auto-detects source dirs, languages, guidance paths)
|
|
45
|
+
- `.claude/settings.json` — workflow gate hooks
|
|
46
|
+
- `.claude/skills/flo/` — the `/flo` issue execution skill (with `/fl` alias)
|
|
47
|
+
- `CLAUDE.md` — appends a MoFlo workflow section so Claude knows how to use it
|
|
48
|
+
- `.gitignore` — adds state directories
|
|
49
|
+
|
|
50
|
+
## Commands
|
|
51
|
+
|
|
52
|
+
### Memory
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
flo memory store -k "key" --value "data" # Store with 384-dim embedding
|
|
56
|
+
flo memory search -q "auth patterns" # Semantic search
|
|
57
|
+
flo memory index-guidance # Index guidance docs
|
|
58
|
+
flo memory code-map # Index code structure
|
|
59
|
+
flo memory rebuild-index # Regenerate all embeddings
|
|
60
|
+
flo memory stats # Show statistics
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Routing & Learning
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
flo hooks route --task "description" # Route task to optimal agent
|
|
67
|
+
flo hooks learn --pattern "..." --domain "." # Store a pattern
|
|
68
|
+
flo hooks patterns # List learned patterns
|
|
69
|
+
flo hooks consolidate # Promote/prune patterns
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Workflow Gates
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
flo gate check-before-scan # Blocks Glob/Grep if memory not searched
|
|
76
|
+
flo gate check-before-agent # Blocks Agent tool if no TaskCreate
|
|
77
|
+
flo gate prompt-reminder # Context bracket tracking
|
|
78
|
+
flo gate session-reset # Reset workflow state
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Feature Orchestration
|
|
82
|
+
|
|
83
|
+
Sequence multiple GitHub issues through `/flo` workflows using a YAML definition:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
flo orc run feature.yaml # Execute a feature (stories in dependency order)
|
|
87
|
+
flo orc run feature.yaml --dry-run # Show execution plan without running
|
|
88
|
+
flo orc run feature.yaml --verbose # Execute with Claude output streaming
|
|
89
|
+
flo orc status my-feature # Check progress of a feature
|
|
90
|
+
flo orc reset my-feature # Reset feature state for re-run
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Feature YAML example:
|
|
94
|
+
|
|
95
|
+
```yaml
|
|
96
|
+
feature:
|
|
97
|
+
id: my-feature
|
|
98
|
+
name: "My Feature"
|
|
99
|
+
repository: /path/to/project
|
|
100
|
+
base_branch: main
|
|
101
|
+
|
|
102
|
+
stories:
|
|
103
|
+
- id: story-1
|
|
104
|
+
name: "Entity and service"
|
|
105
|
+
issue: 101
|
|
106
|
+
|
|
107
|
+
- id: story-2
|
|
108
|
+
name: "Routes and tests"
|
|
109
|
+
issue: 102
|
|
110
|
+
depends_on: [story-1]
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Stories are resolved via topological sort (respecting `depends_on`), then executed sequentially by spawning `claude -p "/flo <issue>"`.
|
|
114
|
+
|
|
115
|
+
### System
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
flo init # Initialize project (one-time setup)
|
|
119
|
+
flo doctor # Health check
|
|
120
|
+
flo --version # Show version
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Configuration
|
|
124
|
+
|
|
125
|
+
`flo init` generates a `moflo.yaml` at your project root:
|
|
126
|
+
|
|
127
|
+
```yaml
|
|
128
|
+
project:
|
|
129
|
+
name: "my-project"
|
|
130
|
+
|
|
131
|
+
guidance:
|
|
132
|
+
directories: [.claude/guidance] # Where your knowledge docs live
|
|
133
|
+
namespace: guidance
|
|
134
|
+
|
|
135
|
+
code_map:
|
|
136
|
+
directories: [src, packages] # Source dirs to index
|
|
137
|
+
extensions: [".ts", ".tsx"] # Auto-detected from your project
|
|
138
|
+
exclude: [node_modules, dist]
|
|
139
|
+
namespace: code-map
|
|
140
|
+
|
|
141
|
+
gates:
|
|
142
|
+
memory_first: true # Must search memory before file exploration
|
|
143
|
+
task_create_first: true # Must TaskCreate before Agent tool
|
|
144
|
+
context_tracking: true # Track context window depletion
|
|
145
|
+
|
|
146
|
+
auto_index:
|
|
147
|
+
guidance: true # Auto-index docs on session start
|
|
148
|
+
code_map: true # Auto-index code on session start
|
|
149
|
+
|
|
150
|
+
# Hook toggles (all on by default — disable to slim down)
|
|
151
|
+
hooks:
|
|
152
|
+
pre_edit: true # Track file edits for learning
|
|
153
|
+
post_edit: true # Record edit outcomes, train neural patterns
|
|
154
|
+
pre_task: true # Get agent routing before task spawn
|
|
155
|
+
post_task: true # Record task results for learning
|
|
156
|
+
gate: true # Workflow gate enforcement
|
|
157
|
+
route: true # Intelligent task routing on each prompt
|
|
158
|
+
stop_hook: true # Session-end persistence
|
|
159
|
+
session_restore: true # Restore session state on start
|
|
160
|
+
notification: true # Hook into Claude Code notifications
|
|
161
|
+
|
|
162
|
+
models:
|
|
163
|
+
default: opus # General tasks
|
|
164
|
+
research: sonnet # Research/exploration agents
|
|
165
|
+
review: opus # Code review agents
|
|
166
|
+
test: sonnet # Test-writing agents
|
|
167
|
+
|
|
168
|
+
# Optional: intelligent model routing (off by default)
|
|
169
|
+
model_routing:
|
|
170
|
+
enabled: false # Set to true to enable
|
|
171
|
+
confidence_threshold: 0.85
|
|
172
|
+
cost_optimization: true
|
|
173
|
+
circuit_breaker: true
|
|
174
|
+
|
|
175
|
+
# Status line display
|
|
176
|
+
status_line:
|
|
177
|
+
enabled: true
|
|
178
|
+
branding: "Moflo V4"
|
|
179
|
+
mode: single-line # single-line or dashboard
|
|
180
|
+
show_git: true
|
|
181
|
+
show_model: true
|
|
182
|
+
show_session: true
|
|
183
|
+
show_intelligence: true
|
|
184
|
+
show_swarm: true
|
|
185
|
+
show_hooks: true
|
|
186
|
+
show_mcp: true
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Model Routing
|
|
190
|
+
|
|
191
|
+
By default, MoFlo uses **static model preferences** — each agent role uses the model specified in `models:`. This is predictable and gives you full control.
|
|
192
|
+
|
|
193
|
+
Set `model_routing.enabled: true` to enable **intelligent routing**, which analyzes each task's complexity and auto-selects the cheapest capable model:
|
|
194
|
+
|
|
195
|
+
| Complexity | Model | Example Tasks |
|
|
196
|
+
|-----------|-------|---------------|
|
|
197
|
+
| Low | Haiku | Typos, renames, config changes, formatting |
|
|
198
|
+
| Medium | Sonnet | Implement features, write tests, fix bugs |
|
|
199
|
+
| High | Opus | Architecture, security audits, complex debugging |
|
|
200
|
+
|
|
201
|
+
The router learns from outcomes — if a model fails a task, the circuit breaker penalizes it and escalates to a more capable model.
|
|
202
|
+
|
|
203
|
+
You can pin specific agents even when routing is enabled:
|
|
204
|
+
|
|
205
|
+
```yaml
|
|
206
|
+
model_routing:
|
|
207
|
+
enabled: true
|
|
208
|
+
agent_overrides:
|
|
209
|
+
security-architect: opus # Never downgrade security work
|
|
210
|
+
researcher: sonnet # Pin research to sonnet
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## How It Works
|
|
214
|
+
|
|
215
|
+
MoFlo sits between Claude Code and your project. It uses Claude Code's native hook system to enforce good habits, store knowledge, and learn from outcomes — so Claude gets better at working in your codebase over time.
|
|
216
|
+
|
|
217
|
+
### The Gate System
|
|
218
|
+
|
|
219
|
+
MoFlo installs Claude Code hooks that run on every tool call. Together, these gates create a **feedback loop** that prevents Claude from wasting tokens on blind exploration and ensures it builds on prior knowledge.
|
|
220
|
+
|
|
221
|
+
**Memory-first gate** — Before Claude can use Glob, Grep, or Read on guidance files, it must first search the memory database. This forces Claude to check what it already knows (or what was learned in prior sessions) before re-exploring from scratch. The gate automatically classifies each prompt — simple directives like "commit" or "yes" skip the gate, while task-oriented prompts like "fix the auth bug" enforce it.
|
|
222
|
+
|
|
223
|
+
**Task-create gate** — Before Claude can spawn sub-agents via the Task tool, it must call TaskCreate first. This ensures every agent spawn is tracked, preventing runaway agent proliferation and making it possible to review what work was delegated.
|
|
224
|
+
|
|
225
|
+
**Context tracking** — Each interaction increments a counter. As the conversation grows, MoFlo warns Claude about context depletion (FRESH → MODERATE → DEPLETED → CRITICAL) and advises it to checkpoint progress, compact, or start a fresh session before quality degrades.
|
|
226
|
+
|
|
227
|
+
**Routing** — On each prompt, MoFlo's route hook analyzes the task and recommends the optimal agent type and model tier (haiku for simple tasks, sonnet for moderate, opus for complex). This saves cost without sacrificing quality.
|
|
228
|
+
|
|
229
|
+
All gates are configurable via `moflo.yaml` — you can disable any individual hook if it doesn't suit your workflow.
|
|
230
|
+
|
|
231
|
+
### The Task System
|
|
232
|
+
|
|
233
|
+
MoFlo integrates Claude Code's native Task tool with its own coordination layer:
|
|
234
|
+
|
|
235
|
+
1. **Pre-task hook** — Before a sub-agent spawns, MoFlo records what's about to happen and can inject context (prior learnings, routing recommendations) into the agent's prompt.
|
|
236
|
+
2. **Post-task hook** — After a sub-agent completes, MoFlo records the outcome. Successful patterns are stored in the memory database for future reference. Failed patterns feed into the routing circuit breaker.
|
|
237
|
+
3. **The `/flo` skill** — Wraps the entire lifecycle of a GitHub issue: research the issue → enhance the ticket → implement the solution → run tests → simplify the code → create a PR. Each phase can use sub-agents, and all learning feeds back into memory.
|
|
238
|
+
|
|
239
|
+
### Memory & Knowledge Storage
|
|
240
|
+
|
|
241
|
+
MoFlo uses a SQLite database (via sql.js/WASM — no native deps) to store three types of knowledge:
|
|
242
|
+
|
|
243
|
+
| Namespace | What's Stored | How It Gets There |
|
|
244
|
+
|-----------|---------------|-------------------|
|
|
245
|
+
| `guidance` | Chunked project docs (`.claude/guidance/`, `docs/`) with 384-dim embeddings | `flo-index` on session start |
|
|
246
|
+
| `code-map` | Structural index of source files (exports, classes, functions) | `flo-codemap` on session start |
|
|
247
|
+
| `patterns` | Learned patterns from successful task outcomes | Post-task hooks after agent work |
|
|
248
|
+
|
|
249
|
+
**Semantic search** uses cosine similarity on neural embeddings (MiniLM-L6-v2, 384 dimensions). When Claude searches memory, it gets the most relevant chunks ranked by semantic similarity — not keyword matching.
|
|
250
|
+
|
|
251
|
+
**Session start indexing** — Three background processes run on every session start: the guidance indexer, the code map generator, and the learning service. All three are incremental (unchanged files are skipped) and run in parallel so they don't block the session.
|
|
252
|
+
|
|
253
|
+
**Cross-session persistence** — Everything stored in the database survives across sessions. Patterns learned on Monday are available on Friday. The stop hook exports session metrics, and the session-restore hook loads prior state.
|
|
254
|
+
|
|
255
|
+
### For Claude
|
|
256
|
+
|
|
257
|
+
When `flo init` runs, it appends a workflow section to your CLAUDE.md that teaches Claude:
|
|
258
|
+
- Always search memory before Glob/Grep/Read (enforced by gates)
|
|
259
|
+
- Use `mcp__claude-flow__memory_search` for knowledge retrieval
|
|
260
|
+
- Use `/flo <issue>` (or `/fl`) for issue execution
|
|
261
|
+
- Store learnings after task completion
|
|
262
|
+
|
|
263
|
+
## Architecture
|
|
264
|
+
|
|
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
|
+
- **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
|
+
- **Project config system**: `moflo.yaml` for per-project settings
|
|
273
|
+
- **One-stop init**: `flo init` generates everything needed for OOTB operation
|
|
274
|
+
|
|
275
|
+
Upstream remote preserved for cherry-picking future ruflo fixes.
|
|
276
|
+
|
|
277
|
+
## License
|
|
278
|
+
|
|
279
|
+
MIT (inherited from [upstream](https://github.com/ruvnet/ruflo))
|
package/bin/build-embeddings.mjs
CHANGED
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
*
|
|
15
15
|
* Usage:
|
|
16
16
|
* node node_modules/moflo/bin/build-embeddings.mjs # Embed entries without embeddings
|
|
17
|
-
* npx
|
|
18
|
-
* npx
|
|
17
|
+
* npx flo-embeddings --force # Re-embed all entries
|
|
18
|
+
* npx flo-embeddings --namespace guidance # Only specific namespace
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
21
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
* node node_modules/moflo/bin/generate-code-map.mjs --verbose # Detailed logging
|
|
23
23
|
* node node_modules/moflo/bin/generate-code-map.mjs --no-embeddings # Skip embedding generation
|
|
24
24
|
* node node_modules/moflo/bin/generate-code-map.mjs --stats # Print stats and exit
|
|
25
|
-
* npx
|
|
25
|
+
* npx flo-codemap # Via npx
|
|
26
26
|
*/
|
|
27
27
|
|
|
28
28
|
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
package/bin/index-guidance.mjs
CHANGED
|
@@ -16,10 +16,10 @@
|
|
|
16
16
|
*
|
|
17
17
|
* Usage:
|
|
18
18
|
* node node_modules/moflo/bin/index-guidance.mjs # Index all + generate embeddings
|
|
19
|
-
* npx
|
|
20
|
-
* npx
|
|
21
|
-
* npx
|
|
22
|
-
* npx
|
|
19
|
+
* npx flo-index --force # Force reindex all
|
|
20
|
+
* npx flo-index --file X # Index specific file
|
|
21
|
+
* npx flo-index --no-embeddings # Skip embedding generation
|
|
22
|
+
* npx flo-index --overlap 20 # Set context overlap % (default: 15)
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
25
|
import { existsSync, readdirSync, readFileSync, statSync, mkdirSync, writeFileSync } from 'fs';
|
|
@@ -41,13 +41,67 @@ function findProjectRoot() {
|
|
|
41
41
|
|
|
42
42
|
const projectRoot = findProjectRoot();
|
|
43
43
|
|
|
44
|
+
// Locate the moflo package root (for bundled guidance that ships with moflo)
|
|
45
|
+
const mofloRoot = resolve(__dirname, '..');
|
|
46
|
+
|
|
44
47
|
const NAMESPACE = 'guidance';
|
|
45
48
|
const DB_PATH = resolve(projectRoot, '.swarm/memory.db');
|
|
46
49
|
|
|
47
|
-
//
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
50
|
+
// ============================================================================
|
|
51
|
+
// Load guidance directories from moflo.yaml, falling back to defaults
|
|
52
|
+
// ============================================================================
|
|
53
|
+
|
|
54
|
+
function loadGuidanceDirs() {
|
|
55
|
+
const dirs = [];
|
|
56
|
+
|
|
57
|
+
// 1. Read moflo.yaml / moflo.config.json for user-configured directories
|
|
58
|
+
let configDirs = null;
|
|
59
|
+
const yamlPath = resolve(projectRoot, 'moflo.yaml');
|
|
60
|
+
const jsonPath = resolve(projectRoot, 'moflo.config.json');
|
|
61
|
+
|
|
62
|
+
if (existsSync(yamlPath)) {
|
|
63
|
+
try {
|
|
64
|
+
const content = readFileSync(yamlPath, 'utf-8');
|
|
65
|
+
// Simple YAML array extraction — avoids needing js-yaml at runtime
|
|
66
|
+
// Matches: guidance:\n directories:\n - .claude/guidance\n - docs/guides
|
|
67
|
+
const guidanceBlock = content.match(/guidance:\s*\n\s+directories:\s*\n((?:\s+-\s+.+\n?)+)/);
|
|
68
|
+
if (guidanceBlock) {
|
|
69
|
+
const items = guidanceBlock[1].match(/-\s+(.+)/g);
|
|
70
|
+
if (items && items.length > 0) {
|
|
71
|
+
configDirs = items.map(item => item.replace(/^-\s+/, '').trim());
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
} catch { /* ignore parse errors, fall through to defaults */ }
|
|
75
|
+
} else if (existsSync(jsonPath)) {
|
|
76
|
+
try {
|
|
77
|
+
const raw = JSON.parse(readFileSync(jsonPath, 'utf-8'));
|
|
78
|
+
if (raw.guidance?.directories && Array.isArray(raw.guidance.directories)) {
|
|
79
|
+
configDirs = raw.guidance.directories;
|
|
80
|
+
}
|
|
81
|
+
} catch { /* ignore parse errors */ }
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Use config dirs or fall back to defaults
|
|
85
|
+
const userDirs = configDirs || ['.claude/guidance', 'docs/guides'];
|
|
86
|
+
for (const d of userDirs) {
|
|
87
|
+
dirs.push({ path: d, prefix: 'guidance' });
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// 2. Include moflo's own bundled guidance (ships with the package)
|
|
91
|
+
// Only when running inside a consumer project (not moflo itself)
|
|
92
|
+
const bundledGuidanceDir = resolve(mofloRoot, '.claude/guidance');
|
|
93
|
+
const projectGuidanceDir = resolve(projectRoot, '.claude/guidance');
|
|
94
|
+
if (
|
|
95
|
+
existsSync(bundledGuidanceDir) &&
|
|
96
|
+
resolve(bundledGuidanceDir) !== resolve(projectGuidanceDir)
|
|
97
|
+
) {
|
|
98
|
+
dirs.push({ path: bundledGuidanceDir, prefix: 'moflo-bundled', absolute: true });
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return dirs;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const GUIDANCE_DIRS = loadGuidanceDirs();
|
|
51
105
|
|
|
52
106
|
// Chunking config - optimized for Claude's retrieval
|
|
53
107
|
const MIN_CHUNK_SIZE = 50; // Lower minimum to avoid mega-chunks
|
|
@@ -573,11 +627,11 @@ function indexFile(db, filePath, keyPrefix) {
|
|
|
573
627
|
}
|
|
574
628
|
|
|
575
629
|
function indexDirectory(db, dirConfig) {
|
|
576
|
-
const dirPath = resolve(projectRoot, dirConfig.path);
|
|
630
|
+
const dirPath = dirConfig.absolute ? dirConfig.path : resolve(projectRoot, dirConfig.path);
|
|
577
631
|
const results = [];
|
|
578
632
|
|
|
579
633
|
if (!existsSync(dirPath)) {
|
|
580
|
-
|
|
634
|
+
if (verbose) debug(`Directory not found: ${dirConfig.path}`);
|
|
581
635
|
return results;
|
|
582
636
|
}
|
|
583
637
|
|
|
@@ -607,14 +661,24 @@ function cleanStaleEntries(db) {
|
|
|
607
661
|
|
|
608
662
|
let staleCount = 0;
|
|
609
663
|
|
|
664
|
+
// Build a lookup of all indexed directory configs for stale detection
|
|
665
|
+
const prefixToDirMap = {};
|
|
666
|
+
for (const dirConfig of GUIDANCE_DIRS) {
|
|
667
|
+
const dirPath = dirConfig.absolute ? dirConfig.path : resolve(projectRoot, dirConfig.path);
|
|
668
|
+
prefixToDirMap[dirConfig.prefix] = dirPath;
|
|
669
|
+
}
|
|
670
|
+
|
|
610
671
|
for (const { key } of docs) {
|
|
611
|
-
// Convert key back to file path
|
|
672
|
+
// Convert key back to file path by matching doc-{prefix}-{filename}
|
|
612
673
|
let filePath;
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
674
|
+
for (const [prefix, dirPath] of Object.entries(prefixToDirMap)) {
|
|
675
|
+
const docPrefix = `doc-${prefix}-`;
|
|
676
|
+
if (key.startsWith(docPrefix)) {
|
|
677
|
+
filePath = resolve(dirPath, key.replace(docPrefix, '') + '.md');
|
|
678
|
+
break;
|
|
679
|
+
}
|
|
617
680
|
}
|
|
681
|
+
if (!filePath) continue; // Unknown prefix, skip
|
|
618
682
|
|
|
619
683
|
if (!existsSync(filePath)) {
|
|
620
684
|
const chunkPrefix = key.replace('doc-', 'chunk-');
|
|
@@ -651,6 +715,12 @@ function cleanStaleEntries(db) {
|
|
|
651
715
|
console.log('');
|
|
652
716
|
log('Indexing guidance files with FULL RAG linked segments...');
|
|
653
717
|
log(` Context overlap: ${overlapPercent}%`);
|
|
718
|
+
log(` Directories (${GUIDANCE_DIRS.length}):`);
|
|
719
|
+
for (const d of GUIDANCE_DIRS) {
|
|
720
|
+
const dirPath = d.absolute ? d.path : resolve(projectRoot, d.path);
|
|
721
|
+
const exists = existsSync(dirPath);
|
|
722
|
+
log(` ${exists ? '✓' : '✗'} ${d.absolute ? dirPath : d.path} [${d.prefix}]`);
|
|
723
|
+
}
|
|
654
724
|
console.log('');
|
|
655
725
|
|
|
656
726
|
const db = await getDb();
|