@code-insights/cli 3.6.1 → 4.0.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 (214) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/README.md +40 -4
  3. package/dashboard-dist/assets/index-D1JDyyu5.js +660 -0
  4. package/dashboard-dist/assets/index-kwbCW1n2.css +1 -0
  5. package/dashboard-dist/index.html +2 -2
  6. package/dist/commands/reflect.d.ts +3 -0
  7. package/dist/commands/reflect.d.ts.map +1 -0
  8. package/dist/commands/reflect.js +457 -0
  9. package/dist/commands/reflect.js.map +1 -0
  10. package/dist/commands/reset.d.ts.map +1 -1
  11. package/dist/commands/reset.js +3 -1
  12. package/dist/commands/reset.js.map +1 -1
  13. package/dist/commands/stats/actions/patterns.d.ts +3 -0
  14. package/dist/commands/stats/actions/patterns.d.ts.map +1 -0
  15. package/dist/commands/stats/actions/patterns.js +140 -0
  16. package/dist/commands/stats/actions/patterns.js.map +1 -0
  17. package/dist/commands/stats/data/aggregation-helpers.d.ts +23 -0
  18. package/dist/commands/stats/data/aggregation-helpers.d.ts.map +1 -0
  19. package/dist/commands/stats/data/aggregation-helpers.js +128 -0
  20. package/dist/commands/stats/data/aggregation-helpers.js.map +1 -0
  21. package/dist/commands/stats/data/aggregation.d.ts +3 -35
  22. package/dist/commands/stats/data/aggregation.d.ts.map +1 -1
  23. package/dist/commands/stats/data/aggregation.js +8 -290
  24. package/dist/commands/stats/data/aggregation.js.map +1 -1
  25. package/dist/commands/stats/data/time-series.d.ts +24 -0
  26. package/dist/commands/stats/data/time-series.d.ts.map +1 -0
  27. package/dist/commands/stats/data/time-series.js +162 -0
  28. package/dist/commands/stats/data/time-series.js.map +1 -0
  29. package/dist/commands/stats/index.d.ts.map +1 -1
  30. package/dist/commands/stats/index.js +7 -1
  31. package/dist/commands/stats/index.js.map +1 -1
  32. package/dist/commands/sync.d.ts +19 -0
  33. package/dist/commands/sync.d.ts.map +1 -1
  34. package/dist/commands/sync.js +67 -1
  35. package/dist/commands/sync.js.map +1 -1
  36. package/dist/constants/llm-providers.js +1 -1
  37. package/dist/constants/llm-providers.js.map +1 -1
  38. package/dist/db/client.d.ts +7 -0
  39. package/dist/db/client.d.ts.map +1 -1
  40. package/dist/db/client.js +11 -1
  41. package/dist/db/client.js.map +1 -1
  42. package/dist/db/migrate.d.ts +10 -1
  43. package/dist/db/migrate.d.ts.map +1 -1
  44. package/dist/db/migrate.js +96 -0
  45. package/dist/db/migrate.js.map +1 -1
  46. package/dist/db/read.d.ts +5 -0
  47. package/dist/db/read.d.ts.map +1 -1
  48. package/dist/db/read.js +20 -3
  49. package/dist/db/read.js.map +1 -1
  50. package/dist/db/schema.d.ts +1 -1
  51. package/dist/db/schema.js +2 -2
  52. package/dist/db/schema.js.map +1 -1
  53. package/dist/db/write.d.ts.map +1 -1
  54. package/dist/db/write.js +8 -2
  55. package/dist/db/write.js.map +1 -1
  56. package/dist/index.js +39 -3
  57. package/dist/index.js.map +1 -1
  58. package/dist/parser/jsonl.d.ts +19 -1
  59. package/dist/parser/jsonl.d.ts.map +1 -1
  60. package/dist/parser/jsonl.js +109 -3
  61. package/dist/parser/jsonl.js.map +1 -1
  62. package/dist/providers/codex.js +4 -1
  63. package/dist/providers/codex.js.map +1 -1
  64. package/dist/providers/copilot-cli.js +3 -0
  65. package/dist/providers/copilot-cli.js.map +1 -1
  66. package/dist/providers/copilot.js +3 -0
  67. package/dist/providers/copilot.js.map +1 -1
  68. package/dist/providers/cursor.js +3 -0
  69. package/dist/providers/cursor.js.map +1 -1
  70. package/dist/types.d.ts +109 -0
  71. package/dist/types.d.ts.map +1 -1
  72. package/dist/utils/date-utils.d.ts +6 -0
  73. package/dist/utils/date-utils.d.ts.map +1 -0
  74. package/dist/utils/date-utils.js +26 -0
  75. package/dist/utils/date-utils.js.map +1 -0
  76. package/dist/utils/telemetry.d.ts +1 -1
  77. package/dist/utils/telemetry.d.ts.map +1 -1
  78. package/dist/utils/telemetry.js +1 -1
  79. package/dist/utils/telemetry.js.map +1 -1
  80. package/package.json +2 -1
  81. package/server-dist/export/agent-rules.d.ts.map +1 -1
  82. package/server-dist/export/agent-rules.js +15 -4
  83. package/server-dist/export/agent-rules.js.map +1 -1
  84. package/server-dist/export/knowledge-base.d.ts.map +1 -1
  85. package/server-dist/export/knowledge-base.js +30 -4
  86. package/server-dist/export/knowledge-base.js.map +1 -1
  87. package/server-dist/index.d.ts.map +1 -1
  88. package/server-dist/index.js +4 -0
  89. package/server-dist/index.js.map +1 -1
  90. package/server-dist/llm/analysis-db.d.ts +51 -0
  91. package/server-dist/llm/analysis-db.d.ts.map +1 -0
  92. package/server-dist/llm/analysis-db.js +208 -0
  93. package/server-dist/llm/analysis-db.js.map +1 -0
  94. package/server-dist/llm/analysis-internal.d.ts +36 -0
  95. package/server-dist/llm/analysis-internal.d.ts.map +1 -0
  96. package/server-dist/llm/analysis-internal.js +23 -0
  97. package/server-dist/llm/analysis-internal.js.map +1 -0
  98. package/server-dist/llm/analysis-pricing.d.ts +25 -0
  99. package/server-dist/llm/analysis-pricing.d.ts.map +1 -0
  100. package/server-dist/llm/analysis-pricing.js +74 -0
  101. package/server-dist/llm/analysis-pricing.js.map +1 -0
  102. package/server-dist/llm/analysis-usage-db.d.ts +45 -0
  103. package/server-dist/llm/analysis-usage-db.d.ts.map +1 -0
  104. package/server-dist/llm/analysis-usage-db.js +35 -0
  105. package/server-dist/llm/analysis-usage-db.js.map +1 -0
  106. package/server-dist/llm/analysis.d.ts +9 -79
  107. package/server-dist/llm/analysis.d.ts.map +1 -1
  108. package/server-dist/llm/analysis.js +119 -375
  109. package/server-dist/llm/analysis.js.map +1 -1
  110. package/server-dist/llm/facet-extraction.d.ts +14 -0
  111. package/server-dist/llm/facet-extraction.d.ts.map +1 -0
  112. package/server-dist/llm/facet-extraction.js +91 -0
  113. package/server-dist/llm/facet-extraction.js.map +1 -0
  114. package/server-dist/llm/friction-normalize.d.ts +16 -0
  115. package/server-dist/llm/friction-normalize.d.ts.map +1 -0
  116. package/server-dist/llm/friction-normalize.js +54 -0
  117. package/server-dist/llm/friction-normalize.js.map +1 -0
  118. package/server-dist/llm/index.d.ts +3 -2
  119. package/server-dist/llm/index.d.ts.map +1 -1
  120. package/server-dist/llm/index.js +1 -1
  121. package/server-dist/llm/index.js.map +1 -1
  122. package/server-dist/llm/message-format.d.ts +32 -0
  123. package/server-dist/llm/message-format.d.ts.map +1 -0
  124. package/server-dist/llm/message-format.js +129 -0
  125. package/server-dist/llm/message-format.js.map +1 -0
  126. package/server-dist/llm/normalize-utils.d.ts +22 -0
  127. package/server-dist/llm/normalize-utils.d.ts.map +1 -0
  128. package/server-dist/llm/normalize-utils.js +71 -0
  129. package/server-dist/llm/normalize-utils.js.map +1 -0
  130. package/server-dist/llm/pattern-normalize.d.ts +19 -0
  131. package/server-dist/llm/pattern-normalize.d.ts.map +1 -0
  132. package/server-dist/llm/pattern-normalize.js +90 -0
  133. package/server-dist/llm/pattern-normalize.js.map +1 -0
  134. package/server-dist/llm/prompt-constants.d.ts +9 -0
  135. package/server-dist/llm/prompt-constants.d.ts.map +1 -0
  136. package/server-dist/llm/prompt-constants.js +169 -0
  137. package/server-dist/llm/prompt-constants.js.map +1 -0
  138. package/server-dist/llm/prompt-quality-analysis.d.ts +8 -0
  139. package/server-dist/llm/prompt-quality-analysis.d.ts.map +1 -0
  140. package/server-dist/llm/prompt-quality-analysis.js +133 -0
  141. package/server-dist/llm/prompt-quality-analysis.js.map +1 -0
  142. package/server-dist/llm/prompt-quality-normalize.d.ts +26 -0
  143. package/server-dist/llm/prompt-quality-normalize.d.ts.map +1 -0
  144. package/server-dist/llm/prompt-quality-normalize.js +116 -0
  145. package/server-dist/llm/prompt-quality-normalize.js.map +1 -0
  146. package/server-dist/llm/prompt-types.d.ts +124 -0
  147. package/server-dist/llm/prompt-types.d.ts.map +1 -0
  148. package/server-dist/llm/prompt-types.js +4 -0
  149. package/server-dist/llm/prompt-types.js.map +1 -0
  150. package/server-dist/llm/prompts.d.ts +57 -100
  151. package/server-dist/llm/prompts.d.ts.map +1 -1
  152. package/server-dist/llm/prompts.js +606 -232
  153. package/server-dist/llm/prompts.js.map +1 -1
  154. package/server-dist/llm/providers/anthropic.d.ts.map +1 -1
  155. package/server-dist/llm/providers/anthropic.js +12 -0
  156. package/server-dist/llm/providers/anthropic.js.map +1 -1
  157. package/server-dist/llm/providers/gemini.d.ts.map +1 -1
  158. package/server-dist/llm/providers/gemini.js +10 -2
  159. package/server-dist/llm/providers/gemini.js.map +1 -1
  160. package/server-dist/llm/providers/ollama.d.ts.map +1 -1
  161. package/server-dist/llm/providers/ollama.js +3 -1
  162. package/server-dist/llm/providers/ollama.js.map +1 -1
  163. package/server-dist/llm/providers/openai.d.ts.map +1 -1
  164. package/server-dist/llm/providers/openai.js +4 -1
  165. package/server-dist/llm/providers/openai.js.map +1 -1
  166. package/server-dist/llm/recurring-insights.d.ts +26 -0
  167. package/server-dist/llm/recurring-insights.d.ts.map +1 -0
  168. package/server-dist/llm/recurring-insights.js +119 -0
  169. package/server-dist/llm/recurring-insights.js.map +1 -0
  170. package/server-dist/llm/reflect-prompts.d.ts +55 -0
  171. package/server-dist/llm/reflect-prompts.d.ts.map +1 -0
  172. package/server-dist/llm/reflect-prompts.js +151 -0
  173. package/server-dist/llm/reflect-prompts.js.map +1 -0
  174. package/server-dist/llm/response-parsers.d.ts +8 -0
  175. package/server-dist/llm/response-parsers.d.ts.map +1 -0
  176. package/server-dist/llm/response-parsers.js +151 -0
  177. package/server-dist/llm/response-parsers.js.map +1 -0
  178. package/server-dist/llm/types.d.ts +23 -1
  179. package/server-dist/llm/types.d.ts.map +1 -1
  180. package/server-dist/llm/types.js +10 -1
  181. package/server-dist/llm/types.js.map +1 -1
  182. package/server-dist/routes/analysis.d.ts.map +1 -1
  183. package/server-dist/routes/analysis.js +107 -282
  184. package/server-dist/routes/analysis.js.map +1 -1
  185. package/server-dist/routes/analytics.d.ts.map +1 -1
  186. package/server-dist/routes/analytics.js +3 -1
  187. package/server-dist/routes/analytics.js.map +1 -1
  188. package/server-dist/routes/export.d.ts.map +1 -1
  189. package/server-dist/routes/export.js +19 -27
  190. package/server-dist/routes/export.js.map +1 -1
  191. package/server-dist/routes/facets.d.ts +4 -0
  192. package/server-dist/routes/facets.d.ts.map +1 -0
  193. package/server-dist/routes/facets.js +208 -0
  194. package/server-dist/routes/facets.js.map +1 -0
  195. package/server-dist/routes/insights.d.ts.map +1 -1
  196. package/server-dist/routes/insights.js +12 -11
  197. package/server-dist/routes/insights.js.map +1 -1
  198. package/server-dist/routes/reflect.d.ts +4 -0
  199. package/server-dist/routes/reflect.d.ts.map +1 -0
  200. package/server-dist/routes/reflect.js +332 -0
  201. package/server-dist/routes/reflect.js.map +1 -0
  202. package/server-dist/routes/route-helpers.d.ts +124 -0
  203. package/server-dist/routes/route-helpers.d.ts.map +1 -0
  204. package/server-dist/routes/route-helpers.js +242 -0
  205. package/server-dist/routes/route-helpers.js.map +1 -0
  206. package/server-dist/routes/sessions.d.ts.map +1 -1
  207. package/server-dist/routes/sessions.js +29 -5
  208. package/server-dist/routes/sessions.js.map +1 -1
  209. package/server-dist/routes/shared-aggregation.d.ts +82 -0
  210. package/server-dist/routes/shared-aggregation.d.ts.map +1 -0
  211. package/server-dist/routes/shared-aggregation.js +384 -0
  212. package/server-dist/routes/shared-aggregation.js.map +1 -0
  213. package/dashboard-dist/assets/index-BaKju1iW.js +0 -607
  214. package/dashboard-dist/assets/index-_SWpRg6C.css +0 -1
@@ -0,0 +1,384 @@
1
+ // Shared aggregation logic for facets and reflect routes.
2
+ // Extracted to avoid ~150 lines of duplication between the two routes.
3
+ import { normalizeFrictionCategory } from '../llm/friction-normalize.js';
4
+ import { normalizePatternCategory, getPatternCategoryLabel } from '../llm/pattern-normalize.js';
5
+ import { normalizePromptQualityCategory, PQ_CATEGORY_LABELS } from '../llm/prompt-quality-normalize.js';
6
+ import { CANONICAL_PQ_STRENGTH_CATEGORIES } from '../llm/prompt-constants.js';
7
+ // ISO week regex: matches YYYY-WNN format (e.g., 2026-W10)
8
+ const ISO_WEEK_RE = /^(\d{4})-W(\d{2})$/;
9
+ /**
10
+ * Parse an ISO week string (YYYY-WNN) into UTC Monday/Sunday boundaries.
11
+ * Returns { start: Monday 00:00 UTC, end: next Monday 00:00 UTC } (exclusive end).
12
+ *
13
+ * ISO 8601 week rules: week 1 contains the first Thursday of the year,
14
+ * weeks start on Monday. We use the "Thursday trick": Jan 4 is always
15
+ * in week 1, so we find that Monday, then step to the target week.
16
+ */
17
+ export function parseIsoWeek(weekStr) {
18
+ const match = ISO_WEEK_RE.exec(weekStr);
19
+ if (!match)
20
+ return null;
21
+ const year = parseInt(match[1], 10);
22
+ const week = parseInt(match[2], 10);
23
+ if (week < 1 || week > 53)
24
+ return null;
25
+ // Jan 4 is always in ISO week 1. Find that Monday.
26
+ const jan4 = new Date(Date.UTC(year, 0, 4));
27
+ const jan4Day = jan4.getUTCDay(); // 0=Sun, 1=Mon, ..., 6=Sat
28
+ // Days to Monday of week 1: if Sunday (0), go back 6; else go back (day - 1)
29
+ const daysToMonday = jan4Day === 0 ? 6 : jan4Day - 1;
30
+ const week1Monday = new Date(jan4.getTime() - daysToMonday * 86400000);
31
+ // Offset to the target week's Monday
32
+ const start = new Date(week1Monday.getTime() + (week - 1) * 7 * 86400000);
33
+ const end = new Date(start.getTime() + 7 * 86400000);
34
+ return { start, end };
35
+ }
36
+ /**
37
+ * Format a Date (representing a Monday) as an ISO week string (YYYY-WNN).
38
+ * Used when generating week inventory from a list of Mondays.
39
+ */
40
+ export function formatIsoWeek(monday) {
41
+ // Find which ISO week number this Monday belongs to.
42
+ // The Monday's Thursday (3 days ahead) determines the year and week.
43
+ const thursday = new Date(monday.getTime() + 3 * 86400000);
44
+ const year = thursday.getUTCFullYear();
45
+ // Find the Monday of week 1 for this ISO year
46
+ const jan4 = new Date(Date.UTC(year, 0, 4));
47
+ const jan4Day = jan4.getUTCDay();
48
+ const daysToMonday = jan4Day === 0 ? 6 : jan4Day - 1;
49
+ const week1Monday = new Date(jan4.getTime() - daysToMonday * 86400000);
50
+ const weekNum = Math.round((monday.getTime() - week1Monday.getTime()) / (7 * 86400000)) + 1;
51
+ return `${year}-W${String(weekNum).padStart(2, '0')}`;
52
+ }
53
+ export function buildPeriodFilter(period) {
54
+ const now = new Date();
55
+ if (period === '7d')
56
+ return new Date(now.getTime() - 7 * 86400000).toISOString();
57
+ if (period === '30d')
58
+ return new Date(now.getTime() - 30 * 86400000).toISOString();
59
+ if (period === '90d')
60
+ return new Date(now.getTime() - 90 * 86400000).toISOString();
61
+ return null; // 'all'
62
+ }
63
+ export function buildWhereClause(period, project, source) {
64
+ // Always exclude soft-deleted sessions from aggregations
65
+ const conditions = ['s.deleted_at IS NULL'];
66
+ const params = [];
67
+ // ISO week period: use precise Monday-to-Monday UTC boundaries
68
+ const isoWeekBounds = parseIsoWeek(period);
69
+ if (isoWeekBounds) {
70
+ conditions.push('s.started_at >= ?');
71
+ params.push(isoWeekBounds.start.toISOString());
72
+ conditions.push('s.started_at < ?');
73
+ params.push(isoWeekBounds.end.toISOString());
74
+ }
75
+ else {
76
+ const periodStart = buildPeriodFilter(period);
77
+ if (periodStart) {
78
+ conditions.push('s.started_at >= ?');
79
+ params.push(periodStart);
80
+ }
81
+ }
82
+ if (project) {
83
+ conditions.push('s.project_id = ?');
84
+ params.push(project);
85
+ }
86
+ if (source) {
87
+ conditions.push('s.source_tool = ?');
88
+ params.push(source);
89
+ }
90
+ return {
91
+ where: `WHERE ${conditions.join(' AND ')}`,
92
+ params,
93
+ };
94
+ }
95
+ /**
96
+ * Run all aggregation queries needed for facet analysis and synthesis.
97
+ * Aggregation is done in code (SQL), not by LLMs — LLMs synthesize, they don't count.
98
+ *
99
+ * project and source are passed separately so streak can build its own
100
+ * period-free where clause (streak measures continuity across all time).
101
+ */
102
+ export function getAggregatedData(db, where, params, project, source) {
103
+ const hasWhere = where.length > 0;
104
+ const extraPrefix = hasWhere ? 'AND' : 'WHERE';
105
+ const frictionCategories = db.prepare(`
106
+ SELECT
107
+ json_extract(je.value, '$.category') as category,
108
+ COUNT(*) as count,
109
+ AVG(CASE
110
+ WHEN json_extract(je.value, '$.severity') = 'high' THEN 3
111
+ WHEN json_extract(je.value, '$.severity') = 'medium' THEN 2
112
+ ELSE 1
113
+ END) as avg_severity,
114
+ json_group_array(json_extract(je.value, '$.description')) as examples,
115
+ json_group_array(sf.session_id) as session_ids
116
+ FROM session_facets sf
117
+ JOIN sessions s ON sf.session_id = s.id
118
+ CROSS JOIN json_each(sf.friction_points) je
119
+ ${where}
120
+ GROUP BY category
121
+ ORDER BY count DESC, avg_severity DESC
122
+ `).all(...params);
123
+ // Fetch effective patterns with confidence >= 50.
124
+ // Category-based grouping happens in code (post-query) after normalizePatternCategory()
125
+ // to handle any LLM variants that were stored before normalization was applied at write time.
126
+ // extraPrefix handles the case where where is '' (tests pass empty string) vs a WHERE clause.
127
+ const effectivePatternsRaw = db.prepare(`
128
+ SELECT
129
+ json_extract(je.value, '$.category') as category,
130
+ json_extract(je.value, '$.description') as description,
131
+ json_extract(je.value, '$.confidence') as confidence,
132
+ json_extract(je.value, '$.driver') as driver
133
+ FROM session_facets sf
134
+ JOIN sessions s ON sf.session_id = s.id
135
+ CROSS JOIN json_each(sf.effective_patterns) je
136
+ ${where}
137
+ ${extraPrefix} json_extract(je.value, '$.confidence') >= 50
138
+ ORDER BY json_extract(je.value, '$.confidence') DESC
139
+ `).all(...params);
140
+ const outcomeDistribution = db.prepare(`
141
+ SELECT outcome_satisfaction, COUNT(*) as count
142
+ FROM session_facets sf JOIN sessions s ON sf.session_id = s.id
143
+ ${where}
144
+ GROUP BY outcome_satisfaction
145
+ `).all(...params);
146
+ const workflowDistribution = db.prepare(`
147
+ SELECT workflow_pattern, COUNT(*) as count
148
+ FROM session_facets sf JOIN sessions s ON sf.session_id = s.id
149
+ ${where}
150
+ ${extraPrefix} sf.workflow_pattern IS NOT NULL
151
+ GROUP BY workflow_pattern
152
+ `).all(...params);
153
+ const characterDistribution = db.prepare(`
154
+ SELECT session_character, COUNT(*) as count
155
+ FROM sessions s
156
+ ${where}
157
+ ${extraPrefix} s.session_character IS NOT NULL
158
+ GROUP BY session_character
159
+ `).all(...params);
160
+ const totalRow = db.prepare(`SELECT COUNT(*) as count FROM session_facets sf JOIN sessions s ON sf.session_id = s.id ${where}`).get(...params);
161
+ const totalAllRow = db.prepare(`SELECT COUNT(*) as count FROM sessions s ${where}`).get(...params);
162
+ // Parse examples and session_ids from json_group_array output, then normalize via alias + Levenshtein clustering
163
+ const parsedFriction = frictionCategories.map(fc => ({
164
+ ...fc,
165
+ examples: JSON.parse(fc.examples),
166
+ session_ids: JSON.parse(fc.session_ids),
167
+ }));
168
+ const normalizedFriction = new Map();
169
+ for (const fc of parsedFriction) {
170
+ const normalized = normalizeFrictionCategory(fc.category);
171
+ const existing = normalizedFriction.get(normalized);
172
+ if (existing) {
173
+ existing.count += fc.count;
174
+ existing.total_severity += fc.avg_severity * fc.count;
175
+ existing.examples.push(...fc.examples);
176
+ existing.session_ids.push(...fc.session_ids);
177
+ }
178
+ else {
179
+ normalizedFriction.set(normalized, {
180
+ count: fc.count,
181
+ total_severity: fc.avg_severity * fc.count,
182
+ examples: [...fc.examples],
183
+ session_ids: [...fc.session_ids],
184
+ });
185
+ }
186
+ }
187
+ // Partition: separate rate-limit-hit entries from general friction.
188
+ // Rate limits are a billing/plan constraint — surfaced as a usage insight, not friction.
189
+ // The alias map already normalizes all rate limit variants to "rate-limit-hit".
190
+ // A regex sweep catches creative LLM variants ("throttled-by-api", etc.) that bypass
191
+ // both the alias map and Levenshtein clustering.
192
+ const RATE_LIMIT_CATEGORY = 'rate-limit-hit';
193
+ const RATE_LIMIT_REGEX = /rate.?limit|throttl/i;
194
+ let rateLimitInfo = null;
195
+ // Accumulated data for rateLimitInfo, merged from exact match + regex sweep
196
+ let rateLimitCount = 0;
197
+ let rateLimitSessionIds = [];
198
+ let rateLimitExamples = [];
199
+ const rateLimitEntry = normalizedFriction.get(RATE_LIMIT_CATEGORY);
200
+ if (rateLimitEntry) {
201
+ rateLimitCount += rateLimitEntry.count;
202
+ rateLimitSessionIds.push(...rateLimitEntry.session_ids);
203
+ rateLimitExamples.push(...rateLimitEntry.examples);
204
+ normalizedFriction.delete(RATE_LIMIT_CATEGORY);
205
+ }
206
+ // Regex sweep over remaining entries to catch variants the alias map missed
207
+ for (const [category, entry] of normalizedFriction) {
208
+ if (RATE_LIMIT_REGEX.test(category)) {
209
+ rateLimitCount += entry.count;
210
+ rateLimitSessionIds.push(...entry.session_ids);
211
+ rateLimitExamples.push(...entry.examples);
212
+ normalizedFriction.delete(category);
213
+ }
214
+ }
215
+ if (rateLimitCount > 0) {
216
+ const uniqueSessions = new Set(rateLimitSessionIds);
217
+ rateLimitInfo = {
218
+ count: rateLimitCount,
219
+ sessionsAffected: uniqueSessions.size,
220
+ examples: rateLimitExamples.slice(0, 3),
221
+ };
222
+ }
223
+ const mergedFriction = Array.from(normalizedFriction.entries())
224
+ .map(([category, data]) => ({
225
+ category,
226
+ count: data.count,
227
+ avg_severity: data.total_severity / data.count,
228
+ examples: data.examples.slice(0, 10),
229
+ }))
230
+ .sort((a, b) => b.count - a.count || b.avg_severity - a.avg_severity);
231
+ // frictionTotal reflects only non-rate-limit friction (rate limits partitioned separately)
232
+ const frictionTotal = mergedFriction.reduce((sum, fc) => sum + fc.count, 0);
233
+ // Aggregate effective patterns by normalized category.
234
+ // Each row from effectivePatternsRaw is a single pattern entry — we group by normalized
235
+ // category in code so normalizePatternCategory() can handle LLM variants at query time.
236
+ const normalizedPatterns = new Map();
237
+ for (const row of effectivePatternsRaw) {
238
+ // Skip entries with null category or description (malformed JSON in older sessions)
239
+ if (!row.category || !row.description)
240
+ continue;
241
+ const normalized = normalizePatternCategory(row.category);
242
+ const existing = normalizedPatterns.get(normalized);
243
+ if (existing) {
244
+ existing.count += 1;
245
+ existing.total_confidence += row.confidence ?? 0;
246
+ existing.descriptions.push(row.description);
247
+ // Track driver breakdown — null/missing driver is silently skipped (transition period)
248
+ if (row.driver) {
249
+ existing.drivers[row.driver] = (existing.drivers[row.driver] ?? 0) + 1;
250
+ }
251
+ }
252
+ else {
253
+ const drivers = {};
254
+ if (row.driver) {
255
+ drivers[row.driver] = 1;
256
+ }
257
+ normalizedPatterns.set(normalized, {
258
+ count: 1,
259
+ total_confidence: row.confidence ?? 0,
260
+ descriptions: [row.description],
261
+ drivers,
262
+ });
263
+ }
264
+ }
265
+ const effectivePatterns = Array.from(normalizedPatterns.entries())
266
+ .map(([category, data]) => ({
267
+ category,
268
+ label: getPatternCategoryLabel(category),
269
+ frequency: data.count,
270
+ avg_confidence: data.count > 0 ? data.total_confidence / data.count : 0,
271
+ descriptions: data.descriptions.slice(0, 10),
272
+ drivers: data.drivers,
273
+ }))
274
+ .sort((a, b) => b.frequency - a.frequency || b.avg_confidence - a.avg_confidence);
275
+ // Count distinct source tools within scope (for hero card stat pill)
276
+ const sourceToolRow = db.prepare(`SELECT COUNT(DISTINCT source_tool) as count FROM sessions s ${where}`).get(...params);
277
+ // Streak: count consecutive days (backward from today) with at least one session.
278
+ // Always uses all-time scope — filtering by period would cap streak at the window size.
279
+ // Respects project and source filters since those are user-scope constraints.
280
+ const { where: streakWhere, params: streakParams } = buildWhereClause('all', project, source);
281
+ const sessionDates = db.prepare(`SELECT DISTINCT date(started_at) as session_date FROM sessions s ${streakWhere} ORDER BY session_date DESC`).all(...streakParams);
282
+ // Compare dates as YYYY-MM-DD strings in UTC to match SQLite's date() output.
283
+ // Using toISOString().slice(0,10) avoids local timezone shifting the day boundary.
284
+ const todayUTC = new Date().toISOString().slice(0, 10);
285
+ const yesterdayUTC = new Date(Date.now() - 86400000).toISOString().slice(0, 10);
286
+ let streak = 0;
287
+ // baseline is the date we expect for the next streak entry.
288
+ // Start at today; if first session is yesterday, reset baseline to yesterday so
289
+ // the loop can continue counting backward from there correctly.
290
+ let baseline = null;
291
+ for (const { session_date } of sessionDates) {
292
+ if (baseline === null) {
293
+ // First entry: must be today or yesterday to start an active streak
294
+ if (session_date === todayUTC) {
295
+ baseline = todayUTC;
296
+ }
297
+ else if (session_date === yesterdayUTC) {
298
+ baseline = yesterdayUTC;
299
+ }
300
+ else {
301
+ break; // Gap from today — no active streak
302
+ }
303
+ streak++;
304
+ }
305
+ else {
306
+ // Subsequent entries: must be exactly one day before current baseline
307
+ const prevDay = new Date(baseline + 'T00:00:00Z');
308
+ prevDay.setUTCDate(prevDay.getUTCDate() - 1);
309
+ const expectedPrev = prevDay.toISOString().slice(0, 10);
310
+ if (session_date !== expectedPrev)
311
+ break;
312
+ baseline = expectedPrev;
313
+ streak++;
314
+ }
315
+ }
316
+ const { pqDeficits, pqStrengths } = aggregatePQFindings(db, where, params);
317
+ return {
318
+ frictionCategories: mergedFriction,
319
+ effectivePatterns,
320
+ outcomeDistribution: Object.fromEntries(outcomeDistribution.map(o => [o.outcome_satisfaction, o.count])),
321
+ workflowDistribution: Object.fromEntries(workflowDistribution.map(w => [w.workflow_pattern, w.count])),
322
+ characterDistribution: Object.fromEntries(characterDistribution.map(ch => [ch.session_character, ch.count])),
323
+ totalSessions: totalRow.count,
324
+ frictionTotal,
325
+ totalAllSessions: totalAllRow.count,
326
+ rateLimitInfo,
327
+ streak,
328
+ sourceToolCount: sourceToolRow.count,
329
+ pqDeficits,
330
+ pqStrengths,
331
+ };
332
+ }
333
+ /**
334
+ * Aggregate prompt quality findings from the insights table for the given scope.
335
+ * Returns deficits and strengths as separate arrays, pre-filtered to count >= 2.
336
+ * Count is session-level (unique session IDs), not finding-level — more honest signal.
337
+ *
338
+ * Uses the same where/params scope as getAggregatedData so period/project/source filters apply.
339
+ */
340
+ export function aggregatePQFindings(db, where, params) {
341
+ const hasWhere = where.length > 0;
342
+ const extraPrefix = hasWhere ? 'AND' : 'WHERE';
343
+ const rows = db.prepare(`
344
+ SELECT i.metadata, i.session_id
345
+ FROM insights i
346
+ JOIN sessions s ON i.session_id = s.id
347
+ ${where}
348
+ ${extraPrefix} i.type = 'prompt_quality'
349
+ `).all(...params);
350
+ const deficitCounts = new Map();
351
+ const strengthCounts = new Map();
352
+ const strengthSet = new Set(CANONICAL_PQ_STRENGTH_CATEGORIES);
353
+ for (const row of rows) {
354
+ let metadata;
355
+ try {
356
+ metadata = JSON.parse(row.metadata);
357
+ }
358
+ catch {
359
+ continue;
360
+ }
361
+ const findings = metadata.findings;
362
+ if (!Array.isArray(findings))
363
+ continue;
364
+ for (const finding of findings) {
365
+ if (typeof finding?.category !== 'string')
366
+ continue;
367
+ const normalized = normalizePromptQualityCategory(finding.category);
368
+ const bucket = strengthSet.has(normalized) ? strengthCounts : deficitCounts;
369
+ if (!bucket.has(normalized))
370
+ bucket.set(normalized, new Set());
371
+ bucket.get(normalized).add(row.session_id);
372
+ }
373
+ }
374
+ const toSorted = (map) => [...map.entries()]
375
+ .map(([category, sessions]) => ({
376
+ category,
377
+ label: PQ_CATEGORY_LABELS[category] ?? category,
378
+ count: sessions.size,
379
+ }))
380
+ .filter(e => e.count >= 2)
381
+ .sort((a, b) => b.count - a.count);
382
+ return { pqDeficits: toSorted(deficitCounts), pqStrengths: toSorted(strengthCounts) };
383
+ }
384
+ //# sourceMappingURL=shared-aggregation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared-aggregation.js","sourceRoot":"","sources":["../../src/routes/shared-aggregation.ts"],"names":[],"mappings":"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"}