Add descriptive error handling to CustomCommand, update README, fix Uninstall Emoji that was rendering incorrectly, fix Item Editor line color for consistency, fix version number display

This commit is contained in:
Matthew Breedlove committed 2025-08-17 20:15:54 -04:00
1 parent 990fdf3d54
commit 7782e8b455
7 files changed
+91 -13

No files matched your search

+11 -1
View File
@@ -200,7 +200,7 @@ Execute shell commands and display their output dynamically:
### 🔗 Integration Example: ccusage
[ccusage](https://github.com/samuelint/ccusage) is a tool that tracks and displays Claude Code usage metrics. You can integrate it directly into your status line:
[ccusage](https://github.com/ryoppippi/ccusage) is a tool that tracks and displays Claude Code usage metrics. You can integrate it directly into your status line:
1. Add a Custom Command widget
2. Set command: `npx -y ccusage statusline`
@@ -325,6 +325,16 @@ Contributions are welcome! Please feel free to submit a Pull Request.
---
## Star History
<a href="https://www.star-history.com/#sirmalloc/ccstatusline&Timeline">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=sirmalloc/ccstatusline&type=Timeline&theme=dark" />
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=sirmalloc/ccstatusline&type=Timeline" />
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=sirmalloc/ccstatusline&type=Timeline" />
</picture>
</a>
<div align="center">
### 🌟 Show Your Support
+2 -1
View File
@@ -1,6 +1,6 @@
{
"name": "ccstatusline",
"version": "2.0.0",
"version": "2.0.1",
"description": "A customizable status line formatter for Claude Code CLI",
"module": "src/ccstatusline.ts",
"type": "module",
@@ -13,6 +13,7 @@
"statusline": "bun run src/ccstatusline.ts",
"patch": "patch-package",
"build": "bun run patch && rm -rf dist/* && bun build src/ccstatusline.ts --target=node --outfile=dist/ccstatusline.js --target-version=14",
"postbuild": "bun run scripts/replace-version.ts",
"prepublishOnly": "bun run build",
"lint": "bun tsc --noEmit; eslint . --config eslint.config.js --max-warnings=999999 --fix"
},
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/env bun
import {
readFileSync,
writeFileSync
} from 'fs';
import { join } from 'path';
interface PackageJson {
version: string;
[key: string]: unknown;
}
// Read package.json to get version
const packageJson = JSON.parse(readFileSync('package.json', 'utf-8')) as PackageJson;
const version = packageJson.version;
// Read the bundled file
const bundledFilePath = join('dist', 'ccstatusline.js');
let bundledContent = readFileSync(bundledFilePath, 'utf-8');
// Replace the placeholder with the actual version
bundledContent = bundledContent.replace(/__PACKAGE_VERSION__/g, version);
// Write back the modified content
writeFileSync(bundledFilePath, bundledContent);
console.log(`✓ Replaced version placeholder with ${version}`);
+2 -2
View File
@@ -372,8 +372,8 @@ export const ItemsEditor: React.FC<ItemsEditorProps> = ({ widgets, onUpdate, onB
{' '}
{lineNumber}
{' '}
{moveMode && <Text color='yellow'>[MOVE MODE]</Text>}
</Text>
{moveMode && <Text color='blue'>[MOVE MODE]</Text>}
{(settings.powerline.enabled || Boolean(settings.defaultSeparator)) && (
<Box marginLeft={2}>
<Text color='yellow'>
@@ -412,7 +412,7 @@ export const ItemsEditor: React.FC<ItemsEditorProps> = ({ widgets, onUpdate, onB
return (
<Box key={widget.id}>
<Text>
<Text color={isSelected ? (moveMode ? 'yellow' : 'blue') : undefined}>
<Text color={isSelected ? (moveMode ? 'blue' : 'green') : undefined}>
{isSelected ? (moveMode ? '◆ ' : '▶ ') : ' '}
{` ${index + 1}. ${displayText || getWidgetDisplay(widget)}`}
</Text>
+1 -1
View File
@@ -30,7 +30,7 @@ export const MainMenu: React.FC<MainMenuProps> = ({ onSelect, isClaudeInstalled,
{ label: '💻 Terminal Options', value: 'terminalConfig', selectable: true },
{ label: '🌐 Global Overrides', value: 'globalOverrides', selectable: true },
{ label: '', value: '_gap2', selectable: false }, // Visual gap
{ label: isClaudeInstalled ? '🗑️ Uninstall from Claude Code' : '📦 Install to Claude Code', value: 'install', selectable: true }
{ label: isClaudeInstalled ? '🔌 Uninstall from Claude Code' : '📦 Install to Claude Code', value: 'install', selectable: true }
];
if (hasChanges) {
+25 -6
View File
@@ -3,14 +3,33 @@ import * as fs from 'fs';
import * as path from 'path';
// Get package version
// __PACKAGE_VERSION__ will be replaced at build time
const PACKAGE_VERSION = '__PACKAGE_VERSION__';
export function getPackageVersion(): string {
try {
const packageJsonPath = path.join(__dirname, '..', '..', 'package.json');
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8')) as { version?: string };
return packageJson.version ?? '';
} catch {
return '';
// If we have the build-time replaced version, use it (check if it looks like a version)
if (/^\d+\.\d+\.\d+/.test(PACKAGE_VERSION)) {
return PACKAGE_VERSION;
}
// Fallback for development mode
const possiblePaths = [
path.join(__dirname, '..', '..', 'package.json'), // Development: dist/utils/ -> root
path.join(__dirname, '..', 'package.json') // Production: dist/ -> root (bundled)
];
for (const packageJsonPath of possiblePaths) {
try {
if (fs.existsSync(packageJsonPath)) {
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8')) as { version?: string };
return packageJson.version ?? '';
}
} catch {
// Continue to next path
}
}
return '';
}
// Get terminal width
+22 -2
View File
@@ -60,7 +60,8 @@ export class CustomCommandWidget implements Widget {
encoding: 'utf8',
input: jsonInput,
timeout: timeout,
stdio: ['pipe', 'pipe', 'ignore']
stdio: ['pipe', 'pipe', 'ignore'],
env: process.env
}).trim();
// Strip ANSI codes if preserveColors is false
@@ -74,7 +75,26 @@ export class CustomCommandWidget implements Widget {
}
return output || null;
} catch {
} catch (error) {
// Provide more specific error messages
if (error instanceof Error) {
const execError = error as Error & {
code?: string;
signal?: string;
status?: number;
};
if (execError.code === 'ENOENT') {
return '[Cmd not found]';
} else if (execError.code === 'ETIMEDOUT') {
return '[Timeout]';
} else if (execError.code === 'EACCES') {
return '[Permission denied]';
} else if (execError.signal) {
return `[Signal: ${execError.signal}]`;
} else if (execError.status !== undefined) {
return `[Exit: ${execError.status}]`;
}
}
return '[Error]';
}
}