feat: implement infinite scrolling for native sessions and add reset functionality to queue scheduler

This commit is contained in:
catlog22
2026-02-27 21:24:44 +08:00
parent a581a2e62b
commit 9be35ed5fb
12 changed files with 263 additions and 131 deletions

View File

@@ -852,17 +852,33 @@ export async function handleCliRoutes(ctx: RouteContext): Promise<boolean> {
return true;
}
// API: List Native CLI Sessions
// API: List Native CLI Sessions (with pagination support)
if (pathname === '/api/cli/native-sessions' && req.method === 'GET') {
const projectPath = url.searchParams.get('path') || null;
const limit = parseInt(url.searchParams.get('limit') || '100', 10);
const limit = parseInt(url.searchParams.get('limit') || '50', 10);
const offset = parseInt(url.searchParams.get('offset') || '0', 10);
const cursor = url.searchParams.get('cursor'); // ISO timestamp for cursor-based pagination
try {
const sessions = listAllNativeSessions({
// Parse cursor timestamp if provided
const afterTimestamp = cursor ? new Date(cursor) : undefined;
// Fetch sessions with limit + 1 to detect if there are more
const allSessions = listAllNativeSessions({
workingDir: projectPath || undefined,
limit
limit: limit + 1, // Fetch one extra to check hasMore
afterTimestamp
});
// Determine if there are more results
const hasMore = allSessions.length > limit;
const sessions = hasMore ? allSessions.slice(0, limit) : allSessions;
// Get next cursor (timestamp of last item for cursor-based pagination)
const nextCursor = sessions.length > 0
? sessions[sessions.length - 1].updatedAt.toISOString()
: null;
// Group sessions by tool
const byTool: Record<string, typeof sessions> = {};
for (const session of sessions) {
@@ -873,7 +889,13 @@ export async function handleCliRoutes(ctx: RouteContext): Promise<boolean> {
}
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ sessions, byTool }));
res.end(JSON.stringify({
sessions,
byTool,
hasMore,
nextCursor,
count: sessions.length
}));
} catch (err) {
res.writeHead(500, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ error: (err as Error).message }));

View File

@@ -46,6 +46,10 @@ export async function handleQueueSchedulerRoutes(
for (const item of items) {
schedulerService.addItem(item);
}
} else if (state.status === 'completed' || state.status === 'failed') {
// Auto-reset when scheduler is in terminal state and start fresh
schedulerService.reset();
schedulerService.start(items);
} else {
return {
error: `Cannot add items when scheduler is in '${state.status}' state`,
@@ -131,6 +135,22 @@ export async function handleQueueSchedulerRoutes(
return true;
}
// POST /api/queue/scheduler/reset - Reset scheduler to idle state
if (pathname === '/api/queue/scheduler/reset' && req.method === 'POST') {
handlePostRequest(req, res, async () => {
try {
schedulerService.reset();
return {
success: true,
state: schedulerService.getState(),
};
} catch (err) {
return { error: (err as Error).message, status: 409 };
}
});
return true;
}
// POST /api/queue/scheduler/config - Update scheduler configuration
if (pathname === '/api/queue/scheduler/config' && req.method === 'POST') {
handlePostRequest(req, res, async (body) => {