@stackmemoryai/stackmemory 0.3.6 → 0.3.7

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 (213) hide show
  1. package/dist/agents/verifiers/base-verifier.js.map +2 -2
  2. package/dist/agents/verifiers/formatter-verifier.js.map +2 -2
  3. package/dist/agents/verifiers/llm-judge.js.map +2 -2
  4. package/dist/cli/claude-sm.js +24 -13
  5. package/dist/cli/claude-sm.js.map +2 -2
  6. package/dist/cli/codex-sm.js +24 -13
  7. package/dist/cli/codex-sm.js.map +2 -2
  8. package/dist/cli/commands/agent.js.map +2 -2
  9. package/dist/cli/commands/chromadb.js +217 -32
  10. package/dist/cli/commands/chromadb.js.map +2 -2
  11. package/dist/cli/commands/clear.js +12 -1
  12. package/dist/cli/commands/clear.js.map +2 -2
  13. package/dist/cli/commands/context.js +13 -2
  14. package/dist/cli/commands/context.js.map +2 -2
  15. package/dist/cli/commands/dashboard.js.map +2 -2
  16. package/dist/cli/commands/gc.js +202 -0
  17. package/dist/cli/commands/gc.js.map +7 -0
  18. package/dist/cli/commands/handoff.js +12 -1
  19. package/dist/cli/commands/handoff.js.map +2 -2
  20. package/dist/cli/commands/infinite-storage.js +32 -21
  21. package/dist/cli/commands/infinite-storage.js.map +2 -2
  22. package/dist/cli/commands/linear-create.js +13 -2
  23. package/dist/cli/commands/linear-create.js.map +2 -2
  24. package/dist/cli/commands/linear-list.js +12 -1
  25. package/dist/cli/commands/linear-list.js.map +2 -2
  26. package/dist/cli/commands/linear-migrate.js +12 -1
  27. package/dist/cli/commands/linear-migrate.js.map +2 -2
  28. package/dist/cli/commands/linear-test.js +12 -1
  29. package/dist/cli/commands/linear-test.js.map +2 -2
  30. package/dist/cli/commands/linear-unified.js +262 -0
  31. package/dist/cli/commands/linear-unified.js.map +7 -0
  32. package/dist/cli/commands/linear.js +17 -6
  33. package/dist/cli/commands/linear.js.map +2 -2
  34. package/dist/cli/commands/monitor.js.map +2 -2
  35. package/dist/cli/commands/onboard.js.map +2 -2
  36. package/dist/cli/commands/quality.js.map +2 -2
  37. package/dist/cli/commands/search.js.map +2 -2
  38. package/dist/cli/commands/session.js.map +2 -2
  39. package/dist/cli/commands/skills.js +12 -1
  40. package/dist/cli/commands/skills.js.map +2 -2
  41. package/dist/cli/commands/storage.js +18 -7
  42. package/dist/cli/commands/storage.js.map +2 -2
  43. package/dist/cli/commands/tasks.js.map +2 -2
  44. package/dist/cli/commands/tui.js +13 -2
  45. package/dist/cli/commands/tui.js.map +2 -2
  46. package/dist/cli/commands/webhook.js +14 -3
  47. package/dist/cli/commands/webhook.js.map +2 -2
  48. package/dist/cli/commands/workflow.js +14 -3
  49. package/dist/cli/commands/workflow.js.map +2 -2
  50. package/dist/cli/commands/worktree.js.map +2 -2
  51. package/dist/cli/index.js +18 -5
  52. package/dist/cli/index.js.map +2 -2
  53. package/dist/core/config/config-manager.js.map +2 -2
  54. package/dist/core/context/auto-context.js.map +2 -2
  55. package/dist/core/context/compaction-handler.js.map +2 -2
  56. package/dist/core/context/context-bridge.js.map +2 -2
  57. package/dist/core/context/dual-stack-manager.js.map +2 -2
  58. package/dist/core/context/frame-database.js.map +2 -2
  59. package/dist/core/context/frame-digest.js.map +2 -2
  60. package/dist/core/context/frame-handoff-manager.js.map +2 -2
  61. package/dist/core/context/frame-manager.js +12 -1
  62. package/dist/core/context/frame-manager.js.map +2 -2
  63. package/dist/core/context/frame-stack.js.map +2 -2
  64. package/dist/core/context/incremental-gc.js +279 -0
  65. package/dist/core/context/incremental-gc.js.map +7 -0
  66. package/dist/core/context/permission-manager.js +12 -1
  67. package/dist/core/context/permission-manager.js.map +2 -2
  68. package/dist/core/context/refactored-frame-manager.js.map +2 -2
  69. package/dist/core/context/shared-context-layer.js +12 -1
  70. package/dist/core/context/shared-context-layer.js.map +2 -2
  71. package/dist/core/context/stack-merge-resolver.js.map +2 -2
  72. package/dist/core/context/validation.js.map +2 -2
  73. package/dist/core/database/batch-operations.js.map +2 -2
  74. package/dist/core/database/connection-pool.js.map +2 -2
  75. package/dist/core/database/migration-manager.js.map +2 -2
  76. package/dist/core/database/paradedb-adapter.js.map +2 -2
  77. package/dist/core/database/query-cache.js.map +2 -2
  78. package/dist/core/database/query-router.js.map +2 -2
  79. package/dist/core/database/sqlite-adapter.js.map +2 -2
  80. package/dist/core/digest/enhanced-hybrid-digest.js.map +2 -2
  81. package/dist/core/errors/recovery.js.map +2 -2
  82. package/dist/core/merge/resolution-engine.js.map +2 -2
  83. package/dist/core/monitoring/error-handler.js.map +2 -2
  84. package/dist/core/monitoring/logger.js +14 -3
  85. package/dist/core/monitoring/logger.js.map +2 -2
  86. package/dist/core/monitoring/metrics.js +13 -2
  87. package/dist/core/monitoring/metrics.js.map +2 -2
  88. package/dist/core/monitoring/progress-tracker.js +12 -1
  89. package/dist/core/monitoring/progress-tracker.js.map +2 -2
  90. package/dist/core/monitoring/session-monitor.js.map +2 -2
  91. package/dist/core/performance/context-cache.js.map +2 -2
  92. package/dist/core/performance/lazy-context-loader.js.map +2 -2
  93. package/dist/core/performance/monitor.js.map +2 -2
  94. package/dist/core/performance/optimized-frame-context.js.map +2 -2
  95. package/dist/core/performance/performance-benchmark.js.map +2 -2
  96. package/dist/core/performance/performance-profiler.js +12 -1
  97. package/dist/core/performance/performance-profiler.js.map +2 -2
  98. package/dist/core/performance/streaming-jsonl-parser.js.map +2 -2
  99. package/dist/core/persistence/postgres-adapter.js.map +2 -2
  100. package/dist/core/projects/project-manager.js.map +2 -2
  101. package/dist/core/retrieval/context-retriever.js.map +2 -2
  102. package/dist/core/retrieval/graph-retrieval.js.map +2 -2
  103. package/dist/core/retrieval/llm-context-retrieval.js.map +2 -2
  104. package/dist/core/retrieval/retrieval-benchmarks.js.map +2 -2
  105. package/dist/core/retrieval/summary-generator.js.map +2 -2
  106. package/dist/core/session/clear-survival.js.map +2 -2
  107. package/dist/core/session/handoff-generator.js.map +2 -2
  108. package/dist/core/session/session-manager.js +16 -5
  109. package/dist/core/session/session-manager.js.map +2 -2
  110. package/dist/core/skills/skill-storage.js +13 -2
  111. package/dist/core/skills/skill-storage.js.map +2 -2
  112. package/dist/core/storage/chromadb-adapter.js.map +2 -2
  113. package/dist/core/storage/chromadb-simple.js.map +2 -2
  114. package/dist/core/storage/infinite-storage.js.map +2 -2
  115. package/dist/core/storage/railway-optimized-storage.js +19 -8
  116. package/dist/core/storage/railway-optimized-storage.js.map +2 -2
  117. package/dist/core/storage/remote-storage.js +12 -1
  118. package/dist/core/storage/remote-storage.js.map +2 -2
  119. package/dist/core/trace/cli-trace-wrapper.js +16 -5
  120. package/dist/core/trace/cli-trace-wrapper.js.map +2 -2
  121. package/dist/core/trace/db-trace-wrapper.js.map +2 -2
  122. package/dist/core/trace/debug-trace.js +21 -10
  123. package/dist/core/trace/debug-trace.js.map +2 -2
  124. package/dist/core/trace/index.js +46 -35
  125. package/dist/core/trace/index.js.map +2 -2
  126. package/dist/core/trace/trace-demo.js +12 -1
  127. package/dist/core/trace/trace-demo.js.map +2 -2
  128. package/dist/core/trace/trace-detector.js.map +2 -2
  129. package/dist/core/trace/trace-store.js.map +2 -2
  130. package/dist/core/utils/update-checker.js.map +2 -2
  131. package/dist/core/worktree/worktree-manager.js.map +2 -2
  132. package/dist/features/analytics/api/analytics-api.js.map +2 -2
  133. package/dist/features/analytics/core/analytics-service.js +12 -1
  134. package/dist/features/analytics/core/analytics-service.js.map +2 -2
  135. package/dist/features/analytics/queries/metrics-queries.js.map +2 -2
  136. package/dist/features/tasks/pebbles-task-store.js.map +2 -2
  137. package/dist/features/tui/components/analytics-panel.js.map +2 -2
  138. package/dist/features/tui/components/pr-tracker.js.map +2 -2
  139. package/dist/features/tui/components/session-monitor.js.map +2 -2
  140. package/dist/features/tui/components/subagent-fleet.js.map +2 -2
  141. package/dist/features/tui/components/task-board.js +650 -2
  142. package/dist/features/tui/components/task-board.js.map +2 -2
  143. package/dist/features/tui/index.js +16 -5
  144. package/dist/features/tui/index.js.map +2 -2
  145. package/dist/features/tui/services/data-service.js +25 -14
  146. package/dist/features/tui/services/data-service.js.map +2 -2
  147. package/dist/features/tui/services/linear-task-reader.js.map +2 -2
  148. package/dist/features/tui/services/websocket-client.js +13 -2
  149. package/dist/features/tui/services/websocket-client.js.map +2 -2
  150. package/dist/features/tui/terminal-compat.js +27 -16
  151. package/dist/features/tui/terminal-compat.js.map +2 -2
  152. package/dist/features/web/client/stores/task-store.js.map +2 -2
  153. package/dist/features/web/server/index.js +13 -2
  154. package/dist/features/web/server/index.js.map +2 -2
  155. package/dist/integrations/claude-code/enhanced-pre-clear-hooks.js.map +2 -2
  156. package/dist/integrations/claude-code/lifecycle-hooks.js.map +2 -2
  157. package/dist/integrations/claude-code/post-task-hooks.js.map +2 -2
  158. package/dist/integrations/linear/auth.js +17 -6
  159. package/dist/integrations/linear/auth.js.map +2 -2
  160. package/dist/integrations/linear/auto-sync.js.map +2 -2
  161. package/dist/integrations/linear/client.js.map +2 -2
  162. package/dist/integrations/linear/config.js.map +2 -2
  163. package/dist/integrations/linear/migration.js.map +2 -2
  164. package/dist/integrations/linear/oauth-server.js +13 -2
  165. package/dist/integrations/linear/oauth-server.js.map +2 -2
  166. package/dist/integrations/linear/rest-client.js.map +2 -2
  167. package/dist/integrations/linear/sync-enhanced.js +202 -0
  168. package/dist/integrations/linear/sync-enhanced.js.map +7 -0
  169. package/dist/integrations/linear/sync-manager.js.map +2 -2
  170. package/dist/integrations/linear/sync-service.js +12 -1
  171. package/dist/integrations/linear/sync-service.js.map +2 -2
  172. package/dist/integrations/linear/sync.js +34 -3
  173. package/dist/integrations/linear/sync.js.map +2 -2
  174. package/dist/integrations/linear/unified-sync.js +560 -0
  175. package/dist/integrations/linear/unified-sync.js.map +7 -0
  176. package/dist/integrations/linear/webhook-handler.js +12 -1
  177. package/dist/integrations/linear/webhook-handler.js.map +2 -2
  178. package/dist/integrations/linear/webhook-server.js +14 -3
  179. package/dist/integrations/linear/webhook-server.js.map +2 -2
  180. package/dist/integrations/linear/webhook.js +12 -1
  181. package/dist/integrations/linear/webhook.js.map +2 -2
  182. package/dist/integrations/mcp/handlers/context-handlers.js.map +2 -2
  183. package/dist/integrations/mcp/handlers/linear-handlers.js.map +2 -2
  184. package/dist/integrations/mcp/handlers/skill-handlers.js +13 -2
  185. package/dist/integrations/mcp/handlers/skill-handlers.js.map +2 -2
  186. package/dist/integrations/mcp/handlers/task-handlers.js.map +2 -2
  187. package/dist/integrations/mcp/handlers/trace-handlers.js.map +2 -2
  188. package/dist/integrations/mcp/middleware/tool-scoring.js.map +2 -2
  189. package/dist/integrations/mcp/refactored-server.js +15 -4
  190. package/dist/integrations/mcp/refactored-server.js.map +2 -2
  191. package/dist/integrations/mcp/server.js +12 -1
  192. package/dist/integrations/mcp/server.js.map +2 -2
  193. package/dist/integrations/mcp/tool-definitions.js.map +2 -2
  194. package/dist/integrations/pg-aiguide/embedding-provider.js +13 -2
  195. package/dist/integrations/pg-aiguide/embedding-provider.js.map +2 -2
  196. package/dist/integrations/pg-aiguide/semantic-search.js.map +2 -2
  197. package/dist/mcp/stackmemory-mcp-server.js +12 -1
  198. package/dist/mcp/stackmemory-mcp-server.js.map +2 -2
  199. package/dist/middleware/exponential-rate-limiter.js.map +2 -2
  200. package/dist/servers/production/auth-middleware.js +13 -2
  201. package/dist/servers/production/auth-middleware.js.map +2 -2
  202. package/dist/servers/railway/index.js +22 -11
  203. package/dist/servers/railway/index.js.map +2 -2
  204. package/dist/services/config-service.js.map +2 -2
  205. package/dist/services/context-service.js.map +2 -2
  206. package/dist/skills/claude-skills.js +105 -2
  207. package/dist/skills/claude-skills.js.map +2 -2
  208. package/dist/skills/dashboard-launcher.js.map +2 -2
  209. package/dist/skills/repo-ingestion-skill.js +561 -0
  210. package/dist/skills/repo-ingestion-skill.js.map +7 -0
  211. package/dist/utils/logger.js +12 -1
  212. package/dist/utils/logger.js.map +2 -2
  213. package/package.json +5 -1
@@ -87,7 +87,7 @@ class TaskBoard extends EventEmitter {
87
87
  });
88
88
  container.key(["enter"], () => {
89
89
  if (this.selectedTask) {
90
- this.showTaskDetails(this.tasks.get(this.selectedTask));
90
+ this.showTaskCompletionMenu(this.tasks.get(this.selectedTask));
91
91
  }
92
92
  });
93
93
  container.key(["n"], () => {
@@ -103,6 +103,19 @@ class TaskBoard extends EventEmitter {
103
103
  this.assignTask(this.selectedTask);
104
104
  }
105
105
  });
106
+ container.key(["u"], () => {
107
+ if (this.selectedTask) {
108
+ this.showStatusUpdateDialog(this.selectedTask);
109
+ }
110
+ });
111
+ container.key(["c"], () => {
112
+ if (this.selectedTask) {
113
+ this.startTaskWithClaude(this.selectedTask);
114
+ }
115
+ });
116
+ container.key(["s"], () => {
117
+ this.syncWithLinear();
118
+ });
106
119
  }
107
120
  getTasksInColumn(columnId) {
108
121
  return Array.from(this.tasks.values()).filter((task) => this.getTaskColumn(task) === columnId).sort((a, b) => (b.priority || 0) - (a.priority || 0));
@@ -143,8 +156,13 @@ class TaskBoard extends EventEmitter {
143
156
  assignee = "{gray-fg}unassigned{/}";
144
157
  }
145
158
  const labels = task.labels?.map((l) => `{cyan-fg}#${l}{/}`).join(" ") || "";
146
- let taskStr = `${priority} ${task.identifier}: ${task.title}
159
+ let taskStr = `${priority} {bold}${task.identifier}{/}: ${task.title}
147
160
  `;
161
+ if (task.description && task.description.trim()) {
162
+ const descPreview = task.description.split("\n")[0].substring(0, 60).trim();
163
+ taskStr += ` {gray-fg}${descPreview}${task.description.length > 60 ? "..." : ""}{/}
164
+ `;
165
+ }
148
166
  taskStr += ` {gray-fg}${assignee} ${estimate} ${labels}{/}`;
149
167
  if (task.progress !== void 0) {
150
168
  const progressBar = this.createProgressBar(task.progress);
@@ -468,6 +486,636 @@ ${task.description}
468
486
  (col) => col === this.container.screen.focused
469
487
  );
470
488
  }
489
+ showStatusUpdateDialog(taskId) {
490
+ const task = this.tasks.get(taskId);
491
+ if (!task) return;
492
+ const dialog = blessed.list({
493
+ parent: this.container.screen,
494
+ top: "center",
495
+ left: "center",
496
+ width: "50%",
497
+ height: 12,
498
+ border: {
499
+ type: "line"
500
+ },
501
+ style: {
502
+ border: {
503
+ fg: "yellow"
504
+ },
505
+ selected: {
506
+ bg: "blue",
507
+ fg: "white"
508
+ }
509
+ },
510
+ label: ` Update Status: ${task.title.substring(0, 40)}... `,
511
+ items: [
512
+ "1. Backlog",
513
+ "2. Todo",
514
+ "3. In Progress",
515
+ "4. In Review",
516
+ "5. Done",
517
+ "6. Canceled",
518
+ "",
519
+ "ESC to cancel"
520
+ ],
521
+ keys: true,
522
+ vi: true,
523
+ mouse: true
524
+ });
525
+ dialog.on("select", (item, index) => {
526
+ const statusMap = ["backlog", "todo", "in_progress", "review", "completed", "cancelled"];
527
+ if (index < statusMap.length) {
528
+ this.updateTaskStatus(taskId, statusMap[index]);
529
+ }
530
+ dialog.destroy();
531
+ this.container.screen.render();
532
+ });
533
+ dialog.key(["escape"], () => {
534
+ dialog.destroy();
535
+ this.container.screen.render();
536
+ });
537
+ dialog.focus();
538
+ this.container.screen.render();
539
+ }
540
+ async updateTaskStatus(taskId, newStatus) {
541
+ const task = this.tasks.get(taskId);
542
+ if (!task) return;
543
+ task.state = this.mapStatusToLinearState(newStatus);
544
+ this.update(Array.from(this.tasks.values()));
545
+ this.emit("task:status:update", {
546
+ taskId,
547
+ oldStatus: task.state,
548
+ newStatus,
549
+ linearId: task.identifier
550
+ });
551
+ const notification = blessed.message({
552
+ parent: this.container.screen,
553
+ top: "center",
554
+ left: "center",
555
+ width: "50%",
556
+ height: 3,
557
+ border: {
558
+ type: "line"
559
+ },
560
+ style: {
561
+ border: {
562
+ fg: "green"
563
+ }
564
+ },
565
+ content: `Task status updated to: ${newStatus}`
566
+ });
567
+ setTimeout(() => {
568
+ notification.destroy();
569
+ this.container.screen.render();
570
+ }, 1500);
571
+ this.container.screen.render();
572
+ }
573
+ async startTaskWithClaude(taskId) {
574
+ const task = this.tasks.get(taskId);
575
+ if (!task) return;
576
+ try {
577
+ const { exec } = await import("child_process");
578
+ const fs = await import("fs/promises");
579
+ const os = await import("os");
580
+ const path = await import("path");
581
+ const contextDir = path.join(os.homedir(), ".stackmemory", "task-contexts");
582
+ await fs.mkdir(contextDir, { recursive: true });
583
+ const contextFile = path.join(contextDir, `${task.identifier}-context.md`);
584
+ const contextContent = `# Task: ${task.identifier} - ${task.title}
585
+
586
+ ## Description
587
+ ${task.description || "No description provided"}
588
+
589
+ ## Status
590
+ Current: ${task.state}
591
+ Priority: ${this.getPriorityLabel(task.priority)}
592
+
593
+ ## Linear Task ID
594
+ ${task.identifier}
595
+
596
+ ## Quick Commands
597
+ - Update status: stackmemory task:update "${task.identifier}" --status <status>
598
+ - Add comment: stackmemory task:comment "${task.identifier}" --message "<comment>"
599
+ - View details: stackmemory task:show "${task.identifier}"
600
+
601
+ ---
602
+ This task has been loaded from Linear. The context above provides the task details.
603
+ Start working on this task below:
604
+ `;
605
+ await fs.writeFile(contextFile, contextContent);
606
+ const command = `claude-sm --task "${task.identifier}: ${task.title}" --context "${contextFile}"`;
607
+ const notification = blessed.message({
608
+ parent: this.container.screen,
609
+ top: "center",
610
+ left: "center",
611
+ width: "60%",
612
+ height: 5,
613
+ border: {
614
+ type: "line"
615
+ },
616
+ style: {
617
+ border: {
618
+ fg: "cyan"
619
+ }
620
+ },
621
+ content: `Launching Claude for task:
622
+ ${task.identifier}: ${task.title}
623
+
624
+ Command: ${command}`
625
+ });
626
+ this.container.screen.render();
627
+ exec(command, (error, stdout, stderr) => {
628
+ if (error) {
629
+ const errorMsg = blessed.message({
630
+ parent: this.container.screen,
631
+ top: "center",
632
+ left: "center",
633
+ width: "50%",
634
+ height: 4,
635
+ border: {
636
+ type: "line"
637
+ },
638
+ style: {
639
+ border: {
640
+ fg: "red"
641
+ }
642
+ },
643
+ content: `Failed to launch Claude: ${error.message}`
644
+ });
645
+ setTimeout(() => {
646
+ errorMsg.destroy();
647
+ this.container.screen.render();
648
+ }, 3e3);
649
+ }
650
+ });
651
+ setTimeout(() => {
652
+ notification.destroy();
653
+ this.container.screen.render();
654
+ }, 2e3);
655
+ this.emit("task:launch:claude", {
656
+ taskId,
657
+ command,
658
+ task,
659
+ contextFile
660
+ });
661
+ } catch (error) {
662
+ const errorMsg = blessed.message({
663
+ parent: this.container.screen,
664
+ top: "center",
665
+ left: "center",
666
+ width: "50%",
667
+ height: 4,
668
+ border: {
669
+ type: "line"
670
+ },
671
+ style: {
672
+ border: {
673
+ fg: "red"
674
+ }
675
+ },
676
+ content: `Error: ${error.message}`
677
+ });
678
+ setTimeout(() => {
679
+ errorMsg.destroy();
680
+ this.container.screen.render();
681
+ }, 3e3);
682
+ this.container.screen.render();
683
+ }
684
+ }
685
+ showTaskCompletionMenu(task) {
686
+ const menuBox = blessed.box({
687
+ parent: this.container.screen,
688
+ top: "center",
689
+ left: "center",
690
+ width: "70%",
691
+ height: "80%",
692
+ border: {
693
+ type: "line"
694
+ },
695
+ style: {
696
+ border: {
697
+ fg: "cyan"
698
+ }
699
+ },
700
+ label: ` Task Completion Menu: ${task.identifier} `,
701
+ keys: true,
702
+ mouse: true
703
+ });
704
+ const header = blessed.text({
705
+ parent: menuBox,
706
+ top: 1,
707
+ left: 2,
708
+ width: "100%-4",
709
+ height: 5,
710
+ content: `{bold}${task.identifier}: ${task.title}{/}
711
+
712
+ {gray-fg}${(task.description || "No description").substring(0, 200)}{/}`,
713
+ tags: true,
714
+ wrap: true
715
+ });
716
+ const statusDisplay = blessed.text({
717
+ parent: menuBox,
718
+ top: 7,
719
+ left: 2,
720
+ content: `{bold}Current Status:{/} ${this.formatStatus(task.state)}`,
721
+ tags: true
722
+ });
723
+ const menu = blessed.list({
724
+ parent: menuBox,
725
+ top: 9,
726
+ left: 2,
727
+ width: "100%-4",
728
+ height: 12,
729
+ border: {
730
+ type: "line"
731
+ },
732
+ style: {
733
+ border: {
734
+ fg: "gray"
735
+ },
736
+ selected: {
737
+ bg: "blue",
738
+ fg: "white"
739
+ }
740
+ },
741
+ label: " Quick Actions ",
742
+ items: [
743
+ "1. \u2705 Mark as Done",
744
+ "2. \u{1F504} Change Status",
745
+ "3. \u{1F3AF} Update Priority",
746
+ "4. \u{1F464} Assign to Someone",
747
+ "5. \u{1F4AC} Add Comment",
748
+ "6. \u{1F4DD} Edit Description",
749
+ "7. \u{1F680} Start with Claude",
750
+ "8. \u{1F50D} View Full Details",
751
+ "9. \u274C Cancel Task"
752
+ ],
753
+ keys: true,
754
+ vi: true,
755
+ mouse: true
756
+ });
757
+ const metadata = blessed.text({
758
+ parent: menuBox,
759
+ bottom: 3,
760
+ left: 2,
761
+ width: "100%-4",
762
+ height: 4,
763
+ content: this.formatTaskMetadata(task),
764
+ tags: true
765
+ });
766
+ const instructions = blessed.text({
767
+ parent: menuBox,
768
+ bottom: 1,
769
+ left: 2,
770
+ content: "{gray-fg}Use arrows/numbers to select \u2022 Enter to execute \u2022 ESC to close{/}",
771
+ tags: true
772
+ });
773
+ menu.on("select", (item, index) => {
774
+ menuBox.destroy();
775
+ switch (index) {
776
+ case 0:
777
+ this.updateTaskStatus(task.id, "completed");
778
+ this.showNotification(`\u2705 Task ${task.identifier} marked as done`);
779
+ break;
780
+ case 1:
781
+ this.showStatusUpdateDialog(task.id);
782
+ break;
783
+ case 2:
784
+ this.showPriorityUpdateDialog(task);
785
+ break;
786
+ case 3:
787
+ this.showAssignDialog(task);
788
+ break;
789
+ case 4:
790
+ this.showCommentDialog(task);
791
+ break;
792
+ case 5:
793
+ this.showEditDescriptionDialog(task);
794
+ break;
795
+ case 6:
796
+ this.startTaskWithClaude(task.id);
797
+ break;
798
+ case 7:
799
+ this.showTaskDetails(task);
800
+ break;
801
+ case 8:
802
+ this.updateTaskStatus(task.id, "canceled");
803
+ this.showNotification(`\u274C Task ${task.identifier} canceled`);
804
+ break;
805
+ }
806
+ this.container.screen.render();
807
+ });
808
+ menu.key(["1", "2", "3", "4", "5", "6", "7", "8", "9"], (ch) => {
809
+ const index = parseInt(ch, 10) - 1;
810
+ if (index < menu.items.length) {
811
+ menu.select(index);
812
+ menu.emit("select", menu.items[index], index);
813
+ }
814
+ });
815
+ menuBox.key(["escape", "q"], () => {
816
+ menuBox.destroy();
817
+ this.container.screen.render();
818
+ });
819
+ menu.focus();
820
+ this.container.screen.render();
821
+ }
822
+ formatStatus(state) {
823
+ const statusColors = {
824
+ backlog: "{gray-fg}\u{1F4CB} Backlog{/}",
825
+ unstarted: "{yellow-fg}\u23F8\uFE0F Todo{/}",
826
+ started: "{blue-fg}\u25B6\uFE0F In Progress{/}",
827
+ completed: "{green-fg}\u2705 Done{/}",
828
+ canceled: "{red-fg}\u274C Canceled{/}"
829
+ };
830
+ return statusColors[state.toLowerCase()] || state;
831
+ }
832
+ formatTaskMetadata(task) {
833
+ let meta = "";
834
+ if (task.assignee) {
835
+ const name = typeof task.assignee === "string" ? task.assignee : task.assignee.name;
836
+ meta += `{bold}Assignee:{/} ${name} `;
837
+ }
838
+ if (task.priority !== void 0) {
839
+ meta += `{bold}Priority:{/} ${this.getPriorityLabel(task.priority)} `;
840
+ }
841
+ if (task.estimate) {
842
+ meta += `{bold}Points:{/} ${task.estimate} `;
843
+ }
844
+ if (task.dueDate) {
845
+ const daysUntil = this.getDaysUntilDue(task.dueDate);
846
+ const color = daysUntil < 0 ? "red" : daysUntil <= 1 ? "yellow" : "white";
847
+ meta += `{bold}Due:{/} {${color}-fg}${new Date(task.dueDate).toLocaleDateString()}{/}`;
848
+ }
849
+ return meta;
850
+ }
851
+ getPriorityLabel(priority) {
852
+ if (priority === void 0 || priority === null) return "None";
853
+ const labels = ["Urgent", "High", "Medium", "Low", "None"];
854
+ return labels[priority] || "None";
855
+ }
856
+ showPriorityUpdateDialog(task) {
857
+ const dialog = blessed.list({
858
+ parent: this.container.screen,
859
+ top: "center",
860
+ left: "center",
861
+ width: "40%",
862
+ height: 9,
863
+ border: {
864
+ type: "line"
865
+ },
866
+ style: {
867
+ border: {
868
+ fg: "magenta"
869
+ },
870
+ selected: {
871
+ bg: "magenta",
872
+ fg: "white"
873
+ }
874
+ },
875
+ label: ` Set Priority: ${task.identifier} `,
876
+ items: [
877
+ "\u{1F534} Urgent (P0)",
878
+ "\u{1F7E1} High (P1)",
879
+ "\u{1F7E2} Medium (P2)",
880
+ "\u{1F535} Low (P3)",
881
+ "\u26AA None"
882
+ ],
883
+ keys: true,
884
+ vi: true
885
+ });
886
+ dialog.on("select", (item, index) => {
887
+ const priority = index < 4 ? index : void 0;
888
+ this.emit("task:update", {
889
+ taskId: task.id,
890
+ updates: { priority }
891
+ });
892
+ dialog.destroy();
893
+ this.showNotification(`\u{1F3AF} Priority updated for ${task.identifier}`);
894
+ this.container.screen.render();
895
+ });
896
+ dialog.key(["escape"], () => {
897
+ dialog.destroy();
898
+ this.container.screen.render();
899
+ });
900
+ dialog.focus();
901
+ this.container.screen.render();
902
+ }
903
+ showAssignDialog(task) {
904
+ this.showNotification("Assignment dialog coming soon!");
905
+ }
906
+ showCommentDialog(task) {
907
+ const form = blessed.form({
908
+ parent: this.container.screen,
909
+ top: "center",
910
+ left: "center",
911
+ width: "60%",
912
+ height: 10,
913
+ border: {
914
+ type: "line"
915
+ },
916
+ style: {
917
+ border: {
918
+ fg: "green"
919
+ }
920
+ },
921
+ label: ` Add Comment to ${task.identifier} `,
922
+ keys: true
923
+ });
924
+ const commentInput = blessed.textarea({
925
+ parent: form,
926
+ top: 1,
927
+ left: 1,
928
+ width: "100%-2",
929
+ height: 5,
930
+ inputOnFocus: true,
931
+ style: {
932
+ focus: {
933
+ fg: "white",
934
+ bg: "blue"
935
+ }
936
+ }
937
+ });
938
+ const submitBtn = blessed.button({
939
+ parent: form,
940
+ content: " Add Comment ",
941
+ bottom: 1,
942
+ left: "center",
943
+ shrink: true,
944
+ style: {
945
+ focus: {
946
+ bg: "green",
947
+ fg: "white"
948
+ }
949
+ }
950
+ });
951
+ submitBtn.on("press", () => {
952
+ const comment = commentInput.getValue();
953
+ if (comment) {
954
+ this.emit("task:comment", { taskId: task.id, comment });
955
+ this.showNotification(`\u{1F4AC} Comment added to ${task.identifier}`);
956
+ }
957
+ form.destroy();
958
+ this.container.screen.render();
959
+ });
960
+ form.key(["escape"], () => {
961
+ form.destroy();
962
+ this.container.screen.render();
963
+ });
964
+ commentInput.focus();
965
+ this.container.screen.render();
966
+ }
967
+ showEditDescriptionDialog(task) {
968
+ const form = blessed.form({
969
+ parent: this.container.screen,
970
+ top: "center",
971
+ left: "center",
972
+ width: "70%",
973
+ height: 15,
974
+ border: {
975
+ type: "line"
976
+ },
977
+ style: {
978
+ border: {
979
+ fg: "cyan"
980
+ }
981
+ },
982
+ label: ` Edit Description: ${task.identifier} `,
983
+ keys: true
984
+ });
985
+ const descInput = blessed.textarea({
986
+ parent: form,
987
+ top: 1,
988
+ left: 1,
989
+ width: "100%-2",
990
+ height: 10,
991
+ inputOnFocus: true,
992
+ content: task.description || "",
993
+ style: {
994
+ focus: {
995
+ fg: "white",
996
+ bg: "blue"
997
+ }
998
+ }
999
+ });
1000
+ const submitBtn = blessed.button({
1001
+ parent: form,
1002
+ content: " Save Description ",
1003
+ bottom: 1,
1004
+ left: "center",
1005
+ shrink: true,
1006
+ style: {
1007
+ focus: {
1008
+ bg: "cyan",
1009
+ fg: "white"
1010
+ }
1011
+ }
1012
+ });
1013
+ submitBtn.on("press", () => {
1014
+ const description = descInput.getValue();
1015
+ this.emit("task:update", {
1016
+ taskId: task.id,
1017
+ updates: { description }
1018
+ });
1019
+ this.showNotification(`\u{1F4DD} Description updated for ${task.identifier}`);
1020
+ form.destroy();
1021
+ this.container.screen.render();
1022
+ });
1023
+ form.key(["escape"], () => {
1024
+ form.destroy();
1025
+ this.container.screen.render();
1026
+ });
1027
+ descInput.focus();
1028
+ this.container.screen.render();
1029
+ }
1030
+ showNotification(message) {
1031
+ const notification = blessed.box({
1032
+ parent: this.container.screen,
1033
+ top: 1,
1034
+ right: 1,
1035
+ width: message.length + 4,
1036
+ height: 3,
1037
+ content: ` ${message} `,
1038
+ style: {
1039
+ fg: "white",
1040
+ bg: "blue"
1041
+ },
1042
+ border: {
1043
+ type: "line",
1044
+ fg: "cyan"
1045
+ }
1046
+ });
1047
+ this.container.screen.render();
1048
+ setTimeout(() => {
1049
+ notification.destroy();
1050
+ this.container.screen.render();
1051
+ }, 3e3);
1052
+ }
1053
+ async syncWithLinear() {
1054
+ try {
1055
+ const notification = blessed.box({
1056
+ parent: this.container.screen,
1057
+ top: "center",
1058
+ left: "center",
1059
+ width: "40%",
1060
+ height: 5,
1061
+ border: {
1062
+ type: "line"
1063
+ },
1064
+ style: {
1065
+ border: {
1066
+ fg: "cyan"
1067
+ }
1068
+ },
1069
+ content: "{center}Syncing with Linear...{/center}",
1070
+ tags: true
1071
+ });
1072
+ this.container.screen.render();
1073
+ const { exec } = await import("child_process");
1074
+ const util = await import("util");
1075
+ const execAsync = util.promisify(exec);
1076
+ await execAsync("cd /Users/jwu/Dev/stackmemory && npm run linear:sync");
1077
+ notification.setContent("{center}\u2713 Sync complete! Refreshing...{/center}");
1078
+ notification.style.border.fg = "green";
1079
+ setTimeout(() => {
1080
+ notification.destroy();
1081
+ this.emit("tasks:refresh");
1082
+ this.container.screen.render();
1083
+ }, 1e3);
1084
+ } catch (error) {
1085
+ const errorMsg = blessed.message({
1086
+ parent: this.container.screen,
1087
+ top: "center",
1088
+ left: "center",
1089
+ width: "50%",
1090
+ height: 4,
1091
+ border: {
1092
+ type: "line"
1093
+ },
1094
+ style: {
1095
+ border: {
1096
+ fg: "red"
1097
+ }
1098
+ },
1099
+ content: `Sync failed: ${error.message}`
1100
+ });
1101
+ setTimeout(() => {
1102
+ errorMsg.destroy();
1103
+ this.container.screen.render();
1104
+ }, 3e3);
1105
+ this.container.screen.render();
1106
+ }
1107
+ }
1108
+ mapStatusToLinearState(status) {
1109
+ const mapping = {
1110
+ "backlog": "Backlog",
1111
+ "todo": "Todo",
1112
+ "in_progress": "In Progress",
1113
+ "review": "In Review",
1114
+ "completed": "Done",
1115
+ "cancelled": "Canceled"
1116
+ };
1117
+ return mapping[status] || "Backlog";
1118
+ }
471
1119
  }
472
1120
  export {
473
1121
  TaskBoard