@hasna/todos 0.11.82 → 0.11.84
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/cloud-router.d.ts +190 -1
- package/dist/cli/cloud-router.d.ts.map +1 -1
- package/dist/cli/commands/agent-commands.d.ts.map +1 -1
- package/dist/cli/commands/mcp-hooks-commands.d.ts.map +1 -1
- package/dist/cli/commands/project-commands.d.ts.map +1 -1
- package/dist/cli/commands/query-commands.d.ts.map +1 -1
- package/dist/cli/commands/task-commands.d.ts.map +1 -1
- package/dist/cli/index.js +754 -84
- package/dist/index.js +114 -4
- package/dist/mcp/index.js +271 -5
- package/dist/mcp/tools/agents.d.ts.map +1 -1
- package/dist/release-provenance.json +3 -3
- package/dist/server/index.js +289 -23
- package/dist/server/v1.d.ts.map +1 -1
- package/dist/storage/interfaces.d.ts +58 -1
- package/dist/storage/interfaces.d.ts.map +1 -1
- package/dist/storage/postgres-adapter.d.ts.map +1 -1
- package/dist/storage.js +111 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -23525,7 +23525,19 @@ function createPostgresTodosStorageAdapter(options) {
|
|
|
23525
23525
|
claimNext: (agentId, filters) => claimNextTask2(agentId, filters, store),
|
|
23526
23526
|
getNext: (_agentId, filters) => getNextTask2(filters, store),
|
|
23527
23527
|
getActiveWork: (filters) => getActiveWork2(filters, store),
|
|
23528
|
-
getChangedSince: (since, filters) => getChangedSince(since, filters, store)
|
|
23528
|
+
getChangedSince: (since, filters) => getChangedSince(since, filters, store),
|
|
23529
|
+
lock: (id, agentId) => lockTask2(id, agentId, store),
|
|
23530
|
+
unlock: (id, agentId) => unlockTask2(id, agentId, store)
|
|
23531
|
+
},
|
|
23532
|
+
dependencies: {
|
|
23533
|
+
add: (taskId, dependsOn, context) => addDependency2(taskId, dependsOn, store, context),
|
|
23534
|
+
remove: (taskId, dependsOn) => removeDependency2(taskId, dependsOn, store),
|
|
23535
|
+
list: (taskId) => listDependencies(taskId, store),
|
|
23536
|
+
listAll: () => store.list("dependencies")
|
|
23537
|
+
},
|
|
23538
|
+
verifications: {
|
|
23539
|
+
add: (input, context) => addVerification(input, store, context),
|
|
23540
|
+
list: (taskId) => listVerifications(taskId, store)
|
|
23529
23541
|
},
|
|
23530
23542
|
projects: {
|
|
23531
23543
|
create: (input, context) => createProject2(input, store, context),
|
|
@@ -23980,6 +23992,104 @@ async function patchTask(task2, patch, store) {
|
|
|
23980
23992
|
await store.upsert("tasks", updated);
|
|
23981
23993
|
return updated;
|
|
23982
23994
|
}
|
|
23995
|
+
var CLOUD_LOCK_EXPIRY_MINUTES = 30;
|
|
23996
|
+
function cloudLockExpired(lockedAt) {
|
|
23997
|
+
if (!lockedAt)
|
|
23998
|
+
return true;
|
|
23999
|
+
return new Date(lockedAt).getTime() + CLOUD_LOCK_EXPIRY_MINUTES * 60 * 1000 < Date.now();
|
|
24000
|
+
}
|
|
24001
|
+
function cloudLockExpiresAt(lockedAt) {
|
|
24002
|
+
return new Date(new Date(lockedAt).getTime() + CLOUD_LOCK_EXPIRY_MINUTES * 60 * 1000).toISOString();
|
|
24003
|
+
}
|
|
24004
|
+
async function lockTask2(id, agentId, store) {
|
|
24005
|
+
const task2 = await requireRecord("tasks", id, store);
|
|
24006
|
+
if (task2.status === "completed" || task2.status === "cancelled") {
|
|
24007
|
+
return { success: false, error: `Task is ${task2.status} and cannot be locked` };
|
|
24008
|
+
}
|
|
24009
|
+
if (task2.locked_by && task2.locked_by !== agentId && !cloudLockExpired(task2.locked_at)) {
|
|
24010
|
+
return { success: false, locked_by: task2.locked_by, locked_at: task2.locked_at ?? undefined, error: `Task is locked by ${task2.locked_by}` };
|
|
24011
|
+
}
|
|
24012
|
+
const timestamp2 = new Date().toISOString();
|
|
24013
|
+
await patchTask(task2, { locked_by: agentId, locked_at: timestamp2 }, store);
|
|
24014
|
+
return { success: true, locked_by: agentId, locked_at: timestamp2, expires_at: cloudLockExpiresAt(timestamp2) };
|
|
24015
|
+
}
|
|
24016
|
+
async function unlockTask2(id, agentId, store) {
|
|
24017
|
+
const task2 = await requireRecord("tasks", id, store);
|
|
24018
|
+
if (agentId && task2.locked_by && task2.locked_by !== agentId) {
|
|
24019
|
+
throw new Error(`Task ${id} is locked by ${task2.locked_by}, not ${agentId}`);
|
|
24020
|
+
}
|
|
24021
|
+
await patchTask(task2, { locked_by: null, locked_at: null }, store);
|
|
24022
|
+
return true;
|
|
24023
|
+
}
|
|
24024
|
+
function dependencyId(taskId, dependsOn) {
|
|
24025
|
+
return `${taskId}::${dependsOn}`;
|
|
24026
|
+
}
|
|
24027
|
+
async function addDependency2(taskId, dependsOn, store, context) {
|
|
24028
|
+
if (taskId === dependsOn)
|
|
24029
|
+
throw new Error("A task cannot depend on itself");
|
|
24030
|
+
if (!await store.get("tasks", taskId))
|
|
24031
|
+
throw new Error(`Task not found: ${taskId}`);
|
|
24032
|
+
if (!await store.get("tasks", dependsOn))
|
|
24033
|
+
throw new Error(`Task not found: ${dependsOn}`);
|
|
24034
|
+
const edges = await store.list("dependencies");
|
|
24035
|
+
const adjacency = new Map;
|
|
24036
|
+
for (const edge of edges) {
|
|
24037
|
+
if (!adjacency.has(edge.task_id))
|
|
24038
|
+
adjacency.set(edge.task_id, []);
|
|
24039
|
+
adjacency.get(edge.task_id).push(edge.depends_on);
|
|
24040
|
+
}
|
|
24041
|
+
const queue = [dependsOn];
|
|
24042
|
+
const seen = new Set;
|
|
24043
|
+
while (queue.length) {
|
|
24044
|
+
const node = queue.shift();
|
|
24045
|
+
if (node === taskId)
|
|
24046
|
+
throw new Error(`Adding dependency ${taskId} -> ${dependsOn} would create a cycle`);
|
|
24047
|
+
if (seen.has(node))
|
|
24048
|
+
continue;
|
|
24049
|
+
seen.add(node);
|
|
24050
|
+
for (const next of adjacency.get(node) ?? [])
|
|
24051
|
+
queue.push(next);
|
|
24052
|
+
}
|
|
24053
|
+
const timestamp2 = new Date().toISOString();
|
|
24054
|
+
const record = { id: dependencyId(taskId, dependsOn), task_id: taskId, depends_on: dependsOn, created_at: timestamp2, updated_at: timestamp2 };
|
|
24055
|
+
await store.upsert("dependencies", record, context);
|
|
24056
|
+
return { task_id: taskId, depends_on: dependsOn };
|
|
24057
|
+
}
|
|
24058
|
+
async function removeDependency2(taskId, dependsOn, store) {
|
|
24059
|
+
const existing = await store.get("dependencies", dependencyId(taskId, dependsOn));
|
|
24060
|
+
if (!existing)
|
|
24061
|
+
return false;
|
|
24062
|
+
await store.delete("dependencies", dependencyId(taskId, dependsOn));
|
|
24063
|
+
return true;
|
|
24064
|
+
}
|
|
24065
|
+
async function listDependencies(taskId, store) {
|
|
24066
|
+
const edges = await store.list("dependencies");
|
|
24067
|
+
return {
|
|
24068
|
+
dependencies: edges.filter((edge) => edge.task_id === taskId).map((edge) => ({ task_id: edge.task_id, depends_on: edge.depends_on })),
|
|
24069
|
+
blocked_by: edges.filter((edge) => edge.depends_on === taskId).map((edge) => ({ task_id: edge.task_id, depends_on: edge.depends_on }))
|
|
24070
|
+
};
|
|
24071
|
+
}
|
|
24072
|
+
async function addVerification(input, store, context) {
|
|
24073
|
+
if (!await store.get("tasks", input.task_id))
|
|
24074
|
+
throw new Error(`Task not found: ${input.task_id}`);
|
|
24075
|
+
const timestamp2 = new Date().toISOString();
|
|
24076
|
+
const verification = {
|
|
24077
|
+
id: randomUUID3(),
|
|
24078
|
+
task_id: input.task_id,
|
|
24079
|
+
command: input.command,
|
|
24080
|
+
status: input.status ?? "unknown",
|
|
24081
|
+
output_summary: input.output_summary ?? null,
|
|
24082
|
+
artifact_path: input.artifact_path ?? null,
|
|
24083
|
+
agent_id: input.agent_id ?? context?.agentId ?? null,
|
|
24084
|
+
run_at: timestamp2,
|
|
24085
|
+
created_at: timestamp2
|
|
24086
|
+
};
|
|
24087
|
+
await store.upsert("verifications", { ...verification, updated_at: timestamp2 }, context);
|
|
24088
|
+
return verification;
|
|
24089
|
+
}
|
|
24090
|
+
async function listVerifications(taskId, store) {
|
|
24091
|
+
return (await store.list("verifications")).filter((verification) => verification.task_id === taskId).sort((a, b) => b.run_at.localeCompare(a.run_at));
|
|
24092
|
+
}
|
|
23983
24093
|
var TASK_ORDER_BY = "ORDER BY CASE payload->>'priority' WHEN 'critical' THEN 0 WHEN 'high' THEN 1 WHEN 'medium' THEN 2 WHEN 'low' THEN 3 ELSE 4 END ASC, payload->>'created_at' ASC, payload->>'id' ASC";
|
|
23984
24094
|
function toFilterArray(value) {
|
|
23985
24095
|
return Array.isArray(value) ? value : [value];
|
|
@@ -31783,13 +31893,13 @@ function importTodosMarkdown(markdown, options = {}, db) {
|
|
|
31783
31893
|
if (!taskId)
|
|
31784
31894
|
continue;
|
|
31785
31895
|
for (const dependencyTitle of item.depends_on_titles) {
|
|
31786
|
-
const
|
|
31787
|
-
if (!
|
|
31896
|
+
const dependencyId2 = taskByTitle.get(dependencyTitle);
|
|
31897
|
+
if (!dependencyId2) {
|
|
31788
31898
|
skipped.task_dependencies++;
|
|
31789
31899
|
issues.push(`missing dependency task: ${dependencyTitle}`);
|
|
31790
31900
|
continue;
|
|
31791
31901
|
}
|
|
31792
|
-
addDependency(taskId,
|
|
31902
|
+
addDependency(taskId, dependencyId2, d);
|
|
31793
31903
|
inserted.task_dependencies++;
|
|
31794
31904
|
}
|
|
31795
31905
|
}
|
package/dist/mcp/index.js
CHANGED
|
@@ -22863,6 +22863,13 @@ async function cloudCountTasks(client, filter = {}) {
|
|
|
22863
22863
|
const tasks = await cloudListTasks(client, rest);
|
|
22864
22864
|
return tasks.length;
|
|
22865
22865
|
}
|
|
22866
|
+
async function cloudRegisterAgent(client, input) {
|
|
22867
|
+
const raw = await client.transport.post("/agents", input);
|
|
22868
|
+
if (raw && typeof raw === "object" && "agent" in raw) {
|
|
22869
|
+
return raw.agent;
|
|
22870
|
+
}
|
|
22871
|
+
return raw;
|
|
22872
|
+
}
|
|
22866
22873
|
var _cache;
|
|
22867
22874
|
var init_cloud_router = __esm(() => {
|
|
22868
22875
|
init_storage();
|
|
@@ -44195,6 +44202,33 @@ function registerAgentTools(server, { shouldRegisterTool, resolveId, formatError
|
|
|
44195
44202
|
force: exports_external.boolean().optional().describe("Force takeover of an active agent's name. Use with caution \u2014 only when you know the previous session is dead.")
|
|
44196
44203
|
}, async ({ name, description, role, title, level, permissions, capabilities, session_id, working_dir, force }) => {
|
|
44197
44204
|
try {
|
|
44205
|
+
const cloud = getTodosCloudClient();
|
|
44206
|
+
if (cloud) {
|
|
44207
|
+
const agent2 = await cloudRegisterAgent(cloud, {
|
|
44208
|
+
name,
|
|
44209
|
+
description,
|
|
44210
|
+
role,
|
|
44211
|
+
title,
|
|
44212
|
+
level,
|
|
44213
|
+
permissions,
|
|
44214
|
+
capabilities,
|
|
44215
|
+
session_id,
|
|
44216
|
+
working_dir,
|
|
44217
|
+
force
|
|
44218
|
+
});
|
|
44219
|
+
return {
|
|
44220
|
+
content: [{
|
|
44221
|
+
type: "text",
|
|
44222
|
+
text: `Agent registered:
|
|
44223
|
+
ID: ${agent2.id}
|
|
44224
|
+
Name: ${agent2.name}${agent2.description ? `
|
|
44225
|
+
Description: ${agent2.description}` : ""}
|
|
44226
|
+
Session: ${agent2.session_id ?? "unbound"}
|
|
44227
|
+
Created: ${agent2.created_at}
|
|
44228
|
+
Last seen: ${agent2.last_seen_at}`
|
|
44229
|
+
}]
|
|
44230
|
+
};
|
|
44231
|
+
}
|
|
44198
44232
|
const pool = getAgentPoolForProject(working_dir);
|
|
44199
44233
|
const result = registerAgent({ name, description, role, title, level, permissions, capabilities, session_id, working_dir, force, pool: pool || undefined });
|
|
44200
44234
|
if (isAgentConflict(result)) {
|
|
@@ -48094,7 +48128,19 @@ function createPostgresTodosStorageAdapter(options) {
|
|
|
48094
48128
|
claimNext: (agentId, filters) => claimNextTask2(agentId, filters, store),
|
|
48095
48129
|
getNext: (_agentId, filters) => getNextTask2(filters, store),
|
|
48096
48130
|
getActiveWork: (filters) => getActiveWork2(filters, store),
|
|
48097
|
-
getChangedSince: (since, filters) => getChangedSince(since, filters, store)
|
|
48131
|
+
getChangedSince: (since, filters) => getChangedSince(since, filters, store),
|
|
48132
|
+
lock: (id, agentId) => lockTask2(id, agentId, store),
|
|
48133
|
+
unlock: (id, agentId) => unlockTask2(id, agentId, store)
|
|
48134
|
+
},
|
|
48135
|
+
dependencies: {
|
|
48136
|
+
add: (taskId, dependsOn, context) => addDependency2(taskId, dependsOn, store, context),
|
|
48137
|
+
remove: (taskId, dependsOn) => removeDependency2(taskId, dependsOn, store),
|
|
48138
|
+
list: (taskId) => listDependencies(taskId, store),
|
|
48139
|
+
listAll: () => store.list("dependencies")
|
|
48140
|
+
},
|
|
48141
|
+
verifications: {
|
|
48142
|
+
add: (input, context) => addVerification(input, store, context),
|
|
48143
|
+
list: (taskId) => listVerifications(taskId, store)
|
|
48098
48144
|
},
|
|
48099
48145
|
projects: {
|
|
48100
48146
|
create: (input, context) => createProject2(input, store, context),
|
|
@@ -48549,6 +48595,103 @@ async function patchTask(task2, patch, store) {
|
|
|
48549
48595
|
await store.upsert("tasks", updated);
|
|
48550
48596
|
return updated;
|
|
48551
48597
|
}
|
|
48598
|
+
function cloudLockExpired(lockedAt) {
|
|
48599
|
+
if (!lockedAt)
|
|
48600
|
+
return true;
|
|
48601
|
+
return new Date(lockedAt).getTime() + CLOUD_LOCK_EXPIRY_MINUTES * 60 * 1000 < Date.now();
|
|
48602
|
+
}
|
|
48603
|
+
function cloudLockExpiresAt(lockedAt) {
|
|
48604
|
+
return new Date(new Date(lockedAt).getTime() + CLOUD_LOCK_EXPIRY_MINUTES * 60 * 1000).toISOString();
|
|
48605
|
+
}
|
|
48606
|
+
async function lockTask2(id, agentId, store) {
|
|
48607
|
+
const task2 = await requireRecord("tasks", id, store);
|
|
48608
|
+
if (task2.status === "completed" || task2.status === "cancelled") {
|
|
48609
|
+
return { success: false, error: `Task is ${task2.status} and cannot be locked` };
|
|
48610
|
+
}
|
|
48611
|
+
if (task2.locked_by && task2.locked_by !== agentId && !cloudLockExpired(task2.locked_at)) {
|
|
48612
|
+
return { success: false, locked_by: task2.locked_by, locked_at: task2.locked_at ?? undefined, error: `Task is locked by ${task2.locked_by}` };
|
|
48613
|
+
}
|
|
48614
|
+
const timestamp3 = new Date().toISOString();
|
|
48615
|
+
await patchTask(task2, { locked_by: agentId, locked_at: timestamp3 }, store);
|
|
48616
|
+
return { success: true, locked_by: agentId, locked_at: timestamp3, expires_at: cloudLockExpiresAt(timestamp3) };
|
|
48617
|
+
}
|
|
48618
|
+
async function unlockTask2(id, agentId, store) {
|
|
48619
|
+
const task2 = await requireRecord("tasks", id, store);
|
|
48620
|
+
if (agentId && task2.locked_by && task2.locked_by !== agentId) {
|
|
48621
|
+
throw new Error(`Task ${id} is locked by ${task2.locked_by}, not ${agentId}`);
|
|
48622
|
+
}
|
|
48623
|
+
await patchTask(task2, { locked_by: null, locked_at: null }, store);
|
|
48624
|
+
return true;
|
|
48625
|
+
}
|
|
48626
|
+
function dependencyId(taskId, dependsOn) {
|
|
48627
|
+
return `${taskId}::${dependsOn}`;
|
|
48628
|
+
}
|
|
48629
|
+
async function addDependency2(taskId, dependsOn, store, context) {
|
|
48630
|
+
if (taskId === dependsOn)
|
|
48631
|
+
throw new Error("A task cannot depend on itself");
|
|
48632
|
+
if (!await store.get("tasks", taskId))
|
|
48633
|
+
throw new Error(`Task not found: ${taskId}`);
|
|
48634
|
+
if (!await store.get("tasks", dependsOn))
|
|
48635
|
+
throw new Error(`Task not found: ${dependsOn}`);
|
|
48636
|
+
const edges = await store.list("dependencies");
|
|
48637
|
+
const adjacency = new Map;
|
|
48638
|
+
for (const edge of edges) {
|
|
48639
|
+
if (!adjacency.has(edge.task_id))
|
|
48640
|
+
adjacency.set(edge.task_id, []);
|
|
48641
|
+
adjacency.get(edge.task_id).push(edge.depends_on);
|
|
48642
|
+
}
|
|
48643
|
+
const queue = [dependsOn];
|
|
48644
|
+
const seen = new Set;
|
|
48645
|
+
while (queue.length) {
|
|
48646
|
+
const node = queue.shift();
|
|
48647
|
+
if (node === taskId)
|
|
48648
|
+
throw new Error(`Adding dependency ${taskId} -> ${dependsOn} would create a cycle`);
|
|
48649
|
+
if (seen.has(node))
|
|
48650
|
+
continue;
|
|
48651
|
+
seen.add(node);
|
|
48652
|
+
for (const next of adjacency.get(node) ?? [])
|
|
48653
|
+
queue.push(next);
|
|
48654
|
+
}
|
|
48655
|
+
const timestamp3 = new Date().toISOString();
|
|
48656
|
+
const record = { id: dependencyId(taskId, dependsOn), task_id: taskId, depends_on: dependsOn, created_at: timestamp3, updated_at: timestamp3 };
|
|
48657
|
+
await store.upsert("dependencies", record, context);
|
|
48658
|
+
return { task_id: taskId, depends_on: dependsOn };
|
|
48659
|
+
}
|
|
48660
|
+
async function removeDependency2(taskId, dependsOn, store) {
|
|
48661
|
+
const existing = await store.get("dependencies", dependencyId(taskId, dependsOn));
|
|
48662
|
+
if (!existing)
|
|
48663
|
+
return false;
|
|
48664
|
+
await store.delete("dependencies", dependencyId(taskId, dependsOn));
|
|
48665
|
+
return true;
|
|
48666
|
+
}
|
|
48667
|
+
async function listDependencies(taskId, store) {
|
|
48668
|
+
const edges = await store.list("dependencies");
|
|
48669
|
+
return {
|
|
48670
|
+
dependencies: edges.filter((edge) => edge.task_id === taskId).map((edge) => ({ task_id: edge.task_id, depends_on: edge.depends_on })),
|
|
48671
|
+
blocked_by: edges.filter((edge) => edge.depends_on === taskId).map((edge) => ({ task_id: edge.task_id, depends_on: edge.depends_on }))
|
|
48672
|
+
};
|
|
48673
|
+
}
|
|
48674
|
+
async function addVerification(input, store, context) {
|
|
48675
|
+
if (!await store.get("tasks", input.task_id))
|
|
48676
|
+
throw new Error(`Task not found: ${input.task_id}`);
|
|
48677
|
+
const timestamp3 = new Date().toISOString();
|
|
48678
|
+
const verification = {
|
|
48679
|
+
id: randomUUID3(),
|
|
48680
|
+
task_id: input.task_id,
|
|
48681
|
+
command: input.command,
|
|
48682
|
+
status: input.status ?? "unknown",
|
|
48683
|
+
output_summary: input.output_summary ?? null,
|
|
48684
|
+
artifact_path: input.artifact_path ?? null,
|
|
48685
|
+
agent_id: input.agent_id ?? context?.agentId ?? null,
|
|
48686
|
+
run_at: timestamp3,
|
|
48687
|
+
created_at: timestamp3
|
|
48688
|
+
};
|
|
48689
|
+
await store.upsert("verifications", { ...verification, updated_at: timestamp3 }, context);
|
|
48690
|
+
return verification;
|
|
48691
|
+
}
|
|
48692
|
+
async function listVerifications(taskId, store) {
|
|
48693
|
+
return (await store.list("verifications")).filter((verification) => verification.task_id === taskId).sort((a, b) => b.run_at.localeCompare(a.run_at));
|
|
48694
|
+
}
|
|
48552
48695
|
function toFilterArray(value) {
|
|
48553
48696
|
return Array.isArray(value) ? value : [value];
|
|
48554
48697
|
}
|
|
@@ -48922,7 +49065,7 @@ function compareClock(left, right) {
|
|
|
48922
49065
|
function numberValue3(value) {
|
|
48923
49066
|
return typeof value === "number" && Number.isSafeInteger(value) ? value : null;
|
|
48924
49067
|
}
|
|
48925
|
-
var TASK_ORDER_BY = "ORDER BY CASE payload->>'priority' WHEN 'critical' THEN 0 WHEN 'high' THEN 1 WHEN 'medium' THEN 2 WHEN 'low' THEN 3 ELSE 4 END ASC, payload->>'created_at' ASC, payload->>'id' ASC";
|
|
49068
|
+
var CLOUD_LOCK_EXPIRY_MINUTES = 30, TASK_ORDER_BY = "ORDER BY CASE payload->>'priority' WHEN 'critical' THEN 0 WHEN 'high' THEN 1 WHEN 'medium' THEN 2 WHEN 'low' THEN 3 ELSE 4 END ASC, payload->>'created_at' ASC, payload->>'id' ASC";
|
|
48926
49069
|
var init_postgres_adapter = () => {};
|
|
48927
49070
|
|
|
48928
49071
|
// src/server/cloud.ts
|
|
@@ -49420,6 +49563,7 @@ async function handleV1Request(req, url) {
|
|
|
49420
49563
|
const resource = segments[1];
|
|
49421
49564
|
const id = segments[2];
|
|
49422
49565
|
const action = segments[3];
|
|
49566
|
+
const subId = segments[4];
|
|
49423
49567
|
try {
|
|
49424
49568
|
if (resource === "tasks") {
|
|
49425
49569
|
if (id === "exists" && !action) {
|
|
@@ -49495,6 +49639,89 @@ async function handleV1Request(req, url) {
|
|
|
49495
49639
|
}
|
|
49496
49640
|
return error(405, `method ${method} not allowed on /v1/tasks/:id/comments`);
|
|
49497
49641
|
}
|
|
49642
|
+
if (action === "lock" || action === "unlock") {
|
|
49643
|
+
if (method !== "POST")
|
|
49644
|
+
return error(405, `method ${method} not allowed on /v1/tasks/:id/${action}`);
|
|
49645
|
+
if (typeof store.tasks.lock !== "function" || typeof store.tasks.unlock !== "function") {
|
|
49646
|
+
return error(501, "task locking is not supported by this storage backend");
|
|
49647
|
+
}
|
|
49648
|
+
const body2 = await readJson(req) ?? {};
|
|
49649
|
+
if (!await store.tasks.get(id))
|
|
49650
|
+
return error(404, "task not found");
|
|
49651
|
+
if (action === "lock") {
|
|
49652
|
+
const agentId2 = body2.agent_id || principal.agent || "todos-serve";
|
|
49653
|
+
return json2({ result: await store.tasks.lock(id, agentId2) });
|
|
49654
|
+
}
|
|
49655
|
+
const released = await store.tasks.unlock(id, body2.agent_id || principal.agent || undefined);
|
|
49656
|
+
return json2({ success: released });
|
|
49657
|
+
}
|
|
49658
|
+
if (action === "dependencies") {
|
|
49659
|
+
if (!store.dependencies)
|
|
49660
|
+
return error(501, "dependencies are not supported by this storage backend");
|
|
49661
|
+
if (method === "GET") {
|
|
49662
|
+
if (!await store.tasks.get(id))
|
|
49663
|
+
return error(404, "task not found");
|
|
49664
|
+
const edges = await store.dependencies.list(id);
|
|
49665
|
+
return json2(edges);
|
|
49666
|
+
}
|
|
49667
|
+
if (method === "POST") {
|
|
49668
|
+
const body2 = await readJson(req) ?? {};
|
|
49669
|
+
if (typeof body2.depends_on !== "string" || !body2.depends_on.trim()) {
|
|
49670
|
+
return error(400, "depends_on is required");
|
|
49671
|
+
}
|
|
49672
|
+
try {
|
|
49673
|
+
const dependency = await store.dependencies.add(id, body2.depends_on, contextFromPrincipal(principal));
|
|
49674
|
+
return json2({ dependency }, 201);
|
|
49675
|
+
} catch (e) {
|
|
49676
|
+
const msg = e.message || "";
|
|
49677
|
+
if (msg.includes("not found"))
|
|
49678
|
+
return error(404, msg);
|
|
49679
|
+
if (msg.includes("cycle") || msg.includes("itself"))
|
|
49680
|
+
return error(409, msg);
|
|
49681
|
+
throw e;
|
|
49682
|
+
}
|
|
49683
|
+
}
|
|
49684
|
+
if (method === "DELETE") {
|
|
49685
|
+
if (!subId)
|
|
49686
|
+
return error(400, "dependency target id is required (/v1/tasks/:id/dependencies/:dep)");
|
|
49687
|
+
const removed = await store.dependencies.remove(id, subId);
|
|
49688
|
+
return json2({ removed });
|
|
49689
|
+
}
|
|
49690
|
+
return error(405, `method ${method} not allowed on /v1/tasks/:id/dependencies`);
|
|
49691
|
+
}
|
|
49692
|
+
if (action === "verifications") {
|
|
49693
|
+
if (!store.verifications)
|
|
49694
|
+
return error(501, "verifications are not supported by this storage backend");
|
|
49695
|
+
if (method === "GET") {
|
|
49696
|
+
if (!await store.tasks.get(id))
|
|
49697
|
+
return error(404, "task not found");
|
|
49698
|
+
const verifications = await store.verifications.list(id);
|
|
49699
|
+
return json2({ verifications, count: verifications.length });
|
|
49700
|
+
}
|
|
49701
|
+
if (method === "POST") {
|
|
49702
|
+
const body2 = await readJson(req) ?? {};
|
|
49703
|
+
if (typeof body2.command !== "string" || !body2.command.trim()) {
|
|
49704
|
+
return error(400, "command is required");
|
|
49705
|
+
}
|
|
49706
|
+
try {
|
|
49707
|
+
const verification = await store.verifications.add({
|
|
49708
|
+
task_id: id,
|
|
49709
|
+
command: body2.command,
|
|
49710
|
+
status: body2.status,
|
|
49711
|
+
output_summary: body2.output_summary,
|
|
49712
|
+
artifact_path: body2.artifact_path,
|
|
49713
|
+
agent_id: body2.agent_id
|
|
49714
|
+
}, contextFromPrincipal(principal, body2));
|
|
49715
|
+
return json2({ verification }, 201);
|
|
49716
|
+
} catch (e) {
|
|
49717
|
+
const msg = e.message || "";
|
|
49718
|
+
if (msg.includes("not found"))
|
|
49719
|
+
return error(404, msg);
|
|
49720
|
+
throw e;
|
|
49721
|
+
}
|
|
49722
|
+
}
|
|
49723
|
+
return error(405, `method ${method} not allowed on /v1/tasks/:id/verifications`);
|
|
49724
|
+
}
|
|
49498
49725
|
const body = await readJson(req) ?? {};
|
|
49499
49726
|
const agentId = body.agent_id || principal.agent || "todos-serve";
|
|
49500
49727
|
if (action === "start" && method === "POST") {
|
|
@@ -49599,16 +49826,55 @@ async function handleV1Request(req, url) {
|
|
|
49599
49826
|
}
|
|
49600
49827
|
if (!id && method === "POST") {
|
|
49601
49828
|
const body = await readJson(req);
|
|
49602
|
-
if (!body || typeof body.name !== "string")
|
|
49829
|
+
if (!body || typeof body.name !== "string" || !body.name.trim())
|
|
49603
49830
|
return error(400, "name is required");
|
|
49604
|
-
const
|
|
49605
|
-
|
|
49831
|
+
const result = await store.agents.register(body, contextFromPrincipal(principal));
|
|
49832
|
+
if (result && typeof result === "object" && "conflict" in result) {
|
|
49833
|
+
return error(409, result.message ?? "agent name conflict", { conflict: true });
|
|
49834
|
+
}
|
|
49835
|
+
return json2({ agent: result }, 201);
|
|
49606
49836
|
}
|
|
49607
49837
|
if (id && method === "GET") {
|
|
49608
49838
|
const agent = await store.agents.get(id);
|
|
49609
49839
|
return agent ? json2({ agent }) : error(404, "agent not found");
|
|
49610
49840
|
}
|
|
49611
49841
|
}
|
|
49842
|
+
if (resource === "activity" && !id) {
|
|
49843
|
+
if (method !== "GET")
|
|
49844
|
+
return error(405, `method ${method} not allowed on /v1/activity`);
|
|
49845
|
+
const limitParam = url.searchParams.get("limit");
|
|
49846
|
+
const limit = limitParam ? Math.max(1, Math.min(1e4, Number(limitParam) || 50)) : 50;
|
|
49847
|
+
const activity = await store.audit.getRecentActivity(limit);
|
|
49848
|
+
return json2({ activity, count: activity.length });
|
|
49849
|
+
}
|
|
49850
|
+
if (resource === "task-lists" && !id) {
|
|
49851
|
+
if (method !== "GET")
|
|
49852
|
+
return error(405, `method ${method} not allowed on /v1/task-lists`);
|
|
49853
|
+
const projectId = url.searchParams.get("project_id") ?? undefined;
|
|
49854
|
+
const taskLists = await store.taskLists.list(projectId);
|
|
49855
|
+
return json2({ task_lists: taskLists, count: taskLists.length });
|
|
49856
|
+
}
|
|
49857
|
+
if (resource === "dependencies" && !id) {
|
|
49858
|
+
if (method !== "GET")
|
|
49859
|
+
return error(405, `method ${method} not allowed on /v1/dependencies`);
|
|
49860
|
+
if (typeof store.dependencies?.listAll !== "function") {
|
|
49861
|
+
return error(501, "dependency edge listing is not supported by this storage backend");
|
|
49862
|
+
}
|
|
49863
|
+
const dependencies = await store.dependencies.listAll();
|
|
49864
|
+
return json2({ dependencies, count: dependencies.length });
|
|
49865
|
+
}
|
|
49866
|
+
if (resource === "next" && !id) {
|
|
49867
|
+
if (method !== "GET")
|
|
49868
|
+
return error(405, `method ${method} not allowed on /v1/next`);
|
|
49869
|
+
const agent = url.searchParams.get("agent") ?? undefined;
|
|
49870
|
+
const filters = {
|
|
49871
|
+
...url.searchParams.get("project_id") ? { project_id: url.searchParams.get("project_id") } : {},
|
|
49872
|
+
...url.searchParams.get("task_list_id") ? { task_list_id: url.searchParams.get("task_list_id") } : {},
|
|
49873
|
+
...url.searchParams.get("plan_id") ? { plan_id: url.searchParams.get("plan_id") } : {}
|
|
49874
|
+
};
|
|
49875
|
+
const task2 = await store.tasks.getNext(agent, filters);
|
|
49876
|
+
return json2({ task: task2 ?? null });
|
|
49877
|
+
}
|
|
49612
49878
|
if (resource === "stats" && method === "GET") {
|
|
49613
49879
|
const [tasks, tasksAll, projects] = await Promise.all([
|
|
49614
49880
|
store.tasks.count(),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/agents.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAOzE,UAAU,UAAU;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,KAAK,OAAO,GAAG;IACb,kBAAkB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IAC9C,SAAS,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IAClD,WAAW,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,MAAM,CAAC;IACpC,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACvC,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,UAAU,GAAG,SAAS,CAAC;CAC5D,CAAC;AAEF,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,kBAAkB,EAAE,SAAS,EAAE,WAAW,EAAE,aAAa,EAAE,aAAa,EAAE,EAAE,OAAO,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/agents.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAOzE,UAAU,UAAU;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,KAAK,OAAO,GAAG;IACb,kBAAkB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IAC9C,SAAS,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IAClD,WAAW,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,MAAM,CAAC;IACpC,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACvC,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,UAAU,GAAG,SAAS,CAAC;CAC5D,CAAC;AAEF,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,kBAAkB,EAAE,SAAS,EAAE,WAAW,EAAE,aAAa,EAAE,aAAa,EAAE,EAAE,OAAO,GAAG,IAAI,CA6cjJ"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"packageName": "@hasna/todos",
|
|
3
|
-
"packageVersion": "0.11.
|
|
3
|
+
"packageVersion": "0.11.84",
|
|
4
4
|
"repository": "https://github.com/hasna/todos.git",
|
|
5
|
-
"gitCommit": "
|
|
6
|
-
"generatedAt": "2026-07-
|
|
5
|
+
"gitCommit": "f7fcea3d57bf87853fcc48b009019733b2206ca7",
|
|
6
|
+
"generatedAt": "2026-07-08T15:23:54.541Z"
|
|
7
7
|
}
|