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.

92 lines (85 loc) 2.49 kB
#!/usr/bin/env node /** * On-task-complete hook for StackMemory * Triggers when a task is marked as done in Claude Code. * * Actions: * 1. Auto-updates PROMPT_PLAN.md checkboxes (fuzzy match on task keywords) * 2. Syncs Linear tasks (if STA-* identifier present) * 3. Logs to ~/.stackmemory/logs/hook-errors.log on failure (non-blocking) */ import fs from 'fs'; import path from 'path'; async function onTaskComplete() { try { const input = JSON.parse(fs.readFileSync(0, 'utf-8')); // Sync Linear if STA task if (input.task && input.task.includes('STA-')) { try { const smBin = path.join(process.env.HOME || '', '.stackmemory', 'bin'); const syncScript = path.join( process.cwd(), 'scripts', 'sync-linear-graphql.js' ); if (fs.existsSync(syncScript)) { const { execSync } = await import('child_process'); execSync(`node "${syncScript}"`, { stdio: 'ignore', timeout: 10000, }); } } catch (_e) { // Non-blocking } } // Auto-update PROMPT_PLAN checkboxes if spec exists const promptPlanPath = path.join( process.cwd(), 'docs', 'specs', 'PROMPT_PLAN.md' ); if (fs.existsSync(promptPlanPath) && input.task) { try { const content = fs.readFileSync(promptPlanPath, 'utf-8'); const taskWords = input.task.split(/\s+/).filter((w) => w.length > 3); const lines = content.split('\n'); let updated = false; for (let i = 0; i < lines.length; i++) { if ( lines[i].includes('- [ ]') && taskWords.some((w) => lines[i].toLowerCase().includes(w.toLowerCase()) ) ) { lines[i] = lines[i].replace('- [ ]', '- [x]'); updated = true; break; } } if (updated) { fs.writeFileSync(promptPlanPath, lines.join('\n')); } } catch (_e) { // Silently fail } } } catch (error) { const logDir = path.join( process.env.HOME || '/tmp', '.stackmemory', 'logs' ); try { fs.mkdirSync(logDir, { recursive: true }); fs.appendFileSync( path.join(logDir, 'hook-errors.log'), `[${new Date().toISOString()}] on-task-complete: ${error.message}\n` ); } catch (_e) { // Last resort: silent } } } onTaskComplete();