create-merlin-brain 3.5.2 → 3.5.3
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 +30 -23
- package/files/hooks/session-start.sh +61 -9
- package/package.json +1 -1
package/bin/install.cjs
CHANGED
|
@@ -937,15 +937,18 @@ async function install() {
|
|
|
937
937
|
return hookArray;
|
|
938
938
|
};
|
|
939
939
|
|
|
940
|
-
// SessionStart
|
|
940
|
+
// SessionStart: single consolidated hook (analytics + agent sync + context injection)
|
|
941
|
+
// Previously this was 3 separate hooks, causing 3x "startup hook success" messages.
|
|
942
|
+
// Now consolidated into session-start.sh which handles all three concerns.
|
|
941
943
|
settings.hooks.SessionStart = settings.hooks.SessionStart || [];
|
|
942
|
-
|
|
943
|
-
|
|
944
|
+
// Remove old separate hooks if present (from previous installs)
|
|
945
|
+
settings.hooks.SessionStart = settings.hooks.SessionStart.filter(entry => {
|
|
946
|
+
const cmd = entry.hooks?.[0]?.command || '';
|
|
947
|
+
if (cmd.includes('agent-sync.sh') || cmd.includes('session-start-context.sh')) return false;
|
|
948
|
+
return true;
|
|
944
949
|
});
|
|
945
|
-
|
|
946
|
-
// SessionStart hook: Agent sync (background, runs at most once/hour)
|
|
947
950
|
addHookIfMissing(settings.hooks.SessionStart, {
|
|
948
|
-
hooks: [{ type: 'command', command: 'bash ~/.claude/hooks/
|
|
951
|
+
hooks: [{ type: 'command', command: 'bash ~/.claude/hooks/session-start.sh' }]
|
|
949
952
|
});
|
|
950
953
|
|
|
951
954
|
// PreToolUse hook (Edit/Write only)
|
|
@@ -1001,29 +1004,33 @@ async function install() {
|
|
|
1001
1004
|
settings.hooks.TaskCompleted = settings.hooks.TaskCompleted || [];
|
|
1002
1005
|
settings.hooks.TaskCompleted = removeAllPromptHooks(settings.hooks.TaskCompleted);
|
|
1003
1006
|
|
|
1004
|
-
// Now add fresh hooks in new format
|
|
1005
|
-
// NOTE: SessionStart does NOT support prompt hooks (only command hooks).
|
|
1006
|
-
// The Merlin boot sequence is handled via CLAUDE.md instructions instead.
|
|
1007
|
-
// We use a command hook to inject additionalContext at session start.
|
|
1008
|
-
addHookIfMissing(settings.hooks.SessionStart, {
|
|
1009
|
-
hooks: [{ type: 'command', command: 'bash ~/.claude/hooks/session-start-context.sh' }]
|
|
1010
|
-
});
|
|
1011
|
-
|
|
1012
1007
|
// NOTE: The PreToolUse prompt hook has been REMOVED. It caused an infinite
|
|
1013
1008
|
// rejection loop because the evaluator model cannot see conversation history
|
|
1014
1009
|
// to verify whether merlin_get_context was called. The command-type hook
|
|
1015
1010
|
// (pre-edit-sights-check.sh) handles advisory logging instead.
|
|
1016
1011
|
// Sights enforcement is done via CLAUDE.md instructions, not hook blocking.
|
|
1017
1012
|
|
|
1018
|
-
//
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
//
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1013
|
+
// ═══════════════════════════════════════════════════════════════
|
|
1014
|
+
// PROMPT HOOKS PERMANENTLY REMOVED (v3.5.3)
|
|
1015
|
+
// ═══════════════════════════════════════════════════════════════
|
|
1016
|
+
// Stop and TaskCompleted prompt hooks have been REMOVED because:
|
|
1017
|
+
//
|
|
1018
|
+
// 1. The evaluator model (Haiku) frequently wraps JSON responses
|
|
1019
|
+
// in markdown code fences or adds explanatory text, causing
|
|
1020
|
+
// "JSON validation failed" errors on every session stop.
|
|
1021
|
+
//
|
|
1022
|
+
// 2. This is inherent to prompt-type hooks — they depend on a
|
|
1023
|
+
// small model producing byte-perfect JSON output, which is
|
|
1024
|
+
// unreliable.
|
|
1025
|
+
//
|
|
1026
|
+
// 3. Stop behavior is already governed by CLAUDE.md instructions.
|
|
1027
|
+
// Task completion verification is handled by the session's own
|
|
1028
|
+
// Claude instance, which has full conversation context (unlike
|
|
1029
|
+
// the tiny evaluator model).
|
|
1030
|
+
//
|
|
1031
|
+
// The removeAllPromptHooks() calls above (lines ~996-1002) will
|
|
1032
|
+
// clean up existing prompt hooks from previous installs.
|
|
1033
|
+
// ═══════════════════════════════════════════════════════════════
|
|
1027
1034
|
|
|
1028
1035
|
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
1029
1036
|
logSuccess('Configured hooks in settings.local.json');
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
#
|
|
3
|
-
# Merlin Hook: SessionStart
|
|
4
|
-
#
|
|
3
|
+
# Merlin Hook: SessionStart (consolidated)
|
|
4
|
+
# Does three things in a single hook (avoids 3x "success" messages):
|
|
5
|
+
# 1. Analytics: initialize session, log start event
|
|
6
|
+
# 2. Agent sync: refresh agent files from cloud (background, max once/hour)
|
|
7
|
+
# 3. Context injection: output additionalContext for the session
|
|
8
|
+
#
|
|
5
9
|
# Always exits 0 — never blocks Claude Code startup.
|
|
6
10
|
#
|
|
7
11
|
set -euo pipefail
|
|
@@ -9,25 +13,73 @@ trap 'echo "{}"; exit 0' ERR
|
|
|
9
13
|
|
|
10
14
|
HOOKS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
15
|
|
|
12
|
-
#
|
|
16
|
+
# ── 1. Analytics ────────────────────────────────────────────────
|
|
13
17
|
# shellcheck source=lib/analytics.sh
|
|
14
18
|
. "${HOOKS_DIR}/lib/analytics.sh"
|
|
15
19
|
# shellcheck source=lib/sights-check.sh
|
|
16
20
|
. "${HOOKS_DIR}/lib/sights-check.sh"
|
|
17
21
|
|
|
18
|
-
# Initialize analytics session
|
|
19
22
|
ensure_session_file
|
|
20
|
-
|
|
21
|
-
# Log session start with working directory
|
|
22
23
|
cwd="${PWD:-$(pwd)}"
|
|
23
24
|
log_event "session_start" "$(printf '{"cwd":"%s"}' "$cwd")"
|
|
24
25
|
|
|
25
|
-
#
|
|
26
|
+
# Warm up Sights context in background
|
|
26
27
|
if command -v merlin >/dev/null 2>&1; then
|
|
27
28
|
merlin context "session start" >/dev/null 2>&1 &
|
|
28
29
|
record_sights_call
|
|
29
30
|
fi
|
|
30
31
|
|
|
31
|
-
#
|
|
32
|
-
|
|
32
|
+
# ── 2. Agent sync (background, max once/hour) ──────────────────
|
|
33
|
+
_merlin_sync_agents() {
|
|
34
|
+
local agents_dir="${HOME}/.claude/agents"
|
|
35
|
+
local merlin_dir="${HOME}/.claude/merlin"
|
|
36
|
+
local last_sync="${merlin_dir}/.last-agent-sync"
|
|
37
|
+
local api_url="${MERLIN_API_URL:-https://api.merlin.build}"
|
|
38
|
+
|
|
39
|
+
[ -d "${agents_dir}" ] || return 0
|
|
40
|
+
|
|
41
|
+
# Skip if synced within the last hour
|
|
42
|
+
if [ -f "${last_sync}" ]; then
|
|
43
|
+
local last
|
|
44
|
+
last=$(cat "${last_sync}" 2>/dev/null || echo "0")
|
|
45
|
+
[ $(($(date +%s) - last)) -lt 3600 ] && return 0
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
local installed=""
|
|
49
|
+
for f in "${agents_dir}"/*.md; do
|
|
50
|
+
[ -f "${f}" ] || continue
|
|
51
|
+
local name hash
|
|
52
|
+
name=$(basename "${f}" .md)
|
|
53
|
+
hash=$(md5sum "${f}" 2>/dev/null | cut -c1-8 || md5 -q "${f}" 2>/dev/null | cut -c1-8 || echo "unknown")
|
|
54
|
+
installed="${installed}${name}:${hash},"
|
|
55
|
+
done
|
|
56
|
+
|
|
57
|
+
local response
|
|
58
|
+
response=$(curl -s --max-time 5 "${api_url}/api/agents-sync/check?installed=${installed}" 2>/dev/null) || return 0
|
|
59
|
+
local stale_names
|
|
60
|
+
stale_names=$(echo "${response}" | grep -o '"name":"[^"]*"' | sed 's/"name":"//;s/"//' 2>/dev/null) || return 0
|
|
61
|
+
[ -z "${stale_names}" ] && { date +%s > "${last_sync}"; return 0; }
|
|
62
|
+
|
|
63
|
+
for agent_name in ${stale_names}; do
|
|
64
|
+
local content md_content
|
|
65
|
+
content=$(curl -s --max-time 5 "${api_url}/api/agents-sync/${agent_name}" 2>/dev/null) || continue
|
|
66
|
+
md_content=$(echo "${content}" | python3 -c "import sys,json;print(json.load(sys.stdin).get('content',''))" 2>/dev/null) || continue
|
|
67
|
+
[ -n "${md_content}" ] && echo "${md_content}" > "${agents_dir}/${agent_name}.md"
|
|
68
|
+
done
|
|
69
|
+
date +%s > "${last_sync}"
|
|
70
|
+
}
|
|
71
|
+
_merlin_sync_agents &
|
|
72
|
+
|
|
73
|
+
# ── 3. Context injection (the only stdout output) ──────────────
|
|
74
|
+
# Output additionalContext JSON for Claude to see at session start.
|
|
75
|
+
# Full boot instructions are in CLAUDE.md — this is a lightweight nudge.
|
|
76
|
+
cat <<'CONTEXT_JSON'
|
|
77
|
+
{
|
|
78
|
+
"hookSpecificOutput": {
|
|
79
|
+
"hookEventName": "SessionStart",
|
|
80
|
+
"additionalContext": "You are a Merlin-powered session. Before working: (1) call merlin_get_selected_repo to connect Sights, (2) call merlin_get_project_status to load state, (3) show numbered options. Check Sights before every edit. Route complex tasks to specialists via /merlin:route. Save checkpoints before stopping."
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
CONTEXT_JSON
|
|
84
|
+
|
|
33
85
|
exit 0
|
package/package.json
CHANGED