@sodiumhq/mcp-pm 0.1.0-beta.6194 → 0.1.0-beta.6299
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/http.js +1 -1
- package/dist/index.js +1 -1
- package/dist/{src-BB0-Ejj-.mjs → src-b0BBk3Y8.mjs} +42 -29
- package/package.json +1 -1
package/dist/http.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { t as buildServer } from "./src-
|
|
2
|
+
import { t as buildServer } from "./src-b0BBk3Y8.mjs";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import { SUPPORTED_PROTOCOL_VERSIONS, createMcpHandler } from "@modelcontextprotocol/server";
|
|
5
5
|
import { createHash, randomUUID } from "node:crypto";
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { t as buildServer } from "./src-
|
|
2
|
+
import { t as buildServer } from "./src-b0BBk3Y8.mjs";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import { serveStdio } from "@modelcontextprotocol/server/stdio";
|
|
5
5
|
import { parseArgs } from "node:util";
|
|
@@ -2070,11 +2070,26 @@ const getTaskItem = (options) => (options.client ?? client).get({
|
|
|
2070
2070
|
...options
|
|
2071
2071
|
});
|
|
2072
2072
|
/**
|
|
2073
|
-
*
|
|
2073
|
+
* Patch TaskItem
|
|
2074
2074
|
*
|
|
2075
|
-
* Updates
|
|
2075
|
+
* Updates part of one task, following JSON Merge Patch. Send only the fields to change: a field left
|
|
2076
|
+
* out is not touched, so a quick action (moving the task on the calendar, a status button, a checklist
|
|
2077
|
+
* tick) never overwrites details it did not send, such as the description. A field sent as null is
|
|
2078
|
+
* cleared: description, statutory due date, time estimate, checklist, assignee, team, category, service
|
|
2079
|
+
* and primary client. The name, status, dates and times are required on a task, so sending one of those
|
|
2080
|
+
* as null is a 400.
|
|
2081
|
+
*
|
|
2082
|
+
* **Clients**: the same rules as a full update. The primary client always stays on the task, and a task
|
|
2083
|
+
* with clients but no primary gets its first client as primary. To remove every client, send the client
|
|
2084
|
+
* list and the primary client as null. Changing the primary client clears the task's service and
|
|
2085
|
+
* pipeline links (they belong to a client) unless a service code is sent.
|
|
2086
|
+
*
|
|
2087
|
+
* The change is saved through the same update as a full update, so dated workflow steps follow the
|
|
2088
|
+
* task when its dates move (unless MoveWorkflowStepDates is false), and colleagues see the change live.
|
|
2089
|
+
*
|
|
2090
|
+
* Only a saved task can be patched. A projected (upcoming) task must be materialised first.
|
|
2076
2091
|
*/
|
|
2077
|
-
const
|
|
2092
|
+
const patchTaskItem = (options) => (options.client ?? client).patch({
|
|
2078
2093
|
security: [{
|
|
2079
2094
|
name: "x-api-key",
|
|
2080
2095
|
type: "apiKey"
|
|
@@ -3756,9 +3771,9 @@ var SodiumApiClient = class {
|
|
|
3756
3771
|
if (error !== void 0 || !data) throw this.toError(response, error, correlationId, "create task");
|
|
3757
3772
|
return data;
|
|
3758
3773
|
}
|
|
3759
|
-
async
|
|
3774
|
+
async patchTask(code, body) {
|
|
3760
3775
|
const correlationId = randomUUID();
|
|
3761
|
-
const { data, error, response } = await
|
|
3776
|
+
const { data, error, response } = await patchTaskItem({
|
|
3762
3777
|
path: {
|
|
3763
3778
|
tenant: this.tenant,
|
|
3764
3779
|
code
|
|
@@ -4515,6 +4530,7 @@ function format(input) {
|
|
|
4515
4530
|
if (task.assignedUser) lines.push(`Assigned user: ${formatCodeAndName(task.assignedUser)}`);
|
|
4516
4531
|
if (task.assignedTeam) lines.push(`Assigned team: ${formatCodeAndName(task.assignedTeam)}`);
|
|
4517
4532
|
if (task.category) lines.push(`Category: ${formatCodeAndName(task.category)}`);
|
|
4533
|
+
if (task.clientBillableService) lines.push(`Service: ${formatCodeAndName(task.clientBillableService)}`);
|
|
4518
4534
|
if (task.recurringTask) lines.push(`Recurring template: ${formatCodeAndName(task.recurringTask)}`);
|
|
4519
4535
|
if (task.workflow) lines.push(`Workflow template: ${formatCodeAndName(task.workflow)}`);
|
|
4520
4536
|
const description = task.description?.trim();
|
|
@@ -4905,7 +4921,7 @@ const ListTasksInputSchema = {
|
|
|
4905
4921
|
};
|
|
4906
4922
|
function formatTask(t) {
|
|
4907
4923
|
const code = t.code ?? "(no code)";
|
|
4908
|
-
return `- ${t.name ?? "(unnamed)"} (${code})${t.isOverdue ? " [OVERDUE]" : ""}${t.dueDate ? ` · due ${t.dueDate}` : ""}${t.primaryClient ? ` · ${t.primaryClient.name}` : t.clients?.[0] ? ` · ${t.clients[0].name}` : ""}${t.assignedUser?.name ? ` · ${t.assignedUser.name}` : ""}${t.status && t.status !== "NotStarted" ? ` · ${t.status}` : ""}${t.workflow ? ` · workflow ${t.workflowStepsComplete ?? 0}/${t.workflowSteps ?? 0}` : ""}`;
|
|
4924
|
+
return `- ${t.name ?? "(unnamed)"} (${code})${t.isOverdue ? " [OVERDUE]" : ""}${t.dueDate ? ` · due ${t.dueDate}` : ""}${t.statutoryDueDate ? ` · statutory ${t.statutoryDueDate}` : ""}${t.primaryClient ? ` · ${t.primaryClient.name}` : t.clients?.[0] ? ` · ${t.clients[0].name}` : ""}${t.clientBillableService?.name ? ` · service ${t.clientBillableService.name}${t.clientBillableService.code ? ` (${t.clientBillableService.code})` : ""}` : ""}${t.assignedUser?.name ? ` · ${t.assignedUser.name}` : ""}${t.status && t.status !== "NotStarted" ? ` · ${t.status}` : ""}${t.workflow ? ` · workflow ${t.workflowStepsComplete ?? 0}/${t.workflowSteps ?? 0}` : ""}`;
|
|
4909
4925
|
}
|
|
4910
4926
|
async function handleListTasks(api, args) {
|
|
4911
4927
|
try {
|
|
@@ -7298,26 +7314,23 @@ const UpdateTaskInputSchema = {
|
|
|
7298
7314
|
};
|
|
7299
7315
|
async function handleUpdateTask(api, args) {
|
|
7300
7316
|
try {
|
|
7301
|
-
const current = await api.getTask(args.taskCode);
|
|
7302
7317
|
const has = (key) => args[key] !== void 0;
|
|
7303
|
-
const body = {
|
|
7304
|
-
|
|
7305
|
-
|
|
7306
|
-
|
|
7307
|
-
|
|
7308
|
-
|
|
7309
|
-
|
|
7310
|
-
|
|
7311
|
-
|
|
7312
|
-
|
|
7313
|
-
|
|
7314
|
-
|
|
7315
|
-
|
|
7316
|
-
|
|
7317
|
-
|
|
7318
|
-
|
|
7319
|
-
};
|
|
7320
|
-
const updated = await api.updateTask(args.taskCode, body);
|
|
7318
|
+
const body = {};
|
|
7319
|
+
if (has("status")) body.status = args.status;
|
|
7320
|
+
if (has("name")) body.name = args.name;
|
|
7321
|
+
if (has("description")) body.description = args.description;
|
|
7322
|
+
if (has("startDate")) body.startDate = args.startDate;
|
|
7323
|
+
if (has("dueDate")) body.dueDate = args.dueDate;
|
|
7324
|
+
if (has("statutoryDueDate")) body.statutoryDueDate = args.statutoryDueDate;
|
|
7325
|
+
if (has("timeEstimateMinutes")) body.timeEstimateMinutes = args.timeEstimateMinutes;
|
|
7326
|
+
if (has("assignedUserCode")) body.assignedUserCode = args.assignedUserCode;
|
|
7327
|
+
if (has("assignedTeamCode")) body.assignedTeamCode = args.assignedTeamCode;
|
|
7328
|
+
if (has("categoryCode")) body.categoryCode = args.categoryCode;
|
|
7329
|
+
if (Object.keys(body).length === 0) return { content: [{
|
|
7330
|
+
type: "text",
|
|
7331
|
+
text: `Task ${args.taskCode} not changed: no fields were passed to update.`
|
|
7332
|
+
}] };
|
|
7333
|
+
const updated = await api.patchTask(args.taskCode, body);
|
|
7321
7334
|
const changes = [];
|
|
7322
7335
|
if (has("status")) changes.push(`status → ${updated.status}`);
|
|
7323
7336
|
if (has("name")) changes.push(`name → ${updated.name}`);
|
|
@@ -7331,7 +7344,7 @@ async function handleUpdateTask(api, args) {
|
|
|
7331
7344
|
if (has("timeEstimateMinutes")) changes.push(`estimate → ${updated.timeEstimateMinutes ?? "cleared"}m`);
|
|
7332
7345
|
return { content: [{
|
|
7333
7346
|
type: "text",
|
|
7334
|
-
text: [`Task updated: ${updated.name} (${updated.code})`,
|
|
7347
|
+
text: [`Task updated: ${updated.name} (${updated.code})`, `Changed: ${changes.join(", ")}`].join("\n")
|
|
7335
7348
|
}] };
|
|
7336
7349
|
} catch (error) {
|
|
7337
7350
|
return {
|
|
@@ -9520,7 +9533,7 @@ async function buildServer(config) {
|
|
|
9520
9533
|
}, (args) => handleListClientNotes(api, args));
|
|
9521
9534
|
registerTenantTool(server, api, "list_tasks", {
|
|
9522
9535
|
title: "List / filter tasks across the practice",
|
|
9523
|
-
description: "List tasks with any combination of filters: assigned user(s), unassigned, client(s), the primary client's client manager / partner (portfolio views: 'tasks across the clients Jane manages'), status, overdue flag, preset date range (Today / ThisWeek / Next7Days / CustomDateRange etc), category, team, billable service, workflow, workflow step type, current step name, recurring task template, free-text search, saved filter, include-projected, include-workflow-steps (Agenda Mode), sort, and pagination. Use for: 'my tasks' (pass current user's code from startup context), 'Jane's overdue tasks' (user + isOverdue), 'tasks for ACME due this week' (client + dateRange=Next7Days + dateBasis=DueDate), 'what is the team working on this month' (dateRange=ThisMonth, no user filter). Returns up to 50 tasks per page. IMPORTANT constraints to avoid API errors and keep queries efficient: (1) Querying NotStarted tasks requires one of — a dateRange, isOverdue=true, or restricting status to non-NotStarted values. (2) Prefer the narrowest date range that answers the question — broad ranges (quarterly/yearly) are expensive; prefer Today / ThisWeek / Next7Days / ThisMonth over larger windows unless explicitly asked. (3) For 'oldest incomplete tasks' prefer status=['InProgress','Blocked'] with sortBy=StartDate (no date range needed), or add isOverdue=true if 'oldest overdue' is meant. (4) For 'how many X?' questions, pass limit=0 to get just the total count without fetching any task data — much cheaper than fetching a full page and counting.",
|
|
9536
|
+
description: "List tasks with any combination of filters: assigned user(s), unassigned, client(s), the primary client's client manager / partner (portfolio views: 'tasks across the clients Jane manages'), status, overdue flag, preset date range (Today / ThisWeek / Next7Days / CustomDateRange etc), category, team, billable service, workflow, workflow step type, current step name, recurring task template, free-text search, saved filter, include-projected, include-workflow-steps (Agenda Mode), sort, and pagination. Use for: 'my tasks' (pass current user's code from startup context), 'Jane's overdue tasks' (user + isOverdue), 'tasks for ACME due this week' (client + dateRange=Next7Days + dateBasis=DueDate), 'what is the team working on this month' (dateRange=ThisMonth, no user filter). Returns up to 50 tasks per page; each row shows due date, statutory due date (when set), client, billable service (name + code), assignee, status and workflow progress. IMPORTANT constraints to avoid API errors and keep queries efficient: (1) Querying NotStarted tasks requires one of — a dateRange, isOverdue=true, or restricting status to non-NotStarted values. (2) Prefer the narrowest date range that answers the question — broad ranges (quarterly/yearly) are expensive; prefer Today / ThisWeek / Next7Days / ThisMonth over larger windows unless explicitly asked. (3) For 'oldest incomplete tasks' prefer status=['InProgress','Blocked'] with sortBy=StartDate (no date range needed), or add isOverdue=true if 'oldest overdue' is meant. (4) For 'how many X?' questions, pass limit=0 to get just the total count without fetching any task data — much cheaper than fetching a full page and counting.",
|
|
9524
9537
|
inputSchema: ListTasksInputSchema,
|
|
9525
9538
|
annotations: {
|
|
9526
9539
|
readOnlyHint: true,
|
|
@@ -9530,7 +9543,7 @@ async function buildServer(config) {
|
|
|
9530
9543
|
}, (args) => handleListTasks(api, args));
|
|
9531
9544
|
registerTenantTool(server, api, "get_task_context", {
|
|
9532
9545
|
title: "Get full context for a single task",
|
|
9533
|
-
description: "Get a consolidated view of one task by code: identity (name, code, status, overdue flag, start/due/statutory dates, time estimate, assignee), description, task-level checklist, workflow progress (groups and steps with status, assignee, and completion info — only if the task has a workflow attached), notes (pinned first, then newest first), and the parent client. Use this AFTER list_tasks identifies a task of interest, or when the user references a specific task by code. Tolerates partial failures — if notes or workflow steps can't be loaded, the task details are still returned with a note about what's missing. Only fails outright if the task itself can't be fetched (e.g. unknown code).",
|
|
9546
|
+
description: "Get a consolidated view of one task by code: identity (name, code, status, overdue flag, start/due/statutory dates, time estimate, assignee, category, billable service, recurring/workflow templates), description, task-level checklist, workflow progress (groups and steps with status, assignee, and completion info — only if the task has a workflow attached), notes (pinned first, then newest first), and the parent client. Use this AFTER list_tasks identifies a task of interest, or when the user references a specific task by code. Tolerates partial failures — if notes or workflow steps can't be loaded, the task details are still returned with a note about what's missing. Only fails outright if the task itself can't be fetched (e.g. unknown code).",
|
|
9534
9547
|
inputSchema: GetTaskContextInputSchema,
|
|
9535
9548
|
annotations: {
|
|
9536
9549
|
readOnlyHint: true,
|
|
@@ -10063,7 +10076,7 @@ async function buildServer(config) {
|
|
|
10063
10076
|
}, (args) => handleCreateTask(api, args));
|
|
10064
10077
|
registerWriteTool(server, api, config.context, "update_task", {
|
|
10065
10078
|
title: "Update a task (status, dates, assignment, details)",
|
|
10066
|
-
description: "Update fields on an existing task by code: status (mark Completed / InProgress / Blocked / Skipped), name, description, start/due/statutory dates, time estimate, assigned user or team, and category. Only the fields you pass change —
|
|
10079
|
+
description: "Update fields on an existing task by code: status (mark Completed / InProgress / Blocked / Skipped), name, description, start/due/statutory dates, time estimate, assigned user or team, and category. Only the fields you pass change — everything else on the task (clients, checklist, start and due times, service and recurring-task links) is left exactly as it is, so it's safe to pass just { taskCode, status: 'Completed' } for 'mark it done'. Pass null to clear a clearable field (description, statutory date, estimate, assignee, team, category). Use for 'mark TSK-123 complete', 'push the deadline to Friday', 'reassign it to Jane' (resolve her code from the roster), 'unassign this task' (assignedUserCode=null). Completing a task does NOT complete its workflow steps — if get_task_context showed open steps, tell the user they remain open. Cannot delete tasks — deletion isn't available through the MCP.",
|
|
10067
10080
|
inputSchema: UpdateTaskInputSchema,
|
|
10068
10081
|
annotations: {
|
|
10069
10082
|
readOnlyHint: false,
|