@hasna/todos 0.9.74 → 0.9.76
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 +1021 -2
- package/dist/db/checklists.d.ts +13 -0
- package/dist/db/checklists.d.ts.map +1 -0
- package/dist/db/database.d.ts.map +1 -1
- package/dist/db/handoffs.d.ts +25 -0
- package/dist/db/handoffs.d.ts.map +1 -0
- package/dist/db/projects.d.ts +5 -1
- package/dist/db/projects.d.ts.map +1 -1
- package/dist/db/tasks.d.ts +1 -0
- package/dist/db/tasks.d.ts.map +1 -1
- package/dist/index.d.ts +6 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +255 -1
- package/dist/mcp/index.js +513 -1
- package/dist/server/index.js +146 -17
- package/dist/types/index.d.ts +55 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/mcp/index.js
CHANGED
|
@@ -1,6 +1,23 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
// @bun
|
|
3
3
|
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __moduleCache = /* @__PURE__ */ new WeakMap;
|
|
8
|
+
var __toCommonJS = (from) => {
|
|
9
|
+
var entry = __moduleCache.get(from), desc;
|
|
10
|
+
if (entry)
|
|
11
|
+
return entry;
|
|
12
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function")
|
|
14
|
+
__getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
|
|
15
|
+
get: () => from[key],
|
|
16
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
17
|
+
}));
|
|
18
|
+
__moduleCache.set(from, entry);
|
|
19
|
+
return entry;
|
|
20
|
+
};
|
|
4
21
|
var __export = (target, all) => {
|
|
5
22
|
for (var name in all)
|
|
6
23
|
__defProp(target, name, {
|
|
@@ -181,6 +198,28 @@ function ensureSchema(db) {
|
|
|
181
198
|
metadata TEXT DEFAULT '{}',
|
|
182
199
|
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
183
200
|
)`);
|
|
201
|
+
ensureTable("task_checklists", `
|
|
202
|
+
CREATE TABLE task_checklists (
|
|
203
|
+
id TEXT PRIMARY KEY,
|
|
204
|
+
task_id TEXT NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
|
|
205
|
+
position INTEGER NOT NULL DEFAULT 0,
|
|
206
|
+
text TEXT NOT NULL,
|
|
207
|
+
checked INTEGER NOT NULL DEFAULT 0,
|
|
208
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
209
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
210
|
+
)`);
|
|
211
|
+
ensureTable("project_sources", `
|
|
212
|
+
CREATE TABLE project_sources (
|
|
213
|
+
id TEXT PRIMARY KEY,
|
|
214
|
+
project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
|
215
|
+
type TEXT NOT NULL,
|
|
216
|
+
name TEXT NOT NULL,
|
|
217
|
+
uri TEXT NOT NULL,
|
|
218
|
+
description TEXT,
|
|
219
|
+
metadata TEXT DEFAULT '{}',
|
|
220
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
221
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
222
|
+
)`);
|
|
184
223
|
ensureColumn("projects", "task_list_id", "TEXT");
|
|
185
224
|
ensureColumn("projects", "task_prefix", "TEXT");
|
|
186
225
|
ensureColumn("projects", "task_counter", "INTEGER NOT NULL DEFAULT 0");
|
|
@@ -225,6 +264,9 @@ function ensureSchema(db) {
|
|
|
225
264
|
ensureIndex("CREATE INDEX IF NOT EXISTS idx_task_history_agent ON task_history(agent_id)");
|
|
226
265
|
ensureIndex("CREATE INDEX IF NOT EXISTS idx_tasks_recurrence_parent ON tasks(recurrence_parent_id)");
|
|
227
266
|
ensureIndex("CREATE INDEX IF NOT EXISTS idx_tasks_recurrence_rule ON tasks(recurrence_rule) WHERE recurrence_rule IS NOT NULL");
|
|
267
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_task_checklists_task ON task_checklists(task_id)");
|
|
268
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_project_sources_project ON project_sources(project_id)");
|
|
269
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_project_sources_type ON project_sources(type)");
|
|
228
270
|
}
|
|
229
271
|
function backfillTaskTags(db) {
|
|
230
272
|
try {
|
|
@@ -602,6 +644,49 @@ var init_database = __esm(() => {
|
|
|
602
644
|
ALTER TABLE tasks ADD COLUMN reason TEXT;
|
|
603
645
|
ALTER TABLE tasks ADD COLUMN spawned_from_session TEXT;
|
|
604
646
|
INSERT OR IGNORE INTO _migrations (id) VALUES (19);
|
|
647
|
+
`,
|
|
648
|
+
`
|
|
649
|
+
CREATE TABLE IF NOT EXISTS handoffs (
|
|
650
|
+
id TEXT PRIMARY KEY,
|
|
651
|
+
agent_id TEXT,
|
|
652
|
+
project_id TEXT REFERENCES projects(id) ON DELETE SET NULL,
|
|
653
|
+
summary TEXT NOT NULL,
|
|
654
|
+
completed TEXT,
|
|
655
|
+
in_progress TEXT,
|
|
656
|
+
blockers TEXT,
|
|
657
|
+
next_steps TEXT,
|
|
658
|
+
created_at TEXT NOT NULL
|
|
659
|
+
);
|
|
660
|
+
INSERT OR IGNORE INTO _migrations (id) VALUES (20);
|
|
661
|
+
`,
|
|
662
|
+
`
|
|
663
|
+
CREATE TABLE IF NOT EXISTS task_checklists (
|
|
664
|
+
id TEXT PRIMARY KEY,
|
|
665
|
+
task_id TEXT NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
|
|
666
|
+
position INTEGER NOT NULL DEFAULT 0,
|
|
667
|
+
text TEXT NOT NULL,
|
|
668
|
+
checked INTEGER NOT NULL DEFAULT 0,
|
|
669
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
670
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
671
|
+
);
|
|
672
|
+
CREATE INDEX IF NOT EXISTS idx_task_checklists_task ON task_checklists(task_id);
|
|
673
|
+
INSERT OR IGNORE INTO _migrations (id) VALUES (21);
|
|
674
|
+
`,
|
|
675
|
+
`
|
|
676
|
+
CREATE TABLE IF NOT EXISTS project_sources (
|
|
677
|
+
id TEXT PRIMARY KEY,
|
|
678
|
+
project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
|
679
|
+
type TEXT NOT NULL,
|
|
680
|
+
name TEXT NOT NULL,
|
|
681
|
+
uri TEXT NOT NULL,
|
|
682
|
+
description TEXT,
|
|
683
|
+
metadata TEXT DEFAULT '{}',
|
|
684
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
685
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
686
|
+
);
|
|
687
|
+
CREATE INDEX IF NOT EXISTS idx_project_sources_project ON project_sources(project_id);
|
|
688
|
+
CREATE INDEX IF NOT EXISTS idx_project_sources_type ON project_sources(type);
|
|
689
|
+
INSERT OR IGNORE INTO _migrations (id) VALUES (22);
|
|
605
690
|
`
|
|
606
691
|
];
|
|
607
692
|
});
|
|
@@ -933,6 +1018,77 @@ var init_agents = __esm(() => {
|
|
|
933
1018
|
AGENT_ACTIVE_WINDOW_MS = 30 * 60 * 1000;
|
|
934
1019
|
});
|
|
935
1020
|
|
|
1021
|
+
// src/db/handoffs.ts
|
|
1022
|
+
var exports_handoffs = {};
|
|
1023
|
+
__export(exports_handoffs, {
|
|
1024
|
+
listHandoffs: () => listHandoffs,
|
|
1025
|
+
getLatestHandoff: () => getLatestHandoff,
|
|
1026
|
+
createHandoff: () => createHandoff
|
|
1027
|
+
});
|
|
1028
|
+
function createHandoff(input, db) {
|
|
1029
|
+
const d = db || getDatabase();
|
|
1030
|
+
const id = uuid();
|
|
1031
|
+
const timestamp = now();
|
|
1032
|
+
d.run(`INSERT INTO handoffs (id, agent_id, project_id, summary, completed, in_progress, blockers, next_steps, created_at)
|
|
1033
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
1034
|
+
id,
|
|
1035
|
+
input.agent_id || null,
|
|
1036
|
+
input.project_id || null,
|
|
1037
|
+
input.summary,
|
|
1038
|
+
input.completed ? JSON.stringify(input.completed) : null,
|
|
1039
|
+
input.in_progress ? JSON.stringify(input.in_progress) : null,
|
|
1040
|
+
input.blockers ? JSON.stringify(input.blockers) : null,
|
|
1041
|
+
input.next_steps ? JSON.stringify(input.next_steps) : null,
|
|
1042
|
+
timestamp
|
|
1043
|
+
]);
|
|
1044
|
+
return {
|
|
1045
|
+
id,
|
|
1046
|
+
agent_id: input.agent_id || null,
|
|
1047
|
+
project_id: input.project_id || null,
|
|
1048
|
+
summary: input.summary,
|
|
1049
|
+
completed: input.completed || null,
|
|
1050
|
+
in_progress: input.in_progress || null,
|
|
1051
|
+
blockers: input.blockers || null,
|
|
1052
|
+
next_steps: input.next_steps || null,
|
|
1053
|
+
created_at: timestamp
|
|
1054
|
+
};
|
|
1055
|
+
}
|
|
1056
|
+
function rowToHandoff(row) {
|
|
1057
|
+
return {
|
|
1058
|
+
...row,
|
|
1059
|
+
completed: row.completed ? JSON.parse(row.completed) : null,
|
|
1060
|
+
in_progress: row.in_progress ? JSON.parse(row.in_progress) : null,
|
|
1061
|
+
blockers: row.blockers ? JSON.parse(row.blockers) : null,
|
|
1062
|
+
next_steps: row.next_steps ? JSON.parse(row.next_steps) : null
|
|
1063
|
+
};
|
|
1064
|
+
}
|
|
1065
|
+
function listHandoffs(projectId, limit = 10, db) {
|
|
1066
|
+
const d = db || getDatabase();
|
|
1067
|
+
if (projectId) {
|
|
1068
|
+
return d.query("SELECT * FROM handoffs WHERE project_id = ? ORDER BY rowid DESC LIMIT ?").all(projectId, limit).map(rowToHandoff);
|
|
1069
|
+
}
|
|
1070
|
+
return d.query("SELECT * FROM handoffs ORDER BY rowid DESC LIMIT ?").all(limit).map(rowToHandoff);
|
|
1071
|
+
}
|
|
1072
|
+
function getLatestHandoff(agentId, projectId, db) {
|
|
1073
|
+
const d = db || getDatabase();
|
|
1074
|
+
let query = "SELECT * FROM handoffs WHERE 1=1";
|
|
1075
|
+
const params = [];
|
|
1076
|
+
if (agentId) {
|
|
1077
|
+
query += " AND agent_id = ?";
|
|
1078
|
+
params.push(agentId);
|
|
1079
|
+
}
|
|
1080
|
+
if (projectId) {
|
|
1081
|
+
query += " AND project_id = ?";
|
|
1082
|
+
params.push(projectId);
|
|
1083
|
+
}
|
|
1084
|
+
query += " ORDER BY rowid DESC LIMIT 1";
|
|
1085
|
+
const row = d.query(query).get(...params);
|
|
1086
|
+
return row ? rowToHandoff(row) : null;
|
|
1087
|
+
}
|
|
1088
|
+
var init_handoffs = __esm(() => {
|
|
1089
|
+
init_database();
|
|
1090
|
+
});
|
|
1091
|
+
|
|
936
1092
|
// src/mcp/index.ts
|
|
937
1093
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
938
1094
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
@@ -5067,6 +5223,40 @@ function listProjects(db) {
|
|
|
5067
5223
|
const d = db || getDatabase();
|
|
5068
5224
|
return d.query("SELECT * FROM projects ORDER BY name").all();
|
|
5069
5225
|
}
|
|
5226
|
+
function rowToSource(row) {
|
|
5227
|
+
return {
|
|
5228
|
+
...row,
|
|
5229
|
+
metadata: row.metadata ? JSON.parse(row.metadata) : {}
|
|
5230
|
+
};
|
|
5231
|
+
}
|
|
5232
|
+
function addProjectSource(input, db) {
|
|
5233
|
+
const d = db || getDatabase();
|
|
5234
|
+
const id = uuid();
|
|
5235
|
+
const timestamp = now();
|
|
5236
|
+
d.run(`INSERT INTO project_sources (id, project_id, type, name, uri, description, metadata, created_at, updated_at)
|
|
5237
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
5238
|
+
id,
|
|
5239
|
+
input.project_id,
|
|
5240
|
+
input.type,
|
|
5241
|
+
input.name,
|
|
5242
|
+
input.uri,
|
|
5243
|
+
input.description || null,
|
|
5244
|
+
JSON.stringify(input.metadata || {}),
|
|
5245
|
+
timestamp,
|
|
5246
|
+
timestamp
|
|
5247
|
+
]);
|
|
5248
|
+
return rowToSource(d.query("SELECT * FROM project_sources WHERE id = ?").get(id));
|
|
5249
|
+
}
|
|
5250
|
+
function removeProjectSource(id, db) {
|
|
5251
|
+
const d = db || getDatabase();
|
|
5252
|
+
const result = d.run("DELETE FROM project_sources WHERE id = ?", [id]);
|
|
5253
|
+
return result.changes > 0;
|
|
5254
|
+
}
|
|
5255
|
+
function listProjectSources(projectId, db) {
|
|
5256
|
+
const d = db || getDatabase();
|
|
5257
|
+
const rows = d.query("SELECT * FROM project_sources WHERE project_id = ? ORDER BY name").all(projectId);
|
|
5258
|
+
return rows.map(rowToSource);
|
|
5259
|
+
}
|
|
5070
5260
|
function nextTaskShortId(projectId, db) {
|
|
5071
5261
|
const d = db || getDatabase();
|
|
5072
5262
|
const project = getProject(projectId, d);
|
|
@@ -5331,6 +5521,52 @@ function nextOccurrence(rule, from) {
|
|
|
5331
5521
|
// src/db/tasks.ts
|
|
5332
5522
|
init_webhooks();
|
|
5333
5523
|
init_templates();
|
|
5524
|
+
|
|
5525
|
+
// src/db/checklists.ts
|
|
5526
|
+
init_database();
|
|
5527
|
+
function rowToItem(row) {
|
|
5528
|
+
return { ...row, checked: !!row.checked };
|
|
5529
|
+
}
|
|
5530
|
+
function getChecklist(taskId, db) {
|
|
5531
|
+
const d = db || getDatabase();
|
|
5532
|
+
const rows = d.query("SELECT * FROM task_checklists WHERE task_id = ? ORDER BY position, created_at").all(taskId);
|
|
5533
|
+
return rows.map(rowToItem);
|
|
5534
|
+
}
|
|
5535
|
+
function addChecklistItem(input, db) {
|
|
5536
|
+
const d = db || getDatabase();
|
|
5537
|
+
const id = uuid();
|
|
5538
|
+
const timestamp = now();
|
|
5539
|
+
let position = input.position;
|
|
5540
|
+
if (position === undefined) {
|
|
5541
|
+
const maxRow = d.query("SELECT MAX(position) as max_pos FROM task_checklists WHERE task_id = ?").get(input.task_id);
|
|
5542
|
+
position = (maxRow?.max_pos ?? -1) + 1;
|
|
5543
|
+
}
|
|
5544
|
+
d.run("INSERT INTO task_checklists (id, task_id, position, text, checked, created_at, updated_at) VALUES (?, ?, ?, ?, 0, ?, ?)", [id, input.task_id, position, input.text, timestamp, timestamp]);
|
|
5545
|
+
return rowToItem(d.query("SELECT * FROM task_checklists WHERE id = ?").get(id));
|
|
5546
|
+
}
|
|
5547
|
+
function checkChecklistItem(id, checked, db) {
|
|
5548
|
+
const d = db || getDatabase();
|
|
5549
|
+
const timestamp = now();
|
|
5550
|
+
const result = d.run("UPDATE task_checklists SET checked = ?, updated_at = ? WHERE id = ?", [checked ? 1 : 0, timestamp, id]);
|
|
5551
|
+
if (result.changes === 0)
|
|
5552
|
+
return null;
|
|
5553
|
+
return rowToItem(d.query("SELECT * FROM task_checklists WHERE id = ?").get(id));
|
|
5554
|
+
}
|
|
5555
|
+
function updateChecklistItemText(id, text, db) {
|
|
5556
|
+
const d = db || getDatabase();
|
|
5557
|
+
const timestamp = now();
|
|
5558
|
+
const result = d.run("UPDATE task_checklists SET text = ?, updated_at = ? WHERE id = ?", [text, timestamp, id]);
|
|
5559
|
+
if (result.changes === 0)
|
|
5560
|
+
return null;
|
|
5561
|
+
return rowToItem(d.query("SELECT * FROM task_checklists WHERE id = ?").get(id));
|
|
5562
|
+
}
|
|
5563
|
+
function removeChecklistItem(id, db) {
|
|
5564
|
+
const d = db || getDatabase();
|
|
5565
|
+
const result = d.run("DELETE FROM task_checklists WHERE id = ?", [id]);
|
|
5566
|
+
return result.changes > 0;
|
|
5567
|
+
}
|
|
5568
|
+
|
|
5569
|
+
// src/db/tasks.ts
|
|
5334
5570
|
function rowToTask(row) {
|
|
5335
5571
|
return {
|
|
5336
5572
|
...row,
|
|
@@ -5423,13 +5659,15 @@ function getTaskWithRelations(id, db) {
|
|
|
5423
5659
|
const blocked_by = blockedByRows.map(rowToTask);
|
|
5424
5660
|
const comments = d.query("SELECT * FROM task_comments WHERE task_id = ? ORDER BY created_at").all(id);
|
|
5425
5661
|
const parent = task.parent_id ? getTask(task.parent_id, d) : null;
|
|
5662
|
+
const checklist = getChecklist(id, d);
|
|
5426
5663
|
return {
|
|
5427
5664
|
...task,
|
|
5428
5665
|
subtasks,
|
|
5429
5666
|
dependencies,
|
|
5430
5667
|
blocked_by,
|
|
5431
5668
|
comments,
|
|
5432
|
-
parent
|
|
5669
|
+
parent,
|
|
5670
|
+
checklist
|
|
5433
5671
|
};
|
|
5434
5672
|
}
|
|
5435
5673
|
function listTasks(filter = {}, db) {
|
|
@@ -7450,6 +7688,14 @@ Comments (${task.comments.length}):`);
|
|
|
7450
7688
|
parts.push(`
|
|
7451
7689
|
Parent: ${task.parent.id.slice(0, 8)} | ${task.parent.title}`);
|
|
7452
7690
|
}
|
|
7691
|
+
if (task.checklist.length > 0) {
|
|
7692
|
+
const done = task.checklist.filter((i) => i.checked).length;
|
|
7693
|
+
parts.push(`
|
|
7694
|
+
Checklist (${done}/${task.checklist.length}):`);
|
|
7695
|
+
for (const item of task.checklist) {
|
|
7696
|
+
parts.push(` ${item.position + 1}. [${item.checked ? "x" : " "}] ${item.text} (${item.id.slice(0, 8)})`);
|
|
7697
|
+
}
|
|
7698
|
+
}
|
|
7453
7699
|
return { content: [{ type: "text", text: parts.join(`
|
|
7454
7700
|
`) }] };
|
|
7455
7701
|
} catch (e) {
|
|
@@ -7679,6 +7925,171 @@ if (shouldRegisterTool("create_project")) {
|
|
|
7679
7925
|
}
|
|
7680
7926
|
});
|
|
7681
7927
|
}
|
|
7928
|
+
if (shouldRegisterTool("add_project_source")) {
|
|
7929
|
+
server.tool("add_project_source", "Add a data source to a project (S3 bucket, Google Drive folder, local path, GitHub repo, Notion page, etc.). Sources are revealed to agents when they load the project.", {
|
|
7930
|
+
project_id: exports_external.string().describe("Project ID"),
|
|
7931
|
+
type: exports_external.string().describe("Source type: 's3', 'gdrive', 'local', 'github', 'notion', 'http', or any custom label"),
|
|
7932
|
+
name: exports_external.string().describe("Human-readable label for this source"),
|
|
7933
|
+
uri: exports_external.string().describe("The source URI (bucket path, folder URL, local path, repo URL, etc.)"),
|
|
7934
|
+
description: exports_external.string().optional().describe("What this source contains or how agents should use it"),
|
|
7935
|
+
metadata: exports_external.record(exports_external.unknown()).optional().describe("Extra config (e.g. region, access role, subfolder)")
|
|
7936
|
+
}, async (params) => {
|
|
7937
|
+
try {
|
|
7938
|
+
const resolvedProjectId = resolveId(params.project_id, "projects");
|
|
7939
|
+
const source = addProjectSource({ ...params, project_id: resolvedProjectId });
|
|
7940
|
+
return {
|
|
7941
|
+
content: [{
|
|
7942
|
+
type: "text",
|
|
7943
|
+
text: `Source added: ${source.id.slice(0, 8)} | [${source.type}] ${source.name} \u2192 ${source.uri}`
|
|
7944
|
+
}]
|
|
7945
|
+
};
|
|
7946
|
+
} catch (e) {
|
|
7947
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
7948
|
+
}
|
|
7949
|
+
});
|
|
7950
|
+
}
|
|
7951
|
+
if (shouldRegisterTool("remove_project_source")) {
|
|
7952
|
+
server.tool("remove_project_source", "Remove a data source from a project by source ID.", {
|
|
7953
|
+
source_id: exports_external.string().describe("Source ID to remove")
|
|
7954
|
+
}, async ({ source_id }) => {
|
|
7955
|
+
try {
|
|
7956
|
+
const db = getDatabase();
|
|
7957
|
+
const row = db.query("SELECT * FROM project_sources WHERE id LIKE ?").get(`${source_id}%`);
|
|
7958
|
+
if (!row)
|
|
7959
|
+
return { content: [{ type: "text", text: `Source not found: ${source_id}` }], isError: true };
|
|
7960
|
+
removeProjectSource(row.id);
|
|
7961
|
+
return { content: [{ type: "text", text: `Source removed: ${row.name}` }] };
|
|
7962
|
+
} catch (e) {
|
|
7963
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
7964
|
+
}
|
|
7965
|
+
});
|
|
7966
|
+
}
|
|
7967
|
+
if (shouldRegisterTool("list_project_sources")) {
|
|
7968
|
+
server.tool("list_project_sources", "List all data sources attached to a project.", {
|
|
7969
|
+
project_id: exports_external.string().describe("Project ID")
|
|
7970
|
+
}, async ({ project_id }) => {
|
|
7971
|
+
try {
|
|
7972
|
+
const resolvedId = resolveId(project_id, "projects");
|
|
7973
|
+
const sources = listProjectSources(resolvedId);
|
|
7974
|
+
if (sources.length === 0) {
|
|
7975
|
+
return { content: [{ type: "text", text: "No sources configured for this project." }] };
|
|
7976
|
+
}
|
|
7977
|
+
const lines = sources.map((s) => `${s.id.slice(0, 8)} | [${s.type}] ${s.name} \u2192 ${s.uri}${s.description ? `
|
|
7978
|
+
${s.description}` : ""}`);
|
|
7979
|
+
return { content: [{ type: "text", text: `${sources.length} source(s):
|
|
7980
|
+
${lines.join(`
|
|
7981
|
+
`)}` }] };
|
|
7982
|
+
} catch (e) {
|
|
7983
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
7984
|
+
}
|
|
7985
|
+
});
|
|
7986
|
+
}
|
|
7987
|
+
if (shouldRegisterTool("add_checklist_item")) {
|
|
7988
|
+
server.tool("add_checklist_item", "Add a checklist item to a task. Items are numbered and individually checkable.", {
|
|
7989
|
+
task_id: exports_external.string().describe("Task ID"),
|
|
7990
|
+
text: exports_external.string().describe("Checklist item text"),
|
|
7991
|
+
position: exports_external.number().optional().describe("Position (0-based). Appended to end if omitted.")
|
|
7992
|
+
}, async ({ task_id, text, position }) => {
|
|
7993
|
+
try {
|
|
7994
|
+
const resolvedId = resolveId(task_id, "tasks");
|
|
7995
|
+
const item = addChecklistItem({ task_id: resolvedId, text, position });
|
|
7996
|
+
return {
|
|
7997
|
+
content: [{
|
|
7998
|
+
type: "text",
|
|
7999
|
+
text: `Item added: ${item.position + 1}. [ ] ${item.text} (${item.id.slice(0, 8)})`
|
|
8000
|
+
}]
|
|
8001
|
+
};
|
|
8002
|
+
} catch (e) {
|
|
8003
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
8004
|
+
}
|
|
8005
|
+
});
|
|
8006
|
+
}
|
|
8007
|
+
if (shouldRegisterTool("check_checklist_item")) {
|
|
8008
|
+
server.tool("check_checklist_item", "Mark a checklist item as checked or unchecked.", {
|
|
8009
|
+
item_id: exports_external.string().describe("Checklist item ID or prefix"),
|
|
8010
|
+
checked: exports_external.boolean().describe("true to check, false to uncheck")
|
|
8011
|
+
}, async ({ item_id, checked }) => {
|
|
8012
|
+
try {
|
|
8013
|
+
const db = getDatabase();
|
|
8014
|
+
const row = db.query("SELECT id FROM task_checklists WHERE id LIKE ?").get(`${item_id}%`);
|
|
8015
|
+
if (!row)
|
|
8016
|
+
return { content: [{ type: "text", text: `Checklist item not found: ${item_id}` }], isError: true };
|
|
8017
|
+
const item = checkChecklistItem(row.id, checked);
|
|
8018
|
+
if (!item)
|
|
8019
|
+
return { content: [{ type: "text", text: "Update failed" }], isError: true };
|
|
8020
|
+
return {
|
|
8021
|
+
content: [{
|
|
8022
|
+
type: "text",
|
|
8023
|
+
text: `${item.position + 1}. [${item.checked ? "x" : " "}] ${item.text}`
|
|
8024
|
+
}]
|
|
8025
|
+
};
|
|
8026
|
+
} catch (e) {
|
|
8027
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
8028
|
+
}
|
|
8029
|
+
});
|
|
8030
|
+
}
|
|
8031
|
+
if (shouldRegisterTool("update_checklist_item")) {
|
|
8032
|
+
server.tool("update_checklist_item", "Update the text of a checklist item.", {
|
|
8033
|
+
item_id: exports_external.string().describe("Checklist item ID or prefix"),
|
|
8034
|
+
text: exports_external.string().describe("New text")
|
|
8035
|
+
}, async ({ item_id, text }) => {
|
|
8036
|
+
try {
|
|
8037
|
+
const db = getDatabase();
|
|
8038
|
+
const row = db.query("SELECT id FROM task_checklists WHERE id LIKE ?").get(`${item_id}%`);
|
|
8039
|
+
if (!row)
|
|
8040
|
+
return { content: [{ type: "text", text: `Checklist item not found: ${item_id}` }], isError: true };
|
|
8041
|
+
const item = updateChecklistItemText(row.id, text);
|
|
8042
|
+
if (!item)
|
|
8043
|
+
return { content: [{ type: "text", text: "Update failed" }], isError: true };
|
|
8044
|
+
return {
|
|
8045
|
+
content: [{
|
|
8046
|
+
type: "text",
|
|
8047
|
+
text: `Updated: ${item.position + 1}. [${item.checked ? "x" : " "}] ${item.text}`
|
|
8048
|
+
}]
|
|
8049
|
+
};
|
|
8050
|
+
} catch (e) {
|
|
8051
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
8052
|
+
}
|
|
8053
|
+
});
|
|
8054
|
+
}
|
|
8055
|
+
if (shouldRegisterTool("remove_checklist_item")) {
|
|
8056
|
+
server.tool("remove_checklist_item", "Remove a checklist item from a task.", {
|
|
8057
|
+
item_id: exports_external.string().describe("Checklist item ID or prefix")
|
|
8058
|
+
}, async ({ item_id }) => {
|
|
8059
|
+
try {
|
|
8060
|
+
const db = getDatabase();
|
|
8061
|
+
const row = db.query("SELECT id, text FROM task_checklists WHERE id LIKE ?").get(`${item_id}%`);
|
|
8062
|
+
if (!row)
|
|
8063
|
+
return { content: [{ type: "text", text: `Checklist item not found: ${item_id}` }], isError: true };
|
|
8064
|
+
removeChecklistItem(row.id);
|
|
8065
|
+
return { content: [{ type: "text", text: `Removed: ${row.text}` }] };
|
|
8066
|
+
} catch (e) {
|
|
8067
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
8068
|
+
}
|
|
8069
|
+
});
|
|
8070
|
+
}
|
|
8071
|
+
if (shouldRegisterTool("get_checklist")) {
|
|
8072
|
+
server.tool("get_checklist", "Get all checklist items for a task with progress summary.", {
|
|
8073
|
+
task_id: exports_external.string().describe("Task ID")
|
|
8074
|
+
}, async ({ task_id }) => {
|
|
8075
|
+
try {
|
|
8076
|
+
const resolvedId = resolveId(task_id, "tasks");
|
|
8077
|
+
const items = getChecklist(resolvedId);
|
|
8078
|
+
if (items.length === 0) {
|
|
8079
|
+
return { content: [{ type: "text", text: "No checklist items." }] };
|
|
8080
|
+
}
|
|
8081
|
+
const done = items.filter((i) => i.checked).length;
|
|
8082
|
+
const lines = [`Checklist (${done}/${items.length} done):`];
|
|
8083
|
+
for (const item of items) {
|
|
8084
|
+
lines.push(` ${item.position + 1}. [${item.checked ? "x" : " "}] ${item.text} (${item.id.slice(0, 8)})`);
|
|
8085
|
+
}
|
|
8086
|
+
return { content: [{ type: "text", text: lines.join(`
|
|
8087
|
+
`) }] };
|
|
8088
|
+
} catch (e) {
|
|
8089
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
8090
|
+
}
|
|
8091
|
+
});
|
|
8092
|
+
}
|
|
7682
8093
|
if (shouldRegisterTool("create_plan")) {
|
|
7683
8094
|
server.tool("create_plan", "Create a plan to group related tasks.", {
|
|
7684
8095
|
name: exports_external.string(),
|
|
@@ -8995,6 +9406,19 @@ if (shouldRegisterTool("bootstrap")) {
|
|
|
8995
9406
|
lines.push(`Other agents active: ${others.slice(0, 3).map((w) => `${w.short_id || w.id.slice(0, 8)} (${w.assigned_to || "?"})`).join(", ")}`);
|
|
8996
9407
|
}
|
|
8997
9408
|
}
|
|
9409
|
+
if (project_id) {
|
|
9410
|
+
const resolvedId = resolveId(project_id, "projects");
|
|
9411
|
+
const sources = listProjectSources(resolvedId);
|
|
9412
|
+
if (sources.length > 0) {
|
|
9413
|
+
lines.push("");
|
|
9414
|
+
lines.push(`## Data Sources`);
|
|
9415
|
+
for (const s of sources) {
|
|
9416
|
+
lines.push(`[${s.type}] ${s.name}: ${s.uri}${s.description ? ` \u2014 ${s.description}` : ""}`);
|
|
9417
|
+
}
|
|
9418
|
+
}
|
|
9419
|
+
}
|
|
9420
|
+
lines.push(`
|
|
9421
|
+
as_of: ${new Date().toISOString()}`);
|
|
8998
9422
|
return { content: [{ type: "text", text: lines.join(`
|
|
8999
9423
|
`) }] };
|
|
9000
9424
|
} catch (e) {
|
|
@@ -9045,6 +9469,14 @@ if (shouldRegisterTool("search_tools")) {
|
|
|
9045
9469
|
"log_progress",
|
|
9046
9470
|
"create_project",
|
|
9047
9471
|
"list_projects",
|
|
9472
|
+
"add_project_source",
|
|
9473
|
+
"remove_project_source",
|
|
9474
|
+
"list_project_sources",
|
|
9475
|
+
"add_checklist_item",
|
|
9476
|
+
"check_checklist_item",
|
|
9477
|
+
"update_checklist_item",
|
|
9478
|
+
"remove_checklist_item",
|
|
9479
|
+
"get_checklist",
|
|
9048
9480
|
"create_plan",
|
|
9049
9481
|
"list_plans",
|
|
9050
9482
|
"get_plan",
|
|
@@ -9153,6 +9585,30 @@ if (shouldRegisterTool("describe_tools")) {
|
|
|
9153
9585
|
Params: name(string, req), path(string, req \u2014 unique absolute path), description(string), task_list_id(string)
|
|
9154
9586
|
Example: {name: 'my-app', path: '/Users/dev/my-app'}`,
|
|
9155
9587
|
list_projects: "List all registered projects. No params.",
|
|
9588
|
+
add_checklist_item: `Add a checklist item (numbered sub-step) to a task.
|
|
9589
|
+
Params: task_id(string, req), text(string, req), position(number \u2014 0-based, appended to end if omitted)
|
|
9590
|
+
Example: {task_id: 'a1b2c3d4', text: 'Cancel Slack subscription'}`,
|
|
9591
|
+
check_checklist_item: `Mark a checklist item checked or unchecked.
|
|
9592
|
+
Params: item_id(string, req \u2014 item ID or prefix), checked(boolean, req)
|
|
9593
|
+
Example: {item_id: 'abc12345', checked: true}`,
|
|
9594
|
+
update_checklist_item: `Update the text of a checklist item.
|
|
9595
|
+
Params: item_id(string, req), text(string, req)
|
|
9596
|
+
Example: {item_id: 'abc12345', text: 'Cancel GitHub subscription'}`,
|
|
9597
|
+
remove_checklist_item: `Remove a checklist item permanently.
|
|
9598
|
+
Params: item_id(string, req)
|
|
9599
|
+
Example: {item_id: 'abc12345'}`,
|
|
9600
|
+
get_checklist: `Get all checklist items for a task with progress (done/total).
|
|
9601
|
+
Params: task_id(string, req)
|
|
9602
|
+
Example: {task_id: 'a1b2c3d4'}`,
|
|
9603
|
+
add_project_source: `Add a data source to a project (S3, GDrive, local path, GitHub, Notion, HTTP, etc.).
|
|
9604
|
+
Params: project_id(string, req), type(string, req \u2014 e.g. 's3','gdrive','local','github','notion','http'), name(string, req), uri(string, req), description(string), metadata(object)
|
|
9605
|
+
Example: {project_id: 'a1b2c3d4', type: 's3', name: 'Assets bucket', uri: 's3://my-bucket/assets/', description: 'Project media files'}`,
|
|
9606
|
+
remove_project_source: `Remove a data source from a project.
|
|
9607
|
+
Params: source_id(string, req \u2014 source ID or prefix)
|
|
9608
|
+
Example: {source_id: 'abc12345'}`,
|
|
9609
|
+
list_project_sources: `List all data sources for a project.
|
|
9610
|
+
Params: project_id(string, req)
|
|
9611
|
+
Example: {project_id: 'a1b2c3d4'}`,
|
|
9156
9612
|
create_plan: `Create a plan to group related tasks.
|
|
9157
9613
|
Params: name(string, req), project_id(string), description(string), status(active|completed|archived, default:active), task_list_id(string), agent_id(string)
|
|
9158
9614
|
Example: {name: 'Sprint 1', project_id: 'a1b2c3d4'}`,
|
|
@@ -9313,6 +9769,62 @@ server.resource("agents", "todos://agents", { description: "All registered agent
|
|
|
9313
9769
|
const agents = listAgents();
|
|
9314
9770
|
return { contents: [{ uri: "todos://agents", text: JSON.stringify(agents, null, 2), mimeType: "application/json" }] };
|
|
9315
9771
|
});
|
|
9772
|
+
if (shouldRegisterTool("create_handoff")) {
|
|
9773
|
+
server.tool("create_handoff", "Create a session handoff note for agent coordination.", {
|
|
9774
|
+
agent_id: exports_external.string().optional().describe("Agent creating the handoff"),
|
|
9775
|
+
project_id: exports_external.string().optional().describe("Project ID"),
|
|
9776
|
+
summary: exports_external.string().describe("What was accomplished this session"),
|
|
9777
|
+
completed: exports_external.array(exports_external.string()).optional().describe("Items completed"),
|
|
9778
|
+
in_progress: exports_external.array(exports_external.string()).optional().describe("Items still in progress"),
|
|
9779
|
+
blockers: exports_external.array(exports_external.string()).optional().describe("Blocking issues"),
|
|
9780
|
+
next_steps: exports_external.array(exports_external.string()).optional().describe("Recommended next actions")
|
|
9781
|
+
}, async ({ agent_id, project_id, summary, completed, in_progress, blockers, next_steps }) => {
|
|
9782
|
+
try {
|
|
9783
|
+
const { createHandoff: createHandoff2 } = (init_handoffs(), __toCommonJS(exports_handoffs));
|
|
9784
|
+
const handoff = createHandoff2({
|
|
9785
|
+
agent_id,
|
|
9786
|
+
project_id: project_id ? resolveId(project_id, "projects") : undefined,
|
|
9787
|
+
summary,
|
|
9788
|
+
completed,
|
|
9789
|
+
in_progress,
|
|
9790
|
+
blockers,
|
|
9791
|
+
next_steps
|
|
9792
|
+
});
|
|
9793
|
+
return { content: [{ type: "text", text: `Handoff created: ${handoff.id.slice(0, 8)} by ${handoff.agent_id || "unknown"}` }] };
|
|
9794
|
+
} catch (e) {
|
|
9795
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
9796
|
+
}
|
|
9797
|
+
});
|
|
9798
|
+
}
|
|
9799
|
+
if (shouldRegisterTool("get_latest_handoff")) {
|
|
9800
|
+
server.tool("get_latest_handoff", "Get the most recent handoff for an agent or project.", {
|
|
9801
|
+
agent_id: exports_external.string().optional().describe("Filter by agent"),
|
|
9802
|
+
project_id: exports_external.string().optional().describe("Filter by project")
|
|
9803
|
+
}, async ({ agent_id, project_id }) => {
|
|
9804
|
+
try {
|
|
9805
|
+
const { getLatestHandoff: getLatestHandoff2 } = (init_handoffs(), __toCommonJS(exports_handoffs));
|
|
9806
|
+
const handoff = getLatestHandoff2(agent_id, project_id ? resolveId(project_id, "projects") : undefined);
|
|
9807
|
+
if (!handoff)
|
|
9808
|
+
return { content: [{ type: "text", text: "No handoffs found." }] };
|
|
9809
|
+
const lines = [
|
|
9810
|
+
`${handoff.created_at.slice(0, 16)} ${handoff.agent_id || "unknown"}`,
|
|
9811
|
+
handoff.summary
|
|
9812
|
+
];
|
|
9813
|
+
if (handoff.completed?.length)
|
|
9814
|
+
lines.push(`Done: ${handoff.completed.join(", ")}`);
|
|
9815
|
+
if (handoff.in_progress?.length)
|
|
9816
|
+
lines.push(`In progress: ${handoff.in_progress.join(", ")}`);
|
|
9817
|
+
if (handoff.blockers?.length)
|
|
9818
|
+
lines.push(`Blocked: ${handoff.blockers.join(", ")}`);
|
|
9819
|
+
if (handoff.next_steps?.length)
|
|
9820
|
+
lines.push(`Next: ${handoff.next_steps.join(", ")}`);
|
|
9821
|
+
return { content: [{ type: "text", text: lines.join(`
|
|
9822
|
+
`) }] };
|
|
9823
|
+
} catch (e) {
|
|
9824
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
9825
|
+
}
|
|
9826
|
+
});
|
|
9827
|
+
}
|
|
9316
9828
|
server.resource("task-lists", "todos://task-lists", { description: "All task lists", mimeType: "application/json" }, async () => {
|
|
9317
9829
|
const lists = listTaskLists();
|
|
9318
9830
|
return { contents: [{ uri: "todos://task-lists", text: JSON.stringify(lists, null, 2), mimeType: "application/json" }] };
|