@stackmemoryai/stackmemory 0.3.6 → 0.3.8

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