mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-03-01 15:03:57 +08:00
feat(workflow): add lightweight interactive planning workflow with in-memory execution and code exploration
- Introduced `lite-plan` command for intelligent task analysis and planning. - Implemented dynamic exploration and clarification phases based on task complexity. - Added support for auto mode and forced exploration flags. - Defined output artifacts and session structure for planning results. - Enhanced execution process with context handoff to `lite-execute`. chore(temp): create temporary memory content and import script - Added `.temp-memory-content.txt` to store session details and execution plan. - Implemented `temp-import-memory.cjs` to handle memory import using core-memory command. - Ensured cleanup of temporary files after execution.
This commit is contained in:
@@ -3,6 +3,10 @@ import { launchBrowser } from '../utils/browser-launcher.js';
|
||||
import { validatePath } from '../utils/path-resolver.js';
|
||||
import { startReactFrontend, stopReactFrontend } from '../utils/react-frontend.js';
|
||||
import chalk from 'chalk';
|
||||
import { exec } from 'child_process';
|
||||
import { promisify } from 'util';
|
||||
|
||||
const execAsync = promisify(exec);
|
||||
|
||||
interface ServeOptions {
|
||||
port?: number;
|
||||
@@ -11,6 +15,36 @@ interface ServeOptions {
|
||||
browser?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a port is in use
|
||||
* @param port - Port number to check
|
||||
* @returns Promise<boolean> - true if port is in use
|
||||
*/
|
||||
async function isPortInUse(port: number): Promise<boolean> {
|
||||
try {
|
||||
const { stdout } = await execAsync(`netstat -ano | findstr :${port}`);
|
||||
const lines = stdout.trim().split(/\r?\n/).filter(Boolean);
|
||||
|
||||
for (const line of lines) {
|
||||
const parts = line.trim().split(/\s+/);
|
||||
if (parts.length < 4) continue;
|
||||
|
||||
const proto = parts[0]?.toUpperCase();
|
||||
const localAddress = parts[1] || '';
|
||||
const state = parts[3]?.toUpperCase();
|
||||
|
||||
// Check if this is a TCP connection in LISTENING state on our port
|
||||
if (proto === 'TCP' && localAddress.endsWith(`:${port}`) && state === 'LISTENING') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} catch {
|
||||
// If netstat fails or no matches found, assume port is free
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serve command handler - starts dashboard server with live path switching
|
||||
* @param {Object} options - Command options
|
||||
@@ -33,13 +67,36 @@ export async function serveCommand(options: ServeOptions): Promise<void> {
|
||||
initialPath = pathValidation.path;
|
||||
}
|
||||
|
||||
const startupId = Math.random().toString(36).substring(7);
|
||||
console.log(chalk.blue.bold('\n CCW Dashboard Server\n'));
|
||||
console.log(chalk.gray(` Startup ID: ${startupId}`));
|
||||
console.log(chalk.gray(` Initial project: ${initialPath}`));
|
||||
console.log(chalk.gray(` Host: ${host}`));
|
||||
console.log(chalk.gray(` Port: ${port}\n`));
|
||||
|
||||
// Start React frontend
|
||||
// Calculate React frontend port
|
||||
const reactPort = port + 1;
|
||||
|
||||
// Check if ports are already in use
|
||||
const mainPortInUse = await isPortInUse(port);
|
||||
const reactPortInUse = await isPortInUse(reactPort);
|
||||
|
||||
if (mainPortInUse) {
|
||||
console.error(chalk.red(`\n Error: Port ${port} is already in use.`));
|
||||
console.error(chalk.yellow(` Another CCW server may be running.`));
|
||||
console.error(chalk.gray(` Try stopping it first: ccw stop`));
|
||||
console.error(chalk.gray(` Or use a different port: ccw serve --port ${port + 2}\n`));
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (reactPortInUse) {
|
||||
console.error(chalk.red(`\n Error: Port ${reactPort} (React frontend) is already in use.`));
|
||||
console.error(chalk.yellow(` Another process may be using this port.`));
|
||||
console.error(chalk.gray(` Try using a different port: ccw serve --port ${port + 2}\n`));
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Start React frontend
|
||||
try {
|
||||
await startReactFrontend(reactPort);
|
||||
} catch (error) {
|
||||
|
||||
@@ -32,7 +32,8 @@ async function findProcessOnPort(port: number): Promise<string | null> {
|
||||
|
||||
if (proto !== 'TCP') continue;
|
||||
if (!localAddress.endsWith(`:${port}`)) continue;
|
||||
if (!/^\d+$/.test(pidCandidate)) continue;
|
||||
// Reject PID 0 (System Idle Process) and non-numeric PIDs
|
||||
if (!/^[1-9]\d*$/.test(pidCandidate)) continue;
|
||||
|
||||
return pidCandidate; // PID is the last column
|
||||
}
|
||||
@@ -43,7 +44,8 @@ async function findProcessOnPort(port: number): Promise<string | null> {
|
||||
}
|
||||
|
||||
async function getProcessCommandLine(pid: string): Promise<string | null> {
|
||||
if (!/^\d+$/.test(pid)) return null;
|
||||
// Reject PID 0 (System Idle Process) and non-numeric PIDs
|
||||
if (!/^[1-9]\d*$/.test(pid)) return null;
|
||||
|
||||
try {
|
||||
const probeCommand =
|
||||
@@ -78,7 +80,8 @@ function isLikelyViteCommandLine(commandLine: string, port: number): boolean {
|
||||
* @returns {Promise<boolean>} Success status
|
||||
*/
|
||||
async function killProcess(pid: string): Promise<boolean> {
|
||||
if (!/^\d+$/.test(pid)) return false;
|
||||
// Reject PID 0 (System Idle Process) and non-numeric PIDs
|
||||
if (!/^[1-9]\d*$/.test(pid)) return false;
|
||||
|
||||
try {
|
||||
// Prefer taskkill to terminate the entire process tree on Windows (npm/cmd wrappers can orphan children).
|
||||
|
||||
Reference in New Issue
Block a user