@arthai/agents 1.0.5 → 1.0.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.
- package/README.md +33 -3
- package/VERSION +1 -1
- package/agents/troubleshooter.md +132 -0
- package/bin/cli.js +296 -0
- package/bundles/canvas.json +1 -1
- package/bundles/compass.json +1 -1
- package/bundles/counsel.json +1 -0
- package/bundles/cruise.json +1 -1
- package/bundles/forge.json +12 -1
- package/bundles/prism.json +1 -0
- package/bundles/scalpel.json +5 -2
- package/bundles/sentinel.json +8 -2
- package/bundles/shield.json +1 -0
- package/bundles/spark.json +1 -0
- package/compiler.sh +14 -0
- package/dist/plugins/canvas/.claude-plugin/plugin.json +1 -1
- package/dist/plugins/canvas/VERSION +1 -0
- package/dist/plugins/canvas/commands/planning.md +100 -11
- package/dist/plugins/canvas/hooks/hooks.json +16 -0
- package/dist/plugins/canvas/hooks/project-setup.sh +109 -0
- package/dist/plugins/canvas/templates/CLAUDE.md.managed-block +123 -0
- package/dist/plugins/canvas/templates/CLAUDE.md.template +111 -0
- package/dist/plugins/compass/.claude-plugin/plugin.json +1 -1
- package/dist/plugins/compass/VERSION +1 -0
- package/dist/plugins/compass/commands/planning.md +100 -11
- package/dist/plugins/compass/hooks/hooks.json +16 -0
- package/dist/plugins/compass/hooks/project-setup.sh +109 -0
- package/dist/plugins/compass/templates/CLAUDE.md.managed-block +123 -0
- package/dist/plugins/compass/templates/CLAUDE.md.template +111 -0
- package/dist/plugins/counsel/.claude-plugin/plugin.json +1 -1
- package/dist/plugins/counsel/VERSION +1 -0
- package/dist/plugins/counsel/hooks/hooks.json +10 -0
- package/dist/plugins/counsel/hooks/project-setup.sh +109 -0
- package/dist/plugins/counsel/templates/CLAUDE.md.managed-block +123 -0
- package/dist/plugins/counsel/templates/CLAUDE.md.template +111 -0
- package/dist/plugins/cruise/.claude-plugin/plugin.json +1 -1
- package/dist/plugins/cruise/VERSION +1 -0
- package/dist/plugins/cruise/hooks/hooks.json +16 -0
- package/dist/plugins/cruise/hooks/project-setup.sh +109 -0
- package/dist/plugins/cruise/templates/CLAUDE.md.managed-block +123 -0
- package/dist/plugins/cruise/templates/CLAUDE.md.template +111 -0
- package/dist/plugins/forge/.claude-plugin/plugin.json +1 -1
- package/dist/plugins/forge/VERSION +1 -0
- package/dist/plugins/forge/agents/troubleshooter.md +132 -0
- package/dist/plugins/forge/commands/implement.md +99 -1
- package/dist/plugins/forge/commands/planning.md +100 -11
- package/dist/plugins/forge/hooks/escalation-guard.sh +177 -0
- package/dist/plugins/forge/hooks/hooks.json +22 -0
- package/dist/plugins/forge/hooks/project-setup.sh +109 -0
- package/dist/plugins/forge/templates/CLAUDE.md.managed-block +123 -0
- package/dist/plugins/forge/templates/CLAUDE.md.template +111 -0
- package/dist/plugins/prime/.claude-plugin/plugin.json +1 -1
- package/dist/plugins/prime/VERSION +1 -0
- package/dist/plugins/prime/agents/troubleshooter.md +132 -0
- package/dist/plugins/prime/commands/calibrate.md +20 -0
- package/dist/plugins/prime/commands/ci-fix.md +36 -0
- package/dist/plugins/prime/commands/fix.md +23 -0
- package/dist/plugins/prime/commands/implement.md +99 -1
- package/dist/plugins/prime/commands/planning.md +100 -11
- package/dist/plugins/prime/commands/qa-incident.md +54 -0
- package/dist/plugins/prime/commands/restart.md +186 -30
- package/dist/plugins/prime/hooks/escalation-guard.sh +177 -0
- package/dist/plugins/prime/hooks/hooks.json +60 -0
- package/dist/plugins/prime/hooks/post-config-change-restart-reminder.sh +86 -0
- package/dist/plugins/prime/hooks/post-server-crash-watch.sh +120 -0
- package/dist/plugins/prime/hooks/pre-server-port-guard.sh +110 -0
- package/dist/plugins/prime/hooks/project-setup.sh +109 -0
- package/dist/plugins/prime/hooks/sync-agents.sh +99 -12
- package/dist/plugins/prime/templates/CLAUDE.md.managed-block +123 -0
- package/dist/plugins/prime/templates/CLAUDE.md.template +111 -0
- package/dist/plugins/prism/.claude-plugin/plugin.json +1 -1
- package/dist/plugins/prism/VERSION +1 -0
- package/dist/plugins/prism/commands/qa-incident.md +54 -0
- package/dist/plugins/prism/hooks/hooks.json +12 -0
- package/dist/plugins/prism/hooks/project-setup.sh +109 -0
- package/dist/plugins/prism/templates/CLAUDE.md.managed-block +123 -0
- package/dist/plugins/prism/templates/CLAUDE.md.template +111 -0
- package/dist/plugins/scalpel/.claude-plugin/plugin.json +1 -1
- package/dist/plugins/scalpel/VERSION +1 -0
- package/dist/plugins/scalpel/agents/troubleshooter.md +132 -0
- package/dist/plugins/scalpel/commands/ci-fix.md +36 -0
- package/dist/plugins/scalpel/commands/fix.md +23 -0
- package/dist/plugins/scalpel/hooks/escalation-guard.sh +177 -0
- package/dist/plugins/scalpel/hooks/hooks.json +24 -0
- package/dist/plugins/scalpel/hooks/project-setup.sh +109 -0
- package/dist/plugins/scalpel/templates/CLAUDE.md.managed-block +123 -0
- package/dist/plugins/scalpel/templates/CLAUDE.md.template +111 -0
- package/dist/plugins/sentinel/.claude-plugin/plugin.json +1 -1
- package/dist/plugins/sentinel/VERSION +1 -0
- package/dist/plugins/sentinel/agents/troubleshooter.md +132 -0
- package/dist/plugins/sentinel/commands/restart.md +186 -30
- package/dist/plugins/sentinel/hooks/escalation-guard.sh +177 -0
- package/dist/plugins/sentinel/hooks/hooks.json +64 -0
- package/dist/plugins/sentinel/hooks/post-config-change-restart-reminder.sh +86 -0
- package/dist/plugins/sentinel/hooks/post-server-crash-watch.sh +120 -0
- package/dist/plugins/sentinel/hooks/pre-server-port-guard.sh +110 -0
- package/dist/plugins/sentinel/hooks/project-setup.sh +109 -0
- package/dist/plugins/sentinel/templates/CLAUDE.md.managed-block +123 -0
- package/dist/plugins/sentinel/templates/CLAUDE.md.template +111 -0
- package/dist/plugins/shield/.claude-plugin/plugin.json +1 -1
- package/dist/plugins/shield/VERSION +1 -0
- package/dist/plugins/shield/hooks/hooks.json +22 -12
- package/dist/plugins/shield/hooks/project-setup.sh +109 -0
- package/dist/plugins/shield/templates/CLAUDE.md.managed-block +123 -0
- package/dist/plugins/shield/templates/CLAUDE.md.template +111 -0
- package/dist/plugins/spark/.claude-plugin/plugin.json +1 -1
- package/dist/plugins/spark/VERSION +1 -0
- package/dist/plugins/spark/commands/calibrate.md +20 -0
- package/dist/plugins/spark/hooks/hooks.json +10 -0
- package/dist/plugins/spark/hooks/project-setup.sh +109 -0
- package/dist/plugins/spark/templates/CLAUDE.md.managed-block +123 -0
- package/dist/plugins/spark/templates/CLAUDE.md.template +111 -0
- package/hook-defs.json +31 -0
- package/hooks/escalation-guard.sh +177 -0
- package/hooks/post-config-change-restart-reminder.sh +86 -0
- package/hooks/post-server-crash-watch.sh +120 -0
- package/hooks/pre-server-port-guard.sh +110 -0
- package/hooks/project-setup.sh +109 -0
- package/hooks/sync-agents.sh +99 -12
- package/install.sh +2 -2
- package/package.json +1 -1
- package/portable.manifest +7 -1
- package/skills/calibrate/SKILL.md +20 -0
- package/skills/ci-fix/SKILL.md +36 -0
- package/skills/fix/SKILL.md +23 -0
- package/skills/implement/SKILL.md +99 -1
- package/skills/license/SKILL.md +159 -0
- package/skills/planning/SKILL.md +100 -11
- package/skills/qa-incident/SKILL.md +54 -0
- package/skills/restart/SKILL.md +187 -31
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# PostToolUse hook (Bash): Detect server start commands and check for crash loops.
|
|
3
|
+
# After a server start is detected, waits briefly then verifies the process is
|
|
4
|
+
# still running and the port is responding. Catches services that start then die.
|
|
5
|
+
#
|
|
6
|
+
# stdout is injected as context.
|
|
7
|
+
|
|
8
|
+
set -euo pipefail
|
|
9
|
+
|
|
10
|
+
COMMAND="${CLAUDE_TOOL_INPUT_COMMAND:-}"
|
|
11
|
+
if [ -z "$COMMAND" ] && [ -n "${CLAUDE_TOOL_INPUT:-}" ]; then
|
|
12
|
+
COMMAND=$(echo "$CLAUDE_TOOL_INPUT" | python3 -c "import json,sys; print(json.load(sys.stdin).get('command',''))" 2>/dev/null) || true
|
|
13
|
+
fi
|
|
14
|
+
|
|
15
|
+
[ -z "$COMMAND" ] && exit 0
|
|
16
|
+
|
|
17
|
+
# Only check commands that ran successfully
|
|
18
|
+
EXIT_CODE="${CLAUDE_TOOL_RESULT_EXIT_CODE:-0}"
|
|
19
|
+
[ "$EXIT_CODE" != "0" ] && exit 0
|
|
20
|
+
|
|
21
|
+
# ---------------------------------------------------------------------------
|
|
22
|
+
# Detect server start commands and extract ports
|
|
23
|
+
# ---------------------------------------------------------------------------
|
|
24
|
+
|
|
25
|
+
PORT=""
|
|
26
|
+
SERVICE=""
|
|
27
|
+
|
|
28
|
+
# npm/pnpm/yarn dev/start
|
|
29
|
+
if echo "$COMMAND" | grep -qE '\b(npm|pnpm|yarn)\s+run\s+(dev|start|serve)\b'; then
|
|
30
|
+
PORT=$(echo "$COMMAND" | grep -oE '\-\-port\s+([0-9]+)' | awk '{print $2}')
|
|
31
|
+
PORT="${PORT:-3000}"
|
|
32
|
+
SERVICE="Node.js dev server"
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
# next dev
|
|
36
|
+
if echo "$COMMAND" | grep -qE '\bnext\s+dev\b'; then
|
|
37
|
+
PORT=$(echo "$COMMAND" | grep -oE '\-\-port\s+([0-9]+)' | awk '{print $2}')
|
|
38
|
+
PORT="${PORT:-3000}"
|
|
39
|
+
SERVICE="Next.js dev server"
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
# uvicorn
|
|
43
|
+
if echo "$COMMAND" | grep -qE '\buvicorn\b'; then
|
|
44
|
+
PORT=$(echo "$COMMAND" | grep -oE '\-\-port\s+([0-9]+)' | awk '{print $2}')
|
|
45
|
+
PORT="${PORT:-8000}"
|
|
46
|
+
SERVICE="Uvicorn"
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
# gunicorn
|
|
50
|
+
if echo "$COMMAND" | grep -qE '\bgunicorn\b'; then
|
|
51
|
+
PORT=$(echo "$COMMAND" | grep -oE '\-b\s+[^:]+:([0-9]+)' | grep -oE '[0-9]+$')
|
|
52
|
+
if [ -z "$PORT" ]; then
|
|
53
|
+
PORT=$(echo "$COMMAND" | grep -oE '\-\-bind\s+[^:]+:([0-9]+)' | grep -oE '[0-9]+$')
|
|
54
|
+
fi
|
|
55
|
+
PORT="${PORT:-8000}"
|
|
56
|
+
SERVICE="Gunicorn"
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
# flask run
|
|
60
|
+
if echo "$COMMAND" | grep -qE '\bflask\s+run\b'; then
|
|
61
|
+
PORT=$(echo "$COMMAND" | grep -oE '\-\-port\s+([0-9]+)' | awk '{print $2}')
|
|
62
|
+
PORT="${PORT:-5000}"
|
|
63
|
+
SERVICE="Flask"
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
# docker compose up
|
|
67
|
+
if echo "$COMMAND" | grep -qE '\bdocker\s+compose\s+up\b'; then
|
|
68
|
+
SERVICE="Docker Compose services"
|
|
69
|
+
# For docker compose, check container status instead of port
|
|
70
|
+
sleep 8
|
|
71
|
+
down_containers=$(docker compose ps --format '{{.Name}} {{.Status}}' 2>/dev/null | grep -viE 'Up|running' | head -5) || true
|
|
72
|
+
if [ -n "$down_containers" ]; then
|
|
73
|
+
echo "CRASH DETECTED — Docker containers not healthy after 8s:"
|
|
74
|
+
echo "$down_containers"
|
|
75
|
+
echo "Check logs: docker compose logs --tail=30"
|
|
76
|
+
fi
|
|
77
|
+
exit 0
|
|
78
|
+
fi
|
|
79
|
+
|
|
80
|
+
# rails server
|
|
81
|
+
if echo "$COMMAND" | grep -qE '\brails\s+s(erver)?\b'; then
|
|
82
|
+
PORT=$(echo "$COMMAND" | grep -oE '\-p\s+([0-9]+)' | awk '{print $2}')
|
|
83
|
+
PORT="${PORT:-3000}"
|
|
84
|
+
SERVICE="Rails server"
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
# No server start detected
|
|
88
|
+
[ -z "$SERVICE" ] && exit 0
|
|
89
|
+
[ -z "$PORT" ] && exit 0
|
|
90
|
+
|
|
91
|
+
# ---------------------------------------------------------------------------
|
|
92
|
+
# Wait and check for crash loop
|
|
93
|
+
# ---------------------------------------------------------------------------
|
|
94
|
+
|
|
95
|
+
sleep 8
|
|
96
|
+
|
|
97
|
+
# Check if process is still listening on the port
|
|
98
|
+
pid=$(lsof -ti:"$PORT" 2>/dev/null | head -1) || true
|
|
99
|
+
|
|
100
|
+
if [ -z "$pid" ]; then
|
|
101
|
+
echo "CRASH DETECTED — $SERVICE (port $PORT) is no longer running after 8s."
|
|
102
|
+
echo "The process started but has since exited. Check the terminal output for errors."
|
|
103
|
+
echo "Common causes: missing env vars, port conflict, dependency errors, syntax errors."
|
|
104
|
+
exit 0
|
|
105
|
+
fi
|
|
106
|
+
|
|
107
|
+
# Process is alive — try a quick HTTP health check
|
|
108
|
+
http_status=$(timeout 5 curl -sf -o /dev/null -w "%{http_code}" "http://localhost:$PORT/" 2>/dev/null) || http_status="no_response"
|
|
109
|
+
|
|
110
|
+
if [ "$http_status" = "no_response" ]; then
|
|
111
|
+
# Process exists but not responding to HTTP — might be starting up or non-HTTP
|
|
112
|
+
echo "$SERVICE (port $PORT): process alive (PID $pid) but not responding to HTTP yet. May still be starting."
|
|
113
|
+
elif echo "$http_status" | grep -qE '^[2345]'; then
|
|
114
|
+
# Any HTTP response means the server is up
|
|
115
|
+
: # Silent success — don't spam on healthy starts
|
|
116
|
+
else
|
|
117
|
+
echo "$SERVICE (port $PORT): process alive but returned HTTP $http_status."
|
|
118
|
+
fi
|
|
119
|
+
|
|
120
|
+
exit 0
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# PreToolUse hook (Bash): Check port availability before server start commands.
|
|
3
|
+
# Detects server start commands and warns if the target port is already occupied
|
|
4
|
+
# by an unexpected process.
|
|
5
|
+
#
|
|
6
|
+
# Exit 0 = allow the command
|
|
7
|
+
# Exit 2 = block the command (stdout shown as reason)
|
|
8
|
+
# stdout = injected as context (warnings)
|
|
9
|
+
|
|
10
|
+
set -euo pipefail
|
|
11
|
+
|
|
12
|
+
COMMAND="${CLAUDE_TOOL_INPUT_COMMAND:-}"
|
|
13
|
+
if [ -z "$COMMAND" ] && [ -n "${CLAUDE_TOOL_INPUT:-}" ]; then
|
|
14
|
+
COMMAND=$(echo "$CLAUDE_TOOL_INPUT" | python3 -c "import json,sys; print(json.load(sys.stdin).get('command',''))" 2>/dev/null) || true
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
[ -z "$COMMAND" ] && exit 0
|
|
18
|
+
|
|
19
|
+
# ---------------------------------------------------------------------------
|
|
20
|
+
# Detect server start commands and extract ports
|
|
21
|
+
# ---------------------------------------------------------------------------
|
|
22
|
+
|
|
23
|
+
declare -a PORTS=()
|
|
24
|
+
|
|
25
|
+
# npm/pnpm/yarn dev/start — default port 3000 unless --port specified
|
|
26
|
+
if echo "$COMMAND" | grep -qE '\b(npm|pnpm|yarn)\s+run\s+(dev|start|serve)\b'; then
|
|
27
|
+
port=$(echo "$COMMAND" | grep -oE '\-\-port\s+([0-9]+)' | awk '{print $2}')
|
|
28
|
+
if [ -z "$port" ]; then
|
|
29
|
+
port=$(echo "$COMMAND" | grep -oE '\bp(ort)?\s*=?\s*([0-9]{4,5})' | grep -oE '[0-9]+')
|
|
30
|
+
fi
|
|
31
|
+
PORTS+=("${port:-3000}")
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
# next dev — default port 3000
|
|
35
|
+
if echo "$COMMAND" | grep -qE '\bnext\s+dev\b'; then
|
|
36
|
+
port=$(echo "$COMMAND" | grep -oE '\-\-port\s+([0-9]+)' | awk '{print $2}')
|
|
37
|
+
PORTS+=("${port:-3000}")
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
# vite — default port 5173
|
|
41
|
+
if echo "$COMMAND" | grep -qE '\bvite\b' && ! echo "$COMMAND" | grep -qE '\bvite\s+build\b'; then
|
|
42
|
+
port=$(echo "$COMMAND" | grep -oE '\-\-port\s+([0-9]+)' | awk '{print $2}')
|
|
43
|
+
PORTS+=("${port:-5173}")
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
# uvicorn — default port 8000
|
|
47
|
+
if echo "$COMMAND" | grep -qE '\buvicorn\b'; then
|
|
48
|
+
port=$(echo "$COMMAND" | grep -oE '\-\-port\s+([0-9]+)' | awk '{print $2}')
|
|
49
|
+
PORTS+=("${port:-8000}")
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
# gunicorn — default port 8000
|
|
53
|
+
if echo "$COMMAND" | grep -qE '\bgunicorn\b'; then
|
|
54
|
+
port=$(echo "$COMMAND" | grep -oE '\-b\s+[^:]+:([0-9]+)' | grep -oE '[0-9]+$')
|
|
55
|
+
if [ -z "$port" ]; then
|
|
56
|
+
port=$(echo "$COMMAND" | grep -oE '\-\-bind\s+[^:]+:([0-9]+)' | grep -oE '[0-9]+$')
|
|
57
|
+
fi
|
|
58
|
+
PORTS+=("${port:-8000}")
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
# flask run — default port 5000
|
|
62
|
+
if echo "$COMMAND" | grep -qE '\bflask\s+run\b'; then
|
|
63
|
+
port=$(echo "$COMMAND" | grep -oE '\-\-port\s+([0-9]+)' | awk '{print $2}')
|
|
64
|
+
PORTS+=("${port:-5000}")
|
|
65
|
+
fi
|
|
66
|
+
|
|
67
|
+
# docker compose up — check compose file for ports
|
|
68
|
+
if echo "$COMMAND" | grep -qE '\bdocker\s+compose\s+up\b'; then
|
|
69
|
+
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}"
|
|
70
|
+
if [ -f "$PROJECT_DIR/docker-compose.yml" ]; then
|
|
71
|
+
# Extract host ports from ports: mappings (e.g., "3000:3000", "5432:5432")
|
|
72
|
+
compose_ports=$(grep -oE '^\s*-\s*"?([0-9]+):' "$PROJECT_DIR/docker-compose.yml" 2>/dev/null | grep -oE '[0-9]+' | head -5) || true
|
|
73
|
+
for p in $compose_ports; do
|
|
74
|
+
PORTS+=("$p")
|
|
75
|
+
done
|
|
76
|
+
fi
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
# rails server — default port 3000
|
|
80
|
+
if echo "$COMMAND" | grep -qE '\brails\s+s(erver)?\b'; then
|
|
81
|
+
port=$(echo "$COMMAND" | grep -oE '\-p\s+([0-9]+)' | awk '{print $2}')
|
|
82
|
+
PORTS+=("${port:-3000}")
|
|
83
|
+
fi
|
|
84
|
+
|
|
85
|
+
# go run with -addr or explicit port
|
|
86
|
+
if echo "$COMMAND" | grep -qE '\bgo\s+run\b'; then
|
|
87
|
+
port=$(echo "$COMMAND" | grep -oE ':([0-9]{4,5})' | head -1 | tr -d ':')
|
|
88
|
+
[ -n "$port" ] && PORTS+=("$port")
|
|
89
|
+
fi
|
|
90
|
+
|
|
91
|
+
# No server command detected
|
|
92
|
+
[ ${#PORTS[@]} -eq 0 ] && exit 0
|
|
93
|
+
|
|
94
|
+
# ---------------------------------------------------------------------------
|
|
95
|
+
# Check each port for conflicts
|
|
96
|
+
# ---------------------------------------------------------------------------
|
|
97
|
+
|
|
98
|
+
for port in "${PORTS[@]}"; do
|
|
99
|
+
[ -z "$port" ] && continue
|
|
100
|
+
|
|
101
|
+
pid=$(lsof -ti:"$port" 2>/dev/null | head -1) || true
|
|
102
|
+
if [ -n "$pid" ]; then
|
|
103
|
+
proc_name=$(ps -p "$pid" -o comm= 2>/dev/null) || proc_name="unknown"
|
|
104
|
+
echo "PORT CONFLICT — port $port is already in use by $proc_name (PID $pid)."
|
|
105
|
+
echo "Kill it first: lsof -ti:$port | xargs kill -9"
|
|
106
|
+
echo "Or use a different port."
|
|
107
|
+
fi
|
|
108
|
+
done
|
|
109
|
+
|
|
110
|
+
exit 0
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# hooks/project-setup.sh — SessionStart hook: first-run project setup for marketplace installs.
|
|
3
|
+
#
|
|
4
|
+
# Runs on every SessionStart. Checks for marker file .claude/.toolkit-setup-done.
|
|
5
|
+
# If missing (or version is stale): creates CLAUDE.md from template, injects managed block,
|
|
6
|
+
# updates .gitignore with toolkit markers.
|
|
7
|
+
#
|
|
8
|
+
# Templates are read from ${CLAUDE_PLUGIN_ROOT}/templates/ (bundled with the plugin).
|
|
9
|
+
|
|
10
|
+
set -euo pipefail
|
|
11
|
+
|
|
12
|
+
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}"
|
|
13
|
+
PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-}"
|
|
14
|
+
MARKER_FILE="$PROJECT_DIR/.claude/.toolkit-setup-done"
|
|
15
|
+
|
|
16
|
+
# Exit silently if CLAUDE_PLUGIN_ROOT is not set (not running from a plugin context)
|
|
17
|
+
if [ -z "$PLUGIN_ROOT" ]; then
|
|
18
|
+
exit 0
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
TEMPLATES_DIR="$PLUGIN_ROOT/templates"
|
|
22
|
+
TEMPLATE_CLAUDE="$TEMPLATES_DIR/CLAUDE.md.template"
|
|
23
|
+
TEMPLATE_BLOCK="$TEMPLATES_DIR/CLAUDE.md.managed-block"
|
|
24
|
+
|
|
25
|
+
# Exit silently if templates are not bundled
|
|
26
|
+
if [ ! -f "$TEMPLATE_CLAUDE" ] || [ ! -f "$TEMPLATE_BLOCK" ]; then
|
|
27
|
+
exit 0
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
# Read toolkit version from VERSION file (bundled alongside plugin)
|
|
31
|
+
TOOLKIT_VERSION="0.0.0"
|
|
32
|
+
if [ -f "$PLUGIN_ROOT/VERSION" ]; then
|
|
33
|
+
TOOLKIT_VERSION=$(cat "$PLUGIN_ROOT/VERSION" 2>/dev/null | tr -d '[:space:]' || echo "0.0.0")
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
MANAGED_START="<!-- >>> claude-agents toolkit (DO NOT EDIT THIS BLOCK) >>> -->"
|
|
37
|
+
MANAGED_END="<!-- <<< claude-agents toolkit <<< -->"
|
|
38
|
+
GITIGNORE_START="# >>> claude-agents managed (DO NOT EDIT THIS BLOCK) >>>"
|
|
39
|
+
|
|
40
|
+
# Check marker file — skip if current version is already set up
|
|
41
|
+
if [ -f "$MARKER_FILE" ]; then
|
|
42
|
+
STORED_VERSION=$(cat "$MARKER_FILE" 2>/dev/null | tr -d '[:space:]' || echo "")
|
|
43
|
+
if [ "$STORED_VERSION" = "$TOOLKIT_VERSION" ]; then
|
|
44
|
+
exit 0
|
|
45
|
+
fi
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
CLAUDE_MD="$PROJECT_DIR/CLAUDE.md"
|
|
49
|
+
GITIGNORE="$PROJECT_DIR/.gitignore"
|
|
50
|
+
|
|
51
|
+
# 1. Create CLAUDE.md from template if it doesn't exist (never overwrite existing)
|
|
52
|
+
if [ ! -f "$CLAUDE_MD" ]; then
|
|
53
|
+
PROJECT_NAME=$(basename "$PROJECT_DIR")
|
|
54
|
+
sed "s/{{PROJECT_NAME}}/$PROJECT_NAME/g" "$TEMPLATE_CLAUDE" > "$CLAUDE_MD"
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
# 2. Inject managed block into CLAUDE.md if missing, or update if version is stale
|
|
58
|
+
if [ -f "$CLAUDE_MD" ]; then
|
|
59
|
+
BLOCK_CONTENT=$(cat "$TEMPLATE_BLOCK")
|
|
60
|
+
NEW_BLOCK=$(printf '%s\n<!-- version: %s -->\n%s\n%s' \
|
|
61
|
+
"$MANAGED_START" "$TOOLKIT_VERSION" "$BLOCK_CONTENT" "$MANAGED_END")
|
|
62
|
+
|
|
63
|
+
if ! grep -qF "$MANAGED_START" "$CLAUDE_MD"; then
|
|
64
|
+
# Block missing — append it
|
|
65
|
+
printf '\n\n%s\n' "$NEW_BLOCK" >> "$CLAUDE_MD"
|
|
66
|
+
else
|
|
67
|
+
# Block exists — update if version changed
|
|
68
|
+
EXISTING_VERSION=$(grep -o '<!-- version: [^>]* -->' "$CLAUDE_MD" 2>/dev/null | head -1 | sed 's/<!-- version: //;s/ -->//' | tr -d '[:space:]' || echo "")
|
|
69
|
+
if [ "$EXISTING_VERSION" != "$TOOLKIT_VERSION" ]; then
|
|
70
|
+
# Replace block contents between markers
|
|
71
|
+
tmp=$(mktemp)
|
|
72
|
+
in_block=false
|
|
73
|
+
wrote_block=false
|
|
74
|
+
while IFS= read -r line; do
|
|
75
|
+
if echo "$line" | grep -qF "$MANAGED_START"; then
|
|
76
|
+
in_block=true
|
|
77
|
+
printf '%s\n' "$NEW_BLOCK" >> "$tmp"
|
|
78
|
+
wrote_block=true
|
|
79
|
+
continue
|
|
80
|
+
fi
|
|
81
|
+
if echo "$line" | grep -qF "$MANAGED_END"; then
|
|
82
|
+
in_block=false
|
|
83
|
+
continue
|
|
84
|
+
fi
|
|
85
|
+
if ! $in_block; then
|
|
86
|
+
echo "$line" >> "$tmp"
|
|
87
|
+
fi
|
|
88
|
+
done < "$CLAUDE_MD"
|
|
89
|
+
mv "$tmp" "$CLAUDE_MD"
|
|
90
|
+
fi
|
|
91
|
+
fi
|
|
92
|
+
fi
|
|
93
|
+
|
|
94
|
+
# 3. Update .gitignore with toolkit marker block if missing
|
|
95
|
+
if [ ! -f "$GITIGNORE" ] || ! grep -qF "$GITIGNORE_START" "$GITIGNORE" 2>/dev/null; then
|
|
96
|
+
GITIGNORE_BLOCK=$(printf '%s\n.claude/.toolkit-last-seen-sha\n.claude/.toolkit-setup-done\n.claude/.claude-agents.conf\n%s' \
|
|
97
|
+
"$GITIGNORE_START" "# <<< claude-agents managed <<<")
|
|
98
|
+
if [ ! -f "$GITIGNORE" ]; then
|
|
99
|
+
printf '%s\n' "$GITIGNORE_BLOCK" > "$GITIGNORE"
|
|
100
|
+
else
|
|
101
|
+
printf '\n\n%s\n' "$GITIGNORE_BLOCK" >> "$GITIGNORE"
|
|
102
|
+
fi
|
|
103
|
+
fi
|
|
104
|
+
|
|
105
|
+
# 4. Write marker file with current version
|
|
106
|
+
mkdir -p "$PROJECT_DIR/.claude"
|
|
107
|
+
printf '%s\n' "$TOOLKIT_VERSION" > "$MARKER_FILE"
|
|
108
|
+
|
|
109
|
+
exit 0
|
package/hooks/sync-agents.sh
CHANGED
|
@@ -22,8 +22,9 @@ if [ ! -d "$AGENTS_DIR/.git" ]; then
|
|
|
22
22
|
exit 0
|
|
23
23
|
fi
|
|
24
24
|
|
|
25
|
-
# Exit silently if no license
|
|
26
|
-
|
|
25
|
+
# Exit silently if no license found in any path
|
|
26
|
+
ARTHAI_LICENSE_PATH="$REAL_HOME/.arthai/license"
|
|
27
|
+
if [ ! -f "$LICENSE_FILE" ] && [ ! -f "$ARTHAI_LICENSE_PATH" ] && [ -z "${ARTHAI_LICENSE_KEY:-}" ]; then
|
|
27
28
|
exit 0
|
|
28
29
|
fi
|
|
29
30
|
|
|
@@ -108,6 +109,27 @@ fi
|
|
|
108
109
|
|
|
109
110
|
# --- Step 2: Check license (with revocation enforcement) ---
|
|
110
111
|
NOW=$(date +%s)
|
|
112
|
+
WORKER_URL="https://license-worker.muddassar-shaikh.workers.dev"
|
|
113
|
+
|
|
114
|
+
# Resolve license key: ~/.claude-agents/.license takes priority (existing clone-install users),
|
|
115
|
+
# fall back to ~/.arthai/license (npm activate users).
|
|
116
|
+
ARTHAI_LICENSE_KEY_VALUE="${ARTHAI_LICENSE_KEY:-}"
|
|
117
|
+
RESOLVED_KEY=""
|
|
118
|
+
if [ -n "$ARTHAI_LICENSE_KEY_VALUE" ]; then
|
|
119
|
+
RESOLVED_KEY="$ARTHAI_LICENSE_KEY_VALUE"
|
|
120
|
+
elif [ -f "$LICENSE_FILE" ]; then
|
|
121
|
+
RESOLVED_KEY=$(cat "$LICENSE_FILE" 2>/dev/null | tr -d '[:space:]' || echo "")
|
|
122
|
+
elif [ -f "$REAL_HOME/.arthai/license" ]; then
|
|
123
|
+
RESOLVED_KEY=$(cat "$REAL_HOME/.arthai/license" 2>/dev/null | tr -d '[:space:]' || echo "")
|
|
124
|
+
fi
|
|
125
|
+
|
|
126
|
+
# Validate key format before using it in any JSON payload — prevents JSON injection
|
|
127
|
+
# via a crafted key value in the env var or license file.
|
|
128
|
+
KEY_FORMAT='^ARTH-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}$'
|
|
129
|
+
if [ -n "$RESOLVED_KEY" ] && ! echo "$RESOLVED_KEY" | grep -qE "$KEY_FORMAT"; then
|
|
130
|
+
# Key has invalid format — don't use it for Worker call or local check
|
|
131
|
+
RESOLVED_KEY=""
|
|
132
|
+
fi
|
|
111
133
|
|
|
112
134
|
# Detect if authorized-keys.txt changed in the pull — force re-check if so
|
|
113
135
|
AK_HASH_FILE="$AGENTS_DIR/.ak-hash"
|
|
@@ -128,6 +150,49 @@ fi
|
|
|
128
150
|
# Store current hash for next comparison
|
|
129
151
|
[ -n "$AK_CURRENT_HASH" ] && echo "$AK_CURRENT_HASH" > "$AK_HASH_FILE" 2>/dev/null || true
|
|
130
152
|
|
|
153
|
+
# validate_with_worker: call Worker /validate with the resolved key.
|
|
154
|
+
# Sets WORKER_RESULT: "valid", "invalid" (definitive), or "network_error".
|
|
155
|
+
validate_with_worker() {
|
|
156
|
+
local key="$1"
|
|
157
|
+
if [ -z "$key" ]; then
|
|
158
|
+
WORKER_RESULT="invalid"
|
|
159
|
+
return
|
|
160
|
+
fi
|
|
161
|
+
|
|
162
|
+
local payload="{\"key\":\"$key\"}"
|
|
163
|
+
local response
|
|
164
|
+
local curl_exit
|
|
165
|
+
|
|
166
|
+
# Pass payload via stdin (--data @-) so the key is not visible in the process list
|
|
167
|
+
response=$(printf '%s' "$payload" | curl \
|
|
168
|
+
--silent \
|
|
169
|
+
--max-time 10 \
|
|
170
|
+
--connect-timeout 5 \
|
|
171
|
+
--request POST \
|
|
172
|
+
--header "Content-Type: application/json" \
|
|
173
|
+
--data "@-" \
|
|
174
|
+
"$WORKER_URL/validate" 2>/dev/null)
|
|
175
|
+
curl_exit=$?
|
|
176
|
+
|
|
177
|
+
if [ $curl_exit -ne 0 ] || [ -z "$response" ]; then
|
|
178
|
+
WORKER_RESULT="network_error"
|
|
179
|
+
return
|
|
180
|
+
fi
|
|
181
|
+
|
|
182
|
+
# Parse "valid" field from JSON — minimal grep-based parse, no jq dependency
|
|
183
|
+
local valid_field
|
|
184
|
+
valid_field=$(echo "$response" | grep -o '"valid"[[:space:]]*:[[:space:]]*[a-z]*' | head -1 | grep -o '[a-z]*$')
|
|
185
|
+
|
|
186
|
+
if [ "$valid_field" = "true" ]; then
|
|
187
|
+
WORKER_RESULT="valid"
|
|
188
|
+
elif [ "$valid_field" = "false" ]; then
|
|
189
|
+
WORKER_RESULT="invalid"
|
|
190
|
+
else
|
|
191
|
+
# Unexpected response format — treat as network error (fail safe)
|
|
192
|
+
WORKER_RESULT="network_error"
|
|
193
|
+
fi
|
|
194
|
+
}
|
|
195
|
+
|
|
131
196
|
LICENSE_VALID=true
|
|
132
197
|
if [ -f "$LICENSE_CACHE" ]; then
|
|
133
198
|
LAST_CHECK=$(cat "$LICENSE_CACHE" 2>/dev/null || echo "0")
|
|
@@ -136,19 +201,41 @@ if [ -f "$LICENSE_CACHE" ]; then
|
|
|
136
201
|
# Cache is fresh, skip validation
|
|
137
202
|
:
|
|
138
203
|
else
|
|
139
|
-
# Re-validate
|
|
140
|
-
|
|
204
|
+
# Re-validate: try Worker first, fall back to local only on network error
|
|
205
|
+
validate_with_worker "$RESOLVED_KEY"
|
|
206
|
+
if [ "$WORKER_RESULT" = "valid" ]; then
|
|
207
|
+
echo "$NOW" > "$LICENSE_CACHE"
|
|
208
|
+
elif [ "$WORKER_RESULT" = "invalid" ]; then
|
|
209
|
+
# Worker says definitively invalid — no local fallback, clear cache
|
|
210
|
+
rm -f "$LICENSE_CACHE" 2>/dev/null || true
|
|
141
211
|
LICENSE_VALID=false
|
|
142
212
|
else
|
|
143
|
-
|
|
213
|
+
# Network error — fall back to local authorized-keys.txt check
|
|
214
|
+
echo "License server unavailable. Retrying with local validation..." >&2
|
|
215
|
+
if ! "$AGENTS_DIR/install.sh" --check-license-only 2>/dev/null; then
|
|
216
|
+
LICENSE_VALID=false
|
|
217
|
+
else
|
|
218
|
+
echo "$NOW" > "$LICENSE_CACHE"
|
|
219
|
+
fi
|
|
144
220
|
fi
|
|
145
221
|
fi
|
|
146
222
|
else
|
|
147
|
-
# First check (or cache was invalidated by AK change)
|
|
148
|
-
|
|
223
|
+
# First check (or cache was invalidated by AK change): try Worker first
|
|
224
|
+
validate_with_worker "$RESOLVED_KEY"
|
|
225
|
+
if [ "$WORKER_RESULT" = "valid" ]; then
|
|
226
|
+
echo "$NOW" > "$LICENSE_CACHE"
|
|
227
|
+
elif [ "$WORKER_RESULT" = "invalid" ]; then
|
|
228
|
+
# Worker says definitively invalid — no local fallback, ensure cache stays clear
|
|
229
|
+
rm -f "$LICENSE_CACHE" 2>/dev/null || true
|
|
149
230
|
LICENSE_VALID=false
|
|
150
231
|
else
|
|
151
|
-
|
|
232
|
+
# Network error — fall back to local authorized-keys.txt check
|
|
233
|
+
echo "License server unavailable. Retrying with local validation..." >&2
|
|
234
|
+
if ! "$AGENTS_DIR/install.sh" --check-license-only 2>/dev/null; then
|
|
235
|
+
LICENSE_VALID=false
|
|
236
|
+
else
|
|
237
|
+
echo "$NOW" > "$LICENSE_CACHE"
|
|
238
|
+
fi
|
|
152
239
|
fi
|
|
153
240
|
fi
|
|
154
241
|
|
|
@@ -182,12 +269,12 @@ if ! $LICENSE_VALID; then
|
|
|
182
269
|
|
|
183
270
|
# Remove CLAUDE.md managed block
|
|
184
271
|
CLAUDEMD="$PROJECT_DIR/CLAUDE.md"
|
|
185
|
-
if [ -f "$CLAUDEMD" ] && grep -qF "<!-- >>> claude-agents toolkit -->" "$CLAUDEMD" 2>/dev/null; then
|
|
272
|
+
if [ -f "$CLAUDEMD" ] && grep -qF "<!-- >>> claude-agents toolkit (DO NOT EDIT THIS BLOCK) >>> -->" "$CLAUDEMD" 2>/dev/null; then
|
|
186
273
|
tmp=$(mktemp)
|
|
187
274
|
in_block=false
|
|
188
275
|
skip_next_blank=false
|
|
189
276
|
while IFS= read -r line; do
|
|
190
|
-
if echo "$line" | grep -qF "<!-- >>> claude-agents toolkit -->"; then
|
|
277
|
+
if echo "$line" | grep -qF "<!-- >>> claude-agents toolkit (DO NOT EDIT THIS BLOCK) >>> -->"; then
|
|
191
278
|
in_block=true
|
|
192
279
|
continue
|
|
193
280
|
fi
|
|
@@ -218,8 +305,8 @@ if ! $LICENSE_VALID; then
|
|
|
218
305
|
rm -f "$LICENSE_CACHE" 2>/dev/null || true
|
|
219
306
|
fi
|
|
220
307
|
|
|
221
|
-
echo "
|
|
222
|
-
echo "
|
|
308
|
+
echo "Invalid license key. Toolkit has been disabled for this project."
|
|
309
|
+
echo " Check your key or get one at arthai.dev/pricing"
|
|
223
310
|
exit 0
|
|
224
311
|
fi
|
|
225
312
|
|
package/install.sh
CHANGED
|
@@ -114,7 +114,7 @@ get_category_items() {
|
|
|
114
114
|
echo "agents/architect.md agents/code-reviewer.md agents/design-studio-create.md agents/design-studio-critique.md agents/design-studio-think.md agents/gtm-expert.md agents/product-manager.md agents/stakeholder-reporter.md agents/meeting-prep.md agents/content-strategist.md agents/user-researcher.md agents/competitive-analyst.md"
|
|
115
115
|
;;
|
|
116
116
|
development)
|
|
117
|
-
echo "agents/frontend.md agents/python-backend.md agents/ops.md skills/planning skills/implement skills/fix skills/pr skills/precheck skills/review-pr skills/issue"
|
|
117
|
+
echo "agents/frontend.md agents/python-backend.md agents/ops.md agents/troubleshooter.md skills/planning skills/implement skills/fix skills/pr skills/precheck skills/review-pr skills/issue"
|
|
118
118
|
;;
|
|
119
119
|
quality)
|
|
120
120
|
echo "agents/qa.md agents/qa-e2e.md agents/qa-challenger.md agents/qa-test-promoter.md agents/qa-baseline-updater.md agents/qa-domain.md skills/qa skills/ci-fix skills/qa-incident skills/qa-learn"
|
|
@@ -126,7 +126,7 @@ get_category_items() {
|
|
|
126
126
|
echo "hooks/triage-router.sh hooks/session-end.sh"
|
|
127
127
|
;;
|
|
128
128
|
guardrails)
|
|
129
|
-
echo "hooks/session-bootstrap.sh hooks/pre-bash-guard.sh hooks/pre-task-context.sh hooks/pre-edit-guard.sh hooks/post-test-summary.sh hooks/post-edit-lint.sh hooks/post-deploy-health.sh hooks/post-diff-test-compare.sh hooks/post-git-state.sh hooks/post-merge-cleanup.sh skills/onboard skills/welcome skills/share skills/templates skills/wizard skills/autopilot skills/continue"
|
|
129
|
+
echo "hooks/session-bootstrap.sh hooks/pre-bash-guard.sh hooks/pre-task-context.sh hooks/pre-edit-guard.sh hooks/post-test-summary.sh hooks/post-edit-lint.sh hooks/post-deploy-health.sh hooks/post-diff-test-compare.sh hooks/post-git-state.sh hooks/post-merge-cleanup.sh hooks/escalation-guard.sh hooks/project-setup.sh hooks/pre-server-port-guard.sh hooks/post-config-change-restart-reminder.sh hooks/post-server-crash-watch.sh skills/onboard skills/welcome skills/share skills/templates skills/wizard skills/autopilot skills/continue"
|
|
130
130
|
;;
|
|
131
131
|
railway)
|
|
132
132
|
echo "skills/railway/central-station skills/railway/database skills/railway/deploy skills/railway/deployment skills/railway/domain skills/railway/environment skills/railway/metrics skills/railway/new skills/railway/projects skills/railway/railway-docs skills/railway/service skills/railway/status skills/railway/templates"
|
package/package.json
CHANGED
package/portable.manifest
CHANGED
|
@@ -38,6 +38,7 @@ agent agents/content-strategist.md
|
|
|
38
38
|
agent agents/user-researcher.md
|
|
39
39
|
agent agents/competitive-analyst.md
|
|
40
40
|
agent agents/ai-consultant.md
|
|
41
|
+
agent agents/troubleshooter.md
|
|
41
42
|
|
|
42
43
|
# Portable skills (30)
|
|
43
44
|
skill skills/explore.md
|
|
@@ -78,7 +79,8 @@ skill-dir skills/solution-architect
|
|
|
78
79
|
skill-dir skills/deliverable-builder
|
|
79
80
|
skill-dir skills/engagement-tracker
|
|
80
81
|
|
|
81
|
-
# Portable hooks (
|
|
82
|
+
# Portable hooks (14)
|
|
83
|
+
hook hooks/project-setup.sh
|
|
82
84
|
hook hooks/ensure-client-dir.sh
|
|
83
85
|
hook hooks/check-deliverable.sh
|
|
84
86
|
hook hooks/session-summary.sh
|
|
@@ -109,4 +111,8 @@ railway-skill-dir skills/railway/railway-docs
|
|
|
109
111
|
railway-skill-dir skills/railway/service
|
|
110
112
|
railway-skill-dir skills/railway/status
|
|
111
113
|
railway-skill-dir skills/railway/templates
|
|
114
|
+
hook hooks/escalation-guard.sh
|
|
115
|
+
hook hooks/pre-server-port-guard.sh
|
|
116
|
+
hook hooks/post-config-change-restart-reminder.sh
|
|
117
|
+
hook hooks/post-server-crash-watch.sh
|
|
112
118
|
hook hooks/session-end.sh
|
|
@@ -74,6 +74,26 @@ This goes far deeper than `/scan`. Read **actual source code** to understand HOW
|
|
|
74
74
|
|
|
75
75
|
#### Step 1.1: Foundation Scan
|
|
76
76
|
|
|
77
|
+
**Managed block check (belt-and-suspenders — runs before anything else):**
|
|
78
|
+
|
|
79
|
+
Check if CLAUDE.md has the toolkit managed block. If missing, inject it before proceeding:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
MANAGED_START="<!-- >>> claude-agents toolkit (DO NOT EDIT THIS BLOCK) >>> -->"
|
|
83
|
+
if [ -f "$CLAUDE_PROJECT_DIR/CLAUDE.md" ]; then
|
|
84
|
+
grep -qF "$MANAGED_START" "$CLAUDE_PROJECT_DIR/CLAUDE.md" || echo "MISSING_BLOCK"
|
|
85
|
+
fi
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
If the managed block is missing:
|
|
89
|
+
1. Read `~/.claude-agents/templates/CLAUDE.md.managed-block` (or `$CLAUDE_PROJECT_DIR/.claude/hooks/../templates/CLAUDE.md.managed-block` if installed via plugin)
|
|
90
|
+
2. Inject it at the end of CLAUDE.md using the markers:
|
|
91
|
+
- Start: `<!-- >>> claude-agents toolkit (DO NOT EDIT THIS BLOCK) >>> -->`
|
|
92
|
+
- End: `<!-- <<< claude-agents toolkit <<< -->`
|
|
93
|
+
3. Report: "Injected toolkit managed block into CLAUDE.md (was missing)"
|
|
94
|
+
|
|
95
|
+
This catches any install path that missed the injection — clone installs, manual setups, or projects that predate the managed block feature.
|
|
96
|
+
|
|
77
97
|
Run `/scan` first if CLAUDE.md has `<!-- TODO -->` placeholders or doesn't exist. This populates
|
|
78
98
|
the basics (tech stack, services, test commands, infrastructure). Then proceed to deep scan.
|
|
79
99
|
|
package/skills/ci-fix/SKILL.md
CHANGED
|
@@ -162,6 +162,42 @@ gh run view <FAILED_RUN_ID> --log-failed 2>&1 | tail -200
|
|
|
162
162
|
| **Build failures** | build errors | Read error, fix import/export/config |
|
|
163
163
|
| **Migration** | Alembic/Django errors | Fix migration file |
|
|
164
164
|
| **Dependency** | pip/npm install failures | Fix requirements/package.json |
|
|
165
|
+
| **Toolkit tests** | 15/20-skill-runtime-safety, manifest-coverage | See Toolkit Test Fixes below |
|
|
166
|
+
|
|
167
|
+
#### Toolkit-Specific Test Fixes (claude-agents repo)
|
|
168
|
+
|
|
169
|
+
When CI fails on the mechanical test suite (`tests/run.sh`), these are the common failures and auto-fixes:
|
|
170
|
+
|
|
171
|
+
| Test | Failure message | Root cause | Auto-fix |
|
|
172
|
+
|------|----------------|-----------|----------|
|
|
173
|
+
| `20-skill-runtime-safety` | "regex-unsafe [brackets] in descriptions" | SKILL.md `description:` or `arguments:` field contains `[text]` | Replace `[text]` with `<text>` in the frontmatter field. Brackets break regex matching in Claude Code. |
|
|
174
|
+
| `20-skill-runtime-safety` | "Skills missing required frontmatter fields" | SKILL.md missing `user-invocable: true` or `arguments:` | Add missing field to the YAML frontmatter between `---` markers. Check `git show HEAD~1:path/to/SKILL.md` for the original. |
|
|
175
|
+
| `15-manifest-coverage` | "entries mapped to categories" | New file in `portable.manifest` not listed in any `get_category_items()` category in `install.sh` | Add the manifest entry to the appropriate category in `install.sh:get_category_items()`. |
|
|
176
|
+
| `15-manifest-coverage` | "Install creates all expected symlinks" | New file in `portable.manifest` but install didn't create the symlink | Usually follows from the category mapping fix above. |
|
|
177
|
+
| `15-manifest-coverage` | "Entry counts are consistent" | Mismatch between manifest entries and installed files | Check that new manifest entries have matching source files. |
|
|
178
|
+
| `19-brownfield-assessment` | "classify_file returns IDENTICAL" | Agent fixture is stale after editing an agent `.md` file | Update fixture: `cp agents/{name}.md tests/fixtures/claude-setups/poweruser/.claude/agents/` |
|
|
179
|
+
|
|
180
|
+
**Auto-fix sequence for toolkit tests:**
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
# 1. Get the exact failure
|
|
184
|
+
gh run view <ID> --log-failed 2>&1 | grep -E "FAIL|✗" | head -5
|
|
185
|
+
|
|
186
|
+
# 2. For bracket issues — find and fix ALL bracket descriptions
|
|
187
|
+
grep -rn 'description:.*\[' skills/*/SKILL.md
|
|
188
|
+
# Replace [text] with <text> in each match
|
|
189
|
+
|
|
190
|
+
# 3. For missing frontmatter — compare against last known good
|
|
191
|
+
git show HEAD~1:path/to/SKILL.md | head -6
|
|
192
|
+
# Restore missing fields
|
|
193
|
+
|
|
194
|
+
# 4. For manifest coverage — add to install.sh categories
|
|
195
|
+
grep "get_category_items" install.sh
|
|
196
|
+
# Add new entries to the right category
|
|
197
|
+
|
|
198
|
+
# 5. Verify locally before pushing
|
|
199
|
+
bash tests/run.sh --suite 15,20 --scenario a
|
|
200
|
+
```
|
|
165
201
|
|
|
166
202
|
**Attempt escalation:**
|
|
167
203
|
- Attempt 1: Apply the obvious fix (auto-fix tools, direct code fix)
|
package/skills/fix/SKILL.md
CHANGED
|
@@ -478,6 +478,29 @@ Select the right agent based on which layer the bug is in:
|
|
|
478
478
|
If `.claude/project-profile.md` exists, read it to determine the platform and pick the right agent.
|
|
479
479
|
If `/calibrate` generated custom agents (e.g., `ios-developer.md`), use those for platform-specific bugs.
|
|
480
480
|
|
|
481
|
+
**4.2b: Escalation protocol for fix agents**
|
|
482
|
+
|
|
483
|
+
Include this in the implementation agent's prompt:
|
|
484
|
+
|
|
485
|
+
```
|
|
486
|
+
## When Your Fix Doesn't Work (MANDATORY)
|
|
487
|
+
|
|
488
|
+
1. After first failed attempt: re-read the root cause analysis from Step 1.
|
|
489
|
+
Is the root cause correct? If not, go back to Step 1.
|
|
490
|
+
2. After second failed attempt: consult knowledge base:
|
|
491
|
+
- .claude/knowledge/qa-knowledge/ (error keywords)
|
|
492
|
+
- .claude/knowledge/shared/conventions.md (project gotchas)
|
|
493
|
+
- git log --all --grep="<error keyword>" --oneline -10
|
|
494
|
+
3. After third failed attempt: STOP. Do not try another fix.
|
|
495
|
+
Generate a STUCK REPORT and send to team-lead:
|
|
496
|
+
- Error: [exact message]
|
|
497
|
+
- Root cause hypothesis: [from Step 1]
|
|
498
|
+
- Fix attempts: [1, 2, 3 with results]
|
|
499
|
+
- KB consultation results: [what you found]
|
|
500
|
+
- Recommendation: [re-investigate root cause / ask user for X / try different approach]
|
|
501
|
+
4. If a troubleshooter agent is available, team-lead may spawn one.
|
|
502
|
+
```
|
|
503
|
+
|
|
481
504
|
**Agent prompt includes:**
|
|
482
505
|
```
|
|
483
506
|
1. Root cause analysis from Step 1
|