@task-mcp/shared 1.0.22 → 1.0.24

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 (184) hide show
  1. package/dist/algorithms/critical-path.d.ts +47 -0
  2. package/dist/algorithms/critical-path.d.ts.map +1 -0
  3. package/dist/algorithms/critical-path.js +340 -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 +184 -0
  8. package/dist/algorithms/critical-path.test.js.map +1 -0
  9. package/dist/algorithms/dependency-integrity.d.ts +81 -0
  10. package/dist/algorithms/dependency-integrity.d.ts.map +1 -0
  11. package/dist/algorithms/dependency-integrity.js +209 -0
  12. package/dist/algorithms/dependency-integrity.js.map +1 -0
  13. package/dist/algorithms/dependency-integrity.test.d.ts +2 -0
  14. package/dist/algorithms/dependency-integrity.test.d.ts.map +1 -0
  15. package/dist/algorithms/dependency-integrity.test.js +296 -0
  16. package/dist/algorithms/dependency-integrity.test.js.map +1 -0
  17. package/dist/algorithms/index.d.ts +5 -0
  18. package/dist/algorithms/index.d.ts.map +1 -0
  19. package/dist/algorithms/index.js +5 -0
  20. package/dist/algorithms/index.js.map +1 -0
  21. package/dist/algorithms/tech-analysis.d.ts +106 -0
  22. package/dist/algorithms/tech-analysis.d.ts.map +1 -0
  23. package/dist/algorithms/tech-analysis.js +351 -0
  24. package/dist/algorithms/tech-analysis.js.map +1 -0
  25. package/dist/algorithms/tech-analysis.test.d.ts +2 -0
  26. package/dist/algorithms/tech-analysis.test.d.ts.map +1 -0
  27. package/dist/algorithms/tech-analysis.test.js +330 -0
  28. package/dist/algorithms/tech-analysis.test.js.map +1 -0
  29. package/dist/algorithms/topological-sort.d.ts +58 -0
  30. package/dist/algorithms/topological-sort.d.ts.map +1 -0
  31. package/dist/algorithms/topological-sort.js +201 -0
  32. package/dist/algorithms/topological-sort.js.map +1 -0
  33. package/dist/algorithms/topological-sort.test.d.ts +2 -0
  34. package/dist/algorithms/topological-sort.test.d.ts.map +1 -0
  35. package/dist/algorithms/topological-sort.test.js +154 -0
  36. package/dist/algorithms/topological-sort.test.js.map +1 -0
  37. package/dist/index.d.ts +4 -0
  38. package/dist/index.d.ts.map +1 -0
  39. package/dist/index.js +7 -0
  40. package/dist/index.js.map +1 -0
  41. package/dist/schemas/inbox.d.ts +55 -0
  42. package/dist/schemas/inbox.d.ts.map +1 -0
  43. package/dist/schemas/inbox.js +25 -0
  44. package/dist/schemas/inbox.js.map +1 -0
  45. package/dist/schemas/index.d.ts +7 -0
  46. package/dist/schemas/index.d.ts.map +1 -0
  47. package/dist/schemas/index.js +17 -0
  48. package/dist/schemas/index.js.map +1 -0
  49. package/dist/schemas/llm-guide.d.ts +147 -0
  50. package/dist/schemas/llm-guide.d.ts.map +1 -0
  51. package/dist/schemas/llm-guide.js +72 -0
  52. package/dist/schemas/llm-guide.js.map +1 -0
  53. package/dist/schemas/project.d.ts +177 -0
  54. package/dist/schemas/project.d.ts.map +1 -0
  55. package/dist/schemas/project.js +56 -0
  56. package/dist/schemas/project.js.map +1 -0
  57. package/dist/schemas/response-format.d.ts +148 -0
  58. package/dist/schemas/response-format.d.ts.map +1 -0
  59. package/dist/schemas/response-format.js +18 -0
  60. package/dist/schemas/response-format.js.map +1 -0
  61. package/dist/schemas/response-schema.d.ts +307 -0
  62. package/dist/schemas/response-schema.d.ts.map +1 -0
  63. package/dist/schemas/response-schema.js +78 -0
  64. package/dist/schemas/response-schema.js.map +1 -0
  65. package/dist/schemas/response-schema.test.d.ts +2 -0
  66. package/dist/schemas/response-schema.test.d.ts.map +1 -0
  67. package/dist/schemas/response-schema.test.js +256 -0
  68. package/dist/schemas/response-schema.test.js.map +1 -0
  69. package/dist/schemas/state.d.ts +17 -0
  70. package/dist/schemas/state.d.ts.map +1 -0
  71. package/dist/schemas/state.js +17 -0
  72. package/dist/schemas/state.js.map +1 -0
  73. package/dist/schemas/task.d.ts +881 -0
  74. package/dist/schemas/task.d.ts.map +1 -0
  75. package/dist/schemas/task.js +177 -0
  76. package/dist/schemas/task.js.map +1 -0
  77. package/dist/schemas/view.d.ts +143 -0
  78. package/dist/schemas/view.d.ts.map +1 -0
  79. package/dist/schemas/view.js +48 -0
  80. package/dist/schemas/view.js.map +1 -0
  81. package/dist/utils/dashboard-renderer.d.ts +93 -0
  82. package/dist/utils/dashboard-renderer.d.ts.map +1 -0
  83. package/dist/utils/dashboard-renderer.js +416 -0
  84. package/dist/utils/dashboard-renderer.js.map +1 -0
  85. package/dist/utils/dashboard-renderer.test.d.ts +2 -0
  86. package/dist/utils/dashboard-renderer.test.d.ts.map +1 -0
  87. package/dist/utils/dashboard-renderer.test.js +772 -0
  88. package/dist/utils/dashboard-renderer.test.js.map +1 -0
  89. package/dist/utils/date.d.ts +94 -0
  90. package/dist/utils/date.d.ts.map +1 -0
  91. package/dist/utils/date.js +323 -0
  92. package/dist/utils/date.js.map +1 -0
  93. package/dist/utils/date.test.d.ts +2 -0
  94. package/dist/utils/date.test.d.ts.map +1 -0
  95. package/dist/utils/date.test.js +276 -0
  96. package/dist/utils/date.test.js.map +1 -0
  97. package/dist/utils/hierarchy.d.ts +102 -0
  98. package/dist/utils/hierarchy.d.ts.map +1 -0
  99. package/dist/utils/hierarchy.js +236 -0
  100. package/dist/utils/hierarchy.js.map +1 -0
  101. package/dist/utils/hierarchy.test.d.ts +2 -0
  102. package/dist/utils/hierarchy.test.d.ts.map +1 -0
  103. package/dist/utils/hierarchy.test.js +423 -0
  104. package/dist/utils/hierarchy.test.js.map +1 -0
  105. package/dist/utils/id.d.ts +60 -0
  106. package/dist/utils/id.d.ts.map +1 -0
  107. package/dist/utils/id.js +118 -0
  108. package/dist/utils/id.js.map +1 -0
  109. package/dist/utils/id.test.d.ts +2 -0
  110. package/dist/utils/id.test.d.ts.map +1 -0
  111. package/dist/utils/id.test.js +193 -0
  112. package/dist/utils/id.test.js.map +1 -0
  113. package/dist/utils/index.d.ts +12 -0
  114. package/dist/utils/index.d.ts.map +1 -0
  115. package/dist/utils/index.js +34 -0
  116. package/dist/utils/index.js.map +1 -0
  117. package/dist/utils/natural-language.d.ts +111 -0
  118. package/dist/utils/natural-language.d.ts.map +1 -0
  119. package/dist/utils/natural-language.js +297 -0
  120. package/dist/utils/natural-language.js.map +1 -0
  121. package/dist/utils/natural-language.test.d.ts +2 -0
  122. package/dist/utils/natural-language.test.d.ts.map +1 -0
  123. package/dist/utils/natural-language.test.js +197 -0
  124. package/dist/utils/natural-language.test.js.map +1 -0
  125. package/dist/utils/priority-queue.d.ts +17 -0
  126. package/dist/utils/priority-queue.d.ts.map +1 -0
  127. package/dist/utils/priority-queue.js +62 -0
  128. package/dist/utils/priority-queue.js.map +1 -0
  129. package/dist/utils/priority-queue.test.d.ts +2 -0
  130. package/dist/utils/priority-queue.test.d.ts.map +1 -0
  131. package/dist/utils/priority-queue.test.js +82 -0
  132. package/dist/utils/priority-queue.test.js.map +1 -0
  133. package/dist/utils/projection.d.ts +65 -0
  134. package/dist/utils/projection.d.ts.map +1 -0
  135. package/dist/utils/projection.js +180 -0
  136. package/dist/utils/projection.js.map +1 -0
  137. package/dist/utils/projection.test.d.ts +2 -0
  138. package/dist/utils/projection.test.d.ts.map +1 -0
  139. package/dist/utils/projection.test.js +341 -0
  140. package/dist/utils/projection.test.js.map +1 -0
  141. package/dist/utils/terminal-ui.d.ts +208 -0
  142. package/dist/utils/terminal-ui.d.ts.map +1 -0
  143. package/dist/utils/terminal-ui.js +614 -0
  144. package/dist/utils/terminal-ui.js.map +1 -0
  145. package/dist/utils/terminal-ui.test.d.ts +2 -0
  146. package/dist/utils/terminal-ui.test.d.ts.map +1 -0
  147. package/dist/utils/terminal-ui.test.js +683 -0
  148. package/dist/utils/terminal-ui.test.js.map +1 -0
  149. package/dist/utils/workspace.d.ts +102 -0
  150. package/dist/utils/workspace.d.ts.map +1 -0
  151. package/dist/utils/workspace.js +183 -0
  152. package/dist/utils/workspace.js.map +1 -0
  153. package/dist/utils/workspace.test.d.ts +2 -0
  154. package/dist/utils/workspace.test.d.ts.map +1 -0
  155. package/dist/utils/workspace.test.js +97 -0
  156. package/dist/utils/workspace.test.js.map +1 -0
  157. package/package.json +5 -1
  158. package/src/algorithms/critical-path.test.ts +227 -0
  159. package/src/algorithms/critical-path.ts +14 -34
  160. package/src/algorithms/dependency-integrity.test.ts +335 -0
  161. package/src/algorithms/dependency-integrity.ts +4 -13
  162. package/src/algorithms/tech-analysis.test.ts +405 -0
  163. package/src/algorithms/tech-analysis.ts +27 -27
  164. package/src/algorithms/topological-sort.test.ts +182 -0
  165. package/src/algorithms/topological-sort.ts +6 -10
  166. package/src/schemas/index.ts +2 -13
  167. package/src/schemas/response-format.ts +6 -6
  168. package/src/schemas/response-schema.test.ts +314 -0
  169. package/src/schemas/response-schema.ts +25 -20
  170. package/src/schemas/task.ts +4 -22
  171. package/src/utils/dashboard-renderer.test.ts +976 -0
  172. package/src/utils/dashboard-renderer.ts +27 -59
  173. package/src/utils/date.test.ts +329 -0
  174. package/src/utils/date.ts +2 -10
  175. package/src/utils/hierarchy.test.ts +488 -0
  176. package/src/utils/hierarchy.ts +4 -5
  177. package/src/utils/id.test.ts +235 -0
  178. package/src/utils/index.ts +7 -1
  179. package/src/utils/natural-language.test.ts +234 -0
  180. package/src/utils/priority-queue.test.ts +103 -0
  181. package/src/utils/projection.test.ts +430 -0
  182. package/src/utils/terminal-ui.test.ts +831 -0
  183. package/src/utils/terminal-ui.ts +53 -54
  184. package/src/utils/workspace.test.ts +125 -0
@@ -0,0 +1,297 @@
1
+ import { parseRelativeDate, formatDate } from "./date.js";
2
+ /**
3
+ * Maximum allowed input length for natural language parsing.
4
+ * Prevents DoS attacks from extremely long input strings.
5
+ */
6
+ export const MAX_INPUT_LENGTH = 1000;
7
+ /**
8
+ * Error thrown when input validation fails
9
+ */
10
+ export class InputValidationError extends Error {
11
+ constructor(message) {
12
+ super(message);
13
+ this.name = "InputValidationError";
14
+ }
15
+ }
16
+ /**
17
+ * Validates input string length
18
+ * @throws {InputValidationError} if input exceeds MAX_INPUT_LENGTH
19
+ */
20
+ function validateInputLength(input) {
21
+ if (input.length > MAX_INPUT_LENGTH) {
22
+ throw new InputValidationError(`Input exceeds maximum length of ${MAX_INPUT_LENGTH} characters (received ${input.length})`);
23
+ }
24
+ }
25
+ const DEFAULT_EXTRACT_OPTIONS = {
26
+ extractPriority: true,
27
+ extractDate: true,
28
+ extractTags: true,
29
+ extractEstimate: true,
30
+ };
31
+ /**
32
+ * Extract metadata from natural language input
33
+ *
34
+ * Supports:
35
+ * - Priority: !high, !medium, !low, !critical, !높음, !보통, !낮음, !긴급
36
+ * - Date: today, tomorrow, next week, 내일, 오늘, by Friday, 금요일까지
37
+ * - Tags: #tag, #개발, #backend
38
+ * - Time estimate: ~2h, ~30m, ~1h30m (with ~ prefix)
39
+ *
40
+ * @param input - Raw natural language input
41
+ * @param options - Options to control which metadata types to extract
42
+ * @returns Extracted metadata and remaining text
43
+ *
44
+ * @example
45
+ * ```typescript
46
+ * const result = extractMetadata("Review PR tomorrow #dev !high ~2h");
47
+ * // {
48
+ * // priority: "high",
49
+ * // dueDate: "2025-01-01",
50
+ * // tags: ["dev"],
51
+ * // estimateMinutes: 120,
52
+ * // remaining: "Review PR"
53
+ * // }
54
+ * ```
55
+ */
56
+ export function extractMetadata(input, options = DEFAULT_EXTRACT_OPTIONS) {
57
+ validateInputLength(input);
58
+ let remaining = input.trim();
59
+ const result = { remaining: "" };
60
+ // Extract priority (!high, !critical, !medium, !low, !높음, !보통, !낮음)
61
+ if (options.extractPriority !== false) {
62
+ const priorityMatch = remaining.match(/!([\p{L}\p{N}_]+)/gu);
63
+ if (priorityMatch) {
64
+ for (const match of priorityMatch) {
65
+ const priority = parsePriority(match.slice(1));
66
+ if (priority) {
67
+ result.priority = priority;
68
+ remaining = remaining.replace(match, "").trim();
69
+ break;
70
+ }
71
+ }
72
+ }
73
+ }
74
+ // Extract tags (#dev, #backend, #개발)
75
+ if (options.extractTags !== false) {
76
+ const tagMatches = remaining.match(/#([\p{L}\p{N}_]+)/gu);
77
+ if (tagMatches) {
78
+ result.tags = tagMatches.map((m) => m.slice(1));
79
+ for (const match of tagMatches) {
80
+ remaining = remaining.replace(match, "").trim();
81
+ }
82
+ }
83
+ }
84
+ // Extract due date patterns
85
+ if (options.extractDate !== false) {
86
+ // "by Friday", "by tomorrow", "until next week"
87
+ const byMatch = remaining.match(/\b(by|until|before)\s+(\w+(\s+\w+)?)/i);
88
+ if (byMatch) {
89
+ const dateStr = byMatch[2];
90
+ const date = parseRelativeDate(dateStr);
91
+ if (date) {
92
+ result.dueDate = formatDate(date);
93
+ remaining = remaining.replace(byMatch[0], "").trim();
94
+ }
95
+ }
96
+ // Korean date patterns: "내일까지", "금요일까지"
97
+ if (!result.dueDate) {
98
+ const koreanDueMatch = remaining.match(/(\S+)까지/);
99
+ if (koreanDueMatch) {
100
+ const dateStr = koreanDueMatch[1];
101
+ const date = parseRelativeDate(dateStr);
102
+ if (date) {
103
+ result.dueDate = formatDate(date);
104
+ remaining = remaining.replace(koreanDueMatch[0], "").trim();
105
+ }
106
+ }
107
+ }
108
+ // "tomorrow", "today" at the end
109
+ if (!result.dueDate) {
110
+ const dateWords = ["tomorrow", "today", "내일", "오늘", "모레"];
111
+ for (const word of dateWords) {
112
+ if (remaining.toLowerCase().endsWith(word)) {
113
+ const date = parseRelativeDate(word);
114
+ if (date) {
115
+ result.dueDate = formatDate(date);
116
+ remaining = remaining.slice(0, -word.length).trim();
117
+ break;
118
+ }
119
+ }
120
+ }
121
+ }
122
+ }
123
+ // Extract time estimate (~2h, ~30m, ~1h30m)
124
+ if (options.extractEstimate !== false) {
125
+ const timeMatch = remaining.match(/~(\d+h\d+m|\d+h|\d+m)\b/);
126
+ if (timeMatch) {
127
+ let minutes = 0;
128
+ const hoursMatch = timeMatch[1].match(/(\d+)h/);
129
+ const minsMatch = timeMatch[1].match(/(\d+)m/);
130
+ if (hoursMatch) {
131
+ minutes += parseInt(hoursMatch[1], 10) * 60;
132
+ }
133
+ if (minsMatch) {
134
+ minutes += parseInt(minsMatch[1], 10);
135
+ }
136
+ if (minutes > 0) {
137
+ result.estimateMinutes = minutes;
138
+ remaining = remaining.replace(timeMatch[0], "").trim();
139
+ }
140
+ }
141
+ }
142
+ // Clean up extra spaces
143
+ result.remaining = remaining.replace(/\s+/g, " ").trim();
144
+ return result;
145
+ }
146
+ /**
147
+ * Parse natural language input with target detection
148
+ *
149
+ * Target keywords:
150
+ * - >>inbox, >>메모, >>아이디어 → capture to inbox
151
+ * - >>task, >>태스크 (default) → create task
152
+ *
153
+ * Examples:
154
+ * - "API 리팩토링 아이디어 >>inbox #backend"
155
+ * - "Review PR tomorrow #dev !high" (default: task)
156
+ * - "새 기능 구상 >>메모"
157
+ */
158
+ export function parseInput(input) {
159
+ validateInputLength(input);
160
+ let remaining = input.trim();
161
+ let target = "task";
162
+ // Detect target keywords (>>inbox, >>task, >>메모, >>아이디어, >>태스크)
163
+ const targetMatch = remaining.match(/>>(inbox|task|메모|아이디어|태스크)/i);
164
+ if (targetMatch) {
165
+ const keyword = targetMatch[1].toLowerCase();
166
+ if (keyword === "inbox" || keyword === "메모" || keyword === "아이디어") {
167
+ target = "inbox";
168
+ }
169
+ else {
170
+ target = "task";
171
+ }
172
+ remaining = remaining.replace(targetMatch[0], "").trim();
173
+ }
174
+ if (target === "inbox") {
175
+ return {
176
+ target: "inbox",
177
+ inbox: parseInboxInput(remaining),
178
+ };
179
+ }
180
+ return {
181
+ target: "task",
182
+ task: parseTaskInput(remaining),
183
+ };
184
+ }
185
+ /**
186
+ * Parse natural language inbox input
187
+ *
188
+ * Examples:
189
+ * - "GraphQL 도입 검토 #backend #연구"
190
+ * - "성능 개선 아이디어 #performance"
191
+ */
192
+ export function parseInboxInput(input) {
193
+ // Inbox only extracts tags
194
+ const metadata = extractMetadata(input, {
195
+ extractPriority: false,
196
+ extractDate: false,
197
+ extractTags: true,
198
+ extractEstimate: false,
199
+ });
200
+ const result = { content: "" };
201
+ if (metadata.tags) {
202
+ result.tags = metadata.tags;
203
+ }
204
+ result.content = metadata.remaining;
205
+ if (!result.content) {
206
+ throw new InputValidationError("Content cannot be empty after parsing. Input contained only metadata (tags).");
207
+ }
208
+ return result;
209
+ }
210
+ /**
211
+ * Parse natural language task input
212
+ *
213
+ * Examples:
214
+ * - "Review PR tomorrow #dev !high ~2h"
215
+ * - "내일까지 보고서 작성 #업무 !높음 @집중"
216
+ * - "Fix bug by Friday #backend !critical"
217
+ * - "Write tests every Monday #testing"
218
+ */
219
+ export function parseTaskInput(input) {
220
+ validateInputLength(input);
221
+ let remaining = input.trim();
222
+ const result = { title: "" };
223
+ // Extract contexts first (@focus, @review, @집중) - task-specific
224
+ const contextMatches = remaining.match(/@([\p{L}\p{N}_]+)/gu);
225
+ if (contextMatches) {
226
+ result.contexts = contextMatches.map((m) => m.slice(1));
227
+ for (const match of contextMatches) {
228
+ remaining = remaining.replace(match, "").trim();
229
+ }
230
+ }
231
+ // Extract sortOrder (^1, ^10) - task-specific
232
+ const sortMatch = remaining.match(/\^(\d+)/);
233
+ if (sortMatch) {
234
+ result.sortOrder = parseInt(sortMatch[1], 10);
235
+ remaining = remaining.replace(sortMatch[0], "").trim();
236
+ }
237
+ // Extract time estimate without ~ prefix for backward compatibility (30m, 2h, 1h30m)
238
+ // This handles the legacy format before extractMetadata handles ~prefix format
239
+ const legacyTimeMatch = remaining.match(/\b(\d+h\d+m|\d+h|\d+m)\b/);
240
+ if (legacyTimeMatch && !remaining.includes("~" + legacyTimeMatch[1])) {
241
+ let minutes = 0;
242
+ const hoursMatch = legacyTimeMatch[0].match(/(\d+)h/);
243
+ const minsMatch = legacyTimeMatch[0].match(/(\d+)m/);
244
+ if (hoursMatch) {
245
+ minutes += parseInt(hoursMatch[1], 10) * 60;
246
+ }
247
+ if (minsMatch) {
248
+ minutes += parseInt(minsMatch[1], 10);
249
+ }
250
+ if (minutes > 0) {
251
+ result.estimate = { expected: minutes, confidence: "medium" };
252
+ remaining = remaining.replace(legacyTimeMatch[0], "").trim();
253
+ }
254
+ }
255
+ // Use extractMetadata for common patterns
256
+ const metadata = extractMetadata(remaining, {
257
+ extractPriority: true,
258
+ extractDate: true,
259
+ extractTags: true,
260
+ extractEstimate: true,
261
+ });
262
+ // Apply extracted metadata
263
+ if (metadata.priority) {
264
+ result.priority = metadata.priority;
265
+ }
266
+ if (metadata.dueDate) {
267
+ result.dueDate = metadata.dueDate;
268
+ }
269
+ if (metadata.tags) {
270
+ result.tags = metadata.tags;
271
+ }
272
+ if (metadata.estimateMinutes && !result.estimate) {
273
+ result.estimate = { expected: metadata.estimateMinutes, confidence: "medium" };
274
+ }
275
+ result.title = metadata.remaining;
276
+ if (!result.title) {
277
+ throw new InputValidationError("Task title cannot be empty after parsing. Input contained only metadata.");
278
+ }
279
+ return result;
280
+ }
281
+ function parsePriority(input) {
282
+ const lower = input.toLowerCase();
283
+ const priorityMap = {
284
+ critical: "critical",
285
+ highest: "critical",
286
+ 긴급: "critical",
287
+ high: "high",
288
+ 높음: "high",
289
+ medium: "medium",
290
+ normal: "medium",
291
+ 보통: "medium",
292
+ low: "low",
293
+ 낮음: "low",
294
+ };
295
+ return priorityMap[lower] ?? null;
296
+ }
297
+ //# sourceMappingURL=natural-language.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"natural-language.js","sourceRoot":"","sources":["../../src/utils/natural-language.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=natural-language.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"natural-language.test.d.ts","sourceRoot":"","sources":["../../src/utils/natural-language.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,197 @@
1
+ import { describe, test, expect } from "bun:test";
2
+ import { parseTaskInput, parseInboxInput, InputValidationError } from "./natural-language.js";
3
+ describe("parseTaskInput", () => {
4
+ describe("priority parsing", () => {
5
+ test("parses !critical priority", () => {
6
+ const result = parseTaskInput("Fix bug !critical");
7
+ expect(result.priority).toBe("critical");
8
+ expect(result.title).toBe("Fix bug");
9
+ });
10
+ test("parses !high priority", () => {
11
+ const result = parseTaskInput("Review PR !high");
12
+ expect(result.priority).toBe("high");
13
+ });
14
+ test("parses !medium priority", () => {
15
+ const result = parseTaskInput("Write docs !medium");
16
+ expect(result.priority).toBe("medium");
17
+ });
18
+ test("parses !low priority", () => {
19
+ const result = parseTaskInput("Clean up !low");
20
+ expect(result.priority).toBe("low");
21
+ });
22
+ test("parses Korean priority !높음", () => {
23
+ const result = parseTaskInput("버그 수정 !높음");
24
+ expect(result.priority).toBe("high");
25
+ expect(result.title).toBe("버그 수정");
26
+ });
27
+ test("parses Korean priority !긴급", () => {
28
+ const result = parseTaskInput("장애 대응 !긴급");
29
+ expect(result.priority).toBe("critical");
30
+ expect(result.title).toBe("장애 대응");
31
+ });
32
+ });
33
+ describe("tag parsing", () => {
34
+ test("parses single tag", () => {
35
+ const result = parseTaskInput("Fix auth #backend");
36
+ expect(result.tags).toEqual(["backend"]);
37
+ expect(result.title).toBe("Fix auth");
38
+ });
39
+ test("parses multiple tags", () => {
40
+ const result = parseTaskInput("Update API #backend #api #v2");
41
+ expect(result.tags).toEqual(["backend", "api", "v2"]);
42
+ });
43
+ test("parses Korean tags", () => {
44
+ const result = parseTaskInput("보고서 작성 #업무 #문서");
45
+ expect(result.tags).toEqual(["업무", "문서"]);
46
+ expect(result.title).toBe("보고서 작성");
47
+ });
48
+ });
49
+ describe("context parsing", () => {
50
+ test("parses single context", () => {
51
+ const result = parseTaskInput("Deep work task @focus");
52
+ expect(result.contexts).toEqual(["focus"]);
53
+ expect(result.title).toBe("Deep work task");
54
+ });
55
+ test("parses multiple contexts", () => {
56
+ const result = parseTaskInput("Review code @focus @office");
57
+ expect(result.contexts).toEqual(["focus", "office"]);
58
+ });
59
+ });
60
+ describe("due date parsing", () => {
61
+ test("parses 'by tomorrow'", () => {
62
+ const result = parseTaskInput("Submit report by tomorrow");
63
+ expect(result.dueDate).toBeDefined();
64
+ expect(result.title).toBe("Submit report");
65
+ });
66
+ test("parses 'until Friday'", () => {
67
+ const result = parseTaskInput("Complete feature until Friday");
68
+ expect(result.dueDate).toBeDefined();
69
+ });
70
+ test("parses Korean '내일까지'", () => {
71
+ const result = parseTaskInput("보고서 제출 내일까지");
72
+ expect(result.dueDate).toBeDefined();
73
+ expect(result.title).toBe("보고서 제출");
74
+ });
75
+ test("parses standalone 'tomorrow' at end", () => {
76
+ const result = parseTaskInput("Submit PR tomorrow");
77
+ expect(result.dueDate).toBeDefined();
78
+ expect(result.title).toBe("Submit PR");
79
+ });
80
+ });
81
+ describe("time estimate parsing", () => {
82
+ test("parses hours only", () => {
83
+ const result = parseTaskInput("Write tests 2h");
84
+ expect(result.estimate?.expected).toBe(120);
85
+ });
86
+ test("parses minutes only", () => {
87
+ const result = parseTaskInput("Quick fix 30m");
88
+ expect(result.estimate?.expected).toBe(30);
89
+ });
90
+ test("parses combined hours and minutes", () => {
91
+ const result = parseTaskInput("Big refactor 1h30m");
92
+ expect(result.estimate?.expected).toBe(90);
93
+ });
94
+ test("removes time estimate from title", () => {
95
+ const result = parseTaskInput("Task 2h30m done");
96
+ expect(result.estimate?.expected).toBe(150);
97
+ expect(result.title).toBe("Task done");
98
+ });
99
+ });
100
+ describe("sortOrder parsing", () => {
101
+ test("parses ^1 as sortOrder 1", () => {
102
+ const result = parseTaskInput("First task ^1");
103
+ expect(result.sortOrder).toBe(1);
104
+ expect(result.title).toBe("First task");
105
+ });
106
+ test("parses ^10 as sortOrder 10", () => {
107
+ const result = parseTaskInput("Tenth task ^10");
108
+ expect(result.sortOrder).toBe(10);
109
+ expect(result.title).toBe("Tenth task");
110
+ });
111
+ test("parses sortOrder in middle of input", () => {
112
+ const result = parseTaskInput("Task ^5 with more text");
113
+ expect(result.sortOrder).toBe(5);
114
+ expect(result.title).toBe("Task with more text");
115
+ });
116
+ test("parses sortOrder with other metadata", () => {
117
+ const result = parseTaskInput("Task ^3 #dev !high");
118
+ expect(result.sortOrder).toBe(3);
119
+ expect(result.tags).toEqual(["dev"]);
120
+ expect(result.priority).toBe("high");
121
+ expect(result.title).toBe("Task");
122
+ });
123
+ });
124
+ describe("combined parsing", () => {
125
+ test("parses full English input", () => {
126
+ const result = parseTaskInput("Review PR #dev !high @focus");
127
+ expect(result.title).toBe("Review PR");
128
+ expect(result.tags).toEqual(["dev"]);
129
+ expect(result.priority).toBe("high");
130
+ expect(result.contexts).toEqual(["focus"]);
131
+ });
132
+ test("parses input with due date", () => {
133
+ const result = parseTaskInput("Submit report by tomorrow #work");
134
+ expect(result.title).toBe("Submit report");
135
+ expect(result.tags).toEqual(["work"]);
136
+ expect(result.dueDate).toBeDefined();
137
+ });
138
+ test("parses full Korean input", () => {
139
+ const result = parseTaskInput("보고서 작성 내일까지 #업무 !높음 @집중");
140
+ expect(result.title).toBe("보고서 작성");
141
+ expect(result.tags).toEqual(["업무"]);
142
+ expect(result.priority).toBe("high");
143
+ expect(result.contexts).toEqual(["집중"]);
144
+ expect(result.dueDate).toBeDefined();
145
+ });
146
+ test("returns clean title with no metadata", () => {
147
+ const result = parseTaskInput("Simple task");
148
+ expect(result.title).toBe("Simple task");
149
+ expect(result.tags).toBeUndefined();
150
+ expect(result.priority).toBeUndefined();
151
+ expect(result.contexts).toBeUndefined();
152
+ expect(result.dueDate).toBeUndefined();
153
+ });
154
+ });
155
+ describe("empty content validation", () => {
156
+ test("throws error when input contains only tags", () => {
157
+ expect(() => parseTaskInput("#tag #only")).toThrow(InputValidationError);
158
+ expect(() => parseTaskInput("#tag #only")).toThrow("Task title cannot be empty after parsing");
159
+ });
160
+ test("throws error when input contains only metadata", () => {
161
+ expect(() => parseTaskInput("#dev !high @focus")).toThrow(InputValidationError);
162
+ });
163
+ test("throws error for empty input", () => {
164
+ expect(() => parseTaskInput("")).toThrow(InputValidationError);
165
+ });
166
+ test("throws error for whitespace-only input", () => {
167
+ expect(() => parseTaskInput(" ")).toThrow(InputValidationError);
168
+ });
169
+ });
170
+ });
171
+ describe("parseInboxInput", () => {
172
+ describe("basic parsing", () => {
173
+ test("parses content with tags", () => {
174
+ const result = parseInboxInput("GraphQL 도입 검토 #backend #연구");
175
+ expect(result.content).toBe("GraphQL 도입 검토");
176
+ expect(result.tags).toEqual(["backend", "연구"]);
177
+ });
178
+ test("parses content without tags", () => {
179
+ const result = parseInboxInput("Simple idea to capture");
180
+ expect(result.content).toBe("Simple idea to capture");
181
+ expect(result.tags).toBeUndefined();
182
+ });
183
+ });
184
+ describe("empty content validation", () => {
185
+ test("throws error when input contains only tags", () => {
186
+ expect(() => parseInboxInput("#tag #only")).toThrow(InputValidationError);
187
+ expect(() => parseInboxInput("#tag #only")).toThrow("Content cannot be empty after parsing");
188
+ });
189
+ test("throws error for empty input", () => {
190
+ expect(() => parseInboxInput("")).toThrow(InputValidationError);
191
+ });
192
+ test("throws error for whitespace-only input", () => {
193
+ expect(() => parseInboxInput(" ")).toThrow(InputValidationError);
194
+ });
195
+ });
196
+ });
197
+ //# sourceMappingURL=natural-language.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"natural-language.test.js","sourceRoot":"","sources":["../../src/utils/natural-language.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Max-heap implementation for priority queue (higher priority = higher value comes first)
3
+ * O(log n) insert and extract operations vs O(n log n) for sort-based approach
4
+ */
5
+ export declare class PriorityQueue<T> {
6
+ private heap;
7
+ private compare;
8
+ constructor(compare: (a: T, b: T) => number);
9
+ get length(): number;
10
+ push(item: T): void;
11
+ pop(): T | undefined;
12
+ peek(): T | undefined;
13
+ isEmpty(): boolean;
14
+ private bubbleUp;
15
+ private bubbleDown;
16
+ }
17
+ //# sourceMappingURL=priority-queue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"priority-queue.d.ts","sourceRoot":"","sources":["../../src/utils/priority-queue.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,qBAAa,aAAa,CAAC,CAAC;IAC1B,OAAO,CAAC,IAAI,CAAW;IACvB,OAAO,CAAC,OAAO,CAAyB;gBAE5B,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,MAAM;IAI3C,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,IAAI,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI;IAKnB,GAAG,IAAI,CAAC,GAAG,SAAS;IAUpB,IAAI,IAAI,CAAC,GAAG,SAAS;IAIrB,OAAO,IAAI,OAAO;IAIlB,OAAO,CAAC,QAAQ;IAShB,OAAO,CAAC,UAAU;CAmBnB"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Max-heap implementation for priority queue (higher priority = higher value comes first)
3
+ * O(log n) insert and extract operations vs O(n log n) for sort-based approach
4
+ */
5
+ export class PriorityQueue {
6
+ heap = [];
7
+ compare;
8
+ constructor(compare) {
9
+ this.compare = compare;
10
+ }
11
+ get length() {
12
+ return this.heap.length;
13
+ }
14
+ push(item) {
15
+ this.heap.push(item);
16
+ this.bubbleUp(this.heap.length - 1);
17
+ }
18
+ pop() {
19
+ if (this.heap.length === 0)
20
+ return undefined;
21
+ if (this.heap.length === 1)
22
+ return this.heap.pop();
23
+ const result = this.heap[0];
24
+ this.heap[0] = this.heap.pop();
25
+ this.bubbleDown(0);
26
+ return result;
27
+ }
28
+ peek() {
29
+ return this.heap[0];
30
+ }
31
+ isEmpty() {
32
+ return this.heap.length === 0;
33
+ }
34
+ bubbleUp(index) {
35
+ while (index > 0) {
36
+ const parentIndex = Math.floor((index - 1) / 2);
37
+ if (this.compare(this.heap[index], this.heap[parentIndex]) <= 0)
38
+ break;
39
+ [this.heap[index], this.heap[parentIndex]] = [this.heap[parentIndex], this.heap[index]];
40
+ index = parentIndex;
41
+ }
42
+ }
43
+ bubbleDown(index) {
44
+ const length = this.heap.length;
45
+ while (true) {
46
+ const leftChild = 2 * index + 1;
47
+ const rightChild = 2 * index + 2;
48
+ let largest = index;
49
+ if (leftChild < length && this.compare(this.heap[leftChild], this.heap[largest]) > 0) {
50
+ largest = leftChild;
51
+ }
52
+ if (rightChild < length && this.compare(this.heap[rightChild], this.heap[largest]) > 0) {
53
+ largest = rightChild;
54
+ }
55
+ if (largest === index)
56
+ break;
57
+ [this.heap[index], this.heap[largest]] = [this.heap[largest], this.heap[index]];
58
+ index = largest;
59
+ }
60
+ }
61
+ }
62
+ //# sourceMappingURL=priority-queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"priority-queue.js","sourceRoot":"","sources":["../../src/utils/priority-queue.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=priority-queue.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"priority-queue.test.d.ts","sourceRoot":"","sources":["../../src/utils/priority-queue.test.ts"],"names":[],"mappings":""}