continuous-improvement 3.8.0 → 3.9.2
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/.claude-plugin/marketplace.json +2 -14
- package/CHANGELOG.md +25 -0
- package/LICENSE +21 -21
- package/QUICKSTART.md +148 -101
- package/README.md +50 -18
- package/action.yml +33 -33
- package/bin/analyze.sh +161 -161
- package/bin/backfill.mjs +19 -19
- package/bin/check-doc-runtime-claims.mjs +120 -0
- package/bin/generate-plugin-manifests.mjs +2 -0
- package/bin/hook-stats.mjs +21 -21
- package/bin/install.mjs +51 -44
- package/bin/mcp-server.mjs +43 -40
- package/bin/refresh-third-party.mjs +416 -416
- package/commands/continuous-improvement.md +115 -115
- package/commands/dashboard.md +56 -56
- package/commands/discipline.md +51 -51
- package/commands/proceed-with-the-recommendation.md +62 -62
- package/commands/seven-laws.md +16 -16
- package/commands/superpowers.md +119 -92
- package/commands/workspace-surface-audit.md +77 -77
- package/hooks/gateguard.mjs +172 -0
- package/hooks/observe.sh +172 -172
- package/hooks/session.sh +106 -106
- package/hooks/three-section-close.mjs +181 -181
- package/instinct-packs/go.json +58 -58
- package/instinct-packs/meta.json +16 -16
- package/instinct-packs/python.json +58 -58
- package/instinct-packs/react.json +58 -58
- package/lib/gateguard-state.mjs +85 -0
- package/lib/plugin-metadata.mjs +25 -18
- package/llms.txt +68 -68
- package/package.json +3 -2
- package/plugins/beginner.json +1 -1
- package/plugins/continuous-improvement/.claude-plugin/marketplace.json +1 -1
- package/plugins/continuous-improvement/.claude-plugin/plugin.json +1 -1
- package/plugins/continuous-improvement/LICENSE +21 -21
- package/plugins/continuous-improvement/README.md +1 -0
- package/plugins/continuous-improvement/agents/README.md +120 -0
- package/plugins/continuous-improvement/agents/code-reviewer.md +97 -0
- package/plugins/continuous-improvement/agents/security-auditor.md +101 -0
- package/plugins/continuous-improvement/agents/test-engineer.md +95 -0
- package/plugins/continuous-improvement/bin/backfill.mjs +19 -19
- package/plugins/continuous-improvement/bin/mcp-server.mjs +43 -40
- package/plugins/continuous-improvement/commands/continuous-improvement.md +115 -115
- package/plugins/continuous-improvement/commands/dashboard.md +56 -56
- package/plugins/continuous-improvement/commands/discipline.md +51 -51
- package/plugins/continuous-improvement/commands/proceed-with-the-recommendation.md +62 -62
- package/plugins/continuous-improvement/commands/seven-laws.md +16 -16
- package/plugins/continuous-improvement/commands/superpowers.md +119 -92
- package/plugins/continuous-improvement/commands/workspace-surface-audit.md +77 -77
- package/plugins/continuous-improvement/hooks/gateguard.mjs +172 -0
- package/plugins/continuous-improvement/hooks/hooks.json +6 -1
- package/plugins/continuous-improvement/hooks/observe.sh +172 -172
- package/plugins/continuous-improvement/hooks/session.sh +106 -106
- package/plugins/continuous-improvement/hooks/three-section-close.mjs +181 -181
- package/plugins/continuous-improvement/instinct-packs/go.json +58 -58
- package/plugins/continuous-improvement/instinct-packs/meta.json +16 -16
- package/plugins/continuous-improvement/instinct-packs/python.json +58 -58
- package/plugins/continuous-improvement/instinct-packs/react.json +58 -58
- package/plugins/continuous-improvement/lib/plugin-metadata.mjs +25 -18
- package/plugins/continuous-improvement/skills/README.md +4 -1
- package/plugins/continuous-improvement/skills/deploy-receipt/SKILL.md +47 -0
- package/plugins/continuous-improvement/skills/gateguard/SKILL.md +17 -9
- package/plugins/continuous-improvement/skills/para-memory-files/SKILL.md +108 -108
- package/plugins/continuous-improvement/skills/proceed-with-the-recommendation/SKILL.md +1 -8
- package/plugins/continuous-improvement/skills/ralph/SKILL.md +221 -221
- package/plugins/continuous-improvement/skills/recovery-classification/SKILL.md +73 -0
- package/plugins/continuous-improvement/skills/safety-guard/SKILL.md +76 -76
- package/plugins/continuous-improvement/skills/state-reconciliation/SKILL.md +63 -0
- package/plugins/continuous-improvement/skills/strategic-compact/SKILL.md +104 -104
- package/plugins/continuous-improvement/skills/superpowers/SKILL.md +22 -15
- package/plugins/continuous-improvement/skills/tdd-workflow/SKILL.md +411 -411
- package/plugins/continuous-improvement/skills/token-budget-advisor/SKILL.md +136 -136
- package/plugins/continuous-improvement/skills/verification-loop/SKILL.md +32 -0
- package/plugins/continuous-improvement/skills/wild-risa-balance/SKILL.md +191 -191
- package/plugins/continuous-improvement/skills/worktree-safety/SKILL.md +66 -0
- package/plugins/expert.json +1 -1
- package/skills/README.md +79 -79
- package/skills/deploy-receipt.md +47 -0
- package/skills/gateguard.md +17 -9
- package/skills/para-memory-files.md +108 -108
- package/skills/proceed-with-the-recommendation.md +1 -8
- package/skills/ralph.md +221 -221
- package/skills/recovery-classification.md +73 -0
- package/skills/safety-guard.md +76 -76
- package/skills/state-reconciliation.md +63 -0
- package/skills/strategic-compact.md +104 -104
- package/skills/superpowers.md +22 -15
- package/skills/tdd-workflow.md +411 -411
- package/skills/token-budget-advisor.md +136 -136
- package/skills/verification-loop.md +32 -0
- package/skills/wild-risa-balance.md +191 -191
- package/skills/worktree-safety.md +66 -0
- package/templates/insights-claude-md.md +91 -0
- package/templates/verify-ladder.example.json +37 -24
package/bin/analyze.sh
CHANGED
|
@@ -1,161 +1,161 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# analyze.sh — Read observations.jsonl, detect patterns, create instinct YAML files
|
|
3
|
-
# Runs via /continuous-improvement command. Uses claude CLI with Haiku for cost-efficient analysis.
|
|
4
|
-
|
|
5
|
-
set -euo pipefail
|
|
6
|
-
|
|
7
|
-
INSTINCTS_DIR="${HOME}/.claude/instincts"
|
|
8
|
-
|
|
9
|
-
# ---------------------------------------------------------------------------
|
|
10
|
-
# Detect project
|
|
11
|
-
# ---------------------------------------------------------------------------
|
|
12
|
-
PROJECT_ROOT=""
|
|
13
|
-
if [[ -n "${CLAUDE_PROJECT_DIR:-}" && -d "${CLAUDE_PROJECT_DIR}" ]]; then
|
|
14
|
-
PROJECT_ROOT="${CLAUDE_PROJECT_DIR}"
|
|
15
|
-
fi
|
|
16
|
-
if [[ -z "$PROJECT_ROOT" ]]; then
|
|
17
|
-
PROJECT_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || true)"
|
|
18
|
-
fi
|
|
19
|
-
if [[ -z "$PROJECT_ROOT" ]]; then
|
|
20
|
-
PROJECT_ROOT="global"
|
|
21
|
-
fi
|
|
22
|
-
|
|
23
|
-
# Use shasum on macOS, sha256sum on Linux
|
|
24
|
-
if command -v sha256sum &>/dev/null; then
|
|
25
|
-
PROJECT_HASH="$(printf '%s' "$PROJECT_ROOT" | sha256sum | cut -c1-12)"
|
|
26
|
-
elif command -v shasum &>/dev/null; then
|
|
27
|
-
PROJECT_HASH="$(printf '%s' "$PROJECT_ROOT" | shasum -a 256 | cut -c1-12)"
|
|
28
|
-
else
|
|
29
|
-
# Fallback: use project root basename if no hashing available
|
|
30
|
-
PROJECT_HASH="$(basename "$PROJECT_ROOT" | tr -cd 'a-zA-Z0-9' | cut -c1-12)"
|
|
31
|
-
fi
|
|
32
|
-
PROJECT_NAME="$(basename "${PROJECT_ROOT%.git}")"
|
|
33
|
-
PROJECT_DIR="${INSTINCTS_DIR}/${PROJECT_HASH}"
|
|
34
|
-
OBS_FILE="${PROJECT_DIR}/observations.jsonl"
|
|
35
|
-
|
|
36
|
-
# ---------------------------------------------------------------------------
|
|
37
|
-
# Check observations exist
|
|
38
|
-
# ---------------------------------------------------------------------------
|
|
39
|
-
if [[ ! -f "$OBS_FILE" ]] || [[ ! -s "$OBS_FILE" ]]; then
|
|
40
|
-
echo "No observations found at ${OBS_FILE}"
|
|
41
|
-
echo "Use Claude Code with hooks installed to generate observations."
|
|
42
|
-
exit 0
|
|
43
|
-
fi
|
|
44
|
-
|
|
45
|
-
OBS_COUNT=$(wc -l < "$OBS_FILE")
|
|
46
|
-
echo "Found ${OBS_COUNT} observations in ${OBS_FILE}"
|
|
47
|
-
|
|
48
|
-
if (( OBS_COUNT < 20 )); then
|
|
49
|
-
echo "Need at least 20 observations for meaningful analysis. Keep using Claude Code (${OBS_COUNT}/20)."
|
|
50
|
-
exit 0
|
|
51
|
-
fi
|
|
52
|
-
|
|
53
|
-
# ---------------------------------------------------------------------------
|
|
54
|
-
# Read existing instincts to avoid duplicates
|
|
55
|
-
# ---------------------------------------------------------------------------
|
|
56
|
-
EXISTING_INSTINCTS=""
|
|
57
|
-
for f in "${PROJECT_DIR}"/*.yaml "${INSTINCTS_DIR}/global"/*.yaml; do
|
|
58
|
-
[[ -f "$f" ]] && EXISTING_INSTINCTS="${EXISTING_INSTINCTS}$(cat "$f")"$'\n'
|
|
59
|
-
done
|
|
60
|
-
|
|
61
|
-
# ---------------------------------------------------------------------------
|
|
62
|
-
# Take last 500 observations
|
|
63
|
-
# ---------------------------------------------------------------------------
|
|
64
|
-
RECENT_OBS=$(tail -500 "$OBS_FILE")
|
|
65
|
-
|
|
66
|
-
# ---------------------------------------------------------------------------
|
|
67
|
-
# Build analysis prompt
|
|
68
|
-
# ---------------------------------------------------------------------------
|
|
69
|
-
ANALYSIS_PROMPT="Analyze these Claude Code session observations and extract behavioral patterns as instinct YAML files.
|
|
70
|
-
|
|
71
|
-
OBSERVATIONS (JSONL — each line is a tool call):
|
|
72
|
-
${RECENT_OBS}
|
|
73
|
-
|
|
74
|
-
EXISTING INSTINCTS (already learned — do NOT duplicate these):
|
|
75
|
-
${EXISTING_INSTINCTS}
|
|
76
|
-
|
|
77
|
-
YOUR TASK:
|
|
78
|
-
1. Look for REPEATED PATTERNS — same tool sequence used 3+ times
|
|
79
|
-
2. Look for ERROR-THEN-FIX sequences — tool fails, next tools fix it
|
|
80
|
-
3. Look for TOOL PREFERENCES — one tool consistently chosen over alternatives
|
|
81
|
-
4. Look for WORKFLOW PATTERNS — consistent ordering of operations
|
|
82
|
-
5. Look for USER CORRECTIONS — user says no/stop/don't after an action
|
|
83
|
-
|
|
84
|
-
OUTPUT FORMAT — output ONLY new instincts as YAML blocks, separated by ---:
|
|
85
|
-
|
|
86
|
-
id: descriptive-kebab-case-id
|
|
87
|
-
trigger: \"when [specific situation]\"
|
|
88
|
-
confidence: 0.5
|
|
89
|
-
domain: workflow|tooling|testing|patterns
|
|
90
|
-
source: observation
|
|
91
|
-
scope: project
|
|
92
|
-
project_id: ${PROJECT_HASH}
|
|
93
|
-
created: \"$(date -u +%Y-%m-%d)\"
|
|
94
|
-
last_seen: \"$(date -u +%Y-%m-%d)\"
|
|
95
|
-
observation_count: [number of times pattern was seen]
|
|
96
|
-
---
|
|
97
|
-
[One sentence describing the specific actionable behavior]
|
|
98
|
-
|
|
99
|
-
Rules:
|
|
100
|
-
- Only create instincts for patterns seen 3+ times
|
|
101
|
-
- Start confidence at 0.5 (suggest level)
|
|
102
|
-
- Be specific and actionable (not vague advice)
|
|
103
|
-
- Different from existing instincts listed above
|
|
104
|
-
|
|
105
|
-
If no new patterns are found, output exactly: NO_NEW_PATTERNS
|
|
106
|
-
|
|
107
|
-
Output ONLY the YAML blocks or NO_NEW_PATTERNS. No explanation, no preamble."
|
|
108
|
-
|
|
109
|
-
# ---------------------------------------------------------------------------
|
|
110
|
-
# Run analysis with Haiku
|
|
111
|
-
# ---------------------------------------------------------------------------
|
|
112
|
-
echo "Analyzing patterns with Haiku..."
|
|
113
|
-
RESULT=$(echo "$ANALYSIS_PROMPT" | claude --model haiku --print -p - 2>/dev/null) || {
|
|
114
|
-
echo "Analysis failed — claude CLI error. Try running manually."
|
|
115
|
-
exit 1
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
if [[ "$RESULT" == "NO_NEW_PATTERNS" ]] || [[ -z "$RESULT" ]]; then
|
|
119
|
-
echo "No new patterns detected yet. Keep using Claude Code — patterns emerge over time."
|
|
120
|
-
exit 0
|
|
121
|
-
fi
|
|
122
|
-
|
|
123
|
-
# ---------------------------------------------------------------------------
|
|
124
|
-
# Write instinct YAML files
|
|
125
|
-
# ---------------------------------------------------------------------------
|
|
126
|
-
mkdir -p "$PROJECT_DIR"
|
|
127
|
-
|
|
128
|
-
NEW_COUNT=0
|
|
129
|
-
INSTINCT_ID=""
|
|
130
|
-
BLOCK=""
|
|
131
|
-
|
|
132
|
-
while IFS= read -r line; do
|
|
133
|
-
if [[ "$line" == "---" ]] && [[ -n "$BLOCK" ]]; then
|
|
134
|
-
if [[ -n "$INSTINCT_ID" ]]; then
|
|
135
|
-
DEST="${PROJECT_DIR}/${INSTINCT_ID}.yaml"
|
|
136
|
-
printf '%s\n' "$BLOCK" > "$DEST"
|
|
137
|
-
echo " + ${INSTINCT_ID} -> ${DEST}"
|
|
138
|
-
NEW_COUNT=$((NEW_COUNT + 1))
|
|
139
|
-
fi
|
|
140
|
-
INSTINCT_ID=""
|
|
141
|
-
BLOCK=""
|
|
142
|
-
else
|
|
143
|
-
BLOCK="${BLOCK}${line}"$'\n'
|
|
144
|
-
if [[ "$line" =~ ^id:\ (.+) ]]; then
|
|
145
|
-
INSTINCT_ID="${BASH_REMATCH[1]}"
|
|
146
|
-
INSTINCT_ID="${INSTINCT_ID//\"/}"
|
|
147
|
-
INSTINCT_ID="${INSTINCT_ID//\'/}"
|
|
148
|
-
fi
|
|
149
|
-
fi
|
|
150
|
-
done <<< "$RESULT"
|
|
151
|
-
|
|
152
|
-
# Handle last block
|
|
153
|
-
if [[ -n "$INSTINCT_ID" ]] && [[ -n "$BLOCK" ]]; then
|
|
154
|
-
DEST="${PROJECT_DIR}/${INSTINCT_ID}.yaml"
|
|
155
|
-
printf '%s\n' "$BLOCK" > "$DEST"
|
|
156
|
-
echo " + ${INSTINCT_ID} -> ${DEST}"
|
|
157
|
-
NEW_COUNT=$((NEW_COUNT + 1))
|
|
158
|
-
fi
|
|
159
|
-
|
|
160
|
-
echo ""
|
|
161
|
-
echo "Created ${NEW_COUNT} new instinct(s) in ${PROJECT_DIR}/"
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# analyze.sh — Read observations.jsonl, detect patterns, create instinct YAML files
|
|
3
|
+
# Runs via /continuous-improvement command. Uses claude CLI with Haiku for cost-efficient analysis.
|
|
4
|
+
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
INSTINCTS_DIR="${HOME}/.claude/instincts"
|
|
8
|
+
|
|
9
|
+
# ---------------------------------------------------------------------------
|
|
10
|
+
# Detect project
|
|
11
|
+
# ---------------------------------------------------------------------------
|
|
12
|
+
PROJECT_ROOT=""
|
|
13
|
+
if [[ -n "${CLAUDE_PROJECT_DIR:-}" && -d "${CLAUDE_PROJECT_DIR}" ]]; then
|
|
14
|
+
PROJECT_ROOT="${CLAUDE_PROJECT_DIR}"
|
|
15
|
+
fi
|
|
16
|
+
if [[ -z "$PROJECT_ROOT" ]]; then
|
|
17
|
+
PROJECT_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || true)"
|
|
18
|
+
fi
|
|
19
|
+
if [[ -z "$PROJECT_ROOT" ]]; then
|
|
20
|
+
PROJECT_ROOT="global"
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
# Use shasum on macOS, sha256sum on Linux
|
|
24
|
+
if command -v sha256sum &>/dev/null; then
|
|
25
|
+
PROJECT_HASH="$(printf '%s' "$PROJECT_ROOT" | sha256sum | cut -c1-12)"
|
|
26
|
+
elif command -v shasum &>/dev/null; then
|
|
27
|
+
PROJECT_HASH="$(printf '%s' "$PROJECT_ROOT" | shasum -a 256 | cut -c1-12)"
|
|
28
|
+
else
|
|
29
|
+
# Fallback: use project root basename if no hashing available
|
|
30
|
+
PROJECT_HASH="$(basename "$PROJECT_ROOT" | tr -cd 'a-zA-Z0-9' | cut -c1-12)"
|
|
31
|
+
fi
|
|
32
|
+
PROJECT_NAME="$(basename "${PROJECT_ROOT%.git}")"
|
|
33
|
+
PROJECT_DIR="${INSTINCTS_DIR}/${PROJECT_HASH}"
|
|
34
|
+
OBS_FILE="${PROJECT_DIR}/observations.jsonl"
|
|
35
|
+
|
|
36
|
+
# ---------------------------------------------------------------------------
|
|
37
|
+
# Check observations exist
|
|
38
|
+
# ---------------------------------------------------------------------------
|
|
39
|
+
if [[ ! -f "$OBS_FILE" ]] || [[ ! -s "$OBS_FILE" ]]; then
|
|
40
|
+
echo "No observations found at ${OBS_FILE}"
|
|
41
|
+
echo "Use Claude Code with hooks installed to generate observations."
|
|
42
|
+
exit 0
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
OBS_COUNT=$(wc -l < "$OBS_FILE")
|
|
46
|
+
echo "Found ${OBS_COUNT} observations in ${OBS_FILE}"
|
|
47
|
+
|
|
48
|
+
if (( OBS_COUNT < 20 )); then
|
|
49
|
+
echo "Need at least 20 observations for meaningful analysis. Keep using Claude Code (${OBS_COUNT}/20)."
|
|
50
|
+
exit 0
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
# ---------------------------------------------------------------------------
|
|
54
|
+
# Read existing instincts to avoid duplicates
|
|
55
|
+
# ---------------------------------------------------------------------------
|
|
56
|
+
EXISTING_INSTINCTS=""
|
|
57
|
+
for f in "${PROJECT_DIR}"/*.yaml "${INSTINCTS_DIR}/global"/*.yaml; do
|
|
58
|
+
[[ -f "$f" ]] && EXISTING_INSTINCTS="${EXISTING_INSTINCTS}$(cat "$f")"$'\n'
|
|
59
|
+
done
|
|
60
|
+
|
|
61
|
+
# ---------------------------------------------------------------------------
|
|
62
|
+
# Take last 500 observations
|
|
63
|
+
# ---------------------------------------------------------------------------
|
|
64
|
+
RECENT_OBS=$(tail -500 "$OBS_FILE")
|
|
65
|
+
|
|
66
|
+
# ---------------------------------------------------------------------------
|
|
67
|
+
# Build analysis prompt
|
|
68
|
+
# ---------------------------------------------------------------------------
|
|
69
|
+
ANALYSIS_PROMPT="Analyze these Claude Code session observations and extract behavioral patterns as instinct YAML files.
|
|
70
|
+
|
|
71
|
+
OBSERVATIONS (JSONL — each line is a tool call):
|
|
72
|
+
${RECENT_OBS}
|
|
73
|
+
|
|
74
|
+
EXISTING INSTINCTS (already learned — do NOT duplicate these):
|
|
75
|
+
${EXISTING_INSTINCTS}
|
|
76
|
+
|
|
77
|
+
YOUR TASK:
|
|
78
|
+
1. Look for REPEATED PATTERNS — same tool sequence used 3+ times
|
|
79
|
+
2. Look for ERROR-THEN-FIX sequences — tool fails, next tools fix it
|
|
80
|
+
3. Look for TOOL PREFERENCES — one tool consistently chosen over alternatives
|
|
81
|
+
4. Look for WORKFLOW PATTERNS — consistent ordering of operations
|
|
82
|
+
5. Look for USER CORRECTIONS — user says no/stop/don't after an action
|
|
83
|
+
|
|
84
|
+
OUTPUT FORMAT — output ONLY new instincts as YAML blocks, separated by ---:
|
|
85
|
+
|
|
86
|
+
id: descriptive-kebab-case-id
|
|
87
|
+
trigger: \"when [specific situation]\"
|
|
88
|
+
confidence: 0.5
|
|
89
|
+
domain: workflow|tooling|testing|patterns
|
|
90
|
+
source: observation
|
|
91
|
+
scope: project
|
|
92
|
+
project_id: ${PROJECT_HASH}
|
|
93
|
+
created: \"$(date -u +%Y-%m-%d)\"
|
|
94
|
+
last_seen: \"$(date -u +%Y-%m-%d)\"
|
|
95
|
+
observation_count: [number of times pattern was seen]
|
|
96
|
+
---
|
|
97
|
+
[One sentence describing the specific actionable behavior]
|
|
98
|
+
|
|
99
|
+
Rules:
|
|
100
|
+
- Only create instincts for patterns seen 3+ times
|
|
101
|
+
- Start confidence at 0.5 (suggest level)
|
|
102
|
+
- Be specific and actionable (not vague advice)
|
|
103
|
+
- Different from existing instincts listed above
|
|
104
|
+
|
|
105
|
+
If no new patterns are found, output exactly: NO_NEW_PATTERNS
|
|
106
|
+
|
|
107
|
+
Output ONLY the YAML blocks or NO_NEW_PATTERNS. No explanation, no preamble."
|
|
108
|
+
|
|
109
|
+
# ---------------------------------------------------------------------------
|
|
110
|
+
# Run analysis with Haiku
|
|
111
|
+
# ---------------------------------------------------------------------------
|
|
112
|
+
echo "Analyzing patterns with Haiku..."
|
|
113
|
+
RESULT=$(echo "$ANALYSIS_PROMPT" | claude --model haiku --print -p - 2>/dev/null) || {
|
|
114
|
+
echo "Analysis failed — claude CLI error. Try running manually."
|
|
115
|
+
exit 1
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if [[ "$RESULT" == "NO_NEW_PATTERNS" ]] || [[ -z "$RESULT" ]]; then
|
|
119
|
+
echo "No new patterns detected yet. Keep using Claude Code — patterns emerge over time."
|
|
120
|
+
exit 0
|
|
121
|
+
fi
|
|
122
|
+
|
|
123
|
+
# ---------------------------------------------------------------------------
|
|
124
|
+
# Write instinct YAML files
|
|
125
|
+
# ---------------------------------------------------------------------------
|
|
126
|
+
mkdir -p "$PROJECT_DIR"
|
|
127
|
+
|
|
128
|
+
NEW_COUNT=0
|
|
129
|
+
INSTINCT_ID=""
|
|
130
|
+
BLOCK=""
|
|
131
|
+
|
|
132
|
+
while IFS= read -r line; do
|
|
133
|
+
if [[ "$line" == "---" ]] && [[ -n "$BLOCK" ]]; then
|
|
134
|
+
if [[ -n "$INSTINCT_ID" ]]; then
|
|
135
|
+
DEST="${PROJECT_DIR}/${INSTINCT_ID}.yaml"
|
|
136
|
+
printf '%s\n' "$BLOCK" > "$DEST"
|
|
137
|
+
echo " + ${INSTINCT_ID} -> ${DEST}"
|
|
138
|
+
NEW_COUNT=$((NEW_COUNT + 1))
|
|
139
|
+
fi
|
|
140
|
+
INSTINCT_ID=""
|
|
141
|
+
BLOCK=""
|
|
142
|
+
else
|
|
143
|
+
BLOCK="${BLOCK}${line}"$'\n'
|
|
144
|
+
if [[ "$line" =~ ^id:\ (.+) ]]; then
|
|
145
|
+
INSTINCT_ID="${BASH_REMATCH[1]}"
|
|
146
|
+
INSTINCT_ID="${INSTINCT_ID//\"/}"
|
|
147
|
+
INSTINCT_ID="${INSTINCT_ID//\'/}"
|
|
148
|
+
fi
|
|
149
|
+
fi
|
|
150
|
+
done <<< "$RESULT"
|
|
151
|
+
|
|
152
|
+
# Handle last block
|
|
153
|
+
if [[ -n "$INSTINCT_ID" ]] && [[ -n "$BLOCK" ]]; then
|
|
154
|
+
DEST="${PROJECT_DIR}/${INSTINCT_ID}.yaml"
|
|
155
|
+
printf '%s\n' "$BLOCK" > "$DEST"
|
|
156
|
+
echo " + ${INSTINCT_ID} -> ${DEST}"
|
|
157
|
+
NEW_COUNT=$((NEW_COUNT + 1))
|
|
158
|
+
fi
|
|
159
|
+
|
|
160
|
+
echo ""
|
|
161
|
+
echo "Created ${NEW_COUNT} new instinct(s) in ${PROJECT_DIR}/"
|
package/bin/backfill.mjs
CHANGED
|
@@ -27,25 +27,25 @@ const args = process.argv.slice(2);
|
|
|
27
27
|
const DRY_RUN = args.includes("--dry-run");
|
|
28
28
|
const HELP = args.includes("--help") || args.includes("-h");
|
|
29
29
|
if (HELP) {
|
|
30
|
-
console.log(`
|
|
31
|
-
backfill — Tag legacy thin-schema observation rows.
|
|
32
|
-
|
|
33
|
-
Usage:
|
|
34
|
-
npx continuous-improvement backfill Tag rows in place
|
|
35
|
-
npx continuous-improvement backfill --dry-run Report counts, write nothing
|
|
36
|
-
|
|
37
|
-
What it does:
|
|
38
|
-
Walks ~/.claude/instincts/<hash>/observations.jsonl files and adds a
|
|
39
|
-
schema field ("thin" or "rich") to every row that lacks one. Thin rows
|
|
40
|
-
came from the legacy bash fallback (jq missing) and have no input_summary;
|
|
41
|
-
rich rows came from the Node observer and have full tool_input.command /
|
|
42
|
-
Edit.file_path / etc.
|
|
43
|
-
|
|
44
|
-
Output:
|
|
45
|
-
- observations.jsonl rewritten in place (original kept as .bak)
|
|
46
|
-
- backfill-summary.json with per-project counts
|
|
47
|
-
|
|
48
|
-
Idempotent. Always exits 0 — failures go to stderr only.
|
|
30
|
+
console.log(`
|
|
31
|
+
backfill — Tag legacy thin-schema observation rows.
|
|
32
|
+
|
|
33
|
+
Usage:
|
|
34
|
+
npx continuous-improvement backfill Tag rows in place
|
|
35
|
+
npx continuous-improvement backfill --dry-run Report counts, write nothing
|
|
36
|
+
|
|
37
|
+
What it does:
|
|
38
|
+
Walks ~/.claude/instincts/<hash>/observations.jsonl files and adds a
|
|
39
|
+
schema field ("thin" or "rich") to every row that lacks one. Thin rows
|
|
40
|
+
came from the legacy bash fallback (jq missing) and have no input_summary;
|
|
41
|
+
rich rows came from the Node observer and have full tool_input.command /
|
|
42
|
+
Edit.file_path / etc.
|
|
43
|
+
|
|
44
|
+
Output:
|
|
45
|
+
- observations.jsonl rewritten in place (original kept as .bak)
|
|
46
|
+
- backfill-summary.json with per-project counts
|
|
47
|
+
|
|
48
|
+
Idempotent. Always exits 0 — failures go to stderr only.
|
|
49
49
|
`);
|
|
50
50
|
process.exit(0);
|
|
51
51
|
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Doc Runtime-Claims Check
|
|
4
|
+
*
|
|
5
|
+
* Codifies the audit-twice rule (memory: feedback_grep_hook_before_claim).
|
|
6
|
+
*
|
|
7
|
+
* Any user-facing line that claims a runtime hook / PreToolUse gate /
|
|
8
|
+
* physical block must be accompanied by a `hooks/<file>.mjs` reference
|
|
9
|
+
* inside a ±5-line window. Without that anchor, the doc is making a
|
|
10
|
+
* claim a future reader cannot verify against the actual filesystem.
|
|
11
|
+
*
|
|
12
|
+
* Origin: PR #105 shipped a smoke test that promised gateguard would
|
|
13
|
+
* physically block, when the hook did not yet exist. PR #108 built the
|
|
14
|
+
* hook. PR #115 reverted the inverse drift after the hook shipped but
|
|
15
|
+
* docs still said "roadmap." This lint locks the audit-twice rule into
|
|
16
|
+
* automation so the next runtime claim cannot land without its anchor.
|
|
17
|
+
*
|
|
18
|
+
* Scope: QUICKSTART.md, README.md, skills/*.md.
|
|
19
|
+
* Out of scope: bundle mirrors under plugins/, docs/, third-party/.
|
|
20
|
+
*
|
|
21
|
+
* Trigger phrases (case-insensitive substring match on the line):
|
|
22
|
+
* - "PreToolUse hook"
|
|
23
|
+
* - "physically block" (catches "physically blocks", "physical block")
|
|
24
|
+
* - "runtime gate"
|
|
25
|
+
*
|
|
26
|
+
* Deliberately narrow per the spec that authorized this lint. "runtime
|
|
27
|
+
* hook" was considered and dropped: too prone to false positives on
|
|
28
|
+
* disclaimers ("not a runtime hook", "no runtime hook is bundled").
|
|
29
|
+
* Future trigger additions need an explicit owner decision; do not bolt
|
|
30
|
+
* on phrases just because they sound related.
|
|
31
|
+
*
|
|
32
|
+
* Anchor: any reference matching `hooks/<name>.mjs` (case-insensitive)
|
|
33
|
+
* inside the ±5-line window (the trigger line itself plus 5 lines above
|
|
34
|
+
* and 5 lines below).
|
|
35
|
+
*
|
|
36
|
+
* Usage:
|
|
37
|
+
* node bin/check-doc-runtime-claims.mjs # Check the current repo
|
|
38
|
+
* node bin/check-doc-runtime-claims.mjs <repo-root> # Check a specific repo root
|
|
39
|
+
*
|
|
40
|
+
* Exit codes:
|
|
41
|
+
* 0 — every runtime-claim line has an in-window hooks/ anchor
|
|
42
|
+
* 1 — at least one claim line is unanchored
|
|
43
|
+
*/
|
|
44
|
+
import { readFileSync, readdirSync } from "node:fs";
|
|
45
|
+
import { join } from "node:path";
|
|
46
|
+
import { argv, cwd, exit } from "node:process";
|
|
47
|
+
const SCAN_FILES = ["QUICKSTART.md", "README.md"];
|
|
48
|
+
const SCAN_SKILL_DIR = "skills";
|
|
49
|
+
const ANCHOR_WINDOW = 5;
|
|
50
|
+
const TRIGGER_PHRASES = [
|
|
51
|
+
"pretooluse hook",
|
|
52
|
+
"physically block",
|
|
53
|
+
"runtime gate",
|
|
54
|
+
];
|
|
55
|
+
const ANCHOR_PATTERN = /hooks\/[a-z0-9-]+\.mjs/i;
|
|
56
|
+
function listSkillFiles(repoRoot) {
|
|
57
|
+
const skillsDir = join(repoRoot, SCAN_SKILL_DIR);
|
|
58
|
+
let entries;
|
|
59
|
+
try {
|
|
60
|
+
entries = readdirSync(skillsDir);
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return [];
|
|
64
|
+
}
|
|
65
|
+
return entries
|
|
66
|
+
.filter((f) => /^[a-z][a-z0-9-]*\.md$/.test(f))
|
|
67
|
+
.map((f) => join(SCAN_SKILL_DIR, f))
|
|
68
|
+
.sort();
|
|
69
|
+
}
|
|
70
|
+
function scanFile(repoRoot, relPath) {
|
|
71
|
+
const fullPath = join(repoRoot, relPath);
|
|
72
|
+
let content;
|
|
73
|
+
try {
|
|
74
|
+
content = readFileSync(fullPath, "utf8");
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return [];
|
|
78
|
+
}
|
|
79
|
+
const lines = content.split(/\r?\n/);
|
|
80
|
+
const violations = [];
|
|
81
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
82
|
+
const lower = lines[i].toLowerCase();
|
|
83
|
+
const matchedPhrase = TRIGGER_PHRASES.find((p) => lower.includes(p));
|
|
84
|
+
if (!matchedPhrase)
|
|
85
|
+
continue;
|
|
86
|
+
const start = Math.max(0, i - ANCHOR_WINDOW);
|
|
87
|
+
const end = Math.min(lines.length - 1, i + ANCHOR_WINDOW);
|
|
88
|
+
const window = lines.slice(start, end + 1).join("\n");
|
|
89
|
+
if (ANCHOR_PATTERN.test(window))
|
|
90
|
+
continue;
|
|
91
|
+
violations.push({
|
|
92
|
+
file: relPath,
|
|
93
|
+
line: i + 1,
|
|
94
|
+
text: lines[i].trim(),
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
return violations;
|
|
98
|
+
}
|
|
99
|
+
function main() {
|
|
100
|
+
const repoRoot = argv[2] ?? cwd();
|
|
101
|
+
const files = [...SCAN_FILES, ...listSkillFiles(repoRoot)];
|
|
102
|
+
const allViolations = [];
|
|
103
|
+
for (const file of files) {
|
|
104
|
+
allViolations.push(...scanFile(repoRoot, file));
|
|
105
|
+
}
|
|
106
|
+
if (allViolations.length === 0) {
|
|
107
|
+
console.log(`OK doc-runtime-claims: every runtime-claim line in ${files.length} scanned file(s) has a hooks/<name>.mjs anchor within ±${ANCHOR_WINDOW} lines.`);
|
|
108
|
+
exit(0);
|
|
109
|
+
}
|
|
110
|
+
console.error(`FAIL doc-runtime-claims: ${allViolations.length} unanchored runtime-claim line(s) found.`);
|
|
111
|
+
console.error(`Each line below contains a runtime-claim phrase but has no hooks/<name>.mjs reference within ±${ANCHOR_WINDOW} lines.`);
|
|
112
|
+
console.error("Add the hook file path inline so a reader can verify the claim against the filesystem.");
|
|
113
|
+
console.error("");
|
|
114
|
+
for (const v of allViolations) {
|
|
115
|
+
console.error(` ${v.file}:${v.line}`);
|
|
116
|
+
console.error(` ${v.text}`);
|
|
117
|
+
}
|
|
118
|
+
exit(1);
|
|
119
|
+
}
|
|
120
|
+
main();
|
|
@@ -80,6 +80,7 @@ async function writePluginBundleReadme() {
|
|
|
80
80
|
"- `.claude-plugin/marketplace.json`",
|
|
81
81
|
"- `skills/`",
|
|
82
82
|
"- `commands/`",
|
|
83
|
+
"- `agents/` — `code-reviewer`, `security-auditor`, `test-engineer` personas (auto-discovered Claude Code subagents; pattern from addy/agent-skills)",
|
|
83
84
|
"- `hooks/`",
|
|
84
85
|
"- `bin/mcp-server.mjs`",
|
|
85
86
|
"- `bin/observe.mjs`",
|
|
@@ -137,6 +138,7 @@ async function writePluginBundle() {
|
|
|
137
138
|
writeJson(join(PLUGIN_BUNDLE_DIR, ".claude-plugin", "plugin.json"), getClaudePluginManifest()),
|
|
138
139
|
writeJson(join(PLUGIN_BUNDLE_DIR, ".claude-plugin", "marketplace.json"), getClaudePluginMarketplaceManifest()),
|
|
139
140
|
copyDirectory(join(REPO_ROOT, "commands"), join(PLUGIN_BUNDLE_DIR, "commands")),
|
|
141
|
+
copyDirectory(join(REPO_ROOT, "agents"), join(PLUGIN_BUNDLE_DIR, "agents")),
|
|
140
142
|
copyDirectory(join(REPO_ROOT, "hooks"), join(PLUGIN_BUNDLE_DIR, "hooks")),
|
|
141
143
|
copyDirectory(join(REPO_ROOT, "instinct-packs"), join(PLUGIN_BUNDLE_DIR, "instinct-packs")),
|
|
142
144
|
copyDirectory(join(REPO_ROOT, "templates", "planning-with-files"), join(PLUGIN_BUNDLE_DIR, "templates", "planning-with-files")),
|
package/bin/hook-stats.mjs
CHANGED
|
@@ -46,27 +46,27 @@ import { platform } from "node:os";
|
|
|
46
46
|
import { join } from "node:path";
|
|
47
47
|
import { argv, cwd, exit, stderr, stdout } from "node:process";
|
|
48
48
|
import { resolveHomeDir } from "../lib/resolve-home-dir.mjs";
|
|
49
|
-
const USAGE = `Usage: node bin/hook-stats.mjs [options]
|
|
50
|
-
|
|
51
|
-
Reads JSONL telemetry from <HOME>/.claude/hook-telemetry/*.jsonl and
|
|
52
|
-
prints per-hook aggregate counts over a recent time window.
|
|
53
|
-
|
|
54
|
-
Options:
|
|
55
|
-
--hours=<n> Time window in hours (default: 24)
|
|
56
|
-
--hash=<hash> Only read this single <hash>.jsonl file
|
|
57
|
-
(default: sha256 of the current working directory,
|
|
58
|
-
normalized to forward slashes and lowercased on
|
|
59
|
-
Windows, then first 12 hex chars)
|
|
60
|
-
--telemetry-dir=<path> Override telemetry dir
|
|
61
|
-
(default: <HOME>/.claude/hook-telemetry)
|
|
62
|
-
--help Show this help and exit 0
|
|
63
|
-
|
|
64
|
-
Output:
|
|
65
|
-
One line per hook: "<hook> last <hours>h: pass=<n> block=<n>
|
|
66
|
-
skip-short=<n> total=<n> avg-duration=<X>ms".
|
|
67
|
-
If there are no records in the window: "no records in last <hours>h".
|
|
68
|
-
|
|
69
|
-
The reader is parse-tolerant: malformed JSONL lines are skipped silently.
|
|
49
|
+
const USAGE = `Usage: node bin/hook-stats.mjs [options]
|
|
50
|
+
|
|
51
|
+
Reads JSONL telemetry from <HOME>/.claude/hook-telemetry/*.jsonl and
|
|
52
|
+
prints per-hook aggregate counts over a recent time window.
|
|
53
|
+
|
|
54
|
+
Options:
|
|
55
|
+
--hours=<n> Time window in hours (default: 24)
|
|
56
|
+
--hash=<hash> Only read this single <hash>.jsonl file
|
|
57
|
+
(default: sha256 of the current working directory,
|
|
58
|
+
normalized to forward slashes and lowercased on
|
|
59
|
+
Windows, then first 12 hex chars)
|
|
60
|
+
--telemetry-dir=<path> Override telemetry dir
|
|
61
|
+
(default: <HOME>/.claude/hook-telemetry)
|
|
62
|
+
--help Show this help and exit 0
|
|
63
|
+
|
|
64
|
+
Output:
|
|
65
|
+
One line per hook: "<hook> last <hours>h: pass=<n> block=<n>
|
|
66
|
+
skip-short=<n> total=<n> avg-duration=<X>ms".
|
|
67
|
+
If there are no records in the window: "no records in last <hours>h".
|
|
68
|
+
|
|
69
|
+
The reader is parse-tolerant: malformed JSONL lines are skipped silently.
|
|
70
70
|
`;
|
|
71
71
|
function parseArgs(rawArgs) {
|
|
72
72
|
const opts = {
|