@hasna/todos 0.11.37 → 0.11.38
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 +16 -1
- package/dist/cli/index.js +615 -87
- package/dist/index.js +18 -17
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +562 -71
- package/dist/mcp/token-utils.d.ts +15 -0
- package/dist/mcp/token-utils.d.ts.map +1 -0
- package/dist/mcp/tools/task-adv-tools.d.ts.map +1 -1
- package/dist/mcp/tools/task-crud.d.ts.map +1 -1
- package/dist/mcp/tools/task-meta-tools.d.ts.map +1 -1
- package/dist/mcp/tools/task-project-tools.d.ts.map +1 -1
- package/dist/mcp/tools/task-workflow-tools.d.ts.map +1 -1
- package/dist/sdk/client.d.ts +30 -8
- package/dist/sdk/client.d.ts.map +1 -1
- package/dist/sdk/types.d.ts +6 -0
- package/dist/sdk/types.d.ts.map +1 -1
- package/dist/server/index.js +47 -15
- package/dist/server/routes.d.ts +3 -3
- package/dist/server/routes.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -8290,6 +8290,18 @@ var init_orgs = __esm(() => {
|
|
|
8290
8290
|
|
|
8291
8291
|
// src/server/routes.ts
|
|
8292
8292
|
import { join as join8, resolve as resolve5, sep } from "path";
|
|
8293
|
+
function parseFieldsParam(url) {
|
|
8294
|
+
const fieldsParam = url.searchParams.get("fields");
|
|
8295
|
+
return fieldsParam ? fieldsParam.split(",").map((f) => f.trim()).filter(Boolean) : undefined;
|
|
8296
|
+
}
|
|
8297
|
+
function parseBoundedLimit(value, fallback, max) {
|
|
8298
|
+
if (!value)
|
|
8299
|
+
return fallback;
|
|
8300
|
+
const parsed = parseInt(value, 10);
|
|
8301
|
+
if (!Number.isFinite(parsed) || parsed <= 0)
|
|
8302
|
+
return fallback;
|
|
8303
|
+
return Math.min(parsed, max);
|
|
8304
|
+
}
|
|
8293
8305
|
function handleSseEvents(_req, url, ctx) {
|
|
8294
8306
|
const agentId = url.searchParams.get("agent_id") || undefined;
|
|
8295
8307
|
const projectId = url.searchParams.get("project_id") || undefined;
|
|
@@ -8402,8 +8414,7 @@ async function handleListTasks(_req, url, _ctx, json2, taskToSummary2) {
|
|
|
8402
8414
|
const agentId = url.searchParams.get("agent_id") || undefined;
|
|
8403
8415
|
const limitParam = url.searchParams.get("limit");
|
|
8404
8416
|
const offsetParam = url.searchParams.get("offset");
|
|
8405
|
-
const
|
|
8406
|
-
const fields = fieldsParam ? fieldsParam.split(",").map((f) => f.trim()).filter(Boolean) : undefined;
|
|
8417
|
+
const fields = parseFieldsParam(url);
|
|
8407
8418
|
const tasks = listTasks({
|
|
8408
8419
|
status,
|
|
8409
8420
|
project_id: projectId,
|
|
@@ -8504,8 +8515,9 @@ function handleTasksNext(_req, url, _ctx, json2, taskToSummary2) {
|
|
|
8504
8515
|
try {
|
|
8505
8516
|
const projectId = url.searchParams.get("project_id") || undefined;
|
|
8506
8517
|
const agentId = url.searchParams.get("agent_id") || undefined;
|
|
8518
|
+
const fields = parseFieldsParam(url);
|
|
8507
8519
|
const task = getNextTask(agentId, projectId ? { project_id: projectId } : undefined);
|
|
8508
|
-
return json2({ task: task ? taskToSummary2(task) : null });
|
|
8520
|
+
return json2({ task: task ? taskToSummary2(task, fields) : null });
|
|
8509
8521
|
} catch (e) {
|
|
8510
8522
|
return json2({ error: e instanceof Error ? e.message : "Failed" }, 500);
|
|
8511
8523
|
}
|
|
@@ -8523,8 +8535,9 @@ function handleTasksStale(_req, url, _ctx, json2, taskToSummary2) {
|
|
|
8523
8535
|
try {
|
|
8524
8536
|
const projectId = url.searchParams.get("project_id") || undefined;
|
|
8525
8537
|
const minutes = parseInt(url.searchParams.get("minutes") || "30", 10);
|
|
8538
|
+
const fields = parseFieldsParam(url);
|
|
8526
8539
|
const tasks = getStaleTasks(minutes, projectId ? { project_id: projectId } : undefined);
|
|
8527
|
-
return json2({ tasks: tasks.map((t) => taskToSummary2(t)), count: tasks.length });
|
|
8540
|
+
return json2({ tasks: tasks.map((t) => taskToSummary2(t, fields)), count: tasks.length });
|
|
8528
8541
|
} catch (e) {
|
|
8529
8542
|
return json2({ error: e instanceof Error ? e.message : "Failed" }, 500);
|
|
8530
8543
|
}
|
|
@@ -8535,8 +8548,9 @@ function handleTasksChanged(_req, url, _ctx, json2, taskToSummary2) {
|
|
|
8535
8548
|
if (!since)
|
|
8536
8549
|
return json2({ error: "since parameter required (ISO date string)" }, 400);
|
|
8537
8550
|
const projectId = url.searchParams.get("project_id") || undefined;
|
|
8551
|
+
const fields = parseFieldsParam(url);
|
|
8538
8552
|
const tasks = getTasksChangedSince(since, projectId ? { project_id: projectId } : undefined);
|
|
8539
|
-
return json2({ tasks: tasks.map((t) => taskToSummary2(t)), count: tasks.length, since });
|
|
8553
|
+
return json2({ tasks: tasks.map((t) => taskToSummary2(t, fields)), count: tasks.length, since });
|
|
8540
8554
|
} catch (e) {
|
|
8541
8555
|
return json2({ error: e instanceof Error ? e.message : "Failed" }, 500);
|
|
8542
8556
|
}
|
|
@@ -8545,11 +8559,12 @@ function handleTasksContext(_req, url, _ctx, json2, taskToSummary2) {
|
|
|
8545
8559
|
const agentId = url.searchParams.get("agent_id") || undefined;
|
|
8546
8560
|
const projectId = url.searchParams.get("project_id") || undefined;
|
|
8547
8561
|
const format = url.searchParams.get("format") || "text";
|
|
8562
|
+
const fields = parseFieldsParam(url);
|
|
8548
8563
|
const filters = projectId ? { project_id: projectId } : undefined;
|
|
8549
8564
|
const status = getStatus(filters, agentId);
|
|
8550
8565
|
const next = getNextTask(agentId, filters);
|
|
8551
8566
|
if (format === "json") {
|
|
8552
|
-
return json2({ status, next_task: next ? taskToSummary2(next) : null });
|
|
8567
|
+
return json2({ status, next_task: next ? taskToSummary2(next, fields) : null });
|
|
8553
8568
|
}
|
|
8554
8569
|
const lines = [];
|
|
8555
8570
|
lines.push(`Tasks: ${status.pending} pending | ${status.in_progress} active | ${status.completed} done`);
|
|
@@ -8574,7 +8589,7 @@ function handleTaskAttachments(id, _ctx, json2) {
|
|
|
8574
8589
|
const attachmentIds = evidence.attachments || [];
|
|
8575
8590
|
return json2({ task_id: id, short_id: task.short_id, attachment_ids: attachmentIds, count: attachmentIds.length, files_changed: evidence.files_changed, commit_hash: evidence.commit_hash, notes: evidence.notes });
|
|
8576
8591
|
}
|
|
8577
|
-
async function handleTaskProgress(id, req, method, _ctx, json2) {
|
|
8592
|
+
async function handleTaskProgress(id, req, method, _ctx, json2, url) {
|
|
8578
8593
|
const task = getTask(id);
|
|
8579
8594
|
if (!task)
|
|
8580
8595
|
return json2({ error: "Task not found" }, 404);
|
|
@@ -8582,7 +8597,21 @@ async function handleTaskProgress(id, req, method, _ctx, json2) {
|
|
|
8582
8597
|
const all = listComments(id);
|
|
8583
8598
|
const progress = all.filter((c) => c.type === "progress");
|
|
8584
8599
|
const latest = progress[progress.length - 1] || null;
|
|
8585
|
-
|
|
8600
|
+
const format = url?.searchParams.get("format") || "compact";
|
|
8601
|
+
const limit = parseBoundedLimit(url?.searchParams.get("limit") || null, 20, 200);
|
|
8602
|
+
const progressEntries = format === "full" ? progress : progress.slice(-limit);
|
|
8603
|
+
return json2({
|
|
8604
|
+
task_id: id,
|
|
8605
|
+
progress_entries: progressEntries,
|
|
8606
|
+
latest,
|
|
8607
|
+
count: progress.length,
|
|
8608
|
+
summary: {
|
|
8609
|
+
total: progress.length,
|
|
8610
|
+
returned: progressEntries.length,
|
|
8611
|
+
omitted: Math.max(0, progress.length - progressEntries.length),
|
|
8612
|
+
format
|
|
8613
|
+
}
|
|
8614
|
+
});
|
|
8586
8615
|
}
|
|
8587
8616
|
if (method === "POST") {
|
|
8588
8617
|
try {
|
|
@@ -8597,11 +8626,11 @@ async function handleTaskProgress(id, req, method, _ctx, json2) {
|
|
|
8597
8626
|
}
|
|
8598
8627
|
return null;
|
|
8599
8628
|
}
|
|
8600
|
-
function handleGetTask(id, _ctx, json2, taskToSummary2) {
|
|
8629
|
+
function handleGetTask(id, _ctx, json2, taskToSummary2, url) {
|
|
8601
8630
|
const task = getTask(id);
|
|
8602
8631
|
if (!task)
|
|
8603
8632
|
return json2({ error: "Task not found" }, 404);
|
|
8604
|
-
return json2(taskToSummary2(task));
|
|
8633
|
+
return json2(taskToSummary2(task, url ? parseFieldsParam(url) : undefined));
|
|
8605
8634
|
}
|
|
8606
8635
|
async function handlePatchTask(id, req, _ctx, json2, taskToSummary2) {
|
|
8607
8636
|
try {
|
|
@@ -8864,8 +8893,11 @@ function handleActivity(_req, url, _ctx, json2) {
|
|
|
8864
8893
|
const limit = parseInt(url.searchParams.get("limit") || "50", 10);
|
|
8865
8894
|
return json2(getRecentActivity(limit));
|
|
8866
8895
|
}
|
|
8867
|
-
function handleTaskHistory(id, _ctx, json2) {
|
|
8868
|
-
|
|
8896
|
+
function handleTaskHistory(id, _ctx, json2, url) {
|
|
8897
|
+
const history = getTaskHistory(id);
|
|
8898
|
+
const format = url?.searchParams.get("format") || "compact";
|
|
8899
|
+
const limit = parseBoundedLimit(url?.searchParams.get("limit") || null, 20, 500);
|
|
8900
|
+
return json2(format === "full" ? history : history.slice(0, limit));
|
|
8869
8901
|
}
|
|
8870
8902
|
function handleListWebhooks(_ctx, json2) {
|
|
8871
8903
|
return json2(listWebhooks());
|
|
@@ -9260,7 +9292,7 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
9260
9292
|
}
|
|
9261
9293
|
const progressMatch = path.match(/^\/api\/tasks\/([^/]+)\/progress$/);
|
|
9262
9294
|
if (progressMatch) {
|
|
9263
|
-
const res = await handleTaskProgress(progressMatch[1], req, method, ctx, json);
|
|
9295
|
+
const res = await handleTaskProgress(progressMatch[1], req, method, ctx, json, url);
|
|
9264
9296
|
if (res !== null)
|
|
9265
9297
|
return res;
|
|
9266
9298
|
}
|
|
@@ -9268,7 +9300,7 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
9268
9300
|
if (taskMatch) {
|
|
9269
9301
|
const id = taskMatch[1];
|
|
9270
9302
|
if (method === "GET") {
|
|
9271
|
-
return handleGetTask(id, ctx, jsonWithCors, taskToSummary);
|
|
9303
|
+
return handleGetTask(id, ctx, jsonWithCors, taskToSummary, url);
|
|
9272
9304
|
}
|
|
9273
9305
|
if (method === "PATCH") {
|
|
9274
9306
|
return handlePatchTask(id, req, ctx, jsonWithCors, taskToSummary);
|
|
@@ -9359,7 +9391,7 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
9359
9391
|
}
|
|
9360
9392
|
const historyMatch = path.match(/^\/api\/tasks\/([^/]+)\/history$/);
|
|
9361
9393
|
if (historyMatch && method === "GET") {
|
|
9362
|
-
return handleTaskHistory(historyMatch[1], ctx, json);
|
|
9394
|
+
return handleTaskHistory(historyMatch[1], ctx, json, url);
|
|
9363
9395
|
}
|
|
9364
9396
|
if (path === "/api/webhooks" && method === "GET") {
|
|
9365
9397
|
return handleListWebhooks(ctx, json);
|
|
@@ -26879,6 +26911,384 @@ var init_dispatch2 = __esm(() => {
|
|
|
26879
26911
|
init_database();
|
|
26880
26912
|
});
|
|
26881
26913
|
|
|
26914
|
+
// src/mcp/token-utils.ts
|
|
26915
|
+
function splitTokens(value) {
|
|
26916
|
+
return (value || "").split(",").map((item) => item.trim().toLowerCase()).filter(Boolean);
|
|
26917
|
+
}
|
|
26918
|
+
function addGroupTools(toolNames, groupName) {
|
|
26919
|
+
const tools = MCP_TOOL_GROUPS[groupName];
|
|
26920
|
+
if (!tools)
|
|
26921
|
+
return false;
|
|
26922
|
+
for (const tool of tools)
|
|
26923
|
+
toolNames.add(tool);
|
|
26924
|
+
return true;
|
|
26925
|
+
}
|
|
26926
|
+
function shouldRegisterToolForProfile(name, profileValue = process.env["TODOS_PROFILE"], groupValue = process.env["TODOS_TOOL_GROUPS"]) {
|
|
26927
|
+
const profileTokens = splitTokens(profileValue || "minimal");
|
|
26928
|
+
const groupTokens = splitTokens(groupValue);
|
|
26929
|
+
if (profileTokens.includes("full") || profileTokens.includes("all"))
|
|
26930
|
+
return true;
|
|
26931
|
+
const tools = new Set;
|
|
26932
|
+
let matchedProfile = false;
|
|
26933
|
+
for (const token of profileTokens) {
|
|
26934
|
+
const profileGroups = MCP_PROFILE_GROUPS[token];
|
|
26935
|
+
if (profileGroups) {
|
|
26936
|
+
matchedProfile = true;
|
|
26937
|
+
for (const group of profileGroups)
|
|
26938
|
+
addGroupTools(tools, group);
|
|
26939
|
+
continue;
|
|
26940
|
+
}
|
|
26941
|
+
if (addGroupTools(tools, token)) {
|
|
26942
|
+
matchedProfile = true;
|
|
26943
|
+
continue;
|
|
26944
|
+
}
|
|
26945
|
+
if (token.startsWith("tool:")) {
|
|
26946
|
+
matchedProfile = true;
|
|
26947
|
+
tools.add(token.slice("tool:".length));
|
|
26948
|
+
}
|
|
26949
|
+
}
|
|
26950
|
+
if (!matchedProfile) {
|
|
26951
|
+
addGroupTools(tools, "core");
|
|
26952
|
+
}
|
|
26953
|
+
for (const token of groupTokens) {
|
|
26954
|
+
if (token === "full" || token === "all")
|
|
26955
|
+
return true;
|
|
26956
|
+
if (!addGroupTools(tools, token) && token.startsWith("tool:")) {
|
|
26957
|
+
tools.add(token.slice("tool:".length));
|
|
26958
|
+
}
|
|
26959
|
+
}
|
|
26960
|
+
return tools.has(name);
|
|
26961
|
+
}
|
|
26962
|
+
function truncateText(value, maxChars = 240) {
|
|
26963
|
+
if (!value)
|
|
26964
|
+
return null;
|
|
26965
|
+
if (maxChars <= 0)
|
|
26966
|
+
return "";
|
|
26967
|
+
if (value.length <= maxChars)
|
|
26968
|
+
return value;
|
|
26969
|
+
return `${value.slice(0, Math.max(0, maxChars - 3))}...`;
|
|
26970
|
+
}
|
|
26971
|
+
function compactTask(task, maxDescriptionChars = 180) {
|
|
26972
|
+
const summary = {
|
|
26973
|
+
id: task.id,
|
|
26974
|
+
short_id: task.short_id || task.id.slice(0, 8),
|
|
26975
|
+
title: task.title,
|
|
26976
|
+
status: task.status,
|
|
26977
|
+
priority: task.priority,
|
|
26978
|
+
assigned_to: task.assigned_to,
|
|
26979
|
+
project_id: task.project_id,
|
|
26980
|
+
due_at: task.due_at,
|
|
26981
|
+
updated_at: task.updated_at
|
|
26982
|
+
};
|
|
26983
|
+
if (task.tags?.length)
|
|
26984
|
+
summary["tags"] = task.tags.slice(0, 8);
|
|
26985
|
+
const description = truncateText(task.description, maxDescriptionChars);
|
|
26986
|
+
if (description)
|
|
26987
|
+
summary["description"] = description;
|
|
26988
|
+
return summary;
|
|
26989
|
+
}
|
|
26990
|
+
function compactStatus(status) {
|
|
26991
|
+
const compact = {};
|
|
26992
|
+
for (const key of [
|
|
26993
|
+
"total",
|
|
26994
|
+
"pending",
|
|
26995
|
+
"in_progress",
|
|
26996
|
+
"completed",
|
|
26997
|
+
"failed",
|
|
26998
|
+
"cancelled",
|
|
26999
|
+
"stale_count",
|
|
27000
|
+
"overdue_recurring",
|
|
27001
|
+
"blocked_count"
|
|
27002
|
+
]) {
|
|
27003
|
+
if (status[key] !== undefined)
|
|
27004
|
+
compact[key] = status[key];
|
|
27005
|
+
}
|
|
27006
|
+
const activeWork = status["active_work"];
|
|
27007
|
+
if (Array.isArray(activeWork)) {
|
|
27008
|
+
compact["active_work"] = activeWork.slice(0, 5).map((task) => {
|
|
27009
|
+
if (!task || typeof task !== "object")
|
|
27010
|
+
return task;
|
|
27011
|
+
const record = task;
|
|
27012
|
+
return {
|
|
27013
|
+
id: record["id"],
|
|
27014
|
+
short_id: record["short_id"],
|
|
27015
|
+
title: record["title"],
|
|
27016
|
+
priority: record["priority"],
|
|
27017
|
+
assigned_to: record["assigned_to"],
|
|
27018
|
+
updated_at: record["updated_at"]
|
|
27019
|
+
};
|
|
27020
|
+
});
|
|
27021
|
+
if (activeWork.length > 5)
|
|
27022
|
+
compact["active_work_omitted"] = activeWork.length - 5;
|
|
27023
|
+
}
|
|
27024
|
+
const blocked = status["blocked"];
|
|
27025
|
+
if (Array.isArray(blocked)) {
|
|
27026
|
+
compact["blocked"] = blocked.slice(0, 5);
|
|
27027
|
+
if (blocked.length > 5)
|
|
27028
|
+
compact["blocked_omitted"] = blocked.length - 5;
|
|
27029
|
+
}
|
|
27030
|
+
return compact;
|
|
27031
|
+
}
|
|
27032
|
+
function compactHandoff(handoff) {
|
|
27033
|
+
if (!handoff || typeof handoff !== "object")
|
|
27034
|
+
return handoff ?? null;
|
|
27035
|
+
const record = handoff;
|
|
27036
|
+
return {
|
|
27037
|
+
id: record["id"],
|
|
27038
|
+
from_agent: record["from_agent"],
|
|
27039
|
+
to_agent: record["to_agent"],
|
|
27040
|
+
summary: truncateText(typeof record["summary"] === "string" ? record["summary"] : null, 240),
|
|
27041
|
+
created_at: record["created_at"]
|
|
27042
|
+
};
|
|
27043
|
+
}
|
|
27044
|
+
function compactJson(value) {
|
|
27045
|
+
return JSON.stringify(value);
|
|
27046
|
+
}
|
|
27047
|
+
function tokenTelemetryEnabled() {
|
|
27048
|
+
return /^(1|true|yes|on)$/i.test(process.env["TODOS_MCP_TOKEN_TELEMETRY"] || "");
|
|
27049
|
+
}
|
|
27050
|
+
function withMcpTokenTelemetry(result, toolName, enabled = tokenTelemetryEnabled()) {
|
|
27051
|
+
if (!enabled || !result || typeof result !== "object")
|
|
27052
|
+
return result;
|
|
27053
|
+
const response = result;
|
|
27054
|
+
if (!Array.isArray(response.content))
|
|
27055
|
+
return result;
|
|
27056
|
+
const content = response.content;
|
|
27057
|
+
const textChars = content.reduce((sum, item) => item["type"] === "text" && typeof item["text"] === "string" ? sum + item["text"].length : sum, 0);
|
|
27058
|
+
const telemetry = `[mcp-token-telemetry tool=${toolName} chars=${textChars} approx_tokens=${Math.max(1, Math.ceil(textChars / 4))}]`;
|
|
27059
|
+
const nextContent = [...content];
|
|
27060
|
+
let lastTextIndex = -1;
|
|
27061
|
+
for (let index = nextContent.length - 1;index >= 0; index -= 1) {
|
|
27062
|
+
const item = nextContent[index];
|
|
27063
|
+
if (item["type"] === "text" && typeof item["text"] === "string") {
|
|
27064
|
+
lastTextIndex = index;
|
|
27065
|
+
break;
|
|
27066
|
+
}
|
|
27067
|
+
}
|
|
27068
|
+
if (lastTextIndex >= 0) {
|
|
27069
|
+
const item = nextContent[lastTextIndex];
|
|
27070
|
+
nextContent[lastTextIndex] = { ...item, text: `${item["text"]}
|
|
27071
|
+
|
|
27072
|
+
${telemetry}` };
|
|
27073
|
+
} else {
|
|
27074
|
+
nextContent.push({ type: "text", text: telemetry });
|
|
27075
|
+
}
|
|
27076
|
+
return { ...response, content: nextContent };
|
|
27077
|
+
}
|
|
27078
|
+
function installMcpTokenTelemetry(server) {
|
|
27079
|
+
const originalTool = server.tool.bind(server);
|
|
27080
|
+
server.tool = (...args) => {
|
|
27081
|
+
const name = String(args[0]);
|
|
27082
|
+
const last = args[args.length - 1];
|
|
27083
|
+
if (typeof last !== "function")
|
|
27084
|
+
return originalTool(...args);
|
|
27085
|
+
const wrapped = async (...handlerArgs) => {
|
|
27086
|
+
const result = await last(...handlerArgs);
|
|
27087
|
+
return withMcpTokenTelemetry(result, name);
|
|
27088
|
+
};
|
|
27089
|
+
return originalTool(...args.slice(0, -1), wrapped);
|
|
27090
|
+
};
|
|
27091
|
+
}
|
|
27092
|
+
var CORE_MCP_TOOLS, MCP_TOOL_GROUPS, MCP_PROFILE_GROUPS;
|
|
27093
|
+
var init_token_utils = __esm(() => {
|
|
27094
|
+
CORE_MCP_TOOLS = new Set([
|
|
27095
|
+
"add_comment",
|
|
27096
|
+
"bootstrap",
|
|
27097
|
+
"claim_next_task",
|
|
27098
|
+
"complete_task",
|
|
27099
|
+
"create_task",
|
|
27100
|
+
"fail_task",
|
|
27101
|
+
"get_context",
|
|
27102
|
+
"get_health",
|
|
27103
|
+
"get_next_task",
|
|
27104
|
+
"get_status",
|
|
27105
|
+
"get_task",
|
|
27106
|
+
"get_tasks_changed_since",
|
|
27107
|
+
"heartbeat",
|
|
27108
|
+
"list_agents",
|
|
27109
|
+
"list_tasks",
|
|
27110
|
+
"register_agent",
|
|
27111
|
+
"release_agent",
|
|
27112
|
+
"start_task",
|
|
27113
|
+
"suggest_agent_name"
|
|
27114
|
+
]);
|
|
27115
|
+
MCP_TOOL_GROUPS = {
|
|
27116
|
+
core: [...CORE_MCP_TOOLS],
|
|
27117
|
+
tasks: [
|
|
27118
|
+
"archive_completed",
|
|
27119
|
+
"approve_task",
|
|
27120
|
+
"bulk_create_tasks",
|
|
27121
|
+
"bulk_delete_tasks",
|
|
27122
|
+
"bulk_update_tasks",
|
|
27123
|
+
"cancel_task",
|
|
27124
|
+
"claim_task",
|
|
27125
|
+
"clone_task",
|
|
27126
|
+
"delete_task",
|
|
27127
|
+
"extend_task",
|
|
27128
|
+
"get_active_work",
|
|
27129
|
+
"get_archived_tasks",
|
|
27130
|
+
"get_blocked_tasks",
|
|
27131
|
+
"get_blocking_tasks",
|
|
27132
|
+
"get_my_tasks",
|
|
27133
|
+
"get_review_queue",
|
|
27134
|
+
"get_stale_tasks",
|
|
27135
|
+
"list_my_tasks",
|
|
27136
|
+
"move_task",
|
|
27137
|
+
"patrol_tasks",
|
|
27138
|
+
"prioritize_task",
|
|
27139
|
+
"reassign_task",
|
|
27140
|
+
"release_task",
|
|
27141
|
+
"reschedule_task",
|
|
27142
|
+
"search_tasks",
|
|
27143
|
+
"standup",
|
|
27144
|
+
"task_context",
|
|
27145
|
+
"unarchive_task",
|
|
27146
|
+
"update_task"
|
|
27147
|
+
],
|
|
27148
|
+
projects: [
|
|
27149
|
+
"create_plan",
|
|
27150
|
+
"create_project",
|
|
27151
|
+
"create_task_list",
|
|
27152
|
+
"delete_plan",
|
|
27153
|
+
"delete_project",
|
|
27154
|
+
"delete_task_list",
|
|
27155
|
+
"get_focus",
|
|
27156
|
+
"get_plan",
|
|
27157
|
+
"get_project",
|
|
27158
|
+
"get_task_list",
|
|
27159
|
+
"list_plans",
|
|
27160
|
+
"list_projects",
|
|
27161
|
+
"list_task_lists",
|
|
27162
|
+
"set_focus",
|
|
27163
|
+
"unfocus",
|
|
27164
|
+
"update_plan",
|
|
27165
|
+
"update_project",
|
|
27166
|
+
"update_task_list"
|
|
27167
|
+
],
|
|
27168
|
+
resources: [
|
|
27169
|
+
"add_task_dependency",
|
|
27170
|
+
"add_task_file",
|
|
27171
|
+
"add_task_relationship",
|
|
27172
|
+
"bulk_find_tasks_by_files",
|
|
27173
|
+
"check_file_lock",
|
|
27174
|
+
"create_comment",
|
|
27175
|
+
"delete_comment",
|
|
27176
|
+
"detect_file_relationships",
|
|
27177
|
+
"find_path",
|
|
27178
|
+
"find_task_by_commit",
|
|
27179
|
+
"find_tasks_by_file",
|
|
27180
|
+
"get_comments",
|
|
27181
|
+
"get_critical_path",
|
|
27182
|
+
"get_file_heat_map",
|
|
27183
|
+
"get_impact_analysis",
|
|
27184
|
+
"get_latest_handoff",
|
|
27185
|
+
"get_related_entities",
|
|
27186
|
+
"get_task_commits",
|
|
27187
|
+
"get_task_dependencies",
|
|
27188
|
+
"get_task_relationships",
|
|
27189
|
+
"get_task_watchers",
|
|
27190
|
+
"link_task_to_commit",
|
|
27191
|
+
"list_active_files",
|
|
27192
|
+
"list_comments",
|
|
27193
|
+
"list_file_locks",
|
|
27194
|
+
"list_task_files",
|
|
27195
|
+
"lock_file",
|
|
27196
|
+
"log_time",
|
|
27197
|
+
"remove_task_dependency",
|
|
27198
|
+
"remove_task_relationship",
|
|
27199
|
+
"sync_kg",
|
|
27200
|
+
"unlock_file",
|
|
27201
|
+
"unwatch_task",
|
|
27202
|
+
"update_comment",
|
|
27203
|
+
"watch_task"
|
|
27204
|
+
],
|
|
27205
|
+
agents: [
|
|
27206
|
+
"auto_assign_task",
|
|
27207
|
+
"delete_agent",
|
|
27208
|
+
"get_agent",
|
|
27209
|
+
"get_agent_metrics",
|
|
27210
|
+
"get_capable_agents",
|
|
27211
|
+
"get_leaderboard",
|
|
27212
|
+
"get_my_workload",
|
|
27213
|
+
"get_org_chart",
|
|
27214
|
+
"get_project_org_chart",
|
|
27215
|
+
"get_time_report",
|
|
27216
|
+
"list_project_agent_roles",
|
|
27217
|
+
"rebalance_workload",
|
|
27218
|
+
"rename_agent",
|
|
27219
|
+
"set_project_agent_role",
|
|
27220
|
+
"set_reports_to",
|
|
27221
|
+
"unarchive_agent",
|
|
27222
|
+
"update_agent"
|
|
27223
|
+
],
|
|
27224
|
+
metadata: [
|
|
27225
|
+
"create_label",
|
|
27226
|
+
"create_tag",
|
|
27227
|
+
"delete_label",
|
|
27228
|
+
"delete_tag",
|
|
27229
|
+
"get_label",
|
|
27230
|
+
"get_recent_activity",
|
|
27231
|
+
"get_tag",
|
|
27232
|
+
"get_task_graph",
|
|
27233
|
+
"get_task_history",
|
|
27234
|
+
"get_task_stats",
|
|
27235
|
+
"list_labels",
|
|
27236
|
+
"list_tags",
|
|
27237
|
+
"search_tools",
|
|
27238
|
+
"describe_tools",
|
|
27239
|
+
"update_label",
|
|
27240
|
+
"update_tag"
|
|
27241
|
+
],
|
|
27242
|
+
dispatch: [
|
|
27243
|
+
"cancel_dispatch",
|
|
27244
|
+
"dispatch_task_list",
|
|
27245
|
+
"dispatch_tasks",
|
|
27246
|
+
"dispatch_to_multiple",
|
|
27247
|
+
"list_dispatches",
|
|
27248
|
+
"run_due_dispatches"
|
|
27249
|
+
],
|
|
27250
|
+
templates: [
|
|
27251
|
+
"create_task_from_template",
|
|
27252
|
+
"create_template",
|
|
27253
|
+
"delete_template",
|
|
27254
|
+
"export_template",
|
|
27255
|
+
"import_template",
|
|
27256
|
+
"init_templates",
|
|
27257
|
+
"list_templates",
|
|
27258
|
+
"preview_template",
|
|
27259
|
+
"template_history",
|
|
27260
|
+
"update_template"
|
|
27261
|
+
],
|
|
27262
|
+
webhooks: ["create_webhook", "delete_webhook", "list_webhooks"],
|
|
27263
|
+
machines: [
|
|
27264
|
+
"machines_archive",
|
|
27265
|
+
"machines_delete",
|
|
27266
|
+
"machines_list",
|
|
27267
|
+
"machines_register",
|
|
27268
|
+
"machines_set_primary",
|
|
27269
|
+
"machines_unarchive"
|
|
27270
|
+
],
|
|
27271
|
+
cloud: [
|
|
27272
|
+
"sync_all",
|
|
27273
|
+
"todos_cloud_conflicts",
|
|
27274
|
+
"todos_cloud_feedback",
|
|
27275
|
+
"todos_cloud_pull",
|
|
27276
|
+
"todos_cloud_push",
|
|
27277
|
+
"todos_cloud_status",
|
|
27278
|
+
"todos_inbox",
|
|
27279
|
+
"todos_retro"
|
|
27280
|
+
],
|
|
27281
|
+
maintenance: ["extract_todos", "migrate_pg", "notify_upcoming_deadlines", "score_task"]
|
|
27282
|
+
};
|
|
27283
|
+
MCP_PROFILE_GROUPS = {
|
|
27284
|
+
minimal: ["core"],
|
|
27285
|
+
core: ["core"],
|
|
27286
|
+
standard: ["core", "tasks", "projects", "resources", "agents", "metadata"],
|
|
27287
|
+
agent: ["core", "tasks", "projects", "resources"],
|
|
27288
|
+
maintainer: ["core", "tasks", "projects", "resources", "agents", "metadata", "dispatch", "maintenance"]
|
|
27289
|
+
};
|
|
27290
|
+
});
|
|
27291
|
+
|
|
26882
27292
|
// src/mcp/tools/task-crud.ts
|
|
26883
27293
|
function registerTaskCrudTools(server, ctx) {
|
|
26884
27294
|
const { shouldRegisterTool, resolveId, formatError, formatTask } = ctx;
|
|
@@ -26969,15 +27379,31 @@ function registerTaskCrudTools(server, ctx) {
|
|
|
26969
27379
|
});
|
|
26970
27380
|
}
|
|
26971
27381
|
if (shouldRegisterTool("get_task")) {
|
|
26972
|
-
server.tool("get_task", "Get
|
|
26973
|
-
task_id: exports_external2.string().describe("Task ID (full or short)")
|
|
26974
|
-
|
|
27382
|
+
server.tool("get_task", "Get compact task details by default. Pass detail=full for the full multi-line view.", {
|
|
27383
|
+
task_id: exports_external2.string().describe("Task ID (full or short)"),
|
|
27384
|
+
detail: exports_external2.enum(["compact", "full"]).optional().describe("Response detail (default: compact)"),
|
|
27385
|
+
max_description_chars: exports_external2.number().optional().describe("Max description chars in compact mode (default: 240)"),
|
|
27386
|
+
include_metadata: exports_external2.boolean().optional().describe("Include metadata in compact mode")
|
|
27387
|
+
}, async ({ task_id, detail, max_description_chars, include_metadata }) => {
|
|
26975
27388
|
try {
|
|
26976
27389
|
const resolvedId = resolveId(task_id);
|
|
26977
27390
|
const task = getTask(resolvedId);
|
|
26978
27391
|
if (!task)
|
|
26979
27392
|
throw new TaskNotFoundError(task_id);
|
|
26980
27393
|
const focus = ctx.getAgentFocus(task.assigned_to || "");
|
|
27394
|
+
if (detail !== "full") {
|
|
27395
|
+
const compact = compactTask(task, max_description_chars || 240);
|
|
27396
|
+
compact["version"] = task.version;
|
|
27397
|
+
compact["created_at"] = task.created_at;
|
|
27398
|
+
compact["focus"] = focus ? { agent_id: focus.agent_id, project_id: focus.project_id || null } : null;
|
|
27399
|
+
if (include_metadata && task.metadata && Object.keys(task.metadata).length > 0) {
|
|
27400
|
+
compact["metadata"] = task.metadata;
|
|
27401
|
+
}
|
|
27402
|
+
if (task.description && !compact["description"]) {
|
|
27403
|
+
compact["description"] = truncateText(task.description, max_description_chars || 240);
|
|
27404
|
+
}
|
|
27405
|
+
return { content: [{ type: "text", text: compactJson(compact) }] };
|
|
27406
|
+
}
|
|
26981
27407
|
const lines = [
|
|
26982
27408
|
`ID: ${task.id}`,
|
|
26983
27409
|
`Short ID: ${task.short_id || "(none)"}`,
|
|
@@ -27076,6 +27502,7 @@ var init_task_crud2 = __esm(() => {
|
|
|
27076
27502
|
init_zod2();
|
|
27077
27503
|
init_tasks();
|
|
27078
27504
|
init_types();
|
|
27505
|
+
init_token_utils();
|
|
27079
27506
|
});
|
|
27080
27507
|
|
|
27081
27508
|
// src/mcp/tools/task-project-tools.ts
|
|
@@ -27227,8 +27654,17 @@ function registerTaskProjectTools(server, ctx) {
|
|
|
27227
27654
|
direction: exports_external2.enum(["upstream", "downstream", "both"]).optional().describe("Upstream = tasks this task depends on; downstream = tasks depending on this")
|
|
27228
27655
|
}, async ({ task_id, direction }) => {
|
|
27229
27656
|
try {
|
|
27230
|
-
const { getTaskDependencies: getTaskDependencies3 } = (init_tasks(), __toCommonJS(exports_tasks));
|
|
27231
|
-
const
|
|
27657
|
+
const { getTaskDependencies: getTaskDependencies3, getTaskDependents: getTaskDependents2, getTask: getTask2 } = (init_tasks(), __toCommonJS(exports_tasks));
|
|
27658
|
+
const resolvedId = resolveId(task_id);
|
|
27659
|
+
const upstream = direction !== "downstream" ? getTaskDependencies3(resolvedId).map((dep) => {
|
|
27660
|
+
const dependency = getTask2(dep.depends_on);
|
|
27661
|
+
return { direction: "upstream", task_id: dep.depends_on, status: dependency?.status || "unknown" };
|
|
27662
|
+
}) : [];
|
|
27663
|
+
const downstream = direction !== "upstream" ? getTaskDependents2(resolvedId).map((dep) => {
|
|
27664
|
+
const dependent = getTask2(dep.task_id);
|
|
27665
|
+
return { direction: "downstream", task_id: dep.task_id, status: dependent?.status || "unknown" };
|
|
27666
|
+
}) : [];
|
|
27667
|
+
const deps = [...upstream, ...downstream];
|
|
27232
27668
|
if (deps.length === 0)
|
|
27233
27669
|
return { content: [{ type: "text", text: "No dependencies." }] };
|
|
27234
27670
|
const lines = deps.map((d) => `[${d.direction}] ${d.task_id.slice(0, 8)} (${d.status})`);
|
|
@@ -28025,8 +28461,10 @@ function registerTaskWorkflowTools(server, ctx) {
|
|
|
28025
28461
|
agent_id: exports_external2.string().optional().describe("Agent ID or name"),
|
|
28026
28462
|
project_id: exports_external2.string().optional().describe("Filter by project"),
|
|
28027
28463
|
task_list_id: exports_external2.string().optional().describe("Filter by task list"),
|
|
28028
|
-
explain_blocked: exports_external2.boolean().optional().describe("Include blocked task details")
|
|
28029
|
-
|
|
28464
|
+
explain_blocked: exports_external2.boolean().optional().describe("Include blocked task details"),
|
|
28465
|
+
detail: exports_external2.enum(["compact", "full"]).optional().describe("Response detail (default: compact)"),
|
|
28466
|
+
max_description_chars: exports_external2.number().optional().describe("Max task description chars in compact mode (default: 180)")
|
|
28467
|
+
}, async ({ agent_id, project_id, task_list_id, explain_blocked, detail, max_description_chars }) => {
|
|
28030
28468
|
try {
|
|
28031
28469
|
const { getStatus: getStatus2, getNextTask: getNextTask2, getOverdueTasks: getOverdueTasks2 } = (init_tasks(), __toCommonJS(exports_tasks));
|
|
28032
28470
|
const { getLatestHandoff: getLatestHandoff2 } = (init_handoffs(), __toCommonJS(exports_handoffs));
|
|
@@ -28039,16 +28477,31 @@ function registerTaskWorkflowTools(server, ctx) {
|
|
|
28039
28477
|
const next_task = getNextTask2(agent_id, filters);
|
|
28040
28478
|
const overdue = getOverdueTasks2(filters.project_id);
|
|
28041
28479
|
const latest_handoff = getLatestHandoff2(agent_id, filters.project_id);
|
|
28480
|
+
const payload = {
|
|
28481
|
+
status,
|
|
28482
|
+
next_task,
|
|
28483
|
+
overdue_count: overdue.length,
|
|
28484
|
+
latest_handoff,
|
|
28485
|
+
as_of: new Date().toISOString()
|
|
28486
|
+
};
|
|
28487
|
+
if (detail === "full") {
|
|
28488
|
+
return {
|
|
28489
|
+
content: [{
|
|
28490
|
+
type: "text",
|
|
28491
|
+
text: JSON.stringify(payload, null, 2)
|
|
28492
|
+
}]
|
|
28493
|
+
};
|
|
28494
|
+
}
|
|
28042
28495
|
return {
|
|
28043
28496
|
content: [{
|
|
28044
28497
|
type: "text",
|
|
28045
|
-
text:
|
|
28046
|
-
status,
|
|
28047
|
-
next_task,
|
|
28498
|
+
text: compactJson({
|
|
28499
|
+
status: compactStatus(status),
|
|
28500
|
+
next_task: next_task ? compactTask(next_task, max_description_chars || 180) : null,
|
|
28048
28501
|
overdue_count: overdue.length,
|
|
28049
|
-
latest_handoff,
|
|
28050
|
-
as_of:
|
|
28051
|
-
}
|
|
28502
|
+
latest_handoff: compactHandoff(latest_handoff),
|
|
28503
|
+
as_of: payload.as_of
|
|
28504
|
+
})
|
|
28052
28505
|
}]
|
|
28053
28506
|
};
|
|
28054
28507
|
} catch (e) {
|
|
@@ -28112,6 +28565,7 @@ function registerTaskWorkflowTools(server, ctx) {
|
|
|
28112
28565
|
var init_task_workflow_tools = __esm(() => {
|
|
28113
28566
|
init_zod2();
|
|
28114
28567
|
init_types();
|
|
28568
|
+
init_token_utils();
|
|
28115
28569
|
});
|
|
28116
28570
|
|
|
28117
28571
|
// src/mcp/tools/task-auto-tools.ts
|
|
@@ -28491,14 +28945,37 @@ var init_task_relationships = __esm(() => {
|
|
|
28491
28945
|
// src/mcp/tools/task-adv-tools.ts
|
|
28492
28946
|
function registerTaskAdvTools(server, ctx) {
|
|
28493
28947
|
const { shouldRegisterTool, resolveId, formatError, formatTask, formatTaskDetail } = ctx;
|
|
28948
|
+
function getDependencyContext(taskId) {
|
|
28949
|
+
const { getTaskDependencies: getTaskDependencies3, getTaskDependents: getTaskDependents2, getTask: getTask2 } = (init_tasks(), __toCommonJS(exports_tasks));
|
|
28950
|
+
const upstream = getTaskDependencies3(taskId).map((dep) => {
|
|
28951
|
+
const dependency = getTask2(dep.depends_on);
|
|
28952
|
+
return {
|
|
28953
|
+
direction: "upstream",
|
|
28954
|
+
task_id: dep.depends_on,
|
|
28955
|
+
status: dependency?.status || "unknown"
|
|
28956
|
+
};
|
|
28957
|
+
});
|
|
28958
|
+
const downstream = getTaskDependents2(taskId).map((dep) => {
|
|
28959
|
+
const dependent = getTask2(dep.task_id);
|
|
28960
|
+
return {
|
|
28961
|
+
direction: "downstream",
|
|
28962
|
+
task_id: dep.task_id,
|
|
28963
|
+
status: dependent?.status || "unknown"
|
|
28964
|
+
};
|
|
28965
|
+
});
|
|
28966
|
+
return [...upstream, ...downstream];
|
|
28967
|
+
}
|
|
28494
28968
|
if (shouldRegisterTool("get_status")) {
|
|
28495
28969
|
server.tool("get_status", "Get queue status summary, or pass task_id for a task's detailed status.", {
|
|
28496
28970
|
task_id: exports_external2.string().optional().describe("Task ID for task-specific status"),
|
|
28497
28971
|
project_id: exports_external2.string().optional().describe("Filter summary by project"),
|
|
28498
28972
|
task_list_id: exports_external2.string().optional().describe("Filter summary by task list"),
|
|
28499
28973
|
agent_id: exports_external2.string().optional().describe("Agent for next-task affinity"),
|
|
28500
|
-
explain_blocked: exports_external2.boolean().optional().describe("Include blocked task explanations in summary")
|
|
28501
|
-
|
|
28974
|
+
explain_blocked: exports_external2.boolean().optional().describe("Include blocked task explanations in summary"),
|
|
28975
|
+
detail: exports_external2.enum(["compact", "full"]).optional().describe("Response detail (default: compact)"),
|
|
28976
|
+
comment_limit: exports_external2.number().optional().describe("Max recent comments for task status (default: 5)"),
|
|
28977
|
+
file_limit: exports_external2.number().optional().describe("Max files for task status (default: 10)")
|
|
28978
|
+
}, async ({ task_id, project_id, task_list_id, agent_id, explain_blocked, detail, comment_limit, file_limit }) => {
|
|
28502
28979
|
try {
|
|
28503
28980
|
if (!task_id) {
|
|
28504
28981
|
const { getStatus: getStatus2 } = (init_tasks(), __toCommonJS(exports_tasks));
|
|
@@ -28508,21 +28985,51 @@ function registerTaskAdvTools(server, ctx) {
|
|
|
28508
28985
|
if (task_list_id)
|
|
28509
28986
|
filters.task_list_id = resolveId(task_list_id, "task_lists");
|
|
28510
28987
|
const status = getStatus2(filters, agent_id, { explain_blocked });
|
|
28511
|
-
return { content: [{ type: "text", text: JSON.stringify(status, null, 2) }] };
|
|
28988
|
+
return { content: [{ type: "text", text: detail === "full" ? JSON.stringify(status, null, 2) : compactJson(compactStatus(status)) }] };
|
|
28512
28989
|
}
|
|
28513
28990
|
const resolvedId = resolveId(task_id);
|
|
28514
28991
|
const { getTask: getTask2 } = (init_tasks(), __toCommonJS(exports_tasks));
|
|
28515
28992
|
const task = getTask2(resolvedId);
|
|
28516
28993
|
if (!task)
|
|
28517
28994
|
throw new Error(`Task not found: ${task_id}`);
|
|
28518
|
-
const { getTaskDependencies: getTaskDependencies3 } = (init_tasks(), __toCommonJS(exports_tasks));
|
|
28519
28995
|
const { listComments: listComments2 } = (init_comments(), __toCommonJS(exports_comments));
|
|
28520
28996
|
const { listTaskFiles: listTaskFiles2 } = (init_task_files(), __toCommonJS(exports_task_files));
|
|
28521
28997
|
const [deps, comments, files] = await Promise.all([
|
|
28522
|
-
Promise.resolve(
|
|
28998
|
+
Promise.resolve(getDependencyContext(resolvedId)),
|
|
28523
28999
|
Promise.resolve(listComments2(resolvedId)),
|
|
28524
29000
|
Promise.resolve(listTaskFiles2(resolvedId))
|
|
28525
29001
|
]);
|
|
29002
|
+
if (detail !== "full") {
|
|
29003
|
+
const commentsShown = comments.slice(-(comment_limit || 5));
|
|
29004
|
+
const filesShown = files.slice(0, file_limit || 10);
|
|
29005
|
+
return {
|
|
29006
|
+
content: [{
|
|
29007
|
+
type: "text",
|
|
29008
|
+
text: compactJson({
|
|
29009
|
+
task: compactTask(task, 160),
|
|
29010
|
+
dependencies: {
|
|
29011
|
+
count: deps.length,
|
|
29012
|
+
items: deps.slice(0, 10).map((d) => ({ direction: d.direction, task_id: d.task_id, status: d.status })),
|
|
29013
|
+
omitted: Math.max(0, deps.length - 10)
|
|
29014
|
+
},
|
|
29015
|
+
comments: {
|
|
29016
|
+
count: comments.length,
|
|
29017
|
+
recent: commentsShown.map((c) => ({
|
|
29018
|
+
agent_id: c.agent_id || null,
|
|
29019
|
+
created_at: c.created_at,
|
|
29020
|
+
content: truncateText(c.content, 120)
|
|
29021
|
+
})),
|
|
29022
|
+
omitted: Math.max(0, comments.length - commentsShown.length)
|
|
29023
|
+
},
|
|
29024
|
+
files: {
|
|
29025
|
+
count: files.length,
|
|
29026
|
+
items: filesShown.map((f) => ({ status: f.status, path: f.path })),
|
|
29027
|
+
omitted: Math.max(0, files.length - filesShown.length)
|
|
29028
|
+
}
|
|
29029
|
+
})
|
|
29030
|
+
}]
|
|
29031
|
+
};
|
|
29032
|
+
}
|
|
28526
29033
|
const lines = [
|
|
28527
29034
|
`Status: ${task.status} | Priority: ${task.priority}`,
|
|
28528
29035
|
task.assigned_to ? `Assigned: ${task.assigned_to}` : "Unassigned",
|
|
@@ -28546,29 +29053,81 @@ Files (${files.length}):` : null,
|
|
|
28546
29053
|
});
|
|
28547
29054
|
}
|
|
28548
29055
|
if (shouldRegisterTool("task_context")) {
|
|
28549
|
-
server.tool("task_context", "Get
|
|
28550
|
-
task_id: exports_external2.string().describe("Task ID")
|
|
28551
|
-
|
|
29056
|
+
server.tool("task_context", "Get compact context for a task by default: details, dependencies, relationships, comments, files, commits, and watchers. Pass detail=full for all data.", {
|
|
29057
|
+
task_id: exports_external2.string().describe("Task ID"),
|
|
29058
|
+
detail: exports_external2.enum(["compact", "full"]).optional().describe("Response detail (default: compact)"),
|
|
29059
|
+
comment_limit: exports_external2.number().optional().describe("Max recent comments in compact mode (default: 5)"),
|
|
29060
|
+
file_limit: exports_external2.number().optional().describe("Max files in compact mode (default: 10)"),
|
|
29061
|
+
commit_limit: exports_external2.number().optional().describe("Max commits in compact mode (default: 10)"),
|
|
29062
|
+
max_description_chars: exports_external2.number().optional().describe("Max description chars in compact mode (default: 240)")
|
|
29063
|
+
}, async ({ task_id, detail, comment_limit, file_limit, commit_limit, max_description_chars }) => {
|
|
28552
29064
|
try {
|
|
28553
29065
|
const resolvedId = resolveId(task_id);
|
|
28554
29066
|
const { getTask: getTask2 } = (init_tasks(), __toCommonJS(exports_tasks));
|
|
28555
29067
|
const task = getTask2(resolvedId);
|
|
28556
29068
|
if (!task)
|
|
28557
29069
|
throw new Error(`Task not found: ${task_id}`);
|
|
28558
|
-
const { getTaskDependencies: getTaskDependencies3 } = (init_tasks(), __toCommonJS(exports_tasks));
|
|
28559
29070
|
const { getTaskRelationships: getTaskRelationships2 } = (init_task_relationships(), __toCommonJS(exports_task_relationships));
|
|
28560
29071
|
const { listComments: listComments2 } = (init_comments(), __toCommonJS(exports_comments));
|
|
28561
29072
|
const { listTaskFiles: listTaskFiles2 } = (init_task_files(), __toCommonJS(exports_task_files));
|
|
28562
29073
|
const { getTaskCommits: getTaskCommits2 } = (init_task_commits(), __toCommonJS(exports_task_commits));
|
|
28563
29074
|
const { getTaskWatchers: getTaskWatchers2 } = (init_tasks(), __toCommonJS(exports_tasks));
|
|
28564
29075
|
const [deps, rels, comments, files, commits, watchers] = await Promise.all([
|
|
28565
|
-
Promise.resolve(
|
|
29076
|
+
Promise.resolve(getDependencyContext(resolvedId)),
|
|
28566
29077
|
Promise.resolve(getTaskRelationships2(resolvedId)),
|
|
28567
29078
|
Promise.resolve(listComments2(resolvedId)),
|
|
28568
29079
|
Promise.resolve(listTaskFiles2(resolvedId)),
|
|
28569
29080
|
Promise.resolve(getTaskCommits2(resolvedId)),
|
|
28570
29081
|
Promise.resolve(getTaskWatchers2(resolvedId))
|
|
28571
29082
|
]);
|
|
29083
|
+
if (detail !== "full") {
|
|
29084
|
+
const commentsShown = comments.slice(-(comment_limit || 5));
|
|
29085
|
+
const filesShown = files.slice(0, file_limit || 10);
|
|
29086
|
+
const commitsShown = commits.slice(0, commit_limit || 10);
|
|
29087
|
+
return {
|
|
29088
|
+
content: [{
|
|
29089
|
+
type: "text",
|
|
29090
|
+
text: compactJson({
|
|
29091
|
+
task: compactTask(task, max_description_chars || 240),
|
|
29092
|
+
dependencies: {
|
|
29093
|
+
count: deps.length,
|
|
29094
|
+
items: deps.slice(0, 10).map((d) => ({ direction: d.direction, task_id: d.task_id, status: d.status })),
|
|
29095
|
+
omitted: Math.max(0, deps.length - 10)
|
|
29096
|
+
},
|
|
29097
|
+
relationships: {
|
|
29098
|
+
count: rels.length,
|
|
29099
|
+
items: rels.slice(0, 10).map((r) => ({
|
|
29100
|
+
source_task_id: r.source_task_id,
|
|
29101
|
+
relationship_type: r.relationship_type,
|
|
29102
|
+
target_task_id: r.target_task_id
|
|
29103
|
+
})),
|
|
29104
|
+
omitted: Math.max(0, rels.length - 10)
|
|
29105
|
+
},
|
|
29106
|
+
comments: {
|
|
29107
|
+
count: comments.length,
|
|
29108
|
+
recent: commentsShown.map((c) => ({
|
|
29109
|
+
agent_id: c.agent_id || null,
|
|
29110
|
+
created_at: c.created_at,
|
|
29111
|
+
content: truncateText(c.content, 160)
|
|
29112
|
+
})),
|
|
29113
|
+
omitted: Math.max(0, comments.length - commentsShown.length)
|
|
29114
|
+
},
|
|
29115
|
+
files: {
|
|
29116
|
+
count: files.length,
|
|
29117
|
+
items: filesShown.map((f) => ({ status: f.status, path: f.path })),
|
|
29118
|
+
omitted: Math.max(0, files.length - filesShown.length)
|
|
29119
|
+
},
|
|
29120
|
+
commits: {
|
|
29121
|
+
count: commits.length,
|
|
29122
|
+
items: commitsShown.map((c) => ({ sha: c.sha, message: truncateText(c.message || "(no message)", 120) })),
|
|
29123
|
+
omitted: Math.max(0, commits.length - commitsShown.length)
|
|
29124
|
+
},
|
|
29125
|
+
watchers: { count: watchers.length },
|
|
29126
|
+
metadata_keys: task.metadata ? Object.keys(task.metadata) : []
|
|
29127
|
+
})
|
|
29128
|
+
}]
|
|
29129
|
+
};
|
|
29130
|
+
}
|
|
28572
29131
|
const lines = [
|
|
28573
29132
|
`== ${task.title} ====================`,
|
|
28574
29133
|
`ID: ${task.id}`,
|
|
@@ -28734,15 +29293,20 @@ No blocked tasks.`,
|
|
|
28734
29293
|
});
|
|
28735
29294
|
}
|
|
28736
29295
|
if (shouldRegisterTool("get_comments")) {
|
|
28737
|
-
server.tool("get_comments", "
|
|
28738
|
-
task_id: exports_external2.string().describe("Task ID")
|
|
28739
|
-
|
|
29296
|
+
server.tool("get_comments", "List recent comments for a task. Compact by default; pass detail=full for all comment text.", {
|
|
29297
|
+
task_id: exports_external2.string().describe("Task ID"),
|
|
29298
|
+
detail: exports_external2.enum(["compact", "full"]).optional().describe("Response detail (default: compact)"),
|
|
29299
|
+
limit: exports_external2.number().optional().describe("Max recent comments in compact mode (default: 20)")
|
|
29300
|
+
}, async ({ task_id, detail, limit }) => {
|
|
28740
29301
|
try {
|
|
28741
29302
|
const { listComments: listComments2 } = (init_comments(), __toCommonJS(exports_comments));
|
|
28742
29303
|
const comments = listComments2(resolveId(task_id));
|
|
28743
29304
|
if (comments.length === 0)
|
|
28744
29305
|
return { content: [{ type: "text", text: "No comments." }] };
|
|
28745
|
-
const
|
|
29306
|
+
const shown = detail === "full" ? comments : comments.slice(-(limit || 20));
|
|
29307
|
+
const lines = shown.map((c) => `[${c.agent_id || "?"}] ${c.created_at?.slice(0, 16)}: ${detail === "full" ? c.content : truncateText(c.content, 180)}`);
|
|
29308
|
+
if (shown.length < comments.length)
|
|
29309
|
+
lines.unshift(`Showing ${shown.length} of ${comments.length} comments (${comments.length - shown.length} older omitted).`);
|
|
28746
29310
|
return { content: [{ type: "text", text: lines.join(`
|
|
28747
29311
|
|
|
28748
29312
|
`) }] };
|
|
@@ -28782,6 +29346,7 @@ No blocked tasks.`,
|
|
|
28782
29346
|
}
|
|
28783
29347
|
var init_task_adv_tools = __esm(() => {
|
|
28784
29348
|
init_zod2();
|
|
29349
|
+
init_token_utils();
|
|
28785
29350
|
});
|
|
28786
29351
|
|
|
28787
29352
|
// src/mcp/tools/task-meta-tools.ts
|
|
@@ -28812,7 +29377,7 @@ function registerTaskMetaTools(server, ctx) {
|
|
|
28812
29377
|
const toolDocs = {
|
|
28813
29378
|
create_task: "create_task \u2014 Create a new task. Params: title (required), description, status, priority, project_id, task_list_id, assigned_to, depends_on, short_id (null to disable), tags, estimate (minutes), confidence (0.0-1.0), deadline (ISO), retry_count",
|
|
28814
29379
|
list_tasks: "list_tasks \u2014 List tasks with filters. Params: status, priority, project_id, task_list_id, assigned_to, tags[], created_after, created_before, limit, offset",
|
|
28815
|
-
get_task: "get_task \u2014 Get
|
|
29380
|
+
get_task: "get_task \u2014 Get compact task details by default. Params: task_id, detail=compact|full, max_description_chars, include_metadata",
|
|
28816
29381
|
update_task: "update_task \u2014 Update task fields (optimistic locking). Params: task_id (required), title, description, status, priority, assigned_to (null to unassign), project_id, task_list_id, depends_on[], tags[], estimate, actual_minutes, confidence, approved_by, completed_at, deadline, retry_count, version",
|
|
28817
29382
|
delete_task: "delete_task \u2014 Delete a task. Params: task_id, force (skip child check)",
|
|
28818
29383
|
start_task: "start_task \u2014 Mark task in_progress. Params: task_id, version",
|
|
@@ -28826,8 +29391,8 @@ function registerTaskMetaTools(server, ctx) {
|
|
|
28826
29391
|
get_next_task: "get_next_task \u2014 Get the next available task without claiming it. Params: agent_id, project_id, task_list_id, plan_id, tags",
|
|
28827
29392
|
claim_next_task: "claim_next_task \u2014 Atomically claim and start the next available task. Params: agent_id, project_id, task_list_id, plan_id, tags",
|
|
28828
29393
|
get_tasks_changed_since: "get_tasks_changed_since \u2014 List tasks changed since an ISO timestamp. Params: since, project_id, task_list_id, limit",
|
|
28829
|
-
get_context: "get_context \u2014 Get session start context. Params: agent_id, project_id, task_list_id, explain_blocked",
|
|
28830
|
-
bootstrap: "bootstrap \u2014 Bootstrap an agent session with queue context. Params: agent_id, project_id, task_list_id, explain_blocked",
|
|
29394
|
+
get_context: "get_context \u2014 Get compact session start context by default. Params: agent_id, project_id, task_list_id, explain_blocked, detail=compact|full, max_description_chars",
|
|
29395
|
+
bootstrap: "bootstrap \u2014 Bootstrap an agent session with compact queue context by default. Params: agent_id, project_id, task_list_id, explain_blocked, detail=compact|full, max_description_chars",
|
|
28831
29396
|
standup: "standup \u2014 Get standup report. Params: agent_id, project_id",
|
|
28832
29397
|
patrol_tasks: "patrol_tasks \u2014 Scan for task issues. Params: stuck_minutes, confidence_threshold, project_id",
|
|
28833
29398
|
get_review_queue: "get_review_queue \u2014 Get tasks needing review. Params: project_id, limit",
|
|
@@ -28864,6 +29429,7 @@ function registerTaskMetaTools(server, ctx) {
|
|
|
28864
29429
|
get_task_relationships: "get_task_relationships \u2014 Get all relationships. Params: task_id, relationship_type",
|
|
28865
29430
|
create_comment: "create_comment \u2014 Add comment. Params: task_id, body, author",
|
|
28866
29431
|
list_comments: "list_comments \u2014 List comments. Params: task_id",
|
|
29432
|
+
get_comments: "get_comments \u2014 List recent comments by default. Params: task_id, detail=compact|full, limit",
|
|
28867
29433
|
update_comment: "update_comment \u2014 Edit comment. Params: comment_id, body",
|
|
28868
29434
|
delete_comment: "delete_comment \u2014 Delete comment. Params: comment_id",
|
|
28869
29435
|
lock_task: "lock_task \u2014 Acquire exclusive lock. Params: task_id, agent_id, ttl_seconds",
|
|
@@ -31716,11 +32282,7 @@ function hasVersionFlag() {
|
|
|
31716
32282
|
return process.argv.includes("--version") || process.argv.includes("-V");
|
|
31717
32283
|
}
|
|
31718
32284
|
function shouldRegisterTool(name) {
|
|
31719
|
-
|
|
31720
|
-
return MINIMAL_TOOLS.has(name);
|
|
31721
|
-
if (TODOS_PROFILE === "standard")
|
|
31722
|
-
return !STANDARD_EXCLUDED.has(name);
|
|
31723
|
-
return true;
|
|
32285
|
+
return shouldRegisterToolForProfile(name);
|
|
31724
32286
|
}
|
|
31725
32287
|
function getAgentFocus(agentId) {
|
|
31726
32288
|
const sessionFocus = agentFocusMap.get(agentId);
|
|
@@ -31857,7 +32419,7 @@ async function main() {
|
|
|
31857
32419
|
const transport = new StdioServerTransport;
|
|
31858
32420
|
await server.connect(transport);
|
|
31859
32421
|
}
|
|
31860
|
-
var server,
|
|
32422
|
+
var server, agentFocusMap, toolContext;
|
|
31861
32423
|
var init_mcp = __esm(() => {
|
|
31862
32424
|
init_cloud();
|
|
31863
32425
|
init_agents();
|
|
@@ -31876,6 +32438,7 @@ var init_mcp = __esm(() => {
|
|
|
31876
32438
|
init_machines2();
|
|
31877
32439
|
init_agents2();
|
|
31878
32440
|
init_package_version();
|
|
32441
|
+
init_token_utils();
|
|
31879
32442
|
if (hasVersionFlag()) {
|
|
31880
32443
|
console.log(getMcpVersion());
|
|
31881
32444
|
process.exit(0);
|
|
@@ -31884,42 +32447,7 @@ var init_mcp = __esm(() => {
|
|
|
31884
32447
|
name: "todos",
|
|
31885
32448
|
version: getMcpVersion()
|
|
31886
32449
|
});
|
|
31887
|
-
|
|
31888
|
-
MINIMAL_TOOLS = new Set([
|
|
31889
|
-
"claim_next_task",
|
|
31890
|
-
"complete_task",
|
|
31891
|
-
"fail_task",
|
|
31892
|
-
"get_status",
|
|
31893
|
-
"get_context",
|
|
31894
|
-
"get_task",
|
|
31895
|
-
"start_task",
|
|
31896
|
-
"add_comment",
|
|
31897
|
-
"get_next_task",
|
|
31898
|
-
"bootstrap",
|
|
31899
|
-
"get_tasks_changed_since",
|
|
31900
|
-
"get_health",
|
|
31901
|
-
"heartbeat",
|
|
31902
|
-
"release_agent"
|
|
31903
|
-
]);
|
|
31904
|
-
STANDARD_EXCLUDED = new Set([
|
|
31905
|
-
"rename_agent",
|
|
31906
|
-
"delete_agent",
|
|
31907
|
-
"unarchive_agent",
|
|
31908
|
-
"create_webhook",
|
|
31909
|
-
"list_webhooks",
|
|
31910
|
-
"delete_webhook",
|
|
31911
|
-
"create_template",
|
|
31912
|
-
"list_templates",
|
|
31913
|
-
"create_task_from_template",
|
|
31914
|
-
"delete_template",
|
|
31915
|
-
"update_template",
|
|
31916
|
-
"init_templates",
|
|
31917
|
-
"preview_template",
|
|
31918
|
-
"export_template",
|
|
31919
|
-
"import_template",
|
|
31920
|
-
"template_history",
|
|
31921
|
-
"approve_task"
|
|
31922
|
-
]);
|
|
32450
|
+
installMcpTokenTelemetry(server);
|
|
31923
32451
|
agentFocusMap = new Map;
|
|
31924
32452
|
toolContext = {
|
|
31925
32453
|
shouldRegisterTool,
|