claude-capsule-kit 3.0.0

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.
Files changed (107) hide show
  1. package/README.md +281 -0
  2. package/agents/agent-developer.md +206 -0
  3. package/agents/architecture-explorer.md +90 -0
  4. package/agents/brainstorm-coordinator.md +120 -0
  5. package/agents/code-reviewer.md +135 -0
  6. package/agents/context-librarian.md +227 -0
  7. package/agents/context-manager.md +151 -0
  8. package/agents/database-architect.md +107 -0
  9. package/agents/database-navigator.md +136 -0
  10. package/agents/debugger.md +121 -0
  11. package/agents/devops-sre.md +102 -0
  12. package/agents/error-detective.md +128 -0
  13. package/agents/git-workflow-manager.md +212 -0
  14. package/agents/github-issue-tracker.md +252 -0
  15. package/agents/product-dx-specialist.md +99 -0
  16. package/agents/refactoring-specialist.md +159 -0
  17. package/agents/security-engineer.md +102 -0
  18. package/agents/session-summarizer.md +126 -0
  19. package/agents/system-architect.md +103 -0
  20. package/bin/cck.js +1624 -0
  21. package/commands/crew-setup.md +75 -0
  22. package/commands/load-session.md +68 -0
  23. package/commands/sessions.md +55 -0
  24. package/commands/statusline.md +51 -0
  25. package/commands/sync-disable.md +35 -0
  26. package/commands/sync-enable.md +32 -0
  27. package/commands/sync.md +31 -0
  28. package/crew/lib/activity-monitor.js +128 -0
  29. package/crew/lib/crew-config-reader.js +255 -0
  30. package/crew/lib/health-monitor.js +171 -0
  31. package/crew/lib/merge-pilot.js +340 -0
  32. package/crew/lib/prompt-generator.js +268 -0
  33. package/crew/lib/role-presets.js +63 -0
  34. package/crew/lib/task-decomposer.js +382 -0
  35. package/crew/lib/team-spawner.sh +557 -0
  36. package/crew/lib/team-state-manager.js +155 -0
  37. package/crew/lib/worktree-gc.js +357 -0
  38. package/crew/lib/worktree-manager.sh +700 -0
  39. package/docs/AGENT_ROUTING_GUIDE.md +655 -0
  40. package/docs/AGENT_TEAMS_WORKTREE_MODE.md +681 -0
  41. package/docs/BEST_PRACTICES.md +194 -0
  42. package/docs/CAPSULE_DEGRADATION_RCA.md +577 -0
  43. package/docs/SKILLS_ORCHESTRATION_ARCHITECTURE.md +455 -0
  44. package/docs/SUPER_CLAUDE_SYSTEM_ARCHITECTURE.md +1647 -0
  45. package/docs/TOOL_ENFORCEMENT_REFERENCE.md +418 -0
  46. package/hooks/check-refresh-needed.sh +77 -0
  47. package/hooks/detect-changes.sh +90 -0
  48. package/hooks/keyword-triggers.sh +66 -0
  49. package/hooks/lib/crew-detect.js +241 -0
  50. package/hooks/lib/handoff-generator.js +158 -0
  51. package/hooks/load-from-journal.sh +41 -0
  52. package/hooks/post-tool-use.js +212 -0
  53. package/hooks/pre-compact.js +77 -0
  54. package/hooks/pre-edit-analysis.sh +68 -0
  55. package/hooks/pre-tool-use.sh +212 -0
  56. package/hooks/prompt-submit-memory.sh +87 -0
  57. package/hooks/quality-check.sh +48 -0
  58. package/hooks/session-end.js +133 -0
  59. package/hooks/session-start.js +439 -0
  60. package/hooks/stop.sh +66 -0
  61. package/hooks/suggest-discoveries.sh +84 -0
  62. package/hooks/summarize-session.sh +122 -0
  63. package/hooks/sync-to-journal.sh +77 -0
  64. package/hooks/sync-todowrite.sh +37 -0
  65. package/hooks/tool-auto-suggest.sh +77 -0
  66. package/hooks/user-prompt-submit.sh +71 -0
  67. package/lib/audit-logger.sh +120 -0
  68. package/lib/sandbox-validator.sh +194 -0
  69. package/lib/tool-runner.sh +274 -0
  70. package/package.json +67 -0
  71. package/scripts/postinstall.js +4 -0
  72. package/scripts/show-capsule-visual.sh +103 -0
  73. package/scripts/show-capsule.sh +113 -0
  74. package/scripts/show-deps-tree.sh +66 -0
  75. package/scripts/show-stats-dashboard.sh +52 -0
  76. package/scripts/show-stats.sh +79 -0
  77. package/skills/code-review/SKILL.md +520 -0
  78. package/skills/crew/SKILL.md +395 -0
  79. package/skills/debug/SKILL.md +473 -0
  80. package/skills/deep-context/SKILL.md +446 -0
  81. package/skills/task-router/SKILL.md +390 -0
  82. package/skills/workflow/SKILL.md +370 -0
  83. package/templates/CLAUDE.md +124 -0
  84. package/templates/crew-config.json +21 -0
  85. package/templates/settings-hooks.json +74 -0
  86. package/templates/statusline-command.sh +208 -0
  87. package/tools/context-query/context-query.js +312 -0
  88. package/tools/context-query/context-query.sh +5 -0
  89. package/tools/context-query/tool.json +42 -0
  90. package/tools/dependency-scanner/dependency-scanner.sh +53 -0
  91. package/tools/dependency-scanner/tool.json +8 -0
  92. package/tools/find-circular/find-circular.sh +41 -0
  93. package/tools/find-circular/tool.json +36 -0
  94. package/tools/find-dead-code/find-dead-code.sh +41 -0
  95. package/tools/find-dead-code/tool.json +36 -0
  96. package/tools/impact-analysis/impact-analysis.sh +99 -0
  97. package/tools/impact-analysis/tool.json +38 -0
  98. package/tools/progressive-reader/progressive-reader.sh +14 -0
  99. package/tools/progressive-reader/tool.json +69 -0
  100. package/tools/query-deps/query-deps.sh +69 -0
  101. package/tools/query-deps/tool.json +34 -0
  102. package/tools/stats/stats.js +299 -0
  103. package/tools/stats/stats.sh +5 -0
  104. package/tools/stats/tool.json +34 -0
  105. package/tools/token-counter/README.md +73 -0
  106. package/tools/token-counter/token-counter.py +202 -0
  107. package/tools/token-counter/tool.json +40 -0
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * PreCompact Hook - Session Continuity Before Context Compaction
4
+ *
5
+ * Fires right before Claude Code auto-compacts the context window.
6
+ * Saves a rich handoff document to capsule.db so the post-compaction
7
+ * session can resume with full context of what was happening.
8
+ *
9
+ * This is the most critical moment to save state — we still have
10
+ * full context but it's about to be wiped.
11
+ */
12
+
13
+ import { Blink } from 'blink-query';
14
+ import { createInterface } from 'readline';
15
+ import { execSync } from 'child_process';
16
+ import { getCapsuleDbPath, getCrewIdentity, crewNamespace, getProjectHash, isDisabled } from './lib/crew-detect.js';
17
+ import { generateHandoff } from './lib/handoff-generator.js';
18
+
19
+ function getCurrentBranch() {
20
+ try {
21
+ return execSync('git rev-parse --abbrev-ref HEAD', {
22
+ encoding: 'utf-8',
23
+ stdio: ['pipe', 'pipe', 'pipe']
24
+ }).trim();
25
+ } catch {
26
+ return null;
27
+ }
28
+ }
29
+
30
+ async function main() {
31
+ try {
32
+ const rl = createInterface({ input: process.stdin });
33
+ let inputJson = '';
34
+ for await (const line of rl) {
35
+ inputJson += line;
36
+ }
37
+
38
+ const input = JSON.parse(inputJson);
39
+ const sessionId = input.session_id || 'default';
40
+ if (isDisabled()) process.exit(0);
41
+
42
+ const projectHash = getProjectHash();
43
+ const crewId = getCrewIdentity();
44
+ const dbPath = getCapsuleDbPath();
45
+ const branch = getCurrentBranch();
46
+
47
+ // Generate handoff document while we still have full context
48
+ const handoff = generateHandoff(dbPath, sessionId, crewId, projectHash);
49
+
50
+ const blink = new Blink({ dbPath });
51
+
52
+ // Save pre-compaction handoff (tagged distinctly so session-start can find the latest)
53
+ blink.save({
54
+ namespace: crewNamespace(`session/${sessionId}/handoff`, crewId, projectHash),
55
+ title: `Pre-compact handoff ${sessionId}`,
56
+ summary: handoff,
57
+ type: 'SUMMARY',
58
+ content: {
59
+ sessionId,
60
+ teammateName: crewId?.teammate_name || null,
61
+ branch,
62
+ trigger: 'pre-compact',
63
+ generatedAt: Date.now()
64
+ },
65
+ tags: ['handoff', 'pre-compact', sessionId, ...(crewId ? [crewId.teammate_name] : [])]
66
+ });
67
+
68
+ blink.close();
69
+ process.exit(0);
70
+
71
+ } catch (error) {
72
+ // Never block compaction — fail silently
73
+ process.exit(0);
74
+ }
75
+ }
76
+
77
+ main();
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env bash
2
+ # Pre-edit analysis - shows impact analysis before file modifications
3
+ # Auto-runs before significant edits to show which files might be affected
4
+
5
+ set -euo pipefail
6
+
7
+ FILE_PATH="${1:-}"
8
+
9
+ if [ -z "$FILE_PATH" ]; then
10
+ exit 0
11
+ fi
12
+
13
+ DEP_GRAPH="$HOME/.claude/dep-graph.toon"
14
+
15
+ if [ ! -f "$DEP_GRAPH" ]; then
16
+ TOOL_RUNNER_PATH="$HOME/.claude/cck/lib/tool-runner.sh"
17
+
18
+ if [ -f "$TOOL_RUNNER_PATH" ]; then
19
+ source "$TOOL_RUNNER_PATH"
20
+ if command -v run_tool &> /dev/null; then
21
+ run_tool dependency-scanner --path "$(pwd)" --output "$DEP_GRAPH" &> /dev/null || true
22
+ fi
23
+ fi
24
+ fi
25
+
26
+ if [ ! -f "$DEP_GRAPH" ]; then
27
+ exit 0
28
+ fi
29
+
30
+ # Source TOON parser
31
+ TOON_PARSER="$HOME/.claude/cck/lib/toon-parser.sh"
32
+ if [ -f "$TOON_PARSER" ]; then
33
+ source "$TOON_PARSER"
34
+ else
35
+ exit 0
36
+ fi
37
+
38
+ # Check if file exists in graph
39
+ if ! toon_file_exists "$DEP_GRAPH" "$FILE_PATH"; then
40
+ exit 0
41
+ fi
42
+
43
+ IMPORTER_COUNT=$(toon_count_importers "$DEP_GRAPH" "$FILE_PATH")
44
+
45
+ if [ "$IMPORTER_COUNT" -gt 0 ]; then
46
+ echo ""
47
+ echo "Impact Analysis for: $(basename "$FILE_PATH")"
48
+ echo " Files that import this: $IMPORTER_COUNT"
49
+
50
+ IMPORTERS=$(toon_get_importers "$DEP_GRAPH" "$FILE_PATH" | head -5)
51
+
52
+ if [ -n "$IMPORTERS" ]; then
53
+ echo " Affected files:"
54
+ echo "$IMPORTERS" | while read -r importer; do
55
+ echo " $(basename "$importer")"
56
+ done
57
+ fi
58
+
59
+ if [ "$IMPORTER_COUNT" -gt 5 ]; then
60
+ echo " ... and $((IMPORTER_COUNT - 5)) more"
61
+ fi
62
+
63
+ echo ""
64
+ echo " Run 'run_tool impact-analysis $FILE_PATH' for full analysis"
65
+ echo ""
66
+ fi
67
+
68
+ exit 0
@@ -0,0 +1,212 @@
1
+ #!/bin/bash
2
+
3
+ # Pre-Tool-Use Hook
4
+ # 1. Warns before redundant file reads to encourage using capsule data
5
+ # 2. Enforces Claude Capsule Kit tools for dependency analysis
6
+ # 3. Auto-logs file access to capsule
7
+ # Runs BEFORE each tool call
8
+ # Claude Code passes arguments via stdin as JSON, NOT positional args
9
+
10
+ set -euo pipefail
11
+
12
+ # Defensive check: Ensure CWD exists (can be invalid if directory was deleted)
13
+ if ! cd "$(pwd 2>/dev/null)" 2>/dev/null; then
14
+ cd "$HOME" 2>/dev/null || exit 0
15
+ fi
16
+
17
+ # CCK opt-out check
18
+ [ -f "$PWD/.cck-disable" ] && exit 0
19
+
20
+ # Read JSON from stdin (Claude Code's hook protocol)
21
+ INPUT_JSON=$(cat)
22
+
23
+ # Extract fields from JSON using python3
24
+ TOOL_NAME=$(echo "$INPUT_JSON" | python3 -c "import sys, json; print(json.load(sys.stdin).get('tool_name', ''))" 2>/dev/null || echo "")
25
+ TOOL_INPUT=$(echo "$INPUT_JSON" | python3 -c "import sys, json; import json as j; print(j.dumps(json.load(sys.stdin).get('tool_input', {})))" 2>/dev/null || echo "{}")
26
+
27
+ # Task tool interception - enforce dependency tools
28
+ if [ "$TOOL_NAME" == "Task" ]; then
29
+ # Extract prompt from Task tool input
30
+ TASK_PROMPT=$(echo "$TOOL_INPUT" | python3 -c "import sys, json; print(json.load(sys.stdin).get('prompt', ''))" 2>/dev/null || echo "")
31
+
32
+ if [ -n "$TASK_PROMPT" ]; then
33
+ # Convert to lowercase for pattern matching
34
+ PROMPT_LOWER=$(echo "$TASK_PROMPT" | tr '[:upper:]' '[:lower:]')
35
+
36
+ # Detect dependency-related queries
37
+ if echo "$PROMPT_LOWER" | grep -qE '(depend|import|require|module.*load|circular.*depend|who.*use|what.*import|find.*import)'; then
38
+ # Output JSON enforcement message (to stderr for informational display)
39
+ cat << 'EOF' >&2
40
+ {"type":"tool-enforcement","category":"dependency-analysis","warning":"Query appears to be about code dependencies","dontUse":{"tool":"Task","reason":"inefficient","issues":["Slower: Scans files one-by-one","Limited: Cannot detect circular dependencies","Expensive: High token usage"]},"useInstead":[{"name":"query-deps","useCase":"what imports X, who uses X","command":"bash $HOME/.claude/cck/tools/query-deps/query-deps.sh <file-path>"},{"name":"impact-analysis","useCase":"what would break if I change X","command":"bash $HOME/.claude/cck/tools/impact-analysis/impact-analysis.sh <file-path>"},{"name":"find-circular","useCase":"circular dependencies","command":"bash $HOME/.claude/cck/tools/find-circular/find-circular.sh"}],"benefit":"These tools are instant and read pre-built dependency graph"}
41
+ EOF
42
+ fi
43
+
44
+ # Detect file search queries
45
+ if echo "$PROMPT_LOWER" | grep -qE '(where.*file|find.*file|locate.*file|search.*file)' && ! echo "$PROMPT_LOWER" | grep -qE '(depend|import|require)'; then
46
+ # Output JSON suggestion message (to stderr for informational display)
47
+ cat << 'EOF' >&2
48
+ {"type":"tool-suggestion","category":"file-search","useInstead":{"tool":"Glob","reason":"faster-and-direct","pattern":"**/*<filename>*","description":"For finding files by name pattern"}}
49
+ EOF
50
+ fi
51
+
52
+ # Context-librarian suggestion for Task spawning (check for past agent findings)
53
+ SUBAGENT_TYPE=$(echo "$TOOL_INPUT" | python3 -c "import sys, json; print(json.load(sys.stdin).get('subagent_type', ''))" 2>/dev/null || echo "")
54
+
55
+ # Skip if already invoking context-librarian
56
+ if [ "$SUBAGENT_TYPE" != "context-librarian" ] && [ -f "$HOME/.claude/cck/state/session_subagents.log" ]; then
57
+ # Extract keywords from task prompt
58
+ KEYWORDS=$(echo "$TASK_PROMPT" | grep -oiE "(auth|database|schema|error|bug|architecture|api|routing|payment)" | head -1)
59
+
60
+ if [ -n "$KEYWORDS" ] && grep -qi "$KEYWORDS" "$HOME/.claude/cck/state/session_subagents.log" 2>/dev/null; then
61
+ cat << EOF >&2
62
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
63
+ 💡 PAST AGENT FINDINGS AVAILABLE
64
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
65
+
66
+ Agent: $SUBAGENT_TYPE
67
+ Topic: $KEYWORDS
68
+
69
+ Past findings exist in subagent logs.
70
+
71
+ Suggestion: Query context-librarian first:
72
+ Bash("$HOME/.claude/cck/tools/context-query/context-query.sh search $KEYWORDS")
73
+
74
+ This checks if similar work was already done (saves 30-60s).
75
+
76
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
77
+ EOF
78
+ fi
79
+ fi
80
+ fi
81
+
82
+ exit 0
83
+ fi
84
+
85
+ # Read tool monitoring and large file detection
86
+ if [ "$TOOL_NAME" != "Read" ]; then
87
+ exit 0
88
+ fi
89
+
90
+ FILE_PATH=$(echo "$TOOL_INPUT" | python3 -c "import sys, json; print(json.load(sys.stdin).get('file_path', ''))" 2>/dev/null || echo "")
91
+
92
+ # Find project root via git
93
+ PROJECT_ROOT="$PWD"
94
+ while [ "$PROJECT_ROOT" != "/" ] && [ ! -d "$PROJECT_ROOT/.git" ]; do
95
+ PROJECT_ROOT=$(dirname "$PROJECT_ROOT")
96
+ done
97
+ [ "$PROJECT_ROOT" = "/" ] && PROJECT_ROOT="$PWD"
98
+
99
+ # Check file size and block Read for large files (force progressive-reader)
100
+ if [ -n "$FILE_PATH" ]; then
101
+ RESOLVED_PATH=""
102
+
103
+ # Try multiple path resolutions
104
+ if [ -f "$FILE_PATH" ]; then
105
+ RESOLVED_PATH="$FILE_PATH"
106
+ elif [ -f "$PROJECT_ROOT/$FILE_PATH" ]; then
107
+ RESOLVED_PATH="$PROJECT_ROOT/$FILE_PATH"
108
+ elif [ -f "$(pwd)/$FILE_PATH" ]; then
109
+ RESOLVED_PATH="$(pwd)/$FILE_PATH"
110
+ fi
111
+
112
+ if [ -n "$RESOLVED_PATH" ]; then
113
+ # Skip size check for images and binary files (Claude handles these natively)
114
+ FILE_EXT="${RESOLVED_PATH##*.}"
115
+ FILE_EXT_LOWER=$(echo "$FILE_EXT" | tr '[:upper:]' '[:lower:]')
116
+
117
+ case "$FILE_EXT_LOWER" in
118
+ jpg|jpeg|png|gif|webp|svg|bmp|ico|pdf|ipynb)
119
+ # Allow images, PDFs, notebooks regardless of size
120
+ exit 0
121
+ ;;
122
+ esac
123
+
124
+ FILE_SIZE=$(stat -f%z "$RESOLVED_PATH" 2>/dev/null || stat -c%s "$RESOLVED_PATH" 2>/dev/null || echo "0")
125
+ FILE_SIZE_KB=$((FILE_SIZE / 1024))
126
+
127
+ if [ "$FILE_SIZE" -gt 51200 ]; then # 50KB threshold
128
+ echo "{\"decision\": \"block\", \"reason\": \"File ${FILE_SIZE_KB}KB exceeds 50KB. Use progressive-reader instead: \$HOME/.claude/bin/progressive-reader --path $FILE_PATH --list\"}"
129
+ exit 0
130
+ fi
131
+
132
+ # Context-librarian suggestion if file is in capsule
133
+ if [ -f "$HOME/.claude/cck/state/capsule.toon" ] && grep -q "$FILE_PATH" "$HOME/.claude/cck/state/capsule.toon" 2>/dev/null; then
134
+ FILE_AGE=$(grep "$FILE_PATH" "$HOME/.claude/cck/state/capsule.toon" | tail -1 | grep -oE '[0-9]+' | head -1 || echo "0")
135
+ FILE_AGE_MIN=$((FILE_AGE / 60))
136
+
137
+ if [ "$FILE_AGE_MIN" -lt 30 ]; then
138
+ FILE_BASENAME=$(basename "$FILE_PATH" .ts .js .go .py .tsx .jsx)
139
+ cat << EOF >&2
140
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
141
+ 💡 CONTEXT AVAILABLE
142
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
143
+
144
+ File: $FILE_PATH
145
+ Status: Already read ${FILE_AGE_MIN}m ago (in capsule)
146
+
147
+ Suggestion: Query context-librarian first (faster, 90% attention):
148
+ Bash("$HOME/.claude/cck/tools/context-query/context-query.sh search $FILE_BASENAME")
149
+
150
+ This retrieves focused context and avoids re-reading ~12,000 tokens.
151
+
152
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
153
+ EOF
154
+ fi
155
+ fi
156
+ fi
157
+ fi
158
+
159
+ if [ -z "$FILE_PATH" ]; then
160
+ exit 0
161
+ fi
162
+
163
+ # Tracking files
164
+ CCK_STATE_DIR="$HOME/.claude/cck/state"
165
+ mkdir -p "$CCK_STATE_DIR"
166
+ RECENT_READS_LOG="$CCK_STATE_DIR/recent_reads.log"
167
+ WARNINGS_SHOWN="$CCK_STATE_DIR/read_warnings_shown.log"
168
+
169
+ # Create logs if they don't exist
170
+ touch "$RECENT_READS_LOG"
171
+ touch "$WARNINGS_SHOWN"
172
+
173
+ # Check if we already warned about this file this session
174
+ if grep -q "^${FILE_PATH}$" "$WARNINGS_SHOWN" 2>/dev/null; then
175
+ exit 0
176
+ fi
177
+
178
+ # Check if file was recently accessed
179
+ CURRENT_TIME=$(date +%s)
180
+ THRESHOLD=300 # 5 minutes in seconds
181
+
182
+ if grep -q "^${FILE_PATH}," "$RECENT_READS_LOG" 2>/dev/null; then
183
+ # Get last read time
184
+ LAST_READ=$(grep "^${FILE_PATH}," "$RECENT_READS_LOG" | tail -1 | cut -d',' -f2)
185
+ TIME_SINCE=$((CURRENT_TIME - LAST_READ))
186
+
187
+ if [ $TIME_SINCE -lt $THRESHOLD ]; then
188
+ # Convert to human readable
189
+ if [ $TIME_SINCE -lt 60 ]; then
190
+ TIME_STR="${TIME_SINCE}s"
191
+ else
192
+ TIME_STR="$((TIME_SINCE / 60))m"
193
+ fi
194
+
195
+ # Show warning as JSON (to stderr so it doesn't interfere with JSON blocking output)
196
+ echo "{\"type\":\"read-warning\",\"file\":\"$FILE_PATH\",\"lastRead\":\"${TIME_STR} ago\",\"message\":\"File recently read - check capsule first\"}" >&2
197
+
198
+ # Mark as warned
199
+ echo "$FILE_PATH" >> "$WARNINGS_SHOWN"
200
+ fi
201
+ fi
202
+
203
+ # Record this read attempt
204
+ echo "$FILE_PATH,$CURRENT_TIME" >> "$RECENT_READS_LOG"
205
+
206
+ # Auto-log file access to capsule
207
+ if [ -x "$HOME/.claude/cck/hooks/log-file-access.sh" ] && [ -x "$HOME/.claude/cck/hooks/log-file-access.sh" ]; then
208
+ # Auto-log this read operation (suppress output to avoid noise)
209
+ "$HOME/.claude/cck/hooks/log-file-access.sh" "$FILE_PATH" "read" > /dev/null 2>&1 || true
210
+ fi
211
+
212
+ exit 0
@@ -0,0 +1,87 @@
1
+ #!/bin/bash
2
+ # UserPromptSubmit Memory Injection
3
+ # Injects relevant context based on user's prompt
4
+
5
+ set -euo pipefail
6
+
7
+ # Determine script directory for finding tools
8
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
9
+ if [[ "$SCRIPT_DIR" == *".claude/hooks"* ]]; then
10
+ PROJECT_ROOT="$(dirname "$(dirname "$SCRIPT_DIR")")"
11
+ else
12
+ PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
13
+ fi
14
+
15
+ MEMORY_DIR="${CLAUDE_MEMORY_DIR:-.claude/memory}"
16
+ TOOLS_DIR="$PROJECT_ROOT/tools/memory-graph"
17
+ QUERY_PY="$TOOLS_DIR/lib/query.py"
18
+
19
+ # Read prompt from stdin
20
+ INPUT_JSON=$(cat)
21
+ PROMPT=$(echo "$INPUT_JSON" | python3 -c "import sys, json; print(json.load(sys.stdin).get('prompt', ''))" 2>/dev/null || echo "")
22
+
23
+ if [ -z "$PROMPT" ]; then
24
+ exit 0
25
+ fi
26
+
27
+ # Check if memory graph exists
28
+ if [ ! -d "$MEMORY_DIR/nodes" ] || [ ! -f "$QUERY_PY" ]; then
29
+ exit 0
30
+ fi
31
+
32
+ # Check if graph has nodes
33
+ NODE_COUNT=$(python3 -c "import json; print(json.load(open('$MEMORY_DIR/graph.json')).get('node_count', 0))" 2>/dev/null || echo "0")
34
+ if [ "$NODE_COUNT" = "0" ]; then
35
+ exit 0
36
+ fi
37
+
38
+ CONTEXT=""
39
+
40
+ # Extract potential file paths from prompt (common extensions)
41
+ FILE_MATCHES=$(echo "$PROMPT" | grep -oE '[a-zA-Z0-9_/.-]+\.(ts|tsx|js|jsx|py|go|rs|java|md|sh|json|yaml|yml)' | head -3 || echo "")
42
+
43
+ # Search for file-related knowledge
44
+ for FILE in $FILE_MATCHES; do
45
+ # Convert file path to node ID pattern
46
+ NODE_PATTERN=$(echo "$FILE" | sed 's/[^a-zA-Z0-9]/-/g' | tr '[:upper:]' '[:lower:]')
47
+
48
+ RESULT=$(CLAUDE_MEMORY_DIR="$MEMORY_DIR" python3 "$QUERY_PY" \
49
+ --memory-dir "$MEMORY_DIR" \
50
+ --command search \
51
+ --query "$FILE" \
52
+ --format summary \
53
+ --limit 2 \
54
+ --status active 2>/dev/null || echo "")
55
+
56
+ if [ -n "$RESULT" ]; then
57
+ CONTEXT="$CONTEXT$RESULT"$'\n'
58
+ fi
59
+ done
60
+
61
+ # Extract keywords (simple approach - words 4+ chars)
62
+ KEYWORDS=$(echo "$PROMPT" | tr '[:upper:]' '[:lower:]' | grep -oE '\b[a-z]{4,}\b' | sort -u | head -5 || echo "")
63
+
64
+ # Search for keyword matches in tags
65
+ for KEYWORD in $KEYWORDS; do
66
+ RESULT=$(CLAUDE_MEMORY_DIR="$MEMORY_DIR" python3 "$QUERY_PY" \
67
+ --memory-dir "$MEMORY_DIR" \
68
+ --command tag \
69
+ --query "$KEYWORD" \
70
+ --format summary \
71
+ --limit 2 \
72
+ --status active 2>/dev/null || echo "")
73
+
74
+ if [ -n "$RESULT" ]; then
75
+ CONTEXT="$CONTEXT$RESULT"$'\n'
76
+ fi
77
+ done
78
+
79
+ # Dedupe and output
80
+ if [ -n "$CONTEXT" ]; then
81
+ echo "# Relevant Memory"
82
+ echo ""
83
+ echo "$CONTEXT" | sort -u | head -10
84
+ echo ""
85
+ fi
86
+
87
+ exit 0
@@ -0,0 +1,48 @@
1
+ #!/bin/bash
2
+
3
+ # Quality Check Hook
4
+ # Post-response validation to ensure optimal approach was used
5
+ # Runs AFTER Claude responds but BEFORE sending to user
6
+
7
+ # This hook analyzes the response and provides improvement suggestions
8
+ # It's a learning/reminder tool, not blocking
9
+
10
+ echo ""
11
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
12
+ echo "📊 QUALITY CHECK (Post-Response Validation)"
13
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
14
+ echo ""
15
+ echo "Self-Assessment Checklist:"
16
+ echo ""
17
+ echo "1. ⚡ Parallel Tool Calls"
18
+ echo " ❓ Did I use parallel tool calls for independent operations?"
19
+ echo " 💡 If reading 3+ files → Use multiple Read calls in one message"
20
+ echo ""
21
+ echo "2. 🤖 Sub-Agent Delegation"
22
+ echo " ❓ Should this task have been delegated to a sub-agent?"
23
+ echo " 💡 Complex (>30 min) or specialized (agent dev, Labs, DB) → Delegate"
24
+ echo ""
25
+ echo "3. 🧠 Memory Usage"
26
+ echo " ❓ Did I check exploration journal for continuation work?"
27
+ echo " 💡 'Continue/resume' keywords → Read docs/exploration/ first"
28
+ echo ""
29
+ echo "4. 📝 Progress Tracking"
30
+ echo " ❓ Did I use TodoWrite for multi-step tasks?"
31
+ echo " 💡 3+ steps or >30 min → Track with todos"
32
+ echo ""
33
+ echo "5. 💾 Save Discoveries"
34
+ echo " ❓ Should I save important findings for future sessions?"
35
+ echo " 💡 Discoveries are auto-saved via session handoff on session end"
36
+ echo ""
37
+ echo "6. 🔄 Avoid Redundancy"
38
+ echo " ❓ Did I re-read files I already read recently?"
39
+ echo " 💡 Reference previous reads when possible"
40
+ echo ""
41
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
42
+ echo "✅ If all checked: Response quality is optimal!"
43
+ echo "⚠️ If any unchecked: Consider improvements for next time"
44
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
45
+ echo ""
46
+
47
+ # Always continue (this is informational, not blocking)
48
+ exit 0
@@ -0,0 +1,133 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * SessionEnd Hook - Capsule Integration
4
+ *
5
+ * Finalizes the session by creating a session summary record in Capsule.
6
+ * Crew-aware: scopes to teammate namespace and writes to shared DB.
7
+ */
8
+
9
+ import { Blink } from 'blink-query';
10
+ import { createInterface } from 'readline';
11
+ import { existsSync, readFileSync, writeFileSync } from 'fs';
12
+ import { homedir } from 'os';
13
+ import { resolve } from 'path';
14
+ import { execSync } from 'child_process';
15
+ import { getCapsuleDbPath, getCrewIdentity, crewNamespace, getProjectHash, isDisabled } from './lib/crew-detect.js';
16
+ import { generateHandoff } from './lib/handoff-generator.js';
17
+
18
+ function getCurrentBranch() {
19
+ try {
20
+ return execSync('git rev-parse --abbrev-ref HEAD', {
21
+ encoding: 'utf-8',
22
+ stdio: ['pipe', 'pipe', 'pipe']
23
+ }).trim();
24
+ } catch {
25
+ return null;
26
+ }
27
+ }
28
+
29
+ async function main() {
30
+ try {
31
+ // Read hook input from stdin
32
+ const rl = createInterface({ input: process.stdin });
33
+ let inputJson = '';
34
+
35
+ for await (const line of rl) {
36
+ inputJson += line;
37
+ }
38
+
39
+ const input = JSON.parse(inputJson);
40
+ const sessionId = input.session_id || 'default';
41
+ if (isDisabled()) process.exit(0);
42
+ const projectHash = getProjectHash();
43
+ const currentBranch = getCurrentBranch();
44
+
45
+ // Shared DB in crew mode, local otherwise
46
+ const blink = new Blink({ dbPath: getCapsuleDbPath() });
47
+ const crewId = getCrewIdentity();
48
+
49
+ // Query session activity (from this teammate's namespace)
50
+ const filesNs = crewNamespace(`session/${sessionId}/files`, crewId, projectHash);
51
+ const agentsNs = crewNamespace(`session/${sessionId}/subagents`, crewId, projectHash);
52
+ const sessionFiles = blink.list(filesNs);
53
+ const sessionSubagents = blink.list(agentsNs);
54
+
55
+ // Create session summary
56
+ const teammateSuffix = crewId ? ` (${crewId.teammate_name})` : '';
57
+ const summary = [
58
+ `Session ${sessionId}${teammateSuffix}`,
59
+ `Files accessed: ${sessionFiles.length}`,
60
+ `Sub-agents used: ${sessionSubagents.length}`,
61
+ `Completed at: ${new Date().toISOString()}`
62
+ ].join(' | ');
63
+
64
+ // Save SESSION record (META = structured session metadata)
65
+ blink.save({
66
+ namespace: crewNamespace('session', crewId, projectHash),
67
+ title: `Session ${new Date().toISOString()}`,
68
+ summary,
69
+ type: 'META',
70
+ content: {
71
+ sessionId,
72
+ teammateName: crewId?.teammate_name || null,
73
+ branch: currentBranch,
74
+ filesCount: sessionFiles.length,
75
+ subagentsCount: sessionSubagents.length,
76
+ endedAt: Date.now()
77
+ },
78
+ tags: ['session', sessionId, ...(crewId ? [crewId.teammate_name] : [])]
79
+ });
80
+
81
+ // Generate and save handoff document (SUMMARY type for direct consumption)
82
+ const handoff = generateHandoff(getCapsuleDbPath(), sessionId, crewId, projectHash);
83
+ blink.save({
84
+ namespace: crewNamespace(`session/${sessionId}/handoff`, crewId, projectHash),
85
+ title: `Session ${sessionId} Handoff`,
86
+ summary: handoff,
87
+ type: 'SUMMARY',
88
+ content: {
89
+ sessionId,
90
+ teammateName: crewId?.teammate_name || null,
91
+ branch: currentBranch,
92
+ generatedAt: Date.now()
93
+ },
94
+ tags: ['handoff', sessionId, ...(crewId ? [crewId.teammate_name] : [])]
95
+ });
96
+
97
+ blink.close();
98
+
99
+ // Update team-state.json when in crew mode
100
+ if (crewId) {
101
+ try {
102
+ const profileName = crewId.profile_name || 'default';
103
+ const baseStateDir = resolve(homedir(), '.claude', 'crew', projectHash);
104
+ const profileStateDir = resolve(baseStateDir, profileName);
105
+
106
+ // Try profile-scoped path first, then legacy flat path
107
+ let statePath = resolve(profileStateDir, 'team-state.json');
108
+ if (!existsSync(statePath)) {
109
+ statePath = resolve(baseStateDir, 'team-state.json');
110
+ }
111
+
112
+ if (existsSync(statePath)) {
113
+ const state = JSON.parse(readFileSync(statePath, 'utf-8'));
114
+ if (state.teammates?.[crewId.teammate_name]) {
115
+ state.teammates[crewId.teammate_name].last_active = new Date().toISOString();
116
+ state.teammates[crewId.teammate_name].status = 'idle';
117
+ state.updated_at = new Date().toISOString();
118
+ writeFileSync(statePath, JSON.stringify(state, null, 2));
119
+ }
120
+ }
121
+ } catch { /* best effort */ }
122
+ }
123
+
124
+ // No output needed for SessionEnd
125
+ process.exit(0);
126
+
127
+ } catch (error) {
128
+ console.error(`[session-end.js] Error: ${error.message}`);
129
+ process.exit(0);
130
+ }
131
+ }
132
+
133
+ main();