@task-mcp/shared 0.1.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.
Files changed (81) hide show
  1. package/dist/algorithms/critical-path.d.ts +46 -0
  2. package/dist/algorithms/critical-path.d.ts.map +1 -0
  3. package/dist/algorithms/critical-path.js +308 -0
  4. package/dist/algorithms/critical-path.js.map +1 -0
  5. package/dist/algorithms/critical-path.test.d.ts +2 -0
  6. package/dist/algorithms/critical-path.test.d.ts.map +1 -0
  7. package/dist/algorithms/critical-path.test.js +194 -0
  8. package/dist/algorithms/critical-path.test.js.map +1 -0
  9. package/dist/algorithms/index.d.ts +3 -0
  10. package/dist/algorithms/index.d.ts.map +1 -0
  11. package/dist/algorithms/index.js +3 -0
  12. package/dist/algorithms/index.js.map +1 -0
  13. package/dist/algorithms/topological-sort.d.ts +41 -0
  14. package/dist/algorithms/topological-sort.d.ts.map +1 -0
  15. package/dist/algorithms/topological-sort.js +168 -0
  16. package/dist/algorithms/topological-sort.js.map +1 -0
  17. package/dist/algorithms/topological-sort.test.d.ts +2 -0
  18. package/dist/algorithms/topological-sort.test.d.ts.map +1 -0
  19. package/dist/algorithms/topological-sort.test.js +162 -0
  20. package/dist/algorithms/topological-sort.test.js.map +1 -0
  21. package/dist/index.d.ts +4 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +7 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/schemas/index.d.ts +4 -0
  26. package/dist/schemas/index.d.ts.map +1 -0
  27. package/dist/schemas/index.js +7 -0
  28. package/dist/schemas/index.js.map +1 -0
  29. package/dist/schemas/project.d.ts +55 -0
  30. package/dist/schemas/project.d.ts.map +1 -0
  31. package/dist/schemas/project.js +48 -0
  32. package/dist/schemas/project.js.map +1 -0
  33. package/dist/schemas/task.d.ts +124 -0
  34. package/dist/schemas/task.d.ts.map +1 -0
  35. package/dist/schemas/task.js +89 -0
  36. package/dist/schemas/task.js.map +1 -0
  37. package/dist/schemas/view.d.ts +44 -0
  38. package/dist/schemas/view.d.ts.map +1 -0
  39. package/dist/schemas/view.js +33 -0
  40. package/dist/schemas/view.js.map +1 -0
  41. package/dist/utils/date.d.ts +25 -0
  42. package/dist/utils/date.d.ts.map +1 -0
  43. package/dist/utils/date.js +103 -0
  44. package/dist/utils/date.js.map +1 -0
  45. package/dist/utils/date.test.d.ts +2 -0
  46. package/dist/utils/date.test.d.ts.map +1 -0
  47. package/dist/utils/date.test.js +138 -0
  48. package/dist/utils/date.test.js.map +1 -0
  49. package/dist/utils/id.d.ts +27 -0
  50. package/dist/utils/id.d.ts.map +1 -0
  51. package/dist/utils/id.js +41 -0
  52. package/dist/utils/id.js.map +1 -0
  53. package/dist/utils/index.d.ts +4 -0
  54. package/dist/utils/index.d.ts.map +1 -0
  55. package/dist/utils/index.js +4 -0
  56. package/dist/utils/index.js.map +1 -0
  57. package/dist/utils/natural-language.d.ts +12 -0
  58. package/dist/utils/natural-language.d.ts.map +1 -0
  59. package/dist/utils/natural-language.js +112 -0
  60. package/dist/utils/natural-language.js.map +1 -0
  61. package/dist/utils/natural-language.test.d.ts +2 -0
  62. package/dist/utils/natural-language.test.d.ts.map +1 -0
  63. package/dist/utils/natural-language.test.js +132 -0
  64. package/dist/utils/natural-language.test.js.map +1 -0
  65. package/package.json +46 -0
  66. package/src/algorithms/critical-path.test.ts +241 -0
  67. package/src/algorithms/critical-path.ts +413 -0
  68. package/src/algorithms/index.ts +17 -0
  69. package/src/algorithms/topological-sort.test.ts +190 -0
  70. package/src/algorithms/topological-sort.ts +204 -0
  71. package/src/index.ts +8 -0
  72. package/src/schemas/index.ts +30 -0
  73. package/src/schemas/project.ts +62 -0
  74. package/src/schemas/task.ts +116 -0
  75. package/src/schemas/view.ts +46 -0
  76. package/src/utils/date.test.ts +160 -0
  77. package/src/utils/date.ts +119 -0
  78. package/src/utils/id.ts +45 -0
  79. package/src/utils/index.ts +3 -0
  80. package/src/utils/natural-language.test.ts +154 -0
  81. package/src/utils/natural-language.ts +125 -0
@@ -0,0 +1,89 @@
1
+ import { type } from "arktype";
2
+ // Priority levels
3
+ export const Priority = type("'critical' | 'high' | 'medium' | 'low'");
4
+ // Task status with clear state machine
5
+ export const TaskStatus = type("'pending' | 'in_progress' | 'blocked' | 'completed' | 'cancelled'");
6
+ // Dependency relationship types
7
+ export const DependencyType = type("'blocks' | 'blocked_by' | 'related'");
8
+ // A single dependency link
9
+ export const Dependency = type({
10
+ taskId: "string",
11
+ type: DependencyType,
12
+ "reason?": "string",
13
+ });
14
+ // Time estimation
15
+ export const TimeEstimate = type({
16
+ "optimistic?": "number", // minutes
17
+ "expected?": "number", // minutes
18
+ "pessimistic?": "number", // minutes
19
+ "confidence?": "'low' | 'medium' | 'high'",
20
+ });
21
+ // Recurrence pattern
22
+ export const Recurrence = type({
23
+ pattern: "'daily' | 'weekly' | 'monthly' | 'after_completion'",
24
+ "interval?": "number", // every N days/weeks/months
25
+ "daysOfWeek?": "number[]", // 0-6 for weekly
26
+ "endDate?": "string",
27
+ });
28
+ // Core Task schema
29
+ export const Task = type({
30
+ id: "string",
31
+ title: "string",
32
+ "description?": "string",
33
+ status: TaskStatus,
34
+ priority: Priority,
35
+ projectId: "string",
36
+ // Dependencies
37
+ "dependencies?": Dependency.array(),
38
+ // Time tracking
39
+ "estimate?": TimeEstimate,
40
+ "actualMinutes?": "number",
41
+ "dueDate?": "string", // ISO date string
42
+ "startDate?": "string", // When task can start
43
+ "startedAt?": "string",
44
+ "completedAt?": "string",
45
+ // Organization
46
+ "contexts?": "string[]", // e.g., ["focus", "review"]
47
+ "tags?": "string[]",
48
+ // Recurrence
49
+ "recurrence?": Recurrence,
50
+ // Metadata
51
+ createdAt: "string",
52
+ updatedAt: "string",
53
+ // Computed fields (populated at runtime)
54
+ "criticalPath?": "boolean",
55
+ "slack?": "number", // Minutes of slack time
56
+ "earliestStart?": "number", // Minutes from project start
57
+ "latestStart?": "number",
58
+ });
59
+ // Task creation input (minimal required fields)
60
+ export const TaskCreateInput = type({
61
+ title: "string",
62
+ "description?": "string",
63
+ "projectId?": "string",
64
+ "priority?": Priority,
65
+ "dependencies?": Dependency.array(),
66
+ "estimate?": TimeEstimate,
67
+ "dueDate?": "string",
68
+ "startDate?": "string",
69
+ "contexts?": "string[]",
70
+ "tags?": "string[]",
71
+ "recurrence?": Recurrence,
72
+ });
73
+ // Task update input
74
+ export const TaskUpdateInput = type({
75
+ "title?": "string",
76
+ "description?": "string",
77
+ "status?": TaskStatus,
78
+ "priority?": Priority,
79
+ "projectId?": "string",
80
+ "dependencies?": Dependency.array(),
81
+ "estimate?": TimeEstimate,
82
+ "actualMinutes?": "number",
83
+ "dueDate?": "string",
84
+ "startDate?": "string",
85
+ "contexts?": "string[]",
86
+ "tags?": "string[]",
87
+ "recurrence?": Recurrence,
88
+ });
89
+ //# sourceMappingURL=task.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task.js","sourceRoot":"","sources":["../../src/schemas/task.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE/B,kBAAkB;AAClB,MAAM,CAAC,MAAM,QAAQ,GAAG,IAAI,CAAC,wCAAwC,CAAC,CAAC;AAGvE,uCAAuC;AACvC,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,CAC5B,mEAAmE,CACpE,CAAC;AAGF,gCAAgC;AAChC,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,CAChC,qCAAqC,CACtC,CAAC;AAGF,2BAA2B;AAC3B,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,CAAC;IAC7B,MAAM,EAAE,QAAQ;IAChB,IAAI,EAAE,cAAc;IACpB,SAAS,EAAE,QAAQ;CACpB,CAAC,CAAC;AAGH,kBAAkB;AAClB,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,CAAC;IAC/B,aAAa,EAAE,QAAQ,EAAE,UAAU;IACnC,WAAW,EAAE,QAAQ,EAAE,UAAU;IACjC,cAAc,EAAE,QAAQ,EAAE,UAAU;IACpC,aAAa,EAAE,2BAA2B;CAC3C,CAAC,CAAC;AAGH,qBAAqB;AACrB,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,CAAC;IAC7B,OAAO,EAAE,qDAAqD;IAC9D,WAAW,EAAE,QAAQ,EAAE,4BAA4B;IACnD,aAAa,EAAE,UAAU,EAAE,iBAAiB;IAC5C,UAAU,EAAE,QAAQ;CACrB,CAAC,CAAC;AAGH,mBAAmB;AACnB,MAAM,CAAC,MAAM,IAAI,GAAG,IAAI,CAAC;IACvB,EAAE,EAAE,QAAQ;IACZ,KAAK,EAAE,QAAQ;IACf,cAAc,EAAE,QAAQ;IACxB,MAAM,EAAE,UAAU;IAClB,QAAQ,EAAE,QAAQ;IAClB,SAAS,EAAE,QAAQ;IAEnB,eAAe;IACf,eAAe,EAAE,UAAU,CAAC,KAAK,EAAE;IAEnC,gBAAgB;IAChB,WAAW,EAAE,YAAY;IACzB,gBAAgB,EAAE,QAAQ;IAC1B,UAAU,EAAE,QAAQ,EAAE,kBAAkB;IACxC,YAAY,EAAE,QAAQ,EAAE,sBAAsB;IAC9C,YAAY,EAAE,QAAQ;IACtB,cAAc,EAAE,QAAQ;IAExB,eAAe;IACf,WAAW,EAAE,UAAU,EAAE,4BAA4B;IACrD,OAAO,EAAE,UAAU;IAEnB,aAAa;IACb,aAAa,EAAE,UAAU;IAEzB,WAAW;IACX,SAAS,EAAE,QAAQ;IACnB,SAAS,EAAE,QAAQ;IAEnB,yCAAyC;IACzC,eAAe,EAAE,SAAS;IAC1B,QAAQ,EAAE,QAAQ,EAAE,wBAAwB;IAC5C,gBAAgB,EAAE,QAAQ,EAAE,6BAA6B;IACzD,cAAc,EAAE,QAAQ;CACzB,CAAC,CAAC;AAGH,gDAAgD;AAChD,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,CAAC;IAClC,KAAK,EAAE,QAAQ;IACf,cAAc,EAAE,QAAQ;IACxB,YAAY,EAAE,QAAQ;IACtB,WAAW,EAAE,QAAQ;IACrB,eAAe,EAAE,UAAU,CAAC,KAAK,EAAE;IACnC,WAAW,EAAE,YAAY;IACzB,UAAU,EAAE,QAAQ;IACpB,YAAY,EAAE,QAAQ;IACtB,WAAW,EAAE,UAAU;IACvB,OAAO,EAAE,UAAU;IACnB,aAAa,EAAE,UAAU;CAC1B,CAAC,CAAC;AAGH,oBAAoB;AACpB,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,CAAC;IAClC,QAAQ,EAAE,QAAQ;IAClB,cAAc,EAAE,QAAQ;IACxB,SAAS,EAAE,UAAU;IACrB,WAAW,EAAE,QAAQ;IACrB,YAAY,EAAE,QAAQ;IACtB,eAAe,EAAE,UAAU,CAAC,KAAK,EAAE;IACnC,WAAW,EAAE,YAAY;IACzB,gBAAgB,EAAE,QAAQ;IAC1B,UAAU,EAAE,QAAQ;IACpB,YAAY,EAAE,QAAQ;IACtB,WAAW,EAAE,UAAU;IACvB,OAAO,EAAE,UAAU;IACnB,aAAa,EAAE,UAAU;CAC1B,CAAC,CAAC"}
@@ -0,0 +1,44 @@
1
+ export declare const SmartViewFilter: import("arktype/internal/methods/object.ts").ObjectType<{
2
+ statuses?: ("pending" | "in_progress" | "blocked" | "completed" | "cancelled")[];
3
+ priorities?: ("critical" | "high" | "medium" | "low")[];
4
+ contexts?: string[];
5
+ tags?: string[];
6
+ projectIds?: string[];
7
+ dueBefore?: string;
8
+ dueAfter?: string;
9
+ isBlocked?: boolean;
10
+ isCriticalPath?: boolean;
11
+ hasNoDependencies?: boolean;
12
+ search?: string;
13
+ }, {}>;
14
+ export type SmartViewFilter = typeof SmartViewFilter.infer;
15
+ export declare const SortField: import("arktype/internal/methods/string.ts").StringType<"title" | "priority" | "createdAt" | "dueDate" | "criticalPath" | "slack", {}>;
16
+ export type SortField = typeof SortField.infer;
17
+ export declare const SortOrder: import("arktype/internal/methods/string.ts").StringType<"asc" | "desc", {}>;
18
+ export type SortOrder = typeof SortOrder.infer;
19
+ export declare const SmartView: import("arktype/internal/methods/object.ts").ObjectType<{
20
+ id: string;
21
+ name: string;
22
+ filter: {
23
+ statuses?: ("pending" | "in_progress" | "blocked" | "completed" | "cancelled")[];
24
+ priorities?: ("critical" | "high" | "medium" | "low")[];
25
+ contexts?: string[];
26
+ tags?: string[];
27
+ projectIds?: string[];
28
+ dueBefore?: string;
29
+ dueAfter?: string;
30
+ isBlocked?: boolean;
31
+ isCriticalPath?: boolean;
32
+ hasNoDependencies?: boolean;
33
+ search?: string;
34
+ };
35
+ createdAt: string;
36
+ updatedAt: string;
37
+ description?: string;
38
+ sortBy?: "title" | "priority" | "createdAt" | "dueDate" | "criticalPath" | "slack";
39
+ sortOrder?: "asc" | "desc";
40
+ }, {}>;
41
+ export type SmartView = typeof SmartView.infer;
42
+ export declare const BuiltInView: import("arktype/internal/methods/string.ts").StringType<"blocked" | "today" | "this_week" | "critical_path" | "quick_wins" | "all", {}>;
43
+ export type BuiltInView = typeof BuiltInView.infer;
44
+ //# sourceMappingURL=view.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../../src/schemas/view.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,eAAe;;;;;;;;;;;;MAY1B,CAAC;AACH,MAAM,MAAM,eAAe,GAAG,OAAO,eAAe,CAAC,KAAK,CAAC;AAG3D,eAAO,MAAM,SAAS,wIAErB,CAAC;AACF,MAAM,MAAM,SAAS,GAAG,OAAO,SAAS,CAAC,KAAK,CAAC;AAE/C,eAAO,MAAM,SAAS,6EAAyB,CAAC;AAChD,MAAM,MAAM,SAAS,GAAG,OAAO,SAAS,CAAC,KAAK,CAAC;AAG/C,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;MASpB,CAAC;AACH,MAAM,MAAM,SAAS,GAAG,OAAO,SAAS,CAAC,KAAK,CAAC;AAG/C,eAAO,MAAM,WAAW,yIAEvB,CAAC;AACF,MAAM,MAAM,WAAW,GAAG,OAAO,WAAW,CAAC,KAAK,CAAC"}
@@ -0,0 +1,33 @@
1
+ import { type } from "arktype";
2
+ import { Priority, TaskStatus } from "./task.js";
3
+ // Smart View filter
4
+ export const SmartViewFilter = type({
5
+ "statuses?": TaskStatus.array(),
6
+ "priorities?": Priority.array(),
7
+ "contexts?": "string[]",
8
+ "tags?": "string[]",
9
+ "projectIds?": "string[]",
10
+ "dueBefore?": "string",
11
+ "dueAfter?": "string",
12
+ "isBlocked?": "boolean",
13
+ "isCriticalPath?": "boolean",
14
+ "hasNoDependencies?": "boolean",
15
+ "search?": "string", // Search in title/description
16
+ });
17
+ // Sort options
18
+ export const SortField = type("'priority' | 'dueDate' | 'createdAt' | 'criticalPath' | 'slack' | 'title'");
19
+ export const SortOrder = type("'asc' | 'desc'");
20
+ // Smart View definition
21
+ export const SmartView = type({
22
+ id: "string",
23
+ name: "string",
24
+ "description?": "string",
25
+ filter: SmartViewFilter,
26
+ "sortBy?": SortField,
27
+ "sortOrder?": SortOrder,
28
+ createdAt: "string",
29
+ updatedAt: "string",
30
+ });
31
+ // Built-in view names
32
+ export const BuiltInView = type("'today' | 'this_week' | 'blocked' | 'critical_path' | 'quick_wins' | 'all'");
33
+ //# sourceMappingURL=view.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"view.js","sourceRoot":"","sources":["../../src/schemas/view.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC/B,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEjD,oBAAoB;AACpB,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,CAAC;IAClC,WAAW,EAAE,UAAU,CAAC,KAAK,EAAE;IAC/B,aAAa,EAAE,QAAQ,CAAC,KAAK,EAAE;IAC/B,WAAW,EAAE,UAAU;IACvB,OAAO,EAAE,UAAU;IACnB,aAAa,EAAE,UAAU;IACzB,YAAY,EAAE,QAAQ;IACtB,WAAW,EAAE,QAAQ;IACrB,YAAY,EAAE,SAAS;IACvB,iBAAiB,EAAE,SAAS;IAC5B,oBAAoB,EAAE,SAAS;IAC/B,SAAS,EAAE,QAAQ,EAAE,8BAA8B;CACpD,CAAC,CAAC;AAGH,eAAe;AACf,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,CAC3B,2EAA2E,CAC5E,CAAC;AAGF,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,CAAC,gBAAgB,CAAC,CAAC;AAGhD,wBAAwB;AACxB,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,CAAC;IAC5B,EAAE,EAAE,QAAQ;IACZ,IAAI,EAAE,QAAQ;IACd,cAAc,EAAE,QAAQ;IACxB,MAAM,EAAE,eAAe;IACvB,SAAS,EAAE,SAAS;IACpB,YAAY,EAAE,SAAS;IACvB,SAAS,EAAE,QAAQ;IACnB,SAAS,EAAE,QAAQ;CACpB,CAAC,CAAC;AAGH,sBAAsB;AACtB,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,CAC7B,4EAA4E,CAC7E,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Get current ISO timestamp
3
+ */
4
+ export declare function now(): string;
5
+ /**
6
+ * Parse relative date strings
7
+ */
8
+ export declare function parseRelativeDate(input: string): Date | null;
9
+ /**
10
+ * Format date as YYYY-MM-DD
11
+ */
12
+ export declare function formatDate(date: Date): string;
13
+ /**
14
+ * Check if a date is today
15
+ */
16
+ export declare function isToday(date: Date | string): boolean;
17
+ /**
18
+ * Check if a date is before today
19
+ */
20
+ export declare function isPastDue(date: Date | string): boolean;
21
+ /**
22
+ * Check if a date is within the next N days
23
+ */
24
+ export declare function isWithinDays(date: Date | string, days: number): boolean;
25
+ //# sourceMappingURL=date.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date.d.ts","sourceRoot":"","sources":["../../src/utils/date.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,GAAG,IAAI,MAAM,CAE5B;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAkE5D;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAE7C;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,OAAO,CAQpD;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,OAAO,CAKtD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAOvE"}
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Get current ISO timestamp
3
+ */
4
+ export function now() {
5
+ return new Date().toISOString();
6
+ }
7
+ /**
8
+ * Parse relative date strings
9
+ */
10
+ export function parseRelativeDate(input) {
11
+ const today = new Date();
12
+ today.setHours(0, 0, 0, 0);
13
+ const lower = input.toLowerCase().trim();
14
+ // Today
15
+ if (lower === "today" || lower === "오늘") {
16
+ return today;
17
+ }
18
+ // Tomorrow
19
+ if (lower === "tomorrow" || lower === "내일") {
20
+ const d = new Date(today);
21
+ d.setDate(d.getDate() + 1);
22
+ return d;
23
+ }
24
+ // Yesterday
25
+ if (lower === "yesterday" || lower === "어제") {
26
+ const d = new Date(today);
27
+ d.setDate(d.getDate() - 1);
28
+ return d;
29
+ }
30
+ // Next week
31
+ if (lower === "next week" || lower === "다음주") {
32
+ const d = new Date(today);
33
+ d.setDate(d.getDate() + 7);
34
+ return d;
35
+ }
36
+ // In N days
37
+ const inDaysMatch = lower.match(/^in (\d+) days?$/);
38
+ if (inDaysMatch) {
39
+ const d = new Date(today);
40
+ d.setDate(d.getDate() + parseInt(inDaysMatch[1], 10));
41
+ return d;
42
+ }
43
+ // N일 후
44
+ const koreanDaysMatch = lower.match(/^(\d+)일\s*후$/);
45
+ if (koreanDaysMatch) {
46
+ const d = new Date(today);
47
+ d.setDate(d.getDate() + parseInt(koreanDaysMatch[1], 10));
48
+ return d;
49
+ }
50
+ // Weekday names
51
+ const weekdays = ["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"];
52
+ const weekdayIndex = weekdays.indexOf(lower);
53
+ if (weekdayIndex !== -1) {
54
+ const d = new Date(today);
55
+ const currentDay = d.getDay();
56
+ const daysUntil = (weekdayIndex - currentDay + 7) % 7 || 7;
57
+ d.setDate(d.getDate() + daysUntil);
58
+ return d;
59
+ }
60
+ // Try parsing as ISO date
61
+ const parsed = new Date(input);
62
+ if (!isNaN(parsed.getTime())) {
63
+ return parsed;
64
+ }
65
+ return null;
66
+ }
67
+ /**
68
+ * Format date as YYYY-MM-DD
69
+ */
70
+ export function formatDate(date) {
71
+ return date.toISOString().split("T")[0];
72
+ }
73
+ /**
74
+ * Check if a date is today
75
+ */
76
+ export function isToday(date) {
77
+ const d = typeof date === "string" ? new Date(date) : date;
78
+ const today = new Date();
79
+ return (d.getFullYear() === today.getFullYear() &&
80
+ d.getMonth() === today.getMonth() &&
81
+ d.getDate() === today.getDate());
82
+ }
83
+ /**
84
+ * Check if a date is before today
85
+ */
86
+ export function isPastDue(date) {
87
+ const d = typeof date === "string" ? new Date(date) : date;
88
+ const today = new Date();
89
+ today.setHours(0, 0, 0, 0);
90
+ return d < today;
91
+ }
92
+ /**
93
+ * Check if a date is within the next N days
94
+ */
95
+ export function isWithinDays(date, days) {
96
+ const d = typeof date === "string" ? new Date(date) : date;
97
+ const today = new Date();
98
+ today.setHours(0, 0, 0, 0);
99
+ const future = new Date(today);
100
+ future.setDate(future.getDate() + days);
101
+ return d >= today && d <= future;
102
+ }
103
+ //# sourceMappingURL=date.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date.js","sourceRoot":"","sources":["../../src/utils/date.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=date.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date.test.d.ts","sourceRoot":"","sources":["../../src/utils/date.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,138 @@
1
+ import { describe, test, expect } from "bun:test";
2
+ import { now, parseRelativeDate, formatDate, isToday, isPastDue, isWithinDays } from "./date.js";
3
+ describe("now", () => {
4
+ test("returns ISO timestamp string", () => {
5
+ const result = now();
6
+ expect(typeof result).toBe("string");
7
+ expect(result).toMatch(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/);
8
+ });
9
+ test("returns current time within tolerance", () => {
10
+ const before = Date.now();
11
+ const result = now();
12
+ const after = Date.now();
13
+ const resultTime = new Date(result).getTime();
14
+ expect(resultTime).toBeGreaterThanOrEqual(before);
15
+ expect(resultTime).toBeLessThanOrEqual(after);
16
+ });
17
+ });
18
+ describe("parseRelativeDate", () => {
19
+ test("parses 'today'", () => {
20
+ const result = parseRelativeDate("today");
21
+ expect(result).not.toBeNull();
22
+ const today = new Date();
23
+ expect(result.getDate()).toBe(today.getDate());
24
+ });
25
+ test("parses '오늘' (Korean today)", () => {
26
+ const result = parseRelativeDate("오늘");
27
+ expect(result).not.toBeNull();
28
+ const today = new Date();
29
+ expect(result.getDate()).toBe(today.getDate());
30
+ });
31
+ test("parses 'tomorrow'", () => {
32
+ const result = parseRelativeDate("tomorrow");
33
+ expect(result).not.toBeNull();
34
+ const tomorrow = new Date();
35
+ tomorrow.setDate(tomorrow.getDate() + 1);
36
+ expect(result.getDate()).toBe(tomorrow.getDate());
37
+ });
38
+ test("parses '내일' (Korean tomorrow)", () => {
39
+ const result = parseRelativeDate("내일");
40
+ expect(result).not.toBeNull();
41
+ const tomorrow = new Date();
42
+ tomorrow.setDate(tomorrow.getDate() + 1);
43
+ expect(result.getDate()).toBe(tomorrow.getDate());
44
+ });
45
+ test("parses 'yesterday'", () => {
46
+ const result = parseRelativeDate("yesterday");
47
+ expect(result).not.toBeNull();
48
+ const yesterday = new Date();
49
+ yesterday.setDate(yesterday.getDate() - 1);
50
+ expect(result.getDate()).toBe(yesterday.getDate());
51
+ });
52
+ test("parses 'next week'", () => {
53
+ const result = parseRelativeDate("next week");
54
+ expect(result).not.toBeNull();
55
+ const nextWeek = new Date();
56
+ nextWeek.setDate(nextWeek.getDate() + 7);
57
+ expect(result.getDate()).toBe(nextWeek.getDate());
58
+ });
59
+ test("parses 'in 3 days'", () => {
60
+ const result = parseRelativeDate("in 3 days");
61
+ expect(result).not.toBeNull();
62
+ const future = new Date();
63
+ future.setDate(future.getDate() + 3);
64
+ expect(result.getDate()).toBe(future.getDate());
65
+ });
66
+ test("parses '5일 후' (Korean days later)", () => {
67
+ const result = parseRelativeDate("5일 후");
68
+ expect(result).not.toBeNull();
69
+ const future = new Date();
70
+ future.setDate(future.getDate() + 5);
71
+ expect(result.getDate()).toBe(future.getDate());
72
+ });
73
+ test("parses weekday names", () => {
74
+ const result = parseRelativeDate("monday");
75
+ expect(result).not.toBeNull();
76
+ expect(result.getDay()).toBe(1); // Monday = 1
77
+ });
78
+ test("parses ISO date string", () => {
79
+ const result = parseRelativeDate("2025-12-31");
80
+ expect(result).not.toBeNull();
81
+ expect(result.getFullYear()).toBe(2025);
82
+ expect(result.getMonth()).toBe(11); // December = 11
83
+ expect(result.getDate()).toBe(31);
84
+ });
85
+ test("returns null for invalid input", () => {
86
+ const result = parseRelativeDate("invalid date string");
87
+ expect(result).toBeNull();
88
+ });
89
+ });
90
+ describe("formatDate", () => {
91
+ test("formats date as YYYY-MM-DD", () => {
92
+ const date = new Date("2025-06-15T10:30:00");
93
+ expect(formatDate(date)).toBe("2025-06-15");
94
+ });
95
+ });
96
+ describe("isToday", () => {
97
+ test("returns true for today", () => {
98
+ expect(isToday(new Date())).toBe(true);
99
+ });
100
+ test("returns false for tomorrow", () => {
101
+ const tomorrow = new Date();
102
+ tomorrow.setDate(tomorrow.getDate() + 1);
103
+ expect(isToday(tomorrow)).toBe(false);
104
+ });
105
+ test("accepts string input", () => {
106
+ expect(isToday(new Date().toISOString())).toBe(true);
107
+ });
108
+ });
109
+ describe("isPastDue", () => {
110
+ test("returns true for yesterday", () => {
111
+ const yesterday = new Date();
112
+ yesterday.setDate(yesterday.getDate() - 1);
113
+ expect(isPastDue(yesterday)).toBe(true);
114
+ });
115
+ test("returns false for tomorrow", () => {
116
+ const tomorrow = new Date();
117
+ tomorrow.setDate(tomorrow.getDate() + 1);
118
+ expect(isPastDue(tomorrow)).toBe(false);
119
+ });
120
+ });
121
+ describe("isWithinDays", () => {
122
+ test("returns true for date within range", () => {
123
+ const inThreeDays = new Date();
124
+ inThreeDays.setDate(inThreeDays.getDate() + 3);
125
+ expect(isWithinDays(inThreeDays, 7)).toBe(true);
126
+ });
127
+ test("returns false for date outside range", () => {
128
+ const inTenDays = new Date();
129
+ inTenDays.setDate(inTenDays.getDate() + 10);
130
+ expect(isWithinDays(inTenDays, 7)).toBe(false);
131
+ });
132
+ test("returns false for past date", () => {
133
+ const yesterday = new Date();
134
+ yesterday.setDate(yesterday.getDate() - 1);
135
+ expect(isWithinDays(yesterday, 7)).toBe(false);
136
+ });
137
+ });
138
+ //# sourceMappingURL=date.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date.test.js","sourceRoot":"","sources":["../../src/utils/date.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Generate a unique ID with optional prefix
3
+ */
4
+ export declare function generateId(prefix?: string): string;
5
+ /**
6
+ * Generate a task ID
7
+ */
8
+ export declare function generateTaskId(): string;
9
+ /**
10
+ * Generate a project ID
11
+ */
12
+ export declare function generateProjectId(): string;
13
+ /**
14
+ * Generate a view ID
15
+ */
16
+ export declare function generateViewId(): string;
17
+ /**
18
+ * Validate a project ID format
19
+ * @returns true if valid format (proj_[alphanumeric])
20
+ */
21
+ export declare function isValidProjectId(id: string): boolean;
22
+ /**
23
+ * Validate a task ID format
24
+ * @returns true if valid format (task_[alphanumeric])
25
+ */
26
+ export declare function isValidTaskId(id: string): boolean;
27
+ //# sourceMappingURL=id.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"id.d.ts","sourceRoot":"","sources":["../../src/utils/id.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,GAAE,MAAW,GAAG,MAAM,CAItD;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAEjD"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Generate a unique ID with optional prefix
3
+ */
4
+ export function generateId(prefix = "") {
5
+ const timestamp = Date.now().toString(36);
6
+ const random = Math.random().toString(36).substring(2, 8);
7
+ return prefix ? `${prefix}_${timestamp}${random}` : `${timestamp}${random}`;
8
+ }
9
+ /**
10
+ * Generate a task ID
11
+ */
12
+ export function generateTaskId() {
13
+ return generateId("task");
14
+ }
15
+ /**
16
+ * Generate a project ID
17
+ */
18
+ export function generateProjectId() {
19
+ return generateId("proj");
20
+ }
21
+ /**
22
+ * Generate a view ID
23
+ */
24
+ export function generateViewId() {
25
+ return generateId("view");
26
+ }
27
+ /**
28
+ * Validate a project ID format
29
+ * @returns true if valid format (proj_[alphanumeric])
30
+ */
31
+ export function isValidProjectId(id) {
32
+ return /^proj_[a-z0-9]+$/.test(id);
33
+ }
34
+ /**
35
+ * Validate a task ID format
36
+ * @returns true if valid format (task_[alphanumeric])
37
+ */
38
+ export function isValidTaskId(id) {
39
+ return /^task_[a-z0-9]+$/.test(id);
40
+ }
41
+ //# sourceMappingURL=id.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"id.js","sourceRoot":"","sources":["../../src/utils/id.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,SAAiB,EAAE;IAC5C,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC1D,OAAO,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,SAAS,GAAG,MAAM,EAAE,CAAC,CAAC,CAAC,GAAG,SAAS,GAAG,MAAM,EAAE,CAAC;AAC9E,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc;IAC5B,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC;AAC5B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC;AAC5B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc;IAC5B,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC;AAC5B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,EAAU;IACzC,OAAO,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACrC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,EAAU;IACtC,OAAO,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACrC,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { generateId, generateTaskId, generateProjectId, generateViewId, isValidProjectId, isValidTaskId } from "./id.js";
2
+ export { now, parseRelativeDate, formatDate, isToday, isPastDue, isWithinDays } from "./date.js";
3
+ export { parseTaskInput } from "./natural-language.js";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,iBAAiB,EAAE,cAAc,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACzH,OAAO,EAAE,GAAG,EAAE,iBAAiB,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACjG,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { generateId, generateTaskId, generateProjectId, generateViewId, isValidProjectId, isValidTaskId } from "./id.js";
2
+ export { now, parseRelativeDate, formatDate, isToday, isPastDue, isWithinDays } from "./date.js";
3
+ export { parseTaskInput } from "./natural-language.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,iBAAiB,EAAE,cAAc,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACzH,OAAO,EAAE,GAAG,EAAE,iBAAiB,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACjG,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { TaskCreateInput } from "../schemas/task.js";
2
+ /**
3
+ * Parse natural language task input
4
+ *
5
+ * Examples:
6
+ * - "Review PR tomorrow #dev !high"
7
+ * - "내일까지 보고서 작성 #업무 !높음 @집중"
8
+ * - "Fix bug by Friday #backend !critical"
9
+ * - "Write tests every Monday #testing"
10
+ */
11
+ export declare function parseTaskInput(input: string): TaskCreateInput;
12
+ //# sourceMappingURL=natural-language.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"natural-language.d.ts","sourceRoot":"","sources":["../../src/utils/natural-language.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAY,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAGpE;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,eAAe,CA6F7D"}