@hasna/todos 0.10.9 → 0.10.11
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 +80 -11
- package/dist/db/task-files.d.ts +12 -0
- package/dist/db/task-files.d.ts.map +1 -1
- package/dist/mcp/index.js +80 -11
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -9812,6 +9812,7 @@ __export(exports_task_files, {
|
|
|
9812
9812
|
listActiveFiles: () => listActiveFiles,
|
|
9813
9813
|
getTaskFile: () => getTaskFile,
|
|
9814
9814
|
findTasksByFile: () => findTasksByFile,
|
|
9815
|
+
detectFileConflicts: () => detectFileConflicts,
|
|
9815
9816
|
bulkFindTasksByFiles: () => bulkFindTasksByFiles,
|
|
9816
9817
|
bulkAddTaskFiles: () => bulkAddTaskFiles,
|
|
9817
9818
|
addTaskFile: () => addTaskFile
|
|
@@ -9853,6 +9854,24 @@ function removeTaskFile(taskId, path, db) {
|
|
|
9853
9854
|
const result = d.run("DELETE FROM task_files WHERE task_id = ? AND path = ?", [taskId, path]);
|
|
9854
9855
|
return result.changes > 0;
|
|
9855
9856
|
}
|
|
9857
|
+
function detectFileConflicts(taskId, paths, db) {
|
|
9858
|
+
const d = db || getDatabase();
|
|
9859
|
+
if (paths.length === 0)
|
|
9860
|
+
return [];
|
|
9861
|
+
const placeholders = paths.map(() => "?").join(", ");
|
|
9862
|
+
const rows = d.query(`
|
|
9863
|
+
SELECT tf.path, tf.agent_id AS conflicting_agent_id, t.id AS conflicting_task_id,
|
|
9864
|
+
t.title AS conflicting_task_title, t.status AS conflicting_task_status
|
|
9865
|
+
FROM task_files tf
|
|
9866
|
+
JOIN tasks t ON tf.task_id = t.id
|
|
9867
|
+
WHERE tf.path IN (${placeholders})
|
|
9868
|
+
AND tf.task_id != ?
|
|
9869
|
+
AND tf.status != 'removed'
|
|
9870
|
+
AND t.status = 'in_progress'
|
|
9871
|
+
ORDER BY tf.updated_at DESC
|
|
9872
|
+
`).all(...paths, taskId);
|
|
9873
|
+
return rows;
|
|
9874
|
+
}
|
|
9856
9875
|
function bulkFindTasksByFiles(paths, db) {
|
|
9857
9876
|
const d = db || getDatabase();
|
|
9858
9877
|
if (paths.length === 0)
|
|
@@ -10817,8 +10836,6 @@ var init_mcp = __esm(() => {
|
|
|
10817
10836
|
"heartbeat"
|
|
10818
10837
|
]);
|
|
10819
10838
|
STANDARD_EXCLUDED = new Set([
|
|
10820
|
-
"get_org_chart",
|
|
10821
|
-
"set_reports_to",
|
|
10822
10839
|
"rename_agent",
|
|
10823
10840
|
"delete_agent",
|
|
10824
10841
|
"unarchive_agent",
|
|
@@ -12263,14 +12280,32 @@ In Progress:`);
|
|
|
12263
12280
|
});
|
|
12264
12281
|
}
|
|
12265
12282
|
if (shouldRegisterTool("get_org_chart")) {
|
|
12266
|
-
server.tool("get_org_chart", "Get agent org chart showing reporting hierarchy
|
|
12283
|
+
server.tool("get_org_chart", "Get agent org chart showing reporting hierarchy with roles, titles, capabilities, and activity status.", {
|
|
12284
|
+
format: exports_external.enum(["text", "json"]).optional().describe("Output format (default: text)"),
|
|
12285
|
+
role: exports_external.string().optional().describe("Filter by agent role (e.g. 'lead', 'developer')"),
|
|
12286
|
+
active_only: exports_external.coerce.boolean().optional().describe("Only show agents active in last 30 min")
|
|
12287
|
+
}, async ({ format, role, active_only }) => {
|
|
12267
12288
|
try {
|
|
12268
|
-
let
|
|
12289
|
+
let filterTree = function(nodes) {
|
|
12290
|
+
return nodes.map((n) => ({ ...n, reports: filterTree(n.reports) })).filter((n) => {
|
|
12291
|
+
if (role && n.agent.role !== role)
|
|
12292
|
+
return false;
|
|
12293
|
+
if (active_only) {
|
|
12294
|
+
const lastSeen = new Date(n.agent.last_seen_at).getTime();
|
|
12295
|
+
if (now2 - lastSeen > ACTIVE_MS)
|
|
12296
|
+
return false;
|
|
12297
|
+
}
|
|
12298
|
+
return true;
|
|
12299
|
+
});
|
|
12300
|
+
}, render = function(nodes, indent = 0) {
|
|
12269
12301
|
return nodes.map((n) => {
|
|
12270
12302
|
const prefix = " ".repeat(indent);
|
|
12271
12303
|
const title = n.agent.title ? ` \u2014 ${n.agent.title}` : "";
|
|
12272
|
-
const level = n.agent.level ? `
|
|
12273
|
-
const
|
|
12304
|
+
const level = n.agent.level ? ` [${n.agent.level}]` : "";
|
|
12305
|
+
const caps = n.agent.capabilities?.length > 0 ? ` {${n.agent.capabilities.join(", ")}}` : "";
|
|
12306
|
+
const lastSeen = new Date(n.agent.last_seen_at).getTime();
|
|
12307
|
+
const active = now2 - lastSeen < ACTIVE_MS ? " \u25CF" : " \u25CB";
|
|
12308
|
+
const line = `${prefix}${active} ${n.agent.name}${title}${level}${caps}`;
|
|
12274
12309
|
const children = n.reports.length > 0 ? `
|
|
12275
12310
|
` + render(n.reports, indent + 1) : "";
|
|
12276
12311
|
return line + children;
|
|
@@ -12278,7 +12313,14 @@ In Progress:`);
|
|
|
12278
12313
|
`);
|
|
12279
12314
|
};
|
|
12280
12315
|
const { getOrgChart: getOrgChart2 } = await Promise.resolve().then(() => (init_agents(), exports_agents));
|
|
12281
|
-
|
|
12316
|
+
let tree = getOrgChart2();
|
|
12317
|
+
const now2 = Date.now();
|
|
12318
|
+
const ACTIVE_MS = 1800000;
|
|
12319
|
+
if (role || active_only)
|
|
12320
|
+
tree = filterTree(tree);
|
|
12321
|
+
if (format === "json") {
|
|
12322
|
+
return { content: [{ type: "text", text: JSON.stringify(tree, null, 2) }] };
|
|
12323
|
+
}
|
|
12282
12324
|
const text = tree.length > 0 ? render(tree) : "No agents registered.";
|
|
12283
12325
|
return { content: [{ type: "text", text }] };
|
|
12284
12326
|
} catch (e) {
|
|
@@ -13289,7 +13331,7 @@ Claimed: ${formatTask(result.claimed)}`);
|
|
|
13289
13331
|
return { contents: [{ uri: "todos://agents", text: JSON.stringify(agents, null, 2), mimeType: "application/json" }] };
|
|
13290
13332
|
});
|
|
13291
13333
|
if (shouldRegisterTool("add_task_file")) {
|
|
13292
|
-
server.tool("add_task_file", "Link a file path to a task. Tracks which files an agent is working on. Upserts if same task+path exists.", {
|
|
13334
|
+
server.tool("add_task_file", "Link a file path to a task. Tracks which files an agent is working on. Upserts if same task+path exists. Auto-detects conflicts with other in-progress tasks.", {
|
|
13293
13335
|
task_id: exports_external.string().describe("Task ID"),
|
|
13294
13336
|
path: exports_external.string().describe("File path (relative or absolute)"),
|
|
13295
13337
|
paths: exports_external.array(exports_external.string()).optional().describe("Multiple file paths to add at once"),
|
|
@@ -13298,14 +13340,41 @@ Claimed: ${formatTask(result.claimed)}`);
|
|
|
13298
13340
|
note: exports_external.string().optional().describe("Note about why this file is linked")
|
|
13299
13341
|
}, async ({ task_id, path, paths: multiplePaths, status, agent_id, note }) => {
|
|
13300
13342
|
try {
|
|
13301
|
-
const { addTaskFile: addTaskFile2, bulkAddTaskFiles: bulkAddTaskFiles2 } = (init_task_files(), __toCommonJS(exports_task_files));
|
|
13343
|
+
const { addTaskFile: addTaskFile2, bulkAddTaskFiles: bulkAddTaskFiles2, detectFileConflicts: detectFileConflicts2 } = (init_task_files(), __toCommonJS(exports_task_files));
|
|
13302
13344
|
const resolvedId = resolveId(task_id);
|
|
13345
|
+
let addedFiles;
|
|
13303
13346
|
if (multiplePaths && multiplePaths.length > 0) {
|
|
13304
13347
|
const allPaths = path ? [path, ...multiplePaths] : multiplePaths;
|
|
13305
|
-
|
|
13306
|
-
|
|
13348
|
+
addedFiles = bulkAddTaskFiles2(resolvedId, allPaths, agent_id);
|
|
13349
|
+
const conflicts2 = detectFileConflicts2(resolvedId, allPaths);
|
|
13350
|
+
if (conflicts2.length > 0) {
|
|
13351
|
+
return {
|
|
13352
|
+
content: [{
|
|
13353
|
+
type: "text",
|
|
13354
|
+
text: JSON.stringify({
|
|
13355
|
+
added: addedFiles.length,
|
|
13356
|
+
conflicts: conflicts2,
|
|
13357
|
+
warning: `${conflicts2.length} file(s) already claimed by other in-progress tasks`
|
|
13358
|
+
}, null, 2)
|
|
13359
|
+
}]
|
|
13360
|
+
};
|
|
13361
|
+
}
|
|
13362
|
+
return { content: [{ type: "text", text: `${addedFiles.length} file(s) linked to task ${resolvedId.slice(0, 8)}` }] };
|
|
13307
13363
|
}
|
|
13308
13364
|
const file = addTaskFile2({ task_id: resolvedId, path, status, agent_id, note });
|
|
13365
|
+
const conflicts = detectFileConflicts2(resolvedId, [path]);
|
|
13366
|
+
if (conflicts.length > 0) {
|
|
13367
|
+
return {
|
|
13368
|
+
content: [{
|
|
13369
|
+
type: "text",
|
|
13370
|
+
text: JSON.stringify({
|
|
13371
|
+
file,
|
|
13372
|
+
conflicts,
|
|
13373
|
+
warning: `${path} is already claimed by another in-progress task`
|
|
13374
|
+
}, null, 2)
|
|
13375
|
+
}]
|
|
13376
|
+
};
|
|
13377
|
+
}
|
|
13309
13378
|
return { content: [{ type: "text", text: `${file.status} ${file.path} \u2192 task ${resolvedId.slice(0, 8)}` }] };
|
|
13310
13379
|
} catch (e) {
|
|
13311
13380
|
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
package/dist/db/task-files.d.ts
CHANGED
|
@@ -22,6 +22,18 @@ export declare function listTaskFiles(taskId: string, db?: Database): TaskFile[]
|
|
|
22
22
|
export declare function findTasksByFile(path: string, db?: Database): TaskFile[];
|
|
23
23
|
export declare function updateTaskFileStatus(taskId: string, path: string, status: TaskFile["status"], agentId?: string, db?: Database): TaskFile | null;
|
|
24
24
|
export declare function removeTaskFile(taskId: string, path: string, db?: Database): boolean;
|
|
25
|
+
export interface FileConflict {
|
|
26
|
+
path: string;
|
|
27
|
+
conflicting_task_id: string;
|
|
28
|
+
conflicting_agent_id: string | null;
|
|
29
|
+
conflicting_task_title: string;
|
|
30
|
+
conflicting_task_status: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Check if adding a file to a task would conflict with another in-progress task.
|
|
34
|
+
* Returns conflicts (not a hard block — caller decides what to do).
|
|
35
|
+
*/
|
|
36
|
+
export declare function detectFileConflicts(taskId: string, paths: string[], db?: Database): FileConflict[];
|
|
25
37
|
export interface BulkFileResult {
|
|
26
38
|
path: string;
|
|
27
39
|
tasks: TaskFile[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task-files.d.ts","sourceRoot":"","sources":["../../src/db/task-files.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"task-files.d.ts","sourceRoot":"","sources":["../../src/db/task-files.ts"],"names":[],"mappings":"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"}
|
package/dist/mcp/index.js
CHANGED
|
@@ -1357,6 +1357,7 @@ __export(exports_task_files, {
|
|
|
1357
1357
|
listActiveFiles: () => listActiveFiles,
|
|
1358
1358
|
getTaskFile: () => getTaskFile,
|
|
1359
1359
|
findTasksByFile: () => findTasksByFile,
|
|
1360
|
+
detectFileConflicts: () => detectFileConflicts,
|
|
1360
1361
|
bulkFindTasksByFiles: () => bulkFindTasksByFiles,
|
|
1361
1362
|
bulkAddTaskFiles: () => bulkAddTaskFiles,
|
|
1362
1363
|
addTaskFile: () => addTaskFile
|
|
@@ -1398,6 +1399,24 @@ function removeTaskFile(taskId, path, db) {
|
|
|
1398
1399
|
const result = d.run("DELETE FROM task_files WHERE task_id = ? AND path = ?", [taskId, path]);
|
|
1399
1400
|
return result.changes > 0;
|
|
1400
1401
|
}
|
|
1402
|
+
function detectFileConflicts(taskId, paths, db) {
|
|
1403
|
+
const d = db || getDatabase();
|
|
1404
|
+
if (paths.length === 0)
|
|
1405
|
+
return [];
|
|
1406
|
+
const placeholders = paths.map(() => "?").join(", ");
|
|
1407
|
+
const rows = d.query(`
|
|
1408
|
+
SELECT tf.path, tf.agent_id AS conflicting_agent_id, t.id AS conflicting_task_id,
|
|
1409
|
+
t.title AS conflicting_task_title, t.status AS conflicting_task_status
|
|
1410
|
+
FROM task_files tf
|
|
1411
|
+
JOIN tasks t ON tf.task_id = t.id
|
|
1412
|
+
WHERE tf.path IN (${placeholders})
|
|
1413
|
+
AND tf.task_id != ?
|
|
1414
|
+
AND tf.status != 'removed'
|
|
1415
|
+
AND t.status = 'in_progress'
|
|
1416
|
+
ORDER BY tf.updated_at DESC
|
|
1417
|
+
`).all(...paths, taskId);
|
|
1418
|
+
return rows;
|
|
1419
|
+
}
|
|
1401
1420
|
function bulkFindTasksByFiles(paths, db) {
|
|
1402
1421
|
const d = db || getDatabase();
|
|
1403
1422
|
if (paths.length === 0)
|
|
@@ -8422,8 +8441,6 @@ var MINIMAL_TOOLS = new Set([
|
|
|
8422
8441
|
"heartbeat"
|
|
8423
8442
|
]);
|
|
8424
8443
|
var STANDARD_EXCLUDED = new Set([
|
|
8425
|
-
"get_org_chart",
|
|
8426
|
-
"set_reports_to",
|
|
8427
8444
|
"rename_agent",
|
|
8428
8445
|
"delete_agent",
|
|
8429
8446
|
"unarchive_agent",
|
|
@@ -9991,14 +10008,32 @@ In Progress:`);
|
|
|
9991
10008
|
});
|
|
9992
10009
|
}
|
|
9993
10010
|
if (shouldRegisterTool("get_org_chart")) {
|
|
9994
|
-
server.tool("get_org_chart", "Get agent org chart showing reporting hierarchy
|
|
10011
|
+
server.tool("get_org_chart", "Get agent org chart showing reporting hierarchy with roles, titles, capabilities, and activity status.", {
|
|
10012
|
+
format: exports_external.enum(["text", "json"]).optional().describe("Output format (default: text)"),
|
|
10013
|
+
role: exports_external.string().optional().describe("Filter by agent role (e.g. 'lead', 'developer')"),
|
|
10014
|
+
active_only: exports_external.coerce.boolean().optional().describe("Only show agents active in last 30 min")
|
|
10015
|
+
}, async ({ format, role, active_only }) => {
|
|
9995
10016
|
try {
|
|
9996
|
-
let
|
|
10017
|
+
let filterTree = function(nodes) {
|
|
10018
|
+
return nodes.map((n) => ({ ...n, reports: filterTree(n.reports) })).filter((n) => {
|
|
10019
|
+
if (role && n.agent.role !== role)
|
|
10020
|
+
return false;
|
|
10021
|
+
if (active_only) {
|
|
10022
|
+
const lastSeen = new Date(n.agent.last_seen_at).getTime();
|
|
10023
|
+
if (now2 - lastSeen > ACTIVE_MS)
|
|
10024
|
+
return false;
|
|
10025
|
+
}
|
|
10026
|
+
return true;
|
|
10027
|
+
});
|
|
10028
|
+
}, render = function(nodes, indent = 0) {
|
|
9997
10029
|
return nodes.map((n) => {
|
|
9998
10030
|
const prefix = " ".repeat(indent);
|
|
9999
10031
|
const title = n.agent.title ? ` \u2014 ${n.agent.title}` : "";
|
|
10000
|
-
const level = n.agent.level ? `
|
|
10001
|
-
const
|
|
10032
|
+
const level = n.agent.level ? ` [${n.agent.level}]` : "";
|
|
10033
|
+
const caps = n.agent.capabilities?.length > 0 ? ` {${n.agent.capabilities.join(", ")}}` : "";
|
|
10034
|
+
const lastSeen = new Date(n.agent.last_seen_at).getTime();
|
|
10035
|
+
const active = now2 - lastSeen < ACTIVE_MS ? " \u25CF" : " \u25CB";
|
|
10036
|
+
const line = `${prefix}${active} ${n.agent.name}${title}${level}${caps}`;
|
|
10002
10037
|
const children = n.reports.length > 0 ? `
|
|
10003
10038
|
` + render(n.reports, indent + 1) : "";
|
|
10004
10039
|
return line + children;
|
|
@@ -10006,7 +10041,14 @@ if (shouldRegisterTool("get_org_chart")) {
|
|
|
10006
10041
|
`);
|
|
10007
10042
|
};
|
|
10008
10043
|
const { getOrgChart: getOrgChart2 } = await Promise.resolve().then(() => (init_agents(), exports_agents));
|
|
10009
|
-
|
|
10044
|
+
let tree = getOrgChart2();
|
|
10045
|
+
const now2 = Date.now();
|
|
10046
|
+
const ACTIVE_MS = 1800000;
|
|
10047
|
+
if (role || active_only)
|
|
10048
|
+
tree = filterTree(tree);
|
|
10049
|
+
if (format === "json") {
|
|
10050
|
+
return { content: [{ type: "text", text: JSON.stringify(tree, null, 2) }] };
|
|
10051
|
+
}
|
|
10010
10052
|
const text = tree.length > 0 ? render(tree) : "No agents registered.";
|
|
10011
10053
|
return { content: [{ type: "text", text }] };
|
|
10012
10054
|
} catch (e) {
|
|
@@ -11017,7 +11059,7 @@ server.resource("agents", "todos://agents", { description: "All registered agent
|
|
|
11017
11059
|
return { contents: [{ uri: "todos://agents", text: JSON.stringify(agents, null, 2), mimeType: "application/json" }] };
|
|
11018
11060
|
});
|
|
11019
11061
|
if (shouldRegisterTool("add_task_file")) {
|
|
11020
|
-
server.tool("add_task_file", "Link a file path to a task. Tracks which files an agent is working on. Upserts if same task+path exists.", {
|
|
11062
|
+
server.tool("add_task_file", "Link a file path to a task. Tracks which files an agent is working on. Upserts if same task+path exists. Auto-detects conflicts with other in-progress tasks.", {
|
|
11021
11063
|
task_id: exports_external.string().describe("Task ID"),
|
|
11022
11064
|
path: exports_external.string().describe("File path (relative or absolute)"),
|
|
11023
11065
|
paths: exports_external.array(exports_external.string()).optional().describe("Multiple file paths to add at once"),
|
|
@@ -11026,14 +11068,41 @@ if (shouldRegisterTool("add_task_file")) {
|
|
|
11026
11068
|
note: exports_external.string().optional().describe("Note about why this file is linked")
|
|
11027
11069
|
}, async ({ task_id, path, paths: multiplePaths, status, agent_id, note }) => {
|
|
11028
11070
|
try {
|
|
11029
|
-
const { addTaskFile: addTaskFile2, bulkAddTaskFiles: bulkAddTaskFiles2 } = (init_task_files(), __toCommonJS(exports_task_files));
|
|
11071
|
+
const { addTaskFile: addTaskFile2, bulkAddTaskFiles: bulkAddTaskFiles2, detectFileConflicts: detectFileConflicts2 } = (init_task_files(), __toCommonJS(exports_task_files));
|
|
11030
11072
|
const resolvedId = resolveId(task_id);
|
|
11073
|
+
let addedFiles;
|
|
11031
11074
|
if (multiplePaths && multiplePaths.length > 0) {
|
|
11032
11075
|
const allPaths = path ? [path, ...multiplePaths] : multiplePaths;
|
|
11033
|
-
|
|
11034
|
-
|
|
11076
|
+
addedFiles = bulkAddTaskFiles2(resolvedId, allPaths, agent_id);
|
|
11077
|
+
const conflicts2 = detectFileConflicts2(resolvedId, allPaths);
|
|
11078
|
+
if (conflicts2.length > 0) {
|
|
11079
|
+
return {
|
|
11080
|
+
content: [{
|
|
11081
|
+
type: "text",
|
|
11082
|
+
text: JSON.stringify({
|
|
11083
|
+
added: addedFiles.length,
|
|
11084
|
+
conflicts: conflicts2,
|
|
11085
|
+
warning: `${conflicts2.length} file(s) already claimed by other in-progress tasks`
|
|
11086
|
+
}, null, 2)
|
|
11087
|
+
}]
|
|
11088
|
+
};
|
|
11089
|
+
}
|
|
11090
|
+
return { content: [{ type: "text", text: `${addedFiles.length} file(s) linked to task ${resolvedId.slice(0, 8)}` }] };
|
|
11035
11091
|
}
|
|
11036
11092
|
const file = addTaskFile2({ task_id: resolvedId, path, status, agent_id, note });
|
|
11093
|
+
const conflicts = detectFileConflicts2(resolvedId, [path]);
|
|
11094
|
+
if (conflicts.length > 0) {
|
|
11095
|
+
return {
|
|
11096
|
+
content: [{
|
|
11097
|
+
type: "text",
|
|
11098
|
+
text: JSON.stringify({
|
|
11099
|
+
file,
|
|
11100
|
+
conflicts,
|
|
11101
|
+
warning: `${path} is already claimed by another in-progress task`
|
|
11102
|
+
}, null, 2)
|
|
11103
|
+
}]
|
|
11104
|
+
};
|
|
11105
|
+
}
|
|
11037
11106
|
return { content: [{ type: "text", text: `${file.status} ${file.path} \u2192 task ${resolvedId.slice(0, 8)}` }] };
|
|
11038
11107
|
} catch (e) {
|
|
11039
11108
|
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|