@stackmemoryai/stackmemory 0.5.31 → 0.5.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/claude-sm.js +199 -16
- package/dist/cli/claude-sm.js.map +2 -2
- package/dist/cli/commands/context.js +0 -11
- package/dist/cli/commands/context.js.map +2 -2
- package/dist/cli/commands/linear.js +1 -14
- package/dist/cli/commands/linear.js.map +2 -2
- package/dist/cli/commands/login.js +32 -10
- package/dist/cli/commands/login.js.map +2 -2
- package/dist/cli/commands/migrate.js +80 -22
- package/dist/cli/commands/migrate.js.map +2 -2
- package/dist/cli/commands/model.js +533 -0
- package/dist/cli/commands/model.js.map +7 -0
- package/dist/cli/commands/ralph.js +93 -28
- package/dist/cli/commands/ralph.js.map +2 -2
- package/dist/cli/commands/service.js +10 -3
- package/dist/cli/commands/service.js.map +2 -2
- package/dist/cli/commands/skills.js +60 -10
- package/dist/cli/commands/skills.js.map +2 -2
- package/dist/cli/commands/sms-notify.js +342 -22
- package/dist/cli/commands/sms-notify.js.map +3 -3
- package/dist/cli/index.js +2 -0
- package/dist/cli/index.js.map +2 -2
- package/dist/core/context/dual-stack-manager.js +23 -7
- package/dist/core/context/dual-stack-manager.js.map +2 -2
- package/dist/core/context/frame-database.js +33 -5
- package/dist/core/context/frame-database.js.map +2 -2
- package/dist/core/context/frame-digest.js +6 -1
- package/dist/core/context/frame-digest.js.map +2 -2
- package/dist/core/context/frame-manager.js +56 -9
- package/dist/core/context/frame-manager.js.map +2 -2
- package/dist/core/context/permission-manager.js +0 -11
- package/dist/core/context/permission-manager.js.map +2 -2
- package/dist/core/context/recursive-context-manager.js +15 -9
- package/dist/core/context/recursive-context-manager.js.map +2 -2
- package/dist/core/context/shared-context-layer.js +0 -11
- package/dist/core/context/shared-context-layer.js.map +2 -2
- package/dist/core/context/validation.js +6 -1
- package/dist/core/context/validation.js.map +2 -2
- package/dist/core/models/fallback-monitor.js +229 -0
- package/dist/core/models/fallback-monitor.js.map +7 -0
- package/dist/core/models/model-router.js +331 -0
- package/dist/core/models/model-router.js.map +7 -0
- package/dist/hooks/claude-code-whatsapp-hook.js +197 -0
- package/dist/hooks/claude-code-whatsapp-hook.js.map +7 -0
- package/dist/hooks/linear-task-picker.js +1 -1
- package/dist/hooks/linear-task-picker.js.map +2 -2
- package/dist/hooks/schemas.js +55 -1
- package/dist/hooks/schemas.js.map +2 -2
- package/dist/hooks/session-summary.js +5 -1
- package/dist/hooks/session-summary.js.map +2 -2
- package/dist/hooks/sms-action-runner.js +12 -1
- package/dist/hooks/sms-action-runner.js.map +2 -2
- package/dist/hooks/sms-notify.js +4 -2
- package/dist/hooks/sms-notify.js.map +2 -2
- package/dist/hooks/sms-webhook.js +23 -2
- package/dist/hooks/sms-webhook.js.map +2 -2
- package/dist/hooks/whatsapp-commands.js +376 -0
- package/dist/hooks/whatsapp-commands.js.map +7 -0
- package/dist/hooks/whatsapp-scheduler.js +317 -0
- package/dist/hooks/whatsapp-scheduler.js.map +7 -0
- package/dist/hooks/whatsapp-sync.js +375 -0
- package/dist/hooks/whatsapp-sync.js.map +7 -0
- package/package.json +2 -3
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/core/context/frame-database.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Frame Database Operations\n * Handles all database interactions for frames, events, and anchors\n */\n\nimport Database from 'better-sqlite3';\nimport { Frame, Event, Anchor } from './frame-types.js';\nimport { logger } from '../monitoring/logger.js';\nimport { DatabaseError, ErrorCode } from '../errors/index.js';\n\nexport class FrameDatabase {\n constructor(private db: Database.Database) {}\n\n /**\n * Initialize database schema\n */\n initSchema(): void {\n try {\n // Enable WAL mode for better concurrency\n this.db.pragma('journal_mode = WAL');\n this.db.pragma('synchronous = NORMAL');\n // Enforce referential integrity\n this.db.pragma('foreign_keys = ON');\n\n // Create frames table\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS frames (\n frame_id TEXT PRIMARY KEY,\n run_id TEXT NOT NULL,\n project_id TEXT NOT NULL,\n parent_frame_id TEXT,\n depth INTEGER NOT NULL DEFAULT 0,\n type TEXT NOT NULL,\n name TEXT NOT NULL,\n state TEXT NOT NULL DEFAULT 'active',\n inputs TEXT DEFAULT '{}',\n outputs TEXT DEFAULT '{}',\n digest_text TEXT,\n digest_json TEXT DEFAULT '{}',\n created_at INTEGER NOT NULL DEFAULT (unixepoch()),\n closed_at INTEGER,\n FOREIGN KEY (parent_frame_id) REFERENCES frames(frame_id)\n );\n `);\n\n // Create events table\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS events (\n event_id TEXT PRIMARY KEY,\n frame_id TEXT NOT NULL,\n run_id TEXT NOT NULL,\n seq INTEGER NOT NULL,\n event_type TEXT NOT NULL,\n payload TEXT NOT NULL DEFAULT '{}',\n ts INTEGER NOT NULL DEFAULT (unixepoch() * 1000),\n FOREIGN KEY (frame_id) REFERENCES frames(frame_id) ON DELETE CASCADE\n );\n `);\n\n // Create anchors table\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS anchors (\n anchor_id TEXT PRIMARY KEY,\n frame_id TEXT NOT NULL,\n type TEXT NOT NULL,\n text TEXT NOT NULL,\n priority INTEGER NOT NULL DEFAULT 5,\n metadata TEXT DEFAULT '{}',\n created_at INTEGER NOT NULL DEFAULT (unixepoch()),\n FOREIGN KEY (frame_id) REFERENCES frames(frame_id) ON DELETE CASCADE\n );\n `);\n\n // Create indexes for performance\n this.db.exec(`\n CREATE INDEX IF NOT EXISTS idx_frames_project_state ON frames(project_id, state);\n CREATE INDEX IF NOT EXISTS idx_frames_parent ON frames(parent_frame_id);\n CREATE INDEX IF NOT EXISTS idx_events_frame_seq ON events(frame_id, seq);\n CREATE INDEX IF NOT EXISTS idx_anchors_frame_priority ON anchors(frame_id, priority DESC);\n `);\n\n logger.info('Frame database schema initialized');\n } catch (error: unknown) {\n throw new DatabaseError(\n 'Failed to initialize frame database schema',\n ErrorCode.DB_SCHEMA_ERROR,\n { operation: 'initSchema' },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Insert new frame\n */\n insertFrame(frame: Omit<Frame, 'created_at' | 'closed_at'>): Frame {\n try {\n const stmt = this.db.prepare(`\n INSERT INTO frames (frame_id, run_id, project_id, parent_frame_id, depth, type, name, state, inputs, outputs, digest_json)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n\n const result = stmt.run(\n frame.frame_id,\n frame.run_id,\n frame.project_id,\n frame.parent_frame_id || null,\n frame.depth,\n frame.type,\n frame.name,\n frame.state,\n JSON.stringify(frame.inputs),\n JSON.stringify(frame.outputs),\n JSON.stringify(frame.digest_json)\n );\n\n if (result.changes === 0) {\n throw new Error('Frame insertion failed - no rows affected');\n }\n\n // Return the created frame with timestamp\n const createdFrame = this.getFrame(frame.frame_id);\n if (!createdFrame) {\n throw new Error('Failed to retrieve created frame');\n }\n\n return createdFrame;\n } catch (error: unknown) {\n throw new DatabaseError(\n `Failed to insert frame: ${frame.frame_id}`,\n ErrorCode.DB_INSERT_FAILED,\n {\n frameId: frame.frame_id,\n frameName: frame.name,\n operation: 'insertFrame',\n },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Get frame by ID\n */\n getFrame(frameId: string): Frame | undefined {\n try {\n const row = this.db\n .prepare('SELECT * FROM frames WHERE frame_id = ?')\n .get(frameId) as any;\n\n if (!row) return undefined;\n\n return {\n ...row,\n inputs: JSON.parse(row.inputs || '{}'),\n outputs: JSON.parse(row.outputs || '{}'),\n digest_json: JSON.parse(row.digest_json || '{}'),\n };\n } catch (error: unknown) {\n logger.warn(`Failed to get frame: ${frameId}`, { error });\n return undefined;\n }\n }\n\n /**\n * Update frame state and outputs\n */\n updateFrame(frameId: string, updates: Partial<Frame>): void {\n try {\n const setClauses: string[] = [];\n const values: any[] = [];\n\n if (updates.state !== undefined) {\n setClauses.push('state = ?');\n values.push(updates.state);\n }\n\n if (updates.outputs !== undefined) {\n setClauses.push('outputs = ?');\n values.push(JSON.stringify(updates.outputs));\n }\n\n if (updates.digest_text !== undefined) {\n setClauses.push('digest_text = ?');\n values.push(updates.digest_text);\n }\n\n if (updates.digest_json !== undefined) {\n setClauses.push('digest_json = ?');\n values.push(JSON.stringify(updates.digest_json));\n }\n\n if (updates.closed_at !== undefined) {\n setClauses.push('closed_at = ?');\n values.push(updates.closed_at);\n }\n\n if (setClauses.length === 0) {\n return; // No updates to apply\n }\n\n values.push(frameId);\n\n const stmt = this.db.prepare(`\n UPDATE frames SET ${setClauses.join(', ')} WHERE frame_id = ?\n `);\n\n const result = stmt.run(...values);\n\n if (result.changes === 0) {\n throw new Error(`Frame not found: ${frameId}`);\n }\n } catch (error: unknown) {\n throw new DatabaseError(\n `Failed to update frame: ${frameId}`,\n ErrorCode.DB_UPDATE_FAILED,\n { frameId, updates, operation: 'updateFrame' },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Get frames by project and state\n */\n getFramesByProject(projectId: string, state?: 'active' | 'closed'): Frame[] {\n try {\n const query = state\n ? 'SELECT * FROM frames WHERE project_id = ? AND state = ? ORDER BY created_at'\n : 'SELECT * FROM frames WHERE project_id = ? ORDER BY created_at';\n\n const params = state ? [projectId, state] : [projectId];\n const rows = this.db.prepare(query).all(...params) as any[];\n\n return rows.map((row: any) => ({\n ...row,\n inputs: JSON.parse(row.inputs || '{}'),\n outputs: JSON.parse(row.outputs || '{}'),\n digest_json: JSON.parse(row.digest_json || '{}'),\n }));\n } catch (error: unknown) {\n throw new DatabaseError(\n `Failed to get frames for project: ${projectId}`,\n ErrorCode.DB_QUERY_FAILED,\n { projectId, state, operation: 'getFramesByProject' },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Insert event\n */\n insertEvent(event: Omit<Event, 'ts'>): Event {\n try {\n const stmt = this.db.prepare(`\n INSERT INTO events (event_id, frame_id, run_id, seq, event_type, payload)\n VALUES (?, ?, ?, ?, ?, ?)\n `);\n\n const result = stmt.run(\n event.event_id,\n event.frame_id,\n event.run_id,\n event.seq,\n event.event_type,\n JSON.stringify(event.payload)\n );\n\n if (result.changes === 0) {\n throw new Error('Event insertion failed');\n }\n\n // Return the created event with timestamp\n const createdEvent = this.db\n .prepare('SELECT * FROM events WHERE event_id = ?')\n .get(event.event_id) as any;\n\n return {\n ...createdEvent,\n payload: JSON.parse(createdEvent.payload),\n };\n } catch (error: unknown) {\n throw new DatabaseError(\n `Failed to insert event: ${event.event_id}`,\n ErrorCode.DB_INSERT_FAILED,\n {\n eventId: event.event_id,\n frameId: event.frame_id,\n operation: 'insertEvent',\n },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Get events for a frame\n */\n getFrameEvents(frameId: string, limit?: number): Event[] {\n try {\n const query = limit\n ? 'SELECT * FROM events WHERE frame_id = ? ORDER BY seq DESC LIMIT ?'\n : 'SELECT * FROM events WHERE frame_id = ? ORDER BY seq ASC';\n\n const params = limit ? [frameId, limit] : [frameId];\n const rows = this.db.prepare(query).all(...params) as any[];\n\n return rows.map((row: any) => ({\n ...row,\n payload: JSON.parse(row.payload),\n }));\n } catch (error: unknown) {\n throw new DatabaseError(\n `Failed to get events for frame: ${frameId}`,\n ErrorCode.DB_QUERY_FAILED,\n { frameId, limit, operation: 'getFrameEvents' },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Get next event sequence number\n */\n getNextEventSequence(frameId: string): number {\n try {\n const result = this.db\n .prepare('SELECT MAX(seq) as max_seq FROM events WHERE frame_id = ?')\n .get(frameId) as { max_seq: number | null };\n\n return (result.max_seq || 0) + 1;\n } catch (error: unknown) {\n throw new DatabaseError(\n `Failed to get next event sequence for frame: ${frameId}`,\n ErrorCode.DB_QUERY_FAILED,\n { frameId, operation: 'getNextEventSequence' },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Insert anchor\n */\n insertAnchor(anchor: Omit<Anchor, 'created_at'>): Anchor {\n try {\n const stmt = this.db.prepare(`\n INSERT INTO anchors (anchor_id, frame_id, type, text, priority, metadata)\n VALUES (?, ?, ?, ?, ?, ?)\n `);\n\n const result = stmt.run(\n anchor.anchor_id,\n anchor.frame_id,\n anchor.type,\n anchor.text,\n anchor.priority,\n JSON.stringify(anchor.metadata)\n );\n\n if (result.changes === 0) {\n throw new Error('Anchor insertion failed');\n }\n\n // Return the created anchor with timestamp\n const createdAnchor = this.db\n .prepare('SELECT * FROM anchors WHERE anchor_id = ?')\n .get(anchor.anchor_id) as any;\n\n return {\n ...createdAnchor,\n metadata: JSON.parse(createdAnchor.metadata || '{}'),\n };\n } catch (error: unknown) {\n throw new DatabaseError(\n `Failed to insert anchor: ${anchor.anchor_id}`,\n ErrorCode.DB_INSERT_FAILED,\n {\n anchorId: anchor.anchor_id,\n frameId: anchor.frame_id,\n operation: 'insertAnchor',\n },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Get anchors for a frame\n */\n getFrameAnchors(frameId: string): Anchor[] {\n try {\n const rows = this.db\n .prepare(\n 'SELECT * FROM anchors WHERE frame_id = ? ORDER BY priority DESC, created_at ASC'\n )\n .all(frameId) as any[];\n\n return rows.map((row: any) => ({\n ...row,\n metadata: JSON.parse(row.metadata || '{}'),\n }));\n } catch (error: unknown) {\n throw new DatabaseError(\n `Failed to get anchors for frame: ${frameId}`,\n ErrorCode.DB_QUERY_FAILED,\n { frameId, operation: 'getFrameAnchors' },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Delete frame and all related data\n */\n deleteFrame(frameId: string): void {\n try {\n // Delete in order due to foreign keys\n this.db.prepare('DELETE FROM anchors WHERE frame_id = ?').run(frameId);\n this.db.prepare('DELETE FROM events WHERE frame_id = ?').run(frameId);\n this.db.prepare('DELETE FROM frames WHERE frame_id = ?').run(frameId);\n\n logger.info('Frame deleted', { frameId });\n } catch (error: unknown) {\n throw new DatabaseError(\n `Failed to delete frame: ${frameId}`,\n ErrorCode.DB_DELETE_FAILED,\n { frameId, operation: 'deleteFrame' },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Get database statistics\n */\n getStatistics(): Record<string, number> {\n try {\n const frameCount = this.db\n .prepare('SELECT COUNT(*) as count FROM frames')\n .get() as { count: number };\n const eventCount = this.db\n .prepare('SELECT COUNT(*) as count FROM events')\n .get() as { count: number };\n const anchorCount = this.db\n .prepare('SELECT COUNT(*) as count FROM anchors')\n .get() as { count: number };\n const activeFrames = this.db\n .prepare(\"SELECT COUNT(*) as count FROM frames WHERE state = 'active'\")\n .get() as { count: number };\n\n return {\n totalFrames: frameCount.count,\n totalEvents: eventCount.count,\n totalAnchors: anchorCount.count,\n activeFrames: activeFrames.count,\n };\n } catch (error: unknown) {\n logger.warn('Failed to get database statistics', {\n error: error instanceof Error ? error.message : String(error),\n });\n return {};\n }\n }\n}\n"],
|
|
5
|
-
"mappings": ";;;;AAOA,SAAS,cAAc;AACvB,SAAS,eAAe,iBAAiB;AAElC,MAAM,cAAc;AAAA,EACzB,YAAoB,IAAuB;AAAvB;AAAA,EAAwB;AAAA;AAAA;AAAA;AAAA,EAK5C,aAAmB;AACjB,QAAI;AAEF,WAAK,GAAG,OAAO,oBAAoB;AACnC,WAAK,GAAG,OAAO,sBAAsB;AAErC,WAAK,GAAG,OAAO,mBAAmB;AAGlC,WAAK,GAAG,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,OAkBZ;AAGD,WAAK,GAAG,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,OAWZ;AAGD,WAAK,GAAG,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,OAWZ;AAGD,WAAK,GAAG,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA,OAKZ;AAED,aAAO,KAAK,mCAAmC;AAAA,IACjD,SAAS,OAAgB;AACvB,YAAM,IAAI;AAAA,QACR;AAAA,QACA,UAAU;AAAA,QACV,EAAE,WAAW,aAAa;AAAA,QAC1B,iBAAiB,QAAQ,QAAQ;AAAA,MACnC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY,OAAuD;AACjE,QAAI;AACF,YAAM,OAAO,KAAK,GAAG,QAAQ;AAAA;AAAA;AAAA,OAG5B;AAED,YAAM,SAAS,KAAK;AAAA,QAClB,MAAM;AAAA,QACN,MAAM;AAAA,QACN,MAAM;AAAA,QACN,MAAM,mBAAmB;AAAA,QACzB,MAAM;AAAA,QACN,MAAM;AAAA,QACN,MAAM;AAAA,QACN,MAAM;AAAA,QACN,KAAK,UAAU,MAAM,MAAM;AAAA,QAC3B,KAAK,UAAU,MAAM,OAAO;AAAA,QAC5B,KAAK,UAAU,MAAM,WAAW;AAAA,MAClC;AAEA,UAAI,OAAO,YAAY,GAAG;AACxB,cAAM,IAAI,MAAM,
|
|
4
|
+
"sourcesContent": ["/**\n * Frame Database Operations\n * Handles all database interactions for frames, events, and anchors\n */\n\nimport Database from 'better-sqlite3';\nimport { Frame, Event, Anchor } from './frame-types.js';\nimport { logger } from '../monitoring/logger.js';\nimport { DatabaseError, ErrorCode } from '../errors/index.js';\n\nexport class FrameDatabase {\n constructor(private db: Database.Database) {}\n\n /**\n * Initialize database schema\n */\n initSchema(): void {\n try {\n // Enable WAL mode for better concurrency\n this.db.pragma('journal_mode = WAL');\n this.db.pragma('synchronous = NORMAL');\n // Enforce referential integrity\n this.db.pragma('foreign_keys = ON');\n\n // Create frames table\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS frames (\n frame_id TEXT PRIMARY KEY,\n run_id TEXT NOT NULL,\n project_id TEXT NOT NULL,\n parent_frame_id TEXT,\n depth INTEGER NOT NULL DEFAULT 0,\n type TEXT NOT NULL,\n name TEXT NOT NULL,\n state TEXT NOT NULL DEFAULT 'active',\n inputs TEXT DEFAULT '{}',\n outputs TEXT DEFAULT '{}',\n digest_text TEXT,\n digest_json TEXT DEFAULT '{}',\n created_at INTEGER NOT NULL DEFAULT (unixepoch()),\n closed_at INTEGER,\n FOREIGN KEY (parent_frame_id) REFERENCES frames(frame_id)\n );\n `);\n\n // Create events table\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS events (\n event_id TEXT PRIMARY KEY,\n frame_id TEXT NOT NULL,\n run_id TEXT NOT NULL,\n seq INTEGER NOT NULL,\n event_type TEXT NOT NULL,\n payload TEXT NOT NULL DEFAULT '{}',\n ts INTEGER NOT NULL DEFAULT (unixepoch() * 1000),\n FOREIGN KEY (frame_id) REFERENCES frames(frame_id) ON DELETE CASCADE\n );\n `);\n\n // Create anchors table\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS anchors (\n anchor_id TEXT PRIMARY KEY,\n frame_id TEXT NOT NULL,\n type TEXT NOT NULL,\n text TEXT NOT NULL,\n priority INTEGER NOT NULL DEFAULT 5,\n metadata TEXT DEFAULT '{}',\n created_at INTEGER NOT NULL DEFAULT (unixepoch()),\n FOREIGN KEY (frame_id) REFERENCES frames(frame_id) ON DELETE CASCADE\n );\n `);\n\n // Create indexes for performance\n this.db.exec(`\n CREATE INDEX IF NOT EXISTS idx_frames_project_state ON frames(project_id, state);\n CREATE INDEX IF NOT EXISTS idx_frames_parent ON frames(parent_frame_id);\n CREATE INDEX IF NOT EXISTS idx_events_frame_seq ON events(frame_id, seq);\n CREATE INDEX IF NOT EXISTS idx_anchors_frame_priority ON anchors(frame_id, priority DESC);\n `);\n\n logger.info('Frame database schema initialized');\n } catch (error: unknown) {\n throw new DatabaseError(\n 'Failed to initialize frame database schema',\n ErrorCode.DB_SCHEMA_ERROR,\n { operation: 'initSchema' },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Insert new frame\n */\n insertFrame(frame: Omit<Frame, 'created_at' | 'closed_at'>): Frame {\n try {\n const stmt = this.db.prepare(`\n INSERT INTO frames (frame_id, run_id, project_id, parent_frame_id, depth, type, name, state, inputs, outputs, digest_json)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n\n const result = stmt.run(\n frame.frame_id,\n frame.run_id,\n frame.project_id,\n frame.parent_frame_id || null,\n frame.depth,\n frame.type,\n frame.name,\n frame.state,\n JSON.stringify(frame.inputs),\n JSON.stringify(frame.outputs),\n JSON.stringify(frame.digest_json)\n );\n\n if (result.changes === 0) {\n throw new DatabaseError(\n 'Frame insertion failed - no rows affected',\n ErrorCode.DB_INSERT_FAILED,\n { frameId: frame.frame_id, operation: 'insertFrame' }\n );\n }\n\n // Return the created frame with timestamp\n const createdFrame = this.getFrame(frame.frame_id);\n if (!createdFrame) {\n throw new DatabaseError(\n 'Failed to retrieve created frame',\n ErrorCode.DB_QUERY_FAILED,\n { frameId: frame.frame_id, operation: 'insertFrame' }\n );\n }\n\n return createdFrame;\n } catch (error: unknown) {\n throw new DatabaseError(\n `Failed to insert frame: ${frame.frame_id}`,\n ErrorCode.DB_INSERT_FAILED,\n {\n frameId: frame.frame_id,\n frameName: frame.name,\n operation: 'insertFrame',\n },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Get frame by ID\n */\n getFrame(frameId: string): Frame | undefined {\n try {\n const row = this.db\n .prepare('SELECT * FROM frames WHERE frame_id = ?')\n .get(frameId) as any;\n\n if (!row) return undefined;\n\n return {\n ...row,\n inputs: JSON.parse(row.inputs || '{}'),\n outputs: JSON.parse(row.outputs || '{}'),\n digest_json: JSON.parse(row.digest_json || '{}'),\n };\n } catch (error: unknown) {\n logger.warn(`Failed to get frame: ${frameId}`, { error });\n return undefined;\n }\n }\n\n /**\n * Update frame state and outputs\n */\n updateFrame(frameId: string, updates: Partial<Frame>): void {\n try {\n const setClauses: string[] = [];\n const values: any[] = [];\n\n if (updates.state !== undefined) {\n setClauses.push('state = ?');\n values.push(updates.state);\n }\n\n if (updates.outputs !== undefined) {\n setClauses.push('outputs = ?');\n values.push(JSON.stringify(updates.outputs));\n }\n\n if (updates.digest_text !== undefined) {\n setClauses.push('digest_text = ?');\n values.push(updates.digest_text);\n }\n\n if (updates.digest_json !== undefined) {\n setClauses.push('digest_json = ?');\n values.push(JSON.stringify(updates.digest_json));\n }\n\n if (updates.closed_at !== undefined) {\n setClauses.push('closed_at = ?');\n values.push(updates.closed_at);\n }\n\n if (setClauses.length === 0) {\n return; // No updates to apply\n }\n\n values.push(frameId);\n\n const stmt = this.db.prepare(`\n UPDATE frames SET ${setClauses.join(', ')} WHERE frame_id = ?\n `);\n\n const result = stmt.run(...values);\n\n if (result.changes === 0) {\n throw new DatabaseError(\n `Frame not found: ${frameId}`,\n ErrorCode.DB_UPDATE_FAILED,\n { frameId, operation: 'updateFrame' }\n );\n }\n } catch (error: unknown) {\n throw new DatabaseError(\n `Failed to update frame: ${frameId}`,\n ErrorCode.DB_UPDATE_FAILED,\n { frameId, updates, operation: 'updateFrame' },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Get frames by project and state\n */\n getFramesByProject(projectId: string, state?: 'active' | 'closed'): Frame[] {\n try {\n const query = state\n ? 'SELECT * FROM frames WHERE project_id = ? AND state = ? ORDER BY created_at'\n : 'SELECT * FROM frames WHERE project_id = ? ORDER BY created_at';\n\n const params = state ? [projectId, state] : [projectId];\n const rows = this.db.prepare(query).all(...params) as any[];\n\n return rows.map((row: any) => ({\n ...row,\n inputs: JSON.parse(row.inputs || '{}'),\n outputs: JSON.parse(row.outputs || '{}'),\n digest_json: JSON.parse(row.digest_json || '{}'),\n }));\n } catch (error: unknown) {\n throw new DatabaseError(\n `Failed to get frames for project: ${projectId}`,\n ErrorCode.DB_QUERY_FAILED,\n { projectId, state, operation: 'getFramesByProject' },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Insert event\n */\n insertEvent(event: Omit<Event, 'ts'>): Event {\n try {\n const stmt = this.db.prepare(`\n INSERT INTO events (event_id, frame_id, run_id, seq, event_type, payload)\n VALUES (?, ?, ?, ?, ?, ?)\n `);\n\n const result = stmt.run(\n event.event_id,\n event.frame_id,\n event.run_id,\n event.seq,\n event.event_type,\n JSON.stringify(event.payload)\n );\n\n if (result.changes === 0) {\n throw new DatabaseError(\n 'Event insertion failed - no rows affected',\n ErrorCode.DB_INSERT_FAILED,\n {\n eventId: event.event_id,\n frameId: event.frame_id,\n operation: 'insertEvent',\n }\n );\n }\n\n // Return the created event with timestamp\n const createdEvent = this.db\n .prepare('SELECT * FROM events WHERE event_id = ?')\n .get(event.event_id) as any;\n\n return {\n ...createdEvent,\n payload: JSON.parse(createdEvent.payload),\n };\n } catch (error: unknown) {\n throw new DatabaseError(\n `Failed to insert event: ${event.event_id}`,\n ErrorCode.DB_INSERT_FAILED,\n {\n eventId: event.event_id,\n frameId: event.frame_id,\n operation: 'insertEvent',\n },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Get events for a frame\n */\n getFrameEvents(frameId: string, limit?: number): Event[] {\n try {\n const query = limit\n ? 'SELECT * FROM events WHERE frame_id = ? ORDER BY seq DESC LIMIT ?'\n : 'SELECT * FROM events WHERE frame_id = ? ORDER BY seq ASC';\n\n const params = limit ? [frameId, limit] : [frameId];\n const rows = this.db.prepare(query).all(...params) as any[];\n\n return rows.map((row: any) => ({\n ...row,\n payload: JSON.parse(row.payload),\n }));\n } catch (error: unknown) {\n throw new DatabaseError(\n `Failed to get events for frame: ${frameId}`,\n ErrorCode.DB_QUERY_FAILED,\n { frameId, limit, operation: 'getFrameEvents' },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Get next event sequence number\n */\n getNextEventSequence(frameId: string): number {\n try {\n const result = this.db\n .prepare('SELECT MAX(seq) as max_seq FROM events WHERE frame_id = ?')\n .get(frameId) as { max_seq: number | null };\n\n return (result.max_seq || 0) + 1;\n } catch (error: unknown) {\n throw new DatabaseError(\n `Failed to get next event sequence for frame: ${frameId}`,\n ErrorCode.DB_QUERY_FAILED,\n { frameId, operation: 'getNextEventSequence' },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Insert anchor\n */\n insertAnchor(anchor: Omit<Anchor, 'created_at'>): Anchor {\n try {\n const stmt = this.db.prepare(`\n INSERT INTO anchors (anchor_id, frame_id, type, text, priority, metadata)\n VALUES (?, ?, ?, ?, ?, ?)\n `);\n\n const result = stmt.run(\n anchor.anchor_id,\n anchor.frame_id,\n anchor.type,\n anchor.text,\n anchor.priority,\n JSON.stringify(anchor.metadata)\n );\n\n if (result.changes === 0) {\n throw new DatabaseError(\n 'Anchor insertion failed - no rows affected',\n ErrorCode.DB_INSERT_FAILED,\n {\n anchorId: anchor.anchor_id,\n frameId: anchor.frame_id,\n operation: 'insertAnchor',\n }\n );\n }\n\n // Return the created anchor with timestamp\n const createdAnchor = this.db\n .prepare('SELECT * FROM anchors WHERE anchor_id = ?')\n .get(anchor.anchor_id) as any;\n\n return {\n ...createdAnchor,\n metadata: JSON.parse(createdAnchor.metadata || '{}'),\n };\n } catch (error: unknown) {\n throw new DatabaseError(\n `Failed to insert anchor: ${anchor.anchor_id}`,\n ErrorCode.DB_INSERT_FAILED,\n {\n anchorId: anchor.anchor_id,\n frameId: anchor.frame_id,\n operation: 'insertAnchor',\n },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Get anchors for a frame\n */\n getFrameAnchors(frameId: string): Anchor[] {\n try {\n const rows = this.db\n .prepare(\n 'SELECT * FROM anchors WHERE frame_id = ? ORDER BY priority DESC, created_at ASC'\n )\n .all(frameId) as any[];\n\n return rows.map((row: any) => ({\n ...row,\n metadata: JSON.parse(row.metadata || '{}'),\n }));\n } catch (error: unknown) {\n throw new DatabaseError(\n `Failed to get anchors for frame: ${frameId}`,\n ErrorCode.DB_QUERY_FAILED,\n { frameId, operation: 'getFrameAnchors' },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Delete frame and all related data\n */\n deleteFrame(frameId: string): void {\n try {\n // Delete in order due to foreign keys\n this.db.prepare('DELETE FROM anchors WHERE frame_id = ?').run(frameId);\n this.db.prepare('DELETE FROM events WHERE frame_id = ?').run(frameId);\n this.db.prepare('DELETE FROM frames WHERE frame_id = ?').run(frameId);\n\n logger.info('Frame deleted', { frameId });\n } catch (error: unknown) {\n throw new DatabaseError(\n `Failed to delete frame: ${frameId}`,\n ErrorCode.DB_DELETE_FAILED,\n { frameId, operation: 'deleteFrame' },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Get database statistics\n */\n getStatistics(): Record<string, number> {\n try {\n const frameCount = this.db\n .prepare('SELECT COUNT(*) as count FROM frames')\n .get() as { count: number };\n const eventCount = this.db\n .prepare('SELECT COUNT(*) as count FROM events')\n .get() as { count: number };\n const anchorCount = this.db\n .prepare('SELECT COUNT(*) as count FROM anchors')\n .get() as { count: number };\n const activeFrames = this.db\n .prepare(\"SELECT COUNT(*) as count FROM frames WHERE state = 'active'\")\n .get() as { count: number };\n\n return {\n totalFrames: frameCount.count,\n totalEvents: eventCount.count,\n totalAnchors: anchorCount.count,\n activeFrames: activeFrames.count,\n };\n } catch (error: unknown) {\n logger.warn('Failed to get database statistics', {\n error: error instanceof Error ? error.message : String(error),\n });\n return {};\n }\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -3,6 +3,7 @@ import { dirname as __pathDirname } from 'path';
|
|
|
3
3
|
const __filename = __fileURLToPath(import.meta.url);
|
|
4
4
|
const __dirname = __pathDirname(__filename);
|
|
5
5
|
import { logger } from "../monitoring/logger.js";
|
|
6
|
+
import { FrameError, ErrorCode } from "../errors/index.js";
|
|
6
7
|
class FrameDigestGenerator {
|
|
7
8
|
constructor(frameDb) {
|
|
8
9
|
this.frameDb = frameDb;
|
|
@@ -14,7 +15,11 @@ class FrameDigestGenerator {
|
|
|
14
15
|
try {
|
|
15
16
|
const frame = this.frameDb.getFrame(frameId);
|
|
16
17
|
if (!frame) {
|
|
17
|
-
throw new
|
|
18
|
+
throw new FrameError(
|
|
19
|
+
`Frame not found: ${frameId}`,
|
|
20
|
+
ErrorCode.FRAME_NOT_FOUND,
|
|
21
|
+
{ frameId }
|
|
22
|
+
);
|
|
18
23
|
}
|
|
19
24
|
const events = this.frameDb.getFrameEvents(frameId);
|
|
20
25
|
const anchors = this.frameDb.getFrameAnchors(frameId);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/core/context/frame-digest.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Frame Digest Generation\n * Handles creation of frame summaries and digests\n */\n\nimport { Frame, Event, Anchor, DigestResult } from './frame-types.js';\nimport { FrameDatabase } from './frame-database.js';\nimport { logger } from '../monitoring/logger.js';\n\nexport class FrameDigestGenerator {\n constructor(private frameDb: FrameDatabase) {}\n\n /**\n * Generate digest for a frame\n */\n generateDigest(frameId: string): DigestResult {\n try {\n const frame = this.frameDb.getFrame(frameId);\n if (!frame) {\n throw new
|
|
5
|
-
"mappings": ";;;;AAOA,SAAS,cAAc;
|
|
4
|
+
"sourcesContent": ["/**\n * Frame Digest Generation\n * Handles creation of frame summaries and digests\n */\n\nimport { Frame, Event, Anchor, DigestResult } from './frame-types.js';\nimport { FrameDatabase } from './frame-database.js';\nimport { logger } from '../monitoring/logger.js';\nimport { FrameError, ErrorCode } from '../errors/index.js';\n\nexport class FrameDigestGenerator {\n constructor(private frameDb: FrameDatabase) {}\n\n /**\n * Generate digest for a frame\n */\n generateDigest(frameId: string): DigestResult {\n try {\n const frame = this.frameDb.getFrame(frameId);\n if (!frame) {\n throw new FrameError(\n `Frame not found: ${frameId}`,\n ErrorCode.FRAME_NOT_FOUND,\n { frameId }\n );\n }\n\n const events = this.frameDb.getFrameEvents(frameId);\n const anchors = this.frameDb.getFrameAnchors(frameId);\n\n // Generate text summary\n const text = this.generateTextDigest(frame, events, anchors);\n\n // Generate structured data\n const structured = this.generateStructuredDigest(frame, events, anchors);\n\n return { text, structured };\n } catch (error: unknown) {\n logger.error('Failed to generate frame digest', { frameId, error });\n\n return {\n text: `Error generating digest for frame ${frameId}`,\n structured: { error: (error as Error).message },\n };\n }\n }\n\n /**\n * Generate text summary of frame\n */\n private generateTextDigest(\n frame: Frame,\n events: Event[],\n anchors: Anchor[]\n ): string {\n const lines: string[] = [];\n\n // Frame header\n lines.push(`Frame: ${frame.name} (${frame.type})`);\n lines.push(\n `Duration: ${this.formatDuration(frame.created_at, frame.closed_at)}`\n );\n lines.push('');\n\n // Goals and constraints\n if (frame.inputs.goals) {\n lines.push(`Goals: ${frame.inputs.goals}`);\n }\n\n if (frame.inputs.constraints && frame.inputs.constraints.length > 0) {\n lines.push(`Constraints: ${frame.inputs.constraints.join(', ')}`);\n }\n\n // Key anchors\n const importantAnchors = anchors\n .filter((a: any) => a.priority >= 7)\n .sort((a, b) => b.priority - a.priority);\n\n if (importantAnchors.length > 0) {\n lines.push('');\n lines.push('Key Decisions & Facts:');\n importantAnchors.forEach((anchor) => {\n lines.push(`- ${anchor.type}: ${anchor.text}`);\n });\n }\n\n // Activity summary\n const eventSummary = this.summarizeEvents(events);\n if (eventSummary.length > 0) {\n lines.push('');\n lines.push('Activity Summary:');\n eventSummary.forEach((summary) => {\n lines.push(`- ${summary}`);\n });\n }\n\n // Outputs\n if (frame.outputs && Object.keys(frame.outputs).length > 0) {\n lines.push('');\n lines.push('Outputs:');\n Object.entries(frame.outputs).forEach(([key, value]) => {\n lines.push(`- ${key}: ${this.formatValue(value)}`);\n });\n }\n\n return lines.join('\\n');\n }\n\n /**\n * Generate structured digest data\n */\n private generateStructuredDigest(\n frame: Frame,\n events: Event[],\n anchors: Anchor[]\n ): Record<string, any> {\n const eventsByType = this.groupEventsByType(events);\n const anchorsByType = this.groupAnchorsByType(anchors);\n\n return {\n frameId: frame.frame_id,\n frameName: frame.name,\n frameType: frame.type,\n duration: {\n startTime: frame.created_at,\n endTime: frame.closed_at,\n durationMs: frame.closed_at\n ? (frame.closed_at - frame.created_at) * 1000\n : null,\n },\n activity: {\n totalEvents: events.length,\n eventsByType,\n eventTimeline: events.slice(-10).map((e: any) => ({\n type: e.event_type,\n timestamp: e.ts,\n summary: this.summarizeEvent(e),\n })),\n },\n knowledge: {\n totalAnchors: anchors.length,\n anchorsByType,\n keyDecisions: anchors\n .filter((a: any) => a.type === 'DECISION' && a.priority >= 7)\n .map((a: any) => a.text),\n constraints: anchors\n .filter((a: any) => a.type === 'CONSTRAINT')\n .map((a: any) => a.text),\n risks: anchors\n .filter((a: any) => a.type === 'RISK')\n .map((a: any) => a.text),\n },\n outcomes: {\n outputs: frame.outputs,\n success: frame.state === 'closed' && !this.hasErrorEvents(events),\n artifacts: this.extractArtifacts(events),\n },\n metadata: {\n projectId: frame.project_id,\n runId: frame.run_id,\n parentFrameId: frame.parent_frame_id,\n depth: frame.depth,\n },\n };\n }\n\n /**\n * Summarize events into readable format\n */\n private summarizeEvents(events: Event[]): string[] {\n const summaries: string[] = [];\n const eventsByType = this.groupEventsByType(events);\n\n // Tool calls summary\n if (eventsByType.tool_call && eventsByType.tool_call.length > 0) {\n const toolCounts = this.countTools(eventsByType.tool_call);\n const toolSummary = Object.entries(toolCounts)\n .map(([tool, count]) => `${tool} (${count})`)\n .join(', ');\n summaries.push(`Tool calls: ${toolSummary}`);\n }\n\n // Decisions summary\n if (eventsByType.decision && eventsByType.decision.length > 0) {\n summaries.push(`Made ${eventsByType.decision.length} decisions`);\n }\n\n // Observations summary\n if (eventsByType.observation && eventsByType.observation.length > 0) {\n summaries.push(\n `Recorded ${eventsByType.observation.length} observations`\n );\n }\n\n // Error summary\n const errorEvents = events.filter(\n (e: any) => e.payload.error || e.payload.status === 'error'\n );\n if (errorEvents.length > 0) {\n summaries.push(`Encountered ${errorEvents.length} errors`);\n }\n\n return summaries;\n }\n\n /**\n * Group events by type\n */\n private groupEventsByType(events: Event[]): Record<string, Event[]> {\n const groups: Record<string, Event[]> = {};\n\n for (const event of events) {\n if (!groups[event.event_type]) {\n groups[event.event_type] = [];\n }\n groups[event.event_type].push(event);\n }\n\n return groups;\n }\n\n /**\n * Group anchors by type\n */\n private groupAnchorsByType(anchors: Anchor[]): Record<string, number> {\n const groups: Record<string, number> = {};\n\n for (const anchor of anchors) {\n groups[anchor.type] = (groups[anchor.type] || 0) + 1;\n }\n\n return groups;\n }\n\n /**\n * Count tool usage\n */\n private countTools(toolEvents: Event[]): Record<string, number> {\n const counts: Record<string, number> = {};\n\n for (const event of toolEvents) {\n const toolName = event.payload.tool_name || 'unknown';\n counts[toolName] = (counts[toolName] || 0) + 1;\n }\n\n return counts;\n }\n\n /**\n * Check if events contain errors\n */\n private hasErrorEvents(events: Event[]): boolean {\n return events.some((e) => e.payload.error || e.payload.status === 'error');\n }\n\n /**\n * Extract artifacts from events\n */\n private extractArtifacts(events: Event[]): string[] {\n const artifacts: string[] = [];\n\n for (const event of events) {\n if (event.event_type === 'artifact' && event.payload.path) {\n artifacts.push(event.payload.path);\n }\n }\n\n return [...new Set(artifacts)];\n }\n\n /**\n * Summarize a single event\n */\n private summarizeEvent(event: Event): string {\n switch (event.event_type) {\n case 'tool_call':\n return `${event.payload.tool_name || 'tool'}`;\n case 'decision':\n return `${event.payload.type}: ${event.payload.content?.substring(0, 50)}...`;\n case 'observation':\n return `${event.payload.content?.substring(0, 50)}...`;\n case 'artifact':\n return `Created ${event.payload.path}`;\n default:\n return event.event_type;\n }\n }\n\n /**\n * Format duration\n */\n private formatDuration(startTime: number, endTime?: number): string {\n if (!endTime) {\n return 'ongoing';\n }\n\n const durationMs = (endTime - startTime) * 1000;\n\n if (durationMs < 1000) {\n return `${durationMs.toFixed(0)}ms`;\n } else if (durationMs < 60000) {\n return `${(durationMs / 1000).toFixed(1)}s`;\n } else {\n return `${(durationMs / 60000).toFixed(1)}m`;\n }\n }\n\n /**\n * Format value for display\n */\n private formatValue(value: any): string {\n if (typeof value === 'string') {\n return value.length > 100 ? `${value.substring(0, 100)}...` : value;\n } else if (typeof value === 'object') {\n return JSON.stringify(value).substring(0, 100) + '...';\n } else {\n return String(value);\n }\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -7,18 +7,38 @@ import { logger } from "../monitoring/logger.js";
|
|
|
7
7
|
import {
|
|
8
8
|
DatabaseError,
|
|
9
9
|
FrameError,
|
|
10
|
+
SystemError,
|
|
10
11
|
ErrorCode,
|
|
11
12
|
createErrorHandler
|
|
12
13
|
} from "../errors/index.js";
|
|
13
14
|
import { sessionManager, FrameQueryMode } from "../session/index.js";
|
|
14
15
|
import { contextBridge } from "./context-bridge.js";
|
|
16
|
+
let whatsappSync = null;
|
|
17
|
+
async function loadWhatsAppSync() {
|
|
18
|
+
if (whatsappSync !== null) return whatsappSync;
|
|
19
|
+
try {
|
|
20
|
+
const mod = await import("../../hooks/whatsapp-sync.js");
|
|
21
|
+
whatsappSync = {
|
|
22
|
+
onFrameClosed: mod.onFrameClosed,
|
|
23
|
+
createFrameDigestData: mod.createFrameDigestData
|
|
24
|
+
};
|
|
25
|
+
return whatsappSync;
|
|
26
|
+
} catch {
|
|
27
|
+
whatsappSync = null;
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
15
31
|
const MAX_FRAME_DEPTH = 100;
|
|
16
32
|
const DEFAULT_MAX_DEPTH = 100;
|
|
17
33
|
function getEnv(key, defaultValue) {
|
|
18
34
|
const value = process.env[key];
|
|
19
35
|
if (value === void 0) {
|
|
20
36
|
if (defaultValue !== void 0) return defaultValue;
|
|
21
|
-
throw new
|
|
37
|
+
throw new SystemError(
|
|
38
|
+
`Environment variable ${key} is required`,
|
|
39
|
+
ErrorCode.CONFIGURATION_ERROR,
|
|
40
|
+
{ variable: key }
|
|
41
|
+
);
|
|
22
42
|
}
|
|
23
43
|
return value;
|
|
24
44
|
}
|
|
@@ -82,7 +102,11 @@ class FrameManager {
|
|
|
82
102
|
});
|
|
83
103
|
try {
|
|
84
104
|
if (!this.db || typeof this.db.exec !== "function") {
|
|
85
|
-
throw new
|
|
105
|
+
throw new DatabaseError(
|
|
106
|
+
"Database not properly initialized. Expected SQLite Database instance with exec() method.",
|
|
107
|
+
ErrorCode.DB_CONNECTION_FAILED,
|
|
108
|
+
{ operation: "initializeSchema" }
|
|
109
|
+
);
|
|
86
110
|
}
|
|
87
111
|
this.db.pragma("foreign_keys = ON");
|
|
88
112
|
this.db.exec(`
|
|
@@ -150,7 +174,10 @@ class FrameManager {
|
|
|
150
174
|
try {
|
|
151
175
|
this.ensureCascadeConstraints();
|
|
152
176
|
} catch (e) {
|
|
153
|
-
logger.warn(
|
|
177
|
+
logger.warn(
|
|
178
|
+
"Failed to ensure cascade constraints (frame-manager)",
|
|
179
|
+
e
|
|
180
|
+
);
|
|
154
181
|
}
|
|
155
182
|
} catch (error) {
|
|
156
183
|
const dbError = errorHandler(error, {
|
|
@@ -176,7 +203,9 @@ class FrameManager {
|
|
|
176
203
|
ensureCascadeConstraints() {
|
|
177
204
|
const needsCascade = (table) => {
|
|
178
205
|
const rows = this.db.prepare(`PRAGMA foreign_key_list(${table})`).all();
|
|
179
|
-
return rows.some(
|
|
206
|
+
return rows.some(
|
|
207
|
+
(r) => r.table === "frames" && String(r.on_delete).toUpperCase() !== "CASCADE"
|
|
208
|
+
);
|
|
180
209
|
};
|
|
181
210
|
const migrateTable = (table) => {
|
|
182
211
|
const createSql = table === "events" ? `CREATE TABLE events_new (
|
|
@@ -209,13 +238,17 @@ class FrameManager {
|
|
|
209
238
|
this.db.exec("PRAGMA foreign_keys = OFF;");
|
|
210
239
|
this.db.exec("BEGIN;");
|
|
211
240
|
this.db.exec(createSql);
|
|
212
|
-
this.db.prepare(
|
|
241
|
+
this.db.prepare(
|
|
242
|
+
`INSERT INTO ${table === "events" ? "events_new" : "anchors_new"} (${cols}) SELECT ${cols} FROM ${table}`
|
|
243
|
+
).run();
|
|
213
244
|
this.db.exec(`DROP TABLE ${table};`);
|
|
214
245
|
this.db.exec(`ALTER TABLE ${table}_new RENAME TO ${table};`);
|
|
215
246
|
for (const stmt of idxSql) this.db.exec(stmt);
|
|
216
247
|
this.db.exec("COMMIT;");
|
|
217
248
|
this.db.exec("PRAGMA foreign_keys = ON;");
|
|
218
|
-
logger.info(
|
|
249
|
+
logger.info(
|
|
250
|
+
`Migrated ${table} to include ON DELETE CASCADE (frame-manager)`
|
|
251
|
+
);
|
|
219
252
|
};
|
|
220
253
|
if (needsCascade("events")) migrateTable("events");
|
|
221
254
|
if (needsCascade("anchors")) migrateTable("anchors");
|
|
@@ -478,6 +511,8 @@ class FrameManager {
|
|
|
478
511
|
}
|
|
479
512
|
this.activeStack = this.activeStack.filter((id) => id !== targetFrameId);
|
|
480
513
|
this.closeChildFrames(targetFrameId);
|
|
514
|
+
this.triggerWhatsAppSync(frame, targetFrameId).catch(() => {
|
|
515
|
+
});
|
|
481
516
|
logger.info("Closed frame", {
|
|
482
517
|
frameId: targetFrameId,
|
|
483
518
|
name: frame.name,
|
|
@@ -486,6 +521,20 @@ class FrameManager {
|
|
|
486
521
|
stackDepth: this.activeStack.length
|
|
487
522
|
});
|
|
488
523
|
}
|
|
524
|
+
/**
|
|
525
|
+
* Trigger WhatsApp sync for closed frame (non-blocking)
|
|
526
|
+
*/
|
|
527
|
+
async triggerWhatsAppSync(frame, frameId) {
|
|
528
|
+
const sync = await loadWhatsAppSync();
|
|
529
|
+
if (!sync) return;
|
|
530
|
+
try {
|
|
531
|
+
const events = this.getFrameEvents(frameId);
|
|
532
|
+
const anchors = this.getFrameAnchors(frameId);
|
|
533
|
+
const digestData = sync.createFrameDigestData(frame, events, anchors);
|
|
534
|
+
await sync.onFrameClosed(digestData);
|
|
535
|
+
} catch {
|
|
536
|
+
}
|
|
537
|
+
}
|
|
489
538
|
/**
|
|
490
539
|
* Delete a frame completely from the database (used in handoffs)
|
|
491
540
|
*/
|
|
@@ -994,9 +1043,7 @@ Activity: ${eventCount} events, ${structured.tool_calls_count} tool calls`;
|
|
|
994
1043
|
}
|
|
995
1044
|
}
|
|
996
1045
|
try {
|
|
997
|
-
this.db.prepare(
|
|
998
|
-
`UPDATE frames SET parent_frame_id = ? WHERE frame_id = ?`
|
|
999
|
-
).run(newParentFrameId, frameId);
|
|
1046
|
+
this.db.prepare(`UPDATE frames SET parent_frame_id = ? WHERE frame_id = ?`).run(newParentFrameId, frameId);
|
|
1000
1047
|
logger.info("Updated parent frame", {
|
|
1001
1048
|
frameId,
|
|
1002
1049
|
oldParentId: frame.parent_frame_id,
|