@task-mcp/shared 1.0.21 → 1.0.23

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.
@@ -28,26 +28,27 @@ const BaseResponse = z.object({
28
28
  type: ResponseType.describe("Type of response: question, suggestion, or confirmation"),
29
29
  message: z.string().describe("Main message to display to user"),
30
30
  context: z.string().optional().describe("Additional context or explanation"),
31
- priority: ResponsePriority.optional().describe("Urgency/importance of response (default: medium)"),
31
+ priority: ResponsePriority.optional().describe(
32
+ "Urgency/importance of response (default: medium)"
33
+ ),
32
34
  });
33
35
 
34
36
  // Question response - for clarification
35
37
  export const QuestionResponse = BaseResponse.extend({
36
38
  type: z.literal("question"),
37
- options: z.array(ResponseOption).optional()
39
+ options: z
40
+ .array(ResponseOption)
41
+ .optional()
38
42
  .describe("Multiple choice options (omit for free-form answer)"),
39
- defaultOption: z.string().optional()
40
- .describe("Default option value if user provides no input"),
43
+ defaultOption: z.string().optional().describe("Default option value if user provides no input"),
41
44
  });
42
45
  export type QuestionResponse = z.infer<typeof QuestionResponse>;
43
46
 
44
47
  // Suggestion response - for recommendations
45
48
  export const SuggestionResponse = BaseResponse.extend({
46
49
  type: z.literal("suggestion"),
47
- options: z.array(ResponseOption).min(1)
48
- .describe("Suggested options for user to choose from"),
49
- reasoning: z.string().optional()
50
- .describe("Explanation of why these suggestions were made"),
50
+ options: z.array(ResponseOption).min(1).describe("Suggested options for user to choose from"),
51
+ reasoning: z.string().optional().describe("Explanation of why these suggestions were made"),
51
52
  });
52
53
  export type SuggestionResponse = z.infer<typeof SuggestionResponse>;
53
54
 
@@ -55,9 +56,13 @@ export type SuggestionResponse = z.infer<typeof SuggestionResponse>;
55
56
  export const ConfirmationResponse = BaseResponse.extend({
56
57
  type: z.literal("confirmation"),
57
58
  action: z.string().describe("Action that will be taken if confirmed"),
58
- consequences: z.array(z.string()).optional()
59
+ consequences: z
60
+ .array(z.string())
61
+ .optional()
59
62
  .describe("List of effects or changes that will occur"),
60
- defaultConfirm: z.boolean().optional()
63
+ defaultConfirm: z
64
+ .boolean()
65
+ .optional()
61
66
  .describe("Default choice if user provides no input (default: false)"),
62
67
  });
63
68
  export type ConfirmationResponse = z.infer<typeof ConfirmationResponse>;
@@ -74,19 +79,19 @@ export type AgentResponse = z.infer<typeof AgentResponse>;
74
79
  export const GenerateResponseInput = z.object({
75
80
  type: ResponseType.describe("Type of response to generate"),
76
81
  message: z.string().describe("Main message"),
77
- options: z.array(ResponseOption).optional()
78
- .describe("Options for question/suggestion types"),
82
+ options: z.array(ResponseOption).optional().describe("Options for question/suggestion types"),
79
83
  context: z.string().optional(),
80
84
  priority: ResponsePriority.optional().default("medium"),
81
- action: z.string().optional()
82
- .describe("Action description (for confirmation type)"),
83
- consequences: z.array(z.string()).optional()
85
+ action: z.string().optional().describe("Action description (for confirmation type)"),
86
+ consequences: z
87
+ .array(z.string())
88
+ .optional()
84
89
  .describe("Consequences list (for confirmation type)"),
85
- reasoning: z.string().optional()
86
- .describe("Reasoning explanation (for suggestion type)"),
87
- defaultOption: z.string().optional()
88
- .describe("Default option value (for question type)"),
89
- defaultConfirm: z.boolean().optional()
90
+ reasoning: z.string().optional().describe("Reasoning explanation (for suggestion type)"),
91
+ defaultOption: z.string().optional().describe("Default option value (for question type)"),
92
+ defaultConfirm: z
93
+ .boolean()
94
+ .optional()
90
95
  .describe("Default confirmation choice (for confirmation type)"),
91
96
  });
92
97
  export type GenerateResponseInput = z.infer<typeof GenerateResponseInput>;
@@ -5,13 +5,7 @@ export const Priority = z.enum(["critical", "high", "medium", "low"]);
5
5
  export type Priority = z.infer<typeof Priority>;
6
6
 
7
7
  // Task status with clear state machine
8
- export const TaskStatus = z.enum([
9
- "pending",
10
- "in_progress",
11
- "blocked",
12
- "completed",
13
- "cancelled",
14
- ]);
8
+ export const TaskStatus = z.enum(["pending", "in_progress", "blocked", "completed", "cancelled"]);
15
9
  export type TaskStatus = z.infer<typeof TaskStatus>;
16
10
 
17
11
  // Dependency relationship types
@@ -37,25 +31,13 @@ export const TimeEstimate = z
37
31
  .refine(
38
32
  (data) => {
39
33
  const { optimistic, expected, pessimistic } = data;
40
- if (
41
- optimistic !== undefined &&
42
- expected !== undefined &&
43
- optimistic > expected
44
- ) {
34
+ if (optimistic !== undefined && expected !== undefined && optimistic > expected) {
45
35
  return false;
46
36
  }
47
- if (
48
- expected !== undefined &&
49
- pessimistic !== undefined &&
50
- expected > pessimistic
51
- ) {
37
+ if (expected !== undefined && pessimistic !== undefined && expected > pessimistic) {
52
38
  return false;
53
39
  }
54
- if (
55
- optimistic !== undefined &&
56
- pessimistic !== undefined &&
57
- optimistic > pessimistic
58
- ) {
40
+ if (optimistic !== undefined && pessimistic !== undefined && optimistic > pessimistic) {
59
41
  return false;
60
42
  }
61
43
  return true;
@@ -41,11 +41,13 @@ export interface DashboardStats {
41
41
  export interface DependencyMetrics {
42
42
  readyToWork: number;
43
43
  blockedByDependencies: number;
44
- mostDependedOn?: {
45
- id: string;
46
- title: string;
47
- dependentCount: number;
48
- } | undefined;
44
+ mostDependedOn?:
45
+ | {
46
+ id: string;
47
+ title: string;
48
+ dependentCount: number;
49
+ }
50
+ | undefined;
49
51
  }
50
52
 
51
53
  export interface WorkspaceInfo {
@@ -107,9 +109,7 @@ export function calculateStats(tasks: Task[]): DashboardStats {
107
109
  }
108
110
 
109
111
  export function calculateDependencyMetrics(tasks: Task[]): DependencyMetrics {
110
- const completedIds = new Set(
111
- tasks.filter((t) => t.status === "completed").map((t) => t.id)
112
- );
112
+ const completedIds = new Set(tasks.filter((t) => t.status === "completed").map((t) => t.id));
113
113
 
114
114
  let readyToWork = 0;
115
115
  let blockedByDependencies = 0;
@@ -134,10 +134,7 @@ export function calculateDependencyMetrics(tasks: Task[]): DependencyMetrics {
134
134
 
135
135
  // Track dependent counts
136
136
  for (const dep of deps) {
137
- dependentCounts.set(
138
- dep.taskId,
139
- (dependentCounts.get(dep.taskId) ?? 0) + 1
140
- );
137
+ dependentCounts.set(dep.taskId, (dependentCounts.get(dep.taskId) ?? 0) + 1);
141
138
  }
142
139
  }
143
140
 
@@ -192,8 +189,7 @@ export function renderStatusWidget(tasks: Task[]): string {
192
189
  const today = getTodayTasks(tasks);
193
190
  const overdue = getOverdueTasks(tasks);
194
191
  const activeTasks = stats.total - stats.cancelled;
195
- const percent =
196
- activeTasks > 0 ? Math.round((stats.completed / activeTasks) * 100) : 0;
192
+ const percent = activeTasks > 0 ? Math.round((stats.completed / activeTasks) * 100) : 0;
197
193
 
198
194
  const lines: string[] = [];
199
195
 
@@ -252,16 +248,10 @@ export function renderActionsWidget(tasks: Task[]): string {
252
248
 
253
249
  // Get top 4 ready tasks sorted by priority
254
250
  const readyTasks = tasks
255
- .filter(
256
- (t) =>
257
- t.status === "pending" &&
258
- (!t.dependencies || t.dependencies.length === 0)
259
- )
251
+ .filter((t) => t.status === "pending" && (!t.dependencies || t.dependencies.length === 0))
260
252
  .sort((a, b) => {
261
253
  const priorityOrder = { critical: 0, high: 1, medium: 2, low: 3 };
262
- return (
263
- (priorityOrder[a.priority] ?? 2) - (priorityOrder[b.priority] ?? 2)
264
- );
254
+ return (priorityOrder[a.priority] ?? 2) - (priorityOrder[b.priority] ?? 2);
265
255
  })
266
256
  .slice(0, 4);
267
257
 
@@ -341,17 +331,13 @@ export function renderWorkspacesTable(
341
331
  const stats = calculateStats(tasks);
342
332
  const depMetrics = calculateDependencyMetrics(tasks);
343
333
  const activeTasks = stats.total - stats.cancelled;
344
- const percent =
345
- activeTasks > 0
346
- ? Math.round((stats.completed / activeTasks) * 100)
347
- : 0;
334
+ const percent = activeTasks > 0 ? Math.round((stats.completed / activeTasks) * 100) : 0;
348
335
 
349
336
  // Create mini progress bar
350
337
  const barWidth = 8;
351
338
  const filled = Math.round((percent / 100) * barWidth);
352
339
  const empty = barWidth - filled;
353
- const miniBar =
354
- c.green("█".repeat(filled)) + c.gray("░".repeat(empty));
340
+ const miniBar = c.green("█".repeat(filled)) + c.gray("░".repeat(empty));
355
341
 
356
342
  rows.push({
357
343
  name: truncateStr(ws.name, 20),
@@ -392,9 +378,7 @@ export const renderProjectsTable = renderWorkspacesTable;
392
378
  * Render Tasks table for single workspace view
393
379
  */
394
380
  export function renderTasksTable(tasks: Task[], limit: number = 10): string {
395
- const activeTasks = tasks.filter(
396
- (t) => t.status !== "completed" && t.status !== "cancelled"
397
- );
381
+ const activeTasks = tasks.filter((t) => t.status !== "completed" && t.status !== "cancelled");
398
382
 
399
383
  if (activeTasks.length === 0) {
400
384
  return c.gray("No active tasks.");
@@ -421,10 +405,7 @@ export function renderTasksTable(tasks: Task[], limit: number = 10): string {
421
405
  },
422
406
  ];
423
407
 
424
- let result = table(
425
- displayTasks as unknown as Record<string, unknown>[],
426
- columns
427
- );
408
+ let result = table(displayTasks as unknown as Record<string, unknown>[], columns);
428
409
 
429
410
  if (activeTasks.length > limit) {
430
411
  result += `\n${c.gray(`(+${activeTasks.length - limit} more tasks)`)}`;
@@ -440,21 +421,14 @@ export function renderTasksTable(tasks: Task[], limit: number = 10): string {
440
421
  function getTodayTasks(tasks: Task[]): Task[] {
441
422
  const today = new Date().toISOString().split("T")[0];
442
423
  return tasks.filter(
443
- (t) =>
444
- t.dueDate === today &&
445
- t.status !== "completed" &&
446
- t.status !== "cancelled"
424
+ (t) => t.dueDate === today && t.status !== "completed" && t.status !== "cancelled"
447
425
  );
448
426
  }
449
427
 
450
428
  function getOverdueTasks(tasks: Task[]): Task[] {
451
429
  const today = new Date().toISOString().split("T")[0] ?? "";
452
430
  return tasks.filter(
453
- (t) =>
454
- t.dueDate &&
455
- t.dueDate < today &&
456
- t.status !== "completed" &&
457
- t.status !== "cancelled"
431
+ (t) => t.dueDate && t.dueDate < today && t.status !== "completed" && t.status !== "cancelled"
458
432
  );
459
433
  }
460
434
 
@@ -538,9 +512,7 @@ export function renderDashboard(
538
512
 
539
513
  // Tasks table (for single workspace view)
540
514
  if (showTasks && (currentWorkspace || workspaces.length === 1)) {
541
- const activeTasks = tasks.filter(
542
- (t) => t.status !== "completed" && t.status !== "cancelled"
543
- );
515
+ const activeTasks = tasks.filter((t) => t.status !== "completed" && t.status !== "cancelled");
544
516
  if (activeTasks.length > 0) {
545
517
  lines.push(c.bold(`Tasks (${activeTasks.length})`));
546
518
  lines.push("");
@@ -565,7 +537,7 @@ export function renderWorkspaceDashboard(
565
537
  const wsInfo: WorkspaceInfo = {
566
538
  name: workspace,
567
539
  taskCount: tasks.length,
568
- completedCount: tasks.filter(t => t.status === "completed").length,
540
+ completedCount: tasks.filter((t) => t.status === "completed").length,
569
541
  };
570
542
 
571
543
  const data: DashboardData = {
@@ -576,17 +548,13 @@ export function renderWorkspaceDashboard(
576
548
  activeTag: options.activeTag,
577
549
  };
578
550
 
579
- return renderDashboard(
580
- data,
581
- () => tasks,
582
- {
583
- showBanner: true,
584
- showInbox: false,
585
- showWorkspaces: false,
586
- showTasks: true,
587
- stripAnsiCodes: options.stripAnsiCodes,
588
- }
589
- );
551
+ return renderDashboard(data, () => tasks, {
552
+ showBanner: true,
553
+ showInbox: false,
554
+ showWorkspaces: false,
555
+ showTasks: true,
556
+ stripAnsiCodes: options.stripAnsiCodes,
557
+ });
590
558
  }
591
559
 
592
560
  // Legacy export for backwards compatibility
package/src/utils/date.ts CHANGED
@@ -247,11 +247,7 @@ export function parseDateString(input: string): Date {
247
247
 
248
248
  const d = new Date(input);
249
249
  if (isNaN(d.getTime())) {
250
- throw new DateParseError(
251
- `Unable to parse "${input}" as a date`,
252
- input,
253
- "invalid_format"
254
- );
250
+ throw new DateParseError(`Unable to parse "${input}" as a date`, input, "invalid_format");
255
251
  }
256
252
 
257
253
  return d;
@@ -280,11 +276,7 @@ export function formatDisplayDate(date: Date | string): string {
280
276
  }
281
277
 
282
278
  if (!isValidDate(d)) {
283
- throw new DateParseError(
284
- "Invalid Date object provided",
285
- String(date),
286
- "invalid_date"
287
- );
279
+ throw new DateParseError("Invalid Date object provided", String(date), "invalid_date");
288
280
  }
289
281
 
290
282
  const parts = new Intl.DateTimeFormat(undefined, {
@@ -34,7 +34,9 @@ export function getTaskLevel(tasks: Task[], taskId: string): number {
34
34
  while (currentTask.parentId) {
35
35
  const parent = taskMap.get(currentTask.parentId);
36
36
  if (!parent) {
37
- console.warn(`[task-mcp] Orphaned parent reference: task "${currentTask.id}" references non-existent parent "${currentTask.parentId}"`);
37
+ console.warn(
38
+ `[task-mcp] Orphaned parent reference: task "${currentTask.id}" references non-existent parent "${currentTask.parentId}"`
39
+ );
38
40
  break;
39
41
  }
40
42
  level++;
@@ -57,10 +59,7 @@ export function getTaskLevel(tasks: Task[], taskId: string): number {
57
59
  * @param parentId - ID of the proposed parent task
58
60
  * @returns true if a child can be added, false if it would exceed max depth
59
61
  */
60
- export function validateHierarchyDepth(
61
- tasks: Task[],
62
- parentId: string
63
- ): boolean {
62
+ export function validateHierarchyDepth(tasks: Task[], parentId: string): boolean {
64
63
  const parentLevel = getTaskLevel(tasks, parentId);
65
64
 
66
65
  if (parentLevel === -1) {
@@ -31,7 +31,13 @@ export {
31
31
  type DateParseResult,
32
32
  type IsWithinDaysResult,
33
33
  } from "./date.js";
34
- export { parseTaskInput, parseInboxInput, parseInput, type ParseTarget, type ParsedInput } from "./natural-language.js";
34
+ export {
35
+ parseTaskInput,
36
+ parseInboxInput,
37
+ parseInput,
38
+ type ParseTarget,
39
+ type ParsedInput,
40
+ } from "./natural-language.js";
35
41
  export {
36
42
  MAX_HIERARCHY_DEPTH,
37
43
  getTaskLevel,
@@ -46,11 +52,11 @@ export {
46
52
 
47
53
  // Projection utilities (token optimization)
48
54
  export {
49
- projectTask,
50
- projectTasks,
51
- projectTasksPaginated,
52
- projectInboxItem,
53
- projectInboxItems,
55
+ formatTask,
56
+ formatTasks,
57
+ formatTasksPaginated,
58
+ formatInboxItem,
59
+ formatInboxItems,
54
60
  formatResponse,
55
61
  applyPagination,
56
62
  truncate,