agkan 1.0.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 (208) hide show
  1. package/README.ja.md +1127 -0
  2. package/README.md +1140 -0
  3. package/bin/agkan +2 -0
  4. package/dist/cli/commands/block/add.d.ts +6 -0
  5. package/dist/cli/commands/block/add.d.ts.map +1 -0
  6. package/dist/cli/commands/block/add.js +135 -0
  7. package/dist/cli/commands/block/add.js.map +1 -0
  8. package/dist/cli/commands/block/list.d.ts +6 -0
  9. package/dist/cli/commands/block/list.d.ts.map +1 -0
  10. package/dist/cli/commands/block/list.js +120 -0
  11. package/dist/cli/commands/block/list.js.map +1 -0
  12. package/dist/cli/commands/block/remove.d.ts +6 -0
  13. package/dist/cli/commands/block/remove.d.ts.map +1 -0
  14. package/dist/cli/commands/block/remove.js +117 -0
  15. package/dist/cli/commands/block/remove.js.map +1 -0
  16. package/dist/cli/commands/meta/delete.d.ts +6 -0
  17. package/dist/cli/commands/meta/delete.d.ts.map +1 -0
  18. package/dist/cli/commands/meta/delete.js +67 -0
  19. package/dist/cli/commands/meta/delete.js.map +1 -0
  20. package/dist/cli/commands/meta/get.d.ts +6 -0
  21. package/dist/cli/commands/meta/get.d.ts.map +1 -0
  22. package/dist/cli/commands/meta/get.js +71 -0
  23. package/dist/cli/commands/meta/get.js.map +1 -0
  24. package/dist/cli/commands/meta/list.d.ts +6 -0
  25. package/dist/cli/commands/meta/list.d.ts.map +1 -0
  26. package/dist/cli/commands/meta/list.js +69 -0
  27. package/dist/cli/commands/meta/list.js.map +1 -0
  28. package/dist/cli/commands/meta/set.d.ts +6 -0
  29. package/dist/cli/commands/meta/set.d.ts.map +1 -0
  30. package/dist/cli/commands/meta/set.js +85 -0
  31. package/dist/cli/commands/meta/set.js.map +1 -0
  32. package/dist/cli/commands/tag/add.d.ts +6 -0
  33. package/dist/cli/commands/tag/add.d.ts.map +1 -0
  34. package/dist/cli/commands/tag/add.js +99 -0
  35. package/dist/cli/commands/tag/add.js.map +1 -0
  36. package/dist/cli/commands/tag/attach.d.ts +6 -0
  37. package/dist/cli/commands/tag/attach.d.ts.map +1 -0
  38. package/dist/cli/commands/tag/attach.js +119 -0
  39. package/dist/cli/commands/tag/attach.js.map +1 -0
  40. package/dist/cli/commands/tag/delete.d.ts +6 -0
  41. package/dist/cli/commands/tag/delete.d.ts.map +1 -0
  42. package/dist/cli/commands/tag/delete.js +93 -0
  43. package/dist/cli/commands/tag/delete.js.map +1 -0
  44. package/dist/cli/commands/tag/detach.d.ts +6 -0
  45. package/dist/cli/commands/tag/detach.d.ts.map +1 -0
  46. package/dist/cli/commands/tag/detach.js +118 -0
  47. package/dist/cli/commands/tag/detach.js.map +1 -0
  48. package/dist/cli/commands/tag/list.d.ts +6 -0
  49. package/dist/cli/commands/tag/list.d.ts.map +1 -0
  50. package/dist/cli/commands/tag/list.js +80 -0
  51. package/dist/cli/commands/tag/list.js.map +1 -0
  52. package/dist/cli/commands/tag/show.d.ts +6 -0
  53. package/dist/cli/commands/tag/show.d.ts.map +1 -0
  54. package/dist/cli/commands/tag/show.js +88 -0
  55. package/dist/cli/commands/tag/show.js.map +1 -0
  56. package/dist/cli/commands/task/add-helpers.d.ts +17 -0
  57. package/dist/cli/commands/task/add-helpers.d.ts.map +1 -0
  58. package/dist/cli/commands/task/add-helpers.js +122 -0
  59. package/dist/cli/commands/task/add-helpers.js.map +1 -0
  60. package/dist/cli/commands/task/add.d.ts +6 -0
  61. package/dist/cli/commands/task/add.d.ts.map +1 -0
  62. package/dist/cli/commands/task/add.js +140 -0
  63. package/dist/cli/commands/task/add.js.map +1 -0
  64. package/dist/cli/commands/task/count.d.ts +6 -0
  65. package/dist/cli/commands/task/count.d.ts.map +1 -0
  66. package/dist/cli/commands/task/count.js +97 -0
  67. package/dist/cli/commands/task/count.js.map +1 -0
  68. package/dist/cli/commands/task/delete.d.ts +6 -0
  69. package/dist/cli/commands/task/delete.d.ts.map +1 -0
  70. package/dist/cli/commands/task/delete.js +59 -0
  71. package/dist/cli/commands/task/delete.js.map +1 -0
  72. package/dist/cli/commands/task/find.d.ts +7 -0
  73. package/dist/cli/commands/task/find.d.ts.map +1 -0
  74. package/dist/cli/commands/task/find.js +118 -0
  75. package/dist/cli/commands/task/find.js.map +1 -0
  76. package/dist/cli/commands/task/get.d.ts +6 -0
  77. package/dist/cli/commands/task/get.d.ts.map +1 -0
  78. package/dist/cli/commands/task/get.js +196 -0
  79. package/dist/cli/commands/task/get.js.map +1 -0
  80. package/dist/cli/commands/task/list.d.ts +6 -0
  81. package/dist/cli/commands/task/list.d.ts.map +1 -0
  82. package/dist/cli/commands/task/list.js +301 -0
  83. package/dist/cli/commands/task/list.js.map +1 -0
  84. package/dist/cli/commands/task/update-parent.d.ts +6 -0
  85. package/dist/cli/commands/task/update-parent.d.ts.map +1 -0
  86. package/dist/cli/commands/task/update-parent.js +123 -0
  87. package/dist/cli/commands/task/update-parent.js.map +1 -0
  88. package/dist/cli/commands/task/update.d.ts +6 -0
  89. package/dist/cli/commands/task/update.d.ts.map +1 -0
  90. package/dist/cli/commands/task/update.js +96 -0
  91. package/dist/cli/commands/task/update.js.map +1 -0
  92. package/dist/cli/index.d.ts +3 -0
  93. package/dist/cli/index.d.ts.map +1 -0
  94. package/dist/cli/index.js +68 -0
  95. package/dist/cli/index.js.map +1 -0
  96. package/dist/cli/utils/array-utils.d.ts +15 -0
  97. package/dist/cli/utils/array-utils.d.ts.map +1 -0
  98. package/dist/cli/utils/array-utils.js +20 -0
  99. package/dist/cli/utils/array-utils.js.map +1 -0
  100. package/dist/cli/utils/error-handler.d.ts +35 -0
  101. package/dist/cli/utils/error-handler.d.ts.map +1 -0
  102. package/dist/cli/utils/error-handler.js +84 -0
  103. package/dist/cli/utils/error-handler.js.map +1 -0
  104. package/dist/cli/utils/output-formatter.d.ts +34 -0
  105. package/dist/cli/utils/output-formatter.d.ts.map +1 -0
  106. package/dist/cli/utils/output-formatter.js +44 -0
  107. package/dist/cli/utils/output-formatter.js.map +1 -0
  108. package/dist/cli/utils/response-formatter.d.ts +19 -0
  109. package/dist/cli/utils/response-formatter.d.ts.map +1 -0
  110. package/dist/cli/utils/response-formatter.js +43 -0
  111. package/dist/cli/utils/response-formatter.js.map +1 -0
  112. package/dist/cli/utils/validators.d.ts +23 -0
  113. package/dist/cli/utils/validators.d.ts.map +1 -0
  114. package/dist/cli/utils/validators.js +47 -0
  115. package/dist/cli/utils/validators.js.map +1 -0
  116. package/dist/db/config.d.ts +27 -0
  117. package/dist/db/config.d.ts.map +1 -0
  118. package/dist/db/config.js +116 -0
  119. package/dist/db/config.js.map +1 -0
  120. package/dist/db/connection.d.ts +24 -0
  121. package/dist/db/connection.d.ts.map +1 -0
  122. package/dist/db/connection.js +62 -0
  123. package/dist/db/connection.js.map +1 -0
  124. package/dist/db/reset.d.ts +8 -0
  125. package/dist/db/reset.d.ts.map +1 -0
  126. package/dist/db/reset.js +33 -0
  127. package/dist/db/reset.js.map +1 -0
  128. package/dist/db/schema.d.ts +6 -0
  129. package/dist/db/schema.d.ts.map +1 -0
  130. package/dist/db/schema.js +134 -0
  131. package/dist/db/schema.js.map +1 -0
  132. package/dist/models/Attachment.d.ts +25 -0
  133. package/dist/models/Attachment.d.ts.map +1 -0
  134. package/dist/models/Attachment.js +7 -0
  135. package/dist/models/Attachment.js.map +1 -0
  136. package/dist/models/Tag.d.ts +24 -0
  137. package/dist/models/Tag.d.ts.map +1 -0
  138. package/dist/models/Tag.js +3 -0
  139. package/dist/models/Tag.js.map +1 -0
  140. package/dist/models/Task.d.ts +55 -0
  141. package/dist/models/Task.d.ts.map +1 -0
  142. package/dist/models/Task.js +7 -0
  143. package/dist/models/Task.js.map +1 -0
  144. package/dist/models/TaskBlock.d.ts +11 -0
  145. package/dist/models/TaskBlock.d.ts.map +1 -0
  146. package/dist/models/TaskBlock.js +3 -0
  147. package/dist/models/TaskBlock.js.map +1 -0
  148. package/dist/models/TaskMetadata.d.ts +30 -0
  149. package/dist/models/TaskMetadata.d.ts.map +1 -0
  150. package/dist/models/TaskMetadata.js +3 -0
  151. package/dist/models/TaskMetadata.js.map +1 -0
  152. package/dist/models/TaskTag.d.ts +11 -0
  153. package/dist/models/TaskTag.d.ts.map +1 -0
  154. package/dist/models/TaskTag.js +3 -0
  155. package/dist/models/TaskTag.js.map +1 -0
  156. package/dist/models/index.d.ts +10 -0
  157. package/dist/models/index.d.ts.map +1 -0
  158. package/dist/models/index.js +7 -0
  159. package/dist/models/index.js.map +1 -0
  160. package/dist/services/AttachmentService.d.ts +62 -0
  161. package/dist/services/AttachmentService.d.ts.map +1 -0
  162. package/dist/services/AttachmentService.js +95 -0
  163. package/dist/services/AttachmentService.js.map +1 -0
  164. package/dist/services/FileService.d.ts +31 -0
  165. package/dist/services/FileService.d.ts.map +1 -0
  166. package/dist/services/FileService.js +77 -0
  167. package/dist/services/FileService.js.map +1 -0
  168. package/dist/services/MetadataService.d.ts +49 -0
  169. package/dist/services/MetadataService.d.ts.map +1 -0
  170. package/dist/services/MetadataService.js +126 -0
  171. package/dist/services/MetadataService.js.map +1 -0
  172. package/dist/services/TagService.d.ts +49 -0
  173. package/dist/services/TagService.d.ts.map +1 -0
  174. package/dist/services/TagService.js +127 -0
  175. package/dist/services/TagService.js.map +1 -0
  176. package/dist/services/TaskBlockService.d.ts +49 -0
  177. package/dist/services/TaskBlockService.d.ts.map +1 -0
  178. package/dist/services/TaskBlockService.js +118 -0
  179. package/dist/services/TaskBlockService.js.map +1 -0
  180. package/dist/services/TaskService.d.ts +89 -0
  181. package/dist/services/TaskService.d.ts.map +1 -0
  182. package/dist/services/TaskService.js +285 -0
  183. package/dist/services/TaskService.js.map +1 -0
  184. package/dist/services/TaskTagService.d.ts +66 -0
  185. package/dist/services/TaskTagService.d.ts.map +1 -0
  186. package/dist/services/TaskTagService.js +171 -0
  187. package/dist/services/TaskTagService.js.map +1 -0
  188. package/dist/services/index.d.ts +11 -0
  189. package/dist/services/index.d.ts.map +1 -0
  190. package/dist/services/index.js +20 -0
  191. package/dist/services/index.js.map +1 -0
  192. package/dist/utils/cycle-detector.d.ts +14 -0
  193. package/dist/utils/cycle-detector.d.ts.map +1 -0
  194. package/dist/utils/cycle-detector.js +32 -0
  195. package/dist/utils/cycle-detector.js.map +1 -0
  196. package/dist/utils/format.d.ts +13 -0
  197. package/dist/utils/format.d.ts.map +1 -0
  198. package/dist/utils/format.js +29 -0
  199. package/dist/utils/format.js.map +1 -0
  200. package/dist/utils/input-validators.d.ts +32 -0
  201. package/dist/utils/input-validators.d.ts.map +1 -0
  202. package/dist/utils/input-validators.js +108 -0
  203. package/dist/utils/input-validators.js.map +1 -0
  204. package/dist/utils/security.d.ts +11 -0
  205. package/dist/utils/security.d.ts.map +1 -0
  206. package/dist/utils/security.js +29 -0
  207. package/dist/utils/security.js.map +1 -0
  208. package/package.json +70 -0
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AttachmentService = void 0;
4
+ const connection_1 = require("../db/connection");
5
+ /**
6
+ * Attachment Service
7
+ * Provides management of attachment records
8
+ *
9
+ * @remarks
10
+ * **Future Feature**: This service is fully implemented but CLI commands are not yet available.
11
+ * See docs/planned-features.md for implementation timeline and planned CLI interface.
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * const service = new AttachmentService();
16
+ * const attachment = service.createAttachment({
17
+ * task_id: 1,
18
+ * file_name: 'design.pdf',
19
+ * file_path: '/path/to/design.pdf'
20
+ * });
21
+ * ```
22
+ */
23
+ class AttachmentService {
24
+ constructor(db) {
25
+ this.db = db || (0, connection_1.getDatabase)();
26
+ }
27
+ /**
28
+ * Create a new attachment record
29
+ *
30
+ * @remarks
31
+ * **Future Feature**: CLI command not yet implemented.
32
+ * Planned command: `agkan task attach add <task-id> <file-path>`
33
+ *
34
+ * @param input - Attachment creation input
35
+ * @returns Created attachment record
36
+ * @throws Will throw if task_id does not exist (foreign key constraint)
37
+ */
38
+ createAttachment(input) {
39
+ const db = this.db;
40
+ const now = new Date().toISOString();
41
+ const stmt = db.prepare(`
42
+ INSERT INTO attachments (task_id, file_name, file_path, created_at)
43
+ VALUES (?, ?, ?, ?)
44
+ `);
45
+ const result = stmt.run(input.task_id, input.file_name, input.file_path, now);
46
+ return {
47
+ id: result.lastInsertRowid,
48
+ task_id: input.task_id,
49
+ file_name: input.file_name,
50
+ file_path: input.file_path,
51
+ created_at: now,
52
+ };
53
+ }
54
+ /**
55
+ * Get attachments for a specific task
56
+ *
57
+ * @remarks
58
+ * **Future Feature**: CLI command not yet implemented.
59
+ * Planned command: `agkan task attach list <task-id>`
60
+ *
61
+ * @param taskId - Task ID
62
+ * @returns Array of attachments ordered by creation date (newest first)
63
+ */
64
+ getAttachmentsByTaskId(taskId) {
65
+ const db = this.db;
66
+ const stmt = db.prepare('SELECT * FROM attachments WHERE task_id = ? ORDER BY created_at DESC');
67
+ return stmt.all(taskId);
68
+ }
69
+ /**
70
+ * Delete an attachment record
71
+ *
72
+ * @remarks
73
+ * **Future Feature**: CLI command not yet implemented.
74
+ * Planned command: `agkan task attach delete <attachment-id>`
75
+ *
76
+ * @param id - Attachment ID
77
+ * @returns True if deletion succeeded, false if not found
78
+ *
79
+ * @todo Implement file deletion from filesystem
80
+ * @todo Add --keep-file option to CLI command
81
+ */
82
+ deleteAttachment(id) {
83
+ const db = this.db;
84
+ const stmt = db.prepare('SELECT * FROM attachments WHERE id = ?');
85
+ const attachment = stmt.get(id);
86
+ if (!attachment) {
87
+ return false;
88
+ }
89
+ const deleteStmt = db.prepare('DELETE FROM attachments WHERE id = ?');
90
+ deleteStmt.run(id);
91
+ return true;
92
+ }
93
+ }
94
+ exports.AttachmentService = AttachmentService;
95
+ //# sourceMappingURL=AttachmentService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AttachmentService.js","sourceRoot":"","sources":["../../src/services/AttachmentService.ts"],"names":[],"mappings":";;;AACA,iDAA+C;AAG/C;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAa,iBAAiB;IAG5B,YAAY,EAAsB;QAChC,IAAI,CAAC,EAAE,GAAG,EAAE,IAAI,IAAA,wBAAW,GAAE,CAAC;IAChC,CAAC;IAED;;;;;;;;;;OAUG;IACH,gBAAgB,CAAC,KAA4B;QAC3C,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC;QACnB,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAErC,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC;;;KAGvB,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QAE9E,OAAO;YACL,EAAE,EAAE,MAAM,CAAC,eAAyB;YACpC,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,UAAU,EAAE,GAAG;SAChB,CAAC;IACJ,CAAC;IAED;;;;;;;;;OASG;IACH,sBAAsB,CAAC,MAAc;QACnC,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC;QAEnB,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC,sEAAsE,CAAC,CAAC;QAChG,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,CAAiB,CAAC;IAC1C,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,gBAAgB,CAAC,EAAU;QACzB,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC;QAEnB,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC,wCAAwC,CAAC,CAAC;QAClE,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAEhC,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,OAAO,KAAK,CAAC;QACf,CAAC;QAED,MAAM,UAAU,GAAG,EAAE,CAAC,OAAO,CAAC,sCAAsC,CAAC,CAAC;QACtE,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAEnB,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AAnFD,8CAmFC"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * File Service
3
+ * Provides file system operations
4
+ */
5
+ export declare class FileService {
6
+ /**
7
+ * Save file to attachments directory
8
+ * @param sourceFile - Source file path
9
+ * @param taskId - Related task ID
10
+ * @returns Saved file name and path
11
+ * @throws If file not found
12
+ */
13
+ saveFile(sourceFile: string, taskId: number): {
14
+ file_name: string;
15
+ file_path: string;
16
+ };
17
+ /**
18
+ * Read markdown file contents
19
+ * @param filePath - Path of file to read
20
+ * @returns File contents
21
+ * @throws If file not found or path is unsafe
22
+ */
23
+ readMarkdownFile(filePath: string): string;
24
+ /**
25
+ * Delete file
26
+ * @param filePath - Path of file to delete
27
+ * @returns Returns true if deletion succeeds, false if file does not exist
28
+ */
29
+ deleteFile(filePath: string): boolean;
30
+ }
31
+ //# sourceMappingURL=FileService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FileService.d.ts","sourceRoot":"","sources":["../../src/services/FileService.ts"],"names":[],"mappings":"AAIA;;;GAGG;AACH,qBAAa,WAAW;IACtB;;;;;;OAMG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE;IA2BtF;;;;;OAKG;IACH,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAY1C;;;;OAIG;IACH,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;CAYtC"}
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.FileService = void 0;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const security_1 = require("../utils/security");
10
+ /**
11
+ * File Service
12
+ * Provides file system operations
13
+ */
14
+ class FileService {
15
+ /**
16
+ * Save file to attachments directory
17
+ * @param sourceFile - Source file path
18
+ * @param taskId - Related task ID
19
+ * @returns Saved file name and path
20
+ * @throws If file not found
21
+ */
22
+ saveFile(sourceFile, taskId) {
23
+ // Check if file exists
24
+ if (!fs_1.default.existsSync(sourceFile)) {
25
+ throw new Error(`File not found: ${sourceFile}`);
26
+ }
27
+ // Get file name
28
+ const fileName = path_1.default.basename(sourceFile);
29
+ // Create destination directory (attachments/<task_id>/)
30
+ const attachmentDir = path_1.default.join(process.cwd(), 'attachments', taskId.toString());
31
+ fs_1.default.mkdirSync(attachmentDir, { recursive: true });
32
+ // Generate filename with timestamp
33
+ const timestamp = Date.now();
34
+ const destFileName = `${timestamp}_${fileName}`;
35
+ const destPath = path_1.default.join(attachmentDir, destFileName);
36
+ // Copy file
37
+ fs_1.default.copyFileSync(sourceFile, destPath);
38
+ return {
39
+ file_name: fileName,
40
+ file_path: destPath,
41
+ };
42
+ }
43
+ /**
44
+ * Read markdown file contents
45
+ * @param filePath - Path of file to read
46
+ * @returns File contents
47
+ * @throws If file not found or path is unsafe
48
+ */
49
+ readMarkdownFile(filePath) {
50
+ if (!(0, security_1.isPathSafe)(filePath)) {
51
+ throw new Error(`Unsafe file path: ${filePath}`);
52
+ }
53
+ if (!fs_1.default.existsSync(filePath)) {
54
+ throw new Error(`File not found: ${filePath}`);
55
+ }
56
+ return fs_1.default.readFileSync(filePath, 'utf-8');
57
+ }
58
+ /**
59
+ * Delete file
60
+ * @param filePath - Path of file to delete
61
+ * @returns Returns true if deletion succeeds, false if file does not exist
62
+ */
63
+ deleteFile(filePath) {
64
+ if (!fs_1.default.existsSync(filePath)) {
65
+ return false;
66
+ }
67
+ try {
68
+ fs_1.default.unlinkSync(filePath);
69
+ return true;
70
+ }
71
+ catch {
72
+ throw new Error(`Failed to delete file: ${filePath}`);
73
+ }
74
+ }
75
+ }
76
+ exports.FileService = FileService;
77
+ //# sourceMappingURL=FileService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FileService.js","sourceRoot":"","sources":["../../src/services/FileService.ts"],"names":[],"mappings":";;;;;;AAAA,4CAAoB;AACpB,gDAAwB;AACxB,gDAA+C;AAE/C;;;GAGG;AACH,MAAa,WAAW;IACtB;;;;;;OAMG;IACH,QAAQ,CAAC,UAAkB,EAAE,MAAc;QACzC,uBAAuB;QACvB,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CAAC,mBAAmB,UAAU,EAAE,CAAC,CAAC;QACnD,CAAC;QAED,gBAAgB;QAChB,MAAM,QAAQ,GAAG,cAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QAE3C,wDAAwD;QACxD,MAAM,aAAa,GAAG,cAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;QACjF,YAAE,CAAC,SAAS,CAAC,aAAa,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAEjD,mCAAmC;QACnC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,MAAM,YAAY,GAAG,GAAG,SAAS,IAAI,QAAQ,EAAE,CAAC;QAChD,MAAM,QAAQ,GAAG,cAAI,CAAC,IAAI,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC;QAExD,YAAY;QACZ,YAAE,CAAC,YAAY,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QAEtC,OAAO;YACL,SAAS,EAAE,QAAQ;YACnB,SAAS,EAAE,QAAQ;SACpB,CAAC;IACJ,CAAC;IAED;;;;;OAKG;IACH,gBAAgB,CAAC,QAAgB;QAC/B,IAAI,CAAC,IAAA,qBAAU,EAAC,QAAQ,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CAAC,qBAAqB,QAAQ,EAAE,CAAC,CAAC;QACnD,CAAC;QAED,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CAAC,mBAAmB,QAAQ,EAAE,CAAC,CAAC;QACjD,CAAC;QAED,OAAO,YAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC5C,CAAC;IAED;;;;OAIG;IACH,UAAU,CAAC,QAAgB;QACzB,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7B,OAAO,KAAK,CAAC;QACf,CAAC;QAED,IAAI,CAAC;YACH,YAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;YACxB,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,KAAK,CAAC,0BAA0B,QAAQ,EAAE,CAAC,CAAC;QACxD,CAAC;IACH,CAAC;CACF;AAtED,kCAsEC"}
@@ -0,0 +1,49 @@
1
+ import { TaskMetadata, CreateTaskMetadataInput } from '../models';
2
+ import Database from 'better-sqlite3';
3
+ /**
4
+ * Metadata Service
5
+ * Manages creation, retrieval, update, and deletion of task metadata
6
+ */
7
+ export declare class MetadataService {
8
+ private db;
9
+ constructor(db?: Database.Database);
10
+ /**
11
+ * Set metadata for a task (create or update)
12
+ * @param input - Metadata creation input
13
+ * @returns Metadata object
14
+ */
15
+ setMetadata(input: CreateTaskMetadataInput): TaskMetadata;
16
+ /**
17
+ * Get metadata by task ID and key
18
+ * @param taskId - Task ID
19
+ * @param key - Metadata key
20
+ * @returns Metadata object or null if not found
21
+ */
22
+ getMetadataByKey(taskId: number, key: string): TaskMetadata | null;
23
+ /**
24
+ * List metadata for a task
25
+ * @param taskId - Task ID
26
+ * @returns Array of metadata objects
27
+ */
28
+ listMetadata(taskId: number): TaskMetadata[];
29
+ /**
30
+ * Delete metadata by task ID and key
31
+ * @param taskId - Task ID
32
+ * @param key - Metadata key
33
+ * @returns True if deletion succeeded, false if metadata not found
34
+ */
35
+ deleteMetadata(taskId: number, key: string): boolean;
36
+ /**
37
+ * Get all metadata for multiple tasks at once
38
+ * Avoids the N+1 problem by fetching all metadata in a single query
39
+ * @returns Map<task_id, TaskMetadata[]>
40
+ */
41
+ getAllTasksMetadata(): Map<number, TaskMetadata[]>;
42
+ /**
43
+ * Delete all metadata for a task
44
+ * @param taskId - Task ID
45
+ * @returns Number of deleted metadata entries
46
+ */
47
+ deleteAllMetadata(taskId: number): number;
48
+ }
49
+ //# sourceMappingURL=MetadataService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MetadataService.d.ts","sourceRoot":"","sources":["../../src/services/MetadataService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,WAAW,CAAC;AAElE,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAEtC;;;GAGG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,EAAE,CAAoB;gBAElB,EAAE,CAAC,EAAE,QAAQ,CAAC,QAAQ;IAIlC;;;;OAIG;IACH,WAAW,CAAC,KAAK,EAAE,uBAAuB,GAAG,YAAY;IAgCzD;;;;;OAKG;IACH,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI;IAalE;;;;OAIG;IACH,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,EAAE;IAc5C;;;;;OAKG;IACH,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO;IAapD;;;;OAIG;IACH,mBAAmB,IAAI,GAAG,CAAC,MAAM,EAAE,YAAY,EAAE,CAAC;IAsBlD;;;;OAIG;IACH,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;CAY1C"}
@@ -0,0 +1,126 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MetadataService = void 0;
4
+ const connection_1 = require("../db/connection");
5
+ /**
6
+ * Metadata Service
7
+ * Manages creation, retrieval, update, and deletion of task metadata
8
+ */
9
+ class MetadataService {
10
+ constructor(db) {
11
+ this.db = db || (0, connection_1.getDatabase)();
12
+ }
13
+ /**
14
+ * Set metadata for a task (create or update)
15
+ * @param input - Metadata creation input
16
+ * @returns Metadata object
17
+ */
18
+ setMetadata(input) {
19
+ const db = this.db;
20
+ // Check if metadata already exists
21
+ const existing = this.getMetadataByKey(input.task_id, input.key);
22
+ const now = new Date().toISOString();
23
+ if (existing) {
24
+ // Update existing metadata
25
+ const stmt = db.prepare(`
26
+ UPDATE task_metadata
27
+ SET value = ?, updated_at = ?
28
+ WHERE task_id = ? AND key = ?
29
+ `);
30
+ stmt.run(input.value, now, input.task_id, input.key);
31
+ return this.getMetadataByKey(input.task_id, input.key);
32
+ }
33
+ else {
34
+ // Create new metadata
35
+ const stmt = db.prepare(`
36
+ INSERT INTO task_metadata (task_id, key, value, created_at, updated_at)
37
+ VALUES (?, ?, ?, ?, ?)
38
+ `);
39
+ stmt.run(input.task_id, input.key, input.value, now, now);
40
+ return this.getMetadataByKey(input.task_id, input.key);
41
+ }
42
+ }
43
+ /**
44
+ * Get metadata by task ID and key
45
+ * @param taskId - Task ID
46
+ * @param key - Metadata key
47
+ * @returns Metadata object or null if not found
48
+ */
49
+ getMetadataByKey(taskId, key) {
50
+ const db = this.db;
51
+ const stmt = db.prepare(`
52
+ SELECT * FROM task_metadata
53
+ WHERE task_id = ? AND key = ?
54
+ `);
55
+ const result = stmt.get(taskId, key);
56
+ return result ? result : null;
57
+ }
58
+ /**
59
+ * List metadata for a task
60
+ * @param taskId - Task ID
61
+ * @returns Array of metadata objects
62
+ */
63
+ listMetadata(taskId) {
64
+ const db = this.db;
65
+ const stmt = db.prepare(`
66
+ SELECT * FROM task_metadata
67
+ WHERE task_id = ?
68
+ ORDER BY created_at DESC
69
+ `);
70
+ const results = stmt.all(taskId);
71
+ return results;
72
+ }
73
+ /**
74
+ * Delete metadata by task ID and key
75
+ * @param taskId - Task ID
76
+ * @param key - Metadata key
77
+ * @returns True if deletion succeeded, false if metadata not found
78
+ */
79
+ deleteMetadata(taskId, key) {
80
+ const db = this.db;
81
+ const stmt = db.prepare(`
82
+ DELETE FROM task_metadata
83
+ WHERE task_id = ? AND key = ?
84
+ `);
85
+ const result = stmt.run(taskId, key);
86
+ return result.changes > 0;
87
+ }
88
+ /**
89
+ * Get all metadata for multiple tasks at once
90
+ * Avoids the N+1 problem by fetching all metadata in a single query
91
+ * @returns Map<task_id, TaskMetadata[]>
92
+ */
93
+ getAllTasksMetadata() {
94
+ const db = this.db;
95
+ const stmt = db.prepare(`
96
+ SELECT * FROM task_metadata
97
+ ORDER BY task_id, created_at DESC
98
+ `);
99
+ const results = stmt.all();
100
+ const metadataMap = new Map();
101
+ for (const row of results) {
102
+ const taskId = row.task_id;
103
+ if (!metadataMap.has(taskId)) {
104
+ metadataMap.set(taskId, []);
105
+ }
106
+ metadataMap.get(taskId).push(row);
107
+ }
108
+ return metadataMap;
109
+ }
110
+ /**
111
+ * Delete all metadata for a task
112
+ * @param taskId - Task ID
113
+ * @returns Number of deleted metadata entries
114
+ */
115
+ deleteAllMetadata(taskId) {
116
+ const db = this.db;
117
+ const stmt = db.prepare(`
118
+ DELETE FROM task_metadata
119
+ WHERE task_id = ?
120
+ `);
121
+ const result = stmt.run(taskId);
122
+ return result.changes;
123
+ }
124
+ }
125
+ exports.MetadataService = MetadataService;
126
+ //# sourceMappingURL=MetadataService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MetadataService.js","sourceRoot":"","sources":["../../src/services/MetadataService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ import { Tag, CreateTagInput, UpdateTagInput } from '../models';
2
+ import Database from 'better-sqlite3';
3
+ /**
4
+ * Tag Service
5
+ * Manages creation, retrieval, update, and deletion of tags
6
+ */
7
+ export declare class TagService {
8
+ private db;
9
+ constructor(db?: Database.Database);
10
+ /**
11
+ * Create a new tag
12
+ * @param input - Tag creation input
13
+ * @returns Newly created tag
14
+ * @throws Error if tag name already exists
15
+ */
16
+ createTag(input: CreateTagInput): Tag;
17
+ /**
18
+ * Get tag by ID
19
+ * @param id - Tag ID
20
+ * @returns Tag object or null if not found
21
+ */
22
+ getTag(id: number): Tag | null;
23
+ /**
24
+ * Get tag by name
25
+ * @param name - Tag name
26
+ * @returns Tag object or null if not found
27
+ */
28
+ getTagByName(name: string): Tag | null;
29
+ /**
30
+ * List all tags
31
+ * @returns Array of tags sorted by creation date in descending order
32
+ */
33
+ listTags(): Tag[];
34
+ /**
35
+ * Update tag
36
+ * @param id - Tag ID
37
+ * @param input - Tag update input
38
+ * @returns Updated tag object or null if not found
39
+ * @throws Error if tag name already exists
40
+ */
41
+ updateTag(id: number, input: UpdateTagInput): Tag | null;
42
+ /**
43
+ * Delete tag
44
+ * @param id - Tag ID
45
+ * @returns True if deletion succeeded, false if tag not found
46
+ */
47
+ deleteTag(id: number): boolean;
48
+ }
49
+ //# sourceMappingURL=TagService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TagService.d.ts","sourceRoot":"","sources":["../../src/services/TagService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAGhE,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAEtC;;;GAGG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,EAAE,CAAoB;gBAElB,EAAE,CAAC,EAAE,QAAQ,CAAC,QAAQ;IAGlC;;;;;OAKG;IACH,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,GAAG;IA4BrC;;;;OAIG;IACH,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,GAAG,GAAG,IAAI;IAS9B;;;;OAIG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,GAAG,IAAI;IAStC;;;OAGG;IACH,QAAQ,IAAI,GAAG,EAAE;IASjB;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc,GAAG,GAAG,GAAG,IAAI;IAyCxD;;;;OAIG;IACH,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;CAQ/B"}
@@ -0,0 +1,127 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TagService = void 0;
4
+ const connection_1 = require("../db/connection");
5
+ const input_validators_1 = require("../utils/input-validators");
6
+ /**
7
+ * Tag Service
8
+ * Manages creation, retrieval, update, and deletion of tags
9
+ */
10
+ class TagService {
11
+ constructor(db) {
12
+ this.db = db || (0, connection_1.getDatabase)();
13
+ }
14
+ /**
15
+ * Create a new tag
16
+ * @param input - Tag creation input
17
+ * @returns Newly created tag
18
+ * @throws Error if tag name already exists
19
+ */
20
+ createTag(input) {
21
+ const db = this.db;
22
+ // Validate input fields
23
+ const validationErrors = (0, input_validators_1.validateTagInput)(input);
24
+ if (validationErrors.length > 0) {
25
+ throw new Error(validationErrors[0].message);
26
+ }
27
+ // Check for duplicate tag names
28
+ const existingTag = this.getTagByName(input.name);
29
+ if (existingTag) {
30
+ throw new Error(`Tag with name "${input.name}" already exists`);
31
+ }
32
+ const now = new Date().toISOString();
33
+ const stmt = db.prepare(`
34
+ INSERT INTO tags (name, created_at)
35
+ VALUES (?, ?)
36
+ `);
37
+ const result = stmt.run(input.name, now);
38
+ const getStmt = db.prepare('SELECT * FROM tags WHERE id = ?');
39
+ return getStmt.get(result.lastInsertRowid);
40
+ }
41
+ /**
42
+ * Get tag by ID
43
+ * @param id - Tag ID
44
+ * @returns Tag object or null if not found
45
+ */
46
+ getTag(id) {
47
+ const db = this.db;
48
+ const stmt = db.prepare('SELECT * FROM tags WHERE id = ?');
49
+ const result = stmt.get(id);
50
+ return result ? result : null;
51
+ }
52
+ /**
53
+ * Get tag by name
54
+ * @param name - Tag name
55
+ * @returns Tag object or null if not found
56
+ */
57
+ getTagByName(name) {
58
+ const db = this.db;
59
+ const stmt = db.prepare('SELECT * FROM tags WHERE name = ?');
60
+ const result = stmt.get(name);
61
+ return result ? result : null;
62
+ }
63
+ /**
64
+ * List all tags
65
+ * @returns Array of tags sorted by creation date in descending order
66
+ */
67
+ listTags() {
68
+ const db = this.db;
69
+ const stmt = db.prepare('SELECT * FROM tags ORDER BY created_at DESC');
70
+ const results = stmt.all();
71
+ return results;
72
+ }
73
+ /**
74
+ * Update tag
75
+ * @param id - Tag ID
76
+ * @param input - Tag update input
77
+ * @returns Updated tag object or null if not found
78
+ * @throws Error if tag name already exists
79
+ */
80
+ updateTag(id, input) {
81
+ const db = this.db;
82
+ // Verify that tag exists
83
+ const existingTag = this.getTag(id);
84
+ if (!existingTag) {
85
+ return null;
86
+ }
87
+ // Validate name if being updated
88
+ if (input.name !== undefined) {
89
+ if (!input.name || input.name.trim().length === 0) {
90
+ throw new Error('Name is required');
91
+ }
92
+ if (input.name.length > 50) {
93
+ throw new Error('Name must not exceed 50 characters');
94
+ }
95
+ if (/^\d+$/.test(input.name.trim())) {
96
+ throw new Error('Tag name cannot be purely numeric');
97
+ }
98
+ }
99
+ // Check for duplicate tag name if changing the name
100
+ if (input.name !== undefined && input.name !== existingTag.name) {
101
+ const duplicateTag = this.getTagByName(input.name);
102
+ if (duplicateTag) {
103
+ throw new Error(`Tag with name "${input.name}" already exists`);
104
+ }
105
+ }
106
+ const stmt = db.prepare(`
107
+ UPDATE tags
108
+ SET name = COALESCE(?, name)
109
+ WHERE id = ?
110
+ `);
111
+ stmt.run(input.name, id);
112
+ return this.getTag(id);
113
+ }
114
+ /**
115
+ * Delete tag
116
+ * @param id - Tag ID
117
+ * @returns True if deletion succeeded, false if tag not found
118
+ */
119
+ deleteTag(id) {
120
+ const db = this.db;
121
+ const stmt = db.prepare('DELETE FROM tags WHERE id = ?');
122
+ const result = stmt.run(id);
123
+ return result.changes > 0;
124
+ }
125
+ }
126
+ exports.TagService = TagService;
127
+ //# sourceMappingURL=TagService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TagService.js","sourceRoot":"","sources":["../../src/services/TagService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ import { TaskBlock, CreateTaskBlockInput } from '../models';
2
+ import { TaskService } from './TaskService';
3
+ import Database from 'better-sqlite3';
4
+ /**
5
+ * Task Block Service
6
+ * Manages blocking relationships between tasks
7
+ */
8
+ export declare class TaskBlockService {
9
+ private db;
10
+ private taskService;
11
+ constructor(db?: Database.Database, taskService?: TaskService);
12
+ /**
13
+ * Add a blocking relationship between tasks
14
+ * @param input - Creation input for the blocking relationship
15
+ * @returns Created blocking relationship
16
+ * @throws Error if tasks do not exist, self-reference is detected, or circular reference would be created
17
+ */
18
+ addBlock(input: CreateTaskBlockInput): TaskBlock;
19
+ /**
20
+ * Remove a blocking relationship between tasks
21
+ * @param blockerId - ID of the blocking task
22
+ * @param blockedId - ID of the blocked task
23
+ * @returns True if removal was successful, false if relationship was not found
24
+ */
25
+ removeBlock(blockerId: number, blockedId: number): boolean;
26
+ /**
27
+ * Get IDs of tasks blocked by the specified task
28
+ * Returns a list of IDs for tasks that are blocked by the given blocker task
29
+ * @param blockerId - ID of the blocking task
30
+ * @returns Array of IDs for tasks blocked by this task
31
+ */
32
+ getBlockedTaskIds(blockerId: number): number[];
33
+ /**
34
+ * Get IDs of tasks blocking the specified task
35
+ * Returns a list of IDs for tasks that block the given task
36
+ * @param blockedId - ID of the blocked task
37
+ * @returns Array of IDs for blocking tasks
38
+ */
39
+ getBlockerTaskIds(blockedId: number): number[];
40
+ /**
41
+ * Check for circular references in blocking relationships (private method)
42
+ * Detects whether adding a new blocking relationship would create a cycle using BFS algorithm
43
+ * @param blockerId - ID of the blocking task
44
+ * @param blockedId - ID of the blocked task
45
+ * @returns True if a circular reference would be created, false otherwise
46
+ */
47
+ private wouldCreateBlockCycle;
48
+ }
49
+ //# sourceMappingURL=TaskBlockService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TaskBlockService.d.ts","sourceRoot":"","sources":["../../src/services/TaskBlockService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAE5D,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAEtC;;;GAGG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,EAAE,CAAoB;IAC9B,OAAO,CAAC,WAAW,CAAc;gBAErB,EAAE,CAAC,EAAE,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,EAAE,WAAW;IAK7D;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,EAAE,oBAAoB,GAAG,SAAS;IAuChD;;;;;OAKG;IACH,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO;IAa1D;;;;;OAKG;IACH,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE;IAY9C;;;;;OAKG;IACH,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE;IAY9C;;;;;;OAMG;IACH,OAAO,CAAC,qBAAqB;CAiB9B"}