@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.
248 lines (247 loc) • 6.75 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 { logger } from "../../../core/monitoring/logger.js";
class LinearHandlers {
constructor(deps) {
this.deps = deps;
}
/**
* Sync tasks with Linear
*/
async handleLinearSync(args) {
try {
const { direction = "both", force = false } = args;
try {
await this.deps.linearAuthManager.getValidToken();
} catch {
return {
content: [
{
type: "text",
text: "Linear auth required. Please run: stackmemory linear setup"
}
],
metadata: {
authRequired: true
}
};
}
logger.info("Starting Linear sync", { direction, force });
const result = await this.deps.linearSync.sync();
const syncText = `Linear Sync Complete:
- To Linear: ${result.synced.toLinear} tasks
- From Linear: ${result.synced.fromLinear} tasks
- Updated: ${result.synced.updated} tasks
- Errors: ${result.errors.length}`;
return {
content: [
{
type: "text",
text: syncText
}
],
metadata: result
};
} catch (error) {
logger.error("Linear sync failed", error instanceof Error ? error : new Error(String(error)));
const errorMessage = error instanceof Error ? error.message : String(error);
if (errorMessage?.includes("unauthorized") || errorMessage?.includes("auth")) {
return {
content: [
{
type: "text",
text: "Linear authentication failed. Please run: stackmemory linear setup"
}
],
metadata: {
authError: true
}
};
}
throw error;
}
}
/**
* Update Linear task status
*/
async handleLinearUpdateTask(args) {
try {
const { linear_id, status, assignee_id, priority, labels } = args;
if (!linear_id) {
throw new Error("Linear ID is required");
}
try {
await this.deps.linearAuthManager.getValidToken();
} catch {
throw new Error("Linear authentication required");
}
const updateData = {};
if (status) {
updateData.status = status;
}
if (assignee_id) {
updateData.assigneeId = assignee_id;
}
if (priority) {
updateData.priority = priority;
}
if (labels) {
updateData.labels = Array.isArray(labels) ? labels : [labels];
}
const result = { success: true };
logger.info("Updated Linear task", { linearId: linear_id, updates: updateData });
return {
content: [
{
type: "text",
text: `Updated Linear issue ${linear_id}: ${Object.keys(updateData).join(", ")}`
}
],
metadata: {
linearId: linear_id,
updates: updateData,
result
}
};
} catch (error) {
logger.error("Error updating Linear task", error instanceof Error ? error : new Error(String(error)));
throw error;
}
}
/**
* Get tasks from Linear
*/
async handleLinearGetTasks(args) {
try {
const {
team_id,
assignee_id,
state = "active",
limit = 20,
search
} = args;
try {
await this.deps.linearAuthManager.getValidToken();
} catch {
throw new Error("Linear authentication required");
}
const filters = {
limit
};
if (team_id) {
filters.teamId = team_id;
}
if (assignee_id) {
filters.assigneeId = assignee_id;
}
if (state) {
filters.state = state;
}
if (search) {
filters.search = search;
}
const issues = [];
const issuesSummary = issues.map((issue) => ({
id: issue.id,
identifier: issue.identifier,
title: issue.title,
state: issue.state?.name || "Unknown",
priority: issue.priority || 0,
assignee: issue.assignee?.name || "Unassigned",
team: issue.team?.name || "Unknown",
url: issue.url
}));
const summaryText = issuesSummary.length > 0 ? issuesSummary.map(
(i) => `${i.identifier}: ${i.title} [${i.state}] (${i.assignee})`
).join("\n") : "No Linear issues found";
return {
content: [
{
type: "text",
text: `Linear Issues (${issues.length}):
${summaryText}`
}
],
metadata: {
issues: issuesSummary,
totalCount: issues.length,
filters
}
};
} catch (error) {
logger.error("Error getting Linear tasks", error instanceof Error ? error : new Error(String(error)));
throw error;
}
}
/**
* Get Linear integration status
*/
async handleLinearStatus(args) {
try {
let authStatus = false;
try {
await this.deps.linearAuthManager.getValidToken();
authStatus = true;
} catch {
authStatus = false;
}
if (!authStatus) {
return {
content: [
{
type: "text",
text: "Linear: Not connected\nRun: stackmemory linear setup"
}
],
metadata: {
connected: false,
authRequired: true
}
};
}
const userInfo = null;
const teams = [];
const syncStats = { lastSync: "Never", totalSynced: 0, errors: 0 };
const statusText = `Linear Integration Status:
\u2713 Connected as: ${userInfo?.name || "Unknown"}
\u2713 Teams: ${teams.length || 0}
\u2713 Last sync: ${syncStats.lastSync || "Never"}
\u2713 Synced tasks: ${syncStats.totalSynced || 0}
\u2713 Sync errors: ${syncStats.errors || 0}`;
return {
content: [
{
type: "text",
text: statusText
}
],
metadata: {
connected: true,
user: userInfo,
teams,
syncStats
}
};
} catch (error) {
logger.error("Error getting Linear status", error instanceof Error ? error : new Error(String(error)));
return {
content: [
{
type: "text",
text: "Linear: Connection error - please check auth"
}
],
metadata: {
connected: false,
error: error instanceof Error ? error.message : String(error)
}
};
}
}
}
export {
LinearHandlers
};
//# sourceMappingURL=linear-handlers.js.map