@dalmasonto/taskflow-mcp 1.0.35 → 2.0.0
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/README.md +138 -193
- package/dist/attachment-download.d.ts +74 -0
- package/dist/attachment-download.js +193 -0
- package/dist/attachment-download.js.map +1 -0
- package/dist/attachments.d.ts +23 -0
- package/dist/attachments.js +66 -0
- package/dist/attachments.js.map +1 -0
- package/dist/client.d.ts +206 -0
- package/dist/client.js +279 -0
- package/dist/client.js.map +1 -0
- package/dist/config.d.ts +137 -18
- package/dist/config.js +187 -106
- package/dist/config.js.map +1 -0
- package/dist/connect.d.ts +89 -0
- package/dist/connect.js +269 -0
- package/dist/connect.js.map +1 -0
- package/dist/doctor.d.ts +24 -0
- package/dist/doctor.js +120 -0
- package/dist/doctor.js.map +1 -0
- package/dist/events.d.ts +186 -0
- package/dist/events.js +407 -0
- package/dist/events.js.map +1 -0
- package/dist/index.d.ts +7 -1
- package/dist/index.js +121 -218
- package/dist/index.js.map +1 -0
- package/dist/instructions.d.ts +12 -0
- package/dist/instructions.js +114 -0
- package/dist/instructions.js.map +1 -0
- package/dist/mint.d.ts +62 -0
- package/dist/mint.js +135 -0
- package/dist/mint.js.map +1 -0
- package/dist/mirror.d.ts +68 -0
- package/dist/mirror.js +103 -0
- package/dist/mirror.js.map +1 -0
- package/dist/pane-queue.d.ts +29 -0
- package/dist/pane-queue.js +35 -0
- package/dist/pane-queue.js.map +1 -0
- package/dist/prompts.d.ts +79 -0
- package/dist/prompts.js +211 -0
- package/dist/prompts.js.map +1 -0
- package/dist/resolve.d.ts +72 -0
- package/dist/resolve.js +89 -0
- package/dist/resolve.js.map +1 -0
- package/dist/runtime.d.ts +54 -0
- package/dist/runtime.js +321 -0
- package/dist/runtime.js.map +1 -0
- package/dist/server.d.ts +56 -0
- package/dist/server.js +793 -0
- package/dist/server.js.map +1 -0
- package/dist/session-identifier.d.ts +48 -0
- package/dist/session-identifier.js +44 -0
- package/dist/session-identifier.js.map +1 -0
- package/dist/sessions-store.d.ts +38 -0
- package/dist/sessions-store.js +88 -0
- package/dist/sessions-store.js.map +1 -0
- package/dist/tmux.d.ts +200 -0
- package/dist/tmux.js +580 -0
- package/dist/tmux.js.map +1 -0
- package/hooks/metadata.mjs +99 -0
- package/hooks/permission-prompt.mjs +100 -0
- package/hooks/taskflow-hook.mjs +499 -0
- package/hooks/tool-logging.mjs +63 -0
- package/package.json +38 -29
- package/dist/agent-registry.d.ts +0 -28
- package/dist/agent-registry.js +0 -158
- package/dist/db.d.ts +0 -5
- package/dist/db.js +0 -220
- package/dist/helpers.d.ts +0 -21
- package/dist/helpers.js +0 -27
- package/dist/resources.d.ts +0 -2
- package/dist/resources.js +0 -89
- package/dist/retry.d.ts +0 -34
- package/dist/retry.js +0 -94
- package/dist/sse.d.ts +0 -10
- package/dist/sse.js +0 -824
- package/dist/tmux-bridge.d.ts +0 -13
- package/dist/tmux-bridge.js +0 -217
- package/dist/tools/activity.d.ts +0 -39
- package/dist/tools/activity.js +0 -152
- package/dist/tools/agent-inbox.d.ts +0 -12
- package/dist/tools/agent-inbox.js +0 -272
- package/dist/tools/agent.d.ts +0 -14
- package/dist/tools/agent.js +0 -168
- package/dist/tools/analytics.d.ts +0 -21
- package/dist/tools/analytics.js +0 -191
- package/dist/tools/checkpoint.d.ts +0 -27
- package/dist/tools/checkpoint.js +0 -105
- package/dist/tools/notifications.d.ts +0 -31
- package/dist/tools/notifications.js +0 -59
- package/dist/tools/projects.d.ts +0 -55
- package/dist/tools/projects.js +0 -112
- package/dist/tools/settings.d.ts +0 -19
- package/dist/tools/settings.js +0 -73
- package/dist/tools/tasks.d.ts +0 -105
- package/dist/tools/tasks.js +0 -403
- package/dist/tools/terminal.d.ts +0 -4
- package/dist/tools/terminal.js +0 -98
- package/dist/tools/timer.d.ts +0 -37
- package/dist/tools/timer.js +0 -154
- package/dist/types.d.ts +0 -83
- package/dist/types.js +0 -30
package/dist/tools/analytics.js
DELETED
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
import { getDb } from '../db.js';
|
|
3
|
-
import { successResponse, errorResponse } from '../helpers.js';
|
|
4
|
-
// ─── exported handler functions ───────────────────────────────────────
|
|
5
|
-
export async function getAnalytics(params) {
|
|
6
|
-
const db = getDb();
|
|
7
|
-
const { start_date, end_date } = params;
|
|
8
|
-
// Build date filter for sessions
|
|
9
|
-
const sessionConditions = [];
|
|
10
|
-
const sessionValues = [];
|
|
11
|
-
if (start_date) {
|
|
12
|
-
sessionConditions.push('start >= ?');
|
|
13
|
-
sessionValues.push(start_date);
|
|
14
|
-
}
|
|
15
|
-
if (end_date) {
|
|
16
|
-
sessionConditions.push('start <= ?');
|
|
17
|
-
sessionValues.push(end_date);
|
|
18
|
-
}
|
|
19
|
-
const sessionWhere = sessionConditions.length > 0
|
|
20
|
-
? `WHERE ${sessionConditions.join(' AND ')}`
|
|
21
|
-
: '';
|
|
22
|
-
// Total focused time (sum of all session durations in ms)
|
|
23
|
-
const durationFormula = `(julianday(COALESCE(end, datetime('now'))) - julianday(start)) * 86400000`;
|
|
24
|
-
const timeRow = db.prepare(`SELECT COALESCE(SUM(${durationFormula}), 0) AS total_focused_time FROM sessions ${sessionWhere}`).get(...sessionValues);
|
|
25
|
-
const total_focused_time = Math.round(timeRow.total_focused_time);
|
|
26
|
-
// Task counts by status
|
|
27
|
-
const taskRows = db.prepare('SELECT status, COUNT(*) AS count FROM tasks GROUP BY status').all();
|
|
28
|
-
const status_distribution = {};
|
|
29
|
-
let tasks_completed = 0;
|
|
30
|
-
let tasks_in_progress = 0;
|
|
31
|
-
let total_tasks = 0;
|
|
32
|
-
for (const row of taskRows) {
|
|
33
|
-
status_distribution[row.status] = row.count;
|
|
34
|
-
total_tasks += row.count;
|
|
35
|
-
if (row.status === 'done')
|
|
36
|
-
tasks_completed = row.count;
|
|
37
|
-
if (row.status === 'in_progress')
|
|
38
|
-
tasks_in_progress = row.count;
|
|
39
|
-
}
|
|
40
|
-
// Time per project (only tasks that belong to a project)
|
|
41
|
-
const projectTimeRows = db.prepare(`SELECT
|
|
42
|
-
t.project_id,
|
|
43
|
-
p.name AS project_name,
|
|
44
|
-
COALESCE(SUM(${durationFormula.replace(/start/g, 's.start').replace(/end/g, 's.end')}), 0) AS total_time
|
|
45
|
-
FROM sessions s
|
|
46
|
-
JOIN tasks t ON s.task_id = t.id
|
|
47
|
-
JOIN projects p ON t.project_id = p.id
|
|
48
|
-
${sessionWhere.replace(/start/g, 's.start')}
|
|
49
|
-
GROUP BY t.project_id, p.name`).all(...sessionValues);
|
|
50
|
-
const time_per_project = projectTimeRows.map(row => ({
|
|
51
|
-
project_id: row.project_id,
|
|
52
|
-
project_name: row.project_name,
|
|
53
|
-
total_time: Math.round(row.total_time),
|
|
54
|
-
}));
|
|
55
|
-
return successResponse({
|
|
56
|
-
total_focused_time,
|
|
57
|
-
tasks_completed,
|
|
58
|
-
tasks_in_progress,
|
|
59
|
-
total_tasks,
|
|
60
|
-
status_distribution,
|
|
61
|
-
time_per_project,
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
export async function getTimeline(params) {
|
|
65
|
-
const db = getDb();
|
|
66
|
-
const { start_date, end_date, group_by = 'day' } = params;
|
|
67
|
-
const periodExpr = group_by === 'week'
|
|
68
|
-
? `strftime('%Y-W%W', start)`
|
|
69
|
-
: `strftime('%Y-%m-%d', start)`;
|
|
70
|
-
const durationFormula = `(julianday(COALESCE(end, datetime('now'))) - julianday(start)) * 86400000`;
|
|
71
|
-
const conditions = [];
|
|
72
|
-
const values = [];
|
|
73
|
-
if (start_date) {
|
|
74
|
-
conditions.push('start >= ?');
|
|
75
|
-
values.push(start_date);
|
|
76
|
-
}
|
|
77
|
-
if (end_date) {
|
|
78
|
-
conditions.push('start <= ?');
|
|
79
|
-
values.push(end_date);
|
|
80
|
-
}
|
|
81
|
-
const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
|
|
82
|
-
const rows = db.prepare(`SELECT
|
|
83
|
-
${periodExpr} AS period,
|
|
84
|
-
COALESCE(SUM(${durationFormula}), 0) AS total_time,
|
|
85
|
-
COUNT(*) AS session_count
|
|
86
|
-
FROM sessions
|
|
87
|
-
${where}
|
|
88
|
-
GROUP BY period
|
|
89
|
-
ORDER BY period ASC`).all(...values);
|
|
90
|
-
const timeline = rows.map(row => ({
|
|
91
|
-
period: row.period,
|
|
92
|
-
total_time: Math.round(row.total_time),
|
|
93
|
-
session_count: row.session_count,
|
|
94
|
-
}));
|
|
95
|
-
return successResponse(timeline);
|
|
96
|
-
}
|
|
97
|
-
// ─── MCP registration ─────────────────────────────────────────────────
|
|
98
|
-
export function registerAnalyticsTools(server) {
|
|
99
|
-
server.tool('get_analytics', 'Get a high-level analytics summary: total focused time, task completion rates, status distribution, and time per project. Useful for standup reports or understanding workload.', {
|
|
100
|
-
start_date: z.string().optional(),
|
|
101
|
-
end_date: z.string().optional(),
|
|
102
|
-
}, { readOnlyHint: true }, async (params) => getAnalytics(params));
|
|
103
|
-
server.tool('get_timeline', 'Get focused time grouped by day or week. Use for visualizing work patterns over time.', {
|
|
104
|
-
start_date: z.string().optional(),
|
|
105
|
-
end_date: z.string().optional(),
|
|
106
|
-
group_by: z.enum(['day', 'week']).optional(),
|
|
107
|
-
}, { readOnlyHint: true }, async (params) => getTimeline(params));
|
|
108
|
-
server.tool('get_tool_stats', 'Get tool execution statistics: call count, success rate, average duration per tool. Shows which tools are used most and which are slow or failing.', {
|
|
109
|
-
since: z.string().optional().describe('ISO date to filter from (e.g. "2026-04-01"). Defaults to all time.'),
|
|
110
|
-
tool_name: z.string().optional().describe('Filter to a specific tool name'),
|
|
111
|
-
}, { readOnlyHint: true }, async (params) => {
|
|
112
|
-
const db = getDb();
|
|
113
|
-
const conditions = [];
|
|
114
|
-
const values = [];
|
|
115
|
-
if (params.since) {
|
|
116
|
-
conditions.push('created_at >= ?');
|
|
117
|
-
values.push(params.since);
|
|
118
|
-
}
|
|
119
|
-
if (params.tool_name) {
|
|
120
|
-
conditions.push('tool_name = ?');
|
|
121
|
-
values.push(params.tool_name);
|
|
122
|
-
}
|
|
123
|
-
const where = conditions.length > 0 ? ` WHERE ${conditions.join(' AND ')}` : '';
|
|
124
|
-
const stats = db.prepare(`
|
|
125
|
-
SELECT
|
|
126
|
-
tool_name,
|
|
127
|
-
COUNT(*) as call_count,
|
|
128
|
-
SUM(CASE WHEN success = 1 THEN 1 ELSE 0 END) as success_count,
|
|
129
|
-
SUM(CASE WHEN success = 0 THEN 1 ELSE 0 END) as failure_count,
|
|
130
|
-
ROUND(AVG(duration_ms)) as avg_duration_ms,
|
|
131
|
-
MAX(duration_ms) as max_duration_ms,
|
|
132
|
-
MIN(created_at) as first_call,
|
|
133
|
-
MAX(created_at) as last_call
|
|
134
|
-
FROM tool_executions${where}
|
|
135
|
-
GROUP BY tool_name
|
|
136
|
-
ORDER BY call_count DESC
|
|
137
|
-
`).all(...values);
|
|
138
|
-
const total = db.prepare(`SELECT COUNT(*) as count FROM tool_executions${where}`).get(...values);
|
|
139
|
-
return successResponse({ total_executions: total.count, tools: stats });
|
|
140
|
-
});
|
|
141
|
-
server.tool('get_task_cost', 'Get per-task cost metrics: tool calls made during active timer sessions, total execution time, and tool breakdown. Useful for understanding which tasks consume the most resources.', {
|
|
142
|
-
task_id: z.number().optional().describe('Get cost for a specific task. Omit for all tasks.'),
|
|
143
|
-
project_id: z.number().optional().describe('Get cost for all tasks in a project'),
|
|
144
|
-
}, { readOnlyHint: true }, async (params) => {
|
|
145
|
-
const db = getDb();
|
|
146
|
-
if (params.task_id) {
|
|
147
|
-
// Cost for a single task — use subqueries to avoid cross-join inflation
|
|
148
|
-
const task = db.prepare('SELECT id, title, status FROM tasks WHERE id = ?').get(params.task_id);
|
|
149
|
-
if (!task)
|
|
150
|
-
return errorResponse(`Task ${params.task_id} not found`, 'NOT_FOUND');
|
|
151
|
-
const sessionTime = db.prepare('SELECT COALESCE(SUM(CASE WHEN end IS NOT NULL THEN (julianday(end) - julianday(start)) * 86400000 ELSE 0 END), 0) as total FROM sessions WHERE task_id = ?').get(params.task_id);
|
|
152
|
-
// Tool calls that occurred during any session for this task
|
|
153
|
-
const toolCalls = db.prepare(`
|
|
154
|
-
SELECT COUNT(*) as total, COALESCE(SUM(te.duration_ms), 0) as duration_ms,
|
|
155
|
-
SUM(CASE WHEN te.success = 0 THEN 1 ELSE 0 END) as failed
|
|
156
|
-
FROM tool_executions te
|
|
157
|
-
WHERE EXISTS (SELECT 1 FROM sessions s WHERE s.task_id = ? AND te.created_at >= s.start AND (s.end IS NULL OR te.created_at <= s.end))
|
|
158
|
-
`).get(params.task_id);
|
|
159
|
-
// Tool breakdown for this task
|
|
160
|
-
const tools = db.prepare(`
|
|
161
|
-
SELECT te.tool_name, COUNT(*) as call_count, ROUND(AVG(te.duration_ms)) as avg_ms
|
|
162
|
-
FROM tool_executions te
|
|
163
|
-
WHERE EXISTS (SELECT 1 FROM sessions s WHERE s.task_id = ? AND te.created_at >= s.start AND (s.end IS NULL OR te.created_at <= s.end))
|
|
164
|
-
GROUP BY te.tool_name
|
|
165
|
-
ORDER BY call_count DESC
|
|
166
|
-
`).all(params.task_id);
|
|
167
|
-
return successResponse({
|
|
168
|
-
task: { task_id: task.id, title: task.title, status: task.status, tool_calls: toolCalls.total, total_tool_duration_ms: toolCalls.duration_ms, failed_calls: toolCalls.failed, total_session_time_ms: sessionTime.total },
|
|
169
|
-
tool_breakdown: tools,
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
// All tasks (optionally filtered by project) — use subqueries to avoid cross-join
|
|
173
|
-
const projectFilter = params.project_id ? 'WHERE t.project_id = ?' : '';
|
|
174
|
-
const filterValues = params.project_id ? [params.project_id] : [];
|
|
175
|
-
const tasks = db.prepare(`
|
|
176
|
-
SELECT
|
|
177
|
-
t.id as task_id,
|
|
178
|
-
t.title,
|
|
179
|
-
t.status,
|
|
180
|
-
(SELECT COUNT(*) FROM tool_executions te WHERE EXISTS (SELECT 1 FROM sessions s WHERE s.task_id = t.id AND te.created_at >= s.start AND (s.end IS NULL OR te.created_at <= s.end))) as tool_calls,
|
|
181
|
-
(SELECT COALESCE(SUM(te.duration_ms), 0) FROM tool_executions te WHERE EXISTS (SELECT 1 FROM sessions s WHERE s.task_id = t.id AND te.created_at >= s.start AND (s.end IS NULL OR te.created_at <= s.end))) as total_tool_duration_ms,
|
|
182
|
-
(SELECT COALESCE(SUM(CASE WHEN end IS NOT NULL THEN (julianday(end) - julianday(start)) * 86400000 ELSE 0 END), 0) FROM sessions WHERE task_id = t.id) as total_session_time_ms
|
|
183
|
-
FROM tasks t
|
|
184
|
-
${projectFilter}
|
|
185
|
-
HAVING tool_calls > 0
|
|
186
|
-
ORDER BY tool_calls DESC
|
|
187
|
-
LIMIT 30
|
|
188
|
-
`).all(...filterValues);
|
|
189
|
-
return successResponse({ tasks });
|
|
190
|
-
});
|
|
191
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
-
export declare function createCheckpoint(params: {
|
|
3
|
-
task_id: number;
|
|
4
|
-
}): Promise<{
|
|
5
|
-
content: {
|
|
6
|
-
type: "text";
|
|
7
|
-
text: string;
|
|
8
|
-
}[];
|
|
9
|
-
}>;
|
|
10
|
-
export declare function getCheckpoint(params: {
|
|
11
|
-
task_id: number;
|
|
12
|
-
latest?: boolean;
|
|
13
|
-
}): Promise<{
|
|
14
|
-
content: {
|
|
15
|
-
type: "text";
|
|
16
|
-
text: string;
|
|
17
|
-
}[];
|
|
18
|
-
}>;
|
|
19
|
-
export declare function listCheckpoints(params: {
|
|
20
|
-
task_id: number;
|
|
21
|
-
}): Promise<{
|
|
22
|
-
content: {
|
|
23
|
-
type: "text";
|
|
24
|
-
text: string;
|
|
25
|
-
}[];
|
|
26
|
-
}>;
|
|
27
|
-
export declare function registerCheckpointTools(server: McpServer): void;
|
package/dist/tools/checkpoint.js
DELETED
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
import { readFileSync, writeFileSync, mkdirSync, readdirSync, unlinkSync } from 'fs';
|
|
3
|
-
import { resolve } from 'path';
|
|
4
|
-
import { homedir } from 'os';
|
|
5
|
-
import { getDb } from '../db.js';
|
|
6
|
-
import { successResponse, errorResponse } from '../helpers.js';
|
|
7
|
-
const CHECKPOINTS_DIR = resolve(homedir(), '.taskflow/checkpoints');
|
|
8
|
-
const MAX_CHECKPOINTS_PER_TASK = 10;
|
|
9
|
-
function getTaskDir(taskId) {
|
|
10
|
-
const dir = resolve(CHECKPOINTS_DIR, String(taskId));
|
|
11
|
-
mkdirSync(dir, { recursive: true });
|
|
12
|
-
return dir;
|
|
13
|
-
}
|
|
14
|
-
export async function createCheckpoint(params) {
|
|
15
|
-
const db = getDb();
|
|
16
|
-
const task = db.prepare('SELECT * FROM tasks WHERE id = ?').get(params.task_id);
|
|
17
|
-
if (!task)
|
|
18
|
-
return errorResponse(`Task ${params.task_id} not found`, 'NOT_FOUND');
|
|
19
|
-
// Gather task state
|
|
20
|
-
const deps = db.prepare('SELECT dependency_id FROM task_dependencies WHERE task_id = ?').all(params.task_id);
|
|
21
|
-
const recentActivity = db.prepare('SELECT * FROM activity_logs WHERE entity_id = ? AND entity_type = ? ORDER BY created_at DESC LIMIT 20').all(params.task_id, 'task');
|
|
22
|
-
const activeSession = db.prepare('SELECT * FROM sessions WHERE task_id = ? AND end IS NULL').get(params.task_id);
|
|
23
|
-
const totalTime = db.prepare('SELECT SUM(CASE WHEN end IS NOT NULL THEN (julianday(end) - julianday(start)) * 86400000 ELSE 0 END) as total FROM sessions WHERE task_id = ?').get(params.task_id);
|
|
24
|
-
// Tool stats during this task's sessions
|
|
25
|
-
const toolStats = db.prepare(`
|
|
26
|
-
SELECT te.tool_name, COUNT(*) as calls, ROUND(AVG(te.duration_ms)) as avg_ms
|
|
27
|
-
FROM tool_executions te
|
|
28
|
-
JOIN sessions s ON s.task_id = ? AND te.created_at >= s.start AND (s.end IS NULL OR te.created_at <= s.end)
|
|
29
|
-
GROUP BY te.tool_name ORDER BY calls DESC LIMIT 10
|
|
30
|
-
`).all(params.task_id);
|
|
31
|
-
const checkpoint = {
|
|
32
|
-
task_id: params.task_id,
|
|
33
|
-
timestamp: new Date().toISOString(),
|
|
34
|
-
task,
|
|
35
|
-
dependencies: deps.map(d => d.dependency_id),
|
|
36
|
-
recent_activity: recentActivity,
|
|
37
|
-
active_session: activeSession,
|
|
38
|
-
total_time_ms: totalTime.total ?? 0,
|
|
39
|
-
tool_stats: toolStats,
|
|
40
|
-
};
|
|
41
|
-
// Write checkpoint file
|
|
42
|
-
const taskDir = getTaskDir(params.task_id);
|
|
43
|
-
const filename = `${checkpoint.timestamp.replace(/[:.]/g, '-')}.json`;
|
|
44
|
-
const filepath = resolve(taskDir, filename);
|
|
45
|
-
writeFileSync(filepath, JSON.stringify(checkpoint, null, 2), 'utf-8');
|
|
46
|
-
// Prune old checkpoints
|
|
47
|
-
const files = readdirSync(taskDir).filter(f => f.endsWith('.json')).sort();
|
|
48
|
-
while (files.length > MAX_CHECKPOINTS_PER_TASK) {
|
|
49
|
-
const oldest = files.shift();
|
|
50
|
-
try {
|
|
51
|
-
unlinkSync(resolve(taskDir, oldest));
|
|
52
|
-
}
|
|
53
|
-
catch { /* ignore */ }
|
|
54
|
-
}
|
|
55
|
-
return successResponse({
|
|
56
|
-
task_id: params.task_id,
|
|
57
|
-
checkpoint: filename,
|
|
58
|
-
path: filepath,
|
|
59
|
-
total_checkpoints: Math.min(files.length, MAX_CHECKPOINTS_PER_TASK),
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
export async function getCheckpoint(params) {
|
|
63
|
-
const taskDir = resolve(CHECKPOINTS_DIR, String(params.task_id));
|
|
64
|
-
let files;
|
|
65
|
-
try {
|
|
66
|
-
files = readdirSync(taskDir).filter(f => f.endsWith('.json')).sort();
|
|
67
|
-
}
|
|
68
|
-
catch {
|
|
69
|
-
return errorResponse(`No checkpoints found for task ${params.task_id}`, 'NOT_FOUND');
|
|
70
|
-
}
|
|
71
|
-
if (files.length === 0) {
|
|
72
|
-
return errorResponse(`No checkpoints found for task ${params.task_id}`, 'NOT_FOUND');
|
|
73
|
-
}
|
|
74
|
-
// Return latest by default
|
|
75
|
-
const file = files[files.length - 1];
|
|
76
|
-
const data = JSON.parse(readFileSync(resolve(taskDir, file), 'utf-8'));
|
|
77
|
-
return successResponse({
|
|
78
|
-
checkpoint: file,
|
|
79
|
-
data,
|
|
80
|
-
available_checkpoints: files.length,
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
export async function listCheckpoints(params) {
|
|
84
|
-
const taskDir = resolve(CHECKPOINTS_DIR, String(params.task_id));
|
|
85
|
-
let files;
|
|
86
|
-
try {
|
|
87
|
-
files = readdirSync(taskDir).filter(f => f.endsWith('.json')).sort();
|
|
88
|
-
}
|
|
89
|
-
catch {
|
|
90
|
-
return successResponse({ task_id: params.task_id, checkpoints: [] });
|
|
91
|
-
}
|
|
92
|
-
return successResponse({
|
|
93
|
-
task_id: params.task_id,
|
|
94
|
-
checkpoints: files.map(f => ({
|
|
95
|
-
filename: f,
|
|
96
|
-
timestamp: f.replace('.json', '').replace(/-/g, (m, offset) => offset <= 9 ? '-' : offset <= 15 ? ':' : '.'),
|
|
97
|
-
})),
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
// ─── MCP registration ─────────────────────────────────────────────────
|
|
101
|
-
export function registerCheckpointTools(server) {
|
|
102
|
-
server.tool('create_checkpoint', 'Create a checkpoint snapshot of a task\'s current state. Captures: task data, dependencies, recent activity, active timer, tool stats. Useful before context switches or at key milestones.', { task_id: z.number().describe('The task ID to checkpoint') }, { readOnlyHint: false }, async (params) => createCheckpoint(params));
|
|
103
|
-
server.tool('get_checkpoint', 'Get the latest checkpoint for a task. Returns the full task snapshot — useful for resuming work after an interruption.', { task_id: z.number().describe('The task ID to get checkpoint for') }, { readOnlyHint: true }, async (params) => getCheckpoint(params));
|
|
104
|
-
server.tool('list_checkpoints', 'List all available checkpoints for a task.', { task_id: z.number().describe('The task ID to list checkpoints for') }, { readOnlyHint: true }, async (params) => listCheckpoints(params));
|
|
105
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
-
export declare function listNotifications(params: {
|
|
3
|
-
limit?: number;
|
|
4
|
-
unread_only?: boolean;
|
|
5
|
-
}): Promise<{
|
|
6
|
-
content: {
|
|
7
|
-
type: "text";
|
|
8
|
-
text: string;
|
|
9
|
-
}[];
|
|
10
|
-
}>;
|
|
11
|
-
export declare function markNotificationRead(params: {
|
|
12
|
-
id: number;
|
|
13
|
-
}): Promise<{
|
|
14
|
-
content: {
|
|
15
|
-
type: "text";
|
|
16
|
-
text: string;
|
|
17
|
-
}[];
|
|
18
|
-
}>;
|
|
19
|
-
export declare function markAllNotificationsRead(): Promise<{
|
|
20
|
-
content: {
|
|
21
|
-
type: "text";
|
|
22
|
-
text: string;
|
|
23
|
-
}[];
|
|
24
|
-
}>;
|
|
25
|
-
export declare function clearNotifications(): Promise<{
|
|
26
|
-
content: {
|
|
27
|
-
type: "text";
|
|
28
|
-
text: string;
|
|
29
|
-
}[];
|
|
30
|
-
}>;
|
|
31
|
-
export declare function registerNotificationTools(server: McpServer): void;
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
import { getDb } from '../db.js';
|
|
3
|
-
import { errorResponse, successResponse, broadcastChange } from '../helpers.js';
|
|
4
|
-
// ─── exported handler functions ───────────────────────────────────────
|
|
5
|
-
export async function listNotifications(params) {
|
|
6
|
-
const db = getDb();
|
|
7
|
-
const limit = params.limit ?? 50;
|
|
8
|
-
let sql = 'SELECT * FROM notifications';
|
|
9
|
-
const values = [];
|
|
10
|
-
if (params.unread_only) {
|
|
11
|
-
sql += ' WHERE read = 0';
|
|
12
|
-
}
|
|
13
|
-
sql += ' ORDER BY created_at DESC LIMIT ?';
|
|
14
|
-
values.push(limit);
|
|
15
|
-
const rows = db.prepare(sql).all(...values);
|
|
16
|
-
return successResponse(rows);
|
|
17
|
-
}
|
|
18
|
-
export async function markNotificationRead(params) {
|
|
19
|
-
const db = getDb();
|
|
20
|
-
const result = db
|
|
21
|
-
.prepare('UPDATE notifications SET read = 1 WHERE id = ?')
|
|
22
|
-
.run(params.id);
|
|
23
|
-
if (result.changes === 0) {
|
|
24
|
-
return errorResponse('Notification not found', 'NOT_FOUND');
|
|
25
|
-
}
|
|
26
|
-
const row = db
|
|
27
|
-
.prepare('SELECT * FROM notifications WHERE id = ?')
|
|
28
|
-
.get(params.id);
|
|
29
|
-
const notification = row;
|
|
30
|
-
broadcastChange('notification', 'notification_updated', notification);
|
|
31
|
-
return successResponse(notification);
|
|
32
|
-
}
|
|
33
|
-
export async function markAllNotificationsRead() {
|
|
34
|
-
const db = getDb();
|
|
35
|
-
const result = db
|
|
36
|
-
.prepare('UPDATE notifications SET read = 1 WHERE read = 0')
|
|
37
|
-
.run();
|
|
38
|
-
broadcastChange('notification', 'notifications_all_read', {});
|
|
39
|
-
return successResponse({ updated: result.changes });
|
|
40
|
-
}
|
|
41
|
-
export async function clearNotifications() {
|
|
42
|
-
const db = getDb();
|
|
43
|
-
const countRow = db
|
|
44
|
-
.prepare('SELECT COUNT(*) AS count FROM notifications')
|
|
45
|
-
.get();
|
|
46
|
-
db.prepare('DELETE FROM notifications').run();
|
|
47
|
-
broadcastChange('notification', 'notifications_cleared', {});
|
|
48
|
-
return successResponse({ deleted: countRow.count, message: 'Notifications cleared' });
|
|
49
|
-
}
|
|
50
|
-
// ─── MCP registration ─────────────────────────────────────────────────
|
|
51
|
-
export function registerNotificationTools(server) {
|
|
52
|
-
server.tool('list_notifications', 'List notifications. Check with unread_only=true at conversation start to surface important updates for the user.', {
|
|
53
|
-
limit: z.number().optional(),
|
|
54
|
-
unread_only: z.boolean().optional(),
|
|
55
|
-
}, { readOnlyHint: true }, async (params) => listNotifications(params));
|
|
56
|
-
server.tool('mark_notification_read', 'Mark a notification as read after surfacing it to the user.', { id: z.number() }, { readOnlyHint: false }, async (params) => markNotificationRead(params));
|
|
57
|
-
server.tool('mark_all_notifications_read', 'Mark all unread notifications as read. Call after the user has been briefed on pending notifications.', {}, { readOnlyHint: false }, async () => markAllNotificationsRead());
|
|
58
|
-
server.tool('clear_notifications', 'Delete all notifications. Use with caution — this is irreversible.', {}, { destructiveHint: true }, async () => clearNotifications());
|
|
59
|
-
}
|
package/dist/tools/projects.d.ts
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
-
export declare function createProject(params: {
|
|
3
|
-
name: string;
|
|
4
|
-
color?: string;
|
|
5
|
-
type?: string;
|
|
6
|
-
description?: string;
|
|
7
|
-
}): Promise<{
|
|
8
|
-
content: {
|
|
9
|
-
type: "text";
|
|
10
|
-
text: string;
|
|
11
|
-
}[];
|
|
12
|
-
}>;
|
|
13
|
-
export declare function listProjects(): Promise<{
|
|
14
|
-
content: {
|
|
15
|
-
type: "text";
|
|
16
|
-
text: string;
|
|
17
|
-
}[];
|
|
18
|
-
}>;
|
|
19
|
-
export declare function getProject(params: {
|
|
20
|
-
id: number;
|
|
21
|
-
}): Promise<{
|
|
22
|
-
content: {
|
|
23
|
-
type: "text";
|
|
24
|
-
text: string;
|
|
25
|
-
}[];
|
|
26
|
-
}>;
|
|
27
|
-
export declare function updateProject(params: {
|
|
28
|
-
id: number;
|
|
29
|
-
name?: string;
|
|
30
|
-
color?: string;
|
|
31
|
-
type?: string;
|
|
32
|
-
description?: string;
|
|
33
|
-
}): Promise<{
|
|
34
|
-
content: {
|
|
35
|
-
type: "text";
|
|
36
|
-
text: string;
|
|
37
|
-
}[];
|
|
38
|
-
}>;
|
|
39
|
-
export declare function deleteProject(params: {
|
|
40
|
-
id: number;
|
|
41
|
-
}): Promise<{
|
|
42
|
-
content: {
|
|
43
|
-
type: "text";
|
|
44
|
-
text: string;
|
|
45
|
-
}[];
|
|
46
|
-
}>;
|
|
47
|
-
export declare function searchProjects(params: {
|
|
48
|
-
query: string;
|
|
49
|
-
}): Promise<{
|
|
50
|
-
content: {
|
|
51
|
-
type: "text";
|
|
52
|
-
text: string;
|
|
53
|
-
}[];
|
|
54
|
-
}>;
|
|
55
|
-
export declare function registerProjectTools(server: McpServer): void;
|
package/dist/tools/projects.js
DELETED
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
import { getDb } from '../db.js';
|
|
3
|
-
import { logActivity, errorResponse, successResponse, now, broadcastChange } from '../helpers.js';
|
|
4
|
-
import { ProjectType } from '../types.js';
|
|
5
|
-
function parseTask(row) {
|
|
6
|
-
return {
|
|
7
|
-
...row,
|
|
8
|
-
dependencies: JSON.parse(row.dependencies),
|
|
9
|
-
links: JSON.parse(row.links),
|
|
10
|
-
tags: JSON.parse(row.tags),
|
|
11
|
-
};
|
|
12
|
-
}
|
|
13
|
-
// ─── exported handler functions ───────────────────────────────────────
|
|
14
|
-
export async function createProject(params) {
|
|
15
|
-
const db = getDb();
|
|
16
|
-
const { name, color = '#de8eff', type = 'active_project', description, } = params;
|
|
17
|
-
const ts = now();
|
|
18
|
-
const result = db.prepare(`INSERT INTO projects (name, color, type, description, created_at, updated_at)
|
|
19
|
-
VALUES (?, ?, ?, ?, ?, ?)`).run(name, color, type, description ?? null, ts, ts);
|
|
20
|
-
const project = db.prepare('SELECT * FROM projects WHERE id = ?').get(result.lastInsertRowid);
|
|
21
|
-
logActivity('project_created', name, { entityType: 'project', entityId: project.id });
|
|
22
|
-
const createdProject = project;
|
|
23
|
-
broadcastChange('project', 'project_created', createdProject);
|
|
24
|
-
return successResponse(createdProject);
|
|
25
|
-
}
|
|
26
|
-
export async function listProjects() {
|
|
27
|
-
const db = getDb();
|
|
28
|
-
const rows = db.prepare(`SELECT projects.*, COUNT(tasks.id) AS task_count
|
|
29
|
-
FROM projects
|
|
30
|
-
LEFT JOIN tasks ON tasks.project_id = projects.id
|
|
31
|
-
GROUP BY projects.id`).all();
|
|
32
|
-
return successResponse(rows);
|
|
33
|
-
}
|
|
34
|
-
export async function getProject(params) {
|
|
35
|
-
const db = getDb();
|
|
36
|
-
const project = db.prepare('SELECT * FROM projects WHERE id = ?').get(params.id);
|
|
37
|
-
if (!project)
|
|
38
|
-
return errorResponse('Project not found', 'NOT_FOUND');
|
|
39
|
-
const tasks = db.prepare('SELECT * FROM tasks WHERE project_id = ?').all(params.id);
|
|
40
|
-
return successResponse({
|
|
41
|
-
...project,
|
|
42
|
-
tasks: tasks.map(parseTask),
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
export async function updateProject(params) {
|
|
46
|
-
const db = getDb();
|
|
47
|
-
const existing = db.prepare('SELECT * FROM projects WHERE id = ?').get(params.id);
|
|
48
|
-
if (!existing)
|
|
49
|
-
return errorResponse('Project not found', 'NOT_FOUND');
|
|
50
|
-
const updates = {};
|
|
51
|
-
if (params.name !== undefined)
|
|
52
|
-
updates.name = params.name;
|
|
53
|
-
if (params.color !== undefined)
|
|
54
|
-
updates.color = params.color;
|
|
55
|
-
if (params.type !== undefined)
|
|
56
|
-
updates.type = params.type;
|
|
57
|
-
if (params.description !== undefined)
|
|
58
|
-
updates.description = params.description;
|
|
59
|
-
if (Object.keys(updates).length === 0) {
|
|
60
|
-
return successResponse(existing);
|
|
61
|
-
}
|
|
62
|
-
updates.updated_at = now();
|
|
63
|
-
const setClauses = Object.keys(updates).map(k => `${k} = ?`).join(', ');
|
|
64
|
-
const vals = Object.values(updates);
|
|
65
|
-
db.prepare(`UPDATE projects SET ${setClauses} WHERE id = ?`).run(...vals, params.id);
|
|
66
|
-
logActivity('project_updated', params.name ?? existing.name, { entityType: 'project', entityId: params.id });
|
|
67
|
-
const updated = db.prepare('SELECT * FROM projects WHERE id = ?').get(params.id);
|
|
68
|
-
const updatedProject = updated;
|
|
69
|
-
broadcastChange('project', 'project_updated', updatedProject);
|
|
70
|
-
return successResponse(updatedProject);
|
|
71
|
-
}
|
|
72
|
-
export async function deleteProject(params) {
|
|
73
|
-
const db = getDb();
|
|
74
|
-
const project = db.prepare('SELECT * FROM projects WHERE id = ?').get(params.id);
|
|
75
|
-
if (!project)
|
|
76
|
-
return errorResponse('Project not found', 'NOT_FOUND');
|
|
77
|
-
// FK ON DELETE SET NULL handles unlinking tasks automatically
|
|
78
|
-
db.prepare('DELETE FROM projects WHERE id = ?').run(params.id);
|
|
79
|
-
logActivity('project_deleted', project.name, { entityType: 'project', entityId: params.id });
|
|
80
|
-
broadcastChange('project', 'project_deleted', { id: params.id });
|
|
81
|
-
return successResponse({ deleted: true, id: params.id });
|
|
82
|
-
}
|
|
83
|
-
export async function searchProjects(params) {
|
|
84
|
-
const db = getDb();
|
|
85
|
-
const like = `%${params.query}%`;
|
|
86
|
-
const rows = db.prepare(`SELECT projects.*, COUNT(tasks.id) AS task_count
|
|
87
|
-
FROM projects
|
|
88
|
-
LEFT JOIN tasks ON tasks.project_id = projects.id
|
|
89
|
-
WHERE projects.name LIKE ? COLLATE NOCASE OR projects.description LIKE ? COLLATE NOCASE
|
|
90
|
-
GROUP BY projects.id`).all(like, like);
|
|
91
|
-
return successResponse(rows);
|
|
92
|
-
}
|
|
93
|
-
// ─── MCP registration ─────────────────────────────────────────────────
|
|
94
|
-
export function registerProjectTools(server) {
|
|
95
|
-
server.tool('create_project', 'Create a new project. Projects group related tasks and track time across them.', {
|
|
96
|
-
name: z.string(),
|
|
97
|
-
color: z.string().optional(),
|
|
98
|
-
type: ProjectType.optional(),
|
|
99
|
-
description: z.string().optional(),
|
|
100
|
-
}, { readOnlyHint: false }, async (params) => createProject(params));
|
|
101
|
-
server.tool('list_projects', 'List all projects with task count. Call this at conversation start to understand the workspace.', {}, { readOnlyHint: true }, async () => listProjects());
|
|
102
|
-
server.tool('get_project', 'Get a project by ID with all its tasks. Use this to understand the full scope of a project before starting work.', { id: z.number() }, { readOnlyHint: true }, async (params) => getProject(params));
|
|
103
|
-
server.tool('update_project', 'Update project fields such as name, color, type, or description.', {
|
|
104
|
-
id: z.number(),
|
|
105
|
-
name: z.string().optional(),
|
|
106
|
-
color: z.string().optional(),
|
|
107
|
-
type: ProjectType.optional(),
|
|
108
|
-
description: z.string().optional(),
|
|
109
|
-
}, { readOnlyHint: false }, async (params) => updateProject(params));
|
|
110
|
-
server.tool('delete_project', 'Delete a project by ID. Tasks under this project will be unlinked (project_id set to NULL), not deleted.', { id: z.number() }, { destructiveHint: true }, async (params) => deleteProject(params));
|
|
111
|
-
server.tool('search_projects', 'Search projects by name or description. Use this to find projects related to your current work.', { query: z.string() }, { readOnlyHint: true }, async (params) => searchProjects(params));
|
|
112
|
-
}
|
package/dist/tools/settings.d.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
-
export declare function getSetting(params: {
|
|
3
|
-
key: string;
|
|
4
|
-
}): Promise<{
|
|
5
|
-
content: {
|
|
6
|
-
type: "text";
|
|
7
|
-
text: string;
|
|
8
|
-
}[];
|
|
9
|
-
}>;
|
|
10
|
-
export declare function updateSetting(params: {
|
|
11
|
-
key: string;
|
|
12
|
-
value: unknown;
|
|
13
|
-
}): Promise<{
|
|
14
|
-
content: {
|
|
15
|
-
type: "text";
|
|
16
|
-
text: string;
|
|
17
|
-
}[];
|
|
18
|
-
}>;
|
|
19
|
-
export declare function registerSettingsTools(server: McpServer): void;
|