moflo 4.8.43 → 4.8.45

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.
@@ -1,183 +1,193 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Sequential indexer chain for session-start.
4
- *
5
- * Runs all DB-writing indexers one at a time to avoid sql.js last-write-wins
6
- * concurrency issues (#78), then triggers HNSW rebuild once everything is
7
- * committed (#81).
8
- *
9
- * Spawned as a single detached background process by hooks.mjs session-start.
10
- */
11
-
12
- import { existsSync, appendFileSync, readFileSync } from 'fs';
13
- import { resolve, dirname } from 'path';
14
- import { fileURLToPath } from 'url';
15
- import { execFileSync } from 'child_process';
16
-
17
- const __dirname = dirname(fileURLToPath(import.meta.url));
18
-
19
- // Detect project root by walking up from cwd to find package.json.
20
- // IMPORTANT: Do NOT use resolve(__dirname, '..') — this script lives in bin/
21
- // during development but gets synced to .claude/scripts/ in consumer projects,
22
- // so __dirname-relative paths break. findProjectRoot() works in both locations.
23
- function findProjectRoot() {
24
- let dir = process.cwd();
25
- const root = resolve(dir, '/');
26
- while (dir !== root) {
27
- if (existsSync(resolve(dir, 'package.json'))) return dir;
28
- dir = dirname(dir);
29
- }
30
- return process.cwd();
31
- }
32
-
33
- const projectRoot = findProjectRoot();
34
- const LOG_PATH = resolve(projectRoot, '.swarm/hooks.log');
35
-
36
- function log(msg) {
37
- const ts = new Date().toISOString().replace('T', ' ').slice(0, 19);
38
- const line = `[${ts}] [index-all] ${msg}\n`;
39
- try { appendFileSync(LOG_PATH, line); } catch { /* ignore */ }
40
- }
41
-
42
- function resolveBin(binName, localScript) {
43
- const mofloScript = resolve(projectRoot, 'node_modules/moflo/bin', localScript);
44
- if (existsSync(mofloScript)) return mofloScript;
45
- const npmBin = resolve(projectRoot, 'node_modules/.bin', binName);
46
- if (existsSync(npmBin)) return npmBin;
47
- const localPath = resolve(projectRoot, '.claude/scripts', localScript);
48
- if (existsSync(localPath)) return localPath;
49
- // Also check bin/ directory (for development use)
50
- const binPath = resolve(projectRoot, 'bin', localScript);
51
- if (existsSync(binPath)) return binPath;
52
- return null;
53
- }
54
-
55
- function getLocalCliPath() {
56
- const paths = [
57
- resolve(projectRoot, 'node_modules/moflo/src/@claude-flow/cli/bin/cli.js'),
58
- resolve(projectRoot, 'node_modules/moflo/bin/cli.js'),
59
- resolve(projectRoot, 'node_modules/.bin/flo'),
60
- // Development: local CLI
61
- resolve(projectRoot, 'src/@claude-flow/cli/bin/cli.js'),
62
- ];
63
- for (const p of paths) {
64
- if (existsSync(p)) return p;
65
- }
66
- return null;
67
- }
68
-
69
- /** Read moflo.yaml once and cache auto_index flags. */
70
- let _autoIndexFlags = null;
71
- function isIndexEnabled(key) {
72
- if (_autoIndexFlags === null) {
73
- _autoIndexFlags = {};
74
- const yamlPath = resolve(projectRoot, 'moflo.yaml');
75
- if (existsSync(yamlPath)) {
76
- try {
77
- const content = readFileSync(yamlPath, 'utf-8');
78
- for (const k of ['guidance', 'code_map', 'tests', 'patterns']) {
79
- const re = new RegExp(`auto_index:\\s*\\n(?:.*\\n)*?\\s+${k}:\\s*(true|false)`);
80
- const match = content.match(re);
81
- _autoIndexFlags[k] = match ? match[1] !== 'false' : true;
82
- }
83
- } catch { /* ignore, all default to true */ }
84
- }
85
- }
86
- return _autoIndexFlags[key] !== false;
87
- }
88
-
89
- function runStep(label, cmd, args, timeoutMs = 120_000) {
90
- const start = Date.now();
91
- log(`START ${label}`);
92
- try {
93
- execFileSync(cmd, args, {
94
- cwd: projectRoot,
95
- timeout: timeoutMs,
96
- stdio: 'ignore',
97
- windowsHide: true,
98
- });
99
- const elapsed = ((Date.now() - start) / 1000).toFixed(1);
100
- log(`DONE ${label} (${elapsed}s)`);
101
- return true;
102
- } catch (err) {
103
- const elapsed = ((Date.now() - start) / 1000).toFixed(1);
104
- log(`FAIL ${label} (${elapsed}s): ${err.message?.split('\n')[0] || 'unknown'}`);
105
- return false;
106
- }
107
- }
108
-
109
- async function main() {
110
- const startTime = Date.now();
111
- log('Sequential indexing chain started');
112
-
113
- // 1. Guidance indexer
114
- if (isIndexEnabled('guidance')) {
115
- const guidanceScript = resolveBin('flo-index', 'index-guidance.mjs');
116
- if (guidanceScript) {
117
- runStep('guidance-index', 'node', [guidanceScript]);
118
- } else {
119
- log('SKIP guidance-index (script not found)');
120
- }
121
- } else {
122
- log('SKIP guidance-index (disabled in moflo.yaml)');
123
- }
124
-
125
- // 2. Code map generator (the big one — ~22s)
126
- if (isIndexEnabled('code_map')) {
127
- const codeMapScript = resolveBin('flo-codemap', 'generate-code-map.mjs');
128
- if (codeMapScript) {
129
- runStep('code-map', 'node', [codeMapScript], 180_000);
130
- } else {
131
- log('SKIP code-map (script not found)');
132
- }
133
- } else {
134
- log('SKIP code-map (disabled in moflo.yaml)');
135
- }
136
-
137
- // 3. Test indexer
138
- if (isIndexEnabled('tests')) {
139
- const testScript = resolveBin('flo-testmap', 'index-tests.mjs');
140
- if (testScript) {
141
- runStep('test-index', 'node', [testScript]);
142
- } else {
143
- log('SKIP test-index (script not found)');
144
- }
145
- } else {
146
- log('SKIP test-index (disabled in moflo.yaml)');
147
- }
148
-
149
- // 4. Patterns indexer
150
- if (isIndexEnabled('patterns')) {
151
- const patternsScript = resolveBin('flo-patterns', 'index-patterns.mjs');
152
- if (patternsScript) {
153
- runStep('patterns-index', 'node', [patternsScript]);
154
- } else {
155
- log('SKIP patterns-index (script not found)');
156
- }
157
- } else {
158
- log('SKIP patterns-index (disabled in moflo.yaml)');
159
- }
160
-
161
- // 5. Pretrain (extracts patterns from repository)
162
- const localCli = getLocalCliPath();
163
- if (localCli) {
164
- runStep('pretrain', 'node', [localCli, 'hooks', 'pretrain']);
165
- } else {
166
- log('SKIP pretrain (CLI not found)');
167
- }
168
-
169
- // 6. HNSW rebuildMUST run last, after all writes are committed (#81)
170
- if (localCli) {
171
- runStep('hnsw-rebuild', 'node', [localCli, 'memory', 'rebuild', '--force']);
172
- } else {
173
- log('SKIP hnsw-rebuild (CLI not found)');
174
- }
175
-
176
- const totalElapsed = ((Date.now() - startTime) / 1000).toFixed(1);
177
- log(`Sequential indexing chain complete (${totalElapsed}s)`);
178
- }
179
-
180
- main().catch(err => {
181
- log(`FATAL: ${err.message}`);
182
- process.exit(1);
183
- });
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Sequential indexer chain for session-start.
4
+ *
5
+ * Runs all DB-writing indexers one at a time to avoid sql.js last-write-wins
6
+ * concurrency issues (#78), then triggers HNSW rebuild once everything is
7
+ * committed (#81).
8
+ *
9
+ * Spawned as a single detached background process by hooks.mjs session-start.
10
+ */
11
+
12
+ import { existsSync, appendFileSync, readFileSync } from 'fs';
13
+ import { resolve, dirname } from 'path';
14
+ import { fileURLToPath } from 'url';
15
+ import { execFileSync } from 'child_process';
16
+
17
+ const __dirname = dirname(fileURLToPath(import.meta.url));
18
+
19
+ // Detect project root by walking up from cwd to find package.json.
20
+ // IMPORTANT: Do NOT use resolve(__dirname, '..') — this script lives in bin/
21
+ // during development but gets synced to .claude/scripts/ in consumer projects,
22
+ // so __dirname-relative paths break. findProjectRoot() works in both locations.
23
+ function findProjectRoot() {
24
+ let dir = process.cwd();
25
+ const root = resolve(dir, '/');
26
+ while (dir !== root) {
27
+ if (existsSync(resolve(dir, 'package.json'))) return dir;
28
+ dir = dirname(dir);
29
+ }
30
+ return process.cwd();
31
+ }
32
+
33
+ const projectRoot = findProjectRoot();
34
+ const LOG_PATH = resolve(projectRoot, '.swarm/hooks.log');
35
+
36
+ function log(msg) {
37
+ const ts = new Date().toISOString().replace('T', ' ').slice(0, 19);
38
+ const line = `[${ts}] [index-all] ${msg}\n`;
39
+ try { appendFileSync(LOG_PATH, line); } catch { /* ignore */ }
40
+ }
41
+
42
+ function resolveBin(binName, localScript) {
43
+ const mofloScript = resolve(projectRoot, 'node_modules/moflo/bin', localScript);
44
+ if (existsSync(mofloScript)) return mofloScript;
45
+ const npmBin = resolve(projectRoot, 'node_modules/.bin', binName);
46
+ if (existsSync(npmBin)) return npmBin;
47
+ const localPath = resolve(projectRoot, '.claude/scripts', localScript);
48
+ if (existsSync(localPath)) return localPath;
49
+ // Also check bin/ directory (for development use)
50
+ const binPath = resolve(projectRoot, 'bin', localScript);
51
+ if (existsSync(binPath)) return binPath;
52
+ return null;
53
+ }
54
+
55
+ function getLocalCliPath() {
56
+ const paths = [
57
+ resolve(projectRoot, 'node_modules/moflo/src/@claude-flow/cli/bin/cli.js'),
58
+ resolve(projectRoot, 'node_modules/moflo/bin/cli.js'),
59
+ resolve(projectRoot, 'node_modules/.bin/flo'),
60
+ // Development: local CLI
61
+ resolve(projectRoot, 'src/@claude-flow/cli/bin/cli.js'),
62
+ ];
63
+ for (const p of paths) {
64
+ if (existsSync(p)) return p;
65
+ }
66
+ return null;
67
+ }
68
+
69
+ /** Read moflo.yaml once and cache auto_index flags. */
70
+ let _autoIndexFlags = null;
71
+ function isIndexEnabled(key) {
72
+ if (_autoIndexFlags === null) {
73
+ _autoIndexFlags = {};
74
+ const yamlPath = resolve(projectRoot, 'moflo.yaml');
75
+ if (existsSync(yamlPath)) {
76
+ try {
77
+ const content = readFileSync(yamlPath, 'utf-8');
78
+ for (const k of ['guidance', 'code_map', 'tests', 'patterns']) {
79
+ const re = new RegExp(`auto_index:\\s*\\n(?:.*\\n)*?\\s+${k}:\\s*(true|false)`);
80
+ const match = content.match(re);
81
+ _autoIndexFlags[k] = match ? match[1] !== 'false' : true;
82
+ }
83
+ } catch { /* ignore, all default to true */ }
84
+ }
85
+ }
86
+ return _autoIndexFlags[key] !== false;
87
+ }
88
+
89
+ function runStep(label, cmd, args, timeoutMs = 120_000) {
90
+ const start = Date.now();
91
+ log(`START ${label}`);
92
+ try {
93
+ execFileSync(cmd, args, {
94
+ cwd: projectRoot,
95
+ timeout: timeoutMs,
96
+ stdio: 'ignore',
97
+ windowsHide: true,
98
+ });
99
+ const elapsed = ((Date.now() - start) / 1000).toFixed(1);
100
+ log(`DONE ${label} (${elapsed}s)`);
101
+ return true;
102
+ } catch (err) {
103
+ const elapsed = ((Date.now() - start) / 1000).toFixed(1);
104
+ log(`FAIL ${label} (${elapsed}s): ${err.message?.split('\n')[0] || 'unknown'}`);
105
+ return false;
106
+ }
107
+ }
108
+
109
+ async function main() {
110
+ const startTime = Date.now();
111
+ log('Sequential indexing chain started');
112
+
113
+ // 1. Guidance indexer
114
+ if (isIndexEnabled('guidance')) {
115
+ const guidanceScript = resolveBin('flo-index', 'index-guidance.mjs');
116
+ if (guidanceScript) {
117
+ runStep('guidance-index', 'node', [guidanceScript, '--no-embeddings']);
118
+ } else {
119
+ log('SKIP guidance-index (script not found)');
120
+ }
121
+ } else {
122
+ log('SKIP guidance-index (disabled in moflo.yaml)');
123
+ }
124
+
125
+ // 2. Code map generator (the big one — ~22s)
126
+ if (isIndexEnabled('code_map')) {
127
+ const codeMapScript = resolveBin('flo-codemap', 'generate-code-map.mjs');
128
+ if (codeMapScript) {
129
+ runStep('code-map', 'node', [codeMapScript, '--no-embeddings'], 180_000);
130
+ } else {
131
+ log('SKIP code-map (script not found)');
132
+ }
133
+ } else {
134
+ log('SKIP code-map (disabled in moflo.yaml)');
135
+ }
136
+
137
+ // 3. Test indexer
138
+ if (isIndexEnabled('tests')) {
139
+ const testScript = resolveBin('flo-testmap', 'index-tests.mjs');
140
+ if (testScript) {
141
+ runStep('test-index', 'node', [testScript, '--no-embeddings']);
142
+ } else {
143
+ log('SKIP test-index (script not found)');
144
+ }
145
+ } else {
146
+ log('SKIP test-index (disabled in moflo.yaml)');
147
+ }
148
+
149
+ // 4. Patterns indexer
150
+ if (isIndexEnabled('patterns')) {
151
+ const patternsScript = resolveBin('flo-patterns', 'index-patterns.mjs');
152
+ if (patternsScript) {
153
+ runStep('patterns-index', 'node', [patternsScript]);
154
+ } else {
155
+ log('SKIP patterns-index (script not found)');
156
+ }
157
+ } else {
158
+ log('SKIP patterns-index (disabled in moflo.yaml)');
159
+ }
160
+
161
+ // 5. Pretrain (extracts patterns from repository)
162
+ const localCli = getLocalCliPath();
163
+ if (localCli) {
164
+ runStep('pretrain', 'node', [localCli, 'hooks', 'pretrain']);
165
+ } else {
166
+ log('SKIP pretrain (CLI not found)');
167
+ }
168
+
169
+ // 6. Build embeddingssingle pass for ALL namespaces, after all indexers finish.
170
+ // Individual indexers are called with --no-embeddings to prevent background
171
+ // embedding spawns that race with this chain (sql.js last-write-wins).
172
+ const embeddingsScript = resolveBin('flo-embeddings', 'build-embeddings.mjs');
173
+ if (embeddingsScript) {
174
+ runStep('build-embeddings', 'node', [embeddingsScript], 300_000);
175
+ } else {
176
+ log('SKIP build-embeddings (script not found)');
177
+ }
178
+
179
+ // 7. HNSW rebuild — MUST run last, after all writes are committed (#81)
180
+ if (localCli) {
181
+ runStep('hnsw-rebuild', 'node', [localCli, 'memory', 'rebuild', '--force']);
182
+ } else {
183
+ log('SKIP hnsw-rebuild (CLI not found)');
184
+ }
185
+
186
+ const totalElapsed = ((Date.now() - startTime) / 1000).toFixed(1);
187
+ log(`Sequential indexing chain complete (${totalElapsed}s)`);
188
+ }
189
+
190
+ main().catch(err => {
191
+ log(`FATAL: ${err.message}`);
192
+ process.exit(1);
193
+ });
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
  /**
3
3
  * Index guidance files into claude-flow memory with full RAG linked segments
4
4
  *
@@ -106,7 +106,18 @@ function loadGuidanceDirs() {
106
106
  ? bundledShippedDir
107
107
  : resolve(mofloRoot, '.claude/guidance');
108
108
  const projectGuidanceDir = resolve(projectRoot, '.claude/guidance');
109
+
110
+ // Detect self-reference: if the project IS the moflo package, skip bundled scan
111
+ // to avoid double-indexing the same files under two prefixes.
112
+ let isSelfRef = false;
113
+ try {
114
+ const projPkg = JSON.parse(readFileSync(resolve(projectRoot, 'package.json'), 'utf-8'));
115
+ const mofloPkg = JSON.parse(readFileSync(resolve(mofloRoot, 'package.json'), 'utf-8'));
116
+ isSelfRef = projPkg.name === mofloPkg.name;
117
+ } catch { /* ignore — defaults to false */ }
118
+
109
119
  if (
120
+ !isSelfRef &&
110
121
  existsSync(bundledGuidanceDir) &&
111
122
  resolve(bundledGuidanceDir) !== resolve(projectGuidanceDir) &&
112
123
  resolve(bundledGuidanceDir) !== resolve(projectGuidanceDir, 'shipped')