@hasna/todos 0.9.79 → 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 +209 -1
- package/dist/db/database.d.ts.map +1 -1
- package/dist/db/task-files.d.ts +26 -0
- package/dist/db/task-files.d.ts.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +72 -0
- package/dist/mcp/index.d.ts +1 -1
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +208 -0
- package/dist/server/index.js +16 -0
- package/package.json +1 -1
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, {
|
|
@@ -9658,6 +9737,9 @@ var init_handoffs = __esm(() => {
|
|
|
9658
9737
|
|
|
9659
9738
|
// src/mcp/index.ts
|
|
9660
9739
|
var exports_mcp = {};
|
|
9740
|
+
__export(exports_mcp, {
|
|
9741
|
+
applyFocus: () => applyFocus
|
|
9742
|
+
});
|
|
9661
9743
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
9662
9744
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
9663
9745
|
import { readFileSync as readFileSync3 } from "fs";
|
|
@@ -9679,6 +9761,28 @@ function shouldRegisterTool(name) {
|
|
|
9679
9761
|
return !STANDARD_EXCLUDED.has(name);
|
|
9680
9762
|
return true;
|
|
9681
9763
|
}
|
|
9764
|
+
function getAgentFocus(agentId) {
|
|
9765
|
+
const sessionFocus = agentFocusMap.get(agentId);
|
|
9766
|
+
if (sessionFocus)
|
|
9767
|
+
return sessionFocus;
|
|
9768
|
+
try {
|
|
9769
|
+
const agent = getAgentByName(agentId) || getAgent(agentId);
|
|
9770
|
+
if (agent && agent.active_project_id) {
|
|
9771
|
+
return { agent_id: agentId, project_id: agent.active_project_id };
|
|
9772
|
+
}
|
|
9773
|
+
} catch {}
|
|
9774
|
+
return;
|
|
9775
|
+
}
|
|
9776
|
+
function applyFocus(params, agentId) {
|
|
9777
|
+
if (!agentId)
|
|
9778
|
+
return;
|
|
9779
|
+
if (params.project_id)
|
|
9780
|
+
return;
|
|
9781
|
+
const focus = getAgentFocus(agentId);
|
|
9782
|
+
if (focus?.project_id) {
|
|
9783
|
+
params.project_id = focus.project_id;
|
|
9784
|
+
}
|
|
9785
|
+
}
|
|
9682
9786
|
function formatError(error) {
|
|
9683
9787
|
if (error instanceof VersionConflictError) {
|
|
9684
9788
|
return JSON.stringify({ code: VersionConflictError.code, message: error.message, suggestion: VersionConflictError.suggestion });
|
|
@@ -9777,7 +9881,7 @@ async function main() {
|
|
|
9777
9881
|
const transport = new StdioServerTransport;
|
|
9778
9882
|
await server.connect(transport);
|
|
9779
9883
|
}
|
|
9780
|
-
var server, TODOS_PROFILE, MINIMAL_TOOLS, STANDARD_EXCLUDED;
|
|
9884
|
+
var server, TODOS_PROFILE, MINIMAL_TOOLS, STANDARD_EXCLUDED, agentFocusMap;
|
|
9781
9885
|
var init_mcp = __esm(() => {
|
|
9782
9886
|
init_zod();
|
|
9783
9887
|
init_tasks();
|
|
@@ -9824,6 +9928,7 @@ var init_mcp = __esm(() => {
|
|
|
9824
9928
|
"delete_template",
|
|
9825
9929
|
"approve_task"
|
|
9826
9930
|
]);
|
|
9931
|
+
agentFocusMap = new Map;
|
|
9827
9932
|
if (shouldRegisterTool("create_task")) {
|
|
9828
9933
|
server.tool("create_task", "Create a new task", {
|
|
9829
9934
|
title: exports_external.string(),
|
|
@@ -10602,6 +10707,52 @@ ${text}` }] };
|
|
|
10602
10707
|
}
|
|
10603
10708
|
});
|
|
10604
10709
|
}
|
|
10710
|
+
if (shouldRegisterTool("set_focus")) {
|
|
10711
|
+
server.tool("set_focus", "Focus this agent on a project. All list/search/status tools will default to this project.", {
|
|
10712
|
+
agent_id: exports_external.string().describe("Agent ID or name"),
|
|
10713
|
+
project_id: exports_external.string().optional().describe("Project to focus on. Omit to clear."),
|
|
10714
|
+
task_list_id: exports_external.string().optional().describe("Task list to focus on")
|
|
10715
|
+
}, async ({ agent_id, project_id, task_list_id }) => {
|
|
10716
|
+
try {
|
|
10717
|
+
const resolvedProject = project_id ? resolveId(project_id, "projects") : undefined;
|
|
10718
|
+
const focus = { agent_id, project_id: resolvedProject, task_list_id };
|
|
10719
|
+
agentFocusMap.set(agent_id, focus);
|
|
10720
|
+
try {
|
|
10721
|
+
const agent = getAgentByName(agent_id) || getAgent(agent_id);
|
|
10722
|
+
if (agent) {
|
|
10723
|
+
const db = getDatabase();
|
|
10724
|
+
db.run("UPDATE agents SET active_project_id = ? WHERE id = ?", [resolvedProject || null, agent.id]);
|
|
10725
|
+
}
|
|
10726
|
+
} catch {}
|
|
10727
|
+
const projectName = resolvedProject ? ` (${resolvedProject.slice(0, 8)})` : "";
|
|
10728
|
+
return { content: [{ type: "text", text: `Focused on project${projectName}. Read tools will default to this scope. Pass explicit project_id to override.` }] };
|
|
10729
|
+
} catch (e) {
|
|
10730
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
10731
|
+
}
|
|
10732
|
+
});
|
|
10733
|
+
}
|
|
10734
|
+
if (shouldRegisterTool("get_focus")) {
|
|
10735
|
+
server.tool("get_focus", "Get the current focus for an agent.", { agent_id: exports_external.string().describe("Agent ID or name") }, async ({ agent_id }) => {
|
|
10736
|
+
const focus = getAgentFocus(agent_id);
|
|
10737
|
+
if (!focus?.project_id) {
|
|
10738
|
+
return { content: [{ type: "text", text: "No focus set. Showing all projects." }] };
|
|
10739
|
+
}
|
|
10740
|
+
return { content: [{ type: "text", text: `Focused on project: ${focus.project_id}${focus.task_list_id ? `, task list: ${focus.task_list_id}` : ""}` }] };
|
|
10741
|
+
});
|
|
10742
|
+
}
|
|
10743
|
+
if (shouldRegisterTool("unfocus")) {
|
|
10744
|
+
server.tool("unfocus", "Clear focus \u2014 show all projects and tasks.", { agent_id: exports_external.string().describe("Agent ID or name") }, async ({ agent_id }) => {
|
|
10745
|
+
agentFocusMap.delete(agent_id);
|
|
10746
|
+
try {
|
|
10747
|
+
const agent = getAgentByName(agent_id) || getAgent(agent_id);
|
|
10748
|
+
if (agent) {
|
|
10749
|
+
const db = getDatabase();
|
|
10750
|
+
db.run("UPDATE agents SET active_project_id = NULL WHERE id = ?", [agent.id]);
|
|
10751
|
+
}
|
|
10752
|
+
} catch {}
|
|
10753
|
+
return { content: [{ type: "text", text: "Focus cleared. Showing all projects." }] };
|
|
10754
|
+
});
|
|
10755
|
+
}
|
|
10605
10756
|
if (shouldRegisterTool("register_agent")) {
|
|
10606
10757
|
server.tool("register_agent", "Register an agent. Pass session_id (unique per coding session) to prevent name conflicts. Returns conflict error if name is taken by an active agent in a different session.", {
|
|
10607
10758
|
name: exports_external.string(),
|
|
@@ -12115,6 +12266,63 @@ Claimed: ${formatTask(result.claimed)}`);
|
|
|
12115
12266
|
const agents = listAgents();
|
|
12116
12267
|
return { contents: [{ uri: "todos://agents", text: JSON.stringify(agents, null, 2), mimeType: "application/json" }] };
|
|
12117
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
|
+
}
|
|
12118
12326
|
if (shouldRegisterTool("create_handoff")) {
|
|
12119
12327
|
server.tool("create_handoff", "Create a session handoff note for agent coordination.", {
|
|
12120
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;
|
|
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";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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.d.ts
CHANGED
package/dist/mcp/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":";AA6IA,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAO9E"}
|
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, {
|
|
@@ -7447,6 +7526,29 @@ function shouldRegisterTool(name) {
|
|
|
7447
7526
|
return !STANDARD_EXCLUDED.has(name);
|
|
7448
7527
|
return true;
|
|
7449
7528
|
}
|
|
7529
|
+
var agentFocusMap = new Map;
|
|
7530
|
+
function getAgentFocus(agentId) {
|
|
7531
|
+
const sessionFocus = agentFocusMap.get(agentId);
|
|
7532
|
+
if (sessionFocus)
|
|
7533
|
+
return sessionFocus;
|
|
7534
|
+
try {
|
|
7535
|
+
const agent = getAgentByName(agentId) || getAgent(agentId);
|
|
7536
|
+
if (agent && agent.active_project_id) {
|
|
7537
|
+
return { agent_id: agentId, project_id: agent.active_project_id };
|
|
7538
|
+
}
|
|
7539
|
+
} catch {}
|
|
7540
|
+
return;
|
|
7541
|
+
}
|
|
7542
|
+
function applyFocus(params, agentId) {
|
|
7543
|
+
if (!agentId)
|
|
7544
|
+
return;
|
|
7545
|
+
if (params.project_id)
|
|
7546
|
+
return;
|
|
7547
|
+
const focus = getAgentFocus(agentId);
|
|
7548
|
+
if (focus?.project_id) {
|
|
7549
|
+
params.project_id = focus.project_id;
|
|
7550
|
+
}
|
|
7551
|
+
}
|
|
7450
7552
|
function formatError(error) {
|
|
7451
7553
|
if (error instanceof VersionConflictError) {
|
|
7452
7554
|
return JSON.stringify({ code: VersionConflictError.code, message: error.message, suggestion: VersionConflictError.suggestion });
|
|
@@ -8319,6 +8421,52 @@ if (shouldRegisterTool("sync")) {
|
|
|
8319
8421
|
}
|
|
8320
8422
|
});
|
|
8321
8423
|
}
|
|
8424
|
+
if (shouldRegisterTool("set_focus")) {
|
|
8425
|
+
server.tool("set_focus", "Focus this agent on a project. All list/search/status tools will default to this project.", {
|
|
8426
|
+
agent_id: exports_external.string().describe("Agent ID or name"),
|
|
8427
|
+
project_id: exports_external.string().optional().describe("Project to focus on. Omit to clear."),
|
|
8428
|
+
task_list_id: exports_external.string().optional().describe("Task list to focus on")
|
|
8429
|
+
}, async ({ agent_id, project_id, task_list_id }) => {
|
|
8430
|
+
try {
|
|
8431
|
+
const resolvedProject = project_id ? resolveId(project_id, "projects") : undefined;
|
|
8432
|
+
const focus = { agent_id, project_id: resolvedProject, task_list_id };
|
|
8433
|
+
agentFocusMap.set(agent_id, focus);
|
|
8434
|
+
try {
|
|
8435
|
+
const agent = getAgentByName(agent_id) || getAgent(agent_id);
|
|
8436
|
+
if (agent) {
|
|
8437
|
+
const db = getDatabase();
|
|
8438
|
+
db.run("UPDATE agents SET active_project_id = ? WHERE id = ?", [resolvedProject || null, agent.id]);
|
|
8439
|
+
}
|
|
8440
|
+
} catch {}
|
|
8441
|
+
const projectName = resolvedProject ? ` (${resolvedProject.slice(0, 8)})` : "";
|
|
8442
|
+
return { content: [{ type: "text", text: `Focused on project${projectName}. Read tools will default to this scope. Pass explicit project_id to override.` }] };
|
|
8443
|
+
} catch (e) {
|
|
8444
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
8445
|
+
}
|
|
8446
|
+
});
|
|
8447
|
+
}
|
|
8448
|
+
if (shouldRegisterTool("get_focus")) {
|
|
8449
|
+
server.tool("get_focus", "Get the current focus for an agent.", { agent_id: exports_external.string().describe("Agent ID or name") }, async ({ agent_id }) => {
|
|
8450
|
+
const focus = getAgentFocus(agent_id);
|
|
8451
|
+
if (!focus?.project_id) {
|
|
8452
|
+
return { content: [{ type: "text", text: "No focus set. Showing all projects." }] };
|
|
8453
|
+
}
|
|
8454
|
+
return { content: [{ type: "text", text: `Focused on project: ${focus.project_id}${focus.task_list_id ? `, task list: ${focus.task_list_id}` : ""}` }] };
|
|
8455
|
+
});
|
|
8456
|
+
}
|
|
8457
|
+
if (shouldRegisterTool("unfocus")) {
|
|
8458
|
+
server.tool("unfocus", "Clear focus \u2014 show all projects and tasks.", { agent_id: exports_external.string().describe("Agent ID or name") }, async ({ agent_id }) => {
|
|
8459
|
+
agentFocusMap.delete(agent_id);
|
|
8460
|
+
try {
|
|
8461
|
+
const agent = getAgentByName(agent_id) || getAgent(agent_id);
|
|
8462
|
+
if (agent) {
|
|
8463
|
+
const db = getDatabase();
|
|
8464
|
+
db.run("UPDATE agents SET active_project_id = NULL WHERE id = ?", [agent.id]);
|
|
8465
|
+
}
|
|
8466
|
+
} catch {}
|
|
8467
|
+
return { content: [{ type: "text", text: "Focus cleared. Showing all projects." }] };
|
|
8468
|
+
});
|
|
8469
|
+
}
|
|
8322
8470
|
if (shouldRegisterTool("register_agent")) {
|
|
8323
8471
|
server.tool("register_agent", "Register an agent. Pass session_id (unique per coding session) to prevent name conflicts. Returns conflict error if name is taken by an active agent in a different session.", {
|
|
8324
8472
|
name: exports_external.string(),
|
|
@@ -9832,6 +9980,63 @@ server.resource("agents", "todos://agents", { description: "All registered agent
|
|
|
9832
9980
|
const agents = listAgents();
|
|
9833
9981
|
return { contents: [{ uri: "todos://agents", text: JSON.stringify(agents, null, 2), mimeType: "application/json" }] };
|
|
9834
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
|
+
}
|
|
9835
10040
|
if (shouldRegisterTool("create_handoff")) {
|
|
9836
10041
|
server.tool("create_handoff", "Create a session handoff note for agent coordination.", {
|
|
9837
10042
|
agent_id: exports_external.string().optional().describe("Agent creating the handoff"),
|
|
@@ -9900,3 +10105,6 @@ main().catch((err) => {
|
|
|
9900
10105
|
console.error("MCP server error:", err);
|
|
9901
10106
|
process.exit(1);
|
|
9902
10107
|
});
|
|
10108
|
+
export {
|
|
10109
|
+
applyFocus
|
|
10110
|
+
};
|
package/dist/server/index.js
CHANGED
|
@@ -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
|
});
|