@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.
163 lines (135 loc) ⢠5.72 kB
JavaScript
/**
* Add all StackMemory phase tasks to Linear via API
*/
import 'dotenv/config';
import fs from 'fs';
import { LinearRestClient } from '../dist/integrations/linear/rest-client.js';
const API_KEY = process.env.LINEAR_API_KEY;
if (!API_KEY) {
console.error('ā LINEAR_API_KEY environment variable not set');
console.log('Please set LINEAR_API_KEY in your .env file or export it in your shell');
process.exit(1);
}
const DELAY_BETWEEN_TASKS = 5000; // 5 seconds to avoid rate limits
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
async function addTasksToLinear() {
try {
console.log('š Starting to add StackMemory phase tasks to Linear...');
// Read the generated tasks
const tasksFile = `stackmemory-phase-tasks-${new Date().toISOString().split('T')[0]}.json`;
if (!fs.existsSync(tasksFile)) {
throw new Error(`Tasks file not found: ${tasksFile}`);
}
const taskData = JSON.parse(fs.readFileSync(tasksFile, 'utf8'));
console.log(`š Found ${taskData.totalTasks} tasks to create`);
const client = new LinearRestClient(API_KEY);
// Get team info
console.log('š Getting team information...');
const team = await client.getTeam();
console.log(`šÆ Target team: ${team.name} (${team.key})`);
let created = 0;
let failed = 0;
const results = [];
// Process each phase
for (const [phaseName, tasks] of Object.entries(taskData.phases)) {
console.log(`\nš¦ Processing ${phaseName} (${tasks.length} tasks)`);
for (let i = 0; i < tasks.length; i++) {
const task = tasks[i];
console.log(`\nā³ Creating task ${i + 1}/${tasks.length}: ${task.title}`);
try {
// Create task via GraphQL
const createQuery = `
mutation CreateIssue($input: IssueCreateInput!) {
issueCreate(input: $input) {
success
issue {
id
identifier
title
state { name }
priority
url
}
}
}
`;
const taskInput = {
title: task.title.replace('STA-XXX:', '').trim(), // Remove placeholder ID
description: task.description,
teamId: team.id,
priority: task.priority
};
const response = await client.makeRequest(createQuery, { input: taskInput });
if (response.data?.issueCreate?.success) {
const createdTask = response.data.issueCreate.issue;
console.log(`ā
Created: ${createdTask.identifier} - ${createdTask.title}`);
console.log(` URL: ${createdTask.url}`);
results.push({
original: task.title,
created: createdTask.identifier,
url: createdTask.url,
success: true
});
created++;
} else {
const errors = response.data?.issueCreate?.errors || [{ message: 'Unknown error' }];
throw new Error(errors[0].message);
}
// Delay to avoid rate limits (except for last task)
if (i < tasks.length - 1) {
console.log(`ā³ Waiting ${DELAY_BETWEEN_TASKS / 1000}s to avoid rate limits...`);
await delay(DELAY_BETWEEN_TASKS);
}
} catch (error) {
console.log(`ā Failed: ${error.message}`);
results.push({
original: task.title,
error: error.message,
success: false
});
failed++;
// If rate limited, wait longer and continue
if (error.message.includes('usage limit') || error.message.includes('rate limit')) {
console.log('š« Hit rate limit. Waiting 60 seconds...');
await delay(60000);
}
}
}
}
// Summary
console.log('\nš Creation Summary:');
console.log(`ā
Successfully created: ${created} tasks`);
console.log(`ā Failed: ${failed} tasks`);
console.log(`š Success rate: ${Math.round((created / (created + failed)) * 100)}%`);
// Save results
const resultsFile = `linear-task-creation-results-${new Date().toISOString().split('T')[0]}.json`;
fs.writeFileSync(resultsFile, JSON.stringify({
summary: { created, failed, total: created + failed },
results: results,
timestamp: new Date().toISOString()
}, null, 2));
console.log(`š¾ Results saved to: ${resultsFile}`);
if (created > 0) {
console.log('\nš Success! StackMemory phase tasks have been added to Linear.');
console.log('š” Next steps:');
console.log(' 1. Review and organize tasks in Linear workspace');
console.log(' 2. Start with high-priority Phase 2 tasks');
console.log(' 3. Assign tasks to team members');
console.log(' 4. Begin implementation of LLM-driven context retrieval');
}
if (failed > 0) {
console.log('\nā ļø Some tasks failed to create. Check the results file for details.');
console.log(' You can retry failed tasks manually using:');
console.log(' node dist/cli/index.js linear:create --api-key <key> --title "..." --description "..."');
}
} catch (error) {
console.error('š„ Script failed:', error.message);
process.exit(1);
}
}
// Run if called directly
if (import.meta.url === `file://${process.argv[1]}`) {
addTasksToLinear().catch(console.error);
}
export { addTasksToLinear };