@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.
- package/dist/agents/verifiers/base-verifier.js.map +2 -2
- package/dist/agents/verifiers/formatter-verifier.js.map +2 -2
- package/dist/agents/verifiers/llm-judge.js.map +2 -2
- package/dist/cli/claude-sm.js +24 -13
- package/dist/cli/claude-sm.js.map +2 -2
- package/dist/cli/codex-sm.js +24 -13
- package/dist/cli/codex-sm.js.map +2 -2
- package/dist/cli/commands/agent.js.map +2 -2
- package/dist/cli/commands/chromadb.js +217 -32
- package/dist/cli/commands/chromadb.js.map +2 -2
- package/dist/cli/commands/clear.js +12 -1
- package/dist/cli/commands/clear.js.map +2 -2
- package/dist/cli/commands/context.js +13 -2
- package/dist/cli/commands/context.js.map +2 -2
- package/dist/cli/commands/dashboard.js.map +2 -2
- package/dist/cli/commands/gc.js +202 -0
- package/dist/cli/commands/gc.js.map +7 -0
- package/dist/cli/commands/handoff.js +12 -1
- package/dist/cli/commands/handoff.js.map +2 -2
- package/dist/cli/commands/infinite-storage.js +32 -21
- package/dist/cli/commands/infinite-storage.js.map +2 -2
- package/dist/cli/commands/linear-create.js +13 -2
- package/dist/cli/commands/linear-create.js.map +2 -2
- package/dist/cli/commands/linear-list.js +12 -1
- package/dist/cli/commands/linear-list.js.map +2 -2
- package/dist/cli/commands/linear-migrate.js +12 -1
- package/dist/cli/commands/linear-migrate.js.map +2 -2
- package/dist/cli/commands/linear-test.js +12 -1
- package/dist/cli/commands/linear-test.js.map +2 -2
- package/dist/cli/commands/linear-unified.js +262 -0
- package/dist/cli/commands/linear-unified.js.map +7 -0
- package/dist/cli/commands/linear.js +17 -6
- package/dist/cli/commands/linear.js.map +2 -2
- package/dist/cli/commands/monitor.js.map +2 -2
- package/dist/cli/commands/onboard.js.map +2 -2
- package/dist/cli/commands/quality.js.map +2 -2
- package/dist/cli/commands/search.js.map +2 -2
- package/dist/cli/commands/session.js.map +2 -2
- package/dist/cli/commands/skills.js +12 -1
- package/dist/cli/commands/skills.js.map +2 -2
- package/dist/cli/commands/storage.js +18 -7
- package/dist/cli/commands/storage.js.map +2 -2
- package/dist/cli/commands/tasks.js.map +2 -2
- package/dist/cli/commands/tui.js +13 -2
- package/dist/cli/commands/tui.js.map +2 -2
- package/dist/cli/commands/webhook.js +14 -3
- package/dist/cli/commands/webhook.js.map +2 -2
- package/dist/cli/commands/workflow.js +14 -3
- package/dist/cli/commands/workflow.js.map +2 -2
- package/dist/cli/commands/worktree.js.map +2 -2
- package/dist/cli/index.js +18 -5
- package/dist/cli/index.js.map +2 -2
- package/dist/core/config/config-manager.js.map +2 -2
- package/dist/core/context/auto-context.js.map +2 -2
- package/dist/core/context/compaction-handler.js.map +2 -2
- package/dist/core/context/context-bridge.js.map +2 -2
- package/dist/core/context/dual-stack-manager.js.map +2 -2
- package/dist/core/context/frame-database.js.map +2 -2
- package/dist/core/context/frame-digest.js.map +2 -2
- package/dist/core/context/frame-handoff-manager.js.map +2 -2
- package/dist/core/context/frame-manager.js +12 -1
- package/dist/core/context/frame-manager.js.map +2 -2
- package/dist/core/context/frame-stack.js.map +2 -2
- package/dist/core/context/incremental-gc.js +279 -0
- package/dist/core/context/incremental-gc.js.map +7 -0
- package/dist/core/context/permission-manager.js +12 -1
- package/dist/core/context/permission-manager.js.map +2 -2
- package/dist/core/context/refactored-frame-manager.js.map +2 -2
- package/dist/core/context/shared-context-layer.js +12 -1
- package/dist/core/context/shared-context-layer.js.map +2 -2
- package/dist/core/context/stack-merge-resolver.js.map +2 -2
- package/dist/core/context/validation.js.map +2 -2
- package/dist/core/database/batch-operations.js.map +2 -2
- package/dist/core/database/connection-pool.js.map +2 -2
- package/dist/core/database/migration-manager.js.map +2 -2
- package/dist/core/database/paradedb-adapter.js.map +2 -2
- package/dist/core/database/query-cache.js.map +2 -2
- package/dist/core/database/query-router.js.map +2 -2
- package/dist/core/database/sqlite-adapter.js.map +2 -2
- package/dist/core/digest/enhanced-hybrid-digest.js.map +2 -2
- package/dist/core/errors/recovery.js.map +2 -2
- package/dist/core/merge/resolution-engine.js.map +2 -2
- package/dist/core/monitoring/error-handler.js.map +2 -2
- package/dist/core/monitoring/logger.js +14 -3
- package/dist/core/monitoring/logger.js.map +2 -2
- package/dist/core/monitoring/metrics.js +13 -2
- package/dist/core/monitoring/metrics.js.map +2 -2
- package/dist/core/monitoring/progress-tracker.js +12 -1
- package/dist/core/monitoring/progress-tracker.js.map +2 -2
- package/dist/core/monitoring/session-monitor.js.map +2 -2
- package/dist/core/performance/context-cache.js.map +2 -2
- package/dist/core/performance/lazy-context-loader.js.map +2 -2
- package/dist/core/performance/monitor.js.map +2 -2
- package/dist/core/performance/optimized-frame-context.js.map +2 -2
- package/dist/core/performance/performance-benchmark.js.map +2 -2
- package/dist/core/performance/performance-profiler.js +12 -1
- package/dist/core/performance/performance-profiler.js.map +2 -2
- package/dist/core/performance/streaming-jsonl-parser.js.map +2 -2
- package/dist/core/persistence/postgres-adapter.js.map +2 -2
- package/dist/core/projects/project-manager.js.map +2 -2
- package/dist/core/retrieval/context-retriever.js.map +2 -2
- package/dist/core/retrieval/graph-retrieval.js.map +2 -2
- package/dist/core/retrieval/llm-context-retrieval.js.map +2 -2
- package/dist/core/retrieval/retrieval-benchmarks.js.map +2 -2
- package/dist/core/retrieval/summary-generator.js.map +2 -2
- package/dist/core/session/clear-survival.js.map +2 -2
- package/dist/core/session/handoff-generator.js.map +2 -2
- package/dist/core/session/session-manager.js +16 -5
- package/dist/core/session/session-manager.js.map +2 -2
- package/dist/core/skills/skill-storage.js +13 -2
- package/dist/core/skills/skill-storage.js.map +2 -2
- package/dist/core/storage/chromadb-adapter.js.map +2 -2
- package/dist/core/storage/chromadb-simple.js.map +2 -2
- package/dist/core/storage/infinite-storage.js.map +2 -2
- package/dist/core/storage/railway-optimized-storage.js +19 -8
- package/dist/core/storage/railway-optimized-storage.js.map +2 -2
- package/dist/core/storage/remote-storage.js +12 -1
- package/dist/core/storage/remote-storage.js.map +2 -2
- package/dist/core/trace/cli-trace-wrapper.js +16 -5
- package/dist/core/trace/cli-trace-wrapper.js.map +2 -2
- package/dist/core/trace/db-trace-wrapper.js.map +2 -2
- package/dist/core/trace/debug-trace.js +21 -10
- package/dist/core/trace/debug-trace.js.map +2 -2
- package/dist/core/trace/index.js +46 -35
- package/dist/core/trace/index.js.map +2 -2
- package/dist/core/trace/trace-demo.js +12 -1
- package/dist/core/trace/trace-demo.js.map +2 -2
- package/dist/core/trace/trace-detector.js.map +2 -2
- package/dist/core/trace/trace-store.js.map +2 -2
- package/dist/core/utils/update-checker.js.map +2 -2
- package/dist/core/worktree/worktree-manager.js.map +2 -2
- package/dist/features/analytics/api/analytics-api.js.map +2 -2
- package/dist/features/analytics/core/analytics-service.js +12 -1
- package/dist/features/analytics/core/analytics-service.js.map +2 -2
- package/dist/features/analytics/queries/metrics-queries.js.map +2 -2
- package/dist/features/tasks/pebbles-task-store.js.map +2 -2
- package/dist/features/tui/components/analytics-panel.js.map +2 -2
- package/dist/features/tui/components/pr-tracker.js.map +2 -2
- package/dist/features/tui/components/session-monitor.js.map +2 -2
- package/dist/features/tui/components/subagent-fleet.js.map +2 -2
- package/dist/features/tui/components/task-board.js +650 -2
- package/dist/features/tui/components/task-board.js.map +2 -2
- package/dist/features/tui/index.js +16 -5
- package/dist/features/tui/index.js.map +2 -2
- package/dist/features/tui/services/data-service.js +25 -14
- package/dist/features/tui/services/data-service.js.map +2 -2
- package/dist/features/tui/services/linear-task-reader.js.map +2 -2
- package/dist/features/tui/services/websocket-client.js +13 -2
- package/dist/features/tui/services/websocket-client.js.map +2 -2
- package/dist/features/tui/terminal-compat.js +27 -16
- package/dist/features/tui/terminal-compat.js.map +2 -2
- package/dist/features/web/client/stores/task-store.js.map +2 -2
- package/dist/features/web/server/index.js +13 -2
- package/dist/features/web/server/index.js.map +2 -2
- package/dist/integrations/claude-code/enhanced-pre-clear-hooks.js.map +2 -2
- package/dist/integrations/claude-code/lifecycle-hooks.js.map +2 -2
- package/dist/integrations/claude-code/post-task-hooks.js.map +2 -2
- package/dist/integrations/linear/auth.js +17 -6
- package/dist/integrations/linear/auth.js.map +2 -2
- package/dist/integrations/linear/auto-sync.js.map +2 -2
- package/dist/integrations/linear/client.js.map +2 -2
- package/dist/integrations/linear/config.js.map +2 -2
- package/dist/integrations/linear/migration.js.map +2 -2
- package/dist/integrations/linear/oauth-server.js +13 -2
- package/dist/integrations/linear/oauth-server.js.map +2 -2
- package/dist/integrations/linear/rest-client.js.map +2 -2
- package/dist/integrations/linear/sync-enhanced.js +202 -0
- package/dist/integrations/linear/sync-enhanced.js.map +7 -0
- package/dist/integrations/linear/sync-manager.js.map +2 -2
- package/dist/integrations/linear/sync-service.js +12 -1
- package/dist/integrations/linear/sync-service.js.map +2 -2
- package/dist/integrations/linear/sync.js +34 -3
- package/dist/integrations/linear/sync.js.map +2 -2
- package/dist/integrations/linear/unified-sync.js +560 -0
- package/dist/integrations/linear/unified-sync.js.map +7 -0
- package/dist/integrations/linear/webhook-handler.js +12 -1
- package/dist/integrations/linear/webhook-handler.js.map +2 -2
- package/dist/integrations/linear/webhook-server.js +14 -3
- package/dist/integrations/linear/webhook-server.js.map +2 -2
- package/dist/integrations/linear/webhook.js +12 -1
- package/dist/integrations/linear/webhook.js.map +2 -2
- package/dist/integrations/mcp/handlers/context-handlers.js.map +2 -2
- package/dist/integrations/mcp/handlers/linear-handlers.js.map +2 -2
- package/dist/integrations/mcp/handlers/skill-handlers.js +13 -2
- package/dist/integrations/mcp/handlers/skill-handlers.js.map +2 -2
- package/dist/integrations/mcp/handlers/task-handlers.js.map +2 -2
- package/dist/integrations/mcp/handlers/trace-handlers.js.map +2 -2
- package/dist/integrations/mcp/middleware/tool-scoring.js.map +2 -2
- package/dist/integrations/mcp/refactored-server.js +15 -4
- package/dist/integrations/mcp/refactored-server.js.map +2 -2
- package/dist/integrations/mcp/server.js +12 -1
- package/dist/integrations/mcp/server.js.map +2 -2
- package/dist/integrations/mcp/tool-definitions.js.map +2 -2
- package/dist/integrations/pg-aiguide/embedding-provider.js +13 -2
- package/dist/integrations/pg-aiguide/embedding-provider.js.map +2 -2
- package/dist/integrations/pg-aiguide/semantic-search.js.map +2 -2
- package/dist/mcp/stackmemory-mcp-server.js +12 -1
- package/dist/mcp/stackmemory-mcp-server.js.map +2 -2
- package/dist/middleware/exponential-rate-limiter.js.map +2 -2
- package/dist/servers/production/auth-middleware.js +13 -2
- package/dist/servers/production/auth-middleware.js.map +2 -2
- package/dist/servers/railway/index.js +22 -11
- package/dist/servers/railway/index.js.map +2 -2
- package/dist/services/config-service.js.map +2 -2
- package/dist/services/context-service.js.map +2 -2
- package/dist/skills/claude-skills.js +105 -2
- package/dist/skills/claude-skills.js.map +2 -2
- package/dist/skills/dashboard-launcher.js.map +2 -2
- package/dist/skills/repo-ingestion-skill.js +561 -0
- package/dist/skills/repo-ingestion-skill.js.map +7 -0
- package/dist/utils/logger.js +12 -1
- package/dist/utils/logger.js.map +2 -2
- package/package.json +5 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/features/tui/components/task-board.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Task Board Component\n * Displays Linear tasks with live synchronization\n */\n\nimport blessed from 'blessed';\nimport { EventEmitter } from 'events';\nimport type { LinearTask, TaskColumn } from '../types.js';\n\nexport class TaskBoard extends EventEmitter {\n private container: blessed.Widgets.BoxElement;\n private columns: Map<string, blessed.Widgets.ListElement>;\n private tasks: Map<string, LinearTask>;\n private selectedTask: string | null = null;\n private currentColumn: string = 'todo';\n\n private readonly columnConfig: TaskColumn[] = [\n { id: 'backlog', title: 'Backlog', color: 'gray' },\n { id: 'todo', title: 'To Do', color: 'cyan' },\n { id: 'in_progress', title: 'In Progress', color: 'yellow' },\n { id: 'review', title: 'Review', color: 'magenta' },\n { id: 'done', title: 'Done', color: 'green' },\n ];\n\n constructor(container: blessed.Widgets.BoxElement) {\n super();\n this.container = container;\n this.columns = new Map();\n this.tasks = new Map();\n this.initializeUI();\n }\n\n private initializeUI(): void {\n const columnWidth = Math.floor(100 / this.columnConfig.length);\n\n this.columnConfig.forEach((column, index) => {\n // Column container\n const columnBox = blessed.box({\n parent: this.container,\n left: `${index * columnWidth}%`,\n top: 0,\n width: `${columnWidth}%`,\n height: '100%',\n border: {\n type: 'line',\n },\n style: {\n border: {\n fg: column.color,\n },\n },\n label: ` ${column.title} `,\n });\n\n // Task list within column\n const taskList = blessed.list({\n parent: columnBox,\n top: 0,\n left: 0,\n width: '100%-2',\n height: '100%-2',\n style: {\n selected: {\n bg: column.color,\n fg: 'black',\n bold: true,\n },\n item: {\n fg: 'white',\n },\n },\n mouse: true,\n keys: true,\n vi: true,\n scrollable: true,\n tags: true,\n });\n\n taskList.on('select', (item, index) => {\n const tasksInColumn = this.getTasksInColumn(column.id);\n if (tasksInColumn[index]) {\n this.selectTask(tasksInColumn[index].id);\n }\n });\n\n this.columns.set(column.id, taskList);\n });\n\n // Set up keyboard navigation\n this.setupKeyboardNavigation();\n }\n\n private setupKeyboardNavigation(): void {\n const container = this.container;\n\n // Navigate between columns\n container.key(['left', 'h'], () => {\n this.navigateColumn(-1);\n });\n\n container.key(['right', 'l'], () => {\n this.navigateColumn(1);\n });\n\n // Move tasks between columns\n container.key(['S-left'], () => {\n this.moveTaskToColumn(-1);\n });\n\n container.key(['S-right'], () => {\n this.moveTaskToColumn(1);\n });\n\n // Quick actions\n container.key(['enter'], () => {\n if (this.selectedTask) {\n this.showTaskDetails(this.tasks.get(this.selectedTask)!);\n }\n });\n\n container.key(['n'], () => {\n this.createNewTask();\n });\n\n container.key(['d'], () => {\n if (this.selectedTask) {\n this.markTaskDone(this.selectedTask);\n }\n });\n\n container.key(['a'], () => {\n if (this.selectedTask) {\n this.assignTask(this.selectedTask);\n }\n });\n }\n\n private getTasksInColumn(columnId: string): LinearTask[] {\n return Array.from(this.tasks.values())\n .filter((task) => this.getTaskColumn(task) === columnId)\n .sort((a, b) => (b.priority || 0) - (a.priority || 0));\n }\n\n private getTaskColumn(task: LinearTask): string {\n // Map Linear states to our columns - handle both raw API states and formatted display states\n const stateMapping: Record<string, string> = {\n // Raw Linear API states\n backlog: 'backlog',\n unstarted: 'todo',\n started: 'in_progress',\n completed: 'done',\n canceled: 'done',\n cancelled: 'done',\n // Formatted display states from data service\n Backlog: 'backlog',\n 'To Do': 'todo',\n 'In Progress': 'in_progress',\n Done: 'done',\n Canceled: 'done',\n // Legacy mappings\n todo: 'todo',\n in_progress: 'in_progress',\n in_review: 'review',\n done: 'done',\n };\n\n const state = task.state || 'todo';\n return stateMapping[state] || stateMapping[state.toLowerCase()] || 'todo';\n }\n\n private formatTaskItem(task: LinearTask): string {\n const priority = this.getPriorityIcon(task.priority);\n const estimate = task.estimate ? `[${task.estimate}]` : '';\n\n // Handle both object and string assignee formats\n let assignee: string;\n if (typeof task.assignee === 'string') {\n assignee = `@${task.assignee}`;\n } else if (task.assignee?.name) {\n assignee = `@${task.assignee.name}`;\n } else {\n assignee = '{gray-fg}unassigned{/}';\n }\n\n const labels = task.labels?.map((l) => `{cyan-fg}#${l}{/}`).join(' ') || '';\n\n let taskStr = `${priority} ${task.identifier}: ${task.title}\\n`;\n taskStr += ` {gray-fg}${assignee} ${estimate} ${labels}{/}`;\n\n // Add progress indicators\n if (task.progress !== undefined) {\n const progressBar = this.createProgressBar(task.progress);\n taskStr += `\\n ${progressBar}`;\n }\n\n // Add due date warning\n if (task.dueDate) {\n const daysUntilDue = this.getDaysUntilDue(task.dueDate);\n if (daysUntilDue < 0) {\n taskStr += ` {red-fg}\u26A0 Overdue{/}`;\n } else if (daysUntilDue <= 1) {\n taskStr += ` {yellow-fg}\u26A0 Due soon{/}`;\n }\n }\n\n return taskStr;\n }\n\n private getPriorityIcon(priority?: number): string {\n if (!priority) return '\u25CB';\n switch (priority) {\n case 0:\n return '{red-fg}\uD83D\uDD34{/}'; // Urgent\n case 1:\n return '{yellow-fg}\uD83D\uDFE1{/}'; // High\n case 2:\n return '{green-fg}\uD83D\uDFE2{/}'; // Medium\n case 3:\n return '{blue-fg}\uD83D\uDD35{/}'; // Low\n default:\n return '\u25CB';\n }\n }\n\n private createProgressBar(progress: number): string {\n const width = 10;\n const filled = Math.round(progress * width);\n const empty = width - filled;\n\n const color = progress >= 1 ? 'green' : progress >= 0.5 ? 'yellow' : 'red';\n return `{${color}-fg}${'\u2588'.repeat(filled)}{/}{gray-fg}${'\u2591'.repeat(empty)}{/} ${Math.round(progress * 100)}%`;\n }\n\n private getDaysUntilDue(dueDate: string): number {\n const due = new Date(dueDate);\n const now = new Date();\n const diffTime = due.getTime() - now.getTime();\n return Math.ceil(diffTime / (1000 * 60 * 60 * 24));\n }\n\n public update(tasks: LinearTask[]): void {\n // Update task map\n this.tasks.clear();\n tasks.forEach((task) => {\n this.tasks.set(task.id, task);\n });\n\n // Update each column\n this.columnConfig.forEach((column) => {\n const columnTasks = this.getTasksInColumn(column.id);\n const items = columnTasks.map((task) => this.formatTaskItem(task));\n\n const list = this.columns.get(column.id);\n if (list) {\n list.setItems(items);\n\n // Update column label with count\n const parent = list.parent;\n if (parent && typeof (parent as any).setLabel === 'function') {\n (parent as any).setLabel(` ${column.title} (${columnTasks.length}) `);\n }\n }\n });\n\n this.container.screen.render();\n }\n\n private navigateColumn(direction: number): void {\n const columnIds = this.columnConfig.map((c) => c.id);\n const currentIndex = columnIds.indexOf(this.currentColumn);\n const newIndex = Math.max(\n 0,\n Math.min(columnIds.length - 1, currentIndex + direction)\n );\n\n this.currentColumn = columnIds[newIndex];\n this.columns.get(this.currentColumn)?.focus();\n this.container.screen.render();\n }\n\n private moveTaskToColumn(direction: number): void {\n if (!this.selectedTask) return;\n\n const task = this.tasks.get(this.selectedTask);\n if (!task) return;\n\n const columnIds = this.columnConfig.map((c) => c.id);\n const currentColumnIndex = columnIds.indexOf(this.getTaskColumn(task));\n const newColumnIndex = Math.max(\n 0,\n Math.min(columnIds.length - 1, currentColumnIndex + direction)\n );\n const newColumn = columnIds[newColumnIndex];\n\n // Emit event to update task state in Linear\n this.emit('task:move', {\n taskId: task.id,\n fromColumn: columnIds[currentColumnIndex],\n toColumn: newColumn,\n });\n\n // Optimistically update UI\n const stateMapping: Record<string, string> = {\n backlog: 'backlog',\n todo: 'unstarted',\n in_progress: 'started',\n review: 'in_review',\n done: 'completed',\n };\n\n task.state = stateMapping[newColumn] || task.state;\n this.update(Array.from(this.tasks.values()));\n }\n\n private selectTask(taskId: string): void {\n this.selectedTask = taskId;\n const task = this.tasks.get(taskId);\n if (task) {\n this.emit('task:selected', task);\n }\n }\n\n private showTaskDetails(task: LinearTask): void {\n const details = blessed.box({\n parent: this.container.screen,\n top: 'center',\n left: 'center',\n width: '70%',\n height: '70%',\n content: this.formatTaskDetails(task),\n tags: true,\n border: {\n type: 'line',\n },\n style: {\n border: {\n fg: 'green',\n },\n },\n scrollable: true,\n keys: true,\n vi: true,\n mouse: true,\n hidden: false,\n label: ` Task: ${task.identifier} - ${task.title} `,\n });\n\n details.key(['escape', 'q'], () => {\n details.destroy();\n this.container.screen.render();\n });\n\n details.focus();\n this.container.screen.render();\n }\n\n private formatTaskDetails(task: LinearTask): string {\n let details = `{bold}ID:{/} ${task.identifier}\\n`;\n details += `{bold}Title:{/} ${task.title}\\n`;\n details += `{bold}State:{/} ${task.state}\\n`;\n details += `{bold}Priority:{/} ${this.getPriorityIcon(task.priority)} ${task.priority || 'None'}\\n`;\n\n if (task.assignee) {\n if (typeof task.assignee === 'string') {\n details += `{bold}Assignee:{/} ${task.assignee}\\n`;\n } else {\n details += `{bold}Assignee:{/} ${task.assignee.name} (${task.assignee.email})\\n`;\n }\n }\n\n if (task.estimate) {\n details += `{bold}Estimate:{/} ${task.estimate} points\\n`;\n }\n\n if (task.dueDate) {\n const daysUntil = this.getDaysUntilDue(task.dueDate);\n const dueColor =\n daysUntil < 0 ? 'red' : daysUntil <= 1 ? 'yellow' : 'white';\n details += `{bold}Due Date:{/} {${dueColor}-fg}${new Date(task.dueDate).toLocaleDateString()}{/}\\n`;\n }\n\n if (task.labels && task.labels.length > 0) {\n details += `{bold}Labels:{/} ${task.labels.map((l) => `{cyan-fg}#${l}{/}`).join(' ')}\\n`;\n }\n\n if (task.description) {\n details += `\\n{bold}Description:{/}\\n${task.description}\\n`;\n }\n\n if (task.comments && task.comments.length > 0) {\n details += `\\n{bold}Comments ({${task.comments.length}}):{/}\\n`;\n task.comments.slice(-5).forEach((comment) => {\n details += `\\n{gray-fg}${comment.author} - ${new Date(comment.createdAt).toLocaleString()}{/}\\n`;\n details += `${comment.body}\\n`;\n });\n }\n\n if (task.subtasks && task.subtasks.length > 0) {\n details += `\\n{bold}Subtasks:{/}\\n`;\n task.subtasks.forEach((subtask) => {\n const check = subtask.completed ? '\u2713' : '\u25CB';\n details += ` ${check} ${subtask.title}\\n`;\n });\n }\n\n details += `\\n{bold}Actions:{/}\\n`;\n details += ` [d] Mark Done | [a] Assign | [c] Comment | [e] Edit\\n`;\n\n return details;\n }\n\n private createNewTask(): void {\n const form = blessed.form({\n parent: this.container.screen,\n top: 'center',\n left: 'center',\n width: '50%',\n height: 14,\n border: {\n type: 'line',\n },\n style: {\n border: {\n fg: 'cyan',\n },\n },\n label: ' Create New Task ',\n keys: true,\n });\n\n const titleLabel = blessed.text({\n parent: form,\n content: 'Title:',\n top: 1,\n left: 2,\n });\n\n const titleInput = blessed.textbox({\n parent: form,\n name: 'title',\n top: 1,\n left: 10,\n width: '100%-12',\n height: 1,\n inputOnFocus: true,\n style: {\n focus: {\n fg: 'white',\n bg: 'blue',\n },\n },\n });\n\n const descLabel = blessed.text({\n parent: form,\n content: 'Desc:',\n top: 3,\n left: 2,\n });\n\n const descInput = blessed.textarea({\n parent: form,\n name: 'description',\n top: 3,\n left: 10,\n width: '100%-12',\n height: 4,\n inputOnFocus: true,\n style: {\n focus: {\n fg: 'white',\n bg: 'blue',\n },\n },\n });\n\n const submitBtn = blessed.button({\n parent: form,\n content: ' Create ',\n top: 9,\n left: 'center',\n shrink: true,\n style: {\n focus: {\n bg: 'green',\n fg: 'white',\n },\n },\n });\n\n submitBtn.on('press', () => {\n const title = titleInput.getValue();\n const description = descInput.getValue();\n\n if (title) {\n this.emit('task:create', { title, description });\n }\n\n form.destroy();\n this.container.screen.render();\n });\n\n form.key(['escape'], () => {\n form.destroy();\n this.container.screen.render();\n });\n\n titleInput.focus();\n this.container.screen.render();\n }\n\n private markTaskDone(taskId: string): void {\n const task = this.tasks.get(taskId);\n if (task) {\n this.emit('task:update', {\n taskId: task.id,\n updates: { state: 'completed' },\n });\n\n // Optimistically update UI\n task.state = 'completed';\n this.update(Array.from(this.tasks.values()));\n }\n }\n\n private assignTask(taskId: string): void {\n // Would open assignment dialog\n this.emit('task:assign', { taskId });\n }\n\n public focus(): void {\n const column = this.columns.get(this.currentColumn);\n if (column) {\n column.focus();\n }\n }\n\n public hasFocus(): boolean {\n return Array.from(this.columns.values()).some(\n (col) => col === this.container.screen.focused\n );\n }\n}\n"],
|
|
5
|
-
"mappings": "AAKA,OAAO,aAAa;AACpB,SAAS,oBAAoB;AAGtB,MAAM,kBAAkB,aAAa;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAA8B;AAAA,EAC9B,gBAAwB;AAAA,EAEf,eAA6B;AAAA,IAC5C,EAAE,IAAI,WAAW,OAAO,WAAW,OAAO,OAAO;AAAA,IACjD,EAAE,IAAI,QAAQ,OAAO,SAAS,OAAO,OAAO;AAAA,IAC5C,EAAE,IAAI,eAAe,OAAO,eAAe,OAAO,SAAS;AAAA,IAC3D,EAAE,IAAI,UAAU,OAAO,UAAU,OAAO,UAAU;AAAA,IAClD,EAAE,IAAI,QAAQ,OAAO,QAAQ,OAAO,QAAQ;AAAA,EAC9C;AAAA,EAEA,YAAY,WAAuC;AACjD,UAAM;AACN,SAAK,YAAY;AACjB,SAAK,UAAU,oBAAI,IAAI;AACvB,SAAK,QAAQ,oBAAI,IAAI;AACrB,SAAK,aAAa;AAAA,EACpB;AAAA,EAEQ,eAAqB;AAC3B,UAAM,cAAc,KAAK,MAAM,MAAM,KAAK,aAAa,MAAM;AAE7D,SAAK,aAAa,QAAQ,CAAC,QAAQ,UAAU;AAE3C,YAAM,YAAY,QAAQ,IAAI;AAAA,QAC5B,QAAQ,KAAK;AAAA,QACb,MAAM,GAAG,QAAQ,WAAW;AAAA,QAC5B,KAAK;AAAA,QACL,OAAO,GAAG,WAAW;AAAA,QACrB,QAAQ;AAAA,QACR,QAAQ;AAAA,UACN,MAAM;AAAA,QACR;AAAA,QACA,OAAO;AAAA,UACL,QAAQ;AAAA,YACN,IAAI,OAAO;AAAA,UACb;AAAA,QACF;AAAA,QACA,OAAO,IAAI,OAAO,KAAK;AAAA,MACzB,CAAC;AAGD,YAAM,WAAW,QAAQ,KAAK;AAAA,QAC5B,QAAQ;AAAA,QACR,KAAK;AAAA,QACL,MAAM;AAAA,QACN,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,OAAO;AAAA,UACL,UAAU;AAAA,YACR,IAAI,OAAO;AAAA,YACX,IAAI;AAAA,YACJ,MAAM;AAAA,UACR;AAAA,UACA,MAAM;AAAA,YACJ,IAAI;AAAA,UACN;AAAA,QACF;AAAA,QACA,OAAO;AAAA,QACP,MAAM;AAAA,QACN,IAAI;AAAA,QACJ,YAAY;AAAA,QACZ,MAAM;AAAA,MACR,CAAC;AAED,eAAS,GAAG,UAAU,CAAC,MAAMA,WAAU;AACrC,cAAM,gBAAgB,KAAK,iBAAiB,OAAO,EAAE;AACrD,YAAI,cAAcA,MAAK,GAAG;AACxB,eAAK,WAAW,cAAcA,MAAK,EAAE,EAAE;AAAA,QACzC;AAAA,MACF,CAAC;AAED,WAAK,QAAQ,IAAI,OAAO,IAAI,QAAQ;AAAA,IACtC,CAAC;AAGD,SAAK,wBAAwB;AAAA,EAC/B;AAAA,EAEQ,0BAAgC;AACtC,UAAM,YAAY,KAAK;AAGvB,cAAU,IAAI,CAAC,QAAQ,GAAG,GAAG,MAAM;AACjC,WAAK,eAAe,EAAE;AAAA,IACxB,CAAC;AAED,cAAU,IAAI,CAAC,SAAS,GAAG,GAAG,MAAM;AAClC,WAAK,eAAe,CAAC;AAAA,IACvB,CAAC;AAGD,cAAU,IAAI,CAAC,QAAQ,GAAG,MAAM;AAC9B,WAAK,iBAAiB,EAAE;AAAA,IAC1B,CAAC;AAED,cAAU,IAAI,CAAC,SAAS,GAAG,MAAM;AAC/B,WAAK,iBAAiB,CAAC;AAAA,IACzB,CAAC;AAGD,cAAU,IAAI,CAAC,OAAO,GAAG,MAAM;AAC7B,UAAI,KAAK,cAAc;AACrB,aAAK,gBAAgB,KAAK,MAAM,IAAI,KAAK,YAAY,CAAE;AAAA,MACzD;AAAA,IACF,CAAC;AAED,cAAU,IAAI,CAAC,GAAG,GAAG,MAAM;AACzB,WAAK,cAAc;AAAA,IACrB,CAAC;AAED,cAAU,IAAI,CAAC,GAAG,GAAG,MAAM;AACzB,UAAI,KAAK,cAAc;AACrB,aAAK,aAAa,KAAK,YAAY;AAAA,MACrC;AAAA,IACF,CAAC;AAED,cAAU,IAAI,CAAC,GAAG,GAAG,MAAM;AACzB,UAAI,KAAK,cAAc;AACrB,aAAK,WAAW,KAAK,YAAY;AAAA,MACnC;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEQ,iBAAiB,UAAgC;AACvD,WAAO,MAAM,KAAK,KAAK,MAAM,OAAO,CAAC,EAClC,OAAO,CAAC,SAAS,KAAK,cAAc,IAAI,MAAM,QAAQ,EACtD,KAAK,CAAC,GAAG,OAAO,EAAE,YAAY,MAAM,EAAE,YAAY,EAAE;AAAA,EACzD;AAAA,EAEQ,cAAc,MAA0B;AAE9C,UAAM,eAAuC;AAAA;AAAA,MAE3C,SAAS;AAAA,MACT,WAAW;AAAA,MACX,SAAS;AAAA,MACT,WAAW;AAAA,MACX,UAAU;AAAA,MACV,WAAW;AAAA;AAAA,MAEX,SAAS;AAAA,MACT,SAAS;AAAA,MACT,eAAe;AAAA,MACf,MAAM;AAAA,MACN,UAAU;AAAA;AAAA,MAEV,MAAM;AAAA,MACN,aAAa;AAAA,MACb,WAAW;AAAA,MACX,MAAM;AAAA,IACR;AAEA,UAAM,QAAQ,KAAK,SAAS;AAC5B,WAAO,aAAa,KAAK,KAAK,aAAa,MAAM,YAAY,CAAC,KAAK;AAAA,EACrE;AAAA,EAEQ,eAAe,MAA0B;AAC/C,UAAM,WAAW,KAAK,gBAAgB,KAAK,QAAQ;AACnD,UAAM,WAAW,KAAK,WAAW,IAAI,KAAK,QAAQ,MAAM;AAGxD,QAAI;AACJ,QAAI,OAAO,KAAK,aAAa,UAAU;AACrC,iBAAW,IAAI,KAAK,QAAQ;AAAA,IAC9B,WAAW,KAAK,UAAU,MAAM;AAC9B,iBAAW,IAAI,KAAK,SAAS,IAAI;AAAA,IACnC,OAAO;AACL,iBAAW;AAAA,IACb;AAEA,UAAM,SAAS,KAAK,QAAQ,IAAI,CAAC,MAAM,aAAa,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK;AAEzE,QAAI,UAAU,GAAG,QAAQ,IAAI,KAAK,UAAU,KAAK,KAAK,KAAK;AAAA;AAC3D,eAAW,cAAc,QAAQ,IAAI,QAAQ,IAAI,MAAM;AAGvD,QAAI,KAAK,aAAa,QAAW;AAC/B,YAAM,cAAc,KAAK,kBAAkB,KAAK,QAAQ;AACxD,iBAAW;AAAA,IAAO,WAAW;AAAA,IAC/B;AAGA,QAAI,KAAK,SAAS;AAChB,YAAM,eAAe,KAAK,gBAAgB,KAAK,OAAO;AACtD,UAAI,eAAe,GAAG;AACpB,mBAAW;AAAA,MACb,WAAW,gBAAgB,GAAG;AAC5B,mBAAW;AAAA,MACb;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEQ,gBAAgB,UAA2B;AACjD,QAAI,CAAC,SAAU,QAAO;AACtB,YAAQ,UAAU;AAAA,MAChB,KAAK;AACH,eAAO;AAAA;AAAA,MACT,KAAK;AACH,eAAO;AAAA;AAAA,MACT,KAAK;AACH,eAAO;AAAA;AAAA,MACT,KAAK;AACH,eAAO;AAAA;AAAA,MACT;AACE,eAAO;AAAA,IACX;AAAA,EACF;AAAA,EAEQ,kBAAkB,UAA0B;AAClD,UAAM,QAAQ;AACd,UAAM,SAAS,KAAK,MAAM,WAAW,KAAK;AAC1C,UAAM,QAAQ,QAAQ;AAEtB,UAAM,QAAQ,YAAY,IAAI,UAAU,YAAY,MAAM,WAAW;AACrE,WAAO,IAAI,KAAK,OAAO,SAAI,OAAO,MAAM,CAAC,eAAe,SAAI,OAAO,KAAK,CAAC,OAAO,KAAK,MAAM,WAAW,GAAG,CAAC;AAAA,EAC5G;AAAA,EAEQ,gBAAgB,SAAyB;AAC/C,UAAM,MAAM,IAAI,KAAK,OAAO;AAC5B,UAAM,MAAM,oBAAI,KAAK;AACrB,UAAM,WAAW,IAAI,QAAQ,IAAI,IAAI,QAAQ;AAC7C,WAAO,KAAK,KAAK,YAAY,MAAO,KAAK,KAAK,GAAG;AAAA,EACnD;AAAA,EAEO,OAAO,OAA2B;AAEvC,SAAK,MAAM,MAAM;AACjB,UAAM,QAAQ,CAAC,SAAS;AACtB,WAAK,MAAM,IAAI,KAAK,IAAI,IAAI;AAAA,IAC9B,CAAC;AAGD,SAAK,aAAa,QAAQ,CAAC,WAAW;AACpC,YAAM,cAAc,KAAK,iBAAiB,OAAO,EAAE;AACnD,YAAM,QAAQ,YAAY,IAAI,CAAC,SAAS,KAAK,eAAe,IAAI,CAAC;AAEjE,YAAM,OAAO,KAAK,QAAQ,IAAI,OAAO,EAAE;AACvC,UAAI,MAAM;AACR,aAAK,SAAS,KAAK;AAGnB,cAAM,SAAS,KAAK;AACpB,YAAI,UAAU,OAAQ,OAAe,aAAa,YAAY;AAC5D,UAAC,OAAe,SAAS,IAAI,OAAO,KAAK,KAAK,YAAY,MAAM,IAAI;AAAA,QACtE;AAAA,MACF;AAAA,IACF,CAAC;AAED,SAAK,UAAU,OAAO,OAAO;AAAA,EAC/B;AAAA,EAEQ,eAAe,WAAyB;AAC9C,UAAM,YAAY,KAAK,aAAa,IAAI,CAAC,MAAM,EAAE,EAAE;AACnD,UAAM,eAAe,UAAU,QAAQ,KAAK,aAAa;AACzD,UAAM,WAAW,KAAK;AAAA,MACpB;AAAA,MACA,KAAK,IAAI,UAAU,SAAS,GAAG,eAAe,SAAS;AAAA,IACzD;AAEA,SAAK,gBAAgB,UAAU,QAAQ;AACvC,SAAK,QAAQ,IAAI,KAAK,aAAa,GAAG,MAAM;AAC5C,SAAK,UAAU,OAAO,OAAO;AAAA,EAC/B;AAAA,EAEQ,iBAAiB,WAAyB;AAChD,QAAI,CAAC,KAAK,aAAc;AAExB,UAAM,OAAO,KAAK,MAAM,IAAI,KAAK,YAAY;AAC7C,QAAI,CAAC,KAAM;AAEX,UAAM,YAAY,KAAK,aAAa,IAAI,CAAC,MAAM,EAAE,EAAE;AACnD,UAAM,qBAAqB,UAAU,QAAQ,KAAK,cAAc,IAAI,CAAC;AACrE,UAAM,iBAAiB,KAAK;AAAA,MAC1B;AAAA,MACA,KAAK,IAAI,UAAU,SAAS,GAAG,qBAAqB,SAAS;AAAA,IAC/D;AACA,UAAM,YAAY,UAAU,cAAc;AAG1C,SAAK,KAAK,aAAa;AAAA,MACrB,QAAQ,KAAK;AAAA,MACb,YAAY,UAAU,kBAAkB;AAAA,MACxC,UAAU;AAAA,IACZ,CAAC;AAGD,UAAM,eAAuC;AAAA,MAC3C,SAAS;AAAA,MACT,MAAM;AAAA,MACN,aAAa;AAAA,MACb,QAAQ;AAAA,MACR,MAAM;AAAA,IACR;AAEA,SAAK,QAAQ,aAAa,SAAS,KAAK,KAAK;AAC7C,SAAK,OAAO,MAAM,KAAK,KAAK,MAAM,OAAO,CAAC,CAAC;AAAA,EAC7C;AAAA,EAEQ,WAAW,QAAsB;AACvC,SAAK,eAAe;AACpB,UAAM,OAAO,KAAK,MAAM,IAAI,MAAM;AAClC,QAAI,MAAM;AACR,WAAK,KAAK,iBAAiB,IAAI;AAAA,IACjC;AAAA,EACF;AAAA,EAEQ,gBAAgB,MAAwB;AAC9C,UAAM,UAAU,QAAQ,IAAI;AAAA,MAC1B,QAAQ,KAAK,UAAU;AAAA,MACvB,KAAK;AAAA,MACL,MAAM;AAAA,MACN,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,SAAS,KAAK,kBAAkB,IAAI;AAAA,MACpC,MAAM;AAAA,MACN,QAAQ;AAAA,QACN,MAAM;AAAA,MACR;AAAA,MACA,OAAO;AAAA,QACL,QAAQ;AAAA,UACN,IAAI;AAAA,QACN;AAAA,MACF;AAAA,MACA,YAAY;AAAA,MACZ,MAAM;AAAA,MACN,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,OAAO,UAAU,KAAK,UAAU,MAAM,KAAK,KAAK;AAAA,IAClD,CAAC;AAED,YAAQ,IAAI,CAAC,UAAU,GAAG,GAAG,MAAM;AACjC,cAAQ,QAAQ;AAChB,WAAK,UAAU,OAAO,OAAO;AAAA,IAC/B,CAAC;AAED,YAAQ,MAAM;AACd,SAAK,UAAU,OAAO,OAAO;AAAA,EAC/B;AAAA,EAEQ,kBAAkB,MAA0B;AAClD,QAAI,UAAU,gBAAgB,KAAK,UAAU;AAAA;AAC7C,eAAW,mBAAmB,KAAK,KAAK;AAAA;AACxC,eAAW,mBAAmB,KAAK,KAAK;AAAA;AACxC,eAAW,sBAAsB,KAAK,gBAAgB,KAAK,QAAQ,CAAC,IAAI,KAAK,YAAY,MAAM;AAAA;AAE/F,QAAI,KAAK,UAAU;AACjB,UAAI,OAAO,KAAK,aAAa,UAAU;AACrC,mBAAW,sBAAsB,KAAK,QAAQ;AAAA;AAAA,MAChD,OAAO;AACL,mBAAW,sBAAsB,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS,KAAK;AAAA;AAAA,MAC7E;AAAA,IACF;AAEA,QAAI,KAAK,UAAU;AACjB,iBAAW,sBAAsB,KAAK,QAAQ;AAAA;AAAA,IAChD;AAEA,QAAI,KAAK,SAAS;AAChB,YAAM,YAAY,KAAK,gBAAgB,KAAK,OAAO;AACnD,YAAM,WACJ,YAAY,IAAI,QAAQ,aAAa,IAAI,WAAW;AACtD,iBAAW,uBAAuB,QAAQ,OAAO,IAAI,KAAK,KAAK,OAAO,EAAE,mBAAmB,CAAC;AAAA;AAAA,IAC9F;AAEA,QAAI,KAAK,UAAU,KAAK,OAAO,SAAS,GAAG;AACzC,iBAAW,oBAAoB,KAAK,OAAO,IAAI,CAAC,MAAM,aAAa,CAAC,KAAK,EAAE,KAAK,GAAG,CAAC;AAAA;AAAA,IACtF;AAEA,QAAI,KAAK,aAAa;AACpB,iBAAW;AAAA;AAAA,EAA4B,KAAK,WAAW;AAAA;AAAA,IACzD;AAEA,QAAI,KAAK,YAAY,KAAK,SAAS,SAAS,GAAG;AAC7C,iBAAW;AAAA,mBAAsB,KAAK,SAAS,MAAM;AAAA;AACrD,WAAK,SAAS,MAAM,EAAE,EAAE,QAAQ,CAAC,YAAY;AAC3C,mBAAW;AAAA,WAAc,QAAQ,MAAM,MAAM,IAAI,KAAK,QAAQ,SAAS,EAAE,eAAe,CAAC;AAAA;AACzF,mBAAW,GAAG,QAAQ,IAAI;AAAA;AAAA,MAC5B,CAAC;AAAA,IACH;AAEA,QAAI,KAAK,YAAY,KAAK,SAAS,SAAS,GAAG;AAC7C,iBAAW;AAAA;AAAA;AACX,WAAK,SAAS,QAAQ,CAAC,YAAY;AACjC,cAAM,QAAQ,QAAQ,YAAY,WAAM;AACxC,mBAAW,KAAK,KAAK,IAAI,QAAQ,KAAK;AAAA;AAAA,MACxC,CAAC;AAAA,IACH;AAEA,eAAW;AAAA;AAAA;AACX,eAAW;AAAA;AAEX,WAAO;AAAA,EACT;AAAA,EAEQ,gBAAsB;AAC5B,UAAM,OAAO,QAAQ,KAAK;AAAA,MACxB,QAAQ,KAAK,UAAU;AAAA,MACvB,KAAK;AAAA,MACL,MAAM;AAAA,MACN,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,QAAQ;AAAA,QACN,MAAM;AAAA,MACR;AAAA,MACA,OAAO;AAAA,QACL,QAAQ;AAAA,UACN,IAAI;AAAA,QACN;AAAA,MACF;AAAA,MACA,OAAO;AAAA,MACP,MAAM;AAAA,IACR,CAAC;AAED,UAAM,aAAa,QAAQ,KAAK;AAAA,MAC9B,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,KAAK;AAAA,MACL,MAAM;AAAA,IACR,CAAC;AAED,UAAM,aAAa,QAAQ,QAAQ;AAAA,MACjC,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,KAAK;AAAA,MACL,MAAM;AAAA,MACN,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,cAAc;AAAA,MACd,OAAO;AAAA,QACL,OAAO;AAAA,UACL,IAAI;AAAA,UACJ,IAAI;AAAA,QACN;AAAA,MACF;AAAA,IACF,CAAC;AAED,UAAM,YAAY,QAAQ,KAAK;AAAA,MAC7B,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,KAAK;AAAA,MACL,MAAM;AAAA,IACR,CAAC;AAED,UAAM,YAAY,QAAQ,SAAS;AAAA,MACjC,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,KAAK;AAAA,MACL,MAAM;AAAA,MACN,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,cAAc;AAAA,MACd,OAAO;AAAA,QACL,OAAO;AAAA,UACL,IAAI;AAAA,UACJ,IAAI;AAAA,QACN;AAAA,MACF;AAAA,IACF,CAAC;AAED,UAAM,YAAY,QAAQ,OAAO;AAAA,MAC/B,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,KAAK;AAAA,MACL,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,OAAO;AAAA,QACL,OAAO;AAAA,UACL,IAAI;AAAA,UACJ,IAAI;AAAA,QACN;AAAA,MACF;AAAA,IACF,CAAC;AAED,cAAU,GAAG,SAAS,MAAM;AAC1B,YAAM,QAAQ,WAAW,SAAS;AAClC,YAAM,cAAc,UAAU,SAAS;AAEvC,UAAI,OAAO;AACT,aAAK,KAAK,eAAe,EAAE,OAAO,YAAY,CAAC;AAAA,MACjD;AAEA,WAAK,QAAQ;AACb,WAAK,UAAU,OAAO,OAAO;AAAA,IAC/B,CAAC;AAED,SAAK,IAAI,CAAC,QAAQ,GAAG,MAAM;AACzB,WAAK,QAAQ;AACb,WAAK,UAAU,OAAO,OAAO;AAAA,IAC/B,CAAC;AAED,eAAW,MAAM;AACjB,SAAK,UAAU,OAAO,OAAO;AAAA,EAC/B;AAAA,EAEQ,aAAa,QAAsB;AACzC,UAAM,OAAO,KAAK,MAAM,IAAI,MAAM;AAClC,QAAI,MAAM;AACR,WAAK,KAAK,eAAe;AAAA,QACvB,QAAQ,KAAK;AAAA,QACb,SAAS,EAAE,OAAO,YAAY;AAAA,MAChC,CAAC;AAGD,WAAK,QAAQ;AACb,WAAK,OAAO,MAAM,KAAK,KAAK,MAAM,OAAO,CAAC,CAAC;AAAA,IAC7C;AAAA,EACF;AAAA,EAEQ,WAAW,QAAsB;AAEvC,SAAK,KAAK,eAAe,EAAE,OAAO,CAAC;AAAA,EACrC;AAAA,EAEO,QAAc;AACnB,UAAM,SAAS,KAAK,QAAQ,IAAI,KAAK,aAAa;AAClD,QAAI,QAAQ;AACV,aAAO,MAAM;AAAA,IACf;AAAA,EACF;AAAA,EAEO,WAAoB;AACzB,WAAO,MAAM,KAAK,KAAK,QAAQ,OAAO,CAAC,EAAE;AAAA,MACvC,CAAC,QAAQ,QAAQ,KAAK,UAAU,OAAO;AAAA,IACzC;AAAA,EACF;AACF;",
|
|
4
|
+
"sourcesContent": ["/**\n * Task Board Component\n * Displays Linear tasks with live synchronization\n */\n\nimport blessed from 'blessed';\nimport { EventEmitter } from 'events';\nimport type { LinearTask, TaskColumn } from '../types.js';\n\nexport class TaskBoard extends EventEmitter {\n private container: blessed.Widgets.BoxElement;\n private columns: Map<string, blessed.Widgets.ListElement>;\n private tasks: Map<string, LinearTask>;\n private selectedTask: string | null = null;\n private currentColumn: string = 'todo';\n\n private readonly columnConfig: TaskColumn[] = [\n { id: 'backlog', title: 'Backlog', color: 'gray' },\n { id: 'todo', title: 'To Do', color: 'cyan' },\n { id: 'in_progress', title: 'In Progress', color: 'yellow' },\n { id: 'review', title: 'Review', color: 'magenta' },\n { id: 'done', title: 'Done', color: 'green' },\n ];\n\n constructor(container: blessed.Widgets.BoxElement) {\n super();\n this.container = container;\n this.columns = new Map();\n this.tasks = new Map();\n this.initializeUI();\n }\n\n private initializeUI(): void {\n const columnWidth = Math.floor(100 / this.columnConfig.length);\n\n this.columnConfig.forEach((column, index) => {\n // Column container\n const columnBox = blessed.box({\n parent: this.container,\n left: `${index * columnWidth}%`,\n top: 0,\n width: `${columnWidth}%`,\n height: '100%',\n border: {\n type: 'line',\n },\n style: {\n border: {\n fg: column.color,\n },\n },\n label: ` ${column.title} `,\n });\n\n // Task list within column\n const taskList = blessed.list({\n parent: columnBox,\n top: 0,\n left: 0,\n width: '100%-2',\n height: '100%-2',\n style: {\n selected: {\n bg: column.color,\n fg: 'black',\n bold: true,\n },\n item: {\n fg: 'white',\n },\n },\n mouse: true,\n keys: true,\n vi: true,\n scrollable: true,\n tags: true,\n });\n\n taskList.on('select', (item, index) => {\n const tasksInColumn = this.getTasksInColumn(column.id);\n if (tasksInColumn[index]) {\n this.selectTask(tasksInColumn[index].id);\n }\n });\n\n this.columns.set(column.id, taskList);\n });\n\n // Set up keyboard navigation\n this.setupKeyboardNavigation();\n }\n\n private setupKeyboardNavigation(): void {\n const container = this.container;\n\n // Navigate between columns\n container.key(['left', 'h'], () => {\n this.navigateColumn(-1);\n });\n\n container.key(['right', 'l'], () => {\n this.navigateColumn(1);\n });\n\n // Move tasks between columns\n container.key(['S-left'], () => {\n this.moveTaskToColumn(-1);\n });\n\n container.key(['S-right'], () => {\n this.moveTaskToColumn(1);\n });\n\n // Quick actions - Enter opens task completion menu\n container.key(['enter'], () => {\n if (this.selectedTask) {\n this.showTaskCompletionMenu(this.tasks.get(this.selectedTask)!);\n }\n });\n\n container.key(['n'], () => {\n this.createNewTask();\n });\n\n container.key(['d'], () => {\n if (this.selectedTask) {\n this.markTaskDone(this.selectedTask);\n }\n });\n\n container.key(['a'], () => {\n if (this.selectedTask) {\n this.assignTask(this.selectedTask);\n }\n });\n\n // Update task status (u key)\n container.key(['u'], () => {\n if (this.selectedTask) {\n this.showStatusUpdateDialog(this.selectedTask);\n }\n });\n\n // Start working on task with Claude (c key)\n container.key(['c'], () => {\n if (this.selectedTask) {\n this.startTaskWithClaude(this.selectedTask);\n }\n });\n\n // Sync with Linear (s key)\n container.key(['s'], () => {\n this.syncWithLinear();\n });\n }\n\n private getTasksInColumn(columnId: string): LinearTask[] {\n return Array.from(this.tasks.values())\n .filter((task) => this.getTaskColumn(task) === columnId)\n .sort((a, b) => (b.priority || 0) - (a.priority || 0));\n }\n\n private getTaskColumn(task: LinearTask): string {\n // Map Linear states to our columns - handle both raw API states and formatted display states\n const stateMapping: Record<string, string> = {\n // Raw Linear API states\n backlog: 'backlog',\n unstarted: 'todo',\n started: 'in_progress',\n completed: 'done',\n canceled: 'done',\n cancelled: 'done',\n // Formatted display states from data service\n Backlog: 'backlog',\n 'To Do': 'todo',\n 'In Progress': 'in_progress',\n Done: 'done',\n Canceled: 'done',\n // Legacy mappings\n todo: 'todo',\n in_progress: 'in_progress',\n in_review: 'review',\n done: 'done',\n };\n\n const state = task.state || 'todo';\n return stateMapping[state] || stateMapping[state.toLowerCase()] || 'todo';\n }\n\n private formatTaskItem(task: LinearTask): string {\n const priority = this.getPriorityIcon(task.priority);\n const estimate = task.estimate ? `[${task.estimate}]` : '';\n\n // Handle both object and string assignee formats\n let assignee: string;\n if (typeof task.assignee === 'string') {\n assignee = `@${task.assignee}`;\n } else if (task.assignee?.name) {\n assignee = `@${task.assignee.name}`;\n } else {\n assignee = '{gray-fg}unassigned{/}';\n }\n\n const labels = task.labels?.map((l) => `{cyan-fg}#${l}{/}`).join(' ') || '';\n\n // Show task identifier (STA-100) prominently with description preview\n let taskStr = `${priority} {bold}${task.identifier}{/}: ${task.title}\\n`;\n \n // Add description preview if available (first line or 60 chars)\n if (task.description && task.description.trim()) {\n const descPreview = task.description.split('\\n')[0].substring(0, 60).trim();\n taskStr += ` {gray-fg}${descPreview}${task.description.length > 60 ? '...' : ''}{/}\\n`;\n }\n \n taskStr += ` {gray-fg}${assignee} ${estimate} ${labels}{/}`;\n\n // Add progress indicators\n if (task.progress !== undefined) {\n const progressBar = this.createProgressBar(task.progress);\n taskStr += `\\n ${progressBar}`;\n }\n\n // Add due date warning\n if (task.dueDate) {\n const daysUntilDue = this.getDaysUntilDue(task.dueDate);\n if (daysUntilDue < 0) {\n taskStr += ` {red-fg}\u26A0 Overdue{/}`;\n } else if (daysUntilDue <= 1) {\n taskStr += ` {yellow-fg}\u26A0 Due soon{/}`;\n }\n }\n\n return taskStr;\n }\n\n private getPriorityIcon(priority?: number): string {\n if (!priority) return '\u25CB';\n switch (priority) {\n case 0:\n return '{red-fg}\uD83D\uDD34{/}'; // Urgent\n case 1:\n return '{yellow-fg}\uD83D\uDFE1{/}'; // High\n case 2:\n return '{green-fg}\uD83D\uDFE2{/}'; // Medium\n case 3:\n return '{blue-fg}\uD83D\uDD35{/}'; // Low\n default:\n return '\u25CB';\n }\n }\n\n private createProgressBar(progress: number): string {\n const width = 10;\n const filled = Math.round(progress * width);\n const empty = width - filled;\n\n const color = progress >= 1 ? 'green' : progress >= 0.5 ? 'yellow' : 'red';\n return `{${color}-fg}${'\u2588'.repeat(filled)}{/}{gray-fg}${'\u2591'.repeat(empty)}{/} ${Math.round(progress * 100)}%`;\n }\n\n private getDaysUntilDue(dueDate: string): number {\n const due = new Date(dueDate);\n const now = new Date();\n const diffTime = due.getTime() - now.getTime();\n return Math.ceil(diffTime / (1000 * 60 * 60 * 24));\n }\n\n public update(tasks: LinearTask[]): void {\n // Update task map\n this.tasks.clear();\n tasks.forEach((task) => {\n this.tasks.set(task.id, task);\n });\n\n // Update each column\n this.columnConfig.forEach((column) => {\n const columnTasks = this.getTasksInColumn(column.id);\n const items = columnTasks.map((task) => this.formatTaskItem(task));\n\n const list = this.columns.get(column.id);\n if (list) {\n list.setItems(items);\n\n // Update column label with count\n const parent = list.parent;\n if (parent && typeof (parent as any).setLabel === 'function') {\n (parent as any).setLabel(` ${column.title} (${columnTasks.length}) `);\n }\n }\n });\n\n this.container.screen.render();\n }\n\n private navigateColumn(direction: number): void {\n const columnIds = this.columnConfig.map((c) => c.id);\n const currentIndex = columnIds.indexOf(this.currentColumn);\n const newIndex = Math.max(\n 0,\n Math.min(columnIds.length - 1, currentIndex + direction)\n );\n\n this.currentColumn = columnIds[newIndex];\n this.columns.get(this.currentColumn)?.focus();\n this.container.screen.render();\n }\n\n private moveTaskToColumn(direction: number): void {\n if (!this.selectedTask) return;\n\n const task = this.tasks.get(this.selectedTask);\n if (!task) return;\n\n const columnIds = this.columnConfig.map((c) => c.id);\n const currentColumnIndex = columnIds.indexOf(this.getTaskColumn(task));\n const newColumnIndex = Math.max(\n 0,\n Math.min(columnIds.length - 1, currentColumnIndex + direction)\n );\n const newColumn = columnIds[newColumnIndex];\n\n // Emit event to update task state in Linear\n this.emit('task:move', {\n taskId: task.id,\n fromColumn: columnIds[currentColumnIndex],\n toColumn: newColumn,\n });\n\n // Optimistically update UI\n const stateMapping: Record<string, string> = {\n backlog: 'backlog',\n todo: 'unstarted',\n in_progress: 'started',\n review: 'in_review',\n done: 'completed',\n };\n\n task.state = stateMapping[newColumn] || task.state;\n this.update(Array.from(this.tasks.values()));\n }\n\n private selectTask(taskId: string): void {\n this.selectedTask = taskId;\n const task = this.tasks.get(taskId);\n if (task) {\n this.emit('task:selected', task);\n }\n }\n\n private showTaskDetails(task: LinearTask): void {\n const details = blessed.box({\n parent: this.container.screen,\n top: 'center',\n left: 'center',\n width: '70%',\n height: '70%',\n content: this.formatTaskDetails(task),\n tags: true,\n border: {\n type: 'line',\n },\n style: {\n border: {\n fg: 'green',\n },\n },\n scrollable: true,\n keys: true,\n vi: true,\n mouse: true,\n hidden: false,\n label: ` Task: ${task.identifier} - ${task.title} `,\n });\n\n details.key(['escape', 'q'], () => {\n details.destroy();\n this.container.screen.render();\n });\n\n details.focus();\n this.container.screen.render();\n }\n\n private formatTaskDetails(task: LinearTask): string {\n let details = `{bold}ID:{/} ${task.identifier}\\n`;\n details += `{bold}Title:{/} ${task.title}\\n`;\n details += `{bold}State:{/} ${task.state}\\n`;\n details += `{bold}Priority:{/} ${this.getPriorityIcon(task.priority)} ${task.priority || 'None'}\\n`;\n\n if (task.assignee) {\n if (typeof task.assignee === 'string') {\n details += `{bold}Assignee:{/} ${task.assignee}\\n`;\n } else {\n details += `{bold}Assignee:{/} ${task.assignee.name} (${task.assignee.email})\\n`;\n }\n }\n\n if (task.estimate) {\n details += `{bold}Estimate:{/} ${task.estimate} points\\n`;\n }\n\n if (task.dueDate) {\n const daysUntil = this.getDaysUntilDue(task.dueDate);\n const dueColor =\n daysUntil < 0 ? 'red' : daysUntil <= 1 ? 'yellow' : 'white';\n details += `{bold}Due Date:{/} {${dueColor}-fg}${new Date(task.dueDate).toLocaleDateString()}{/}\\n`;\n }\n\n if (task.labels && task.labels.length > 0) {\n details += `{bold}Labels:{/} ${task.labels.map((l) => `{cyan-fg}#${l}{/}`).join(' ')}\\n`;\n }\n\n if (task.description) {\n details += `\\n{bold}Description:{/}\\n${task.description}\\n`;\n }\n\n if (task.comments && task.comments.length > 0) {\n details += `\\n{bold}Comments ({${task.comments.length}}):{/}\\n`;\n task.comments.slice(-5).forEach((comment) => {\n details += `\\n{gray-fg}${comment.author} - ${new Date(comment.createdAt).toLocaleString()}{/}\\n`;\n details += `${comment.body}\\n`;\n });\n }\n\n if (task.subtasks && task.subtasks.length > 0) {\n details += `\\n{bold}Subtasks:{/}\\n`;\n task.subtasks.forEach((subtask) => {\n const check = subtask.completed ? '\u2713' : '\u25CB';\n details += ` ${check} ${subtask.title}\\n`;\n });\n }\n\n details += `\\n{bold}Actions:{/}\\n`;\n details += ` [d] Mark Done | [a] Assign | [c] Comment | [e] Edit\\n`;\n\n return details;\n }\n\n private createNewTask(): void {\n const form = blessed.form({\n parent: this.container.screen,\n top: 'center',\n left: 'center',\n width: '50%',\n height: 14,\n border: {\n type: 'line',\n },\n style: {\n border: {\n fg: 'cyan',\n },\n },\n label: ' Create New Task ',\n keys: true,\n });\n\n const titleLabel = blessed.text({\n parent: form,\n content: 'Title:',\n top: 1,\n left: 2,\n });\n\n const titleInput = blessed.textbox({\n parent: form,\n name: 'title',\n top: 1,\n left: 10,\n width: '100%-12',\n height: 1,\n inputOnFocus: true,\n style: {\n focus: {\n fg: 'white',\n bg: 'blue',\n },\n },\n });\n\n const descLabel = blessed.text({\n parent: form,\n content: 'Desc:',\n top: 3,\n left: 2,\n });\n\n const descInput = blessed.textarea({\n parent: form,\n name: 'description',\n top: 3,\n left: 10,\n width: '100%-12',\n height: 4,\n inputOnFocus: true,\n style: {\n focus: {\n fg: 'white',\n bg: 'blue',\n },\n },\n });\n\n const submitBtn = blessed.button({\n parent: form,\n content: ' Create ',\n top: 9,\n left: 'center',\n shrink: true,\n style: {\n focus: {\n bg: 'green',\n fg: 'white',\n },\n },\n });\n\n submitBtn.on('press', () => {\n const title = titleInput.getValue();\n const description = descInput.getValue();\n\n if (title) {\n this.emit('task:create', { title, description });\n }\n\n form.destroy();\n this.container.screen.render();\n });\n\n form.key(['escape'], () => {\n form.destroy();\n this.container.screen.render();\n });\n\n titleInput.focus();\n this.container.screen.render();\n }\n\n private markTaskDone(taskId: string): void {\n const task = this.tasks.get(taskId);\n if (task) {\n this.emit('task:update', {\n taskId: task.id,\n updates: { state: 'completed' },\n });\n\n // Optimistically update UI\n task.state = 'completed';\n this.update(Array.from(this.tasks.values()));\n }\n }\n\n private assignTask(taskId: string): void {\n // Would open assignment dialog\n this.emit('task:assign', { taskId });\n }\n\n public focus(): void {\n const column = this.columns.get(this.currentColumn);\n if (column) {\n column.focus();\n }\n }\n\n public hasFocus(): boolean {\n return Array.from(this.columns.values()).some(\n (col) => col === this.container.screen.focused\n );\n }\n\n private showStatusUpdateDialog(taskId: string): void {\n const task = this.tasks.get(taskId);\n if (!task) return;\n\n // Create status selection dialog\n const dialog = blessed.list({\n parent: this.container.screen,\n top: 'center',\n left: 'center',\n width: '50%',\n height: 12,\n border: {\n type: 'line',\n },\n style: {\n border: {\n fg: 'yellow',\n },\n selected: {\n bg: 'blue',\n fg: 'white',\n },\n },\n label: ` Update Status: ${task.title.substring(0, 40)}... `,\n items: [\n '1. Backlog',\n '2. Todo',\n '3. In Progress',\n '4. In Review',\n '5. Done',\n '6. Canceled',\n '',\n 'ESC to cancel',\n ],\n keys: true,\n vi: true,\n mouse: true,\n });\n\n dialog.on('select', (item: any, index: number) => {\n const statusMap = ['backlog', 'todo', 'in_progress', 'review', 'completed', 'cancelled'];\n if (index < statusMap.length) {\n this.updateTaskStatus(taskId, statusMap[index]);\n }\n dialog.destroy();\n this.container.screen.render();\n });\n\n dialog.key(['escape'], () => {\n dialog.destroy();\n this.container.screen.render();\n });\n\n dialog.focus();\n this.container.screen.render();\n }\n\n private async updateTaskStatus(taskId: string, newStatus: string): Promise<void> {\n const task = this.tasks.get(taskId);\n if (!task) return;\n\n // Update local state immediately for responsiveness\n task.state = this.mapStatusToLinearState(newStatus);\n this.update(Array.from(this.tasks.values()));\n\n // Emit event for status update\n this.emit('task:status:update', {\n taskId,\n oldStatus: task.state,\n newStatus,\n linearId: task.identifier,\n });\n\n // Show notification\n const notification = blessed.message({\n parent: this.container.screen,\n top: 'center',\n left: 'center',\n width: '50%',\n height: 3,\n border: {\n type: 'line',\n },\n style: {\n border: {\n fg: 'green',\n },\n },\n content: `Task status updated to: ${newStatus}`,\n });\n\n setTimeout(() => {\n notification.destroy();\n this.container.screen.render();\n }, 1500);\n\n this.container.screen.render();\n }\n\n private async startTaskWithClaude(taskId: string): Promise<void> {\n const task = this.tasks.get(taskId);\n if (!task) return;\n\n try {\n const { exec } = await import('child_process');\n const fs = await import('fs/promises');\n const os = await import('os');\n const path = await import('path');\n \n // Create a context file with task details\n const contextDir = path.join(os.homedir(), '.stackmemory', 'task-contexts');\n await fs.mkdir(contextDir, { recursive: true });\n const contextFile = path.join(contextDir, `${task.identifier}-context.md`);\n const contextContent = `# Task: ${task.identifier} - ${task.title}\n\n## Description\n${task.description || 'No description provided'}\n\n## Status\nCurrent: ${task.state}\nPriority: ${this.getPriorityLabel(task.priority)}\n\n## Linear Task ID\n${task.identifier}\n\n## Quick Commands\n- Update status: stackmemory task:update \"${task.identifier}\" --status <status>\n- Add comment: stackmemory task:comment \"${task.identifier}\" --message \"<comment>\"\n- View details: stackmemory task:show \"${task.identifier}\"\n\n---\nThis task has been loaded from Linear. The context above provides the task details.\nStart working on this task below:\n`;\n \n await fs.writeFile(contextFile, contextContent);\n \n // Build the claude-sm command\n const command = `claude-sm --task \"${task.identifier}: ${task.title}\" --context \"${contextFile}\"`;\n \n // Show launching notification\n const notification = blessed.message({\n parent: this.container.screen,\n top: 'center',\n left: 'center',\n width: '60%',\n height: 5,\n border: {\n type: 'line',\n },\n style: {\n border: {\n fg: 'cyan',\n },\n },\n content: `Launching Claude for task:\\n${task.identifier}: ${task.title}\\n\\nCommand: ${command}`,\n });\n \n this.container.screen.render();\n \n // Execute in background\n exec(command, (error, stdout, stderr) => {\n if (error) {\n const errorMsg = blessed.message({\n parent: this.container.screen,\n top: 'center',\n left: 'center',\n width: '50%',\n height: 4,\n border: {\n type: 'line',\n },\n style: {\n border: {\n fg: 'red',\n },\n },\n content: `Failed to launch Claude: ${error.message}`,\n });\n \n setTimeout(() => {\n errorMsg.destroy();\n this.container.screen.render();\n }, 3000);\n }\n });\n \n setTimeout(() => {\n notification.destroy();\n this.container.screen.render();\n }, 2000);\n \n // Emit event for tracking\n this.emit('task:launch:claude', {\n taskId,\n command,\n task,\n contextFile,\n });\n \n } catch (error: any) {\n const errorMsg = blessed.message({\n parent: this.container.screen,\n top: 'center',\n left: 'center',\n width: '50%',\n height: 4,\n border: {\n type: 'line',\n },\n style: {\n border: {\n fg: 'red',\n },\n },\n content: `Error: ${error.message}`,\n });\n \n setTimeout(() => {\n errorMsg.destroy();\n this.container.screen.render();\n }, 3000);\n \n this.container.screen.render();\n }\n }\n\n private showTaskCompletionMenu(task: LinearTask): void {\n // Create completion menu with task details and actions\n const menuBox = blessed.box({\n parent: this.container.screen,\n top: 'center',\n left: 'center',\n width: '70%',\n height: '80%',\n border: {\n type: 'line',\n },\n style: {\n border: {\n fg: 'cyan',\n },\n },\n label: ` Task Completion Menu: ${task.identifier} `,\n keys: true,\n mouse: true,\n });\n\n // Task header with ID and description\n const header = blessed.text({\n parent: menuBox,\n top: 1,\n left: 2,\n width: '100%-4',\n height: 5,\n content: `{bold}${task.identifier}: ${task.title}{/}\\n\\n` +\n `{gray-fg}${(task.description || 'No description').substring(0, 200)}{/}`,\n tags: true,\n wrap: true,\n });\n\n // Current status display\n const statusDisplay = blessed.text({\n parent: menuBox,\n top: 7,\n left: 2,\n content: `{bold}Current Status:{/} ${this.formatStatus(task.state)}`,\n tags: true,\n });\n\n // Menu options\n const menu = blessed.list({\n parent: menuBox,\n top: 9,\n left: 2,\n width: '100%-4',\n height: 12,\n border: {\n type: 'line',\n },\n style: {\n border: {\n fg: 'gray',\n },\n selected: {\n bg: 'blue',\n fg: 'white',\n },\n },\n label: ' Quick Actions ',\n items: [\n '1. \u2705 Mark as Done',\n '2. \uD83D\uDD04 Change Status',\n '3. \uD83C\uDFAF Update Priority',\n '4. \uD83D\uDC64 Assign to Someone',\n '5. \uD83D\uDCAC Add Comment',\n '6. \uD83D\uDCDD Edit Description',\n '7. \uD83D\uDE80 Start with Claude',\n '8. \uD83D\uDD0D View Full Details',\n '9. \u274C Cancel Task',\n ],\n keys: true,\n vi: true,\n mouse: true,\n });\n\n // Task metadata\n const metadata = blessed.text({\n parent: menuBox,\n bottom: 3,\n left: 2,\n width: '100%-4',\n height: 4,\n content: this.formatTaskMetadata(task),\n tags: true,\n });\n\n // Instructions\n const instructions = blessed.text({\n parent: menuBox,\n bottom: 1,\n left: 2,\n content: '{gray-fg}Use arrows/numbers to select \u2022 Enter to execute \u2022 ESC to close{/}',\n tags: true,\n });\n\n // Handle menu selection\n menu.on('select', (item, index) => {\n menuBox.destroy();\n \n switch (index) {\n case 0: // Mark as Done\n this.updateTaskStatus(task.id, 'completed');\n this.showNotification(`\u2705 Task ${task.identifier} marked as done`);\n break;\n case 1: // Change Status\n this.showStatusUpdateDialog(task.id);\n break;\n case 2: // Update Priority\n this.showPriorityUpdateDialog(task);\n break;\n case 3: // Assign\n this.showAssignDialog(task);\n break;\n case 4: // Add Comment\n this.showCommentDialog(task);\n break;\n case 5: // Edit Description\n this.showEditDescriptionDialog(task);\n break;\n case 6: // Start with Claude\n this.startTaskWithClaude(task.id);\n break;\n case 7: // View Full Details\n this.showTaskDetails(task);\n break;\n case 8: // Cancel Task\n this.updateTaskStatus(task.id, 'canceled');\n this.showNotification(`\u274C Task ${task.identifier} canceled`);\n break;\n }\n \n this.container.screen.render();\n });\n\n // Handle number keys for quick selection\n menu.key(['1', '2', '3', '4', '5', '6', '7', '8', '9'], (ch) => {\n const index = parseInt(ch, 10) - 1;\n if (index < menu.items.length) {\n menu.select(index);\n menu.emit('select', menu.items[index], index);\n }\n });\n\n // ESC to close\n menuBox.key(['escape', 'q'], () => {\n menuBox.destroy();\n this.container.screen.render();\n });\n\n menu.focus();\n this.container.screen.render();\n }\n\n private formatStatus(state: string): string {\n const statusColors: Record<string, string> = {\n backlog: '{gray-fg}\uD83D\uDCCB Backlog{/}',\n unstarted: '{yellow-fg}\u23F8\uFE0F Todo{/}',\n started: '{blue-fg}\u25B6\uFE0F In Progress{/}',\n completed: '{green-fg}\u2705 Done{/}',\n canceled: '{red-fg}\u274C Canceled{/}',\n };\n return statusColors[state.toLowerCase()] || state;\n }\n\n private formatTaskMetadata(task: LinearTask): string {\n let meta = '';\n \n if (task.assignee) {\n const name = typeof task.assignee === 'string' ? task.assignee : task.assignee.name;\n meta += `{bold}Assignee:{/} ${name} `;\n }\n \n if (task.priority !== undefined) {\n meta += `{bold}Priority:{/} ${this.getPriorityLabel(task.priority)} `;\n }\n \n if (task.estimate) {\n meta += `{bold}Points:{/} ${task.estimate} `;\n }\n \n if (task.dueDate) {\n const daysUntil = this.getDaysUntilDue(task.dueDate);\n const color = daysUntil < 0 ? 'red' : daysUntil <= 1 ? 'yellow' : 'white';\n meta += `{bold}Due:{/} {${color}-fg}${new Date(task.dueDate).toLocaleDateString()}{/}`;\n }\n \n return meta;\n }\n\n private getPriorityLabel(priority?: number): string {\n if (priority === undefined || priority === null) return 'None';\n const labels = ['Urgent', 'High', 'Medium', 'Low', 'None'];\n return labels[priority] || 'None';\n }\n\n private showPriorityUpdateDialog(task: LinearTask): void {\n const dialog = blessed.list({\n parent: this.container.screen,\n top: 'center',\n left: 'center',\n width: '40%',\n height: 9,\n border: {\n type: 'line',\n },\n style: {\n border: {\n fg: 'magenta',\n },\n selected: {\n bg: 'magenta',\n fg: 'white',\n },\n },\n label: ` Set Priority: ${task.identifier} `,\n items: [\n '\uD83D\uDD34 Urgent (P0)',\n '\uD83D\uDFE1 High (P1)',\n '\uD83D\uDFE2 Medium (P2)',\n '\uD83D\uDD35 Low (P3)',\n '\u26AA None',\n ],\n keys: true,\n vi: true,\n });\n\n dialog.on('select', (item, index) => {\n const priority = index < 4 ? index : undefined;\n this.emit('task:update', {\n taskId: task.id,\n updates: { priority },\n });\n dialog.destroy();\n this.showNotification(`\uD83C\uDFAF Priority updated for ${task.identifier}`);\n this.container.screen.render();\n });\n\n dialog.key(['escape'], () => {\n dialog.destroy();\n this.container.screen.render();\n });\n\n dialog.focus();\n this.container.screen.render();\n }\n\n private showAssignDialog(task: LinearTask): void {\n // Placeholder for assignment dialog\n this.showNotification('Assignment dialog coming soon!');\n }\n\n private showCommentDialog(task: LinearTask): void {\n const form = blessed.form({\n parent: this.container.screen,\n top: 'center',\n left: 'center',\n width: '60%',\n height: 10,\n border: {\n type: 'line',\n },\n style: {\n border: {\n fg: 'green',\n },\n },\n label: ` Add Comment to ${task.identifier} `,\n keys: true,\n });\n\n const commentInput = blessed.textarea({\n parent: form,\n top: 1,\n left: 1,\n width: '100%-2',\n height: 5,\n inputOnFocus: true,\n style: {\n focus: {\n fg: 'white',\n bg: 'blue',\n },\n },\n });\n\n const submitBtn = blessed.button({\n parent: form,\n content: ' Add Comment ',\n bottom: 1,\n left: 'center',\n shrink: true,\n style: {\n focus: {\n bg: 'green',\n fg: 'white',\n },\n },\n });\n\n submitBtn.on('press', () => {\n const comment = commentInput.getValue();\n if (comment) {\n this.emit('task:comment', { taskId: task.id, comment });\n this.showNotification(`\uD83D\uDCAC Comment added to ${task.identifier}`);\n }\n form.destroy();\n this.container.screen.render();\n });\n\n form.key(['escape'], () => {\n form.destroy();\n this.container.screen.render();\n });\n\n commentInput.focus();\n this.container.screen.render();\n }\n\n private showEditDescriptionDialog(task: LinearTask): void {\n const form = blessed.form({\n parent: this.container.screen,\n top: 'center',\n left: 'center',\n width: '70%',\n height: 15,\n border: {\n type: 'line',\n },\n style: {\n border: {\n fg: 'cyan',\n },\n },\n label: ` Edit Description: ${task.identifier} `,\n keys: true,\n });\n\n const descInput = blessed.textarea({\n parent: form,\n top: 1,\n left: 1,\n width: '100%-2',\n height: 10,\n inputOnFocus: true,\n content: task.description || '',\n style: {\n focus: {\n fg: 'white',\n bg: 'blue',\n },\n },\n });\n\n const submitBtn = blessed.button({\n parent: form,\n content: ' Save Description ',\n bottom: 1,\n left: 'center',\n shrink: true,\n style: {\n focus: {\n bg: 'cyan',\n fg: 'white',\n },\n },\n });\n\n submitBtn.on('press', () => {\n const description = descInput.getValue();\n this.emit('task:update', {\n taskId: task.id,\n updates: { description },\n });\n this.showNotification(`\uD83D\uDCDD Description updated for ${task.identifier}`);\n form.destroy();\n this.container.screen.render();\n });\n\n form.key(['escape'], () => {\n form.destroy();\n this.container.screen.render();\n });\n\n descInput.focus();\n this.container.screen.render();\n }\n\n private showNotification(message: string): void {\n const notification = blessed.box({\n parent: this.container.screen,\n top: 1,\n right: 1,\n width: message.length + 4,\n height: 3,\n content: ` ${message} `,\n style: {\n fg: 'white',\n bg: 'blue',\n },\n border: {\n type: 'line',\n fg: 'cyan',\n },\n });\n\n this.container.screen.render();\n\n // Auto-hide after 3 seconds\n setTimeout(() => {\n notification.destroy();\n this.container.screen.render();\n }, 3000);\n }\n\n\n private async syncWithLinear(): Promise<void> {\n try {\n // Show syncing notification\n const notification = blessed.box({\n parent: this.container.screen,\n top: 'center',\n left: 'center',\n width: '40%',\n height: 5,\n border: {\n type: 'line',\n },\n style: {\n border: {\n fg: 'cyan',\n },\n },\n content: '{center}Syncing with Linear...{/center}',\n tags: true,\n });\n \n this.container.screen.render();\n \n const { exec } = await import('child_process');\n const util = await import('util');\n const execAsync = util.promisify(exec);\n \n // Run the sync command\n await execAsync('cd /Users/jwu/Dev/stackmemory && npm run linear:sync');\n \n // Update notification\n notification.setContent('{center}\u2713 Sync complete! Refreshing...{/center}');\n notification.style.border.fg = 'green';\n \n setTimeout(() => {\n notification.destroy();\n // Trigger refresh of tasks\n this.emit('tasks:refresh');\n this.container.screen.render();\n }, 1000);\n \n } catch (error: any) {\n const errorMsg = blessed.message({\n parent: this.container.screen,\n top: 'center',\n left: 'center',\n width: '50%',\n height: 4,\n border: {\n type: 'line',\n },\n style: {\n border: {\n fg: 'red',\n },\n },\n content: `Sync failed: ${error.message}`,\n });\n \n setTimeout(() => {\n errorMsg.destroy();\n this.container.screen.render();\n }, 3000);\n \n this.container.screen.render();\n }\n }\n\n private mapStatusToLinearState(status: string): string {\n const mapping: Record<string, string> = {\n 'backlog': 'Backlog',\n 'todo': 'Todo', \n 'in_progress': 'In Progress',\n 'review': 'In Review',\n 'completed': 'Done',\n 'cancelled': 'Canceled',\n };\n return mapping[status] || 'Backlog';\n }\n\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["index"]
|
|
7
7
|
}
|
|
@@ -12,6 +12,17 @@ import { PRTracker } from "./components/pr-tracker.js";
|
|
|
12
12
|
import { AnalyticsPanel } from "./components/analytics-panel.js";
|
|
13
13
|
import { DataService } from "./services/data-service.js";
|
|
14
14
|
import { WebSocketClient } from "./services/websocket-client.js";
|
|
15
|
+
function getEnv(key, defaultValue) {
|
|
16
|
+
const value = process.env[key];
|
|
17
|
+
if (value === void 0) {
|
|
18
|
+
if (defaultValue !== void 0) return defaultValue;
|
|
19
|
+
throw new Error(`Environment variable ${key} is required`);
|
|
20
|
+
}
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
23
|
+
function getOptionalEnv(key) {
|
|
24
|
+
return process.env[key];
|
|
25
|
+
}
|
|
15
26
|
terminalCompat.configureEnvironment();
|
|
16
27
|
class StackMemoryTUI extends EventEmitter {
|
|
17
28
|
screen;
|
|
@@ -49,7 +60,7 @@ class StackMemoryTUI extends EventEmitter {
|
|
|
49
60
|
left: 0,
|
|
50
61
|
width: "100%",
|
|
51
62
|
height: 3,
|
|
52
|
-
content: "{center}\u{1F680} StackMemory TUI Dashboard v1.0.0{/center}",
|
|
63
|
+
content: "{center}\u{1F680} StackMemory TUI Dashboard v1.0.0 | [u]pdate status | [c]laude task | [s]ync | [q]uit{/center}",
|
|
53
64
|
tags: true,
|
|
54
65
|
style: {
|
|
55
66
|
fg: "white",
|
|
@@ -284,7 +295,7 @@ class StackMemoryTUI extends EventEmitter {
|
|
|
284
295
|
console.log("");
|
|
285
296
|
await new Promise((resolve) => setTimeout(resolve, 2e3));
|
|
286
297
|
}
|
|
287
|
-
if (process.env
|
|
298
|
+
if (process.env["DEBUG"] || process.env["TUI_DEBUG"]) {
|
|
288
299
|
console.log("\u{1F50D} Terminal Capabilities:");
|
|
289
300
|
console.log(` ${terminalCompat.getCapabilitiesString()}`);
|
|
290
301
|
console.log("");
|
|
@@ -299,7 +310,7 @@ class StackMemoryTUI extends EventEmitter {
|
|
|
299
310
|
if (this.config.refreshInterval > 0) {
|
|
300
311
|
this.refreshInterval = setInterval(() => {
|
|
301
312
|
this.updateAll().catch((error) => {
|
|
302
|
-
if (process.env
|
|
313
|
+
if (process.env["DEBUG"]) {
|
|
303
314
|
console.error("Update error:", error);
|
|
304
315
|
}
|
|
305
316
|
});
|
|
@@ -311,7 +322,7 @@ class StackMemoryTUI extends EventEmitter {
|
|
|
311
322
|
console.error("\n\u274C TUI startup error:", error);
|
|
312
323
|
if (error instanceof Error) {
|
|
313
324
|
console.error("Error details:", error.message);
|
|
314
|
-
if (process.env
|
|
325
|
+
if (process.env["DEBUG"]) {
|
|
315
326
|
console.error("Stack trace:", error.stack);
|
|
316
327
|
}
|
|
317
328
|
}
|
|
@@ -361,7 +372,7 @@ if (isMainModule) {
|
|
|
361
372
|
try {
|
|
362
373
|
tui = new StackMemoryTUI({
|
|
363
374
|
refreshInterval: 2e3,
|
|
364
|
-
wsUrl: process.env
|
|
375
|
+
wsUrl: process.env["STACKMEMORY_WS_URL"] || "ws://localhost:8080"
|
|
365
376
|
});
|
|
366
377
|
} catch (constructorError) {
|
|
367
378
|
console.error(
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/features/tui/index.ts"],
|
|
4
|
-
"sourcesContent": ["#!/usr/bin/env node\n/**\n * StackMemory TUI Dashboard\n * Interactive monitoring interface for sessions, tasks, frames, and integrations\n */\n\nimport 'dotenv/config';\nimport blessed from 'blessed';\nimport contrib from 'blessed-contrib';\nimport { EventEmitter } from 'events';\nimport { terminalCompat } from './terminal-compat.js';\nimport { SessionMonitor } from './components/session-monitor.js';\nimport { TaskBoard } from './components/task-board.js';\nimport { FrameVisualizer } from './components/frame-visualizer.js';\nimport { SubagentFleet } from './components/subagent-fleet.js';\nimport { PRTracker } from './components/pr-tracker.js';\nimport { AnalyticsPanel } from './components/analytics-panel.js';\nimport { DataService } from './services/data-service.js';\nimport { WebSocketClient } from './services/websocket-client.js';\nimport type { DashboardConfig, SessionData, TaskData } from './types.js';\n\n// Configure terminal environment before creating any blessed elements\nterminalCompat.configureEnvironment();\n\nexport class StackMemoryTUI extends EventEmitter {\n private screen: blessed.Widgets.Screen;\n private grid: any;\n private components: Map<string, any>;\n private dataService: DataService;\n private wsClient: WebSocketClient;\n private config: DashboardConfig;\n private refreshInterval: NodeJS.Timeout | null = null;\n\n constructor(config: DashboardConfig = {}) {\n super();\n this.config = {\n refreshInterval: 1000,\n wsUrl: 'ws://localhost:8080',\n theme: 'dark',\n ...config,\n };\n\n this.components = new Map();\n this.dataService = new DataService();\n this.wsClient = new WebSocketClient(this.config.wsUrl);\n this.screen = this.createScreen();\n this.grid = this.createGrid();\n this.initializeComponents();\n this.setupEventHandlers();\n }\n\n private createScreen(): blessed.Widgets.Screen {\n // Get terminal-specific configuration\n const blessedConfig = terminalCompat.getBlessedConfig();\n\n const screen = blessed.screen({\n ...blessedConfig,\n autoPadding: true,\n });\n\n // Add header\n const header = blessed.box({\n parent: screen,\n top: 0,\n left: 0,\n width: '100%',\n height: 3,\n content: '{center}\uD83D\uDE80 StackMemory TUI Dashboard v1.0.0{/center}',\n tags: true,\n style: {\n fg: 'white',\n bg: 'blue',\n bold: true,\n },\n });\n\n return screen;\n }\n\n private createGrid(): any {\n // Create a 12x12 grid for flexible layout\n const grid = new contrib.grid({\n rows: 12,\n cols: 12,\n screen: this.screen,\n });\n\n return grid;\n }\n\n private initializeComponents(): void {\n // Session Monitor (Top Left - 6x4)\n const sessionMonitor = new SessionMonitor(\n this.grid.set(0, 0, 4, 6, blessed.box, {\n label: '\uD83D\uDCCA Sessions',\n border: { type: 'line' },\n style: { border: { fg: 'cyan' } },\n })\n );\n this.components.set('sessions', sessionMonitor);\n\n // Task Board - Linear Integration (Top Right - 6x4)\n const taskBoard = new TaskBoard(\n this.grid.set(0, 6, 4, 6, blessed.box, {\n label: '\uD83D\uDCCB Linear Tasks',\n border: { type: 'line' },\n style: { border: { fg: 'green' } },\n })\n );\n this.components.set('tasks', taskBoard);\n\n // Frame Visualizer (Middle Left - 6x4)\n // Create a box container first, then add the tree inside\n const frameContainer = this.grid.set(4, 0, 4, 6, blessed.box, {\n label: '\uD83D\uDDC2\uFE0F Frame Storage',\n border: { type: 'line' },\n style: { border: { fg: 'yellow' } },\n });\n\n const frameTree = contrib.tree({\n parent: frameContainer,\n top: 0,\n left: 0,\n width: '100%-2',\n height: '100%-2',\n style: {\n text: 'green',\n selected: {\n bg: 'yellow',\n fg: 'black',\n },\n },\n template: {\n lines: true,\n },\n label: '',\n });\n\n const frameViz = new FrameVisualizer(frameTree);\n this.components.set('frames', frameViz);\n\n // Subagent Fleet (Middle Right - 6x4)\n const subagentFleet = new SubagentFleet(\n this.grid.set(4, 6, 4, 6, blessed.box, {\n label: '\uD83E\uDD16 Subagent Fleet',\n border: { type: 'line' },\n style: { border: { fg: 'magenta' } },\n })\n );\n this.components.set('subagents', subagentFleet);\n\n // PR/Issue Tracker (Bottom Left - 6x2)\n const prTracker = new PRTracker(\n this.grid.set(8, 0, 2, 6, blessed.list, {\n label: '\uD83D\uDD00 PR/Issues',\n border: { type: 'line' },\n style: { border: { fg: 'red' } },\n scrollable: true,\n mouse: true,\n })\n );\n this.components.set('prs', prTracker);\n\n // Analytics Panel (Bottom Right - 6x2)\n const analytics = new AnalyticsPanel(\n this.grid.set(8, 6, 2, 6, contrib.line, {\n label: '\uD83D\uDCC8 Analytics',\n border: { type: 'line' },\n style: {\n border: { fg: 'white' },\n line: 'yellow',\n text: 'green',\n baseline: 'black',\n },\n showLegend: true,\n wholeNumbersOnly: false,\n })\n );\n this.components.set('analytics', analytics);\n\n // Status Bar (Bottom - 12x2)\n const statusBar = blessed.box({\n parent: this.screen,\n bottom: 0,\n left: 0,\n width: '100%',\n height: 2,\n tags: true,\n style: {\n fg: 'white',\n bg: 'black',\n },\n });\n this.components.set('status', statusBar);\n\n this.updateStatusBar('Ready');\n }\n\n private setupEventHandlers(): void {\n // Keyboard shortcuts\n this.screen.key(['q', 'C-c'], () => {\n this.cleanup();\n process.exit(0);\n });\n\n this.screen.key(['r', 'C-r'], () => {\n this.refresh();\n });\n\n this.screen.key(['tab'], () => {\n this.focusNext();\n });\n\n this.screen.key(['S-tab'], () => {\n this.focusPrevious();\n });\n\n // View switching\n this.screen.key(['1'], () => this.showView('sessions'));\n this.screen.key(['2'], () => this.showView('tasks'));\n this.screen.key(['3'], () => this.showView('frames'));\n this.screen.key(['4'], () => this.showView('subagents'));\n this.screen.key(['5'], () => this.showView('prs'));\n this.screen.key(['6'], () => this.showView('analytics'));\n\n // WebSocket events\n this.wsClient.on('session:update', (data: SessionData) => {\n this.components.get('sessions')?.update(data);\n });\n\n this.wsClient.on('task:update', (data: TaskData) => {\n this.components.get('tasks')?.update(data);\n });\n\n this.wsClient.on('frame:update', (data) => {\n this.components.get('frames')?.update(data);\n });\n\n this.wsClient.on('agent:status', (data) => {\n this.components.get('subagents')?.update(data);\n });\n\n this.wsClient.on('pr:update', (data) => {\n this.components.get('prs')?.update(data);\n });\n\n // Data service events\n this.dataService.on('data:ready', () => {\n this.updateAll();\n });\n\n this.dataService.on('error', (error) => {\n this.showError(error.message);\n });\n }\n\n private async updateAll(): Promise<void> {\n try {\n // Fetch latest data\n const [sessions, tasks, frames, agents, prs, issues, analytics] =\n await Promise.all([\n this.dataService.getSessions(),\n this.dataService.getTasks(),\n this.dataService.getFrames(),\n this.dataService.getAgents(),\n this.dataService.getPRs(),\n this.dataService.getIssues(),\n this.dataService.getAnalytics(),\n ]);\n\n // Update components\n this.components.get('sessions')?.update(sessions);\n this.components.get('tasks')?.update(tasks);\n this.components.get('frames')?.update(frames);\n this.components.get('subagents')?.update(agents);\n // PR/Issue tracker expects an object with prs/issues\n this.components.get('prs')?.update({ prs, issues });\n this.components.get('analytics')?.update(analytics);\n\n this.updateStatusBar(`Last updated: ${new Date().toLocaleTimeString()}`);\n this.screen.render();\n } catch (error) {\n this.showError(`Update failed: ${error.message}`);\n }\n }\n\n private refresh(): void {\n this.updateStatusBar('Refreshing...');\n this.updateAll();\n }\n\n private focusNext(): void {\n const components = Array.from(this.components.values());\n const currentIndex = components.findIndex((c) => c.hasFocus?.());\n const nextIndex = (currentIndex + 1) % components.length;\n components[nextIndex]?.focus?.();\n this.screen.render();\n }\n\n private focusPrevious(): void {\n const components = Array.from(this.components.values());\n const currentIndex = components.findIndex((c) => c.hasFocus?.());\n const prevIndex =\n currentIndex <= 0 ? components.length - 1 : currentIndex - 1;\n components[prevIndex]?.focus?.();\n this.screen.render();\n }\n\n private showView(viewName: string): void {\n const component = this.components.get(viewName);\n if (component) {\n component.focus?.();\n component.show?.();\n this.updateStatusBar(`Viewing: ${viewName}`);\n this.screen.render();\n }\n }\n\n private updateStatusBar(message: string): void {\n const statusBar = this.components.get('status');\n if (statusBar) {\n const shortcuts =\n '{yellow-fg}[q]{/} Quit | {yellow-fg}[r]{/} Refresh | {yellow-fg}[Tab]{/} Navigate | {yellow-fg}[1-6]{/} Views';\n statusBar.setContent(`{bold}${message}{/} | ${shortcuts}`);\n this.screen.render();\n }\n }\n\n private showError(message: string): void {\n const msg = blessed.message({\n parent: this.screen,\n border: 'line',\n height: 'shrink',\n width: 'half',\n top: 'center',\n left: 'center',\n label: '{red-fg}Error{/}',\n tags: true,\n hidden: true,\n });\n\n msg.display(message, () => {\n msg.destroy();\n this.screen.render();\n });\n }\n\n public async start(): Promise<void> {\n try {\n // Show terminal compatibility info\n const termInfo = terminalCompat.getTerminalInfo();\n const warnings = terminalCompat.getWarnings();\n\n if (warnings.length > 0) {\n console.log('\u26A0\uFE0F Terminal Compatibility Warnings:');\n warnings.forEach((w) => console.log(` \u2022 ${w}`));\n console.log('');\n\n // Give user time to read warnings\n await new Promise((resolve) => setTimeout(resolve, 2000));\n }\n\n // Show terminal capabilities in debug mode\n if (process.env.DEBUG || process.env.TUI_DEBUG) {\n console.log('\uD83D\uDD0D Terminal Capabilities:');\n console.log(` ${terminalCompat.getCapabilitiesString()}`);\n console.log('');\n await new Promise((resolve) => setTimeout(resolve, 1000));\n }\n\n // Connect WebSocket (but don't fail if it can't connect)\n try {\n await this.wsClient.connect();\n } catch (wsError) {\n console.log('\u26A0\uFE0F Running in offline mode (no WebSocket connection)');\n }\n\n // Initialize data service\n await this.dataService.initialize();\n\n // Start auto-refresh\n if (this.config.refreshInterval > 0) {\n this.refreshInterval = setInterval(() => {\n this.updateAll().catch((error) => {\n // Silent error handling for refresh failures\n if (process.env.DEBUG) {\n console.error('Update error:', error);\n }\n });\n }, this.config.refreshInterval);\n }\n\n // Initial data load\n await this.updateAll();\n\n // Render screen\n this.screen.render();\n } catch (error) {\n console.error('\\n\u274C TUI startup error:', error);\n if (error instanceof Error) {\n console.error('Error details:', error.message);\n if (process.env.DEBUG) {\n console.error('Stack trace:', error.stack);\n }\n }\n throw error;\n }\n }\n\n public cleanup(): void {\n if (this.refreshInterval) {\n clearInterval(this.refreshInterval);\n }\n this.wsClient.disconnect();\n this.dataService.cleanup();\n }\n}\n\n// CLI entry point\n// Check if this file is being run directly\nconst isMainModule =\n typeof process !== 'undefined' &&\n process.argv &&\n process.argv[1] &&\n (import.meta.url === `file://${process.argv[1]}` ||\n process.argv[1].endsWith('/index.js'));\n\nif (isMainModule) {\n // Check terminal compatibility first\n if (!terminalCompat.isCompatible()) {\n console.error('\u274C Terminal is not compatible with TUI mode');\n console.error(\n ' Please use the dashboard command instead: stackmemory dashboard --watch'\n );\n process.exit(1);\n }\n\n // Handle uncaught errors gracefully\n process.on('uncaughtException', (error) => {\n console.error('\\n\u274C TUI Error:', error.message || error);\n console.error('Error type:', error.constructor.name);\n if (error.stack) {\n console.error('Stack trace:', error.stack);\n }\n console.error(\n '\\n\uD83D\uDCA1 Try the simpler dashboard instead: stackmemory dashboard --watch'\n );\n process.exit(1);\n });\n\n process.on('unhandledRejection', (reason, promise) => {\n console.error('\\n\u274C Unhandled promise rejection at:', promise);\n console.error('Reason:', reason);\n if (reason instanceof Error) {\n console.error('Stack trace:', reason.stack);\n }\n console.error(\n '\\n\uD83D\uDCA1 Try the simpler dashboard instead: stackmemory dashboard --watch'\n );\n process.exit(1);\n });\n\n let tui;\n try {\n tui = new StackMemoryTUI({\n refreshInterval: 2000,\n wsUrl: process.env.STACKMEMORY_WS_URL || 'ws://localhost:8080',\n });\n } catch (constructorError) {\n console.error(\n '\\n\u274C Failed to create TUI:',\n constructorError.message || constructorError\n );\n if (constructorError.stack) {\n console.error('Stack trace:', constructorError.stack);\n }\n console.error(\n '\\n\uD83D\uDCA1 Try the simpler dashboard instead: stackmemory dashboard --watch'\n );\n process.exit(1);\n }\n\n tui.start().catch((error) => {\n console.error('\\n\u274C Failed to start TUI:', error.message || error);\n if (error.stack) {\n console.error('Stack trace:', error.stack);\n }\n console.error(\n '\\n\uD83D\uDCA1 Try the simpler dashboard instead: stackmemory dashboard --watch'\n );\n process.exit(1);\n });\n\n process.on('SIGINT', () => {\n tui.cleanup();\n process.exit(0);\n });\n}\n"],
|
|
5
|
-
"mappings": ";AAMA,OAAO;AACP,OAAO,aAAa;AACpB,OAAO,aAAa;AACpB,SAAS,oBAAoB;AAC7B,SAAS,sBAAsB;AAC/B,SAAS,sBAAsB;AAC/B,SAAS,iBAAiB;AAC1B,SAAS,uBAAuB;AAChC,SAAS,qBAAqB;AAC9B,SAAS,iBAAiB;AAC1B,SAAS,sBAAsB;AAC/B,SAAS,mBAAmB;AAC5B,SAAS,uBAAuB;
|
|
4
|
+
"sourcesContent": ["#!/usr/bin/env node\n/**\n * StackMemory TUI Dashboard\n * Interactive monitoring interface for sessions, tasks, frames, and integrations\n */\n\nimport 'dotenv/config';\nimport blessed from 'blessed';\nimport contrib from 'blessed-contrib';\nimport { EventEmitter } from 'events';\nimport { terminalCompat } from './terminal-compat.js';\nimport { SessionMonitor } from './components/session-monitor.js';\nimport { TaskBoard } from './components/task-board.js';\nimport { FrameVisualizer } from './components/frame-visualizer.js';\nimport { SubagentFleet } from './components/subagent-fleet.js';\nimport { PRTracker } from './components/pr-tracker.js';\nimport { AnalyticsPanel } from './components/analytics-panel.js';\nimport { DataService } from './services/data-service.js';\nimport { WebSocketClient } from './services/websocket-client.js';\nimport type { DashboardConfig, SessionData, TaskData } from './types.js';\n// Type-safe environment variable access\nfunction getEnv(key: string, defaultValue?: string): string {\n const value = process.env[key];\n if (value === undefined) {\n if (defaultValue !== undefined) return defaultValue;\n throw new Error(`Environment variable ${key} is required`);\n }\n return value;\n}\n\nfunction getOptionalEnv(key: string): string | undefined {\n return process.env[key];\n}\n\n\n// Configure terminal environment before creating any blessed elements\nterminalCompat.configureEnvironment();\n\nexport class StackMemoryTUI extends EventEmitter {\n private screen: blessed.Widgets.Screen;\n private grid: any;\n private components: Map<string, any>;\n private dataService: DataService;\n private wsClient: WebSocketClient;\n private config: DashboardConfig;\n private refreshInterval: NodeJS.Timeout | null = null;\n\n constructor(config: DashboardConfig = {}) {\n super();\n this.config = {\n refreshInterval: 1000,\n wsUrl: 'ws://localhost:8080',\n theme: 'dark',\n ...config,\n };\n\n this.components = new Map();\n this.dataService = new DataService();\n this.wsClient = new WebSocketClient(this.config.wsUrl);\n this.screen = this.createScreen();\n this.grid = this.createGrid();\n this.initializeComponents();\n this.setupEventHandlers();\n }\n\n private createScreen(): blessed.Widgets.Screen {\n // Get terminal-specific configuration\n const blessedConfig = terminalCompat.getBlessedConfig();\n\n const screen = blessed.screen({\n ...blessedConfig,\n autoPadding: true,\n });\n\n // Add header with keyboard shortcuts\n const header = blessed.box({\n parent: screen,\n top: 0,\n left: 0,\n width: '100%',\n height: 3,\n content: '{center}\uD83D\uDE80 StackMemory TUI Dashboard v1.0.0 | [u]pdate status | [c]laude task | [s]ync | [q]uit{/center}',\n tags: true,\n style: {\n fg: 'white',\n bg: 'blue',\n bold: true,\n },\n });\n\n return screen;\n }\n\n private createGrid(): any {\n // Create a 12x12 grid for flexible layout\n const grid = new contrib.grid({\n rows: 12,\n cols: 12,\n screen: this.screen,\n });\n\n return grid;\n }\n\n private initializeComponents(): void {\n // Session Monitor (Top Left - 6x4)\n const sessionMonitor = new SessionMonitor(\n this.grid.set(0, 0, 4, 6, blessed.box, {\n label: '\uD83D\uDCCA Sessions',\n border: { type: 'line' },\n style: { border: { fg: 'cyan' } },\n })\n );\n this.components.set('sessions', sessionMonitor);\n\n // Task Board - Linear Integration (Top Right - 6x4)\n const taskBoard = new TaskBoard(\n this.grid.set(0, 6, 4, 6, blessed.box, {\n label: '\uD83D\uDCCB Linear Tasks',\n border: { type: 'line' },\n style: { border: { fg: 'green' } },\n })\n );\n this.components.set('tasks', taskBoard);\n\n // Frame Visualizer (Middle Left - 6x4)\n // Create a box container first, then add the tree inside\n const frameContainer = this.grid.set(4, 0, 4, 6, blessed.box, {\n label: '\uD83D\uDDC2\uFE0F Frame Storage',\n border: { type: 'line' },\n style: { border: { fg: 'yellow' } },\n });\n\n const frameTree = contrib.tree({\n parent: frameContainer,\n top: 0,\n left: 0,\n width: '100%-2',\n height: '100%-2',\n style: {\n text: 'green',\n selected: {\n bg: 'yellow',\n fg: 'black',\n },\n },\n template: {\n lines: true,\n },\n label: '',\n });\n\n const frameViz = new FrameVisualizer(frameTree);\n this.components.set('frames', frameViz);\n\n // Subagent Fleet (Middle Right - 6x4)\n const subagentFleet = new SubagentFleet(\n this.grid.set(4, 6, 4, 6, blessed.box, {\n label: '\uD83E\uDD16 Subagent Fleet',\n border: { type: 'line' },\n style: { border: { fg: 'magenta' } },\n })\n );\n this.components.set('subagents', subagentFleet);\n\n // PR/Issue Tracker (Bottom Left - 6x2)\n const prTracker = new PRTracker(\n this.grid.set(8, 0, 2, 6, blessed.list, {\n label: '\uD83D\uDD00 PR/Issues',\n border: { type: 'line' },\n style: { border: { fg: 'red' } },\n scrollable: true,\n mouse: true,\n })\n );\n this.components.set('prs', prTracker);\n\n // Analytics Panel (Bottom Right - 6x2)\n const analytics = new AnalyticsPanel(\n this.grid.set(8, 6, 2, 6, contrib.line, {\n label: '\uD83D\uDCC8 Analytics',\n border: { type: 'line' },\n style: {\n border: { fg: 'white' },\n line: 'yellow',\n text: 'green',\n baseline: 'black',\n },\n showLegend: true,\n wholeNumbersOnly: false,\n })\n );\n this.components.set('analytics', analytics);\n\n // Status Bar (Bottom - 12x2)\n const statusBar = blessed.box({\n parent: this.screen,\n bottom: 0,\n left: 0,\n width: '100%',\n height: 2,\n tags: true,\n style: {\n fg: 'white',\n bg: 'black',\n },\n });\n this.components.set('status', statusBar);\n\n this.updateStatusBar('Ready');\n }\n\n private setupEventHandlers(): void {\n // Keyboard shortcuts\n this.screen.key(['q', 'C-c'], () => {\n this.cleanup();\n process.exit(0);\n });\n\n this.screen.key(['r', 'C-r'], () => {\n this.refresh();\n });\n\n this.screen.key(['tab'], () => {\n this.focusNext();\n });\n\n this.screen.key(['S-tab'], () => {\n this.focusPrevious();\n });\n\n // View switching\n this.screen.key(['1'], () => this.showView('sessions'));\n this.screen.key(['2'], () => this.showView('tasks'));\n this.screen.key(['3'], () => this.showView('frames'));\n this.screen.key(['4'], () => this.showView('subagents'));\n this.screen.key(['5'], () => this.showView('prs'));\n this.screen.key(['6'], () => this.showView('analytics'));\n\n // WebSocket events\n this.wsClient.on('session:update', (data: SessionData) => {\n this.components.get('sessions')?.update(data);\n });\n\n this.wsClient.on('task:update', (data: TaskData) => {\n this.components.get('tasks')?.update(data);\n });\n\n this.wsClient.on('frame:update', (data) => {\n this.components.get('frames')?.update(data);\n });\n\n this.wsClient.on('agent:status', (data) => {\n this.components.get('subagents')?.update(data);\n });\n\n this.wsClient.on('pr:update', (data) => {\n this.components.get('prs')?.update(data);\n });\n\n // Data service events\n this.dataService.on('data:ready', () => {\n this.updateAll();\n });\n\n this.dataService.on('error', (error) => {\n this.showError(error.message);\n });\n }\n\n private async updateAll(): Promise<void> {\n try {\n // Fetch latest data\n const [sessions, tasks, frames, agents, prs, issues, analytics] =\n await Promise.all([\n this.dataService.getSessions(),\n this.dataService.getTasks(),\n this.dataService.getFrames(),\n this.dataService.getAgents(),\n this.dataService.getPRs(),\n this.dataService.getIssues(),\n this.dataService.getAnalytics(),\n ]);\n\n // Update components\n this.components.get('sessions')?.update(sessions);\n this.components.get('tasks')?.update(tasks);\n this.components.get('frames')?.update(frames);\n this.components.get('subagents')?.update(agents);\n // PR/Issue tracker expects an object with prs/issues\n this.components.get('prs')?.update({ prs, issues });\n this.components.get('analytics')?.update(analytics);\n\n this.updateStatusBar(`Last updated: ${new Date().toLocaleTimeString()}`);\n this.screen.render();\n } catch (error: unknown) {\n this.showError(`Update failed: ${error.message}`);\n }\n }\n\n private refresh(): void {\n this.updateStatusBar('Refreshing...');\n this.updateAll();\n }\n\n private focusNext(): void {\n const components = Array.from(this.components.values());\n const currentIndex = components.findIndex((c) => c.hasFocus?.());\n const nextIndex = (currentIndex + 1) % components.length;\n components[nextIndex]?.focus?.();\n this.screen.render();\n }\n\n private focusPrevious(): void {\n const components = Array.from(this.components.values());\n const currentIndex = components.findIndex((c) => c.hasFocus?.());\n const prevIndex =\n currentIndex <= 0 ? components.length - 1 : currentIndex - 1;\n components[prevIndex]?.focus?.();\n this.screen.render();\n }\n\n private showView(viewName: string): void {\n const component = this.components.get(viewName);\n if (component) {\n component.focus?.();\n component.show?.();\n this.updateStatusBar(`Viewing: ${viewName}`);\n this.screen.render();\n }\n }\n\n private updateStatusBar(message: string): void {\n const statusBar = this.components.get('status');\n if (statusBar) {\n const shortcuts =\n '{yellow-fg}[q]{/} Quit | {yellow-fg}[r]{/} Refresh | {yellow-fg}[Tab]{/} Navigate | {yellow-fg}[1-6]{/} Views';\n statusBar.setContent(`{bold}${message}{/} | ${shortcuts}`);\n this.screen.render();\n }\n }\n\n private showError(message: string): void {\n const msg = blessed.message({\n parent: this.screen,\n border: 'line',\n height: 'shrink',\n width: 'half',\n top: 'center',\n left: 'center',\n label: '{red-fg}Error{/}',\n tags: true,\n hidden: true,\n });\n\n msg.display(message, () => {\n msg.destroy();\n this.screen.render();\n });\n }\n\n public async start(): Promise<void> {\n try {\n // Show terminal compatibility info\n const termInfo = terminalCompat.getTerminalInfo();\n const warnings = terminalCompat.getWarnings();\n\n if (warnings.length > 0) {\n console.log('\u26A0\uFE0F Terminal Compatibility Warnings:');\n warnings.forEach((w) => console.log(` \u2022 ${w}`));\n console.log('');\n\n // Give user time to read warnings\n await new Promise((resolve) => setTimeout(resolve, 2000));\n }\n\n // Show terminal capabilities in debug mode\n if (process.env['DEBUG'] || process.env['TUI_DEBUG']) {\n console.log('\uD83D\uDD0D Terminal Capabilities:');\n console.log(` ${terminalCompat.getCapabilitiesString()}`);\n console.log('');\n await new Promise((resolve) => setTimeout(resolve, 1000));\n }\n\n // Connect WebSocket (but don't fail if it can't connect)\n try {\n await this.wsClient.connect();\n } catch (wsError: unknown) {\n console.log('\u26A0\uFE0F Running in offline mode (no WebSocket connection)');\n }\n\n // Initialize data service\n await this.dataService.initialize();\n\n // Start auto-refresh\n if (this.config.refreshInterval > 0) {\n this.refreshInterval = setInterval(() => {\n this.updateAll().catch((error) => {\n // Silent error handling for refresh failures\n if (process.env['DEBUG']) {\n console.error('Update error:', error);\n }\n });\n }, this.config.refreshInterval);\n }\n\n // Initial data load\n await this.updateAll();\n\n // Render screen\n this.screen.render();\n } catch (error: unknown) {\n console.error('\\n\u274C TUI startup error:', error);\n if (error instanceof Error) {\n console.error('Error details:', error.message);\n if (process.env['DEBUG']) {\n console.error('Stack trace:', error.stack);\n }\n }\n throw error;\n }\n }\n\n public cleanup(): void {\n if (this.refreshInterval) {\n clearInterval(this.refreshInterval);\n }\n this.wsClient.disconnect();\n this.dataService.cleanup();\n }\n}\n\n// CLI entry point\n// Check if this file is being run directly\nconst isMainModule =\n typeof process !== 'undefined' &&\n process.argv &&\n process.argv[1] &&\n (import.meta.url === `file://${process.argv[1]}` ||\n process.argv[1].endsWith('/index.js'));\n\nif (isMainModule) {\n // Check terminal compatibility first\n if (!terminalCompat.isCompatible()) {\n console.error('\u274C Terminal is not compatible with TUI mode');\n console.error(\n ' Please use the dashboard command instead: stackmemory dashboard --watch'\n );\n process.exit(1);\n }\n\n // Handle uncaught errors gracefully\n process.on('uncaughtException', (error) => {\n console.error('\\n\u274C TUI Error:', error.message || error);\n console.error('Error type:', error.constructor.name);\n if (error.stack) {\n console.error('Stack trace:', error.stack);\n }\n console.error(\n '\\n\uD83D\uDCA1 Try the simpler dashboard instead: stackmemory dashboard --watch'\n );\n process.exit(1);\n });\n\n process.on('unhandledRejection', (reason, promise) => {\n console.error('\\n\u274C Unhandled promise rejection at:', promise);\n console.error('Reason:', reason);\n if (reason instanceof Error) {\n console.error('Stack trace:', reason.stack);\n }\n console.error(\n '\\n\uD83D\uDCA1 Try the simpler dashboard instead: stackmemory dashboard --watch'\n );\n process.exit(1);\n });\n\n let tui;\n try {\n tui = new StackMemoryTUI({\n refreshInterval: 2000,\n wsUrl: process.env['STACKMEMORY_WS_URL'] || 'ws://localhost:8080',\n });\n } catch (constructorError: unknown) {\n console.error(\n '\\n\u274C Failed to create TUI:',\n constructorError.message || constructorError\n );\n if (constructorError.stack) {\n console.error('Stack trace:', constructorError.stack);\n }\n console.error(\n '\\n\uD83D\uDCA1 Try the simpler dashboard instead: stackmemory dashboard --watch'\n );\n process.exit(1);\n }\n\n tui.start().catch((error) => {\n console.error('\\n\u274C Failed to start TUI:', error.message || error);\n if (error.stack) {\n console.error('Stack trace:', error.stack);\n }\n console.error(\n '\\n\uD83D\uDCA1 Try the simpler dashboard instead: stackmemory dashboard --watch'\n );\n process.exit(1);\n });\n\n process.on('SIGINT', () => {\n tui.cleanup();\n process.exit(0);\n });\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -4,6 +4,17 @@ import { SessionManager } from "../../../core/session/session-manager.js";
|
|
|
4
4
|
import { FrameManager } from "../../../core/context/frame-manager.js";
|
|
5
5
|
import { LinearTaskReader } from "./linear-task-reader.js";
|
|
6
6
|
import { existsSync } from "fs";
|
|
7
|
+
function getEnv(key, defaultValue) {
|
|
8
|
+
const value = process.env[key];
|
|
9
|
+
if (value === void 0) {
|
|
10
|
+
if (defaultValue !== void 0) return defaultValue;
|
|
11
|
+
throw new Error(`Environment variable ${key} is required`);
|
|
12
|
+
}
|
|
13
|
+
return value;
|
|
14
|
+
}
|
|
15
|
+
function getOptionalEnv(key) {
|
|
16
|
+
return process.env[key];
|
|
17
|
+
}
|
|
7
18
|
class DataService extends EventEmitter {
|
|
8
19
|
db = null;
|
|
9
20
|
sessionManager = null;
|
|
@@ -16,24 +27,24 @@ class DataService extends EventEmitter {
|
|
|
16
27
|
async initialize() {
|
|
17
28
|
try {
|
|
18
29
|
try {
|
|
19
|
-
const dbPath = process.env
|
|
30
|
+
const dbPath = process.env["PROJECT_ROOT"] ? `${process.env["PROJECT_ROOT"]}/.stackmemory/context.db` : `${process.cwd()}/.stackmemory/context.db`;
|
|
20
31
|
if (existsSync(dbPath)) {
|
|
21
32
|
this.db = new Database(dbPath);
|
|
22
33
|
}
|
|
23
34
|
} catch (dbError) {
|
|
24
|
-
if (process.env
|
|
35
|
+
if (process.env["DEBUG"]) {
|
|
25
36
|
console.log("Database not accessible, continuing without it");
|
|
26
37
|
}
|
|
27
38
|
}
|
|
28
39
|
try {
|
|
29
|
-
this.taskReader = new LinearTaskReader(process.env
|
|
40
|
+
this.taskReader = new LinearTaskReader(process.env["PROJECT_ROOT"] || process.cwd());
|
|
30
41
|
this.linearMappings = this.taskReader.getMappings();
|
|
31
|
-
if (process.env
|
|
42
|
+
if (process.env["DEBUG"]) {
|
|
32
43
|
const tasks = this.taskReader.getTasks();
|
|
33
44
|
console.log(`LinearTaskReader initialized with ${tasks.length} tasks`);
|
|
34
45
|
}
|
|
35
46
|
} catch (tsError) {
|
|
36
|
-
if (process.env
|
|
47
|
+
if (process.env["DEBUG"]) {
|
|
37
48
|
console.log("Task reader initialization failed:", tsError.message);
|
|
38
49
|
}
|
|
39
50
|
}
|
|
@@ -42,7 +53,7 @@ class DataService extends EventEmitter {
|
|
|
42
53
|
enableMonitoring: true
|
|
43
54
|
});
|
|
44
55
|
} catch (smError) {
|
|
45
|
-
if (process.env
|
|
56
|
+
if (process.env["DEBUG"]) {
|
|
46
57
|
console.log("SessionManager initialization failed:", smError.message);
|
|
47
58
|
}
|
|
48
59
|
}
|
|
@@ -50,19 +61,19 @@ class DataService extends EventEmitter {
|
|
|
50
61
|
try {
|
|
51
62
|
this.frameManager = new FrameManager(this.db, "tui");
|
|
52
63
|
} catch (fmError) {
|
|
53
|
-
if (process.env
|
|
64
|
+
if (process.env["DEBUG"]) {
|
|
54
65
|
console.log("FrameManager initialization failed:", fmError.message);
|
|
55
66
|
}
|
|
56
67
|
}
|
|
57
68
|
}
|
|
58
|
-
if (process.env
|
|
69
|
+
if (process.env["DEBUG"]) {
|
|
59
70
|
console.log(
|
|
60
71
|
"TUI: Using local task store only (no direct Linear API calls)"
|
|
61
72
|
);
|
|
62
73
|
}
|
|
63
74
|
this.emit("data:ready");
|
|
64
75
|
} catch (error) {
|
|
65
|
-
if (process.env
|
|
76
|
+
if (process.env["DEBUG"]) {
|
|
66
77
|
console.error("DataService initialization error:", error);
|
|
67
78
|
}
|
|
68
79
|
this.emit("data:ready");
|
|
@@ -84,7 +95,7 @@ class DataService extends EventEmitter {
|
|
|
84
95
|
`);
|
|
85
96
|
recentSessions = stmt.all() || [];
|
|
86
97
|
} catch (dbError) {
|
|
87
|
-
if (process.env
|
|
98
|
+
if (process.env["DEBUG"]) {
|
|
88
99
|
console.log("Sessions table not found, using mock data");
|
|
89
100
|
}
|
|
90
101
|
}
|
|
@@ -101,7 +112,7 @@ class DataService extends EventEmitter {
|
|
|
101
112
|
this.setCache("sessions", sessions);
|
|
102
113
|
return sessions;
|
|
103
114
|
} catch (error) {
|
|
104
|
-
if (process.env
|
|
115
|
+
if (process.env["DEBUG"]) {
|
|
105
116
|
console.error("Error getting sessions:", error);
|
|
106
117
|
}
|
|
107
118
|
return this.getMockSessions();
|
|
@@ -115,13 +126,13 @@ class DataService extends EventEmitter {
|
|
|
115
126
|
try {
|
|
116
127
|
const localTasks = this.taskReader.getTasks();
|
|
117
128
|
tasks.push(...localTasks);
|
|
118
|
-
if (process.env
|
|
129
|
+
if (process.env["DEBUG"]) {
|
|
119
130
|
console.log(
|
|
120
131
|
`Loaded ${tasks.length} tasks from local store (no Linear API calls)`
|
|
121
132
|
);
|
|
122
133
|
}
|
|
123
134
|
} catch (error) {
|
|
124
|
-
if (process.env
|
|
135
|
+
if (process.env["DEBUG"]) {
|
|
125
136
|
console.log("Failed to get local tasks:", error.message);
|
|
126
137
|
}
|
|
127
138
|
}
|
|
@@ -151,7 +162,7 @@ class DataService extends EventEmitter {
|
|
|
151
162
|
this.setCache("frames", formatted);
|
|
152
163
|
return formatted;
|
|
153
164
|
} catch (error) {
|
|
154
|
-
if (process.env
|
|
165
|
+
if (process.env["DEBUG"]) {
|
|
155
166
|
console.error("Error getting frames:", error);
|
|
156
167
|
}
|
|
157
168
|
const mockFrames = this.getMockFrames();
|