claudepod 1.0.2 → 1.1.1
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/.devcontainer/config/claude/mcp.json +77 -0
- package/.devcontainer/config/claude/mcp.json.backup +77 -0
- package/.devcontainer/config/claude/mcp.json.template +118 -0
- package/.devcontainer/config/claude/output-styles/strict-development.md +158 -0
- package/.devcontainer/config/claude/settings.json +4 -173
- package/.devcontainer/config/claude/system-prompt.md +3 -0
- package/.devcontainer/config/searxng/ods_config.json +16 -0
- package/.devcontainer/config/searxng/searxng_env_template +71 -0
- package/.devcontainer/config/serena/serena_config.yml +72 -0
- package/.devcontainer/config/taskmaster/config.json +37 -0
- package/.devcontainer/devcontainer.json +5 -2
- package/.devcontainer/ods_config.json +21 -0
- package/.devcontainer/post-create.sh +832 -155
- package/.devcontainer/post-start.sh +368 -187
- package/.devcontainer/sanitize-system-prompt.sh +31 -0
- package/.devcontainer/scripts/config/claude-core.sh +210 -0
- package/.devcontainer/scripts/config/searxng.sh +252 -0
- package/.devcontainer/scripts/config/serena.sh +47 -0
- package/.devcontainer/scripts/config/taskmaster.sh +41 -0
- package/.devcontainer/scripts/generate-mcp-config.js +205 -0
- package/.devcontainer/scripts/install/claude-code.sh +112 -0
- package/.devcontainer/scripts/shell/zsh-config.sh +271 -0
- package/.devcontainer/scripts/utils.sh +44 -0
- package/.devcontainer/setup-zsh.sh +51 -202
- package/LICENSE.txt +674 -0
- package/README.md +172 -117
- package/package.json +17 -7
|
@@ -6,59 +6,152 @@ set -euo pipefail
|
|
|
6
6
|
|
|
7
7
|
echo "🚀 Starting ClaudePod post-create setup..."
|
|
8
8
|
|
|
9
|
-
# Source
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
# Source environment file if it exists
|
|
10
|
+
if [ -f "/workspace/.devcontainer/.env" ]; then
|
|
11
|
+
echo "📋 Loading environment variables from .devcontainer/.env"
|
|
12
|
+
set -a # Export all variables
|
|
13
|
+
source "/workspace/.devcontainer/.env"
|
|
14
|
+
set +a # Stop exporting
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
# Source shared utility functions
|
|
18
|
+
source "/workspace/.devcontainer/scripts/utils.sh"
|
|
19
|
+
|
|
20
|
+
# State tracking directory
|
|
21
|
+
STATE_DIR="/workspace/.devcontainer/state"
|
|
13
22
|
|
|
14
|
-
#
|
|
15
|
-
|
|
16
|
-
local
|
|
17
|
-
local
|
|
18
|
-
shift 2
|
|
19
|
-
local attempt=1
|
|
23
|
+
# Function to create state marker
|
|
24
|
+
create_state_marker() {
|
|
25
|
+
local component="$1"
|
|
26
|
+
local method="${2:-unknown}"
|
|
20
27
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
fi
|
|
25
|
-
echo "⚠️ Command failed (attempt $attempt/$max_attempts): $*"
|
|
26
|
-
if [ $attempt -lt $max_attempts ]; then
|
|
27
|
-
echo " Retrying in ${delay}s..."
|
|
28
|
-
sleep $delay
|
|
29
|
-
fi
|
|
30
|
-
((attempt++))
|
|
31
|
-
done
|
|
32
|
-
return 1
|
|
28
|
+
mkdir -p "$STATE_DIR"
|
|
29
|
+
echo "$(date '+%Y-%m-%d %H:%M:%S') - $method" > "$STATE_DIR/${component}.installed"
|
|
30
|
+
chown -R node:node "$STATE_DIR"
|
|
33
31
|
}
|
|
34
32
|
|
|
35
|
-
# Function to
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
# Function to check if component is already installed
|
|
34
|
+
is_component_installed() {
|
|
35
|
+
local component="$1"
|
|
38
36
|
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
[ -f "$STATE_DIR/${component}.installed" ]
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
# Source configuration modules
|
|
41
|
+
source "/workspace/.devcontainer/scripts/config/claude-core.sh"
|
|
42
|
+
source "/workspace/.devcontainer/scripts/config/serena.sh"
|
|
43
|
+
source "/workspace/.devcontainer/scripts/config/taskmaster.sh"
|
|
44
|
+
source "/workspace/.devcontainer/scripts/config/searxng.sh"
|
|
45
|
+
|
|
46
|
+
# Source installation modules
|
|
47
|
+
source "/workspace/.devcontainer/scripts/install/claude-code.sh"
|
|
48
|
+
|
|
49
|
+
# Source NVM to make Node.js and npm available
|
|
50
|
+
export NVM_DIR="/usr/local/share/nvm"
|
|
51
|
+
# Wait for NVM to be available (up to 30 seconds)
|
|
52
|
+
for i in {1..30}; do
|
|
53
|
+
[ -s "$NVM_DIR/nvm.sh" ] && break
|
|
54
|
+
echo "⏳ Waiting for NVM installation... (attempt $i/30)"
|
|
55
|
+
sleep 1
|
|
56
|
+
done
|
|
57
|
+
|
|
58
|
+
if [ -s "$NVM_DIR/nvm.sh" ]; then
|
|
59
|
+
echo "🔧 Sourcing NVM..."
|
|
60
|
+
. "$NVM_DIR/nvm.sh"
|
|
41
61
|
|
|
42
|
-
#
|
|
43
|
-
if
|
|
44
|
-
echo "✅
|
|
62
|
+
# Verify npm is now available
|
|
63
|
+
if command -v npm &> /dev/null; then
|
|
64
|
+
echo "✅ npm is available: $(which npm)"
|
|
65
|
+
echo "📌 npm version: $(npm --version)"
|
|
66
|
+
echo "📌 node version: $(node --version)"
|
|
45
67
|
|
|
46
|
-
#
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
68
|
+
# Setup npm permissions immediately after npm becomes available
|
|
69
|
+
echo "🔧 Setting up npm directories and permissions..."
|
|
70
|
+
|
|
71
|
+
# Create npm directories with correct ownership
|
|
72
|
+
npm_dirs=(
|
|
73
|
+
"/home/node/.npm"
|
|
74
|
+
"/home/node/.npm/_cacache"
|
|
75
|
+
"/home/node/.npm/_logs"
|
|
76
|
+
"/home/node/.config"
|
|
77
|
+
"/home/node/.local"
|
|
78
|
+
"/home/node/.local/bin"
|
|
79
|
+
"/home/node/.cache"
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
for dir in "${npm_dirs[@]}"; do
|
|
83
|
+
mkdir -p "$dir"
|
|
84
|
+
chown -R node:node "$dir"
|
|
85
|
+
chmod -R 755 "$dir"
|
|
86
|
+
done
|
|
87
|
+
|
|
88
|
+
# Remove any existing .npmrc directory/file and create .npmrc file
|
|
89
|
+
# Use NVM-compatible configuration (no prefix setting to avoid NVM conflicts)
|
|
90
|
+
rm -rf /home/node/.npmrc
|
|
91
|
+
|
|
92
|
+
# Also clear any existing npm config that might conflict with NVM
|
|
93
|
+
npm config delete prefix 2>/dev/null || true
|
|
94
|
+
npm config delete globalconfig 2>/dev/null || true
|
|
95
|
+
|
|
96
|
+
cat > /home/node/.npmrc << 'EOF'
|
|
97
|
+
cache=/home/node/.npm/_cacache
|
|
98
|
+
update-notifier=false
|
|
99
|
+
# Note: prefix and globalconfig settings removed to avoid NVM conflicts
|
|
100
|
+
EOF
|
|
101
|
+
|
|
102
|
+
# Set environment variable to suppress NVM warnings about prefix
|
|
103
|
+
export NVM_SUPPRESS_PREFIX_WARNING=1
|
|
104
|
+
echo "export NVM_SUPPRESS_PREFIX_WARNING=1" >> /home/node/.profile
|
|
105
|
+
echo "export NVM_SUPPRESS_PREFIX_WARNING=1" >> /home/node/.bashrc
|
|
106
|
+
echo "export NVM_SUPPRESS_PREFIX_WARNING=1" >> /home/node/.zshrc
|
|
107
|
+
|
|
108
|
+
# Set proper ownership for .npmrc
|
|
109
|
+
chown node:node /home/node/.npmrc
|
|
110
|
+
chmod 644 /home/node/.npmrc
|
|
111
|
+
|
|
112
|
+
# Fix NVM symlink permissions issue PROPERLY
|
|
113
|
+
echo "🔧 Fixing NVM symlink permissions..."
|
|
114
|
+
if [ -d "/usr/local/share/nvm" ]; then
|
|
115
|
+
# Remove the problematic root-owned symlink if it exists
|
|
116
|
+
rm -f "/usr/local/share/nvm/current" 2>/dev/null || true
|
|
117
|
+
|
|
118
|
+
# More aggressive permissions fix: make node user owner of NVM directory
|
|
119
|
+
chown -R node:node "/usr/local/share/nvm"
|
|
120
|
+
chmod -R 755 "/usr/local/share/nvm"
|
|
121
|
+
|
|
122
|
+
# Pre-create the current symlink as the node user to avoid permission issues
|
|
123
|
+
if command -v node &> /dev/null; then
|
|
124
|
+
node_version=$(node --version | sed 's/v//')
|
|
125
|
+
node_path="/usr/local/share/nvm/versions/node/v${node_version}"
|
|
126
|
+
if [ -d "$node_path" ]; then
|
|
127
|
+
ln -sf "$node_path" "/usr/local/share/nvm/current" 2>/dev/null || true
|
|
128
|
+
chown -h node:node "/usr/local/share/nvm/current" 2>/dev/null || true
|
|
129
|
+
fi
|
|
130
|
+
fi
|
|
131
|
+
|
|
132
|
+
echo "✅ NVM directory now owned by node user with symlink pre-created"
|
|
56
133
|
fi
|
|
134
|
+
|
|
135
|
+
echo "✅ npm directories and permissions configured (NVM conflicts resolved)"
|
|
57
136
|
else
|
|
58
|
-
echo "❌
|
|
59
|
-
|
|
137
|
+
echo "❌ npm still not found after sourcing NVM"
|
|
138
|
+
exit 1
|
|
60
139
|
fi
|
|
61
|
-
|
|
140
|
+
else
|
|
141
|
+
echo "❌ NVM not found at $NVM_DIR/nvm.sh"
|
|
142
|
+
exit 1
|
|
143
|
+
fi
|
|
144
|
+
|
|
145
|
+
# Set environment for Node.js operations (using PATH helper to avoid duplicates)
|
|
146
|
+
add_to_path "/home/node/.local/bin"
|
|
147
|
+
export npm_config_prefix="/home/node/.local"
|
|
148
|
+
|
|
149
|
+
# Claude Code installation is now handled by focused functions:
|
|
150
|
+
# - install_claude_code_native(): Native binary installation
|
|
151
|
+
# - install_claude_code_npm(): NPM fallback installation
|
|
152
|
+
# - verify_claude_installation(): Installation verification
|
|
153
|
+
# - install_claude_code(): Main orchestrator function
|
|
154
|
+
# See: /workspace/.devcontainer/scripts/install/claude-code.sh
|
|
62
155
|
|
|
63
156
|
# Function to setup workspace directories for bind mounts
|
|
64
157
|
setup_workspace_directories() {
|
|
@@ -144,60 +237,379 @@ EOF
|
|
|
144
237
|
fi
|
|
145
238
|
}
|
|
146
239
|
|
|
147
|
-
# Function to
|
|
148
|
-
|
|
149
|
-
|
|
240
|
+
# Function to create configuration backup
|
|
241
|
+
create_config_backup() {
|
|
242
|
+
local config_file="$1"
|
|
243
|
+
local backup_dir="/workspace/.devcontainer/config/backups"
|
|
244
|
+
|
|
245
|
+
if [ -f "$config_file" ]; then
|
|
246
|
+
mkdir -p "$backup_dir"
|
|
247
|
+
local filename=$(basename "$config_file")
|
|
248
|
+
# Include path to distinguish home vs workspace configs
|
|
249
|
+
local path_prefix=$(echo "$config_file" | sed 's|/|_|g' | sed 's|^_||')
|
|
250
|
+
local timestamp=$(date +"%Y%m%d_%H%M%S")
|
|
251
|
+
local backup_file="${backup_dir}/${path_prefix}.${timestamp}.backup"
|
|
252
|
+
|
|
253
|
+
cp "$config_file" "$backup_file"
|
|
254
|
+
chown node:node "$backup_file"
|
|
255
|
+
chmod 600 "$backup_file"
|
|
256
|
+
echo "📦 Created backup: $backup_file"
|
|
257
|
+
|
|
258
|
+
# Keep only the last 5 backups for each unique file path
|
|
259
|
+
local base_name="${backup_dir}/${path_prefix}"
|
|
260
|
+
ls -t ${base_name}.*.backup 2>/dev/null | tail -n +6 | xargs -r rm -f
|
|
261
|
+
fi
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
# Configuration is now handled by focused modules:
|
|
265
|
+
# - claude-core.sh: Claude directory and core config files
|
|
266
|
+
# - serena.sh: Serena MCP server configuration
|
|
267
|
+
# - taskmaster.sh: TaskMaster AI configuration
|
|
268
|
+
|
|
269
|
+
# Function to install ccusage CLI tool
|
|
270
|
+
install_ccusage() {
|
|
271
|
+
# Check if ccusage is already installed
|
|
272
|
+
if is_component_installed "ccusage"; then
|
|
273
|
+
echo "✅ ccusage already installed (marker found)"
|
|
274
|
+
if command -v ccusage &> /dev/null; then
|
|
275
|
+
local version=$(ccusage --version 2>/dev/null || echo "installed")
|
|
276
|
+
echo "📌 ccusage version: $version"
|
|
277
|
+
return 0
|
|
278
|
+
else
|
|
279
|
+
echo "⚠️ Marker exists but verification failed, reinstalling..."
|
|
280
|
+
rm -f "$STATE_DIR/ccusage.installed"
|
|
281
|
+
fi
|
|
282
|
+
fi
|
|
150
283
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
284
|
+
echo "📊 Installing ccusage..."
|
|
285
|
+
|
|
286
|
+
# Ensure npm uses the correct directories for the node user
|
|
287
|
+
export npm_config_prefix="/home/node/.local"
|
|
288
|
+
|
|
289
|
+
# Task 1: Clean ccusage directory conflicts before installation attempts
|
|
290
|
+
echo "🧹 Cleaning any existing ccusage directories to prevent ENOTEMPTY errors..."
|
|
291
|
+
local ccusage_dirs=(
|
|
292
|
+
"/home/node/.local/lib/node_modules/ccusage"
|
|
293
|
+
"/home/node/.local/lib/node_modules/.ccusage-*"
|
|
294
|
+
"/home/node/.npm/_cacache/index-v5/*/ccusage"
|
|
155
295
|
)
|
|
156
296
|
|
|
157
|
-
for
|
|
158
|
-
if [
|
|
159
|
-
|
|
160
|
-
|
|
297
|
+
for pattern in "${ccusage_dirs[@]}"; do
|
|
298
|
+
if [ -d "$pattern" ] || ls $pattern >/dev/null 2>&1; then
|
|
299
|
+
echo "🗑️ Removing existing directory: $pattern"
|
|
300
|
+
rm -rf $pattern 2>/dev/null || true
|
|
161
301
|
fi
|
|
162
|
-
# Set proper permissions
|
|
163
|
-
chown -R node:node "$dir"
|
|
164
|
-
chmod -R 700 "$dir"
|
|
165
302
|
done
|
|
166
303
|
|
|
167
|
-
#
|
|
168
|
-
|
|
169
|
-
|
|
304
|
+
# Clear npm cache for ccusage specifically
|
|
305
|
+
npm cache clean --force --silent 2>/dev/null || true
|
|
306
|
+
|
|
307
|
+
# Task 2: Add proper error handling for npm ENOTEMPTY issues
|
|
308
|
+
echo "📦 Attempting ccusage installation with ENOTEMPTY error handling..."
|
|
309
|
+
local install_success=false
|
|
310
|
+
local attempts=3
|
|
311
|
+
|
|
312
|
+
for attempt in $(seq 1 $attempts); do
|
|
313
|
+
echo "📦 Installation attempt $attempt/$attempts..."
|
|
314
|
+
|
|
315
|
+
if npm install -g ccusage 2>/dev/null; then
|
|
316
|
+
install_success=true
|
|
317
|
+
break
|
|
318
|
+
else
|
|
319
|
+
local exit_code=$?
|
|
320
|
+
|
|
321
|
+
# Check for ENOTEMPTY error in npm logs
|
|
322
|
+
local latest_log=$(find /home/node/.npm/_logs -name "*debug*.log" -type f -exec ls -t {} + | head -1 2>/dev/null)
|
|
323
|
+
if [ -n "$latest_log" ] && grep -q "ENOTEMPTY" "$latest_log" 2>/dev/null; then
|
|
324
|
+
echo "⚠️ ENOTEMPTY error detected, cleaning npm directories..."
|
|
325
|
+
|
|
326
|
+
# Remove conflicting directories more aggressively
|
|
327
|
+
rm -rf /home/node/.local/lib/node_modules/ccusage* 2>/dev/null || true
|
|
328
|
+
rm -rf /home/node/.local/lib/node_modules/.ccusage* 2>/dev/null || true
|
|
329
|
+
|
|
330
|
+
# Clear npm cache completely
|
|
331
|
+
npm cache clean --force --silent 2>/dev/null || true
|
|
332
|
+
rm -rf /home/node/.npm/_cacache/* 2>/dev/null || true
|
|
333
|
+
|
|
334
|
+
if [ $attempt -lt $attempts ]; then
|
|
335
|
+
echo "🔄 Retrying installation after cleanup..."
|
|
336
|
+
sleep 2
|
|
337
|
+
fi
|
|
338
|
+
else
|
|
339
|
+
echo "⚠️ Installation failed with exit code $exit_code (attempt $attempt/$attempts)"
|
|
340
|
+
if [ $attempt -lt $attempts ]; then
|
|
341
|
+
echo "🔄 Retrying installation..."
|
|
342
|
+
sleep 2
|
|
343
|
+
fi
|
|
344
|
+
fi
|
|
345
|
+
fi
|
|
346
|
+
done
|
|
170
347
|
|
|
171
|
-
if [
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
echo "
|
|
348
|
+
if [ "$install_success" = "true" ]; then
|
|
349
|
+
echo "✅ ccusage installed successfully"
|
|
350
|
+
|
|
351
|
+
# Task 3: Verify installations work after fixes
|
|
352
|
+
echo "🔍 Performing comprehensive installation verification..."
|
|
353
|
+
|
|
354
|
+
# Wait for filesystem consistency
|
|
355
|
+
sleep 1
|
|
356
|
+
|
|
357
|
+
# Check multiple installation indicators
|
|
358
|
+
local verification_passed=false
|
|
359
|
+
local ccusage_bin="/home/node/.local/bin/ccusage"
|
|
360
|
+
local ccusage_module="/home/node/.local/lib/node_modules/ccusage"
|
|
361
|
+
|
|
362
|
+
if [ -f "$ccusage_bin" ] && [ -d "$ccusage_module" ]; then
|
|
363
|
+
echo "✓ Binary and module directory both exist"
|
|
364
|
+
|
|
365
|
+
# Test if the command actually works
|
|
366
|
+
if "$ccusage_bin" --version >/dev/null 2>&1; then
|
|
367
|
+
local version=$("$ccusage_bin" --version 2>/dev/null || echo "installed")
|
|
368
|
+
echo "📌 ccusage version: $version"
|
|
369
|
+
echo "✓ Command execution test passed"
|
|
370
|
+
verification_passed=true
|
|
371
|
+
else
|
|
372
|
+
echo "⚠️ Binary exists but command execution failed"
|
|
373
|
+
fi
|
|
374
|
+
elif command -v ccusage &> /dev/null; then
|
|
375
|
+
local version=$(ccusage --version 2>/dev/null || echo "installed")
|
|
376
|
+
echo "📌 ccusage version: $version"
|
|
377
|
+
echo "✓ Command found in PATH"
|
|
378
|
+
verification_passed=true
|
|
379
|
+
else
|
|
380
|
+
echo "❌ Installation verification failed:"
|
|
381
|
+
echo " - Binary check: $([ -f "$ccusage_bin" ] && echo "FOUND" || echo "MISSING")"
|
|
382
|
+
echo " - Module check: $([ -d "$ccusage_module" ] && echo "FOUND" || echo "MISSING")"
|
|
383
|
+
echo " - PATH check: $(command -v ccusage &> /dev/null && echo "FOUND" || echo "MISSING")"
|
|
384
|
+
fi
|
|
385
|
+
|
|
386
|
+
if [ "$verification_passed" = "true" ]; then
|
|
387
|
+
echo "✅ ccusage installation verification passed"
|
|
388
|
+
create_state_marker "ccusage" "npm"
|
|
389
|
+
return 0
|
|
390
|
+
else
|
|
391
|
+
echo "❌ ccusage installation verification failed"
|
|
392
|
+
return 1
|
|
393
|
+
fi
|
|
176
394
|
else
|
|
177
|
-
echo "
|
|
395
|
+
echo "❌ Failed to install ccusage after $attempts attempts"
|
|
396
|
+
echo "💡 Manual installation command: npm install -g ccusage"
|
|
397
|
+
return 1
|
|
398
|
+
fi
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
# Function to install cchistory CLI tool
|
|
402
|
+
install_cchistory() {
|
|
403
|
+
# Check if cchistory is already installed
|
|
404
|
+
if is_component_installed "cchistory"; then
|
|
405
|
+
echo "✅ cchistory already installed (marker found)"
|
|
406
|
+
if command -v cchistory &> /dev/null; then
|
|
407
|
+
local version=$(cchistory --help 2>/dev/null | grep -i version || echo "installed")
|
|
408
|
+
echo "📌 cchistory version: installed"
|
|
409
|
+
return 0
|
|
410
|
+
else
|
|
411
|
+
echo "⚠️ Marker exists but verification failed, reinstalling..."
|
|
412
|
+
rm -f "$STATE_DIR/cchistory.installed"
|
|
413
|
+
fi
|
|
178
414
|
fi
|
|
179
415
|
|
|
180
|
-
echo "
|
|
416
|
+
echo "📊 Installing cchistory (Claude Code prompt analyzer)..."
|
|
417
|
+
|
|
418
|
+
# Ensure npm uses the correct directories for the node user
|
|
419
|
+
export npm_config_prefix="/home/node/.local"
|
|
420
|
+
|
|
421
|
+
# Clean any existing cchistory directories to prevent conflicts
|
|
422
|
+
echo "🧹 Cleaning any existing cchistory directories..."
|
|
423
|
+
local cchistory_dirs=(
|
|
424
|
+
"/home/node/.local/lib/node_modules/@mariozechner/cchistory"
|
|
425
|
+
"/home/node/.local/lib/node_modules/.@mariozechner-cchistory-*"
|
|
426
|
+
"/home/node/.npm/_cacache/index-v5/*/cchistory"
|
|
427
|
+
)
|
|
428
|
+
|
|
429
|
+
for pattern in "${cchistory_dirs[@]}"; do
|
|
430
|
+
if [ -d "$pattern" ] || ls $pattern >/dev/null 2>&1; then
|
|
431
|
+
echo "🗑️ Removing existing directory: $pattern"
|
|
432
|
+
rm -rf $pattern 2>/dev/null || true
|
|
433
|
+
fi
|
|
434
|
+
done
|
|
435
|
+
|
|
436
|
+
# Install cchistory with error handling
|
|
437
|
+
echo "📦 Attempting cchistory installation..."
|
|
438
|
+
local install_success=false
|
|
439
|
+
local attempts=2
|
|
440
|
+
|
|
441
|
+
for attempt in $(seq 1 $attempts); do
|
|
442
|
+
echo "📦 Installation attempt $attempt/$attempts..."
|
|
443
|
+
|
|
444
|
+
if npm install -g @mariozechner/cchistory 2>/dev/null; then
|
|
445
|
+
install_success=true
|
|
446
|
+
break
|
|
447
|
+
else
|
|
448
|
+
local exit_code=$?
|
|
449
|
+
echo "⚠️ Installation failed with exit code $exit_code (attempt $attempt/$attempts)"
|
|
450
|
+
if [ $attempt -lt $attempts ]; then
|
|
451
|
+
echo "🔄 Retrying installation..."
|
|
452
|
+
sleep 2
|
|
453
|
+
fi
|
|
454
|
+
fi
|
|
455
|
+
done
|
|
456
|
+
|
|
457
|
+
if [ "$install_success" = "true" ]; then
|
|
458
|
+
echo "✅ cchistory installed successfully"
|
|
459
|
+
|
|
460
|
+
# Verify installation
|
|
461
|
+
echo "🔍 Verifying cchistory installation..."
|
|
462
|
+
|
|
463
|
+
# Wait for filesystem consistency
|
|
464
|
+
sleep 1
|
|
465
|
+
|
|
466
|
+
# Check installation indicators
|
|
467
|
+
local verification_passed=false
|
|
468
|
+
local cchistory_bin="/home/node/.local/bin/cchistory"
|
|
469
|
+
local cchistory_module="/home/node/.local/lib/node_modules/@mariozechner/cchistory"
|
|
470
|
+
|
|
471
|
+
if [ -f "$cchistory_bin" ] && [ -d "$cchistory_module" ]; then
|
|
472
|
+
echo "✓ Binary and module directory both exist"
|
|
473
|
+
|
|
474
|
+
# Test if the command actually works
|
|
475
|
+
if "$cchistory_bin" --help >/dev/null 2>&1; then
|
|
476
|
+
echo "📌 cchistory: Claude Code prompt analyzer"
|
|
477
|
+
echo "✓ Command execution test passed"
|
|
478
|
+
verification_passed=true
|
|
479
|
+
else
|
|
480
|
+
echo "⚠️ Binary exists but command execution failed"
|
|
481
|
+
fi
|
|
482
|
+
elif command -v cchistory &> /dev/null; then
|
|
483
|
+
echo "📌 cchistory: Claude Code prompt analyzer"
|
|
484
|
+
echo "✓ Command found in PATH"
|
|
485
|
+
verification_passed=true
|
|
486
|
+
else
|
|
487
|
+
echo "❌ Installation verification failed:"
|
|
488
|
+
echo " - Binary check: $([ -f "$cchistory_bin" ] && echo "FOUND" || echo "MISSING")"
|
|
489
|
+
echo " - Module check: $([ -d "$cchistory_module" ] && echo "FOUND" || echo "MISSING")"
|
|
490
|
+
echo " - PATH check: $(command -v cchistory &> /dev/null && echo "FOUND" || echo "MISSING")"
|
|
491
|
+
fi
|
|
492
|
+
|
|
493
|
+
if [ "$verification_passed" = "true" ]; then
|
|
494
|
+
echo "✅ cchistory installation verification passed"
|
|
495
|
+
create_state_marker "cchistory" "npm"
|
|
496
|
+
return 0
|
|
497
|
+
else
|
|
498
|
+
echo "❌ cchistory installation verification failed"
|
|
499
|
+
return 1
|
|
500
|
+
fi
|
|
501
|
+
else
|
|
502
|
+
echo "❌ Failed to install cchistory after $attempts attempts"
|
|
503
|
+
echo "💡 Manual installation command: npm install -g @mariozechner/cchistory"
|
|
504
|
+
return 1
|
|
505
|
+
fi
|
|
181
506
|
}
|
|
182
507
|
|
|
183
|
-
# Function to install
|
|
184
|
-
|
|
185
|
-
|
|
508
|
+
# Function to install claude-trace CLI tool
|
|
509
|
+
install_claude_trace() {
|
|
510
|
+
# Check if claude-trace is already installed
|
|
511
|
+
if is_component_installed "claude-trace"; then
|
|
512
|
+
echo "✅ claude-trace already installed (marker found)"
|
|
513
|
+
if command -v claude-trace &> /dev/null; then
|
|
514
|
+
local version=$(claude-trace --version 2>/dev/null || echo "installed")
|
|
515
|
+
echo "📌 claude-trace version: $version"
|
|
516
|
+
return 0
|
|
517
|
+
else
|
|
518
|
+
echo "⚠️ Marker exists but verification failed, reinstalling..."
|
|
519
|
+
rm -f "$STATE_DIR/claude-trace.installed"
|
|
520
|
+
fi
|
|
521
|
+
fi
|
|
186
522
|
|
|
187
|
-
|
|
188
|
-
|
|
523
|
+
echo "🔍 Installing claude-trace (Claude Code interaction recorder)..."
|
|
524
|
+
|
|
525
|
+
# Ensure npm uses the correct directories for the node user
|
|
526
|
+
export npm_config_prefix="/home/node/.local"
|
|
527
|
+
|
|
528
|
+
# Clean any existing claude-trace directories to prevent conflicts
|
|
529
|
+
echo "🧹 Cleaning any existing claude-trace directories..."
|
|
530
|
+
local claude_trace_dirs=(
|
|
531
|
+
"/home/node/.local/lib/node_modules/@mariozechner/claude-trace"
|
|
532
|
+
"/home/node/.local/lib/node_modules/.@mariozechner-claude-trace-*"
|
|
533
|
+
"/home/node/.npm/_cacache/index-v5/*/claude-trace"
|
|
534
|
+
)
|
|
535
|
+
|
|
536
|
+
for pattern in "${claude_trace_dirs[@]}"; do
|
|
537
|
+
if [ -d "$pattern" ] || ls $pattern >/dev/null 2>&1; then
|
|
538
|
+
echo "🗑️ Removing existing directory: $pattern"
|
|
539
|
+
rm -rf $pattern 2>/dev/null || true
|
|
540
|
+
fi
|
|
541
|
+
done
|
|
542
|
+
|
|
543
|
+
# Install claude-trace with error handling
|
|
544
|
+
echo "📦 Attempting claude-trace installation..."
|
|
545
|
+
local install_success=false
|
|
546
|
+
local attempts=2
|
|
547
|
+
|
|
548
|
+
for attempt in $(seq 1 $attempts); do
|
|
549
|
+
echo "📦 Installation attempt $attempt/$attempts..."
|
|
550
|
+
|
|
551
|
+
if npm install -g @mariozechner/claude-trace 2>/dev/null; then
|
|
552
|
+
install_success=true
|
|
553
|
+
break
|
|
554
|
+
else
|
|
555
|
+
local exit_code=$?
|
|
556
|
+
echo "⚠️ Installation failed with exit code $exit_code (attempt $attempt/$attempts)"
|
|
557
|
+
if [ $attempt -lt $attempts ]; then
|
|
558
|
+
echo "🔄 Retrying installation..."
|
|
559
|
+
sleep 2
|
|
560
|
+
fi
|
|
561
|
+
fi
|
|
562
|
+
done
|
|
563
|
+
|
|
564
|
+
if [ "$install_success" = "true" ]; then
|
|
565
|
+
echo "✅ claude-trace installed successfully"
|
|
189
566
|
|
|
190
567
|
# Verify installation
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
568
|
+
echo "🔍 Verifying claude-trace installation..."
|
|
569
|
+
|
|
570
|
+
# Wait for filesystem consistency
|
|
571
|
+
sleep 1
|
|
572
|
+
|
|
573
|
+
# Check installation indicators
|
|
574
|
+
local verification_passed=false
|
|
575
|
+
local claude_trace_bin="/home/node/.local/bin/claude-trace"
|
|
576
|
+
local claude_trace_module="/home/node/.local/lib/node_modules/@mariozechner/claude-trace"
|
|
577
|
+
|
|
578
|
+
if [ -f "$claude_trace_bin" ] && [ -d "$claude_trace_module" ]; then
|
|
579
|
+
echo "✓ Binary and module directory both exist"
|
|
580
|
+
|
|
581
|
+
# Test if the command actually works
|
|
582
|
+
if "$claude_trace_bin" --version >/dev/null 2>&1; then
|
|
583
|
+
local version=$("$claude_trace_bin" --version 2>/dev/null || echo "installed")
|
|
584
|
+
echo "📌 claude-trace version: $version"
|
|
585
|
+
echo "✓ Command execution test passed"
|
|
586
|
+
verification_passed=true
|
|
587
|
+
else
|
|
588
|
+
echo "⚠️ Binary exists but command execution failed"
|
|
589
|
+
fi
|
|
590
|
+
elif command -v claude-trace &> /dev/null; then
|
|
591
|
+
local version=$(claude-trace --version 2>/dev/null || echo "installed")
|
|
592
|
+
echo "📌 claude-trace version: $version"
|
|
593
|
+
echo "✓ Command found in PATH"
|
|
594
|
+
verification_passed=true
|
|
595
|
+
else
|
|
596
|
+
echo "❌ Installation verification failed:"
|
|
597
|
+
echo " - Binary check: $([ -f "$claude_trace_bin" ] && echo "FOUND" || echo "MISSING")"
|
|
598
|
+
echo " - Module check: $([ -d "$claude_trace_module" ] && echo "FOUND" || echo "MISSING")"
|
|
599
|
+
echo " - PATH check: $(command -v claude-trace &> /dev/null && echo "FOUND" || echo "MISSING")"
|
|
600
|
+
fi
|
|
601
|
+
|
|
602
|
+
if [ "$verification_passed" = "true" ]; then
|
|
603
|
+
echo "✅ claude-trace installation verification passed"
|
|
604
|
+
create_state_marker "claude-trace" "npm"
|
|
194
605
|
return 0
|
|
195
606
|
else
|
|
196
|
-
echo "
|
|
607
|
+
echo "❌ claude-trace installation verification failed"
|
|
197
608
|
return 1
|
|
198
609
|
fi
|
|
199
610
|
else
|
|
200
|
-
echo "❌ Failed to install
|
|
611
|
+
echo "❌ Failed to install claude-trace after $attempts attempts"
|
|
612
|
+
echo "💡 Manual installation command: npm install -g @mariozechner/claude-trace"
|
|
201
613
|
return 1
|
|
202
614
|
fi
|
|
203
615
|
}
|
|
@@ -206,30 +618,52 @@ install_ccusage() {
|
|
|
206
618
|
install_dev_tools() {
|
|
207
619
|
echo "🛠️ Installing additional development tools..."
|
|
208
620
|
|
|
209
|
-
# Install git-delta for better git diffs
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
#
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
local delta_version="0.18.2"
|
|
217
|
-
local delta_url="https://github.com/dandavison/delta/releases/download/${delta_version}/delta-${delta_version}-x86_64-unknown-linux-musl.tar.gz"
|
|
218
|
-
|
|
219
|
-
if retry_command 2 5 wget -q -O /tmp/delta.tar.gz "$delta_url"; then
|
|
220
|
-
sudo tar -xzf /tmp/delta.tar.gz -C /usr/local/bin delta-${delta_version}-x86_64-unknown-linux-musl/delta --strip-components=1
|
|
221
|
-
sudo chmod +x /usr/local/bin/delta
|
|
222
|
-
rm -f /tmp/delta.tar.gz
|
|
223
|
-
echo "✅ git-delta installed successfully"
|
|
224
|
-
|
|
225
|
-
# Configure git to use delta
|
|
621
|
+
# Install git-delta for better git diffs
|
|
622
|
+
if command -v delta &> /dev/null; then
|
|
623
|
+
echo "✅ git-delta already installed"
|
|
624
|
+
# Still check and configure git if needed
|
|
625
|
+
current_pager=$(git config --global core.pager 2>/dev/null || echo "")
|
|
626
|
+
if [ "$current_pager" != "delta" ]; then
|
|
627
|
+
echo "🔧 Configuring git to use delta..."
|
|
226
628
|
git config --global core.pager "delta"
|
|
227
629
|
git config --global interactive.diffFilter "delta --color-only"
|
|
228
630
|
git config --global delta.navigate true
|
|
229
631
|
git config --global delta.light false
|
|
230
632
|
git config --global delta.side-by-side true
|
|
231
633
|
else
|
|
232
|
-
echo "
|
|
634
|
+
echo "✅ Git already configured to use delta"
|
|
635
|
+
fi
|
|
636
|
+
else
|
|
637
|
+
echo "📦 Installing git-delta..."
|
|
638
|
+
if command -v cargo &> /dev/null; then
|
|
639
|
+
# If cargo is available, use it
|
|
640
|
+
cargo install git-delta
|
|
641
|
+
else
|
|
642
|
+
# Otherwise, download the binary
|
|
643
|
+
delta_version="0.18.2"
|
|
644
|
+
delta_url="https://github.com/dandavison/delta/releases/download/${delta_version}/delta-${delta_version}-x86_64-unknown-linux-musl.tar.gz"
|
|
645
|
+
|
|
646
|
+
if retry_command 2 5 wget -q -O /tmp/delta.tar.gz "$delta_url"; then
|
|
647
|
+
sudo tar -xzf /tmp/delta.tar.gz -C /usr/local/bin delta-${delta_version}-x86_64-unknown-linux-musl/delta --strip-components=1
|
|
648
|
+
sudo chmod +x /usr/local/bin/delta
|
|
649
|
+
rm -f /tmp/delta.tar.gz
|
|
650
|
+
echo "✅ git-delta installed successfully"
|
|
651
|
+
|
|
652
|
+
# Configure git to use delta (idempotent)
|
|
653
|
+
current_pager=$(git config --global core.pager 2>/dev/null || echo "")
|
|
654
|
+
if [ "$current_pager" != "delta" ]; then
|
|
655
|
+
echo "🔧 Configuring git to use delta..."
|
|
656
|
+
git config --global core.pager "delta"
|
|
657
|
+
git config --global interactive.diffFilter "delta --color-only"
|
|
658
|
+
git config --global delta.navigate true
|
|
659
|
+
git config --global delta.light false
|
|
660
|
+
git config --global delta.side-by-side true
|
|
661
|
+
else
|
|
662
|
+
echo "✅ Git already configured to use delta"
|
|
663
|
+
fi
|
|
664
|
+
else
|
|
665
|
+
echo "⚠️ Failed to install git-delta"
|
|
666
|
+
fi
|
|
233
667
|
fi
|
|
234
668
|
fi
|
|
235
669
|
|
|
@@ -237,12 +671,187 @@ install_dev_tools() {
|
|
|
237
671
|
setup_shell_config
|
|
238
672
|
}
|
|
239
673
|
|
|
674
|
+
# Function to setup Claude Code environment variables
|
|
675
|
+
setup_claude_environment() {
|
|
676
|
+
echo "🔧 Setting up Claude Code environment variables..."
|
|
677
|
+
|
|
678
|
+
# Claude Code Performance and Timeout Settings (configurable via .env)
|
|
679
|
+
export BASH_DEFAULT_TIMEOUT_MS="${BASH_DEFAULT_TIMEOUT_MS:-120000}"
|
|
680
|
+
export BASH_MAX_TIMEOUT_MS="${BASH_MAX_TIMEOUT_MS:-600000}"
|
|
681
|
+
export CLAUDE_CODE_MAX_OUTPUT_TOKENS="${CLAUDE_CODE_MAX_OUTPUT_TOKENS:-31999}"
|
|
682
|
+
export MAX_THINKING_TOKENS="${MAX_THINKING_TOKENS:-62000}"
|
|
683
|
+
export MAX_MCP_OUTPUT_TOKENS="${MAX_MCP_OUTPUT_TOKENS:-31999}"
|
|
684
|
+
export MCP_TIMEOUT="${MCP_TIMEOUT:-60000}"
|
|
685
|
+
export MCP_TOOL_TIMEOUT="${MCP_TOOL_TIMEOUT:-120000}"
|
|
686
|
+
|
|
687
|
+
# Claude Code Stability Settings
|
|
688
|
+
# DISABLE_AUTOUPDATER prevents Claude Code from auto-updating during work sessions
|
|
689
|
+
# which can cause model selections to change and potential loss of system prompts
|
|
690
|
+
export DISABLE_AUTOUPDATER="${DISABLE_AUTOUPDATER:-true}"
|
|
691
|
+
|
|
692
|
+
# DISABLE_BUG_COMMAND prevents accidental bug reports in container environments
|
|
693
|
+
export DISABLE_BUG_COMMAND="${DISABLE_BUG_COMMAND:-true}"
|
|
694
|
+
|
|
695
|
+
# ENABLE_AUTOMATIC_TERMINAL_SETUP controls whether terminal keybindings are automatically configured
|
|
696
|
+
# This performs the equivalent of Claude Code's /terminal-setup slash command
|
|
697
|
+
export ENABLE_AUTOMATIC_TERMINAL_SETUP="${ENABLE_AUTOMATIC_TERMINAL_SETUP:-false}"
|
|
698
|
+
|
|
699
|
+
echo "✅ Claude Code environment variables configured:"
|
|
700
|
+
echo " 📊 BASH_DEFAULT_TIMEOUT_MS: $BASH_DEFAULT_TIMEOUT_MS"
|
|
701
|
+
echo " 📊 BASH_MAX_TIMEOUT_MS: $BASH_MAX_TIMEOUT_MS"
|
|
702
|
+
echo " 📊 CLAUDE_CODE_MAX_OUTPUT_TOKENS: $CLAUDE_CODE_MAX_OUTPUT_TOKENS"
|
|
703
|
+
echo " 📊 MAX_THINKING_TOKENS: $MAX_THINKING_TOKENS"
|
|
704
|
+
echo " 📊 MAX_MCP_OUTPUT_TOKENS: $MAX_MCP_OUTPUT_TOKENS"
|
|
705
|
+
echo " 📊 MCP_TIMEOUT: $MCP_TIMEOUT"
|
|
706
|
+
echo " 📊 MCP_TOOL_TIMEOUT: $MCP_TOOL_TIMEOUT"
|
|
707
|
+
echo " 🔒 DISABLE_AUTOUPDATER: $DISABLE_AUTOUPDATER"
|
|
708
|
+
echo " 🔒 DISABLE_BUG_COMMAND: $DISABLE_BUG_COMMAND"
|
|
709
|
+
echo " ⌨️ ENABLE_AUTOMATIC_TERMINAL_SETUP: $ENABLE_AUTOMATIC_TERMINAL_SETUP"
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
# Function to setup terminal keybindings (equivalent to /terminal-setup)
|
|
713
|
+
setup_terminal_keybindings() {
|
|
714
|
+
echo "🔧 Setting up terminal keybindings..."
|
|
715
|
+
|
|
716
|
+
# Check if automatic terminal setup is enabled (default: false)
|
|
717
|
+
if [ "${ENABLE_AUTOMATIC_TERMINAL_SETUP:-false}" != "true" ]; then
|
|
718
|
+
echo "⏭️ Automatic terminal setup disabled (set ENABLE_AUTOMATIC_TERMINAL_SETUP=true to enable)"
|
|
719
|
+
return 0
|
|
720
|
+
fi
|
|
721
|
+
|
|
722
|
+
local keybindings_file="/home/node/.config/Code/User/keybindings.json"
|
|
723
|
+
local keybindings_dir="/home/node/.config/Code/User"
|
|
724
|
+
|
|
725
|
+
# Create VSCode config directory if it doesn't exist
|
|
726
|
+
if [ ! -d "$keybindings_dir" ]; then
|
|
727
|
+
mkdir -p "$keybindings_dir"
|
|
728
|
+
chown -R node:node "/home/node/.config/Code"
|
|
729
|
+
fi
|
|
730
|
+
|
|
731
|
+
# Create or update keybindings file with proper Shift+Enter setup
|
|
732
|
+
if [ -f "$keybindings_file" ]; then
|
|
733
|
+
# Check if Shift+Enter binding already exists and is correctly configured
|
|
734
|
+
if grep -q "shift+enter" "$keybindings_file" 2>/dev/null; then
|
|
735
|
+
echo "📝 Existing Shift+Enter keybinding found, validating configuration..."
|
|
736
|
+
|
|
737
|
+
# Check if it's the correct terminal setup binding
|
|
738
|
+
if grep -A 5 -B 5 "shift+enter" "$keybindings_file" | grep -q "workbench.action.terminal.sendSequence" && \
|
|
739
|
+
grep -A 5 -B 5 "shift+enter" "$keybindings_file" | grep -q "terminalFocus"; then
|
|
740
|
+
echo "✅ Correct terminal Shift+Enter keybinding already configured"
|
|
741
|
+
return 0
|
|
742
|
+
else
|
|
743
|
+
echo "⚠️ Incorrect Shift+Enter keybinding found, replacing with correct terminal setup..."
|
|
744
|
+
# Create backup
|
|
745
|
+
cp "$keybindings_file" "${keybindings_file}.backup.$(date +%Y%m%d_%H%M%S)"
|
|
746
|
+
|
|
747
|
+
# Remove existing Shift+Enter bindings
|
|
748
|
+
if command -v jq >/dev/null 2>&1; then
|
|
749
|
+
jq 'map(select(.key != "shift+enter"))' "$keybindings_file" > "${keybindings_file}.tmp" && \
|
|
750
|
+
mv "${keybindings_file}.tmp" "$keybindings_file"
|
|
751
|
+
else
|
|
752
|
+
sed -i '/shift+enter/,/}/d' "$keybindings_file"
|
|
753
|
+
sed -i 's/,\s*]/]/g' "$keybindings_file"
|
|
754
|
+
sed -i 's/,\s*}/}/g' "$keybindings_file"
|
|
755
|
+
fi
|
|
756
|
+
fi
|
|
757
|
+
else
|
|
758
|
+
echo "📝 No Shift+Enter keybinding found, adding terminal setup..."
|
|
759
|
+
fi
|
|
760
|
+
|
|
761
|
+
# Add the correct terminal Shift+Enter keybinding
|
|
762
|
+
if command -v jq >/dev/null 2>&1; then
|
|
763
|
+
# Use jq to properly add the terminal keybinding
|
|
764
|
+
jq '. += [{
|
|
765
|
+
"key": "shift+enter",
|
|
766
|
+
"command": "workbench.action.terminal.sendSequence",
|
|
767
|
+
"args": {
|
|
768
|
+
"text": "\\r\\n"
|
|
769
|
+
},
|
|
770
|
+
"when": "terminalFocus"
|
|
771
|
+
}]' "$keybindings_file" > "${keybindings_file}.tmp" && \
|
|
772
|
+
mv "${keybindings_file}.tmp" "$keybindings_file"
|
|
773
|
+
else
|
|
774
|
+
# Fallback: manually construct the JSON
|
|
775
|
+
if [ "$(cat "$keybindings_file")" = "[]" ]; then
|
|
776
|
+
# Empty array, replace entirely
|
|
777
|
+
cat > "$keybindings_file" << 'EOF'
|
|
778
|
+
[
|
|
779
|
+
{
|
|
780
|
+
"key": "shift+enter",
|
|
781
|
+
"command": "workbench.action.terminal.sendSequence",
|
|
782
|
+
"args": {
|
|
783
|
+
"text": "\\r\\n"
|
|
784
|
+
},
|
|
785
|
+
"when": "terminalFocus"
|
|
786
|
+
}
|
|
787
|
+
]
|
|
788
|
+
EOF
|
|
789
|
+
else
|
|
790
|
+
# Existing content, need to insert
|
|
791
|
+
# Remove the closing ] and add the new binding
|
|
792
|
+
sed -i '$s/]//' "$keybindings_file"
|
|
793
|
+
cat >> "$keybindings_file" << 'EOF'
|
|
794
|
+
,{
|
|
795
|
+
"key": "shift+enter",
|
|
796
|
+
"command": "workbench.action.terminal.sendSequence",
|
|
797
|
+
"args": {
|
|
798
|
+
"text": "\\r\\n"
|
|
799
|
+
},
|
|
800
|
+
"when": "terminalFocus"
|
|
801
|
+
}
|
|
802
|
+
]
|
|
803
|
+
EOF
|
|
804
|
+
fi
|
|
805
|
+
fi
|
|
806
|
+
|
|
807
|
+
# Validate JSON
|
|
808
|
+
if ! python3 -m json.tool "$keybindings_file" >/dev/null 2>&1; then
|
|
809
|
+
echo "⚠️ JSON validation failed, creating clean terminal setup..."
|
|
810
|
+
cat > "$keybindings_file" << 'EOF'
|
|
811
|
+
[
|
|
812
|
+
{
|
|
813
|
+
"key": "shift+enter",
|
|
814
|
+
"command": "workbench.action.terminal.sendSequence",
|
|
815
|
+
"args": {
|
|
816
|
+
"text": "\\r\\n"
|
|
817
|
+
},
|
|
818
|
+
"when": "terminalFocus"
|
|
819
|
+
}
|
|
820
|
+
]
|
|
821
|
+
EOF
|
|
822
|
+
fi
|
|
823
|
+
|
|
824
|
+
else
|
|
825
|
+
# Create new keybindings file with terminal setup
|
|
826
|
+
echo "📝 Creating new keybindings.json with terminal setup..."
|
|
827
|
+
cat > "$keybindings_file" << 'EOF'
|
|
828
|
+
[
|
|
829
|
+
{
|
|
830
|
+
"key": "shift+enter",
|
|
831
|
+
"command": "workbench.action.terminal.sendSequence",
|
|
832
|
+
"args": {
|
|
833
|
+
"text": "\\r\\n"
|
|
834
|
+
},
|
|
835
|
+
"when": "terminalFocus"
|
|
836
|
+
}
|
|
837
|
+
]
|
|
838
|
+
EOF
|
|
839
|
+
fi
|
|
840
|
+
|
|
841
|
+
# Set proper ownership and permissions
|
|
842
|
+
chown node:node "$keybindings_file"
|
|
843
|
+
chmod 644 "$keybindings_file"
|
|
844
|
+
|
|
845
|
+
echo "✅ Terminal Shift+Enter keybinding configured successfully"
|
|
846
|
+
echo " 💡 Shift+Enter will now send newlines in VSCode terminal (equivalent to /terminal-setup)"
|
|
847
|
+
}
|
|
848
|
+
|
|
240
849
|
# Function to setup enhanced ZSH configuration
|
|
241
850
|
setup_shell_config() {
|
|
242
851
|
echo "🐚 Setting up enhanced shell configuration..."
|
|
243
852
|
|
|
244
853
|
# Add PATH configuration to shell files
|
|
245
|
-
|
|
854
|
+
shell_files=(
|
|
246
855
|
"/home/node/.bashrc"
|
|
247
856
|
"/home/node/.zshrc"
|
|
248
857
|
"/home/node/.profile"
|
|
@@ -257,7 +866,33 @@ setup_shell_config() {
|
|
|
257
866
|
cat >> "$shell_file" << 'EOF'
|
|
258
867
|
|
|
259
868
|
# ClaudePod custom configuration
|
|
260
|
-
|
|
869
|
+
# Function to add directory to PATH without duplication
|
|
870
|
+
add_to_path() {
|
|
871
|
+
local dir="$1"
|
|
872
|
+
case ":$PATH:" in
|
|
873
|
+
*":$dir:"*) ;;
|
|
874
|
+
*) export PATH="$dir:$PATH" ;;
|
|
875
|
+
esac
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
# Add local bin to PATH (avoiding duplicates)
|
|
879
|
+
add_to_path "$HOME/.local/bin"
|
|
880
|
+
|
|
881
|
+
# Source NVM (Node Version Manager)
|
|
882
|
+
export NVM_DIR="/usr/local/share/nvm"
|
|
883
|
+
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
|
|
884
|
+
|
|
885
|
+
# Claude Code Environment Variables (configurable via .devcontainer/.env)
|
|
886
|
+
export BASH_DEFAULT_TIMEOUT_MS="${BASH_DEFAULT_TIMEOUT_MS:-120000}"
|
|
887
|
+
export BASH_MAX_TIMEOUT_MS="${BASH_MAX_TIMEOUT_MS:-600000}"
|
|
888
|
+
export CLAUDE_CODE_MAX_OUTPUT_TOKENS="${CLAUDE_CODE_MAX_OUTPUT_TOKENS:-31999}"
|
|
889
|
+
export MAX_THINKING_TOKENS="${MAX_THINKING_TOKENS:-62000}"
|
|
890
|
+
export MAX_MCP_OUTPUT_TOKENS="${MAX_MCP_OUTPUT_TOKENS:-31999}"
|
|
891
|
+
export MCP_TIMEOUT="${MCP_TIMEOUT:-60000}"
|
|
892
|
+
export MCP_TOOL_TIMEOUT="${MCP_TOOL_TIMEOUT:-120000}"
|
|
893
|
+
export DISABLE_AUTOUPDATER="${DISABLE_AUTOUPDATER:-true}"
|
|
894
|
+
export DISABLE_BUG_COMMAND="${DISABLE_BUG_COMMAND:-true}"
|
|
895
|
+
export ENABLE_AUTOMATIC_TERMINAL_SETUP="${ENABLE_AUTOMATIC_TERMINAL_SETUP:-false}"
|
|
261
896
|
|
|
262
897
|
# Git aliases
|
|
263
898
|
alias gs='git status'
|
|
@@ -266,13 +901,43 @@ alias gc='git commit'
|
|
|
266
901
|
alias gp='git push'
|
|
267
902
|
alias gl='git log --oneline --graph --decorate'
|
|
268
903
|
|
|
269
|
-
# Claude Code alias with permissions flag
|
|
270
|
-
alias claude='claude --model sonnet --dangerously-skip-permissions'
|
|
271
|
-
|
|
272
904
|
# List aliases
|
|
273
905
|
alias ll='ls -alF'
|
|
274
906
|
alias la='ls -A'
|
|
275
907
|
alias l='ls -CF'
|
|
908
|
+
|
|
909
|
+
# ClaudePod usage information function
|
|
910
|
+
claudepod_info() {
|
|
911
|
+
echo ""
|
|
912
|
+
echo "🐳 ClaudePod Development Container"
|
|
913
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
914
|
+
echo "🔧 Core Tools:"
|
|
915
|
+
echo " claude # Start Claude Code CLI"
|
|
916
|
+
echo " ccusage # View Claude Code usage analytics"
|
|
917
|
+
echo " cchistory # Analyze Claude Code prompt changes"
|
|
918
|
+
echo " claude-trace # Record Claude Code interactions"
|
|
919
|
+
echo ""
|
|
920
|
+
echo "📊 Quick Commands:"
|
|
921
|
+
echo " ccusage # Daily usage report"
|
|
922
|
+
echo " ccusage session # Usage by conversation"
|
|
923
|
+
echo " cchistory 1.0.50 --latest # Compare prompts since v1.0.50"
|
|
924
|
+
echo " cchistory --current # View current version prompts"
|
|
925
|
+
echo " claude-trace # Start logging Claude interactions"
|
|
926
|
+
echo " claude-trace --generate-html logs.jsonl report.html # Create HTML report"
|
|
927
|
+
echo ""
|
|
928
|
+
echo "💡 Tips:"
|
|
929
|
+
echo " • Claude statusline shows real-time usage/costs"
|
|
930
|
+
echo " • Use 'gs', 'gd', 'gc' for git shortcuts"
|
|
931
|
+
echo " • Run 'claudepod_info' anytime to see this again"
|
|
932
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
933
|
+
echo ""
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
# Show ClaudePod info on first terminal open (once per session)
|
|
937
|
+
if [ ! -f "/tmp/.claudepod_info_shown_$$" ]; then
|
|
938
|
+
claudepod_info
|
|
939
|
+
touch "/tmp/.claudepod_info_shown_$$"
|
|
940
|
+
fi
|
|
276
941
|
EOF
|
|
277
942
|
fi
|
|
278
943
|
|
|
@@ -282,10 +947,19 @@ EOF
|
|
|
282
947
|
done
|
|
283
948
|
|
|
284
949
|
# Run ZSH enhancement setup as the node user if available
|
|
285
|
-
if [ -f "
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
950
|
+
if [ -f "/workspace/.devcontainer/setup-zsh.sh" ]; then
|
|
951
|
+
echo "🔧 Clearing npm prefix conflicts before ZSH setup..."
|
|
952
|
+
# Clear npm prefix environment variables that conflict with NVM during shell setup
|
|
953
|
+
unset npm_config_prefix 2>/dev/null || true
|
|
954
|
+
unset NPM_CONFIG_PREFIX 2>/dev/null || true
|
|
955
|
+
|
|
956
|
+
if sudo -u node -E bash -c 'unset npm_config_prefix; unset NPM_CONFIG_PREFIX; bash /workspace/.devcontainer/setup-zsh.sh' 2>&1; then
|
|
957
|
+
echo "✅ ZSH setup completed successfully"
|
|
958
|
+
else
|
|
959
|
+
local exit_code=$?
|
|
960
|
+
echo "⚠️ ZSH setup encountered some non-critical errors (exit code: $exit_code), continuing..."
|
|
961
|
+
echo " You can manually run: sudo -u node bash /workspace/.devcontainer/setup-zsh.sh"
|
|
962
|
+
fi
|
|
289
963
|
echo "✅ Enhanced ZSH configuration completed"
|
|
290
964
|
else
|
|
291
965
|
echo "✅ Basic shell configuration completed"
|
|
@@ -305,49 +979,23 @@ display_completion_message() {
|
|
|
305
979
|
echo " 3. Your configuration will persist in the mounted volumes"
|
|
306
980
|
echo ""
|
|
307
981
|
echo "🛠️ Installed tools:"
|
|
308
|
-
echo " - Claude Code CLI"
|
|
982
|
+
echo " - Claude Code CLI with statusline integration"
|
|
309
983
|
echo " - ccusage (Claude Code usage analytics)"
|
|
984
|
+
echo " - cchistory (Claude Code prompt analyzer)"
|
|
985
|
+
echo " - claude-trace (Claude Code interaction recorder)"
|
|
310
986
|
echo " - git-delta (better git diffs)"
|
|
311
987
|
echo " - Shell aliases (gs, gd, gc, gp, gl)"
|
|
312
988
|
echo ""
|
|
313
|
-
echo "💡
|
|
989
|
+
echo "💡 Tips:"
|
|
990
|
+
echo " • Run 'claude' to start Claude Code with statusline integration"
|
|
991
|
+
echo " • Use 'ccusage' for real-time usage analytics and cost tracking"
|
|
992
|
+
echo " • Use 'cchistory' to analyze Claude Code prompt changes"
|
|
993
|
+
echo " • Use 'claude-trace' to record and analyze Claude interactions"
|
|
994
|
+
echo " • Terminal info shown on new terminal sessions"
|
|
995
|
+
echo " • Run 'claudepod_info' anytime for quick command reference"
|
|
314
996
|
echo "════════════════════════════════════════════════════════════════"
|
|
315
997
|
}
|
|
316
998
|
|
|
317
|
-
# Function to setup npm directories and permissions
|
|
318
|
-
setup_npm_permissions() {
|
|
319
|
-
echo "🔧 Setting up npm directories and permissions..."
|
|
320
|
-
|
|
321
|
-
# Create npm directories with correct ownership
|
|
322
|
-
local npm_dirs=(
|
|
323
|
-
"/home/node/.npm"
|
|
324
|
-
"/home/node/.npm/_cacache"
|
|
325
|
-
"/home/node/.npm/_logs"
|
|
326
|
-
"/home/node/.config"
|
|
327
|
-
"/home/node/.local"
|
|
328
|
-
"/home/node/.local/bin"
|
|
329
|
-
)
|
|
330
|
-
|
|
331
|
-
for dir in "${npm_dirs[@]}"; do
|
|
332
|
-
mkdir -p "$dir"
|
|
333
|
-
chown -R node:node "$dir"
|
|
334
|
-
chmod -R 755 "$dir"
|
|
335
|
-
done
|
|
336
|
-
|
|
337
|
-
# Remove any existing .npmrc directory/file and create .npmrc file
|
|
338
|
-
rm -rf /home/node/.npmrc
|
|
339
|
-
cat > /home/node/.npmrc << 'EOF'
|
|
340
|
-
cache=/home/node/.npm/_cacache
|
|
341
|
-
prefix=/home/node/.local
|
|
342
|
-
update-notifier=false
|
|
343
|
-
EOF
|
|
344
|
-
|
|
345
|
-
# Set proper ownership for .npmrc
|
|
346
|
-
chown node:node /home/node/.npmrc
|
|
347
|
-
chmod 644 /home/node/.npmrc
|
|
348
|
-
|
|
349
|
-
echo "✅ npm directories and permissions configured"
|
|
350
|
-
}
|
|
351
999
|
|
|
352
1000
|
# Main execution
|
|
353
1001
|
main() {
|
|
@@ -355,37 +1003,66 @@ main() {
|
|
|
355
1003
|
echo "🐳 ClaudePod Post-Create Setup - Phases 2 & 4"
|
|
356
1004
|
echo "════════════════════════════════════════════════════════════════"
|
|
357
1005
|
|
|
358
|
-
# Source NVM and ensure PATH is set correctly for the entire script
|
|
359
|
-
export NVM_DIR="/usr/local/share/nvm"
|
|
360
|
-
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
|
|
361
|
-
export PATH="/home/node/.local/bin:$PATH"
|
|
362
|
-
|
|
363
1006
|
# Fix workspace permissions
|
|
364
1007
|
echo "🔧 Setting workspace permissions..."
|
|
365
|
-
|
|
366
|
-
|
|
1008
|
+
if [ -d "/workspace" ]; then
|
|
1009
|
+
sudo chown -R node:node /workspace
|
|
1010
|
+
sudo chmod -R u+rwX,g+rwX /workspace
|
|
1011
|
+
else
|
|
1012
|
+
echo "⚠️ /workspace directory not found - this is unexpected"
|
|
1013
|
+
exit 1
|
|
1014
|
+
fi
|
|
367
1015
|
|
|
368
1016
|
# Setup workspace directories for bind mounts (Claude and Serena)
|
|
369
1017
|
setup_workspace_directories
|
|
370
1018
|
|
|
371
|
-
# Setup npm permissions and directories
|
|
372
|
-
setup_npm_permissions
|
|
373
|
-
|
|
374
1019
|
# Add node user to docker group for Docker socket access
|
|
375
1020
|
echo "🐳 Adding node user to docker group..."
|
|
376
|
-
sudo usermod -aG docker node
|
|
1021
|
+
sudo usermod -aG docker node 2>/dev/null || echo " Docker group already configured"
|
|
377
1022
|
echo "✅ Node user added to docker group"
|
|
378
1023
|
|
|
1024
|
+
# Setup Claude Code environment variables
|
|
1025
|
+
setup_claude_environment
|
|
1026
|
+
|
|
379
1027
|
# Install Claude Code
|
|
380
1028
|
if install_claude_code; then
|
|
381
|
-
# Setup configuration
|
|
382
|
-
|
|
1029
|
+
# Setup configuration directories using focused modules
|
|
1030
|
+
setup_claude_core_config
|
|
1031
|
+
echo "✓ Claude core config completed successfully"
|
|
1032
|
+
|
|
1033
|
+
setup_serena_config
|
|
1034
|
+
echo "✓ Serena config completed successfully"
|
|
1035
|
+
|
|
1036
|
+
setup_taskmaster_config
|
|
1037
|
+
echo "✓ TaskMaster config completed successfully"
|
|
1038
|
+
|
|
1039
|
+
setup_searxng
|
|
1040
|
+
echo "✓ SearXNG setup completed successfully"
|
|
383
1041
|
|
|
384
1042
|
# Install ccusage CLI tool
|
|
1043
|
+
echo "📊 Starting ccusage installation..."
|
|
385
1044
|
install_ccusage || echo "⚠️ Continuing without ccusage..."
|
|
1045
|
+
echo "✓ ccusage installation phase completed"
|
|
1046
|
+
|
|
1047
|
+
# Install cchistory CLI tool
|
|
1048
|
+
echo "📊 Starting cchistory installation..."
|
|
1049
|
+
install_cchistory || echo "⚠️ Continuing without cchistory..."
|
|
1050
|
+
echo "✓ cchistory installation phase completed"
|
|
1051
|
+
|
|
1052
|
+
# Install claude-trace CLI tool
|
|
1053
|
+
echo "📊 Starting claude-trace installation..."
|
|
1054
|
+
install_claude_trace || echo "⚠️ Continuing without claude-trace..."
|
|
1055
|
+
echo "✓ claude-trace installation phase completed"
|
|
386
1056
|
|
|
387
1057
|
# Install development tools
|
|
388
|
-
|
|
1058
|
+
echo "🛠️ Starting development tools installation..."
|
|
1059
|
+
install_dev_tools || echo "⚠️ Continuing without some dev tools..."
|
|
1060
|
+
echo "✓ Development tools installation phase completed"
|
|
1061
|
+
|
|
1062
|
+
# Setup terminal keybindings (equivalent to /terminal-setup)
|
|
1063
|
+
echo "⌨️ Starting terminal keybindings setup..."
|
|
1064
|
+
setup_terminal_keybindings || echo "⚠️ Continuing without terminal keybindings..."
|
|
1065
|
+
echo "✓ Terminal keybindings setup completed"
|
|
389
1066
|
|
|
390
1067
|
# Display completion message
|
|
391
1068
|
display_completion_message
|
|
@@ -397,4 +1074,4 @@ main() {
|
|
|
397
1074
|
}
|
|
398
1075
|
|
|
399
1076
|
# Execute main function
|
|
400
|
-
main
|
|
1077
|
+
main
|