moflo 4.8.17 → 4.8.19

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.
@@ -25,7 +25,7 @@
25
25
  * npx flo-codemap # Via npx
26
26
  */
27
27
 
28
- import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
28
+ import { existsSync, readFileSync, writeFileSync, mkdirSync, readdirSync } from 'fs';
29
29
  import { resolve, dirname, relative, basename, extname } from 'path';
30
30
  import { fileURLToPath } from 'url';
31
31
  import { createHash } from 'crypto';
@@ -177,23 +177,102 @@ function countNamespace(db) {
177
177
  }
178
178
 
179
179
  // ---------------------------------------------------------------------------
180
- // Source file enumeration via git ls-files
180
+ // Source file enumeration git ls-files with filesystem fallback
181
181
  // ---------------------------------------------------------------------------
182
182
 
183
+ /** Read code_map config from moflo.yaml (directories, extensions, exclude). */
184
+ function readCodeMapConfig() {
185
+ const defaults = {
186
+ directories: ['src'],
187
+ extensions: ['.ts', '.tsx', '.js', '.mjs', '.jsx'],
188
+ exclude: [...EXCLUDE_DIRS],
189
+ };
190
+ try {
191
+ const yamlPath = resolve(projectRoot, 'moflo.yaml');
192
+ if (!existsSync(yamlPath)) return defaults;
193
+ const content = readFileSync(yamlPath, 'utf-8');
194
+ // Simple YAML parsing for code_map block
195
+ const block = content.match(/code_map:\s*\n((?:\s+\w+:.*\n?|\s+- .*\n?)+)/);
196
+ if (!block) return defaults;
197
+ const lines = block[1].split('\n');
198
+ let currentKey = null;
199
+ const result = { ...defaults };
200
+ for (const line of lines) {
201
+ const keyMatch = line.match(/^\s+(\w+):/);
202
+ const itemMatch = line.match(/^\s+- (.+)/);
203
+ if (keyMatch) {
204
+ currentKey = keyMatch[1];
205
+ // Inline array: extensions: [".ts", ".tsx"]
206
+ const inlineArray = line.match(/\[([^\]]+)\]/);
207
+ if (inlineArray && (currentKey === 'extensions' || currentKey === 'exclude' || currentKey === 'directories')) {
208
+ result[currentKey] = inlineArray[1].split(',').map(s => s.trim().replace(/^["']|["']$/g, ''));
209
+ }
210
+ } else if (itemMatch && currentKey) {
211
+ if (!Array.isArray(result[currentKey])) result[currentKey] = [];
212
+ result[currentKey].push(itemMatch[1].trim().replace(/^["']|["']$/g, ''));
213
+ }
214
+ }
215
+ return result;
216
+ } catch { return defaults; }
217
+ }
218
+
219
+ /** Walk a directory tree collecting source files (filesystem fallback). */
220
+ function walkDir(dir, extensions, excludeSet, maxDepth = 8, depth = 0) {
221
+ if (depth > maxDepth) return [];
222
+ const results = [];
223
+ let entries;
224
+ try {
225
+ entries = readdirSync(resolve(projectRoot, dir), { withFileTypes: true });
226
+ } catch { return []; }
227
+ for (const entry of entries) {
228
+ if (excludeSet.has(entry.name)) continue;
229
+ // Use forward slashes for consistent cross-platform paths
230
+ const rel = dir ? `${dir}/${entry.name}` : entry.name;
231
+ if (entry.isDirectory()) {
232
+ results.push(...walkDir(rel, extensions, excludeSet, maxDepth, depth + 1));
233
+ } else if (entry.isFile()) {
234
+ const ext = extname(entry.name);
235
+ if (extensions.has(ext)) results.push(rel);
236
+ }
237
+ }
238
+ return results;
239
+ }
240
+
183
241
  function getSourceFiles() {
184
- const raw = execSync(
185
- `git ls-files -- "*.ts" "*.tsx" "*.js" "*.mjs" "*.jsx"`,
186
- { cwd: projectRoot, encoding: 'utf-8', maxBuffer: 10 * 1024 * 1024 }
187
- ).trim();
242
+ // Try git ls-files first (fast, respects .gitignore)
243
+ try {
244
+ const raw = execSync(
245
+ `git ls-files -- "*.ts" "*.tsx" "*.js" "*.mjs" "*.jsx"`,
246
+ { cwd: projectRoot, encoding: 'utf-8', maxBuffer: 10 * 1024 * 1024 }
247
+ ).trim();
248
+
249
+ if (raw) {
250
+ const files = raw.split('\n').filter(f => {
251
+ for (const ex of EXCLUDE_DIRS) {
252
+ if (f.startsWith(ex + '/') || f.startsWith(ex + '\\')) return false;
253
+ }
254
+ return true;
255
+ });
256
+ if (files.length > 0) return files;
257
+ }
258
+ } catch {
259
+ // git not available or not a git repo — fall through
260
+ }
188
261
 
189
- if (!raw) return [];
262
+ // Fallback: walk configured directories from moflo.yaml
263
+ log('git ls-files returned no files — falling back to filesystem walk');
264
+ const config = readCodeMapConfig();
265
+ const extSet = new Set(config.extensions);
266
+ const excludeSet = new Set(config.exclude);
267
+ const files = [];
190
268
 
191
- return raw.split('\n').filter(f => {
192
- for (const ex of EXCLUDE_DIRS) {
193
- if (f.startsWith(ex + '/') || f.startsWith(ex + '\\')) return false;
269
+ for (const dir of config.directories) {
270
+ if (existsSync(resolve(projectRoot, dir))) {
271
+ files.push(...walkDir(dir, extSet, excludeSet));
194
272
  }
195
- return true;
196
- });
273
+ }
274
+
275
+ return files;
197
276
  }
198
277
 
199
278
  function computeFileListHash(files) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "moflo",
3
- "version": "4.8.17",
3
+ "version": "4.8.19",
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",
@@ -8,6 +8,11 @@
8
8
  * This allows: echo '{"jsonrpc":"2.0",...}' | npx @claude-flow/cli
9
9
  */
10
10
 
11
+ // Suppress agentic-flow's agentdb-runtime-patch warning. The patch targets
12
+ // agentdb v1.x (dist/controllers/) but v3+ uses dist/src/controllers/ and
13
+ // already ships with correct .js extensions — the patch is unnecessary.
14
+ process.env.SKIP_AGENTDB_PATCH ??= '1';
15
+
11
16
  import { randomUUID } from 'crypto';
12
17
 
13
18
  // Check if we should run in MCP server mode
@@ -558,6 +558,15 @@ function generateHooks(root, force, answers) {
558
558
  };
559
559
  // Merge: preserve existing non-MoFlo hooks, add MoFlo hooks
560
560
  existing.hooks = hooks;
561
+ // Ensure statusLine is always present (required for dashboard display).
562
+ // The executor.ts / settings-generator.ts code path adds this, but
563
+ // moflo-init.ts uses its own generateHooks() which was missing it.
564
+ if (!existing.statusLine) {
565
+ existing.statusLine = {
566
+ type: 'command',
567
+ command: 'node "$CLAUDE_PROJECT_DIR/.claude/helpers/statusline.cjs"',
568
+ };
569
+ }
561
570
  fs.writeFileSync(settingsPath, JSON.stringify(existing, null, 2), 'utf-8');
562
571
  return { name: '.claude/settings.json', status: existing.hooks ? 'updated' : 'created', detail: '14 hooks configured (gates, lifecycle, routing, session)' };
563
572
  }
@@ -7,6 +7,12 @@
7
7
  *
8
8
  * @module agentic-flow-bridge
9
9
  */
10
+ // Suppress agentic-flow's agentdb-runtime-patch warning. The patch targets
11
+ // agentdb v1.x (dist/controllers/) but v3+ uses dist/src/controllers/ and
12
+ // already ships with correct .js extensions — the patch is unnecessary.
13
+ if (typeof process !== 'undefined' && !process.env.SKIP_AGENTDB_PATCH) {
14
+ process.env.SKIP_AGENTDB_PATCH = '1';
15
+ }
10
16
  // ---------------------------------------------------------------------------
11
17
  // Cached module handles (Promise-based to prevent TOCTOU races)
12
18
  // ---------------------------------------------------------------------------
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moflo/cli",
3
- "version": "4.8.17",
3
+ "version": "4.8.19",
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",