@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
JavaScript
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