moflo 4.8.21 → 4.8.23
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/browser/browser-agent.yaml +182 -182
- 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/database-specialist.yaml +21 -21
- 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/index.yaml +17 -17
- package/.claude/agents/neural/safla-neural.md +73 -73
- package/.claude/agents/project-coordinator.yaml +15 -15
- package/.claude/agents/python-specialist.yaml +21 -21
- package/.claude/agents/reasoning/goal-planner.md +72 -72
- package/.claude/agents/security-auditor.yaml +20 -20
- 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/agents/typescript-specialist.yaml +21 -21
- package/.claude/checkpoints/1767754460.json +8 -8
- package/.claude/commands/agents/agent-spawning.md +28 -28
- 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/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/workflows/development.md +77 -77
- package/.claude/commands/workflows/research.md +62 -62
- package/.claude/guidance/moflo-bootstrap.md +126 -126
- package/.claude/guidance/shipped/agent-bootstrap.md +126 -126
- package/.claude/guidance/shipped/guidance-memory-strategy.md +262 -262
- package/.claude/guidance/shipped/memory-strategy.md +204 -204
- package/.claude/guidance/shipped/moflo.md +668 -653
- package/.claude/guidance/shipped/task-swarm-integration.md +441 -441
- package/.claude/helpers/intelligence.cjs +207 -207
- package/.claude/helpers/statusline.cjs +851 -851
- package/.claude/settings.local.json +18 -0
- package/.claude/skills/fl/SKILL.md +583 -583
- package/.claude/skills/flo/SKILL.md +583 -583
- package/.claude/skills/github-code-review/SKILL.md +1140 -1140
- package/.claude/skills/github-multi-repo/SKILL.md +874 -874
- package/.claude/skills/github-project-management/SKILL.md +1277 -1277
- package/.claude/skills/github-release-management/SKILL.md +1081 -1081
- package/.claude/skills/github-workflow-automation/SKILL.md +1065 -1065
- package/.claude/skills/hive-mind-advanced/SKILL.md +712 -712
- 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 +1115 -1115
- package/.claude/skills/swarm-advanced/SKILL.md +973 -973
- package/.claude/workflow-state.json +4 -4
- package/LICENSE +21 -21
- package/README.md +698 -685
- package/bin/cli.js +0 -0
- package/bin/gate-hook.mjs +50 -50
- package/bin/gate.cjs +138 -138
- package/bin/generate-code-map.mjs +775 -775
- package/bin/hook-handler.cjs +83 -83
- package/bin/hooks.mjs +656 -656
- package/bin/index-guidance.mjs +892 -892
- package/bin/index-tests.mjs +709 -709
- package/bin/lib/process-manager.mjs +243 -243
- package/bin/lib/registry-cleanup.cjs +41 -41
- package/bin/prompt-hook.mjs +72 -72
- package/bin/semantic-search.mjs +472 -472
- package/bin/session-start-launcher.mjs +238 -238
- package/bin/setup-project.mjs +250 -250
- package/package.json +123 -123
- package/src/@claude-flow/cli/README.md +452 -452
- package/src/@claude-flow/cli/bin/cli.js +180 -180
- package/src/@claude-flow/cli/bin/preinstall.cjs +2 -2
- package/src/@claude-flow/cli/dist/src/commands/completions.js +409 -409
- package/src/@claude-flow/cli/dist/src/commands/doctor.js +18 -2
- package/src/@claude-flow/cli/dist/src/commands/embeddings.js +25 -25
- package/src/@claude-flow/cli/dist/src/commands/github.js +61 -61
- package/src/@claude-flow/cli/dist/src/commands/hive-mind.js +90 -90
- package/src/@claude-flow/cli/dist/src/commands/hooks.js +9 -9
- package/src/@claude-flow/cli/dist/src/commands/init.js +3 -8
- package/src/@claude-flow/cli/dist/src/commands/ruvector/import.js +14 -14
- package/src/@claude-flow/cli/dist/src/commands/ruvector/setup.js +624 -624
- package/src/@claude-flow/cli/dist/src/config/moflo-config.d.ts +3 -0
- package/src/@claude-flow/cli/dist/src/config/moflo-config.js +101 -91
- package/src/@claude-flow/cli/dist/src/index.d.ts +5 -0
- package/src/@claude-flow/cli/dist/src/index.js +44 -0
- package/src/@claude-flow/cli/dist/src/init/claudemd-generator.d.ts +29 -29
- package/src/@claude-flow/cli/dist/src/init/claudemd-generator.js +43 -43
- package/src/@claude-flow/cli/dist/src/init/executor.js +453 -453
- package/src/@claude-flow/cli/dist/src/init/helpers-generator.js +482 -482
- package/src/@claude-flow/cli/dist/src/init/moflo-init.d.ts +30 -30
- package/src/@claude-flow/cli/dist/src/init/moflo-init.js +140 -140
- package/src/@claude-flow/cli/dist/src/init/statusline-generator.js +876 -876
- package/src/@claude-flow/cli/dist/src/memory/memory-initializer.js +371 -371
- package/src/@claude-flow/cli/dist/src/runtime/headless.js +28 -28
- package/src/@claude-flow/cli/dist/src/services/container-worker-pool.d.ts +197 -0
- package/src/@claude-flow/cli/dist/src/services/container-worker-pool.js +584 -0
- package/src/@claude-flow/cli/dist/src/services/daemon-lock.d.ts +14 -0
- package/src/@claude-flow/cli/dist/src/services/daemon-lock.js +1 -1
- package/src/@claude-flow/cli/dist/src/services/headless-worker-executor.js +84 -84
- package/src/@claude-flow/cli/package.json +1 -1
- package/src/@claude-flow/guidance/README.md +1195 -1195
- package/src/@claude-flow/guidance/package.json +198 -198
- package/src/@claude-flow/memory/README.md +587 -587
- package/src/@claude-flow/memory/dist/agentdb-backend.js +26 -26
- package/src/@claude-flow/memory/dist/auto-memory-bridge.test.js +27 -27
- package/src/@claude-flow/memory/dist/hybrid-backend.d.ts +245 -0
- package/src/@claude-flow/memory/dist/hybrid-backend.js +569 -0
- package/src/@claude-flow/memory/dist/hybrid-backend.test.d.ts +8 -0
- package/src/@claude-flow/memory/dist/hybrid-backend.test.js +320 -0
- package/src/@claude-flow/memory/dist/sqlite-backend.d.ts +121 -0
- package/src/@claude-flow/memory/dist/sqlite-backend.js +572 -0
- package/src/@claude-flow/memory/dist/sqljs-backend.js +26 -26
- package/src/@claude-flow/memory/package.json +44 -44
- package/src/@claude-flow/shared/README.md +323 -323
- package/src/@claude-flow/shared/dist/events/event-store.js +31 -31
- package/src/README.md +493 -493
package/bin/cli.js
CHANGED
|
File without changes
|
package/bin/gate-hook.mjs
CHANGED
|
@@ -1,50 +1,50 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { execSync } from 'child_process';
|
|
3
|
-
import { resolve } from 'path';
|
|
4
|
-
|
|
5
|
-
var command = process.argv[2];
|
|
6
|
-
if (!command) process.exit(0);
|
|
7
|
-
|
|
8
|
-
// Read stdin JSON from Claude Code
|
|
9
|
-
var stdinData = '';
|
|
10
|
-
try {
|
|
11
|
-
stdinData = await new Promise(function(res) {
|
|
12
|
-
var data = '';
|
|
13
|
-
var timeout = setTimeout(function() { res(data); }, 500);
|
|
14
|
-
process.stdin.setEncoding('utf-8');
|
|
15
|
-
process.stdin.on('data', function(chunk) { data += chunk; });
|
|
16
|
-
process.stdin.on('end', function() { clearTimeout(timeout); res(data); });
|
|
17
|
-
process.stdin.on('error', function() { clearTimeout(timeout); res(''); });
|
|
18
|
-
if (process.stdin.isTTY) { clearTimeout(timeout); res(''); }
|
|
19
|
-
});
|
|
20
|
-
} catch (e) { /* no stdin */ }
|
|
21
|
-
|
|
22
|
-
var hookContext = {};
|
|
23
|
-
try { if (stdinData.trim()) hookContext = JSON.parse(stdinData); } catch (e) {}
|
|
24
|
-
|
|
25
|
-
// Pass tool info as env vars for gate.cjs
|
|
26
|
-
var env = Object.assign({}, process.env);
|
|
27
|
-
if (hookContext.tool_name) env.TOOL_NAME = hookContext.tool_name;
|
|
28
|
-
if (hookContext.tool_input && typeof hookContext.tool_input === 'object') {
|
|
29
|
-
Object.keys(hookContext.tool_input).forEach(function(key) {
|
|
30
|
-
if (typeof hookContext.tool_input[key] === 'string') {
|
|
31
|
-
env['TOOL_INPUT_' + key] = hookContext.tool_input[key];
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// Run gate.cjs with the enriched environment
|
|
37
|
-
var projectDir = (env.CLAUDE_PROJECT_DIR || process.cwd()).replace(/^\/([a-z])\//i, '$1:/');
|
|
38
|
-
var gateScript = resolve(projectDir, '.claude/helpers/gate.cjs');
|
|
39
|
-
try {
|
|
40
|
-
var output = execSync('node "' + gateScript + '" ' + command, {
|
|
41
|
-
env: env, encoding: 'utf-8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe']
|
|
42
|
-
});
|
|
43
|
-
if (output.trim()) process.stdout.write(output);
|
|
44
|
-
process.exit(0);
|
|
45
|
-
} catch (err) {
|
|
46
|
-
// gate.cjs exit(2) = block, exit(1) = also block attempt — translate both to exit(2)
|
|
47
|
-
if (err.stderr) process.stderr.write(err.stderr);
|
|
48
|
-
if (err.stdout) process.stderr.write(err.stdout);
|
|
49
|
-
process.exit(err.status === 2 || err.status === 1 ? 2 : 0);
|
|
50
|
-
}
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { execSync } from 'child_process';
|
|
3
|
+
import { resolve } from 'path';
|
|
4
|
+
|
|
5
|
+
var command = process.argv[2];
|
|
6
|
+
if (!command) process.exit(0);
|
|
7
|
+
|
|
8
|
+
// Read stdin JSON from Claude Code
|
|
9
|
+
var stdinData = '';
|
|
10
|
+
try {
|
|
11
|
+
stdinData = await new Promise(function(res) {
|
|
12
|
+
var data = '';
|
|
13
|
+
var timeout = setTimeout(function() { res(data); }, 500);
|
|
14
|
+
process.stdin.setEncoding('utf-8');
|
|
15
|
+
process.stdin.on('data', function(chunk) { data += chunk; });
|
|
16
|
+
process.stdin.on('end', function() { clearTimeout(timeout); res(data); });
|
|
17
|
+
process.stdin.on('error', function() { clearTimeout(timeout); res(''); });
|
|
18
|
+
if (process.stdin.isTTY) { clearTimeout(timeout); res(''); }
|
|
19
|
+
});
|
|
20
|
+
} catch (e) { /* no stdin */ }
|
|
21
|
+
|
|
22
|
+
var hookContext = {};
|
|
23
|
+
try { if (stdinData.trim()) hookContext = JSON.parse(stdinData); } catch (e) {}
|
|
24
|
+
|
|
25
|
+
// Pass tool info as env vars for gate.cjs
|
|
26
|
+
var env = Object.assign({}, process.env);
|
|
27
|
+
if (hookContext.tool_name) env.TOOL_NAME = hookContext.tool_name;
|
|
28
|
+
if (hookContext.tool_input && typeof hookContext.tool_input === 'object') {
|
|
29
|
+
Object.keys(hookContext.tool_input).forEach(function(key) {
|
|
30
|
+
if (typeof hookContext.tool_input[key] === 'string') {
|
|
31
|
+
env['TOOL_INPUT_' + key] = hookContext.tool_input[key];
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Run gate.cjs with the enriched environment
|
|
37
|
+
var projectDir = (env.CLAUDE_PROJECT_DIR || process.cwd()).replace(/^\/([a-z])\//i, '$1:/');
|
|
38
|
+
var gateScript = resolve(projectDir, '.claude/helpers/gate.cjs');
|
|
39
|
+
try {
|
|
40
|
+
var output = execSync('node "' + gateScript + '" ' + command, {
|
|
41
|
+
env: env, encoding: 'utf-8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe']
|
|
42
|
+
});
|
|
43
|
+
if (output.trim()) process.stdout.write(output);
|
|
44
|
+
process.exit(0);
|
|
45
|
+
} catch (err) {
|
|
46
|
+
// gate.cjs exit(2) = block, exit(1) = also block attempt — translate both to exit(2)
|
|
47
|
+
if (err.stderr) process.stderr.write(err.stderr);
|
|
48
|
+
if (err.stdout) process.stderr.write(err.stdout);
|
|
49
|
+
process.exit(err.status === 2 || err.status === 1 ? 2 : 0);
|
|
50
|
+
}
|
package/bin/gate.cjs
CHANGED
|
@@ -1,138 +1,138 @@
|
|
|
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()).replace(/^\/([a-z])\//i, '$1:/');
|
|
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 EXEMPT = ['.claude/', '.claude\\', 'CLAUDE.md', 'MEMORY.md', 'workflow-state', 'node_modules'];
|
|
43
|
-
var DANGEROUS = ['rm -rf /', 'format c:', 'del /s /q c:\\', ':(){:|:&};:', 'mkfs.', '> /dev/sda'];
|
|
44
|
-
var DIRECTIVE_RE = /^(yes|no|yeah|yep|nope|sure|ok|okay|correct|right|exactly|perfect)\b/i;
|
|
45
|
-
var TASK_RE = /\b(fix|bug|error|implement|add|create|build|write|refactor|debug|test|feature|issue|security|optimi)\b/i;
|
|
46
|
-
|
|
47
|
-
switch (command) {
|
|
48
|
-
case 'check-before-agent': {
|
|
49
|
-
var s = readState();
|
|
50
|
-
// Hard gate: memory must be searched
|
|
51
|
-
if (config.memory_first && s.memoryRequired && !s.memorySearched) {
|
|
52
|
-
process.stderr.write('BLOCKED: Search memory (mcp__moflo__memory_search) before spawning agents.\n');
|
|
53
|
-
process.exit(2);
|
|
54
|
-
}
|
|
55
|
-
// Soft gate: TaskCreate recommended but not blocking
|
|
56
|
-
// (TaskCreate PostToolUse doesn't fire in Claude Code, so we can't track it reliably)
|
|
57
|
-
if (config.task_create_first && !s.tasksCreated) {
|
|
58
|
-
process.stdout.write('REMINDER: Use TaskCreate before spawning agents. Task tool is blocked until then.\n');
|
|
59
|
-
}
|
|
60
|
-
break;
|
|
61
|
-
}
|
|
62
|
-
case 'check-before-scan': {
|
|
63
|
-
if (!config.memory_first) break;
|
|
64
|
-
var s = readState();
|
|
65
|
-
if (s.memorySearched || !s.memoryRequired) break;
|
|
66
|
-
var target = (process.env.TOOL_INPUT_pattern || '') + ' ' + (process.env.TOOL_INPUT_path || '');
|
|
67
|
-
if (EXEMPT.some(function(p) { return target.indexOf(p) >= 0; })) break;
|
|
68
|
-
process.stderr.write('BLOCKED: Search memory before exploring files. Use mcp__moflo__memory_search.\n');
|
|
69
|
-
process.exit(2);
|
|
70
|
-
}
|
|
71
|
-
case 'check-before-read': {
|
|
72
|
-
if (!config.memory_first) break;
|
|
73
|
-
var s = readState();
|
|
74
|
-
if (s.memorySearched || !s.memoryRequired) break;
|
|
75
|
-
var fp = process.env.TOOL_INPUT_file_path || '';
|
|
76
|
-
if (fp.indexOf('.claude/guidance/') < 0 && fp.indexOf('.claude\\guidance\\') < 0) break;
|
|
77
|
-
process.stderr.write('BLOCKED: Search memory before reading guidance files. Use mcp__moflo__memory_search.\n');
|
|
78
|
-
process.exit(2);
|
|
79
|
-
}
|
|
80
|
-
case 'record-task-created': {
|
|
81
|
-
var s = readState();
|
|
82
|
-
s.tasksCreated = true;
|
|
83
|
-
s.taskCount = (s.taskCount || 0) + 1;
|
|
84
|
-
writeState(s);
|
|
85
|
-
break;
|
|
86
|
-
}
|
|
87
|
-
case 'record-memory-searched': {
|
|
88
|
-
var s = readState();
|
|
89
|
-
s.memorySearched = true;
|
|
90
|
-
writeState(s);
|
|
91
|
-
break;
|
|
92
|
-
}
|
|
93
|
-
case 'check-bash-memory': {
|
|
94
|
-
var cmd = process.env.TOOL_INPUT_command || '';
|
|
95
|
-
if (/semantic-search|memory search|memory retrieve|memory-search/.test(cmd)) {
|
|
96
|
-
var s = readState();
|
|
97
|
-
s.memorySearched = true;
|
|
98
|
-
writeState(s);
|
|
99
|
-
}
|
|
100
|
-
break;
|
|
101
|
-
}
|
|
102
|
-
case 'check-dangerous-command': {
|
|
103
|
-
var cmd = (process.env.TOOL_INPUT_command || '').toLowerCase();
|
|
104
|
-
for (var i = 0; i < DANGEROUS.length; i++) {
|
|
105
|
-
if (cmd.indexOf(DANGEROUS[i]) >= 0) {
|
|
106
|
-
console.log('[BLOCKED] Dangerous command: ' + DANGEROUS[i]);
|
|
107
|
-
process.exit(2);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
break;
|
|
111
|
-
}
|
|
112
|
-
case 'prompt-reminder': {
|
|
113
|
-
var s = readState();
|
|
114
|
-
s.memorySearched = false;
|
|
115
|
-
var prompt = process.env.CLAUDE_USER_PROMPT || '';
|
|
116
|
-
s.memoryRequired = prompt.length >= 4 && !DIRECTIVE_RE.test(prompt) && (TASK_RE.test(prompt) || prompt.length > 80);
|
|
117
|
-
s.interactionCount = (s.interactionCount || 0) + 1;
|
|
118
|
-
writeState(s);
|
|
119
|
-
if (!s.tasksCreated) console.log('REMINDER: Use TaskCreate before spawning agents. Task tool is blocked until then.');
|
|
120
|
-
if (config.context_tracking) {
|
|
121
|
-
var ic = s.interactionCount;
|
|
122
|
-
if (ic > 30) console.log('Context: CRITICAL. Commit, store learnings, suggest new session.');
|
|
123
|
-
else if (ic > 20) console.log('Context: DEPLETED. Checkpoint progress. Recommend /compact or fresh session.');
|
|
124
|
-
else if (ic > 10) console.log('Context: MODERATE. Re-state goal before architectural decisions. Use agents for >300 LOC.');
|
|
125
|
-
}
|
|
126
|
-
break;
|
|
127
|
-
}
|
|
128
|
-
case 'compact-guidance': {
|
|
129
|
-
console.log('Pre-Compact: Check CLAUDE.md for rules. Use memory search to recover context after compact.');
|
|
130
|
-
break;
|
|
131
|
-
}
|
|
132
|
-
case 'session-reset': {
|
|
133
|
-
writeState({ tasksCreated: false, taskCount: 0, memorySearched: false, memoryRequired: true, interactionCount: 0, sessionStart: new Date().toISOString(), lastBlockedAt: null });
|
|
134
|
-
break;
|
|
135
|
-
}
|
|
136
|
-
default:
|
|
137
|
-
break;
|
|
138
|
-
}
|
|
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()).replace(/^\/([a-z])\//i, '$1:/');
|
|
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 EXEMPT = ['.claude/', '.claude\\', 'CLAUDE.md', 'MEMORY.md', 'workflow-state', 'node_modules'];
|
|
43
|
+
var DANGEROUS = ['rm -rf /', 'format c:', 'del /s /q c:\\', ':(){:|:&};:', 'mkfs.', '> /dev/sda'];
|
|
44
|
+
var DIRECTIVE_RE = /^(yes|no|yeah|yep|nope|sure|ok|okay|correct|right|exactly|perfect)\b/i;
|
|
45
|
+
var TASK_RE = /\b(fix|bug|error|implement|add|create|build|write|refactor|debug|test|feature|issue|security|optimi)\b/i;
|
|
46
|
+
|
|
47
|
+
switch (command) {
|
|
48
|
+
case 'check-before-agent': {
|
|
49
|
+
var s = readState();
|
|
50
|
+
// Hard gate: memory must be searched
|
|
51
|
+
if (config.memory_first && s.memoryRequired && !s.memorySearched) {
|
|
52
|
+
process.stderr.write('BLOCKED: Search memory (mcp__moflo__memory_search) before spawning agents.\n');
|
|
53
|
+
process.exit(2);
|
|
54
|
+
}
|
|
55
|
+
// Soft gate: TaskCreate recommended but not blocking
|
|
56
|
+
// (TaskCreate PostToolUse doesn't fire in Claude Code, so we can't track it reliably)
|
|
57
|
+
if (config.task_create_first && !s.tasksCreated) {
|
|
58
|
+
process.stdout.write('REMINDER: Use TaskCreate before spawning agents. Task tool is blocked until then.\n');
|
|
59
|
+
}
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
case 'check-before-scan': {
|
|
63
|
+
if (!config.memory_first) break;
|
|
64
|
+
var s = readState();
|
|
65
|
+
if (s.memorySearched || !s.memoryRequired) break;
|
|
66
|
+
var target = (process.env.TOOL_INPUT_pattern || '') + ' ' + (process.env.TOOL_INPUT_path || '');
|
|
67
|
+
if (EXEMPT.some(function(p) { return target.indexOf(p) >= 0; })) break;
|
|
68
|
+
process.stderr.write('BLOCKED: Search memory before exploring files. Use mcp__moflo__memory_search.\n');
|
|
69
|
+
process.exit(2);
|
|
70
|
+
}
|
|
71
|
+
case 'check-before-read': {
|
|
72
|
+
if (!config.memory_first) break;
|
|
73
|
+
var s = readState();
|
|
74
|
+
if (s.memorySearched || !s.memoryRequired) break;
|
|
75
|
+
var fp = process.env.TOOL_INPUT_file_path || '';
|
|
76
|
+
if (fp.indexOf('.claude/guidance/') < 0 && fp.indexOf('.claude\\guidance\\') < 0) break;
|
|
77
|
+
process.stderr.write('BLOCKED: Search memory before reading guidance files. Use mcp__moflo__memory_search.\n');
|
|
78
|
+
process.exit(2);
|
|
79
|
+
}
|
|
80
|
+
case 'record-task-created': {
|
|
81
|
+
var s = readState();
|
|
82
|
+
s.tasksCreated = true;
|
|
83
|
+
s.taskCount = (s.taskCount || 0) + 1;
|
|
84
|
+
writeState(s);
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
case 'record-memory-searched': {
|
|
88
|
+
var s = readState();
|
|
89
|
+
s.memorySearched = true;
|
|
90
|
+
writeState(s);
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
case 'check-bash-memory': {
|
|
94
|
+
var cmd = process.env.TOOL_INPUT_command || '';
|
|
95
|
+
if (/semantic-search|memory search|memory retrieve|memory-search/.test(cmd)) {
|
|
96
|
+
var s = readState();
|
|
97
|
+
s.memorySearched = true;
|
|
98
|
+
writeState(s);
|
|
99
|
+
}
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
case 'check-dangerous-command': {
|
|
103
|
+
var cmd = (process.env.TOOL_INPUT_command || '').toLowerCase();
|
|
104
|
+
for (var i = 0; i < DANGEROUS.length; i++) {
|
|
105
|
+
if (cmd.indexOf(DANGEROUS[i]) >= 0) {
|
|
106
|
+
console.log('[BLOCKED] Dangerous command: ' + DANGEROUS[i]);
|
|
107
|
+
process.exit(2);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
case 'prompt-reminder': {
|
|
113
|
+
var s = readState();
|
|
114
|
+
s.memorySearched = false;
|
|
115
|
+
var prompt = process.env.CLAUDE_USER_PROMPT || '';
|
|
116
|
+
s.memoryRequired = prompt.length >= 4 && !DIRECTIVE_RE.test(prompt) && (TASK_RE.test(prompt) || prompt.length > 80);
|
|
117
|
+
s.interactionCount = (s.interactionCount || 0) + 1;
|
|
118
|
+
writeState(s);
|
|
119
|
+
if (!s.tasksCreated) console.log('REMINDER: Use TaskCreate before spawning agents. Task tool is blocked until then.');
|
|
120
|
+
if (config.context_tracking) {
|
|
121
|
+
var ic = s.interactionCount;
|
|
122
|
+
if (ic > 30) console.log('Context: CRITICAL. Commit, store learnings, suggest new session.');
|
|
123
|
+
else if (ic > 20) console.log('Context: DEPLETED. Checkpoint progress. Recommend /compact or fresh session.');
|
|
124
|
+
else if (ic > 10) console.log('Context: MODERATE. Re-state goal before architectural decisions. Use agents for >300 LOC.');
|
|
125
|
+
}
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
case 'compact-guidance': {
|
|
129
|
+
console.log('Pre-Compact: Check CLAUDE.md for rules. Use memory search to recover context after compact.');
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
case 'session-reset': {
|
|
133
|
+
writeState({ tasksCreated: false, taskCount: 0, memorySearched: false, memoryRequired: true, interactionCount: 0, sessionStart: new Date().toISOString(), lastBlockedAt: null });
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
default:
|
|
137
|
+
break;
|
|
138
|
+
}
|