Skip to content

Commit 603e53d

Browse files
committed
✨ Add new Vercel deployment and error monitoring status lines; enhance colorful status line command
1 parent 3a0f0d2 commit 603e53d

File tree

8 files changed

+98
-28
lines changed

8 files changed

+98
-28
lines changed

.claude/settings.local.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,6 @@
5959
],
6060
"statusLine": {
6161
"type": "command",
62-
"command": "bash -c 'input=$(cat); MODEL=$(echo \"$input\" | jq -r \".model.display_name\"); DIR=$(echo \"$input\" | jq -r \".workspace.current_dir\"); SESSION=$(echo \"$input\" | jq -r \".session_id\" | cut -c1-8); CACHE=\"/tmp/spaceship_$SESSION\"; if [ ! -f \"$CACHE\" ]; then echo \"100 0 0\" > \"$CACHE\"; fi; read FUEL DISTANCE WARP < \"$CACHE\"; FUEL=$((FUEL - 1)); DISTANCE=$((DISTANCE + 5)); if [ $FUEL -le 0 ]; then FUEL=100; WARP=$((WARP + 1)); fi; echo \"$FUEL $DISTANCE $WARP\" > \"$CACHE\"; SHIP=$([ $FUEL -gt 80 ] && echo \"🚀\" || [ $FUEL -gt 40 ] && echo \"🛸\" || echo \"🆘\"); STARS=$(python3 -c \"import random; print(''.join(random.choice('⭐🌟✨') for _ in range(3)))\" 2>/dev/null || echo \"⭐🌟✨\"); echo \"[$MODEL] $SHIP Warp $WARP | ⛽$FUEL% | 🌌 ${DISTANCE}ly | $STARS | 📁 ${DIR##*/}\"'"
62+
"command": "bash -c 'input=$(cat); MODEL=$(echo \"$input\" | jq -r \".model.display_name\"); DIR=$(echo \"$input\" | jq -r \".workspace.current_dir\"); SESSION=$(echo \"$input\" | jq -r \".session_id\" | cut -c1-8); CACHE=\"/tmp/tamagochi_$SESSION\"; if [ ! -f \"$CACHE\" ]; then echo \"100 50 0\" > \"$CACHE\"; fi; read HEALTH HAPPINESS COMMITS < \"$CACHE\"; COMMITS=$((COMMITS + 1)); if [ $((COMMITS % 10)) -eq 0 ]; then HAPPINESS=$((HAPPINESS + 5)); fi; if [ $((COMMITS % 20)) -eq 0 ]; then HEALTH=$((HEALTH - 10)); fi; HEALTH=$((HEALTH > 100 ? 100 : HEALTH)); HAPPINESS=$((HAPPINESS > 100 ? 100 : HAPPINESS)); echo \"$HEALTH $HAPPINESS $COMMITS\" > \"$CACHE\"; if [ $HEALTH -gt 80 ]; then PET=\"🐱\"; elif [ $HEALTH -gt 60 ]; then PET=\"😺\"; elif [ $HEALTH -gt 40 ]; then PET=\"😿\"; else PET=\"💀\"; fi; if [ $HAPPINESS -gt 80 ]; then MOOD=\"✨\"; elif [ $HAPPINESS -gt 60 ]; then MOOD=\"😊\"; elif [ $HAPPINESS -gt 40 ]; then MOOD=\"😐\"; else MOOD=\"😢\"; fi; echo \"[$MODEL] $PET$MOOD HP:$HEALTH Joy:$HAPPINESS | 📁 ${DIR##*/} | Commits:$COMMITS\"'"
6363
}
6464
}

cli-tool/.claude/settings.json

Lines changed: 0 additions & 5 deletions
This file was deleted.

cli-tool/components/settings/statusline/colorful-statusline.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22
"description": "Colorful status line with ANSI color codes for enhanced visual appeal. Uses colors to distinguish between different information types: blue for model, green for directory, yellow for git branch.",
33
"statusLine": {
44
"type": "command",
5-
"command": "bash -c 'input=$(cat); MODEL=$(echo \"$input\" | jq -r \".model.display_name\"); DIR=$(echo \"$input\" | jq -r \".workspace.current_dir\"); BRANCH=\"\"; if git rev-parse --git-dir >/dev/null 2>&1; then BRANCH=\" | \\033[33m🌿 $(git branch --show-current 2>/dev/null)\\033[0m\"; fi; echo \"\\033[34m[$MODEL]\\033[0m \\033[32m📁 ${DIR##*/}\\033[0m$BRANCH\"'"
5+
"command": "bash -c 'input=$(cat); MODEL=$(echo \"$input\" | jq -r \".model.display_name\"); DIR=$(echo \"$input\" | jq -r \".workspace.current_dir\"); BRANCH=\"\"; if git rev-parse --git-dir >/dev/null 2>&1; then BRANCH=\" | 🌿 $(git branch --show-current 2>/dev/null)\"; fi; echo \"[$MODEL] 📁 ${DIR##*/}$BRANCH\"'"
66
}
77
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"description": "Real-time Vercel deployment monitor showing current build status, deployment URL, and time since last deployment. Displays build state with intuitive icons and tracks deployment history. Setup: Export environment variables 'export VERCEL_TOKEN=your_token' and 'export VERCEL_ORG_ID=your_team_id' (or manually replace $VERCEL_TOKEN and $VERCEL_ORG_ID in the command if you prefer not to use environment variables). Get your token from vercel.com/account/tokens and team ID from your Vercel dashboard.",
3+
"statusLine": {
4+
"type": "command",
5+
"command": "bash -c 'input=$(cat); MODEL=$(echo \"$input\" | jq -r \".model.display_name\"); DIR=$(echo \"$input\" | jq -r \".workspace.current_dir\"); TOKEN=\"$VERCEL_TOKEN\"; TEAM=\"$VERCEL_ORG_ID\"; PROJECT=$(basename \"$PWD\"); DEPLOY_DATA=$(timeout 5 curl -s -H \"Authorization: Bearer $TOKEN\" \"https://api.vercel.com/v6/deployments?projectId=$PROJECT&teamId=$TEAM&limit=1\" 2>/dev/null); STATE=$(echo \"$DEPLOY_DATA\" | grep -o '\"state\":\"[^\"]*\"' | head -1 | cut -d'\"' -f4); URL=$(echo \"$DEPLOY_DATA\" | grep -o '\"url\":\"[^\"]*\"' | head -1 | cut -d'\"' -f4 | cut -c1-20); CREATED=$(echo \"$DEPLOY_DATA\" | grep -o '\"createdAt\":[0-9]*' | cut -d':' -f2 | head -1); if [ -n \"$CREATED\" ]; then AGO=$(( ($(date +%s) - $CREATED/1000) / 60 )); TIME_AGO=\"${AGO}m ago\"; else TIME_AGO=\"unknown\"; fi; STATUS_ICON=$([ \"$STATE\" = \"READY\" ] && echo \"✅\" || [ \"$STATE\" = \"BUILDING\" ] && echo \"🔄\" || [ \"$STATE\" = \"QUEUED\" ] && echo \"⏳\" || [ \"$STATE\" = \"ERROR\" ] && echo \"❌\" || echo \"❓\"); echo \"[$MODEL] 🚀 $STATUS_ICON $STATE | 🌐 $URL | ⏰ $TIME_AGO | 📁 ${DIR##*/}\"'"
6+
}
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"description": "Intelligent error monitoring system that tracks deployment failures and build issues. Automatically sends desktop notifications when errors are detected and maintains error count tracking. Features building status monitoring and provides immediate alerts for deployment problems, helping you catch issues quickly. Setup: Export environment variables 'export VERCEL_TOKEN=your_token' and 'export VERCEL_ORG_ID=your_team_id' (or manually replace $VERCEL_TOKEN and $VERCEL_ORG_ID in the command if you prefer not to use environment variables). Get your token from vercel.com/account/tokens and team ID from your Vercel dashboard. Desktop notifications work on macOS.",
3+
"statusLine": {
4+
"type": "command",
5+
"command": "bash -c 'input=$(cat); MODEL=$(echo \"$input\" | jq -r \".model.display_name\"); DIR=$(echo \"$input\" | jq -r \".workspace.current_dir\"); TOKEN=\"$VERCEL_TOKEN\"; TEAM=\"$VERCEL_ORG_ID\"; PROJECT=$(basename \"$PWD\"); SESSION=$(echo \"$input\" | jq -r \".session_id\" | cut -c1-8); ERROR_FILE=\"/tmp/vercel_errors_$SESSION\"; DEPLOYS=$(timeout 5 curl -s -H \"Authorization: Bearer $TOKEN\" \"https://api.vercel.com/v6/deployments?projectId=$PROJECT&teamId=$TEAM&limit=5\" 2>/dev/null); ERRORS=$(echo \"$DEPLOYS\" | grep -c '\"state\":\"ERROR\"' || echo \"0\"); BUILDING=$(echo \"$DEPLOYS\" | grep -c '\"state\":\"BUILDING\"' || echo \"0\"); if [ \"$ERRORS\" -gt 0 ]; then echo \"$ERRORS\" > \"$ERROR_FILE\"; ALERT=\"🚨 $ERRORS errors!\"; osascript -e \"display notification \\\"$ERRORS deployment errors found\\\" with title \\\"Vercel Alert\\\"\" 2>/dev/null; elif [ \"$BUILDING\" -gt 0 ]; then ALERT=\"🔄 Building...\"; else ALERT=\"✅ All good\"; fi; echo \"[$MODEL] 🚀 $ALERT | Building: $BUILDING | 📁 ${DIR##*/}\"'"
6+
}
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"description": "Monitors both production and preview environments simultaneously with color-coded status indicators. Perfect for teams managing multiple deployment targets. Shows real-time status of your latest production and preview deployments with green/yellow/red indicators for quick visual assessment. Setup: Export environment variables 'export VERCEL_TOKEN=your_token' and 'export VERCEL_ORG_ID=your_team_id' (or manually replace $VERCEL_TOKEN and $VERCEL_ORG_ID in the command if you prefer not to use environment variables). Get your token from vercel.com/account/tokens and team ID from your Vercel dashboard.",
3+
"statusLine": {
4+
"type": "command",
5+
"command": "bash -c 'input=$(cat); MODEL=$(echo \"$input\" | jq -r \".model.display_name\"); DIR=$(echo \"$input\" | jq -r \".workspace.current_dir\"); TOKEN=\"$VERCEL_TOKEN\"; TEAM=\"$VERCEL_ORG_ID\"; PROJECT=$(basename \"$PWD\"); DEPLOYS=$(timeout 5 curl -s -H \"Authorization: Bearer $TOKEN\" \"https://api.vercel.com/v6/deployments?projectId=$PROJECT&teamId=$TEAM&limit=3\" 2>/dev/null); PROD=$(echo \"$DEPLOYS\" | grep -B5 -A5 '\"target\":\"production\"' | grep -o '\"state\":\"[^\"]*\"' | head -1 | cut -d'\"' -f4); PREVIEW=$(echo \"$DEPLOYS\" | grep -B5 -A5 '\"target\":\"preview\"' | grep -o '\"state\":\"[^\"]*\"' | head -1 | cut -d'\"' -f4); PROD_ICON=$([ \"$PROD\" = \"READY\" ] && echo \"🟢\" || [ \"$PROD\" = \"BUILDING\" ] && echo \"🟡\" || echo \"🔴\"); PREV_ICON=$([ \"$PREVIEW\" = \"READY\" ] && echo \"🟢\" || [ \"$PREVIEW\" = \"BUILDING\" ] && echo \"🟡\" || echo \"🔴\"); echo \"[$MODEL] 🚀 Prod:$PROD_ICON Prev:$PREV_ICON | 📁 ${DIR##*/}\"'"
6+
}
7+
}

cli-tool/src/index.js

Lines changed: 50 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -401,8 +401,11 @@ async function installIndividualAgent(agentName, targetDir, options) {
401401
source: 'github_main'
402402
});
403403

404+
return true;
405+
404406
} catch (error) {
405407
console.log(chalk.red(`❌ Error installing agent: ${error.message}`));
408+
return false;
406409
}
407410
}
408411

@@ -464,8 +467,11 @@ async function installIndividualCommand(commandName, targetDir, options) {
464467
source: 'github_main'
465468
});
466469

470+
return true;
471+
467472
} catch (error) {
468473
console.log(chalk.red(`❌ Error installing command: ${error.message}`));
474+
return false;
469475
}
470476
}
471477

@@ -547,8 +553,11 @@ async function installIndividualMCP(mcpName, targetDir, options) {
547553
source: 'github_main'
548554
});
549555

556+
return true;
557+
550558
} catch (error) {
551559
console.log(chalk.red(`❌ Error installing MCP: ${error.message}`));
560+
return false;
552561
}
553562
}
554563

@@ -712,13 +721,20 @@ async function installIndividualSetting(settingName, targetDir, options) {
712721
// Check for conflicting top-level settings
713722
Object.keys(settingConfig).forEach(key => {
714723
if (key !== 'permissions' && key !== 'env' && key !== 'hooks' &&
715-
existingConfig[key] !== undefined && existingConfig[key] !== settingConfig[key]) {
716-
conflicts.push(`Setting "${key}" (current: "${existingConfig[key]}", new: "${settingConfig[key]}")`);
724+
existingConfig[key] !== undefined && JSON.stringify(existingConfig[key]) !== JSON.stringify(settingConfig[key])) {
725+
726+
// For objects, just indicate the setting name without showing the complex values
727+
if (typeof existingConfig[key] === 'object' && existingConfig[key] !== null &&
728+
typeof settingConfig[key] === 'object' && settingConfig[key] !== null) {
729+
conflicts.push(`Setting "${key}" (will be overwritten with new configuration)`);
730+
} else {
731+
conflicts.push(`Setting "${key}" (current: "${existingConfig[key]}", new: "${settingConfig[key]}")`);
732+
}
717733
}
718734
});
719735

720-
// Ask user about conflicts if any exist and not in silent mode
721-
if (conflicts.length > 0 && !options.silent) {
736+
// Ask user about conflicts if any exist
737+
if (conflicts.length > 0) {
722738
console.log(chalk.yellow(`\n⚠️ Conflicts detected while installing setting "${settingName}" in ${installLocation}:`));
723739
conflicts.forEach(conflict => console.log(chalk.gray(` • ${conflict}`)));
724740

@@ -734,10 +750,6 @@ async function installIndividualSetting(settingName, targetDir, options) {
734750
console.log(chalk.yellow(`⏹️ Installation of setting "${settingName}" in ${installLocation} cancelled by user.`));
735751
continue; // Skip this location and continue with others
736752
}
737-
} else if (conflicts.length > 0 && options.silent) {
738-
// In silent mode (batch installation), skip conflicting settings and warn
739-
console.log(chalk.yellow(`⚠️ Skipping setting "${settingName}" in ${installLocation} due to conflicts (use individual installation to resolve)`));
740-
continue; // Skip this location and continue with others
741753
}
742754

743755
// Deep merge configurations
@@ -809,8 +821,11 @@ async function installIndividualSetting(settingName, targetDir, options) {
809821
}
810822
}
811823

824+
return successfulInstallations;
825+
812826
} catch (error) {
813827
console.log(chalk.red(`❌ Error installing setting: ${error.message}`));
828+
return 0;
814829
}
815830
}
816831

@@ -966,8 +981,8 @@ async function installIndividualHook(hookName, targetDir, options) {
966981
// This is because Claude Code's array format naturally supports multiple hooks
967982
// Conflicts are less likely and generally hooks can coexist
968983

969-
// Ask user about conflicts if any exist and not in silent mode
970-
if (conflicts.length > 0 && !options.silent) {
984+
// Ask user about conflicts if any exist
985+
if (conflicts.length > 0) {
971986
console.log(chalk.yellow(`\n⚠️ Conflicts detected while installing hook "${hookName}" in ${installLocation}:`));
972987
conflicts.forEach(conflict => console.log(chalk.gray(` • ${conflict}`)));
973988

@@ -983,10 +998,6 @@ async function installIndividualHook(hookName, targetDir, options) {
983998
console.log(chalk.yellow(`⏹️ Installation of hook "${hookName}" in ${installLocation} cancelled by user.`));
984999
continue; // Skip this location and continue with others
9851000
}
986-
} else if (conflicts.length > 0 && options.silent) {
987-
// In silent mode (batch installation), skip conflicting hooks and warn
988-
console.log(chalk.yellow(`⚠️ Skipping hook "${hookName}" in ${installLocation} due to conflicts (use individual installation to resolve)`));
989-
continue; // Skip this location and continue with others
9901001
}
9911002

9921003
// Deep merge configurations with proper hook array structure
@@ -1066,8 +1077,11 @@ async function installIndividualHook(hookName, targetDir, options) {
10661077
}
10671078
}
10681079

1080+
return successfulInstallations;
1081+
10691082
} catch (error) {
10701083
console.log(chalk.red(`❌ Error installing hook: ${error.message}`));
1084+
return 0;
10711085
}
10721086
}
10731087

@@ -1208,6 +1222,9 @@ async function installMultipleComponents(options, targetDir) {
12081222
console.log(chalk.gray(` Settings: ${components.settings.length}`));
12091223
console.log(chalk.gray(` Hooks: ${components.hooks.length}`));
12101224

1225+
// Counter for successfully installed components
1226+
let successfullyInstalled = 0;
1227+
12111228
// Ask for installation locations once for configuration components (if any exist and not in silent mode)
12121229
let sharedInstallLocations = ['local']; // default
12131230
const hasSettingsOrHooks = components.settings.length > 0 || components.hooks.length > 0;
@@ -1253,39 +1270,44 @@ async function installMultipleComponents(options, targetDir) {
12531270
// Install agents
12541271
for (const agent of components.agents) {
12551272
console.log(chalk.gray(` Installing agent: ${agent}`));
1256-
await installIndividualAgent(agent, targetDir, { ...options, silent: true });
1273+
const agentSuccess = await installIndividualAgent(agent, targetDir, { ...options, silent: true });
1274+
if (agentSuccess) successfullyInstalled++;
12571275
}
12581276

12591277
// Install commands
12601278
for (const command of components.commands) {
12611279
console.log(chalk.gray(` Installing command: ${command}`));
1262-
await installIndividualCommand(command, targetDir, { ...options, silent: true });
1280+
const commandSuccess = await installIndividualCommand(command, targetDir, { ...options, silent: true });
1281+
if (commandSuccess) successfullyInstalled++;
12631282
}
12641283

12651284
// Install MCPs
12661285
for (const mcp of components.mcps) {
12671286
console.log(chalk.gray(` Installing MCP: ${mcp}`));
1268-
await installIndividualMCP(mcp, targetDir, { ...options, silent: true });
1287+
const mcpSuccess = await installIndividualMCP(mcp, targetDir, { ...options, silent: true });
1288+
if (mcpSuccess) successfullyInstalled++;
12691289
}
12701290

12711291
// Install settings (using shared installation locations)
12721292
for (const setting of components.settings) {
12731293
console.log(chalk.gray(` Installing setting: ${setting}`));
1274-
await installIndividualSetting(setting, targetDir, {
1294+
const settingSuccess = await installIndividualSetting(setting, targetDir, {
12751295
...options,
12761296
silent: true,
12771297
sharedInstallLocations: sharedInstallLocations
12781298
});
1299+
if (settingSuccess > 0) successfullyInstalled++;
12791300
}
12801301

12811302
// Install hooks (using shared installation locations)
12821303
for (const hook of components.hooks) {
12831304
console.log(chalk.gray(` Installing hook: ${hook}`));
1284-
await installIndividualHook(hook, targetDir, {
1305+
const hookSuccess = await installIndividualHook(hook, targetDir, {
12851306
...options,
12861307
silent: true,
12871308
sharedInstallLocations: sharedInstallLocations
12881309
});
1310+
if (hookSuccess > 0) successfullyInstalled++;
12891311
}
12901312

12911313
// Handle YAML workflow if provided
@@ -1317,7 +1339,15 @@ async function installMultipleComponents(options, targetDir) {
13171339
}
13181340
}
13191341

1320-
console.log(chalk.green(`\n✅ Successfully installed ${totalComponents} components!`));
1342+
if (successfullyInstalled === totalComponents) {
1343+
console.log(chalk.green(`\n✅ Successfully installed ${successfullyInstalled} components!`));
1344+
} else if (successfullyInstalled > 0) {
1345+
console.log(chalk.yellow(`\n⚠️ Successfully installed ${successfullyInstalled} of ${totalComponents} components.`));
1346+
console.log(chalk.red(`❌ ${totalComponents - successfullyInstalled} component(s) failed to install.`));
1347+
} else {
1348+
console.log(chalk.red(`\n❌ No components were installed successfully.`));
1349+
return; // Exit early if nothing was installed
1350+
}
13211351
console.log(chalk.cyan(`📁 Components installed to: .claude/`));
13221352

13231353
if (options.yaml) {

0 commit comments

Comments
 (0)