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,171 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TaskTagService = void 0;
4
+ const connection_1 = require("../db/connection");
5
+ const TaskService_1 = require("./TaskService");
6
+ const TagService_1 = require("./TagService");
7
+ /**
8
+ * Task Tag Service
9
+ * Manages associations between tasks and tags
10
+ */
11
+ class TaskTagService {
12
+ constructor(db, taskService, tagService) {
13
+ this.db = db || (0, connection_1.getDatabase)();
14
+ this.taskService = taskService || new TaskService_1.TaskService(this.db);
15
+ this.tagService = tagService || new TagService_1.TagService(this.db);
16
+ }
17
+ /**
18
+ * Add tag to task
19
+ * @param input - Task tag creation input
20
+ * @returns Created task tag association
21
+ * @throws Error if task or tag does not exist, or if the association already exists
22
+ */
23
+ addTagToTask(input) {
24
+ const db = this.db;
25
+ // Check if task exists
26
+ const task = this.taskService.getTask(input.task_id);
27
+ if (!task) {
28
+ throw new Error(`Task with id ${input.task_id} does not exist`);
29
+ }
30
+ // Check if tag exists
31
+ const tag = this.tagService.getTag(input.tag_id);
32
+ if (!tag) {
33
+ throw new Error(`Tag with id ${input.tag_id} does not exist`);
34
+ }
35
+ // Check if the association already exists
36
+ if (this.hasTag(input.task_id, input.tag_id)) {
37
+ throw new Error(`Task ${input.task_id} already has tag ${input.tag_id}`);
38
+ }
39
+ const now = new Date().toISOString();
40
+ const stmt = db.prepare(`
41
+ INSERT INTO task_tags (task_id, tag_id, created_at)
42
+ VALUES (?, ?, ?)
43
+ `);
44
+ const result = stmt.run(input.task_id, input.tag_id, now);
45
+ const getStmt = db.prepare('SELECT * FROM task_tags WHERE id = ?');
46
+ return getStmt.get(result.lastInsertRowid);
47
+ }
48
+ /**
49
+ * Remove tag from task
50
+ * @param taskId - Task ID
51
+ * @param tagId - Tag ID
52
+ * @returns True if removal was successful, false if association not found
53
+ */
54
+ removeTagFromTask(taskId, tagId) {
55
+ const db = this.db;
56
+ const stmt = db.prepare(`
57
+ DELETE FROM task_tags
58
+ WHERE task_id = ? AND tag_id = ?
59
+ `);
60
+ const result = stmt.run(taskId, tagId);
61
+ return result.changes > 0;
62
+ }
63
+ /**
64
+ * Check if task has a tag
65
+ * @param taskId - Task ID
66
+ * @param tagId - Tag ID
67
+ * @returns True if task has the tag, false otherwise
68
+ */
69
+ hasTag(taskId, tagId) {
70
+ const db = this.db;
71
+ const stmt = db.prepare(`
72
+ SELECT COUNT(*) as count FROM task_tags
73
+ WHERE task_id = ? AND tag_id = ?
74
+ `);
75
+ const result = stmt.get(taskId, tagId);
76
+ return result.count > 0;
77
+ }
78
+ /**
79
+ * Get tag IDs for a task
80
+ * @param taskId - Task ID
81
+ * @returns Array of tag IDs in order of assignment
82
+ */
83
+ getTagIdsForTask(taskId) {
84
+ const db = this.db;
85
+ const stmt = db.prepare(`
86
+ SELECT tag_id FROM task_tags
87
+ WHERE task_id = ?
88
+ ORDER BY created_at ASC
89
+ `);
90
+ const results = stmt.all(taskId);
91
+ return results.map((row) => row.tag_id);
92
+ }
93
+ /**
94
+ * Get tag objects for a task
95
+ * @param taskId - Task ID
96
+ * @returns Array of tag objects in order of assignment
97
+ */
98
+ getTagsForTask(taskId) {
99
+ const db = this.db;
100
+ const stmt = db.prepare(`
101
+ SELECT t.*
102
+ FROM tags t
103
+ INNER JOIN task_tags tt ON t.id = tt.tag_id
104
+ WHERE tt.task_id = ?
105
+ ORDER BY tt.created_at ASC
106
+ `);
107
+ return stmt.all(taskId);
108
+ }
109
+ /**
110
+ * Get task IDs for a tag
111
+ * @param tagId - Tag ID
112
+ * @returns Array of task IDs
113
+ */
114
+ getTaskIdsForTag(tagId) {
115
+ const db = this.db;
116
+ const stmt = db.prepare(`
117
+ SELECT task_id FROM task_tags
118
+ WHERE tag_id = ?
119
+ ORDER BY created_at ASC
120
+ `);
121
+ const results = stmt.all(tagId);
122
+ return results.map((row) => row.task_id);
123
+ }
124
+ /**
125
+ * Get task objects for a tag
126
+ * @param tagId - Tag ID
127
+ * @returns Array of task objects
128
+ */
129
+ getTasksForTag(tagId) {
130
+ const db = this.db;
131
+ const stmt = db.prepare(`
132
+ SELECT t.*
133
+ FROM tasks t
134
+ INNER JOIN task_tags tt ON t.id = tt.task_id
135
+ WHERE tt.tag_id = ?
136
+ ORDER BY tt.created_at ASC
137
+ `);
138
+ return stmt.all(tagId);
139
+ }
140
+ /**
141
+ * Get all task tags at once
142
+ * Avoids the N+1 problem by fetching all task tags in a single query
143
+ * @returns Map<task_id, Tag[]>
144
+ */
145
+ getAllTaskTags() {
146
+ const db = this.db;
147
+ const stmt = db.prepare(`
148
+ SELECT tt.task_id, t.*
149
+ FROM tags t
150
+ INNER JOIN task_tags tt ON t.id = tt.tag_id
151
+ ORDER BY tt.task_id, tt.created_at ASC
152
+ `);
153
+ const results = stmt.all();
154
+ const taskTagsMap = new Map();
155
+ for (const row of results) {
156
+ const taskId = row.task_id;
157
+ const tag = {
158
+ id: row.id,
159
+ name: row.name,
160
+ created_at: row.created_at,
161
+ };
162
+ if (!taskTagsMap.has(taskId)) {
163
+ taskTagsMap.set(taskId, []);
164
+ }
165
+ taskTagsMap.get(taskId).push(tag);
166
+ }
167
+ return taskTagsMap;
168
+ }
169
+ }
170
+ exports.TaskTagService = TaskTagService;
171
+ //# sourceMappingURL=TaskTagService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TaskTagService.js","sourceRoot":"","sources":["../../src/services/TaskTagService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Service layer exports
3
+ * Centrally manages all service classes
4
+ */
5
+ export { TaskService } from './TaskService';
6
+ export { FileService } from './FileService';
7
+ export { TaskBlockService } from './TaskBlockService';
8
+ export { TagService } from './TagService';
9
+ export { TaskTagService } from './TaskTagService';
10
+ export { MetadataService } from './MetadataService';
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/services/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ /**
3
+ * Service layer exports
4
+ * Centrally manages all service classes
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.MetadataService = exports.TaskTagService = exports.TagService = exports.TaskBlockService = exports.FileService = exports.TaskService = void 0;
8
+ var TaskService_1 = require("./TaskService");
9
+ Object.defineProperty(exports, "TaskService", { enumerable: true, get: function () { return TaskService_1.TaskService; } });
10
+ var FileService_1 = require("./FileService");
11
+ Object.defineProperty(exports, "FileService", { enumerable: true, get: function () { return FileService_1.FileService; } });
12
+ var TaskBlockService_1 = require("./TaskBlockService");
13
+ Object.defineProperty(exports, "TaskBlockService", { enumerable: true, get: function () { return TaskBlockService_1.TaskBlockService; } });
14
+ var TagService_1 = require("./TagService");
15
+ Object.defineProperty(exports, "TagService", { enumerable: true, get: function () { return TagService_1.TagService; } });
16
+ var TaskTagService_1 = require("./TaskTagService");
17
+ Object.defineProperty(exports, "TaskTagService", { enumerable: true, get: function () { return TaskTagService_1.TaskTagService; } });
18
+ var MetadataService_1 = require("./MetadataService");
19
+ Object.defineProperty(exports, "MetadataService", { enumerable: true, get: function () { return MetadataService_1.MetadataService; } });
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/services/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,6CAA4C;AAAnC,0GAAA,WAAW,OAAA;AACpB,6CAA4C;AAAnC,0GAAA,WAAW,OAAA;AACpB,uDAAsD;AAA7C,oHAAA,gBAAgB,OAAA;AACzB,2CAA0C;AAAjC,wGAAA,UAAU,OAAA;AACnB,mDAAkD;AAAzC,gHAAA,cAAc,OAAA;AACvB,qDAAoD;AAA3C,kHAAA,eAAe,OAAA"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Cycle detection utility for task parent-child relationships
3
+ * Decoupled from TaskService so it can be tested without a database.
4
+ */
5
+ /**
6
+ * Check whether setting a new parent would create a circular reference.
7
+ *
8
+ * @param taskId - The task that would become a child
9
+ * @param proposedParentId - The proposed new parent (null = remove parent)
10
+ * @param getParentId - Callback that returns the parent_id of a task (null if no parent / not found)
11
+ * @returns true if assigning proposedParentId as parent of taskId would create a cycle
12
+ */
13
+ export declare function wouldCreateCycle(taskId: number, proposedParentId: number | null, getParentId: (id: number) => number | null): boolean;
14
+ //# sourceMappingURL=cycle-detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cycle-detector.d.ts","sourceRoot":"","sources":["../../src/utils/cycle-detector.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,EACd,gBAAgB,EAAE,MAAM,GAAG,IAAI,EAC/B,WAAW,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,GACzC,OAAO,CAgBT"}
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ /**
3
+ * Cycle detection utility for task parent-child relationships
4
+ * Decoupled from TaskService so it can be tested without a database.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.wouldCreateCycle = wouldCreateCycle;
8
+ /**
9
+ * Check whether setting a new parent would create a circular reference.
10
+ *
11
+ * @param taskId - The task that would become a child
12
+ * @param proposedParentId - The proposed new parent (null = remove parent)
13
+ * @param getParentId - Callback that returns the parent_id of a task (null if no parent / not found)
14
+ * @returns true if assigning proposedParentId as parent of taskId would create a cycle
15
+ */
16
+ function wouldCreateCycle(taskId, proposedParentId, getParentId) {
17
+ if (!proposedParentId)
18
+ return false;
19
+ if (taskId === proposedParentId)
20
+ return true;
21
+ let currentId = proposedParentId;
22
+ const visited = new Set();
23
+ while (currentId !== null) {
24
+ if (visited.has(currentId) || currentId === taskId) {
25
+ return true;
26
+ }
27
+ visited.add(currentId);
28
+ currentId = getParentId(currentId);
29
+ }
30
+ return false;
31
+ }
32
+ //# sourceMappingURL=cycle-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cycle-detector.js","sourceRoot":"","sources":["../../src/utils/cycle-detector.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAUH,4CAoBC;AA5BD;;;;;;;GAOG;AACH,SAAgB,gBAAgB,CAC9B,MAAc,EACd,gBAA+B,EAC/B,WAA0C;IAE1C,IAAI,CAAC,gBAAgB;QAAE,OAAO,KAAK,CAAC;IACpC,IAAI,MAAM,KAAK,gBAAgB;QAAE,OAAO,IAAI,CAAC;IAE7C,IAAI,SAAS,GAAkB,gBAAgB,CAAC;IAChD,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAElC,OAAO,SAAS,KAAK,IAAI,EAAE,CAAC;QAC1B,IAAI,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,SAAS,KAAK,MAAM,EAAE,CAAC;YACnD,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACvB,SAAS,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC;IACrC,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { TaskStatus } from '../models';
2
+ /**
3
+ * Get the color corresponding to a status
4
+ * Returns the color name to be used by chalk
5
+ */
6
+ export declare function getStatusColor(status: TaskStatus): 'gray' | 'blue' | 'yellow' | 'cyan' | 'green' | 'magenta';
7
+ /**
8
+ * Format a date from ISO 8601 format to Japanese locale format
9
+ * @param isoDate - ISO 8601 format date string
10
+ * @returns Formatted date string
11
+ */
12
+ export declare function formatDate(isoDate: string): string;
13
+ //# sourceMappingURL=format.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/utils/format.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvC;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAU5G;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGlD"}
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getStatusColor = getStatusColor;
4
+ exports.formatDate = formatDate;
5
+ /**
6
+ * Get the color corresponding to a status
7
+ * Returns the color name to be used by chalk
8
+ */
9
+ function getStatusColor(status) {
10
+ const colorMap = {
11
+ backlog: 'gray',
12
+ ready: 'blue',
13
+ in_progress: 'yellow',
14
+ review: 'cyan',
15
+ done: 'green',
16
+ closed: 'magenta',
17
+ };
18
+ return colorMap[status];
19
+ }
20
+ /**
21
+ * Format a date from ISO 8601 format to Japanese locale format
22
+ * @param isoDate - ISO 8601 format date string
23
+ * @returns Formatted date string
24
+ */
25
+ function formatDate(isoDate) {
26
+ const date = new Date(isoDate);
27
+ return date.toLocaleString('ja-JP');
28
+ }
29
+ //# sourceMappingURL=format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/utils/format.ts"],"names":[],"mappings":";;AAMA,wCAUC;AAOD,gCAGC;AAxBD;;;GAGG;AACH,SAAgB,cAAc,CAAC,MAAkB;IAC/C,MAAM,QAAQ,GAAkF;QAC9F,OAAO,EAAE,MAAM;QACf,KAAK,EAAE,MAAM;QACb,WAAW,EAAE,QAAQ;QACrB,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,OAAO;QACb,MAAM,EAAE,SAAS;KAClB,CAAC;IACF,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC;AAC1B,CAAC;AAED;;;;GAIG;AACH,SAAgB,UAAU,CAAC,OAAe;IACxC,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC;IAC/B,OAAO,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;AACtC,CAAC"}
@@ -0,0 +1,32 @@
1
+ import type { CreateTaskInput, UpdateTaskInput } from '../models/Task';
2
+ import type { CreateTagInput } from '../models/Tag';
3
+ /**
4
+ * Input validation utility functions
5
+ * Provides validation for user input with length limits
6
+ */
7
+ /**
8
+ * Validation error interface
9
+ */
10
+ export interface ValidationError {
11
+ field: string;
12
+ message: string;
13
+ }
14
+ /**
15
+ * Validate task input for security and length constraints
16
+ * @param input - Task creation input to validate
17
+ * @returns Array of validation errors (empty if valid)
18
+ */
19
+ export declare function validateTaskInput(input: CreateTaskInput): ValidationError[];
20
+ /**
21
+ * Validate task update input for security and length constraints
22
+ * @param input - Task update input to validate (all fields optional)
23
+ * @returns Array of validation errors (empty if valid)
24
+ */
25
+ export declare function validateTaskUpdateInput(input: UpdateTaskInput): ValidationError[];
26
+ /**
27
+ * Validate tag input for security and length constraints
28
+ * @param input - Tag creation input to validate
29
+ * @returns Array of validation errors (empty if valid)
30
+ */
31
+ export declare function validateTagInput(input: CreateTagInput): ValidationError[];
32
+ //# sourceMappingURL=input-validators.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input-validators.d.ts","sourceRoot":"","sources":["../../src/utils/input-validators.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACvE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD;;;GAGG;AAEH;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,eAAe,GAAG,eAAe,EAAE,CAiC3E;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,eAAe,GAAG,eAAe,EAAE,CAmCjF;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,cAAc,GAAG,eAAe,EAAE,CAsBzE"}
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateTaskInput = validateTaskInput;
4
+ exports.validateTaskUpdateInput = validateTaskUpdateInput;
5
+ exports.validateTagInput = validateTagInput;
6
+ /**
7
+ * Validate task input for security and length constraints
8
+ * @param input - Task creation input to validate
9
+ * @returns Array of validation errors (empty if valid)
10
+ */
11
+ function validateTaskInput(input) {
12
+ const errors = [];
13
+ // Validate title (required, max 200 chars)
14
+ if (!input.title || input.title.trim().length === 0) {
15
+ errors.push({
16
+ field: 'title',
17
+ message: 'Title is required',
18
+ });
19
+ }
20
+ else if (input.title.length > 200) {
21
+ errors.push({
22
+ field: 'title',
23
+ message: 'Title must not exceed 200 characters',
24
+ });
25
+ }
26
+ // Validate body (optional, max 10000 chars)
27
+ if (input.body && input.body.length > 10000) {
28
+ errors.push({
29
+ field: 'body',
30
+ message: 'Body must not exceed 10000 characters',
31
+ });
32
+ }
33
+ // Validate author (optional, max 100 chars)
34
+ if (input.author && input.author.length > 100) {
35
+ errors.push({
36
+ field: 'author',
37
+ message: 'Author must not exceed 100 characters',
38
+ });
39
+ }
40
+ return errors;
41
+ }
42
+ /**
43
+ * Validate task update input for security and length constraints
44
+ * @param input - Task update input to validate (all fields optional)
45
+ * @returns Array of validation errors (empty if valid)
46
+ */
47
+ function validateTaskUpdateInput(input) {
48
+ const errors = [];
49
+ // Validate title if being updated (required when provided, max 200 chars)
50
+ if (input.title !== undefined) {
51
+ if (!input.title || input.title.trim().length === 0) {
52
+ errors.push({
53
+ field: 'title',
54
+ message: 'Title is required',
55
+ });
56
+ }
57
+ else if (input.title.length > 200) {
58
+ errors.push({
59
+ field: 'title',
60
+ message: 'Title must not exceed 200 characters',
61
+ });
62
+ }
63
+ }
64
+ // Validate body if being updated (optional, max 10000 chars)
65
+ if (input.body !== undefined && input.body !== null && input.body.length > 10000) {
66
+ errors.push({
67
+ field: 'body',
68
+ message: 'Body must not exceed 10000 characters',
69
+ });
70
+ }
71
+ // Validate author if being updated (optional, max 100 chars)
72
+ if (input.author !== undefined && input.author !== null && input.author.length > 100) {
73
+ errors.push({
74
+ field: 'author',
75
+ message: 'Author must not exceed 100 characters',
76
+ });
77
+ }
78
+ return errors;
79
+ }
80
+ /**
81
+ * Validate tag input for security and length constraints
82
+ * @param input - Tag creation input to validate
83
+ * @returns Array of validation errors (empty if valid)
84
+ */
85
+ function validateTagInput(input) {
86
+ const errors = [];
87
+ // Validate name (required, max 50 chars)
88
+ if (!input.name || input.name.trim().length === 0) {
89
+ errors.push({
90
+ field: 'name',
91
+ message: 'Name is required',
92
+ });
93
+ }
94
+ else if (input.name.length > 50) {
95
+ errors.push({
96
+ field: 'name',
97
+ message: 'Name must not exceed 50 characters',
98
+ });
99
+ }
100
+ else if (/^\d+$/.test(input.name.trim())) {
101
+ errors.push({
102
+ field: 'name',
103
+ message: 'Tag name cannot be purely numeric',
104
+ });
105
+ }
106
+ return errors;
107
+ }
108
+ //# sourceMappingURL=input-validators.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input-validators.js","sourceRoot":"","sources":["../../src/utils/input-validators.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Security utility functions
3
+ * Provides path validation and security checks
4
+ */
5
+ /**
6
+ * Check if a file path is safe from path traversal attacks
7
+ * @param filePath - Path to validate
8
+ * @returns True if path is safe, false otherwise
9
+ */
10
+ export declare function isPathSafe(filePath: string): boolean;
11
+ //# sourceMappingURL=security.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../../src/utils/security.ts"],"names":[],"mappings":"AAEA;;;GAGG;AAEH;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAapD"}
@@ -0,0 +1,29 @@
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.isPathSafe = isPathSafe;
7
+ const path_1 = __importDefault(require("path"));
8
+ /**
9
+ * Security utility functions
10
+ * Provides path validation and security checks
11
+ */
12
+ /**
13
+ * Check if a file path is safe from path traversal attacks
14
+ * @param filePath - Path to validate
15
+ * @returns True if path is safe, false otherwise
16
+ */
17
+ function isPathSafe(filePath) {
18
+ // Check for path traversal (..)
19
+ if (filePath.includes('..')) {
20
+ return false;
21
+ }
22
+ // For additional safety, check the normalized path doesn't contain '..'
23
+ const normalizedPath = path_1.default.normalize(filePath);
24
+ if (normalizedPath.includes('..')) {
25
+ return false;
26
+ }
27
+ return true;
28
+ }
29
+ //# sourceMappingURL=security.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.js","sourceRoot":"","sources":["../../src/utils/security.ts"],"names":[],"mappings":";;;;;AAYA,gCAaC;AAzBD,gDAAwB;AAExB;;;GAGG;AAEH;;;;GAIG;AACH,SAAgB,UAAU,CAAC,QAAgB;IACzC,gCAAgC;IAChC,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAC5B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,wEAAwE;IACxE,MAAM,cAAc,GAAG,cAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IAChD,IAAI,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAClC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
package/package.json ADDED
@@ -0,0 +1,70 @@
1
+ {
2
+ "name": "agkan",
3
+ "version": "1.0.0",
4
+ "description": "TypeScript-based CLI task management tool with SQLite storage",
5
+ "main": "dist/cli/index.js",
6
+ "bin": {
7
+ "agkan": "./bin/agkan"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "bin"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsc",
15
+ "dev": "tsc --watch",
16
+ "start": "node dist/cli/index.js",
17
+ "test": "vitest",
18
+ "test:errors": "vitest run --reporter=./tests/reporters/error-only.ts",
19
+ "test:e2e": "./test-e2e.sh",
20
+ "lint": "eslint src tests --ext .ts",
21
+ "lint:fix": "eslint src tests --ext .ts --fix",
22
+ "format": "prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"",
23
+ "format:check": "prettier --check \"src/**/*.ts\" \"tests/**/*.ts\"",
24
+ "type-check": "tsc --noEmit",
25
+ "check": "npm run type-check && npm run lint && npm run format:check",
26
+ "prepublishOnly": "npm run check && npm run build && vitest run",
27
+ "prepare": "husky || true"
28
+ },
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "git+https://github.com/gendosu/agkan.git"
32
+ },
33
+ "bugs": {
34
+ "url": "https://github.com/gendosu/agkan/issues"
35
+ },
36
+ "homepage": "https://github.com/gendosu/agkan#readme",
37
+ "keywords": [
38
+ "cli",
39
+ "task-management",
40
+ "kanban",
41
+ "typescript",
42
+ "sqlite"
43
+ ],
44
+ "author": "gendosu <gendosu@gmail.com>",
45
+ "license": "ISC",
46
+ "engines": {
47
+ "node": ">=18.0.0"
48
+ },
49
+ "dependencies": {
50
+ "better-sqlite3": "^11.7.0",
51
+ "chalk": "^4.1.2",
52
+ "commander": "^12.1.0",
53
+ "js-yaml": "^4.1.1"
54
+ },
55
+ "devDependencies": {
56
+ "@types/better-sqlite3": "^7.6.12",
57
+ "@types/js-yaml": "^4.0.9",
58
+ "@types/node": "^22.10.5",
59
+ "@typescript-eslint/eslint-plugin": "^8.55.0",
60
+ "@typescript-eslint/parser": "^8.55.0",
61
+ "@vitest/coverage-v8": "^4.0.18",
62
+ "eslint": "^9.39.2",
63
+ "eslint-config-prettier": "^10.1.8",
64
+ "husky": "^9.1.7",
65
+ "lint-staged": "^15.5.2",
66
+ "prettier": "^3.8.1",
67
+ "typescript": "^5.7.3",
68
+ "vitest": "^4.0.18"
69
+ }
70
+ }