@hasna/todos 0.9.41 → 0.9.43
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/dist/cli/index.js +190 -1
- package/dist/db/tasks.d.ts +17 -1
- package/dist/db/tasks.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +69 -0
- package/dist/mcp/index.js +135 -0
- package/dist/server/index.js +121 -1
- package/dist/server/serve.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -3158,6 +3158,8 @@ __export(exports_tasks, {
|
|
|
3158
3158
|
updateTask: () => updateTask,
|
|
3159
3159
|
unlockTask: () => unlockTask,
|
|
3160
3160
|
startTask: () => startTask,
|
|
3161
|
+
setTaskStatus: () => setTaskStatus,
|
|
3162
|
+
setTaskPriority: () => setTaskPriority,
|
|
3161
3163
|
removeDependency: () => removeDependency,
|
|
3162
3164
|
moveTask: () => moveTask,
|
|
3163
3165
|
lockTask: () => lockTask,
|
|
@@ -3176,6 +3178,7 @@ __export(exports_tasks, {
|
|
|
3176
3178
|
getActiveWork: () => getActiveWork,
|
|
3177
3179
|
failTask: () => failTask,
|
|
3178
3180
|
deleteTask: () => deleteTask,
|
|
3181
|
+
decomposeTasks: () => decomposeTasks,
|
|
3179
3182
|
createTask: () => createTask,
|
|
3180
3183
|
countTasks: () => countTasks,
|
|
3181
3184
|
completeTask: () => completeTask,
|
|
@@ -3967,6 +3970,72 @@ function getStatus(filters, agentId, db) {
|
|
|
3967
3970
|
overdue_recurring: overdueRow.count
|
|
3968
3971
|
};
|
|
3969
3972
|
}
|
|
3973
|
+
function decomposeTasks(parentId, subtasks, options, db) {
|
|
3974
|
+
const d = db || getDatabase();
|
|
3975
|
+
const parent = getTask(parentId, d);
|
|
3976
|
+
if (!parent)
|
|
3977
|
+
throw new TaskNotFoundError(parentId);
|
|
3978
|
+
const created = [];
|
|
3979
|
+
const tx = d.transaction(() => {
|
|
3980
|
+
for (const input of subtasks) {
|
|
3981
|
+
const task = createTask({
|
|
3982
|
+
title: input.title,
|
|
3983
|
+
description: input.description,
|
|
3984
|
+
priority: input.priority || parent.priority,
|
|
3985
|
+
parent_id: parentId,
|
|
3986
|
+
project_id: parent.project_id || undefined,
|
|
3987
|
+
plan_id: parent.plan_id || undefined,
|
|
3988
|
+
task_list_id: parent.task_list_id || undefined,
|
|
3989
|
+
assigned_to: input.assigned_to || parent.assigned_to || undefined,
|
|
3990
|
+
estimated_minutes: input.estimated_minutes,
|
|
3991
|
+
tags: input.tags
|
|
3992
|
+
}, d);
|
|
3993
|
+
if (options?.depends_on_prev && created.length > 0) {
|
|
3994
|
+
const prev = created[created.length - 1];
|
|
3995
|
+
addDependency(task.id, prev.id, d);
|
|
3996
|
+
}
|
|
3997
|
+
created.push(task);
|
|
3998
|
+
}
|
|
3999
|
+
});
|
|
4000
|
+
tx();
|
|
4001
|
+
return { parent, subtasks: created };
|
|
4002
|
+
}
|
|
4003
|
+
function setTaskStatus(id, status, _agentId, db) {
|
|
4004
|
+
const d = db || getDatabase();
|
|
4005
|
+
for (let attempt = 0;attempt < 3; attempt++) {
|
|
4006
|
+
const task = getTask(id, d);
|
|
4007
|
+
if (!task)
|
|
4008
|
+
throw new TaskNotFoundError(id);
|
|
4009
|
+
if (task.status === status)
|
|
4010
|
+
return task;
|
|
4011
|
+
try {
|
|
4012
|
+
return updateTask(id, { status, version: task.version }, d);
|
|
4013
|
+
} catch (e) {
|
|
4014
|
+
if (e instanceof VersionConflictError && attempt < 2)
|
|
4015
|
+
continue;
|
|
4016
|
+
throw e;
|
|
4017
|
+
}
|
|
4018
|
+
}
|
|
4019
|
+
throw new Error(`Failed to set status after 3 attempts`);
|
|
4020
|
+
}
|
|
4021
|
+
function setTaskPriority(id, priority, _agentId, db) {
|
|
4022
|
+
const d = db || getDatabase();
|
|
4023
|
+
for (let attempt = 0;attempt < 3; attempt++) {
|
|
4024
|
+
const task = getTask(id, d);
|
|
4025
|
+
if (!task)
|
|
4026
|
+
throw new TaskNotFoundError(id);
|
|
4027
|
+
if (task.priority === priority)
|
|
4028
|
+
return task;
|
|
4029
|
+
try {
|
|
4030
|
+
return updateTask(id, { priority, version: task.version }, d);
|
|
4031
|
+
} catch (e) {
|
|
4032
|
+
if (e instanceof VersionConflictError && attempt < 2)
|
|
4033
|
+
continue;
|
|
4034
|
+
throw e;
|
|
4035
|
+
}
|
|
4036
|
+
}
|
|
4037
|
+
throw new Error(`Failed to set priority after 3 attempts`);
|
|
4038
|
+
}
|
|
3970
4039
|
function wouldCreateCycle(taskId, dependsOn, db) {
|
|
3971
4040
|
const visited = new Set;
|
|
3972
4041
|
const queue = [dependsOn];
|
|
@@ -10648,6 +10717,63 @@ No pending tasks available.`);
|
|
|
10648
10717
|
}
|
|
10649
10718
|
});
|
|
10650
10719
|
}
|
|
10720
|
+
if (shouldRegisterTool("decompose_task")) {
|
|
10721
|
+
server.tool("decompose_task", "Break a task into subtasks in one call. Optionally chain them sequentially with depends_on_prev.", {
|
|
10722
|
+
parent_id: exports_external.string(),
|
|
10723
|
+
subtasks: exports_external.array(exports_external.object({
|
|
10724
|
+
title: exports_external.string(),
|
|
10725
|
+
description: exports_external.string().optional(),
|
|
10726
|
+
priority: exports_external.enum(["low", "medium", "high", "critical"]).optional(),
|
|
10727
|
+
assigned_to: exports_external.string().optional(),
|
|
10728
|
+
estimated_minutes: exports_external.number().optional(),
|
|
10729
|
+
tags: exports_external.array(exports_external.string()).optional()
|
|
10730
|
+
})),
|
|
10731
|
+
depends_on_prev: exports_external.boolean().optional()
|
|
10732
|
+
}, async ({ parent_id, subtasks, depends_on_prev }) => {
|
|
10733
|
+
try {
|
|
10734
|
+
const resolvedId = resolveId(parent_id);
|
|
10735
|
+
const result = decomposeTasks(resolvedId, subtasks, { depends_on_prev }, undefined);
|
|
10736
|
+
const lines = [
|
|
10737
|
+
`Decomposed: ${formatTask(result.parent)}`,
|
|
10738
|
+
`Created ${result.subtasks.length} subtask(s)${depends_on_prev ? " (chained)" : ""}:`,
|
|
10739
|
+
...result.subtasks.map((t, i) => ` ${i + 1}. ${formatTask(t)}`)
|
|
10740
|
+
];
|
|
10741
|
+
return { content: [{ type: "text", text: lines.join(`
|
|
10742
|
+
`) }] };
|
|
10743
|
+
} catch (e) {
|
|
10744
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
10745
|
+
}
|
|
10746
|
+
});
|
|
10747
|
+
}
|
|
10748
|
+
if (shouldRegisterTool("set_task_status")) {
|
|
10749
|
+
server.tool("set_task_status", "Set task status without needing version. Auto-retries on conflict.", {
|
|
10750
|
+
id: exports_external.string(),
|
|
10751
|
+
status: exports_external.enum(["pending", "in_progress", "completed", "failed", "cancelled"]),
|
|
10752
|
+
agent_id: exports_external.string().optional()
|
|
10753
|
+
}, async ({ id, status, agent_id }) => {
|
|
10754
|
+
try {
|
|
10755
|
+
const resolvedId = resolveId(id);
|
|
10756
|
+
const task = setTaskStatus(resolvedId, status, agent_id);
|
|
10757
|
+
return { content: [{ type: "text", text: `set: ${formatTask(task)}` }] };
|
|
10758
|
+
} catch (e) {
|
|
10759
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
10760
|
+
}
|
|
10761
|
+
});
|
|
10762
|
+
}
|
|
10763
|
+
if (shouldRegisterTool("set_task_priority")) {
|
|
10764
|
+
server.tool("set_task_priority", "Set task priority without needing version. Auto-retries on conflict.", {
|
|
10765
|
+
id: exports_external.string(),
|
|
10766
|
+
priority: exports_external.enum(["low", "medium", "high", "critical"])
|
|
10767
|
+
}, async ({ id, priority }) => {
|
|
10768
|
+
try {
|
|
10769
|
+
const resolvedId = resolveId(id);
|
|
10770
|
+
const task = setTaskPriority(resolvedId, priority);
|
|
10771
|
+
return { content: [{ type: "text", text: `set: ${formatTask(task)}` }] };
|
|
10772
|
+
} catch (e) {
|
|
10773
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
10774
|
+
}
|
|
10775
|
+
});
|
|
10776
|
+
}
|
|
10651
10777
|
if (shouldRegisterTool("search_tools")) {
|
|
10652
10778
|
server.tool("search_tools", "List all tool names, optionally filtered by substring.", { query: exports_external.string().optional() }, async ({ query }) => {
|
|
10653
10779
|
const all = [
|
|
@@ -10708,6 +10834,9 @@ No pending tasks available.`);
|
|
|
10708
10834
|
"get_tasks_changed_since",
|
|
10709
10835
|
"get_stale_tasks",
|
|
10710
10836
|
"get_status",
|
|
10837
|
+
"decompose_task",
|
|
10838
|
+
"set_task_status",
|
|
10839
|
+
"set_task_priority",
|
|
10711
10840
|
"search_tools",
|
|
10712
10841
|
"describe_tools"
|
|
10713
10842
|
].filter((name) => shouldRegisterTool(name));
|
|
@@ -10880,6 +11009,15 @@ No pending tasks available.`);
|
|
|
10880
11009
|
get_status: `Get a full project health snapshot \u2014 pending/in_progress/completed counts, active work, next recommended task, stale task count, overdue recurring tasks. Saves 4+ round trips at session start.
|
|
10881
11010
|
Params: agent_id(string, optional \u2014 prefers tasks assigned to this agent for next_task), project_id(string, optional), task_list_id(string, optional)
|
|
10882
11011
|
Example: {agent_id: 'a1b2c3d4', project_id: 'e5f6g7h8'}`,
|
|
11012
|
+
decompose_task: `Break a task into subtasks in one call. Subtasks inherit project/plan/list from parent.
|
|
11013
|
+
Params: parent_id(string, req), subtasks(array, req \u2014 [{title, description, priority, assigned_to, estimated_minutes, tags}]), depends_on_prev(boolean \u2014 chain subtasks sequentially)
|
|
11014
|
+
Example: {parent_id: 'a1b2c3d4', subtasks: [{title: 'Research'}, {title: 'Implement'}, {title: 'Test'}], depends_on_prev: true}`,
|
|
11015
|
+
set_task_status: `Set task status without needing version. Auto-retries on conflict (up to 3 attempts). Use instead of update_task when you only need to change status.
|
|
11016
|
+
Params: id(string, req), status(pending|in_progress|completed|failed|cancelled, req), agent_id(string)
|
|
11017
|
+
Example: {id: 'a1b2c3d4', status: 'completed'}`,
|
|
11018
|
+
set_task_priority: `Set task priority without needing version. Auto-retries on conflict (up to 3 attempts). Use instead of update_task when you only need to change priority.
|
|
11019
|
+
Params: id(string, req), priority(low|medium|high|critical, req)
|
|
11020
|
+
Example: {id: 'a1b2c3d4', priority: 'high'}`,
|
|
10883
11021
|
search_tools: `List all tool names or filter by substring.
|
|
10884
11022
|
Params: query(string, optional)
|
|
10885
11023
|
Example: {query: 'task'}`,
|
|
@@ -11060,6 +11198,7 @@ async function startServer(port, options) {
|
|
|
11060
11198
|
const shouldOpen = options?.open ?? true;
|
|
11061
11199
|
getDatabase();
|
|
11062
11200
|
const sseClients = new Set;
|
|
11201
|
+
const filteredSseClients = new Set;
|
|
11063
11202
|
function broadcastEvent(event) {
|
|
11064
11203
|
const data = JSON.stringify({ ...event, timestamp: new Date().toISOString() });
|
|
11065
11204
|
for (const controller of sseClients) {
|
|
@@ -11071,6 +11210,21 @@ async function startServer(port, options) {
|
|
|
11071
11210
|
sseClients.delete(controller);
|
|
11072
11211
|
}
|
|
11073
11212
|
}
|
|
11213
|
+
const eventName = `task.${event.action}`;
|
|
11214
|
+
for (const client of filteredSseClients) {
|
|
11215
|
+
if (client.events && !client.events.has(eventName) && !client.events.has("*"))
|
|
11216
|
+
continue;
|
|
11217
|
+
if (client.agentId && event.agent_id !== client.agentId)
|
|
11218
|
+
continue;
|
|
11219
|
+
try {
|
|
11220
|
+
client.controller.enqueue(`event: ${eventName}
|
|
11221
|
+
data: ${data}
|
|
11222
|
+
|
|
11223
|
+
`);
|
|
11224
|
+
} catch {
|
|
11225
|
+
filteredSseClients.delete(client);
|
|
11226
|
+
}
|
|
11227
|
+
}
|
|
11074
11228
|
}
|
|
11075
11229
|
const dashboardDir = resolveDashboardDir();
|
|
11076
11230
|
const dashboardExists = existsSync6(dashboardDir);
|
|
@@ -11118,6 +11272,35 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
11118
11272
|
}
|
|
11119
11273
|
});
|
|
11120
11274
|
}
|
|
11275
|
+
if (path === "/api/tasks/stream" && method === "GET") {
|
|
11276
|
+
const agentId = url.searchParams.get("agent_id") || undefined;
|
|
11277
|
+
const projectId = url.searchParams.get("project_id") || undefined;
|
|
11278
|
+
const eventsParam = url.searchParams.get("events");
|
|
11279
|
+
const eventFilter = eventsParam ? new Set(eventsParam.split(",").map((e) => e.trim())) : undefined;
|
|
11280
|
+
const client = { controller: null, agentId, projectId, events: eventFilter };
|
|
11281
|
+
const stream = new ReadableStream({
|
|
11282
|
+
start(controller) {
|
|
11283
|
+
client.controller = controller;
|
|
11284
|
+
filteredSseClients.add(client);
|
|
11285
|
+
controller.enqueue(`: connected
|
|
11286
|
+
|
|
11287
|
+
data: ${JSON.stringify({ type: "connected", agent_id: agentId, timestamp: new Date().toISOString() })}
|
|
11288
|
+
|
|
11289
|
+
`);
|
|
11290
|
+
},
|
|
11291
|
+
cancel() {
|
|
11292
|
+
filteredSseClients.delete(client);
|
|
11293
|
+
}
|
|
11294
|
+
});
|
|
11295
|
+
return new Response(stream, {
|
|
11296
|
+
headers: {
|
|
11297
|
+
"Content-Type": "text/event-stream",
|
|
11298
|
+
"Cache-Control": "no-cache",
|
|
11299
|
+
Connection: "keep-alive",
|
|
11300
|
+
"Access-Control-Allow-Origin": "*"
|
|
11301
|
+
}
|
|
11302
|
+
});
|
|
11303
|
+
}
|
|
11121
11304
|
if (path === "/api/stats" && method === "GET") {
|
|
11122
11305
|
const all = listTasks({ limit: 1e4 });
|
|
11123
11306
|
const projects = listProjects();
|
|
@@ -11136,13 +11319,19 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
11136
11319
|
if (path === "/api/tasks" && method === "GET") {
|
|
11137
11320
|
const status = url.searchParams.get("status") || undefined;
|
|
11138
11321
|
const projectId = url.searchParams.get("project_id") || undefined;
|
|
11322
|
+
const sessionId = url.searchParams.get("session_id") || undefined;
|
|
11323
|
+
const agentId = url.searchParams.get("agent_id") || undefined;
|
|
11139
11324
|
const limitParam = url.searchParams.get("limit");
|
|
11325
|
+
const offsetParam = url.searchParams.get("offset");
|
|
11140
11326
|
const fieldsParam = url.searchParams.get("fields");
|
|
11141
11327
|
const fields = fieldsParam ? fieldsParam.split(",").map((f) => f.trim()).filter(Boolean) : undefined;
|
|
11142
11328
|
const tasks = listTasks({
|
|
11143
11329
|
status,
|
|
11144
11330
|
project_id: projectId,
|
|
11145
|
-
|
|
11331
|
+
session_id: sessionId,
|
|
11332
|
+
agent_id: agentId,
|
|
11333
|
+
limit: limitParam ? parseInt(limitParam, 10) : undefined,
|
|
11334
|
+
offset: offsetParam ? parseInt(offsetParam, 10) : undefined
|
|
11146
11335
|
});
|
|
11147
11336
|
return json(tasks.map((t) => taskToSummary(t, fields)), 200, port);
|
|
11148
11337
|
}
|
package/dist/db/tasks.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Database } from "bun:sqlite";
|
|
2
|
-
import type { CreateTaskInput, LockResult, Task, TaskDependency, TaskFilter, TaskWithRelations, UpdateTaskInput } from "../types/index.js";
|
|
2
|
+
import type { CreateTaskInput, LockResult, Task, TaskDependency, TaskFilter, TaskPriority, TaskStatus, TaskWithRelations, UpdateTaskInput } from "../types/index.js";
|
|
3
3
|
export declare function createTask(input: CreateTaskInput, db?: Database): Task;
|
|
4
4
|
export declare function getTask(id: string, db?: Database): Task | null;
|
|
5
5
|
export declare function getTaskWithRelations(id: string, db?: Database): TaskWithRelations | null;
|
|
@@ -99,6 +99,22 @@ export declare function getStatus(filters?: {
|
|
|
99
99
|
project_id?: string;
|
|
100
100
|
task_list_id?: string;
|
|
101
101
|
}, agentId?: string, db?: Database): StatusSummary;
|
|
102
|
+
export interface DecomposeSubtaskInput {
|
|
103
|
+
title: string;
|
|
104
|
+
description?: string;
|
|
105
|
+
priority?: Task["priority"];
|
|
106
|
+
assigned_to?: string;
|
|
107
|
+
estimated_minutes?: number;
|
|
108
|
+
tags?: string[];
|
|
109
|
+
}
|
|
110
|
+
export declare function decomposeTasks(parentId: string, subtasks: DecomposeSubtaskInput[], options?: {
|
|
111
|
+
depends_on_prev?: boolean;
|
|
112
|
+
}, db?: Database): {
|
|
113
|
+
parent: Task;
|
|
114
|
+
subtasks: Task[];
|
|
115
|
+
};
|
|
116
|
+
export declare function setTaskStatus(id: string, status: TaskStatus, _agentId?: string, db?: Database): Task;
|
|
117
|
+
export declare function setTaskPriority(id: string, priority: TaskPriority, _agentId?: string, db?: Database): Task;
|
|
102
118
|
export declare function getTaskStats(filters?: {
|
|
103
119
|
project_id?: string;
|
|
104
120
|
task_list_id?: string;
|
package/dist/db/tasks.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tasks.d.ts","sourceRoot":"","sources":["../../src/db/tasks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAoB,MAAM,YAAY,CAAC;AAC7D,OAAO,KAAK,EACV,eAAe,EACf,UAAU,EACV,IAAI,EACJ,cAAc,EACd,UAAU,
|
|
1
|
+
{"version":3,"file":"tasks.d.ts","sourceRoot":"","sources":["../../src/db/tasks.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { getDatabase, closeDatabase, resetDatabase, resolvePartialId, now, uuid } from "./db/database.js";
|
|
2
|
-
export { createTask, getTask, getTaskWithRelations, listTasks, countTasks, updateTask, deleteTask, startTask, completeTask, lockTask, unlockTask, addDependency, removeDependency, getTaskDependencies, getTaskDependents, getBlockingDeps, bulkUpdateTasks, bulkCreateTasks, cloneTask, getTaskStats, getTaskGraph, moveTask, getNextTask, claimNextTask, getActiveWork, failTask, getTasksChangedSince, getStaleTasks, getStatus, } from "./db/tasks.js";
|
|
3
|
-
export type { TaskGraphNode, TaskGraph, BulkCreateTaskInput, ActiveWorkItem, StatusSummary } from "./db/tasks.js";
|
|
2
|
+
export { createTask, getTask, getTaskWithRelations, listTasks, countTasks, updateTask, deleteTask, startTask, completeTask, lockTask, unlockTask, addDependency, removeDependency, getTaskDependencies, getTaskDependents, getBlockingDeps, bulkUpdateTasks, bulkCreateTasks, cloneTask, getTaskStats, getTaskGraph, moveTask, getNextTask, claimNextTask, getActiveWork, failTask, getTasksChangedSince, getStaleTasks, getStatus, decomposeTasks, setTaskStatus, setTaskPriority, } from "./db/tasks.js";
|
|
3
|
+
export type { TaskGraphNode, TaskGraph, BulkCreateTaskInput, ActiveWorkItem, StatusSummary, DecomposeSubtaskInput } from "./db/tasks.js";
|
|
4
4
|
export { createProject, getProject, getProjectByPath, listProjects, updateProject, deleteProject, ensureProject, nextTaskShortId, slugify, } from "./db/projects.js";
|
|
5
5
|
export { createPlan, getPlan, listPlans, updatePlan, deletePlan, } from "./db/plans.js";
|
|
6
6
|
export { addComment, getComment, listComments, deleteComment, } from "./db/comments.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,aAAa,EAAE,gBAAgB,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAG1G,OAAO,EACL,UAAU,EACV,OAAO,EACP,oBAAoB,EACpB,SAAS,EACT,UAAU,EACV,UAAU,EACV,UAAU,EACV,SAAS,EACT,YAAY,EACZ,QAAQ,EACR,UAAU,EACV,aAAa,EACb,gBAAgB,EAChB,mBAAmB,EACnB,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,eAAe,EACf,SAAS,EACT,YAAY,EACZ,YAAY,EACZ,QAAQ,EACR,WAAW,EACX,aAAa,EACb,aAAa,EACb,QAAQ,EACR,oBAAoB,EACpB,aAAa,EACb,SAAS,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1838,6 +1838,72 @@ function getStatus(filters, agentId, db) {
|
|
|
1838
1838
|
overdue_recurring: overdueRow.count
|
|
1839
1839
|
};
|
|
1840
1840
|
}
|
|
1841
|
+
function decomposeTasks(parentId, subtasks, options, db) {
|
|
1842
|
+
const d = db || getDatabase();
|
|
1843
|
+
const parent = getTask(parentId, d);
|
|
1844
|
+
if (!parent)
|
|
1845
|
+
throw new TaskNotFoundError(parentId);
|
|
1846
|
+
const created = [];
|
|
1847
|
+
const tx = d.transaction(() => {
|
|
1848
|
+
for (const input of subtasks) {
|
|
1849
|
+
const task = createTask({
|
|
1850
|
+
title: input.title,
|
|
1851
|
+
description: input.description,
|
|
1852
|
+
priority: input.priority || parent.priority,
|
|
1853
|
+
parent_id: parentId,
|
|
1854
|
+
project_id: parent.project_id || undefined,
|
|
1855
|
+
plan_id: parent.plan_id || undefined,
|
|
1856
|
+
task_list_id: parent.task_list_id || undefined,
|
|
1857
|
+
assigned_to: input.assigned_to || parent.assigned_to || undefined,
|
|
1858
|
+
estimated_minutes: input.estimated_minutes,
|
|
1859
|
+
tags: input.tags
|
|
1860
|
+
}, d);
|
|
1861
|
+
if (options?.depends_on_prev && created.length > 0) {
|
|
1862
|
+
const prev = created[created.length - 1];
|
|
1863
|
+
addDependency(task.id, prev.id, d);
|
|
1864
|
+
}
|
|
1865
|
+
created.push(task);
|
|
1866
|
+
}
|
|
1867
|
+
});
|
|
1868
|
+
tx();
|
|
1869
|
+
return { parent, subtasks: created };
|
|
1870
|
+
}
|
|
1871
|
+
function setTaskStatus(id, status, _agentId, db) {
|
|
1872
|
+
const d = db || getDatabase();
|
|
1873
|
+
for (let attempt = 0;attempt < 3; attempt++) {
|
|
1874
|
+
const task = getTask(id, d);
|
|
1875
|
+
if (!task)
|
|
1876
|
+
throw new TaskNotFoundError(id);
|
|
1877
|
+
if (task.status === status)
|
|
1878
|
+
return task;
|
|
1879
|
+
try {
|
|
1880
|
+
return updateTask(id, { status, version: task.version }, d);
|
|
1881
|
+
} catch (e) {
|
|
1882
|
+
if (e instanceof VersionConflictError && attempt < 2)
|
|
1883
|
+
continue;
|
|
1884
|
+
throw e;
|
|
1885
|
+
}
|
|
1886
|
+
}
|
|
1887
|
+
throw new Error(`Failed to set status after 3 attempts`);
|
|
1888
|
+
}
|
|
1889
|
+
function setTaskPriority(id, priority, _agentId, db) {
|
|
1890
|
+
const d = db || getDatabase();
|
|
1891
|
+
for (let attempt = 0;attempt < 3; attempt++) {
|
|
1892
|
+
const task = getTask(id, d);
|
|
1893
|
+
if (!task)
|
|
1894
|
+
throw new TaskNotFoundError(id);
|
|
1895
|
+
if (task.priority === priority)
|
|
1896
|
+
return task;
|
|
1897
|
+
try {
|
|
1898
|
+
return updateTask(id, { priority, version: task.version }, d);
|
|
1899
|
+
} catch (e) {
|
|
1900
|
+
if (e instanceof VersionConflictError && attempt < 2)
|
|
1901
|
+
continue;
|
|
1902
|
+
throw e;
|
|
1903
|
+
}
|
|
1904
|
+
}
|
|
1905
|
+
throw new Error(`Failed to set priority after 3 attempts`);
|
|
1906
|
+
}
|
|
1841
1907
|
function wouldCreateCycle(taskId, dependsOn, db) {
|
|
1842
1908
|
const visited = new Set;
|
|
1843
1909
|
const queue = [dependsOn];
|
|
@@ -3003,6 +3069,8 @@ export {
|
|
|
3003
3069
|
syncWithAgent,
|
|
3004
3070
|
startTask,
|
|
3005
3071
|
slugify,
|
|
3072
|
+
setTaskStatus,
|
|
3073
|
+
setTaskPriority,
|
|
3006
3074
|
searchTasks,
|
|
3007
3075
|
resolvePartialId,
|
|
3008
3076
|
resetDatabase,
|
|
@@ -3073,6 +3141,7 @@ export {
|
|
|
3073
3141
|
deleteComment,
|
|
3074
3142
|
deleteAgent,
|
|
3075
3143
|
defaultSyncAgents,
|
|
3144
|
+
decomposeTasks,
|
|
3076
3145
|
createWebhook,
|
|
3077
3146
|
createTemplate,
|
|
3078
3147
|
createTaskList,
|
package/dist/mcp/index.js
CHANGED
|
@@ -5991,6 +5991,72 @@ function getStatus(filters, agentId, db) {
|
|
|
5991
5991
|
overdue_recurring: overdueRow.count
|
|
5992
5992
|
};
|
|
5993
5993
|
}
|
|
5994
|
+
function decomposeTasks(parentId, subtasks, options, db) {
|
|
5995
|
+
const d = db || getDatabase();
|
|
5996
|
+
const parent = getTask(parentId, d);
|
|
5997
|
+
if (!parent)
|
|
5998
|
+
throw new TaskNotFoundError(parentId);
|
|
5999
|
+
const created = [];
|
|
6000
|
+
const tx = d.transaction(() => {
|
|
6001
|
+
for (const input of subtasks) {
|
|
6002
|
+
const task = createTask({
|
|
6003
|
+
title: input.title,
|
|
6004
|
+
description: input.description,
|
|
6005
|
+
priority: input.priority || parent.priority,
|
|
6006
|
+
parent_id: parentId,
|
|
6007
|
+
project_id: parent.project_id || undefined,
|
|
6008
|
+
plan_id: parent.plan_id || undefined,
|
|
6009
|
+
task_list_id: parent.task_list_id || undefined,
|
|
6010
|
+
assigned_to: input.assigned_to || parent.assigned_to || undefined,
|
|
6011
|
+
estimated_minutes: input.estimated_minutes,
|
|
6012
|
+
tags: input.tags
|
|
6013
|
+
}, d);
|
|
6014
|
+
if (options?.depends_on_prev && created.length > 0) {
|
|
6015
|
+
const prev = created[created.length - 1];
|
|
6016
|
+
addDependency(task.id, prev.id, d);
|
|
6017
|
+
}
|
|
6018
|
+
created.push(task);
|
|
6019
|
+
}
|
|
6020
|
+
});
|
|
6021
|
+
tx();
|
|
6022
|
+
return { parent, subtasks: created };
|
|
6023
|
+
}
|
|
6024
|
+
function setTaskStatus(id, status, _agentId, db) {
|
|
6025
|
+
const d = db || getDatabase();
|
|
6026
|
+
for (let attempt = 0;attempt < 3; attempt++) {
|
|
6027
|
+
const task = getTask(id, d);
|
|
6028
|
+
if (!task)
|
|
6029
|
+
throw new TaskNotFoundError(id);
|
|
6030
|
+
if (task.status === status)
|
|
6031
|
+
return task;
|
|
6032
|
+
try {
|
|
6033
|
+
return updateTask(id, { status, version: task.version }, d);
|
|
6034
|
+
} catch (e) {
|
|
6035
|
+
if (e instanceof VersionConflictError && attempt < 2)
|
|
6036
|
+
continue;
|
|
6037
|
+
throw e;
|
|
6038
|
+
}
|
|
6039
|
+
}
|
|
6040
|
+
throw new Error(`Failed to set status after 3 attempts`);
|
|
6041
|
+
}
|
|
6042
|
+
function setTaskPriority(id, priority, _agentId, db) {
|
|
6043
|
+
const d = db || getDatabase();
|
|
6044
|
+
for (let attempt = 0;attempt < 3; attempt++) {
|
|
6045
|
+
const task = getTask(id, d);
|
|
6046
|
+
if (!task)
|
|
6047
|
+
throw new TaskNotFoundError(id);
|
|
6048
|
+
if (task.priority === priority)
|
|
6049
|
+
return task;
|
|
6050
|
+
try {
|
|
6051
|
+
return updateTask(id, { priority, version: task.version }, d);
|
|
6052
|
+
} catch (e) {
|
|
6053
|
+
if (e instanceof VersionConflictError && attempt < 2)
|
|
6054
|
+
continue;
|
|
6055
|
+
throw e;
|
|
6056
|
+
}
|
|
6057
|
+
}
|
|
6058
|
+
throw new Error(`Failed to set priority after 3 attempts`);
|
|
6059
|
+
}
|
|
5994
6060
|
function wouldCreateCycle(taskId, dependsOn, db) {
|
|
5995
6061
|
const visited = new Set;
|
|
5996
6062
|
const queue = [dependsOn];
|
|
@@ -8442,6 +8508,63 @@ No pending tasks available.`);
|
|
|
8442
8508
|
}
|
|
8443
8509
|
});
|
|
8444
8510
|
}
|
|
8511
|
+
if (shouldRegisterTool("decompose_task")) {
|
|
8512
|
+
server.tool("decompose_task", "Break a task into subtasks in one call. Optionally chain them sequentially with depends_on_prev.", {
|
|
8513
|
+
parent_id: exports_external.string(),
|
|
8514
|
+
subtasks: exports_external.array(exports_external.object({
|
|
8515
|
+
title: exports_external.string(),
|
|
8516
|
+
description: exports_external.string().optional(),
|
|
8517
|
+
priority: exports_external.enum(["low", "medium", "high", "critical"]).optional(),
|
|
8518
|
+
assigned_to: exports_external.string().optional(),
|
|
8519
|
+
estimated_minutes: exports_external.number().optional(),
|
|
8520
|
+
tags: exports_external.array(exports_external.string()).optional()
|
|
8521
|
+
})),
|
|
8522
|
+
depends_on_prev: exports_external.boolean().optional()
|
|
8523
|
+
}, async ({ parent_id, subtasks, depends_on_prev }) => {
|
|
8524
|
+
try {
|
|
8525
|
+
const resolvedId = resolveId(parent_id);
|
|
8526
|
+
const result = decomposeTasks(resolvedId, subtasks, { depends_on_prev }, undefined);
|
|
8527
|
+
const lines = [
|
|
8528
|
+
`Decomposed: ${formatTask(result.parent)}`,
|
|
8529
|
+
`Created ${result.subtasks.length} subtask(s)${depends_on_prev ? " (chained)" : ""}:`,
|
|
8530
|
+
...result.subtasks.map((t, i) => ` ${i + 1}. ${formatTask(t)}`)
|
|
8531
|
+
];
|
|
8532
|
+
return { content: [{ type: "text", text: lines.join(`
|
|
8533
|
+
`) }] };
|
|
8534
|
+
} catch (e) {
|
|
8535
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
8536
|
+
}
|
|
8537
|
+
});
|
|
8538
|
+
}
|
|
8539
|
+
if (shouldRegisterTool("set_task_status")) {
|
|
8540
|
+
server.tool("set_task_status", "Set task status without needing version. Auto-retries on conflict.", {
|
|
8541
|
+
id: exports_external.string(),
|
|
8542
|
+
status: exports_external.enum(["pending", "in_progress", "completed", "failed", "cancelled"]),
|
|
8543
|
+
agent_id: exports_external.string().optional()
|
|
8544
|
+
}, async ({ id, status, agent_id }) => {
|
|
8545
|
+
try {
|
|
8546
|
+
const resolvedId = resolveId(id);
|
|
8547
|
+
const task = setTaskStatus(resolvedId, status, agent_id);
|
|
8548
|
+
return { content: [{ type: "text", text: `set: ${formatTask(task)}` }] };
|
|
8549
|
+
} catch (e) {
|
|
8550
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
8551
|
+
}
|
|
8552
|
+
});
|
|
8553
|
+
}
|
|
8554
|
+
if (shouldRegisterTool("set_task_priority")) {
|
|
8555
|
+
server.tool("set_task_priority", "Set task priority without needing version. Auto-retries on conflict.", {
|
|
8556
|
+
id: exports_external.string(),
|
|
8557
|
+
priority: exports_external.enum(["low", "medium", "high", "critical"])
|
|
8558
|
+
}, async ({ id, priority }) => {
|
|
8559
|
+
try {
|
|
8560
|
+
const resolvedId = resolveId(id);
|
|
8561
|
+
const task = setTaskPriority(resolvedId, priority);
|
|
8562
|
+
return { content: [{ type: "text", text: `set: ${formatTask(task)}` }] };
|
|
8563
|
+
} catch (e) {
|
|
8564
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
8565
|
+
}
|
|
8566
|
+
});
|
|
8567
|
+
}
|
|
8445
8568
|
if (shouldRegisterTool("search_tools")) {
|
|
8446
8569
|
server.tool("search_tools", "List all tool names, optionally filtered by substring.", { query: exports_external.string().optional() }, async ({ query }) => {
|
|
8447
8570
|
const all = [
|
|
@@ -8502,6 +8625,9 @@ if (shouldRegisterTool("search_tools")) {
|
|
|
8502
8625
|
"get_tasks_changed_since",
|
|
8503
8626
|
"get_stale_tasks",
|
|
8504
8627
|
"get_status",
|
|
8628
|
+
"decompose_task",
|
|
8629
|
+
"set_task_status",
|
|
8630
|
+
"set_task_priority",
|
|
8505
8631
|
"search_tools",
|
|
8506
8632
|
"describe_tools"
|
|
8507
8633
|
].filter((name) => shouldRegisterTool(name));
|
|
@@ -8674,6 +8800,15 @@ if (shouldRegisterTool("describe_tools")) {
|
|
|
8674
8800
|
get_status: `Get a full project health snapshot \u2014 pending/in_progress/completed counts, active work, next recommended task, stale task count, overdue recurring tasks. Saves 4+ round trips at session start.
|
|
8675
8801
|
Params: agent_id(string, optional \u2014 prefers tasks assigned to this agent for next_task), project_id(string, optional), task_list_id(string, optional)
|
|
8676
8802
|
Example: {agent_id: 'a1b2c3d4', project_id: 'e5f6g7h8'}`,
|
|
8803
|
+
decompose_task: `Break a task into subtasks in one call. Subtasks inherit project/plan/list from parent.
|
|
8804
|
+
Params: parent_id(string, req), subtasks(array, req \u2014 [{title, description, priority, assigned_to, estimated_minutes, tags}]), depends_on_prev(boolean \u2014 chain subtasks sequentially)
|
|
8805
|
+
Example: {parent_id: 'a1b2c3d4', subtasks: [{title: 'Research'}, {title: 'Implement'}, {title: 'Test'}], depends_on_prev: true}`,
|
|
8806
|
+
set_task_status: `Set task status without needing version. Auto-retries on conflict (up to 3 attempts). Use instead of update_task when you only need to change status.
|
|
8807
|
+
Params: id(string, req), status(pending|in_progress|completed|failed|cancelled, req), agent_id(string)
|
|
8808
|
+
Example: {id: 'a1b2c3d4', status: 'completed'}`,
|
|
8809
|
+
set_task_priority: `Set task priority without needing version. Auto-retries on conflict (up to 3 attempts). Use instead of update_task when you only need to change priority.
|
|
8810
|
+
Params: id(string, req), priority(low|medium|high|critical, req)
|
|
8811
|
+
Example: {id: 'a1b2c3d4', priority: 'high'}`,
|
|
8677
8812
|
search_tools: `List all tool names or filter by substring.
|
|
8678
8813
|
Params: query(string, optional)
|
|
8679
8814
|
Example: {query: 'task'}`,
|
package/dist/server/index.js
CHANGED
|
@@ -1002,6 +1002,8 @@ __export(exports_tasks, {
|
|
|
1002
1002
|
updateTask: () => updateTask,
|
|
1003
1003
|
unlockTask: () => unlockTask,
|
|
1004
1004
|
startTask: () => startTask,
|
|
1005
|
+
setTaskStatus: () => setTaskStatus,
|
|
1006
|
+
setTaskPriority: () => setTaskPriority,
|
|
1005
1007
|
removeDependency: () => removeDependency,
|
|
1006
1008
|
moveTask: () => moveTask,
|
|
1007
1009
|
lockTask: () => lockTask,
|
|
@@ -1020,6 +1022,7 @@ __export(exports_tasks, {
|
|
|
1020
1022
|
getActiveWork: () => getActiveWork,
|
|
1021
1023
|
failTask: () => failTask,
|
|
1022
1024
|
deleteTask: () => deleteTask,
|
|
1025
|
+
decomposeTasks: () => decomposeTasks,
|
|
1023
1026
|
createTask: () => createTask,
|
|
1024
1027
|
countTasks: () => countTasks,
|
|
1025
1028
|
completeTask: () => completeTask,
|
|
@@ -1811,6 +1814,72 @@ function getStatus(filters, agentId, db) {
|
|
|
1811
1814
|
overdue_recurring: overdueRow.count
|
|
1812
1815
|
};
|
|
1813
1816
|
}
|
|
1817
|
+
function decomposeTasks(parentId, subtasks, options, db) {
|
|
1818
|
+
const d = db || getDatabase();
|
|
1819
|
+
const parent = getTask(parentId, d);
|
|
1820
|
+
if (!parent)
|
|
1821
|
+
throw new TaskNotFoundError(parentId);
|
|
1822
|
+
const created = [];
|
|
1823
|
+
const tx = d.transaction(() => {
|
|
1824
|
+
for (const input of subtasks) {
|
|
1825
|
+
const task = createTask({
|
|
1826
|
+
title: input.title,
|
|
1827
|
+
description: input.description,
|
|
1828
|
+
priority: input.priority || parent.priority,
|
|
1829
|
+
parent_id: parentId,
|
|
1830
|
+
project_id: parent.project_id || undefined,
|
|
1831
|
+
plan_id: parent.plan_id || undefined,
|
|
1832
|
+
task_list_id: parent.task_list_id || undefined,
|
|
1833
|
+
assigned_to: input.assigned_to || parent.assigned_to || undefined,
|
|
1834
|
+
estimated_minutes: input.estimated_minutes,
|
|
1835
|
+
tags: input.tags
|
|
1836
|
+
}, d);
|
|
1837
|
+
if (options?.depends_on_prev && created.length > 0) {
|
|
1838
|
+
const prev = created[created.length - 1];
|
|
1839
|
+
addDependency(task.id, prev.id, d);
|
|
1840
|
+
}
|
|
1841
|
+
created.push(task);
|
|
1842
|
+
}
|
|
1843
|
+
});
|
|
1844
|
+
tx();
|
|
1845
|
+
return { parent, subtasks: created };
|
|
1846
|
+
}
|
|
1847
|
+
function setTaskStatus(id, status, _agentId, db) {
|
|
1848
|
+
const d = db || getDatabase();
|
|
1849
|
+
for (let attempt = 0;attempt < 3; attempt++) {
|
|
1850
|
+
const task = getTask(id, d);
|
|
1851
|
+
if (!task)
|
|
1852
|
+
throw new TaskNotFoundError(id);
|
|
1853
|
+
if (task.status === status)
|
|
1854
|
+
return task;
|
|
1855
|
+
try {
|
|
1856
|
+
return updateTask(id, { status, version: task.version }, d);
|
|
1857
|
+
} catch (e) {
|
|
1858
|
+
if (e instanceof VersionConflictError && attempt < 2)
|
|
1859
|
+
continue;
|
|
1860
|
+
throw e;
|
|
1861
|
+
}
|
|
1862
|
+
}
|
|
1863
|
+
throw new Error(`Failed to set status after 3 attempts`);
|
|
1864
|
+
}
|
|
1865
|
+
function setTaskPriority(id, priority, _agentId, db) {
|
|
1866
|
+
const d = db || getDatabase();
|
|
1867
|
+
for (let attempt = 0;attempt < 3; attempt++) {
|
|
1868
|
+
const task = getTask(id, d);
|
|
1869
|
+
if (!task)
|
|
1870
|
+
throw new TaskNotFoundError(id);
|
|
1871
|
+
if (task.priority === priority)
|
|
1872
|
+
return task;
|
|
1873
|
+
try {
|
|
1874
|
+
return updateTask(id, { priority, version: task.version }, d);
|
|
1875
|
+
} catch (e) {
|
|
1876
|
+
if (e instanceof VersionConflictError && attempt < 2)
|
|
1877
|
+
continue;
|
|
1878
|
+
throw e;
|
|
1879
|
+
}
|
|
1880
|
+
}
|
|
1881
|
+
throw new Error(`Failed to set priority after 3 attempts`);
|
|
1882
|
+
}
|
|
1814
1883
|
function wouldCreateCycle(taskId, dependsOn, db) {
|
|
1815
1884
|
const visited = new Set;
|
|
1816
1885
|
const queue = [dependsOn];
|
|
@@ -2361,6 +2430,7 @@ async function startServer(port, options) {
|
|
|
2361
2430
|
const shouldOpen = options?.open ?? true;
|
|
2362
2431
|
getDatabase();
|
|
2363
2432
|
const sseClients = new Set;
|
|
2433
|
+
const filteredSseClients = new Set;
|
|
2364
2434
|
function broadcastEvent(event) {
|
|
2365
2435
|
const data = JSON.stringify({ ...event, timestamp: new Date().toISOString() });
|
|
2366
2436
|
for (const controller of sseClients) {
|
|
@@ -2372,6 +2442,21 @@ async function startServer(port, options) {
|
|
|
2372
2442
|
sseClients.delete(controller);
|
|
2373
2443
|
}
|
|
2374
2444
|
}
|
|
2445
|
+
const eventName = `task.${event.action}`;
|
|
2446
|
+
for (const client of filteredSseClients) {
|
|
2447
|
+
if (client.events && !client.events.has(eventName) && !client.events.has("*"))
|
|
2448
|
+
continue;
|
|
2449
|
+
if (client.agentId && event.agent_id !== client.agentId)
|
|
2450
|
+
continue;
|
|
2451
|
+
try {
|
|
2452
|
+
client.controller.enqueue(`event: ${eventName}
|
|
2453
|
+
data: ${data}
|
|
2454
|
+
|
|
2455
|
+
`);
|
|
2456
|
+
} catch {
|
|
2457
|
+
filteredSseClients.delete(client);
|
|
2458
|
+
}
|
|
2459
|
+
}
|
|
2375
2460
|
}
|
|
2376
2461
|
const dashboardDir = resolveDashboardDir();
|
|
2377
2462
|
const dashboardExists = existsSync4(dashboardDir);
|
|
@@ -2419,6 +2504,35 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
2419
2504
|
}
|
|
2420
2505
|
});
|
|
2421
2506
|
}
|
|
2507
|
+
if (path === "/api/tasks/stream" && method === "GET") {
|
|
2508
|
+
const agentId = url.searchParams.get("agent_id") || undefined;
|
|
2509
|
+
const projectId = url.searchParams.get("project_id") || undefined;
|
|
2510
|
+
const eventsParam = url.searchParams.get("events");
|
|
2511
|
+
const eventFilter = eventsParam ? new Set(eventsParam.split(",").map((e) => e.trim())) : undefined;
|
|
2512
|
+
const client = { controller: null, agentId, projectId, events: eventFilter };
|
|
2513
|
+
const stream = new ReadableStream({
|
|
2514
|
+
start(controller) {
|
|
2515
|
+
client.controller = controller;
|
|
2516
|
+
filteredSseClients.add(client);
|
|
2517
|
+
controller.enqueue(`: connected
|
|
2518
|
+
|
|
2519
|
+
data: ${JSON.stringify({ type: "connected", agent_id: agentId, timestamp: new Date().toISOString() })}
|
|
2520
|
+
|
|
2521
|
+
`);
|
|
2522
|
+
},
|
|
2523
|
+
cancel() {
|
|
2524
|
+
filteredSseClients.delete(client);
|
|
2525
|
+
}
|
|
2526
|
+
});
|
|
2527
|
+
return new Response(stream, {
|
|
2528
|
+
headers: {
|
|
2529
|
+
"Content-Type": "text/event-stream",
|
|
2530
|
+
"Cache-Control": "no-cache",
|
|
2531
|
+
Connection: "keep-alive",
|
|
2532
|
+
"Access-Control-Allow-Origin": "*"
|
|
2533
|
+
}
|
|
2534
|
+
});
|
|
2535
|
+
}
|
|
2422
2536
|
if (path === "/api/stats" && method === "GET") {
|
|
2423
2537
|
const all = listTasks({ limit: 1e4 });
|
|
2424
2538
|
const projects = listProjects();
|
|
@@ -2437,13 +2551,19 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
2437
2551
|
if (path === "/api/tasks" && method === "GET") {
|
|
2438
2552
|
const status = url.searchParams.get("status") || undefined;
|
|
2439
2553
|
const projectId = url.searchParams.get("project_id") || undefined;
|
|
2554
|
+
const sessionId = url.searchParams.get("session_id") || undefined;
|
|
2555
|
+
const agentId = url.searchParams.get("agent_id") || undefined;
|
|
2440
2556
|
const limitParam = url.searchParams.get("limit");
|
|
2557
|
+
const offsetParam = url.searchParams.get("offset");
|
|
2441
2558
|
const fieldsParam = url.searchParams.get("fields");
|
|
2442
2559
|
const fields = fieldsParam ? fieldsParam.split(",").map((f) => f.trim()).filter(Boolean) : undefined;
|
|
2443
2560
|
const tasks = listTasks({
|
|
2444
2561
|
status,
|
|
2445
2562
|
project_id: projectId,
|
|
2446
|
-
|
|
2563
|
+
session_id: sessionId,
|
|
2564
|
+
agent_id: agentId,
|
|
2565
|
+
limit: limitParam ? parseInt(limitParam, 10) : undefined,
|
|
2566
|
+
offset: offsetParam ? parseInt(offsetParam, 10) : undefined
|
|
2447
2567
|
});
|
|
2448
2568
|
return json(tasks.map((t) => taskToSummary(t, fields)), 200, port);
|
|
2449
2569
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/server/serve.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAgHH,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/server/serve.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAgHH,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA6sB3F"}
|