create-merlin-brain 5.3.7 → 5.3.8
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/bin/install.cjs +17 -4
- package/files/CLAUDE.md +1 -0
- package/files/commands/merlin/check-size.md +152 -0
- package/files/hooks/check-file-size.sh +166 -58
- package/files/merlin-system-prompt.txt +3 -1
- package/package.json +1 -1
package/bin/install.cjs
CHANGED
|
@@ -1320,10 +1320,17 @@ async function install() {
|
|
|
1320
1320
|
hooks: [{ type: 'command', command: 'bash ~/.claude/hooks/user-prompt-router.sh' }]
|
|
1321
1321
|
});
|
|
1322
1322
|
|
|
1323
|
-
//
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1323
|
+
// PreToolUse: file size enforcement (400-LOC rule, blocks oversized writes)
|
|
1324
|
+
// NOTE: Moved from PostToolUse to PreToolUse in v5.3.8 to BLOCK before write, not warn after.
|
|
1325
|
+
addHookIfMissing(settings.hooks.PreToolUse, {
|
|
1326
|
+
matcher: 'Edit|Write|MultiEdit',
|
|
1327
|
+
hooks: [{ type: 'command', command: 'bash ~/.claude/hooks/check-file-size.sh', timeout: 10 }]
|
|
1328
|
+
});
|
|
1329
|
+
|
|
1330
|
+
// Remove legacy PostToolUse check-file-size.sh (pre-5.3.8)
|
|
1331
|
+
settings.hooks.PostToolUse = settings.hooks.PostToolUse.filter(entry => {
|
|
1332
|
+
const cmd = entry.hooks?.[0]?.command || '';
|
|
1333
|
+
return !cmd.includes('check-file-size.sh');
|
|
1327
1334
|
});
|
|
1328
1335
|
|
|
1329
1336
|
// PreToolUse: security scanner (prompt injection, secrets, data exfiltration)
|
|
@@ -1760,6 +1767,12 @@ ${colors.cyan}Discovery-first (NEW in 5.3.7):${colors.reset}
|
|
|
1760
1767
|
• ${colors.bright}/merlin:install <slug>${colors.reset} - One-keystroke install of any catalog agent
|
|
1761
1768
|
• smart_route + discover_agents wired into the orchestrator protocol
|
|
1762
1769
|
|
|
1770
|
+
${colors.cyan}File-size enforcement (NEW in 5.3.8):${colors.reset}
|
|
1771
|
+
• 400-LOC rule now enforced by PreToolUse hook (blocks oversized writes)
|
|
1772
|
+
• ${colors.bright}/merlin:check-size${colors.reset} - Scan repo for violations
|
|
1773
|
+
• Justify exceptions with: ${colors.yellow}// merlin:allow-large-file: <reason>${colors.reset}
|
|
1774
|
+
• Override: MERLIN_SKIP_FILE_SIZE_CHECK=1 or MERLIN_FILE_SIZE_LIMIT=N
|
|
1775
|
+
|
|
1763
1776
|
${colors.cyan}Merlin works with or without Sights:${colors.reset}
|
|
1764
1777
|
• ${colors.green}With Sights${colors.reset}: Instant context, cross-session memory
|
|
1765
1778
|
• ${colors.green}Without${colors.reset}: Full workflows, uses file exploration
|
package/files/CLAUDE.md
CHANGED
|
@@ -83,6 +83,7 @@ When user corrects you → `merlin_save_behavior`. When user says "always/never/
|
|
|
83
83
|
- Never kill user processes (Xcode, VS Code, browsers) without explicit confirmation.
|
|
84
84
|
- Never claim "done" without actually building/compiling/testing.
|
|
85
85
|
- Badge on EVERY action — call `~/.claude/scripts/duo-badge.sh` to get the right badge. If the user can't see the badge, you're not doing your job.
|
|
86
|
+
- No file may exceed 400 LOC. Enforced by ~/.claude/hooks/check-file-size.sh (PreToolUse hook). Override per-file with `// merlin:allow-large-file: <reason>` comment. Override per-session with MERLIN_SKIP_FILE_SIZE_CHECK=1.
|
|
86
87
|
|
|
87
88
|
## Codex Execution Mode
|
|
88
89
|
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: merlin:check-size
|
|
3
|
+
description: Scan the repo for files exceeding the 400-LOC convention and surface violations
|
|
4
|
+
argument-hint: "[path]"
|
|
5
|
+
allowed-tools:
|
|
6
|
+
- Read
|
|
7
|
+
- Glob
|
|
8
|
+
- Grep
|
|
9
|
+
- Bash
|
|
10
|
+
- AskUserQuestion
|
|
11
|
+
- mcp__merlin__merlin_route
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<objective>
|
|
15
|
+
Scan the current repository for files that exceed the 400-LOC project convention.
|
|
16
|
+
Surface violations grouped by severity, identify opt-out markers, and offer to route to
|
|
17
|
+
`code-organization-supervisor` for refactor proposals on the worst offenders.
|
|
18
|
+
</objective>
|
|
19
|
+
|
|
20
|
+
<context>
|
|
21
|
+
Optional path argument: $ARGUMENTS
|
|
22
|
+
If provided, scan only that directory. Otherwise scan from repo root (cwd).
|
|
23
|
+
</context>
|
|
24
|
+
|
|
25
|
+
<process>
|
|
26
|
+
|
|
27
|
+
## Step 1: Discover Code Files
|
|
28
|
+
|
|
29
|
+
Run a find command to locate all code files, excluding common generated/vendor directories:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
find "${1:-.}" -type f \( \
|
|
33
|
+
-name "*.ts" -o -name "*.tsx" -o -name "*.js" -o -name "*.jsx" \
|
|
34
|
+
-o -name "*.py" -o -name "*.rs" -o -name "*.go" -o -name "*.sh" \
|
|
35
|
+
-o -name "*.cjs" -o -name "*.mjs" -o -name "*.swift" -o -name "*.kt" \
|
|
36
|
+
-o -name "*.java" -o -name "*.rb" -o -name "*.php" -o -name "*.c" \
|
|
37
|
+
-o -name "*.cpp" -o -name "*.h" -o -name "*.hpp" \
|
|
38
|
+
\) \
|
|
39
|
+
-not -path "*/node_modules/*" \
|
|
40
|
+
-not -path "*/dist/*" \
|
|
41
|
+
-not -path "*/build/*" \
|
|
42
|
+
-not -path "*/.next/*" \
|
|
43
|
+
-not -path "*/.git/*" \
|
|
44
|
+
-not -path "*/coverage/*" \
|
|
45
|
+
-not -path "*/.vite/*" \
|
|
46
|
+
-not -path "*/vendor/*" \
|
|
47
|
+
-not -path "*/__pycache__/*" \
|
|
48
|
+
2>/dev/null | xargs wc -l 2>/dev/null | awk '$1 > 400 && !/total$/' | sort -rn
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Capture the output as VIOLATIONS.
|
|
52
|
+
|
|
53
|
+
## Step 2: Group by Severity
|
|
54
|
+
|
|
55
|
+
Parse VIOLATIONS and categorize:
|
|
56
|
+
|
|
57
|
+
| Tier | LOC Range | Label |
|
|
58
|
+
|------|-----------|-------|
|
|
59
|
+
| Critical | 1000+ | files that urgently need splitting |
|
|
60
|
+
| High | 600-999 | should be refactored soon |
|
|
61
|
+
| Warn | 401-599 | approaching limit, watch closely |
|
|
62
|
+
|
|
63
|
+
## Step 3: Check for Opt-Out Markers
|
|
64
|
+
|
|
65
|
+
For each violation, check if the file contains the opt-out marker:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
grep -l "merlin:allow-large-file:" <file>
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Tag files that have the marker with "(justified)" in the output.
|
|
72
|
+
|
|
73
|
+
## Step 4: Present Report
|
|
74
|
+
|
|
75
|
+
Output a structured report:
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
============================================
|
|
79
|
+
FILE SIZE AUDIT — 400-LOC Convention
|
|
80
|
+
============================================
|
|
81
|
+
|
|
82
|
+
CRITICAL (1000+ LOC):
|
|
83
|
+
* path/to/file.ts — 1523 lines
|
|
84
|
+
* path/to/other.js — 1201 lines
|
|
85
|
+
|
|
86
|
+
HIGH (600-999 LOC):
|
|
87
|
+
* path/to/module.py — 812 lines (justified: "generated parser tables")
|
|
88
|
+
|
|
89
|
+
WARN (401-599 LOC):
|
|
90
|
+
* path/to/component.tsx — 456 lines
|
|
91
|
+
|
|
92
|
+
--------------------------------------------
|
|
93
|
+
Total violations: X files
|
|
94
|
+
- X critical, X high, X warn
|
|
95
|
+
- X have justification markers
|
|
96
|
+
--------------------------------------------
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
If no violations found:
|
|
100
|
+
```
|
|
101
|
+
All files are within the 400-LOC convention.
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Step 5: Offer Refactor Help
|
|
105
|
+
|
|
106
|
+
If there are critical-tier violations (1000+ LOC) without markers, ask:
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
The following files are critically oversized and lack justification:
|
|
110
|
+
* path/to/file.ts (1523 lines)
|
|
111
|
+
* path/to/other.js (1201 lines)
|
|
112
|
+
|
|
113
|
+
Would you like me to route these to `code-organization-supervisor` for
|
|
114
|
+
a proposed split? (y/n)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
If user says yes, route to the agent:
|
|
118
|
+
|
|
119
|
+
```
|
|
120
|
+
Call: merlin_route
|
|
121
|
+
Agent: code-organization-supervisor
|
|
122
|
+
Task: "Propose a refactor plan to split these oversized files into smaller, focused modules:
|
|
123
|
+
- <file1>: <LOC> lines
|
|
124
|
+
- <file2>: <LOC> lines
|
|
125
|
+
|
|
126
|
+
Each resulting module should be under 400 lines. Provide:
|
|
127
|
+
1. Proposed module boundaries
|
|
128
|
+
2. Which functions/classes go where
|
|
129
|
+
3. Import graph after the split
|
|
130
|
+
4. Step-by-step migration plan"
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
</process>
|
|
134
|
+
|
|
135
|
+
<error_handling>
|
|
136
|
+
|
|
137
|
+
| Condition | Action |
|
|
138
|
+
|-----------|--------|
|
|
139
|
+
| No code files found | Report "No code files found in <path>." |
|
|
140
|
+
| Permission errors | Skip inaccessible files, note count skipped |
|
|
141
|
+
| wc/find unavailable | Fall back to Glob + Read with manual line counting |
|
|
142
|
+
| Path doesn't exist | Report error and suggest checking the path |
|
|
143
|
+
|
|
144
|
+
</error_handling>
|
|
145
|
+
|
|
146
|
+
<tips>
|
|
147
|
+
- This command is advisory — it doesn't block anything
|
|
148
|
+
- The PreToolUse hook (`~/.claude/hooks/check-file-size.sh`) does the actual blocking
|
|
149
|
+
- Add `// merlin:allow-large-file: <reason>` to justify genuinely large files
|
|
150
|
+
- Override the limit per-session with `MERLIN_FILE_SIZE_LIMIT=600`
|
|
151
|
+
- Skip all checks with `MERLIN_SKIP_FILE_SIZE_CHECK=1`
|
|
152
|
+
</tips>
|
|
@@ -1,73 +1,181 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
+
# check-file-size.sh — Claude Code PreToolUse hook
|
|
2
3
|
#
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
#
|
|
4
|
+
# Enforces the 400-LOC project rule. Blocks Edit/Write/MultiEdit when the
|
|
5
|
+
# resulting file would exceed the limit, unless the file contains an opt-out
|
|
6
|
+
# marker (`merlin:allow-large-file: <reason>`).
|
|
6
7
|
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
8
|
+
# Contract per hooks-rules.md + Claude Code hooks docs:
|
|
9
|
+
# - stdin: JSON {tool_name, tool_input, ...}
|
|
10
|
+
# - block: exit 0 + stdout JSON {"decision":"block","reason":"..."}
|
|
11
|
+
# - allow: exit 0 + stdout {} (or empty)
|
|
12
|
+
# - any other exit code is treated as pass; never exit 1 to block
|
|
9
13
|
#
|
|
10
|
-
|
|
11
|
-
|
|
14
|
+
# Env opt-outs (allow legitimate overrides):
|
|
15
|
+
# MERLIN_SKIP_FILE_SIZE_CHECK=1 — skip entirely
|
|
16
|
+
# MERLIN_FILE_SIZE_LIMIT=N — override 400 default
|
|
12
17
|
|
|
13
|
-
|
|
14
|
-
|
|
18
|
+
set -uo pipefail
|
|
19
|
+
# NO `set -e` and NO ERR trap — explicit exit codes only, so a stray non-zero
|
|
20
|
+
# step (e.g. a grep that finds nothing) doesn't accidentally short-circuit the
|
|
21
|
+
# decision.
|
|
15
22
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
exit 0
|
|
32
|
-
;;
|
|
33
|
-
esac
|
|
23
|
+
allow() { echo '{}'; exit 0; }
|
|
24
|
+
block() {
|
|
25
|
+
local reason="$1"
|
|
26
|
+
# Escape backslashes and double quotes for JSON.
|
|
27
|
+
local escaped="${reason//\\/\\\\}"
|
|
28
|
+
escaped="${escaped//\"/\\\"}"
|
|
29
|
+
escaped="${escaped//$'\n'/\\n}"
|
|
30
|
+
printf '{"decision":"block","reason":"%s"}\n' "$escaped"
|
|
31
|
+
exit 0
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
# Opt-out via env
|
|
35
|
+
[ "${MERLIN_SKIP_FILE_SIZE_CHECK:-0}" = "1" ] && allow
|
|
36
|
+
|
|
37
|
+
LIMIT="${MERLIN_FILE_SIZE_LIMIT:-400}"
|
|
34
38
|
|
|
35
|
-
# Read
|
|
36
|
-
|
|
39
|
+
# Read stdin (defensive: never block on TTY)
|
|
40
|
+
INPUT=""
|
|
37
41
|
if [ ! -t 0 ]; then
|
|
38
|
-
|
|
42
|
+
INPUT=$(cat 2>/dev/null || true)
|
|
39
43
|
fi
|
|
44
|
+
[ -z "$INPUT" ] && allow
|
|
40
45
|
|
|
41
|
-
#
|
|
42
|
-
|
|
43
|
-
if [ -n "$input" ] && command -v jq >/dev/null 2>&1; then
|
|
44
|
-
file_path=$(echo "$input" | jq -r '.tool_input.file_path // .tool_input.path // empty' 2>/dev/null || true)
|
|
45
|
-
fi
|
|
46
|
+
# Need python3 for reliable JSON parsing + line counting. If missing, allow.
|
|
47
|
+
command -v python3 >/dev/null 2>&1 || allow
|
|
46
48
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
echo '{}'
|
|
50
|
-
exit 0
|
|
51
|
-
fi
|
|
49
|
+
RESULT=$(MERLIN_LIMIT="$LIMIT" python3 - "$INPUT" <<'PYEOF' 2>/dev/null || echo "ERROR"
|
|
50
|
+
import sys, json, os, fnmatch, re
|
|
52
51
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
*node_modules*|*.git/*) echo '{}'; exit 0 ;;
|
|
58
|
-
esac
|
|
52
|
+
try:
|
|
53
|
+
payload = json.loads(sys.argv[1])
|
|
54
|
+
except Exception:
|
|
55
|
+
print("ALLOW||json-error"); sys.exit(0)
|
|
59
56
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
57
|
+
limit = int(os.environ.get("MERLIN_LIMIT", "400"))
|
|
58
|
+
tool = payload.get("tool_name", "")
|
|
59
|
+
ti = payload.get("tool_input") or {}
|
|
60
|
+
fp = ti.get("file_path") or ""
|
|
63
61
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
62
|
+
IGNORE_GLOBS = [
|
|
63
|
+
"*.lock", "*-lock.json", "pnpm-lock.yaml", "yarn.lock", "bun.lockb",
|
|
64
|
+
"Cargo.lock", "Pipfile.lock", "composer.lock", "Gemfile.lock",
|
|
65
|
+
"*.min.*", "*.bundle.*",
|
|
66
|
+
"*.svg", "*.png", "*.jpg", "*.jpeg", "*.gif", "*.ico", "*.webp", "*.pdf",
|
|
67
|
+
"*.woff", "*.woff2", "*.ttf", "*.eot",
|
|
68
|
+
"*.snap", "*.csv", "*.tsv",
|
|
69
|
+
"*.md",
|
|
70
|
+
]
|
|
71
|
+
IGNORE_PATH_SUBSTRINGS = [
|
|
72
|
+
"/node_modules/", "/dist/", "/build/", "/.next/", "/.git/", "/out/",
|
|
73
|
+
"/coverage/", "/.vite/", "/migrations/", "/__fixtures__/", "/fixtures/",
|
|
74
|
+
"/__snapshots__/",
|
|
75
|
+
]
|
|
76
|
+
|
|
77
|
+
def is_ignored(path):
|
|
78
|
+
if not path: return True
|
|
79
|
+
base = os.path.basename(path).lower()
|
|
80
|
+
for g in IGNORE_GLOBS:
|
|
81
|
+
if fnmatch.fnmatchcase(base, g.lower()): return True
|
|
82
|
+
norm = path.replace("\\", "/")
|
|
83
|
+
for s in IGNORE_PATH_SUBSTRINGS:
|
|
84
|
+
if s in norm: return True
|
|
85
|
+
return False
|
|
86
|
+
|
|
87
|
+
if is_ignored(fp):
|
|
88
|
+
print("ALLOW||ignored"); sys.exit(0)
|
|
89
|
+
|
|
90
|
+
def read_existing():
|
|
91
|
+
try:
|
|
92
|
+
with open(fp, "r", encoding="utf-8") as f:
|
|
93
|
+
return f.read()
|
|
94
|
+
except Exception:
|
|
95
|
+
return ""
|
|
70
96
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
97
|
+
if tool == "Write":
|
|
98
|
+
new_content = ti.get("content") or ""
|
|
99
|
+
elif tool == "Edit":
|
|
100
|
+
existing = read_existing()
|
|
101
|
+
old = ti.get("old_string", "")
|
|
102
|
+
new = ti.get("new_string", "")
|
|
103
|
+
if not existing:
|
|
104
|
+
new_content = new
|
|
105
|
+
elif ti.get("replace_all"):
|
|
106
|
+
new_content = existing.replace(old, new)
|
|
107
|
+
else:
|
|
108
|
+
new_content = existing.replace(old, new, 1)
|
|
109
|
+
elif tool == "MultiEdit":
|
|
110
|
+
cur = read_existing()
|
|
111
|
+
for e in ti.get("edits") or []:
|
|
112
|
+
old = e.get("old_string", "")
|
|
113
|
+
new = e.get("new_string", "")
|
|
114
|
+
if e.get("replace_all"):
|
|
115
|
+
cur = cur.replace(old, new)
|
|
116
|
+
else:
|
|
117
|
+
cur = cur.replace(old, new, 1)
|
|
118
|
+
new_content = cur
|
|
119
|
+
else:
|
|
120
|
+
print("ALLOW||unknown-tool"); sys.exit(0)
|
|
121
|
+
|
|
122
|
+
# Opt-out marker scan (first 50 + last 50 lines — let big middles still trigger)
|
|
123
|
+
lines = new_content.split("\n")
|
|
124
|
+
loc = len(lines)
|
|
125
|
+
if loc > 100:
|
|
126
|
+
sample = "\n".join(lines[:50] + lines[-50:])
|
|
127
|
+
else:
|
|
128
|
+
sample = new_content
|
|
129
|
+
marker = re.search(r"merlin:allow-large-file:\s*([^\n\r]*)", sample)
|
|
130
|
+
if marker:
|
|
131
|
+
reason = marker.group(1).strip()[:200].replace("|", "/")
|
|
132
|
+
print(f"ALLOW||marker:{reason}"); sys.exit(0)
|
|
133
|
+
|
|
134
|
+
if loc > limit:
|
|
135
|
+
print(f"BLOCK||{loc}||{fp}"); sys.exit(0)
|
|
136
|
+
|
|
137
|
+
print(f"ALLOW||{loc}"); sys.exit(0)
|
|
138
|
+
PYEOF
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
# Defensive: any python error → allow
|
|
142
|
+
[ "$RESULT" = "ERROR" ] && allow
|
|
143
|
+
[ -z "$RESULT" ] && allow
|
|
144
|
+
|
|
145
|
+
ACTION="${RESULT%%||*}"
|
|
146
|
+
|
|
147
|
+
case "$ACTION" in
|
|
148
|
+
BLOCK)
|
|
149
|
+
REST="${RESULT#BLOCK||}"
|
|
150
|
+
LOC_COUNT="${REST%%||*}"
|
|
151
|
+
FILE_PATH="${REST#*||}"
|
|
152
|
+
REASON="File ${FILE_PATH} would be ${LOC_COUNT} LOC, exceeding the ${LIMIT}-LOC project rule.
|
|
153
|
+
|
|
154
|
+
To proceed, either:
|
|
155
|
+
|
|
156
|
+
1. REFACTOR — split this file into smaller modules by feature.
|
|
157
|
+
• Invoke the code-organization-supervisor agent for proposed splits
|
|
158
|
+
• Run /merlin:check-size to scan the whole repo for offenders
|
|
159
|
+
|
|
160
|
+
2. JUSTIFY — add this comment in the first 50 lines of the file:
|
|
161
|
+
// merlin:allow-large-file: <one-line reason this file must stay long>
|
|
162
|
+
(Python/shell: # merlin:allow-large-file: <reason>)
|
|
163
|
+
(CSS: /* merlin:allow-large-file: <reason> */)
|
|
164
|
+
(HTML/JSX: <!-- merlin:allow-large-file: <reason> -->)
|
|
165
|
+
The reason is your audit trail — make it specific (e.g. 'generated by codegen', 'single-source-of-truth lookup table', 'vendored library').
|
|
166
|
+
|
|
167
|
+
Override per-session: MERLIN_SKIP_FILE_SIZE_CHECK=1
|
|
168
|
+
Override limit: MERLIN_FILE_SIZE_LIMIT=600"
|
|
169
|
+
block "$REASON"
|
|
170
|
+
;;
|
|
171
|
+
ALLOW)
|
|
172
|
+
REST="${RESULT#ALLOW||}"
|
|
173
|
+
if [[ "$REST" == marker:* ]]; then
|
|
174
|
+
echo "[merlin] Allowed large file with marker: ${REST#marker:}" >&2
|
|
175
|
+
fi
|
|
176
|
+
allow
|
|
177
|
+
;;
|
|
178
|
+
*)
|
|
179
|
+
allow
|
|
180
|
+
;;
|
|
181
|
+
esac
|
|
@@ -34,4 +34,6 @@ wait
|
|
|
34
34
|
|
|
35
35
|
TASK OPTIMIZATION: Before EVERY routing decision (workflows, agents, specialists), run ~/.claude/scripts/task-optimize.sh --task "<user text>". It returns {intent, skills[], agent, score, matched_phrases}. If score>=25, ALWAYS announce "⟡🔮 MERLIN › Intent: <X>. Loading <skills> + routing to <agent>." then route with skills prepended to context. Registry: ~/.claude/merlin/skills/TASK-OPTIMIZER.json. Slash commands /merlin:optimize, /merlin:design-audit, /merlin:polish, /merlin:redesign wrap common flows.
|
|
36
36
|
|
|
37
|
-
DISCOVERY-FIRST: Before routing any non-trivial task to a built-in specialist, call `merlin_smart_route(task="...")` and `merlin_discover_agents(query="...")` to check the community catalog (1000+ indexed agents/skills). If a catalog match scores a higher grade (A+/A++) than the best built-in for the task, surface it: "⟡🔮 MERLIN › I found a community agent that fits better: <name> (Grade: <X>). Install with /merlin:install <slug> or stick with built-in <built-in>?" — then wait for user choice. NEVER install without confirmation. Skip discovery only for: trivial single-file edits, debug runs, doc updates, or when the user explicitly names an agent.
|
|
37
|
+
DISCOVERY-FIRST: Before routing any non-trivial task to a built-in specialist, call `merlin_smart_route(task="...")` and `merlin_discover_agents(query="...")` to check the community catalog (1000+ indexed agents/skills). If a catalog match scores a higher grade (A+/A++) than the best built-in for the task, surface it: "⟡🔮 MERLIN › I found a community agent that fits better: <name> (Grade: <X>). Install with /merlin:install <slug> or stick with built-in <built-in>?" — then wait for user choice. NEVER install without confirmation. Skip discovery only for: trivial single-file edits, debug runs, doc updates, or when the user explicitly names an agent.
|
|
38
|
+
|
|
39
|
+
FILE-SIZE ENFORCEMENT: Every Write/Edit/MultiEdit is blocked by ~/.claude/hooks/check-file-size.sh if the resulting file exceeds 400 LOC (configurable via MERLIN_FILE_SIZE_LIMIT). When blocked, EITHER refactor into smaller modules (preferred) OR add `// merlin:allow-large-file: <one-line reason>` in the first 50 lines if the size is genuinely justified (e.g., generated code, big lookup table, single-file library). Use /merlin:check-size to scan the whole repo at any time.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-merlin-brain",
|
|
3
|
-
"version": "5.3.
|
|
3
|
+
"version": "5.3.8",
|
|
4
4
|
"description": "Merlin - The Ultimate AI Brain for Claude Code, Codex, and other AI CLIs. One install: workflows, agents, loop, and Sights MCP server.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/server/index.js",
|