@stackmemoryai/stackmemory 0.1.0 → 0.2.0
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/scripts/initialize.js +15 -15
- package/dist/scripts/initialize.js.map +1 -1
- package/dist/scripts/status.js +21 -11
- package/dist/scripts/status.js.map +1 -1
- package/dist/src/beads/beads-task-store.d.ts +117 -0
- package/dist/src/beads/beads-task-store.d.ts.map +1 -0
- package/dist/src/beads/beads-task-store.js +318 -0
- package/dist/src/beads/beads-task-store.js.map +1 -0
- package/dist/src/beads/task-aware-context.d.ts +103 -0
- package/dist/src/beads/task-aware-context.d.ts.map +1 -0
- package/dist/src/beads/task-aware-context.js +395 -0
- package/dist/src/beads/task-aware-context.js.map +1 -0
- package/dist/src/beads-task-store.d.ts +117 -0
- package/dist/src/beads-task-store.d.ts.map +1 -0
- package/dist/src/beads-task-store.js +318 -0
- package/dist/src/beads-task-store.js.map +1 -0
- package/dist/src/cli/cli.d.ts +7 -0
- package/dist/src/cli/cli.d.ts.map +1 -0
- package/dist/src/cli/cli.js +471 -0
- package/dist/src/cli/cli.js.map +1 -0
- package/dist/src/core/error-handler.d.ts +46 -0
- package/dist/src/core/error-handler.d.ts.map +1 -0
- package/dist/src/core/error-handler.js +212 -0
- package/dist/src/core/error-handler.js.map +1 -0
- package/dist/src/core/frame-manager.d.ts +106 -0
- package/dist/src/core/frame-manager.d.ts.map +1 -0
- package/dist/src/core/frame-manager.js +387 -0
- package/dist/src/core/frame-manager.js.map +1 -0
- package/dist/src/core/logger.d.ts +24 -0
- package/dist/src/core/logger.d.ts.map +1 -0
- package/dist/src/core/logger.js +121 -0
- package/dist/src/core/logger.js.map +1 -0
- package/dist/src/core/logger.test.d.ts +2 -0
- package/dist/src/core/logger.test.d.ts.map +1 -0
- package/dist/src/core/logger.test.js +31 -0
- package/dist/src/core/logger.test.js.map +1 -0
- package/dist/src/index.d.ts +4 -4
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +4 -4
- package/dist/src/index.js.map +1 -1
- package/dist/src/integrations/linear-auth.d.ts +99 -0
- package/dist/src/integrations/linear-auth.d.ts.map +1 -0
- package/dist/src/integrations/linear-auth.js +319 -0
- package/dist/src/integrations/linear-auth.js.map +1 -0
- package/dist/src/integrations/linear-auto-sync.d.ts +77 -0
- package/dist/src/integrations/linear-auto-sync.d.ts.map +1 -0
- package/dist/src/integrations/linear-auto-sync.js +268 -0
- package/dist/src/integrations/linear-auto-sync.js.map +1 -0
- package/dist/src/integrations/linear-client.d.ts +86 -0
- package/dist/src/integrations/linear-client.d.ts.map +1 -0
- package/dist/src/integrations/linear-client.js +275 -0
- package/dist/src/integrations/linear-client.js.map +1 -0
- package/dist/src/integrations/linear-config.d.ts +51 -0
- package/dist/src/integrations/linear-config.d.ts.map +1 -0
- package/dist/src/integrations/linear-config.js +103 -0
- package/dist/src/integrations/linear-config.js.map +1 -0
- package/dist/src/integrations/linear-sync.d.ts +95 -0
- package/dist/src/integrations/linear-sync.d.ts.map +1 -0
- package/dist/src/integrations/linear-sync.js +340 -0
- package/dist/src/integrations/linear-sync.js.map +1 -0
- package/dist/src/mcp/mcp-server.d.ts +38 -0
- package/dist/src/mcp/mcp-server.d.ts.map +1 -0
- package/dist/src/mcp/mcp-server.js +812 -0
- package/dist/src/mcp/mcp-server.js.map +1 -0
- package/dist/src/pebbles/pebbles-task-store.d.ts +117 -0
- package/dist/src/pebbles/pebbles-task-store.d.ts.map +1 -0
- package/dist/src/pebbles/pebbles-task-store.js +335 -0
- package/dist/src/pebbles/pebbles-task-store.js.map +1 -0
- package/dist/src/pebbles/task-aware-context.d.ts +103 -0
- package/dist/src/pebbles/task-aware-context.d.ts.map +1 -0
- package/dist/src/pebbles/task-aware-context.js +412 -0
- package/dist/src/pebbles/task-aware-context.js.map +1 -0
- package/dist/src/task-aware-context.d.ts +103 -0
- package/dist/src/task-aware-context.d.ts.map +1 -0
- package/dist/src/task-aware-context.js +395 -0
- package/dist/src/task-aware-context.js.map +1 -0
- package/package.json +40 -9
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Linear Auto-Sync Service
|
|
3
|
+
* Background service for automatic bidirectional synchronization
|
|
4
|
+
*/
|
|
5
|
+
import { logger } from '../core/logger.js';
|
|
6
|
+
import { PebblesTaskStore } from '../pebbles/pebbles-task-store.js';
|
|
7
|
+
import { LinearAuthManager } from './linear-auth.js';
|
|
8
|
+
import { LinearSyncEngine, DEFAULT_SYNC_CONFIG, } from './linear-sync.js';
|
|
9
|
+
import { LinearConfigManager } from './linear-config.js';
|
|
10
|
+
import Database from 'better-sqlite3';
|
|
11
|
+
import { join } from 'path';
|
|
12
|
+
import { existsSync } from 'fs';
|
|
13
|
+
export class LinearAutoSyncService {
|
|
14
|
+
config;
|
|
15
|
+
projectRoot;
|
|
16
|
+
configManager;
|
|
17
|
+
syncEngine;
|
|
18
|
+
intervalId;
|
|
19
|
+
isRunning = false;
|
|
20
|
+
lastSyncTime = 0;
|
|
21
|
+
retryCount = 0;
|
|
22
|
+
constructor(projectRoot, config) {
|
|
23
|
+
this.projectRoot = projectRoot;
|
|
24
|
+
this.configManager = new LinearConfigManager(projectRoot);
|
|
25
|
+
// Load persisted config or use defaults
|
|
26
|
+
const persistedConfig = this.configManager.loadConfig();
|
|
27
|
+
const baseConfig = persistedConfig
|
|
28
|
+
? this.configManager.toAutoSyncConfig(persistedConfig)
|
|
29
|
+
: {
|
|
30
|
+
...DEFAULT_SYNC_CONFIG,
|
|
31
|
+
enabled: true,
|
|
32
|
+
interval: 5,
|
|
33
|
+
retryAttempts: 3,
|
|
34
|
+
retryDelay: 30000,
|
|
35
|
+
autoSync: true,
|
|
36
|
+
direction: 'bidirectional',
|
|
37
|
+
conflictResolution: 'newest_wins',
|
|
38
|
+
quietHours: { start: 22, end: 7 },
|
|
39
|
+
};
|
|
40
|
+
this.config = { ...baseConfig, ...config };
|
|
41
|
+
// Save any new config updates
|
|
42
|
+
if (config && Object.keys(config).length > 0) {
|
|
43
|
+
this.configManager.saveConfig(config);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Start the auto-sync service
|
|
48
|
+
*/
|
|
49
|
+
async start() {
|
|
50
|
+
if (this.isRunning) {
|
|
51
|
+
logger.warn('Linear auto-sync service is already running');
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
// Verify Linear integration is configured
|
|
56
|
+
const authManager = new LinearAuthManager(this.projectRoot);
|
|
57
|
+
if (!authManager.isConfigured()) {
|
|
58
|
+
throw new Error('Linear integration not configured. Run "stackmemory linear setup" first.');
|
|
59
|
+
}
|
|
60
|
+
// Initialize sync engine
|
|
61
|
+
const dbPath = join(this.projectRoot, '.stackmemory', 'context.db');
|
|
62
|
+
if (!existsSync(dbPath)) {
|
|
63
|
+
throw new Error('StackMemory not initialized. Run "stackmemory init" first.');
|
|
64
|
+
}
|
|
65
|
+
const db = new Database(dbPath);
|
|
66
|
+
const taskStore = new PebblesTaskStore(this.projectRoot, db);
|
|
67
|
+
this.syncEngine = new LinearSyncEngine(taskStore, authManager, this.config);
|
|
68
|
+
// Test connection before starting
|
|
69
|
+
const token = await authManager.getValidToken();
|
|
70
|
+
if (!token) {
|
|
71
|
+
throw new Error('Unable to get valid Linear token. Check authentication.');
|
|
72
|
+
}
|
|
73
|
+
this.isRunning = true;
|
|
74
|
+
this.scheduleNextSync();
|
|
75
|
+
logger.info('Linear auto-sync service started', {
|
|
76
|
+
interval: this.config.interval,
|
|
77
|
+
direction: this.config.direction,
|
|
78
|
+
conflictResolution: this.config.conflictResolution,
|
|
79
|
+
});
|
|
80
|
+
// Perform initial sync
|
|
81
|
+
this.performSync();
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
logger.error('Failed to start Linear auto-sync service:', error);
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Stop the auto-sync service
|
|
90
|
+
*/
|
|
91
|
+
stop() {
|
|
92
|
+
if (this.intervalId) {
|
|
93
|
+
clearTimeout(this.intervalId);
|
|
94
|
+
this.intervalId = undefined;
|
|
95
|
+
}
|
|
96
|
+
this.isRunning = false;
|
|
97
|
+
logger.info('Linear auto-sync service stopped');
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Get service status
|
|
101
|
+
*/
|
|
102
|
+
getStatus() {
|
|
103
|
+
const nextSyncTime = this.intervalId
|
|
104
|
+
? this.lastSyncTime + this.config.interval * 60 * 1000
|
|
105
|
+
: undefined;
|
|
106
|
+
return {
|
|
107
|
+
running: this.isRunning,
|
|
108
|
+
lastSyncTime: this.lastSyncTime,
|
|
109
|
+
nextSyncTime,
|
|
110
|
+
retryCount: this.retryCount,
|
|
111
|
+
config: this.config,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Update configuration
|
|
116
|
+
*/
|
|
117
|
+
updateConfig(newConfig) {
|
|
118
|
+
this.config = { ...this.config, ...newConfig };
|
|
119
|
+
if (this.isRunning) {
|
|
120
|
+
// Restart with new config
|
|
121
|
+
this.stop();
|
|
122
|
+
this.start();
|
|
123
|
+
}
|
|
124
|
+
logger.info('Linear auto-sync config updated', newConfig);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Force immediate sync
|
|
128
|
+
*/
|
|
129
|
+
async forceSync() {
|
|
130
|
+
if (!this.syncEngine) {
|
|
131
|
+
throw new Error('Sync engine not initialized');
|
|
132
|
+
}
|
|
133
|
+
logger.info('Forcing immediate Linear sync');
|
|
134
|
+
await this.performSync();
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Schedule next sync based on configuration
|
|
138
|
+
*/
|
|
139
|
+
scheduleNextSync() {
|
|
140
|
+
if (!this.isRunning)
|
|
141
|
+
return;
|
|
142
|
+
const delay = this.config.interval * 60 * 1000; // Convert minutes to milliseconds
|
|
143
|
+
this.intervalId = setTimeout(() => {
|
|
144
|
+
if (this.isRunning) {
|
|
145
|
+
this.performSync();
|
|
146
|
+
}
|
|
147
|
+
}, delay);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Perform synchronization with error handling and retries
|
|
151
|
+
*/
|
|
152
|
+
async performSync() {
|
|
153
|
+
if (!this.syncEngine) {
|
|
154
|
+
logger.error('Sync engine not available');
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
// Check quiet hours
|
|
158
|
+
if (this.isInQuietHours()) {
|
|
159
|
+
logger.debug('Skipping sync during quiet hours');
|
|
160
|
+
this.scheduleNextSync();
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
try {
|
|
164
|
+
logger.debug('Starting Linear auto-sync');
|
|
165
|
+
const result = await this.syncEngine.sync();
|
|
166
|
+
if (result.success) {
|
|
167
|
+
this.lastSyncTime = Date.now();
|
|
168
|
+
this.retryCount = 0;
|
|
169
|
+
// Log sync results
|
|
170
|
+
const hasChanges = result.synced.toLinear > 0 ||
|
|
171
|
+
result.synced.fromLinear > 0 ||
|
|
172
|
+
result.synced.updated > 0;
|
|
173
|
+
if (hasChanges) {
|
|
174
|
+
logger.info('Linear auto-sync completed with changes', {
|
|
175
|
+
toLinear: result.synced.toLinear,
|
|
176
|
+
fromLinear: result.synced.fromLinear,
|
|
177
|
+
updated: result.synced.updated,
|
|
178
|
+
conflicts: result.conflicts.length,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
logger.debug('Linear auto-sync completed - no changes');
|
|
183
|
+
}
|
|
184
|
+
// Handle conflicts
|
|
185
|
+
if (result.conflicts.length > 0) {
|
|
186
|
+
logger.warn('Linear sync conflicts detected', {
|
|
187
|
+
count: result.conflicts.length,
|
|
188
|
+
conflicts: result.conflicts.map((c) => ({
|
|
189
|
+
taskId: c.taskId,
|
|
190
|
+
reason: c.reason,
|
|
191
|
+
})),
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
throw new Error(`Sync failed: ${result.errors.join(', ')}`);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
catch (error) {
|
|
200
|
+
logger.error('Linear auto-sync failed:', error);
|
|
201
|
+
this.retryCount++;
|
|
202
|
+
if (this.retryCount <= this.config.retryAttempts) {
|
|
203
|
+
logger.info(`Retrying Linear sync in ${this.config.retryDelay / 1000}s (attempt ${this.retryCount}/${this.config.retryAttempts})`);
|
|
204
|
+
// Schedule retry
|
|
205
|
+
setTimeout(() => {
|
|
206
|
+
if (this.isRunning) {
|
|
207
|
+
this.performSync();
|
|
208
|
+
}
|
|
209
|
+
}, this.config.retryDelay);
|
|
210
|
+
return; // Don't schedule next sync yet
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
logger.error(`Linear auto-sync failed after ${this.config.retryAttempts} attempts, skipping until next interval`);
|
|
214
|
+
this.retryCount = 0;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
// Schedule next sync
|
|
218
|
+
this.scheduleNextSync();
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Check if current time is within quiet hours
|
|
222
|
+
*/
|
|
223
|
+
isInQuietHours() {
|
|
224
|
+
if (!this.config.quietHours)
|
|
225
|
+
return false;
|
|
226
|
+
const now = new Date();
|
|
227
|
+
const currentHour = now.getHours();
|
|
228
|
+
const { start, end } = this.config.quietHours;
|
|
229
|
+
if (start < end) {
|
|
230
|
+
// Quiet hours within same day (e.g., 22:00 - 07:00 next day)
|
|
231
|
+
return currentHour >= start || currentHour < end;
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
// Quiet hours span midnight (e.g., 10:00 - 18:00)
|
|
235
|
+
return currentHour >= start && currentHour < end;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Global auto-sync service instance
|
|
241
|
+
*/
|
|
242
|
+
let autoSyncService = null;
|
|
243
|
+
/**
|
|
244
|
+
* Initialize global auto-sync service
|
|
245
|
+
*/
|
|
246
|
+
export function initializeAutoSync(projectRoot, config) {
|
|
247
|
+
if (autoSyncService) {
|
|
248
|
+
autoSyncService.stop();
|
|
249
|
+
}
|
|
250
|
+
autoSyncService = new LinearAutoSyncService(projectRoot, config);
|
|
251
|
+
return autoSyncService;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Get global auto-sync service
|
|
255
|
+
*/
|
|
256
|
+
export function getAutoSyncService() {
|
|
257
|
+
return autoSyncService;
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Stop global auto-sync service
|
|
261
|
+
*/
|
|
262
|
+
export function stopAutoSync() {
|
|
263
|
+
if (autoSyncService) {
|
|
264
|
+
autoSyncService.stop();
|
|
265
|
+
autoSyncService = null;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
//# sourceMappingURL=linear-auto-sync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"linear-auto-sync.js","sourceRoot":"","sources":["../../../src/integrations/linear-auto-sync.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Linear API Client for StackMemory
|
|
3
|
+
* Handles bi-directional sync with Linear's GraphQL API
|
|
4
|
+
*/
|
|
5
|
+
export interface LinearConfig {
|
|
6
|
+
apiKey: string;
|
|
7
|
+
teamId?: string;
|
|
8
|
+
webhookSecret?: string;
|
|
9
|
+
baseUrl?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface LinearIssue {
|
|
12
|
+
id: string;
|
|
13
|
+
identifier: string;
|
|
14
|
+
title: string;
|
|
15
|
+
description?: string;
|
|
16
|
+
state: {
|
|
17
|
+
id: string;
|
|
18
|
+
name: string;
|
|
19
|
+
type: 'backlog' | 'unstarted' | 'started' | 'completed' | 'cancelled';
|
|
20
|
+
};
|
|
21
|
+
priority: number;
|
|
22
|
+
assignee?: {
|
|
23
|
+
id: string;
|
|
24
|
+
name: string;
|
|
25
|
+
email: string;
|
|
26
|
+
};
|
|
27
|
+
estimate?: number;
|
|
28
|
+
labels: Array<{
|
|
29
|
+
id: string;
|
|
30
|
+
name: string;
|
|
31
|
+
}>;
|
|
32
|
+
createdAt: string;
|
|
33
|
+
updatedAt: string;
|
|
34
|
+
url: string;
|
|
35
|
+
}
|
|
36
|
+
export interface LinearCreateIssueInput {
|
|
37
|
+
title: string;
|
|
38
|
+
description?: string;
|
|
39
|
+
teamId: string;
|
|
40
|
+
priority?: number;
|
|
41
|
+
estimate?: number;
|
|
42
|
+
labelIds?: string[];
|
|
43
|
+
}
|
|
44
|
+
export declare class LinearClient {
|
|
45
|
+
private config;
|
|
46
|
+
private baseUrl;
|
|
47
|
+
constructor(config: LinearConfig);
|
|
48
|
+
/**
|
|
49
|
+
* Execute GraphQL query against Linear API
|
|
50
|
+
*/
|
|
51
|
+
private graphql;
|
|
52
|
+
/**
|
|
53
|
+
* Create a new issue in Linear
|
|
54
|
+
*/
|
|
55
|
+
createIssue(input: LinearCreateIssueInput): Promise<LinearIssue>;
|
|
56
|
+
/**
|
|
57
|
+
* Update an existing Linear issue
|
|
58
|
+
*/
|
|
59
|
+
updateIssue(issueId: string, updates: Partial<LinearCreateIssueInput>): Promise<LinearIssue>;
|
|
60
|
+
/**
|
|
61
|
+
* Get issue by ID
|
|
62
|
+
*/
|
|
63
|
+
getIssue(issueId: string): Promise<LinearIssue | null>;
|
|
64
|
+
/**
|
|
65
|
+
* Search for issues by identifier (e.g., "SM-123")
|
|
66
|
+
*/
|
|
67
|
+
findIssueByIdentifier(identifier: string): Promise<LinearIssue | null>;
|
|
68
|
+
/**
|
|
69
|
+
* Get team information
|
|
70
|
+
*/
|
|
71
|
+
getTeam(teamId?: string): Promise<{
|
|
72
|
+
id: string;
|
|
73
|
+
name: string;
|
|
74
|
+
key: string;
|
|
75
|
+
}>;
|
|
76
|
+
/**
|
|
77
|
+
* Get workflow states for the team
|
|
78
|
+
*/
|
|
79
|
+
getWorkflowStates(teamId: string): Promise<Array<{
|
|
80
|
+
id: string;
|
|
81
|
+
name: string;
|
|
82
|
+
type: string;
|
|
83
|
+
position: number;
|
|
84
|
+
}>>;
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=linear-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"linear-client.d.ts","sourceRoot":"","sources":["../../../src/integrations/linear-client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE;QACL,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,WAAW,GAAG,WAAW,CAAC;KACvE,CAAC;IACF,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE;QACT,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IACF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,KAAK,CAAC;QACZ,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;KACd,CAAC,CAAC;IACH,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,OAAO,CAAS;gBAEZ,MAAM,EAAE,YAAY;IAShC;;OAEG;YACW,OAAO;IAgCrB;;OAEG;IACG,WAAW,CAAC,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,WAAW,CAAC;IAkDtE;;OAEG;IACG,WAAW,CACf,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,CAAC,sBAAsB,CAAC,GACvC,OAAO,CAAC,WAAW,CAAC;IAkDvB;;OAEG;IACG,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAwC5D;;OAEG;IACG,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAkD5E;;OAEG;IACG,OAAO,CACX,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IA8CrD;;OAEG;IACG,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAC9C,KAAK,CAAC;QACJ,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC,CACH;CA+BF"}
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Linear API Client for StackMemory
|
|
3
|
+
* Handles bi-directional sync with Linear's GraphQL API
|
|
4
|
+
*/
|
|
5
|
+
import { logger } from '../core/logger.js';
|
|
6
|
+
export class LinearClient {
|
|
7
|
+
config;
|
|
8
|
+
baseUrl;
|
|
9
|
+
constructor(config) {
|
|
10
|
+
this.config = config;
|
|
11
|
+
this.baseUrl = config.baseUrl || 'https://api.linear.app';
|
|
12
|
+
if (!config.apiKey) {
|
|
13
|
+
throw new Error('Linear API key is required');
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Execute GraphQL query against Linear API
|
|
18
|
+
*/
|
|
19
|
+
async graphql(query, variables) {
|
|
20
|
+
const response = await fetch(`${this.baseUrl}/graphql`, {
|
|
21
|
+
method: 'POST',
|
|
22
|
+
headers: {
|
|
23
|
+
Authorization: `Bearer ${this.config.apiKey}`,
|
|
24
|
+
'Content-Type': 'application/json',
|
|
25
|
+
},
|
|
26
|
+
body: JSON.stringify({
|
|
27
|
+
query,
|
|
28
|
+
variables,
|
|
29
|
+
}),
|
|
30
|
+
});
|
|
31
|
+
if (!response.ok) {
|
|
32
|
+
throw new Error(`Linear API error: ${response.status} ${response.statusText}`);
|
|
33
|
+
}
|
|
34
|
+
const result = (await response.json());
|
|
35
|
+
if (result.errors) {
|
|
36
|
+
logger.error('Linear GraphQL errors:', result.errors);
|
|
37
|
+
throw new Error(`Linear GraphQL error: ${result.errors[0].message}`);
|
|
38
|
+
}
|
|
39
|
+
return result.data;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Create a new issue in Linear
|
|
43
|
+
*/
|
|
44
|
+
async createIssue(input) {
|
|
45
|
+
const mutation = `
|
|
46
|
+
mutation CreateIssue($input: IssueCreateInput!) {
|
|
47
|
+
issueCreate(input: $input) {
|
|
48
|
+
success
|
|
49
|
+
issue {
|
|
50
|
+
id
|
|
51
|
+
identifier
|
|
52
|
+
title
|
|
53
|
+
description
|
|
54
|
+
state {
|
|
55
|
+
id
|
|
56
|
+
name
|
|
57
|
+
type
|
|
58
|
+
}
|
|
59
|
+
priority
|
|
60
|
+
assignee {
|
|
61
|
+
id
|
|
62
|
+
name
|
|
63
|
+
email
|
|
64
|
+
}
|
|
65
|
+
estimate
|
|
66
|
+
labels {
|
|
67
|
+
nodes {
|
|
68
|
+
id
|
|
69
|
+
name
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
createdAt
|
|
73
|
+
updatedAt
|
|
74
|
+
url
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
`;
|
|
79
|
+
const result = await this.graphql(mutation, { input });
|
|
80
|
+
if (!result.issueCreate.success) {
|
|
81
|
+
throw new Error('Failed to create Linear issue');
|
|
82
|
+
}
|
|
83
|
+
return result.issueCreate.issue;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Update an existing Linear issue
|
|
87
|
+
*/
|
|
88
|
+
async updateIssue(issueId, updates) {
|
|
89
|
+
const mutation = `
|
|
90
|
+
mutation UpdateIssue($id: String!, $input: IssueUpdateInput!) {
|
|
91
|
+
issueUpdate(id: $id, input: $input) {
|
|
92
|
+
success
|
|
93
|
+
issue {
|
|
94
|
+
id
|
|
95
|
+
identifier
|
|
96
|
+
title
|
|
97
|
+
description
|
|
98
|
+
state {
|
|
99
|
+
id
|
|
100
|
+
name
|
|
101
|
+
type
|
|
102
|
+
}
|
|
103
|
+
priority
|
|
104
|
+
assignee {
|
|
105
|
+
id
|
|
106
|
+
name
|
|
107
|
+
email
|
|
108
|
+
}
|
|
109
|
+
estimate
|
|
110
|
+
labels {
|
|
111
|
+
nodes {
|
|
112
|
+
id
|
|
113
|
+
name
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
createdAt
|
|
117
|
+
updatedAt
|
|
118
|
+
url
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
`;
|
|
123
|
+
const result = await this.graphql(mutation, { id: issueId, input: updates });
|
|
124
|
+
if (!result.issueUpdate.success) {
|
|
125
|
+
throw new Error(`Failed to update Linear issue ${issueId}`);
|
|
126
|
+
}
|
|
127
|
+
return result.issueUpdate.issue;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Get issue by ID
|
|
131
|
+
*/
|
|
132
|
+
async getIssue(issueId) {
|
|
133
|
+
const query = `
|
|
134
|
+
query GetIssue($id: String!) {
|
|
135
|
+
issue(id: $id) {
|
|
136
|
+
id
|
|
137
|
+
identifier
|
|
138
|
+
title
|
|
139
|
+
description
|
|
140
|
+
state {
|
|
141
|
+
id
|
|
142
|
+
name
|
|
143
|
+
type
|
|
144
|
+
}
|
|
145
|
+
priority
|
|
146
|
+
assignee {
|
|
147
|
+
id
|
|
148
|
+
name
|
|
149
|
+
email
|
|
150
|
+
}
|
|
151
|
+
estimate
|
|
152
|
+
labels {
|
|
153
|
+
nodes {
|
|
154
|
+
id
|
|
155
|
+
name
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
createdAt
|
|
159
|
+
updatedAt
|
|
160
|
+
url
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
`;
|
|
164
|
+
const result = await this.graphql(query, { id: issueId });
|
|
165
|
+
return result.issue;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Search for issues by identifier (e.g., "SM-123")
|
|
169
|
+
*/
|
|
170
|
+
async findIssueByIdentifier(identifier) {
|
|
171
|
+
const query = `
|
|
172
|
+
query FindIssue($filter: IssueFilter!) {
|
|
173
|
+
issues(filter: $filter, first: 1) {
|
|
174
|
+
nodes {
|
|
175
|
+
id
|
|
176
|
+
identifier
|
|
177
|
+
title
|
|
178
|
+
description
|
|
179
|
+
state {
|
|
180
|
+
id
|
|
181
|
+
name
|
|
182
|
+
type
|
|
183
|
+
}
|
|
184
|
+
priority
|
|
185
|
+
assignee {
|
|
186
|
+
id
|
|
187
|
+
name
|
|
188
|
+
email
|
|
189
|
+
}
|
|
190
|
+
estimate
|
|
191
|
+
labels {
|
|
192
|
+
nodes {
|
|
193
|
+
id
|
|
194
|
+
name
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
createdAt
|
|
198
|
+
updatedAt
|
|
199
|
+
url
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
`;
|
|
204
|
+
const result = await this.graphql(query, {
|
|
205
|
+
filter: {
|
|
206
|
+
number: {
|
|
207
|
+
eq: parseInt(identifier.split('-')[1] || '0') || 0,
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
});
|
|
211
|
+
return result.issues.nodes[0] || null;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Get team information
|
|
215
|
+
*/
|
|
216
|
+
async getTeam(teamId) {
|
|
217
|
+
const query = teamId
|
|
218
|
+
? `
|
|
219
|
+
query GetTeam($id: String!) {
|
|
220
|
+
team(id: $id) {
|
|
221
|
+
id
|
|
222
|
+
name
|
|
223
|
+
key
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
`
|
|
227
|
+
: `
|
|
228
|
+
query GetTeams {
|
|
229
|
+
teams(first: 1) {
|
|
230
|
+
nodes {
|
|
231
|
+
id
|
|
232
|
+
name
|
|
233
|
+
key
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
`;
|
|
238
|
+
if (teamId) {
|
|
239
|
+
const result = await this.graphql(query, { id: teamId });
|
|
240
|
+
if (!result.team) {
|
|
241
|
+
throw new Error(`Team ${teamId} not found`);
|
|
242
|
+
}
|
|
243
|
+
return result.team;
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
const result = await this.graphql(query);
|
|
247
|
+
if (result.teams.nodes.length === 0) {
|
|
248
|
+
throw new Error('No teams found');
|
|
249
|
+
}
|
|
250
|
+
return result.teams.nodes[0];
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Get workflow states for the team
|
|
255
|
+
*/
|
|
256
|
+
async getWorkflowStates(teamId) {
|
|
257
|
+
const query = `
|
|
258
|
+
query GetWorkflowStates($teamId: String!) {
|
|
259
|
+
team(id: $teamId) {
|
|
260
|
+
states {
|
|
261
|
+
nodes {
|
|
262
|
+
id
|
|
263
|
+
name
|
|
264
|
+
type
|
|
265
|
+
position
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
`;
|
|
271
|
+
const result = await this.graphql(query, { teamId });
|
|
272
|
+
return result.team.states.nodes;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
//# sourceMappingURL=linear-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"linear-client.js","sourceRoot":"","sources":["../../../src/integrations/linear-client.ts"],"names":[],"mappings":"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"}
|