moflo 4.7.6 → 4.7.7
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.
|
@@ -0,0 +1,148 @@
|
|
|
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 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
|
+
if (config.task_create_first && !s.tasksCreated) {
|
|
51
|
+
console.log('BLOCKED: Call TaskCreate before spawning agents.');
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
if (config.memory_first && !s.memorySearched) {
|
|
55
|
+
console.log('BLOCKED: Search memory before spawning agents.');
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
case 'check-before-scan': {
|
|
61
|
+
if (!config.memory_first) break;
|
|
62
|
+
var s = readState();
|
|
63
|
+
if (s.memorySearched || !s.memoryRequired) break;
|
|
64
|
+
var target = (process.env.TOOL_INPUT_pattern || '') + ' ' + (process.env.TOOL_INPUT_path || '');
|
|
65
|
+
if (EXEMPT.some(function(p) { return target.indexOf(p) >= 0; })) break;
|
|
66
|
+
var now = Date.now();
|
|
67
|
+
var last = s.lastBlockedAt ? new Date(s.lastBlockedAt).getTime() : 0;
|
|
68
|
+
if (now - last > 2000) {
|
|
69
|
+
s.lastBlockedAt = new Date(now).toISOString();
|
|
70
|
+
writeState(s);
|
|
71
|
+
console.log('BLOCKED: Search memory before exploring files.');
|
|
72
|
+
}
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
case 'check-before-read': {
|
|
76
|
+
if (!config.memory_first) break;
|
|
77
|
+
var s = readState();
|
|
78
|
+
if (s.memorySearched || !s.memoryRequired) break;
|
|
79
|
+
var fp = process.env.TOOL_INPUT_file_path || '';
|
|
80
|
+
if (fp.indexOf('.claude/guidance/') < 0 && fp.indexOf('.claude\\guidance\\') < 0) break;
|
|
81
|
+
var now = Date.now();
|
|
82
|
+
var last = s.lastBlockedAt ? new Date(s.lastBlockedAt).getTime() : 0;
|
|
83
|
+
if (now - last > 2000) {
|
|
84
|
+
s.lastBlockedAt = new Date(now).toISOString();
|
|
85
|
+
writeState(s);
|
|
86
|
+
console.log('BLOCKED: Search memory before reading guidance files.');
|
|
87
|
+
}
|
|
88
|
+
process.exit(1);
|
|
89
|
+
}
|
|
90
|
+
case 'record-task-created': {
|
|
91
|
+
var s = readState();
|
|
92
|
+
s.tasksCreated = true;
|
|
93
|
+
s.taskCount = (s.taskCount || 0) + 1;
|
|
94
|
+
writeState(s);
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
case 'record-memory-searched': {
|
|
98
|
+
var s = readState();
|
|
99
|
+
s.memorySearched = true;
|
|
100
|
+
writeState(s);
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
case 'check-bash-memory': {
|
|
104
|
+
var cmd = process.env.TOOL_INPUT_command || '';
|
|
105
|
+
if (/semantic-search|memory search|memory retrieve|memory-search/.test(cmd)) {
|
|
106
|
+
var s = readState();
|
|
107
|
+
s.memorySearched = true;
|
|
108
|
+
writeState(s);
|
|
109
|
+
}
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
case 'check-dangerous-command': {
|
|
113
|
+
var cmd = (process.env.TOOL_INPUT_command || '').toLowerCase();
|
|
114
|
+
for (var i = 0; i < DANGEROUS.length; i++) {
|
|
115
|
+
if (cmd.indexOf(DANGEROUS[i]) >= 0) {
|
|
116
|
+
console.log('[BLOCKED] Dangerous command: ' + DANGEROUS[i]);
|
|
117
|
+
process.exit(2);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
case 'prompt-reminder': {
|
|
123
|
+
var s = readState();
|
|
124
|
+
s.memorySearched = false;
|
|
125
|
+
var prompt = process.env.CLAUDE_USER_PROMPT || '';
|
|
126
|
+
s.memoryRequired = prompt.length >= 4 && !DIRECTIVE_RE.test(prompt) && (TASK_RE.test(prompt) || prompt.length > 80);
|
|
127
|
+
s.interactionCount = (s.interactionCount || 0) + 1;
|
|
128
|
+
writeState(s);
|
|
129
|
+
if (!s.tasksCreated) console.log('REMINDER: Use TaskCreate before spawning agents. Task tool is blocked until then.');
|
|
130
|
+
if (config.context_tracking) {
|
|
131
|
+
var ic = s.interactionCount;
|
|
132
|
+
if (ic > 30) console.log('Context: CRITICAL. Commit, store learnings, suggest new session.');
|
|
133
|
+
else if (ic > 20) console.log('Context: DEPLETED. Checkpoint progress. Recommend /compact or fresh session.');
|
|
134
|
+
else if (ic > 10) console.log('Context: MODERATE. Re-state goal before architectural decisions.');
|
|
135
|
+
}
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
case 'compact-guidance': {
|
|
139
|
+
console.log('Pre-Compact: Check CLAUDE.md for rules. Use memory search to recover context after compact.');
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
case 'session-reset': {
|
|
143
|
+
writeState({ tasksCreated: false, taskCount: 0, memorySearched: false, memoryRequired: true, interactionCount: 0, sessionStart: new Date().toISOString(), lastBlockedAt: null });
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
default:
|
|
147
|
+
break;
|
|
148
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "moflo",
|
|
3
|
-
"version": "4.7.
|
|
3
|
+
"version": "4.7.7",
|
|
4
4
|
"description": "MoFlo — AI agent orchestration for Claude Code. Forked from ruflo/claude-flow with patches applied to source, plus feature-level orchestration.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -935,12 +935,10 @@ async function writeHelpers(targetDir, options, result) {
|
|
|
935
935
|
result.skipped.push(`.claude/helpers/${file}`);
|
|
936
936
|
}
|
|
937
937
|
}
|
|
938
|
-
|
|
939
|
-
return; // Skip generating if we copied from source
|
|
940
|
-
}
|
|
938
|
+
// Don't return early — still need to generate any missing required helpers below
|
|
941
939
|
}
|
|
942
|
-
//
|
|
943
|
-
// gate.cjs and hook-handler.cjs are
|
|
940
|
+
// Generate required helpers that weren't copied from source.
|
|
941
|
+
// gate.cjs and hook-handler.cjs are critical — hooks call them directly
|
|
944
942
|
// via `node` instead of `npx flo` to avoid CLI bootstrap overhead.
|
|
945
943
|
const helpers = {
|
|
946
944
|
'pre-commit': generatePreCommitHook(),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@moflo/cli",
|
|
3
|
-
"version": "4.7.
|
|
3
|
+
"version": "4.7.7",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "MoFlo CLI — AI agent orchestration with specialized agents, swarm coordination, MCP server, self-learning hooks, and vector memory for Claude Code",
|
|
6
6
|
"main": "dist/src/index.js",
|