feat: add task queue sidebar and resume functionality for CLI sessions

- Implemented task queue sidebar for managing active tasks with filtering options.
- Added functionality to close notification sidebar when opening task queue.
- Enhanced CLI history view to support resuming previous sessions with optional prompts.
- Updated CLI executor to handle resuming sessions for Codex, Gemini, and Qwen tools.
- Introduced utility functions for finding CLI history directories recursively.
- Improved task queue data management and rendering logic.
This commit is contained in:
catlog22
2025-12-13 11:51:53 +08:00
parent 335f5e9ec6
commit 93d3df1e08
14 changed files with 2000 additions and 128 deletions

View File

@@ -44,6 +44,7 @@ const MODULE_FILES = [
'components/carousel.js',
'components/notifications.js',
'components/global-notifications.js',
'components/task-queue-sidebar.js',
'components/cli-status.js',
'components/cli-history.js',
'components/mcp-manager.js',

View File

@@ -8,7 +8,7 @@ import { createHash } from 'crypto';
import { scanSessions } from './session-scanner.js';
import { aggregateData } from './data-aggregator.js';
import { resolvePath, getRecentPaths, trackRecentPath, removeRecentPath, normalizePathForDisplay, getWorkflowDir } from '../utils/path-resolver.js';
import { getCliToolsStatus, getExecutionHistory, getExecutionDetail, deleteExecution, executeCliTool } from '../tools/cli-executor.js';
import { getCliToolsStatus, getExecutionHistory, getExecutionDetail, deleteExecution, executeCliTool, resumeCliSession } from '../tools/cli-executor.js';
import { getAllManifests } from './manifest.js';
import { checkVenvStatus, bootstrapVenv, executeCodexLens, checkSemanticStatus, installSemantic } from '../tools/codex-lens.js';
import { listTools } from '../tools/index.js';
@@ -641,8 +641,9 @@ export async function startServer(options: ServerOptions = {}): Promise<http.Ser
const limit = parseInt(url.searchParams.get('limit') || '50', 10);
const tool = url.searchParams.get('tool') || null;
const status = url.searchParams.get('status') || null;
const recursive = url.searchParams.get('recursive') !== 'false'; // Default true
const history = getExecutionHistory(projectPath, { limit, tool, status });
const history = getExecutionHistory(projectPath, { limit, tool, status, recursive });
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify(history));
return;
@@ -763,6 +764,81 @@ export async function startServer(options: ServerOptions = {}): Promise<http.Ser
return;
}
// API: Resume CLI Session
if (pathname === '/api/cli/resume' && req.method === 'POST') {
handlePostRequest(req, res, async (body) => {
const { executionId, tool, last, prompt } = body as {
executionId?: string;
tool?: string;
last?: boolean;
prompt?: string;
};
if (!executionId && !last && tool !== 'codex') {
return { error: 'executionId or --last flag is required', status: 400 };
}
// Broadcast resume started
const resumeId = `${Date.now()}-resume`;
broadcastToClients({
type: 'CLI_EXECUTION_STARTED',
payload: {
executionId: resumeId,
tool: tool || 'resume',
mode: 'resume',
resumeFrom: executionId,
timestamp: new Date().toISOString()
}
});
try {
const result = await resumeCliSession(
initialPath,
{ tool, executionId, last, prompt },
(chunk) => {
broadcastToClients({
type: 'CLI_OUTPUT',
payload: {
executionId: resumeId,
chunkType: chunk.type,
data: chunk.data
}
});
}
);
// Broadcast completion
broadcastToClients({
type: 'CLI_EXECUTION_COMPLETED',
payload: {
executionId: resumeId,
success: result.success,
status: result.execution.status,
duration_ms: result.execution.duration_ms,
resumeFrom: executionId
}
});
return {
success: result.success,
execution: result.execution
};
} catch (error: unknown) {
broadcastToClients({
type: 'CLI_EXECUTION_ERROR',
payload: {
executionId: resumeId,
error: (error as Error).message
}
});
return { error: (error as Error).message, status: 500 };
}
});
return;
}
// API: Update CLAUDE.md using CLI tools (Explorer view)
if (pathname === '/api/update-claude-md' && req.method === 'POST') {
handlePostRequest(req, res, async (body) => {