@stackmemoryai/stackmemory 0.3.17 โ 0.3.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/claude-sm.js +51 -5
- package/dist/cli/claude-sm.js.map +2 -2
- package/dist/cli/codex-sm.js +52 -19
- package/dist/cli/codex-sm.js.map +2 -2
- package/dist/cli/commands/db.js +143 -0
- package/dist/cli/commands/db.js.map +7 -0
- package/dist/cli/commands/login.js +50 -0
- package/dist/cli/commands/login.js.map +7 -0
- package/dist/cli/commands/migrate.js +178 -0
- package/dist/cli/commands/migrate.js.map +7 -0
- package/dist/cli/commands/onboard.js +158 -2
- package/dist/cli/commands/onboard.js.map +2 -2
- package/dist/cli/commands/skills.js +15 -2
- package/dist/cli/commands/skills.js.map +2 -2
- package/dist/cli/index.js +118 -834
- package/dist/cli/index.js.map +3 -3
- package/dist/core/context/dual-stack-manager.js +1 -1
- package/dist/core/context/dual-stack-manager.js.map +1 -1
- package/dist/core/context/frame-database.js +1 -0
- package/dist/core/context/frame-database.js.map +2 -2
- package/dist/core/context/frame-manager.js +59 -2
- package/dist/core/context/frame-manager.js.map +2 -2
- package/dist/core/database/database-adapter.js +6 -1
- package/dist/core/database/database-adapter.js.map +2 -2
- package/dist/core/database/sqlite-adapter.js +60 -2
- package/dist/core/database/sqlite-adapter.js.map +2 -2
- package/dist/integrations/claude-code/subagent-client.js +106 -3
- package/dist/integrations/claude-code/subagent-client.js.map +2 -2
- package/dist/servers/railway/config.js +51 -0
- package/dist/servers/railway/config.js.map +7 -0
- package/dist/servers/railway/index-enhanced.js +156 -0
- package/dist/servers/railway/index-enhanced.js.map +7 -0
- package/dist/servers/railway/index.js +843 -82
- package/dist/servers/railway/index.js.map +3 -3
- package/dist/servers/railway/minimal.js +48 -3
- package/dist/servers/railway/minimal.js.map +2 -2
- package/dist/servers/railway/storage-test.js +455 -0
- package/dist/servers/railway/storage-test.js.map +7 -0
- package/dist/skills/claude-skills.js +13 -12
- package/dist/skills/claude-skills.js.map +2 -2
- package/dist/skills/recursive-agent-orchestrator.js +27 -18
- package/dist/skills/recursive-agent-orchestrator.js.map +2 -2
- package/dist/skills/unified-rlm-orchestrator.js.map +2 -2
- package/package.json +13 -21
- package/scripts/README-TESTING.md +186 -0
- package/scripts/analyze-cli-security.js +288 -0
- package/scripts/archive/add-phase-tasks-to-linear.js +163 -0
- package/scripts/archive/analyze-linear-duplicates.js +214 -0
- package/scripts/archive/analyze-remaining-duplicates.js +230 -0
- package/scripts/archive/analyze-sta-duplicates.js +292 -0
- package/scripts/archive/analyze-sta-graphql.js +399 -0
- package/scripts/archive/cancel-duplicate-tasks.ts +246 -0
- package/scripts/archive/check-all-duplicates.ts +419 -0
- package/scripts/archive/clean-duplicate-tasks.js +114 -0
- package/scripts/archive/cleanup-duplicate-tasks.ts +286 -0
- package/scripts/archive/create-phase-tasks.js +387 -0
- package/scripts/archive/delete-linear-duplicates.js +182 -0
- package/scripts/archive/delete-remaining-duplicates.js +158 -0
- package/scripts/archive/delete-sta-duplicates.js +201 -0
- package/scripts/archive/delete-sta-oauth.js +201 -0
- package/scripts/archive/export-sta-tasks.js +62 -0
- package/scripts/archive/install-auto-sync.js +266 -0
- package/scripts/archive/install-chromadb-hooks.sh +133 -0
- package/scripts/archive/install-enhanced-clear-hooks.sh +431 -0
- package/scripts/archive/install-post-task-hooks.sh +289 -0
- package/scripts/archive/install-stackmemory-hooks.sh +420 -0
- package/scripts/archive/merge-linear-duplicates-safe.ts +362 -0
- package/scripts/archive/merge-linear-duplicates.ts +180 -0
- package/scripts/archive/remove-sta-tasks.js +70 -0
- package/scripts/archive/setup-background-sync.sh +168 -0
- package/scripts/archive/setup-claude-auto-triggers.sh +181 -0
- package/scripts/archive/setup-claude-autostart.sh +305 -0
- package/scripts/archive/setup-git-hooks.sh +25 -0
- package/scripts/archive/setup-linear-oauth.sh +46 -0
- package/scripts/archive/setup-mcp.sh +113 -0
- package/scripts/archive/setup-railway-deployment.sh +81 -0
- package/scripts/auto-handoff.sh +262 -0
- package/scripts/background-sync-manager.js +416 -0
- package/scripts/benchmark-performance.ts +57 -0
- package/scripts/check-redis.ts +48 -0
- package/scripts/chromadb-auto-loader.sh +128 -0
- package/scripts/chromadb-context-loader.js +479 -0
- package/scripts/claude-chromadb-hook.js +460 -0
- package/scripts/claude-code-wrapper.sh +66 -0
- package/scripts/claude-linear-skill.js +455 -0
- package/scripts/claude-pre-commit.sh +302 -0
- package/scripts/claude-sm-autostart.js +532 -0
- package/scripts/claude-sm-setup.sh +367 -0
- package/scripts/claude-with-chromadb.sh +69 -0
- package/scripts/claude-worktree-manager.sh +323 -0
- package/scripts/claude-worktree-monitor.sh +371 -0
- package/scripts/claude-worktree-setup.sh +327 -0
- package/scripts/clean-linear-backlog.js +273 -0
- package/scripts/cleanup-old-sessions.sh +57 -0
- package/scripts/codex-wrapper.sh +88 -0
- package/scripts/create-sandbox.sh +269 -0
- package/scripts/debug-linear-update.js +174 -0
- package/scripts/delete-linear-tasks.js +167 -0
- package/scripts/deploy.sh +89 -0
- package/scripts/deployment/railway.sh +352 -0
- package/scripts/deployment/test-deployment.js +194 -0
- package/scripts/detect-and-rehydrate.js +162 -0
- package/scripts/detect-and-rehydrate.mjs +165 -0
- package/scripts/development/create-demo-tasks.js +143 -0
- package/scripts/development/debug-frame-test.js +16 -0
- package/scripts/development/demo-auto-sync.js +128 -0
- package/scripts/development/fix-all-imports.js +213 -0
- package/scripts/development/fix-imports.js +229 -0
- package/scripts/development/fix-lint-loop.cjs +103 -0
- package/scripts/development/fix-project-id.ts +161 -0
- package/scripts/development/fix-strict-mode-issues.ts +291 -0
- package/scripts/development/reorganize-structure.sh +228 -0
- package/scripts/development/test-persistence-direct.js +148 -0
- package/scripts/development/test-persistence.js +114 -0
- package/scripts/development/test-tasks.js +93 -0
- package/scripts/development/update-imports.js +212 -0
- package/scripts/fetch-linear-status.js +125 -0
- package/scripts/git-hooks/README.md +310 -0
- package/scripts/git-hooks/branch-context-manager.sh +342 -0
- package/scripts/git-hooks/post-checkout-stackmemory.sh +63 -0
- package/scripts/git-hooks/post-commit-stackmemory.sh +305 -0
- package/scripts/git-hooks/pre-commit-stackmemory.sh +275 -0
- package/scripts/hooks/cleanup-shell.sh +130 -0
- package/scripts/hooks/task-complete.sh +114 -0
- package/scripts/initialize.ts +129 -0
- package/scripts/install-claude-hooks-auto.js +104 -0
- package/scripts/install-claude-hooks.sh +133 -0
- package/scripts/install-global.sh +296 -0
- package/scripts/install.sh +235 -0
- package/scripts/linear-auto-sync.js +262 -0
- package/scripts/linear-auto-sync.sh +161 -0
- package/scripts/linear-sync-daemon.js +150 -0
- package/scripts/linear-task-review.js +237 -0
- package/scripts/list-linear-tasks.ts +178 -0
- package/scripts/mcp-proxy.js +66 -0
- package/scripts/opencode-wrapper.sh +85 -0
- package/scripts/publish-local.js +74 -0
- package/scripts/query-chromadb.ts +201 -0
- package/scripts/railway-env-setup.sh +39 -0
- package/scripts/reconcile-local-tasks.js +170 -0
- package/scripts/recreate-frames-db.js +89 -0
- package/scripts/setup/claude-integration.js +138 -0
- package/scripts/setup/configure-alias.js +125 -0
- package/scripts/setup/configure-codex-alias.js +161 -0
- package/scripts/setup/configure-opencode-alias.js +175 -0
- package/scripts/setup-claude-integration.js +204 -0
- package/scripts/setup-claude-integration.sh +183 -0
- package/scripts/setup-railway-deployment.sh +37 -0
- package/scripts/setup.sh +31 -0
- package/scripts/show-linear-summary.ts +172 -0
- package/scripts/stackmemory-auto-handoff.sh +231 -0
- package/scripts/stackmemory-daemon.sh +40 -0
- package/scripts/start-linear-sync-daemon.sh +141 -0
- package/scripts/start-temporal-paradox.sh +214 -0
- package/scripts/status.ts +159 -0
- package/scripts/sync-and-clean-tasks.js +258 -0
- package/scripts/sync-frames-from-railway.js +228 -0
- package/scripts/sync-linear-graphql.js +303 -0
- package/scripts/sync-linear-tasks.js +186 -0
- package/scripts/test-auto-triggers.sh +57 -0
- package/scripts/test-browser-mcp.js +74 -0
- package/scripts/test-chromadb-full.js +115 -0
- package/scripts/test-chromadb-hooks.sh +28 -0
- package/scripts/test-chromadb-sync.ts +245 -0
- package/scripts/test-cli-security.js +293 -0
- package/scripts/test-hooks-persistence.sh +220 -0
- package/scripts/test-installation-scenarios.sh +359 -0
- package/scripts/test-installation.sh +224 -0
- package/scripts/test-mcp.js +163 -0
- package/scripts/test-pre-publish-quick.sh +75 -0
- package/scripts/test-quality-gates.sh +263 -0
- package/scripts/test-railway-db.js +222 -0
- package/scripts/test-redis-storage.ts +490 -0
- package/scripts/test-rlm-basic.sh +122 -0
- package/scripts/test-rlm-comprehensive.sh +260 -0
- package/scripts/test-rlm-e2e.sh +268 -0
- package/scripts/test-rlm-simple.js +90 -0
- package/scripts/test-rlm.js +110 -0
- package/scripts/test-session-handoff.sh +165 -0
- package/scripts/test-shell-integration.sh +275 -0
- package/scripts/testing/ab-test-runner.ts +508 -0
- package/scripts/testing/collect-metrics.ts +457 -0
- package/scripts/testing/quick-effectiveness-demo.js +187 -0
- package/scripts/testing/real-performance-test.js +422 -0
- package/scripts/testing/run-effectiveness-tests.sh +176 -0
- package/scripts/testing/scripts/testing/ab-test-runner.js +363 -0
- package/scripts/testing/scripts/testing/collect-metrics.js +292 -0
- package/scripts/testing/simple-effectiveness-test.js +310 -0
- package/scripts/testing/src/core/context/context-bridge.js +253 -0
- package/scripts/testing/src/core/context/frame-manager.js +746 -0
- package/scripts/testing/src/core/context/shared-context-layer.js +437 -0
- package/scripts/testing/src/core/database/database-adapter.js +54 -0
- package/scripts/testing/src/core/errors/index.js +291 -0
- package/scripts/testing/src/core/errors/recovery.js +268 -0
- package/scripts/testing/src/core/monitoring/logger.js +145 -0
- package/scripts/testing/src/core/retrieval/context-retriever.js +516 -0
- package/scripts/testing/src/core/session/index.js +1 -0
- package/scripts/testing/src/core/session/session-manager.js +323 -0
- package/scripts/testing/src/core/trace/cli-trace-wrapper.js +140 -0
- package/scripts/testing/src/core/trace/db-trace-wrapper.js +251 -0
- package/scripts/testing/src/core/trace/debug-trace.js +398 -0
- package/scripts/testing/src/core/trace/index.js +120 -0
- package/scripts/testing/src/core/trace/linear-api-wrapper.js +204 -0
- package/scripts/update-linear-status.js +268 -0
- package/scripts/update-linear-tasks-fixed.js +284 -0
- package/scripts/verify-railway-schema.ts +35 -0
- package/templates/claude-hooks/hooks.json +5 -0
- package/templates/claude-hooks/on-clear.js +56 -0
- package/templates/claude-hooks/on-startup.js +56 -0
- package/templates/claude-hooks/tool-use-trace.js +67 -0
- package/dist/features/tui/components/analytics-panel.js +0 -157
- package/dist/features/tui/components/analytics-panel.js.map +0 -7
- package/dist/features/tui/components/frame-visualizer.js +0 -377
- package/dist/features/tui/components/frame-visualizer.js.map +0 -7
- package/dist/features/tui/components/pr-tracker.js +0 -135
- package/dist/features/tui/components/pr-tracker.js.map +0 -7
- package/dist/features/tui/components/session-monitor.js +0 -299
- package/dist/features/tui/components/session-monitor.js.map +0 -7
- package/dist/features/tui/components/subagent-fleet.js +0 -395
- package/dist/features/tui/components/subagent-fleet.js.map +0 -7
- package/dist/features/tui/components/task-board.js +0 -1139
- package/dist/features/tui/components/task-board.js.map +0 -7
- package/dist/features/tui/index.js +0 -408
- package/dist/features/tui/index.js.map +0 -7
- package/dist/features/tui/services/data-service.js +0 -641
- package/dist/features/tui/services/data-service.js.map +0 -7
- package/dist/features/tui/services/linear-task-reader.js +0 -102
- package/dist/features/tui/services/linear-task-reader.js.map +0 -7
- package/dist/features/tui/services/websocket-client.js +0 -162
- package/dist/features/tui/services/websocket-client.js.map +0 -7
- package/dist/features/tui/terminal-compat.js +0 -220
- package/dist/features/tui/terminal-compat.js.map +0 -7
- package/dist/features/tui/types.js +0 -1
- package/dist/features/tui/types.js.map +0 -7
|
@@ -0,0 +1,237 @@
|
|
|
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
|
+
dotenv.config({
|
|
11
|
+
path: path.join(__dirname, '..', '.env'),
|
|
12
|
+
silent: true
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
async function queryLinear(query, variables = {}) {
|
|
16
|
+
const response = await fetch('https://api.linear.app/graphql', {
|
|
17
|
+
method: 'POST',
|
|
18
|
+
headers: {
|
|
19
|
+
'Content-Type': 'application/json',
|
|
20
|
+
'Authorization': process.env.LINEAR_API_KEY
|
|
21
|
+
},
|
|
22
|
+
body: JSON.stringify({ query, variables })
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const data = await response.json();
|
|
26
|
+
if (data.errors) {
|
|
27
|
+
throw new Error(data.errors[0].message);
|
|
28
|
+
}
|
|
29
|
+
return data.data;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function reviewTasks() {
|
|
33
|
+
console.log('๐ LINEAR TASK REVIEW\n' + '='.repeat(50));
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
// Get viewer info
|
|
37
|
+
const viewerData = await queryLinear(`
|
|
38
|
+
query {
|
|
39
|
+
viewer {
|
|
40
|
+
name
|
|
41
|
+
email
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
`);
|
|
45
|
+
|
|
46
|
+
console.log(`๐ค Logged in as: ${viewerData.viewer.name || viewerData.viewer.email}\n`);
|
|
47
|
+
|
|
48
|
+
// Get all active issues
|
|
49
|
+
const issuesData = await queryLinear(`
|
|
50
|
+
query {
|
|
51
|
+
issues(
|
|
52
|
+
filter: {
|
|
53
|
+
state: { type: { in: ["started", "unstarted"] } }
|
|
54
|
+
}
|
|
55
|
+
orderBy: updatedAt
|
|
56
|
+
first: 100
|
|
57
|
+
) {
|
|
58
|
+
nodes {
|
|
59
|
+
identifier
|
|
60
|
+
title
|
|
61
|
+
priority
|
|
62
|
+
priorityLabel
|
|
63
|
+
createdAt
|
|
64
|
+
updatedAt
|
|
65
|
+
state {
|
|
66
|
+
name
|
|
67
|
+
type
|
|
68
|
+
}
|
|
69
|
+
assignee {
|
|
70
|
+
name
|
|
71
|
+
email
|
|
72
|
+
}
|
|
73
|
+
labels {
|
|
74
|
+
nodes {
|
|
75
|
+
name
|
|
76
|
+
color
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
estimate
|
|
80
|
+
url
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
`);
|
|
85
|
+
|
|
86
|
+
const issues = issuesData.issues.nodes;
|
|
87
|
+
|
|
88
|
+
// Group by state
|
|
89
|
+
const byState = {};
|
|
90
|
+
issues.forEach(issue => {
|
|
91
|
+
const stateName = issue.state.name;
|
|
92
|
+
if (!byState[stateName]) byState[stateName] = [];
|
|
93
|
+
byState[stateName].push(issue);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// Priority mapping
|
|
97
|
+
const priorityLabels = {
|
|
98
|
+
0: '๐ด No Priority',
|
|
99
|
+
1: '๐ด Urgent',
|
|
100
|
+
2: '๐ High',
|
|
101
|
+
3: '๐ก Medium',
|
|
102
|
+
4: '๐ต Low'
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
// Display by state
|
|
106
|
+
const stateOrder = ['In Progress', 'Todo', 'Triage', 'Backlog'];
|
|
107
|
+
|
|
108
|
+
stateOrder.forEach(state => {
|
|
109
|
+
if (byState[state] && byState[state].length > 0) {
|
|
110
|
+
console.log(`\n๐ ${state.toUpperCase()} (${byState[state].length} tasks)`);
|
|
111
|
+
console.log('-'.repeat(50));
|
|
112
|
+
|
|
113
|
+
byState[state]
|
|
114
|
+
.sort((a, b) => (a.priority || 5) - (b.priority || 5))
|
|
115
|
+
.slice(0, 10)
|
|
116
|
+
.forEach(issue => {
|
|
117
|
+
const priority = priorityLabels[issue.priority] || 'โช None';
|
|
118
|
+
const assignee = issue.assignee ? `๐ค ${issue.assignee.name}` : '๐ค Unassigned';
|
|
119
|
+
const labels = issue.labels.nodes.map(l => l.name).join(', ');
|
|
120
|
+
const labelStr = labels ? ` [${labels}]` : '';
|
|
121
|
+
|
|
122
|
+
console.log(`\n ${issue.identifier}: ${issue.title}`);
|
|
123
|
+
console.log(` ${priority} | ${assignee}${labelStr}`);
|
|
124
|
+
console.log(` ๐ ${issue.url}`);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
if (byState[state].length > 10) {
|
|
128
|
+
console.log(`\n ... and ${byState[state].length - 10} more tasks`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// Summary statistics
|
|
134
|
+
console.log('\n' + '='.repeat(50));
|
|
135
|
+
console.log('๐ SUMMARY STATISTICS\n');
|
|
136
|
+
|
|
137
|
+
const inProgress = byState['In Progress']?.length || 0;
|
|
138
|
+
const todo = byState['Todo']?.length || 0;
|
|
139
|
+
const triage = byState['Triage']?.length || 0;
|
|
140
|
+
const backlog = byState['Backlog']?.length || 0;
|
|
141
|
+
|
|
142
|
+
console.log(` ๐ In Progress: ${inProgress}`);
|
|
143
|
+
console.log(` ๐ Todo: ${todo}`);
|
|
144
|
+
console.log(` ๐ Triage: ${triage}`);
|
|
145
|
+
console.log(` ๐ฆ Backlog: ${backlog}`);
|
|
146
|
+
console.log(` ๐ Total Active: ${issues.length}`);
|
|
147
|
+
|
|
148
|
+
// High priority items
|
|
149
|
+
const urgent = issues.filter(i => i.priority === 1);
|
|
150
|
+
const high = issues.filter(i => i.priority === 2);
|
|
151
|
+
|
|
152
|
+
if (urgent.length > 0) {
|
|
153
|
+
console.log('\n๐จ URGENT PRIORITY TASKS:');
|
|
154
|
+
urgent.forEach(issue => {
|
|
155
|
+
const state = issue.state.name;
|
|
156
|
+
const assignee = issue.assignee?.name || 'Unassigned';
|
|
157
|
+
console.log(` โข ${issue.identifier}: ${issue.title} [${state}] - ${assignee}`);
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (high.length > 0) {
|
|
162
|
+
console.log('\n๐ฅ HIGH PRIORITY TASKS:');
|
|
163
|
+
high.slice(0, 5).forEach(issue => {
|
|
164
|
+
const state = issue.state.name;
|
|
165
|
+
const assignee = issue.assignee?.name || 'Unassigned';
|
|
166
|
+
console.log(` โข ${issue.identifier}: ${issue.title} [${state}] - ${assignee}`);
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Recommendations
|
|
171
|
+
console.log('\n' + '='.repeat(50));
|
|
172
|
+
console.log('๐ก RECOMMENDED NEXT ACTIONS:\n');
|
|
173
|
+
|
|
174
|
+
// Find tasks to work on
|
|
175
|
+
const recommendations = [];
|
|
176
|
+
|
|
177
|
+
// 1. In-progress tasks that need completion
|
|
178
|
+
const myInProgress = issues.filter(i =>
|
|
179
|
+
i.state.name === 'In Progress' &&
|
|
180
|
+
(!i.assignee || i.assignee.name === viewerData.viewer.name)
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
if (myInProgress.length > 0) {
|
|
184
|
+
recommendations.push({
|
|
185
|
+
reason: '๐ Continue in-progress work',
|
|
186
|
+
tasks: myInProgress.slice(0, 2)
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// 2. High priority unassigned todos
|
|
191
|
+
const highPriorityTodos = issues.filter(i =>
|
|
192
|
+
i.state.name === 'Todo' &&
|
|
193
|
+
i.priority <= 2 &&
|
|
194
|
+
!i.assignee
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
if (highPriorityTodos.length > 0) {
|
|
198
|
+
recommendations.push({
|
|
199
|
+
reason: '๐ฅ High priority unassigned tasks',
|
|
200
|
+
tasks: highPriorityTodos.slice(0, 2)
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// 3. Any todo tasks
|
|
205
|
+
const todoTasks = issues.filter(i =>
|
|
206
|
+
i.state.name === 'Todo' &&
|
|
207
|
+
!i.assignee
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
if (todoTasks.length > 0 && recommendations.length < 2) {
|
|
211
|
+
recommendations.push({
|
|
212
|
+
reason: '๐ Available todo tasks',
|
|
213
|
+
tasks: todoTasks.slice(0, 2)
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (recommendations.length > 0) {
|
|
218
|
+
recommendations.forEach(rec => {
|
|
219
|
+
console.log(rec.reason);
|
|
220
|
+
rec.tasks.forEach(task => {
|
|
221
|
+
const priority = priorityLabels[task.priority] || 'โช None';
|
|
222
|
+
console.log(` โโ ${task.identifier}: ${task.title}`);
|
|
223
|
+
console.log(` ${priority} | ${task.url}`);
|
|
224
|
+
});
|
|
225
|
+
console.log('');
|
|
226
|
+
});
|
|
227
|
+
} else {
|
|
228
|
+
console.log('โ
No immediate tasks requiring attention');
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
} catch (error) {
|
|
232
|
+
console.error('โ Error:', error.message);
|
|
233
|
+
process.exit(1);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
reviewTasks();
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
#!/usr/bin/env ts-node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Standalone script to list all Linear tasks grouped by status
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { LinearClient } from '../src/integrations/linear/client.js';
|
|
8
|
+
import { LinearAuthManager } from '../src/integrations/linear/auth.js';
|
|
9
|
+
import chalk from 'chalk';
|
|
10
|
+
// Type-safe environment variable access
|
|
11
|
+
function getEnv(key: string, defaultValue?: string): string {
|
|
12
|
+
const value = process.env[key];
|
|
13
|
+
if (value === undefined) {
|
|
14
|
+
if (defaultValue !== undefined) return defaultValue;
|
|
15
|
+
throw new Error(`Environment variable ${key} is required`);
|
|
16
|
+
}
|
|
17
|
+
return value;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function getOptionalEnv(key: string): string | undefined {
|
|
21
|
+
return process.env[key];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface TasksByStatus {
|
|
25
|
+
[status: string]: Array<{
|
|
26
|
+
identifier: string;
|
|
27
|
+
title: string;
|
|
28
|
+
priority: number;
|
|
29
|
+
assignee?: string;
|
|
30
|
+
url: string;
|
|
31
|
+
}>;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function main() {
|
|
35
|
+
try {
|
|
36
|
+
console.log(chalk.cyan('๐ Fetching Linear tasks...\n'));
|
|
37
|
+
|
|
38
|
+
// Try to get authentication
|
|
39
|
+
const authManager = new LinearAuthManager(process.cwd());
|
|
40
|
+
const tokens = authManager.loadTokens();
|
|
41
|
+
const apiKey = process.env['LINEAR_API_KEY'];
|
|
42
|
+
|
|
43
|
+
if (!tokens && !apiKey) {
|
|
44
|
+
console.log(chalk.red('โ Not authenticated with Linear'));
|
|
45
|
+
console.log('Run: node dist/src/cli/index.js linear setup');
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Create client
|
|
50
|
+
const client = apiKey
|
|
51
|
+
? new LinearClient({ apiKey })
|
|
52
|
+
: new LinearClient({
|
|
53
|
+
apiKey: tokens?.accessToken ?? '',
|
|
54
|
+
useBearer: true,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Get all issues (increase limit to get more tasks)
|
|
58
|
+
console.log(chalk.gray('Fetching issues...'));
|
|
59
|
+
const issues = await client.getIssues({ limit: 200 });
|
|
60
|
+
|
|
61
|
+
if (!issues || issues.length === 0) {
|
|
62
|
+
console.log(chalk.gray('No issues found'));
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
console.log(chalk.green(`โ Found ${issues.length} tasks`));
|
|
67
|
+
|
|
68
|
+
// Group tasks by status
|
|
69
|
+
const tasksByStatus: TasksByStatus = {};
|
|
70
|
+
|
|
71
|
+
issues.forEach((issue) => {
|
|
72
|
+
const statusType = issue.state.type;
|
|
73
|
+
const statusName = issue.state.name;
|
|
74
|
+
const key = `${statusType} (${statusName})`;
|
|
75
|
+
|
|
76
|
+
if (!tasksByStatus[key]) {
|
|
77
|
+
tasksByStatus[key] = [];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
tasksByStatus[key].push({
|
|
81
|
+
identifier: issue.identifier,
|
|
82
|
+
title: issue.title,
|
|
83
|
+
priority: issue.priority,
|
|
84
|
+
assignee: issue.assignee?.name,
|
|
85
|
+
url: issue.url,
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// Define status order for display
|
|
90
|
+
const statusOrder = [
|
|
91
|
+
'backlog',
|
|
92
|
+
'unstarted',
|
|
93
|
+
'started',
|
|
94
|
+
'completed',
|
|
95
|
+
'cancelled',
|
|
96
|
+
];
|
|
97
|
+
|
|
98
|
+
// Display results grouped by status
|
|
99
|
+
console.log(chalk.cyan('\n๐ Linear Tasks by Status:\n'));
|
|
100
|
+
|
|
101
|
+
statusOrder.forEach((statusType) => {
|
|
102
|
+
// Find all status keys that match this type
|
|
103
|
+
const matchingKeys = Object.keys(tasksByStatus).filter((key) =>
|
|
104
|
+
key.startsWith(statusType)
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
matchingKeys.forEach((statusKey) => {
|
|
108
|
+
const tasks = tasksByStatus[statusKey];
|
|
109
|
+
if (tasks.length === 0) return;
|
|
110
|
+
|
|
111
|
+
// Status header with count
|
|
112
|
+
console.log(
|
|
113
|
+
chalk.bold.white(
|
|
114
|
+
`\n${getStatusEmoji(statusType)} ${statusKey} (${tasks.length} tasks)`
|
|
115
|
+
)
|
|
116
|
+
);
|
|
117
|
+
console.log(chalk.gray(''.padEnd(60, 'โ')));
|
|
118
|
+
|
|
119
|
+
// List tasks
|
|
120
|
+
tasks.forEach((task) => {
|
|
121
|
+
const priorityStr =
|
|
122
|
+
task.priority > 0
|
|
123
|
+
? chalk.yellow(`P${task.priority}`)
|
|
124
|
+
: chalk.gray('--');
|
|
125
|
+
const assigneeStr = task.assignee
|
|
126
|
+
? chalk.blue(task.assignee)
|
|
127
|
+
: chalk.gray('Unassigned');
|
|
128
|
+
const titleStr =
|
|
129
|
+
task.title.length > 50
|
|
130
|
+
? task.title.substring(0, 47) + '...'
|
|
131
|
+
: task.title;
|
|
132
|
+
|
|
133
|
+
console.log(
|
|
134
|
+
` ${chalk.cyan(task.identifier.padEnd(8))} ${titleStr.padEnd(50)} ${priorityStr.padEnd(8)} ${assigneeStr}`
|
|
135
|
+
);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// Summary
|
|
141
|
+
const totalTasks = issues.length;
|
|
142
|
+
const statusCounts = Object.entries(tasksByStatus).map(
|
|
143
|
+
([status, tasks]) => ({
|
|
144
|
+
status,
|
|
145
|
+
count: tasks.length,
|
|
146
|
+
})
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
console.log(chalk.cyan('\n๐ Summary:'));
|
|
150
|
+
statusCounts.forEach(({ status, count }) => {
|
|
151
|
+
console.log(chalk.gray(` ${status}: ${count} tasks`));
|
|
152
|
+
});
|
|
153
|
+
console.log(chalk.bold(` Total: ${totalTasks} tasks`));
|
|
154
|
+
} catch (error: unknown) {
|
|
155
|
+
console.error(chalk.red('โ Error:'), (error as Error).message);
|
|
156
|
+
process.exit(1);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function getStatusEmoji(statusType: string): string {
|
|
161
|
+
switch (statusType) {
|
|
162
|
+
case 'backlog':
|
|
163
|
+
return '๐';
|
|
164
|
+
case 'unstarted':
|
|
165
|
+
return '๐';
|
|
166
|
+
case 'started':
|
|
167
|
+
return 'โณ';
|
|
168
|
+
case 'completed':
|
|
169
|
+
return 'โ
';
|
|
170
|
+
case 'cancelled':
|
|
171
|
+
return 'โ';
|
|
172
|
+
default:
|
|
173
|
+
return '๐';
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Direct execution
|
|
178
|
+
main();
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* MCP Proxy for Railway-hosted StackMemory
|
|
4
|
+
* Bridges Claude Desktop to Railway API
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import https from 'https';
|
|
8
|
+
|
|
9
|
+
const RAILWAY_URL = process.env.RAILWAY_URL || 'https://stackmemory-production.up.railway.app';
|
|
10
|
+
const API_KEY = process.env.API_KEY;
|
|
11
|
+
|
|
12
|
+
if (!API_KEY) {
|
|
13
|
+
console.error('ERROR: API_KEY environment variable is required');
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Simple proxy that forwards MCP requests to Railway
|
|
18
|
+
process.stdin.on('data', async (data) => {
|
|
19
|
+
try {
|
|
20
|
+
const request = JSON.parse(data.toString());
|
|
21
|
+
|
|
22
|
+
// Forward to Railway API
|
|
23
|
+
const response = await makeRequest('/api/tools/execute', {
|
|
24
|
+
tool: request.method,
|
|
25
|
+
params: request.params
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// Send response back to Claude
|
|
29
|
+
process.stdout.write(JSON.stringify(response) + '\n');
|
|
30
|
+
} catch (error) {
|
|
31
|
+
process.stderr.write(`Error: ${error.message}\n`);
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
async function makeRequest(path, body) {
|
|
36
|
+
return new Promise((resolve, reject) => {
|
|
37
|
+
const url = new URL(path, RAILWAY_URL);
|
|
38
|
+
|
|
39
|
+
const options = {
|
|
40
|
+
method: 'POST',
|
|
41
|
+
headers: {
|
|
42
|
+
'Authorization': `Bearer ${API_KEY}`,
|
|
43
|
+
'Content-Type': 'application/json'
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const req = https.request(url, options, (res) => {
|
|
48
|
+
let data = '';
|
|
49
|
+
res.on('data', chunk => data += chunk);
|
|
50
|
+
res.on('end', () => {
|
|
51
|
+
try {
|
|
52
|
+
resolve(JSON.parse(data));
|
|
53
|
+
} catch (e) {
|
|
54
|
+
resolve({ error: data });
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
req.on('error', reject);
|
|
60
|
+
req.write(JSON.stringify(body));
|
|
61
|
+
req.end();
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
console.error('StackMemory Railway MCP Proxy started');
|
|
66
|
+
console.error(`Connected to: ${RAILWAY_URL}`);
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# OpenCode wrapper with StackMemory integration
|
|
4
|
+
# Usage: Add alias to ~/.zshrc: alias opencode-sm='~/Dev/stackmemory/scripts/opencode-wrapper.sh'
|
|
5
|
+
|
|
6
|
+
# Check for auto-sync flag
|
|
7
|
+
AUTO_SYNC=false
|
|
8
|
+
SYNC_INTERVAL=5
|
|
9
|
+
for arg in "$@"; do
|
|
10
|
+
case $arg in
|
|
11
|
+
--auto-sync)
|
|
12
|
+
AUTO_SYNC=true
|
|
13
|
+
shift
|
|
14
|
+
;;
|
|
15
|
+
--sync-interval=*)
|
|
16
|
+
SYNC_INTERVAL="${arg#*=}"
|
|
17
|
+
shift
|
|
18
|
+
;;
|
|
19
|
+
esac
|
|
20
|
+
done
|
|
21
|
+
|
|
22
|
+
# Auto-initialize StackMemory if in git repo without it
|
|
23
|
+
if [ -d ".git" ] && [ ! -d ".stackmemory" ]; then
|
|
24
|
+
echo "๐ฆ Initializing StackMemory for this project..."
|
|
25
|
+
stackmemory init --silent 2>/dev/null || true
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
# Load existing context if available
|
|
29
|
+
if [ -d ".stackmemory" ]; then
|
|
30
|
+
echo "๐ง Loading StackMemory context..."
|
|
31
|
+
stackmemory status --brief 2>/dev/null || true
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
# Start Linear auto-sync in background if requested
|
|
35
|
+
SYNC_PID=""
|
|
36
|
+
if [ "$AUTO_SYNC" = true ] && [ -n "$LINEAR_API_KEY" ]; then
|
|
37
|
+
echo "๐ Starting Linear auto-sync (${SYNC_INTERVAL}min intervals)..."
|
|
38
|
+
(
|
|
39
|
+
while true; do
|
|
40
|
+
sleep $((SYNC_INTERVAL * 60))
|
|
41
|
+
if [ -d ".stackmemory" ]; then
|
|
42
|
+
stackmemory linear sync --quiet 2>/dev/null || true
|
|
43
|
+
fi
|
|
44
|
+
done
|
|
45
|
+
) &
|
|
46
|
+
SYNC_PID=$!
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
cleanup() {
|
|
50
|
+
echo ""
|
|
51
|
+
echo "๐ Saving StackMemory context..."
|
|
52
|
+
|
|
53
|
+
# Kill auto-sync if running
|
|
54
|
+
if [ -n "$SYNC_PID" ] && kill -0 $SYNC_PID 2>/dev/null; then
|
|
55
|
+
echo "๐ Stopping auto-sync..."
|
|
56
|
+
kill $SYNC_PID 2>/dev/null || true
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
# Check if in a git repo with stackmemory
|
|
60
|
+
if [ -d ".stackmemory" ]; then
|
|
61
|
+
# Save current context
|
|
62
|
+
stackmemory status 2>/dev/null
|
|
63
|
+
|
|
64
|
+
# If Linear API key is set, final sync
|
|
65
|
+
if [ -n "$LINEAR_API_KEY" ]; then
|
|
66
|
+
echo "๐ Final Linear sync..."
|
|
67
|
+
stackmemory linear sync 2>/dev/null
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
echo "โ
StackMemory context saved"
|
|
71
|
+
fi
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
# Set trap for exit signals
|
|
75
|
+
trap cleanup EXIT INT TERM
|
|
76
|
+
|
|
77
|
+
# Run OpenCode
|
|
78
|
+
if command -v opencode &> /dev/null; then
|
|
79
|
+
opencode "$@"
|
|
80
|
+
else
|
|
81
|
+
echo "โ OpenCode not found. Please install it first."
|
|
82
|
+
echo " Run: curl -fsSL https://opencode.ai/install | bash"
|
|
83
|
+
echo " Or: npm install -g opencode-ai"
|
|
84
|
+
exit 1
|
|
85
|
+
fi
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Local NPM Publishing Script with Token
|
|
4
|
+
* Usage: node scripts/publish-local.js
|
|
5
|
+
*
|
|
6
|
+
* Requires NPM_TOKEN in environment or .env file
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { execSync } from 'child_process';
|
|
10
|
+
import { existsSync, readFileSync } from 'fs';
|
|
11
|
+
import { join } from 'path';
|
|
12
|
+
import chalk from 'chalk';
|
|
13
|
+
|
|
14
|
+
// Load .env file if it exists
|
|
15
|
+
const envPath = join(process.cwd(), '.env');
|
|
16
|
+
if (existsSync(envPath)) {
|
|
17
|
+
const envContent = readFileSync(envPath, 'utf-8');
|
|
18
|
+
envContent.split('\n').forEach(line => {
|
|
19
|
+
const [key, value] = line.split('=');
|
|
20
|
+
if (key && value && !process.env[key]) {
|
|
21
|
+
process.env[key.trim()] = value.trim();
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Check for NPM token
|
|
27
|
+
const npmToken = process.env.NPM_TOKEN;
|
|
28
|
+
if (!npmToken) {
|
|
29
|
+
console.error(chalk.red('โ NPM_TOKEN not found'));
|
|
30
|
+
console.log(chalk.yellow('Please set NPM_TOKEN environment variable:'));
|
|
31
|
+
console.log(chalk.gray(' export NPM_TOKEN=npm_xxx...'));
|
|
32
|
+
console.log(chalk.gray(' Or create a .env file with NPM_TOKEN=npm_xxx...'));
|
|
33
|
+
console.log();
|
|
34
|
+
console.log(chalk.yellow('Get your token from:'));
|
|
35
|
+
console.log(chalk.blue(' https://www.npmjs.com/settings/YOUR_USERNAME/tokens'));
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Create .npmrc with token
|
|
40
|
+
const npmrcContent = `//registry.npmjs.org/:_authToken=${npmToken}
|
|
41
|
+
registry=https://registry.npmjs.org/
|
|
42
|
+
access=public
|
|
43
|
+
`;
|
|
44
|
+
|
|
45
|
+
console.log(chalk.green('๐ Setting up NPM authentication...'));
|
|
46
|
+
execSync(`echo "${npmrcContent}" > ~/.npmrc`);
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
// Check current version
|
|
50
|
+
console.log(chalk.yellow('๐ฆ Current package info:'));
|
|
51
|
+
execSync('npm view @stackmemoryai/stackmemory version', { stdio: 'inherit' });
|
|
52
|
+
|
|
53
|
+
// Build
|
|
54
|
+
console.log(chalk.yellow('\n๐จ Building package...'));
|
|
55
|
+
execSync('npm run build', { stdio: 'inherit' });
|
|
56
|
+
|
|
57
|
+
// Publish
|
|
58
|
+
console.log(chalk.yellow('\n๐ Publishing to NPM...'));
|
|
59
|
+
execSync('npm publish --access public', { stdio: 'inherit' });
|
|
60
|
+
|
|
61
|
+
console.log(chalk.green('\nโ
Successfully published to NPM!'));
|
|
62
|
+
|
|
63
|
+
// Show new version
|
|
64
|
+
console.log(chalk.yellow('\n๐ฆ New package info:'));
|
|
65
|
+
execSync('npm view @stackmemoryai/stackmemory version', { stdio: 'inherit' });
|
|
66
|
+
|
|
67
|
+
} catch (error) {
|
|
68
|
+
console.error(chalk.red('\nโ Publishing failed:'), error.message);
|
|
69
|
+
process.exit(1);
|
|
70
|
+
} finally {
|
|
71
|
+
// Clean up .npmrc (optional, for security)
|
|
72
|
+
console.log(chalk.gray('\n๐งน Cleaning up credentials...'));
|
|
73
|
+
execSync('rm ~/.npmrc 2>/dev/null || true');
|
|
74
|
+
}
|