@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.
Files changed (212) hide show
  1. package/dist/cli/commands/skills.js +15 -2
  2. package/dist/cli/commands/skills.js.map +2 -2
  3. package/dist/cli/index.js +113 -834
  4. package/dist/cli/index.js.map +3 -3
  5. package/dist/core/context/dual-stack-manager.js +1 -1
  6. package/dist/core/context/dual-stack-manager.js.map +1 -1
  7. package/dist/core/context/frame-manager.js +3 -0
  8. package/dist/core/context/frame-manager.js.map +2 -2
  9. package/dist/integrations/claude-code/subagent-client.js +106 -3
  10. package/dist/integrations/claude-code/subagent-client.js.map +2 -2
  11. package/dist/servers/railway/config.js +51 -0
  12. package/dist/servers/railway/config.js.map +7 -0
  13. package/dist/servers/railway/index-enhanced.js +156 -0
  14. package/dist/servers/railway/index-enhanced.js.map +7 -0
  15. package/dist/servers/railway/minimal.js +48 -3
  16. package/dist/servers/railway/minimal.js.map +2 -2
  17. package/dist/servers/railway/storage-test.js +455 -0
  18. package/dist/servers/railway/storage-test.js.map +7 -0
  19. package/dist/skills/claude-skills.js +13 -12
  20. package/dist/skills/claude-skills.js.map +2 -2
  21. package/dist/skills/recursive-agent-orchestrator.js +27 -18
  22. package/dist/skills/recursive-agent-orchestrator.js.map +2 -2
  23. package/dist/skills/unified-rlm-orchestrator.js.map +2 -2
  24. package/package.json +6 -18
  25. package/scripts/README-TESTING.md +186 -0
  26. package/scripts/analyze-cli-security.js +288 -0
  27. package/scripts/archive/add-phase-tasks-to-linear.js +163 -0
  28. package/scripts/archive/analyze-linear-duplicates.js +214 -0
  29. package/scripts/archive/analyze-remaining-duplicates.js +230 -0
  30. package/scripts/archive/analyze-sta-duplicates.js +292 -0
  31. package/scripts/archive/analyze-sta-graphql.js +399 -0
  32. package/scripts/archive/cancel-duplicate-tasks.ts +246 -0
  33. package/scripts/archive/check-all-duplicates.ts +419 -0
  34. package/scripts/archive/clean-duplicate-tasks.js +114 -0
  35. package/scripts/archive/cleanup-duplicate-tasks.ts +286 -0
  36. package/scripts/archive/create-phase-tasks.js +387 -0
  37. package/scripts/archive/delete-linear-duplicates.js +182 -0
  38. package/scripts/archive/delete-remaining-duplicates.js +158 -0
  39. package/scripts/archive/delete-sta-duplicates.js +201 -0
  40. package/scripts/archive/delete-sta-oauth.js +201 -0
  41. package/scripts/archive/export-sta-tasks.js +62 -0
  42. package/scripts/archive/install-auto-sync.js +266 -0
  43. package/scripts/archive/install-chromadb-hooks.sh +133 -0
  44. package/scripts/archive/install-enhanced-clear-hooks.sh +431 -0
  45. package/scripts/archive/install-post-task-hooks.sh +289 -0
  46. package/scripts/archive/install-stackmemory-hooks.sh +420 -0
  47. package/scripts/archive/merge-linear-duplicates-safe.ts +362 -0
  48. package/scripts/archive/merge-linear-duplicates.ts +180 -0
  49. package/scripts/archive/remove-sta-tasks.js +70 -0
  50. package/scripts/archive/setup-background-sync.sh +168 -0
  51. package/scripts/archive/setup-claude-auto-triggers.sh +181 -0
  52. package/scripts/archive/setup-claude-autostart.sh +305 -0
  53. package/scripts/archive/setup-git-hooks.sh +25 -0
  54. package/scripts/archive/setup-linear-oauth.sh +46 -0
  55. package/scripts/archive/setup-mcp.sh +113 -0
  56. package/scripts/archive/setup-railway-deployment.sh +81 -0
  57. package/scripts/auto-handoff.sh +262 -0
  58. package/scripts/background-sync-manager.js +416 -0
  59. package/scripts/benchmark-performance.ts +57 -0
  60. package/scripts/check-redis.ts +48 -0
  61. package/scripts/chromadb-auto-loader.sh +128 -0
  62. package/scripts/chromadb-context-loader.js +479 -0
  63. package/scripts/claude-chromadb-hook.js +460 -0
  64. package/scripts/claude-code-wrapper.sh +66 -0
  65. package/scripts/claude-linear-skill.js +455 -0
  66. package/scripts/claude-pre-commit.sh +302 -0
  67. package/scripts/claude-sm-autostart.js +532 -0
  68. package/scripts/claude-sm-setup.sh +367 -0
  69. package/scripts/claude-with-chromadb.sh +69 -0
  70. package/scripts/claude-worktree-manager.sh +323 -0
  71. package/scripts/claude-worktree-monitor.sh +371 -0
  72. package/scripts/claude-worktree-setup.sh +327 -0
  73. package/scripts/clean-linear-backlog.js +273 -0
  74. package/scripts/cleanup-old-sessions.sh +57 -0
  75. package/scripts/codex-wrapper.sh +88 -0
  76. package/scripts/create-sandbox.sh +269 -0
  77. package/scripts/debug-linear-update.js +174 -0
  78. package/scripts/delete-linear-tasks.js +167 -0
  79. package/scripts/deploy.sh +89 -0
  80. package/scripts/deployment/railway.sh +352 -0
  81. package/scripts/deployment/test-deployment.js +194 -0
  82. package/scripts/detect-and-rehydrate.js +162 -0
  83. package/scripts/detect-and-rehydrate.mjs +165 -0
  84. package/scripts/development/create-demo-tasks.js +143 -0
  85. package/scripts/development/debug-frame-test.js +16 -0
  86. package/scripts/development/demo-auto-sync.js +128 -0
  87. package/scripts/development/fix-all-imports.js +213 -0
  88. package/scripts/development/fix-imports.js +229 -0
  89. package/scripts/development/fix-lint-loop.cjs +103 -0
  90. package/scripts/development/fix-project-id.ts +161 -0
  91. package/scripts/development/fix-strict-mode-issues.ts +291 -0
  92. package/scripts/development/reorganize-structure.sh +228 -0
  93. package/scripts/development/test-persistence-direct.js +148 -0
  94. package/scripts/development/test-persistence.js +114 -0
  95. package/scripts/development/test-tasks.js +93 -0
  96. package/scripts/development/update-imports.js +212 -0
  97. package/scripts/fetch-linear-status.js +125 -0
  98. package/scripts/git-hooks/README.md +310 -0
  99. package/scripts/git-hooks/branch-context-manager.sh +342 -0
  100. package/scripts/git-hooks/post-checkout-stackmemory.sh +63 -0
  101. package/scripts/git-hooks/post-commit-stackmemory.sh +305 -0
  102. package/scripts/git-hooks/pre-commit-stackmemory.sh +275 -0
  103. package/scripts/hooks/cleanup-shell.sh +130 -0
  104. package/scripts/hooks/task-complete.sh +114 -0
  105. package/scripts/initialize.ts +129 -0
  106. package/scripts/install-claude-hooks-auto.js +104 -0
  107. package/scripts/install-claude-hooks.sh +133 -0
  108. package/scripts/install-global.sh +296 -0
  109. package/scripts/install.sh +235 -0
  110. package/scripts/linear-auto-sync.js +262 -0
  111. package/scripts/linear-auto-sync.sh +161 -0
  112. package/scripts/linear-sync-daemon.js +150 -0
  113. package/scripts/linear-task-review.js +237 -0
  114. package/scripts/list-linear-tasks.ts +178 -0
  115. package/scripts/mcp-proxy.js +66 -0
  116. package/scripts/opencode-wrapper.sh +85 -0
  117. package/scripts/publish-local.js +74 -0
  118. package/scripts/query-chromadb.ts +201 -0
  119. package/scripts/railway-env-setup.sh +39 -0
  120. package/scripts/reconcile-local-tasks.js +170 -0
  121. package/scripts/recreate-frames-db.js +89 -0
  122. package/scripts/setup/claude-integration.js +138 -0
  123. package/scripts/setup/configure-alias.js +125 -0
  124. package/scripts/setup/configure-codex-alias.js +161 -0
  125. package/scripts/setup/configure-opencode-alias.js +175 -0
  126. package/scripts/setup-claude-integration.js +204 -0
  127. package/scripts/setup-claude-integration.sh +183 -0
  128. package/scripts/setup.sh +31 -0
  129. package/scripts/show-linear-summary.ts +172 -0
  130. package/scripts/stackmemory-auto-handoff.sh +231 -0
  131. package/scripts/stackmemory-daemon.sh +40 -0
  132. package/scripts/start-linear-sync-daemon.sh +141 -0
  133. package/scripts/start-temporal-paradox.sh +214 -0
  134. package/scripts/status.ts +159 -0
  135. package/scripts/sync-and-clean-tasks.js +258 -0
  136. package/scripts/sync-frames-from-railway.js +228 -0
  137. package/scripts/sync-linear-graphql.js +303 -0
  138. package/scripts/sync-linear-tasks.js +186 -0
  139. package/scripts/test-auto-triggers.sh +57 -0
  140. package/scripts/test-browser-mcp.js +74 -0
  141. package/scripts/test-chromadb-full.js +115 -0
  142. package/scripts/test-chromadb-hooks.sh +28 -0
  143. package/scripts/test-chromadb-sync.ts +245 -0
  144. package/scripts/test-cli-security.js +293 -0
  145. package/scripts/test-hooks-persistence.sh +220 -0
  146. package/scripts/test-installation-scenarios.sh +359 -0
  147. package/scripts/test-installation.sh +224 -0
  148. package/scripts/test-mcp.js +163 -0
  149. package/scripts/test-pre-publish-quick.sh +75 -0
  150. package/scripts/test-quality-gates.sh +263 -0
  151. package/scripts/test-railway-db.js +222 -0
  152. package/scripts/test-redis-storage.ts +490 -0
  153. package/scripts/test-rlm-basic.sh +122 -0
  154. package/scripts/test-rlm-comprehensive.sh +260 -0
  155. package/scripts/test-rlm-e2e.sh +268 -0
  156. package/scripts/test-rlm-simple.js +90 -0
  157. package/scripts/test-rlm.js +110 -0
  158. package/scripts/test-session-handoff.sh +165 -0
  159. package/scripts/test-shell-integration.sh +275 -0
  160. package/scripts/testing/ab-test-runner.ts +508 -0
  161. package/scripts/testing/collect-metrics.ts +457 -0
  162. package/scripts/testing/quick-effectiveness-demo.js +187 -0
  163. package/scripts/testing/real-performance-test.js +422 -0
  164. package/scripts/testing/run-effectiveness-tests.sh +176 -0
  165. package/scripts/testing/scripts/testing/ab-test-runner.js +363 -0
  166. package/scripts/testing/scripts/testing/collect-metrics.js +292 -0
  167. package/scripts/testing/simple-effectiveness-test.js +310 -0
  168. package/scripts/testing/src/core/context/context-bridge.js +253 -0
  169. package/scripts/testing/src/core/context/frame-manager.js +746 -0
  170. package/scripts/testing/src/core/context/shared-context-layer.js +437 -0
  171. package/scripts/testing/src/core/database/database-adapter.js +54 -0
  172. package/scripts/testing/src/core/errors/index.js +291 -0
  173. package/scripts/testing/src/core/errors/recovery.js +268 -0
  174. package/scripts/testing/src/core/monitoring/logger.js +145 -0
  175. package/scripts/testing/src/core/retrieval/context-retriever.js +516 -0
  176. package/scripts/testing/src/core/session/index.js +1 -0
  177. package/scripts/testing/src/core/session/session-manager.js +323 -0
  178. package/scripts/testing/src/core/trace/cli-trace-wrapper.js +140 -0
  179. package/scripts/testing/src/core/trace/db-trace-wrapper.js +251 -0
  180. package/scripts/testing/src/core/trace/debug-trace.js +398 -0
  181. package/scripts/testing/src/core/trace/index.js +120 -0
  182. package/scripts/testing/src/core/trace/linear-api-wrapper.js +204 -0
  183. package/scripts/update-linear-status.js +268 -0
  184. package/scripts/update-linear-tasks-fixed.js +284 -0
  185. package/templates/claude-hooks/hooks.json +5 -0
  186. package/templates/claude-hooks/on-clear.js +56 -0
  187. package/templates/claude-hooks/on-startup.js +56 -0
  188. package/templates/claude-hooks/tool-use-trace.js +67 -0
  189. package/dist/features/tui/components/analytics-panel.js +0 -157
  190. package/dist/features/tui/components/analytics-panel.js.map +0 -7
  191. package/dist/features/tui/components/frame-visualizer.js +0 -377
  192. package/dist/features/tui/components/frame-visualizer.js.map +0 -7
  193. package/dist/features/tui/components/pr-tracker.js +0 -135
  194. package/dist/features/tui/components/pr-tracker.js.map +0 -7
  195. package/dist/features/tui/components/session-monitor.js +0 -299
  196. package/dist/features/tui/components/session-monitor.js.map +0 -7
  197. package/dist/features/tui/components/subagent-fleet.js +0 -395
  198. package/dist/features/tui/components/subagent-fleet.js.map +0 -7
  199. package/dist/features/tui/components/task-board.js +0 -1139
  200. package/dist/features/tui/components/task-board.js.map +0 -7
  201. package/dist/features/tui/index.js +0 -408
  202. package/dist/features/tui/index.js.map +0 -7
  203. package/dist/features/tui/services/data-service.js +0 -641
  204. package/dist/features/tui/services/data-service.js.map +0 -7
  205. package/dist/features/tui/services/linear-task-reader.js +0 -102
  206. package/dist/features/tui/services/linear-task-reader.js.map +0 -7
  207. package/dist/features/tui/services/websocket-client.js +0 -162
  208. package/dist/features/tui/services/websocket-client.js.map +0 -7
  209. package/dist/features/tui/terminal-compat.js +0 -220
  210. package/dist/features/tui/terminal-compat.js.map +0 -7
  211. package/dist/features/tui/types.js +0 -1
  212. 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 };