@agentlensai/server 0.3.0 → 0.6.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 (259) hide show
  1. package/dist/db/embedding-store.d.ts +74 -0
  2. package/dist/db/embedding-store.d.ts.map +1 -0
  3. package/dist/db/embedding-store.js +177 -0
  4. package/dist/db/embedding-store.js.map +1 -0
  5. package/dist/db/health-snapshot-store.d.ts +33 -0
  6. package/dist/db/health-snapshot-store.d.ts.map +1 -0
  7. package/dist/db/health-snapshot-store.js +112 -0
  8. package/dist/db/health-snapshot-store.js.map +1 -0
  9. package/dist/db/lesson-store.d.ts +57 -0
  10. package/dist/db/lesson-store.d.ts.map +1 -0
  11. package/dist/db/lesson-store.js +217 -0
  12. package/dist/db/lesson-store.js.map +1 -0
  13. package/dist/db/migrate.d.ts.map +1 -1
  14. package/dist/db/migrate.js +256 -8
  15. package/dist/db/migrate.js.map +1 -1
  16. package/dist/db/schema.sqlite.d.ts +822 -47
  17. package/dist/db/schema.sqlite.d.ts.map +1 -1
  18. package/dist/db/schema.sqlite.js +79 -4
  19. package/dist/db/schema.sqlite.js.map +1 -1
  20. package/dist/db/session-summary-store.d.ts +45 -0
  21. package/dist/db/session-summary-store.d.ts.map +1 -0
  22. package/dist/db/session-summary-store.js +112 -0
  23. package/dist/db/session-summary-store.js.map +1 -0
  24. package/dist/db/sqlite-store.d.ts +19 -12
  25. package/dist/db/sqlite-store.d.ts.map +1 -1
  26. package/dist/db/sqlite-store.js +145 -44
  27. package/dist/db/sqlite-store.js.map +1 -1
  28. package/dist/db/tenant-scoped-store.d.ts +61 -0
  29. package/dist/db/tenant-scoped-store.d.ts.map +1 -0
  30. package/dist/db/tenant-scoped-store.js +94 -0
  31. package/dist/db/tenant-scoped-store.js.map +1 -0
  32. package/dist/index.d.ts +18 -2
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +78 -5
  35. package/dist/index.js.map +1 -1
  36. package/dist/lib/alert-engine.d.ts +11 -0
  37. package/dist/lib/alert-engine.d.ts.map +1 -1
  38. package/dist/lib/alert-engine.js +65 -24
  39. package/dist/lib/alert-engine.js.map +1 -1
  40. package/dist/lib/analysis/cost-analysis.d.ts +20 -0
  41. package/dist/lib/analysis/cost-analysis.d.ts.map +1 -0
  42. package/dist/lib/analysis/cost-analysis.js +161 -0
  43. package/dist/lib/analysis/cost-analysis.js.map +1 -0
  44. package/dist/lib/analysis/error-patterns.d.ts +26 -0
  45. package/dist/lib/analysis/error-patterns.d.ts.map +1 -0
  46. package/dist/lib/analysis/error-patterns.js +158 -0
  47. package/dist/lib/analysis/error-patterns.js.map +1 -0
  48. package/dist/lib/analysis/index.d.ts +23 -0
  49. package/dist/lib/analysis/index.d.ts.map +1 -0
  50. package/dist/lib/analysis/index.js +144 -0
  51. package/dist/lib/analysis/index.js.map +1 -0
  52. package/dist/lib/analysis/performance-trends.d.ts +19 -0
  53. package/dist/lib/analysis/performance-trends.d.ts.map +1 -0
  54. package/dist/lib/analysis/performance-trends.js +121 -0
  55. package/dist/lib/analysis/performance-trends.js.map +1 -0
  56. package/dist/lib/analysis/tool-sequences.d.ts +19 -0
  57. package/dist/lib/analysis/tool-sequences.d.ts.map +1 -0
  58. package/dist/lib/analysis/tool-sequences.js +148 -0
  59. package/dist/lib/analysis/tool-sequences.js.map +1 -0
  60. package/dist/lib/context/index.d.ts +5 -0
  61. package/dist/lib/context/index.d.ts.map +1 -0
  62. package/dist/lib/context/index.js +5 -0
  63. package/dist/lib/context/index.js.map +1 -0
  64. package/dist/lib/context/retrieval.d.ts +60 -0
  65. package/dist/lib/context/retrieval.d.ts.map +1 -0
  66. package/dist/lib/context/retrieval.js +233 -0
  67. package/dist/lib/context/retrieval.js.map +1 -0
  68. package/dist/lib/embeddings/index.d.ts +31 -0
  69. package/dist/lib/embeddings/index.d.ts.map +1 -0
  70. package/dist/lib/embeddings/index.js +31 -0
  71. package/dist/lib/embeddings/index.js.map +1 -0
  72. package/dist/lib/embeddings/local.d.ts +15 -0
  73. package/dist/lib/embeddings/local.d.ts.map +1 -0
  74. package/dist/lib/embeddings/local.js +65 -0
  75. package/dist/lib/embeddings/local.js.map +1 -0
  76. package/dist/lib/embeddings/math.d.ts +13 -0
  77. package/dist/lib/embeddings/math.d.ts.map +1 -0
  78. package/dist/lib/embeddings/math.js +35 -0
  79. package/dist/lib/embeddings/math.js.map +1 -0
  80. package/dist/lib/embeddings/openai.d.ts +15 -0
  81. package/dist/lib/embeddings/openai.d.ts.map +1 -0
  82. package/dist/lib/embeddings/openai.js +58 -0
  83. package/dist/lib/embeddings/openai.js.map +1 -0
  84. package/dist/lib/embeddings/summarizer.d.ts +26 -0
  85. package/dist/lib/embeddings/summarizer.d.ts.map +1 -0
  86. package/dist/lib/embeddings/summarizer.js +181 -0
  87. package/dist/lib/embeddings/summarizer.js.map +1 -0
  88. package/dist/lib/embeddings/types.d.ts +17 -0
  89. package/dist/lib/embeddings/types.d.ts.map +1 -0
  90. package/dist/lib/embeddings/types.js +5 -0
  91. package/dist/lib/embeddings/types.js.map +1 -0
  92. package/dist/lib/embeddings/worker.d.ts +56 -0
  93. package/dist/lib/embeddings/worker.d.ts.map +1 -0
  94. package/dist/lib/embeddings/worker.js +109 -0
  95. package/dist/lib/embeddings/worker.js.map +1 -0
  96. package/dist/lib/health/computer.d.ts +28 -0
  97. package/dist/lib/health/computer.d.ts.map +1 -0
  98. package/dist/lib/health/computer.js +270 -0
  99. package/dist/lib/health/computer.js.map +1 -0
  100. package/dist/lib/optimization/classifier.d.ts +34 -0
  101. package/dist/lib/optimization/classifier.d.ts.map +1 -0
  102. package/dist/lib/optimization/classifier.js +108 -0
  103. package/dist/lib/optimization/classifier.js.map +1 -0
  104. package/dist/lib/optimization/engine.d.ts +24 -0
  105. package/dist/lib/optimization/engine.d.ts.map +1 -0
  106. package/dist/lib/optimization/engine.js +202 -0
  107. package/dist/lib/optimization/engine.js.map +1 -0
  108. package/dist/lib/optimization/index.d.ts +10 -0
  109. package/dist/lib/optimization/index.d.ts.map +1 -0
  110. package/dist/lib/optimization/index.js +9 -0
  111. package/dist/lib/optimization/index.js.map +1 -0
  112. package/dist/lib/sse.d.ts +1 -0
  113. package/dist/lib/sse.d.ts.map +1 -1
  114. package/dist/lib/sse.js +8 -1
  115. package/dist/lib/sse.js.map +1 -1
  116. package/dist/middleware/auth.d.ts +1 -0
  117. package/dist/middleware/auth.d.ts.map +1 -1
  118. package/dist/middleware/auth.js +2 -1
  119. package/dist/middleware/auth.js.map +1 -1
  120. package/dist/routes/agents.d.ts.map +1 -1
  121. package/dist/routes/agents.js +6 -3
  122. package/dist/routes/agents.js.map +1 -1
  123. package/dist/routes/alerts.d.ts.map +1 -1
  124. package/dist/routes/alerts.js +15 -7
  125. package/dist/routes/alerts.js.map +1 -1
  126. package/dist/routes/analytics.d.ts.map +1 -1
  127. package/dist/routes/analytics.js +16 -2
  128. package/dist/routes/analytics.js.map +1 -1
  129. package/dist/routes/api-keys.d.ts.map +1 -1
  130. package/dist/routes/api-keys.js +30 -5
  131. package/dist/routes/api-keys.js.map +1 -1
  132. package/dist/routes/context.d.ts +23 -0
  133. package/dist/routes/context.d.ts.map +1 -0
  134. package/dist/routes/context.js +52 -0
  135. package/dist/routes/context.js.map +1 -0
  136. package/dist/routes/events.d.ts +6 -1
  137. package/dist/routes/events.d.ts.map +1 -1
  138. package/dist/routes/events.js +61 -6
  139. package/dist/routes/events.js.map +1 -1
  140. package/dist/routes/health.d.ts +21 -0
  141. package/dist/routes/health.d.ts.map +1 -0
  142. package/dist/routes/health.js +142 -0
  143. package/dist/routes/health.js.map +1 -0
  144. package/dist/routes/ingest.d.ts +6 -0
  145. package/dist/routes/ingest.d.ts.map +1 -1
  146. package/dist/routes/ingest.js +23 -4
  147. package/dist/routes/ingest.js.map +1 -1
  148. package/dist/routes/lessons.d.ts +19 -0
  149. package/dist/routes/lessons.d.ts.map +1 -0
  150. package/dist/routes/lessons.js +164 -0
  151. package/dist/routes/lessons.js.map +1 -0
  152. package/dist/routes/optimize.d.ts +15 -0
  153. package/dist/routes/optimize.d.ts.map +1 -0
  154. package/dist/routes/optimize.js +55 -0
  155. package/dist/routes/optimize.js.map +1 -0
  156. package/dist/routes/recall.d.ts +22 -0
  157. package/dist/routes/recall.d.ts.map +1 -0
  158. package/dist/routes/recall.js +91 -0
  159. package/dist/routes/recall.js.map +1 -0
  160. package/dist/routes/reflect.d.ts +15 -0
  161. package/dist/routes/reflect.d.ts.map +1 -0
  162. package/dist/routes/reflect.js +54 -0
  163. package/dist/routes/reflect.js.map +1 -0
  164. package/dist/routes/sessions.d.ts.map +1 -1
  165. package/dist/routes/sessions.js +8 -6
  166. package/dist/routes/sessions.js.map +1 -1
  167. package/dist/routes/stats.d.ts.map +1 -1
  168. package/dist/routes/stats.js +3 -1
  169. package/dist/routes/stats.js.map +1 -1
  170. package/dist/routes/stream.d.ts +9 -2
  171. package/dist/routes/stream.d.ts.map +1 -1
  172. package/dist/routes/stream.js +55 -2
  173. package/dist/routes/stream.js.map +1 -1
  174. package/dist/routes/tenant-helper.d.ts +20 -0
  175. package/dist/routes/tenant-helper.d.ts.map +1 -0
  176. package/dist/routes/tenant-helper.js +35 -0
  177. package/dist/routes/tenant-helper.js.map +1 -0
  178. package/package.json +11 -11
  179. package/LICENSE +0 -21
  180. package/dist/__tests__/agents-stats.test.d.ts +0 -5
  181. package/dist/__tests__/agents-stats.test.d.ts.map +0 -1
  182. package/dist/__tests__/agents-stats.test.js +0 -134
  183. package/dist/__tests__/agents-stats.test.js.map +0 -1
  184. package/dist/__tests__/alerts.test.d.ts +0 -5
  185. package/dist/__tests__/alerts.test.d.ts.map +0 -1
  186. package/dist/__tests__/alerts.test.js +0 -245
  187. package/dist/__tests__/alerts.test.js.map +0 -1
  188. package/dist/__tests__/analytics.test.d.ts +0 -5
  189. package/dist/__tests__/analytics.test.d.ts.map +0 -1
  190. package/dist/__tests__/analytics.test.js +0 -218
  191. package/dist/__tests__/analytics.test.js.map +0 -1
  192. package/dist/__tests__/api-keys.test.d.ts +0 -5
  193. package/dist/__tests__/api-keys.test.d.ts.map +0 -1
  194. package/dist/__tests__/api-keys.test.js +0 -118
  195. package/dist/__tests__/api-keys.test.js.map +0 -1
  196. package/dist/__tests__/auth-no-db.test.d.ts +0 -2
  197. package/dist/__tests__/auth-no-db.test.d.ts.map +0 -1
  198. package/dist/__tests__/auth-no-db.test.js +0 -43
  199. package/dist/__tests__/auth-no-db.test.js.map +0 -1
  200. package/dist/__tests__/auth.test.d.ts +0 -5
  201. package/dist/__tests__/auth.test.d.ts.map +0 -1
  202. package/dist/__tests__/auth.test.js +0 -86
  203. package/dist/__tests__/auth.test.js.map +0 -1
  204. package/dist/__tests__/config.test.d.ts +0 -2
  205. package/dist/__tests__/config.test.d.ts.map +0 -1
  206. package/dist/__tests__/config.test.js +0 -37
  207. package/dist/__tests__/config.test.js.map +0 -1
  208. package/dist/__tests__/events-ingest.test.d.ts +0 -5
  209. package/dist/__tests__/events-ingest.test.d.ts.map +0 -1
  210. package/dist/__tests__/events-ingest.test.js +0 -248
  211. package/dist/__tests__/events-ingest.test.js.map +0 -1
  212. package/dist/__tests__/events-query.test.d.ts +0 -5
  213. package/dist/__tests__/events-query.test.d.ts.map +0 -1
  214. package/dist/__tests__/events-query.test.js +0 -205
  215. package/dist/__tests__/events-query.test.js.map +0 -1
  216. package/dist/__tests__/health.test.d.ts +0 -5
  217. package/dist/__tests__/health.test.d.ts.map +0 -1
  218. package/dist/__tests__/health.test.js +0 -40
  219. package/dist/__tests__/health.test.js.map +0 -1
  220. package/dist/__tests__/ingest.test.d.ts +0 -8
  221. package/dist/__tests__/ingest.test.d.ts.map +0 -1
  222. package/dist/__tests__/ingest.test.js +0 -469
  223. package/dist/__tests__/ingest.test.js.map +0 -1
  224. package/dist/__tests__/llm-tracking.test.d.ts +0 -10
  225. package/dist/__tests__/llm-tracking.test.d.ts.map +0 -1
  226. package/dist/__tests__/llm-tracking.test.js +0 -602
  227. package/dist/__tests__/llm-tracking.test.js.map +0 -1
  228. package/dist/__tests__/sessions.test.d.ts +0 -5
  229. package/dist/__tests__/sessions.test.d.ts.map +0 -1
  230. package/dist/__tests__/sessions.test.js +0 -176
  231. package/dist/__tests__/sessions.test.js.map +0 -1
  232. package/dist/__tests__/stream.test.d.ts +0 -5
  233. package/dist/__tests__/stream.test.d.ts.map +0 -1
  234. package/dist/__tests__/stream.test.js +0 -352
  235. package/dist/__tests__/stream.test.js.map +0 -1
  236. package/dist/__tests__/test-helpers.d.ts +0 -24
  237. package/dist/__tests__/test-helpers.d.ts.map +0 -1
  238. package/dist/__tests__/test-helpers.js +0 -45
  239. package/dist/__tests__/test-helpers.js.map +0 -1
  240. package/dist/db/__tests__/init.test.d.ts +0 -2
  241. package/dist/db/__tests__/init.test.d.ts.map +0 -1
  242. package/dist/db/__tests__/init.test.js +0 -73
  243. package/dist/db/__tests__/init.test.js.map +0 -1
  244. package/dist/db/__tests__/sqlite-store-read.test.d.ts +0 -2
  245. package/dist/db/__tests__/sqlite-store-read.test.d.ts.map +0 -1
  246. package/dist/db/__tests__/sqlite-store-read.test.js +0 -749
  247. package/dist/db/__tests__/sqlite-store-read.test.js.map +0 -1
  248. package/dist/db/__tests__/sqlite-store-write.test.d.ts +0 -2
  249. package/dist/db/__tests__/sqlite-store-write.test.d.ts.map +0 -1
  250. package/dist/db/__tests__/sqlite-store-write.test.js +0 -418
  251. package/dist/db/__tests__/sqlite-store-write.test.js.map +0 -1
  252. package/dist/lib/__tests__/alert-engine.test.d.ts +0 -5
  253. package/dist/lib/__tests__/alert-engine.test.d.ts.map +0 -1
  254. package/dist/lib/__tests__/alert-engine.test.js +0 -211
  255. package/dist/lib/__tests__/alert-engine.test.js.map +0 -1
  256. package/dist/lib/__tests__/retention.test.d.ts +0 -2
  257. package/dist/lib/__tests__/retention.test.d.ts.map +0 -1
  258. package/dist/lib/__tests__/retention.test.js +0 -238
  259. package/dist/lib/__tests__/retention.test.js.map +0 -1
@@ -0,0 +1,217 @@
1
+ /**
2
+ * Lesson Store (Story 3.1)
3
+ *
4
+ * CRUD operations for the lessons table with tenant isolation.
5
+ */
6
+ import { randomUUID } from 'node:crypto';
7
+ import { eq, and, or, sql, isNull } from 'drizzle-orm';
8
+ import { lessons } from './schema.sqlite.js';
9
+ import { NotFoundError } from './errors.js';
10
+ /** Valid importance values for runtime validation */
11
+ const VALID_IMPORTANCE = new Set(['low', 'normal', 'high', 'critical']);
12
+ /** Escape LIKE wildcard characters to prevent injection */
13
+ function escapeLike(s) {
14
+ return s.replace(/[%_]/g, '\\$&');
15
+ }
16
+ /** Parse a DB row into a Lesson */
17
+ function rowToLesson(row) {
18
+ return {
19
+ id: row.id,
20
+ tenantId: row.tenantId,
21
+ agentId: row.agentId ?? undefined,
22
+ category: row.category,
23
+ title: row.title,
24
+ content: row.content,
25
+ context: JSON.parse(row.context),
26
+ importance: VALID_IMPORTANCE.has(row.importance) ? row.importance : 'normal',
27
+ sourceSessionId: row.sourceSessionId ?? undefined,
28
+ sourceEventId: row.sourceEventId ?? undefined,
29
+ accessCount: row.accessCount,
30
+ lastAccessedAt: row.lastAccessedAt ?? undefined,
31
+ createdAt: row.createdAt,
32
+ updatedAt: row.updatedAt,
33
+ archivedAt: row.archivedAt ?? undefined,
34
+ };
35
+ }
36
+ export class LessonStore {
37
+ db;
38
+ constructor(db) {
39
+ this.db = db;
40
+ }
41
+ /**
42
+ * Create a new lesson.
43
+ */
44
+ create(tenantId, input) {
45
+ const now = new Date().toISOString();
46
+ const id = randomUUID();
47
+ const row = {
48
+ id,
49
+ tenantId,
50
+ agentId: input.agentId ?? null,
51
+ category: input.category ?? 'general',
52
+ title: input.title,
53
+ content: input.content,
54
+ context: JSON.stringify(input.context ?? {}),
55
+ importance: input.importance ?? 'normal',
56
+ sourceSessionId: input.sourceSessionId ?? null,
57
+ sourceEventId: input.sourceEventId ?? null,
58
+ accessCount: 0,
59
+ lastAccessedAt: null,
60
+ createdAt: now,
61
+ updatedAt: now,
62
+ archivedAt: null,
63
+ };
64
+ this.db.insert(lessons).values(row).run();
65
+ return rowToLesson(row);
66
+ }
67
+ /**
68
+ * Get a lesson by ID. Increments access_count and updates last_accessed_at.
69
+ * Wrapped in a transaction for atomicity.
70
+ */
71
+ get(tenantId, id) {
72
+ return this.db.transaction((tx) => {
73
+ const row = tx
74
+ .select()
75
+ .from(lessons)
76
+ .where(and(eq(lessons.id, id), eq(lessons.tenantId, tenantId)))
77
+ .get();
78
+ if (!row)
79
+ return null;
80
+ // Atomic increment — uses SQL expression to avoid read-then-write race
81
+ const now = new Date().toISOString();
82
+ tx.update(lessons)
83
+ .set({
84
+ accessCount: sql `${lessons.accessCount} + 1`,
85
+ lastAccessedAt: now,
86
+ })
87
+ .where(and(eq(lessons.id, id), eq(lessons.tenantId, tenantId)))
88
+ .run();
89
+ return rowToLesson({
90
+ ...row,
91
+ accessCount: row.accessCount + 1,
92
+ lastAccessedAt: now,
93
+ });
94
+ });
95
+ }
96
+ /**
97
+ * List lessons with optional filters.
98
+ */
99
+ list(tenantId, query) {
100
+ const conditions = [eq(lessons.tenantId, tenantId)];
101
+ if (!query?.includeArchived) {
102
+ conditions.push(isNull(lessons.archivedAt));
103
+ }
104
+ if (query?.agentId) {
105
+ conditions.push(eq(lessons.agentId, query.agentId));
106
+ }
107
+ if (query?.category) {
108
+ conditions.push(eq(lessons.category, query.category));
109
+ }
110
+ if (query?.importance) {
111
+ conditions.push(eq(lessons.importance, query.importance));
112
+ }
113
+ if (query?.search) {
114
+ const pattern = `%${escapeLike(query.search)}%`;
115
+ conditions.push(or(sql `${lessons.title} LIKE ${pattern} ESCAPE '\\'`, sql `${lessons.content} LIKE ${pattern} ESCAPE '\\'`));
116
+ }
117
+ const limit = query?.limit ?? 50;
118
+ const offset = query?.offset ?? 0;
119
+ const rows = this.db
120
+ .select()
121
+ .from(lessons)
122
+ .where(and(...conditions))
123
+ .limit(limit)
124
+ .offset(offset)
125
+ .orderBy(sql `${lessons.createdAt} DESC`)
126
+ .all();
127
+ return rows.map(rowToLesson);
128
+ }
129
+ /**
130
+ * Update a lesson (partial update).
131
+ */
132
+ update(tenantId, id, updates) {
133
+ // Check existence
134
+ const existing = this.db
135
+ .select()
136
+ .from(lessons)
137
+ .where(and(eq(lessons.id, id), eq(lessons.tenantId, tenantId)))
138
+ .get();
139
+ if (!existing) {
140
+ throw new NotFoundError(`Lesson ${id} not found`);
141
+ }
142
+ const now = new Date().toISOString();
143
+ const setValues = { updatedAt: now };
144
+ if (updates.title !== undefined)
145
+ setValues['title'] = updates.title;
146
+ if (updates.content !== undefined)
147
+ setValues['content'] = updates.content;
148
+ if (updates.category !== undefined)
149
+ setValues['category'] = updates.category;
150
+ if (updates.importance !== undefined)
151
+ setValues['importance'] = updates.importance;
152
+ if (updates.agentId !== undefined)
153
+ setValues['agentId'] = updates.agentId;
154
+ if (updates.context !== undefined)
155
+ setValues['context'] = JSON.stringify(updates.context);
156
+ this.db
157
+ .update(lessons)
158
+ .set(setValues)
159
+ .where(and(eq(lessons.id, id), eq(lessons.tenantId, tenantId)))
160
+ .run();
161
+ // Fetch updated row
162
+ const updated = this.db
163
+ .select()
164
+ .from(lessons)
165
+ .where(and(eq(lessons.id, id), eq(lessons.tenantId, tenantId)))
166
+ .get();
167
+ return rowToLesson(updated);
168
+ }
169
+ /**
170
+ * Soft-delete (archive) a lesson.
171
+ */
172
+ archive(tenantId, id) {
173
+ const existing = this.db
174
+ .select()
175
+ .from(lessons)
176
+ .where(and(eq(lessons.id, id), eq(lessons.tenantId, tenantId)))
177
+ .get();
178
+ if (!existing) {
179
+ throw new NotFoundError(`Lesson ${id} not found`);
180
+ }
181
+ const now = new Date().toISOString();
182
+ this.db
183
+ .update(lessons)
184
+ .set({ archivedAt: now, updatedAt: now })
185
+ .where(and(eq(lessons.id, id), eq(lessons.tenantId, tenantId)))
186
+ .run();
187
+ }
188
+ /**
189
+ * Count lessons matching filters.
190
+ */
191
+ count(tenantId, query) {
192
+ const conditions = [eq(lessons.tenantId, tenantId)];
193
+ if (!query?.includeArchived) {
194
+ conditions.push(isNull(lessons.archivedAt));
195
+ }
196
+ if (query?.agentId) {
197
+ conditions.push(eq(lessons.agentId, query.agentId));
198
+ }
199
+ if (query?.category) {
200
+ conditions.push(eq(lessons.category, query.category));
201
+ }
202
+ if (query?.importance) {
203
+ conditions.push(eq(lessons.importance, query.importance));
204
+ }
205
+ if (query?.search) {
206
+ const pattern = `%${escapeLike(query.search)}%`;
207
+ conditions.push(or(sql `${lessons.title} LIKE ${pattern} ESCAPE '\\'`, sql `${lessons.content} LIKE ${pattern} ESCAPE '\\'`));
208
+ }
209
+ const result = this.db
210
+ .select({ count: sql `count(*)` })
211
+ .from(lessons)
212
+ .where(and(...conditions))
213
+ .get();
214
+ return result?.count ?? 0;
215
+ }
216
+ }
217
+ //# sourceMappingURL=lesson-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lesson-store.js","sourceRoot":"","sources":["../../src/db/lesson-store.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAEvD,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAE7C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAwB5C,qDAAqD;AACrD,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAS,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;AAEhF,2DAA2D;AAC3D,SAAS,UAAU,CAAC,CAAS;IAC3B,OAAO,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;AACpC,CAAC;AAED,mCAAmC;AACnC,SAAS,WAAW,CAAC,GAAgC;IACnD,OAAO;QACL,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,SAAS;QACjC,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAA4B;QAC3D,UAAU,EAAE,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,UAA8B,CAAC,CAAC,CAAC,QAAQ;QAChG,eAAe,EAAE,GAAG,CAAC,eAAe,IAAI,SAAS;QACjD,aAAa,EAAE,GAAG,CAAC,aAAa,IAAI,SAAS;QAC7C,WAAW,EAAE,GAAG,CAAC,WAAW;QAC5B,cAAc,EAAE,GAAG,CAAC,cAAc,IAAI,SAAS;QAC/C,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,UAAU,EAAE,GAAG,CAAC,UAAU,IAAI,SAAS;KACxC,CAAC;AACJ,CAAC;AAED,MAAM,OAAO,WAAW;IACO;IAA7B,YAA6B,EAAY;QAAZ,OAAE,GAAF,EAAE,CAAU;IAAG,CAAC;IAE7C;;OAEG;IACH,MAAM,CAAC,QAAgB,EAAE,KAAwB;QAC/C,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,MAAM,EAAE,GAAG,UAAU,EAAE,CAAC;QAExB,MAAM,GAAG,GAAG;YACV,EAAE;YACF,QAAQ;YACR,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,IAAI;YAC9B,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,SAAS;YACrC,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC;YAC5C,UAAU,EAAE,KAAK,CAAC,UAAU,IAAI,QAAQ;YACxC,eAAe,EAAE,KAAK,CAAC,eAAe,IAAI,IAAI;YAC9C,aAAa,EAAE,KAAK,CAAC,aAAa,IAAI,IAAI;YAC1C,WAAW,EAAE,CAAC;YACd,cAAc,EAAE,IAAI;YACpB,SAAS,EAAE,GAAG;YACd,SAAS,EAAE,GAAG;YACd,UAAU,EAAE,IAAI;SACjB,CAAC;QAEF,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;QAE1C,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC;IAC1B,CAAC;IAED;;;OAGG;IACH,GAAG,CAAC,QAAgB,EAAE,EAAU;QAC9B,OAAO,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE;YAChC,MAAM,GAAG,GAAG,EAAE;iBACX,MAAM,EAAE;iBACR,IAAI,CAAC,OAAO,CAAC;iBACb,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;iBAC9D,GAAG,EAAE,CAAC;YAET,IAAI,CAAC,GAAG;gBAAE,OAAO,IAAI,CAAC;YAEtB,uEAAuE;YACvE,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;YACrC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC;iBACf,GAAG,CAAC;gBACH,WAAW,EAAE,GAAG,CAAA,GAAG,OAAO,CAAC,WAAW,MAAM;gBAC5C,cAAc,EAAE,GAAG;aACpB,CAAC;iBACD,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;iBAC9D,GAAG,EAAE,CAAC;YAET,OAAO,WAAW,CAAC;gBACjB,GAAG,GAAG;gBACN,WAAW,EAAE,GAAG,CAAC,WAAW,GAAG,CAAC;gBAChC,cAAc,EAAE,GAAG;aACpB,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,IAAI,CAAC,QAAgB,EAAE,KAAmB;QACxC,MAAM,UAAU,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;QAEpD,IAAI,CAAC,KAAK,EAAE,eAAe,EAAE,CAAC;YAC5B,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC;QAC9C,CAAC;QAED,IAAI,KAAK,EAAE,OAAO,EAAE,CAAC;YACnB,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QACtD,CAAC;QACD,IAAI,KAAK,EAAE,QAAQ,EAAE,CAAC;YACpB,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;QACxD,CAAC;QACD,IAAI,KAAK,EAAE,UAAU,EAAE,CAAC;YACtB,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC;QAC5D,CAAC;QACD,IAAI,KAAK,EAAE,MAAM,EAAE,CAAC;YAClB,MAAM,OAAO,GAAG,IAAI,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC;YAChD,UAAU,CAAC,IAAI,CACb,EAAE,CACA,GAAG,CAAA,GAAG,OAAO,CAAC,KAAK,SAAS,OAAO,cAAc,EACjD,GAAG,CAAA,GAAG,OAAO,CAAC,OAAO,SAAS,OAAO,cAAc,CACnD,CACH,CAAC;QACJ,CAAC;QAED,MAAM,KAAK,GAAG,KAAK,EAAE,KAAK,IAAI,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,KAAK,EAAE,MAAM,IAAI,CAAC,CAAC;QAElC,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE;aACjB,MAAM,EAAE;aACR,IAAI,CAAC,OAAO,CAAC;aACb,KAAK,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC,CAAC;aACzB,KAAK,CAAC,KAAK,CAAC;aACZ,MAAM,CAAC,MAAM,CAAC;aACd,OAAO,CAAC,GAAG,CAAA,GAAG,OAAO,CAAC,SAAS,OAAO,CAAC;aACvC,GAAG,EAAE,CAAC;QAET,OAAO,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAC/B,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,QAAgB,EAAE,EAAU,EAAE,OAA0B;QAC7D,kBAAkB;QAClB,MAAM,QAAQ,GAAG,IAAI,CAAC,EAAE;aACrB,MAAM,EAAE;aACR,IAAI,CAAC,OAAO,CAAC;aACb,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;aAC9D,GAAG,EAAE,CAAC;QAET,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,aAAa,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;QACpD,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,MAAM,SAAS,GAA4B,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC;QAE9D,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS;YAAE,SAAS,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC;QACpE,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS;YAAE,SAAS,CAAC,SAAS,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC;QAC1E,IAAI,OAAO,CAAC,QAAQ,KAAK,SAAS;YAAE,SAAS,CAAC,UAAU,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC;QAC7E,IAAI,OAAO,CAAC,UAAU,KAAK,SAAS;YAAE,SAAS,CAAC,YAAY,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC;QACnF,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS;YAAE,SAAS,CAAC,SAAS,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC;QAC1E,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS;YAAE,SAAS,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAE1F,IAAI,CAAC,EAAE;aACJ,MAAM,CAAC,OAAO,CAAC;aACf,GAAG,CAAC,SAAS,CAAC;aACd,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;aAC9D,GAAG,EAAE,CAAC;QAET,oBAAoB;QACpB,MAAM,OAAO,GAAG,IAAI,CAAC,EAAE;aACpB,MAAM,EAAE;aACR,IAAI,CAAC,OAAO,CAAC;aACb,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;aAC9D,GAAG,EAAE,CAAC;QAET,OAAO,WAAW,CAAC,OAAQ,CAAC,CAAC;IAC/B,CAAC;IAED;;OAEG;IACH,OAAO,CAAC,QAAgB,EAAE,EAAU;QAClC,MAAM,QAAQ,GAAG,IAAI,CAAC,EAAE;aACrB,MAAM,EAAE;aACR,IAAI,CAAC,OAAO,CAAC;aACb,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;aAC9D,GAAG,EAAE,CAAC;QAET,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,aAAa,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;QACpD,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,IAAI,CAAC,EAAE;aACJ,MAAM,CAAC,OAAO,CAAC;aACf,GAAG,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC;aACxC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;aAC9D,GAAG,EAAE,CAAC;IACX,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,QAAgB,EAAE,KAAmB;QACzC,MAAM,UAAU,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;QAEpD,IAAI,CAAC,KAAK,EAAE,eAAe,EAAE,CAAC;YAC5B,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC;QAC9C,CAAC;QAED,IAAI,KAAK,EAAE,OAAO,EAAE,CAAC;YACnB,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QACtD,CAAC;QACD,IAAI,KAAK,EAAE,QAAQ,EAAE,CAAC;YACpB,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;QACxD,CAAC;QACD,IAAI,KAAK,EAAE,UAAU,EAAE,CAAC;YACtB,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC;QAC5D,CAAC;QACD,IAAI,KAAK,EAAE,MAAM,EAAE,CAAC;YAClB,MAAM,OAAO,GAAG,IAAI,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC;YAChD,UAAU,CAAC,IAAI,CACb,EAAE,CACA,GAAG,CAAA,GAAG,OAAO,CAAC,KAAK,SAAS,OAAO,cAAc,EACjD,GAAG,CAAA,GAAG,OAAO,CAAC,OAAO,SAAS,OAAO,cAAc,CACnD,CACH,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,CAAC,EAAE;aACnB,MAAM,CAAC,EAAE,KAAK,EAAE,GAAG,CAAQ,UAAU,EAAE,CAAC;aACxC,IAAI,CAAC,OAAO,CAAC;aACb,KAAK,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC,CAAC;aACzB,GAAG,EAAE,CAAC;QAET,OAAO,MAAM,EAAE,KAAK,IAAI,CAAC,CAAC;IAC5B,CAAC;CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../src/db/migrate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,CAsHhD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,QAAQ,GAAG;IAC3C,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;CACtB,CAoBA"}
1
+ {"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../src/db/migrate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,CA4YhD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,QAAQ,GAAG;IAC3C,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;CACtB,CAoBA"}
@@ -32,7 +32,7 @@ export function runMigrations(db) {
32
32
  `);
33
33
  db.run(sql `
34
34
  CREATE TABLE IF NOT EXISTS sessions (
35
- id TEXT PRIMARY KEY,
35
+ id TEXT NOT NULL,
36
36
  agent_id TEXT NOT NULL,
37
37
  agent_name TEXT,
38
38
  started_at TEXT NOT NULL,
@@ -45,17 +45,21 @@ export function runMigrations(db) {
45
45
  llm_call_count INTEGER NOT NULL DEFAULT 0,
46
46
  total_input_tokens INTEGER NOT NULL DEFAULT 0,
47
47
  total_output_tokens INTEGER NOT NULL DEFAULT 0,
48
- tags TEXT NOT NULL DEFAULT '[]'
48
+ tags TEXT NOT NULL DEFAULT '[]',
49
+ tenant_id TEXT NOT NULL DEFAULT 'default',
50
+ PRIMARY KEY (id, tenant_id)
49
51
  )
50
52
  `);
51
53
  db.run(sql `
52
54
  CREATE TABLE IF NOT EXISTS agents (
53
- id TEXT PRIMARY KEY,
55
+ id TEXT NOT NULL,
54
56
  name TEXT NOT NULL,
55
57
  description TEXT,
56
58
  first_seen_at TEXT NOT NULL,
57
59
  last_seen_at TEXT NOT NULL,
58
- session_count INTEGER NOT NULL DEFAULT 0
60
+ session_count INTEGER NOT NULL DEFAULT 0,
61
+ tenant_id TEXT NOT NULL DEFAULT 'default',
62
+ PRIMARY KEY (id, tenant_id)
59
63
  )
60
64
  `);
61
65
  db.run(sql `
@@ -111,16 +115,260 @@ export function runMigrations(db) {
111
115
  // Add LLM tracking columns to sessions (v0.3.0)
112
116
  // SQLite doesn't support ADD COLUMN IF NOT EXISTS, so we check first
113
117
  const sessionColumns = db.all(sql `PRAGMA table_info(sessions)`);
114
- const columnNames = new Set(sessionColumns.map((c) => c.name));
115
- if (!columnNames.has('llm_call_count')) {
118
+ const sessionColumnNames = new Set(sessionColumns.map((c) => c.name));
119
+ if (!sessionColumnNames.has('llm_call_count')) {
116
120
  db.run(sql `ALTER TABLE sessions ADD COLUMN llm_call_count INTEGER NOT NULL DEFAULT 0`);
117
121
  }
118
- if (!columnNames.has('total_input_tokens')) {
122
+ if (!sessionColumnNames.has('total_input_tokens')) {
119
123
  db.run(sql `ALTER TABLE sessions ADD COLUMN total_input_tokens INTEGER NOT NULL DEFAULT 0`);
120
124
  }
121
- if (!columnNames.has('total_output_tokens')) {
125
+ if (!sessionColumnNames.has('total_output_tokens')) {
122
126
  db.run(sql `ALTER TABLE sessions ADD COLUMN total_output_tokens INTEGER NOT NULL DEFAULT 0`);
123
127
  }
128
+ // ─── Tenant isolation migration (Epic 1) ──────────────────
129
+ // Add tenant_id to all data tables for multi-tenant support
130
+ // api_keys.tenant_id
131
+ const apiKeyColumns = db.all(sql `PRAGMA table_info(api_keys)`);
132
+ const apiKeyColumnNames = new Set(apiKeyColumns.map((c) => c.name));
133
+ if (!apiKeyColumnNames.has('tenant_id')) {
134
+ db.run(sql `ALTER TABLE api_keys ADD COLUMN tenant_id TEXT NOT NULL DEFAULT 'default'`);
135
+ }
136
+ // events.tenant_id
137
+ const eventColumns = db.all(sql `PRAGMA table_info(events)`);
138
+ const eventColumnNames = new Set(eventColumns.map((c) => c.name));
139
+ if (!eventColumnNames.has('tenant_id')) {
140
+ db.run(sql `ALTER TABLE events ADD COLUMN tenant_id TEXT NOT NULL DEFAULT 'default'`);
141
+ }
142
+ // sessions.tenant_id
143
+ if (!sessionColumnNames.has('tenant_id')) {
144
+ db.run(sql `ALTER TABLE sessions ADD COLUMN tenant_id TEXT NOT NULL DEFAULT 'default'`);
145
+ }
146
+ // agents.tenant_id
147
+ const agentColumns = db.all(sql `PRAGMA table_info(agents)`);
148
+ const agentColumnNames = new Set(agentColumns.map((c) => c.name));
149
+ if (!agentColumnNames.has('tenant_id')) {
150
+ db.run(sql `ALTER TABLE agents ADD COLUMN tenant_id TEXT NOT NULL DEFAULT 'default'`);
151
+ }
152
+ // alert_rules.tenant_id
153
+ const alertRuleColumns = db.all(sql `PRAGMA table_info(alert_rules)`);
154
+ const alertRuleColumnNames = new Set(alertRuleColumns.map((c) => c.name));
155
+ if (!alertRuleColumnNames.has('tenant_id')) {
156
+ db.run(sql `ALTER TABLE alert_rules ADD COLUMN tenant_id TEXT NOT NULL DEFAULT 'default'`);
157
+ }
158
+ // alert_history.tenant_id
159
+ const alertHistoryColumns = db.all(sql `PRAGMA table_info(alert_history)`);
160
+ const alertHistoryColumnNames = new Set(alertHistoryColumns.map((c) => c.name));
161
+ if (!alertHistoryColumnNames.has('tenant_id')) {
162
+ db.run(sql `ALTER TABLE alert_history ADD COLUMN tenant_id TEXT NOT NULL DEFAULT 'default'`);
163
+ }
164
+ // Tenant isolation indexes
165
+ db.run(sql `CREATE INDEX IF NOT EXISTS idx_events_tenant_id ON events(tenant_id)`);
166
+ db.run(sql `CREATE INDEX IF NOT EXISTS idx_events_tenant_session ON events(tenant_id, session_id)`);
167
+ db.run(sql `CREATE INDEX IF NOT EXISTS idx_events_tenant_agent_ts ON events(tenant_id, agent_id, timestamp)`);
168
+ db.run(sql `CREATE INDEX IF NOT EXISTS idx_sessions_tenant_id ON sessions(tenant_id)`);
169
+ db.run(sql `CREATE INDEX IF NOT EXISTS idx_sessions_tenant_agent ON sessions(tenant_id, agent_id)`);
170
+ db.run(sql `CREATE INDEX IF NOT EXISTS idx_sessions_tenant_started ON sessions(tenant_id, started_at)`);
171
+ db.run(sql `CREATE INDEX IF NOT EXISTS idx_agents_tenant_id ON agents(tenant_id)`);
172
+ // ─── Embeddings table (Epic 2 — Story 2.2) ──────────────────
173
+ db.run(sql `
174
+ CREATE TABLE IF NOT EXISTS embeddings (
175
+ id TEXT PRIMARY KEY,
176
+ tenant_id TEXT NOT NULL,
177
+ source_type TEXT NOT NULL,
178
+ source_id TEXT NOT NULL,
179
+ content_hash TEXT NOT NULL,
180
+ text_content TEXT NOT NULL,
181
+ embedding BLOB NOT NULL,
182
+ embedding_model TEXT NOT NULL,
183
+ dimensions INTEGER NOT NULL,
184
+ created_at TEXT NOT NULL
185
+ )
186
+ `);
187
+ db.run(sql `CREATE INDEX IF NOT EXISTS idx_embeddings_tenant ON embeddings(tenant_id)`);
188
+ db.run(sql `CREATE INDEX IF NOT EXISTS idx_embeddings_source ON embeddings(source_type, source_id)`);
189
+ db.run(sql `CREATE INDEX IF NOT EXISTS idx_embeddings_content_hash ON embeddings(tenant_id, content_hash)`);
190
+ // ─── Session Summaries table (Epic 2 — Story 2.2) ──────────────────
191
+ db.run(sql `
192
+ CREATE TABLE IF NOT EXISTS session_summaries (
193
+ session_id TEXT NOT NULL,
194
+ tenant_id TEXT NOT NULL,
195
+ summary TEXT NOT NULL,
196
+ topics TEXT NOT NULL DEFAULT '[]',
197
+ tool_sequence TEXT NOT NULL DEFAULT '[]',
198
+ error_summary TEXT,
199
+ outcome TEXT,
200
+ created_at TEXT NOT NULL,
201
+ updated_at TEXT NOT NULL,
202
+ PRIMARY KEY (session_id, tenant_id)
203
+ )
204
+ `);
205
+ db.run(sql `CREATE INDEX IF NOT EXISTS idx_session_summaries_tenant ON session_summaries(tenant_id)`);
206
+ // ─── Composite PK migration (CRITICAL-2) ──────────────────
207
+ // SQLite doesn't support ALTER TABLE to change PKs, so we recreate
208
+ // tables with composite PKs (id, tenant_id) for tenant isolation.
209
+ // Check if sessions table still has single-column PK
210
+ // by looking at the CREATE TABLE statement
211
+ const sessionsSchema = db.get(sql `SELECT sql FROM sqlite_master WHERE type='table' AND name='sessions'`);
212
+ if (sessionsSchema && sessionsSchema.sql.includes('id TEXT PRIMARY KEY')) {
213
+ // Drop old indexes that reference sessions (they'll be recreated)
214
+ db.run(sql `DROP INDEX IF EXISTS idx_sessions_agent_id`);
215
+ db.run(sql `DROP INDEX IF EXISTS idx_sessions_started_at`);
216
+ db.run(sql `DROP INDEX IF EXISTS idx_sessions_status`);
217
+ db.run(sql `DROP INDEX IF EXISTS idx_sessions_tenant_id`);
218
+ db.run(sql `DROP INDEX IF EXISTS idx_sessions_tenant_agent`);
219
+ db.run(sql `DROP INDEX IF EXISTS idx_sessions_tenant_started`);
220
+ db.run(sql `
221
+ CREATE TABLE sessions_new (
222
+ id TEXT NOT NULL,
223
+ agent_id TEXT NOT NULL,
224
+ agent_name TEXT,
225
+ started_at TEXT NOT NULL,
226
+ ended_at TEXT,
227
+ status TEXT NOT NULL DEFAULT 'active',
228
+ event_count INTEGER NOT NULL DEFAULT 0,
229
+ tool_call_count INTEGER NOT NULL DEFAULT 0,
230
+ error_count INTEGER NOT NULL DEFAULT 0,
231
+ total_cost_usd REAL NOT NULL DEFAULT 0,
232
+ llm_call_count INTEGER NOT NULL DEFAULT 0,
233
+ total_input_tokens INTEGER NOT NULL DEFAULT 0,
234
+ total_output_tokens INTEGER NOT NULL DEFAULT 0,
235
+ tags TEXT NOT NULL DEFAULT '[]',
236
+ tenant_id TEXT NOT NULL DEFAULT 'default',
237
+ PRIMARY KEY (id, tenant_id)
238
+ )
239
+ `);
240
+ db.run(sql `
241
+ INSERT INTO sessions_new
242
+ SELECT id, agent_id, agent_name, started_at, ended_at, status,
243
+ event_count, tool_call_count, error_count, total_cost_usd,
244
+ llm_call_count, total_input_tokens, total_output_tokens,
245
+ tags, tenant_id
246
+ FROM sessions
247
+ `);
248
+ db.run(sql `DROP TABLE sessions`);
249
+ db.run(sql `ALTER TABLE sessions_new RENAME TO sessions`);
250
+ // Recreate indexes
251
+ db.run(sql `CREATE INDEX idx_sessions_agent_id ON sessions(agent_id)`);
252
+ db.run(sql `CREATE INDEX idx_sessions_started_at ON sessions(started_at)`);
253
+ db.run(sql `CREATE INDEX idx_sessions_status ON sessions(status)`);
254
+ db.run(sql `CREATE INDEX idx_sessions_tenant_id ON sessions(tenant_id)`);
255
+ db.run(sql `CREATE INDEX idx_sessions_tenant_agent ON sessions(tenant_id, agent_id)`);
256
+ db.run(sql `CREATE INDEX idx_sessions_tenant_started ON sessions(tenant_id, started_at)`);
257
+ }
258
+ // Check if agents table still has single-column PK
259
+ const agentsSchema = db.get(sql `SELECT sql FROM sqlite_master WHERE type='table' AND name='agents'`);
260
+ if (agentsSchema && agentsSchema.sql.includes('id TEXT PRIMARY KEY')) {
261
+ db.run(sql `DROP INDEX IF EXISTS idx_agents_tenant_id`);
262
+ db.run(sql `
263
+ CREATE TABLE agents_new (
264
+ id TEXT NOT NULL,
265
+ name TEXT NOT NULL,
266
+ description TEXT,
267
+ first_seen_at TEXT NOT NULL,
268
+ last_seen_at TEXT NOT NULL,
269
+ session_count INTEGER NOT NULL DEFAULT 0,
270
+ tenant_id TEXT NOT NULL DEFAULT 'default',
271
+ PRIMARY KEY (id, tenant_id)
272
+ )
273
+ `);
274
+ db.run(sql `
275
+ INSERT INTO agents_new
276
+ SELECT id, name, description, first_seen_at, last_seen_at,
277
+ session_count, tenant_id
278
+ FROM agents
279
+ `);
280
+ db.run(sql `DROP TABLE agents`);
281
+ db.run(sql `ALTER TABLE agents_new RENAME TO agents`);
282
+ db.run(sql `CREATE INDEX idx_agents_tenant_id ON agents(tenant_id)`);
283
+ }
284
+ // ─── Lessons table (Epic 3) ──────────────────────────────
285
+ db.run(sql `
286
+ CREATE TABLE IF NOT EXISTS lessons (
287
+ id TEXT NOT NULL,
288
+ tenant_id TEXT NOT NULL,
289
+ agent_id TEXT,
290
+ category TEXT NOT NULL DEFAULT 'general',
291
+ title TEXT NOT NULL,
292
+ content TEXT NOT NULL,
293
+ context TEXT NOT NULL DEFAULT '{}',
294
+ importance TEXT NOT NULL DEFAULT 'normal',
295
+ source_session_id TEXT,
296
+ source_event_id TEXT,
297
+ access_count INTEGER NOT NULL DEFAULT 0,
298
+ last_accessed_at TEXT,
299
+ created_at TEXT NOT NULL,
300
+ updated_at TEXT NOT NULL,
301
+ archived_at TEXT,
302
+ PRIMARY KEY (id, tenant_id)
303
+ )
304
+ `);
305
+ db.run(sql `CREATE INDEX IF NOT EXISTS idx_lessons_tenant ON lessons(tenant_id)`);
306
+ db.run(sql `CREATE INDEX IF NOT EXISTS idx_lessons_tenant_agent ON lessons(tenant_id, agent_id)`);
307
+ db.run(sql `CREATE INDEX IF NOT EXISTS idx_lessons_tenant_category ON lessons(tenant_id, category)`);
308
+ db.run(sql `CREATE INDEX IF NOT EXISTS idx_lessons_tenant_importance ON lessons(tenant_id, importance)`);
309
+ // ─── Lessons PK migration (H5) ──────────────────────────
310
+ // Migrate existing lessons tables from single-column PK to composite PK
311
+ const lessonsSchema = db.get(sql `SELECT sql FROM sqlite_master WHERE type='table' AND name='lessons'`);
312
+ if (lessonsSchema && lessonsSchema.sql.includes('id TEXT PRIMARY KEY')) {
313
+ db.run(sql `DROP INDEX IF EXISTS idx_lessons_tenant`);
314
+ db.run(sql `DROP INDEX IF EXISTS idx_lessons_tenant_agent`);
315
+ db.run(sql `DROP INDEX IF EXISTS idx_lessons_tenant_category`);
316
+ db.run(sql `DROP INDEX IF EXISTS idx_lessons_tenant_importance`);
317
+ db.run(sql `
318
+ CREATE TABLE lessons_new (
319
+ id TEXT NOT NULL,
320
+ tenant_id TEXT NOT NULL,
321
+ agent_id TEXT,
322
+ category TEXT NOT NULL DEFAULT 'general',
323
+ title TEXT NOT NULL,
324
+ content TEXT NOT NULL,
325
+ context TEXT NOT NULL DEFAULT '{}',
326
+ importance TEXT NOT NULL DEFAULT 'normal',
327
+ source_session_id TEXT,
328
+ source_event_id TEXT,
329
+ access_count INTEGER NOT NULL DEFAULT 0,
330
+ last_accessed_at TEXT,
331
+ created_at TEXT NOT NULL,
332
+ updated_at TEXT NOT NULL,
333
+ archived_at TEXT,
334
+ PRIMARY KEY (id, tenant_id)
335
+ )
336
+ `);
337
+ db.run(sql `
338
+ INSERT INTO lessons_new
339
+ SELECT id, tenant_id, agent_id, category, title, content, context,
340
+ importance, source_session_id, source_event_id, access_count,
341
+ last_accessed_at, created_at, updated_at, archived_at
342
+ FROM lessons
343
+ `);
344
+ db.run(sql `DROP TABLE lessons`);
345
+ db.run(sql `ALTER TABLE lessons_new RENAME TO lessons`);
346
+ db.run(sql `CREATE INDEX idx_lessons_tenant ON lessons(tenant_id)`);
347
+ db.run(sql `CREATE INDEX idx_lessons_tenant_agent ON lessons(tenant_id, agent_id)`);
348
+ db.run(sql `CREATE INDEX idx_lessons_tenant_category ON lessons(tenant_id, category)`);
349
+ db.run(sql `CREATE INDEX idx_lessons_tenant_importance ON lessons(tenant_id, importance)`);
350
+ }
351
+ // ─── Composite index for similarity search (M6) ──────────────────
352
+ db.run(sql `CREATE INDEX IF NOT EXISTS idx_embeddings_tenant_source_time ON embeddings(tenant_id, source_type, created_at)`);
353
+ // ─── Health Snapshots table (Epic 6 — Story 1.3) ──────────────────
354
+ db.run(sql `
355
+ CREATE TABLE IF NOT EXISTS health_snapshots (
356
+ id TEXT NOT NULL,
357
+ tenant_id TEXT NOT NULL,
358
+ agent_id TEXT NOT NULL,
359
+ date TEXT NOT NULL,
360
+ overall_score REAL NOT NULL,
361
+ error_rate_score REAL NOT NULL,
362
+ cost_efficiency_score REAL NOT NULL,
363
+ tool_success_score REAL NOT NULL,
364
+ latency_score REAL NOT NULL,
365
+ completion_rate_score REAL NOT NULL,
366
+ session_count INTEGER NOT NULL,
367
+ created_at TEXT NOT NULL,
368
+ PRIMARY KEY (tenant_id, agent_id, date)
369
+ )
370
+ `);
371
+ db.run(sql `CREATE INDEX IF NOT EXISTS idx_health_snapshots_agent ON health_snapshots(tenant_id, agent_id, date DESC)`);
124
372
  }
125
373
  /**
126
374
  * Verify that WAL mode is enabled.
@@ -1 +1 @@
1
- {"version":3,"file":"migrate.js","sourceRoot":"","sources":["../../src/db/migrate.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"migrate.js","sourceRoot":"","sources":["../../src/db/migrate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAElC;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,EAAY;IACxC,2DAA2D;IAC3D,gEAAgE;IAChE,oDAAoD;IACpD,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA;;;;;;;;;;;;;GAaT,CAAC,CAAC;IAEH,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;GAmBT,CAAC,CAAC;IAEH,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA;;;;;;;;;;;GAWT,CAAC,CAAC;IAEH,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA;;;;;;;;;;;;;GAaT,CAAC,CAAC;IAEH,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA;;;;;;;;;;GAUT,CAAC,CAAC;IAEH,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA;;;;;;;;;;;GAWT,CAAC,CAAC;IAEH,iCAAiC;IACjC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,sEAAsE,CAAC,CAAC;IAClF,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,wEAAwE,CAAC,CAAC;IACpF,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,oEAAoE,CAAC,CAAC;IAChF,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,kEAAkE,CAAC,CAAC;IAC9E,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,mFAAmF,CAAC,CAAC;IAC/F,EAAE,CAAC,GAAG,CACJ,GAAG,CAAA,gGAAgG,CACpG,CAAC;IACF,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,wEAAwE,CAAC,CAAC;IACpF,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,4EAA4E,CAAC,CAAC;IACxF,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,oEAAoE,CAAC,CAAC;IAChF,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,oEAAoE,CAAC,CAAC;IAChF,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,gFAAgF,CAAC,CAAC;IAE5F,2DAA2D;IAC3D,gDAAgD;IAChD,qEAAqE;IACrE,MAAM,cAAc,GAAG,EAAE,CAAC,GAAG,CAAmB,GAAG,CAAA,6BAA6B,CAAC,CAAC;IAClF,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACtE,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,gBAAgB,CAAC,EAAE,CAAC;QAC9C,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,2EAA2E,CAAC,CAAC;IACzF,CAAC;IACD,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,oBAAoB,CAAC,EAAE,CAAC;QAClD,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,+EAA+E,CAAC,CAAC;IAC7F,CAAC;IACD,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,qBAAqB,CAAC,EAAE,CAAC;QACnD,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,gFAAgF,CAAC,CAAC;IAC9F,CAAC;IAED,6DAA6D;IAC7D,4DAA4D;IAE5D,qBAAqB;IACrB,MAAM,aAAa,GAAG,EAAE,CAAC,GAAG,CAAmB,GAAG,CAAA,6BAA6B,CAAC,CAAC;IACjF,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACpE,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;QACxC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,2EAA2E,CAAC,CAAC;IACzF,CAAC;IAED,mBAAmB;IACnB,MAAM,YAAY,GAAG,EAAE,CAAC,GAAG,CAAmB,GAAG,CAAA,2BAA2B,CAAC,CAAC;IAC9E,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAClE,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;QACvC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,yEAAyE,CAAC,CAAC;IACvF,CAAC;IAED,qBAAqB;IACrB,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;QACzC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,2EAA2E,CAAC,CAAC;IACzF,CAAC;IAED,mBAAmB;IACnB,MAAM,YAAY,GAAG,EAAE,CAAC,GAAG,CAAmB,GAAG,CAAA,2BAA2B,CAAC,CAAC;IAC9E,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAClE,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;QACvC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,yEAAyE,CAAC,CAAC;IACvF,CAAC;IAED,wBAAwB;IACxB,MAAM,gBAAgB,GAAG,EAAE,CAAC,GAAG,CAAmB,GAAG,CAAA,gCAAgC,CAAC,CAAC;IACvF,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAC1E,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;QAC3C,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,8EAA8E,CAAC,CAAC;IAC5F,CAAC;IAED,0BAA0B;IAC1B,MAAM,mBAAmB,GAAG,EAAE,CAAC,GAAG,CAAmB,GAAG,CAAA,kCAAkC,CAAC,CAAC;IAC5F,MAAM,uBAAuB,GAAG,IAAI,GAAG,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAChF,IAAI,CAAC,uBAAuB,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;QAC9C,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,gFAAgF,CAAC,CAAC;IAC9F,CAAC;IAED,2BAA2B;IAC3B,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,sEAAsE,CAAC,CAAC;IAClF,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,uFAAuF,CAAC,CAAC;IACnG,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,iGAAiG,CAAC,CAAC;IAC7G,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,0EAA0E,CAAC,CAAC;IACtF,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,uFAAuF,CAAC,CAAC;IACnG,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,2FAA2F,CAAC,CAAC;IACvG,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,sEAAsE,CAAC,CAAC;IAElF,+DAA+D;IAC/D,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA;;;;;;;;;;;;;GAaT,CAAC,CAAC;IACH,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,2EAA2E,CAAC,CAAC;IACvF,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,wFAAwF,CAAC,CAAC;IACpG,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,+FAA+F,CAAC,CAAC;IAE3G,sEAAsE;IACtE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA;;;;;;;;;;;;;GAaT,CAAC,CAAC;IACH,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,yFAAyF,CAAC,CAAC;IAErG,6DAA6D;IAC7D,mEAAmE;IACnE,kEAAkE;IAElE,qDAAqD;IACrD,2CAA2C;IAC3C,MAAM,cAAc,GAAG,EAAE,CAAC,GAAG,CAC3B,GAAG,CAAA,sEAAsE,CAC1E,CAAC;IACF,IAAI,cAAc,IAAI,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,qBAAqB,CAAC,EAAE,CAAC;QACzE,kEAAkE;QAClE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,4CAA4C,CAAC,CAAC;QACxD,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,8CAA8C,CAAC,CAAC;QAC1D,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,0CAA0C,CAAC,CAAC;QACtD,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,6CAA6C,CAAC,CAAC;QACzD,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,gDAAgD,CAAC,CAAC;QAC5D,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,kDAAkD,CAAC,CAAC;QAE9D,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;KAmBT,CAAC,CAAC;QACH,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA;;;;;;;KAOT,CAAC,CAAC;QACH,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,qBAAqB,CAAC,CAAC;QACjC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,6CAA6C,CAAC,CAAC;QAEzD,mBAAmB;QACnB,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,0DAA0D,CAAC,CAAC;QACtE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,8DAA8D,CAAC,CAAC;QAC1E,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,sDAAsD,CAAC,CAAC;QAClE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,4DAA4D,CAAC,CAAC;QACxE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,yEAAyE,CAAC,CAAC;QACrF,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,6EAA6E,CAAC,CAAC;IAC3F,CAAC;IAED,mDAAmD;IACnD,MAAM,YAAY,GAAG,EAAE,CAAC,GAAG,CACzB,GAAG,CAAA,oEAAoE,CACxE,CAAC;IACF,IAAI,YAAY,IAAI,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,qBAAqB,CAAC,EAAE,CAAC;QACrE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,2CAA2C,CAAC,CAAC;QAEvD,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA;;;;;;;;;;;KAWT,CAAC,CAAC;QACH,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA;;;;;KAKT,CAAC,CAAC;QACH,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,mBAAmB,CAAC,CAAC;QAC/B,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,yCAAyC,CAAC,CAAC;QAErD,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,wDAAwD,CAAC,CAAC;IACtE,CAAC;IAED,4DAA4D;IAC5D,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;GAmBT,CAAC,CAAC;IAEH,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,qEAAqE,CAAC,CAAC;IACjF,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,qFAAqF,CAAC,CAAC;IACjG,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,wFAAwF,CAAC,CAAC;IACpG,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,4FAA4F,CAAC,CAAC;IAExG,2DAA2D;IAC3D,wEAAwE;IACxE,MAAM,aAAa,GAAG,EAAE,CAAC,GAAG,CAC1B,GAAG,CAAA,qEAAqE,CACzE,CAAC;IACF,IAAI,aAAa,IAAI,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,qBAAqB,CAAC,EAAE,CAAC;QACvE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,yCAAyC,CAAC,CAAC;QACrD,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,+CAA+C,CAAC,CAAC;QAC3D,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,kDAAkD,CAAC,CAAC;QAC9D,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,oDAAoD,CAAC,CAAC;QAEhE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;KAmBT,CAAC,CAAC;QACH,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA;;;;;;KAMT,CAAC,CAAC;QACH,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,oBAAoB,CAAC,CAAC;QAChC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,2CAA2C,CAAC,CAAC;QAEvD,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,uDAAuD,CAAC,CAAC;QACnE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,uEAAuE,CAAC,CAAC;QACnF,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,0EAA0E,CAAC,CAAC;QACtF,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,8EAA8E,CAAC,CAAC;IAC5F,CAAC;IAED,oEAAoE;IACpE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,gHAAgH,CAAC,CAAC;IAE5H,qEAAqE;IACrE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;GAgBT,CAAC,CAAC;IACH,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,2GAA2G,CAAC,CAAC;AACzH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,EAAY;IAOxC,MAAM,WAAW,GACf,EAAE,CAAC,GAAG,CAA2B,GAAG,CAAA,qBAAqB,CAAC,EAAE,YAAY,IAAI,EAAE,CAAC;IACjF,MAAM,WAAW,GAAG,EAAE,CAAC,GAAG,CAA0B,GAAG,CAAA,oBAAoB,CAAC,EAAE,WAAW,IAAI,CAAC,CAAC,CAAC;IAChG,MAAM,SAAS,GAAG,EAAE,CAAC,GAAG,CAAyB,GAAG,CAAA,mBAAmB,CAAC,EAAE,UAAU,IAAI,CAAC,CAAC;IAC1F,wDAAwD;IACxD,MAAM,WAAW,GAAG,EAAE,CAAC,GAAG,CAAsB,GAAG,CAAA,qBAAqB,CAAC,EAAE,OAAO,IAAI,CAAC,CAAC;IACxF,MAAM,WAAW,GACf,EAAE,CAAC,GAAG,CAA2B,GAAG,CAAA,qBAAqB,CAAC,EAAE,YAAY,KAAK,CAAC,CAAC;IAEjF,gDAAgD;IAChD,MAAM,SAAS,GAA2B,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC;IAE3F,OAAO;QACL,WAAW;QACX,WAAW,EAAE,SAAS,CAAC,WAAW,CAAC,IAAI,MAAM,CAAC,WAAW,CAAC;QAC1D,SAAS;QACT,WAAW;QACX,WAAW;KACZ,CAAC;AACJ,CAAC"}