@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.
158 lines (131 loc) ⢠5.17 kB
JavaScript
/**
* Delete remaining duplicate tasks
*/
import 'dotenv/config';
import fs from 'fs';
import readline from 'readline';
const API_KEY = process.env.LINEAR_OAUTH_TOKEN || process.env.LINEAR_API_KEY;
if (!API_KEY) {
console.error('ā LINEAR_OAUTH_TOKEN or LINEAR_API_KEY environment variable not set');
console.log('Please set LINEAR_OAUTH_TOKEN or LINEAR_API_KEY in your .env file or export it in your shell');
process.exit(1);
}
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
async function deleteRemainingDuplicates() {
try {
// Load deletion list
const deleteFile = `remaining-duplicates-${new Date().toISOString().split('T')[0]}.json`;
if (!fs.existsSync(deleteFile)) {
console.error(`ā Deletion list not found: ${deleteFile}`);
console.log('Run analyze-remaining-duplicates.js first.');
process.exit(1);
}
const deleteList = JSON.parse(fs.readFileSync(deleteFile, 'utf8'));
console.log('š REMAINING DUPLICATES DELETION');
console.log('=' .repeat(60));
console.log(`\n Current tasks: ${deleteList.summary.currentTotal}`);
console.log(` Tasks to delete: ${deleteList.summary.toDelete}`);
console.log(` After deletion: ${deleteList.summary.afterDeletion}\n`);
// Show what will be deleted
console.log('š Tasks to be deleted:');
deleteList.tasks.forEach(task => {
console.log(` ⢠${task.identifier}: ${task.title.substring(0, 60)}...`);
});
// Confirmation
console.log(`\nā ļø This will permanently delete ${deleteList.summary.toDelete} duplicate tasks.`);
console.log('Type "DELETE" to confirm, or press Ctrl+C to cancel:\n');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
const confirmation = await new Promise(resolve => {
rl.question('Confirmation: ', resolve);
});
rl.close();
if (confirmation !== 'DELETE') {
console.log('ā Deletion cancelled');
process.exit(0);
}
console.log('\nšļø Deleting remaining duplicates...\n');
let deleted = 0;
let failed = 0;
const results = [];
for (const task of deleteList.tasks) {
try {
process.stdout.write(`Deleting ${task.identifier}: ${task.title.substring(0, 40)}... `);
const deleteQuery = `
mutation DeleteIssue($id: String!) {
issueDelete(id: $id) {
success
}
}
`;
const response = await fetch('https://api.linear.app/graphql', {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
query: deleteQuery,
variables: { id: task.id }
})
});
const result = await response.json();
if (result.data?.issueDelete?.success) {
console.log('ā
');
deleted++;
results.push({ ...task, status: 'deleted' });
} else if (result.errors?.[0]?.message?.includes('not found')) {
console.log('ā ļø (already gone)');
deleted++;
results.push({ ...task, status: 'already_deleted' });
} else {
const error = result.errors?.[0]?.message || 'Unknown error';
console.log(`ā (${error})`);
failed++;
results.push({ ...task, status: 'failed', error });
}
// Small delay between deletions
await delay(500);
} catch (error) {
console.log(`ā (${error.message})`);
failed++;
results.push({ ...task, status: 'error', error: error.message });
}
}
// Save results
const resultsFile = `remaining-deletion-results-${new Date().toISOString().split('T')[0]}.json`;
fs.writeFileSync(resultsFile, JSON.stringify({
summary: {
attempted: deleteList.tasks.length,
deleted,
failed,
success_rate: Math.round((deleted / deleteList.tasks.length) * 100)
},
results,
timestamp: new Date().toISOString()
}, null, 2));
// Final report
console.log('\n' + '='.repeat(60));
console.log('š DELETION COMPLETE');
console.log('='.repeat(60));
console.log(`\nā
Successfully deleted: ${deleted} tasks`);
console.log(`ā Failed: ${failed} tasks`);
console.log(`š Success rate: ${Math.round((deleted / deleteList.tasks.length) * 100)}%`);
console.log(`\nš¾ Results saved to: ${resultsFile}`);
if (deleted > 0) {
console.log(`\nš Workspace cleaned! Now at ${deleteList.summary.afterDeletion} tasks.`);
console.log('All TypeScript Strict Mode duplicates have been removed.');
}
} catch (error) {
console.error('\nš„ Script failed:', error.message);
process.exit(1);
}
}
// Run if called directly
if (import.meta.url === `file://${process.argv[1]}`) {
deleteRemainingDuplicates().catch(console.error);
}
export { deleteRemainingDuplicates };