cc-dev-template 0.1.19 → 0.1.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/install.js
CHANGED
|
@@ -20,7 +20,7 @@ console.log('='.repeat(50));
|
|
|
20
20
|
console.log(`Installing to ${CLAUDE_DIR}...`);
|
|
21
21
|
|
|
22
22
|
// Create directories
|
|
23
|
-
const dirs = ['agents', 'commands', 'scripts', 'skills', 'mcp-servers'];
|
|
23
|
+
const dirs = ['agents', 'commands', 'scripts', 'skills', 'hooks', 'mcp-servers'];
|
|
24
24
|
dirs.forEach(dir => {
|
|
25
25
|
fs.mkdirSync(path.join(CLAUDE_DIR, dir), { recursive: true });
|
|
26
26
|
});
|
|
@@ -92,6 +92,34 @@ if (fs.existsSync(skillsDir)) {
|
|
|
92
92
|
console.log(' No skills to install');
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
+
// Copy hooks
|
|
96
|
+
console.log('\nHooks:');
|
|
97
|
+
const hooksDir = path.join(SRC_DIR, 'hooks');
|
|
98
|
+
if (fs.existsSync(hooksDir)) {
|
|
99
|
+
const hookScripts = fs.readdirSync(hooksDir).filter(f => f.endsWith('.sh'));
|
|
100
|
+
const hookConfigs = fs.readdirSync(hooksDir).filter(f => f.endsWith('.json'));
|
|
101
|
+
|
|
102
|
+
// Copy shell scripts and make executable
|
|
103
|
+
hookScripts.forEach(file => {
|
|
104
|
+
const src = path.join(hooksDir, file);
|
|
105
|
+
const dest = path.join(CLAUDE_DIR, 'hooks', file);
|
|
106
|
+
fs.copyFileSync(src, dest);
|
|
107
|
+
fs.chmodSync(dest, 0o755); // Make executable
|
|
108
|
+
console.log(` ${file}`);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// Copy JSON configs to scripts dir for merging later
|
|
112
|
+
hookConfigs.forEach(file => {
|
|
113
|
+
const src = path.join(hooksDir, file);
|
|
114
|
+
const dest = path.join(CLAUDE_DIR, 'scripts', file);
|
|
115
|
+
fs.copyFileSync(src, dest);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
console.log(`✓ ${hookScripts.length} hooks installed`);
|
|
119
|
+
} else {
|
|
120
|
+
console.log(' No hooks to install');
|
|
121
|
+
}
|
|
122
|
+
|
|
95
123
|
// Install MCP servers
|
|
96
124
|
console.log('\nMCP Servers:');
|
|
97
125
|
const mcpServersDir = path.join(SRC_DIR, 'mcp-servers');
|
|
@@ -198,7 +226,10 @@ if (fs.existsSync(mergeSettingsPath)) {
|
|
|
198
226
|
const configs = [
|
|
199
227
|
{ file: 'yaml-validation-hook.json', name: 'YAML validation hook' },
|
|
200
228
|
{ file: 'read-guard-hook.json', name: 'Context guard for large reads' },
|
|
201
|
-
{ file: 'statusline-config.json', name: 'Custom status line' }
|
|
229
|
+
{ file: 'statusline-config.json', name: 'Custom status line' },
|
|
230
|
+
{ file: 'orchestration-hook.json', name: 'Orchestration guidance hook' },
|
|
231
|
+
{ file: 'bash-overflow-hook.json', name: 'Bash overflow guard hook' },
|
|
232
|
+
{ file: 'bash-precheck-hook.json', name: 'Bash precheck hook' }
|
|
202
233
|
];
|
|
203
234
|
|
|
204
235
|
configs.forEach(({ file, name }) => {
|
|
@@ -225,6 +256,7 @@ Installed to:
|
|
|
225
256
|
Commands: ${CLAUDE_DIR}/commands/
|
|
226
257
|
Scripts: ${CLAUDE_DIR}/scripts/
|
|
227
258
|
Skills: ${CLAUDE_DIR}/skills/
|
|
259
|
+
Hooks: ${CLAUDE_DIR}/hooks/
|
|
228
260
|
MCP Servers: ${CLAUDE_DIR}/mcp-servers/
|
|
229
261
|
Settings: ${CLAUDE_DIR}/settings.json
|
|
230
262
|
`);
|
package/package.json
CHANGED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# bash-overflow-guard.sh - Intercept large Bash outputs to preserve context
|
|
3
|
+
#
|
|
4
|
+
# PostToolUse hook that catches large Bash outputs, saves them to a file,
|
|
5
|
+
# and tells Claude to use Grep to search the file instead of consuming context.
|
|
6
|
+
|
|
7
|
+
set -e
|
|
8
|
+
|
|
9
|
+
# Configuration
|
|
10
|
+
MAX_CHARS=${BASH_OVERFLOW_MAX_CHARS:-20000} # ~5k tokens
|
|
11
|
+
OVERFLOW_DIR="${HOME}/.claude/bash-overflow"
|
|
12
|
+
|
|
13
|
+
# Read hook input from stdin
|
|
14
|
+
input=$(cat)
|
|
15
|
+
|
|
16
|
+
# Parse the tool response
|
|
17
|
+
tool_name=$(echo "$input" | jq -r '.tool_name // empty')
|
|
18
|
+
|
|
19
|
+
# Only process Bash tool
|
|
20
|
+
if [[ "$tool_name" != "Bash" ]]; then
|
|
21
|
+
exit 0
|
|
22
|
+
fi
|
|
23
|
+
|
|
24
|
+
# Extract stdout from the response
|
|
25
|
+
# tool_response can be a string or object depending on output
|
|
26
|
+
stdout=$(echo "$input" | jq -r '.tool_response // empty')
|
|
27
|
+
|
|
28
|
+
# If tool_response is an object, try to get stdout field
|
|
29
|
+
if echo "$stdout" | jq -e 'type == "object"' > /dev/null 2>&1; then
|
|
30
|
+
stdout=$(echo "$stdout" | jq -r '.stdout // .output // empty')
|
|
31
|
+
fi
|
|
32
|
+
|
|
33
|
+
# Measure size
|
|
34
|
+
char_count=${#stdout}
|
|
35
|
+
line_count=$(echo "$stdout" | wc -l | tr -d ' ')
|
|
36
|
+
|
|
37
|
+
# Check if output exceeds threshold
|
|
38
|
+
if [[ $char_count -gt $MAX_CHARS ]]; then
|
|
39
|
+
# Create overflow directory
|
|
40
|
+
mkdir -p "$OVERFLOW_DIR"
|
|
41
|
+
|
|
42
|
+
# Generate filename with timestamp
|
|
43
|
+
timestamp=$(date +%Y%m%d_%H%M%S)
|
|
44
|
+
overflow_file="$OVERFLOW_DIR/bash_output_${timestamp}.txt"
|
|
45
|
+
|
|
46
|
+
# Save output to file
|
|
47
|
+
echo "$stdout" > "$overflow_file"
|
|
48
|
+
|
|
49
|
+
# Calculate approximate token count (rough heuristic: 4 chars per token)
|
|
50
|
+
approx_tokens=$((char_count / 4))
|
|
51
|
+
|
|
52
|
+
# Return block decision with guidance
|
|
53
|
+
cat << EOF
|
|
54
|
+
{
|
|
55
|
+
"decision": "block",
|
|
56
|
+
"reason": "Bash output too large for context (${line_count} lines, ~${approx_tokens} tokens). Output saved to: ${overflow_file}\n\nUse the Grep tool to search this file:\n Grep(pattern: \"your-pattern\", path: \"${overflow_file}\")\n\nOr read specific sections:\n Read(file_path: \"${overflow_file}\", offset: 1, limit: 100)"
|
|
57
|
+
}
|
|
58
|
+
EOF
|
|
59
|
+
exit 0
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
# Output is small enough, allow it through
|
|
63
|
+
exit 0
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# bash-precheck.sh - PreToolUse hook to wrap Bash commands with output limiting
|
|
3
|
+
#
|
|
4
|
+
# Intercepts Bash commands before execution and wraps them to:
|
|
5
|
+
# 1. Capture output to temp file
|
|
6
|
+
# 2. If output exceeds threshold, save and return truncated version
|
|
7
|
+
#
|
|
8
|
+
# This ACTUALLY prevents large outputs from consuming context.
|
|
9
|
+
# Compatible with bash and zsh on macOS and Linux.
|
|
10
|
+
|
|
11
|
+
set -e
|
|
12
|
+
|
|
13
|
+
# Configuration
|
|
14
|
+
MAX_CHARS=${BASH_OVERFLOW_MAX_CHARS:-20000}
|
|
15
|
+
OVERFLOW_DIR="${HOME}/.claude/bash-overflow"
|
|
16
|
+
|
|
17
|
+
# Read hook input from stdin
|
|
18
|
+
input=$(cat)
|
|
19
|
+
|
|
20
|
+
# Parse tool name and command
|
|
21
|
+
tool_name=$(echo "$input" | jq -r '.tool_name // empty')
|
|
22
|
+
|
|
23
|
+
# Only process Bash tool
|
|
24
|
+
if [[ "$tool_name" != "Bash" ]]; then
|
|
25
|
+
exit 0
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
# Get the original command
|
|
29
|
+
original_cmd=$(echo "$input" | jq -r '.tool_input.command // empty')
|
|
30
|
+
|
|
31
|
+
# Skip if empty
|
|
32
|
+
if [[ -z "$original_cmd" ]]; then
|
|
33
|
+
exit 0
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
# Skip commands that are already piped to head/tail or are simple commands
|
|
37
|
+
if [[ "$original_cmd" =~ \|[[:space:]]*(head|tail|wc|grep.*-c) ]]; then
|
|
38
|
+
exit 0
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
# Skip very short commands (likely simple operations)
|
|
42
|
+
if [[ ${#original_cmd} -lt 10 ]]; then
|
|
43
|
+
exit 0
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
# Create overflow directory
|
|
47
|
+
mkdir -p "$OVERFLOW_DIR"
|
|
48
|
+
|
|
49
|
+
# Generate unique filename
|
|
50
|
+
timestamp=$(date +%Y%m%d_%H%M%S)
|
|
51
|
+
rand_suffix=$RANDOM
|
|
52
|
+
overflow_file="$OVERFLOW_DIR/bash_output_${timestamp}_${rand_suffix}.txt"
|
|
53
|
+
temp_file="/tmp/claude_bash_${timestamp}_${rand_suffix}.tmp"
|
|
54
|
+
|
|
55
|
+
# Escape the original command for embedding in the wrapper
|
|
56
|
+
# Use base64 to safely embed arbitrary commands
|
|
57
|
+
original_cmd_b64=$(echo "$original_cmd" | base64)
|
|
58
|
+
|
|
59
|
+
# Create wrapper that uses temp file approach (more portable)
|
|
60
|
+
read -r -d '' wrapped_cmd << 'WRAPPER_EOF' || true
|
|
61
|
+
__cmd_b64="BASE64_CMD_HERE"
|
|
62
|
+
__cmd=$(echo "$__cmd_b64" | base64 -d)
|
|
63
|
+
__tmpfile="TEMP_FILE_HERE"
|
|
64
|
+
__overflow="OVERFLOW_FILE_HERE"
|
|
65
|
+
__max=MAX_CHARS_HERE
|
|
66
|
+
|
|
67
|
+
# Run command and capture to temp file
|
|
68
|
+
eval "$__cmd" > "$__tmpfile" 2>&1
|
|
69
|
+
__exit_code=$?
|
|
70
|
+
|
|
71
|
+
# Check size
|
|
72
|
+
__size=$(wc -c < "$__tmpfile" | tr -d ' ')
|
|
73
|
+
|
|
74
|
+
if [ "$__size" -gt "$__max" ]; then
|
|
75
|
+
# Save full output
|
|
76
|
+
cp "$__tmpfile" "$__overflow"
|
|
77
|
+
__lines=$(wc -l < "$__tmpfile" | tr -d ' ')
|
|
78
|
+
__tokens=$((__size / 4))
|
|
79
|
+
|
|
80
|
+
echo "=== OUTPUT TRUNCATED (${__lines} lines, ~${__tokens} tokens) ==="
|
|
81
|
+
echo ""
|
|
82
|
+
echo "--- First 40 lines ---"
|
|
83
|
+
head -n 40 "$__tmpfile"
|
|
84
|
+
echo ""
|
|
85
|
+
echo "--- Last 5 lines ---"
|
|
86
|
+
tail -n 5 "$__tmpfile"
|
|
87
|
+
echo ""
|
|
88
|
+
echo "=== Full output saved to: $__overflow ==="
|
|
89
|
+
echo "Use Grep(pattern, path) or Read(file_path, offset, limit) to explore"
|
|
90
|
+
else
|
|
91
|
+
cat "$__tmpfile"
|
|
92
|
+
fi
|
|
93
|
+
|
|
94
|
+
rm -f "$__tmpfile"
|
|
95
|
+
exit $__exit_code
|
|
96
|
+
WRAPPER_EOF
|
|
97
|
+
|
|
98
|
+
# Substitute placeholders
|
|
99
|
+
wrapped_cmd="${wrapped_cmd//BASE64_CMD_HERE/$original_cmd_b64}"
|
|
100
|
+
wrapped_cmd="${wrapped_cmd//TEMP_FILE_HERE/$temp_file}"
|
|
101
|
+
wrapped_cmd="${wrapped_cmd//OVERFLOW_FILE_HERE/$overflow_file}"
|
|
102
|
+
wrapped_cmd="${wrapped_cmd//MAX_CHARS_HERE/$MAX_CHARS}"
|
|
103
|
+
|
|
104
|
+
# Return the modified command
|
|
105
|
+
cat << EOF
|
|
106
|
+
{
|
|
107
|
+
"hookSpecificOutput": {
|
|
108
|
+
"hookEventName": "PreToolUse",
|
|
109
|
+
"permissionDecision": "allow",
|
|
110
|
+
"updatedInput": {
|
|
111
|
+
"command": $(echo "$wrapped_cmd" | jq -Rs .)
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
EOF
|
|
116
|
+
|
|
117
|
+
exit 0
|