@pimzino/claude-code-spec-workflow
Version:
Automated workflows for Claude Code. Includes spec-driven development (Requirements → Design → Tasks → Implementation) with intelligent task execution, optional steering documents and streamlined bug fix workflow (Report → Analyze → Fix → Verify). We have
110 lines • 5.39 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const commander_1 = require("commander");
const chalk_1 = __importDefault(require("chalk"));
const ora_1 = __importDefault(require("ora"));
const multi_server_1 = require("./multi-server");
const tunnel_1 = require("./tunnel");
const program = new commander_1.Command();
program
.name('claude-spec-dashboard')
.description('Launch a real-time dashboard for Claude Code Spec Workflow')
.version('1.3.0');
program
.option('-p, --port <port>', 'Port to run the dashboard on', '8247')
.option('-o, --open', 'Open dashboard in browser automatically')
.option('-t, --tunnel', 'Create a secure tunnel to share the dashboard')
.option('--tunnel-password <password>', 'Password-protect the tunnel')
.option('--tunnel-provider <provider>', 'Tunnel provider to use (cloudflare, ngrok, auto)', 'ngrok')
.option('--ngrok', 'Create a secure tunnel using Ngrok (alias for --tunnel --tunnel-provider ngrok)')
.option('--cloudflare', 'Create a secure tunnel using Cloudflare (alias for --tunnel --tunnel-provider cloudflare)')
.action(async (options) => {
// Handle alias options
if (options.ngrok) {
options.tunnel = true;
options.tunnelProvider = 'ngrok';
}
if (options.cloudflare) {
options.tunnel = true;
options.tunnelProvider = 'cloudflare';
}
console.log(chalk_1.default.cyan.bold('🚀 Claude Code Spec Dashboard'));
console.log(chalk_1.default.gray('Real-time spec and task monitoring'));
console.log();
const spinner = (0, ora_1.default)(options.tunnel ? 'Starting dashboard server and creating tunnel...' : 'Starting dashboard server...').start();
try {
const server = new multi_server_1.MultiProjectDashboardServer({
port: parseInt(options.port),
autoOpen: options.open,
tunnel: options.tunnel,
tunnelPassword: options.tunnelPassword,
tunnelProvider: options.tunnelProvider,
});
await server.start();
// Check if tunnel was created
const tunnelStatus = server.getTunnelStatus();
if (tunnelStatus.active && tunnelStatus.info) {
spinner.succeed(chalk_1.default.green(`Dashboard running at http://localhost:${options.port}`));
console.log();
console.log(chalk_1.default.cyan.bold('╔════════════════════════════════════════════╗'));
console.log(chalk_1.default.cyan.bold('║ 🔗 Tunnel Active ║'));
console.log(chalk_1.default.cyan.bold('╚════════════════════════════════════════════╝'));
console.log();
console.log(chalk_1.default.white.bold('Share this URL:'));
console.log(chalk_1.default.green.bold(tunnelStatus.info.url));
console.log(chalk_1.default.gray('(Copy the URL above to share)'));
console.log();
if (tunnelStatus.info.passwordProtected) {
console.log(chalk_1.default.yellow('Password: ') + chalk_1.default.yellow.bold(options.tunnelPassword));
console.log();
}
console.log(chalk_1.default.gray('Provider: ') + tunnelStatus.info.provider);
console.log(chalk_1.default.gray('Local dashboard: ') + `http://localhost:${options.port}`);
console.log();
console.log(chalk_1.default.gray('Press Ctrl+C to stop'));
console.log();
}
else {
spinner.succeed(chalk_1.default.green(`Dashboard running at http://localhost:${options.port}`));
console.log();
console.log(chalk_1.default.gray('Press Ctrl+C to stop the server'));
console.log();
}
// Handle graceful shutdown
process.on('SIGINT', async () => {
console.log(chalk_1.default.yellow('\n\nShutting down dashboard...'));
const forceExitTimeout = setTimeout(() => {
console.log(chalk_1.default.red('Force exiting...'));
process.exit(1);
}, 5000);
try {
await server.stop();
clearTimeout(forceExitTimeout);
process.exit(0);
}
catch (error) {
console.error(chalk_1.default.red('Error during shutdown:'), error);
process.exit(1);
}
});
}
catch (error) {
spinner.fail('Failed to start dashboard');
// Enhanced error handling for tunnel errors
if (error instanceof tunnel_1.TunnelProviderError) {
console.log();
console.error(chalk_1.default.red.bold('❌ Tunnel Error'));
console.log(chalk_1.default.red(error.getUserFriendlyMessage()));
}
else {
console.error(chalk_1.default.red('Error:'), error instanceof Error ? error.message : error);
}
process.exit(1);
}
});
program.parse(process.argv);
//# sourceMappingURL=cli.js.map