@ccview/core 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 (65) hide show
  1. package/dist/analyzer/claude-md.d.ts +2 -0
  2. package/dist/analyzer/claude-md.d.ts.map +1 -0
  3. package/dist/analyzer/claude-md.js +3 -0
  4. package/dist/analyzer/claude-md.js.map +1 -0
  5. package/dist/analyzer/cost-calculator.d.ts +3 -0
  6. package/dist/analyzer/cost-calculator.d.ts.map +1 -0
  7. package/dist/analyzer/cost-calculator.js +8 -0
  8. package/dist/analyzer/cost-calculator.js.map +1 -0
  9. package/dist/analyzer/insights.d.ts +2 -0
  10. package/dist/analyzer/insights.d.ts.map +1 -0
  11. package/dist/analyzer/insights.js +3 -0
  12. package/dist/analyzer/insights.js.map +1 -0
  13. package/dist/analyzer/waste-detector.d.ts +2 -0
  14. package/dist/analyzer/waste-detector.d.ts.map +1 -0
  15. package/dist/analyzer/waste-detector.js +3 -0
  16. package/dist/analyzer/waste-detector.js.map +1 -0
  17. package/dist/db/index.d.ts +8 -0
  18. package/dist/db/index.d.ts.map +1 -0
  19. package/dist/db/index.js +28 -0
  20. package/dist/db/index.js.map +1 -0
  21. package/dist/db/queries.d.ts +62 -0
  22. package/dist/db/queries.d.ts.map +1 -0
  23. package/dist/db/queries.js +404 -0
  24. package/dist/db/queries.js.map +1 -0
  25. package/dist/db/schema.d.ts +4 -0
  26. package/dist/db/schema.d.ts.map +1 -0
  27. package/dist/db/schema.js +148 -0
  28. package/dist/db/schema.js.map +1 -0
  29. package/dist/db/sync.d.ts +4 -0
  30. package/dist/db/sync.d.ts.map +1 -0
  31. package/dist/db/sync.js +63 -0
  32. package/dist/db/sync.js.map +1 -0
  33. package/dist/index.d.ts +5 -0
  34. package/dist/index.d.ts.map +1 -0
  35. package/dist/index.js +6 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/parser/file-impact.d.ts +5 -0
  38. package/dist/parser/file-impact.d.ts.map +1 -0
  39. package/dist/parser/file-impact.js +102 -0
  40. package/dist/parser/file-impact.js.map +1 -0
  41. package/dist/parser/index.d.ts +7 -0
  42. package/dist/parser/index.d.ts.map +1 -0
  43. package/dist/parser/index.js +6 -0
  44. package/dist/parser/index.js.map +1 -0
  45. package/dist/parser/log-scanner.d.ts +24 -0
  46. package/dist/parser/log-scanner.d.ts.map +1 -0
  47. package/dist/parser/log-scanner.js +115 -0
  48. package/dist/parser/log-scanner.js.map +1 -0
  49. package/dist/parser/session-parser.d.ts +3 -0
  50. package/dist/parser/session-parser.d.ts.map +1 -0
  51. package/dist/parser/session-parser.js +131 -0
  52. package/dist/parser/session-parser.js.map +1 -0
  53. package/dist/parser/step-parser.d.ts +12 -0
  54. package/dist/parser/step-parser.d.ts.map +1 -0
  55. package/dist/parser/step-parser.js +242 -0
  56. package/dist/parser/step-parser.js.map +1 -0
  57. package/dist/parser/token-estimator.d.ts +11 -0
  58. package/dist/parser/token-estimator.d.ts.map +1 -0
  59. package/dist/parser/token-estimator.js +19 -0
  60. package/dist/parser/token-estimator.js.map +1 -0
  61. package/dist/types.d.ts +90 -0
  62. package/dist/types.d.ts.map +1 -0
  63. package/dist/types.js +11 -0
  64. package/dist/types.js.map +1 -0
  65. package/package.json +38 -0
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=claude-md.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-md.d.ts","sourceRoot":"","sources":["../../src/analyzer/claude-md.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ export {};
2
+ // TODO: implementato da db-indexer
3
+ //# sourceMappingURL=claude-md.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-md.js","sourceRoot":"","sources":["../../src/analyzer/claude-md.ts"],"names":[],"mappings":";AAAA,mCAAmC"}
@@ -0,0 +1,3 @@
1
+ import type { ModelName } from '../types.js';
2
+ export declare function calculateCost(tokensIn: number, tokensOut: number, model: ModelName): number;
3
+ //# sourceMappingURL=cost-calculator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost-calculator.d.ts","sourceRoot":"","sources":["../../src/analyzer/cost-calculator.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAE5C,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,MAAM,CAK3F"}
@@ -0,0 +1,8 @@
1
+ import { DEFAULT_PRICING } from '../types.js';
2
+ export function calculateCost(tokensIn, tokensOut, model) {
3
+ const pricing = DEFAULT_PRICING[model];
4
+ const inputCost = (tokensIn / 1_000_000) * pricing.inputPer1M;
5
+ const outputCost = (tokensOut / 1_000_000) * pricing.outputPer1M;
6
+ return Math.round((inputCost + outputCost) * 1_000_000) / 1_000_000;
7
+ }
8
+ //# sourceMappingURL=cost-calculator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost-calculator.js","sourceRoot":"","sources":["../../src/analyzer/cost-calculator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAG7C,MAAM,UAAU,aAAa,CAAC,QAAgB,EAAE,SAAiB,EAAE,KAAgB;IACjF,MAAM,OAAO,GAAG,eAAe,CAAC,KAAK,CAAC,CAAA;IACtC,MAAM,SAAS,GAAG,CAAC,QAAQ,GAAG,SAAS,CAAC,GAAG,OAAO,CAAC,UAAU,CAAA;IAC7D,MAAM,UAAU,GAAG,CAAC,SAAS,GAAG,SAAS,CAAC,GAAG,OAAO,CAAC,WAAW,CAAA;IAChE,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,SAAS,GAAG,UAAU,CAAC,GAAG,SAAS,CAAC,GAAG,SAAS,CAAA;AACrE,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=insights.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"insights.d.ts","sourceRoot":"","sources":["../../src/analyzer/insights.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ export {};
2
+ // TODO: implementato da analytics-charts
3
+ //# sourceMappingURL=insights.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"insights.js","sourceRoot":"","sources":["../../src/analyzer/insights.ts"],"names":[],"mappings":";AAAA,yCAAyC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=waste-detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"waste-detector.d.ts","sourceRoot":"","sources":["../../src/analyzer/waste-detector.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ export {};
2
+ // TODO: implementato da analytics-charts
3
+ //# sourceMappingURL=waste-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"waste-detector.js","sourceRoot":"","sources":["../../src/analyzer/waste-detector.ts"],"names":[],"mappings":";AAAA,yCAAyC"}
@@ -0,0 +1,8 @@
1
+ import Database from 'better-sqlite3';
2
+ export declare function openDatabase(dbPath?: string): Database.Database;
3
+ export { Database };
4
+ export { initSchema } from './schema.js';
5
+ export { SCHEMA_SQL } from './schema.js';
6
+ export * from './queries.js';
7
+ export * from './sync.js';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/db/index.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAA;AAQrC,wBAAgB,YAAY,CAAC,MAAM,SAAkB,GAAG,QAAQ,CAAC,QAAQ,CAsBxE;AAED,OAAO,EAAE,QAAQ,EAAE,CAAA;AACnB,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA"}
@@ -0,0 +1,28 @@
1
+ import Database from 'better-sqlite3';
2
+ import { initSchema } from './schema.js';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import fs from 'node:fs';
6
+ const DEFAULT_DB_PATH = path.join(os.homedir(), '.ccview', 'ccview.db');
7
+ export function openDatabase(dbPath = DEFAULT_DB_PATH) {
8
+ const dir = path.dirname(dbPath);
9
+ if (!fs.existsSync(dir)) {
10
+ fs.mkdirSync(dir, { recursive: true });
11
+ }
12
+ const db = new Database(dbPath);
13
+ db.pragma('journal_mode = WAL');
14
+ db.pragma('foreign_keys = ON');
15
+ const tableExists = db
16
+ .prepare(`SELECT COUNT(*) as cnt FROM sqlite_master WHERE type='table' AND name='sessions'`)
17
+ .get();
18
+ if (!tableExists || tableExists.cnt === 0) {
19
+ initSchema(db);
20
+ }
21
+ return db;
22
+ }
23
+ export { Database };
24
+ export { initSchema } from './schema.js';
25
+ export { SCHEMA_SQL } from './schema.js';
26
+ export * from './queries.js';
27
+ export * from './sync.js';
28
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/db/index.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAA;AACrC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,MAAM,SAAS,CAAA;AACxB,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,EAAE,MAAM,SAAS,CAAA;AAExB,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,WAAW,CAAC,CAAA;AAEvE,MAAM,UAAU,YAAY,CAAC,MAAM,GAAG,eAAe;IACnD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;IAChC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACxB,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IACxC,CAAC;IAED,MAAM,EAAE,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAA;IAE/B,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAA;IAC/B,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAA;IAE9B,MAAM,WAAW,GAAG,EAAE;SACnB,OAAO,CACN,kFAAkF,CACnF;SACA,GAAG,EAAE,CAAA;IAER,IAAI,CAAC,WAAW,IAAI,WAAW,CAAC,GAAG,KAAK,CAAC,EAAE,CAAC;QAC1C,UAAU,CAAC,EAAE,CAAC,CAAA;IAChB,CAAC;IAED,OAAO,EAAE,CAAA;AACX,CAAC;AAED,OAAO,EAAE,QAAQ,EAAE,CAAA;AACnB,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA"}
@@ -0,0 +1,62 @@
1
+ import type Database from 'better-sqlite3';
2
+ import type { Session, Step, FileImpact, Project } from '../types.js';
3
+ export interface SessionFilters {
4
+ project?: string;
5
+ from?: Date;
6
+ to?: Date;
7
+ model?: string;
8
+ search?: string;
9
+ limit?: number;
10
+ offset?: number;
11
+ }
12
+ export interface ProjectStats {
13
+ totalSessions: number;
14
+ totalTokens: number;
15
+ totalCost: number;
16
+ lastSessionAt: Date | null;
17
+ }
18
+ export interface DailyCostRow {
19
+ day: string;
20
+ sessions: number;
21
+ totalTokens: number;
22
+ totalCost: number;
23
+ avgSessionDuration: number;
24
+ }
25
+ export interface FileHotspotRow {
26
+ filePath: string;
27
+ projectName: string;
28
+ totalTouches: number;
29
+ totalLinesAdded: number;
30
+ totalLinesRemoved: number;
31
+ sessionsInvolved: number;
32
+ }
33
+ export interface HotspotOptions {
34
+ project?: string;
35
+ limit?: number;
36
+ }
37
+ export interface OverviewStats {
38
+ totalSessions: number;
39
+ totalTokensIn: number;
40
+ totalTokensOut: number;
41
+ totalCostUsd: number;
42
+ avgSessionDuration: number;
43
+ uniqueFilesTouched: number;
44
+ errorRate: number;
45
+ topProject: string | null;
46
+ }
47
+ export declare function insertSession(db: Database.Database, session: Session): void;
48
+ export declare function getSessionById(db: Database.Database, id: string): Session | null;
49
+ export declare function listSessions(db: Database.Database, filters: SessionFilters): Session[];
50
+ export declare function sessionExistsByHash(db: Database.Database, hash: string): boolean;
51
+ export declare function updateSessionHash(db: Database.Database, logPath: string, hash: string): void;
52
+ export declare function insertStep(db: Database.Database, step: Step): void;
53
+ export declare function listStepsBySession(db: Database.Database, sessionId: string): Step[];
54
+ export declare function insertFileImpact(db: Database.Database, impact: FileImpact): void;
55
+ export declare function listFileImpactsBySession(db: Database.Database, sessionId: string): FileImpact[];
56
+ export declare function upsertProject(db: Database.Database, project: Project): void;
57
+ export declare function listProjects(db: Database.Database): Project[];
58
+ export declare function getProjectStats(db: Database.Database, projectPath: string): ProjectStats;
59
+ export declare function getDailyCosts(db: Database.Database, from?: Date, to?: Date): DailyCostRow[];
60
+ export declare function getFileHotspots(db: Database.Database, options?: HotspotOptions): FileHotspotRow[];
61
+ export declare function getOverviewStats(db: Database.Database, from?: Date, to?: Date): OverviewStats;
62
+ //# sourceMappingURL=queries.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../../src/db/queries.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,404 @@
1
+ // ── Helpers ────────────────────────────────────────────────────────
2
+ function toISOString(d) {
3
+ return d.toISOString();
4
+ }
5
+ function toDateOrNull(v) {
6
+ return v ? new Date(v) : null;
7
+ }
8
+ function mapSessionRow(row) {
9
+ return {
10
+ id: row['id'],
11
+ projectPath: row['project_path'] ?? null,
12
+ projectName: row['project_name'] ?? null,
13
+ startedAt: new Date(row['started_at']),
14
+ endedAt: toDateOrNull(row['ended_at']),
15
+ durationSeconds: row['duration_seconds'] ?? null,
16
+ totalTokensIn: row['total_tokens_in'] ?? 0,
17
+ totalTokensOut: row['total_tokens_out'] ?? 0,
18
+ totalCostUsd: row['total_cost_usd'] ?? 0,
19
+ totalSteps: row['total_steps'] ?? 0,
20
+ toolCallCount: row['tool_call_count'] ?? 0,
21
+ errorCount: row['error_count'] ?? 0,
22
+ retryCount: row['retry_count'] ?? 0,
23
+ model: row['model'] ?? null,
24
+ summary: row['summary'] ?? null,
25
+ rawLogPath: row['raw_log_path'],
26
+ };
27
+ }
28
+ function mapStepRow(row) {
29
+ return {
30
+ id: row['id'],
31
+ sessionId: row['session_id'],
32
+ stepIndex: row['step_index'],
33
+ type: row['type'],
34
+ subtype: row['subtype'] ?? null,
35
+ content: row['content'] ?? null,
36
+ contentSummary: row['content_summary'] ?? null,
37
+ tokensIn: row['tokens_in'] ?? 0,
38
+ tokensOut: row['tokens_out'] ?? 0,
39
+ durationMs: row['duration_ms'] ?? null,
40
+ toolName: row['tool_name'] ?? null,
41
+ toolInput: row['tool_input'] ?? null,
42
+ toolOutput: row['tool_output'] ?? null,
43
+ isError: Boolean(row['is_error']),
44
+ isRetry: Boolean(row['is_retry']),
45
+ retryOfStepId: row['retry_of_step_id'] ?? null,
46
+ createdAt: new Date(row['created_at']),
47
+ };
48
+ }
49
+ function mapFileImpactRow(row) {
50
+ return {
51
+ id: row['id'],
52
+ sessionId: row['session_id'],
53
+ stepId: row['step_id'],
54
+ filePath: row['file_path'],
55
+ action: row['action'],
56
+ linesAdded: row['lines_added'] ?? 0,
57
+ linesRemoved: row['lines_removed'] ?? 0,
58
+ diffContent: row['diff_content'] ?? null,
59
+ createdAt: new Date(row['created_at']),
60
+ };
61
+ }
62
+ function mapProjectRow(row) {
63
+ return {
64
+ path: row['path'],
65
+ name: row['name'],
66
+ totalSessions: row['total_sessions'] ?? 0,
67
+ totalTokens: row['total_tokens'] ?? 0,
68
+ totalCostUsd: row['total_cost_usd'] ?? 0,
69
+ firstSessionAt: toDateOrNull(row['first_session_at']),
70
+ lastSessionAt: toDateOrNull(row['last_session_at']),
71
+ claudeMdPath: row['claude_md_path'] ?? null,
72
+ updatedAt: new Date(row['updated_at']),
73
+ };
74
+ }
75
+ // ── Sessions ───────────────────────────────────────────────────────
76
+ export function insertSession(db, session) {
77
+ db.prepare(`
78
+ INSERT INTO sessions (
79
+ id, project_path, project_name, started_at, ended_at,
80
+ duration_seconds, total_tokens_in, total_tokens_out, total_cost_usd,
81
+ total_steps, tool_call_count, error_count, retry_count,
82
+ model, summary, raw_log_path
83
+ ) VALUES (
84
+ @id, @projectPath, @projectName, @startedAt, @endedAt,
85
+ @durationSeconds, @totalTokensIn, @totalTokensOut, @totalCostUsd,
86
+ @totalSteps, @toolCallCount, @errorCount, @retryCount,
87
+ @model, @summary, @rawLogPath
88
+ )
89
+ `).run({
90
+ id: session.id,
91
+ projectPath: session.projectPath,
92
+ projectName: session.projectName,
93
+ startedAt: toISOString(session.startedAt),
94
+ endedAt: session.endedAt ? toISOString(session.endedAt) : null,
95
+ durationSeconds: session.durationSeconds,
96
+ totalTokensIn: session.totalTokensIn,
97
+ totalTokensOut: session.totalTokensOut,
98
+ totalCostUsd: session.totalCostUsd,
99
+ totalSteps: session.totalSteps,
100
+ toolCallCount: session.toolCallCount,
101
+ errorCount: session.errorCount,
102
+ retryCount: session.retryCount,
103
+ model: session.model,
104
+ summary: session.summary,
105
+ rawLogPath: session.rawLogPath,
106
+ });
107
+ }
108
+ export function getSessionById(db, id) {
109
+ const row = db.prepare(`SELECT * FROM sessions WHERE id = ?`).get(id);
110
+ return row ? mapSessionRow(row) : null;
111
+ }
112
+ export function listSessions(db, filters) {
113
+ const conditions = [];
114
+ const params = {};
115
+ if (filters.project) {
116
+ conditions.push(`project_name = @project`);
117
+ params['project'] = filters.project;
118
+ }
119
+ if (filters.from) {
120
+ conditions.push(`started_at >= @from`);
121
+ params['from'] = toISOString(filters.from);
122
+ }
123
+ if (filters.to) {
124
+ conditions.push(`started_at <= @to`);
125
+ params['to'] = toISOString(filters.to);
126
+ }
127
+ if (filters.model) {
128
+ conditions.push(`model = @model`);
129
+ params['model'] = filters.model;
130
+ }
131
+ if (filters.search) {
132
+ conditions.push(`(summary LIKE @search OR project_name LIKE @search)`);
133
+ params['search'] = `%${filters.search}%`;
134
+ }
135
+ const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
136
+ const limit = filters.limit ?? 50;
137
+ const offset = filters.offset ?? 0;
138
+ const rows = db
139
+ .prepare(`SELECT * FROM sessions ${where} ORDER BY started_at DESC LIMIT @limit OFFSET @offset`)
140
+ .all({ ...params, limit, offset });
141
+ return rows.map(mapSessionRow);
142
+ }
143
+ export function sessionExistsByHash(db, hash) {
144
+ const row = db.prepare(`SELECT 1 FROM sessions WHERE log_hash = ?`).get(hash);
145
+ return row !== undefined;
146
+ }
147
+ export function updateSessionHash(db, logPath, hash) {
148
+ db.prepare(`UPDATE sessions SET log_hash = ? WHERE raw_log_path = ?`).run(hash, logPath);
149
+ }
150
+ // ── Steps ──────────────────────────────────────────────────────────
151
+ export function insertStep(db, step) {
152
+ db.prepare(`
153
+ INSERT INTO steps (
154
+ id, session_id, step_index, type, subtype,
155
+ content, content_summary, tokens_in, tokens_out, duration_ms,
156
+ tool_name, tool_input, tool_output,
157
+ is_error, is_retry, retry_of_step_id, created_at
158
+ ) VALUES (
159
+ @id, @sessionId, @stepIndex, @type, @subtype,
160
+ @content, @contentSummary, @tokensIn, @tokensOut, @durationMs,
161
+ @toolName, @toolInput, @toolOutput,
162
+ @isError, @isRetry, @retryOfStepId, @createdAt
163
+ )
164
+ `).run({
165
+ id: step.id,
166
+ sessionId: step.sessionId,
167
+ stepIndex: step.stepIndex,
168
+ type: step.type,
169
+ subtype: step.subtype,
170
+ content: step.content,
171
+ contentSummary: step.contentSummary,
172
+ tokensIn: step.tokensIn,
173
+ tokensOut: step.tokensOut,
174
+ durationMs: step.durationMs,
175
+ toolName: step.toolName,
176
+ toolInput: step.toolInput,
177
+ toolOutput: step.toolOutput,
178
+ isError: step.isError ? 1 : 0,
179
+ isRetry: step.isRetry ? 1 : 0,
180
+ retryOfStepId: step.retryOfStepId,
181
+ createdAt: toISOString(step.createdAt),
182
+ });
183
+ }
184
+ export function listStepsBySession(db, sessionId) {
185
+ const rows = db
186
+ .prepare(`SELECT * FROM steps WHERE session_id = ? ORDER BY step_index ASC`)
187
+ .all(sessionId);
188
+ return rows.map(mapStepRow);
189
+ }
190
+ // ── FileImpacts ────────────────────────────────────────────────────
191
+ export function insertFileImpact(db, impact) {
192
+ db.prepare(`
193
+ INSERT INTO file_impacts (
194
+ session_id, step_id, file_path, action,
195
+ lines_added, lines_removed, diff_content, created_at
196
+ ) VALUES (
197
+ @sessionId, @stepId, @filePath, @action,
198
+ @linesAdded, @linesRemoved, @diffContent, @createdAt
199
+ )
200
+ `).run({
201
+ sessionId: impact.sessionId,
202
+ stepId: impact.stepId,
203
+ filePath: impact.filePath,
204
+ action: impact.action,
205
+ linesAdded: impact.linesAdded,
206
+ linesRemoved: impact.linesRemoved,
207
+ diffContent: impact.diffContent,
208
+ createdAt: toISOString(impact.createdAt),
209
+ });
210
+ }
211
+ export function listFileImpactsBySession(db, sessionId) {
212
+ const rows = db
213
+ .prepare(`SELECT * FROM file_impacts WHERE session_id = ? ORDER BY created_at ASC`)
214
+ .all(sessionId);
215
+ return rows.map(mapFileImpactRow);
216
+ }
217
+ // ── Projects ───────────────────────────────────────────────────────
218
+ export function upsertProject(db, project) {
219
+ db.prepare(`
220
+ INSERT INTO projects (
221
+ path, name, total_sessions, total_tokens, total_cost_usd,
222
+ first_session_at, last_session_at, claude_md_path, updated_at
223
+ ) VALUES (
224
+ @path, @name, @totalSessions, @totalTokens, @totalCostUsd,
225
+ @firstSessionAt, @lastSessionAt, @claudeMdPath, @updatedAt
226
+ )
227
+ ON CONFLICT(path) DO UPDATE SET
228
+ name = excluded.name,
229
+ total_sessions = excluded.total_sessions,
230
+ total_tokens = excluded.total_tokens,
231
+ total_cost_usd = excluded.total_cost_usd,
232
+ first_session_at = excluded.first_session_at,
233
+ last_session_at = excluded.last_session_at,
234
+ claude_md_path = excluded.claude_md_path,
235
+ updated_at = excluded.updated_at
236
+ `).run({
237
+ path: project.path,
238
+ name: project.name,
239
+ totalSessions: project.totalSessions,
240
+ totalTokens: project.totalTokens,
241
+ totalCostUsd: project.totalCostUsd,
242
+ firstSessionAt: project.firstSessionAt ? toISOString(project.firstSessionAt) : null,
243
+ lastSessionAt: project.lastSessionAt ? toISOString(project.lastSessionAt) : null,
244
+ claudeMdPath: project.claudeMdPath,
245
+ updatedAt: toISOString(project.updatedAt),
246
+ });
247
+ }
248
+ export function listProjects(db) {
249
+ const rows = db
250
+ .prepare(`
251
+ SELECT
252
+ p.path,
253
+ p.name,
254
+ p.first_session_at,
255
+ p.last_session_at,
256
+ p.claude_md_path,
257
+ p.updated_at,
258
+ COUNT(s.id) as total_sessions,
259
+ COALESCE(SUM(s.total_tokens_in + s.total_tokens_out), 0) as total_tokens,
260
+ COALESCE(SUM(s.total_cost_usd), 0) as total_cost_usd
261
+ FROM projects p
262
+ LEFT JOIN sessions s ON s.project_path = p.path
263
+ GROUP BY p.path
264
+ ORDER BY p.last_session_at DESC
265
+ `)
266
+ .all();
267
+ return rows.map(mapProjectRow);
268
+ }
269
+ export function getProjectStats(db, projectPath) {
270
+ const row = db.prepare(`
271
+ SELECT
272
+ COUNT(*) as total_sessions,
273
+ COALESCE(SUM(total_tokens_in + total_tokens_out), 0) as total_tokens,
274
+ COALESCE(SUM(total_cost_usd), 0) as total_cost,
275
+ MAX(started_at) as last_session_at
276
+ FROM sessions
277
+ WHERE project_path = ?
278
+ `).get(projectPath);
279
+ return {
280
+ totalSessions: row['total_sessions'] ?? 0,
281
+ totalTokens: row['total_tokens'] ?? 0,
282
+ totalCost: row['total_cost'] ?? 0,
283
+ lastSessionAt: toDateOrNull(row['last_session_at']),
284
+ };
285
+ }
286
+ // ── Analytics ──────────────────────────────────────────────────────
287
+ export function getDailyCosts(db, from, to) {
288
+ const conditions = [];
289
+ const params = {};
290
+ if (from) {
291
+ conditions.push(`started_at >= @from`);
292
+ params['from'] = toISOString(from);
293
+ }
294
+ if (to) {
295
+ conditions.push(`started_at <= @to`);
296
+ params['to'] = toISOString(to);
297
+ }
298
+ const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
299
+ const rows = db.prepare(`
300
+ SELECT
301
+ DATE(started_at) as day,
302
+ COUNT(*) as sessions,
303
+ SUM(total_tokens_in + total_tokens_out) as total_tokens,
304
+ SUM(total_cost_usd) as total_cost,
305
+ AVG(duration_seconds) as avg_session_duration
306
+ FROM sessions
307
+ ${where}
308
+ GROUP BY DATE(started_at)
309
+ ORDER BY day DESC
310
+ `).all(params);
311
+ return rows.map((row) => ({
312
+ day: row['day'],
313
+ sessions: row['sessions'],
314
+ totalTokens: row['total_tokens'] ?? 0,
315
+ totalCost: row['total_cost'] ?? 0,
316
+ avgSessionDuration: row['avg_session_duration'] ?? 0,
317
+ }));
318
+ }
319
+ export function getFileHotspots(db, options) {
320
+ const conditions = [];
321
+ const params = {};
322
+ if (options?.project) {
323
+ conditions.push(`s.project_name = @project`);
324
+ params['project'] = options.project;
325
+ }
326
+ const where = conditions.length > 0 ? `AND ${conditions.join(' AND ')}` : '';
327
+ const limit = options?.limit ?? 50;
328
+ const rows = db.prepare(`
329
+ SELECT
330
+ fi.file_path,
331
+ s.project_name,
332
+ COUNT(*) as total_touches,
333
+ SUM(fi.lines_added) as total_lines_added,
334
+ SUM(fi.lines_removed) as total_lines_removed,
335
+ COUNT(DISTINCT fi.session_id) as sessions_involved
336
+ FROM file_impacts fi
337
+ JOIN sessions s ON fi.session_id = s.id
338
+ WHERE fi.action IN ('create', 'edit', 'delete') ${where}
339
+ GROUP BY fi.file_path, s.project_name
340
+ ORDER BY total_touches DESC
341
+ LIMIT @limit
342
+ `).all({ ...params, limit });
343
+ return rows.map((row) => ({
344
+ filePath: row['file_path'],
345
+ projectName: row['project_name'] ?? '',
346
+ totalTouches: row['total_touches'],
347
+ totalLinesAdded: row['total_lines_added'] ?? 0,
348
+ totalLinesRemoved: row['total_lines_removed'] ?? 0,
349
+ sessionsInvolved: row['sessions_involved'],
350
+ }));
351
+ }
352
+ export function getOverviewStats(db, from, to) {
353
+ const conditions = [];
354
+ const params = {};
355
+ if (from) {
356
+ conditions.push(`s.started_at >= @from`);
357
+ params['from'] = toISOString(from);
358
+ }
359
+ if (to) {
360
+ conditions.push(`s.started_at <= @to`);
361
+ params['to'] = toISOString(to);
362
+ }
363
+ const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
364
+ const row = db.prepare(`
365
+ SELECT
366
+ COUNT(*) as total_sessions,
367
+ COALESCE(SUM(s.total_tokens_in), 0) as total_tokens_in,
368
+ COALESCE(SUM(s.total_tokens_out), 0) as total_tokens_out,
369
+ COALESCE(SUM(s.total_cost_usd), 0) as total_cost_usd,
370
+ COALESCE(AVG(s.duration_seconds), 0) as avg_session_duration,
371
+ COALESCE(SUM(s.error_count), 0) as total_errors,
372
+ COALESCE(SUM(s.total_steps), 0) as total_steps_sum
373
+ FROM sessions s
374
+ ${where}
375
+ `).get(params);
376
+ const filesRow = db.prepare(`
377
+ SELECT COUNT(DISTINCT fi.file_path) as unique_files
378
+ FROM file_impacts fi
379
+ JOIN sessions s ON fi.session_id = s.id
380
+ ${where}
381
+ `).get(params);
382
+ const topProjectRow = db.prepare(`
383
+ SELECT project_name, COUNT(*) as cnt
384
+ FROM sessions s
385
+ ${where}
386
+ ${where ? 'AND' : 'WHERE'} project_name IS NOT NULL
387
+ GROUP BY project_name
388
+ ORDER BY cnt DESC
389
+ LIMIT 1
390
+ `).get(params);
391
+ const totalStepsSum = row['total_steps_sum'] ?? 0;
392
+ const totalErrors = row['total_errors'] ?? 0;
393
+ return {
394
+ totalSessions: row['total_sessions'] ?? 0,
395
+ totalTokensIn: row['total_tokens_in'] ?? 0,
396
+ totalTokensOut: row['total_tokens_out'] ?? 0,
397
+ totalCostUsd: row['total_cost_usd'] ?? 0,
398
+ avgSessionDuration: row['avg_session_duration'] ?? 0,
399
+ uniqueFilesTouched: filesRow['unique_files'] ?? 0,
400
+ errorRate: totalStepsSum > 0 ? totalErrors / totalStepsSum : 0,
401
+ topProject: topProjectRow ? topProjectRow['project_name'] : null,
402
+ };
403
+ }
404
+ //# sourceMappingURL=queries.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queries.js","sourceRoot":"","sources":["../../src/db/queries.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type Database from 'better-sqlite3';
2
+ export declare const SCHEMA_SQL = "\nCREATE TABLE IF NOT EXISTS _migrations (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n version INTEGER NOT NULL UNIQUE,\n name TEXT NOT NULL,\n applied_at DATETIME DEFAULT CURRENT_TIMESTAMP\n);\n\nCREATE TABLE IF NOT EXISTS sessions (\n id TEXT PRIMARY KEY,\n project_path TEXT,\n project_name TEXT,\n started_at DATETIME NOT NULL,\n ended_at DATETIME,\n duration_seconds INTEGER,\n total_tokens_in INTEGER DEFAULT 0,\n total_tokens_out INTEGER DEFAULT 0,\n total_cost_usd REAL DEFAULT 0,\n total_steps INTEGER DEFAULT 0,\n tool_call_count INTEGER DEFAULT 0,\n error_count INTEGER DEFAULT 0,\n retry_count INTEGER DEFAULT 0,\n model TEXT,\n summary TEXT,\n raw_log_path TEXT,\n log_hash TEXT,\n indexed_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n UNIQUE(raw_log_path)\n);\n\nCREATE INDEX IF NOT EXISTS idx_sessions_project ON sessions(project_name);\nCREATE INDEX IF NOT EXISTS idx_sessions_date ON sessions(started_at DESC);\n\nCREATE TABLE IF NOT EXISTS steps (\n id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL,\n step_index INTEGER NOT NULL,\n type TEXT NOT NULL,\n subtype TEXT,\n content TEXT,\n content_summary TEXT,\n tokens_in INTEGER DEFAULT 0,\n tokens_out INTEGER DEFAULT 0,\n duration_ms INTEGER,\n tool_name TEXT,\n tool_input TEXT,\n tool_output TEXT,\n is_error INTEGER DEFAULT 0,\n is_retry INTEGER DEFAULT 0,\n retry_of_step_id TEXT,\n created_at DATETIME NOT NULL,\n FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE,\n FOREIGN KEY (retry_of_step_id) REFERENCES steps(id)\n);\n\nCREATE INDEX IF NOT EXISTS idx_steps_session ON steps(session_id, step_index);\nCREATE INDEX IF NOT EXISTS idx_steps_type ON steps(type);\n\nCREATE TABLE IF NOT EXISTS file_impacts (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n session_id TEXT NOT NULL,\n step_id TEXT NOT NULL,\n file_path TEXT NOT NULL,\n action TEXT NOT NULL,\n lines_added INTEGER DEFAULT 0,\n lines_removed INTEGER DEFAULT 0,\n diff_content TEXT,\n created_at DATETIME NOT NULL,\n FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE,\n FOREIGN KEY (step_id) REFERENCES steps(id) ON DELETE CASCADE\n);\n\nCREATE INDEX IF NOT EXISTS idx_file_impacts_session ON file_impacts(session_id);\nCREATE INDEX IF NOT EXISTS idx_file_impacts_file ON file_impacts(file_path);\n\nCREATE TABLE IF NOT EXISTS projects (\n path TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n total_sessions INTEGER DEFAULT 0,\n total_tokens INTEGER DEFAULT 0,\n total_cost_usd REAL DEFAULT 0,\n first_session_at DATETIME,\n last_session_at DATETIME,\n claude_md_path TEXT,\n updated_at DATETIME DEFAULT CURRENT_TIMESTAMP\n);\n\nCREATE TABLE IF NOT EXISTS claude_md_rules (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n project_path TEXT NOT NULL,\n rule_text TEXT NOT NULL,\n rule_category TEXT,\n times_respected INTEGER DEFAULT 0,\n times_violated INTEGER DEFAULT 0,\n last_checked_at DATETIME,\n FOREIGN KEY (project_path) REFERENCES projects(path)\n);\n\nCREATE VIEW IF NOT EXISTS v_session_overview AS\nSELECT\n s.*,\n p.name as project_display_name,\n COUNT(DISTINCT fi.file_path) as unique_files_touched,\n SUM(CASE WHEN st.is_error THEN 1 ELSE 0 END) as errors,\n SUM(CASE WHEN st.subtype = 'bash' THEN 1 ELSE 0 END) as bash_commands,\n SUM(CASE WHEN st.subtype = 'file_edit' THEN 1 ELSE 0 END) as file_edits\nFROM sessions s\nLEFT JOIN projects p ON s.project_path = p.path\nLEFT JOIN steps st ON s.id = st.session_id\nLEFT JOIN file_impacts fi ON s.id = fi.session_id\nGROUP BY s.id;\n\nCREATE VIEW IF NOT EXISTS v_file_hotspots AS\nSELECT\n fi.file_path,\n s.project_name,\n COUNT(*) as total_touches,\n SUM(fi.lines_added) as total_lines_added,\n SUM(fi.lines_removed) as total_lines_removed,\n COUNT(DISTINCT fi.session_id) as sessions_involved\nFROM file_impacts fi\nJOIN sessions s ON fi.session_id = s.id\nWHERE fi.action IN ('create', 'edit', 'delete')\nGROUP BY fi.file_path, s.project_name\nORDER BY total_touches DESC;\n\nCREATE VIEW IF NOT EXISTS v_daily_costs AS\nSELECT\n DATE(started_at) as day,\n COUNT(*) as sessions,\n SUM(total_tokens_in + total_tokens_out) as total_tokens,\n SUM(total_cost_usd) as total_cost,\n AVG(duration_seconds) as avg_session_duration\nFROM sessions\nGROUP BY DATE(started_at)\nORDER BY day DESC;\n";
3
+ export declare function initSchema(db: Database.Database): void;
4
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/db/schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAA;AAE1C,eAAO,MAAM,UAAU,ssIAwItB,CAAA;AAID,wBAAgB,UAAU,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,IAAI,CActD"}