claudia-orchestrator 0.1.0

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.
Files changed (296) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +109 -0
  3. package/dist/cli-parser.d.ts +11 -0
  4. package/dist/cli-parser.d.ts.map +1 -0
  5. package/dist/cli-parser.js +57 -0
  6. package/dist/cli-parser.js.map +1 -0
  7. package/dist/cui-server.d.ts +69 -0
  8. package/dist/cui-server.d.ts.map +1 -0
  9. package/dist/cui-server.js +705 -0
  10. package/dist/cui-server.js.map +1 -0
  11. package/dist/mcp-server/claudia-tools.d.ts +15 -0
  12. package/dist/mcp-server/claudia-tools.d.ts.map +1 -0
  13. package/dist/mcp-server/claudia-tools.js +366 -0
  14. package/dist/mcp-server/claudia-tools.js.map +1 -0
  15. package/dist/mcp-server/index.d.ts +3 -0
  16. package/dist/mcp-server/index.d.ts.map +1 -0
  17. package/dist/mcp-server/index.js +176 -0
  18. package/dist/mcp-server/index.js.map +1 -0
  19. package/dist/middleware/auth.d.ts +18 -0
  20. package/dist/middleware/auth.d.ts.map +1 -0
  21. package/dist/middleware/auth.js +136 -0
  22. package/dist/middleware/auth.js.map +1 -0
  23. package/dist/middleware/cors-setup.d.ts +7 -0
  24. package/dist/middleware/cors-setup.d.ts.map +1 -0
  25. package/dist/middleware/cors-setup.js +8 -0
  26. package/dist/middleware/cors-setup.js.map +1 -0
  27. package/dist/middleware/error-handler.d.ts +4 -0
  28. package/dist/middleware/error-handler.d.ts.map +1 -0
  29. package/dist/middleware/error-handler.js +27 -0
  30. package/dist/middleware/error-handler.js.map +1 -0
  31. package/dist/middleware/query-parser.d.ts +11 -0
  32. package/dist/middleware/query-parser.d.ts.map +1 -0
  33. package/dist/middleware/query-parser.js +68 -0
  34. package/dist/middleware/query-parser.js.map +1 -0
  35. package/dist/middleware/request-logger.d.ts +4 -0
  36. package/dist/middleware/request-logger.d.ts.map +1 -0
  37. package/dist/middleware/request-logger.js +29 -0
  38. package/dist/middleware/request-logger.js.map +1 -0
  39. package/dist/process-daemon/index.d.ts +14 -0
  40. package/dist/process-daemon/index.d.ts.map +1 -0
  41. package/dist/process-daemon/index.js +51 -0
  42. package/dist/process-daemon/index.js.map +1 -0
  43. package/dist/process-daemon/process-daemon.d.ts +78 -0
  44. package/dist/process-daemon/process-daemon.d.ts.map +1 -0
  45. package/dist/process-daemon/process-daemon.js +568 -0
  46. package/dist/process-daemon/process-daemon.js.map +1 -0
  47. package/dist/process-daemon/process-manager-client.d.ts +108 -0
  48. package/dist/process-daemon/process-manager-client.d.ts.map +1 -0
  49. package/dist/process-daemon/process-manager-client.js +314 -0
  50. package/dist/process-daemon/process-manager-client.js.map +1 -0
  51. package/dist/process-daemon/process-manager-interface.d.ts +47 -0
  52. package/dist/process-daemon/process-manager-interface.d.ts.map +1 -0
  53. package/dist/process-daemon/process-manager-interface.js +8 -0
  54. package/dist/process-daemon/process-manager-interface.js.map +1 -0
  55. package/dist/process-daemon/test-daemon.d.ts +12 -0
  56. package/dist/process-daemon/test-daemon.d.ts.map +1 -0
  57. package/dist/process-daemon/test-daemon.js +81 -0
  58. package/dist/process-daemon/test-daemon.js.map +1 -0
  59. package/dist/process-daemon/types.d.ts +85 -0
  60. package/dist/process-daemon/types.d.ts.map +1 -0
  61. package/dist/process-daemon/types.js +8 -0
  62. package/dist/process-daemon/types.js.map +1 -0
  63. package/dist/routes/claudia.routes.d.ts +10 -0
  64. package/dist/routes/claudia.routes.d.ts.map +1 -0
  65. package/dist/routes/claudia.routes.js +123 -0
  66. package/dist/routes/claudia.routes.js.map +1 -0
  67. package/dist/routes/config.routes.d.ts +4 -0
  68. package/dist/routes/config.routes.d.ts.map +1 -0
  69. package/dist/routes/config.routes.js +27 -0
  70. package/dist/routes/config.routes.js.map +1 -0
  71. package/dist/routes/conversation.routes.d.ts +8 -0
  72. package/dist/routes/conversation.routes.d.ts.map +1 -0
  73. package/dist/routes/conversation.routes.js +870 -0
  74. package/dist/routes/conversation.routes.js.map +1 -0
  75. package/dist/routes/filesystem.routes.d.ts +4 -0
  76. package/dist/routes/filesystem.routes.d.ts.map +1 -0
  77. package/dist/routes/filesystem.routes.js +86 -0
  78. package/dist/routes/filesystem.routes.js.map +1 -0
  79. package/dist/routes/gemini.routes.d.ts +4 -0
  80. package/dist/routes/gemini.routes.d.ts.map +1 -0
  81. package/dist/routes/gemini.routes.js +93 -0
  82. package/dist/routes/gemini.routes.js.map +1 -0
  83. package/dist/routes/insights.routes.d.ts +17 -0
  84. package/dist/routes/insights.routes.d.ts.map +1 -0
  85. package/dist/routes/insights.routes.js +417 -0
  86. package/dist/routes/insights.routes.js.map +1 -0
  87. package/dist/routes/license.routes.d.ts +3 -0
  88. package/dist/routes/license.routes.d.ts.map +1 -0
  89. package/dist/routes/license.routes.js +111 -0
  90. package/dist/routes/license.routes.js.map +1 -0
  91. package/dist/routes/log.routes.d.ts +3 -0
  92. package/dist/routes/log.routes.d.ts.map +1 -0
  93. package/dist/routes/log.routes.js +65 -0
  94. package/dist/routes/log.routes.js.map +1 -0
  95. package/dist/routes/notifications.routes.d.ts +4 -0
  96. package/dist/routes/notifications.routes.d.ts.map +1 -0
  97. package/dist/routes/notifications.routes.js +71 -0
  98. package/dist/routes/notifications.routes.js.map +1 -0
  99. package/dist/routes/permission.routes.d.ts +4 -0
  100. package/dist/routes/permission.routes.d.ts.map +1 -0
  101. package/dist/routes/permission.routes.js +116 -0
  102. package/dist/routes/permission.routes.js.map +1 -0
  103. package/dist/routes/question.routes.d.ts +8 -0
  104. package/dist/routes/question.routes.d.ts.map +1 -0
  105. package/dist/routes/question.routes.js +82 -0
  106. package/dist/routes/question.routes.js.map +1 -0
  107. package/dist/routes/streaming.routes.d.ts +4 -0
  108. package/dist/routes/streaming.routes.d.ts.map +1 -0
  109. package/dist/routes/streaming.routes.js +28 -0
  110. package/dist/routes/streaming.routes.js.map +1 -0
  111. package/dist/routes/system.routes.d.ts +5 -0
  112. package/dist/routes/system.routes.d.ts.map +1 -0
  113. package/dist/routes/system.routes.js +103 -0
  114. package/dist/routes/system.routes.js.map +1 -0
  115. package/dist/routes/working-directories.routes.d.ts +4 -0
  116. package/dist/routes/working-directories.routes.d.ts.map +1 -0
  117. package/dist/routes/working-directories.routes.js +25 -0
  118. package/dist/routes/working-directories.routes.js.map +1 -0
  119. package/dist/server.d.ts +3 -0
  120. package/dist/server.d.ts.map +1 -0
  121. package/dist/server.js +34 -0
  122. package/dist/server.js.map +1 -0
  123. package/dist/services/ToolMetricsService.d.ts +53 -0
  124. package/dist/services/ToolMetricsService.d.ts.map +1 -0
  125. package/dist/services/ToolMetricsService.js +230 -0
  126. package/dist/services/ToolMetricsService.js.map +1 -0
  127. package/dist/services/anthropic-service.d.ts +186 -0
  128. package/dist/services/anthropic-service.d.ts.map +1 -0
  129. package/dist/services/anthropic-service.js +1132 -0
  130. package/dist/services/anthropic-service.js.map +1 -0
  131. package/dist/services/claude-history-reader.d.ts +126 -0
  132. package/dist/services/claude-history-reader.d.ts.map +1 -0
  133. package/dist/services/claude-history-reader.js +717 -0
  134. package/dist/services/claude-history-reader.js.map +1 -0
  135. package/dist/services/claude-process-manager.d.ts +108 -0
  136. package/dist/services/claude-process-manager.d.ts.map +1 -0
  137. package/dist/services/claude-process-manager.js +909 -0
  138. package/dist/services/claude-process-manager.js.map +1 -0
  139. package/dist/services/claude-router-service.d.ts +19 -0
  140. package/dist/services/claude-router-service.d.ts.map +1 -0
  141. package/dist/services/claude-router-service.js +160 -0
  142. package/dist/services/claude-router-service.js.map +1 -0
  143. package/dist/services/claudia-service.d.ts +77 -0
  144. package/dist/services/claudia-service.d.ts.map +1 -0
  145. package/dist/services/claudia-service.js +194 -0
  146. package/dist/services/claudia-service.js.map +1 -0
  147. package/dist/services/commands-service.d.ts +18 -0
  148. package/dist/services/commands-service.d.ts.map +1 -0
  149. package/dist/services/commands-service.js +76 -0
  150. package/dist/services/commands-service.js.map +1 -0
  151. package/dist/services/config-service.d.ts +68 -0
  152. package/dist/services/config-service.d.ts.map +1 -0
  153. package/dist/services/config-service.js +429 -0
  154. package/dist/services/config-service.js.map +1 -0
  155. package/dist/services/conversation-cache.d.ts +86 -0
  156. package/dist/services/conversation-cache.d.ts.map +1 -0
  157. package/dist/services/conversation-cache.js +235 -0
  158. package/dist/services/conversation-cache.js.map +1 -0
  159. package/dist/services/conversation-status-manager.d.ts +98 -0
  160. package/dist/services/conversation-status-manager.d.ts.map +1 -0
  161. package/dist/services/conversation-status-manager.js +295 -0
  162. package/dist/services/conversation-status-manager.js.map +1 -0
  163. package/dist/services/cost-tracker.d.ts +87 -0
  164. package/dist/services/cost-tracker.d.ts.map +1 -0
  165. package/dist/services/cost-tracker.js +335 -0
  166. package/dist/services/cost-tracker.js.map +1 -0
  167. package/dist/services/file-system-service.d.ts +61 -0
  168. package/dist/services/file-system-service.d.ts.map +1 -0
  169. package/dist/services/file-system-service.js +348 -0
  170. package/dist/services/file-system-service.js.map +1 -0
  171. package/dist/services/gemini-service.d.ts +72 -0
  172. package/dist/services/gemini-service.d.ts.map +1 -0
  173. package/dist/services/gemini-service.js +431 -0
  174. package/dist/services/gemini-service.js.map +1 -0
  175. package/dist/services/insight-queue.d.ts +99 -0
  176. package/dist/services/insight-queue.d.ts.map +1 -0
  177. package/dist/services/insight-queue.js +277 -0
  178. package/dist/services/insight-queue.js.map +1 -0
  179. package/dist/services/insights-service.d.ts +102 -0
  180. package/dist/services/insights-service.d.ts.map +1 -0
  181. package/dist/services/insights-service.js +1152 -0
  182. package/dist/services/insights-service.js.map +1 -0
  183. package/dist/services/json-lines-parser.d.ts +19 -0
  184. package/dist/services/json-lines-parser.d.ts.map +1 -0
  185. package/dist/services/json-lines-parser.js +56 -0
  186. package/dist/services/json-lines-parser.js.map +1 -0
  187. package/dist/services/license-service.d.ts +69 -0
  188. package/dist/services/license-service.d.ts.map +1 -0
  189. package/dist/services/license-service.js +330 -0
  190. package/dist/services/license-service.js.map +1 -0
  191. package/dist/services/log-formatter.d.ts +5 -0
  192. package/dist/services/log-formatter.d.ts.map +1 -0
  193. package/dist/services/log-formatter.js +77 -0
  194. package/dist/services/log-formatter.js.map +1 -0
  195. package/dist/services/log-stream-buffer.d.ts +11 -0
  196. package/dist/services/log-stream-buffer.d.ts.map +1 -0
  197. package/dist/services/log-stream-buffer.js +36 -0
  198. package/dist/services/log-stream-buffer.js.map +1 -0
  199. package/dist/services/logger.d.ts +71 -0
  200. package/dist/services/logger.d.ts.map +1 -0
  201. package/dist/services/logger.js +215 -0
  202. package/dist/services/logger.js.map +1 -0
  203. package/dist/services/mcp-config-generator.d.ts +32 -0
  204. package/dist/services/mcp-config-generator.d.ts.map +1 -0
  205. package/dist/services/mcp-config-generator.js +126 -0
  206. package/dist/services/mcp-config-generator.js.map +1 -0
  207. package/dist/services/message-filter.d.ts +22 -0
  208. package/dist/services/message-filter.d.ts.map +1 -0
  209. package/dist/services/message-filter.js +57 -0
  210. package/dist/services/message-filter.js.map +1 -0
  211. package/dist/services/notification-service.d.ts +45 -0
  212. package/dist/services/notification-service.d.ts.map +1 -0
  213. package/dist/services/notification-service.js +184 -0
  214. package/dist/services/notification-service.js.map +1 -0
  215. package/dist/services/permission-tracker.d.ts +67 -0
  216. package/dist/services/permission-tracker.d.ts.map +1 -0
  217. package/dist/services/permission-tracker.js +161 -0
  218. package/dist/services/permission-tracker.js.map +1 -0
  219. package/dist/services/process-manager-factory.d.ts +81 -0
  220. package/dist/services/process-manager-factory.d.ts.map +1 -0
  221. package/dist/services/process-manager-factory.js +211 -0
  222. package/dist/services/process-manager-factory.js.map +1 -0
  223. package/dist/services/question-tracker.d.ts +47 -0
  224. package/dist/services/question-tracker.d.ts.map +1 -0
  225. package/dist/services/question-tracker.js +105 -0
  226. package/dist/services/question-tracker.js.map +1 -0
  227. package/dist/services/session-activity-watcher.d.ts +33 -0
  228. package/dist/services/session-activity-watcher.d.ts.map +1 -0
  229. package/dist/services/session-activity-watcher.js +194 -0
  230. package/dist/services/session-activity-watcher.js.map +1 -0
  231. package/dist/services/session-info-service.d.ts +228 -0
  232. package/dist/services/session-info-service.d.ts.map +1 -0
  233. package/dist/services/session-info-service.js +920 -0
  234. package/dist/services/session-info-service.js.map +1 -0
  235. package/dist/services/session-insights-service.d.ts +119 -0
  236. package/dist/services/session-insights-service.d.ts.map +1 -0
  237. package/dist/services/session-insights-service.js +889 -0
  238. package/dist/services/session-insights-service.js.map +1 -0
  239. package/dist/services/stream-manager.d.ts +62 -0
  240. package/dist/services/stream-manager.d.ts.map +1 -0
  241. package/dist/services/stream-manager.js +239 -0
  242. package/dist/services/stream-manager.js.map +1 -0
  243. package/dist/services/web-push-service.d.ts +48 -0
  244. package/dist/services/web-push-service.d.ts.map +1 -0
  245. package/dist/services/web-push-service.js +186 -0
  246. package/dist/services/web-push-service.js.map +1 -0
  247. package/dist/services/working-directories-service.d.ts +19 -0
  248. package/dist/services/working-directories-service.d.ts.map +1 -0
  249. package/dist/services/working-directories-service.js +103 -0
  250. package/dist/services/working-directories-service.js.map +1 -0
  251. package/dist/types/config.d.ts +111 -0
  252. package/dist/types/config.d.ts.map +1 -0
  253. package/dist/types/config.js +14 -0
  254. package/dist/types/config.js.map +1 -0
  255. package/dist/types/express.d.ts +5 -0
  256. package/dist/types/express.d.ts.map +1 -0
  257. package/dist/types/express.js +2 -0
  258. package/dist/types/express.js.map +1 -0
  259. package/dist/types/index.d.ts +325 -0
  260. package/dist/types/index.d.ts.map +1 -0
  261. package/dist/types/index.js +18 -0
  262. package/dist/types/index.js.map +1 -0
  263. package/dist/types/insights.d.ts +99 -0
  264. package/dist/types/insights.d.ts.map +1 -0
  265. package/dist/types/insights.js +7 -0
  266. package/dist/types/insights.js.map +1 -0
  267. package/dist/types/license.d.ts +70 -0
  268. package/dist/types/license.d.ts.map +1 -0
  269. package/dist/types/license.js +5 -0
  270. package/dist/types/license.js.map +1 -0
  271. package/dist/types/router-config.d.ts +13 -0
  272. package/dist/types/router-config.d.ts.map +1 -0
  273. package/dist/types/router-config.js +2 -0
  274. package/dist/types/router-config.js.map +1 -0
  275. package/dist/utils/constants.d.ts +26 -0
  276. package/dist/utils/constants.d.ts.map +1 -0
  277. package/dist/utils/constants.js +28 -0
  278. package/dist/utils/constants.js.map +1 -0
  279. package/dist/utils/machine-id.d.ts +7 -0
  280. package/dist/utils/machine-id.d.ts.map +1 -0
  281. package/dist/utils/machine-id.js +76 -0
  282. package/dist/utils/machine-id.js.map +1 -0
  283. package/dist/utils/server-startup.d.ts +13 -0
  284. package/dist/utils/server-startup.d.ts.map +1 -0
  285. package/dist/utils/server-startup.js +20 -0
  286. package/dist/utils/server-startup.js.map +1 -0
  287. package/dist/web/assets/main-DAc2rjJ2.css +1 -0
  288. package/dist/web/assets/main-DvlZ02mT.js +137 -0
  289. package/dist/web/favicon.png +0 -0
  290. package/dist/web/favicon.svg +22 -0
  291. package/dist/web/icon-192x192.png +0 -0
  292. package/dist/web/icon-512x512.png +0 -0
  293. package/dist/web/index.html +36 -0
  294. package/dist/web/manifest.json +61 -0
  295. package/package.json +174 -0
  296. package/scripts/postinstall.js +30 -0
@@ -0,0 +1,920 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import Database from 'better-sqlite3';
4
+ import { CONFIG_DIR, CONFIG_DIR_NAME } from '../utils/constants.js';
5
+ import { createLogger } from './logger.js';
6
+ /**
7
+ * SessionInfoService manages session information using SQLite backend
8
+ * Stores session metadata including custom names in ~/.cui/session-info.db
9
+ * Provides fast lookups and updates for session-specific data
10
+ */
11
+ export class SessionInfoService {
12
+ static instance;
13
+ logger;
14
+ dbPath;
15
+ configDir;
16
+ isInitialized = false;
17
+ db;
18
+ getSessionStmt;
19
+ insertSessionStmt;
20
+ updateSessionStmt;
21
+ deleteSessionStmt;
22
+ getAllStmt;
23
+ countStmt;
24
+ archiveAllStmt;
25
+ setMetadataStmt;
26
+ getMetadataStmt;
27
+ // Insights statements
28
+ getInsightsStmt;
29
+ upsertInsightsStmt;
30
+ getAllInsightsStmt;
31
+ markInsightsStaleStmt;
32
+ getStaleInsightsStmt;
33
+ constructor(customConfigDir) {
34
+ this.logger = createLogger('SessionInfoService');
35
+ this.initializePaths(customConfigDir);
36
+ }
37
+ static getInstance() {
38
+ if (!SessionInfoService.instance) {
39
+ SessionInfoService.instance = new SessionInfoService();
40
+ }
41
+ return SessionInfoService.instance;
42
+ }
43
+ static resetInstance() {
44
+ if (SessionInfoService.instance) {
45
+ SessionInfoService.instance.isInitialized = false;
46
+ }
47
+ SessionInfoService.instance = null;
48
+ }
49
+ initializePaths(customConfigDir) {
50
+ if (customConfigDir) {
51
+ if (customConfigDir === ':memory:') {
52
+ this.configDir = ':memory:';
53
+ this.dbPath = ':memory:';
54
+ return;
55
+ }
56
+ this.configDir = path.join(customConfigDir, CONFIG_DIR_NAME);
57
+ }
58
+ else {
59
+ this.configDir = CONFIG_DIR;
60
+ }
61
+ this.dbPath = path.join(this.configDir, 'session-info.db');
62
+ this.logger.debug('Initializing paths', {
63
+ configDir: this.configDir,
64
+ dbPath: this.dbPath
65
+ });
66
+ }
67
+ async initialize() {
68
+ if (this.isInitialized) {
69
+ return;
70
+ }
71
+ try {
72
+ if (this.dbPath !== ':memory:' && !fs.existsSync(this.configDir)) {
73
+ fs.mkdirSync(this.configDir, { recursive: true });
74
+ this.logger.debug('Created config directory', { dir: this.configDir });
75
+ }
76
+ this.db = new Database(this.dbPath);
77
+ this.db.pragma('journal_mode = WAL');
78
+ this.db.exec(`
79
+ CREATE TABLE IF NOT EXISTS sessions (
80
+ session_id TEXT PRIMARY KEY,
81
+ custom_name TEXT NOT NULL DEFAULT '',
82
+ created_at TEXT NOT NULL,
83
+ updated_at TEXT NOT NULL,
84
+ version INTEGER NOT NULL,
85
+ pinned INTEGER NOT NULL DEFAULT 0,
86
+ archived INTEGER NOT NULL DEFAULT 0,
87
+ continuation_session_id TEXT NOT NULL DEFAULT '',
88
+ initial_commit_head TEXT NOT NULL DEFAULT '',
89
+ permission_mode TEXT NOT NULL DEFAULT 'default'
90
+ );
91
+ CREATE TABLE IF NOT EXISTS metadata (
92
+ key TEXT PRIMARY KEY,
93
+ value TEXT NOT NULL
94
+ );
95
+ CREATE TABLE IF NOT EXISTS session_insights (
96
+ session_id TEXT PRIMARY KEY,
97
+ description TEXT,
98
+ purposes TEXT NOT NULL DEFAULT '[]',
99
+ milestones TEXT NOT NULL DEFAULT '[]',
100
+ recent_actions TEXT NOT NULL DEFAULT '[]',
101
+ progress_completed INTEGER NOT NULL DEFAULT 0,
102
+ progress_total INTEGER NOT NULL DEFAULT 0,
103
+ outstanding_tasks TEXT NOT NULL DEFAULT '[]',
104
+ completed_tasks TEXT NOT NULL DEFAULT '[]',
105
+ current_task TEXT,
106
+ theme TEXT,
107
+ computed_at TEXT NOT NULL,
108
+ stale INTEGER NOT NULL DEFAULT 0
109
+ );
110
+ `);
111
+ // Migration: Add new columns if they don't exist (for existing databases)
112
+ this.migrateSessionsColumns();
113
+ this.migrateInsightsColumns();
114
+ this.prepareStatements();
115
+ this.ensureMetadata();
116
+ this.isInitialized = true;
117
+ }
118
+ catch (error) {
119
+ this.logger.error('Failed to initialize session info database', error);
120
+ throw new Error(`Session info database initialization failed: ${error instanceof Error ? error.message : String(error)}`);
121
+ }
122
+ }
123
+ migrateSessionsColumns() {
124
+ // Check if new columns exist on sessions table and add them if not
125
+ try {
126
+ const tableInfo = this.db.pragma('table_info(sessions)');
127
+ const columnNames = tableInfo.map(col => col.name);
128
+ if (!columnNames.includes('identity_image')) {
129
+ this.db.exec("ALTER TABLE sessions ADD COLUMN identity_image TEXT DEFAULT NULL");
130
+ this.logger.info('Added identity_image column to sessions');
131
+ }
132
+ }
133
+ catch (error) {
134
+ this.logger.debug('Sessions migration check failed', { error });
135
+ }
136
+ }
137
+ migrateInsightsColumns() {
138
+ // Check if new columns exist and add them if not
139
+ try {
140
+ const tableInfo = this.db.pragma('table_info(session_insights)');
141
+ const columnNames = tableInfo.map(col => col.name);
142
+ if (!columnNames.includes('purposes')) {
143
+ this.db.exec("ALTER TABLE session_insights ADD COLUMN purposes TEXT NOT NULL DEFAULT '[]'");
144
+ this.logger.info('Added purposes column to session_insights');
145
+ }
146
+ if (!columnNames.includes('milestones')) {
147
+ this.db.exec("ALTER TABLE session_insights ADD COLUMN milestones TEXT NOT NULL DEFAULT '[]'");
148
+ this.logger.info('Added milestones column to session_insights');
149
+ }
150
+ if (!columnNames.includes('recent_actions')) {
151
+ this.db.exec("ALTER TABLE session_insights ADD COLUMN recent_actions TEXT NOT NULL DEFAULT '[]'");
152
+ this.logger.info('Added recent_actions column to session_insights');
153
+ }
154
+ // New ontology columns
155
+ if (!columnNames.includes('context')) {
156
+ this.db.exec("ALTER TABLE session_insights ADD COLUMN context TEXT DEFAULT NULL");
157
+ this.logger.info('Added context column to session_insights');
158
+ }
159
+ if (!columnNames.includes('notable')) {
160
+ this.db.exec("ALTER TABLE session_insights ADD COLUMN notable TEXT NOT NULL DEFAULT '[]'");
161
+ this.logger.info('Added notable column to session_insights');
162
+ }
163
+ if (!columnNames.includes('tags')) {
164
+ this.db.exec("ALTER TABLE session_insights ADD COLUMN tags TEXT DEFAULT NULL");
165
+ this.logger.info('Added tags column to session_insights');
166
+ }
167
+ if (!columnNames.includes('panels')) {
168
+ this.db.exec("ALTER TABLE session_insights ADD COLUMN panels TEXT NOT NULL DEFAULT '[]'");
169
+ this.logger.info('Added panels column to session_insights');
170
+ }
171
+ // Delta detection metadata columns
172
+ if (!columnNames.includes('message_count')) {
173
+ this.db.exec("ALTER TABLE session_insights ADD COLUMN message_count INTEGER DEFAULT NULL");
174
+ this.logger.info('Added message_count column to session_insights');
175
+ }
176
+ if (!columnNames.includes('last_delta_check_at')) {
177
+ this.db.exec("ALTER TABLE session_insights ADD COLUMN last_delta_check_at TEXT DEFAULT NULL");
178
+ this.logger.info('Added last_delta_check_at column to session_insights');
179
+ }
180
+ if (!columnNames.includes('patched_at')) {
181
+ this.db.exec("ALTER TABLE session_insights ADD COLUMN patched_at TEXT DEFAULT NULL");
182
+ this.logger.info('Added patched_at column to session_insights');
183
+ }
184
+ if (!columnNames.includes('current_state')) {
185
+ this.db.exec("ALTER TABLE session_insights ADD COLUMN current_state TEXT DEFAULT NULL");
186
+ this.logger.info('Added current_state column to session_insights');
187
+ }
188
+ if (!columnNames.includes('last_patch_trace_id')) {
189
+ this.db.exec("ALTER TABLE session_insights ADD COLUMN last_patch_trace_id TEXT DEFAULT NULL");
190
+ this.logger.info('Added last_patch_trace_id column to session_insights');
191
+ }
192
+ }
193
+ catch (error) {
194
+ this.logger.debug('Migration check failed (table may not exist yet)', { error });
195
+ }
196
+ }
197
+ prepareStatements() {
198
+ this.getSessionStmt = this.db.prepare('SELECT * FROM sessions WHERE session_id = ?');
199
+ this.insertSessionStmt = this.db.prepare(`
200
+ INSERT INTO sessions (
201
+ session_id,
202
+ custom_name,
203
+ created_at,
204
+ updated_at,
205
+ version,
206
+ pinned,
207
+ archived,
208
+ continuation_session_id,
209
+ initial_commit_head,
210
+ permission_mode
211
+ ) VALUES (
212
+ @session_id,
213
+ @custom_name,
214
+ @created_at,
215
+ @updated_at,
216
+ @version,
217
+ @pinned,
218
+ @archived,
219
+ @continuation_session_id,
220
+ @initial_commit_head,
221
+ @permission_mode
222
+ )
223
+ `);
224
+ this.updateSessionStmt = this.db.prepare(`
225
+ UPDATE sessions SET
226
+ custom_name=@custom_name,
227
+ updated_at=@updated_at,
228
+ pinned=@pinned,
229
+ archived=@archived,
230
+ continuation_session_id=@continuation_session_id,
231
+ initial_commit_head=@initial_commit_head,
232
+ permission_mode=@permission_mode,
233
+ version=@version
234
+ WHERE session_id=@session_id
235
+ `);
236
+ this.deleteSessionStmt = this.db.prepare('DELETE FROM sessions WHERE session_id = ?');
237
+ this.getAllStmt = this.db.prepare('SELECT * FROM sessions');
238
+ this.countStmt = this.db.prepare('SELECT COUNT(*) as count FROM sessions');
239
+ this.archiveAllStmt = this.db.prepare('UPDATE sessions SET archived=1, updated_at=@updated_at WHERE archived=0');
240
+ this.setMetadataStmt = this.db.prepare('INSERT INTO metadata (key, value) VALUES (@key, @value) ON CONFLICT(key) DO UPDATE SET value=excluded.value');
241
+ this.getMetadataStmt = this.db.prepare('SELECT value FROM metadata WHERE key = ?');
242
+ // Insights statements
243
+ this.getInsightsStmt = this.db.prepare('SELECT * FROM session_insights WHERE session_id = ?');
244
+ this.upsertInsightsStmt = this.db.prepare(`
245
+ INSERT INTO session_insights (
246
+ session_id, description, context, current_state, last_patch_trace_id, purposes, milestones, notable, tags, recent_actions, panels,
247
+ progress_completed, progress_total,
248
+ outstanding_tasks, completed_tasks, current_task, theme, computed_at, stale,
249
+ message_count, last_delta_check_at, patched_at
250
+ ) VALUES (
251
+ @session_id, @description, @context, @current_state, @last_patch_trace_id, @purposes, @milestones, @notable, @tags, @recent_actions, @panels,
252
+ @progress_completed, @progress_total,
253
+ @outstanding_tasks, @completed_tasks, @current_task, @theme, @computed_at, @stale,
254
+ @message_count, @last_delta_check_at, @patched_at
255
+ ) ON CONFLICT(session_id) DO UPDATE SET
256
+ description=excluded.description,
257
+ context=excluded.context,
258
+ current_state=excluded.current_state,
259
+ last_patch_trace_id=excluded.last_patch_trace_id,
260
+ purposes=excluded.purposes,
261
+ milestones=excluded.milestones,
262
+ notable=excluded.notable,
263
+ tags=excluded.tags,
264
+ recent_actions=excluded.recent_actions,
265
+ panels=excluded.panels,
266
+ progress_completed=excluded.progress_completed,
267
+ progress_total=excluded.progress_total,
268
+ outstanding_tasks=excluded.outstanding_tasks,
269
+ completed_tasks=excluded.completed_tasks,
270
+ current_task=excluded.current_task,
271
+ theme=excluded.theme,
272
+ computed_at=excluded.computed_at,
273
+ stale=excluded.stale,
274
+ message_count=excluded.message_count,
275
+ last_delta_check_at=excluded.last_delta_check_at,
276
+ patched_at=excluded.patched_at
277
+ `);
278
+ this.getAllInsightsStmt = this.db.prepare('SELECT * FROM session_insights');
279
+ this.markInsightsStaleStmt = this.db.prepare('UPDATE session_insights SET stale=1 WHERE session_id = ?');
280
+ this.getStaleInsightsStmt = this.db.prepare('SELECT session_id FROM session_insights WHERE stale = 1');
281
+ }
282
+ ensureMetadata() {
283
+ const now = new Date().toISOString();
284
+ const schema = this.getMetadataStmt.get('schema_version');
285
+ if (!schema) {
286
+ this.setMetadataStmt.run({ key: 'schema_version', value: '3' });
287
+ this.setMetadataStmt.run({ key: 'created_at', value: now });
288
+ this.setMetadataStmt.run({ key: 'last_updated', value: now });
289
+ }
290
+ }
291
+ mapRow(row) {
292
+ return {
293
+ custom_name: row.custom_name,
294
+ created_at: row.created_at,
295
+ updated_at: row.updated_at,
296
+ version: row.version,
297
+ pinned: !!row.pinned,
298
+ archived: !!row.archived,
299
+ continuation_session_id: row.continuation_session_id,
300
+ initial_commit_head: row.initial_commit_head,
301
+ permission_mode: row.permission_mode,
302
+ identity_image: row.identity_image ?? undefined
303
+ };
304
+ }
305
+ async getSessionInfo(sessionId) {
306
+ try {
307
+ const row = this.getSessionStmt.get(sessionId);
308
+ if (row) {
309
+ return this.mapRow(row);
310
+ }
311
+ const now = new Date().toISOString();
312
+ const defaultSession = {
313
+ custom_name: '',
314
+ created_at: now,
315
+ updated_at: now,
316
+ version: 3,
317
+ pinned: false,
318
+ archived: false,
319
+ continuation_session_id: '',
320
+ initial_commit_head: '',
321
+ permission_mode: 'default'
322
+ };
323
+ this.insertSessionStmt.run({
324
+ session_id: sessionId,
325
+ custom_name: '',
326
+ created_at: now,
327
+ updated_at: now,
328
+ version: 3,
329
+ pinned: 0,
330
+ archived: 0,
331
+ continuation_session_id: '',
332
+ initial_commit_head: '',
333
+ permission_mode: 'default'
334
+ });
335
+ this.setMetadataStmt.run({ key: 'last_updated', value: now });
336
+ return defaultSession;
337
+ }
338
+ catch (error) {
339
+ this.logger.error('Failed to get session info', { sessionId, error });
340
+ const now = new Date().toISOString();
341
+ return {
342
+ custom_name: '',
343
+ created_at: now,
344
+ updated_at: now,
345
+ version: 3,
346
+ pinned: false,
347
+ archived: false,
348
+ continuation_session_id: '',
349
+ initial_commit_head: '',
350
+ permission_mode: 'default'
351
+ };
352
+ }
353
+ }
354
+ async updateSessionInfo(sessionId, updates) {
355
+ try {
356
+ const existingRow = this.getSessionStmt.get(sessionId);
357
+ const now = new Date().toISOString();
358
+ if (existingRow) {
359
+ const updatedSession = {
360
+ ...this.mapRow(existingRow),
361
+ ...updates,
362
+ updated_at: now
363
+ };
364
+ this.updateSessionStmt.run({
365
+ session_id: sessionId,
366
+ custom_name: updatedSession.custom_name,
367
+ updated_at: updatedSession.updated_at,
368
+ pinned: updatedSession.pinned ? 1 : 0,
369
+ archived: updatedSession.archived ? 1 : 0,
370
+ continuation_session_id: updatedSession.continuation_session_id,
371
+ initial_commit_head: updatedSession.initial_commit_head,
372
+ permission_mode: updatedSession.permission_mode,
373
+ version: updatedSession.version
374
+ });
375
+ this.setMetadataStmt.run({ key: 'last_updated', value: now });
376
+ return updatedSession;
377
+ }
378
+ else {
379
+ const newSession = {
380
+ custom_name: '',
381
+ created_at: now,
382
+ updated_at: now,
383
+ version: 3,
384
+ pinned: false,
385
+ archived: false,
386
+ continuation_session_id: '',
387
+ initial_commit_head: '',
388
+ permission_mode: 'default',
389
+ ...updates
390
+ };
391
+ this.insertSessionStmt.run({
392
+ session_id: sessionId,
393
+ custom_name: newSession.custom_name,
394
+ created_at: newSession.created_at,
395
+ updated_at: newSession.updated_at,
396
+ version: newSession.version,
397
+ pinned: newSession.pinned ? 1 : 0,
398
+ archived: newSession.archived ? 1 : 0,
399
+ continuation_session_id: newSession.continuation_session_id,
400
+ initial_commit_head: newSession.initial_commit_head,
401
+ permission_mode: newSession.permission_mode
402
+ });
403
+ this.setMetadataStmt.run({ key: 'last_updated', value: now });
404
+ return newSession;
405
+ }
406
+ }
407
+ catch (error) {
408
+ this.logger.error('Failed to update session info', { sessionId, updates, error });
409
+ throw new Error(`Failed to update session info: ${error instanceof Error ? error.message : String(error)}`);
410
+ }
411
+ }
412
+ async updateCustomName(sessionId, customName) {
413
+ await this.updateSessionInfo(sessionId, { custom_name: customName });
414
+ }
415
+ /**
416
+ * Set the identity image for a session. This is a one-time operation
417
+ * that doesn't update the session's updated_at timestamp.
418
+ */
419
+ async setIdentityImage(sessionId, imageData) {
420
+ try {
421
+ const stmt = this.db.prepare('UPDATE sessions SET identity_image = ? WHERE session_id = ?');
422
+ stmt.run(imageData, sessionId);
423
+ this.logger.debug('Identity image set for session', { sessionId });
424
+ }
425
+ catch (error) {
426
+ this.logger.error('Failed to set identity image', { sessionId, error });
427
+ throw new Error(`Failed to set identity image: ${error instanceof Error ? error.message : String(error)}`);
428
+ }
429
+ }
430
+ /**
431
+ * Check if a session already has an identity image.
432
+ */
433
+ async hasIdentityImage(sessionId) {
434
+ try {
435
+ const row = this.getSessionStmt.get(sessionId);
436
+ return row?.identity_image != null;
437
+ }
438
+ catch (error) {
439
+ this.logger.error('Failed to check identity image', { sessionId, error });
440
+ return false;
441
+ }
442
+ }
443
+ async deleteSession(sessionId) {
444
+ this.logger.info('Deleting session info', { sessionId });
445
+ try {
446
+ const result = this.deleteSessionStmt.run(sessionId);
447
+ if (result.changes > 0) {
448
+ const now = new Date().toISOString();
449
+ this.setMetadataStmt.run({ key: 'last_updated', value: now });
450
+ this.logger.info('Session info deleted successfully', { sessionId });
451
+ }
452
+ else {
453
+ this.logger.debug('Session info not found for deletion', { sessionId });
454
+ }
455
+ }
456
+ catch (error) {
457
+ this.logger.error('Failed to delete session info', { sessionId, error });
458
+ throw new Error(`Failed to delete session info: ${error instanceof Error ? error.message : String(error)}`);
459
+ }
460
+ }
461
+ async getAllSessionInfo() {
462
+ this.logger.debug('Getting all session info');
463
+ try {
464
+ const rows = this.getAllStmt.all();
465
+ const result = {};
466
+ for (const row of rows) {
467
+ result[row.session_id] = this.mapRow(row);
468
+ }
469
+ return result;
470
+ }
471
+ catch (error) {
472
+ this.logger.error('Failed to get all session info', error);
473
+ return {};
474
+ }
475
+ }
476
+ async getStats() {
477
+ try {
478
+ const countRow = this.countStmt.get();
479
+ let dbSize = 0;
480
+ if (this.dbPath !== ':memory:') {
481
+ try {
482
+ const stats = fs.statSync(this.dbPath);
483
+ dbSize = stats.size;
484
+ }
485
+ catch {
486
+ dbSize = 0;
487
+ }
488
+ }
489
+ const lastUpdatedRow = this.getMetadataStmt.get('last_updated');
490
+ return {
491
+ sessionCount: countRow.count,
492
+ dbSize,
493
+ lastUpdated: lastUpdatedRow?.value || new Date().toISOString()
494
+ };
495
+ }
496
+ catch (error) {
497
+ this.logger.error('Failed to get database stats', error);
498
+ return {
499
+ sessionCount: 0,
500
+ dbSize: 0,
501
+ lastUpdated: new Date().toISOString()
502
+ };
503
+ }
504
+ }
505
+ reinitializePaths(customConfigDir) {
506
+ this.initializePaths(customConfigDir);
507
+ }
508
+ getDbPath() {
509
+ return this.dbPath;
510
+ }
511
+ getConfigDir() {
512
+ return this.configDir;
513
+ }
514
+ async archiveAllSessions() {
515
+ this.logger.info('Archiving all sessions');
516
+ try {
517
+ const now = new Date().toISOString();
518
+ const transaction = this.db.transaction(() => {
519
+ const info = this.archiveAllStmt.run({ updated_at: now });
520
+ if (info.changes > 0) {
521
+ this.setMetadataStmt.run({ key: 'last_updated', value: now });
522
+ }
523
+ return info.changes;
524
+ });
525
+ const archivedCount = transaction();
526
+ this.logger.info('Sessions archived successfully', { archivedCount });
527
+ return archivedCount;
528
+ }
529
+ catch (error) {
530
+ this.logger.error('Failed to archive all sessions', error);
531
+ throw new Error(`Failed to archive all sessions: ${error instanceof Error ? error.message : String(error)}`);
532
+ }
533
+ }
534
+ async syncMissingSessions(sessionIds) {
535
+ try {
536
+ const now = new Date().toISOString();
537
+ const insert = this.db.prepare(`
538
+ INSERT OR IGNORE INTO sessions (
539
+ session_id,
540
+ custom_name,
541
+ created_at,
542
+ updated_at,
543
+ version,
544
+ pinned,
545
+ archived,
546
+ continuation_session_id,
547
+ initial_commit_head,
548
+ permission_mode
549
+ ) VALUES (
550
+ @session_id,
551
+ '',
552
+ @now,
553
+ @now,
554
+ 3,
555
+ 0,
556
+ 0,
557
+ '',
558
+ '',
559
+ 'default'
560
+ )
561
+ `);
562
+ const transaction = this.db.transaction((ids) => {
563
+ let inserted = 0;
564
+ for (const id of ids) {
565
+ const info = insert.run({ session_id: id, now });
566
+ if (info.changes > 0)
567
+ inserted++;
568
+ }
569
+ if (inserted > 0) {
570
+ this.setMetadataStmt.run({ key: 'last_updated', value: now });
571
+ }
572
+ return inserted;
573
+ });
574
+ return transaction(sessionIds);
575
+ }
576
+ catch (error) {
577
+ this.logger.error('Failed to sync missing sessions', error);
578
+ throw new Error(`Failed to sync missing sessions: ${error instanceof Error ? error.message : String(error)}`);
579
+ }
580
+ }
581
+ // ==================== INSIGHTS METHODS ====================
582
+ mapInsightsRow(row) {
583
+ return {
584
+ session_id: row.session_id,
585
+ description: row.description,
586
+ context: row.context ? JSON.parse(row.context) : null,
587
+ current_state: row.current_state ? JSON.parse(row.current_state) : null,
588
+ last_patch_trace_id: row.last_patch_trace_id ?? null,
589
+ purposes: JSON.parse(row.purposes || '[]'),
590
+ milestones: JSON.parse(row.milestones || '[]'),
591
+ notable: JSON.parse(row.notable || '[]'),
592
+ tags: row.tags ? JSON.parse(row.tags) : null,
593
+ recent_actions: JSON.parse(row.recent_actions || '[]'),
594
+ panels: JSON.parse(row.panels || '[]'),
595
+ progress_completed: row.progress_completed,
596
+ progress_total: row.progress_total,
597
+ outstanding_tasks: JSON.parse(row.outstanding_tasks || '[]'),
598
+ completed_tasks: JSON.parse(row.completed_tasks || '[]'),
599
+ current_task: row.current_task,
600
+ theme: row.theme,
601
+ computed_at: row.computed_at,
602
+ stale: !!row.stale,
603
+ message_count: row.message_count ?? undefined,
604
+ last_delta_check_at: row.last_delta_check_at ?? undefined,
605
+ patched_at: row.patched_at ?? undefined
606
+ };
607
+ }
608
+ async getInsights(sessionId) {
609
+ try {
610
+ const row = this.getInsightsStmt.get(sessionId);
611
+ if (row) {
612
+ return this.mapInsightsRow(row);
613
+ }
614
+ return null;
615
+ }
616
+ catch (error) {
617
+ this.logger.error('Failed to get insights', { sessionId, error });
618
+ return null;
619
+ }
620
+ }
621
+ async setInsights(insights) {
622
+ try {
623
+ this.upsertInsightsStmt.run({
624
+ session_id: insights.session_id,
625
+ description: insights.description,
626
+ context: insights.context ? JSON.stringify(insights.context) : null,
627
+ current_state: insights.current_state ? JSON.stringify(insights.current_state) : null,
628
+ last_patch_trace_id: insights.last_patch_trace_id ?? null,
629
+ purposes: JSON.stringify(insights.purposes || []),
630
+ milestones: JSON.stringify(insights.milestones || []),
631
+ notable: JSON.stringify(insights.notable || []),
632
+ tags: insights.tags ? JSON.stringify(insights.tags) : null,
633
+ recent_actions: JSON.stringify(insights.recent_actions || []),
634
+ panels: JSON.stringify(insights.panels || []),
635
+ progress_completed: insights.progress_completed,
636
+ progress_total: insights.progress_total,
637
+ outstanding_tasks: JSON.stringify(insights.outstanding_tasks),
638
+ completed_tasks: JSON.stringify(insights.completed_tasks),
639
+ current_task: insights.current_task,
640
+ theme: insights.theme,
641
+ computed_at: insights.computed_at,
642
+ stale: insights.stale ? 1 : 0,
643
+ message_count: insights.message_count ?? null,
644
+ last_delta_check_at: insights.last_delta_check_at ?? null,
645
+ patched_at: insights.patched_at ?? null
646
+ });
647
+ this.logger.debug('Insights cached', { sessionId: insights.session_id });
648
+ }
649
+ catch (error) {
650
+ this.logger.error('Failed to set insights', { sessionId: insights.session_id, error });
651
+ throw error;
652
+ }
653
+ }
654
+ async getAllInsights() {
655
+ try {
656
+ const rows = this.getAllInsightsStmt.all();
657
+ const result = new Map();
658
+ for (const row of rows) {
659
+ result.set(row.session_id, this.mapInsightsRow(row));
660
+ }
661
+ return result;
662
+ }
663
+ catch (error) {
664
+ this.logger.error('Failed to get all insights', error);
665
+ return new Map();
666
+ }
667
+ }
668
+ async markInsightsStale(sessionId) {
669
+ try {
670
+ this.markInsightsStaleStmt.run(sessionId);
671
+ }
672
+ catch (error) {
673
+ this.logger.error('Failed to mark insights stale', { sessionId, error });
674
+ }
675
+ }
676
+ async getStaleSessionIds() {
677
+ try {
678
+ const rows = this.getStaleInsightsStmt.all();
679
+ return rows.map(r => r.session_id);
680
+ }
681
+ catch (error) {
682
+ this.logger.error('Failed to get stale session IDs', error);
683
+ return [];
684
+ }
685
+ }
686
+ async getMissingInsightsSessionIds(sessionIds) {
687
+ try {
688
+ const existing = await this.getAllInsights();
689
+ return sessionIds.filter(id => !existing.has(id));
690
+ }
691
+ catch (error) {
692
+ this.logger.error('Failed to get missing insights session IDs', error);
693
+ return sessionIds;
694
+ }
695
+ }
696
+ /**
697
+ * Get all non-archived session IDs (for refresh operations)
698
+ */
699
+ getNonArchivedSessionIds() {
700
+ try {
701
+ const rows = this.db.prepare('SELECT session_id FROM sessions WHERE archived = 0').all();
702
+ return rows.map(r => r.session_id);
703
+ }
704
+ catch (error) {
705
+ this.logger.error('Failed to get non-archived session IDs', error);
706
+ return [];
707
+ }
708
+ }
709
+ /**
710
+ * Audit insight regeneration for debugging (legacy method)
711
+ */
712
+ auditRegeneration(params) {
713
+ try {
714
+ // Ensure audit table exists
715
+ this.db.exec(`
716
+ CREATE TABLE IF NOT EXISTS insight_audit (
717
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
718
+ session_id TEXT NOT NULL,
719
+ action TEXT NOT NULL,
720
+ reason TEXT,
721
+ old_mission TEXT,
722
+ new_mission TEXT,
723
+ old_theme TEXT,
724
+ new_theme TEXT,
725
+ message_count INTEGER,
726
+ created_at TEXT DEFAULT CURRENT_TIMESTAMP
727
+ )
728
+ `);
729
+ this.db.prepare(`
730
+ INSERT INTO insight_audit (session_id, action, reason, old_mission, new_mission, old_theme, new_theme, message_count)
731
+ VALUES (@sessionId, @action, @reason, @oldMission, @newMission, @oldTheme, @newTheme, @messageCount)
732
+ `).run({
733
+ sessionId: params.sessionId,
734
+ action: params.action,
735
+ reason: params.reason,
736
+ oldMission: params.oldMission || null,
737
+ newMission: params.newMission || null,
738
+ oldTheme: params.oldTheme || null,
739
+ newTheme: params.newTheme || null,
740
+ messageCount: params.messageCount || null
741
+ });
742
+ }
743
+ catch (error) {
744
+ this.logger.debug('Failed to audit regeneration', { error });
745
+ }
746
+ }
747
+ /**
748
+ * Audit event-driven insight operations with full context for debugging.
749
+ * This captures trace IDs, action content, and before/after state snapshots.
750
+ */
751
+ auditEventInsight(params) {
752
+ try {
753
+ // Ensure extended audit table exists with new columns
754
+ this.db.exec(`
755
+ CREATE TABLE IF NOT EXISTS insight_event_audit (
756
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
757
+ trace_id TEXT NOT NULL,
758
+ session_id TEXT NOT NULL,
759
+ event_type TEXT NOT NULL,
760
+ trigger TEXT NOT NULL,
761
+ action_content TEXT,
762
+ before_state TEXT,
763
+ after_state TEXT,
764
+ llm_response TEXT,
765
+ patched_fields TEXT,
766
+ duration_ms INTEGER,
767
+ skipped_reason TEXT,
768
+ created_at TEXT DEFAULT CURRENT_TIMESTAMP
769
+ )
770
+ `);
771
+ // Create index on trace_id for fast lookups
772
+ this.db.exec(`
773
+ CREATE INDEX IF NOT EXISTS idx_insight_event_audit_trace_id ON insight_event_audit(trace_id)
774
+ `);
775
+ this.db.exec(`
776
+ CREATE INDEX IF NOT EXISTS idx_insight_event_audit_session_id ON insight_event_audit(session_id)
777
+ `);
778
+ this.db.prepare(`
779
+ INSERT INTO insight_event_audit (
780
+ trace_id, session_id, event_type, trigger,
781
+ action_content, before_state, after_state,
782
+ llm_response, patched_fields, duration_ms, skipped_reason
783
+ ) VALUES (
784
+ @traceId, @sessionId, @eventType, @trigger,
785
+ @actionContent, @beforeState, @afterState,
786
+ @llmResponse, @patchedFields, @durationMs, @skippedReason
787
+ )
788
+ `).run({
789
+ traceId: params.traceId,
790
+ sessionId: params.sessionId,
791
+ eventType: params.eventType,
792
+ trigger: params.trigger,
793
+ actionContent: params.actionContent ? JSON.stringify(params.actionContent) : null,
794
+ beforeState: params.beforeState ? JSON.stringify(params.beforeState) : null,
795
+ afterState: params.afterState ? JSON.stringify(params.afterState) : null,
796
+ llmResponse: params.llmResponse || null,
797
+ patchedFields: params.patchedFields ? JSON.stringify(params.patchedFields) : null,
798
+ durationMs: params.durationMs || null,
799
+ skippedReason: params.skippedReason || null
800
+ });
801
+ }
802
+ catch (error) {
803
+ this.logger.debug('Failed to audit event insight', { error });
804
+ }
805
+ }
806
+ /**
807
+ * Get event audit history by trace ID (for debugging a specific event chain)
808
+ */
809
+ getEventAuditByTraceId(traceId) {
810
+ try {
811
+ const rows = this.db.prepare(`
812
+ SELECT * FROM insight_event_audit
813
+ WHERE trace_id = ?
814
+ ORDER BY created_at ASC
815
+ `).all(traceId);
816
+ return rows.map(r => ({
817
+ traceId: r.trace_id,
818
+ sessionId: r.session_id,
819
+ eventType: r.event_type,
820
+ trigger: r.trigger,
821
+ actionContent: r.action_content ? JSON.parse(r.action_content) : null,
822
+ beforeState: r.before_state ? JSON.parse(r.before_state) : null,
823
+ afterState: r.after_state ? JSON.parse(r.after_state) : null,
824
+ llmResponse: r.llm_response,
825
+ patchedFields: r.patched_fields ? JSON.parse(r.patched_fields) : null,
826
+ durationMs: r.duration_ms,
827
+ skippedReason: r.skipped_reason,
828
+ createdAt: r.created_at
829
+ }));
830
+ }
831
+ catch (error) {
832
+ this.logger.debug('Failed to get event audit by trace ID', { error });
833
+ return [];
834
+ }
835
+ }
836
+ /**
837
+ * Get recent event audit history for a session
838
+ */
839
+ getRecentEventAudit(sessionId, limit = 50) {
840
+ try {
841
+ const rows = this.db.prepare(`
842
+ SELECT trace_id, event_type, trigger, patched_fields, duration_ms, skipped_reason, created_at
843
+ FROM insight_event_audit
844
+ WHERE session_id = ?
845
+ ORDER BY created_at DESC
846
+ LIMIT ?
847
+ `).all(sessionId, limit);
848
+ return rows.map(r => ({
849
+ traceId: r.trace_id,
850
+ eventType: r.event_type,
851
+ trigger: r.trigger,
852
+ patchedFields: r.patched_fields ? JSON.parse(r.patched_fields) : null,
853
+ durationMs: r.duration_ms,
854
+ skippedReason: r.skipped_reason,
855
+ createdAt: r.created_at
856
+ }));
857
+ }
858
+ catch (error) {
859
+ this.logger.debug('Failed to get recent event audit', { error });
860
+ return [];
861
+ }
862
+ }
863
+ /**
864
+ * Get all audit history across all sessions
865
+ */
866
+ getAllAuditHistory(limit = 100) {
867
+ try {
868
+ const rows = this.db.prepare(`
869
+ SELECT session_id, action, reason, old_mission, new_mission, old_theme, new_theme, message_count, created_at
870
+ FROM insight_audit
871
+ ORDER BY created_at DESC
872
+ LIMIT ?
873
+ `).all(limit);
874
+ return rows.map(r => ({
875
+ sessionId: r.session_id,
876
+ action: r.action,
877
+ reason: r.reason,
878
+ oldMission: r.old_mission,
879
+ newMission: r.new_mission,
880
+ oldTheme: r.old_theme,
881
+ newTheme: r.new_theme,
882
+ messageCount: r.message_count,
883
+ createdAt: r.created_at
884
+ }));
885
+ }
886
+ catch (error) {
887
+ this.logger.debug('Failed to get all audit history', { error });
888
+ return [];
889
+ }
890
+ }
891
+ /**
892
+ * Get audit history for a session
893
+ */
894
+ getAuditHistory(sessionId, limit = 50) {
895
+ try {
896
+ const rows = this.db.prepare(`
897
+ SELECT action, reason, old_mission, new_mission, old_theme, new_theme, message_count, created_at
898
+ FROM insight_audit
899
+ WHERE session_id = ?
900
+ ORDER BY created_at DESC
901
+ LIMIT ?
902
+ `).all(sessionId, limit);
903
+ return rows.map(r => ({
904
+ action: r.action,
905
+ reason: r.reason,
906
+ oldMission: r.old_mission,
907
+ newMission: r.new_mission,
908
+ oldTheme: r.old_theme,
909
+ newTheme: r.new_theme,
910
+ messageCount: r.message_count,
911
+ createdAt: r.created_at
912
+ }));
913
+ }
914
+ catch (error) {
915
+ this.logger.debug('Failed to get audit history', { error });
916
+ return [];
917
+ }
918
+ }
919
+ }
920
+ //# sourceMappingURL=session-info-service.js.map