@stackmemoryai/stackmemory 0.5.0 → 0.5.2
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/commands/config.js +81 -0
- package/dist/cli/commands/config.js.map +2 -2
- package/dist/cli/commands/decision.js +262 -0
- package/dist/cli/commands/decision.js.map +7 -0
- package/dist/cli/commands/handoff.js +87 -24
- package/dist/cli/commands/handoff.js.map +3 -3
- package/dist/cli/commands/service.js +684 -0
- package/dist/cli/commands/service.js.map +7 -0
- package/dist/cli/commands/sweep.js +311 -0
- package/dist/cli/commands/sweep.js.map +7 -0
- package/dist/cli/index.js +98 -4
- package/dist/cli/index.js.map +2 -2
- package/dist/cli/streamlined-cli.js +144 -0
- package/dist/cli/streamlined-cli.js.map +7 -0
- package/dist/core/config/storage-config.js +111 -0
- package/dist/core/config/storage-config.js.map +7 -0
- package/dist/core/events/event-bus.js +110 -0
- package/dist/core/events/event-bus.js.map +7 -0
- package/dist/core/plugins/plugin-interface.js +87 -0
- package/dist/core/plugins/plugin-interface.js.map +7 -0
- package/dist/core/session/enhanced-handoff.js +654 -0
- package/dist/core/session/enhanced-handoff.js.map +7 -0
- package/dist/core/storage/simplified-storage.js +328 -0
- package/dist/core/storage/simplified-storage.js.map +7 -0
- package/dist/daemon/session-daemon.js +308 -0
- package/dist/daemon/session-daemon.js.map +7 -0
- package/dist/plugins/linear/index.js +166 -0
- package/dist/plugins/linear/index.js.map +7 -0
- package/dist/plugins/loader.js +57 -0
- package/dist/plugins/loader.js.map +7 -0
- package/dist/plugins/plugin-interface.js +67 -0
- package/dist/plugins/plugin-interface.js.map +7 -0
- package/dist/plugins/ralph/simple-ralph-plugin.js +305 -0
- package/dist/plugins/ralph/simple-ralph-plugin.js.map +7 -0
- package/dist/plugins/ralph/use-cases/code-generator.js +151 -0
- package/dist/plugins/ralph/use-cases/code-generator.js.map +7 -0
- package/dist/plugins/ralph/use-cases/test-generator.js +201 -0
- package/dist/plugins/ralph/use-cases/test-generator.js.map +7 -0
- package/dist/skills/repo-ingestion-skill.js +54 -10
- package/dist/skills/repo-ingestion-skill.js.map +2 -2
- package/package.json +4 -8
- package/scripts/archive/check-all-duplicates.ts +2 -2
- package/scripts/archive/merge-linear-duplicates.ts +6 -4
- package/scripts/install-claude-hooks-auto.js +72 -15
- package/scripts/measure-handoff-impact.mjs +395 -0
- package/scripts/measure-handoff-impact.ts +450 -0
- package/templates/claude-hooks/on-startup.js +200 -19
- package/templates/services/com.stackmemory.guardian.plist +59 -0
- package/templates/services/stackmemory-guardian.service +41 -0
- package/scripts/testing/results/real-performance-results.json +0 -90
- package/scripts/testing/test-tier-migration.js +0 -100
package/dist/cli/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/cli/index.ts"],
|
|
4
|
-
"sourcesContent": ["#!/usr/bin/env node\n/**\n * StackMemory CLI\n * Command-line interface for StackMemory operations\n */\n\n// Set environment flag for CLI usage to skip async context bridge\nprocess.env['STACKMEMORY_CLI'] = 'true';\n\n// Load environment variables\nimport 'dotenv/config';\n\n// Initialize tracing system early\nimport { initializeTracing, trace } from '../core/trace/index.js';\ninitializeTracing();\n\nimport { program } from 'commander';\nimport { logger } from '../core/monitoring/logger.js';\nimport { FrameManager } from '../core/context/frame-manager.js';\nimport { sessionManager, FrameQueryMode } from '../core/session/index.js';\nimport { sharedContextLayer } from '../core/context/shared-context-layer.js';\nimport { UpdateChecker } from '../core/utils/update-checker.js';\nimport { ProgressTracker } from '../core/monitoring/progress-tracker.js';\nimport { registerProjectCommands } from './commands/projects.js';\nimport { registerLinearCommands } from './commands/linear.js';\nimport { createSessionCommands } from './commands/session.js';\nimport { registerWorktreeCommands } from './commands/worktree.js';\nimport { registerOnboardingCommand } from './commands/onboard.js';\nimport { createTaskCommands } from './commands/tasks.js';\nimport { createSearchCommand } from './commands/search.js';\nimport { createLogCommand } from './commands/log.js';\nimport { createContextCommands } from './commands/context.js';\nimport { createConfigCommand } from './commands/config.js';\nimport { createHandoffCommand } from './commands/handoff.js';\nimport { createStorageCommand } from './commands/storage.js';\nimport { createSkillsCommand } from './commands/skills.js';\nimport { createTestCommand } from './commands/test.js';\nimport clearCommand from './commands/clear.js';\nimport createWorkflowCommand from './commands/workflow.js';\nimport monitorCommand from './commands/monitor.js';\nimport qualityCommand from './commands/quality.js';\nimport createRalphCommand from './commands/ralph.js';\nimport { registerLoginCommand } from './commands/login.js';\nimport { registerSignupCommand } from './commands/signup.js';\nimport { registerLogoutCommand, registerDbCommands } from './commands/db.js';\nimport { ProjectManager } from '../core/projects/project-manager.js';\nimport Database from 'better-sqlite3';\nimport { join } from 'path';\nimport { existsSync, mkdirSync } from 'fs';\n\nconst VERSION = '0.4.2';\n\n// Check for updates on CLI startup\nUpdateChecker.checkForUpdates(VERSION, true).catch(() => {\n // Silently ignore errors\n});\n\nprogram\n .name('stackmemory')\n .description(\n 'Lossless memory runtime for AI coding tools - organizes context as a call stack instead of linear chat logs, with team collaboration and infinite retention'\n )\n .version(VERSION);\n\nprogram\n .command('init')\n .description('Initialize StackMemory in current project')\n .action(async () => {\n try {\n const projectRoot = process.cwd();\n const dbDir = join(projectRoot, '.stackmemory');\n\n if (!existsSync(dbDir)) {\n mkdirSync(dbDir, { recursive: true });\n }\n\n const dbPath = join(dbDir, 'context.db');\n const db = new Database(dbPath);\n new FrameManager(db, 'cli-project');\n\n logger.info('StackMemory initialized successfully', { projectRoot });\n console.log('\u2705 StackMemory initialized in', projectRoot);\n\n db.close();\n } catch (error: unknown) {\n logger.error('Failed to initialize StackMemory', error as Error);\n console.error('\u274C Initialization failed:', (error as Error).message);\n process.exit(1);\n }\n });\n\nprogram\n .command('status')\n .description('Show current StackMemory status')\n .option('--all', 'Show all active frames across sessions')\n .option('--project', 'Show all active frames in current project')\n .option('--session <id>', 'Show frames for specific session')\n .action(async (options) => {\n return trace.command('stackmemory-status', options, async () => {\n try {\n const projectRoot = process.cwd();\n const dbPath = join(projectRoot, '.stackmemory', 'context.db');\n\n if (!existsSync(dbPath)) {\n console.log(\n '\u274C StackMemory not initialized. Run \"stackmemory init\" first.'\n );\n return;\n }\n\n // Check for updates and display if available\n await UpdateChecker.checkForUpdates(VERSION);\n\n // Initialize session manager and shared context\n await sessionManager.initialize();\n await sharedContextLayer.initialize();\n\n const session = await sessionManager.getOrCreateSession({\n projectPath: projectRoot,\n sessionId: options.session,\n });\n\n // Auto-discover shared context on startup\n const contextDiscovery = await sharedContextLayer.autoDiscoverContext();\n\n // Show context hints if available\n if (\n contextDiscovery.hasSharedContext &&\n contextDiscovery.sessionCount > 1\n ) {\n console.log(`\\n\uD83D\uDCA1 Shared Context Available:`);\n console.log(\n ` ${contextDiscovery.sessionCount} sessions with shared context`\n );\n\n if (contextDiscovery.recentPatterns.length > 0) {\n console.log(` Recent patterns:`);\n contextDiscovery.recentPatterns.slice(0, 3).forEach((p) => {\n console.log(\n ` \u2022 ${p.type}: ${p.pattern.slice(0, 50)} (${p.frequency}x)`\n );\n });\n }\n\n if (contextDiscovery.lastDecisions.length > 0) {\n console.log(\n ` Last decision: ${contextDiscovery.lastDecisions[0].decision.slice(0, 60)}`\n );\n }\n }\n\n const db = new Database(dbPath);\n const frameManager = new FrameManager(db, session.projectId);\n\n // Set query mode based on options\n if (options.all) {\n frameManager.setQueryMode(FrameQueryMode.ALL_ACTIVE);\n } else if (options.project) {\n frameManager.setQueryMode(FrameQueryMode.PROJECT_ACTIVE);\n }\n\n const activeFrames = frameManager.getActiveFramePath();\n const stackDepth = frameManager.getStackDepth();\n\n // Always get total counts across all sessions\n const totalStats = db\n .prepare(\n `\n SELECT \n COUNT(*) as total_frames,\n SUM(CASE WHEN state = 'active' THEN 1 ELSE 0 END) as active_frames,\n SUM(CASE WHEN state = 'closed' THEN 1 ELSE 0 END) as closed_frames,\n COUNT(DISTINCT run_id) as total_sessions\n FROM frames\n WHERE project_id = ?\n `\n )\n .get(session.projectId) as {\n total_frames: number;\n active_frames: number;\n closed_frames: number;\n total_sessions: number;\n };\n\n const contextCount = db\n .prepare(\n `\n SELECT COUNT(*) as count FROM contexts\n `\n )\n .get() as { count: number };\n\n const eventCount = db\n .prepare(\n `\n SELECT COUNT(*) as count FROM events e\n JOIN frames f ON e.frame_id = f.frame_id\n WHERE f.project_id = ?\n `\n )\n .get(session.projectId) as { count: number };\n\n console.log('\uD83D\uDCCA StackMemory Status:');\n console.log(\n ` Session: ${session.sessionId.slice(0, 8)} (${session.state}, ${Math.round((Date.now() - session.startedAt) / 1000 / 60)}min old)`\n );\n console.log(` Project: ${session.projectId}`);\n if (session.branch) {\n console.log(` Branch: ${session.branch}`);\n }\n\n // Show total database statistics\n console.log(`\\n Database Statistics (this project):`);\n console.log(\n ` Frames: ${totalStats.total_frames || 0} (${totalStats.active_frames || 0} active, ${totalStats.closed_frames || 0} closed)`\n );\n console.log(` Events: ${eventCount.count || 0}`);\n console.log(` Sessions: ${totalStats.total_sessions || 0}`);\n console.log(\n ` Cached contexts: ${contextCount.count || 0} (global)`\n );\n\n // Show recent activity\n const recentFrames = db\n .prepare(\n `\n SELECT name, type, state, datetime(created_at, 'unixepoch') as created\n FROM frames\n WHERE project_id = ?\n ORDER BY created_at DESC\n LIMIT 3\n `\n )\n .all(session.projectId) as Array<{\n name: string;\n type: string;\n state: string;\n created: string;\n }>;\n\n if (recentFrames.length > 0) {\n console.log(`\\n Recent Activity:`);\n recentFrames.forEach((f) => {\n const stateIcon = f.state === 'active' ? '\uD83D\uDFE2' : '\u26AB';\n console.log(\n ` ${stateIcon} ${f.name} [${f.type}] - ${f.created}`\n );\n });\n }\n\n console.log(`\\n Current Session:`);\n console.log(` Stack depth: ${stackDepth}`);\n console.log(` Active frames: ${activeFrames.length}`);\n\n if (activeFrames.length > 0) {\n activeFrames.forEach((frame, i) => {\n const indent = ' ' + ' '.repeat(frame.depth || i);\n const prefix = i === 0 ? '\u2514\u2500' : ' \u2514\u2500';\n console.log(`${indent}${prefix} ${frame.name} [${frame.type}]`);\n });\n }\n\n // Show other sessions if in default mode\n if (!options.all && !options.project) {\n const otherSessions = await sessionManager.listSessions({\n projectId: session.projectId,\n state: 'active',\n });\n\n const otherActive = otherSessions.filter(\n (s) => s.sessionId !== session.sessionId\n );\n if (otherActive.length > 0) {\n console.log(`\\n Other Active Sessions (same project):`);\n otherActive.forEach((s) => {\n const age = Math.round(\n (Date.now() - s.lastActiveAt) / 1000 / 60 / 60\n );\n console.log(\n ` - ${s.sessionId.slice(0, 8)}: ${s.branch || 'main'}, ${age}h old`\n );\n });\n console.log(`\\n Tip: Use --all to see frames across sessions`);\n }\n }\n\n db.close();\n } catch (error: unknown) {\n logger.error('Failed to get status', error as Error);\n console.error('\u274C Status check failed:', (error as Error).message);\n process.exit(1);\n }\n });\n });\n\nprogram\n .command('update-check')\n .description('Check for StackMemory updates')\n .action(async () => {\n try {\n console.log('\uD83D\uDD0D Checking for updates...');\n await UpdateChecker.forceCheck(VERSION);\n } catch (error: unknown) {\n logger.error('Update check failed', error as Error);\n console.error('\u274C Update check failed:', (error as Error).message);\n process.exit(1);\n }\n });\n\nprogram\n .command('progress')\n .description('Show current progress and recent changes')\n .action(async () => {\n try {\n const projectRoot = process.cwd();\n const dbPath = join(projectRoot, '.stackmemory', 'context.db');\n\n if (!existsSync(dbPath)) {\n console.log(\n '\u274C StackMemory not initialized. Run \"stackmemory init\" first.'\n );\n return;\n }\n\n const progress = new ProgressTracker(projectRoot);\n console.log(progress.getSummary());\n } catch (error: unknown) {\n logger.error('Failed to show progress', error as Error);\n console.error('\u274C Failed to show progress:', (error as Error).message);\n process.exit(1);\n }\n });\n\nprogram\n .command('mcp-server')\n .description('Start StackMemory MCP server for Claude Desktop')\n .option('-p, --project <path>', 'Project root directory', process.cwd())\n .action(async (options) => {\n try {\n const { runMCPServer } = await import('../integrations/mcp/server.js');\n\n // Set project root\n process.env['PROJECT_ROOT'] = options.project;\n\n console.log('\uD83D\uDE80 Starting StackMemory MCP Server...');\n console.log(` Project: ${options.project}`);\n console.log(` Version: ${VERSION}`);\n\n // Check for updates silently\n UpdateChecker.checkForUpdates(VERSION, true).catch(() => {});\n\n // Start the MCP server\n await runMCPServer();\n } catch (error: unknown) {\n logger.error('Failed to start MCP server', error as Error);\n console.error('\u274C MCP server failed:', (error as Error).message);\n process.exit(1);\n }\n });\n\n// Add test context command\nprogram\n .command('context:test')\n .description('Test context persistence by creating sample frames')\n .action(async () => {\n try {\n const projectRoot = process.cwd();\n const dbPath = join(projectRoot, '.stackmemory', 'context.db');\n\n if (!existsSync(dbPath)) {\n console.log(\n '\u274C StackMemory not initialized. Run \"stackmemory init\" first.'\n );\n return;\n }\n\n const db = new Database(dbPath);\n const frameManager = new FrameManager(db, 'cli-project');\n\n // Create test frames\n console.log('\uD83D\uDCDD Creating test context frames...');\n\n const rootFrame = frameManager.createFrame({\n type: 'task',\n name: 'Test Session',\n inputs: { test: true, timestamp: new Date().toISOString() },\n });\n\n const taskFrame = frameManager.createFrame({\n type: 'subtask',\n name: 'Sample Task',\n inputs: { description: 'Testing context persistence' },\n parentFrameId: rootFrame,\n });\n\n const commandFrame = frameManager.createFrame({\n type: 'tool_scope',\n name: 'test-command',\n inputs: { args: ['--test'] },\n parentFrameId: taskFrame,\n });\n\n // Add some events\n frameManager.addEvent(\n 'observation',\n {\n message: 'Test event recorded',\n },\n commandFrame\n );\n\n console.log('\u2705 Test frames created!');\n console.log(`\uD83D\uDCCA Stack depth: ${frameManager.getStackDepth()}`);\n console.log(\n `\uD83D\uDD04 Active frames: ${frameManager.getActiveFramePath().length}`\n );\n\n // Close one frame to test state changes\n frameManager.closeFrame(commandFrame);\n console.log(\n `\uD83D\uDCCA After closing command frame: depth = ${frameManager.getStackDepth()}`\n );\n\n db.close();\n } catch (error: unknown) {\n logger.error('Test context failed', error as Error);\n console.error('\u274C Test failed:', (error as Error).message);\n process.exit(1);\n }\n });\n\n// Register project management commands\n// Register command modules\nregisterOnboardingCommand(program);\nregisterSignupCommand(program);\nregisterLoginCommand(program);\nregisterLogoutCommand(program);\nregisterDbCommands(program);\nregisterProjectCommands(program);\nregisterWorktreeCommands(program);\n\n// Register Linear integration commands\nregisterLinearCommands(program);\n\n// Register session management commands\nprogram.addCommand(createSessionCommands());\n\n// Register enhanced CLI commands\nprogram.addCommand(createTaskCommands());\nprogram.addCommand(createSearchCommand());\nprogram.addCommand(createLogCommand());\nprogram.addCommand(createContextCommands());\nprogram.addCommand(createConfigCommand());\nprogram.addCommand(createHandoffCommand());\nprogram.addCommand(createStorageCommand());\nprogram.addCommand(createSkillsCommand());\nprogram.addCommand(createTestCommand());\nprogram.addCommand(clearCommand);\nprogram.addCommand(createWorkflowCommand());\nprogram.addCommand(monitorCommand);\nprogram.addCommand(qualityCommand);\nprogram.addCommand(createRalphCommand());\n\n// Register dashboard command\nprogram\n .command('dashboard')\n .description('Display monitoring dashboard in terminal')\n .option('-w, --watch', 'Auto-refresh dashboard')\n .option('-i, --interval <seconds>', 'Refresh interval in seconds', '5')\n .action(async (options) => {\n const { dashboardCommand } = await import('./commands/dashboard.js');\n await dashboardCommand.handler(options);\n });\n\n// Auto-detect current project on startup\nif (process.argv.length > 2) {\n const manager = ProjectManager.getInstance();\n manager.detectProject().catch(() => {\n // Silently fail if not in a project directory\n });\n}\n\n// Only parse when running as main module (not when imported for testing)\nconst isMainModule =\n import.meta.url === `file://${process.argv[1]}` ||\n process.argv[1]?.endsWith('/stackmemory') ||\n process.argv[1]?.endsWith('index.ts') ||\n process.argv[1]?.includes('tsx');\n\nif (isMainModule) {\n program.parse();\n}\n\nexport { program };\n"],
|
|
5
|
-
"mappings": ";AAOA,QAAQ,IAAI,iBAAiB,IAAI;AAGjC,OAAO;AAGP,SAAS,mBAAmB,aAAa;AACzC,kBAAkB;AAElB,SAAS,eAAe;AACxB,SAAS,cAAc;AACvB,SAAS,oBAAoB;AAC7B,SAAS,gBAAgB,sBAAsB;AAC/C,SAAS,0BAA0B;AACnC,SAAS,qBAAqB;AAC9B,SAAS,uBAAuB;AAChC,SAAS,+BAA+B;AACxC,SAAS,8BAA8B;AACvC,SAAS,6BAA6B;AACtC,SAAS,gCAAgC;AACzC,SAAS,iCAAiC;AAC1C,SAAS,0BAA0B;AACnC,SAAS,2BAA2B;AACpC,SAAS,wBAAwB;AACjC,SAAS,6BAA6B;AACtC,SAAS,2BAA2B;AACpC,SAAS,4BAA4B;AACrC,SAAS,4BAA4B;AACrC,SAAS,2BAA2B;AACpC,SAAS,yBAAyB;AAClC,OAAO,kBAAkB;AACzB,OAAO,2BAA2B;AAClC,OAAO,oBAAoB;AAC3B,OAAO,oBAAoB;AAC3B,OAAO,wBAAwB;AAC/B,SAAS,4BAA4B;AACrC,SAAS,6BAA6B;AACtC,SAAS,uBAAuB,0BAA0B;AAC1D,SAAS,sBAAsB;AAC/B,OAAO,cAAc;AACrB,SAAS,YAAY;AACrB,SAAS,YAAY,iBAAiB;
|
|
4
|
+
"sourcesContent": ["#!/usr/bin/env node\n/**\n * StackMemory CLI\n * Command-line interface for StackMemory operations\n */\n\n// Set environment flag for CLI usage to skip async context bridge\nprocess.env['STACKMEMORY_CLI'] = 'true';\n\n// Load environment variables\nimport 'dotenv/config';\n\n// Initialize tracing system early\nimport { initializeTracing, trace } from '../core/trace/index.js';\ninitializeTracing();\n\nimport { program } from 'commander';\nimport { logger } from '../core/monitoring/logger.js';\nimport { FrameManager } from '../core/context/frame-manager.js';\nimport { sessionManager, FrameQueryMode } from '../core/session/index.js';\nimport { sharedContextLayer } from '../core/context/shared-context-layer.js';\nimport { UpdateChecker } from '../core/utils/update-checker.js';\nimport { ProgressTracker } from '../core/monitoring/progress-tracker.js';\nimport { registerProjectCommands } from './commands/projects.js';\nimport { registerLinearCommands } from './commands/linear.js';\nimport { createSessionCommands } from './commands/session.js';\nimport { registerWorktreeCommands } from './commands/worktree.js';\nimport { registerOnboardingCommand } from './commands/onboard.js';\nimport { createTaskCommands } from './commands/tasks.js';\nimport { createSearchCommand } from './commands/search.js';\nimport { createLogCommand } from './commands/log.js';\nimport { createContextCommands } from './commands/context.js';\nimport { createConfigCommand } from './commands/config.js';\nimport { createHandoffCommand } from './commands/handoff.js';\nimport {\n createDecisionCommand,\n createMemoryCommand,\n} from './commands/decision.js';\nimport { createStorageCommand } from './commands/storage.js';\nimport { createSkillsCommand } from './commands/skills.js';\nimport { createTestCommand } from './commands/test.js';\nimport clearCommand from './commands/clear.js';\nimport createWorkflowCommand from './commands/workflow.js';\nimport monitorCommand from './commands/monitor.js';\nimport qualityCommand from './commands/quality.js';\nimport createRalphCommand from './commands/ralph.js';\nimport serviceCommand from './commands/service.js';\nimport { registerLoginCommand } from './commands/login.js';\nimport { registerSignupCommand } from './commands/signup.js';\nimport { registerLogoutCommand, registerDbCommands } from './commands/db.js';\nimport { createSweepCommand } from './commands/sweep.js';\nimport { ProjectManager } from '../core/projects/project-manager.js';\nimport Database from 'better-sqlite3';\nimport { join } from 'path';\nimport { existsSync, mkdirSync } from 'fs';\nimport inquirer from 'inquirer';\nimport chalk from 'chalk';\nimport {\n loadStorageConfig,\n enableChromaDB,\n getStorageModeDescription,\n} from '../core/config/storage-config.js';\n\nconst VERSION = '0.5.2';\n\n// Check for updates on CLI startup\nUpdateChecker.checkForUpdates(VERSION, true).catch(() => {\n // Silently ignore errors\n});\n\nprogram\n .name('stackmemory')\n .description(\n 'Lossless memory runtime for AI coding tools - organizes context as a call stack instead of linear chat logs, with team collaboration and infinite retention'\n )\n .version(VERSION);\n\nprogram\n .command('init')\n .description(\n `Initialize StackMemory in current project\n\nStorage Modes:\n SQLite (default): Local only, fast, no setup required\n ChromaDB (hybrid): Adds semantic search and cloud backup, requires API key`\n )\n .option('--sqlite', 'Use SQLite-only storage (default, skip prompts)')\n .option(\n '--chromadb',\n 'Enable ChromaDB for semantic search (prompts for API key)'\n )\n .option('--skip-storage-prompt', 'Skip storage configuration prompt')\n .action(async (options) => {\n try {\n const projectRoot = process.cwd();\n const dbDir = join(projectRoot, '.stackmemory');\n\n if (!existsSync(dbDir)) {\n mkdirSync(dbDir, { recursive: true });\n }\n\n // Handle storage configuration\n let storageConfig = loadStorageConfig();\n const isFirstTimeSetup =\n !storageConfig.chromadb.enabled && storageConfig.mode === 'sqlite';\n\n // Skip prompts if --sqlite flag or --skip-storage-prompt\n if (options.sqlite || options.skipStoragePrompt) {\n // Use SQLite-only (default)\n console.log(chalk.gray('Using SQLite-only storage mode.'));\n } else if (options.chromadb) {\n // User explicitly requested ChromaDB, prompt for API key\n await promptAndEnableChromaDB();\n } else if (isFirstTimeSetup && process.stdin.isTTY) {\n // Interactive mode - ask user about ChromaDB\n console.log(chalk.cyan('\\nStorage Configuration'));\n console.log(chalk.gray('StackMemory supports two storage modes:\\n'));\n console.log(chalk.white(' SQLite (default):'));\n console.log(chalk.gray(' - Local storage only'));\n console.log(chalk.gray(' - Fast and simple'));\n console.log(chalk.gray(' - No external dependencies\\n'));\n console.log(chalk.white(' ChromaDB (hybrid):'));\n console.log(chalk.gray(' - Semantic search across your context'));\n console.log(chalk.gray(' - Cloud backup capability'));\n console.log(chalk.gray(' - Requires ChromaDB API key\\n'));\n\n const { enableChroma } = await inquirer.prompt([\n {\n type: 'confirm',\n name: 'enableChroma',\n message: 'Enable ChromaDB for semantic search? (requires API key)',\n default: false,\n },\n ]);\n\n if (enableChroma) {\n await promptAndEnableChromaDB();\n } else {\n console.log(chalk.gray('Using SQLite-only storage mode.'));\n }\n }\n\n // Initialize SQLite database\n const dbPath = join(dbDir, 'context.db');\n const db = new Database(dbPath);\n new FrameManager(db, 'cli-project');\n\n logger.info('StackMemory initialized successfully', { projectRoot });\n console.log(\n chalk.green('\\n[OK] StackMemory initialized in'),\n projectRoot\n );\n\n // Show current storage mode\n storageConfig = loadStorageConfig();\n console.log(chalk.gray(`Storage mode: ${getStorageModeDescription()}`));\n\n db.close();\n } catch (error: unknown) {\n logger.error('Failed to initialize StackMemory', error as Error);\n console.error(\n chalk.red('[ERROR] Initialization failed:'),\n (error as Error).message\n );\n process.exit(1);\n }\n });\n\n/**\n * Prompt user for ChromaDB configuration and enable it\n */\nasync function promptAndEnableChromaDB(): Promise<void> {\n const answers = await inquirer.prompt([\n {\n type: 'password',\n name: 'apiKey',\n message: 'Enter your ChromaDB API key:',\n validate: (input: string) => {\n if (!input || input.trim().length === 0) {\n return 'API key is required for ChromaDB';\n }\n return true;\n },\n },\n {\n type: 'input',\n name: 'apiUrl',\n message: 'ChromaDB API URL (press Enter for default):',\n default: 'https://api.trychroma.com',\n },\n ]);\n\n enableChromaDB({\n apiKey: answers.apiKey,\n apiUrl: answers.apiUrl,\n });\n\n console.log(chalk.green('[OK] ChromaDB enabled for semantic search.'));\n console.log(\n chalk.gray('API key saved to ~/.stackmemory/storage-config.json')\n );\n}\n\nprogram\n .command('status')\n .description('Show current StackMemory status')\n .option('--all', 'Show all active frames across sessions')\n .option('--project', 'Show all active frames in current project')\n .option('--session <id>', 'Show frames for specific session')\n .action(async (options) => {\n return trace.command('stackmemory-status', options, async () => {\n try {\n const projectRoot = process.cwd();\n const dbPath = join(projectRoot, '.stackmemory', 'context.db');\n\n if (!existsSync(dbPath)) {\n console.log(\n '\u274C StackMemory not initialized. Run \"stackmemory init\" first.'\n );\n return;\n }\n\n // Check for updates and display if available\n await UpdateChecker.checkForUpdates(VERSION);\n\n // Initialize session manager and shared context\n await sessionManager.initialize();\n await sharedContextLayer.initialize();\n\n const session = await sessionManager.getOrCreateSession({\n projectPath: projectRoot,\n sessionId: options.session,\n });\n\n // Auto-discover shared context on startup\n const contextDiscovery = await sharedContextLayer.autoDiscoverContext();\n\n // Show context hints if available\n if (\n contextDiscovery.hasSharedContext &&\n contextDiscovery.sessionCount > 1\n ) {\n console.log(`\\n\uD83D\uDCA1 Shared Context Available:`);\n console.log(\n ` ${contextDiscovery.sessionCount} sessions with shared context`\n );\n\n if (contextDiscovery.recentPatterns.length > 0) {\n console.log(` Recent patterns:`);\n contextDiscovery.recentPatterns.slice(0, 3).forEach((p) => {\n console.log(\n ` \u2022 ${p.type}: ${p.pattern.slice(0, 50)} (${p.frequency}x)`\n );\n });\n }\n\n if (contextDiscovery.lastDecisions.length > 0) {\n console.log(\n ` Last decision: ${contextDiscovery.lastDecisions[0].decision.slice(0, 60)}`\n );\n }\n }\n\n const db = new Database(dbPath);\n const frameManager = new FrameManager(db, session.projectId);\n\n // Set query mode based on options\n if (options.all) {\n frameManager.setQueryMode(FrameQueryMode.ALL_ACTIVE);\n } else if (options.project) {\n frameManager.setQueryMode(FrameQueryMode.PROJECT_ACTIVE);\n }\n\n const activeFrames = frameManager.getActiveFramePath();\n const stackDepth = frameManager.getStackDepth();\n\n // Always get total counts across all sessions\n const totalStats = db\n .prepare(\n `\n SELECT \n COUNT(*) as total_frames,\n SUM(CASE WHEN state = 'active' THEN 1 ELSE 0 END) as active_frames,\n SUM(CASE WHEN state = 'closed' THEN 1 ELSE 0 END) as closed_frames,\n COUNT(DISTINCT run_id) as total_sessions\n FROM frames\n WHERE project_id = ?\n `\n )\n .get(session.projectId) as {\n total_frames: number;\n active_frames: number;\n closed_frames: number;\n total_sessions: number;\n };\n\n const contextCount = db\n .prepare(\n `\n SELECT COUNT(*) as count FROM contexts\n `\n )\n .get() as { count: number };\n\n const eventCount = db\n .prepare(\n `\n SELECT COUNT(*) as count FROM events e\n JOIN frames f ON e.frame_id = f.frame_id\n WHERE f.project_id = ?\n `\n )\n .get(session.projectId) as { count: number };\n\n console.log('\uD83D\uDCCA StackMemory Status:');\n console.log(\n ` Session: ${session.sessionId.slice(0, 8)} (${session.state}, ${Math.round((Date.now() - session.startedAt) / 1000 / 60)}min old)`\n );\n console.log(` Project: ${session.projectId}`);\n if (session.branch) {\n console.log(` Branch: ${session.branch}`);\n }\n\n // Show total database statistics\n console.log(`\\n Database Statistics (this project):`);\n console.log(\n ` Frames: ${totalStats.total_frames || 0} (${totalStats.active_frames || 0} active, ${totalStats.closed_frames || 0} closed)`\n );\n console.log(` Events: ${eventCount.count || 0}`);\n console.log(` Sessions: ${totalStats.total_sessions || 0}`);\n console.log(\n ` Cached contexts: ${contextCount.count || 0} (global)`\n );\n\n // Show recent activity\n const recentFrames = db\n .prepare(\n `\n SELECT name, type, state, datetime(created_at, 'unixepoch') as created\n FROM frames\n WHERE project_id = ?\n ORDER BY created_at DESC\n LIMIT 3\n `\n )\n .all(session.projectId) as Array<{\n name: string;\n type: string;\n state: string;\n created: string;\n }>;\n\n if (recentFrames.length > 0) {\n console.log(`\\n Recent Activity:`);\n recentFrames.forEach((f) => {\n const stateIcon = f.state === 'active' ? '\uD83D\uDFE2' : '\u26AB';\n console.log(\n ` ${stateIcon} ${f.name} [${f.type}] - ${f.created}`\n );\n });\n }\n\n console.log(`\\n Current Session:`);\n console.log(` Stack depth: ${stackDepth}`);\n console.log(` Active frames: ${activeFrames.length}`);\n\n if (activeFrames.length > 0) {\n activeFrames.forEach((frame, i) => {\n const indent = ' ' + ' '.repeat(frame.depth || i);\n const prefix = i === 0 ? '\u2514\u2500' : ' \u2514\u2500';\n console.log(`${indent}${prefix} ${frame.name} [${frame.type}]`);\n });\n }\n\n // Show other sessions if in default mode\n if (!options.all && !options.project) {\n const otherSessions = await sessionManager.listSessions({\n projectId: session.projectId,\n state: 'active',\n });\n\n const otherActive = otherSessions.filter(\n (s) => s.sessionId !== session.sessionId\n );\n if (otherActive.length > 0) {\n console.log(`\\n Other Active Sessions (same project):`);\n otherActive.forEach((s) => {\n const age = Math.round(\n (Date.now() - s.lastActiveAt) / 1000 / 60 / 60\n );\n console.log(\n ` - ${s.sessionId.slice(0, 8)}: ${s.branch || 'main'}, ${age}h old`\n );\n });\n console.log(`\\n Tip: Use --all to see frames across sessions`);\n }\n }\n\n db.close();\n } catch (error: unknown) {\n logger.error('Failed to get status', error as Error);\n console.error('\u274C Status check failed:', (error as Error).message);\n process.exit(1);\n }\n });\n });\n\nprogram\n .command('update-check')\n .description('Check for StackMemory updates')\n .action(async () => {\n try {\n console.log('\uD83D\uDD0D Checking for updates...');\n await UpdateChecker.forceCheck(VERSION);\n } catch (error: unknown) {\n logger.error('Update check failed', error as Error);\n console.error('\u274C Update check failed:', (error as Error).message);\n process.exit(1);\n }\n });\n\nprogram\n .command('progress')\n .description('Show current progress and recent changes')\n .action(async () => {\n try {\n const projectRoot = process.cwd();\n const dbPath = join(projectRoot, '.stackmemory', 'context.db');\n\n if (!existsSync(dbPath)) {\n console.log(\n '\u274C StackMemory not initialized. Run \"stackmemory init\" first.'\n );\n return;\n }\n\n const progress = new ProgressTracker(projectRoot);\n console.log(progress.getSummary());\n } catch (error: unknown) {\n logger.error('Failed to show progress', error as Error);\n console.error('\u274C Failed to show progress:', (error as Error).message);\n process.exit(1);\n }\n });\n\nprogram\n .command('mcp-server')\n .description('Start StackMemory MCP server for Claude Desktop')\n .option('-p, --project <path>', 'Project root directory', process.cwd())\n .action(async (options) => {\n try {\n const { runMCPServer } = await import('../integrations/mcp/server.js');\n\n // Set project root\n process.env['PROJECT_ROOT'] = options.project;\n\n console.log('\uD83D\uDE80 Starting StackMemory MCP Server...');\n console.log(` Project: ${options.project}`);\n console.log(` Version: ${VERSION}`);\n\n // Check for updates silently\n UpdateChecker.checkForUpdates(VERSION, true).catch(() => {});\n\n // Start the MCP server\n await runMCPServer();\n } catch (error: unknown) {\n logger.error('Failed to start MCP server', error as Error);\n console.error('\u274C MCP server failed:', (error as Error).message);\n process.exit(1);\n }\n });\n\n// Add test context command\nprogram\n .command('context:test')\n .description('Test context persistence by creating sample frames')\n .action(async () => {\n try {\n const projectRoot = process.cwd();\n const dbPath = join(projectRoot, '.stackmemory', 'context.db');\n\n if (!existsSync(dbPath)) {\n console.log(\n '\u274C StackMemory not initialized. Run \"stackmemory init\" first.'\n );\n return;\n }\n\n const db = new Database(dbPath);\n const frameManager = new FrameManager(db, 'cli-project');\n\n // Create test frames\n console.log('\uD83D\uDCDD Creating test context frames...');\n\n const rootFrame = frameManager.createFrame({\n type: 'task',\n name: 'Test Session',\n inputs: { test: true, timestamp: new Date().toISOString() },\n });\n\n const taskFrame = frameManager.createFrame({\n type: 'subtask',\n name: 'Sample Task',\n inputs: { description: 'Testing context persistence' },\n parentFrameId: rootFrame,\n });\n\n const commandFrame = frameManager.createFrame({\n type: 'tool_scope',\n name: 'test-command',\n inputs: { args: ['--test'] },\n parentFrameId: taskFrame,\n });\n\n // Add some events\n frameManager.addEvent(\n 'observation',\n {\n message: 'Test event recorded',\n },\n commandFrame\n );\n\n console.log('\u2705 Test frames created!');\n console.log(`\uD83D\uDCCA Stack depth: ${frameManager.getStackDepth()}`);\n console.log(\n `\uD83D\uDD04 Active frames: ${frameManager.getActiveFramePath().length}`\n );\n\n // Close one frame to test state changes\n frameManager.closeFrame(commandFrame);\n console.log(\n `\uD83D\uDCCA After closing command frame: depth = ${frameManager.getStackDepth()}`\n );\n\n db.close();\n } catch (error: unknown) {\n logger.error('Test context failed', error as Error);\n console.error('\u274C Test failed:', (error as Error).message);\n process.exit(1);\n }\n });\n\n// Register project management commands\n// Register command modules\nregisterOnboardingCommand(program);\nregisterSignupCommand(program);\nregisterLoginCommand(program);\nregisterLogoutCommand(program);\nregisterDbCommands(program);\nregisterProjectCommands(program);\nregisterWorktreeCommands(program);\n\n// Register Linear integration commands\nregisterLinearCommands(program);\n\n// Register session management commands\nprogram.addCommand(createSessionCommands());\n\n// Register enhanced CLI commands\nprogram.addCommand(createTaskCommands());\nprogram.addCommand(createSearchCommand());\nprogram.addCommand(createLogCommand());\nprogram.addCommand(createContextCommands());\nprogram.addCommand(createConfigCommand());\nprogram.addCommand(createHandoffCommand());\nprogram.addCommand(createDecisionCommand());\nprogram.addCommand(createMemoryCommand());\nprogram.addCommand(createStorageCommand());\nprogram.addCommand(createSkillsCommand());\nprogram.addCommand(createTestCommand());\nprogram.addCommand(clearCommand);\nprogram.addCommand(createWorkflowCommand());\nprogram.addCommand(monitorCommand);\nprogram.addCommand(qualityCommand);\nprogram.addCommand(createRalphCommand());\nprogram.addCommand(serviceCommand);\nprogram.addCommand(createSweepCommand());\n\n// Register dashboard command\nprogram\n .command('dashboard')\n .description('Display monitoring dashboard in terminal')\n .option('-w, --watch', 'Auto-refresh dashboard')\n .option('-i, --interval <seconds>', 'Refresh interval in seconds', '5')\n .action(async (options) => {\n const { dashboardCommand } = await import('./commands/dashboard.js');\n await dashboardCommand.handler(options);\n });\n\n// Auto-detect current project on startup\nif (process.argv.length > 2) {\n const manager = ProjectManager.getInstance();\n manager.detectProject().catch(() => {\n // Silently fail if not in a project directory\n });\n}\n\n// Only parse when running as main module (not when imported for testing)\nconst isMainModule =\n import.meta.url === `file://${process.argv[1]}` ||\n process.argv[1]?.endsWith('/stackmemory') ||\n process.argv[1]?.endsWith('index.ts') ||\n process.argv[1]?.includes('tsx');\n\nif (isMainModule) {\n program.parse();\n}\n\nexport { program };\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { readFileSync } from "fs";
|
|
4
|
+
import { join, dirname } from "path";
|
|
5
|
+
import { fileURLToPath } from "url";
|
|
6
|
+
import Database from "better-sqlite3";
|
|
7
|
+
import { FrameManager } from "../core/context/frame-manager.js";
|
|
8
|
+
import { SessionManager } from "../core/session/session-manager.js";
|
|
9
|
+
import { pluginManager, loadPlugins } from "../plugins/loader.js";
|
|
10
|
+
import { logger } from "../core/monitoring/logger.js";
|
|
11
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
const packageJson = JSON.parse(
|
|
13
|
+
readFileSync(join(__dirname, "../../package.json"), "utf-8")
|
|
14
|
+
);
|
|
15
|
+
const program = new Command();
|
|
16
|
+
program.name("stackmemory").description("Git for AI context - persistent memory across sessions").version(packageJson.version);
|
|
17
|
+
program.command("init").description("Initialize StackMemory in current directory").action(async () => {
|
|
18
|
+
const sessionManager = SessionManager.getInstance();
|
|
19
|
+
await sessionManager.initialize();
|
|
20
|
+
const session = await sessionManager.getOrCreateSession();
|
|
21
|
+
console.log("\u2705 StackMemory initialized");
|
|
22
|
+
console.log(` Project: ${session.projectId}`);
|
|
23
|
+
console.log(` Session: ${session.sessionId.slice(0, 8)}`);
|
|
24
|
+
});
|
|
25
|
+
program.command("status").description("Show current context status").action(async () => {
|
|
26
|
+
const sessionManager = SessionManager.getInstance();
|
|
27
|
+
await sessionManager.initialize();
|
|
28
|
+
const session = await sessionManager.getOrCreateSession();
|
|
29
|
+
const dbPath = join(process.cwd(), ".stackmemory", "context.db");
|
|
30
|
+
const db = new Database(dbPath);
|
|
31
|
+
const frameManager = new FrameManager(db, session.projectId);
|
|
32
|
+
const activeFrames = frameManager.getActiveFramePath();
|
|
33
|
+
const depth = frameManager.getStackDepth();
|
|
34
|
+
console.log("\u{1F4CA} StackMemory Status:");
|
|
35
|
+
console.log(` Session: ${session.sessionId.slice(0, 8)}`);
|
|
36
|
+
console.log(` Stack depth: ${depth}`);
|
|
37
|
+
console.log(` Active frames: ${activeFrames.length}`);
|
|
38
|
+
if (activeFrames.length > 0) {
|
|
39
|
+
console.log("\n Current stack:");
|
|
40
|
+
activeFrames.slice(0, 5).forEach((frame, i) => {
|
|
41
|
+
console.log(` ${i + 1}. ${frame.name} [${frame.type}]`);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
program.command("save [message]").description("Save current context with optional message").action(async (message) => {
|
|
46
|
+
const sessionManager = SessionManager.getInstance();
|
|
47
|
+
await sessionManager.initialize();
|
|
48
|
+
const session = await sessionManager.getOrCreateSession();
|
|
49
|
+
const dbPath = join(process.cwd(), ".stackmemory", "context.db");
|
|
50
|
+
const db = new Database(dbPath);
|
|
51
|
+
const frameManager = new FrameManager(db, session.projectId);
|
|
52
|
+
const frame = await frameManager.createFrame({
|
|
53
|
+
type: "context",
|
|
54
|
+
name: message || "Manual save",
|
|
55
|
+
content: message || "",
|
|
56
|
+
metadata: {
|
|
57
|
+
savedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
58
|
+
manual: true
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
console.log("\u2705 Context saved");
|
|
62
|
+
console.log(` Frame ID: ${frame.frame_id.slice(0, 8)}`);
|
|
63
|
+
});
|
|
64
|
+
program.command("load [query]").description("Load context by search query").argument("[query]", "Search query for context").action(async (query) => {
|
|
65
|
+
const sessionManager = SessionManager.getInstance();
|
|
66
|
+
await sessionManager.initialize();
|
|
67
|
+
const dbPath = join(process.cwd(), ".stackmemory", "context.db");
|
|
68
|
+
const db = new Database(dbPath);
|
|
69
|
+
let whereClause = "";
|
|
70
|
+
const params = [];
|
|
71
|
+
if (query) {
|
|
72
|
+
whereClause = "WHERE name LIKE ? OR content LIKE ?";
|
|
73
|
+
params.push(`%${query}%`, `%${query}%`);
|
|
74
|
+
}
|
|
75
|
+
const frames = db.prepare(
|
|
76
|
+
`
|
|
77
|
+
SELECT frame_id, name, type, datetime(created_at, 'unixepoch') as created
|
|
78
|
+
FROM frames
|
|
79
|
+
${whereClause}
|
|
80
|
+
ORDER BY created_at DESC
|
|
81
|
+
LIMIT 10
|
|
82
|
+
`
|
|
83
|
+
).all(...params);
|
|
84
|
+
if (frames.length === 0) {
|
|
85
|
+
console.log("No matching context found");
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
console.log("\u{1F4DA} Found contexts:");
|
|
89
|
+
frames.forEach((f, i) => {
|
|
90
|
+
console.log(` ${i + 1}. ${f.name} [${f.type}] - ${f.created}`);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
program.command("sync").description("Sync context with remote storage").option("--push", "Push local changes to remote").option("--pull", "Pull remote changes to local").action(async (options) => {
|
|
94
|
+
console.log("\u{1F504} Sync functionality:");
|
|
95
|
+
if (options.push) {
|
|
96
|
+
console.log(" Pushing to remote storage...");
|
|
97
|
+
} else if (options.pull) {
|
|
98
|
+
console.log(" Pulling from remote storage...");
|
|
99
|
+
} else {
|
|
100
|
+
console.log(" Use --push or --pull to specify direction");
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
program.command("plugin <action> [name]").description("Manage plugins (list/enable/disable)").action(async (action, name) => {
|
|
104
|
+
if (action === "list") {
|
|
105
|
+
await loadPlugins();
|
|
106
|
+
const plugins = pluginManager.getAllPlugins();
|
|
107
|
+
console.log("\u{1F4E6} Available plugins:");
|
|
108
|
+
if (plugins.length === 0) {
|
|
109
|
+
console.log(" No plugins loaded");
|
|
110
|
+
console.log(
|
|
111
|
+
" Set ENABLE_LINEAR_PLUGIN=true to enable Linear integration"
|
|
112
|
+
);
|
|
113
|
+
} else {
|
|
114
|
+
plugins.forEach((p) => {
|
|
115
|
+
console.log(` - ${p.name} v${p.version}: ${p.description}`);
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
} else if (action === "enable" && name) {
|
|
119
|
+
console.log(`Enabling plugin: ${name}`);
|
|
120
|
+
} else if (action === "disable" && name) {
|
|
121
|
+
console.log(`Disabling plugin: ${name}`);
|
|
122
|
+
} else {
|
|
123
|
+
console.log("Usage: stackmemory plugin <list|enable|disable> [name]");
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
loadPlugins().then(() => {
|
|
127
|
+
const pluginCommands = pluginManager.getAllCommands();
|
|
128
|
+
for (const cmd of pluginCommands) {
|
|
129
|
+
const command = program.command(cmd.name).description(cmd.description).action(cmd.action);
|
|
130
|
+
if (cmd.options) {
|
|
131
|
+
for (const opt of cmd.options) {
|
|
132
|
+
command.option(opt.flag, opt.description, opt.defaultValue);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
program.parse(process.argv);
|
|
137
|
+
}).catch((error) => {
|
|
138
|
+
logger.error("Failed to load plugins", error);
|
|
139
|
+
program.parse(process.argv);
|
|
140
|
+
});
|
|
141
|
+
if (!process.argv.slice(2).length) {
|
|
142
|
+
program.outputHelp();
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=streamlined-cli.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/cli/streamlined-cli.ts"],
|
|
4
|
+
"sourcesContent": ["#!/usr/bin/env node\n/**\n * Streamlined StackMemory CLI\n * Essential commands only - focused on core functionality\n */\n\nimport { Command } from 'commander';\nimport { readFileSync } from 'fs';\nimport { join, dirname } from 'path';\nimport { fileURLToPath } from 'url';\nimport Database from 'better-sqlite3';\nimport { FrameManager } from '../core/context/frame-manager.js';\nimport { SessionManager } from '../core/session/session-manager.js';\nimport { pluginManager, loadPlugins } from '../plugins/loader.js';\nimport { logger } from '../core/monitoring/logger.js';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst packageJson = JSON.parse(\n readFileSync(join(__dirname, '../../package.json'), 'utf-8')\n);\n\nconst program = new Command();\n\nprogram\n .name('stackmemory')\n .description('Git for AI context - persistent memory across sessions')\n .version(packageJson.version);\n\n// 1. INIT - Setup StackMemory in a project\nprogram\n .command('init')\n .description('Initialize StackMemory in current directory')\n .action(async () => {\n const sessionManager = SessionManager.getInstance();\n await sessionManager.initialize();\n const session = await sessionManager.getOrCreateSession();\n console.log('\u2705 StackMemory initialized');\n console.log(` Project: ${session.projectId}`);\n console.log(` Session: ${session.sessionId.slice(0, 8)}`);\n });\n\n// 2. STATUS - Check current status\nprogram\n .command('status')\n .description('Show current context status')\n .action(async () => {\n const sessionManager = SessionManager.getInstance();\n await sessionManager.initialize();\n const session = await sessionManager.getOrCreateSession();\n\n const dbPath = join(process.cwd(), '.stackmemory', 'context.db');\n const db = new Database(dbPath);\n const frameManager = new FrameManager(db, session.projectId);\n\n const activeFrames = frameManager.getActiveFramePath();\n const depth = frameManager.getStackDepth();\n\n console.log('\uD83D\uDCCA StackMemory Status:');\n console.log(` Session: ${session.sessionId.slice(0, 8)}`);\n console.log(` Stack depth: ${depth}`);\n console.log(` Active frames: ${activeFrames.length}`);\n\n if (activeFrames.length > 0) {\n console.log('\\n Current stack:');\n activeFrames.slice(0, 5).forEach((frame, i) => {\n console.log(` ${i + 1}. ${frame.name} [${frame.type}]`);\n });\n }\n });\n\n// 3. SAVE - Save current context\nprogram\n .command('save [message]')\n .description('Save current context with optional message')\n .action(async (message) => {\n const sessionManager = SessionManager.getInstance();\n await sessionManager.initialize();\n const session = await sessionManager.getOrCreateSession();\n\n const dbPath = join(process.cwd(), '.stackmemory', 'context.db');\n const db = new Database(dbPath);\n const frameManager = new FrameManager(db, session.projectId);\n\n const frame = await frameManager.createFrame({\n type: 'context',\n name: message || 'Manual save',\n content: message || '',\n metadata: {\n savedAt: new Date().toISOString(),\n manual: true,\n },\n });\n\n console.log('\u2705 Context saved');\n console.log(` Frame ID: ${frame.frame_id.slice(0, 8)}`);\n });\n\n// 4. LOAD - Load context by query\nprogram\n .command('load [query]')\n .description('Load context by search query')\n .argument('[query]', 'Search query for context')\n .action(async (query) => {\n const sessionManager = SessionManager.getInstance();\n await sessionManager.initialize();\n\n const dbPath = join(process.cwd(), '.stackmemory', 'context.db');\n const db = new Database(dbPath);\n\n let whereClause = '';\n const params: any[] = [];\n\n if (query) {\n whereClause = 'WHERE name LIKE ? OR content LIKE ?';\n params.push(`%${query}%`, `%${query}%`);\n }\n\n const frames = db\n .prepare(\n `\n SELECT frame_id, name, type, datetime(created_at, 'unixepoch') as created\n FROM frames\n ${whereClause}\n ORDER BY created_at DESC\n LIMIT 10\n `\n )\n .all(...params);\n\n if (frames.length === 0) {\n console.log('No matching context found');\n return;\n }\n\n console.log('\uD83D\uDCDA Found contexts:');\n frames.forEach((f: any, i: number) => {\n console.log(` ${i + 1}. ${f.name} [${f.type}] - ${f.created}`);\n });\n });\n\n// 5. SYNC - Sync with remote storage (if configured)\nprogram\n .command('sync')\n .description('Sync context with remote storage')\n .option('--push', 'Push local changes to remote')\n .option('--pull', 'Pull remote changes to local')\n .action(async (options) => {\n // This would integrate with the simplified storage\n console.log('\uD83D\uDD04 Sync functionality:');\n if (options.push) {\n console.log(' Pushing to remote storage...');\n // Implement push to S3/compatible storage\n } else if (options.pull) {\n console.log(' Pulling from remote storage...');\n // Implement pull from S3/compatible storage\n } else {\n console.log(' Use --push or --pull to specify direction');\n }\n });\n\n// 6. PLUGIN - Manage plugins\nprogram\n .command('plugin <action> [name]')\n .description('Manage plugins (list/enable/disable)')\n .action(async (action, name) => {\n if (action === 'list') {\n await loadPlugins();\n const plugins = pluginManager.getAllPlugins();\n\n console.log('\uD83D\uDCE6 Available plugins:');\n if (plugins.length === 0) {\n console.log(' No plugins loaded');\n console.log(\n ' Set ENABLE_LINEAR_PLUGIN=true to enable Linear integration'\n );\n } else {\n plugins.forEach((p) => {\n console.log(` - ${p.name} v${p.version}: ${p.description}`);\n });\n }\n } else if (action === 'enable' && name) {\n console.log(`Enabling plugin: ${name}`);\n // Would update plugins.json\n } else if (action === 'disable' && name) {\n console.log(`Disabling plugin: ${name}`);\n // Would update plugins.json\n } else {\n console.log('Usage: stackmemory plugin <list|enable|disable> [name]');\n }\n });\n\n// Load plugin commands dynamically\nloadPlugins()\n .then(() => {\n const pluginCommands = pluginManager.getAllCommands();\n\n // Register each plugin command\n for (const cmd of pluginCommands) {\n const command = program\n .command(cmd.name)\n .description(cmd.description)\n .action(cmd.action);\n\n // Add options if specified\n if (cmd.options) {\n for (const opt of cmd.options) {\n command.option(opt.flag, opt.description, opt.defaultValue);\n }\n }\n }\n\n // Parse arguments after plugins are loaded\n program.parse(process.argv);\n })\n .catch((error) => {\n logger.error('Failed to load plugins', error);\n program.parse(process.argv);\n });\n\n// Show help if no command provided\nif (!process.argv.slice(2).length) {\n program.outputHelp();\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
import { homedir } from "os";
|
|
4
|
+
const DEFAULT_STORAGE_CONFIG = {
|
|
5
|
+
mode: "sqlite",
|
|
6
|
+
chromadb: {
|
|
7
|
+
enabled: false
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
const STACKMEMORY_DIR = join(homedir(), ".stackmemory");
|
|
11
|
+
const CONFIG_FILE = join(STACKMEMORY_DIR, "storage-config.json");
|
|
12
|
+
function loadStorageConfig() {
|
|
13
|
+
try {
|
|
14
|
+
if (existsSync(CONFIG_FILE)) {
|
|
15
|
+
const content = readFileSync(CONFIG_FILE, "utf-8");
|
|
16
|
+
const config = JSON.parse(content);
|
|
17
|
+
return {
|
|
18
|
+
mode: config.mode || DEFAULT_STORAGE_CONFIG.mode,
|
|
19
|
+
chromadb: {
|
|
20
|
+
...DEFAULT_STORAGE_CONFIG.chromadb,
|
|
21
|
+
...config.chromadb
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
} catch (error) {
|
|
26
|
+
console.warn("Failed to load storage config, using defaults:", error);
|
|
27
|
+
}
|
|
28
|
+
return DEFAULT_STORAGE_CONFIG;
|
|
29
|
+
}
|
|
30
|
+
function saveStorageConfig(config) {
|
|
31
|
+
try {
|
|
32
|
+
if (!existsSync(STACKMEMORY_DIR)) {
|
|
33
|
+
mkdirSync(STACKMEMORY_DIR, { recursive: true });
|
|
34
|
+
}
|
|
35
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), "utf-8");
|
|
36
|
+
} catch (error) {
|
|
37
|
+
console.error("Failed to save storage config:", error);
|
|
38
|
+
throw error;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function isChromaDBEnabled() {
|
|
42
|
+
const config = loadStorageConfig();
|
|
43
|
+
if (!config.chromadb.enabled) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
const apiKey = config.chromadb.apiKey || process.env["CHROMADB_API_KEY"];
|
|
47
|
+
if (!apiKey) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
function getStorageMode() {
|
|
53
|
+
const config = loadStorageConfig();
|
|
54
|
+
if (config.mode === "hybrid" && !isChromaDBEnabled()) {
|
|
55
|
+
return "sqlite";
|
|
56
|
+
}
|
|
57
|
+
return config.mode;
|
|
58
|
+
}
|
|
59
|
+
function getChromaDBConfig() {
|
|
60
|
+
if (!isChromaDBEnabled()) {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
const config = loadStorageConfig();
|
|
64
|
+
const apiKey = config.chromadb.apiKey || process.env["CHROMADB_API_KEY"];
|
|
65
|
+
const apiUrl = config.chromadb.apiUrl || process.env["CHROMADB_API_URL"] || "https://api.trychroma.com";
|
|
66
|
+
return {
|
|
67
|
+
enabled: true,
|
|
68
|
+
apiKey,
|
|
69
|
+
apiUrl,
|
|
70
|
+
tenant: config.chromadb.tenant || process.env["CHROMADB_TENANT"] || "default_tenant",
|
|
71
|
+
database: config.chromadb.database || process.env["CHROMADB_DATABASE"] || "default_database"
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function enableChromaDB(chromaConfig) {
|
|
75
|
+
const config = loadStorageConfig();
|
|
76
|
+
config.mode = "hybrid";
|
|
77
|
+
config.chromadb = {
|
|
78
|
+
enabled: true,
|
|
79
|
+
apiKey: chromaConfig.apiKey,
|
|
80
|
+
apiUrl: chromaConfig.apiUrl || "https://api.trychroma.com",
|
|
81
|
+
tenant: chromaConfig.tenant || "default_tenant",
|
|
82
|
+
database: chromaConfig.database || "default_database"
|
|
83
|
+
};
|
|
84
|
+
saveStorageConfig(config);
|
|
85
|
+
}
|
|
86
|
+
function disableChromaDB() {
|
|
87
|
+
const config = loadStorageConfig();
|
|
88
|
+
config.mode = "sqlite";
|
|
89
|
+
config.chromadb = {
|
|
90
|
+
enabled: false
|
|
91
|
+
};
|
|
92
|
+
saveStorageConfig(config);
|
|
93
|
+
}
|
|
94
|
+
function getStorageModeDescription() {
|
|
95
|
+
const mode = getStorageMode();
|
|
96
|
+
if (mode === "hybrid") {
|
|
97
|
+
return "Hybrid (SQLite + ChromaDB for semantic search and cloud backup)";
|
|
98
|
+
}
|
|
99
|
+
return "SQLite (local storage only, fast, no external dependencies)";
|
|
100
|
+
}
|
|
101
|
+
export {
|
|
102
|
+
disableChromaDB,
|
|
103
|
+
enableChromaDB,
|
|
104
|
+
getChromaDBConfig,
|
|
105
|
+
getStorageMode,
|
|
106
|
+
getStorageModeDescription,
|
|
107
|
+
isChromaDBEnabled,
|
|
108
|
+
loadStorageConfig,
|
|
109
|
+
saveStorageConfig
|
|
110
|
+
};
|
|
111
|
+
//# sourceMappingURL=storage-config.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/core/config/storage-config.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Storage Configuration for StackMemory\n * Handles storage mode detection and ChromaDB configuration\n */\n\nimport { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';\nimport { join } from 'path';\nimport { homedir } from 'os';\n\nexport type StorageMode = 'sqlite' | 'hybrid';\n\nexport interface ChromaDBConfig {\n enabled: boolean;\n apiKey?: string;\n apiUrl?: string;\n tenant?: string;\n database?: string;\n}\n\nexport interface StorageConfig {\n mode: StorageMode;\n chromadb: ChromaDBConfig;\n}\n\nconst DEFAULT_STORAGE_CONFIG: StorageConfig = {\n mode: 'sqlite',\n chromadb: {\n enabled: false,\n },\n};\n\nconst STACKMEMORY_DIR = join(homedir(), '.stackmemory');\nconst CONFIG_FILE = join(STACKMEMORY_DIR, 'storage-config.json');\n\n/**\n * Load storage configuration from disk\n */\nexport function loadStorageConfig(): StorageConfig {\n try {\n if (existsSync(CONFIG_FILE)) {\n const content = readFileSync(CONFIG_FILE, 'utf-8');\n const config = JSON.parse(content) as Partial<StorageConfig>;\n return {\n mode: config.mode || DEFAULT_STORAGE_CONFIG.mode,\n chromadb: {\n ...DEFAULT_STORAGE_CONFIG.chromadb,\n ...config.chromadb,\n },\n };\n }\n } catch (error) {\n console.warn('Failed to load storage config, using defaults:', error);\n }\n return DEFAULT_STORAGE_CONFIG;\n}\n\n/**\n * Save storage configuration to disk\n */\nexport function saveStorageConfig(config: StorageConfig): void {\n try {\n if (!existsSync(STACKMEMORY_DIR)) {\n mkdirSync(STACKMEMORY_DIR, { recursive: true });\n }\n writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), 'utf-8');\n } catch (error) {\n console.error('Failed to save storage config:', error);\n throw error;\n }\n}\n\n/**\n * Check if ChromaDB is enabled and properly configured\n */\nexport function isChromaDBEnabled(): boolean {\n const config = loadStorageConfig();\n\n if (!config.chromadb.enabled) {\n return false;\n }\n\n // ChromaDB requires an API key to be configured\n const apiKey = config.chromadb.apiKey || process.env['CHROMADB_API_KEY'];\n if (!apiKey) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Get the current storage mode\n * Returns 'sqlite' for local-only storage\n * Returns 'hybrid' when ChromaDB is enabled (SQLite + ChromaDB)\n */\nexport function getStorageMode(): StorageMode {\n const config = loadStorageConfig();\n\n // Verify ChromaDB is actually usable before returning hybrid\n if (config.mode === 'hybrid' && !isChromaDBEnabled()) {\n return 'sqlite';\n }\n\n return config.mode;\n}\n\n/**\n * Get ChromaDB configuration (for use when initializing ChromaDB adapter)\n */\nexport function getChromaDBConfig(): ChromaDBConfig | null {\n if (!isChromaDBEnabled()) {\n return null;\n }\n\n const config = loadStorageConfig();\n const apiKey = config.chromadb.apiKey || process.env['CHROMADB_API_KEY'];\n const apiUrl =\n config.chromadb.apiUrl ||\n process.env['CHROMADB_API_URL'] ||\n 'https://api.trychroma.com';\n\n return {\n enabled: true,\n apiKey,\n apiUrl,\n tenant:\n config.chromadb.tenant ||\n process.env['CHROMADB_TENANT'] ||\n 'default_tenant',\n database:\n config.chromadb.database ||\n process.env['CHROMADB_DATABASE'] ||\n 'default_database',\n };\n}\n\n/**\n * Enable ChromaDB with the given configuration\n */\nexport function enableChromaDB(chromaConfig: {\n apiKey: string;\n apiUrl?: string;\n tenant?: string;\n database?: string;\n}): void {\n const config = loadStorageConfig();\n config.mode = 'hybrid';\n config.chromadb = {\n enabled: true,\n apiKey: chromaConfig.apiKey,\n apiUrl: chromaConfig.apiUrl || 'https://api.trychroma.com',\n tenant: chromaConfig.tenant || 'default_tenant',\n database: chromaConfig.database || 'default_database',\n };\n saveStorageConfig(config);\n}\n\n/**\n * Disable ChromaDB and use SQLite-only mode\n */\nexport function disableChromaDB(): void {\n const config = loadStorageConfig();\n config.mode = 'sqlite';\n config.chromadb = {\n enabled: false,\n };\n saveStorageConfig(config);\n}\n\n/**\n * Get a human-readable description of the current storage mode\n */\nexport function getStorageModeDescription(): string {\n const mode = getStorageMode();\n if (mode === 'hybrid') {\n return 'Hybrid (SQLite + ChromaDB for semantic search and cloud backup)';\n }\n return 'SQLite (local storage only, fast, no external dependencies)';\n}\n"],
|
|
5
|
+
"mappings": "AAKA,SAAS,YAAY,cAAc,eAAe,iBAAiB;AACnE,SAAS,YAAY;AACrB,SAAS,eAAe;AAiBxB,MAAM,yBAAwC;AAAA,EAC5C,MAAM;AAAA,EACN,UAAU;AAAA,IACR,SAAS;AAAA,EACX;AACF;AAEA,MAAM,kBAAkB,KAAK,QAAQ,GAAG,cAAc;AACtD,MAAM,cAAc,KAAK,iBAAiB,qBAAqB;AAKxD,SAAS,oBAAmC;AACjD,MAAI;AACF,QAAI,WAAW,WAAW,GAAG;AAC3B,YAAM,UAAU,aAAa,aAAa,OAAO;AACjD,YAAM,SAAS,KAAK,MAAM,OAAO;AACjC,aAAO;AAAA,QACL,MAAM,OAAO,QAAQ,uBAAuB;AAAA,QAC5C,UAAU;AAAA,UACR,GAAG,uBAAuB;AAAA,UAC1B,GAAG,OAAO;AAAA,QACZ;AAAA,MACF;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,YAAQ,KAAK,kDAAkD,KAAK;AAAA,EACtE;AACA,SAAO;AACT;AAKO,SAAS,kBAAkB,QAA6B;AAC7D,MAAI;AACF,QAAI,CAAC,WAAW,eAAe,GAAG;AAChC,gBAAU,iBAAiB,EAAE,WAAW,KAAK,CAAC;AAAA,IAChD;AACA,kBAAc,aAAa,KAAK,UAAU,QAAQ,MAAM,CAAC,GAAG,OAAO;AAAA,EACrE,SAAS,OAAO;AACd,YAAQ,MAAM,kCAAkC,KAAK;AACrD,UAAM;AAAA,EACR;AACF;AAKO,SAAS,oBAA6B;AAC3C,QAAM,SAAS,kBAAkB;AAEjC,MAAI,CAAC,OAAO,SAAS,SAAS;AAC5B,WAAO;AAAA,EACT;AAGA,QAAM,SAAS,OAAO,SAAS,UAAU,QAAQ,IAAI,kBAAkB;AACvE,MAAI,CAAC,QAAQ;AACX,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAOO,SAAS,iBAA8B;AAC5C,QAAM,SAAS,kBAAkB;AAGjC,MAAI,OAAO,SAAS,YAAY,CAAC,kBAAkB,GAAG;AACpD,WAAO;AAAA,EACT;AAEA,SAAO,OAAO;AAChB;AAKO,SAAS,oBAA2C;AACzD,MAAI,CAAC,kBAAkB,GAAG;AACxB,WAAO;AAAA,EACT;AAEA,QAAM,SAAS,kBAAkB;AACjC,QAAM,SAAS,OAAO,SAAS,UAAU,QAAQ,IAAI,kBAAkB;AACvE,QAAM,SACJ,OAAO,SAAS,UAChB,QAAQ,IAAI,kBAAkB,KAC9B;AAEF,SAAO;AAAA,IACL,SAAS;AAAA,IACT;AAAA,IACA;AAAA,IACA,QACE,OAAO,SAAS,UAChB,QAAQ,IAAI,iBAAiB,KAC7B;AAAA,IACF,UACE,OAAO,SAAS,YAChB,QAAQ,IAAI,mBAAmB,KAC/B;AAAA,EACJ;AACF;AAKO,SAAS,eAAe,cAKtB;AACP,QAAM,SAAS,kBAAkB;AACjC,SAAO,OAAO;AACd,SAAO,WAAW;AAAA,IAChB,SAAS;AAAA,IACT,QAAQ,aAAa;AAAA,IACrB,QAAQ,aAAa,UAAU;AAAA,IAC/B,QAAQ,aAAa,UAAU;AAAA,IAC/B,UAAU,aAAa,YAAY;AAAA,EACrC;AACA,oBAAkB,MAAM;AAC1B;AAKO,SAAS,kBAAwB;AACtC,QAAM,SAAS,kBAAkB;AACjC,SAAO,OAAO;AACd,SAAO,WAAW;AAAA,IAChB,SAAS;AAAA,EACX;AACA,oBAAkB,MAAM;AAC1B;AAKO,SAAS,4BAAoC;AAClD,QAAM,OAAO,eAAe;AAC5B,MAAI,SAAS,UAAU;AACrB,WAAO;AAAA,EACT;AACA,SAAO;AACT;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
class SimpleEventBus {
|
|
2
|
+
handlers = /* @__PURE__ */ new Map();
|
|
3
|
+
eventHistory = [];
|
|
4
|
+
maxHistorySize = 1e3;
|
|
5
|
+
subscriptionCounter = 0;
|
|
6
|
+
emit(event) {
|
|
7
|
+
const fullEvent = {
|
|
8
|
+
...event,
|
|
9
|
+
id: this.generateEventId(),
|
|
10
|
+
timestamp: Date.now()
|
|
11
|
+
};
|
|
12
|
+
this.eventHistory.push(fullEvent);
|
|
13
|
+
if (this.eventHistory.length > this.maxHistorySize) {
|
|
14
|
+
this.eventHistory.shift();
|
|
15
|
+
}
|
|
16
|
+
const handlers = this.handlers.get(event.type);
|
|
17
|
+
if (handlers) {
|
|
18
|
+
const handlersCopy = Array.from(handlers);
|
|
19
|
+
for (const handler of handlersCopy) {
|
|
20
|
+
try {
|
|
21
|
+
const result = handler(fullEvent);
|
|
22
|
+
if (result instanceof Promise) {
|
|
23
|
+
result.catch((error) => {
|
|
24
|
+
console.error(`Event handler error for ${event.type}:`, error);
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
} catch (error) {
|
|
28
|
+
console.error(`Event handler error for ${event.type}:`, error);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
on(eventType, handler) {
|
|
34
|
+
if (!this.handlers.has(eventType)) {
|
|
35
|
+
this.handlers.set(eventType, /* @__PURE__ */ new Set());
|
|
36
|
+
}
|
|
37
|
+
this.handlers.get(eventType).add(handler);
|
|
38
|
+
const subscriptionId = `sub-${++this.subscriptionCounter}`;
|
|
39
|
+
return {
|
|
40
|
+
id: subscriptionId,
|
|
41
|
+
unsubscribe: () => this.off(eventType, handler)
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
once(eventType, handler) {
|
|
45
|
+
const wrapper = (event) => {
|
|
46
|
+
handler(event);
|
|
47
|
+
this.off(eventType, wrapper);
|
|
48
|
+
};
|
|
49
|
+
return this.on(eventType, wrapper);
|
|
50
|
+
}
|
|
51
|
+
off(eventType, handler) {
|
|
52
|
+
this.handlers.get(eventType)?.delete(handler);
|
|
53
|
+
}
|
|
54
|
+
offAll(eventType) {
|
|
55
|
+
if (eventType) {
|
|
56
|
+
this.handlers.delete(eventType);
|
|
57
|
+
} else {
|
|
58
|
+
this.handlers.clear();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
async waitFor(eventType, timeout = 3e4) {
|
|
62
|
+
return new Promise((resolve, reject) => {
|
|
63
|
+
const timer = setTimeout(() => {
|
|
64
|
+
reject(new Error(`Timeout waiting for event: ${eventType}`));
|
|
65
|
+
}, timeout);
|
|
66
|
+
const subscription = this.once(eventType, (event) => {
|
|
67
|
+
clearTimeout(timer);
|
|
68
|
+
resolve(event);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
generateEventId() {
|
|
73
|
+
return `evt-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
74
|
+
}
|
|
75
|
+
getHistory(eventType, limit = 100) {
|
|
76
|
+
let events = this.eventHistory;
|
|
77
|
+
if (eventType) {
|
|
78
|
+
events = events.filter((e) => e.type === eventType);
|
|
79
|
+
}
|
|
80
|
+
return events.slice(-limit);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
const globalEventBus = new SimpleEventBus();
|
|
84
|
+
const EventTypes = {
|
|
85
|
+
// Ralph Loop events
|
|
86
|
+
RALPH_ITERATION_START: "ralph.iteration.start",
|
|
87
|
+
RALPH_ITERATION_COMPLETE: "ralph.iteration.complete",
|
|
88
|
+
RALPH_ITERATION_FAILED: "ralph.iteration.failed",
|
|
89
|
+
RALPH_LOOP_COMPLETE: "ralph.loop.complete",
|
|
90
|
+
// Swarm events
|
|
91
|
+
SWARM_AGENT_STARTED: "swarm.agent.started",
|
|
92
|
+
SWARM_AGENT_STOPPED: "swarm.agent.stopped",
|
|
93
|
+
SWARM_TASK_ASSIGNED: "swarm.task.assigned",
|
|
94
|
+
SWARM_TASK_COMPLETE: "swarm.task.complete",
|
|
95
|
+
SWARM_CONFLICT_DETECTED: "swarm.conflict.detected",
|
|
96
|
+
// Context events
|
|
97
|
+
CONTEXT_SAVED: "context.saved",
|
|
98
|
+
CONTEXT_LOADED: "context.loaded",
|
|
99
|
+
CONTEXT_SYNCED: "context.synced",
|
|
100
|
+
// Git events
|
|
101
|
+
GIT_COMMIT_CREATED: "git.commit.created",
|
|
102
|
+
GIT_BRANCH_CREATED: "git.branch.created",
|
|
103
|
+
GIT_MERGE_COMPLETE: "git.merge.complete"
|
|
104
|
+
};
|
|
105
|
+
export {
|
|
106
|
+
EventTypes,
|
|
107
|
+
SimpleEventBus,
|
|
108
|
+
globalEventBus
|
|
109
|
+
};
|
|
110
|
+
//# sourceMappingURL=event-bus.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/core/events/event-bus.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Event Bus - Core event-driven communication system\n * Decouples components through publish/subscribe pattern\n */\n\nexport interface Event {\n id: string;\n type: string;\n timestamp: number;\n source: string;\n data: Record<string, any>;\n metadata?: Record<string, any>;\n}\n\nexport type EventHandler = (event: Event) => void | Promise<void>;\n\nexport interface EventSubscription {\n id: string;\n unsubscribe(): void;\n}\n\nexport interface EventBus {\n emit(event: Omit<Event, 'id' | 'timestamp'>): void;\n on(eventType: string, handler: EventHandler): EventSubscription;\n once(eventType: string, handler: EventHandler): EventSubscription;\n off(eventType: string, handler: EventHandler): void;\n offAll(eventType?: string): void;\n waitFor(eventType: string, timeout?: number): Promise<Event>;\n}\n\nexport class SimpleEventBus implements EventBus {\n private handlers = new Map<string, Set<EventHandler>>();\n private eventHistory: Event[] = [];\n private maxHistorySize = 1000;\n private subscriptionCounter = 0;\n\n emit(event: Omit<Event, 'id' | 'timestamp'>): void {\n const fullEvent: Event = {\n ...event,\n id: this.generateEventId(),\n timestamp: Date.now()\n };\n\n // Store in history\n this.eventHistory.push(fullEvent);\n if (this.eventHistory.length > this.maxHistorySize) {\n this.eventHistory.shift();\n }\n\n // Notify handlers\n const handlers = this.handlers.get(event.type);\n if (handlers) {\n // Clone to avoid modification during iteration\n const handlersCopy = Array.from(handlers);\n for (const handler of handlersCopy) {\n try {\n const result = handler(fullEvent);\n if (result instanceof Promise) {\n result.catch(error => {\n console.error(`Event handler error for ${event.type}:`, error);\n });\n }\n } catch (error) {\n console.error(`Event handler error for ${event.type}:`, error);\n }\n }\n }\n }\n\n on(eventType: string, handler: EventHandler): EventSubscription {\n if (!this.handlers.has(eventType)) {\n this.handlers.set(eventType, new Set());\n }\n this.handlers.get(eventType)!.add(handler);\n\n const subscriptionId = `sub-${++this.subscriptionCounter}`;\n return {\n id: subscriptionId,\n unsubscribe: () => this.off(eventType, handler)\n };\n }\n\n once(eventType: string, handler: EventHandler): EventSubscription {\n const wrapper: EventHandler = (event) => {\n handler(event);\n this.off(eventType, wrapper);\n };\n return this.on(eventType, wrapper);\n }\n\n off(eventType: string, handler: EventHandler): void {\n this.handlers.get(eventType)?.delete(handler);\n }\n\n offAll(eventType?: string): void {\n if (eventType) {\n this.handlers.delete(eventType);\n } else {\n this.handlers.clear();\n }\n }\n\n async waitFor(eventType: string, timeout = 30000): Promise<Event> {\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n reject(new Error(`Timeout waiting for event: ${eventType}`));\n }, timeout);\n\n const subscription = this.once(eventType, (event) => {\n clearTimeout(timer);\n resolve(event);\n });\n });\n }\n\n private generateEventId(): string {\n return `evt-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n }\n\n getHistory(eventType?: string, limit = 100): Event[] {\n let events = this.eventHistory;\n if (eventType) {\n events = events.filter(e => e.type === eventType);\n }\n return events.slice(-limit);\n }\n}\n\n// Global event bus instance\nexport const globalEventBus = new SimpleEventBus();\n\n// Event types\nexport const EventTypes = {\n // Ralph Loop events\n RALPH_ITERATION_START: 'ralph.iteration.start',\n RALPH_ITERATION_COMPLETE: 'ralph.iteration.complete',\n RALPH_ITERATION_FAILED: 'ralph.iteration.failed',\n RALPH_LOOP_COMPLETE: 'ralph.loop.complete',\n\n // Swarm events\n SWARM_AGENT_STARTED: 'swarm.agent.started',\n SWARM_AGENT_STOPPED: 'swarm.agent.stopped',\n SWARM_TASK_ASSIGNED: 'swarm.task.assigned',\n SWARM_TASK_COMPLETE: 'swarm.task.complete',\n SWARM_CONFLICT_DETECTED: 'swarm.conflict.detected',\n\n // Context events\n CONTEXT_SAVED: 'context.saved',\n CONTEXT_LOADED: 'context.loaded',\n CONTEXT_SYNCED: 'context.synced',\n\n // Git events\n GIT_COMMIT_CREATED: 'git.commit.created',\n GIT_BRANCH_CREATED: 'git.branch.created',\n GIT_MERGE_COMPLETE: 'git.merge.complete'\n} as const;"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|