UNPKG

@stackmemoryai/stackmemory

Version:

Project-scoped memory for AI coding tools. Durable context across sessions with MCP integration, frames, smart retrieval, Claude Code skills, and automatic hooks.

137 lines (136 loc) 3.97 kB
import { fileURLToPath as __fileURLToPath } from 'url'; import { dirname as __pathDirname } from 'path'; const __filename = __fileURLToPath(import.meta.url); const __dirname = __pathDirname(__filename); import { existsSync } from "fs"; import { join } from "path"; import { homedir } from "os"; class DaemonLinearService { config; state; intervalId; isRunning = false; onLog; constructor(config, onLog) { this.config = config; this.onLog = onLog; this.state = { lastSyncTime: 0, syncCount: 0, errors: [] }; } async start() { if (this.isRunning || !this.config.enabled) { return; } if (!this.isLinearConfigured()) { this.onLog("WARN", "Linear not configured, skipping linear service"); return; } this.isRunning = true; const intervalMs = this.config.interval * 60 * 1e3; this.onLog("INFO", "Linear service started", { interval: this.config.interval, quietHours: this.config.quietHours }); await this.performSync(); this.intervalId = setInterval(async () => { await this.performSync(); }, intervalMs); } stop() { if (this.intervalId) { clearInterval(this.intervalId); this.intervalId = void 0; } this.isRunning = false; this.onLog("INFO", "Linear service stopped"); } getState() { return { ...this.state, nextSyncTime: this.isRunning ? this.state.lastSyncTime + this.config.interval * 60 * 1e3 : void 0 }; } updateConfig(config) { const wasRunning = this.isRunning; if (wasRunning) { this.stop(); } this.config = { ...this.config, ...config }; if (wasRunning && this.config.enabled) { this.start(); } } async forceSync() { await this.performSync(); } async performSync() { if (!this.isRunning) return; if (this.isInQuietHours()) { this.onLog("DEBUG", "Skipping sync during quiet hours"); return; } try { const { LinearAutoSyncService } = await import("../../integrations/linear/auto-sync.js"); const projectRoot = this.findProjectRoot(); if (!projectRoot) { this.onLog("WARN", "No project root found for Linear sync"); return; } const syncService = new LinearAutoSyncService(projectRoot, { enabled: true, interval: this.config.interval, retryAttempts: this.config.retryAttempts, retryDelay: this.config.retryDelay, quietHours: this.config.quietHours }); await syncService.forceSync(); syncService.stop(); this.state.syncCount++; this.state.lastSyncTime = Date.now(); this.onLog("INFO", "Linear sync completed", { syncCount: this.state.syncCount }); } catch (err) { const errorMsg = err instanceof Error ? err.message : String(err); this.state.errors.push(errorMsg); this.onLog("ERROR", "Linear sync failed", { error: errorMsg }); if (this.state.errors.length > 10) { this.state.errors = this.state.errors.slice(-10); } } } isLinearConfigured() { const homeDir = homedir(); const configPath = join(homeDir, ".stackmemory", "linear-auth.json"); return existsSync(configPath) || !!process.env["LINEAR_API_KEY"]; } findProjectRoot() { const cwd = process.cwd(); if (existsSync(join(cwd, ".stackmemory"))) { return cwd; } const homeDir = homedir(); if (existsSync(join(homeDir, ".stackmemory"))) { return homeDir; } return null; } isInQuietHours() { if (!this.config.quietHours) return false; const now = /* @__PURE__ */ new Date(); const currentHour = now.getHours(); const { start, end } = this.config.quietHours; if (start > end) { return currentHour >= start || currentHour < end; } else { return currentHour >= start && currentHour < end; } } } export { DaemonLinearService }; //# sourceMappingURL=linear-service.js.map