@stackmemoryai/stackmemory 0.3.16 โ†’ 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 (213) hide show
  1. package/README.md +48 -2
  2. package/dist/cli/commands/skills.js +15 -2
  3. package/dist/cli/commands/skills.js.map +2 -2
  4. package/dist/cli/index.js +113 -834
  5. package/dist/cli/index.js.map +3 -3
  6. package/dist/core/context/dual-stack-manager.js +1 -1
  7. package/dist/core/context/dual-stack-manager.js.map +1 -1
  8. package/dist/core/context/frame-manager.js +3 -0
  9. package/dist/core/context/frame-manager.js.map +2 -2
  10. package/dist/integrations/claude-code/subagent-client.js +106 -3
  11. package/dist/integrations/claude-code/subagent-client.js.map +2 -2
  12. package/dist/servers/railway/config.js +51 -0
  13. package/dist/servers/railway/config.js.map +7 -0
  14. package/dist/servers/railway/index-enhanced.js +156 -0
  15. package/dist/servers/railway/index-enhanced.js.map +7 -0
  16. package/dist/servers/railway/minimal.js +48 -3
  17. package/dist/servers/railway/minimal.js.map +2 -2
  18. package/dist/servers/railway/storage-test.js +455 -0
  19. package/dist/servers/railway/storage-test.js.map +7 -0
  20. package/dist/skills/claude-skills.js +13 -12
  21. package/dist/skills/claude-skills.js.map +2 -2
  22. package/dist/skills/recursive-agent-orchestrator.js +27 -18
  23. package/dist/skills/recursive-agent-orchestrator.js.map +2 -2
  24. package/dist/skills/unified-rlm-orchestrator.js.map +2 -2
  25. package/package.json +6 -18
  26. package/scripts/README-TESTING.md +186 -0
  27. package/scripts/analyze-cli-security.js +288 -0
  28. package/scripts/archive/add-phase-tasks-to-linear.js +163 -0
  29. package/scripts/archive/analyze-linear-duplicates.js +214 -0
  30. package/scripts/archive/analyze-remaining-duplicates.js +230 -0
  31. package/scripts/archive/analyze-sta-duplicates.js +292 -0
  32. package/scripts/archive/analyze-sta-graphql.js +399 -0
  33. package/scripts/archive/cancel-duplicate-tasks.ts +246 -0
  34. package/scripts/archive/check-all-duplicates.ts +419 -0
  35. package/scripts/archive/clean-duplicate-tasks.js +114 -0
  36. package/scripts/archive/cleanup-duplicate-tasks.ts +286 -0
  37. package/scripts/archive/create-phase-tasks.js +387 -0
  38. package/scripts/archive/delete-linear-duplicates.js +182 -0
  39. package/scripts/archive/delete-remaining-duplicates.js +158 -0
  40. package/scripts/archive/delete-sta-duplicates.js +201 -0
  41. package/scripts/archive/delete-sta-oauth.js +201 -0
  42. package/scripts/archive/export-sta-tasks.js +62 -0
  43. package/scripts/archive/install-auto-sync.js +266 -0
  44. package/scripts/archive/install-chromadb-hooks.sh +133 -0
  45. package/scripts/archive/install-enhanced-clear-hooks.sh +431 -0
  46. package/scripts/archive/install-post-task-hooks.sh +289 -0
  47. package/scripts/archive/install-stackmemory-hooks.sh +420 -0
  48. package/scripts/archive/merge-linear-duplicates-safe.ts +362 -0
  49. package/scripts/archive/merge-linear-duplicates.ts +180 -0
  50. package/scripts/archive/remove-sta-tasks.js +70 -0
  51. package/scripts/archive/setup-background-sync.sh +168 -0
  52. package/scripts/archive/setup-claude-auto-triggers.sh +181 -0
  53. package/scripts/archive/setup-claude-autostart.sh +305 -0
  54. package/scripts/archive/setup-git-hooks.sh +25 -0
  55. package/scripts/archive/setup-linear-oauth.sh +46 -0
  56. package/scripts/archive/setup-mcp.sh +113 -0
  57. package/scripts/archive/setup-railway-deployment.sh +81 -0
  58. package/scripts/auto-handoff.sh +262 -0
  59. package/scripts/background-sync-manager.js +416 -0
  60. package/scripts/benchmark-performance.ts +57 -0
  61. package/scripts/check-redis.ts +48 -0
  62. package/scripts/chromadb-auto-loader.sh +128 -0
  63. package/scripts/chromadb-context-loader.js +479 -0
  64. package/scripts/claude-chromadb-hook.js +460 -0
  65. package/scripts/claude-code-wrapper.sh +66 -0
  66. package/scripts/claude-linear-skill.js +455 -0
  67. package/scripts/claude-pre-commit.sh +302 -0
  68. package/scripts/claude-sm-autostart.js +532 -0
  69. package/scripts/claude-sm-setup.sh +367 -0
  70. package/scripts/claude-with-chromadb.sh +69 -0
  71. package/scripts/claude-worktree-manager.sh +323 -0
  72. package/scripts/claude-worktree-monitor.sh +371 -0
  73. package/scripts/claude-worktree-setup.sh +327 -0
  74. package/scripts/clean-linear-backlog.js +273 -0
  75. package/scripts/cleanup-old-sessions.sh +57 -0
  76. package/scripts/codex-wrapper.sh +88 -0
  77. package/scripts/create-sandbox.sh +269 -0
  78. package/scripts/debug-linear-update.js +174 -0
  79. package/scripts/delete-linear-tasks.js +167 -0
  80. package/scripts/deploy.sh +89 -0
  81. package/scripts/deployment/railway.sh +352 -0
  82. package/scripts/deployment/test-deployment.js +194 -0
  83. package/scripts/detect-and-rehydrate.js +162 -0
  84. package/scripts/detect-and-rehydrate.mjs +165 -0
  85. package/scripts/development/create-demo-tasks.js +143 -0
  86. package/scripts/development/debug-frame-test.js +16 -0
  87. package/scripts/development/demo-auto-sync.js +128 -0
  88. package/scripts/development/fix-all-imports.js +213 -0
  89. package/scripts/development/fix-imports.js +229 -0
  90. package/scripts/development/fix-lint-loop.cjs +103 -0
  91. package/scripts/development/fix-project-id.ts +161 -0
  92. package/scripts/development/fix-strict-mode-issues.ts +291 -0
  93. package/scripts/development/reorganize-structure.sh +228 -0
  94. package/scripts/development/test-persistence-direct.js +148 -0
  95. package/scripts/development/test-persistence.js +114 -0
  96. package/scripts/development/test-tasks.js +93 -0
  97. package/scripts/development/update-imports.js +212 -0
  98. package/scripts/fetch-linear-status.js +125 -0
  99. package/scripts/git-hooks/README.md +310 -0
  100. package/scripts/git-hooks/branch-context-manager.sh +342 -0
  101. package/scripts/git-hooks/post-checkout-stackmemory.sh +63 -0
  102. package/scripts/git-hooks/post-commit-stackmemory.sh +305 -0
  103. package/scripts/git-hooks/pre-commit-stackmemory.sh +275 -0
  104. package/scripts/hooks/cleanup-shell.sh +130 -0
  105. package/scripts/hooks/task-complete.sh +114 -0
  106. package/scripts/initialize.ts +129 -0
  107. package/scripts/install-claude-hooks-auto.js +104 -0
  108. package/scripts/install-claude-hooks.sh +133 -0
  109. package/scripts/install-global.sh +296 -0
  110. package/scripts/install.sh +235 -0
  111. package/scripts/linear-auto-sync.js +262 -0
  112. package/scripts/linear-auto-sync.sh +161 -0
  113. package/scripts/linear-sync-daemon.js +150 -0
  114. package/scripts/linear-task-review.js +237 -0
  115. package/scripts/list-linear-tasks.ts +178 -0
  116. package/scripts/mcp-proxy.js +66 -0
  117. package/scripts/opencode-wrapper.sh +85 -0
  118. package/scripts/publish-local.js +74 -0
  119. package/scripts/query-chromadb.ts +201 -0
  120. package/scripts/railway-env-setup.sh +39 -0
  121. package/scripts/reconcile-local-tasks.js +170 -0
  122. package/scripts/recreate-frames-db.js +89 -0
  123. package/scripts/setup/claude-integration.js +138 -0
  124. package/scripts/setup/configure-alias.js +125 -0
  125. package/scripts/setup/configure-codex-alias.js +161 -0
  126. package/scripts/setup/configure-opencode-alias.js +175 -0
  127. package/scripts/setup-claude-integration.js +204 -0
  128. package/scripts/setup-claude-integration.sh +183 -0
  129. package/scripts/setup.sh +31 -0
  130. package/scripts/show-linear-summary.ts +172 -0
  131. package/scripts/stackmemory-auto-handoff.sh +231 -0
  132. package/scripts/stackmemory-daemon.sh +40 -0
  133. package/scripts/start-linear-sync-daemon.sh +141 -0
  134. package/scripts/start-temporal-paradox.sh +214 -0
  135. package/scripts/status.ts +159 -0
  136. package/scripts/sync-and-clean-tasks.js +258 -0
  137. package/scripts/sync-frames-from-railway.js +228 -0
  138. package/scripts/sync-linear-graphql.js +303 -0
  139. package/scripts/sync-linear-tasks.js +186 -0
  140. package/scripts/test-auto-triggers.sh +57 -0
  141. package/scripts/test-browser-mcp.js +74 -0
  142. package/scripts/test-chromadb-full.js +115 -0
  143. package/scripts/test-chromadb-hooks.sh +28 -0
  144. package/scripts/test-chromadb-sync.ts +245 -0
  145. package/scripts/test-cli-security.js +293 -0
  146. package/scripts/test-hooks-persistence.sh +220 -0
  147. package/scripts/test-installation-scenarios.sh +359 -0
  148. package/scripts/test-installation.sh +224 -0
  149. package/scripts/test-mcp.js +163 -0
  150. package/scripts/test-pre-publish-quick.sh +75 -0
  151. package/scripts/test-quality-gates.sh +263 -0
  152. package/scripts/test-railway-db.js +222 -0
  153. package/scripts/test-redis-storage.ts +490 -0
  154. package/scripts/test-rlm-basic.sh +122 -0
  155. package/scripts/test-rlm-comprehensive.sh +260 -0
  156. package/scripts/test-rlm-e2e.sh +268 -0
  157. package/scripts/test-rlm-simple.js +90 -0
  158. package/scripts/test-rlm.js +110 -0
  159. package/scripts/test-session-handoff.sh +165 -0
  160. package/scripts/test-shell-integration.sh +275 -0
  161. package/scripts/testing/ab-test-runner.ts +508 -0
  162. package/scripts/testing/collect-metrics.ts +457 -0
  163. package/scripts/testing/quick-effectiveness-demo.js +187 -0
  164. package/scripts/testing/real-performance-test.js +422 -0
  165. package/scripts/testing/run-effectiveness-tests.sh +176 -0
  166. package/scripts/testing/scripts/testing/ab-test-runner.js +363 -0
  167. package/scripts/testing/scripts/testing/collect-metrics.js +292 -0
  168. package/scripts/testing/simple-effectiveness-test.js +310 -0
  169. package/scripts/testing/src/core/context/context-bridge.js +253 -0
  170. package/scripts/testing/src/core/context/frame-manager.js +746 -0
  171. package/scripts/testing/src/core/context/shared-context-layer.js +437 -0
  172. package/scripts/testing/src/core/database/database-adapter.js +54 -0
  173. package/scripts/testing/src/core/errors/index.js +291 -0
  174. package/scripts/testing/src/core/errors/recovery.js +268 -0
  175. package/scripts/testing/src/core/monitoring/logger.js +145 -0
  176. package/scripts/testing/src/core/retrieval/context-retriever.js +516 -0
  177. package/scripts/testing/src/core/session/index.js +1 -0
  178. package/scripts/testing/src/core/session/session-manager.js +323 -0
  179. package/scripts/testing/src/core/trace/cli-trace-wrapper.js +140 -0
  180. package/scripts/testing/src/core/trace/db-trace-wrapper.js +251 -0
  181. package/scripts/testing/src/core/trace/debug-trace.js +398 -0
  182. package/scripts/testing/src/core/trace/index.js +120 -0
  183. package/scripts/testing/src/core/trace/linear-api-wrapper.js +204 -0
  184. package/scripts/update-linear-status.js +268 -0
  185. package/scripts/update-linear-tasks-fixed.js +284 -0
  186. package/templates/claude-hooks/hooks.json +5 -0
  187. package/templates/claude-hooks/on-clear.js +56 -0
  188. package/templates/claude-hooks/on-startup.js +56 -0
  189. package/templates/claude-hooks/tool-use-trace.js +67 -0
  190. package/dist/features/tui/components/analytics-panel.js +0 -157
  191. package/dist/features/tui/components/analytics-panel.js.map +0 -7
  192. package/dist/features/tui/components/frame-visualizer.js +0 -377
  193. package/dist/features/tui/components/frame-visualizer.js.map +0 -7
  194. package/dist/features/tui/components/pr-tracker.js +0 -135
  195. package/dist/features/tui/components/pr-tracker.js.map +0 -7
  196. package/dist/features/tui/components/session-monitor.js +0 -299
  197. package/dist/features/tui/components/session-monitor.js.map +0 -7
  198. package/dist/features/tui/components/subagent-fleet.js +0 -395
  199. package/dist/features/tui/components/subagent-fleet.js.map +0 -7
  200. package/dist/features/tui/components/task-board.js +0 -1139
  201. package/dist/features/tui/components/task-board.js.map +0 -7
  202. package/dist/features/tui/index.js +0 -408
  203. package/dist/features/tui/index.js.map +0 -7
  204. package/dist/features/tui/services/data-service.js +0 -641
  205. package/dist/features/tui/services/data-service.js.map +0 -7
  206. package/dist/features/tui/services/linear-task-reader.js +0 -102
  207. package/dist/features/tui/services/linear-task-reader.js.map +0 -7
  208. package/dist/features/tui/services/websocket-client.js +0 -162
  209. package/dist/features/tui/services/websocket-client.js.map +0 -7
  210. package/dist/features/tui/terminal-compat.js +0 -220
  211. package/dist/features/tui/terminal-compat.js.map +0 -7
  212. package/dist/features/tui/types.js +0 -1
  213. package/dist/features/tui/types.js.map +0 -7
@@ -0,0 +1,303 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+ import { fileURLToPath } from 'url';
6
+ import dotenv from 'dotenv';
7
+
8
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
9
+
10
+ // Load environment variables from .env file
11
+ dotenv.config({
12
+ path: path.join(__dirname, '..', '.env'),
13
+ debug: false,
14
+ override: true,
15
+ silent: true
16
+ });
17
+
18
+ // Debug: Check if key is loaded
19
+ console.log(`API Key loaded: ${process.env.LINEAR_API_KEY ? 'Yes' : 'No'} (length: ${process.env.LINEAR_API_KEY?.length || 0})`);
20
+
21
+ async function queryLinear(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 syncLinearTasks() {
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
+ // Check for --mirror flag to do a complete replacement
47
+ const isMirrorMode = process.argv.includes('--mirror');
48
+
49
+ if (isMirrorMode) {
50
+ console.log('๐Ÿ”„ Running in MIRROR mode - will replace all local tasks with Linear tasks...');
51
+ } else {
52
+ console.log('๐Ÿ”„ Connecting to Linear API...');
53
+ }
54
+
55
+ try {
56
+ // Test connection
57
+ const viewer = await queryLinear('{ viewer { id email name } }');
58
+ console.log(`โœ… Connected as: ${viewer.viewer.name || viewer.viewer.email}`);
59
+
60
+ // Get teams
61
+ const teamsData = await queryLinear(`
62
+ query {
63
+ teams {
64
+ nodes {
65
+ id
66
+ key
67
+ name
68
+ }
69
+ }
70
+ }
71
+ `);
72
+
73
+ console.log(`\n๐Ÿ“‹ Found ${teamsData.teams.nodes.length} teams:`);
74
+ for (const team of teamsData.teams.nodes) {
75
+ console.log(` - ${team.key}: ${team.name}`);
76
+ }
77
+
78
+ // Get ALL issues from all teams using pagination
79
+ let allIssues = [];
80
+ let hasNextPage = true;
81
+ let endCursor = null;
82
+
83
+ while (hasNextPage) {
84
+ const issuesData = await queryLinear(`
85
+ query($after: String) {
86
+ issues(first: 100, orderBy: updatedAt, after: $after) {
87
+ nodes {
88
+ id
89
+ identifier
90
+ title
91
+ description
92
+ state {
93
+ name
94
+ type
95
+ }
96
+ priority
97
+ priorityLabel
98
+ team {
99
+ key
100
+ name
101
+ }
102
+ assignee {
103
+ name
104
+ email
105
+ }
106
+ createdAt
107
+ updatedAt
108
+ url
109
+ }
110
+ pageInfo {
111
+ hasNextPage
112
+ endCursor
113
+ }
114
+ }
115
+ }
116
+ `, { after: endCursor });
117
+
118
+ allIssues = allIssues.concat(issuesData.issues.nodes);
119
+ hasNextPage = issuesData.issues.pageInfo.hasNextPage;
120
+ endCursor = issuesData.issues.pageInfo.endCursor;
121
+
122
+ if (hasNextPage) {
123
+ console.log(` Fetched ${allIssues.length} issues so far...`);
124
+ }
125
+ }
126
+
127
+ const issuesData = { issues: { nodes: allIssues } };
128
+
129
+ console.log(`\n๐Ÿ“ฅ Found ${issuesData.issues.nodes.length} issues total`);
130
+
131
+ // Group by team
132
+ const issuesByTeam = {};
133
+ for (const issue of issuesData.issues.nodes) {
134
+ const teamKey = issue.team.key;
135
+ if (!issuesByTeam[teamKey]) {
136
+ issuesByTeam[teamKey] = [];
137
+ }
138
+ issuesByTeam[teamKey].push(issue);
139
+ }
140
+
141
+ for (const [teamKey, issues] of Object.entries(issuesByTeam)) {
142
+ console.log(` ${teamKey}: ${issues.length} issues`);
143
+ }
144
+
145
+ // Load local tasks
146
+ const tasksFile = path.join(__dirname, '..', '.stackmemory', 'tasks.jsonl');
147
+ let localTasks = [];
148
+ const localLinearIds = new Set();
149
+
150
+ if (isMirrorMode) {
151
+ // In mirror mode, we'll replace everything
152
+ console.log('\n๐Ÿงน Mirror mode: Clearing existing tasks...');
153
+ if (fs.existsSync(tasksFile)) {
154
+ fs.writeFileSync(tasksFile, ''); // Clear the file
155
+ }
156
+ } else if (fs.existsSync(tasksFile)) {
157
+ const lines = fs.readFileSync(tasksFile, 'utf8').split('\n').filter(l => l.trim());
158
+ for (const line of lines) {
159
+ try {
160
+ const task = JSON.parse(line);
161
+ if (task.type === 'task_create' || task.type === 'task_update') {
162
+ localTasks.push(task);
163
+ const match = task.title?.match(/\[(STA-\d+|ENG-\d+)\]/);
164
+ if (match) {
165
+ localLinearIds.add(match[1]);
166
+ }
167
+ }
168
+ } catch (e) {
169
+ // Skip invalid lines
170
+ }
171
+ }
172
+ }
173
+
174
+ console.log(`\n๐Ÿ“‚ Local tasks: ${localTasks.length}`);
175
+ console.log(`๐ŸŒ Linear issues: ${issuesData.issues.nodes.length}`);
176
+
177
+ // In mirror mode, sync ALL issues; otherwise just missing ones
178
+ const issuesToSync = isMirrorMode ? issuesData.issues.nodes : [];
179
+
180
+ if (!isMirrorMode) {
181
+ // Find issues not in local tasks
182
+ for (const issue of issuesData.issues.nodes) {
183
+ if (!localLinearIds.has(issue.identifier)) {
184
+ issuesToSync.push(issue);
185
+ }
186
+ }
187
+ }
188
+
189
+ if (issuesToSync.length > 0) {
190
+ const modeText = isMirrorMode ? 'Mirroring ALL' : 'Adding new';
191
+ console.log(`\n๐Ÿ†• ${modeText} Linear issues (${issuesToSync.length}):`);
192
+
193
+ const newTasks = [];
194
+ const displayLimit = Math.min(issuesToSync.length, 20);
195
+
196
+ for (let i = 0; i < issuesToSync.length; i++) {
197
+ const issue = issuesToSync[i];
198
+
199
+ if (i < displayLimit) {
200
+ console.log(` - ${issue.identifier}: ${issue.title}`);
201
+ }
202
+
203
+ const taskId = `tsk-${Math.random().toString(36).substr(2, 8)}`;
204
+ const task = {
205
+ id: taskId,
206
+ type: 'task_create',
207
+ timestamp: Date.now(),
208
+ frame_id: 'linear-sync',
209
+ title: `[${issue.identifier}] ${issue.title}`,
210
+ description: issue.description || '',
211
+ status: mapLinearState(issue.state.type),
212
+ priority: mapLinearPriority(issue.priority),
213
+ created_at: Date.now(),
214
+ depends_on: [],
215
+ blocks: [],
216
+ tags: ['linear', 'synced', issue.team.key.toLowerCase()],
217
+ context_score: 0.5,
218
+ external_refs: {
219
+ linear_id: issue.id,
220
+ linear_identifier: issue.identifier,
221
+ linear_url: issue.url,
222
+ team: issue.team.key,
223
+ assignee: issue.assignee?.email || null,
224
+ state_name: issue.state.name
225
+ }
226
+ };
227
+
228
+ newTasks.push(JSON.stringify(task));
229
+ }
230
+
231
+ if (issuesToSync.length > displayLimit) {
232
+ console.log(` ... and ${issuesToSync.length - displayLimit} more`);
233
+ }
234
+
235
+ if (newTasks.length > 0) {
236
+ console.log(`\n๐Ÿ’พ Writing ${newTasks.length} tasks to local storage...`);
237
+ fs.appendFileSync(tasksFile, newTasks.join('\n') + '\n');
238
+ console.log('โœ… Tasks synced successfully!');
239
+ }
240
+ } else if (!isMirrorMode) {
241
+ console.log('\nโœ… All Linear issues already exist locally');
242
+ }
243
+
244
+ // Find local tasks not in Linear
245
+ const linearIds = new Set(issuesData.issues.nodes.map(i => i.identifier));
246
+ const missingInLinear = localTasks.filter(task => {
247
+ const match = task.title?.match(/\[(STA-\d+|ENG-\d+)\]/);
248
+ return match && !linearIds.has(match[1]);
249
+ });
250
+
251
+ if (missingInLinear.length > 0) {
252
+ console.log(`\n๐Ÿ“ค Local tasks not in Linear (${missingInLinear.length}):`);
253
+ for (const task of missingInLinear.slice(0, 10)) {
254
+ const match = task.title?.match(/\[(STA-\d+|ENG-\d+)\]/);
255
+ console.log(` - ${match?.[1] || 'Unknown'}: ${task.title}`);
256
+ }
257
+ if (missingInLinear.length > 10) {
258
+ console.log(` ... and ${missingInLinear.length - 10} more`);
259
+ }
260
+ console.log('\n๐Ÿ’ก These may be deleted Linear issues or local-only tasks');
261
+ }
262
+
263
+ // Summary
264
+ console.log('\n๐Ÿ“Š Sync Summary:');
265
+ console.log(` Total Linear issues: ${issuesData.issues.nodes.length}`);
266
+ console.log(` Total local tasks: ${localTasks.length}`);
267
+ if (!isMirrorMode) {
268
+ console.log(` Added to local: ${issuesToSync.length}`);
269
+ console.log(` Local-only tasks: ${missingInLinear.length}`);
270
+ } else {
271
+ console.log(` Mirrored: ${issuesToSync.length} tasks`);
272
+ }
273
+
274
+ } catch (error) {
275
+ console.error('โŒ Error syncing with Linear:', error.message);
276
+ if (error.message.includes('authentication') || error.message.includes('401')) {
277
+ console.log('\n๐Ÿ”‘ Authentication failed. Please check your LINEAR_API_KEY');
278
+ }
279
+ }
280
+ }
281
+
282
+ function mapLinearState(state) {
283
+ switch (state) {
284
+ case 'completed': return 'completed';
285
+ case 'started': return 'in_progress';
286
+ case 'canceled': return 'cancelled';
287
+ case 'cancelled': return 'cancelled';
288
+ default: return 'pending';
289
+ }
290
+ }
291
+
292
+ function mapLinearPriority(priority) {
293
+ switch (priority) {
294
+ case 0: return 'none';
295
+ case 1: return 'urgent';
296
+ case 2: return 'high';
297
+ case 3: return 'medium';
298
+ case 4: return 'low';
299
+ default: return 'medium';
300
+ }
301
+ }
302
+
303
+ syncLinearTasks();
@@ -0,0 +1,186 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { LinearClient } from '@linear/sdk';
4
+ import fs from 'fs';
5
+ import path from 'path';
6
+ import { fileURLToPath } from 'url';
7
+ import dotenv from 'dotenv';
8
+
9
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
10
+
11
+ // Load environment variables from .env file
12
+ dotenv.config({ path: path.join(__dirname, '..', '.env') });
13
+
14
+ async function syncLinearTasks() {
15
+ const apiKey = process.env.LINEAR_API_KEY;
16
+
17
+ if (!apiKey) {
18
+ console.error('โŒ LINEAR_API_KEY not found in environment');
19
+ process.exit(1);
20
+ }
21
+
22
+ console.log('๐Ÿ”„ Connecting to Linear with API key...');
23
+ // Linear SDK expects the API key without the "lin_api_" prefix in some versions
24
+ // But let's use the full key and pass it correctly
25
+ const linearClient = new LinearClient({
26
+ apiKey: apiKey,
27
+ headers: {
28
+ 'Authorization': apiKey
29
+ }
30
+ });
31
+
32
+ try {
33
+ // Test connection and get team info
34
+ console.log('๐Ÿ“Š Fetching workspace info...');
35
+ const me = await linearClient.viewer;
36
+ console.log(`โœ… Connected as: ${me.name || me.email}`);
37
+
38
+ // Get all teams
39
+ const teams = await linearClient.teams();
40
+ console.log(`\n๐Ÿ“‹ Found ${teams.nodes.length} teams:`);
41
+
42
+ for (const team of teams.nodes) {
43
+ console.log(` - ${team.key}: ${team.name}`);
44
+ }
45
+
46
+ // Get issues from StackMemory team
47
+ const stackTeam = teams.nodes.find(t => t.key === 'STA' || t.key === 'STACK');
48
+ if (!stackTeam) {
49
+ console.log('\nโš ๏ธ No StackMemory team found (looking for STA or STACK)');
50
+ return;
51
+ }
52
+
53
+ console.log(`\n๐Ÿ“ฅ Fetching issues from ${stackTeam.name} (${stackTeam.key})...`);
54
+ const issues = await linearClient.issues({
55
+ filter: {
56
+ team: { key: { eq: stackTeam.key } }
57
+ },
58
+ first: 100
59
+ });
60
+
61
+ console.log(`Found ${issues.nodes.length} issues\n`);
62
+
63
+ // Load local tasks
64
+ const tasksFile = path.join(__dirname, '..', '.stackmemory', 'tasks.jsonl');
65
+ const localTasks = [];
66
+
67
+ if (fs.existsSync(tasksFile)) {
68
+ const lines = fs.readFileSync(tasksFile, 'utf8').split('\n').filter(l => l.trim());
69
+ for (const line of lines) {
70
+ try {
71
+ const task = JSON.parse(line);
72
+ if (task.type === 'task_create' || task.type === 'task_update') {
73
+ localTasks.push(task);
74
+ }
75
+ } catch (e) {
76
+ // Skip invalid lines
77
+ }
78
+ }
79
+ }
80
+
81
+ console.log(`๐Ÿ“‚ Local tasks: ${localTasks.length}`);
82
+ console.log(`๐ŸŒ Linear issues: ${issues.nodes.length}`);
83
+
84
+ // Find tasks that exist in Linear but not locally
85
+ const localLinearIds = new Set();
86
+ for (const task of localTasks) {
87
+ const match = task.title?.match(/\[(STA-\d+|ENG-\d+)\]/);
88
+ if (match) {
89
+ localLinearIds.add(match[1]);
90
+ }
91
+ }
92
+
93
+ const missingLocally = [];
94
+ for (const issue of issues.nodes) {
95
+ if (!localLinearIds.has(issue.identifier)) {
96
+ missingLocally.push(issue);
97
+ }
98
+ }
99
+
100
+ if (missingLocally.length > 0) {
101
+ console.log(`\n๐Ÿ†• Issues in Linear but not in local tasks (${missingLocally.length}):`);
102
+
103
+ // Create task entries for missing issues
104
+ const newTasks = [];
105
+ for (const issue of missingLocally) {
106
+ console.log(` - ${issue.identifier}: ${issue.title}`);
107
+
108
+ const taskId = `tsk-${Math.random().toString(36).substr(2, 8)}`;
109
+ const task = {
110
+ id: taskId,
111
+ type: 'task_create',
112
+ timestamp: Date.now(),
113
+ frame_id: 'linear-sync',
114
+ title: `[${issue.identifier}] ${issue.title}`,
115
+ description: issue.description || '',
116
+ status: mapLinearState(issue.state.type),
117
+ priority: mapLinearPriority(issue.priority),
118
+ created_at: Date.now(),
119
+ depends_on: [],
120
+ blocks: [],
121
+ tags: ['linear', 'synced'],
122
+ context_score: 0.5,
123
+ external_refs: {
124
+ linear_id: issue.id,
125
+ linear_url: issue.url
126
+ }
127
+ };
128
+
129
+ newTasks.push(JSON.stringify(task));
130
+ }
131
+
132
+ if (newTasks.length > 0) {
133
+ console.log(`\n๐Ÿ’พ Adding ${newTasks.length} tasks to local storage...`);
134
+ fs.appendFileSync(tasksFile, '\n' + newTasks.join('\n') + '\n');
135
+ console.log('โœ… Tasks synced successfully!');
136
+ }
137
+ } else {
138
+ console.log('\nโœ… All Linear issues already exist locally');
139
+ }
140
+
141
+ // Find local tasks not in Linear
142
+ const linearIds = new Set(issues.nodes.map(i => i.identifier));
143
+ const missingInLinear = localTasks.filter(task => {
144
+ const match = task.title?.match(/\[(STA-\d+|ENG-\d+)\]/);
145
+ return match && !linearIds.has(match[1]);
146
+ });
147
+
148
+ if (missingInLinear.length > 0) {
149
+ console.log(`\n๐Ÿ“ค Local tasks not in Linear (${missingInLinear.length}):`);
150
+ for (const task of missingInLinear.slice(0, 10)) {
151
+ console.log(` - ${task.title}`);
152
+ }
153
+ if (missingInLinear.length > 10) {
154
+ console.log(` ... and ${missingInLinear.length - 10} more`);
155
+ }
156
+ }
157
+
158
+ } catch (error) {
159
+ console.error('โŒ Error syncing with Linear:', error.message);
160
+ if (error.message.includes('authentication') || error.message.includes('401')) {
161
+ console.log('\n๐Ÿ”‘ Authentication failed. Please check your LINEAR_API_KEY');
162
+ console.log('You can get an API key from: https://linear.app/settings/api');
163
+ }
164
+ }
165
+ }
166
+
167
+ function mapLinearState(state) {
168
+ switch (state) {
169
+ case 'completed': return 'completed';
170
+ case 'started': return 'in_progress';
171
+ case 'cancelled': return 'cancelled';
172
+ default: return 'pending';
173
+ }
174
+ }
175
+
176
+ function mapLinearPriority(priority) {
177
+ switch (priority) {
178
+ case 1: return 'urgent';
179
+ case 2: return 'high';
180
+ case 3: return 'medium';
181
+ case 4: return 'low';
182
+ default: return 'medium';
183
+ }
184
+ }
185
+
186
+ syncLinearTasks();
@@ -0,0 +1,57 @@
1
+ #!/bin/bash
2
+
3
+ echo "๐Ÿงช Testing StackMemory Auto-Triggers Implementation"
4
+ echo "===================================================="
5
+ echo ""
6
+
7
+ # Check what's actually available
8
+ echo "๐Ÿ“‹ Checking available commands..."
9
+ stackmemory --help 2>/dev/null | grep -E "clear|handoff|workflow|monitor" || echo "New commands not yet available in built version"
10
+
11
+ echo ""
12
+ echo "๐Ÿ“ Checking source files exist..."
13
+ for file in "src/core/session/clear-survival.ts" \
14
+ "src/core/session/handoff-generator.ts" \
15
+ "src/core/frame/workflow-templates.ts" \
16
+ "src/core/monitoring/session-monitor.ts" \
17
+ "src/cli/commands/clear.ts" \
18
+ "src/cli/commands/workflow.ts" \
19
+ "src/cli/commands/monitor.ts"; do
20
+ if [ -f "/Users/jwu/Dev/stackmemory/$file" ]; then
21
+ echo "โœ… $file exists"
22
+ else
23
+ echo "โŒ $file missing"
24
+ fi
25
+ done
26
+
27
+ echo ""
28
+ echo "๐Ÿ”ง Checking Claude hooks installation..."
29
+ for hook in "on-startup" "on-message" "on-clear" "on-exit"; do
30
+ if [ -f "$HOME/.claude/hooks/$hook" ]; then
31
+ echo "โœ… Hook $hook installed"
32
+ head -2 "$HOME/.claude/hooks/$hook" | tail -1
33
+ else
34
+ echo "โŒ Hook $hook not found"
35
+ fi
36
+ done
37
+
38
+ echo ""
39
+ echo "โš™๏ธ Checking configuration..."
40
+ if [ -f ".stackmemory/config.json" ]; then
41
+ echo "โœ… Config exists:"
42
+ cat .stackmemory/config.json | jq '.monitor, .clearSurvival, .handoff' 2>/dev/null || cat .stackmemory/config.json
43
+ else
44
+ echo "โŒ No config file"
45
+ fi
46
+
47
+ echo ""
48
+ echo "๐Ÿ“Š Status Summary:"
49
+ echo "- Source files: All created successfully โœ…"
50
+ echo "- Build status: Not yet compiled (needs npm run build)"
51
+ echo "- Hooks: Installed in ~/.claude/hooks/ โœ…"
52
+ echo "- Config: Auto-trigger settings configured โœ…"
53
+ echo ""
54
+ echo "๐Ÿš€ Next Steps:"
55
+ echo "1. Build the project: cd /Users/jwu/Dev/stackmemory && npm run build"
56
+ echo "2. Test commands: stackmemory clear --status"
57
+ echo "3. Start monitor: stackmemory monitor --start"
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Browser MCP Test Script
5
+ * Tests the Browser MCP integration for browser automation
6
+ */
7
+
8
+ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
9
+ import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
10
+
11
+ async function testBrowserMCP() {
12
+ console.log('๐ŸŒ Testing Browser MCP Server...\n');
13
+
14
+ try {
15
+ // Create client transport
16
+ const transport = new StdioClientTransport({
17
+ command: 'node',
18
+ args: ['/opt/homebrew/lib/node_modules/@browsermcp/mcp/dist/index.js'],
19
+ });
20
+
21
+ // Create MCP client
22
+ const client = new Client({
23
+ name: 'browser-mcp-test',
24
+ version: '1.0.0',
25
+ }, {
26
+ capabilities: {},
27
+ });
28
+
29
+ // Connect to server
30
+ await client.connect(transport);
31
+ console.log('โœ… Connected to Browser MCP server\n');
32
+
33
+ // List available tools
34
+ const tools = await client.listTools();
35
+ console.log('๐Ÿ“ฆ Available tools:', tools.tools?.length || 0);
36
+ if (tools.tools) {
37
+ tools.tools.forEach(tool => {
38
+ console.log(` - ${tool.name}: ${tool.description}`);
39
+ });
40
+ }
41
+ console.log();
42
+
43
+ // Example: Navigate to a page
44
+ console.log('๐Ÿงช Testing browser navigation...');
45
+ try {
46
+ const result = await client.callTool('browser_navigate', {
47
+ url: 'https://example.com'
48
+ });
49
+ console.log('โœ… Navigation successful:', result);
50
+ } catch (error) {
51
+ console.log('โš ๏ธ Navigation test failed:', error.message);
52
+ }
53
+
54
+ // Example: Take screenshot
55
+ console.log('\n๐Ÿงช Testing screenshot capture...');
56
+ try {
57
+ const screenshot = await client.callTool('browser_screenshot', {});
58
+ console.log('โœ… Screenshot captured');
59
+ } catch (error) {
60
+ console.log('โš ๏ธ Screenshot test failed:', error.message);
61
+ }
62
+
63
+ // Close connection
64
+ await client.close();
65
+ console.log('\nโœ… Browser MCP test complete!');
66
+
67
+ } catch (error) {
68
+ console.error('โŒ Error testing Browser MCP:', error);
69
+ process.exit(1);
70
+ }
71
+ }
72
+
73
+ // Run test
74
+ testBrowserMCP().catch(console.error);