UNPKG

@stackmemoryai/stackmemory

Version:

Project-scoped memory for AI coding tools. Durable context across sessions with MCP integration, frames, smart retrieval, Claude Code skills, and automatic hooks.

125 lines (124 loc) 4.21 kB
#!/usr/bin/env ts-node import { fileURLToPath as __fileURLToPath } from 'url'; import { dirname as __pathDirname } from 'path'; const __filename = __fileURLToPath(import.meta.url); const __dirname = __pathDirname(__filename); import { LinearClient } from "../src/integrations/linear/client.js"; import { LinearAuthManager } from "../src/integrations/linear/auth.js"; import chalk from "chalk"; function getEnv(key, defaultValue) { const value = process.env[key]; if (value === void 0) { if (defaultValue !== void 0) return defaultValue; throw new Error(`Environment variable ${key} is required`); } return value; } function getOptionalEnv(key) { return process.env[key]; } async function main() { try { console.log(chalk.cyan("\u{1F50D} Fetching Linear tasks...\n")); const authManager = new LinearAuthManager(process.cwd()); const tokens = authManager.loadTokens(); const apiKey = process.env["LINEAR_API_KEY"]; if (!tokens && !apiKey) { console.log(chalk.red("\u274C Not authenticated with Linear")); console.log("Run: node dist/src/cli/index.js linear setup"); process.exit(1); } const client = apiKey ? new LinearClient({ apiKey }) : new LinearClient({ apiKey: tokens?.accessToken ?? "", useBearer: true }); console.log(chalk.gray("Fetching issues...")); const issues = await client.getIssues({ limit: 200 }); if (!issues || issues.length === 0) { console.log(chalk.gray("No issues found")); return; } console.log(chalk.green(`\u2713 Found ${issues.length} tasks`)); const tasksByStatus = {}; issues.forEach((issue) => { const statusType = issue.state.type; const statusName = issue.state.name; const key = `${statusType} (${statusName})`; if (!tasksByStatus[key]) { tasksByStatus[key] = []; } tasksByStatus[key].push({ identifier: issue.identifier, title: issue.title, priority: issue.priority, assignee: issue.assignee?.name, url: issue.url }); }); const statusOrder = [ "backlog", "unstarted", "started", "completed", "cancelled" ]; console.log(chalk.cyan("\n\u{1F4CB} Linear Tasks by Status:\n")); statusOrder.forEach((statusType) => { const matchingKeys = Object.keys(tasksByStatus).filter( (key) => key.startsWith(statusType) ); matchingKeys.forEach((statusKey) => { const tasks = tasksByStatus[statusKey]; if (tasks.length === 0) return; console.log( chalk.bold.white( ` ${getStatusEmoji(statusType)} ${statusKey} (${tasks.length} tasks)` ) ); console.log(chalk.gray("".padEnd(60, "\u2500"))); tasks.forEach((task) => { const priorityStr = task.priority > 0 ? chalk.yellow(`P${task.priority}`) : chalk.gray("--"); const assigneeStr = task.assignee ? chalk.blue(task.assignee) : chalk.gray("Unassigned"); const titleStr = task.title.length > 50 ? task.title.substring(0, 47) + "..." : task.title; console.log( ` ${chalk.cyan(task.identifier.padEnd(8))} ${titleStr.padEnd(50)} ${priorityStr.padEnd(8)} ${assigneeStr}` ); }); }); }); const totalTasks = issues.length; const statusCounts = Object.entries(tasksByStatus).map( ([status, tasks]) => ({ status, count: tasks.length }) ); console.log(chalk.cyan("\n\u{1F4CA} Summary:")); statusCounts.forEach(({ status, count }) => { console.log(chalk.gray(` ${status}: ${count} tasks`)); }); console.log(chalk.bold(` Total: ${totalTasks} tasks`)); } catch (error) { console.error(chalk.red("\u274C Error:"), error.message); process.exit(1); } } function getStatusEmoji(statusType) { switch (statusType) { case "backlog": return "\u{1F4CB}"; case "unstarted": return "\u{1F4DD}"; case "started": return "\u23F3"; case "completed": return "\u2705"; case "cancelled": return "\u274C"; default: return "\u{1F4C4}"; } } main(); //# sourceMappingURL=list-linear-tasks.js.map