heyiam 0.1.7 → 0.1.8
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.
- package/dist/analyzer.d.ts +3 -3
- package/dist/archive.d.ts +14 -0
- package/dist/archive.js +125 -0
- package/dist/archive.js.map +1 -0
- package/dist/auth.d.ts +0 -6
- package/dist/auth.js +2 -4
- package/dist/auth.js.map +1 -1
- package/dist/autostart.d.ts +19 -0
- package/dist/autostart.js +103 -0
- package/dist/autostart.js.map +1 -0
- package/dist/bridge.d.ts +0 -2
- package/dist/bridge.js +33 -4
- package/dist/bridge.js.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.js +2 -2
- package/dist/config.js.map +1 -1
- package/dist/context-export.d.ts +22 -0
- package/dist/context-export.js +230 -0
- package/dist/context-export.js.map +1 -0
- package/dist/daemon-install.d.ts +23 -0
- package/dist/daemon-install.js +155 -0
- package/dist/daemon-install.js.map +1 -0
- package/dist/db.d.ts +118 -0
- package/dist/db.js +444 -0
- package/dist/db.js.map +1 -0
- package/dist/export.d.ts +30 -0
- package/dist/export.js +377 -0
- package/dist/export.js.map +1 -0
- package/dist/format-utils.d.ts +6 -0
- package/dist/format-utils.js +15 -0
- package/dist/format-utils.js.map +1 -0
- package/dist/index.js +474 -117
- package/dist/index.js.map +1 -1
- package/dist/llm/project-enhance.js +1 -1
- package/dist/parsers/claude.js +73 -0
- package/dist/parsers/claude.js.map +1 -1
- package/dist/parsers/codex.js +1 -1
- package/dist/parsers/codex.js.map +1 -1
- package/dist/parsers/cursor.d.ts +2 -0
- package/dist/parsers/cursor.js +14 -26
- package/dist/parsers/cursor.js.map +1 -1
- package/dist/parsers/gemini.d.ts +3 -2
- package/dist/parsers/gemini.js +198 -21
- package/dist/parsers/gemini.js.map +1 -1
- package/dist/parsers/index.d.ts +1 -1
- package/dist/parsers/index.js +23 -7
- package/dist/parsers/index.js.map +1 -1
- package/dist/parsers/types.d.ts +27 -1
- package/dist/render/build-render-data.d.ts +59 -0
- package/dist/render/build-render-data.js +101 -0
- package/dist/render/build-render-data.js.map +1 -0
- package/dist/render/components/PortfolioPage.d.ts +4 -0
- package/dist/render/components/PortfolioPage.js +16 -0
- package/dist/render/components/PortfolioPage.js.map +1 -0
- package/dist/render/components/ProjectPage.d.ts +4 -0
- package/dist/render/components/ProjectPage.js +101 -0
- package/dist/render/components/ProjectPage.js.map +1 -0
- package/dist/render/components/SessionPage.d.ts +4 -0
- package/dist/render/components/SessionPage.js +29 -0
- package/dist/render/components/SessionPage.js.map +1 -0
- package/dist/render/index.d.ts +37 -0
- package/dist/render/index.js +140 -0
- package/dist/render/index.js.map +1 -0
- package/dist/render/types.d.ts +121 -0
- package/dist/render/types.js +9 -0
- package/dist/render/types.js.map +1 -0
- package/dist/routes/archive.d.ts +3 -0
- package/dist/routes/archive.js +56 -0
- package/dist/routes/archive.js.map +1 -0
- package/dist/routes/auth.d.ts +3 -0
- package/dist/routes/auth.js +116 -0
- package/dist/routes/auth.js.map +1 -0
- package/dist/routes/context.d.ts +61 -0
- package/dist/routes/context.js +356 -0
- package/dist/routes/context.js.map +1 -0
- package/dist/routes/dashboard.d.ts +3 -0
- package/dist/routes/dashboard.js +103 -0
- package/dist/routes/dashboard.js.map +1 -0
- package/dist/routes/enhance.d.ts +3 -0
- package/dist/routes/enhance.js +305 -0
- package/dist/routes/enhance.js.map +1 -0
- package/dist/routes/export.d.ts +3 -0
- package/dist/routes/export.js +145 -0
- package/dist/routes/export.js.map +1 -0
- package/dist/routes/index.d.ts +12 -0
- package/dist/routes/index.js +13 -0
- package/dist/routes/index.js.map +1 -0
- package/dist/routes/preview.d.ts +3 -0
- package/dist/routes/preview.js +191 -0
- package/dist/routes/preview.js.map +1 -0
- package/dist/routes/projects.d.ts +3 -0
- package/dist/routes/projects.js +356 -0
- package/dist/routes/projects.js.map +1 -0
- package/dist/routes/publish.d.ts +3 -0
- package/dist/routes/publish.js +466 -0
- package/dist/routes/publish.js.map +1 -0
- package/dist/routes/search.d.ts +3 -0
- package/dist/routes/search.js +110 -0
- package/dist/routes/search.js.map +1 -0
- package/dist/routes/sessions.d.ts +3 -0
- package/dist/routes/sessions.js +103 -0
- package/dist/routes/sessions.js.map +1 -0
- package/dist/routes/settings.d.ts +3 -0
- package/dist/routes/settings.js +30 -0
- package/dist/routes/settings.js.map +1 -0
- package/dist/screenshot.d.ts +5 -2
- package/dist/screenshot.js +187 -13
- package/dist/screenshot.js.map +1 -1
- package/dist/search.d.ts +30 -0
- package/dist/search.js +153 -0
- package/dist/search.js.map +1 -0
- package/dist/server.d.ts +1 -1
- package/dist/server.js +55 -1318
- package/dist/server.js.map +1 -1
- package/dist/settings.d.ts +23 -6
- package/dist/settings.js +36 -12
- package/dist/settings.js.map +1 -1
- package/dist/source-audit.d.ts +29 -0
- package/dist/source-audit.js +203 -0
- package/dist/source-audit.js.map +1 -0
- package/dist/sync.d.ts +74 -0
- package/dist/sync.js +358 -0
- package/dist/sync.js.map +1 -0
- package/dist/transcript.d.ts +68 -0
- package/dist/transcript.js +268 -0
- package/dist/transcript.js.map +1 -0
- package/package.json +5 -1
- package/app/dist/assets/html2canvas-Cwn_rrOw.js +0 -5
- package/app/dist/assets/index-CEQyTkgN.js +0 -14
- package/app/dist/assets/index-DLh5xRE8.css +0 -1
- package/app/dist/favicon.svg +0 -5
- package/app/dist/icons.svg +0 -24
- package/app/dist/index.html +0 -20
- package/dist/machine-key.d.ts +0 -10
- package/dist/machine-key.js +0 -51
- package/dist/machine-key.js.map +0 -1
package/dist/db.js
ADDED
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
// SQLite search index for session archive
|
|
2
|
+
// Replaces stats-cache.json with a proper database layer
|
|
3
|
+
import Database from 'better-sqlite3';
|
|
4
|
+
import { mkdirSync, statSync } from 'node:fs';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import { homedir } from 'node:os';
|
|
7
|
+
// ── Constants ────────────────────────────────────────────────
|
|
8
|
+
const CONFIG_DIR = join(homedir(), '.config', 'heyiam');
|
|
9
|
+
export const DB_PATH = join(CONFIG_DIR, 'sessions.db');
|
|
10
|
+
const CURRENT_SCHEMA_VERSION = 2;
|
|
11
|
+
// ── Singleton ────────────────────────────────────────────────
|
|
12
|
+
let _db = null;
|
|
13
|
+
export function getDatabase(dbPath = DB_PATH) {
|
|
14
|
+
if (_db)
|
|
15
|
+
return _db;
|
|
16
|
+
_db = openDatabase(dbPath);
|
|
17
|
+
return _db;
|
|
18
|
+
}
|
|
19
|
+
export function closeDatabase() {
|
|
20
|
+
if (_db) {
|
|
21
|
+
_db.close();
|
|
22
|
+
_db = null;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
// ── Open / Migrate ───────────────────────────────────────────
|
|
26
|
+
export function openDatabase(dbPath = DB_PATH) {
|
|
27
|
+
mkdirSync(join(dbPath, '..'), { recursive: true });
|
|
28
|
+
const db = new Database(dbPath);
|
|
29
|
+
db.pragma('journal_mode = WAL');
|
|
30
|
+
db.pragma('foreign_keys = ON');
|
|
31
|
+
runMigrations(db);
|
|
32
|
+
return db;
|
|
33
|
+
}
|
|
34
|
+
function runMigrations(db) {
|
|
35
|
+
// Create schema_version table if it doesn't exist
|
|
36
|
+
db.exec(`CREATE TABLE IF NOT EXISTS schema_version (version INTEGER)`);
|
|
37
|
+
const row = db.prepare('SELECT version FROM schema_version LIMIT 1').get();
|
|
38
|
+
const currentVersion = row?.version ?? 0;
|
|
39
|
+
if (currentVersion < 2) {
|
|
40
|
+
migrateToV2(db);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function migrateToV2(db) {
|
|
44
|
+
// Drop old tables if upgrading from v1
|
|
45
|
+
db.exec('DROP TABLE IF EXISTS session_files');
|
|
46
|
+
db.exec('DROP TABLE IF EXISTS sessions_fts');
|
|
47
|
+
db.exec('DROP TABLE IF EXISTS sessions');
|
|
48
|
+
const tx = db.transaction(() => {
|
|
49
|
+
// F1: session_files gets composite PK
|
|
50
|
+
// F2: ON DELETE CASCADE on all foreign keys
|
|
51
|
+
// F5: NOT NULL DEFAULT on numeric columns
|
|
52
|
+
// F7: role UNINDEXED in FTS5
|
|
53
|
+
// F21: file_mtime as INTEGER not REAL
|
|
54
|
+
db.exec(`
|
|
55
|
+
CREATE TABLE sessions (
|
|
56
|
+
id TEXT PRIMARY KEY,
|
|
57
|
+
project_dir TEXT NOT NULL,
|
|
58
|
+
source TEXT NOT NULL,
|
|
59
|
+
title TEXT,
|
|
60
|
+
start_time TEXT,
|
|
61
|
+
end_time TEXT,
|
|
62
|
+
duration_minutes REAL NOT NULL DEFAULT 0,
|
|
63
|
+
wall_clock_minutes REAL NOT NULL DEFAULT 0,
|
|
64
|
+
turns INTEGER NOT NULL DEFAULT 0,
|
|
65
|
+
loc_added INTEGER NOT NULL DEFAULT 0,
|
|
66
|
+
loc_removed INTEGER NOT NULL DEFAULT 0,
|
|
67
|
+
loc_net INTEGER NOT NULL DEFAULT 0,
|
|
68
|
+
files_changed INTEGER NOT NULL DEFAULT 0,
|
|
69
|
+
tool_calls INTEGER NOT NULL DEFAULT 0,
|
|
70
|
+
skills TEXT,
|
|
71
|
+
files_touched TEXT,
|
|
72
|
+
models_used TEXT,
|
|
73
|
+
cwd TEXT,
|
|
74
|
+
parent_session_id TEXT,
|
|
75
|
+
agent_role TEXT,
|
|
76
|
+
is_subagent INTEGER NOT NULL DEFAULT 0,
|
|
77
|
+
file_path TEXT,
|
|
78
|
+
file_mtime INTEGER,
|
|
79
|
+
file_size INTEGER,
|
|
80
|
+
indexed_at TEXT,
|
|
81
|
+
context_summary TEXT,
|
|
82
|
+
FOREIGN KEY (parent_session_id) REFERENCES sessions(id) ON DELETE CASCADE
|
|
83
|
+
)
|
|
84
|
+
`);
|
|
85
|
+
db.exec('CREATE INDEX idx_sessions_project ON sessions(project_dir)');
|
|
86
|
+
db.exec('CREATE INDEX idx_sessions_source ON sessions(source)');
|
|
87
|
+
db.exec('CREATE INDEX idx_sessions_start ON sessions(start_time)');
|
|
88
|
+
db.exec('CREATE INDEX idx_sessions_parent ON sessions(parent_session_id)');
|
|
89
|
+
db.exec(`
|
|
90
|
+
CREATE VIRTUAL TABLE sessions_fts USING fts5(
|
|
91
|
+
session_id UNINDEXED,
|
|
92
|
+
role UNINDEXED,
|
|
93
|
+
content,
|
|
94
|
+
tokenize='porter unicode61'
|
|
95
|
+
)
|
|
96
|
+
`);
|
|
97
|
+
db.exec(`
|
|
98
|
+
CREATE TABLE session_files (
|
|
99
|
+
session_id TEXT NOT NULL,
|
|
100
|
+
file_path TEXT NOT NULL,
|
|
101
|
+
additions INTEGER NOT NULL DEFAULT 0,
|
|
102
|
+
deletions INTEGER NOT NULL DEFAULT 0,
|
|
103
|
+
PRIMARY KEY (session_id, file_path),
|
|
104
|
+
FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
|
|
105
|
+
)
|
|
106
|
+
`);
|
|
107
|
+
db.exec('CREATE INDEX idx_session_files_path ON session_files(file_path)');
|
|
108
|
+
// Upsert schema version
|
|
109
|
+
const existing = db.prepare('SELECT version FROM schema_version LIMIT 1').get();
|
|
110
|
+
if (existing) {
|
|
111
|
+
db.prepare('UPDATE schema_version SET version = ?').run(CURRENT_SCHEMA_VERSION);
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
db.prepare('INSERT INTO schema_version (version) VALUES (?)').run(CURRENT_SCHEMA_VERSION);
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
tx();
|
|
118
|
+
}
|
|
119
|
+
// ── Staleness Check ──────────────────────────────────────────
|
|
120
|
+
export function isSessionStale(db, sessionId, filePath) {
|
|
121
|
+
const row = db.prepare('SELECT file_mtime, file_size FROM sessions WHERE id = ?').get(sessionId);
|
|
122
|
+
if (!row)
|
|
123
|
+
return true; // Not in DB — needs indexing
|
|
124
|
+
// Skip stat for non-filesystem paths (e.g. cursor:// URLs) — F23 fix
|
|
125
|
+
if (filePath.includes('://'))
|
|
126
|
+
return true;
|
|
127
|
+
try {
|
|
128
|
+
const stat = statSync(filePath);
|
|
129
|
+
// F21: Use Math.floor to avoid floating-point comparison issues
|
|
130
|
+
const mtime = Math.floor(stat.mtimeMs);
|
|
131
|
+
const size = stat.size;
|
|
132
|
+
return mtime !== row.file_mtime || size !== row.file_size;
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
return true; // Can't stat — re-index to be safe
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
export function upsertSession(db, input) {
|
|
139
|
+
const { meta, analysis, session, fileMtime, fileSize } = input;
|
|
140
|
+
const stmt = db.prepare(`
|
|
141
|
+
INSERT INTO sessions (
|
|
142
|
+
id, project_dir, source, title, start_time, end_time,
|
|
143
|
+
duration_minutes, wall_clock_minutes, turns, loc_added, loc_removed, loc_net,
|
|
144
|
+
files_changed, tool_calls, skills, files_touched, models_used,
|
|
145
|
+
cwd, parent_session_id, agent_role, is_subagent,
|
|
146
|
+
file_path, file_mtime, file_size, indexed_at, context_summary
|
|
147
|
+
) VALUES (
|
|
148
|
+
?, ?, ?, ?, ?, ?,
|
|
149
|
+
?, ?, ?, ?, ?, ?,
|
|
150
|
+
?, ?, ?, ?, ?,
|
|
151
|
+
?, ?, ?, ?,
|
|
152
|
+
?, ?, ?, ?, ?
|
|
153
|
+
)
|
|
154
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
155
|
+
project_dir = excluded.project_dir,
|
|
156
|
+
source = excluded.source,
|
|
157
|
+
title = excluded.title,
|
|
158
|
+
start_time = excluded.start_time,
|
|
159
|
+
end_time = excluded.end_time,
|
|
160
|
+
duration_minutes = excluded.duration_minutes,
|
|
161
|
+
wall_clock_minutes = excluded.wall_clock_minutes,
|
|
162
|
+
turns = excluded.turns,
|
|
163
|
+
loc_added = excluded.loc_added,
|
|
164
|
+
loc_removed = excluded.loc_removed,
|
|
165
|
+
loc_net = excluded.loc_net,
|
|
166
|
+
files_changed = excluded.files_changed,
|
|
167
|
+
tool_calls = excluded.tool_calls,
|
|
168
|
+
skills = excluded.skills,
|
|
169
|
+
files_touched = excluded.files_touched,
|
|
170
|
+
models_used = excluded.models_used,
|
|
171
|
+
cwd = excluded.cwd,
|
|
172
|
+
parent_session_id = excluded.parent_session_id,
|
|
173
|
+
agent_role = excluded.agent_role,
|
|
174
|
+
is_subagent = excluded.is_subagent,
|
|
175
|
+
file_path = excluded.file_path,
|
|
176
|
+
file_mtime = excluded.file_mtime,
|
|
177
|
+
file_size = excluded.file_size,
|
|
178
|
+
indexed_at = excluded.indexed_at,
|
|
179
|
+
context_summary = excluded.context_summary
|
|
180
|
+
`);
|
|
181
|
+
stmt.run(meta.sessionId, meta.projectDir, analysis.source, session.title ?? null, analysis.start_time ?? null, analysis.end_time ?? null, session.durationMinutes, session.wallClockMinutes ?? 0, session.turns, analysis.loc_stats.loc_added, analysis.loc_stats.loc_removed, analysis.loc_stats.loc_net, session.filesChanged.length, session.toolCalls, JSON.stringify(session.skills), JSON.stringify(analysis.files_touched), JSON.stringify(analysis.models_used ?? []), analysis.cwd ?? null, meta.parentSessionId ?? null, meta.agentRole ?? null, meta.isSubagent ? 1 : 0, meta.path, Math.floor(fileMtime), fileSize, new Date().toISOString(), input.contextSummary ?? null);
|
|
182
|
+
}
|
|
183
|
+
// ── Index Session Content (FTS5) ─────────────────────────────
|
|
184
|
+
export function indexSessionContent(db, sessionId, turns) {
|
|
185
|
+
// Clear existing FTS entries for this session
|
|
186
|
+
db.prepare('DELETE FROM sessions_fts WHERE session_id = ?').run(sessionId);
|
|
187
|
+
const insert = db.prepare('INSERT INTO sessions_fts (session_id, role, content) VALUES (?, ?, ?)');
|
|
188
|
+
// F8: Truncate content per turn to prevent FTS index bloat.
|
|
189
|
+
// Tool outputs (file reads, command output) can be 50KB+ but are low-value for search.
|
|
190
|
+
const MAX_CONTENT_CHARS = 10_000;
|
|
191
|
+
for (const turn of turns) {
|
|
192
|
+
const role = turn.type === 'prompt' ? 'user' : turn.type === 'tool' ? 'tool' : 'assistant';
|
|
193
|
+
const content = turn.content;
|
|
194
|
+
if (content && content.length > 0) {
|
|
195
|
+
const truncated = content.length > MAX_CONTENT_CHARS
|
|
196
|
+
? content.slice(0, MAX_CONTENT_CHARS)
|
|
197
|
+
: content;
|
|
198
|
+
insert.run(sessionId, role, truncated);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
// ── Index Session Files ──────────────────────────────────────
|
|
203
|
+
export function indexSessionFiles(db, sessionId, files) {
|
|
204
|
+
db.prepare('DELETE FROM session_files WHERE session_id = ?').run(sessionId);
|
|
205
|
+
const insert = db.prepare('INSERT OR REPLACE INTO session_files (session_id, file_path, additions, deletions) VALUES (?, ?, ?, ?)');
|
|
206
|
+
for (const file of files) {
|
|
207
|
+
insert.run(sessionId, file.path, file.additions, file.deletions);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
// ── Full Index Pipeline (transactional) ──────────────────────
|
|
211
|
+
export function indexSession(db, input, turns) {
|
|
212
|
+
const tx = db.transaction(() => {
|
|
213
|
+
upsertSession(db, input);
|
|
214
|
+
indexSessionContent(db, input.meta.sessionId, turns);
|
|
215
|
+
indexSessionFiles(db, input.meta.sessionId, input.session.filesChanged);
|
|
216
|
+
});
|
|
217
|
+
tx();
|
|
218
|
+
}
|
|
219
|
+
// ── Read: Get Session Stats ──────────────────────────────────
|
|
220
|
+
export function getSessionStats(db, sessionId) {
|
|
221
|
+
const row = db.prepare(`
|
|
222
|
+
SELECT
|
|
223
|
+
id, start_time, end_time, duration_minutes, turns,
|
|
224
|
+
loc_added, loc_removed, files_changed, skills
|
|
225
|
+
FROM sessions WHERE id = ?
|
|
226
|
+
`).get(sessionId);
|
|
227
|
+
if (!row)
|
|
228
|
+
return null;
|
|
229
|
+
const loc = (row.loc_added ?? 0) + (row.loc_removed ?? 0);
|
|
230
|
+
const skills = row.skills ? JSON.parse(row.skills) : [];
|
|
231
|
+
return {
|
|
232
|
+
loc,
|
|
233
|
+
duration: row.duration_minutes ?? 0,
|
|
234
|
+
files: row.files_changed ?? 0,
|
|
235
|
+
turns: row.turns ?? 0,
|
|
236
|
+
skills,
|
|
237
|
+
date: row.start_time ?? '',
|
|
238
|
+
endTime: row.end_time ?? undefined,
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
// ── Read: Get All Project Stats ──────────────────────────────
|
|
242
|
+
export function getAllProjectStats(db) {
|
|
243
|
+
// F9: Single query — no N+1. Fetch aggregates and skills in one pass.
|
|
244
|
+
const rows = db.prepare(`
|
|
245
|
+
SELECT
|
|
246
|
+
project_dir,
|
|
247
|
+
COUNT(*) as session_count,
|
|
248
|
+
COALESCE(SUM(loc_added + loc_removed), 0) as total_loc,
|
|
249
|
+
COALESCE(SUM(duration_minutes), 0) as total_duration,
|
|
250
|
+
COALESCE(SUM(turns), 0) as total_turns,
|
|
251
|
+
MAX(start_time) as latest_date,
|
|
252
|
+
GROUP_CONCAT(DISTINCT source) as sources
|
|
253
|
+
FROM sessions
|
|
254
|
+
WHERE is_subagent = 0
|
|
255
|
+
GROUP BY project_dir
|
|
256
|
+
ORDER BY latest_date DESC
|
|
257
|
+
`).all();
|
|
258
|
+
// Collect all skills in a single query, grouped by project
|
|
259
|
+
const skillRows = db.prepare('SELECT project_dir, skills FROM sessions WHERE skills IS NOT NULL AND is_subagent = 0').all();
|
|
260
|
+
const skillsByProject = new Map();
|
|
261
|
+
for (const sr of skillRows) {
|
|
262
|
+
const parsed = JSON.parse(sr.skills);
|
|
263
|
+
if (!skillsByProject.has(sr.project_dir)) {
|
|
264
|
+
skillsByProject.set(sr.project_dir, new Set());
|
|
265
|
+
}
|
|
266
|
+
const set = skillsByProject.get(sr.project_dir);
|
|
267
|
+
for (const s of parsed)
|
|
268
|
+
set.add(s);
|
|
269
|
+
}
|
|
270
|
+
return rows.map((row) => {
|
|
271
|
+
const projectSkills = skillsByProject.get(row.project_dir);
|
|
272
|
+
const projectName = row.project_dir.replace(/^-/, '').split('-').pop() ?? row.project_dir;
|
|
273
|
+
return {
|
|
274
|
+
projectDir: row.project_dir,
|
|
275
|
+
projectName,
|
|
276
|
+
sessionCount: row.session_count,
|
|
277
|
+
totalLoc: row.total_loc,
|
|
278
|
+
totalDuration: row.total_duration,
|
|
279
|
+
totalTurns: row.total_turns,
|
|
280
|
+
skills: projectSkills ? [...projectSkills].sort() : [],
|
|
281
|
+
sources: row.sources ? row.sources.split(',') : [],
|
|
282
|
+
latestDate: row.latest_date ?? '',
|
|
283
|
+
};
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
// ── Read: Get Session Row ────────────────────────────────────
|
|
287
|
+
export function getSessionRow(db, sessionId) {
|
|
288
|
+
return db.prepare('SELECT * FROM sessions WHERE id = ?').get(sessionId) ?? null;
|
|
289
|
+
}
|
|
290
|
+
// ── Read: Get Context Summary ─────────────────────────────────
|
|
291
|
+
export function getContextSummary(db, sessionId) {
|
|
292
|
+
const row = db.prepare('SELECT context_summary FROM sessions WHERE id = ?').get(sessionId);
|
|
293
|
+
return row?.context_summary ?? null;
|
|
294
|
+
}
|
|
295
|
+
// ── Read: List sessions by project ───────────────────────────
|
|
296
|
+
export function getSessionsByProject(db, projectDir) {
|
|
297
|
+
return db.prepare('SELECT * FROM sessions WHERE project_dir = ? ORDER BY start_time DESC').all(projectDir);
|
|
298
|
+
}
|
|
299
|
+
// ── Delete ───────────────────────────────────────────────────
|
|
300
|
+
export function deleteSession(db, sessionId) {
|
|
301
|
+
const tx = db.transaction(() => {
|
|
302
|
+
db.prepare('DELETE FROM sessions_fts WHERE session_id = ?').run(sessionId);
|
|
303
|
+
db.prepare('DELETE FROM session_files WHERE session_id = ?').run(sessionId);
|
|
304
|
+
db.prepare('DELETE FROM sessions WHERE id = ?').run(sessionId);
|
|
305
|
+
});
|
|
306
|
+
tx();
|
|
307
|
+
}
|
|
308
|
+
// ── Rebuild Index ────────────────────────────────────────────
|
|
309
|
+
export function rebuildIndex(db, onProgress) {
|
|
310
|
+
const tx = db.transaction(() => {
|
|
311
|
+
db.exec('DELETE FROM sessions_fts');
|
|
312
|
+
db.exec('DELETE FROM session_files');
|
|
313
|
+
db.exec('DELETE FROM sessions');
|
|
314
|
+
});
|
|
315
|
+
tx();
|
|
316
|
+
onProgress?.(0, 0);
|
|
317
|
+
}
|
|
318
|
+
/** F17: Merge FTS5 segments for better query performance. Call after bulk indexing. */
|
|
319
|
+
export function optimizeFtsIndex(db) {
|
|
320
|
+
db.exec("INSERT INTO sessions_fts(sessions_fts) VALUES('optimize')");
|
|
321
|
+
}
|
|
322
|
+
// ── Cleanup ──────────────────────────────────────────────────
|
|
323
|
+
//
|
|
324
|
+
// IMPORTANT: We do NOT delete sessions from the DB when the source file
|
|
325
|
+
// is gone. The DB IS the archive — if Claude Code deleted the original
|
|
326
|
+
// after 30 days, the DB row is the preserved copy. That's the whole
|
|
327
|
+
// point of the product.
|
|
328
|
+
//
|
|
329
|
+
// The only valid cleanup is removing sessions that the USER explicitly
|
|
330
|
+
// chose to delete, which would go through deleteSession() directly.
|
|
331
|
+
/** Count sessions whose source file no longer exists (preserved in DB). */
|
|
332
|
+
export function countPreservedSessions(db) {
|
|
333
|
+
const rows = db.prepare("SELECT file_path FROM sessions WHERE file_path IS NOT NULL AND file_path NOT LIKE 'cursor://%'").all();
|
|
334
|
+
let preserved = 0;
|
|
335
|
+
for (const row of rows) {
|
|
336
|
+
try {
|
|
337
|
+
statSync(row.file_path);
|
|
338
|
+
}
|
|
339
|
+
catch {
|
|
340
|
+
preserved++;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
return preserved;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Escape a user query for FTS5. Wraps each term in double quotes
|
|
347
|
+
* to prevent FTS5 syntax injection (*, OR, NOT, NEAR, etc.).
|
|
348
|
+
*/
|
|
349
|
+
function escapeFtsQuery(raw) {
|
|
350
|
+
// Split on whitespace, quote each non-empty term
|
|
351
|
+
const terms = raw.trim().split(/\s+/).filter(Boolean);
|
|
352
|
+
if (terms.length === 0)
|
|
353
|
+
return '""';
|
|
354
|
+
return terms.map((t) => `"${t.replace(/"/g, '""')}"`).join(' ');
|
|
355
|
+
}
|
|
356
|
+
export function searchFts(db, query, limit = 50) {
|
|
357
|
+
const safeQuery = escapeFtsQuery(query);
|
|
358
|
+
// Fetch a larger window of raw FTS matches, then deduplicate in JS.
|
|
359
|
+
// We fetch limit*10 rows to ensure we get enough distinct sessions,
|
|
360
|
+
// since a single session can have dozens of matching turns.
|
|
361
|
+
const rawRows = db.prepare(`
|
|
362
|
+
SELECT
|
|
363
|
+
session_id,
|
|
364
|
+
snippet(sessions_fts, 2, '<mark>', '</mark>', '...', 40) as snippet,
|
|
365
|
+
rank
|
|
366
|
+
FROM sessions_fts
|
|
367
|
+
WHERE sessions_fts MATCH ?
|
|
368
|
+
ORDER BY rank
|
|
369
|
+
LIMIT ?
|
|
370
|
+
`).all(safeQuery, limit * 10);
|
|
371
|
+
// Deduplicate: keep best-ranking entry per session
|
|
372
|
+
const bySession = new Map();
|
|
373
|
+
for (const r of rawRows) {
|
|
374
|
+
const existing = bySession.get(r.session_id);
|
|
375
|
+
if (!existing || r.rank < existing.rank) {
|
|
376
|
+
bySession.set(r.session_id, r);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
// Sort by rank and limit
|
|
380
|
+
const rows = [...bySession.values()]
|
|
381
|
+
.sort((a, b) => a.rank - b.rank)
|
|
382
|
+
.slice(0, limit);
|
|
383
|
+
return rows.map((r) => ({
|
|
384
|
+
sessionId: r.session_id,
|
|
385
|
+
snippet: r.snippet,
|
|
386
|
+
rank: r.rank,
|
|
387
|
+
}));
|
|
388
|
+
}
|
|
389
|
+
// ── File Search ──────────────────────────────────────────────
|
|
390
|
+
export function searchByFile(db, filePath) {
|
|
391
|
+
// Escape LIKE wildcards in user input
|
|
392
|
+
const escaped = filePath.replace(/[%_]/g, (c) => `\\${c}`);
|
|
393
|
+
return db.prepare(`
|
|
394
|
+
SELECT session_id as sessionId, additions, deletions
|
|
395
|
+
FROM session_files
|
|
396
|
+
WHERE file_path LIKE ? ESCAPE '\\'
|
|
397
|
+
`).all(`%${escaped}%`);
|
|
398
|
+
}
|
|
399
|
+
export function getAllSessionMetas(db) {
|
|
400
|
+
const rows = db.prepare(`
|
|
401
|
+
SELECT id, file_path, source, project_dir, is_subagent, parent_session_id, agent_role
|
|
402
|
+
FROM sessions
|
|
403
|
+
ORDER BY project_dir, start_time
|
|
404
|
+
`).all();
|
|
405
|
+
return rows.map((r) => ({
|
|
406
|
+
path: r.file_path ?? '',
|
|
407
|
+
source: r.source,
|
|
408
|
+
sessionId: r.id,
|
|
409
|
+
projectDir: r.project_dir,
|
|
410
|
+
isSubagent: r.is_subagent === 1,
|
|
411
|
+
parentSessionId: r.parent_session_id ?? undefined,
|
|
412
|
+
agentRole: r.agent_role ?? undefined,
|
|
413
|
+
}));
|
|
414
|
+
}
|
|
415
|
+
// ── Session Count ────────────────────────────────────────────
|
|
416
|
+
export function getSessionCount(db) {
|
|
417
|
+
const row = db.prepare('SELECT COUNT(*) as count FROM sessions').get();
|
|
418
|
+
return row.count;
|
|
419
|
+
}
|
|
420
|
+
export function getDashboardStats(db) {
|
|
421
|
+
const agg = db.prepare(`
|
|
422
|
+
SELECT
|
|
423
|
+
COUNT(*) as session_count,
|
|
424
|
+
COUNT(DISTINCT project_dir) as project_count,
|
|
425
|
+
COUNT(DISTINCT source) as source_count
|
|
426
|
+
FROM sessions WHERE is_subagent = 0
|
|
427
|
+
`).get();
|
|
428
|
+
const projects = getAllProjectStats(db);
|
|
429
|
+
return {
|
|
430
|
+
sessionCount: agg.session_count,
|
|
431
|
+
projectCount: agg.project_count,
|
|
432
|
+
sourceCount: agg.source_count,
|
|
433
|
+
projects: projects.map((p) => ({
|
|
434
|
+
projectDir: p.projectDir,
|
|
435
|
+
projectName: p.projectName,
|
|
436
|
+
sessionCount: p.sessionCount,
|
|
437
|
+
totalLoc: p.totalLoc,
|
|
438
|
+
totalDuration: p.totalDuration,
|
|
439
|
+
skills: p.skills,
|
|
440
|
+
latestDate: p.latestDate,
|
|
441
|
+
})),
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
//# sourceMappingURL=db.js.map
|
package/dist/db.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db.js","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"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"}
|
package/dist/export.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Export module — produces Markdown and HTML exports of refined projects.
|
|
3
|
+
*
|
|
4
|
+
* Both functions write self-contained, offline-viewable output.
|
|
5
|
+
* HTML export uses the same render pipeline as publish (ReactDOMServer),
|
|
6
|
+
* producing JS-free static HTML safe for script-src 'self' CSP.
|
|
7
|
+
*/
|
|
8
|
+
import type { ProjectEnhanceCache } from './settings.js';
|
|
9
|
+
import type { Session } from './analyzer.js';
|
|
10
|
+
export interface ExportResult {
|
|
11
|
+
files: string[];
|
|
12
|
+
totalBytes: number;
|
|
13
|
+
outputPath: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function exportMarkdown(dirName: string, cache: ProjectEnhanceCache, sessions: Session[], outputPath: string): Promise<ExportResult>;
|
|
16
|
+
export declare function exportHtml(dirName: string, cache: ProjectEnhanceCache, sessions: Session[], outputPath: string, username?: string): Promise<ExportResult>;
|
|
17
|
+
export interface HtmlFile {
|
|
18
|
+
path: string;
|
|
19
|
+
content: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Generate HTML files in memory (no disk writes).
|
|
23
|
+
* Returns an array of {path, content} for zipping.
|
|
24
|
+
*/
|
|
25
|
+
export declare function generateHtmlFiles(dirName: string, cache: ProjectEnhanceCache, sessions: Session[], username?: string): HtmlFile[];
|
|
26
|
+
/**
|
|
27
|
+
* Create a ZIP file buffer from an array of {path, content} entries.
|
|
28
|
+
* Uses DEFLATE compression via Node's built-in zlib.
|
|
29
|
+
*/
|
|
30
|
+
export declare function createZipBuffer(entries: HtmlFile[]): Buffer;
|