loki-mode 5.7.2 → 5.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/VERSION +1 -1
- package/api/README.md +297 -0
- package/api/client.ts +377 -0
- package/api/middleware/auth.ts +129 -0
- package/api/middleware/cors.ts +145 -0
- package/api/middleware/error.ts +226 -0
- package/api/mod.ts +58 -0
- package/api/openapi.yaml +614 -0
- package/api/routes/events.ts +165 -0
- package/api/routes/health.ts +169 -0
- package/api/routes/sessions.ts +262 -0
- package/api/routes/tasks.ts +182 -0
- package/api/server.js +637 -0
- package/api/server.ts +328 -0
- package/api/server_test.ts +265 -0
- package/api/services/cli-bridge.ts +503 -0
- package/api/services/event-bus.ts +189 -0
- package/api/services/state-watcher.ts +517 -0
- package/api/test.js +494 -0
- package/api/types/api.ts +122 -0
- package/api/types/events.ts +132 -0
- package/autonomy/loki +28 -2
- package/package.json +3 -2
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task Routes
|
|
3
|
+
*
|
|
4
|
+
* REST endpoints for task management.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { cliBridge } from "../services/cli-bridge.ts";
|
|
8
|
+
import type { Task } from "../types/api.ts";
|
|
9
|
+
import {
|
|
10
|
+
LokiApiError,
|
|
11
|
+
ErrorCodes,
|
|
12
|
+
successResponse,
|
|
13
|
+
} from "../middleware/error.ts";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* GET /api/sessions/:id/tasks - List tasks for a session
|
|
17
|
+
*/
|
|
18
|
+
export async function listTasks(
|
|
19
|
+
_req: Request,
|
|
20
|
+
sessionId: string
|
|
21
|
+
): Promise<Response> {
|
|
22
|
+
const session = await cliBridge.getSession(sessionId);
|
|
23
|
+
|
|
24
|
+
if (!session) {
|
|
25
|
+
throw new LokiApiError(
|
|
26
|
+
`Session not found: ${sessionId}`,
|
|
27
|
+
ErrorCodes.SESSION_NOT_FOUND
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const tasks = await cliBridge.getTasks(sessionId);
|
|
32
|
+
|
|
33
|
+
// Parse query parameters for filtering
|
|
34
|
+
const url = new URL(_req.url);
|
|
35
|
+
const status = url.searchParams.get("status");
|
|
36
|
+
const limit = parseInt(url.searchParams.get("limit") || "100", 10);
|
|
37
|
+
const offset = parseInt(url.searchParams.get("offset") || "0", 10);
|
|
38
|
+
|
|
39
|
+
let filteredTasks = tasks;
|
|
40
|
+
|
|
41
|
+
// Filter by status
|
|
42
|
+
if (status) {
|
|
43
|
+
filteredTasks = tasks.filter((t) => t.status === status);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Paginate
|
|
47
|
+
const paginatedTasks = filteredTasks.slice(offset, offset + limit);
|
|
48
|
+
|
|
49
|
+
return successResponse({
|
|
50
|
+
tasks: paginatedTasks,
|
|
51
|
+
pagination: {
|
|
52
|
+
total: filteredTasks.length,
|
|
53
|
+
limit,
|
|
54
|
+
offset,
|
|
55
|
+
hasMore: offset + limit < filteredTasks.length,
|
|
56
|
+
},
|
|
57
|
+
summary: {
|
|
58
|
+
pending: tasks.filter((t) => t.status === "pending").length,
|
|
59
|
+
running: tasks.filter((t) => t.status === "running").length,
|
|
60
|
+
completed: tasks.filter((t) => t.status === "completed").length,
|
|
61
|
+
failed: tasks.filter((t) => t.status === "failed").length,
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* GET /api/sessions/:sessionId/tasks/:taskId - Get a specific task
|
|
68
|
+
*/
|
|
69
|
+
export async function getTask(
|
|
70
|
+
_req: Request,
|
|
71
|
+
sessionId: string,
|
|
72
|
+
taskId: string
|
|
73
|
+
): Promise<Response> {
|
|
74
|
+
const session = await cliBridge.getSession(sessionId);
|
|
75
|
+
|
|
76
|
+
if (!session) {
|
|
77
|
+
throw new LokiApiError(
|
|
78
|
+
`Session not found: ${sessionId}`,
|
|
79
|
+
ErrorCodes.SESSION_NOT_FOUND
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const tasks = await cliBridge.getTasks(sessionId);
|
|
84
|
+
const task = tasks.find((t) => t.id === taskId);
|
|
85
|
+
|
|
86
|
+
if (!task) {
|
|
87
|
+
throw new LokiApiError(
|
|
88
|
+
`Task not found: ${taskId}`,
|
|
89
|
+
ErrorCodes.NOT_FOUND
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return successResponse({ task });
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* GET /api/tasks - List all tasks across sessions
|
|
98
|
+
*/
|
|
99
|
+
export async function listAllTasks(req: Request): Promise<Response> {
|
|
100
|
+
const sessions = await cliBridge.listSessions();
|
|
101
|
+
const allTasks: Task[] = [];
|
|
102
|
+
|
|
103
|
+
for (const session of sessions) {
|
|
104
|
+
const tasks = await cliBridge.getTasks(session.id);
|
|
105
|
+
allTasks.push(...tasks);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Parse query parameters
|
|
109
|
+
const url = new URL(req.url);
|
|
110
|
+
const status = url.searchParams.get("status");
|
|
111
|
+
const limit = parseInt(url.searchParams.get("limit") || "100", 10);
|
|
112
|
+
const offset = parseInt(url.searchParams.get("offset") || "0", 10);
|
|
113
|
+
|
|
114
|
+
let filteredTasks = allTasks;
|
|
115
|
+
|
|
116
|
+
if (status) {
|
|
117
|
+
filteredTasks = allTasks.filter((t) => t.status === status);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Sort by creation time (newest first)
|
|
121
|
+
filteredTasks.sort(
|
|
122
|
+
(a, b) =>
|
|
123
|
+
new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
const paginatedTasks = filteredTasks.slice(offset, offset + limit);
|
|
127
|
+
|
|
128
|
+
return successResponse({
|
|
129
|
+
tasks: paginatedTasks,
|
|
130
|
+
pagination: {
|
|
131
|
+
total: filteredTasks.length,
|
|
132
|
+
limit,
|
|
133
|
+
offset,
|
|
134
|
+
hasMore: offset + limit < filteredTasks.length,
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* GET /api/tasks/active - Get currently running tasks
|
|
141
|
+
*/
|
|
142
|
+
export async function getActiveTasks(_req: Request): Promise<Response> {
|
|
143
|
+
const sessions = await cliBridge.listSessions();
|
|
144
|
+
const activeTasks: Task[] = [];
|
|
145
|
+
|
|
146
|
+
for (const session of sessions) {
|
|
147
|
+
if (session.status === "running") {
|
|
148
|
+
const tasks = await cliBridge.getTasks(session.id);
|
|
149
|
+
activeTasks.push(...tasks.filter((t) => t.status === "running"));
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return successResponse({
|
|
154
|
+
tasks: activeTasks,
|
|
155
|
+
count: activeTasks.length,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* GET /api/tasks/queue - Get queued tasks
|
|
161
|
+
*/
|
|
162
|
+
export async function getQueuedTasks(_req: Request): Promise<Response> {
|
|
163
|
+
const sessions = await cliBridge.listSessions();
|
|
164
|
+
const queuedTasks: Task[] = [];
|
|
165
|
+
|
|
166
|
+
for (const session of sessions) {
|
|
167
|
+
if (session.status === "running") {
|
|
168
|
+
const tasks = await cliBridge.getTasks(session.id);
|
|
169
|
+
queuedTasks.push(
|
|
170
|
+
...tasks.filter((t) => t.status === "pending" || t.status === "queued")
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Sort by priority
|
|
176
|
+
queuedTasks.sort((a, b) => b.priority - a.priority);
|
|
177
|
+
|
|
178
|
+
return successResponse({
|
|
179
|
+
tasks: queuedTasks,
|
|
180
|
+
count: queuedTasks.length,
|
|
181
|
+
});
|
|
182
|
+
}
|