@stackmemoryai/stackmemory 0.3.17 → 0.3.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/commands/skills.js +15 -2
- package/dist/cli/commands/skills.js.map +2 -2
- package/dist/cli/index.js +113 -834
- package/dist/cli/index.js.map +3 -3
- package/dist/core/context/dual-stack-manager.js +1 -1
- package/dist/core/context/dual-stack-manager.js.map +1 -1
- package/dist/core/context/frame-manager.js +3 -0
- package/dist/core/context/frame-manager.js.map +2 -2
- package/dist/integrations/claude-code/subagent-client.js +106 -3
- package/dist/integrations/claude-code/subagent-client.js.map +2 -2
- package/dist/servers/railway/config.js +51 -0
- package/dist/servers/railway/config.js.map +7 -0
- package/dist/servers/railway/index-enhanced.js +156 -0
- package/dist/servers/railway/index-enhanced.js.map +7 -0
- package/dist/servers/railway/minimal.js +48 -3
- package/dist/servers/railway/minimal.js.map +2 -2
- package/dist/servers/railway/storage-test.js +455 -0
- package/dist/servers/railway/storage-test.js.map +7 -0
- package/dist/skills/claude-skills.js +13 -12
- package/dist/skills/claude-skills.js.map +2 -2
- package/dist/skills/recursive-agent-orchestrator.js +27 -18
- package/dist/skills/recursive-agent-orchestrator.js.map +2 -2
- package/dist/skills/unified-rlm-orchestrator.js.map +2 -2
- package/package.json +6 -18
- package/scripts/README-TESTING.md +186 -0
- package/scripts/analyze-cli-security.js +288 -0
- package/scripts/archive/add-phase-tasks-to-linear.js +163 -0
- package/scripts/archive/analyze-linear-duplicates.js +214 -0
- package/scripts/archive/analyze-remaining-duplicates.js +230 -0
- package/scripts/archive/analyze-sta-duplicates.js +292 -0
- package/scripts/archive/analyze-sta-graphql.js +399 -0
- package/scripts/archive/cancel-duplicate-tasks.ts +246 -0
- package/scripts/archive/check-all-duplicates.ts +419 -0
- package/scripts/archive/clean-duplicate-tasks.js +114 -0
- package/scripts/archive/cleanup-duplicate-tasks.ts +286 -0
- package/scripts/archive/create-phase-tasks.js +387 -0
- package/scripts/archive/delete-linear-duplicates.js +182 -0
- package/scripts/archive/delete-remaining-duplicates.js +158 -0
- package/scripts/archive/delete-sta-duplicates.js +201 -0
- package/scripts/archive/delete-sta-oauth.js +201 -0
- package/scripts/archive/export-sta-tasks.js +62 -0
- package/scripts/archive/install-auto-sync.js +266 -0
- package/scripts/archive/install-chromadb-hooks.sh +133 -0
- package/scripts/archive/install-enhanced-clear-hooks.sh +431 -0
- package/scripts/archive/install-post-task-hooks.sh +289 -0
- package/scripts/archive/install-stackmemory-hooks.sh +420 -0
- package/scripts/archive/merge-linear-duplicates-safe.ts +362 -0
- package/scripts/archive/merge-linear-duplicates.ts +180 -0
- package/scripts/archive/remove-sta-tasks.js +70 -0
- package/scripts/archive/setup-background-sync.sh +168 -0
- package/scripts/archive/setup-claude-auto-triggers.sh +181 -0
- package/scripts/archive/setup-claude-autostart.sh +305 -0
- package/scripts/archive/setup-git-hooks.sh +25 -0
- package/scripts/archive/setup-linear-oauth.sh +46 -0
- package/scripts/archive/setup-mcp.sh +113 -0
- package/scripts/archive/setup-railway-deployment.sh +81 -0
- package/scripts/auto-handoff.sh +262 -0
- package/scripts/background-sync-manager.js +416 -0
- package/scripts/benchmark-performance.ts +57 -0
- package/scripts/check-redis.ts +48 -0
- package/scripts/chromadb-auto-loader.sh +128 -0
- package/scripts/chromadb-context-loader.js +479 -0
- package/scripts/claude-chromadb-hook.js +460 -0
- package/scripts/claude-code-wrapper.sh +66 -0
- package/scripts/claude-linear-skill.js +455 -0
- package/scripts/claude-pre-commit.sh +302 -0
- package/scripts/claude-sm-autostart.js +532 -0
- package/scripts/claude-sm-setup.sh +367 -0
- package/scripts/claude-with-chromadb.sh +69 -0
- package/scripts/claude-worktree-manager.sh +323 -0
- package/scripts/claude-worktree-monitor.sh +371 -0
- package/scripts/claude-worktree-setup.sh +327 -0
- package/scripts/clean-linear-backlog.js +273 -0
- package/scripts/cleanup-old-sessions.sh +57 -0
- package/scripts/codex-wrapper.sh +88 -0
- package/scripts/create-sandbox.sh +269 -0
- package/scripts/debug-linear-update.js +174 -0
- package/scripts/delete-linear-tasks.js +167 -0
- package/scripts/deploy.sh +89 -0
- package/scripts/deployment/railway.sh +352 -0
- package/scripts/deployment/test-deployment.js +194 -0
- package/scripts/detect-and-rehydrate.js +162 -0
- package/scripts/detect-and-rehydrate.mjs +165 -0
- package/scripts/development/create-demo-tasks.js +143 -0
- package/scripts/development/debug-frame-test.js +16 -0
- package/scripts/development/demo-auto-sync.js +128 -0
- package/scripts/development/fix-all-imports.js +213 -0
- package/scripts/development/fix-imports.js +229 -0
- package/scripts/development/fix-lint-loop.cjs +103 -0
- package/scripts/development/fix-project-id.ts +161 -0
- package/scripts/development/fix-strict-mode-issues.ts +291 -0
- package/scripts/development/reorganize-structure.sh +228 -0
- package/scripts/development/test-persistence-direct.js +148 -0
- package/scripts/development/test-persistence.js +114 -0
- package/scripts/development/test-tasks.js +93 -0
- package/scripts/development/update-imports.js +212 -0
- package/scripts/fetch-linear-status.js +125 -0
- package/scripts/git-hooks/README.md +310 -0
- package/scripts/git-hooks/branch-context-manager.sh +342 -0
- package/scripts/git-hooks/post-checkout-stackmemory.sh +63 -0
- package/scripts/git-hooks/post-commit-stackmemory.sh +305 -0
- package/scripts/git-hooks/pre-commit-stackmemory.sh +275 -0
- package/scripts/hooks/cleanup-shell.sh +130 -0
- package/scripts/hooks/task-complete.sh +114 -0
- package/scripts/initialize.ts +129 -0
- package/scripts/install-claude-hooks-auto.js +104 -0
- package/scripts/install-claude-hooks.sh +133 -0
- package/scripts/install-global.sh +296 -0
- package/scripts/install.sh +235 -0
- package/scripts/linear-auto-sync.js +262 -0
- package/scripts/linear-auto-sync.sh +161 -0
- package/scripts/linear-sync-daemon.js +150 -0
- package/scripts/linear-task-review.js +237 -0
- package/scripts/list-linear-tasks.ts +178 -0
- package/scripts/mcp-proxy.js +66 -0
- package/scripts/opencode-wrapper.sh +85 -0
- package/scripts/publish-local.js +74 -0
- package/scripts/query-chromadb.ts +201 -0
- package/scripts/railway-env-setup.sh +39 -0
- package/scripts/reconcile-local-tasks.js +170 -0
- package/scripts/recreate-frames-db.js +89 -0
- package/scripts/setup/claude-integration.js +138 -0
- package/scripts/setup/configure-alias.js +125 -0
- package/scripts/setup/configure-codex-alias.js +161 -0
- package/scripts/setup/configure-opencode-alias.js +175 -0
- package/scripts/setup-claude-integration.js +204 -0
- package/scripts/setup-claude-integration.sh +183 -0
- package/scripts/setup.sh +31 -0
- package/scripts/show-linear-summary.ts +172 -0
- package/scripts/stackmemory-auto-handoff.sh +231 -0
- package/scripts/stackmemory-daemon.sh +40 -0
- package/scripts/start-linear-sync-daemon.sh +141 -0
- package/scripts/start-temporal-paradox.sh +214 -0
- package/scripts/status.ts +159 -0
- package/scripts/sync-and-clean-tasks.js +258 -0
- package/scripts/sync-frames-from-railway.js +228 -0
- package/scripts/sync-linear-graphql.js +303 -0
- package/scripts/sync-linear-tasks.js +186 -0
- package/scripts/test-auto-triggers.sh +57 -0
- package/scripts/test-browser-mcp.js +74 -0
- package/scripts/test-chromadb-full.js +115 -0
- package/scripts/test-chromadb-hooks.sh +28 -0
- package/scripts/test-chromadb-sync.ts +245 -0
- package/scripts/test-cli-security.js +293 -0
- package/scripts/test-hooks-persistence.sh +220 -0
- package/scripts/test-installation-scenarios.sh +359 -0
- package/scripts/test-installation.sh +224 -0
- package/scripts/test-mcp.js +163 -0
- package/scripts/test-pre-publish-quick.sh +75 -0
- package/scripts/test-quality-gates.sh +263 -0
- package/scripts/test-railway-db.js +222 -0
- package/scripts/test-redis-storage.ts +490 -0
- package/scripts/test-rlm-basic.sh +122 -0
- package/scripts/test-rlm-comprehensive.sh +260 -0
- package/scripts/test-rlm-e2e.sh +268 -0
- package/scripts/test-rlm-simple.js +90 -0
- package/scripts/test-rlm.js +110 -0
- package/scripts/test-session-handoff.sh +165 -0
- package/scripts/test-shell-integration.sh +275 -0
- package/scripts/testing/ab-test-runner.ts +508 -0
- package/scripts/testing/collect-metrics.ts +457 -0
- package/scripts/testing/quick-effectiveness-demo.js +187 -0
- package/scripts/testing/real-performance-test.js +422 -0
- package/scripts/testing/run-effectiveness-tests.sh +176 -0
- package/scripts/testing/scripts/testing/ab-test-runner.js +363 -0
- package/scripts/testing/scripts/testing/collect-metrics.js +292 -0
- package/scripts/testing/simple-effectiveness-test.js +310 -0
- package/scripts/testing/src/core/context/context-bridge.js +253 -0
- package/scripts/testing/src/core/context/frame-manager.js +746 -0
- package/scripts/testing/src/core/context/shared-context-layer.js +437 -0
- package/scripts/testing/src/core/database/database-adapter.js +54 -0
- package/scripts/testing/src/core/errors/index.js +291 -0
- package/scripts/testing/src/core/errors/recovery.js +268 -0
- package/scripts/testing/src/core/monitoring/logger.js +145 -0
- package/scripts/testing/src/core/retrieval/context-retriever.js +516 -0
- package/scripts/testing/src/core/session/index.js +1 -0
- package/scripts/testing/src/core/session/session-manager.js +323 -0
- package/scripts/testing/src/core/trace/cli-trace-wrapper.js +140 -0
- package/scripts/testing/src/core/trace/db-trace-wrapper.js +251 -0
- package/scripts/testing/src/core/trace/debug-trace.js +398 -0
- package/scripts/testing/src/core/trace/index.js +120 -0
- package/scripts/testing/src/core/trace/linear-api-wrapper.js +204 -0
- package/scripts/update-linear-status.js +268 -0
- package/scripts/update-linear-tasks-fixed.js +284 -0
- package/templates/claude-hooks/hooks.json +5 -0
- package/templates/claude-hooks/on-clear.js +56 -0
- package/templates/claude-hooks/on-startup.js +56 -0
- package/templates/claude-hooks/tool-use-trace.js +67 -0
- package/dist/features/tui/components/analytics-panel.js +0 -157
- package/dist/features/tui/components/analytics-panel.js.map +0 -7
- package/dist/features/tui/components/frame-visualizer.js +0 -377
- package/dist/features/tui/components/frame-visualizer.js.map +0 -7
- package/dist/features/tui/components/pr-tracker.js +0 -135
- package/dist/features/tui/components/pr-tracker.js.map +0 -7
- package/dist/features/tui/components/session-monitor.js +0 -299
- package/dist/features/tui/components/session-monitor.js.map +0 -7
- package/dist/features/tui/components/subagent-fleet.js +0 -395
- package/dist/features/tui/components/subagent-fleet.js.map +0 -7
- package/dist/features/tui/components/task-board.js +0 -1139
- package/dist/features/tui/components/task-board.js.map +0 -7
- package/dist/features/tui/index.js +0 -408
- package/dist/features/tui/index.js.map +0 -7
- package/dist/features/tui/services/data-service.js +0 -641
- package/dist/features/tui/services/data-service.js.map +0 -7
- package/dist/features/tui/services/linear-task-reader.js +0 -102
- package/dist/features/tui/services/linear-task-reader.js.map +0 -7
- package/dist/features/tui/services/websocket-client.js +0 -162
- package/dist/features/tui/services/websocket-client.js.map +0 -7
- package/dist/features/tui/terminal-compat.js +0 -220
- package/dist/features/tui/terminal-compat.js.map +0 -7
- package/dist/features/tui/types.js +0 -1
- package/dist/features/tui/types.js.map +0 -7
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Delete duplicate Linear issues identified by clean-linear-backlog.js
|
|
5
|
+
* This script will delete issues from Linear using their IDs
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import fs from 'fs';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
import { fileURLToPath } from 'url';
|
|
11
|
+
import dotenv from 'dotenv';
|
|
12
|
+
|
|
13
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
14
|
+
|
|
15
|
+
// Load environment variables from .env file
|
|
16
|
+
dotenv.config({
|
|
17
|
+
path: path.join(__dirname, '..', '.env'),
|
|
18
|
+
override: true
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
async function mutateLinear(query, variables = {}) {
|
|
22
|
+
const response = await fetch('https://api.linear.app/graphql', {
|
|
23
|
+
method: 'POST',
|
|
24
|
+
headers: {
|
|
25
|
+
'Content-Type': 'application/json',
|
|
26
|
+
'Authorization': process.env.LINEAR_API_KEY
|
|
27
|
+
},
|
|
28
|
+
body: JSON.stringify({ query, variables })
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const data = await response.json();
|
|
32
|
+
if (data.errors) {
|
|
33
|
+
throw new Error(data.errors[0].message);
|
|
34
|
+
}
|
|
35
|
+
return data.data;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async function deleteLinearDuplicates() {
|
|
39
|
+
const apiKey = process.env.LINEAR_API_KEY;
|
|
40
|
+
|
|
41
|
+
if (!apiKey) {
|
|
42
|
+
console.error('❌ LINEAR_API_KEY not found in environment');
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Load the deletion list
|
|
47
|
+
const deletionFile = path.join(__dirname, '..', 'linear-cleanup-2026-01-07.json');
|
|
48
|
+
|
|
49
|
+
if (!fs.existsSync(deletionFile)) {
|
|
50
|
+
console.error('❌ Deletion list not found. Run clean-linear-backlog.js first');
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const deletionList = JSON.parse(fs.readFileSync(deletionFile, 'utf8'));
|
|
55
|
+
|
|
56
|
+
console.log(`🗑️ Found ${deletionList.length} issues to delete\n`);
|
|
57
|
+
|
|
58
|
+
// Group by reason
|
|
59
|
+
const byReason = {
|
|
60
|
+
duplicate: deletionList.filter(i => i.reason === 'duplicate'),
|
|
61
|
+
test: deletionList.filter(i => i.reason === 'test'),
|
|
62
|
+
cancelled: deletionList.filter(i => i.reason === 'cancelled')
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
console.log('📊 Breakdown:');
|
|
66
|
+
console.log(` Duplicates: ${byReason.duplicate.length}`);
|
|
67
|
+
console.log(` Test tasks: ${byReason.test.length}`);
|
|
68
|
+
console.log(` Cancelled: ${byReason.cancelled.length}`);
|
|
69
|
+
|
|
70
|
+
// Ask for confirmation
|
|
71
|
+
console.log('\n⚠️ WARNING: This will permanently delete these issues from Linear!');
|
|
72
|
+
console.log('Press Ctrl+C to cancel, or wait 5 seconds to continue...\n');
|
|
73
|
+
|
|
74
|
+
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
75
|
+
|
|
76
|
+
console.log('🚀 Starting deletion process...\n');
|
|
77
|
+
|
|
78
|
+
let deleted = 0;
|
|
79
|
+
let failed = 0;
|
|
80
|
+
const errors = [];
|
|
81
|
+
|
|
82
|
+
// Process in batches to avoid rate limiting
|
|
83
|
+
const batchSize = 10;
|
|
84
|
+
for (let i = 0; i < deletionList.length; i += batchSize) {
|
|
85
|
+
const batch = deletionList.slice(i, i + batchSize);
|
|
86
|
+
|
|
87
|
+
console.log(`📦 Processing batch ${Math.floor(i/batchSize) + 1}/${Math.ceil(deletionList.length/batchSize)}...`);
|
|
88
|
+
|
|
89
|
+
for (const issue of batch) {
|
|
90
|
+
try {
|
|
91
|
+
// Archive instead of delete (safer)
|
|
92
|
+
const result = await mutateLinear(`
|
|
93
|
+
mutation ArchiveIssue($id: String!) {
|
|
94
|
+
issueArchive(id: $id) {
|
|
95
|
+
success
|
|
96
|
+
issue {
|
|
97
|
+
id
|
|
98
|
+
identifier
|
|
99
|
+
title
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
`, { id: issue.id });
|
|
104
|
+
|
|
105
|
+
if (result.issueArchive.success) {
|
|
106
|
+
deleted++;
|
|
107
|
+
process.stdout.write('✓');
|
|
108
|
+
} else {
|
|
109
|
+
failed++;
|
|
110
|
+
errors.push({ issue: issue.identifier, error: 'Archive failed' });
|
|
111
|
+
process.stdout.write('✗');
|
|
112
|
+
}
|
|
113
|
+
} catch (error) {
|
|
114
|
+
failed++;
|
|
115
|
+
errors.push({ issue: issue.identifier, error: error.message });
|
|
116
|
+
process.stdout.write('✗');
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
console.log(''); // New line after batch
|
|
121
|
+
|
|
122
|
+
// Rate limiting - wait between batches
|
|
123
|
+
if (i + batchSize < deletionList.length) {
|
|
124
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Summary
|
|
129
|
+
console.log('\n📊 Final Results:');
|
|
130
|
+
console.log(` ✅ Successfully archived: ${deleted}`);
|
|
131
|
+
console.log(` ❌ Failed: ${failed}`);
|
|
132
|
+
|
|
133
|
+
if (errors.length > 0) {
|
|
134
|
+
console.log('\n❌ Errors:');
|
|
135
|
+
for (const error of errors.slice(0, 10)) {
|
|
136
|
+
console.log(` - ${error.issue}: ${error.error}`);
|
|
137
|
+
}
|
|
138
|
+
if (errors.length > 10) {
|
|
139
|
+
console.log(` ... and ${errors.length - 10} more errors`);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Save error log
|
|
143
|
+
const errorFile = `linear-deletion-errors-${new Date().toISOString().split('T')[0]}.json`;
|
|
144
|
+
fs.writeFileSync(
|
|
145
|
+
path.join(__dirname, '..', errorFile),
|
|
146
|
+
JSON.stringify(errors, null, 2)
|
|
147
|
+
);
|
|
148
|
+
console.log(`\n💾 Error log saved to: ${errorFile}`);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
console.log('\n✅ Cleanup complete!');
|
|
152
|
+
console.log('💡 Tip: Run sync-linear-graphql.js to update local tasks');
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Add dry run option
|
|
156
|
+
const isDryRun = process.argv.includes('--dry-run');
|
|
157
|
+
|
|
158
|
+
if (isDryRun) {
|
|
159
|
+
console.log('🔍 DRY RUN MODE - No changes will be made\n');
|
|
160
|
+
|
|
161
|
+
const deletionFile = path.join(__dirname, '..', 'linear-cleanup-2026-01-07.json');
|
|
162
|
+
const deletionList = JSON.parse(fs.readFileSync(deletionFile, 'utf8'));
|
|
163
|
+
|
|
164
|
+
console.log('Would delete:');
|
|
165
|
+
const byTitle = {};
|
|
166
|
+
for (const issue of deletionList) {
|
|
167
|
+
const title = issue.title.substring(0, 50);
|
|
168
|
+
if (!byTitle[title]) {
|
|
169
|
+
byTitle[title] = 0;
|
|
170
|
+
}
|
|
171
|
+
byTitle[title]++;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const sorted = Object.entries(byTitle).sort((a, b) => b[1] - a[1]);
|
|
175
|
+
for (const [title, count] of sorted.slice(0, 15)) {
|
|
176
|
+
console.log(` ${count}x ${title}...`);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
process.exit(0);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
deleteLinearDuplicates();
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Delete remaining duplicate tasks
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import 'dotenv/config';
|
|
8
|
+
import fs from 'fs';
|
|
9
|
+
import readline from 'readline';
|
|
10
|
+
|
|
11
|
+
const API_KEY = process.env.LINEAR_OAUTH_TOKEN || process.env.LINEAR_API_KEY;
|
|
12
|
+
if (!API_KEY) {
|
|
13
|
+
console.error('❌ LINEAR_OAUTH_TOKEN or LINEAR_API_KEY environment variable not set');
|
|
14
|
+
console.log('Please set LINEAR_OAUTH_TOKEN or LINEAR_API_KEY in your .env file or export it in your shell');
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
|
19
|
+
|
|
20
|
+
async function deleteRemainingDuplicates() {
|
|
21
|
+
try {
|
|
22
|
+
// Load deletion list
|
|
23
|
+
const deleteFile = `remaining-duplicates-${new Date().toISOString().split('T')[0]}.json`;
|
|
24
|
+
if (!fs.existsSync(deleteFile)) {
|
|
25
|
+
console.error(`❌ Deletion list not found: ${deleteFile}`);
|
|
26
|
+
console.log('Run analyze-remaining-duplicates.js first.');
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const deleteList = JSON.parse(fs.readFileSync(deleteFile, 'utf8'));
|
|
31
|
+
|
|
32
|
+
console.log('📋 REMAINING DUPLICATES DELETION');
|
|
33
|
+
console.log('=' .repeat(60));
|
|
34
|
+
console.log(`\n Current tasks: ${deleteList.summary.currentTotal}`);
|
|
35
|
+
console.log(` Tasks to delete: ${deleteList.summary.toDelete}`);
|
|
36
|
+
console.log(` After deletion: ${deleteList.summary.afterDeletion}\n`);
|
|
37
|
+
|
|
38
|
+
// Show what will be deleted
|
|
39
|
+
console.log('📝 Tasks to be deleted:');
|
|
40
|
+
deleteList.tasks.forEach(task => {
|
|
41
|
+
console.log(` • ${task.identifier}: ${task.title.substring(0, 60)}...`);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// Confirmation
|
|
45
|
+
console.log(`\n⚠️ This will permanently delete ${deleteList.summary.toDelete} duplicate tasks.`);
|
|
46
|
+
console.log('Type "DELETE" to confirm, or press Ctrl+C to cancel:\n');
|
|
47
|
+
|
|
48
|
+
const rl = readline.createInterface({
|
|
49
|
+
input: process.stdin,
|
|
50
|
+
output: process.stdout
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const confirmation = await new Promise(resolve => {
|
|
54
|
+
rl.question('Confirmation: ', resolve);
|
|
55
|
+
});
|
|
56
|
+
rl.close();
|
|
57
|
+
|
|
58
|
+
if (confirmation !== 'DELETE') {
|
|
59
|
+
console.log('❌ Deletion cancelled');
|
|
60
|
+
process.exit(0);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
console.log('\n🗑️ Deleting remaining duplicates...\n');
|
|
64
|
+
|
|
65
|
+
let deleted = 0;
|
|
66
|
+
let failed = 0;
|
|
67
|
+
const results = [];
|
|
68
|
+
|
|
69
|
+
for (const task of deleteList.tasks) {
|
|
70
|
+
try {
|
|
71
|
+
process.stdout.write(`Deleting ${task.identifier}: ${task.title.substring(0, 40)}... `);
|
|
72
|
+
|
|
73
|
+
const deleteQuery = `
|
|
74
|
+
mutation DeleteIssue($id: String!) {
|
|
75
|
+
issueDelete(id: $id) {
|
|
76
|
+
success
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
`;
|
|
80
|
+
|
|
81
|
+
const response = await fetch('https://api.linear.app/graphql', {
|
|
82
|
+
method: 'POST',
|
|
83
|
+
headers: {
|
|
84
|
+
'Authorization': `Bearer ${API_KEY}`,
|
|
85
|
+
'Content-Type': 'application/json'
|
|
86
|
+
},
|
|
87
|
+
body: JSON.stringify({
|
|
88
|
+
query: deleteQuery,
|
|
89
|
+
variables: { id: task.id }
|
|
90
|
+
})
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const result = await response.json();
|
|
94
|
+
|
|
95
|
+
if (result.data?.issueDelete?.success) {
|
|
96
|
+
console.log('✅');
|
|
97
|
+
deleted++;
|
|
98
|
+
results.push({ ...task, status: 'deleted' });
|
|
99
|
+
} else if (result.errors?.[0]?.message?.includes('not found')) {
|
|
100
|
+
console.log('⚠️ (already gone)');
|
|
101
|
+
deleted++;
|
|
102
|
+
results.push({ ...task, status: 'already_deleted' });
|
|
103
|
+
} else {
|
|
104
|
+
const error = result.errors?.[0]?.message || 'Unknown error';
|
|
105
|
+
console.log(`❌ (${error})`);
|
|
106
|
+
failed++;
|
|
107
|
+
results.push({ ...task, status: 'failed', error });
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Small delay between deletions
|
|
111
|
+
await delay(500);
|
|
112
|
+
|
|
113
|
+
} catch (error) {
|
|
114
|
+
console.log(`❌ (${error.message})`);
|
|
115
|
+
failed++;
|
|
116
|
+
results.push({ ...task, status: 'error', error: error.message });
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Save results
|
|
121
|
+
const resultsFile = `remaining-deletion-results-${new Date().toISOString().split('T')[0]}.json`;
|
|
122
|
+
fs.writeFileSync(resultsFile, JSON.stringify({
|
|
123
|
+
summary: {
|
|
124
|
+
attempted: deleteList.tasks.length,
|
|
125
|
+
deleted,
|
|
126
|
+
failed,
|
|
127
|
+
success_rate: Math.round((deleted / deleteList.tasks.length) * 100)
|
|
128
|
+
},
|
|
129
|
+
results,
|
|
130
|
+
timestamp: new Date().toISOString()
|
|
131
|
+
}, null, 2));
|
|
132
|
+
|
|
133
|
+
// Final report
|
|
134
|
+
console.log('\n' + '='.repeat(60));
|
|
135
|
+
console.log('📊 DELETION COMPLETE');
|
|
136
|
+
console.log('='.repeat(60));
|
|
137
|
+
console.log(`\n✅ Successfully deleted: ${deleted} tasks`);
|
|
138
|
+
console.log(`❌ Failed: ${failed} tasks`);
|
|
139
|
+
console.log(`📈 Success rate: ${Math.round((deleted / deleteList.tasks.length) * 100)}%`);
|
|
140
|
+
console.log(`\n💾 Results saved to: ${resultsFile}`);
|
|
141
|
+
|
|
142
|
+
if (deleted > 0) {
|
|
143
|
+
console.log(`\n🎉 Workspace cleaned! Now at ${deleteList.summary.afterDeletion} tasks.`);
|
|
144
|
+
console.log('All TypeScript Strict Mode duplicates have been removed.');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
} catch (error) {
|
|
148
|
+
console.error('\n💥 Script failed:', error.message);
|
|
149
|
+
process.exit(1);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Run if called directly
|
|
154
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
155
|
+
deleteRemainingDuplicates().catch(console.error);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export { deleteRemainingDuplicates };
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Delete duplicate STA tasks from Linear to free up capacity
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import 'dotenv/config';
|
|
8
|
+
import fs from 'fs';
|
|
9
|
+
import readline from 'readline';
|
|
10
|
+
|
|
11
|
+
// Load API key from environment
|
|
12
|
+
const API_KEY = process.env.LINEAR_API_KEY;
|
|
13
|
+
if (!API_KEY) {
|
|
14
|
+
console.error('❌ LINEAR_API_KEY environment variable not set');
|
|
15
|
+
console.log('Please set LINEAR_API_KEY in your .env file or export it in your shell');
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
const BATCH_SIZE = 10; // Delete in batches to avoid rate limits
|
|
19
|
+
const DELAY_BETWEEN_BATCHES = 3000; // 3 seconds between batches
|
|
20
|
+
|
|
21
|
+
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
|
22
|
+
|
|
23
|
+
async function deleteSTATasks() {
|
|
24
|
+
try {
|
|
25
|
+
// Load deletion list
|
|
26
|
+
const deleteFile = `sta-deletion-list-${new Date().toISOString().split('T')[0]}.json`;
|
|
27
|
+
if (!fs.existsSync(deleteFile)) {
|
|
28
|
+
console.error(`❌ Deletion list not found: ${deleteFile}`);
|
|
29
|
+
console.log('Run analyze-sta-graphql.js first to generate the list.');
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const deleteList = JSON.parse(fs.readFileSync(deleteFile, 'utf8'));
|
|
34
|
+
|
|
35
|
+
console.log('📋 STA TASK DELETION SUMMARY');
|
|
36
|
+
console.log('=' .repeat(60));
|
|
37
|
+
console.log(`\n Total workspace tasks: ${deleteList.summary.totalWorkspace}`);
|
|
38
|
+
console.log(` Current STA tasks: ${deleteList.summary.totalSTA}`);
|
|
39
|
+
console.log(` Tasks to delete: ${deleteList.summary.toDelete}`);
|
|
40
|
+
console.log(` Workspace after deletion: ${deleteList.summary.remainingTotal}`);
|
|
41
|
+
console.log(`\n 🎯 Capacity to be freed: ${deleteList.summary.capacityFreed} task slots\n`);
|
|
42
|
+
|
|
43
|
+
// Show breakdown
|
|
44
|
+
console.log('📝 Tasks to delete by category:');
|
|
45
|
+
Object.entries(deleteList.categories).forEach(([category, tasks]) => {
|
|
46
|
+
if (tasks.length > 0) {
|
|
47
|
+
console.log(` • ${category}: ${tasks.length} tasks`);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// Safety confirmation
|
|
52
|
+
console.log('\n⚠️ WARNING: This will permanently delete ${deleteList.summary.toDelete} tasks from Linear!');
|
|
53
|
+
console.log('This action cannot be undone. Make sure you have reviewed the list.\n');
|
|
54
|
+
console.log('Type "DELETE STA TASKS" to confirm, or press Ctrl+C to cancel:\n');
|
|
55
|
+
|
|
56
|
+
const rl = readline.createInterface({
|
|
57
|
+
input: process.stdin,
|
|
58
|
+
output: process.stdout
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const confirmation = await new Promise(resolve => {
|
|
62
|
+
rl.question('Confirmation: ', resolve);
|
|
63
|
+
});
|
|
64
|
+
rl.close();
|
|
65
|
+
|
|
66
|
+
if (confirmation !== 'DELETE STA TASKS') {
|
|
67
|
+
console.log('❌ Deletion cancelled');
|
|
68
|
+
process.exit(0);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
console.log('\n🗑️ Starting deletion process...');
|
|
72
|
+
console.log(`Will delete in batches of ${BATCH_SIZE} with ${DELAY_BETWEEN_BATCHES/1000}s delay\n`);
|
|
73
|
+
|
|
74
|
+
let deleted = 0;
|
|
75
|
+
let failed = 0;
|
|
76
|
+
let alreadyDeleted = 0;
|
|
77
|
+
const results = [];
|
|
78
|
+
const errors = [];
|
|
79
|
+
|
|
80
|
+
// Process in batches
|
|
81
|
+
for (let i = 0; i < deleteList.tasks.length; i += BATCH_SIZE) {
|
|
82
|
+
const batch = deleteList.tasks.slice(i, i + BATCH_SIZE);
|
|
83
|
+
console.log(`\n📦 Batch ${Math.floor(i/BATCH_SIZE) + 1}/${Math.ceil(deleteList.tasks.length/BATCH_SIZE)}`);
|
|
84
|
+
|
|
85
|
+
for (const task of batch) {
|
|
86
|
+
try {
|
|
87
|
+
process.stdout.write(` Deleting ${task.identifier}: ${task.title.substring(0, 40)}... `);
|
|
88
|
+
|
|
89
|
+
const deleteQuery = `
|
|
90
|
+
mutation DeleteIssue($id: String!) {
|
|
91
|
+
issueDelete(id: $id) {
|
|
92
|
+
success
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
`;
|
|
96
|
+
|
|
97
|
+
const response = await fetch('https://api.linear.app/graphql', {
|
|
98
|
+
method: 'POST',
|
|
99
|
+
headers: {
|
|
100
|
+
'Authorization': API_KEY,
|
|
101
|
+
'Content-Type': 'application/json'
|
|
102
|
+
},
|
|
103
|
+
body: JSON.stringify({
|
|
104
|
+
query: deleteQuery,
|
|
105
|
+
variables: { id: task.id }
|
|
106
|
+
})
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
const result = await response.json();
|
|
110
|
+
|
|
111
|
+
if (result.data?.issueDelete?.success) {
|
|
112
|
+
console.log('✅');
|
|
113
|
+
deleted++;
|
|
114
|
+
results.push({ ...task, status: 'deleted' });
|
|
115
|
+
} else if (result.errors?.[0]?.message?.includes('not found')) {
|
|
116
|
+
console.log('⚠️ (already gone)');
|
|
117
|
+
alreadyDeleted++;
|
|
118
|
+
results.push({ ...task, status: 'already_deleted' });
|
|
119
|
+
} else {
|
|
120
|
+
const error = result.errors?.[0]?.message || 'Unknown error';
|
|
121
|
+
console.log(`❌ (${error})`);
|
|
122
|
+
failed++;
|
|
123
|
+
errors.push({ ...task, error });
|
|
124
|
+
results.push({ ...task, status: 'failed', error });
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
} catch (error) {
|
|
128
|
+
console.log(`❌ (${error.message})`);
|
|
129
|
+
failed++;
|
|
130
|
+
errors.push({ ...task, error: error.message });
|
|
131
|
+
results.push({ ...task, status: 'error', error: error.message });
|
|
132
|
+
|
|
133
|
+
// If rate limited, wait longer
|
|
134
|
+
if (error.message?.includes('rate') || error.message?.includes('429')) {
|
|
135
|
+
console.log('⏳ Rate limited. Waiting 30 seconds...');
|
|
136
|
+
await delay(30000);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Progress update
|
|
142
|
+
const total = deleted + alreadyDeleted + failed;
|
|
143
|
+
const percent = Math.round((total / deleteList.tasks.length) * 100);
|
|
144
|
+
console.log(`\n📊 Progress: ${total}/${deleteList.tasks.length} (${percent}%)`);
|
|
145
|
+
console.log(` ✅ Deleted: ${deleted} | ⚠️ Already gone: ${alreadyDeleted} | ❌ Failed: ${failed}`);
|
|
146
|
+
|
|
147
|
+
// Delay before next batch
|
|
148
|
+
if (i + BATCH_SIZE < deleteList.tasks.length) {
|
|
149
|
+
console.log(`⏳ Waiting ${DELAY_BETWEEN_BATCHES/1000}s before next batch...`);
|
|
150
|
+
await delay(DELAY_BETWEEN_BATCHES);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Save results
|
|
155
|
+
const resultsFile = `sta-deletion-results-${new Date().toISOString().split('T')[0]}.json`;
|
|
156
|
+
fs.writeFileSync(resultsFile, JSON.stringify({
|
|
157
|
+
summary: {
|
|
158
|
+
attempted: deleteList.tasks.length,
|
|
159
|
+
deleted,
|
|
160
|
+
alreadyDeleted,
|
|
161
|
+
failed,
|
|
162
|
+
success_rate: Math.round(((deleted + alreadyDeleted) / deleteList.tasks.length) * 100)
|
|
163
|
+
},
|
|
164
|
+
results,
|
|
165
|
+
errors: errors.length > 0 ? errors : undefined,
|
|
166
|
+
timestamp: new Date().toISOString()
|
|
167
|
+
}, null, 2));
|
|
168
|
+
|
|
169
|
+
// Final report
|
|
170
|
+
console.log('\n' + '='.repeat(60));
|
|
171
|
+
console.log('📊 DELETION COMPLETE');
|
|
172
|
+
console.log('='.repeat(60));
|
|
173
|
+
console.log(`\n✅ Successfully deleted: ${deleted} tasks`);
|
|
174
|
+
console.log(`⚠️ Already deleted: ${alreadyDeleted} tasks`);
|
|
175
|
+
console.log(`❌ Failed: ${failed} tasks`);
|
|
176
|
+
console.log(`📈 Success rate: ${Math.round(((deleted + alreadyDeleted) / deleteList.tasks.length) * 100)}%`);
|
|
177
|
+
console.log(`\n💾 Results saved to: ${resultsFile}`);
|
|
178
|
+
|
|
179
|
+
const totalFreed = deleted + alreadyDeleted;
|
|
180
|
+
if (totalFreed > 0) {
|
|
181
|
+
console.log(`\n🎉 Freed up ${totalFreed} task slots in your Linear workspace!`);
|
|
182
|
+
console.log('\nYour workspace now has capacity for new tasks.');
|
|
183
|
+
console.log('The backlog has been cleaned of duplicates and similar tasks.');
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (failed > 0) {
|
|
187
|
+
console.log(`\n⚠️ ${failed} tasks could not be deleted. Check ${resultsFile} for details.`);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
} catch (error) {
|
|
191
|
+
console.error('\n💥 Script failed:', error.message);
|
|
192
|
+
process.exit(1);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Run if called directly
|
|
197
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
198
|
+
deleteSTATasks().catch(console.error);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export { deleteSTATasks };
|