@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,201 @@
1
+ #!/usr/bin/env tsx
2
+
3
+ /**
4
+ * Query ChromaDB for stored contexts
5
+ */
6
+
7
+ import { ChromaClient } from 'chromadb';
8
+ import dotenv from 'dotenv';
9
+ import chalk from 'chalk';
10
+
11
+ // Load environment variables
12
+ dotenv.config();
13
+
14
+ async function queryChromaDB() {
15
+ const apiKey = process.env.CHROMADB_API_KEY;
16
+ const tenant = process.env.CHROMADB_TENANT;
17
+ const database = process.env.CHROMADB_DATABASE || 'stackmemory';
18
+
19
+ console.log(chalk.cyan('🔍 Querying ChromaDB Contexts\n'));
20
+
21
+ // Connect to ChromaDB
22
+ const client = new ChromaClient({
23
+ ssl: true,
24
+ host: 'api.trychroma.com',
25
+ port: 443,
26
+ headers: {
27
+ 'X-Chroma-Token': apiKey
28
+ },
29
+ tenant: tenant,
30
+ database: database
31
+ });
32
+
33
+ // List all collections first
34
+ const collections = await client.listCollections();
35
+ console.log(chalk.yellow('📚 Available Collections:'));
36
+ collections.forEach(col => {
37
+ console.log(` - ${col.name}`);
38
+ });
39
+ console.log();
40
+
41
+ // Get collection - try claude_context first (from hooks), then stackmemory_contexts
42
+ let collection;
43
+ try {
44
+ collection = await client.getCollection({
45
+ name: 'claude_context'
46
+ });
47
+ console.log(chalk.green('✓ Using collection: claude_context\n'));
48
+ } catch {
49
+ collection = await client.getCollection({
50
+ name: 'stackmemory_contexts'
51
+ });
52
+ console.log(chalk.green('✓ Using collection: stackmemory_contexts\n'));
53
+ }
54
+
55
+ console.log(chalk.yellow('📊 Collection Stats:'));
56
+ const count = await collection.count();
57
+ console.log(` Total documents: ${count}\n`);
58
+
59
+ // Query 1: Get all documents
60
+ console.log(chalk.cyan('📚 All Stored Contexts:\n'));
61
+
62
+ const allDocs = await collection.get({
63
+ limit: 100
64
+ });
65
+
66
+ if (allDocs.ids.length > 0) {
67
+ for (let i = 0; i < allDocs.ids.length; i++) {
68
+ const metadata = allDocs.metadatas[i];
69
+ const document = allDocs.documents[i];
70
+
71
+ console.log(chalk.green(`${i + 1}. ${allDocs.ids[i]}`));
72
+ console.log(` Type: ${metadata.type}`);
73
+ console.log(` Timestamp: ${metadata.timestamp}`);
74
+ console.log(` User: ${metadata.user_id}`);
75
+ console.log(` Project: ${metadata.project}`);
76
+ console.log(` Content: ${document?.substring(0, 100)}...`);
77
+ console.log();
78
+ }
79
+ }
80
+
81
+ // Query 2: Search for specific content
82
+ console.log(chalk.cyan('\n🔎 Search Results for "TypeScript lint error":\n'));
83
+
84
+ const searchResults = await collection.query({
85
+ queryTexts: ['TypeScript lint error fix'],
86
+ nResults: 5
87
+ });
88
+
89
+ if (searchResults.ids[0].length > 0) {
90
+ for (let i = 0; i < searchResults.ids[0].length; i++) {
91
+ const metadata = searchResults.metadatas[0][i];
92
+ const document = searchResults.documents[0][i];
93
+ const distance = searchResults.distances[0][i];
94
+
95
+ console.log(chalk.yellow(`Match ${i + 1} (distance: ${distance.toFixed(3)}):`));
96
+ console.log(` ID: ${searchResults.ids[0][i]}`);
97
+ console.log(` Type: ${metadata.type}`);
98
+ console.log(` Timestamp: ${metadata.timestamp}`);
99
+ console.log(` Content: ${document?.substring(0, 150)}...`);
100
+ console.log();
101
+ }
102
+ } else {
103
+ console.log('No results found');
104
+ }
105
+
106
+ // Query 3: Filter by metadata
107
+ console.log(chalk.cyan('\n📋 Recent Task Completions:\n'));
108
+
109
+ const taskCompletions = await collection.get({
110
+ where: {
111
+ type: 'task_complete'
112
+ },
113
+ limit: 10
114
+ });
115
+
116
+ if (taskCompletions.ids.length > 0) {
117
+ for (let i = 0; i < taskCompletions.ids.length; i++) {
118
+ const metadata = taskCompletions.metadatas[i];
119
+ const document = taskCompletions.documents[i];
120
+
121
+ console.log(chalk.green(`Task ${i + 1}:`));
122
+ console.log(` ID: ${taskCompletions.ids[i]}`);
123
+ console.log(` Timestamp: ${metadata.timestamp}`);
124
+ console.log(` Task ID: ${metadata.task_id}`);
125
+ console.log(` Duration: ${metadata.duration}ms`);
126
+ console.log(` Files Changed: ${metadata.files_changed}`);
127
+ console.log(` Content: ${document?.substring(0, 100)}...`);
128
+ console.log();
129
+ }
130
+ } else {
131
+ console.log('No task completions found');
132
+ }
133
+
134
+ // Query 4: Get periodic saves
135
+ console.log(chalk.cyan('\n⏰ Periodic Checkpoints:\n'));
136
+
137
+ const periodicSaves = await collection.get({
138
+ where: {
139
+ type: 'periodic_save'
140
+ },
141
+ limit: 10
142
+ });
143
+
144
+ if (periodicSaves.ids.length > 0) {
145
+ for (let i = 0; i < periodicSaves.ids.length; i++) {
146
+ const metadata = periodicSaves.metadatas[i];
147
+ const document = periodicSaves.documents[i];
148
+
149
+ console.log(chalk.blue(`Checkpoint ${i + 1}:`));
150
+ console.log(` Timestamp: ${metadata.timestamp}`);
151
+ console.log(` Interval: ${metadata.interval}`);
152
+ console.log(` Active Files: ${metadata.active_files}`);
153
+ console.log(` Git Status: ${document?.substring(0, 150)}...`);
154
+ console.log();
155
+ }
156
+ } else {
157
+ console.log('No periodic saves found');
158
+ }
159
+
160
+ // Query 5: Get decisions
161
+ console.log(chalk.cyan('\n💡 Decisions Made:\n'));
162
+
163
+ const decisions = await collection.get({
164
+ where: {
165
+ type: 'decision_made'
166
+ },
167
+ limit: 10
168
+ });
169
+
170
+ if (decisions.ids.length > 0) {
171
+ for (let i = 0; i < decisions.ids.length; i++) {
172
+ const metadata = decisions.metadatas[i];
173
+ const document = decisions.documents[i];
174
+
175
+ console.log(chalk.magenta(`Decision ${i + 1}:`));
176
+ console.log(` Category: ${metadata.category}`);
177
+ console.log(` Alternatives: ${metadata.alternatives}`);
178
+ console.log(` Reasoning: ${metadata.reasoning}`);
179
+ console.log(` Decision: ${document?.substring(0, 200)}...`);
180
+ console.log();
181
+ }
182
+ } else {
183
+ console.log('No decisions found');
184
+ }
185
+
186
+ // Query 6: Group by type
187
+ console.log(chalk.cyan('\n📈 Context Types Summary:\n'));
188
+
189
+ const types = new Map();
190
+ for (let i = 0; i < allDocs.ids.length; i++) {
191
+ const type = allDocs.metadatas[i].type || 'unknown';
192
+ types.set(type, (types.get(type) || 0) + 1);
193
+ }
194
+
195
+ for (const [type, count] of types.entries()) {
196
+ console.log(` ${type}: ${count} documents`);
197
+ }
198
+ }
199
+
200
+ // Run query
201
+ queryChromaDB().catch(console.error);
@@ -0,0 +1,39 @@
1
+ #!/bin/bash
2
+
3
+ echo "🚂 Railway Environment Variables Setup"
4
+ echo "======================================"
5
+ echo ""
6
+ echo "You need to add these environment variables in the Railway dashboard:"
7
+ echo "https://railway.app/project/90d5083a-4adf-49b8-b2ff-95adfbb610f2/service/b2a145c3-065e-4225-8c84-aa0d8f49d243/settings"
8
+ echo ""
9
+ echo "Copy and paste these into Railway's environment variables section:"
10
+ echo ""
11
+
12
+ # Load .env file
13
+ if [ -f .env ]; then
14
+ source .env
15
+
16
+ echo "REDIS_URL=$REDIS_URL"
17
+ echo "LINEAR_API_KEY=$LINEAR_API_KEY"
18
+ echo "CHROMADB_API_KEY=$CHROMADB_API_KEY"
19
+ echo "CHROMADB_TENANT=$CHROMADB_TENANT"
20
+ echo "CHROMADB_DATABASE=$CHROMADB_DATABASE"
21
+ echo "LINEAR_TEAM_ID=$LINEAR_TEAM_ID"
22
+ echo "LINEAR_ORGANIZATION=$LINEAR_ORGANIZATION"
23
+ echo ""
24
+ echo "Optional (for cold storage tier):"
25
+ echo "GCS_BUCKET_NAME=stackmemory-cold-storage"
26
+ echo "GCS_PROJECT_ID=your-gcp-project-id"
27
+ echo "GCS_CLIENT_EMAIL=your-service-account@project.iam.gserviceaccount.com"
28
+ echo "GCS_PRIVATE_KEY=your-gcs-private-key"
29
+ else
30
+ echo "❌ .env file not found. Please create one first."
31
+ exit 1
32
+ fi
33
+
34
+ echo ""
35
+ echo "After adding these variables:"
36
+ echo "1. Click 'Deploy' in Railway dashboard"
37
+ echo "2. Or run: railway up"
38
+ echo "3. Check deployment: railway logs"
39
+ echo "4. Visit: https://stackmemory-production.up.railway.app/health"
@@ -0,0 +1,170 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+ import { fileURLToPath } from 'url';
6
+
7
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
8
+
9
+ function reconcileLocalTasks() {
10
+ const tasksFile = path.join(__dirname, '..', '.stackmemory', 'tasks.jsonl');
11
+
12
+ if (!fs.existsSync(tasksFile)) {
13
+ console.error('❌ Tasks file not found:', tasksFile);
14
+ return;
15
+ }
16
+
17
+ // Read all tasks
18
+ const lines = fs.readFileSync(tasksFile, 'utf8').split('\n').filter(l => l.trim());
19
+ const tasks = new Map();
20
+ const tasksByLinearId = new Map();
21
+ const tasksByTitle = new Map();
22
+
23
+ console.log('📊 Analyzing local tasks...\n');
24
+
25
+ // Parse and organize tasks
26
+ for (const line of lines) {
27
+ try {
28
+ const task = JSON.parse(line);
29
+
30
+ // Store latest version of each task
31
+ if (!tasks.has(task.id) || task.timestamp > tasks.get(task.id).timestamp) {
32
+ tasks.set(task.id, task);
33
+ }
34
+
35
+ // Extract Linear ID if present
36
+ const linearMatch = task.title?.match(/\[(STA-\d+|ENG-\d+)\]/);
37
+ if (linearMatch) {
38
+ const linearId = linearMatch[1];
39
+ if (!tasksByLinearId.has(linearId)) {
40
+ tasksByLinearId.set(linearId, []);
41
+ }
42
+ tasksByLinearId.get(linearId).push(task);
43
+ }
44
+
45
+ // Normalize title for duplicate detection
46
+ const normalizedTitle = task.title
47
+ ?.replace(/^\[[^\]]+\]\s*/, '') // Remove [STA-XXX] or [ENG-XXX]
48
+ ?.replace(/^\[.*?\]\s*/, '') // Remove priority markers
49
+ ?.trim();
50
+
51
+ if (normalizedTitle) {
52
+ if (!tasksByTitle.has(normalizedTitle)) {
53
+ tasksByTitle.set(normalizedTitle, []);
54
+ }
55
+ tasksByTitle.get(normalizedTitle).push(task);
56
+ }
57
+ } catch (e) {
58
+ // Skip invalid lines
59
+ }
60
+ }
61
+
62
+ console.log(`📋 Total unique tasks: ${tasks.size}`);
63
+ console.log(`🔗 Tasks with Linear IDs: ${tasksByLinearId.size}`);
64
+
65
+ // Find duplicates by Linear ID
66
+ const duplicateLinearIds = [];
67
+ for (const [linearId, taskList] of tasksByLinearId.entries()) {
68
+ if (taskList.length > 1) {
69
+ duplicateLinearIds.push({ linearId, count: taskList.length, tasks: taskList });
70
+ }
71
+ }
72
+
73
+ if (duplicateLinearIds.length > 0) {
74
+ console.log(`\n⚠️ Duplicate Linear IDs found (${duplicateLinearIds.length}):`);
75
+ for (const dup of duplicateLinearIds.slice(0, 5)) {
76
+ console.log(` - ${dup.linearId}: ${dup.count} duplicates`);
77
+ for (const task of dup.tasks) {
78
+ console.log(` • ${task.id}: ${task.status} (${new Date(task.timestamp).toISOString()})`);
79
+ }
80
+ }
81
+ }
82
+
83
+ // Find duplicate titles
84
+ const duplicateTitles = [];
85
+ for (const [title, taskList] of tasksByTitle.entries()) {
86
+ if (taskList.length > 1) {
87
+ // Check if they have different Linear IDs
88
+ const linearIds = new Set();
89
+ for (const task of taskList) {
90
+ const match = task.title?.match(/\[(STA-\d+|ENG-\d+)\]/);
91
+ if (match) linearIds.add(match[1]);
92
+ }
93
+
94
+ if (linearIds.size > 1 || linearIds.size === 0) {
95
+ duplicateTitles.push({ title, count: taskList.length, tasks: taskList });
96
+ }
97
+ }
98
+ }
99
+
100
+ if (duplicateTitles.length > 0) {
101
+ console.log(`\n⚠️ Duplicate titles found (${duplicateTitles.length}):`);
102
+ for (const dup of duplicateTitles.slice(0, 5)) {
103
+ console.log(` - "${dup.title}": ${dup.count} duplicates`);
104
+ }
105
+ }
106
+
107
+ // Show task status breakdown
108
+ const statusCounts = {};
109
+ for (const task of tasks.values()) {
110
+ const status = task.status || 'unknown';
111
+ statusCounts[status] = (statusCounts[status] || 0) + 1;
112
+ }
113
+
114
+ console.log('\n📊 Task Status Breakdown:');
115
+ for (const [status, count] of Object.entries(statusCounts)) {
116
+ const emoji = status === 'completed' ? '✅' :
117
+ status === 'in_progress' ? '🔄' :
118
+ status === 'cancelled' ? '❌' : '⏳';
119
+ console.log(` ${emoji} ${status}: ${count}`);
120
+ }
121
+
122
+ // Priority breakdown
123
+ const priorityCounts = {};
124
+ for (const task of tasks.values()) {
125
+ const priority = task.priority || 'none';
126
+ priorityCounts[priority] = (priorityCounts[priority] || 0) + 1;
127
+ }
128
+
129
+ console.log('\n🎯 Priority Breakdown:');
130
+ for (const [priority, count] of Object.entries(priorityCounts)) {
131
+ console.log(` - ${priority}: ${count}`);
132
+ }
133
+
134
+ // Recent active tasks
135
+ const recentTasks = Array.from(tasks.values())
136
+ .filter(t => t.status === 'in_progress' || (t.timestamp > Date.now() - 7 * 24 * 60 * 60 * 1000))
137
+ .sort((a, b) => b.timestamp - a.timestamp)
138
+ .slice(0, 10);
139
+
140
+ console.log('\n🕒 Recent Active Tasks:');
141
+ for (const task of recentTasks) {
142
+ const status = task.status === 'completed' ? '✅' :
143
+ task.status === 'in_progress' ? '🔄' : '⏳';
144
+ const linearId = task.title?.match(/\[(STA-\d+|ENG-\d+)\]/)?.[1] || '';
145
+ console.log(` ${status} ${linearId ? `[${linearId}]` : ''} ${task.title}`);
146
+ }
147
+
148
+ // Recommendations
149
+ console.log('\n💡 Recommendations:');
150
+ if (duplicateLinearIds.length > 0) {
151
+ console.log(` - ${duplicateLinearIds.length} tasks have duplicate Linear IDs - consider deduplication`);
152
+ }
153
+ if (duplicateTitles.length > 0) {
154
+ console.log(` - ${duplicateTitles.length} task titles are duplicated - review for consolidation`);
155
+ }
156
+
157
+ const pendingCount = statusCounts.pending || 0;
158
+ const inProgressCount = statusCounts.in_progress || 0;
159
+
160
+ if (pendingCount > 20) {
161
+ console.log(` - ${pendingCount} pending tasks - consider prioritizing or archiving old tasks`);
162
+ }
163
+ if (inProgressCount > 5) {
164
+ console.log(` - ${inProgressCount} tasks in progress - consider focusing on completion`);
165
+ }
166
+
167
+ console.log('\n✅ Task reconciliation complete!');
168
+ }
169
+
170
+ reconcileLocalTasks();
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env node
2
+ import 'dotenv/config';
3
+ import Database from 'better-sqlite3';
4
+ import { mkdirSync } from 'fs';
5
+ import { dirname, join } from 'path';
6
+ import { homedir } from 'os';
7
+
8
+ // Create the database directory if it doesn't exist
9
+ const dbPath = join(homedir(), '.stackmemory', 'context.db');
10
+ mkdirSync(dirname(dbPath), { recursive: true });
11
+
12
+ // Connect to the database
13
+ const db = new Database(dbPath);
14
+
15
+ // Create frames table with proper schema
16
+ db.exec(`
17
+ CREATE TABLE IF NOT EXISTS frames (
18
+ frame_id TEXT PRIMARY KEY,
19
+ run_id TEXT NOT NULL,
20
+ project_id TEXT NOT NULL,
21
+ parent_frame_id TEXT REFERENCES frames(frame_id),
22
+ depth INTEGER NOT NULL DEFAULT 0,
23
+ type TEXT NOT NULL,
24
+ name TEXT NOT NULL,
25
+ state TEXT DEFAULT 'active',
26
+ inputs TEXT DEFAULT '{}',
27
+ outputs TEXT DEFAULT '{}',
28
+ digest_text TEXT,
29
+ digest_json TEXT DEFAULT '{}',
30
+ created_at INTEGER DEFAULT (unixepoch()),
31
+ closed_at INTEGER
32
+ );
33
+
34
+ CREATE TABLE IF NOT EXISTS events (
35
+ event_id TEXT PRIMARY KEY,
36
+ run_id TEXT NOT NULL,
37
+ frame_id TEXT NOT NULL,
38
+ seq INTEGER NOT NULL,
39
+ event_type TEXT NOT NULL,
40
+ payload TEXT NOT NULL,
41
+ ts INTEGER DEFAULT (unixepoch()),
42
+ FOREIGN KEY(frame_id) REFERENCES frames(frame_id)
43
+ );
44
+
45
+ CREATE TABLE IF NOT EXISTS anchors (
46
+ anchor_id TEXT PRIMARY KEY,
47
+ frame_id TEXT NOT NULL,
48
+ project_id TEXT NOT NULL,
49
+ type TEXT NOT NULL,
50
+ text TEXT NOT NULL,
51
+ priority INTEGER DEFAULT 0,
52
+ created_at INTEGER DEFAULT (unixepoch()),
53
+ metadata TEXT DEFAULT '{}',
54
+ FOREIGN KEY(frame_id) REFERENCES frames(frame_id)
55
+ );
56
+
57
+ CREATE TABLE IF NOT EXISTS handoff_requests (
58
+ request_id TEXT PRIMARY KEY,
59
+ source_stack_id TEXT NOT NULL,
60
+ target_stack_id TEXT NOT NULL,
61
+ frame_ids TEXT NOT NULL,
62
+ status TEXT NOT NULL DEFAULT 'pending',
63
+ created_at INTEGER DEFAULT (unixepoch()),
64
+ expires_at INTEGER,
65
+ target_user_id TEXT,
66
+ message TEXT
67
+ );
68
+
69
+ CREATE INDEX IF NOT EXISTS idx_frames_run ON frames(run_id);
70
+ CREATE INDEX IF NOT EXISTS idx_frames_parent ON frames(parent_frame_id);
71
+ CREATE INDEX IF NOT EXISTS idx_frames_state ON frames(state);
72
+ CREATE INDEX IF NOT EXISTS idx_events_frame ON events(frame_id);
73
+ CREATE INDEX IF NOT EXISTS idx_events_seq ON events(frame_id, seq);
74
+ CREATE INDEX IF NOT EXISTS idx_anchors_frame ON anchors(frame_id);
75
+ CREATE INDEX IF NOT EXISTS idx_handoff_requests_status ON handoff_requests(status);
76
+ CREATE INDEX IF NOT EXISTS idx_handoff_requests_target ON handoff_requests(target_stack_id);
77
+ `);
78
+
79
+ console.log('✅ Frames database recreated at:', dbPath);
80
+
81
+ // Verify tables exist
82
+ const tables = db.prepare("SELECT name FROM sqlite_master WHERE type='table'").all();
83
+ console.log('📊 Tables created:', tables.map(t => t.name).join(', '));
84
+
85
+ // Check if we have any existing frames
86
+ const frameCount = db.prepare('SELECT COUNT(*) as count FROM frames').get();
87
+ console.log('📈 Existing frames:', frameCount.count);
88
+
89
+ db.close();
@@ -0,0 +1,138 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Automatically configure Claude Desktop to use StackMemory MCP
4
+ */
5
+
6
+ import fs from 'fs';
7
+ import path from 'path';
8
+ import os from 'os';
9
+
10
+ function setupClaudeIntegration() {
11
+ console.log('🔧 Setting up Claude Desktop integration...\n');
12
+
13
+ // Find Claude Desktop config path
14
+ const configPaths = [
15
+ path.join(
16
+ os.homedir(),
17
+ 'Library',
18
+ 'Application Support',
19
+ 'Claude',
20
+ 'claude_desktop_config.json'
21
+ ), // macOS
22
+ path.join(os.homedir(), '.config', 'claude', 'claude_desktop_config.json'), // Linux
23
+ path.join(
24
+ os.homedir(),
25
+ 'AppData',
26
+ 'Roaming',
27
+ 'Claude',
28
+ 'claude_desktop_config.json'
29
+ ), // Windows
30
+ ];
31
+
32
+ let configPath = null;
33
+ for (const p of configPaths) {
34
+ if (fs.existsSync(p) || fs.existsSync(path.dirname(p))) {
35
+ configPath = p;
36
+ break;
37
+ }
38
+ }
39
+
40
+ if (!configPath) {
41
+ console.log('❌ Claude Desktop config directory not found');
42
+ console.log('📝 Manual setup required - add this to your Claude config:');
43
+ printManualConfig();
44
+ return;
45
+ }
46
+
47
+ // Current project path
48
+ const projectRoot = process.cwd();
49
+ const mcpServerPath = path.join(
50
+ projectRoot,
51
+ 'dist',
52
+ 'src',
53
+ 'mcp',
54
+ 'mcp-server.js'
55
+ );
56
+
57
+ // Read existing config or create new
58
+ let config = { mcpServers: {} };
59
+ if (fs.existsSync(configPath)) {
60
+ try {
61
+ const existing = fs.readFileSync(configPath, 'utf8');
62
+ config = JSON.parse(existing);
63
+ if (!config.mcpServers) config.mcpServers = {};
64
+ } catch (error) {
65
+ console.log('⚠️ Could not parse existing config, creating new one');
66
+ }
67
+ }
68
+
69
+ // Add/update StackMemory MCP server
70
+ config.mcpServers.stackmemory = {
71
+ command: 'node',
72
+ args: [mcpServerPath],
73
+ env: {
74
+ PROJECT_ROOT: projectRoot,
75
+ STACKMEMORY_AUTO_CHECK: 'true',
76
+ },
77
+ };
78
+
79
+ // Ensure directory exists
80
+ const configDir = path.dirname(configPath);
81
+ if (!fs.existsSync(configDir)) {
82
+ fs.mkdirSync(configDir, { recursive: true });
83
+ }
84
+
85
+ // Write config
86
+ try {
87
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
88
+ console.log('✅ Claude Desktop config updated successfully!');
89
+ console.log(`📁 Config location: ${configPath}\n`);
90
+
91
+ console.log(
92
+ '🔄 Please restart Claude Desktop to activate StackMemory integration\n'
93
+ );
94
+ console.log('🎯 StackMemory will now automatically:');
95
+ console.log(' • Save context every 15 minutes');
96
+ console.log(' • Load previous context on startup');
97
+ console.log(' • Track tasks and decisions');
98
+ console.log(' • Enable seamless context persistence\n');
99
+ } catch (error) {
100
+ console.log('❌ Failed to write config file:', error.message);
101
+ console.log('📝 Manual setup required:');
102
+ printManualConfig();
103
+ }
104
+ }
105
+
106
+ function printManualConfig() {
107
+ const projectRoot = process.cwd();
108
+ const mcpServerPath = path.join(
109
+ projectRoot,
110
+ 'dist',
111
+ 'src',
112
+ 'mcp',
113
+ 'mcp-server.js'
114
+ );
115
+
116
+ console.log(
117
+ '\n' +
118
+ JSON.stringify(
119
+ {
120
+ mcpServers: {
121
+ stackmemory: {
122
+ command: 'node',
123
+ args: [mcpServerPath],
124
+ env: {
125
+ PROJECT_ROOT: projectRoot,
126
+ STACKMEMORY_AUTO_CHECK: 'true',
127
+ },
128
+ },
129
+ },
130
+ },
131
+ null,
132
+ 2
133
+ ) +
134
+ '\n'
135
+ );
136
+ }
137
+
138
+ setupClaudeIntegration();