moflo 4.8.11 → 4.8.12

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,182 @@
1
+ # Browser Agent Configuration
2
+ # AI-powered web browser automation using agent-browser
3
+ #
4
+ # Capabilities:
5
+ # - Web navigation and interaction
6
+ # - AI-optimized snapshots with element refs
7
+ # - Form filling and submission
8
+ # - Screenshot capture
9
+ # - Network interception
10
+ # - Multi-session coordination
11
+
12
+ name: browser-agent
13
+ description: Web automation specialist using agent-browser with AI-optimized snapshots
14
+ version: 1.0.0
15
+
16
+ # Routing configuration
17
+ routing:
18
+ complexity: medium
19
+ model: sonnet # Good at visual reasoning and DOM interpretation
20
+ priority: normal
21
+ keywords:
22
+ - browser
23
+ - web
24
+ - scrape
25
+ - screenshot
26
+ - navigate
27
+ - login
28
+ - form
29
+ - click
30
+ - automate
31
+
32
+ # Agent capabilities
33
+ capabilities:
34
+ - web-navigation
35
+ - form-interaction
36
+ - screenshot-capture
37
+ - data-extraction
38
+ - network-interception
39
+ - session-management
40
+ - multi-tab-coordination
41
+
42
+ # Available tools (MCP tools with browser/ prefix)
43
+ tools:
44
+ navigation:
45
+ - browser/open
46
+ - browser/back
47
+ - browser/forward
48
+ - browser/reload
49
+ - browser/close
50
+ snapshot:
51
+ - browser/snapshot
52
+ - browser/screenshot
53
+ - browser/pdf
54
+ interaction:
55
+ - browser/click
56
+ - browser/fill
57
+ - browser/type
58
+ - browser/press
59
+ - browser/hover
60
+ - browser/select
61
+ - browser/check
62
+ - browser/uncheck
63
+ - browser/scroll
64
+ - browser/upload
65
+ info:
66
+ - browser/get-text
67
+ - browser/get-html
68
+ - browser/get-value
69
+ - browser/get-attr
70
+ - browser/get-title
71
+ - browser/get-url
72
+ - browser/get-count
73
+ state:
74
+ - browser/is-visible
75
+ - browser/is-enabled
76
+ - browser/is-checked
77
+ wait:
78
+ - browser/wait
79
+ eval:
80
+ - browser/eval
81
+ storage:
82
+ - browser/cookies-get
83
+ - browser/cookies-set
84
+ - browser/cookies-clear
85
+ - browser/localstorage-get
86
+ - browser/localstorage-set
87
+ network:
88
+ - browser/network-route
89
+ - browser/network-unroute
90
+ - browser/network-requests
91
+ tabs:
92
+ - browser/tab-list
93
+ - browser/tab-new
94
+ - browser/tab-switch
95
+ - browser/tab-close
96
+ - browser/session-list
97
+ settings:
98
+ - browser/set-viewport
99
+ - browser/set-device
100
+ - browser/set-geolocation
101
+ - browser/set-offline
102
+ - browser/set-media
103
+ debug:
104
+ - browser/trace-start
105
+ - browser/trace-stop
106
+ - browser/console
107
+ - browser/errors
108
+ - browser/highlight
109
+ - browser/state-save
110
+ - browser/state-load
111
+ find:
112
+ - browser/find-role
113
+ - browser/find-text
114
+ - browser/find-label
115
+ - browser/find-testid
116
+
117
+ # Memory configuration
118
+ memory:
119
+ namespace: browser-sessions
120
+ persist: true
121
+ patterns:
122
+ - login-flows
123
+ - form-submissions
124
+ - scraping-patterns
125
+ - navigation-sequences
126
+
127
+ # Swarm integration
128
+ swarm:
129
+ roles:
130
+ - navigator # Handles authentication and navigation
131
+ - scraper # Extracts data using snapshots
132
+ - validator # Verifies extracted data
133
+ - tester # Runs automated tests
134
+ - monitor # Watches for errors and network issues
135
+ topology: hierarchical # Coordinator manages browser agents
136
+ max_sessions: 5
137
+
138
+ # Hooks integration
139
+ hooks:
140
+ pre_task:
141
+ - route # Get optimal routing
142
+ - memory_search # Check for similar patterns
143
+ post_task:
144
+ - memory_store # Save successful patterns
145
+ - post_edit # Train on outcomes
146
+
147
+ # Default configuration
148
+ defaults:
149
+ timeout: 30000
150
+ headless: true
151
+ viewport:
152
+ width: 1280
153
+ height: 720
154
+
155
+ # Example workflows
156
+ workflows:
157
+ login:
158
+ description: Authenticate to a website
159
+ steps:
160
+ - open: "{url}/login"
161
+ - snapshot: { interactive: true }
162
+ - fill: { target: "@e1", value: "{username}" }
163
+ - fill: { target: "@e2", value: "{password}" }
164
+ - click: "@e3"
165
+ - wait: { url: "**/dashboard" }
166
+ - state-save: "auth-state.json"
167
+
168
+ scrape_list:
169
+ description: Extract data from a list page
170
+ steps:
171
+ - open: "{url}"
172
+ - snapshot: { interactive: true, compact: true }
173
+ - eval: "Array.from(document.querySelectorAll('{selector}')).map(el => el.textContent)"
174
+
175
+ form_submit:
176
+ description: Fill and submit a form
177
+ steps:
178
+ - open: "{url}"
179
+ - snapshot: { interactive: true }
180
+ - fill_fields: "{fields}"
181
+ - click: "{submit_button}"
182
+ - wait: { text: "{success_text}" }
@@ -0,0 +1,129 @@
1
+ <!-- AUTO-GENERATED by moflo session-start. Do not edit — changes will be overwritten. -->
2
+ <!-- Source: node_modules/moflo/.claude/guidance/agent-bootstrap.md -->
3
+
4
+ # MoFlo Agent Bootstrap Guide
5
+
6
+ **Purpose:** Quick-start reference for subagents spawned by coordinators. Every subagent should follow this protocol before doing any work.
7
+
8
+ ---
9
+
10
+ ## 1. Search Memory FIRST
11
+
12
+ **Before reading any files or exploring code, search memory for guidance relevant to your task.**
13
+
14
+ ### Three namespaces to search:
15
+
16
+ | Namespace | When to search | What it returns |
17
+ |-----------|---------------|-----------------|
18
+ | `guidance` | Understanding patterns, rules, conventions | Guidance docs, coding rules, domain context |
19
+ | `code-map` | Finding where code lives (files, types, services) | Project overviews, directory contents, type-to-file mappings |
20
+ | `patterns` | Prior solutions, gotchas, implementation patterns | Learned patterns from previous task execution |
21
+
22
+ **Always search `patterns` alongside `guidance`.** It contains solutions to problems already solved — skipping it means repeating past mistakes or re-discovering known approaches.
23
+
24
+ **Search `code-map` BEFORE using Glob/Grep for navigation.** It's faster and returns structured results including file-level type mappings.
25
+
26
+ ### Option A: MCP Tools (Preferred)
27
+
28
+ If you have MCP tools available (check for `mcp__moflo__*`), use them directly:
29
+
30
+ | Tool | Purpose |
31
+ |------|---------|
32
+ | `mcp__moflo__memory_search` | Semantic search with domain-aware embeddings |
33
+ | `mcp__moflo__memory_store` | Store patterns with auto-vectorization |
34
+ | `mcp__moflo__hooks_route` | Get agent routing suggestions |
35
+
36
+ ### Option B: CLI via Bash
37
+
38
+ ```bash
39
+ npx flo memory search --query "[describe your task]" --namespace guidance --limit 5
40
+ ```
41
+
42
+ | Your task involves... | Search namespace | Example query |
43
+ |-----------------------|------------------|---------------|
44
+ | Database/entities | `guidance` + `patterns` | `"database entity migration"` |
45
+ | Frontend components | `guidance` + `patterns` | `"React frontend component"` |
46
+ | API endpoints | `guidance` + `patterns` | `"API route endpoint pattern"` |
47
+ | Authentication | `guidance` + `patterns` | `"auth middleware JWT"` |
48
+ | Unit tests | `guidance` + `patterns` | `"test mock vitest"` |
49
+ | Prior solutions/gotchas | `patterns` | `"audit log service pattern"` |
50
+ | Where is a file/type? | `code-map` | `"CompanyEntity file location"` |
51
+ | What's in a directory? | `code-map` | `"back-office api routes"` |
52
+
53
+ Use results with score > 0.3. If no good results, fall back to reading project guidance docs.
54
+
55
+ ---
56
+
57
+ ## 2. Check Project-Specific Bootstrap
58
+
59
+ **After reading this file, check for a project-specific bootstrap:**
60
+
61
+ ```bash
62
+ # Project-specific bootstrap (has domain rules, patterns, templates)
63
+ cat .claude/guidance/agent-bootstrap.md 2>/dev/null | head -10
64
+ ```
65
+
66
+ If `.claude/guidance/agent-bootstrap.md` exists, **read it next**. It contains project-specific rules (entity patterns, multi-tenancy, tech stack conventions) that override generic guidance.
67
+
68
+ If no project bootstrap exists, look for general project guidance:
69
+
70
+ ```bash
71
+ ls .claude/guidance/ 2>/dev/null
72
+ cat .claude/guidance/core.md 2>/dev/null | head -50
73
+ ```
74
+
75
+ Project guidance always takes precedence over generic patterns.
76
+
77
+ ---
78
+
79
+ ## 3. Universal Rules
80
+
81
+ ### Memory Protocol
82
+ - Search memory before exploring files
83
+ - Store discoveries back to memory when done
84
+ - Use `patterns` namespace for solutions and gotchas
85
+ - Use `decisions` namespace for architectural choices
86
+
87
+ ### Git/Branches
88
+ - Use conventional commit prefixes: `feat:`, `fix:`, `refactor:`, `test:`, `chore:`
89
+ - Use branch prefixes: `feature/`, `fix/`, `refactor/`
90
+ - Use kebab-case for branch names
91
+
92
+ ### File Organization
93
+ - Never save working files to repository root
94
+ - Keep changes focused (3-10 files)
95
+ - Stay within feature scope
96
+
97
+ ### Build & Test
98
+ - Build and test after code changes
99
+ - Never leave failing tests
100
+
101
+ ---
102
+
103
+ ## 4. Store Discoveries
104
+
105
+ If you discover something new (pattern, solution, gotcha), store it:
106
+
107
+ ### MCP (Preferred):
108
+ ```
109
+ mcp__moflo__memory_store
110
+ namespace: "patterns"
111
+ key: "brief-descriptive-key"
112
+ value: "1-2 sentence insight"
113
+ ```
114
+
115
+ ### CLI Fallback:
116
+ ```bash
117
+ npx flo memory store --namespace patterns --key "brief-descriptive-key" --value "1-2 sentence insight"
118
+ ```
119
+
120
+ **Store:** Solutions to tricky bugs, patterns that worked, gotchas, workarounds
121
+ **Skip:** Summaries of retrieved guidance, general rules, file locations
122
+
123
+ ---
124
+
125
+ ## 5. When Complete
126
+
127
+ 1. Report findings to coordinator
128
+ 2. Store learnings if you discovered something new
129
+ 3. Coordinator will mark your task as completed
@@ -0,0 +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
+ }
@@ -3,7 +3,7 @@
3
3
  var fs = require('fs');
4
4
  var path = require('path');
5
5
 
6
- var PROJECT_DIR = process.env.CLAUDE_PROJECT_DIR || process.cwd();
6
+ var PROJECT_DIR = (process.env.CLAUDE_PROJECT_DIR || process.cwd()).replace(/^\/([a-z])\//i, '$1:/');
7
7
  var STATE_FILE = path.join(PROJECT_DIR, '.claude', 'workflow-state.json');
8
8
 
9
9
  function readState() {
@@ -39,119 +39,23 @@ function loadGateConfig() {
39
39
  var config = loadGateConfig();
40
40
  var command = process.argv[2];
41
41
 
42
+ var EXEMPT = ['.claude/', '.claude\\', 'CLAUDE.md', 'MEMORY.md', 'workflow-state', 'node_modules'];
42
43
  var DANGEROUS = ['rm -rf /', 'format c:', 'del /s /q c:\\', ':(){:|:&};:', 'mkfs.', '> /dev/sda'];
43
44
  var DIRECTIVE_RE = /^(yes|no|yeah|yep|nope|sure|ok|okay|correct|right|exactly|perfect)\b/i;
44
45
  var TASK_RE = /\b(fix|bug|error|implement|add|create|build|write|refactor|debug|test|feature|issue|security|optimi)\b/i;
45
46
 
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
47
  switch (command) {
148
48
  case 'check-before-agent': {
149
49
  var s = readState();
150
- if (config.task_create_first && !s.tasksCreated) {
151
- blockTool('Call TaskCreate before spawning agents. Task tool is blocked until then.');
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);
152
54
  }
153
- if (config.memory_first && !s.memorySearched) {
154
- blockTool('Search memory before spawning agents. Use mcp__moflo__memory_search first.');
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');
155
59
  }
156
60
  break;
157
61
  }
@@ -159,21 +63,19 @@ switch (command) {
159
63
  if (!config.memory_first) break;
160
64
  var s = readState();
161
65
  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".');
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);
166
70
  }
167
71
  case 'check-before-read': {
168
72
  if (!config.memory_first) break;
169
73
  var s = readState();
170
74
  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".');
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);
177
79
  }
178
80
  case 'record-task-created': {
179
81
  var s = readState();
@@ -219,7 +121,7 @@ switch (command) {
219
121
  var ic = s.interactionCount;
220
122
  if (ic > 30) console.log('Context: CRITICAL. Commit, store learnings, suggest new session.');
221
123
  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.');
124
+ else if (ic > 10) console.log('Context: MODERATE. Re-state goal before architectural decisions. Use agents for >300 LOC.');
223
125
  }
224
126
  break;
225
127
  }