@stackmemoryai/stackmemory 0.3.17 → 0.3.19

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 (234) hide show
  1. package/dist/cli/claude-sm.js +51 -5
  2. package/dist/cli/claude-sm.js.map +2 -2
  3. package/dist/cli/codex-sm.js +52 -19
  4. package/dist/cli/codex-sm.js.map +2 -2
  5. package/dist/cli/commands/db.js +143 -0
  6. package/dist/cli/commands/db.js.map +7 -0
  7. package/dist/cli/commands/login.js +50 -0
  8. package/dist/cli/commands/login.js.map +7 -0
  9. package/dist/cli/commands/migrate.js +178 -0
  10. package/dist/cli/commands/migrate.js.map +7 -0
  11. package/dist/cli/commands/onboard.js +158 -2
  12. package/dist/cli/commands/onboard.js.map +2 -2
  13. package/dist/cli/commands/skills.js +15 -2
  14. package/dist/cli/commands/skills.js.map +2 -2
  15. package/dist/cli/index.js +118 -834
  16. package/dist/cli/index.js.map +3 -3
  17. package/dist/core/context/dual-stack-manager.js +1 -1
  18. package/dist/core/context/dual-stack-manager.js.map +1 -1
  19. package/dist/core/context/frame-database.js +1 -0
  20. package/dist/core/context/frame-database.js.map +2 -2
  21. package/dist/core/context/frame-manager.js +59 -2
  22. package/dist/core/context/frame-manager.js.map +2 -2
  23. package/dist/core/database/database-adapter.js +6 -1
  24. package/dist/core/database/database-adapter.js.map +2 -2
  25. package/dist/core/database/sqlite-adapter.js +60 -2
  26. package/dist/core/database/sqlite-adapter.js.map +2 -2
  27. package/dist/integrations/claude-code/subagent-client.js +106 -3
  28. package/dist/integrations/claude-code/subagent-client.js.map +2 -2
  29. package/dist/servers/railway/config.js +51 -0
  30. package/dist/servers/railway/config.js.map +7 -0
  31. package/dist/servers/railway/index-enhanced.js +156 -0
  32. package/dist/servers/railway/index-enhanced.js.map +7 -0
  33. package/dist/servers/railway/index.js +843 -82
  34. package/dist/servers/railway/index.js.map +3 -3
  35. package/dist/servers/railway/minimal.js +48 -3
  36. package/dist/servers/railway/minimal.js.map +2 -2
  37. package/dist/servers/railway/storage-test.js +455 -0
  38. package/dist/servers/railway/storage-test.js.map +7 -0
  39. package/dist/skills/claude-skills.js +13 -12
  40. package/dist/skills/claude-skills.js.map +2 -2
  41. package/dist/skills/recursive-agent-orchestrator.js +27 -18
  42. package/dist/skills/recursive-agent-orchestrator.js.map +2 -2
  43. package/dist/skills/unified-rlm-orchestrator.js.map +2 -2
  44. package/package.json +13 -21
  45. package/scripts/README-TESTING.md +186 -0
  46. package/scripts/analyze-cli-security.js +288 -0
  47. package/scripts/archive/add-phase-tasks-to-linear.js +163 -0
  48. package/scripts/archive/analyze-linear-duplicates.js +214 -0
  49. package/scripts/archive/analyze-remaining-duplicates.js +230 -0
  50. package/scripts/archive/analyze-sta-duplicates.js +292 -0
  51. package/scripts/archive/analyze-sta-graphql.js +399 -0
  52. package/scripts/archive/cancel-duplicate-tasks.ts +246 -0
  53. package/scripts/archive/check-all-duplicates.ts +419 -0
  54. package/scripts/archive/clean-duplicate-tasks.js +114 -0
  55. package/scripts/archive/cleanup-duplicate-tasks.ts +286 -0
  56. package/scripts/archive/create-phase-tasks.js +387 -0
  57. package/scripts/archive/delete-linear-duplicates.js +182 -0
  58. package/scripts/archive/delete-remaining-duplicates.js +158 -0
  59. package/scripts/archive/delete-sta-duplicates.js +201 -0
  60. package/scripts/archive/delete-sta-oauth.js +201 -0
  61. package/scripts/archive/export-sta-tasks.js +62 -0
  62. package/scripts/archive/install-auto-sync.js +266 -0
  63. package/scripts/archive/install-chromadb-hooks.sh +133 -0
  64. package/scripts/archive/install-enhanced-clear-hooks.sh +431 -0
  65. package/scripts/archive/install-post-task-hooks.sh +289 -0
  66. package/scripts/archive/install-stackmemory-hooks.sh +420 -0
  67. package/scripts/archive/merge-linear-duplicates-safe.ts +362 -0
  68. package/scripts/archive/merge-linear-duplicates.ts +180 -0
  69. package/scripts/archive/remove-sta-tasks.js +70 -0
  70. package/scripts/archive/setup-background-sync.sh +168 -0
  71. package/scripts/archive/setup-claude-auto-triggers.sh +181 -0
  72. package/scripts/archive/setup-claude-autostart.sh +305 -0
  73. package/scripts/archive/setup-git-hooks.sh +25 -0
  74. package/scripts/archive/setup-linear-oauth.sh +46 -0
  75. package/scripts/archive/setup-mcp.sh +113 -0
  76. package/scripts/archive/setup-railway-deployment.sh +81 -0
  77. package/scripts/auto-handoff.sh +262 -0
  78. package/scripts/background-sync-manager.js +416 -0
  79. package/scripts/benchmark-performance.ts +57 -0
  80. package/scripts/check-redis.ts +48 -0
  81. package/scripts/chromadb-auto-loader.sh +128 -0
  82. package/scripts/chromadb-context-loader.js +479 -0
  83. package/scripts/claude-chromadb-hook.js +460 -0
  84. package/scripts/claude-code-wrapper.sh +66 -0
  85. package/scripts/claude-linear-skill.js +455 -0
  86. package/scripts/claude-pre-commit.sh +302 -0
  87. package/scripts/claude-sm-autostart.js +532 -0
  88. package/scripts/claude-sm-setup.sh +367 -0
  89. package/scripts/claude-with-chromadb.sh +69 -0
  90. package/scripts/claude-worktree-manager.sh +323 -0
  91. package/scripts/claude-worktree-monitor.sh +371 -0
  92. package/scripts/claude-worktree-setup.sh +327 -0
  93. package/scripts/clean-linear-backlog.js +273 -0
  94. package/scripts/cleanup-old-sessions.sh +57 -0
  95. package/scripts/codex-wrapper.sh +88 -0
  96. package/scripts/create-sandbox.sh +269 -0
  97. package/scripts/debug-linear-update.js +174 -0
  98. package/scripts/delete-linear-tasks.js +167 -0
  99. package/scripts/deploy.sh +89 -0
  100. package/scripts/deployment/railway.sh +352 -0
  101. package/scripts/deployment/test-deployment.js +194 -0
  102. package/scripts/detect-and-rehydrate.js +162 -0
  103. package/scripts/detect-and-rehydrate.mjs +165 -0
  104. package/scripts/development/create-demo-tasks.js +143 -0
  105. package/scripts/development/debug-frame-test.js +16 -0
  106. package/scripts/development/demo-auto-sync.js +128 -0
  107. package/scripts/development/fix-all-imports.js +213 -0
  108. package/scripts/development/fix-imports.js +229 -0
  109. package/scripts/development/fix-lint-loop.cjs +103 -0
  110. package/scripts/development/fix-project-id.ts +161 -0
  111. package/scripts/development/fix-strict-mode-issues.ts +291 -0
  112. package/scripts/development/reorganize-structure.sh +228 -0
  113. package/scripts/development/test-persistence-direct.js +148 -0
  114. package/scripts/development/test-persistence.js +114 -0
  115. package/scripts/development/test-tasks.js +93 -0
  116. package/scripts/development/update-imports.js +212 -0
  117. package/scripts/fetch-linear-status.js +125 -0
  118. package/scripts/git-hooks/README.md +310 -0
  119. package/scripts/git-hooks/branch-context-manager.sh +342 -0
  120. package/scripts/git-hooks/post-checkout-stackmemory.sh +63 -0
  121. package/scripts/git-hooks/post-commit-stackmemory.sh +305 -0
  122. package/scripts/git-hooks/pre-commit-stackmemory.sh +275 -0
  123. package/scripts/hooks/cleanup-shell.sh +130 -0
  124. package/scripts/hooks/task-complete.sh +114 -0
  125. package/scripts/initialize.ts +129 -0
  126. package/scripts/install-claude-hooks-auto.js +104 -0
  127. package/scripts/install-claude-hooks.sh +133 -0
  128. package/scripts/install-global.sh +296 -0
  129. package/scripts/install.sh +235 -0
  130. package/scripts/linear-auto-sync.js +262 -0
  131. package/scripts/linear-auto-sync.sh +161 -0
  132. package/scripts/linear-sync-daemon.js +150 -0
  133. package/scripts/linear-task-review.js +237 -0
  134. package/scripts/list-linear-tasks.ts +178 -0
  135. package/scripts/mcp-proxy.js +66 -0
  136. package/scripts/opencode-wrapper.sh +85 -0
  137. package/scripts/publish-local.js +74 -0
  138. package/scripts/query-chromadb.ts +201 -0
  139. package/scripts/railway-env-setup.sh +39 -0
  140. package/scripts/reconcile-local-tasks.js +170 -0
  141. package/scripts/recreate-frames-db.js +89 -0
  142. package/scripts/setup/claude-integration.js +138 -0
  143. package/scripts/setup/configure-alias.js +125 -0
  144. package/scripts/setup/configure-codex-alias.js +161 -0
  145. package/scripts/setup/configure-opencode-alias.js +175 -0
  146. package/scripts/setup-claude-integration.js +204 -0
  147. package/scripts/setup-claude-integration.sh +183 -0
  148. package/scripts/setup-railway-deployment.sh +37 -0
  149. package/scripts/setup.sh +31 -0
  150. package/scripts/show-linear-summary.ts +172 -0
  151. package/scripts/stackmemory-auto-handoff.sh +231 -0
  152. package/scripts/stackmemory-daemon.sh +40 -0
  153. package/scripts/start-linear-sync-daemon.sh +141 -0
  154. package/scripts/start-temporal-paradox.sh +214 -0
  155. package/scripts/status.ts +159 -0
  156. package/scripts/sync-and-clean-tasks.js +258 -0
  157. package/scripts/sync-frames-from-railway.js +228 -0
  158. package/scripts/sync-linear-graphql.js +303 -0
  159. package/scripts/sync-linear-tasks.js +186 -0
  160. package/scripts/test-auto-triggers.sh +57 -0
  161. package/scripts/test-browser-mcp.js +74 -0
  162. package/scripts/test-chromadb-full.js +115 -0
  163. package/scripts/test-chromadb-hooks.sh +28 -0
  164. package/scripts/test-chromadb-sync.ts +245 -0
  165. package/scripts/test-cli-security.js +293 -0
  166. package/scripts/test-hooks-persistence.sh +220 -0
  167. package/scripts/test-installation-scenarios.sh +359 -0
  168. package/scripts/test-installation.sh +224 -0
  169. package/scripts/test-mcp.js +163 -0
  170. package/scripts/test-pre-publish-quick.sh +75 -0
  171. package/scripts/test-quality-gates.sh +263 -0
  172. package/scripts/test-railway-db.js +222 -0
  173. package/scripts/test-redis-storage.ts +490 -0
  174. package/scripts/test-rlm-basic.sh +122 -0
  175. package/scripts/test-rlm-comprehensive.sh +260 -0
  176. package/scripts/test-rlm-e2e.sh +268 -0
  177. package/scripts/test-rlm-simple.js +90 -0
  178. package/scripts/test-rlm.js +110 -0
  179. package/scripts/test-session-handoff.sh +165 -0
  180. package/scripts/test-shell-integration.sh +275 -0
  181. package/scripts/testing/ab-test-runner.ts +508 -0
  182. package/scripts/testing/collect-metrics.ts +457 -0
  183. package/scripts/testing/quick-effectiveness-demo.js +187 -0
  184. package/scripts/testing/real-performance-test.js +422 -0
  185. package/scripts/testing/run-effectiveness-tests.sh +176 -0
  186. package/scripts/testing/scripts/testing/ab-test-runner.js +363 -0
  187. package/scripts/testing/scripts/testing/collect-metrics.js +292 -0
  188. package/scripts/testing/simple-effectiveness-test.js +310 -0
  189. package/scripts/testing/src/core/context/context-bridge.js +253 -0
  190. package/scripts/testing/src/core/context/frame-manager.js +746 -0
  191. package/scripts/testing/src/core/context/shared-context-layer.js +437 -0
  192. package/scripts/testing/src/core/database/database-adapter.js +54 -0
  193. package/scripts/testing/src/core/errors/index.js +291 -0
  194. package/scripts/testing/src/core/errors/recovery.js +268 -0
  195. package/scripts/testing/src/core/monitoring/logger.js +145 -0
  196. package/scripts/testing/src/core/retrieval/context-retriever.js +516 -0
  197. package/scripts/testing/src/core/session/index.js +1 -0
  198. package/scripts/testing/src/core/session/session-manager.js +323 -0
  199. package/scripts/testing/src/core/trace/cli-trace-wrapper.js +140 -0
  200. package/scripts/testing/src/core/trace/db-trace-wrapper.js +251 -0
  201. package/scripts/testing/src/core/trace/debug-trace.js +398 -0
  202. package/scripts/testing/src/core/trace/index.js +120 -0
  203. package/scripts/testing/src/core/trace/linear-api-wrapper.js +204 -0
  204. package/scripts/update-linear-status.js +268 -0
  205. package/scripts/update-linear-tasks-fixed.js +284 -0
  206. package/scripts/verify-railway-schema.ts +35 -0
  207. package/templates/claude-hooks/hooks.json +5 -0
  208. package/templates/claude-hooks/on-clear.js +56 -0
  209. package/templates/claude-hooks/on-startup.js +56 -0
  210. package/templates/claude-hooks/tool-use-trace.js +67 -0
  211. package/dist/features/tui/components/analytics-panel.js +0 -157
  212. package/dist/features/tui/components/analytics-panel.js.map +0 -7
  213. package/dist/features/tui/components/frame-visualizer.js +0 -377
  214. package/dist/features/tui/components/frame-visualizer.js.map +0 -7
  215. package/dist/features/tui/components/pr-tracker.js +0 -135
  216. package/dist/features/tui/components/pr-tracker.js.map +0 -7
  217. package/dist/features/tui/components/session-monitor.js +0 -299
  218. package/dist/features/tui/components/session-monitor.js.map +0 -7
  219. package/dist/features/tui/components/subagent-fleet.js +0 -395
  220. package/dist/features/tui/components/subagent-fleet.js.map +0 -7
  221. package/dist/features/tui/components/task-board.js +0 -1139
  222. package/dist/features/tui/components/task-board.js.map +0 -7
  223. package/dist/features/tui/index.js +0 -408
  224. package/dist/features/tui/index.js.map +0 -7
  225. package/dist/features/tui/services/data-service.js +0 -641
  226. package/dist/features/tui/services/data-service.js.map +0 -7
  227. package/dist/features/tui/services/linear-task-reader.js +0 -102
  228. package/dist/features/tui/services/linear-task-reader.js.map +0 -7
  229. package/dist/features/tui/services/websocket-client.js +0 -162
  230. package/dist/features/tui/services/websocket-client.js.map +0 -7
  231. package/dist/features/tui/terminal-compat.js +0 -220
  232. package/dist/features/tui/terminal-compat.js.map +0 -7
  233. package/dist/features/tui/types.js +0 -1
  234. package/dist/features/tui/types.js.map +0 -7
@@ -1,1139 +0,0 @@
1
- import blessed from "blessed";
2
- import { EventEmitter } from "events";
3
- class TaskBoard extends EventEmitter {
4
- container;
5
- columns;
6
- tasks;
7
- selectedTask = null;
8
- currentColumn = "todo";
9
- columnConfig = [
10
- { id: "backlog", title: "Backlog", color: "gray" },
11
- { id: "todo", title: "To Do", color: "cyan" },
12
- { id: "in_progress", title: "In Progress", color: "yellow" },
13
- { id: "review", title: "Review", color: "magenta" },
14
- { id: "done", title: "Done", color: "green" }
15
- ];
16
- constructor(container) {
17
- super();
18
- this.container = container;
19
- this.columns = /* @__PURE__ */ new Map();
20
- this.tasks = /* @__PURE__ */ new Map();
21
- this.initializeUI();
22
- }
23
- initializeUI() {
24
- const columnWidth = Math.floor(100 / this.columnConfig.length);
25
- this.columnConfig.forEach((column, index) => {
26
- const columnBox = blessed.box({
27
- parent: this.container,
28
- left: `${index * columnWidth}%`,
29
- top: 0,
30
- width: `${columnWidth}%`,
31
- height: "100%",
32
- border: {
33
- type: "line"
34
- },
35
- style: {
36
- border: {
37
- fg: column.color
38
- }
39
- },
40
- label: ` ${column.title} `
41
- });
42
- const taskList = blessed.list({
43
- parent: columnBox,
44
- top: 0,
45
- left: 0,
46
- width: "100%-2",
47
- height: "100%-2",
48
- style: {
49
- selected: {
50
- bg: column.color,
51
- fg: "black",
52
- bold: true
53
- },
54
- item: {
55
- fg: "white"
56
- }
57
- },
58
- mouse: true,
59
- keys: true,
60
- vi: true,
61
- scrollable: true,
62
- tags: true
63
- });
64
- taskList.on("select", (item, index2) => {
65
- const tasksInColumn = this.getTasksInColumn(column.id);
66
- if (tasksInColumn[index2]) {
67
- this.selectTask(tasksInColumn[index2].id);
68
- }
69
- });
70
- this.columns.set(column.id, taskList);
71
- });
72
- this.setupKeyboardNavigation();
73
- }
74
- setupKeyboardNavigation() {
75
- const container = this.container;
76
- container.key(["left", "h"], () => {
77
- this.navigateColumn(-1);
78
- });
79
- container.key(["right", "l"], () => {
80
- this.navigateColumn(1);
81
- });
82
- container.key(["S-left"], () => {
83
- this.moveTaskToColumn(-1);
84
- });
85
- container.key(["S-right"], () => {
86
- this.moveTaskToColumn(1);
87
- });
88
- container.key(["enter"], () => {
89
- if (this.selectedTask) {
90
- this.showTaskCompletionMenu(this.tasks.get(this.selectedTask));
91
- }
92
- });
93
- container.key(["n"], () => {
94
- this.createNewTask();
95
- });
96
- container.key(["d"], () => {
97
- if (this.selectedTask) {
98
- this.markTaskDone(this.selectedTask);
99
- }
100
- });
101
- container.key(["a"], () => {
102
- if (this.selectedTask) {
103
- this.assignTask(this.selectedTask);
104
- }
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
- });
119
- }
120
- getTasksInColumn(columnId) {
121
- return Array.from(this.tasks.values()).filter((task) => this.getTaskColumn(task) === columnId).sort((a, b) => (b.priority || 0) - (a.priority || 0));
122
- }
123
- getTaskColumn(task) {
124
- const stateMapping = {
125
- // Raw Linear API states
126
- backlog: "backlog",
127
- unstarted: "todo",
128
- started: "in_progress",
129
- completed: "done",
130
- canceled: "done",
131
- cancelled: "done",
132
- // Formatted display states from data service
133
- Backlog: "backlog",
134
- "To Do": "todo",
135
- "In Progress": "in_progress",
136
- Done: "done",
137
- Canceled: "done",
138
- // Legacy mappings
139
- todo: "todo",
140
- in_progress: "in_progress",
141
- in_review: "review",
142
- done: "done"
143
- };
144
- const state = task.state || "todo";
145
- return stateMapping[state] || stateMapping[state.toLowerCase()] || "todo";
146
- }
147
- formatTaskItem(task) {
148
- const priority = this.getPriorityIcon(task.priority);
149
- const estimate = task.estimate ? `[${task.estimate}]` : "";
150
- let assignee;
151
- if (typeof task.assignee === "string") {
152
- assignee = `@${task.assignee}`;
153
- } else if (task.assignee?.name) {
154
- assignee = `@${task.assignee.name}`;
155
- } else {
156
- assignee = "{gray-fg}unassigned{/}";
157
- }
158
- const labels = task.labels?.map((l) => `{cyan-fg}#${l}{/}`).join(" ") || "";
159
- let taskStr = `${priority} {bold}${task.identifier}{/}: ${task.title}
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
- }
166
- taskStr += ` {gray-fg}${assignee} ${estimate} ${labels}{/}`;
167
- if (task.progress !== void 0) {
168
- const progressBar = this.createProgressBar(task.progress);
169
- taskStr += `
170
- ${progressBar}`;
171
- }
172
- if (task.dueDate) {
173
- const daysUntilDue = this.getDaysUntilDue(task.dueDate);
174
- if (daysUntilDue < 0) {
175
- taskStr += ` {red-fg}\u26A0 Overdue{/}`;
176
- } else if (daysUntilDue <= 1) {
177
- taskStr += ` {yellow-fg}\u26A0 Due soon{/}`;
178
- }
179
- }
180
- return taskStr;
181
- }
182
- getPriorityIcon(priority) {
183
- if (!priority) return "\u25CB";
184
- switch (priority) {
185
- case 0:
186
- return "{red-fg}\u{1F534}{/}";
187
- // Urgent
188
- case 1:
189
- return "{yellow-fg}\u{1F7E1}{/}";
190
- // High
191
- case 2:
192
- return "{green-fg}\u{1F7E2}{/}";
193
- // Medium
194
- case 3:
195
- return "{blue-fg}\u{1F535}{/}";
196
- // Low
197
- default:
198
- return "\u25CB";
199
- }
200
- }
201
- createProgressBar(progress) {
202
- const width = 10;
203
- const filled = Math.round(progress * width);
204
- const empty = width - filled;
205
- const color = progress >= 1 ? "green" : progress >= 0.5 ? "yellow" : "red";
206
- return `{${color}-fg}${"\u2588".repeat(filled)}{/}{gray-fg}${"\u2591".repeat(empty)}{/} ${Math.round(progress * 100)}%`;
207
- }
208
- getDaysUntilDue(dueDate) {
209
- const due = new Date(dueDate);
210
- const now = /* @__PURE__ */ new Date();
211
- const diffTime = due.getTime() - now.getTime();
212
- return Math.ceil(diffTime / (1e3 * 60 * 60 * 24));
213
- }
214
- update(tasks) {
215
- this.tasks.clear();
216
- tasks.forEach((task) => {
217
- this.tasks.set(task.id, task);
218
- });
219
- this.columnConfig.forEach((column) => {
220
- const columnTasks = this.getTasksInColumn(column.id);
221
- const items = columnTasks.map((task) => this.formatTaskItem(task));
222
- const list = this.columns.get(column.id);
223
- if (list) {
224
- list.setItems(items);
225
- const parent = list.parent;
226
- if (parent && typeof parent.setLabel === "function") {
227
- parent.setLabel(` ${column.title} (${columnTasks.length}) `);
228
- }
229
- }
230
- });
231
- this.container.screen.render();
232
- }
233
- navigateColumn(direction) {
234
- const columnIds = this.columnConfig.map((c) => c.id);
235
- const currentIndex = columnIds.indexOf(this.currentColumn);
236
- const newIndex = Math.max(
237
- 0,
238
- Math.min(columnIds.length - 1, currentIndex + direction)
239
- );
240
- this.currentColumn = columnIds[newIndex];
241
- this.columns.get(this.currentColumn)?.focus();
242
- this.container.screen.render();
243
- }
244
- moveTaskToColumn(direction) {
245
- if (!this.selectedTask) return;
246
- const task = this.tasks.get(this.selectedTask);
247
- if (!task) return;
248
- const columnIds = this.columnConfig.map((c) => c.id);
249
- const currentColumnIndex = columnIds.indexOf(this.getTaskColumn(task));
250
- const newColumnIndex = Math.max(
251
- 0,
252
- Math.min(columnIds.length - 1, currentColumnIndex + direction)
253
- );
254
- const newColumn = columnIds[newColumnIndex];
255
- this.emit("task:move", {
256
- taskId: task.id,
257
- fromColumn: columnIds[currentColumnIndex],
258
- toColumn: newColumn
259
- });
260
- const stateMapping = {
261
- backlog: "backlog",
262
- todo: "unstarted",
263
- in_progress: "started",
264
- review: "in_review",
265
- done: "completed"
266
- };
267
- task.state = stateMapping[newColumn] || task.state;
268
- this.update(Array.from(this.tasks.values()));
269
- }
270
- selectTask(taskId) {
271
- this.selectedTask = taskId;
272
- const task = this.tasks.get(taskId);
273
- if (task) {
274
- this.emit("task:selected", task);
275
- }
276
- }
277
- showTaskDetails(task) {
278
- const details = blessed.box({
279
- parent: this.container.screen,
280
- top: "center",
281
- left: "center",
282
- width: "70%",
283
- height: "70%",
284
- content: this.formatTaskDetails(task),
285
- tags: true,
286
- border: {
287
- type: "line"
288
- },
289
- style: {
290
- border: {
291
- fg: "green"
292
- }
293
- },
294
- scrollable: true,
295
- keys: true,
296
- vi: true,
297
- mouse: true,
298
- hidden: false,
299
- label: ` Task: ${task.identifier} - ${task.title} `
300
- });
301
- details.key(["escape", "q"], () => {
302
- details.destroy();
303
- this.container.screen.render();
304
- });
305
- details.focus();
306
- this.container.screen.render();
307
- }
308
- formatTaskDetails(task) {
309
- let details = `{bold}ID:{/} ${task.identifier}
310
- `;
311
- details += `{bold}Title:{/} ${task.title}
312
- `;
313
- details += `{bold}State:{/} ${task.state}
314
- `;
315
- details += `{bold}Priority:{/} ${this.getPriorityIcon(task.priority)} ${task.priority || "None"}
316
- `;
317
- if (task.assignee) {
318
- if (typeof task.assignee === "string") {
319
- details += `{bold}Assignee:{/} ${task.assignee}
320
- `;
321
- } else {
322
- details += `{bold}Assignee:{/} ${task.assignee.name} (${task.assignee.email})
323
- `;
324
- }
325
- }
326
- if (task.estimate) {
327
- details += `{bold}Estimate:{/} ${task.estimate} points
328
- `;
329
- }
330
- if (task.dueDate) {
331
- const daysUntil = this.getDaysUntilDue(task.dueDate);
332
- const dueColor = daysUntil < 0 ? "red" : daysUntil <= 1 ? "yellow" : "white";
333
- details += `{bold}Due Date:{/} {${dueColor}-fg}${new Date(task.dueDate).toLocaleDateString()}{/}
334
- `;
335
- }
336
- if (task.labels && task.labels.length > 0) {
337
- details += `{bold}Labels:{/} ${task.labels.map((l) => `{cyan-fg}#${l}{/}`).join(" ")}
338
- `;
339
- }
340
- if (task.description) {
341
- details += `
342
- {bold}Description:{/}
343
- ${task.description}
344
- `;
345
- }
346
- if (task.comments && task.comments.length > 0) {
347
- details += `
348
- {bold}Comments ({${task.comments.length}}):{/}
349
- `;
350
- task.comments.slice(-5).forEach((comment) => {
351
- details += `
352
- {gray-fg}${comment.author} - ${new Date(comment.createdAt).toLocaleString()}{/}
353
- `;
354
- details += `${comment.body}
355
- `;
356
- });
357
- }
358
- if (task.subtasks && task.subtasks.length > 0) {
359
- details += `
360
- {bold}Subtasks:{/}
361
- `;
362
- task.subtasks.forEach((subtask) => {
363
- const check = subtask.completed ? "\u2713" : "\u25CB";
364
- details += ` ${check} ${subtask.title}
365
- `;
366
- });
367
- }
368
- details += `
369
- {bold}Actions:{/}
370
- `;
371
- details += ` [d] Mark Done | [a] Assign | [c] Comment | [e] Edit
372
- `;
373
- return details;
374
- }
375
- createNewTask() {
376
- const form = blessed.form({
377
- parent: this.container.screen,
378
- top: "center",
379
- left: "center",
380
- width: "50%",
381
- height: 14,
382
- border: {
383
- type: "line"
384
- },
385
- style: {
386
- border: {
387
- fg: "cyan"
388
- }
389
- },
390
- label: " Create New Task ",
391
- keys: true
392
- });
393
- const titleLabel = blessed.text({
394
- parent: form,
395
- content: "Title:",
396
- top: 1,
397
- left: 2
398
- });
399
- const titleInput = blessed.textbox({
400
- parent: form,
401
- name: "title",
402
- top: 1,
403
- left: 10,
404
- width: "100%-12",
405
- height: 1,
406
- inputOnFocus: true,
407
- style: {
408
- focus: {
409
- fg: "white",
410
- bg: "blue"
411
- }
412
- }
413
- });
414
- const descLabel = blessed.text({
415
- parent: form,
416
- content: "Desc:",
417
- top: 3,
418
- left: 2
419
- });
420
- const descInput = blessed.textarea({
421
- parent: form,
422
- name: "description",
423
- top: 3,
424
- left: 10,
425
- width: "100%-12",
426
- height: 4,
427
- inputOnFocus: true,
428
- style: {
429
- focus: {
430
- fg: "white",
431
- bg: "blue"
432
- }
433
- }
434
- });
435
- const submitBtn = blessed.button({
436
- parent: form,
437
- content: " Create ",
438
- top: 9,
439
- left: "center",
440
- shrink: true,
441
- style: {
442
- focus: {
443
- bg: "green",
444
- fg: "white"
445
- }
446
- }
447
- });
448
- submitBtn.on("press", () => {
449
- const title = titleInput.getValue();
450
- const description = descInput.getValue();
451
- if (title) {
452
- this.emit("task:create", { title, description });
453
- }
454
- form.destroy();
455
- this.container.screen.render();
456
- });
457
- form.key(["escape"], () => {
458
- form.destroy();
459
- this.container.screen.render();
460
- });
461
- titleInput.focus();
462
- this.container.screen.render();
463
- }
464
- markTaskDone(taskId) {
465
- const task = this.tasks.get(taskId);
466
- if (task) {
467
- this.emit("task:update", {
468
- taskId: task.id,
469
- updates: { state: "completed" }
470
- });
471
- task.state = "completed";
472
- this.update(Array.from(this.tasks.values()));
473
- }
474
- }
475
- assignTask(taskId) {
476
- this.emit("task:assign", { taskId });
477
- }
478
- focus() {
479
- const column = this.columns.get(this.currentColumn);
480
- if (column) {
481
- column.focus();
482
- }
483
- }
484
- hasFocus() {
485
- return Array.from(this.columns.values()).some(
486
- (col) => col === this.container.screen.focused
487
- );
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
- }
1135
- }
1136
- export {
1137
- TaskBoard
1138
- };
1139
- //# sourceMappingURL=task-board.js.map