Refactor database hooks to add new session tracking features

- Introduced `getSessionById` method in HooksDatabase to retrieve session details by ID.
- Updated context, new, save, and summary hooks to utilize the new `getSessionById` method.
- Enhanced session management by adding `worker_port` and `prompt_counter` columns to relevant tables.
- Improved logging in WorkerService to provide clearer output during session initialization and processing.
- Removed redundant error logging in favor of more informative console logs.
This commit is contained in:
Alex Newman
2025-10-17 16:42:23 -04:00
parent be936d8413
commit 015b38c763
8 changed files with 147 additions and 100 deletions
+12 -7
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env node
import S from"better-sqlite3";import{join as i,dirname as R,basename as I}from"path";import{homedir as _}from"os";import{existsSync as L,mkdirSync as h}from"fs";var a=process.env.CLAUDE_MEM_DATA_DIR||i(_(),".claude-mem"),p=process.env.CLAUDE_CONFIG_DIR||i(_(),".claude"),C=i(a,"archives"),w=i(a,"logs"),O=i(a,"trash"),y=i(a,"backups"),P=i(a,"settings.json"),E=i(a,"claude-mem.db"),U=i(p,"settings.json"),H=i(p,"commands"),M=i(p,"CLAUDE.md");function g(o){h(o,{recursive:!0})}var u=class{db;constructor(){g(a),this.db=new S(E),this.db.pragma("journal_mode = WAL"),this.db.pragma("synchronous = NORMAL"),this.db.pragma("foreign_keys = ON"),this.ensureWorkerPortColumn(),this.ensurePromptTrackingColumns(),this.removeSessionSummariesUniqueConstraint()}ensureWorkerPortColumn(){try{this.db.pragma("table_info(sdk_sessions)").some(s=>s.name==="worker_port")||(this.db.exec("ALTER TABLE sdk_sessions ADD COLUMN worker_port INTEGER"),console.error("[HooksDatabase] Added worker_port column to sdk_sessions table"))}catch(e){console.error("[HooksDatabase] Migration error:",e.message)}}ensurePromptTrackingColumns(){try{this.db.pragma("table_info(sdk_sessions)").some(c=>c.name==="prompt_counter")||(this.db.exec("ALTER TABLE sdk_sessions ADD COLUMN prompt_counter INTEGER DEFAULT 0"),console.error("[HooksDatabase] Added prompt_counter column to sdk_sessions table")),this.db.pragma("table_info(observations)").some(c=>c.name==="prompt_number")||(this.db.exec("ALTER TABLE observations ADD COLUMN prompt_number INTEGER"),console.error("[HooksDatabase] Added prompt_number column to observations table")),this.db.pragma("table_info(session_summaries)").some(c=>c.name==="prompt_number")||(this.db.exec("ALTER TABLE session_summaries ADD COLUMN prompt_number INTEGER"),console.error("[HooksDatabase] Added prompt_number column to session_summaries table"));let k=this.db.pragma("index_list(session_summaries)").some(c=>c.unique===1)}catch(e){console.error("[HooksDatabase] Prompt tracking migration error:",e.message)}}removeSessionSummariesUniqueConstraint(){try{if(!this.db.pragma("index_list(session_summaries)").some(s=>s.unique===1))return;console.error("[HooksDatabase] Removing UNIQUE constraint from session_summaries.sdk_session_id..."),this.db.exec("BEGIN TRANSACTION");try{this.db.exec(`
import S from"better-sqlite3";import{join as i,dirname as A,basename as I}from"path";import{homedir as _}from"os";import{existsSync as v,mkdirSync as h}from"fs";var a=process.env.CLAUDE_MEM_DATA_DIR||i(_(),".claude-mem"),p=process.env.CLAUDE_CONFIG_DIR||i(_(),".claude"),C=i(a,"archives"),O=i(a,"logs"),w=i(a,"trash"),y=i(a,"backups"),P=i(a,"settings.json"),E=i(a,"claude-mem.db"),U=i(p,"settings.json"),H=i(p,"commands"),M=i(p,"CLAUDE.md");function g(o){h(o,{recursive:!0})}var u=class{db;constructor(){g(a),this.db=new S(E),this.db.pragma("journal_mode = WAL"),this.db.pragma("synchronous = NORMAL"),this.db.pragma("foreign_keys = ON"),this.ensureWorkerPortColumn(),this.ensurePromptTrackingColumns(),this.removeSessionSummariesUniqueConstraint()}ensureWorkerPortColumn(){try{this.db.pragma("table_info(sdk_sessions)").some(s=>s.name==="worker_port")||(this.db.exec("ALTER TABLE sdk_sessions ADD COLUMN worker_port INTEGER"),console.error("[HooksDatabase] Added worker_port column to sdk_sessions table"))}catch(e){console.error("[HooksDatabase] Migration error:",e.message)}}ensurePromptTrackingColumns(){try{this.db.pragma("table_info(sdk_sessions)").some(c=>c.name==="prompt_counter")||(this.db.exec("ALTER TABLE sdk_sessions ADD COLUMN prompt_counter INTEGER DEFAULT 0"),console.error("[HooksDatabase] Added prompt_counter column to sdk_sessions table")),this.db.pragma("table_info(observations)").some(c=>c.name==="prompt_number")||(this.db.exec("ALTER TABLE observations ADD COLUMN prompt_number INTEGER"),console.error("[HooksDatabase] Added prompt_number column to observations table")),this.db.pragma("table_info(session_summaries)").some(c=>c.name==="prompt_number")||(this.db.exec("ALTER TABLE session_summaries ADD COLUMN prompt_number INTEGER"),console.error("[HooksDatabase] Added prompt_number column to session_summaries table"));let k=this.db.pragma("index_list(session_summaries)").some(c=>c.unique===1)}catch(e){console.error("[HooksDatabase] Prompt tracking migration error:",e.message)}}removeSessionSummariesUniqueConstraint(){try{if(!this.db.pragma("index_list(session_summaries)").some(s=>s.unique===1))return;console.error("[HooksDatabase] Removing UNIQUE constraint from session_summaries.sdk_session_id..."),this.db.exec("BEGIN TRANSACTION");try{this.db.exec(`
CREATE TABLE session_summaries_new (
id INTEGER PRIMARY KEY AUTOINCREMENT,
sdk_session_id TEXT NOT NULL,
@@ -41,7 +41,12 @@ import S from"better-sqlite3";import{join as i,dirname as R,basename as I}from"p
WHERE project = ?
ORDER BY created_at_epoch DESC
LIMIT ?
`).all(e,t)}findActiveSDKSession(e){return this.db.prepare(`
`).all(e,t)}getSessionById(e){return this.db.prepare(`
SELECT id, sdk_session_id, project, user_prompt
FROM sdk_sessions
WHERE id = ?
LIMIT 1
`).get(e)||null}findActiveSDKSession(e){return this.db.prepare(`
SELECT id, sdk_session_id, project, worker_port
FROM sdk_sessions
WHERE claude_session_id = ? AND status = 'active'
@@ -67,11 +72,11 @@ import S from"better-sqlite3";import{join as i,dirname as R,basename as I}from"p
INSERT INTO sdk_sessions
(claude_session_id, project, user_prompt, started_at, started_at_epoch, status)
VALUES (?, ?, ?, ?, ?, 'active')
`).run(e,t,s,r.toISOString(),n).lastInsertRowid}updateSDKSessionId(e,t){this.db.prepare(`
`).run(e,t,s,r.toISOString(),n).lastInsertRowid}updateSDKSessionId(e,t){return this.db.prepare(`
UPDATE sdk_sessions
SET sdk_session_id = ?
WHERE id = ? AND sdk_session_id IS NULL
`).run(t,e).changes===0&&console.error(`[HooksDatabase] Skipped updating sdk_session_id for session ${e} - already set (prevents FOREIGN KEY constraint violation)`)}setWorkerPort(e,t){this.db.prepare(`
`).run(t,e).changes===0?(console.error(`[HooksDatabase] Skipped updating sdk_session_id for session ${e} - already set (prevents FOREIGN KEY constraint violation)`),!1):!0}setWorkerPort(e,t){this.db.prepare(`
UPDATE sdk_sessions
SET worker_port = ?
WHERE id = ?
@@ -80,16 +85,16 @@ import S from"better-sqlite3";import{join as i,dirname as R,basename as I}from"p
FROM sdk_sessions
WHERE id = ?
LIMIT 1
`).get(e)?.worker_port||null}storeObservation(e,t,s,r,n){let m=new Date,d=m.getTime();this.db.prepare(`
`).get(e)?.worker_port||null}storeObservation(e,t,s,r,n){let d=new Date,m=d.getTime();this.db.prepare(`
INSERT INTO observations
(sdk_session_id, project, text, type, prompt_number, created_at, created_at_epoch)
VALUES (?, ?, ?, ?, ?, ?, ?)
`).run(e,t,r,s,n||null,m.toISOString(),d)}storeSummary(e,t,s,r){let n=new Date,m=n.getTime();this.db.prepare(`
`).run(e,t,r,s,n||null,d.toISOString(),m)}storeSummary(e,t,s,r){let n=new Date,d=n.getTime();this.db.prepare(`
INSERT INTO session_summaries
(sdk_session_id, project, request, investigated, learned, completed,
next_steps, files_read, files_edited, notes, prompt_number, created_at, created_at_epoch)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`).run(e,t,s.request||null,s.investigated||null,s.learned||null,s.completed||null,s.next_steps||null,s.files_read||null,s.files_edited||null,s.notes||null,r||null,n.toISOString(),m)}markSessionCompleted(e){let t=new Date,s=t.getTime();this.db.prepare(`
`).run(e,t,s.request||null,s.investigated||null,s.learned||null,s.completed||null,s.next_steps||null,s.files_read||null,s.files_edited||null,s.notes||null,r||null,n.toISOString(),d)}markSessionCompleted(e){let t=new Date,s=t.getTime();this.db.prepare(`
UPDATE sdk_sessions
SET status = 'completed', completed_at = ?, completed_at_epoch = ?
WHERE id = ?