agkan 2.14.3 → 2.15.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 (179) hide show
  1. package/README.ja.md +13 -13
  2. package/README.md +13 -13
  3. package/dist/board/boardFavicon.d.ts +2 -0
  4. package/dist/board/boardFavicon.d.ts.map +1 -0
  5. package/dist/board/boardFavicon.js +5 -0
  6. package/dist/board/boardFavicon.js.map +1 -0
  7. package/dist/board/boardRenderer.d.ts +22 -6
  8. package/dist/board/boardRenderer.d.ts.map +1 -1
  9. package/dist/board/boardRenderer.js +40 -24
  10. package/dist/board/boardRenderer.js.map +1 -1
  11. package/dist/board/boardRoutes.d.ts +2 -2
  12. package/dist/board/boardRoutes.d.ts.map +1 -1
  13. package/dist/board/boardRoutes.js +18 -3
  14. package/dist/board/boardRoutes.js.map +1 -1
  15. package/dist/board/boardStyles.d.ts +1 -1
  16. package/dist/board/boardStyles.d.ts.map +1 -1
  17. package/dist/board/boardStyles.js +14 -6
  18. package/dist/board/boardStyles.js.map +1 -1
  19. package/dist/board/client/board.js +369 -13
  20. package/dist/board/server.d.ts +2 -2
  21. package/dist/board/server.d.ts.map +1 -1
  22. package/dist/board/server.js +5 -5
  23. package/dist/board/server.js.map +1 -1
  24. package/dist/cli/commands/agent-guide.d.ts.map +1 -1
  25. package/dist/cli/commands/agent-guide.js +6 -0
  26. package/dist/cli/commands/agent-guide.js.map +1 -1
  27. package/dist/cli/commands/board.d.ts.map +1 -1
  28. package/dist/cli/commands/board.js +202 -15
  29. package/dist/cli/commands/board.js.map +1 -1
  30. package/dist/cli/commands/ps.d.ts +7 -0
  31. package/dist/cli/commands/ps.d.ts.map +1 -0
  32. package/dist/cli/commands/ps.js +83 -0
  33. package/dist/cli/commands/ps.js.map +1 -0
  34. package/dist/cli/commands/task/add.js +1 -1
  35. package/dist/cli/commands/task/add.js.map +1 -1
  36. package/dist/cli/commands/task/copy.d.ts +6 -0
  37. package/dist/cli/commands/task/copy.d.ts.map +1 -0
  38. package/dist/cli/commands/task/copy.js +118 -0
  39. package/dist/cli/commands/task/copy.js.map +1 -0
  40. package/dist/cli/commands/task/list.d.ts.map +1 -1
  41. package/dist/cli/commands/task/list.js +37 -17
  42. package/dist/cli/commands/task/list.js.map +1 -1
  43. package/dist/cli/index.js +2 -0
  44. package/dist/cli/index.js.map +1 -1
  45. package/dist/cli/utils/board-daemon.d.ts +7 -0
  46. package/dist/cli/utils/board-daemon.d.ts.map +1 -0
  47. package/dist/cli/utils/board-daemon.js +77 -0
  48. package/dist/cli/utils/board-daemon.js.map +1 -0
  49. package/dist/db/adapters/sqlite-storage-backend.d.ts +26 -0
  50. package/dist/db/adapters/sqlite-storage-backend.d.ts.map +1 -0
  51. package/dist/db/adapters/sqlite-storage-backend.js +447 -0
  52. package/dist/db/adapters/sqlite-storage-backend.js.map +1 -0
  53. package/dist/db/connection.d.ts +14 -0
  54. package/dist/db/connection.d.ts.map +1 -1
  55. package/dist/db/connection.js +28 -2
  56. package/dist/db/connection.js.map +1 -1
  57. package/dist/db/migrations/20260328000000_initial_schema.d.ts +3 -0
  58. package/dist/db/migrations/20260328000000_initial_schema.d.ts.map +1 -0
  59. package/dist/db/migrations/20260328000000_initial_schema.js +218 -0
  60. package/dist/db/migrations/20260328000000_initial_schema.js.map +1 -0
  61. package/dist/db/migrations/20260329000000_add_session_id_to_task_run_logs.d.ts +3 -0
  62. package/dist/db/migrations/20260329000000_add_session_id_to_task_run_logs.d.ts.map +1 -0
  63. package/dist/db/migrations/20260329000000_add_session_id_to_task_run_logs.js +7 -0
  64. package/dist/db/migrations/20260329000000_add_session_id_to_task_run_logs.js.map +1 -0
  65. package/dist/db/migrations/index.d.ts +4 -0
  66. package/dist/db/migrations/index.d.ts.map +1 -0
  67. package/dist/db/migrations/index.js +18 -0
  68. package/dist/db/migrations/index.js.map +1 -0
  69. package/dist/db/migrations/types.d.ts +17 -0
  70. package/dist/db/migrations/types.d.ts.map +1 -0
  71. package/dist/{board/client → db/migrations}/types.js +0 -1
  72. package/dist/db/migrations/types.js.map +1 -0
  73. package/dist/db/reset.d.ts.map +1 -1
  74. package/dist/db/reset.js +8 -3
  75. package/dist/db/reset.js.map +1 -1
  76. package/dist/db/schema.d.ts +4 -4
  77. package/dist/db/schema.d.ts.map +1 -1
  78. package/dist/db/schema.js +22 -207
  79. package/dist/db/schema.js.map +1 -1
  80. package/dist/db/types/repository.d.ts +192 -0
  81. package/dist/db/types/repository.d.ts.map +1 -0
  82. package/dist/db/types/repository.js +15 -0
  83. package/dist/db/types/repository.js.map +1 -0
  84. package/dist/models/Attachment.d.ts +25 -0
  85. package/dist/models/Attachment.d.ts.map +1 -0
  86. package/dist/models/Attachment.js +7 -0
  87. package/dist/models/Attachment.js.map +1 -0
  88. package/dist/services/AttachmentService.d.ts +62 -0
  89. package/dist/services/AttachmentService.d.ts.map +1 -0
  90. package/dist/services/AttachmentService.js +95 -0
  91. package/dist/services/AttachmentService.js.map +1 -0
  92. package/dist/services/ClaudeProcessService.d.ts +100 -0
  93. package/dist/services/ClaudeProcessService.d.ts.map +1 -0
  94. package/dist/services/ClaudeProcessService.js +278 -0
  95. package/dist/services/ClaudeProcessService.js.map +1 -0
  96. package/dist/services/CommentService.d.ts +3 -3
  97. package/dist/services/CommentService.d.ts.map +1 -1
  98. package/dist/services/CommentService.js +10 -70
  99. package/dist/services/CommentService.js.map +1 -1
  100. package/dist/services/ExportImportService.d.ts +3 -3
  101. package/dist/services/ExportImportService.d.ts.map +1 -1
  102. package/dist/services/ExportImportService.js +12 -16
  103. package/dist/services/ExportImportService.js.map +1 -1
  104. package/dist/services/MetadataService.d.ts +3 -3
  105. package/dist/services/MetadataService.d.ts.map +1 -1
  106. package/dist/services/MetadataService.js +9 -69
  107. package/dist/services/MetadataService.js.map +1 -1
  108. package/dist/services/TagService.d.ts +3 -3
  109. package/dist/services/TagService.d.ts.map +1 -1
  110. package/dist/services/TagService.js +9 -35
  111. package/dist/services/TagService.js.map +1 -1
  112. package/dist/services/TaskBlockService.d.ts +3 -3
  113. package/dist/services/TaskBlockService.d.ts.map +1 -1
  114. package/dist/services/TaskBlockService.js +9 -36
  115. package/dist/services/TaskBlockService.js.map +1 -1
  116. package/dist/services/TaskService.d.ts +3 -23
  117. package/dist/services/TaskService.d.ts.map +1 -1
  118. package/dist/services/TaskService.js +34 -186
  119. package/dist/services/TaskService.js.map +1 -1
  120. package/dist/services/TaskTagService.d.ts +3 -3
  121. package/dist/services/TaskTagService.d.ts.map +1 -1
  122. package/dist/services/TaskTagService.js +19 -83
  123. package/dist/services/TaskTagService.js.map +1 -1
  124. package/dist/utils/logger.d.ts +7 -0
  125. package/dist/utils/logger.d.ts.map +1 -0
  126. package/dist/utils/logger.js +18 -0
  127. package/dist/utils/logger.js.map +1 -0
  128. package/package.json +12 -5
  129. package/dist/board/boardScript.d.ts +0 -2
  130. package/dist/board/boardScript.d.ts.map +0 -1
  131. package/dist/board/boardScript.js +0 -1202
  132. package/dist/board/boardScript.js.map +0 -1
  133. package/dist/board/client/addTaskModal.d.ts +0 -2
  134. package/dist/board/client/addTaskModal.d.ts.map +0 -1
  135. package/dist/board/client/addTaskModal.js +0 -64
  136. package/dist/board/client/addTaskModal.js.map +0 -1
  137. package/dist/board/client/autoScroll.d.ts +0 -4
  138. package/dist/board/client/autoScroll.d.ts.map +0 -1
  139. package/dist/board/client/autoScroll.js +0 -59
  140. package/dist/board/client/autoScroll.js.map +0 -1
  141. package/dist/board/client/boardPolling.d.ts +0 -15
  142. package/dist/board/client/boardPolling.d.ts.map +0 -1
  143. package/dist/board/client/boardPolling.js +0 -144
  144. package/dist/board/client/boardPolling.js.map +0 -1
  145. package/dist/board/client/burgerMenu.d.ts +0 -2
  146. package/dist/board/client/burgerMenu.d.ts.map +0 -1
  147. package/dist/board/client/burgerMenu.js +0 -80
  148. package/dist/board/client/burgerMenu.js.map +0 -1
  149. package/dist/board/client/contextMenu.d.ts +0 -2
  150. package/dist/board/client/contextMenu.d.ts.map +0 -1
  151. package/dist/board/client/contextMenu.js +0 -52
  152. package/dist/board/client/contextMenu.js.map +0 -1
  153. package/dist/board/client/detailPanel.d.ts +0 -8
  154. package/dist/board/client/detailPanel.d.ts.map +0 -1
  155. package/dist/board/client/detailPanel.js +0 -565
  156. package/dist/board/client/detailPanel.js.map +0 -1
  157. package/dist/board/client/dragDrop.d.ts +0 -6
  158. package/dist/board/client/dragDrop.d.ts.map +0 -1
  159. package/dist/board/client/dragDrop.js +0 -82
  160. package/dist/board/client/dragDrop.js.map +0 -1
  161. package/dist/board/client/filters.d.ts +0 -6
  162. package/dist/board/client/filters.d.ts.map +0 -1
  163. package/dist/board/client/filters.js +0 -167
  164. package/dist/board/client/filters.js.map +0 -1
  165. package/dist/board/client/main.d.ts +0 -2
  166. package/dist/board/client/main.d.ts.map +0 -1
  167. package/dist/board/client/main.js +0 -20
  168. package/dist/board/client/main.js.map +0 -1
  169. package/dist/board/client/tags.d.ts +0 -6
  170. package/dist/board/client/tags.d.ts.map +0 -1
  171. package/dist/board/client/tags.js +0 -198
  172. package/dist/board/client/tags.js.map +0 -1
  173. package/dist/board/client/types.d.ts +0 -48
  174. package/dist/board/client/types.d.ts.map +0 -1
  175. package/dist/board/client/types.js.map +0 -1
  176. package/dist/board/client/utils.d.ts +0 -4
  177. package/dist/board/client/utils.d.ts.map +0 -1
  178. package/dist/board/client/utils.js +0 -44
  179. package/dist/board/client/utils.js.map +0 -1
@@ -31,8 +31,23 @@
31
31
  }
32
32
 
33
33
  // src/board/client/dragDrop.ts
34
+ var _redrawDependencies = null;
35
+ function registerDependencyRedrawCallback(callback) {
36
+ _redrawDependencies = callback;
37
+ }
34
38
  var draggedCard = null;
35
39
  var sourceBody = null;
40
+ var _dragMouseX = 0;
41
+ var _dragMouseY = 0;
42
+ var _dragOffsetX = 0;
43
+ var _dragOffsetY = 0;
44
+ function getDraggedCardVirtualRect() {
45
+ if (!draggedCard) return null;
46
+ const rect = draggedCard.getBoundingClientRect();
47
+ const left = _dragMouseX - _dragOffsetX;
48
+ const top = _dragMouseY - _dragOffsetY;
49
+ return new DOMRect(left, top, rect.width, rect.height);
50
+ }
36
51
  function updateCount(status) {
37
52
  const col = document.querySelector(`.column[data-status="${status}"]`);
38
53
  if (!col) return;
@@ -62,6 +77,9 @@
62
77
  body: JSON.stringify({ status: newStatus })
63
78
  });
64
79
  if (!res.ok) throw new Error("Server error");
80
+ if (_redrawDependencies) {
81
+ _redrawDependencies();
82
+ }
65
83
  } catch {
66
84
  if (prevBody && draggedCard) {
67
85
  prevBody.appendChild(draggedCard);
@@ -72,17 +90,33 @@
72
90
  showToast();
73
91
  }
74
92
  }
93
+ var _documentDragOverListener = null;
75
94
  function attachDragListeners(card) {
76
95
  card.addEventListener("dragstart", (e) => {
77
96
  draggedCard = card;
78
97
  sourceBody = card.parentElement;
79
98
  card.classList.add("dragging");
80
99
  if (e.dataTransfer) e.dataTransfer.effectAllowed = "move";
100
+ const rect = card.getBoundingClientRect();
101
+ _dragOffsetX = e.clientX - rect.left;
102
+ _dragOffsetY = e.clientY - rect.top;
103
+ _dragMouseX = e.clientX;
104
+ _dragMouseY = e.clientY;
105
+ _documentDragOverListener = (ev) => {
106
+ _dragMouseX = ev.clientX;
107
+ _dragMouseY = ev.clientY;
108
+ if (_redrawDependencies) _redrawDependencies();
109
+ };
110
+ document.addEventListener("dragover", _documentDragOverListener);
81
111
  });
82
112
  card.addEventListener("dragend", () => {
83
113
  card.classList.remove("dragging");
84
114
  draggedCard = null;
85
115
  sourceBody = null;
116
+ if (_documentDragOverListener) {
117
+ document.removeEventListener("dragover", _documentDragOverListener);
118
+ _documentDragOverListener = null;
119
+ }
86
120
  });
87
121
  }
88
122
  function initDragDrop() {
@@ -219,14 +253,43 @@
219
253
  });
220
254
  input.placeholder = currentTags.length === 0 ? "Add tags..." : "";
221
255
  }
256
+ async function createAndAddTag(name) {
257
+ const detailTaskId2 = _getDetailTaskId ? _getDetailTaskId() : null;
258
+ try {
259
+ const createRes = await fetch("/api/tags", {
260
+ method: "POST",
261
+ headers: { "Content-Type": "application/json" },
262
+ body: JSON.stringify({ name })
263
+ });
264
+ if (!createRes.ok) throw new Error("Server error");
265
+ const newTag = await createRes.json();
266
+ allAvailableTags.push(newTag);
267
+ const taskRes = await fetch("/api/tasks/" + detailTaskId2 + "/tags", {
268
+ method: "POST",
269
+ headers: { "Content-Type": "application/json" },
270
+ body: JSON.stringify({ tagId: newTag.id })
271
+ });
272
+ if (!taskRes.ok) throw new Error("Server error");
273
+ currentTags.push(newTag);
274
+ input.value = "";
275
+ inputValue = "";
276
+ renderPills();
277
+ renderDropdown();
278
+ } catch {
279
+ showToast("Failed to create tag");
280
+ }
281
+ }
222
282
  function renderDropdown() {
223
283
  const filtered = getFilteredTags();
224
284
  dropdown.innerHTML = "";
225
285
  focusedOptionIndex = -1;
226
- if (filtered.length === 0) {
286
+ const hasInput = inputValue.trim() !== "";
287
+ const exactMatch = hasInput && allAvailableTags.some((t) => t.name.toLowerCase() === inputValue.trim().toLowerCase());
288
+ const showCreate = hasInput && !exactMatch;
289
+ if (filtered.length === 0 && !showCreate) {
227
290
  const noOpt = document.createElement("div");
228
291
  noOpt.className = "tag-select-no-options";
229
- noOpt.textContent = inputValue ? "No matching tags" : "No tags available";
292
+ noOpt.textContent = hasInput ? "No matching tags" : "No tags available";
230
293
  dropdown.appendChild(noOpt);
231
294
  } else {
232
295
  filtered.forEach((t, i) => {
@@ -241,6 +304,18 @@
241
304
  });
242
305
  dropdown.appendChild(opt);
243
306
  });
307
+ if (showCreate) {
308
+ const createOpt = document.createElement("div");
309
+ createOpt.className = "tag-select-option tag-select-create-option";
310
+ createOpt.dataset.create = "true";
311
+ createOpt.textContent = `Create "${inputValue.trim()}"`;
312
+ createOpt.addEventListener("mouseover", () => setFocusedOption(filtered.length));
313
+ createOpt.addEventListener("mousedown", async (e) => {
314
+ e.preventDefault();
315
+ await createAndAddTag(inputValue.trim());
316
+ });
317
+ dropdown.appendChild(createOpt);
318
+ }
244
319
  }
245
320
  }
246
321
  function setFocusedOption(index) {
@@ -296,6 +371,8 @@
296
371
  e.preventDefault();
297
372
  if (focusedOptionIndex >= 0 && filtered[focusedOptionIndex]) {
298
373
  await addTag(String(filtered[focusedOptionIndex].id));
374
+ } else if (focusedOptionIndex >= 0 && inputValue.trim()) {
375
+ await createAndAddTag(inputValue.trim());
299
376
  }
300
377
  } else if (e.key === "Escape") {
301
378
  closeDropdown();
@@ -347,6 +424,7 @@
347
424
  var _showUpdateWarning = null;
348
425
  var _getDetailTaskId2 = null;
349
426
  var _setActiveCard = null;
427
+ var _redrawDependencies2 = null;
350
428
  function registerDetailPanelCallbacks(callbacks) {
351
429
  _openTaskDetail = callbacks.openTaskDetail;
352
430
  _renderDetailPanel = callbacks.renderDetailPanel;
@@ -354,6 +432,9 @@
354
432
  _getDetailTaskId2 = callbacks.getDetailTaskId;
355
433
  _setActiveCard = callbacks.setActiveCard;
356
434
  }
435
+ function registerDependencyRedrawCallback2(callback) {
436
+ _redrawDependencies2 = callback;
437
+ }
357
438
  function attachCardListeners(body) {
358
439
  body.querySelectorAll(".card").forEach((card) => {
359
440
  attachDragListeners(card);
@@ -447,6 +528,9 @@
447
528
  if (detailTaskId2 !== null && _setActiveCard) {
448
529
  _setActiveCard(detailTaskId2);
449
530
  }
531
+ if (_redrawDependencies2) {
532
+ _redrawDependencies2();
533
+ }
450
534
  if (detailTaskId2 !== null) {
451
535
  await refreshOpenDetailPanel(detailTaskId2);
452
536
  }
@@ -512,10 +596,13 @@
512
596
  const filtered = getFilteredAddTags();
513
597
  dropdown.innerHTML = "";
514
598
  tagFocusedIndex = -1;
515
- if (filtered.length === 0) {
599
+ const hasInput = tagInputValue.trim() !== "";
600
+ const exactMatch = hasInput && allAvailableTags.some((t) => t.name.toLowerCase() === tagInputValue.trim().toLowerCase());
601
+ const showCreate = hasInput && !exactMatch;
602
+ if (filtered.length === 0 && !showCreate) {
516
603
  const noOpt = document.createElement("div");
517
604
  noOpt.className = "tag-select-no-options";
518
- noOpt.textContent = tagInputValue ? "No matching tags" : "No tags available";
605
+ noOpt.textContent = hasInput ? "No matching tags" : "No tags available";
519
606
  dropdown.appendChild(noOpt);
520
607
  } else {
521
608
  filtered.forEach((t, i) => {
@@ -530,6 +617,19 @@
530
617
  });
531
618
  dropdown.appendChild(opt);
532
619
  });
620
+ if (showCreate) {
621
+ const createOpt = document.createElement("div");
622
+ createOpt.className = "tag-select-option tag-select-create-option";
623
+ createOpt.dataset.create = "true";
624
+ createOpt.textContent = `Create "${tagInputValue.trim()}"`;
625
+ createOpt.addEventListener("mouseover", () => setAddTagFocused(dropdown, filtered.length));
626
+ createOpt.addEventListener("mousedown", async (e) => {
627
+ e.preventDefault();
628
+ const input = document.getElementById("add-tag-input");
629
+ await createAndSelectAddTag(tagInputValue.trim(), dropdown, input);
630
+ });
631
+ dropdown.appendChild(createOpt);
632
+ }
533
633
  }
534
634
  }
535
635
  function setAddTagFocused(dropdown, index) {
@@ -547,6 +647,21 @@
547
647
  renderAddTagPills(control, input);
548
648
  renderAddTagDropdown(dropdown);
549
649
  }
650
+ async function createAndSelectAddTag(name, dropdown, input) {
651
+ try {
652
+ const res = await fetch("/api/tags", {
653
+ method: "POST",
654
+ headers: { "Content-Type": "application/json" },
655
+ body: JSON.stringify({ name })
656
+ });
657
+ if (!res.ok) throw new Error("Server error");
658
+ const newTag = await res.json();
659
+ allAvailableTags.push(newTag);
660
+ selectAddTag(newTag.id, dropdown, input);
661
+ } catch {
662
+ showToast("Failed to create tag");
663
+ }
664
+ }
550
665
  function initAddTagSelector() {
551
666
  const control = document.getElementById("add-tag-select-control");
552
667
  const dropdown = document.getElementById("add-tag-select-dropdown");
@@ -574,7 +689,7 @@
574
689
  renderAddTagDropdown(dropdown);
575
690
  if (!dropdown.classList.contains("open")) dropdown.classList.add("open");
576
691
  });
577
- input.addEventListener("keydown", (e) => {
692
+ input.addEventListener("keydown", async (e) => {
578
693
  const filtered = getFilteredAddTags();
579
694
  const opts = dropdown.querySelectorAll(".tag-select-option");
580
695
  if (e.key === "ArrowDown") {
@@ -587,6 +702,8 @@
587
702
  e.preventDefault();
588
703
  if (tagFocusedIndex >= 0 && filtered[tagFocusedIndex]) {
589
704
  selectAddTag(filtered[tagFocusedIndex].id, dropdown, input);
705
+ } else if (tagFocusedIndex >= 0 && tagInputValue.trim()) {
706
+ await createAndSelectAddTag(tagInputValue.trim(), dropdown, input);
590
707
  }
591
708
  } else if (e.key === "Escape") {
592
709
  dropdown.classList.remove("open");
@@ -636,7 +753,7 @@
636
753
  function resetAddModal(elements) {
637
754
  elements.addTitle.value = "";
638
755
  elements.addBody.value = "";
639
- elements.addPriority.value = "";
756
+ elements.addPriority.value = "medium";
640
757
  selectedTags = [];
641
758
  tagInputValue = "";
642
759
  tagFocusedIndex = -1;
@@ -903,14 +1020,14 @@
903
1020
  if (parent) {
904
1021
  html += '<div class="detail-relation-row">';
905
1022
  html += '<span class="detail-relation-label">Parent</span>';
906
- html += '<div class="detail-relation-ids"><span class="detail-relation-id">#' + parent.id + " " + escapeHtmlClient(parent.title) + "</span></div>";
1023
+ html += '<div class="detail-relation-ids"><span class="detail-relation-id detail-relation-link" data-task-id="' + parent.id + '">#' + parent.id + " " + escapeHtmlClient(parent.title) + "</span></div>";
907
1024
  html += "</div>";
908
1025
  }
909
1026
  if (blockedBy.length > 0) {
910
1027
  html += '<div class="detail-relation-row"><span class="detail-relation-label">Blocked by</span>';
911
1028
  html += '<div class="detail-relation-ids">';
912
1029
  blockedBy.forEach((t) => {
913
- html += '<span class="detail-relation-id">#' + t.id + "</span>";
1030
+ html += '<span class="detail-relation-id detail-relation-link" data-task-id="' + t.id + '">#' + t.id + "</span>";
914
1031
  });
915
1032
  html += "</div></div>";
916
1033
  }
@@ -918,7 +1035,7 @@
918
1035
  html += '<div class="detail-relation-row"><span class="detail-relation-label">Blocking</span>';
919
1036
  html += '<div class="detail-relation-ids">';
920
1037
  blocking.forEach((t) => {
921
- html += '<span class="detail-relation-id">#' + t.id + "</span>";
1038
+ html += '<span class="detail-relation-id detail-relation-link" data-task-id="' + t.id + '">#' + t.id + "</span>";
922
1039
  });
923
1040
  html += "</div></div>";
924
1041
  }
@@ -926,11 +1043,10 @@
926
1043
  return html;
927
1044
  }
928
1045
  function renderMetadataTable(metadata) {
929
- const otherMeta = metadata.filter((m) => m.key !== "priority");
930
- if (otherMeta.length === 0) return "";
1046
+ if (metadata.length === 0) return "";
931
1047
  let html = '<div class="detail-field"><div class="detail-field-label">Metadata</div>';
932
1048
  html += '<table class="detail-meta-table">';
933
- otherMeta.forEach((m) => {
1049
+ metadata.forEach((m) => {
934
1050
  html += "<tr><td>" + escapeHtmlClient(m.key) + "</td><td>" + escapeHtmlClient(m.value) + "</td></tr>";
935
1051
  });
936
1052
  html += "</table></div>";
@@ -969,7 +1085,7 @@
969
1085
  return html;
970
1086
  }
971
1087
  function buildDetailPanelHtml() {
972
- return '<div class="detail-panel" id="detail-panel"><div class="detail-panel-resize-handle" id="detail-panel-resize-handle"></div><div class="detail-panel-header"><h2 id="detail-panel-title">Task Detail</h2><button class="detail-panel-close" id="detail-panel-close" title="Close">&times;</button></div><div class="detail-tabs" id="detail-tabs"><button class="detail-tab active" data-tab="details">Details</button><button class="detail-tab" data-tab="comments" id="detail-tab-comments">Comments</button></div><div class="detail-panel-body" id="detail-panel-body"><div class="detail-tab-content active" id="detail-tab-content-details"></div><div class="detail-tab-content" id="detail-tab-content-comments"></div></div><div class="detail-panel-footer" id="detail-panel-footer"><button id="detail-save-btn">Save</button></div></div>';
1088
+ return '<div class="detail-panel" id="detail-panel"><div class="detail-panel-resize-handle" id="detail-panel-resize-handle"></div><div class="detail-panel-header"><h2 id="detail-panel-title">Task Detail</h2><button class="detail-panel-copy-id" id="detail-panel-copy-id" title="Copy task ID">&#x2398;</button><button class="detail-panel-close" id="detail-panel-close" title="Close">&times;</button></div><div class="detail-tabs" id="detail-tabs"><button class="detail-tab active" data-tab="details">Details</button><button class="detail-tab" data-tab="comments" id="detail-tab-comments">Comments</button></div><div class="detail-panel-body" id="detail-panel-body"><div class="detail-tab-content active" id="detail-tab-content-details"></div><div class="detail-tab-content" id="detail-tab-content-comments"></div></div><div class="detail-panel-footer" id="detail-panel-footer"><button id="detail-save-btn">Save</button></div></div>';
973
1089
  }
974
1090
  function autoResizeTextarea(el) {
975
1091
  const scrollContainer = el.closest(".detail-tab-content");
@@ -1157,6 +1273,13 @@
1157
1273
  if (detailsPane) {
1158
1274
  detailsPane.innerHTML = renderDetailPanelHtml(data);
1159
1275
  detailsPane.style.padding = "20px";
1276
+ detailsPane.querySelectorAll(".detail-relation-link[data-task-id]").forEach((el) => {
1277
+ el.style.cursor = "pointer";
1278
+ el.addEventListener("click", () => {
1279
+ const tid = el.dataset.taskId;
1280
+ if (tid) void openTaskDetail(tid);
1281
+ });
1282
+ });
1160
1283
  }
1161
1284
  const footer = document.getElementById("detail-panel-footer");
1162
1285
  if (footer) {
@@ -1303,6 +1426,12 @@
1303
1426
  boardContainer.insertAdjacentHTML("beforeend", buildDetailPanelHtml());
1304
1427
  const detailPanel = document.getElementById("detail-panel");
1305
1428
  document.getElementById("detail-panel-close")?.addEventListener("click", closeDetailPanel);
1429
+ document.getElementById("detail-panel-copy-id")?.addEventListener("click", () => {
1430
+ if (detailTaskId === null) return;
1431
+ navigator.clipboard.writeText(String(detailTaskId)).then(() => {
1432
+ showToast("Copied task ID: " + detailTaskId);
1433
+ });
1434
+ });
1306
1435
  document.addEventListener("keydown", (e) => {
1307
1436
  if (e.key === "Escape" && detailPanel.classList.contains("open")) {
1308
1437
  closeDetailPanel();
@@ -1714,6 +1843,232 @@
1714
1843
  initDarkMode();
1715
1844
  }
1716
1845
 
1846
+ // src/board/client/dependencyVisualization.ts
1847
+ var isDependencyVisible = false;
1848
+ var arrowMarkers = /* @__PURE__ */ new Map();
1849
+ var scrollListener = null;
1850
+ var columnScrollListener = null;
1851
+ var resizeListener = null;
1852
+ function getOrCreateArrowMarker(svg, color) {
1853
+ const markerId = `arrow-${color.substring(1)}`;
1854
+ if (!arrowMarkers.has(markerId)) {
1855
+ const defs = document.createElementNS("http://www.w3.org/2000/svg", "defs");
1856
+ const marker = document.createElementNS("http://www.w3.org/2000/svg", "marker");
1857
+ marker.setAttribute("id", markerId);
1858
+ marker.setAttribute("markerWidth", "10");
1859
+ marker.setAttribute("markerHeight", "10");
1860
+ marker.setAttribute("refX", "8");
1861
+ marker.setAttribute("refY", "3");
1862
+ marker.setAttribute("orient", "auto");
1863
+ marker.setAttribute("markerUnits", "strokeWidth");
1864
+ const polygon = document.createElementNS("http://www.w3.org/2000/svg", "polygon");
1865
+ polygon.setAttribute("points", "0 0, 10 3, 0 6");
1866
+ polygon.setAttribute("fill", color);
1867
+ marker.appendChild(polygon);
1868
+ defs.appendChild(marker);
1869
+ svg.appendChild(defs);
1870
+ arrowMarkers.set(markerId, { svg });
1871
+ }
1872
+ return markerId;
1873
+ }
1874
+ function drawBezierLine(svg, x1, y1, x2, y2, color, isHovered) {
1875
+ const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
1876
+ const dx = Math.abs(x2 - x1);
1877
+ const isSameSide = dx < 10;
1878
+ let cp1x;
1879
+ let cp2x;
1880
+ if (isSameSide) {
1881
+ const cpOffset = 80;
1882
+ cp1x = x1 + cpOffset;
1883
+ cp2x = x2 + cpOffset;
1884
+ } else {
1885
+ const cpOffset = Math.max(dx * 0.5, 60);
1886
+ cp1x = x1 < x2 ? x1 + cpOffset : x1 - cpOffset;
1887
+ cp2x = x1 < x2 ? x2 - cpOffset : x2 + cpOffset;
1888
+ }
1889
+ const pathData = `M ${x1} ${y1} C ${cp1x} ${y1}, ${cp2x} ${y2}, ${x2} ${y2}`;
1890
+ path.setAttribute("d", pathData);
1891
+ path.setAttribute("stroke", color);
1892
+ path.setAttribute("stroke-width", isHovered ? "2.5" : "1.5");
1893
+ path.setAttribute("fill", "none");
1894
+ path.setAttribute("stroke-linecap", "round");
1895
+ path.setAttribute("marker-end", `url(#${getOrCreateArrowMarker(svg, color)})`);
1896
+ path.setAttribute("class", "dependency-line");
1897
+ return path;
1898
+ }
1899
+ function getCardRect(card) {
1900
+ if (card === draggedCard) {
1901
+ return getDraggedCardVirtualRect() ?? card.getBoundingClientRect();
1902
+ }
1903
+ return card.getBoundingClientRect();
1904
+ }
1905
+ function getCardEdgePoints(fromCard, toCard, boardRect) {
1906
+ const fromRect = getCardRect(fromCard);
1907
+ const toRect = getCardRect(toCard);
1908
+ const fromCenterX = fromRect.left + fromRect.width / 2;
1909
+ const toCenterX = toRect.left + toRect.width / 2;
1910
+ const columnThreshold = 50;
1911
+ let fromX;
1912
+ let toX;
1913
+ if (Math.abs(fromCenterX - toCenterX) < columnThreshold) {
1914
+ fromX = fromRect.right - boardRect.left;
1915
+ toX = toRect.right - boardRect.left;
1916
+ } else if (fromCenterX <= toCenterX) {
1917
+ fromX = fromRect.right - boardRect.left;
1918
+ toX = toRect.left - boardRect.left;
1919
+ } else {
1920
+ fromX = fromRect.left - boardRect.left;
1921
+ toX = toRect.right - boardRect.left;
1922
+ }
1923
+ return {
1924
+ x1: fromX,
1925
+ y1: fromRect.top - boardRect.top + fromRect.height / 2,
1926
+ x2: toX,
1927
+ y2: toRect.top - boardRect.top + toRect.height / 2
1928
+ };
1929
+ }
1930
+ function createSVGOverlay() {
1931
+ const boardContainer = document.querySelector(".board-container");
1932
+ const existing = boardContainer.querySelector("#dependency-svg");
1933
+ if (existing) {
1934
+ existing.remove();
1935
+ }
1936
+ arrowMarkers.clear();
1937
+ const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
1938
+ svg.setAttribute("id", "dependency-svg");
1939
+ svg.setAttribute("width", "100%");
1940
+ svg.setAttribute("height", "100%");
1941
+ svg.setAttribute("viewBox", `0 0 ${boardContainer.offsetWidth} ${boardContainer.offsetHeight}`);
1942
+ svg.style.position = "absolute";
1943
+ svg.style.top = "0";
1944
+ svg.style.left = "0";
1945
+ svg.style.pointerEvents = "none";
1946
+ svg.style.zIndex = "5";
1947
+ boardContainer.style.position = "relative";
1948
+ boardContainer.appendChild(svg);
1949
+ return svg;
1950
+ }
1951
+ function redrawDependencies() {
1952
+ if (!isDependencyVisible) return;
1953
+ const svg = createSVGOverlay();
1954
+ const boardContainer = document.querySelector(".board-container");
1955
+ svg.querySelectorAll(".dependency-line").forEach((line) => line.remove());
1956
+ const cards = Array.from(document.querySelectorAll(".card"));
1957
+ const cardMap = /* @__PURE__ */ new Map();
1958
+ cards.forEach((card) => {
1959
+ const id = Number(card.getAttribute("data-id"));
1960
+ cardMap.set(id, card);
1961
+ });
1962
+ const hoveredCard = document.querySelector(".card:hover");
1963
+ const hoveredCardId = hoveredCard ? Number(hoveredCard.getAttribute("data-id")) : null;
1964
+ const hoveredBlockedBySet = /* @__PURE__ */ new Set();
1965
+ const hoveredBlockingSet = /* @__PURE__ */ new Set();
1966
+ if (hoveredCardId) {
1967
+ const hoveredElement = cardMap.get(hoveredCardId);
1968
+ if (hoveredElement) {
1969
+ const blockedBy = hoveredElement.getAttribute("data-blocked-by");
1970
+ const blocking = hoveredElement.getAttribute("data-blocking");
1971
+ if (blockedBy) {
1972
+ blockedBy.split(",").forEach((id) => {
1973
+ const numId = Number(id.trim());
1974
+ if (!isNaN(numId)) hoveredBlockedBySet.add(numId);
1975
+ });
1976
+ }
1977
+ if (blocking) {
1978
+ blocking.split(",").forEach((id) => {
1979
+ const numId = Number(id.trim());
1980
+ if (!isNaN(numId)) hoveredBlockingSet.add(numId);
1981
+ });
1982
+ }
1983
+ }
1984
+ }
1985
+ const boardRect = boardContainer.getBoundingClientRect();
1986
+ cards.forEach((card) => {
1987
+ const cardId = Number(card.getAttribute("data-id"));
1988
+ const blockedByStr = card.getAttribute("data-blocked-by");
1989
+ const blockingStr = card.getAttribute("data-blocking");
1990
+ if (!blockedByStr && !blockingStr) return;
1991
+ const isHovered = cardId === hoveredCardId || hoveredBlockedBySet.has(cardId) || hoveredBlockingSet.has(cardId);
1992
+ if (blockingStr) {
1993
+ const blockingIds = blockingStr.split(",").map((s) => Number(s.trim()));
1994
+ blockingIds.forEach((blockedId) => {
1995
+ const blockedCard = cardMap.get(blockedId);
1996
+ if (blockedCard) {
1997
+ const { x1, y1, x2, y2 } = getCardEdgePoints(card, blockedCard, boardRect);
1998
+ const color = isHovered || hoveredBlockedBySet.has(blockedId) ? "#ef4444" : "#cbd5e1";
1999
+ const line = drawBezierLine(svg, x1, y1, x2, y2, color, isHovered);
2000
+ svg.appendChild(line);
2001
+ }
2002
+ });
2003
+ }
2004
+ });
2005
+ svg.setAttribute("viewBox", `0 0 ${boardContainer.offsetWidth} ${boardContainer.offsetHeight}`);
2006
+ }
2007
+ function handleCardHoverEvents() {
2008
+ const cards = document.querySelectorAll(".card");
2009
+ cards.forEach((card) => {
2010
+ card.addEventListener("mouseenter", () => {
2011
+ redrawDependencies();
2012
+ });
2013
+ card.addEventListener("mouseleave", () => {
2014
+ redrawDependencies();
2015
+ });
2016
+ });
2017
+ }
2018
+ function initDependencyVisualization() {
2019
+ const toggleBtn = document.getElementById("dependency-toggle");
2020
+ if (!toggleBtn) return;
2021
+ const redrawIfVisible = () => {
2022
+ if (isDependencyVisible) {
2023
+ handleCardHoverEvents();
2024
+ redrawDependencies();
2025
+ }
2026
+ };
2027
+ registerDependencyRedrawCallback2(redrawIfVisible);
2028
+ registerDependencyRedrawCallback(redrawIfVisible);
2029
+ toggleBtn.addEventListener("click", () => {
2030
+ isDependencyVisible = !isDependencyVisible;
2031
+ if (isDependencyVisible) {
2032
+ toggleBtn.classList.add("active");
2033
+ redrawDependencies();
2034
+ handleCardHoverEvents();
2035
+ const board = document.querySelector(".board");
2036
+ const boardContainer = document.querySelector(".board-container");
2037
+ if (board) {
2038
+ scrollListener = () => redrawDependencies();
2039
+ board.addEventListener("scroll", scrollListener, { passive: true });
2040
+ }
2041
+ columnScrollListener = () => redrawDependencies();
2042
+ document.querySelectorAll(".column-body").forEach((col) => {
2043
+ col.addEventListener("scroll", columnScrollListener, { passive: true });
2044
+ });
2045
+ if (boardContainer) {
2046
+ resizeListener = () => redrawDependencies();
2047
+ window.addEventListener("resize", resizeListener, { passive: true });
2048
+ }
2049
+ } else {
2050
+ toggleBtn.classList.remove("active");
2051
+ const svg = document.querySelector("#dependency-svg");
2052
+ if (svg) svg.remove();
2053
+ const board = document.querySelector(".board");
2054
+ if (board && scrollListener) {
2055
+ board.removeEventListener("scroll", scrollListener);
2056
+ scrollListener = null;
2057
+ }
2058
+ if (columnScrollListener) {
2059
+ document.querySelectorAll(".column-body").forEach((col) => {
2060
+ col.removeEventListener("scroll", columnScrollListener);
2061
+ });
2062
+ columnScrollListener = null;
2063
+ }
2064
+ if (resizeListener) {
2065
+ window.removeEventListener("resize", resizeListener);
2066
+ resizeListener = null;
2067
+ }
2068
+ }
2069
+ });
2070
+ }
2071
+
1717
2072
  // src/board/client/main.ts
1718
2073
  initDragDrop();
1719
2074
  initAutoScroll();
@@ -1723,4 +2078,5 @@
1723
2078
  initBoardPolling();
1724
2079
  initFilters();
1725
2080
  initBurgerMenu();
2081
+ initDependencyVisualization();
1726
2082
  })();
@@ -5,7 +5,7 @@ import { TagService } from '../services/TagService';
5
5
  import { MetadataService } from '../services/MetadataService';
6
6
  import { CommentService } from '../services/CommentService';
7
7
  import { TaskBlockService } from '../services/TaskBlockService';
8
- import { StorageProvider } from '../db/types/storage';
9
- export declare function createBoardApp(taskService?: TaskService, taskTagService?: TaskTagService, metadataService?: MetadataService, db?: StorageProvider, boardTitle?: string, tagService?: TagService, configDir?: string, commentService?: CommentService, taskBlockService?: TaskBlockService): Hono;
8
+ import { StorageBackend } from '../db/types/repository';
9
+ export declare function createBoardApp(taskService?: TaskService, taskTagService?: TaskTagService, metadataService?: MetadataService, db?: StorageBackend, boardTitle?: string, tagService?: TagService, configDir?: string, commentService?: CommentService, taskBlockService?: TaskBlockService): Hono;
10
10
  export declare function startBoardServer(port: number, boardTitle?: string): void;
11
11
  //# sourceMappingURL=server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/board/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAG5B,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAEhE,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAItD,wBAAgB,cAAc,CAC5B,WAAW,CAAC,EAAE,WAAW,EACzB,cAAc,CAAC,EAAE,cAAc,EAC/B,eAAe,CAAC,EAAE,eAAe,EACjC,EAAE,CAAC,EAAE,eAAe,EACpB,UAAU,CAAC,EAAE,MAAM,EACnB,UAAU,CAAC,EAAE,UAAU,EACvB,SAAS,CAAC,EAAE,MAAM,EAClB,cAAc,CAAC,EAAE,cAAc,EAC/B,gBAAgB,CAAC,EAAE,gBAAgB,GAClC,IAAI,CAiBN;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAWxE"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/board/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAG5B,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAEhE,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAIxD,wBAAgB,cAAc,CAC5B,WAAW,CAAC,EAAE,WAAW,EACzB,cAAc,CAAC,EAAE,cAAc,EAC/B,eAAe,CAAC,EAAE,eAAe,EACjC,EAAE,CAAC,EAAE,cAAc,EACnB,UAAU,CAAC,EAAE,MAAM,EACnB,UAAU,CAAC,EAAE,UAAU,EACvB,SAAS,CAAC,EAAE,MAAM,EAClB,cAAc,CAAC,EAAE,cAAc,EAC/B,gBAAgB,CAAC,EAAE,gBAAgB,GAClC,IAAI,CAiBN;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAWxE"}
@@ -20,12 +20,12 @@ const boardRoutes_1 = require("./boardRoutes");
20
20
  function createBoardApp(taskService, taskTagService, metadataService, db, boardTitle, tagService, configDir, commentService, taskBlockService) {
21
21
  const app = new hono_1.Hono();
22
22
  const resolvedConfigDir = configDir ?? path_1.default.join(process.cwd(), (0, config_1.getDefaultDirName)());
23
- const resolvedDb = db ?? (0, connection_1.getDatabase)();
23
+ const resolvedDb = db ?? (0, connection_1.getStorageBackend)();
24
24
  const services = {
25
- ts: taskService ?? new TaskService_1.TaskService(),
26
- tts: taskTagService ?? new TaskTagService_1.TaskTagService(),
27
- tags: tagService ?? new TagService_1.TagService(),
28
- ms: metadataService ?? new MetadataService_1.MetadataService(),
25
+ ts: taskService ?? new TaskService_1.TaskService(resolvedDb),
26
+ tts: taskTagService ?? new TaskTagService_1.TaskTagService(resolvedDb),
27
+ tags: tagService ?? new TagService_1.TagService(resolvedDb),
28
+ ms: metadataService ?? new MetadataService_1.MetadataService(resolvedDb),
29
29
  cs: commentService ?? new CommentService_1.CommentService(resolvedDb),
30
30
  tbs: taskBlockService ?? new TaskBlockService_1.TaskBlockService(resolvedDb),
31
31
  database: resolvedDb,
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/board/server.ts"],"names":[],"mappings":";;;;;AAcA,wCA2BC;AAED,4CAWC;AAtDD,+BAA4B;AAC5B,mDAA0C;AAC1C,gDAAwB;AACxB,yDAAsD;AACtD,+DAA4D;AAC5D,uDAAoD;AACpD,iEAA8D;AAC9D,+DAA4D;AAC5D,mEAAgE;AAChE,iDAA+C;AAE/C,yCAAiD;AACjD,+CAAmE;AAEnE,SAAgB,cAAc,CAC5B,WAAyB,EACzB,cAA+B,EAC/B,eAAiC,EACjC,EAAoB,EACpB,UAAmB,EACnB,UAAuB,EACvB,SAAkB,EAClB,cAA+B,EAC/B,gBAAmC;IAEnC,MAAM,GAAG,GAAG,IAAI,WAAI,EAAE,CAAC;IACvB,MAAM,iBAAiB,GAAG,SAAS,IAAI,cAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAA,0BAAiB,GAAE,CAAC,CAAC;IACrF,MAAM,UAAU,GAAG,EAAE,IAAI,IAAA,wBAAW,GAAE,CAAC;IACvC,MAAM,QAAQ,GAAkB;QAC9B,EAAE,EAAE,WAAW,IAAI,IAAI,yBAAW,EAAE;QACpC,GAAG,EAAE,cAAc,IAAI,IAAI,+BAAc,EAAE;QAC3C,IAAI,EAAE,UAAU,IAAI,IAAI,uBAAU,EAAE;QACpC,EAAE,EAAE,eAAe,IAAI,IAAI,iCAAe,EAAE;QAC5C,EAAE,EAAE,cAAc,IAAI,IAAI,+BAAc,CAAC,UAAU,CAAC;QACpD,GAAG,EAAE,gBAAgB,IAAI,IAAI,mCAAgB,CAAC,UAAU,CAAC;QACzD,QAAQ,EAAE,UAAU;QACpB,UAAU;QACV,SAAS,EAAE,iBAAiB;KAC7B,CAAC;IACF,IAAA,iCAAmB,EAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IACnC,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAgB,gBAAgB,CAAC,IAAY,EAAE,UAAmB;IAChE,MAAM,GAAG,GAAG,cAAc,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;IACnF,IAAA,mBAAK,EACH;QACE,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,IAAI;KACL,EACD,CAAC,IAAI,EAAE,EAAE;QACP,OAAO,CAAC,GAAG,CAAC,yCAAyC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IACpE,CAAC,CACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/board/server.ts"],"names":[],"mappings":";;;;;AAcA,wCA2BC;AAED,4CAWC;AAtDD,+BAA4B;AAC5B,mDAA0C;AAC1C,gDAAwB;AACxB,yDAAsD;AACtD,+DAA4D;AAC5D,uDAAoD;AACpD,iEAA8D;AAC9D,+DAA4D;AAC5D,mEAAgE;AAChE,iDAAqD;AAErD,yCAAiD;AACjD,+CAAmE;AAEnE,SAAgB,cAAc,CAC5B,WAAyB,EACzB,cAA+B,EAC/B,eAAiC,EACjC,EAAmB,EACnB,UAAmB,EACnB,UAAuB,EACvB,SAAkB,EAClB,cAA+B,EAC/B,gBAAmC;IAEnC,MAAM,GAAG,GAAG,IAAI,WAAI,EAAE,CAAC;IACvB,MAAM,iBAAiB,GAAG,SAAS,IAAI,cAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAA,0BAAiB,GAAE,CAAC,CAAC;IACrF,MAAM,UAAU,GAAG,EAAE,IAAI,IAAA,8BAAiB,GAAE,CAAC;IAC7C,MAAM,QAAQ,GAAkB;QAC9B,EAAE,EAAE,WAAW,IAAI,IAAI,yBAAW,CAAC,UAAU,CAAC;QAC9C,GAAG,EAAE,cAAc,IAAI,IAAI,+BAAc,CAAC,UAAU,CAAC;QACrD,IAAI,EAAE,UAAU,IAAI,IAAI,uBAAU,CAAC,UAAU,CAAC;QAC9C,EAAE,EAAE,eAAe,IAAI,IAAI,iCAAe,CAAC,UAAU,CAAC;QACtD,EAAE,EAAE,cAAc,IAAI,IAAI,+BAAc,CAAC,UAAU,CAAC;QACpD,GAAG,EAAE,gBAAgB,IAAI,IAAI,mCAAgB,CAAC,UAAU,CAAC;QACzD,QAAQ,EAAE,UAAU;QACpB,UAAU;QACV,SAAS,EAAE,iBAAiB;KAC7B,CAAC;IACF,IAAA,iCAAmB,EAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IACnC,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAgB,gBAAgB,CAAC,IAAY,EAAE,UAAmB;IAChE,MAAM,GAAG,GAAG,cAAc,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;IACnF,IAAA,mBAAK,EACH;QACE,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,IAAI;KACL,EACD,CAAC,IAAI,EAAE,EAAE;QACP,OAAO,CAAC,GAAG,CAAC,yCAAyC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IACpE,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"agent-guide.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/agent-guide.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAmTpC,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAO7D"}
1
+ {"version":3,"file":"agent-guide.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/agent-guide.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAyTpC,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAO7D"}
@@ -49,6 +49,12 @@ agkan task count --status ready --quiet # Output number only
49
49
  # Update parent-child relationship
50
50
  agkan task update-parent <id> <parent_id>
51
51
  agkan task update-parent <id> null # Remove parent
52
+
53
+ # Copy a task
54
+ agkan task copy <id>
55
+ agkan task copy <id> --status ready # Specify destination status (default: backlog)
56
+ agkan task copy <id> --no-tags # Do not copy tags
57
+ agkan task copy <id> --json # Output in JSON format
52
58
  \`\`\`
53
59
 
54
60
  ### Blocking Relationships
@@ -1 +1 @@
1
- {"version":3,"file":"agent-guide.js","sourceRoot":"","sources":["../../../src/cli/commands/agent-guide.ts"],"names":[],"mappings":";AAAA;;GAEG;;AAqTH,wDAOC;AAxTD,MAAM,mBAAmB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+S3B,CAAC;AAEF,SAAgB,sBAAsB,CAAC,OAAgB;IACrD,OAAO;SACJ,OAAO,CAAC,aAAa,CAAC;SACtB,WAAW,CAAC,kCAAkC,CAAC;SAC/C,MAAM,CAAC,GAAG,EAAE;QACX,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;AACP,CAAC"}
1
+ {"version":3,"file":"agent-guide.js","sourceRoot":"","sources":["../../../src/cli/commands/agent-guide.ts"],"names":[],"mappings":";AAAA;;GAEG;;AA2TH,wDAOC;AA9TD,MAAM,mBAAmB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqT3B,CAAC;AAEF,SAAgB,sBAAsB,CAAC,OAAgB;IACrD,OAAO;SACJ,OAAO,CAAC,aAAa,CAAC;SACtB,WAAW,CAAC,kCAAkC,CAAC;SAC/C,MAAM,CAAC,GAAG,EAAE;QACX,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"board.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/board.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAyBxD"}
1
+ {"version":3,"file":"board.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/board.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA6MpC,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAsBxD"}