create-merlin-brain 5.4.2 → 5.4.4
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
CHANGED
|
@@ -1400,20 +1400,16 @@ async function install() {
|
|
|
1400
1400
|
// clean up existing prompt hooks from previous installs.
|
|
1401
1401
|
// ═══════════════════════════════════════════════════════════════
|
|
1402
1402
|
|
|
1403
|
-
// Configure Merlin
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
const
|
|
1410
|
-
|
|
1411
|
-
)
|
|
1412
|
-
|
|
1413
|
-
settings.statusline.items.push({
|
|
1414
|
-
command: 'bash -c \'echo "⟡🔮 MERLIN"\'',
|
|
1415
|
-
interval: 30
|
|
1416
|
-
});
|
|
1403
|
+
// Configure Merlin statusLine — the ALWAYS-ON purple Merlin presence.
|
|
1404
|
+
// Claude Code uses `statusLine` (camelCase): a command whose plain-text
|
|
1405
|
+
// stdout is rendered. The old lowercase `statusline.items` block was a no-op
|
|
1406
|
+
// (not a format Claude Code reads), so Merlin never actually appeared.
|
|
1407
|
+
// Wire up the real command, but never clobber a user's custom statusLine.
|
|
1408
|
+
if (settings.statusline) delete settings.statusline; // remove legacy no-op
|
|
1409
|
+
const merlinStatusCmd = 'sh ~/.claude/scripts/merlin-statusline.sh';
|
|
1410
|
+
const existingStatus = settings.statusLine && settings.statusLine.command;
|
|
1411
|
+
if (!existingStatus || existingStatus.includes('merlin-statusline')) {
|
|
1412
|
+
settings.statusLine = { type: 'command', command: merlinStatusCmd };
|
|
1417
1413
|
}
|
|
1418
1414
|
|
|
1419
1415
|
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: merlin:duo
|
|
3
|
+
description: Toggle and inspect Merlin's duo mode — parallel + sequential dual-brain (Claude+Codex or twin-Claude) execution. Subcommands: on, off, status, unsuppress, offer.
|
|
4
|
+
argument-hint: "[on|off|status|unsuppress|offer]"
|
|
5
|
+
allowed-tools:
|
|
6
|
+
- Bash
|
|
7
|
+
- Read
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
<objective>
|
|
11
|
+
Manage Merlin's duo mode. Duo runs two brains on the same task — parallel for
|
|
12
|
+
plans/docs/review/tests, sequential for code write/modify — with an arbiter
|
|
13
|
+
merging or a decider gating. This command is the registered entry point for
|
|
14
|
+
`/merlin:duo` and `Skill("merlin:duo", args="…")`.
|
|
15
|
+
|
|
16
|
+
State lives in `~/.claude/merlin-state/duo-mode.json` (24h auto-expire). The
|
|
17
|
+
canonical routing rules are `~/.claude/rules/duo-routing.md` — this command only
|
|
18
|
+
toggles/inspects state; it does not duplicate routing logic.
|
|
19
|
+
</objective>
|
|
20
|
+
|
|
21
|
+
<dispatch>
|
|
22
|
+
Parse the argument (default to `status` when none is given) and run the matching
|
|
23
|
+
section. Each section drives the shell scripts under `~/.claude/scripts/`; the
|
|
24
|
+
detailed prose for each lives in `~/.claude/merlin/skills/duo/<sub>.md`.
|
|
25
|
+
|
|
26
|
+
- `on` → enable duo (see Step: ON)
|
|
27
|
+
- `off` → disable duo (see Step: OFF)
|
|
28
|
+
- `status` → report state (see Step: STATUS)
|
|
29
|
+
- `unsuppress`→ clear suppression memory (see Step: UNSUPPRESS)
|
|
30
|
+
- `offer` → present the duo opt-in for a risky task (see Step: OFFER)
|
|
31
|
+
</dispatch>
|
|
32
|
+
|
|
33
|
+
<step name="ON">
|
|
34
|
+
## ON
|
|
35
|
+
1. `~/.claude/scripts/duo-mode-read.sh` — if it prints `enabled`, duo is already on; show status and stop.
|
|
36
|
+
2. Detect pair: `~/.claude/scripts/codex-installed.sh` (exit 0 → `claude+codex`, else `claude+claude`); `MERLIN_RUNTIME=codex` → `codex+codex`.
|
|
37
|
+
3. Enable: `~/.claude/scripts/duo-mode-write.sh on "<the user phrase that triggered enable>" "$PAIR"`.
|
|
38
|
+
4. Compute badge with `~/.claude/scripts/duo-badge.sh` and emit the pair-specific confirmation block from `~/.claude/merlin/skills/duo/on.md`.
|
|
39
|
+
5. If `codex-mode.json` is also enabled, append: `(codex-mode also active — duo wins per precedence rule)`.
|
|
40
|
+
</step>
|
|
41
|
+
|
|
42
|
+
<step name="OFF">
|
|
43
|
+
## OFF
|
|
44
|
+
1. `~/.claude/scripts/duo-mode-write.sh off "<the user phrase that triggered disable>"`.
|
|
45
|
+
2. Check `~/.claude/merlin-state/codex-mode.json`.
|
|
46
|
+
3. Emit: if codex-mode still active → `⟡🔮 MERLIN › Duo off. (codex-mode is still active.)`; otherwise → `⟡🔮 MERLIN › Duo off. Back to solo routing.`
|
|
47
|
+
</step>
|
|
48
|
+
|
|
49
|
+
<step name="STATUS">
|
|
50
|
+
## STATUS
|
|
51
|
+
Follow `~/.claude/merlin/skills/duo/status.md`: parse `duo-mode.json` with 24h
|
|
52
|
+
expiry logic, check the Codex install gate, parse `duo-suppress.json`, and emit
|
|
53
|
+
ON / OFF / AUTO-EXPIRED plus gate + suppression lines. Always prefix with the
|
|
54
|
+
badge from `~/.claude/scripts/duo-badge.sh`.
|
|
55
|
+
</step>
|
|
56
|
+
|
|
57
|
+
<step name="UNSUPPRESS">
|
|
58
|
+
## UNSUPPRESS
|
|
59
|
+
Follow `~/.claude/merlin/skills/duo/unsuppress.md` to clear `session_skip`,
|
|
60
|
+
`never_for_intents`, and `task_hashes_declined` in `duo-suppress.json`, then
|
|
61
|
+
confirm what was cleared.
|
|
62
|
+
</step>
|
|
63
|
+
|
|
64
|
+
<step name="OFFER">
|
|
65
|
+
## OFFER
|
|
66
|
+
Follow `~/.claude/merlin/skills/duo/offer.md`: present the one-shot duo opt-in
|
|
67
|
+
for a risky task, record the user's choice in `duo-suppress.json`, and route
|
|
68
|
+
accordingly. Never offer mid-flight or more than once per task.
|
|
69
|
+
</step>
|
|
70
|
+
|
|
71
|
+
<notes>
|
|
72
|
+
- Badge: ALWAYS prefix output with `~/.claude/scripts/duo-badge.sh` output (`⟡🔮↔🔮 MERLIN·DUO ›` when on, `⟡🔮 MERLIN ›` when off).
|
|
73
|
+
- The gate authority `reviewer-decider` is Claude-only and must never run via `codex-as.sh`.
|
|
74
|
+
- If a script is missing, fall back to writing `duo-mode.json` directly per the schema in `duo-routing.md` and say so — do not silently no-op.
|
|
75
|
+
</notes>
|
|
@@ -286,7 +286,7 @@ _badge_prefix=$(echo "${_badge}" | sed 's/MERLIN.*//' 2>/dev/null || true)
|
|
|
286
286
|
_banner="${_badge_prefix}MERLIN · connected · ${_project_name} | Mode: ${_mode_label} · Codex: ${_codex_label} | Next: ${_next_action}"
|
|
287
287
|
|
|
288
288
|
# ── 4b. Build the additionalContext with banner + routing rules ─
|
|
289
|
-
_context="${_banner} || STOP. Your FIRST action must be: call
|
|
289
|
+
_context="${_banner} || STOP. Your FIRST action must be the Merlin boot sequence. Merlin tools are MCP tools and may be DEFERRED in this harness (not directly callable until loaded). If a Merlin tool is not directly callable, FIRST run ToolSearch with query select:mcp__merlin__merlin_get_selected_repo,mcp__merlin__merlin_get_project_status,mcp__merlin__merlin_get_rules,mcp__merlin__merlin_get_brief to load them. Then call mcp__merlin__merlin_get_selected_repo, then mcp__merlin__merlin_get_project_status, then mcp__merlin__merlin_get_rules and mcp__merlin__merlin_get_brief in parallel. Never conclude Merlin is broken from a No such tool available miss — load via ToolSearch and retry by full mcp__merlin__ name. Do not respond to the user until you complete the boot sequence."
|
|
290
290
|
_context="${_context} AFTER BOOT — MANDATORY ROUTING (you MUST follow this, do NOT skip):"
|
|
291
291
|
_context="${_context} Bug/crash/error logs/deploy failure: use Skill(merlin:workflow, args=run bug-fix <summary>)."
|
|
292
292
|
_context="${_context} Build feature/add feature: use Skill(merlin:workflow, args=run feature-dev <summary>)."
|
|
@@ -303,7 +303,7 @@ if command -v jq >/dev/null 2>&1; then
|
|
|
303
303
|
jq -n --arg ctx "$_context" '{hookSpecificOutput:{hookEventName:"SessionStart",additionalContext:$ctx}}'
|
|
304
304
|
else
|
|
305
305
|
# Fallback: simple printf with no special chars
|
|
306
|
-
printf '{"hookSpecificOutput":{"hookEventName":"SessionStart","additionalContext":"STOP.
|
|
306
|
+
printf '{"hookSpecificOutput":{"hookEventName":"SessionStart","additionalContext":"STOP. Merlin tools are MCP tools and may be deferred. If not directly callable, first run ToolSearch with query select:mcp__merlin__merlin_get_selected_repo,mcp__merlin__merlin_get_project_status,mcp__merlin__merlin_get_rules,mcp__merlin__merlin_get_brief then call mcp__merlin__merlin_get_selected_repo, mcp__merlin__merlin_get_project_status, mcp__merlin__merlin_get_rules and mcp__merlin__merlin_get_brief in parallel. Never conclude Merlin is broken from a No such tool available miss. After boot, route to workflows not manual work.%s"}}\n' "${_voice_note}"
|
|
307
307
|
fi
|
|
308
308
|
|
|
309
309
|
exit 0
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
MANDATORY: You are Merlin, an orchestrator. Before processing any user request, call merlin_get_selected_repo, merlin_get_project_status, merlin_get_rules and merlin_get_brief. Route ALL implementation work to specialist agents via Skill("merlin:workflow") or merlin_route(). NEVER write, edit, or debug code yourself. Prefix every action with the badge from ~/.claude/scripts/duo-badge.sh (solo: ⟡🔮 MERLIN ›, duo: ⟡🔮↔🔮 MERLIN·DUO ›). Run independent agents in PARALLEL. Before editing code, call merlin_get_context first.
|
|
1
|
+
MANDATORY: You are Merlin, an orchestrator. Before processing any user request, run the boot sequence: call merlin_get_selected_repo, merlin_get_project_status, merlin_get_rules and merlin_get_brief. These are MCP tools — in some harnesses they are exposed as mcp__merlin__merlin_<name> and/or are DEFERRED (not directly callable until loaded). If a call fails with "No such tool available", first load them via ToolSearch with query select:mcp__merlin__merlin_get_selected_repo,mcp__merlin__merlin_get_project_status,mcp__merlin__merlin_get_rules,mcp__merlin__merlin_get_brief, then retry by full name — never conclude Merlin is broken from a bare-name miss. Route ALL implementation work to specialist agents via Skill("merlin:workflow") or merlin_route(). NEVER write, edit, or debug code yourself. Prefix every action with the badge from ~/.claude/scripts/duo-badge.sh (solo: ⟡🔮 MERLIN ›, duo: ⟡🔮↔🔮 MERLIN·DUO ›). Run independent agents in PARALLEL. Before editing code, call merlin_get_context first.
|
|
2
2
|
|
|
3
3
|
## Duo mode (codex+codex)
|
|
4
4
|
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# Merlin statusLine command — PLAIN TEXT output for Claude Code's `statusLine`.
|
|
3
|
+
#
|
|
4
|
+
# Always-on, model-independent "is Merlin active?" indicator: a purple Merlin
|
|
5
|
+
# badge (duo-aware) + version, followed by the live model / dir / context%.
|
|
6
|
+
# Unlike the in-chat badge (which is model behavior and drifts), this renders on
|
|
7
|
+
# every status refresh regardless of what the model does.
|
|
8
|
+
#
|
|
9
|
+
# IMPORTANT: Claude Code's statusLine takes the command's STDOUT as literal text
|
|
10
|
+
# (ANSI allowed). Do NOT emit JSON here — that is the Notification-hook format
|
|
11
|
+
# (see hooks/statusline.sh), which Claude Code would print verbatim.
|
|
12
|
+
#
|
|
13
|
+
# Reads session JSON from stdin. Local files only — no network. Fast (<100ms).
|
|
14
|
+
|
|
15
|
+
input=$(cat)
|
|
16
|
+
|
|
17
|
+
# ── parse stdin (jq if present, grep fallback) ──
|
|
18
|
+
if command -v jq >/dev/null 2>&1; then
|
|
19
|
+
model=$(printf '%s' "$input" | jq -r '.model.display_name // "Claude"' 2>/dev/null)
|
|
20
|
+
cwd=$(printf '%s' "$input" | jq -r '.workspace.current_dir // .cwd // ""' 2>/dev/null)
|
|
21
|
+
used=$(printf '%s' "$input" | jq -r '.context_window.used_percentage // empty' 2>/dev/null)
|
|
22
|
+
else
|
|
23
|
+
model=$(printf '%s' "$input" | grep -o '"display_name":"[^"]*"' | head -1 | cut -d'"' -f4)
|
|
24
|
+
cwd=$(printf '%s' "$input" | grep -o '"current_dir":"[^"]*"' | head -1 | cut -d'"' -f4)
|
|
25
|
+
used=""
|
|
26
|
+
fi
|
|
27
|
+
[ -z "$model" ] && model="Claude"
|
|
28
|
+
dir=$(basename "$cwd" 2>/dev/null)
|
|
29
|
+
[ -z "$dir" ] && dir="project"
|
|
30
|
+
|
|
31
|
+
# ── Merlin badge (duo-aware) ──
|
|
32
|
+
badge="⟡🔮 MERLIN ›"
|
|
33
|
+
if [ -x "$HOME/.claude/scripts/duo-badge.sh" ]; then
|
|
34
|
+
b=$("$HOME/.claude/scripts/duo-badge.sh" 2>/dev/null)
|
|
35
|
+
[ -n "$b" ] && badge="$b"
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
# ── version (best-effort) ──
|
|
39
|
+
mver=""
|
|
40
|
+
if [ -f "$HOME/.claude/merlin/VERSION" ]; then
|
|
41
|
+
v=$(cat "$HOME/.claude/merlin/VERSION" 2>/dev/null)
|
|
42
|
+
[ -n "$v" ] && mver=" \033[90mv${v}\033[0m"
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
# ── context% indicator (green/yellow/red) ──
|
|
46
|
+
ctx_part=""
|
|
47
|
+
if [ -n "$used" ]; then
|
|
48
|
+
ui=$(printf "%.0f" "$used" 2>/dev/null)
|
|
49
|
+
if [ -n "$ui" ]; then
|
|
50
|
+
if [ "$ui" -ge 80 ] 2>/dev/null; then
|
|
51
|
+
ctx_part=" \033[31m${ui}%ctx\033[0m"
|
|
52
|
+
elif [ "$ui" -ge 50 ] 2>/dev/null; then
|
|
53
|
+
ctx_part=" \033[33m${ui}%ctx\033[0m"
|
|
54
|
+
else
|
|
55
|
+
ctx_part=" \033[32m${ui}%ctx\033[0m"
|
|
56
|
+
fi
|
|
57
|
+
fi
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
# Bold magenta badge leads so the purple Merlin icon is always visible.
|
|
61
|
+
printf "\033[1;35m%s\033[0m%s \033[90m·\033[0m \033[36m%s\033[0m \033[90m%s\033[0m%s" \
|
|
62
|
+
"$badge" "$mver" "$model" "$dir" "$ctx_part"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-merlin-brain",
|
|
3
|
-
"version": "5.4.
|
|
3
|
+
"version": "5.4.4",
|
|
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",
|