@hasna/todos 0.9.80 → 0.9.81

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 CHANGED
@@ -2776,6 +2776,22 @@ var init_database = __esm(() => {
2776
2776
  CREATE INDEX IF NOT EXISTS idx_resource_locks_type_id ON resource_locks(resource_type, resource_id);
2777
2777
  CREATE INDEX IF NOT EXISTS idx_resource_locks_agent ON resource_locks(agent_id);
2778
2778
  INSERT OR IGNORE INTO _migrations (id) VALUES (24);
2779
+ `,
2780
+ `
2781
+ CREATE TABLE IF NOT EXISTS task_files (
2782
+ id TEXT PRIMARY KEY,
2783
+ task_id TEXT NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
2784
+ path TEXT NOT NULL,
2785
+ status TEXT NOT NULL DEFAULT 'active',
2786
+ agent_id TEXT,
2787
+ note TEXT,
2788
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
2789
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
2790
+ );
2791
+ CREATE INDEX IF NOT EXISTS idx_task_files_task ON task_files(task_id);
2792
+ CREATE INDEX IF NOT EXISTS idx_task_files_path ON task_files(path);
2793
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_task_files_task_path ON task_files(task_id, path);
2794
+ INSERT OR IGNORE INTO _migrations (id) VALUES (25);
2779
2795
  `
2780
2796
  ];
2781
2797
  });
@@ -9585,6 +9601,69 @@ var init_zod = __esm(() => {
9585
9601
  init_external();
9586
9602
  });
9587
9603
 
9604
+ // src/db/task-files.ts
9605
+ var exports_task_files = {};
9606
+ __export(exports_task_files, {
9607
+ updateTaskFileStatus: () => updateTaskFileStatus,
9608
+ removeTaskFile: () => removeTaskFile,
9609
+ listTaskFiles: () => listTaskFiles,
9610
+ getTaskFile: () => getTaskFile,
9611
+ findTasksByFile: () => findTasksByFile,
9612
+ bulkAddTaskFiles: () => bulkAddTaskFiles,
9613
+ addTaskFile: () => addTaskFile
9614
+ });
9615
+ function addTaskFile(input, db) {
9616
+ const d = db || getDatabase();
9617
+ const id = uuid();
9618
+ const timestamp = now();
9619
+ const existing = d.query("SELECT id FROM task_files WHERE task_id = ? AND path = ?").get(input.task_id, input.path);
9620
+ if (existing) {
9621
+ d.run("UPDATE task_files SET status = ?, agent_id = ?, note = ?, updated_at = ? WHERE id = ?", [input.status || "active", input.agent_id || null, input.note || null, timestamp, existing.id]);
9622
+ return getTaskFile(existing.id, d);
9623
+ }
9624
+ d.run(`INSERT INTO task_files (id, task_id, path, status, agent_id, note, created_at, updated_at)
9625
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, [id, input.task_id, input.path, input.status || "active", input.agent_id || null, input.note || null, timestamp, timestamp]);
9626
+ return getTaskFile(id, d);
9627
+ }
9628
+ function getTaskFile(id, db) {
9629
+ const d = db || getDatabase();
9630
+ return d.query("SELECT * FROM task_files WHERE id = ?").get(id);
9631
+ }
9632
+ function listTaskFiles(taskId, db) {
9633
+ const d = db || getDatabase();
9634
+ return d.query("SELECT * FROM task_files WHERE task_id = ? ORDER BY path").all(taskId);
9635
+ }
9636
+ function findTasksByFile(path, db) {
9637
+ const d = db || getDatabase();
9638
+ return d.query("SELECT * FROM task_files WHERE path = ? AND status != 'removed' ORDER BY updated_at DESC").all(path);
9639
+ }
9640
+ function updateTaskFileStatus(taskId, path, status, agentId, db) {
9641
+ const d = db || getDatabase();
9642
+ const timestamp = now();
9643
+ d.run("UPDATE task_files SET status = ?, agent_id = COALESCE(?, agent_id), updated_at = ? WHERE task_id = ? AND path = ?", [status, agentId || null, timestamp, taskId, path]);
9644
+ const row = d.query("SELECT * FROM task_files WHERE task_id = ? AND path = ?").get(taskId, path);
9645
+ return row;
9646
+ }
9647
+ function removeTaskFile(taskId, path, db) {
9648
+ const d = db || getDatabase();
9649
+ const result = d.run("DELETE FROM task_files WHERE task_id = ? AND path = ?", [taskId, path]);
9650
+ return result.changes > 0;
9651
+ }
9652
+ function bulkAddTaskFiles(taskId, paths, agentId, db) {
9653
+ const d = db || getDatabase();
9654
+ const results = [];
9655
+ const tx = d.transaction(() => {
9656
+ for (const path of paths) {
9657
+ results.push(addTaskFile({ task_id: taskId, path, agent_id: agentId }, d));
9658
+ }
9659
+ });
9660
+ tx();
9661
+ return results;
9662
+ }
9663
+ var init_task_files = __esm(() => {
9664
+ init_database();
9665
+ });
9666
+
9588
9667
  // src/db/handoffs.ts
9589
9668
  var exports_handoffs = {};
9590
9669
  __export(exports_handoffs, {
@@ -12187,6 +12266,63 @@ Claimed: ${formatTask(result.claimed)}`);
12187
12266
  const agents = listAgents();
12188
12267
  return { contents: [{ uri: "todos://agents", text: JSON.stringify(agents, null, 2), mimeType: "application/json" }] };
12189
12268
  });
12269
+ if (shouldRegisterTool("add_task_file")) {
12270
+ 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.", {
12271
+ task_id: exports_external.string().describe("Task ID"),
12272
+ path: exports_external.string().describe("File path (relative or absolute)"),
12273
+ paths: exports_external.array(exports_external.string()).optional().describe("Multiple file paths to add at once"),
12274
+ status: exports_external.enum(["planned", "active", "modified", "reviewed", "removed"]).optional().describe("File status (default: active)"),
12275
+ agent_id: exports_external.string().optional().describe("Agent working on this file"),
12276
+ note: exports_external.string().optional().describe("Note about why this file is linked")
12277
+ }, async ({ task_id, path, paths: multiplePaths, status, agent_id, note }) => {
12278
+ try {
12279
+ const { addTaskFile: addTaskFile2, bulkAddTaskFiles: bulkAddTaskFiles2 } = (init_task_files(), __toCommonJS(exports_task_files));
12280
+ const resolvedId = resolveId(task_id);
12281
+ if (multiplePaths && multiplePaths.length > 0) {
12282
+ const allPaths = path ? [path, ...multiplePaths] : multiplePaths;
12283
+ const files = bulkAddTaskFiles2(resolvedId, allPaths, agent_id);
12284
+ return { content: [{ type: "text", text: `${files.length} file(s) linked to task ${resolvedId.slice(0, 8)}` }] };
12285
+ }
12286
+ const file = addTaskFile2({ task_id: resolvedId, path, status, agent_id, note });
12287
+ return { content: [{ type: "text", text: `${file.status} ${file.path} \u2192 task ${resolvedId.slice(0, 8)}` }] };
12288
+ } catch (e) {
12289
+ return { content: [{ type: "text", text: formatError(e) }], isError: true };
12290
+ }
12291
+ });
12292
+ }
12293
+ if (shouldRegisterTool("list_task_files")) {
12294
+ server.tool("list_task_files", "List all files linked to a task.", { task_id: exports_external.string().describe("Task ID") }, async ({ task_id }) => {
12295
+ try {
12296
+ const { listTaskFiles: listTaskFiles2 } = (init_task_files(), __toCommonJS(exports_task_files));
12297
+ const resolvedId = resolveId(task_id);
12298
+ const files = listTaskFiles2(resolvedId);
12299
+ if (files.length === 0)
12300
+ return { content: [{ type: "text", text: "No files linked." }] };
12301
+ const lines = files.map((f) => `[${f.status}] ${f.path}${f.agent_id ? ` (${f.agent_id})` : ""}${f.note ? ` \u2014 ${f.note}` : ""}`);
12302
+ return { content: [{ type: "text", text: `${files.length} file(s):
12303
+ ${lines.join(`
12304
+ `)}` }] };
12305
+ } catch (e) {
12306
+ return { content: [{ type: "text", text: formatError(e) }], isError: true };
12307
+ }
12308
+ });
12309
+ }
12310
+ if (shouldRegisterTool("find_tasks_by_file")) {
12311
+ server.tool("find_tasks_by_file", "Find which tasks are linked to a specific file path. Shows who's working on what files.", { path: exports_external.string().describe("File path to search for") }, async ({ path }) => {
12312
+ try {
12313
+ const { findTasksByFile: findTasksByFile2 } = (init_task_files(), __toCommonJS(exports_task_files));
12314
+ const files = findTasksByFile2(path);
12315
+ if (files.length === 0)
12316
+ return { content: [{ type: "text", text: `No tasks linked to ${path}` }] };
12317
+ const lines = files.map((f) => `${f.task_id.slice(0, 8)} [${f.status}]${f.agent_id ? ` (${f.agent_id})` : ""}`);
12318
+ return { content: [{ type: "text", text: `${files.length} task(s) linked to ${path}:
12319
+ ${lines.join(`
12320
+ `)}` }] };
12321
+ } catch (e) {
12322
+ return { content: [{ type: "text", text: formatError(e) }], isError: true };
12323
+ }
12324
+ });
12325
+ }
12190
12326
  if (shouldRegisterTool("create_handoff")) {
12191
12327
  server.tool("create_handoff", "Create a session handoff note for agent coordination.", {
12192
12328
  agent_id: exports_external.string().optional().describe("Agent creating the handoff"),
@@ -1 +1 @@
1
- {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/db/database.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAItC,eAAO,MAAM,mBAAmB,KAAK,CAAC;AAuctC,wBAAgB,WAAW,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,QAAQ,CAkBrD;AAgPD,wBAAgB,aAAa,IAAI,IAAI,CAKpC;AAED,wBAAgB,aAAa,IAAI,IAAI,CAEpC;AAED,wBAAgB,GAAG,IAAI,MAAM,CAE5B;AAED,wBAAgB,IAAI,IAAI,MAAM,CAE7B;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAK9D;AAED,wBAAgB,gBAAgB,CAAC,KAAK,SAAa,GAAG,MAAM,CAG3D;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,CAGpD;AAED,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA0B9F"}
1
+ {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/db/database.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAItC,eAAO,MAAM,mBAAmB,KAAK,CAAC;AAwdtC,wBAAgB,WAAW,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,QAAQ,CAkBrD;AAgPD,wBAAgB,aAAa,IAAI,IAAI,CAKpC;AAED,wBAAgB,aAAa,IAAI,IAAI,CAEpC;AAED,wBAAgB,GAAG,IAAI,MAAM,CAE5B;AAED,wBAAgB,IAAI,IAAI,MAAM,CAE7B;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAK9D;AAED,wBAAgB,gBAAgB,CAAC,KAAK,SAAa,GAAG,MAAM,CAG3D;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,CAGpD;AAED,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA0B9F"}
@@ -0,0 +1,26 @@
1
+ import type { Database } from "bun:sqlite";
2
+ export interface TaskFile {
3
+ id: string;
4
+ task_id: string;
5
+ path: string;
6
+ status: "planned" | "active" | "modified" | "reviewed" | "removed";
7
+ agent_id: string | null;
8
+ note: string | null;
9
+ created_at: string;
10
+ updated_at: string;
11
+ }
12
+ export interface AddTaskFileInput {
13
+ task_id: string;
14
+ path: string;
15
+ status?: TaskFile["status"];
16
+ agent_id?: string;
17
+ note?: string;
18
+ }
19
+ export declare function addTaskFile(input: AddTaskFileInput, db?: Database): TaskFile;
20
+ export declare function getTaskFile(id: string, db?: Database): TaskFile | null;
21
+ export declare function listTaskFiles(taskId: string, db?: Database): TaskFile[];
22
+ export declare function findTasksByFile(path: string, db?: Database): TaskFile[];
23
+ export declare function updateTaskFileStatus(taskId: string, path: string, status: TaskFile["status"], agentId?: string, db?: Database): TaskFile | null;
24
+ export declare function removeTaskFile(taskId: string, path: string, db?: Database): boolean;
25
+ export declare function bulkAddTaskFiles(taskId: string, paths: string[], agentId?: string, db?: Database): TaskFile[];
26
+ //# sourceMappingURL=task-files.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-files.d.ts","sourceRoot":"","sources":["../../src/db/task-files.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAG3C,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,GAAG,QAAQ,GAAG,UAAU,GAAG,UAAU,GAAG,SAAS,CAAC;IACnE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAwB5E;AAED,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,IAAI,CAGtE;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,QAAQ,EAAE,CAKvE;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,QAAQ,EAAE,CAKvE;AAED,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,QAAQ,CAAC,QAAQ,CAAC,EAC1B,OAAO,CAAC,EAAE,MAAM,EAChB,EAAE,CAAC,EAAE,QAAQ,GACZ,QAAQ,GAAG,IAAI,CAWjB;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,CAOnF;AAED,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EAAE,EACf,OAAO,CAAC,EAAE,MAAM,EAChB,EAAE,CAAC,EAAE,QAAQ,GACZ,QAAQ,EAAE,CAUZ"}
package/dist/index.d.ts CHANGED
@@ -16,6 +16,8 @@ export { createTemplate, getTemplate, listTemplates, deleteTemplate, taskFromTem
16
16
  export { getChecklist, addChecklistItem, checkChecklistItem, updateChecklistItemText, removeChecklistItem, clearChecklist, getChecklistStats, } from "./db/checklists.js";
17
17
  export { createHandoff, listHandoffs, getLatestHandoff } from "./db/handoffs.js";
18
18
  export type { Handoff, CreateHandoffInput } from "./db/handoffs.js";
19
+ export { addTaskFile, getTaskFile, listTaskFiles, findTasksByFile, updateTaskFileStatus, removeTaskFile, bulkAddTaskFiles } from "./db/task-files.js";
20
+ export type { TaskFile, AddTaskFileInput } from "./db/task-files.js";
19
21
  export { acquireLock, releaseLock, checkLock, cleanExpiredLocks } from "./db/locks.js";
20
22
  export type { ResourceLock } from "./db/locks.js";
21
23
  export { createOrg, getOrg, getOrgByName, listOrgs, updateOrg, deleteOrg } from "./db/orgs.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -637,6 +637,22 @@ var MIGRATIONS = [
637
637
  CREATE INDEX IF NOT EXISTS idx_resource_locks_type_id ON resource_locks(resource_type, resource_id);
638
638
  CREATE INDEX IF NOT EXISTS idx_resource_locks_agent ON resource_locks(agent_id);
639
639
  INSERT OR IGNORE INTO _migrations (id) VALUES (24);
640
+ `,
641
+ `
642
+ CREATE TABLE IF NOT EXISTS task_files (
643
+ id TEXT PRIMARY KEY,
644
+ task_id TEXT NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
645
+ path TEXT NOT NULL,
646
+ status TEXT NOT NULL DEFAULT 'active',
647
+ agent_id TEXT,
648
+ note TEXT,
649
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
650
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
651
+ );
652
+ CREATE INDEX IF NOT EXISTS idx_task_files_task ON task_files(task_id);
653
+ CREATE INDEX IF NOT EXISTS idx_task_files_path ON task_files(path);
654
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_task_files_task_path ON task_files(task_id, path);
655
+ INSERT OR IGNORE INTO _migrations (id) VALUES (25);
640
656
  `
641
657
  ];
642
658
  var _db = null;
@@ -3075,6 +3091,55 @@ function getLatestHandoff(agentId, projectId, db) {
3075
3091
  const row = d.query(query).get(...params);
3076
3092
  return row ? rowToHandoff(row) : null;
3077
3093
  }
3094
+ // src/db/task-files.ts
3095
+ function addTaskFile(input, db) {
3096
+ const d = db || getDatabase();
3097
+ const id = uuid();
3098
+ const timestamp = now();
3099
+ const existing = d.query("SELECT id FROM task_files WHERE task_id = ? AND path = ?").get(input.task_id, input.path);
3100
+ if (existing) {
3101
+ d.run("UPDATE task_files SET status = ?, agent_id = ?, note = ?, updated_at = ? WHERE id = ?", [input.status || "active", input.agent_id || null, input.note || null, timestamp, existing.id]);
3102
+ return getTaskFile(existing.id, d);
3103
+ }
3104
+ d.run(`INSERT INTO task_files (id, task_id, path, status, agent_id, note, created_at, updated_at)
3105
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, [id, input.task_id, input.path, input.status || "active", input.agent_id || null, input.note || null, timestamp, timestamp]);
3106
+ return getTaskFile(id, d);
3107
+ }
3108
+ function getTaskFile(id, db) {
3109
+ const d = db || getDatabase();
3110
+ return d.query("SELECT * FROM task_files WHERE id = ?").get(id);
3111
+ }
3112
+ function listTaskFiles(taskId, db) {
3113
+ const d = db || getDatabase();
3114
+ return d.query("SELECT * FROM task_files WHERE task_id = ? ORDER BY path").all(taskId);
3115
+ }
3116
+ function findTasksByFile(path, db) {
3117
+ const d = db || getDatabase();
3118
+ return d.query("SELECT * FROM task_files WHERE path = ? AND status != 'removed' ORDER BY updated_at DESC").all(path);
3119
+ }
3120
+ function updateTaskFileStatus(taskId, path, status, agentId, db) {
3121
+ const d = db || getDatabase();
3122
+ const timestamp = now();
3123
+ d.run("UPDATE task_files SET status = ?, agent_id = COALESCE(?, agent_id), updated_at = ? WHERE task_id = ? AND path = ?", [status, agentId || null, timestamp, taskId, path]);
3124
+ const row = d.query("SELECT * FROM task_files WHERE task_id = ? AND path = ?").get(taskId, path);
3125
+ return row;
3126
+ }
3127
+ function removeTaskFile(taskId, path, db) {
3128
+ const d = db || getDatabase();
3129
+ const result = d.run("DELETE FROM task_files WHERE task_id = ? AND path = ?", [taskId, path]);
3130
+ return result.changes > 0;
3131
+ }
3132
+ function bulkAddTaskFiles(taskId, paths, agentId, db) {
3133
+ const d = db || getDatabase();
3134
+ const results = [];
3135
+ const tx = d.transaction(() => {
3136
+ for (const path of paths) {
3137
+ results.push(addTaskFile({ task_id: taskId, path, agent_id: agentId }, d));
3138
+ }
3139
+ });
3140
+ tx();
3141
+ return results;
3142
+ }
3078
3143
  // src/db/locks.ts
3079
3144
  function acquireLock(resourceType, resourceId, agentId, lockType = "advisory", expiryMs = 5 * 60 * 1000, db) {
3080
3145
  const d = db || getDatabase();
@@ -3785,6 +3850,7 @@ function syncWithAgents(agents, taskListIdByAgent, projectId, direction = "both"
3785
3850
  export {
3786
3851
  uuid,
3787
3852
  updateTaskList,
3853
+ updateTaskFileStatus,
3788
3854
  updateTask,
3789
3855
  updateSessionActivity,
3790
3856
  updateProject,
@@ -3804,6 +3870,7 @@ export {
3804
3870
  searchTasks,
3805
3871
  resolvePartialId,
3806
3872
  resetDatabase,
3873
+ removeTaskFile,
3807
3874
  removeProjectSource,
3808
3875
  removeDependency,
3809
3876
  removeChecklistItem,
@@ -3823,6 +3890,7 @@ export {
3823
3890
  listTemplates,
3824
3891
  listTasks,
3825
3892
  listTaskLists,
3893
+ listTaskFiles,
3826
3894
  listSessions,
3827
3895
  listProjects,
3828
3896
  listProjectSources,
@@ -3842,6 +3910,7 @@ export {
3842
3910
  getTaskList,
3843
3911
  getTaskHistory,
3844
3912
  getTaskGraph,
3913
+ getTaskFile,
3845
3914
  getTaskDependents,
3846
3915
  getTaskDependencies,
3847
3916
  getTask,
@@ -3869,6 +3938,7 @@ export {
3869
3938
  getAgentByName,
3870
3939
  getAgent,
3871
3940
  getActiveWork,
3941
+ findTasksByFile,
3872
3942
  failTask,
3873
3943
  ensureTaskList,
3874
3944
  ensureProject,
@@ -3907,6 +3977,8 @@ export {
3907
3977
  checkChecklistItem,
3908
3978
  bulkUpdateTasks,
3909
3979
  bulkCreateTasks,
3980
+ bulkAddTaskFiles,
3981
+ addTaskFile,
3910
3982
  addProjectSource,
3911
3983
  addDependency,
3912
3984
  addComment,
package/dist/mcp/index.js CHANGED
@@ -705,6 +705,22 @@ var init_database = __esm(() => {
705
705
  CREATE INDEX IF NOT EXISTS idx_resource_locks_type_id ON resource_locks(resource_type, resource_id);
706
706
  CREATE INDEX IF NOT EXISTS idx_resource_locks_agent ON resource_locks(agent_id);
707
707
  INSERT OR IGNORE INTO _migrations (id) VALUES (24);
708
+ `,
709
+ `
710
+ CREATE TABLE IF NOT EXISTS task_files (
711
+ id TEXT PRIMARY KEY,
712
+ task_id TEXT NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
713
+ path TEXT NOT NULL,
714
+ status TEXT NOT NULL DEFAULT 'active',
715
+ agent_id TEXT,
716
+ note TEXT,
717
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
718
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
719
+ );
720
+ CREATE INDEX IF NOT EXISTS idx_task_files_task ON task_files(task_id);
721
+ CREATE INDEX IF NOT EXISTS idx_task_files_path ON task_files(path);
722
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_task_files_task_path ON task_files(task_id, path);
723
+ INSERT OR IGNORE INTO _migrations (id) VALUES (25);
708
724
  `
709
725
  ];
710
726
  });
@@ -1036,6 +1052,69 @@ var init_agents = __esm(() => {
1036
1052
  AGENT_ACTIVE_WINDOW_MS = 30 * 60 * 1000;
1037
1053
  });
1038
1054
 
1055
+ // src/db/task-files.ts
1056
+ var exports_task_files = {};
1057
+ __export(exports_task_files, {
1058
+ updateTaskFileStatus: () => updateTaskFileStatus,
1059
+ removeTaskFile: () => removeTaskFile,
1060
+ listTaskFiles: () => listTaskFiles,
1061
+ getTaskFile: () => getTaskFile,
1062
+ findTasksByFile: () => findTasksByFile,
1063
+ bulkAddTaskFiles: () => bulkAddTaskFiles,
1064
+ addTaskFile: () => addTaskFile
1065
+ });
1066
+ function addTaskFile(input, db) {
1067
+ const d = db || getDatabase();
1068
+ const id = uuid();
1069
+ const timestamp = now();
1070
+ const existing = d.query("SELECT id FROM task_files WHERE task_id = ? AND path = ?").get(input.task_id, input.path);
1071
+ if (existing) {
1072
+ d.run("UPDATE task_files SET status = ?, agent_id = ?, note = ?, updated_at = ? WHERE id = ?", [input.status || "active", input.agent_id || null, input.note || null, timestamp, existing.id]);
1073
+ return getTaskFile(existing.id, d);
1074
+ }
1075
+ d.run(`INSERT INTO task_files (id, task_id, path, status, agent_id, note, created_at, updated_at)
1076
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, [id, input.task_id, input.path, input.status || "active", input.agent_id || null, input.note || null, timestamp, timestamp]);
1077
+ return getTaskFile(id, d);
1078
+ }
1079
+ function getTaskFile(id, db) {
1080
+ const d = db || getDatabase();
1081
+ return d.query("SELECT * FROM task_files WHERE id = ?").get(id);
1082
+ }
1083
+ function listTaskFiles(taskId, db) {
1084
+ const d = db || getDatabase();
1085
+ return d.query("SELECT * FROM task_files WHERE task_id = ? ORDER BY path").all(taskId);
1086
+ }
1087
+ function findTasksByFile(path, db) {
1088
+ const d = db || getDatabase();
1089
+ return d.query("SELECT * FROM task_files WHERE path = ? AND status != 'removed' ORDER BY updated_at DESC").all(path);
1090
+ }
1091
+ function updateTaskFileStatus(taskId, path, status, agentId, db) {
1092
+ const d = db || getDatabase();
1093
+ const timestamp = now();
1094
+ d.run("UPDATE task_files SET status = ?, agent_id = COALESCE(?, agent_id), updated_at = ? WHERE task_id = ? AND path = ?", [status, agentId || null, timestamp, taskId, path]);
1095
+ const row = d.query("SELECT * FROM task_files WHERE task_id = ? AND path = ?").get(taskId, path);
1096
+ return row;
1097
+ }
1098
+ function removeTaskFile(taskId, path, db) {
1099
+ const d = db || getDatabase();
1100
+ const result = d.run("DELETE FROM task_files WHERE task_id = ? AND path = ?", [taskId, path]);
1101
+ return result.changes > 0;
1102
+ }
1103
+ function bulkAddTaskFiles(taskId, paths, agentId, db) {
1104
+ const d = db || getDatabase();
1105
+ const results = [];
1106
+ const tx = d.transaction(() => {
1107
+ for (const path of paths) {
1108
+ results.push(addTaskFile({ task_id: taskId, path, agent_id: agentId }, d));
1109
+ }
1110
+ });
1111
+ tx();
1112
+ return results;
1113
+ }
1114
+ var init_task_files = __esm(() => {
1115
+ init_database();
1116
+ });
1117
+
1039
1118
  // src/db/handoffs.ts
1040
1119
  var exports_handoffs = {};
1041
1120
  __export(exports_handoffs, {
@@ -9901,6 +9980,63 @@ server.resource("agents", "todos://agents", { description: "All registered agent
9901
9980
  const agents = listAgents();
9902
9981
  return { contents: [{ uri: "todos://agents", text: JSON.stringify(agents, null, 2), mimeType: "application/json" }] };
9903
9982
  });
9983
+ if (shouldRegisterTool("add_task_file")) {
9984
+ 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.", {
9985
+ task_id: exports_external.string().describe("Task ID"),
9986
+ path: exports_external.string().describe("File path (relative or absolute)"),
9987
+ paths: exports_external.array(exports_external.string()).optional().describe("Multiple file paths to add at once"),
9988
+ status: exports_external.enum(["planned", "active", "modified", "reviewed", "removed"]).optional().describe("File status (default: active)"),
9989
+ agent_id: exports_external.string().optional().describe("Agent working on this file"),
9990
+ note: exports_external.string().optional().describe("Note about why this file is linked")
9991
+ }, async ({ task_id, path, paths: multiplePaths, status, agent_id, note }) => {
9992
+ try {
9993
+ const { addTaskFile: addTaskFile2, bulkAddTaskFiles: bulkAddTaskFiles2 } = (init_task_files(), __toCommonJS(exports_task_files));
9994
+ const resolvedId = resolveId(task_id);
9995
+ if (multiplePaths && multiplePaths.length > 0) {
9996
+ const allPaths = path ? [path, ...multiplePaths] : multiplePaths;
9997
+ const files = bulkAddTaskFiles2(resolvedId, allPaths, agent_id);
9998
+ return { content: [{ type: "text", text: `${files.length} file(s) linked to task ${resolvedId.slice(0, 8)}` }] };
9999
+ }
10000
+ const file = addTaskFile2({ task_id: resolvedId, path, status, agent_id, note });
10001
+ return { content: [{ type: "text", text: `${file.status} ${file.path} \u2192 task ${resolvedId.slice(0, 8)}` }] };
10002
+ } catch (e) {
10003
+ return { content: [{ type: "text", text: formatError(e) }], isError: true };
10004
+ }
10005
+ });
10006
+ }
10007
+ if (shouldRegisterTool("list_task_files")) {
10008
+ server.tool("list_task_files", "List all files linked to a task.", { task_id: exports_external.string().describe("Task ID") }, async ({ task_id }) => {
10009
+ try {
10010
+ const { listTaskFiles: listTaskFiles2 } = (init_task_files(), __toCommonJS(exports_task_files));
10011
+ const resolvedId = resolveId(task_id);
10012
+ const files = listTaskFiles2(resolvedId);
10013
+ if (files.length === 0)
10014
+ return { content: [{ type: "text", text: "No files linked." }] };
10015
+ const lines = files.map((f) => `[${f.status}] ${f.path}${f.agent_id ? ` (${f.agent_id})` : ""}${f.note ? ` \u2014 ${f.note}` : ""}`);
10016
+ return { content: [{ type: "text", text: `${files.length} file(s):
10017
+ ${lines.join(`
10018
+ `)}` }] };
10019
+ } catch (e) {
10020
+ return { content: [{ type: "text", text: formatError(e) }], isError: true };
10021
+ }
10022
+ });
10023
+ }
10024
+ if (shouldRegisterTool("find_tasks_by_file")) {
10025
+ server.tool("find_tasks_by_file", "Find which tasks are linked to a specific file path. Shows who's working on what files.", { path: exports_external.string().describe("File path to search for") }, async ({ path }) => {
10026
+ try {
10027
+ const { findTasksByFile: findTasksByFile2 } = (init_task_files(), __toCommonJS(exports_task_files));
10028
+ const files = findTasksByFile2(path);
10029
+ if (files.length === 0)
10030
+ return { content: [{ type: "text", text: `No tasks linked to ${path}` }] };
10031
+ const lines = files.map((f) => `${f.task_id.slice(0, 8)} [${f.status}]${f.agent_id ? ` (${f.agent_id})` : ""}`);
10032
+ return { content: [{ type: "text", text: `${files.length} task(s) linked to ${path}:
10033
+ ${lines.join(`
10034
+ `)}` }] };
10035
+ } catch (e) {
10036
+ return { content: [{ type: "text", text: formatError(e) }], isError: true };
10037
+ }
10038
+ });
10039
+ }
9904
10040
  if (shouldRegisterTool("create_handoff")) {
9905
10041
  server.tool("create_handoff", "Create a session handoff note for agent coordination.", {
9906
10042
  agent_id: exports_external.string().optional().describe("Agent creating the handoff"),
@@ -769,6 +769,22 @@ var init_database = __esm(() => {
769
769
  CREATE INDEX IF NOT EXISTS idx_resource_locks_type_id ON resource_locks(resource_type, resource_id);
770
770
  CREATE INDEX IF NOT EXISTS idx_resource_locks_agent ON resource_locks(agent_id);
771
771
  INSERT OR IGNORE INTO _migrations (id) VALUES (24);
772
+ `,
773
+ `
774
+ CREATE TABLE IF NOT EXISTS task_files (
775
+ id TEXT PRIMARY KEY,
776
+ task_id TEXT NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
777
+ path TEXT NOT NULL,
778
+ status TEXT NOT NULL DEFAULT 'active',
779
+ agent_id TEXT,
780
+ note TEXT,
781
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
782
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
783
+ );
784
+ CREATE INDEX IF NOT EXISTS idx_task_files_task ON task_files(task_id);
785
+ CREATE INDEX IF NOT EXISTS idx_task_files_path ON task_files(path);
786
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_task_files_task_path ON task_files(task_id, path);
787
+ INSERT OR IGNORE INTO _migrations (id) VALUES (25);
772
788
  `
773
789
  ];
774
790
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/todos",
3
- "version": "0.9.80",
3
+ "version": "0.9.81",
4
4
  "description": "Universal task management for AI coding agents - CLI + MCP server + interactive TUI",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",