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.
- package/.claude/agents/core/coder.md +265 -265
- package/.claude/agents/core/planner.md +167 -167
- package/.claude/agents/core/researcher.md +189 -189
- package/.claude/agents/core/reviewer.md +325 -325
- package/.claude/agents/core/tester.md +318 -318
- package/.claude/agents/dual-mode/codex-coordinator.md +224 -224
- package/.claude/agents/dual-mode/codex-worker.md +211 -211
- package/.claude/agents/dual-mode/dual-orchestrator.md +291 -291
- package/.claude/agents/github/code-review-swarm.md +537 -537
- package/.claude/agents/github/github-modes.md +172 -172
- package/.claude/agents/github/issue-tracker.md +318 -318
- package/.claude/agents/github/multi-repo-swarm.md +552 -552
- package/.claude/agents/github/pr-manager.md +190 -190
- package/.claude/agents/github/project-board-sync.md +508 -508
- package/.claude/agents/github/release-manager.md +366 -366
- package/.claude/agents/github/release-swarm.md +582 -582
- package/.claude/agents/github/repo-architect.md +397 -397
- package/.claude/agents/github/swarm-issue.md +572 -572
- package/.claude/agents/github/swarm-pr.md +427 -427
- package/.claude/agents/github/sync-coordinator.md +451 -451
- package/.claude/agents/github/workflow-automation.md +634 -634
- package/.claude/agents/goal/code-goal-planner.md +445 -445
- package/.claude/agents/hive-mind/collective-intelligence-coordinator.md +129 -129
- package/.claude/agents/hive-mind/queen-coordinator.md +202 -202
- package/.claude/agents/hive-mind/scout-explorer.md +241 -241
- package/.claude/agents/hive-mind/swarm-memory-manager.md +192 -192
- package/.claude/agents/hive-mind/worker-specialist.md +216 -216
- package/.claude/agents/neural/safla-neural.md +73 -73
- package/.claude/agents/reasoning/goal-planner.md +72 -72
- package/.claude/agents/swarm/adaptive-coordinator.md +395 -395
- package/.claude/agents/swarm/hierarchical-coordinator.md +326 -326
- package/.claude/agents/swarm/mesh-coordinator.md +391 -391
- package/.claude/agents/templates/migration-plan.md +745 -745
- package/.claude/commands/agents/agent-spawning.md +28 -28
- package/.claude/commands/analysis/COMMAND_COMPLIANCE_REPORT.md +53 -53
- package/.claude/commands/analysis/bottleneck-detect.md +162 -162
- package/.claude/commands/analysis/performance-bottlenecks.md +58 -58
- package/.claude/commands/analysis/token-efficiency.md +44 -44
- package/.claude/commands/automation/auto-agent.md +122 -122
- package/.claude/commands/automation/self-healing.md +105 -105
- package/.claude/commands/automation/session-memory.md +89 -89
- package/.claude/commands/automation/smart-agents.md +72 -72
- package/.claude/commands/coordination/init.md +44 -44
- package/.claude/commands/coordination/orchestrate.md +43 -43
- package/.claude/commands/coordination/spawn.md +45 -45
- package/.claude/commands/coordination/swarm-init.md +85 -85
- package/.claude/commands/github/github-modes.md +146 -146
- package/.claude/commands/github/github-swarm.md +121 -121
- package/.claude/commands/github/issue-tracker.md +291 -291
- package/.claude/commands/github/pr-manager.md +169 -169
- package/.claude/commands/github/release-manager.md +337 -337
- package/.claude/commands/github/repo-architect.md +366 -366
- package/.claude/commands/github/sync-coordinator.md +300 -300
- package/.claude/commands/memory/neural.md +47 -47
- package/.claude/commands/monitoring/agents.md +44 -44
- package/.claude/commands/monitoring/status.md +46 -46
- package/.claude/commands/optimization/auto-topology.md +61 -61
- package/.claude/commands/optimization/parallel-execution.md +49 -49
- package/.claude/commands/sparc/analyzer.md +51 -51
- package/.claude/commands/sparc/architect.md +53 -53
- package/.claude/commands/sparc/ask.md +97 -97
- package/.claude/commands/sparc/batch-executor.md +54 -54
- package/.claude/commands/sparc/code.md +89 -89
- package/.claude/commands/sparc/coder.md +54 -54
- package/.claude/commands/sparc/debug.md +83 -83
- package/.claude/commands/sparc/debugger.md +54 -54
- package/.claude/commands/sparc/designer.md +53 -53
- package/.claude/commands/sparc/devops.md +109 -109
- package/.claude/commands/sparc/docs-writer.md +80 -80
- package/.claude/commands/sparc/documenter.md +54 -54
- package/.claude/commands/sparc/innovator.md +54 -54
- package/.claude/commands/sparc/integration.md +83 -83
- package/.claude/commands/sparc/mcp.md +117 -117
- package/.claude/commands/sparc/memory-manager.md +54 -54
- package/.claude/commands/sparc/optimizer.md +54 -54
- package/.claude/commands/sparc/orchestrator.md +131 -131
- package/.claude/commands/sparc/post-deployment-monitoring-mode.md +83 -83
- package/.claude/commands/sparc/refinement-optimization-mode.md +83 -83
- package/.claude/commands/sparc/researcher.md +54 -54
- package/.claude/commands/sparc/reviewer.md +54 -54
- package/.claude/commands/sparc/security-review.md +80 -80
- package/.claude/commands/sparc/sparc-modes.md +174 -174
- package/.claude/commands/sparc/sparc.md +111 -111
- package/.claude/commands/sparc/spec-pseudocode.md +80 -80
- package/.claude/commands/sparc/supabase-admin.md +348 -348
- package/.claude/commands/sparc/swarm-coordinator.md +54 -54
- package/.claude/commands/sparc/tdd.md +54 -54
- package/.claude/commands/sparc/tester.md +54 -54
- package/.claude/commands/sparc/tutorial.md +79 -79
- package/.claude/commands/sparc/workflow-manager.md +54 -54
- package/.claude/commands/sparc.md +166 -166
- package/.claude/commands/swarm/analysis.md +95 -95
- package/.claude/commands/swarm/development.md +96 -96
- package/.claude/commands/swarm/examples.md +168 -168
- package/.claude/commands/swarm/maintenance.md +102 -102
- package/.claude/commands/swarm/optimization.md +117 -117
- package/.claude/commands/swarm/research.md +136 -136
- package/.claude/commands/swarm/testing.md +131 -131
- package/.claude/commands/training/neural-patterns.md +73 -73
- package/.claude/commands/training/specialization.md +62 -62
- package/.claude/commands/workflows/development.md +77 -77
- package/.claude/commands/workflows/research.md +62 -62
- package/.claude/guidance/{agent-bootstrap.md → shipped/agent-bootstrap.md} +126 -126
- package/.claude/guidance/{guidance-memory-strategy.md → shipped/guidance-memory-strategy.md} +262 -262
- package/.claude/guidance/{memory-strategy.md → shipped/memory-strategy.md} +204 -204
- package/.claude/guidance/{moflo.md → shipped/moflo.md} +45 -31
- package/.claude/guidance/{task-swarm-integration.md → shipped/task-swarm-integration.md} +441 -348
- package/.claude/helpers/gate.cjs +236 -236
- package/.claude/helpers/hook-handler.cjs +42 -46
- package/.claude/settings.json +2 -2
- package/.claude/settings.local.json +3 -3
- package/.claude/skills/fl/SKILL.md +29 -23
- package/.claude/skills/flo/SKILL.md +29 -23
- package/.claude/skills/github-code-review/SKILL.md +4 -4
- package/.claude/skills/github-multi-repo/SKILL.md +8 -8
- package/.claude/skills/github-project-management/SKILL.md +6 -6
- package/.claude/skills/github-release-management/SKILL.md +12 -12
- package/.claude/skills/github-workflow-automation/SKILL.md +6 -6
- package/.claude/skills/hooks-automation/SKILL.md +1201 -1201
- package/.claude/skills/performance-analysis/SKILL.md +563 -563
- package/.claude/skills/sparc-methodology/SKILL.md +64 -64
- package/.claude/skills/swarm-advanced/SKILL.md +77 -77
- package/.claude-plugin/README.md +3 -3
- package/.claude-plugin/docs/PLUGIN_SUMMARY.md +3 -3
- package/.claude-plugin/docs/QUICKSTART.md +4 -4
- package/.claude-plugin/marketplace.json +3 -3
- package/.claude-plugin/plugin.json +3 -3
- package/.claude-plugin/scripts/install.sh +9 -9
- package/.claude-plugin/scripts/verify.sh +7 -7
- package/README.md +311 -116
- package/bin/gate-hook.mjs +50 -0
- package/bin/gate.cjs +138 -0
- package/bin/hook-handler.cjs +83 -0
- package/bin/hooks.mjs +72 -12
- package/bin/index-guidance.mjs +28 -34
- package/bin/index-tests.mjs +710 -0
- package/bin/lib/process-manager.mjs +243 -0
- package/bin/lib/registry-cleanup.cjs +41 -0
- package/bin/prompt-hook.mjs +72 -0
- package/bin/semantic-search.mjs +473 -441
- package/bin/session-start-launcher.mjs +81 -31
- package/bin/setup-project.mjs +13 -10
- package/package.json +4 -2
- package/src/@claude-flow/cli/README.md +1 -1
- package/src/@claude-flow/cli/bin/cli.js +175 -175
- package/src/@claude-flow/cli/dist/src/commands/doctor.js +1091 -736
- package/src/@claude-flow/cli/dist/src/commands/github.d.ts +12 -0
- package/src/@claude-flow/cli/dist/src/commands/github.js +505 -0
- package/src/@claude-flow/cli/dist/src/commands/hive-mind.js +90 -90
- package/src/@claude-flow/cli/dist/src/commands/index.d.ts +1 -0
- package/src/@claude-flow/cli/dist/src/commands/index.js +7 -0
- package/src/@claude-flow/cli/dist/src/config-adapter.js +1 -1
- package/src/@claude-flow/cli/dist/src/init/claudemd-generator.js +1 -1
- package/src/@claude-flow/cli/dist/src/init/executor.js +109 -5
- package/src/@claude-flow/cli/dist/src/init/helpers-generator.d.ts +14 -0
- package/src/@claude-flow/cli/dist/src/init/helpers-generator.js +156 -24
- package/src/@claude-flow/cli/dist/src/init/mcp-generator.js +20 -20
- package/src/@claude-flow/cli/dist/src/init/moflo-init.d.ts +7 -0
- package/src/@claude-flow/cli/dist/src/init/moflo-init.js +72 -10
- package/src/@claude-flow/cli/dist/src/init/settings-generator.js +23 -14
- package/src/@claude-flow/cli/dist/src/mcp-server.js +3 -3
- package/src/@claude-flow/cli/dist/src/plugins/manager.js +9 -8
- package/src/@claude-flow/cli/dist/src/services/worker-daemon.d.ts +1 -0
- package/src/@claude-flow/cli/dist/src/services/worker-daemon.js +3 -1
- package/src/@claude-flow/cli/dist/src/services/workflow-gate.js +10 -10
- package/src/@claude-flow/cli/package.json +1 -1
package/.claude/helpers/gate.cjs
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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
|
-
//
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
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)
|
|
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)
|
|
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)
|
|
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
|
}
|
package/.claude/settings.json
CHANGED
|
@@ -274,7 +274,7 @@
|
|
|
274
274
|
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/helpers/statusline.cjs\""
|
|
275
275
|
},
|
|
276
276
|
"mcpServers": {
|
|
277
|
-
"
|
|
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
|
-
"
|
|
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
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
12
|
+
"mcp__moflo__memory_store",
|
|
13
|
+
"mcp__moflo__memory_retrieve",
|
|
14
|
+
"mcp__moflo__memory_search"
|
|
15
15
|
]
|
|
16
16
|
}
|
|
17
17
|
}
|