moflo 4.8.9 → 4.8.11

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.
Files changed (166) hide show
  1. package/.claude/agents/core/coder.md +265 -265
  2. package/.claude/agents/core/planner.md +167 -167
  3. package/.claude/agents/core/researcher.md +189 -189
  4. package/.claude/agents/core/reviewer.md +325 -325
  5. package/.claude/agents/core/tester.md +318 -318
  6. package/.claude/agents/dual-mode/codex-coordinator.md +224 -224
  7. package/.claude/agents/dual-mode/codex-worker.md +211 -211
  8. package/.claude/agents/dual-mode/dual-orchestrator.md +291 -291
  9. package/.claude/agents/github/code-review-swarm.md +537 -537
  10. package/.claude/agents/github/github-modes.md +172 -172
  11. package/.claude/agents/github/issue-tracker.md +318 -318
  12. package/.claude/agents/github/multi-repo-swarm.md +552 -552
  13. package/.claude/agents/github/pr-manager.md +190 -190
  14. package/.claude/agents/github/project-board-sync.md +508 -508
  15. package/.claude/agents/github/release-manager.md +366 -366
  16. package/.claude/agents/github/release-swarm.md +582 -582
  17. package/.claude/agents/github/repo-architect.md +397 -397
  18. package/.claude/agents/github/swarm-issue.md +572 -572
  19. package/.claude/agents/github/swarm-pr.md +427 -427
  20. package/.claude/agents/github/sync-coordinator.md +451 -451
  21. package/.claude/agents/github/workflow-automation.md +634 -634
  22. package/.claude/agents/goal/code-goal-planner.md +445 -445
  23. package/.claude/agents/hive-mind/collective-intelligence-coordinator.md +129 -129
  24. package/.claude/agents/hive-mind/queen-coordinator.md +202 -202
  25. package/.claude/agents/hive-mind/scout-explorer.md +241 -241
  26. package/.claude/agents/hive-mind/swarm-memory-manager.md +192 -192
  27. package/.claude/agents/hive-mind/worker-specialist.md +216 -216
  28. package/.claude/agents/neural/safla-neural.md +73 -73
  29. package/.claude/agents/reasoning/goal-planner.md +72 -72
  30. package/.claude/agents/swarm/adaptive-coordinator.md +395 -395
  31. package/.claude/agents/swarm/hierarchical-coordinator.md +326 -326
  32. package/.claude/agents/swarm/mesh-coordinator.md +391 -391
  33. package/.claude/agents/templates/migration-plan.md +745 -745
  34. package/.claude/commands/agents/agent-spawning.md +28 -28
  35. package/.claude/commands/analysis/COMMAND_COMPLIANCE_REPORT.md +53 -53
  36. package/.claude/commands/analysis/bottleneck-detect.md +162 -162
  37. package/.claude/commands/analysis/performance-bottlenecks.md +58 -58
  38. package/.claude/commands/analysis/token-efficiency.md +44 -44
  39. package/.claude/commands/automation/auto-agent.md +122 -122
  40. package/.claude/commands/automation/self-healing.md +105 -105
  41. package/.claude/commands/automation/session-memory.md +89 -89
  42. package/.claude/commands/automation/smart-agents.md +72 -72
  43. package/.claude/commands/coordination/init.md +44 -44
  44. package/.claude/commands/coordination/orchestrate.md +43 -43
  45. package/.claude/commands/coordination/spawn.md +45 -45
  46. package/.claude/commands/coordination/swarm-init.md +85 -85
  47. package/.claude/commands/github/github-modes.md +146 -146
  48. package/.claude/commands/github/github-swarm.md +121 -121
  49. package/.claude/commands/github/issue-tracker.md +291 -291
  50. package/.claude/commands/github/pr-manager.md +169 -169
  51. package/.claude/commands/github/release-manager.md +337 -337
  52. package/.claude/commands/github/repo-architect.md +366 -366
  53. package/.claude/commands/github/sync-coordinator.md +300 -300
  54. package/.claude/commands/memory/neural.md +47 -47
  55. package/.claude/commands/monitoring/agents.md +44 -44
  56. package/.claude/commands/monitoring/status.md +46 -46
  57. package/.claude/commands/optimization/auto-topology.md +61 -61
  58. package/.claude/commands/optimization/parallel-execution.md +49 -49
  59. package/.claude/commands/sparc/analyzer.md +51 -51
  60. package/.claude/commands/sparc/architect.md +53 -53
  61. package/.claude/commands/sparc/ask.md +97 -97
  62. package/.claude/commands/sparc/batch-executor.md +54 -54
  63. package/.claude/commands/sparc/code.md +89 -89
  64. package/.claude/commands/sparc/coder.md +54 -54
  65. package/.claude/commands/sparc/debug.md +83 -83
  66. package/.claude/commands/sparc/debugger.md +54 -54
  67. package/.claude/commands/sparc/designer.md +53 -53
  68. package/.claude/commands/sparc/devops.md +109 -109
  69. package/.claude/commands/sparc/docs-writer.md +80 -80
  70. package/.claude/commands/sparc/documenter.md +54 -54
  71. package/.claude/commands/sparc/innovator.md +54 -54
  72. package/.claude/commands/sparc/integration.md +83 -83
  73. package/.claude/commands/sparc/mcp.md +117 -117
  74. package/.claude/commands/sparc/memory-manager.md +54 -54
  75. package/.claude/commands/sparc/optimizer.md +54 -54
  76. package/.claude/commands/sparc/orchestrator.md +131 -131
  77. package/.claude/commands/sparc/post-deployment-monitoring-mode.md +83 -83
  78. package/.claude/commands/sparc/refinement-optimization-mode.md +83 -83
  79. package/.claude/commands/sparc/researcher.md +54 -54
  80. package/.claude/commands/sparc/reviewer.md +54 -54
  81. package/.claude/commands/sparc/security-review.md +80 -80
  82. package/.claude/commands/sparc/sparc-modes.md +174 -174
  83. package/.claude/commands/sparc/sparc.md +111 -111
  84. package/.claude/commands/sparc/spec-pseudocode.md +80 -80
  85. package/.claude/commands/sparc/supabase-admin.md +348 -348
  86. package/.claude/commands/sparc/swarm-coordinator.md +54 -54
  87. package/.claude/commands/sparc/tdd.md +54 -54
  88. package/.claude/commands/sparc/tester.md +54 -54
  89. package/.claude/commands/sparc/tutorial.md +79 -79
  90. package/.claude/commands/sparc/workflow-manager.md +54 -54
  91. package/.claude/commands/sparc.md +166 -166
  92. package/.claude/commands/swarm/analysis.md +95 -95
  93. package/.claude/commands/swarm/development.md +96 -96
  94. package/.claude/commands/swarm/examples.md +168 -168
  95. package/.claude/commands/swarm/maintenance.md +102 -102
  96. package/.claude/commands/swarm/optimization.md +117 -117
  97. package/.claude/commands/swarm/research.md +136 -136
  98. package/.claude/commands/swarm/testing.md +131 -131
  99. package/.claude/commands/training/neural-patterns.md +73 -73
  100. package/.claude/commands/training/specialization.md +62 -62
  101. package/.claude/commands/workflows/development.md +77 -77
  102. package/.claude/commands/workflows/research.md +62 -62
  103. package/.claude/guidance/{agent-bootstrap.md → shipped/agent-bootstrap.md} +126 -126
  104. package/.claude/guidance/{guidance-memory-strategy.md → shipped/guidance-memory-strategy.md} +262 -262
  105. package/.claude/guidance/{memory-strategy.md → shipped/memory-strategy.md} +204 -204
  106. package/.claude/guidance/{moflo.md → shipped/moflo.md} +45 -31
  107. package/.claude/guidance/{task-swarm-integration.md → shipped/task-swarm-integration.md} +441 -348
  108. package/.claude/helpers/gate.cjs +236 -236
  109. package/.claude/helpers/hook-handler.cjs +42 -46
  110. package/.claude/settings.json +2 -2
  111. package/.claude/settings.local.json +3 -3
  112. package/.claude/skills/fl/SKILL.md +29 -23
  113. package/.claude/skills/flo/SKILL.md +29 -23
  114. package/.claude/skills/github-code-review/SKILL.md +4 -4
  115. package/.claude/skills/github-multi-repo/SKILL.md +8 -8
  116. package/.claude/skills/github-project-management/SKILL.md +6 -6
  117. package/.claude/skills/github-release-management/SKILL.md +12 -12
  118. package/.claude/skills/github-workflow-automation/SKILL.md +6 -6
  119. package/.claude/skills/hooks-automation/SKILL.md +1201 -1201
  120. package/.claude/skills/performance-analysis/SKILL.md +563 -563
  121. package/.claude/skills/sparc-methodology/SKILL.md +64 -64
  122. package/.claude/skills/swarm-advanced/SKILL.md +77 -77
  123. package/.claude-plugin/README.md +3 -3
  124. package/.claude-plugin/docs/PLUGIN_SUMMARY.md +3 -3
  125. package/.claude-plugin/docs/QUICKSTART.md +4 -4
  126. package/.claude-plugin/marketplace.json +3 -3
  127. package/.claude-plugin/plugin.json +3 -3
  128. package/.claude-plugin/scripts/install.sh +9 -9
  129. package/.claude-plugin/scripts/verify.sh +7 -7
  130. package/README.md +311 -116
  131. package/bin/gate-hook.mjs +50 -0
  132. package/bin/gate.cjs +138 -0
  133. package/bin/hook-handler.cjs +83 -0
  134. package/bin/hooks.mjs +72 -12
  135. package/bin/index-guidance.mjs +28 -34
  136. package/bin/index-tests.mjs +710 -0
  137. package/bin/lib/process-manager.mjs +243 -0
  138. package/bin/lib/registry-cleanup.cjs +41 -0
  139. package/bin/prompt-hook.mjs +72 -0
  140. package/bin/semantic-search.mjs +473 -441
  141. package/bin/session-start-launcher.mjs +81 -31
  142. package/bin/setup-project.mjs +13 -10
  143. package/package.json +4 -2
  144. package/src/@claude-flow/cli/README.md +1 -1
  145. package/src/@claude-flow/cli/bin/cli.js +175 -175
  146. package/src/@claude-flow/cli/dist/src/commands/doctor.js +1091 -736
  147. package/src/@claude-flow/cli/dist/src/commands/github.d.ts +12 -0
  148. package/src/@claude-flow/cli/dist/src/commands/github.js +505 -0
  149. package/src/@claude-flow/cli/dist/src/commands/hive-mind.js +90 -90
  150. package/src/@claude-flow/cli/dist/src/commands/index.d.ts +1 -0
  151. package/src/@claude-flow/cli/dist/src/commands/index.js +7 -0
  152. package/src/@claude-flow/cli/dist/src/config-adapter.js +1 -1
  153. package/src/@claude-flow/cli/dist/src/init/claudemd-generator.js +1 -1
  154. package/src/@claude-flow/cli/dist/src/init/executor.js +109 -5
  155. package/src/@claude-flow/cli/dist/src/init/helpers-generator.d.ts +14 -0
  156. package/src/@claude-flow/cli/dist/src/init/helpers-generator.js +156 -24
  157. package/src/@claude-flow/cli/dist/src/init/mcp-generator.js +20 -20
  158. package/src/@claude-flow/cli/dist/src/init/moflo-init.d.ts +7 -0
  159. package/src/@claude-flow/cli/dist/src/init/moflo-init.js +72 -10
  160. package/src/@claude-flow/cli/dist/src/init/settings-generator.js +23 -14
  161. package/src/@claude-flow/cli/dist/src/mcp-server.js +3 -3
  162. package/src/@claude-flow/cli/dist/src/plugins/manager.js +9 -8
  163. package/src/@claude-flow/cli/dist/src/services/worker-daemon.d.ts +1 -0
  164. package/src/@claude-flow/cli/dist/src/services/worker-daemon.js +3 -1
  165. package/src/@claude-flow/cli/dist/src/services/workflow-gate.js +10 -10
  166. package/src/@claude-flow/cli/package.json +1 -1
@@ -1,236 +1,236 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
- var fs = require('fs');
4
- var path = require('path');
5
-
6
- var PROJECT_DIR = process.env.CLAUDE_PROJECT_DIR || process.cwd();
7
- var STATE_FILE = path.join(PROJECT_DIR, '.claude', 'workflow-state.json');
8
-
9
- function readState() {
10
- try {
11
- if (fs.existsSync(STATE_FILE)) return JSON.parse(fs.readFileSync(STATE_FILE, 'utf-8'));
12
- } catch (e) { /* reset on corruption */ }
13
- return { tasksCreated: false, taskCount: 0, memorySearched: false, memoryRequired: true, interactionCount: 0, sessionStart: null, lastBlockedAt: null };
14
- }
15
-
16
- function writeState(s) {
17
- try {
18
- var dir = path.dirname(STATE_FILE);
19
- if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
20
- fs.writeFileSync(STATE_FILE, JSON.stringify(s, null, 2));
21
- } catch (e) { /* non-fatal */ }
22
- }
23
-
24
- // Load moflo.yaml gate config (defaults: all enabled)
25
- function loadGateConfig() {
26
- var defaults = { memory_first: true, task_create_first: true, context_tracking: true };
27
- try {
28
- var yamlPath = path.join(PROJECT_DIR, 'moflo.yaml');
29
- if (fs.existsSync(yamlPath)) {
30
- var content = fs.readFileSync(yamlPath, 'utf-8');
31
- if (/memory_first:\s*false/i.test(content)) defaults.memory_first = false;
32
- if (/task_create_first:\s*false/i.test(content)) defaults.task_create_first = false;
33
- if (/context_tracking:\s*false/i.test(content)) defaults.context_tracking = false;
34
- }
35
- } catch (e) { /* use defaults */ }
36
- return defaults;
37
- }
38
-
39
- var config = loadGateConfig();
40
- var command = process.argv[2];
41
-
42
- var DANGEROUS = ['rm -rf /', 'format c:', 'del /s /q c:\\', ':(){:|:&};:', 'mkfs.', '> /dev/sda'];
43
- var DIRECTIVE_RE = /^(yes|no|yeah|yep|nope|sure|ok|okay|correct|right|exactly|perfect)\b/i;
44
- var TASK_RE = /\b(fix|bug|error|implement|add|create|build|write|refactor|debug|test|feature|issue|security|optimi)\b/i;
45
-
46
- // Deny a tool call cleanly via structured JSON (no "hook error" noise).
47
- // Exit 0 + permissionDecision:"deny" is the Claude Code way to block a tool.
48
- function blockTool(reason) {
49
- console.log(JSON.stringify({
50
- hookSpecificOutput: {
51
- hookEventName: 'PreToolUse',
52
- permissionDecision: 'deny',
53
- permissionDecisionReason: reason
54
- }
55
- }));
56
- process.exit(0);
57
- }
58
-
59
- // Determine if a Grep/Glob target is a mechanical/administrative search
60
- // that should bypass the memory-first gate. The idea: if memory/guidance
61
- // wouldn't improve the search outcome, don't block it.
62
- //
63
- // Strategy: path is the strongest signal. When a path clearly points to
64
- // tooling/deps/tests, allow it. When it points to source/docs/scripts,
65
- // block it (require memory). Pattern-based rules only kick in when there's
66
- // no path or when the path is neutral.
67
- function isMechanicalSearch() {
68
- var searchPath = (process.env.TOOL_INPUT_path || '').replace(/\\/g, '/').toLowerCase();
69
- var pattern = (process.env.TOOL_INPUT_pattern || '').toLowerCase();
70
- var filePath = (process.env.TOOL_INPUT_file_path || '').replace(/\\/g, '/').toLowerCase();
71
- var anyPath = searchPath || filePath;
72
-
73
- // --- PATH-BASED RULES (strongest signal, checked first) ---
74
-
75
- if (anyPath) {
76
- // Always mechanical: dependencies, tooling internals, CI, test dirs
77
- var mechanicalPaths = [
78
- 'node_modules/', '.claude/', '.claude-flow/', '.swarm/', '.github/',
79
- 'tests/', 'test/', 'config/', 'examples/',
80
- ];
81
- for (var i = 0; i < mechanicalPaths.length; i++) {
82
- if (anyPath.indexOf(mechanicalPaths[i]) >= 0) return true;
83
- }
84
-
85
- // Targeting a specific config/meta file by path extension
86
- if (/\.(json|yaml|yml|toml|lock|env|cjs|mjs)$/i.test(anyPath)) return true;
87
-
88
- // If path points to source, docs, or scripts — these are knowledge-rich.
89
- // Do NOT fall through to pattern-based exemptions; the path is authoritative.
90
- // (Still allow test-file glob patterns even within source dirs.)
91
- var knowledgePaths = [
92
- 'src/', 'back-office/', 'front-office/', 'docs/', 'scripts/', 'lib/',
93
- ];
94
- var inKnowledgePath = false;
95
- for (var k = 0; k < knowledgePaths.length; k++) {
96
- if (anyPath.indexOf(knowledgePaths[k]) >= 0) { inKnowledgePath = true; break; }
97
- }
98
- if (inKnowledgePath) {
99
- // Exception: searching for test/spec files within source is structural
100
- if (/\*\*?[/\\]?\*?\.(test|spec)\.(ts|js|tsx|jsx)\b/i.test(pattern)) return true;
101
- // Everything else in a knowledge path requires memory
102
- return false;
103
- }
104
- }
105
-
106
- // --- PATTERN-BASED RULES (no path, or path is neutral) ---
107
-
108
- // Glob patterns looking for config/build/tooling files by extension
109
- if (/\*\*?[/\\]?\*?\.(json|yaml|yml|toml|lock|env|config|cjs|mjs)\b/i.test(pattern)) return true;
110
-
111
- // Glob patterns for specific config filenames (eslintrc, Dockerfile, etc.)
112
- if (/\*\*?[/\\]?\*?\.?(eslint|prettier|babel|stylelint|editor|git|docker|nginx|jest|vitest|vite|webpack|rollup|esbuild|tsconfig|browserslist)/i.test(pattern)) return true;
113
-
114
- // Glob patterns for lock files and test files (structural lookups)
115
- if (/\*\*?[/\\]?\*?[\w-]*[-.]lock\b/i.test(pattern)) return true;
116
- if (/\*\*?[/\\]?\*?\.(test|spec)\.(ts|js|tsx|jsx)\b/i.test(pattern)) return true;
117
-
118
- // Config/tooling name searches (bare names without a path).
119
- // Only exempt if ALL tokens in a pipe-separated pattern are config names.
120
- // "webpack|vite" = exempt. "webpack|merchant" = NOT exempt.
121
- var CONFIG_NAME = /^\.?(eslint|prettier|babel|stylelint|editor|gitignore|gitattributes|dockerignore|dockerfile|docker-compose|nginx|jest|vitest|vite|webpack|rollup|esbuild|tsconfig|changelog|license|makefile|procfile|browserslist|commitlint|husky|lint-staged)\b/i;
122
- var tokens = pattern.split(/[|,\s]+/).filter(function(t) { return t.length > 0; });
123
- if (tokens.length > 0 && tokens.every(function(t) { return CONFIG_NAME.test(t.trim()); })) return true;
124
-
125
- // Known tooling/meta file names as substrings (but avoid false matches like "process.env")
126
- var toolingNames = [
127
- 'claude.md', 'memory.md', 'workflow-state', '.mcp.json',
128
- 'package.json', 'package-lock', 'daemon.lock', 'moflo.yaml',
129
- ];
130
- var target = pattern + ' ' + anyPath;
131
- for (var j = 0; j < toolingNames.length; j++) {
132
- if (target.indexOf(toolingNames[j]) >= 0) return true;
133
- }
134
-
135
- // Env file lookups (but NOT "process.env" which is source code searching)
136
- if (/^\.env\b/.test(pattern) || /\*\*?[/\\]?\.env/.test(pattern)) return true;
137
-
138
- // Git/process/system-level pattern searches
139
- if (/^(git\b|pid|daemon|lock|wmic|tasklist|powershell|ps\s)/i.test(pattern)) return true;
140
-
141
- // CI/CD folder exploration
142
- if (/\.github/i.test(pattern)) return true;
143
-
144
- return false;
145
- }
146
-
147
- switch (command) {
148
- case 'check-before-agent': {
149
- var s = readState();
150
- if (config.task_create_first && !s.tasksCreated) {
151
- blockTool('Call TaskCreate before spawning agents. Task tool is blocked until then.');
152
- }
153
- if (config.memory_first && !s.memorySearched) {
154
- blockTool('Search memory before spawning agents. Use mcp__claude-flow__memory_search first.');
155
- }
156
- break;
157
- }
158
- case 'check-before-scan': {
159
- if (!config.memory_first) break;
160
- var s = readState();
161
- if (s.memorySearched || !s.memoryRequired) break;
162
- if (isMechanicalSearch()) break;
163
- s.lastBlockedAt = new Date().toISOString();
164
- writeState(s);
165
- blockTool('Search memory before exploring files. Use mcp__claude-flow__memory_search with namespace "code-map", "patterns", "knowledge", or "guidance".');
166
- }
167
- case 'check-before-read': {
168
- if (!config.memory_first) break;
169
- var s = readState();
170
- if (s.memorySearched || !s.memoryRequired) break;
171
- var fp = (process.env.TOOL_INPUT_file_path || '').replace(/\\/g, '/');
172
- // Block reads of guidance files (that's exactly what memory indexes)
173
- if (fp.indexOf('.claude/guidance/') < 0) break;
174
- s.lastBlockedAt = new Date().toISOString();
175
- writeState(s);
176
- blockTool('Search memory before reading guidance files. Use mcp__claude-flow__memory_search with namespace "guidance".');
177
- }
178
- case 'record-task-created': {
179
- var s = readState();
180
- s.tasksCreated = true;
181
- s.taskCount = (s.taskCount || 0) + 1;
182
- writeState(s);
183
- break;
184
- }
185
- case 'record-memory-searched': {
186
- var s = readState();
187
- s.memorySearched = true;
188
- writeState(s);
189
- break;
190
- }
191
- case 'check-bash-memory': {
192
- var cmd = process.env.TOOL_INPUT_command || '';
193
- if (/semantic-search|memory search|memory retrieve|memory-search/.test(cmd)) {
194
- var s = readState();
195
- s.memorySearched = true;
196
- writeState(s);
197
- }
198
- break;
199
- }
200
- case 'check-dangerous-command': {
201
- var cmd = (process.env.TOOL_INPUT_command || '').toLowerCase();
202
- for (var i = 0; i < DANGEROUS.length; i++) {
203
- if (cmd.indexOf(DANGEROUS[i]) >= 0) {
204
- console.log('[BLOCKED] Dangerous command: ' + DANGEROUS[i]);
205
- process.exit(2);
206
- }
207
- }
208
- break;
209
- }
210
- case 'prompt-reminder': {
211
- var s = readState();
212
- s.memorySearched = false;
213
- var prompt = process.env.CLAUDE_USER_PROMPT || '';
214
- s.memoryRequired = prompt.length >= 4 && !DIRECTIVE_RE.test(prompt) && (TASK_RE.test(prompt) || prompt.length > 80);
215
- s.interactionCount = (s.interactionCount || 0) + 1;
216
- writeState(s);
217
- if (!s.tasksCreated) console.log('REMINDER: Use TaskCreate before spawning agents. Task tool is blocked until then.');
218
- if (config.context_tracking) {
219
- var ic = s.interactionCount;
220
- if (ic > 30) console.log('Context: CRITICAL. Commit, store learnings, suggest new session.');
221
- else if (ic > 20) console.log('Context: DEPLETED. Checkpoint progress. Recommend /compact or fresh session.');
222
- else if (ic > 10) console.log('Context: MODERATE. Re-state goal before architectural decisions.');
223
- }
224
- break;
225
- }
226
- case 'compact-guidance': {
227
- console.log('Pre-Compact: Check CLAUDE.md for rules. Use memory search to recover context after compact.');
228
- break;
229
- }
230
- case 'session-reset': {
231
- writeState({ tasksCreated: false, taskCount: 0, memorySearched: false, memoryRequired: true, interactionCount: 0, sessionStart: new Date().toISOString(), lastBlockedAt: null });
232
- break;
233
- }
234
- default:
235
- break;
236
- }
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+ var fs = require('fs');
4
+ var path = require('path');
5
+
6
+ var PROJECT_DIR = process.env.CLAUDE_PROJECT_DIR || process.cwd();
7
+ var STATE_FILE = path.join(PROJECT_DIR, '.claude', 'workflow-state.json');
8
+
9
+ function readState() {
10
+ try {
11
+ if (fs.existsSync(STATE_FILE)) return JSON.parse(fs.readFileSync(STATE_FILE, 'utf-8'));
12
+ } catch (e) { /* reset on corruption */ }
13
+ return { tasksCreated: false, taskCount: 0, memorySearched: false, memoryRequired: true, interactionCount: 0, sessionStart: null, lastBlockedAt: null };
14
+ }
15
+
16
+ function writeState(s) {
17
+ try {
18
+ var dir = path.dirname(STATE_FILE);
19
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
20
+ fs.writeFileSync(STATE_FILE, JSON.stringify(s, null, 2));
21
+ } catch (e) { /* non-fatal */ }
22
+ }
23
+
24
+ // Load moflo.yaml gate config (defaults: all enabled)
25
+ function loadGateConfig() {
26
+ var defaults = { memory_first: true, task_create_first: true, context_tracking: true };
27
+ try {
28
+ var yamlPath = path.join(PROJECT_DIR, 'moflo.yaml');
29
+ if (fs.existsSync(yamlPath)) {
30
+ var content = fs.readFileSync(yamlPath, 'utf-8');
31
+ if (/memory_first:\s*false/i.test(content)) defaults.memory_first = false;
32
+ if (/task_create_first:\s*false/i.test(content)) defaults.task_create_first = false;
33
+ if (/context_tracking:\s*false/i.test(content)) defaults.context_tracking = false;
34
+ }
35
+ } catch (e) { /* use defaults */ }
36
+ return defaults;
37
+ }
38
+
39
+ var config = loadGateConfig();
40
+ var command = process.argv[2];
41
+
42
+ var DANGEROUS = ['rm -rf /', 'format c:', 'del /s /q c:\\', ':(){:|:&};:', 'mkfs.', '> /dev/sda'];
43
+ var DIRECTIVE_RE = /^(yes|no|yeah|yep|nope|sure|ok|okay|correct|right|exactly|perfect)\b/i;
44
+ var TASK_RE = /\b(fix|bug|error|implement|add|create|build|write|refactor|debug|test|feature|issue|security|optimi)\b/i;
45
+
46
+ // Deny a tool call cleanly via structured JSON (no "hook error" noise).
47
+ // Exit 0 + permissionDecision:"deny" is the Claude Code way to block a tool.
48
+ function blockTool(reason) {
49
+ console.log(JSON.stringify({
50
+ hookSpecificOutput: {
51
+ hookEventName: 'PreToolUse',
52
+ permissionDecision: 'deny',
53
+ permissionDecisionReason: reason
54
+ }
55
+ }));
56
+ process.exit(0);
57
+ }
58
+
59
+ // Determine if a Grep/Glob target is a mechanical/administrative search
60
+ // that should bypass the memory-first gate. The idea: if memory/guidance
61
+ // wouldn't improve the search outcome, don't block it.
62
+ //
63
+ // Strategy: path is the strongest signal. When a path clearly points to
64
+ // tooling/deps/tests, allow it. When it points to source/docs/scripts,
65
+ // block it (require memory). Pattern-based rules only kick in when there's
66
+ // no path or when the path is neutral.
67
+ function isMechanicalSearch() {
68
+ var searchPath = (process.env.TOOL_INPUT_path || '').replace(/\\/g, '/').toLowerCase();
69
+ var pattern = (process.env.TOOL_INPUT_pattern || '').toLowerCase();
70
+ var filePath = (process.env.TOOL_INPUT_file_path || '').replace(/\\/g, '/').toLowerCase();
71
+ var anyPath = searchPath || filePath;
72
+
73
+ // --- PATH-BASED RULES (strongest signal, checked first) ---
74
+
75
+ if (anyPath) {
76
+ // Always mechanical: dependencies, tooling internals, CI, test dirs
77
+ var mechanicalPaths = [
78
+ 'node_modules/', '.claude/', '.claude-flow/', '.swarm/', '.github/',
79
+ 'tests/', 'test/', 'config/', 'examples/',
80
+ ];
81
+ for (var i = 0; i < mechanicalPaths.length; i++) {
82
+ if (anyPath.indexOf(mechanicalPaths[i]) >= 0) return true;
83
+ }
84
+
85
+ // Targeting a specific config/meta file by path extension
86
+ if (/\.(json|yaml|yml|toml|lock|env|cjs|mjs)$/i.test(anyPath)) return true;
87
+
88
+ // If path points to source, docs, or scripts — these are knowledge-rich.
89
+ // Do NOT fall through to pattern-based exemptions; the path is authoritative.
90
+ // (Still allow test-file glob patterns even within source dirs.)
91
+ var knowledgePaths = [
92
+ 'src/', 'back-office/', 'front-office/', 'docs/', 'scripts/', 'lib/',
93
+ ];
94
+ var inKnowledgePath = false;
95
+ for (var k = 0; k < knowledgePaths.length; k++) {
96
+ if (anyPath.indexOf(knowledgePaths[k]) >= 0) { inKnowledgePath = true; break; }
97
+ }
98
+ if (inKnowledgePath) {
99
+ // Exception: searching for test/spec files within source is structural
100
+ if (/\*\*?[/\\]?\*?\.(test|spec)\.(ts|js|tsx|jsx)\b/i.test(pattern)) return true;
101
+ // Everything else in a knowledge path requires memory
102
+ return false;
103
+ }
104
+ }
105
+
106
+ // --- PATTERN-BASED RULES (no path, or path is neutral) ---
107
+
108
+ // Glob patterns looking for config/build/tooling files by extension
109
+ if (/\*\*?[/\\]?\*?\.(json|yaml|yml|toml|lock|env|config|cjs|mjs)\b/i.test(pattern)) return true;
110
+
111
+ // Glob patterns for specific config filenames (eslintrc, Dockerfile, etc.)
112
+ if (/\*\*?[/\\]?\*?\.?(eslint|prettier|babel|stylelint|editor|git|docker|nginx|jest|vitest|vite|webpack|rollup|esbuild|tsconfig|browserslist)/i.test(pattern)) return true;
113
+
114
+ // Glob patterns for lock files and test files (structural lookups)
115
+ if (/\*\*?[/\\]?\*?[\w-]*[-.]lock\b/i.test(pattern)) return true;
116
+ if (/\*\*?[/\\]?\*?\.(test|spec)\.(ts|js|tsx|jsx)\b/i.test(pattern)) return true;
117
+
118
+ // Config/tooling name searches (bare names without a path).
119
+ // Only exempt if ALL tokens in a pipe-separated pattern are config names.
120
+ // "webpack|vite" = exempt. "webpack|merchant" = NOT exempt.
121
+ var CONFIG_NAME = /^\.?(eslint|prettier|babel|stylelint|editor|gitignore|gitattributes|dockerignore|dockerfile|docker-compose|nginx|jest|vitest|vite|webpack|rollup|esbuild|tsconfig|changelog|license|makefile|procfile|browserslist|commitlint|husky|lint-staged)\b/i;
122
+ var tokens = pattern.split(/[|,\s]+/).filter(function(t) { return t.length > 0; });
123
+ if (tokens.length > 0 && tokens.every(function(t) { return CONFIG_NAME.test(t.trim()); })) return true;
124
+
125
+ // Known tooling/meta file names as substrings (but avoid false matches like "process.env")
126
+ var toolingNames = [
127
+ 'claude.md', 'memory.md', 'workflow-state', '.mcp.json',
128
+ 'package.json', 'package-lock', 'daemon.lock', 'moflo.yaml',
129
+ ];
130
+ var target = pattern + ' ' + anyPath;
131
+ for (var j = 0; j < toolingNames.length; j++) {
132
+ if (target.indexOf(toolingNames[j]) >= 0) return true;
133
+ }
134
+
135
+ // Env file lookups (but NOT "process.env" which is source code searching)
136
+ if (/^\.env\b/.test(pattern) || /\*\*?[/\\]?\.env/.test(pattern)) return true;
137
+
138
+ // Git/process/system-level pattern searches
139
+ if (/^(git\b|pid|daemon|lock|wmic|tasklist|powershell|ps\s)/i.test(pattern)) return true;
140
+
141
+ // CI/CD folder exploration
142
+ if (/\.github/i.test(pattern)) return true;
143
+
144
+ return false;
145
+ }
146
+
147
+ switch (command) {
148
+ case 'check-before-agent': {
149
+ var s = readState();
150
+ if (config.task_create_first && !s.tasksCreated) {
151
+ blockTool('Call TaskCreate before spawning agents. Task tool is blocked until then.');
152
+ }
153
+ if (config.memory_first && !s.memorySearched) {
154
+ blockTool('Search memory before spawning agents. Use mcp__moflo__memory_search first.');
155
+ }
156
+ break;
157
+ }
158
+ case 'check-before-scan': {
159
+ if (!config.memory_first) break;
160
+ var s = readState();
161
+ if (s.memorySearched || !s.memoryRequired) break;
162
+ if (isMechanicalSearch()) break;
163
+ s.lastBlockedAt = new Date().toISOString();
164
+ writeState(s);
165
+ blockTool('Search memory before exploring files. Use mcp__moflo__memory_search with namespace "code-map", "patterns", "knowledge", or "guidance".');
166
+ }
167
+ case 'check-before-read': {
168
+ if (!config.memory_first) break;
169
+ var s = readState();
170
+ if (s.memorySearched || !s.memoryRequired) break;
171
+ var fp = (process.env.TOOL_INPUT_file_path || '').replace(/\\/g, '/');
172
+ // Block reads of guidance files (that's exactly what memory indexes)
173
+ if (fp.indexOf('.claude/guidance/') < 0) break;
174
+ s.lastBlockedAt = new Date().toISOString();
175
+ writeState(s);
176
+ blockTool('Search memory before reading guidance files. Use mcp__moflo__memory_search with namespace "guidance".');
177
+ }
178
+ case 'record-task-created': {
179
+ var s = readState();
180
+ s.tasksCreated = true;
181
+ s.taskCount = (s.taskCount || 0) + 1;
182
+ writeState(s);
183
+ break;
184
+ }
185
+ case 'record-memory-searched': {
186
+ var s = readState();
187
+ s.memorySearched = true;
188
+ writeState(s);
189
+ break;
190
+ }
191
+ case 'check-bash-memory': {
192
+ var cmd = process.env.TOOL_INPUT_command || '';
193
+ if (/semantic-search|memory search|memory retrieve|memory-search/.test(cmd)) {
194
+ var s = readState();
195
+ s.memorySearched = true;
196
+ writeState(s);
197
+ }
198
+ break;
199
+ }
200
+ case 'check-dangerous-command': {
201
+ var cmd = (process.env.TOOL_INPUT_command || '').toLowerCase();
202
+ for (var i = 0; i < DANGEROUS.length; i++) {
203
+ if (cmd.indexOf(DANGEROUS[i]) >= 0) {
204
+ console.log('[BLOCKED] Dangerous command: ' + DANGEROUS[i]);
205
+ process.exit(2);
206
+ }
207
+ }
208
+ break;
209
+ }
210
+ case 'prompt-reminder': {
211
+ var s = readState();
212
+ s.memorySearched = false;
213
+ var prompt = process.env.CLAUDE_USER_PROMPT || '';
214
+ s.memoryRequired = prompt.length >= 4 && !DIRECTIVE_RE.test(prompt) && (TASK_RE.test(prompt) || prompt.length > 80);
215
+ s.interactionCount = (s.interactionCount || 0) + 1;
216
+ writeState(s);
217
+ if (!s.tasksCreated) console.log('REMINDER: Use TaskCreate before spawning agents. Task tool is blocked until then.');
218
+ if (config.context_tracking) {
219
+ var ic = s.interactionCount;
220
+ if (ic > 30) console.log('Context: CRITICAL. Commit, store learnings, suggest new session.');
221
+ else if (ic > 20) console.log('Context: DEPLETED. Checkpoint progress. Recommend /compact or fresh session.');
222
+ else if (ic > 10) console.log('Context: MODERATE. Re-state goal before architectural decisions.');
223
+ }
224
+ break;
225
+ }
226
+ case 'compact-guidance': {
227
+ console.log('Pre-Compact: Check CLAUDE.md for rules. Use memory search to recover context after compact.');
228
+ break;
229
+ }
230
+ case 'session-reset': {
231
+ writeState({ tasksCreated: false, taskCount: 0, memorySearched: false, memoryRequired: true, interactionCount: 0, sessionStart: new Date().toISOString(), lastBlockedAt: null });
232
+ break;
233
+ }
234
+ default:
235
+ break;
236
+ }
@@ -122,7 +122,7 @@ const handlers = {
122
122
  console.log('[OK] Edit recorded');
123
123
  },
124
124
 
125
- 'session-restore': () => {
125
+ 'session-restore': async () => {
126
126
  if (session) {
127
127
  var existing = session.restore && session.restore();
128
128
  if (!existing) {
@@ -142,22 +142,30 @@ const handlers = {
142
142
  }
143
143
 
144
144
  // Auto-index guidance, code map, and patterns on session start
145
+ // Delegates to shared ProcessManager for dedup + PID tracking + cleanup.
145
146
  try {
146
147
  var projectDir = path.resolve(path.dirname(helpersDir), '..');
147
- var cp = require('child_process');
148
- var pidFile = path.join(projectDir, '.claude-flow', 'background-pids.json');
149
148
 
150
- // Kill stale background processes from previous sessions
151
- try {
152
- if (fs.existsSync(pidFile)) {
153
- var stalePids = JSON.parse(fs.readFileSync(pidFile, 'utf-8'));
154
- for (var i = 0; i < stalePids.length; i++) {
155
- try { process.kill(stalePids[i].pid, 0); /* test if alive */ } catch (e) { continue; }
156
- try { process.kill(stalePids[i].pid, 'SIGTERM'); } catch (e) { /* already gone */ }
157
- }
158
- fs.unlinkSync(pidFile);
159
- }
160
- } catch (e) { /* non-fatal: best-effort cleanup */ }
149
+ // Dynamic import of ESM process-manager from CJS context
150
+ var pmMod = await import(
151
+ 'file:///' + path.join(projectDir, 'node_modules', 'moflo', 'bin', 'lib', 'process-manager.mjs').replace(/\\/g, '/')
152
+ ).catch(function() {
153
+ // Fallback: try local bin/ (for moflo repo itself)
154
+ return import(
155
+ 'file:///' + path.join(projectDir, 'bin', 'lib', 'process-manager.mjs').replace(/\\/g, '/')
156
+ );
157
+ }).catch(function() { return null; });
158
+
159
+ if (!pmMod) return; // No process manager available
160
+
161
+ var pm = pmMod.createProcessManager(projectDir);
162
+
163
+ // Kill stale background processes from previous session
164
+ pm.killAll();
165
+
166
+ // Guard: prevent concurrent session-restores from spawning duplicates
167
+ if (pm.isLocked()) return;
168
+ pm.acquireLock();
161
169
 
162
170
  // Read moflo.yaml auto_index flags (default: both true)
163
171
  var autoGuidance = true;
@@ -196,63 +204,51 @@ const handlers = {
196
204
  return null;
197
205
  }
198
206
 
199
- // Track PIDs of background processes so next session can clean them up
200
- var trackedPids = [];
201
-
202
- function spawnBackground(script, label, extraArgs) {
203
- var args = [script].concat(extraArgs || []);
204
- var child = cp.spawn('node', args, {
205
- stdio: 'ignore',
206
- cwd: projectDir,
207
- detached: true,
208
- windowsHide: true
209
- });
210
- if (child.pid) {
211
- trackedPids.push({ pid: child.pid, script: label, startedAt: new Date().toISOString() });
212
- }
213
- child.unref();
214
- }
215
-
216
207
  // 1. Index guidance docs (with embeddings for semantic search)
217
208
  if (autoGuidance) {
218
209
  var guidanceScript = findMofloScript('index-guidance.mjs');
219
- if (guidanceScript) spawnBackground(guidanceScript, 'index-guidance');
210
+ if (guidanceScript) pm.spawn('node', [guidanceScript], 'index-guidance');
220
211
  }
221
212
 
222
213
  // 2. Generate code map (structural index of source files)
223
214
  if (autoCodeMap) {
224
215
  var codeMapScript = findMofloScript('generate-code-map.mjs');
225
- if (codeMapScript) spawnBackground(codeMapScript, 'generate-code-map');
216
+ if (codeMapScript) pm.spawn('node', [codeMapScript], 'generate-code-map');
226
217
  }
227
218
 
228
219
  // 3. Start learning service (pattern research on codebase)
229
220
  var learnScript = findMofloScript('../.claude/helpers/learning-service.mjs');
230
221
  if (!learnScript) learnScript = findMofloScript('learning-service.mjs');
231
- // Also check the .claude/helpers location directly
232
222
  if (!learnScript) {
233
223
  var localLearn = path.join(projectDir, '.claude', 'helpers', 'learning-service.mjs');
234
224
  if (fs.existsSync(localLearn)) learnScript = localLearn;
235
225
  }
236
- // Check inside node_modules/moflo/.claude/helpers
237
226
  if (!learnScript) {
238
227
  var nmLearn = path.join(projectDir, 'node_modules', 'moflo', '.claude', 'helpers', 'learning-service.mjs');
239
228
  if (fs.existsSync(nmLearn)) learnScript = nmLearn;
240
229
  }
241
- if (learnScript) spawnBackground(learnScript, 'learning-service');
242
-
243
- // Persist tracked PIDs for cleanup on next session start
244
- if (trackedPids.length > 0) {
245
- try {
246
- var pidDir = path.dirname(pidFile);
247
- if (!fs.existsSync(pidDir)) fs.mkdirSync(pidDir, { recursive: true });
248
- fs.writeFileSync(pidFile, JSON.stringify(trackedPids));
249
- } catch (e) { /* non-fatal */ }
250
- }
230
+ if (learnScript) pm.spawn('node', [learnScript], 'learning-service');
251
231
 
252
232
  } catch (e) { /* non-fatal: session-start indexing is best-effort */ }
253
233
  },
254
234
 
255
235
  'session-end': () => {
236
+ // Kill all tracked background processes using shared sync helper.
237
+ // Must be SYNCHRONOUS — process.exit(0) fires in finally{} so async would never resolve.
238
+ var projectDir = path.resolve(path.dirname(helpersDir), '..');
239
+ try {
240
+ var cleanup = require(path.join(projectDir, 'node_modules', 'moflo', 'bin', 'lib', 'registry-cleanup.cjs'));
241
+ var killed = cleanup.killTrackedSync(projectDir);
242
+ if (killed > 0) console.log('[CLEANUP] Killed ' + killed + ' background process(es)');
243
+ } catch (e) {
244
+ // Fallback: try local bin/ (for moflo repo itself)
245
+ try {
246
+ var cleanup2 = require(path.join(projectDir, 'bin', 'lib', 'registry-cleanup.cjs'));
247
+ var killed2 = cleanup2.killTrackedSync(projectDir);
248
+ if (killed2 > 0) console.log('[CLEANUP] Killed ' + killed2 + ' background process(es)');
249
+ } catch (e2) { /* non-fatal */ }
250
+ }
251
+
256
252
  if (intelligence && intelligence.consolidate) {
257
253
  try {
258
254
  var result = intelligence.consolidate();
@@ -326,7 +322,7 @@ const handlers = {
326
322
 
327
323
  if (command && handlers[command]) {
328
324
  try {
329
- handlers[command]();
325
+ await handlers[command]();
330
326
  } catch (e) {
331
327
  console.log('[WARN] Hook ' + command + ' encountered an error: ' + e.message);
332
328
  }
@@ -274,7 +274,7 @@
274
274
  "command": "node \"$CLAUDE_PROJECT_DIR/.claude/helpers/statusline.cjs\""
275
275
  },
276
276
  "mcpServers": {
277
- "claude-flow": {
277
+ "moflo": {
278
278
  "command": "node",
279
279
  "args": [
280
280
  "bin/cli.js",
@@ -284,7 +284,7 @@
284
284
  }
285
285
  },
286
286
  "enabledMcpjsonServers": [
287
- "claude-flow",
287
+ "moflo",
288
288
  "ruv-swarm"
289
289
  ]
290
290
  }
@@ -9,9 +9,9 @@
9
9
  "Bash(powershell.exe -NoProfile -Command \"Get-Process node -ErrorAction SilentlyContinue | Select-Object Id,ProcessName,StartTime,CommandLine | Format-Table -AutoSize\")",
10
10
  "Bash(npm version:*)",
11
11
  "Bash(gh pr:*)",
12
- "mcp__claude-flow__memory_store",
13
- "mcp__claude-flow__memory_retrieve",
14
- "mcp__claude-flow__memory_search"
12
+ "mcp__moflo__memory_store",
13
+ "mcp__moflo__memory_retrieve",
14
+ "mcp__moflo__memory_search"
15
15
  ]
16
16
  }
17
17
  }