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.
Files changed (136) hide show
  1. package/dist/analyzer.d.ts +3 -3
  2. package/dist/archive.d.ts +14 -0
  3. package/dist/archive.js +125 -0
  4. package/dist/archive.js.map +1 -0
  5. package/dist/auth.d.ts +0 -6
  6. package/dist/auth.js +2 -4
  7. package/dist/auth.js.map +1 -1
  8. package/dist/autostart.d.ts +19 -0
  9. package/dist/autostart.js +103 -0
  10. package/dist/autostart.js.map +1 -0
  11. package/dist/bridge.d.ts +0 -2
  12. package/dist/bridge.js +33 -4
  13. package/dist/bridge.js.map +1 -1
  14. package/dist/config.d.ts +1 -1
  15. package/dist/config.js +2 -2
  16. package/dist/config.js.map +1 -1
  17. package/dist/context-export.d.ts +22 -0
  18. package/dist/context-export.js +230 -0
  19. package/dist/context-export.js.map +1 -0
  20. package/dist/daemon-install.d.ts +23 -0
  21. package/dist/daemon-install.js +155 -0
  22. package/dist/daemon-install.js.map +1 -0
  23. package/dist/db.d.ts +118 -0
  24. package/dist/db.js +444 -0
  25. package/dist/db.js.map +1 -0
  26. package/dist/export.d.ts +30 -0
  27. package/dist/export.js +377 -0
  28. package/dist/export.js.map +1 -0
  29. package/dist/format-utils.d.ts +6 -0
  30. package/dist/format-utils.js +15 -0
  31. package/dist/format-utils.js.map +1 -0
  32. package/dist/index.js +474 -117
  33. package/dist/index.js.map +1 -1
  34. package/dist/llm/project-enhance.js +1 -1
  35. package/dist/parsers/claude.js +73 -0
  36. package/dist/parsers/claude.js.map +1 -1
  37. package/dist/parsers/codex.js +1 -1
  38. package/dist/parsers/codex.js.map +1 -1
  39. package/dist/parsers/cursor.d.ts +2 -0
  40. package/dist/parsers/cursor.js +14 -26
  41. package/dist/parsers/cursor.js.map +1 -1
  42. package/dist/parsers/gemini.d.ts +3 -2
  43. package/dist/parsers/gemini.js +198 -21
  44. package/dist/parsers/gemini.js.map +1 -1
  45. package/dist/parsers/index.d.ts +1 -1
  46. package/dist/parsers/index.js +23 -7
  47. package/dist/parsers/index.js.map +1 -1
  48. package/dist/parsers/types.d.ts +27 -1
  49. package/dist/render/build-render-data.d.ts +59 -0
  50. package/dist/render/build-render-data.js +101 -0
  51. package/dist/render/build-render-data.js.map +1 -0
  52. package/dist/render/components/PortfolioPage.d.ts +4 -0
  53. package/dist/render/components/PortfolioPage.js +16 -0
  54. package/dist/render/components/PortfolioPage.js.map +1 -0
  55. package/dist/render/components/ProjectPage.d.ts +4 -0
  56. package/dist/render/components/ProjectPage.js +101 -0
  57. package/dist/render/components/ProjectPage.js.map +1 -0
  58. package/dist/render/components/SessionPage.d.ts +4 -0
  59. package/dist/render/components/SessionPage.js +29 -0
  60. package/dist/render/components/SessionPage.js.map +1 -0
  61. package/dist/render/index.d.ts +37 -0
  62. package/dist/render/index.js +140 -0
  63. package/dist/render/index.js.map +1 -0
  64. package/dist/render/types.d.ts +121 -0
  65. package/dist/render/types.js +9 -0
  66. package/dist/render/types.js.map +1 -0
  67. package/dist/routes/archive.d.ts +3 -0
  68. package/dist/routes/archive.js +56 -0
  69. package/dist/routes/archive.js.map +1 -0
  70. package/dist/routes/auth.d.ts +3 -0
  71. package/dist/routes/auth.js +116 -0
  72. package/dist/routes/auth.js.map +1 -0
  73. package/dist/routes/context.d.ts +61 -0
  74. package/dist/routes/context.js +356 -0
  75. package/dist/routes/context.js.map +1 -0
  76. package/dist/routes/dashboard.d.ts +3 -0
  77. package/dist/routes/dashboard.js +103 -0
  78. package/dist/routes/dashboard.js.map +1 -0
  79. package/dist/routes/enhance.d.ts +3 -0
  80. package/dist/routes/enhance.js +305 -0
  81. package/dist/routes/enhance.js.map +1 -0
  82. package/dist/routes/export.d.ts +3 -0
  83. package/dist/routes/export.js +145 -0
  84. package/dist/routes/export.js.map +1 -0
  85. package/dist/routes/index.d.ts +12 -0
  86. package/dist/routes/index.js +13 -0
  87. package/dist/routes/index.js.map +1 -0
  88. package/dist/routes/preview.d.ts +3 -0
  89. package/dist/routes/preview.js +191 -0
  90. package/dist/routes/preview.js.map +1 -0
  91. package/dist/routes/projects.d.ts +3 -0
  92. package/dist/routes/projects.js +356 -0
  93. package/dist/routes/projects.js.map +1 -0
  94. package/dist/routes/publish.d.ts +3 -0
  95. package/dist/routes/publish.js +466 -0
  96. package/dist/routes/publish.js.map +1 -0
  97. package/dist/routes/search.d.ts +3 -0
  98. package/dist/routes/search.js +110 -0
  99. package/dist/routes/search.js.map +1 -0
  100. package/dist/routes/sessions.d.ts +3 -0
  101. package/dist/routes/sessions.js +103 -0
  102. package/dist/routes/sessions.js.map +1 -0
  103. package/dist/routes/settings.d.ts +3 -0
  104. package/dist/routes/settings.js +30 -0
  105. package/dist/routes/settings.js.map +1 -0
  106. package/dist/screenshot.d.ts +5 -2
  107. package/dist/screenshot.js +187 -13
  108. package/dist/screenshot.js.map +1 -1
  109. package/dist/search.d.ts +30 -0
  110. package/dist/search.js +153 -0
  111. package/dist/search.js.map +1 -0
  112. package/dist/server.d.ts +1 -1
  113. package/dist/server.js +55 -1318
  114. package/dist/server.js.map +1 -1
  115. package/dist/settings.d.ts +23 -6
  116. package/dist/settings.js +36 -12
  117. package/dist/settings.js.map +1 -1
  118. package/dist/source-audit.d.ts +29 -0
  119. package/dist/source-audit.js +203 -0
  120. package/dist/source-audit.js.map +1 -0
  121. package/dist/sync.d.ts +74 -0
  122. package/dist/sync.js +358 -0
  123. package/dist/sync.js.map +1 -0
  124. package/dist/transcript.d.ts +68 -0
  125. package/dist/transcript.js +268 -0
  126. package/dist/transcript.js.map +1 -0
  127. package/package.json +5 -1
  128. package/app/dist/assets/html2canvas-Cwn_rrOw.js +0 -5
  129. package/app/dist/assets/index-CEQyTkgN.js +0 -14
  130. package/app/dist/assets/index-DLh5xRE8.css +0 -1
  131. package/app/dist/favicon.svg +0 -5
  132. package/app/dist/icons.svg +0 -24
  133. package/app/dist/index.html +0 -20
  134. package/dist/machine-key.d.ts +0 -10
  135. package/dist/machine-key.js +0 -51
  136. package/dist/machine-key.js.map +0 -1
@@ -0,0 +1,103 @@
1
+ import { Router } from 'express';
2
+ import { listSessions, parseSession } from '../parsers/index.js';
3
+ import { bridgeToAnalyzer } from '../bridge.js';
4
+ import { analyzeSession } from '../analyzer.js';
5
+ import { getSessionRow } from '../db.js';
6
+ import { ensureSessionIndexed } from '../sync.js';
7
+ import { exportSessionContext } from '../context-export.js';
8
+ import { buildTranscriptResponse } from '../transcript.js';
9
+ import { displayNameFromDir } from './context.js';
10
+ /**
11
+ * Find a session's file path and project name, checking the DB first,
12
+ * then falling back to live discovery (triggers indexing as a side effect).
13
+ */
14
+ async function resolveSession(ctx, id) {
15
+ // Try DB first
16
+ const row = getSessionRow(ctx.db, id);
17
+ if (row?.file_path) {
18
+ return { filePath: row.file_path, projectName: displayNameFromDir(row.project_dir) };
19
+ }
20
+ // Fallback: discover live sessions and index the match
21
+ const allSessions = await listSessions(ctx.sessionsBasePath);
22
+ const meta = allSessions.find((s) => s.sessionId === id);
23
+ if (!meta)
24
+ return null;
25
+ const projectName = displayNameFromDir(meta.projectDir);
26
+ try {
27
+ await ensureSessionIndexed(ctx.db, meta, projectName);
28
+ }
29
+ catch { /* best effort */ }
30
+ return { filePath: meta.path, projectName };
31
+ }
32
+ export function createSessionsRouter(ctx) {
33
+ const router = Router();
34
+ // Session by ID (cross-project lookup)
35
+ router.get('/api/sessions/:id', async (req, res) => {
36
+ try {
37
+ const id = String(req.params.id);
38
+ const resolved = await resolveSession(ctx, id);
39
+ if (!resolved) {
40
+ res.status(404).json({ error: { code: 'SESSION_NOT_FOUND', message: 'Session not found' } });
41
+ return;
42
+ }
43
+ const session = await ctx.loadSession(resolved.filePath, resolved.projectName, id);
44
+ res.json({ session });
45
+ }
46
+ catch (err) {
47
+ res.status(500).json({ error: { code: 'LOAD_FAILED', message: err.message } });
48
+ }
49
+ });
50
+ // Session context export
51
+ router.get('/api/sessions/:id/context', async (req, res) => {
52
+ try {
53
+ const id = String(req.params.id);
54
+ const format = (String(req.query.format ?? 'summary'));
55
+ const resolved = await resolveSession(ctx, id);
56
+ if (!resolved) {
57
+ res.status(404).json({ error: { code: 'SESSION_NOT_FOUND', message: 'Session not found' } });
58
+ return;
59
+ }
60
+ const parsed = await parseSession(resolved.filePath);
61
+ const analyzerInput = bridgeToAnalyzer(parsed, { sessionId: id, projectName: resolved.projectName });
62
+ const session = analyzeSession(analyzerInput);
63
+ const turns = analyzerInput.turns;
64
+ const result = exportSessionContext(session, turns, { tier: format });
65
+ res.json({
66
+ content: result.content,
67
+ tokens: result.tokens,
68
+ format: result.tier,
69
+ });
70
+ }
71
+ catch (err) {
72
+ res.status(500).json({ error: { code: 'CONTEXT_EXPORT_FAILED', message: err.message } });
73
+ }
74
+ });
75
+ // Session transcript — full conversation for the viewer
76
+ router.get('/api/sessions/:id/transcript', async (req, res) => {
77
+ try {
78
+ const id = String(req.params.id);
79
+ const resolved = await resolveSession(ctx, id);
80
+ if (!resolved) {
81
+ res.status(404).json({ error: { code: 'SESSION_NOT_FOUND', message: 'Session not found' } });
82
+ return;
83
+ }
84
+ const parsed = await parseSession(resolved.filePath);
85
+ const transcript = buildTranscriptResponse(parsed.raw_entries, {
86
+ cwd: parsed.cwd,
87
+ activeMinutes: parsed.duration_ms > 0 ? Math.max(1, Math.round(parsed.duration_ms / 60_000)) : 0,
88
+ wallClockMinutes: parsed.wall_clock_ms > 0 ? Math.max(1, Math.round(parsed.wall_clock_ms / 60_000)) : 0,
89
+ tokenUsage: parsed.token_usage ? {
90
+ input_tokens: parsed.token_usage.input_tokens,
91
+ output_tokens: parsed.token_usage.output_tokens,
92
+ } : undefined,
93
+ modelsUsed: parsed.models_used,
94
+ });
95
+ res.json(transcript);
96
+ }
97
+ catch (err) {
98
+ res.status(500).json({ error: { code: 'TRANSCRIPT_FAILED', message: err.message } });
99
+ }
100
+ });
101
+ return router;
102
+ }
103
+ //# sourceMappingURL=sessions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sessions.js","sourceRoot":"","sources":["../../src/routes/sessions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Router } from 'express';
2
+ import type { RouteContext } from './context.js';
3
+ export declare function createSettingsRouter(_ctx: RouteContext): Router;
@@ -0,0 +1,30 @@
1
+ import { Router } from 'express';
2
+ import { saveAnthropicApiKey, clearAnthropicApiKey, getAnthropicApiKey } from '../settings.js';
3
+ import { getEnhanceMode } from '../llm/index.js';
4
+ export function createSettingsRouter(_ctx) {
5
+ const router = Router();
6
+ // Save or clear the Anthropic API key
7
+ router.post('/api/settings/api-key', (req, res) => {
8
+ const { apiKey } = req.body;
9
+ if (apiKey && typeof apiKey === 'string' && apiKey.trim()) {
10
+ saveAnthropicApiKey(apiKey.trim());
11
+ console.log('[settings] API key saved');
12
+ res.json({ ok: true, mode: getEnhanceMode() });
13
+ }
14
+ else {
15
+ clearAnthropicApiKey();
16
+ console.log('[settings] API key cleared');
17
+ res.json({ ok: true, mode: getEnhanceMode() });
18
+ }
19
+ });
20
+ // Get current API key status (masked)
21
+ router.get('/api/settings/api-key', (_req, res) => {
22
+ const key = getAnthropicApiKey();
23
+ res.json({
24
+ hasKey: !!key,
25
+ maskedKey: key ? `${key.slice(0, 4)}...` : null,
26
+ });
27
+ });
28
+ return router;
29
+ }
30
+ //# sourceMappingURL=settings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.js","sourceRoot":"","sources":["../../src/routes/settings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAA+B,MAAM,SAAS,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAC/F,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAGjD,MAAM,UAAU,oBAAoB,CAAC,IAAkB;IACrD,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;IAExB,sCAAsC;IACtC,MAAM,CAAC,IAAI,CAAC,uBAAuB,EAAE,CAAC,GAAY,EAAE,GAAa,EAAE,EAAE;QACnE,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,IAA2B,CAAC;QACnD,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;YAC1D,mBAAmB,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;YACnC,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;YACxC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,EAAE,EAAE,CAAC,CAAC;QACjD,CAAC;aAAM,CAAC;YACN,oBAAoB,EAAE,CAAC;YACvB,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;YAC1C,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,EAAE,EAAE,CAAC,CAAC;QACjD,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,sCAAsC;IACtC,MAAM,CAAC,GAAG,CAAC,uBAAuB,EAAE,CAAC,IAAa,EAAE,GAAa,EAAE,EAAE;QACnE,MAAM,GAAG,GAAG,kBAAkB,EAAE,CAAC;QACjC,GAAG,CAAC,IAAI,CAAC;YACP,MAAM,EAAE,CAAC,CAAC,GAAG;YACb,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI;SAChD,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -1,10 +1,13 @@
1
+ export declare const SCREENSHOTS_DIR: string;
1
2
  /**
2
3
  * Find the first available Chrome binary on the system.
3
4
  * Returns the path or null if not found.
4
5
  */
5
6
  export declare function findChrome(): string | null;
6
7
  /**
7
- * Capture a screenshot of a URL using headless Chrome.
8
- * Returns the local file path on success, or null if Chrome is unavailable or capture fails.
8
+ * Capture a full-page screenshot using Chrome DevTools Protocol.
9
+ * Uses Page.getLayoutMetrics for exact content height, then
10
+ * Page.captureScreenshot with captureBeyondViewport for a full capture.
11
+ * Falls back to CLI --screenshot on Node < 22 (no built-in WebSocket).
9
12
  */
10
13
  export declare function captureScreenshot(url: string, slug: string): Promise<string | null>;
@@ -1,8 +1,9 @@
1
- import { execFile } from 'node:child_process';
2
- import { existsSync, mkdirSync } from 'node:fs';
1
+ import { spawn, execFile } from 'node:child_process';
2
+ import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
3
3
  import { join } from 'node:path';
4
4
  import { homedir, platform } from 'node:os';
5
- const SCREENSHOTS_DIR = join(homedir(), '.config', 'heyiam', 'screenshots');
5
+ import { get as httpGet } from 'node:http';
6
+ export const SCREENSHOTS_DIR = join(homedir(), '.config', 'heyiam', 'screenshots');
6
7
  /** Known Chrome binary paths by platform */
7
8
  const CHROME_PATHS = {
8
9
  darwin: [
@@ -35,15 +36,98 @@ export function findChrome() {
35
36
  return null;
36
37
  }
37
38
  /**
38
- * Capture a screenshot of a URL using headless Chrome.
39
- * Returns the local file path on success, or null if Chrome is unavailable or capture fails.
39
+ * Validate that a URL is safe for screenshot capture.
40
+ * Only allows http/https schemes and rejects private/internal IPs.
40
41
  */
41
- export async function captureScreenshot(url, slug) {
42
- const chrome = findChrome();
43
- if (!chrome)
44
- return null;
45
- mkdirSync(SCREENSHOTS_DIR, { recursive: true });
46
- const outPath = join(SCREENSHOTS_DIR, `${slug}.png`);
42
+ function isUrlSafe(raw) {
43
+ let parsed;
44
+ try {
45
+ parsed = new URL(raw);
46
+ }
47
+ catch {
48
+ return false;
49
+ }
50
+ // Only allow http(s)
51
+ if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:')
52
+ return false;
53
+ // Reject localhost and private IPs
54
+ const host = parsed.hostname.toLowerCase();
55
+ if (host === 'localhost' || host === '127.0.0.1' || host === '::1') {
56
+ // Allow our own preview server
57
+ const port = parsed.port || (parsed.protocol === 'https:' ? '443' : '80');
58
+ if (port !== '17845')
59
+ return false;
60
+ }
61
+ // Reject private IP ranges
62
+ if (/^(10\.|172\.(1[6-9]|2\d|3[01])\.|192\.168\.|169\.254\.|0\.)/.test(host))
63
+ return false;
64
+ if (host.endsWith('.local') || host.endsWith('.internal'))
65
+ return false;
66
+ return true;
67
+ }
68
+ /**
69
+ * Sanitize a slug for use as a filename — alphanumeric, hyphens, underscores only.
70
+ */
71
+ function sanitizeSlug(slug) {
72
+ return slug.replace(/[^a-zA-Z0-9_-]/g, '_').slice(0, 200);
73
+ }
74
+ /** Send a CDP command over WebSocket and wait for the response */
75
+ function cdpSend(ws, method, params = {}) {
76
+ const id = Math.floor(Math.random() * 1e9);
77
+ return new Promise((resolve, reject) => {
78
+ const timeout = setTimeout(() => reject(new Error(`CDP timeout: ${method}`)), 15_000);
79
+ const handler = (event) => {
80
+ const msg = JSON.parse(String(event.data));
81
+ if (msg.id === id) {
82
+ ws.removeEventListener('message', handler);
83
+ clearTimeout(timeout);
84
+ if (msg.error)
85
+ reject(new Error(msg.error.message));
86
+ else
87
+ resolve(msg.result ?? {});
88
+ }
89
+ };
90
+ ws.addEventListener('message', handler);
91
+ ws.send(JSON.stringify({ id, method, params }));
92
+ });
93
+ }
94
+ /** Wait for a specific CDP event */
95
+ function cdpWaitFor(ws, eventName, timeoutMs = 15_000) {
96
+ return new Promise((resolve, reject) => {
97
+ const timeout = setTimeout(() => reject(new Error(`CDP event timeout: ${eventName}`)), timeoutMs);
98
+ const handler = (event) => {
99
+ const msg = JSON.parse(String(event.data));
100
+ if (msg.method === eventName) {
101
+ ws.removeEventListener('message', handler);
102
+ clearTimeout(timeout);
103
+ resolve();
104
+ }
105
+ };
106
+ ws.addEventListener('message', handler);
107
+ });
108
+ }
109
+ /** Fetch JSON from a local HTTP endpoint */
110
+ function fetchJson(url) {
111
+ return new Promise((resolve, reject) => {
112
+ httpGet(url, (res) => {
113
+ let data = '';
114
+ res.on('data', (chunk) => { data += chunk.toString(); });
115
+ res.on('end', () => {
116
+ try {
117
+ resolve(JSON.parse(data));
118
+ }
119
+ catch {
120
+ reject(new Error('Invalid JSON'));
121
+ }
122
+ });
123
+ }).on('error', reject);
124
+ });
125
+ }
126
+ /**
127
+ * Fallback: capture using Chrome CLI --screenshot (viewport-only, not full page).
128
+ * Used when WebSocket is unavailable (Node < 22).
129
+ */
130
+ async function captureScreenshotFallback(chrome, url, outPath) {
47
131
  try {
48
132
  await new Promise((resolve, reject) => {
49
133
  execFile(chrome, [
@@ -69,12 +153,102 @@ export async function captureScreenshot(url, slug) {
69
153
  resolve();
70
154
  });
71
155
  });
72
- if (existsSync(outPath))
73
- return outPath;
156
+ return existsSync(outPath) ? outPath : null;
157
+ }
158
+ catch {
159
+ return null;
160
+ }
161
+ }
162
+ /**
163
+ * Capture a full-page screenshot using Chrome DevTools Protocol.
164
+ * Uses Page.getLayoutMetrics for exact content height, then
165
+ * Page.captureScreenshot with captureBeyondViewport for a full capture.
166
+ * Falls back to CLI --screenshot on Node < 22 (no built-in WebSocket).
167
+ */
168
+ export async function captureScreenshot(url, slug) {
169
+ if (!isUrlSafe(url))
170
+ return null;
171
+ const chrome = findChrome();
172
+ if (!chrome)
74
173
  return null;
174
+ mkdirSync(SCREENSHOTS_DIR, { recursive: true });
175
+ const safeSlug = sanitizeSlug(slug);
176
+ const outPath = join(SCREENSHOTS_DIR, `${safeSlug}.png`);
177
+ // Fall back to CLI --screenshot if WebSocket is unavailable (Node < 22)
178
+ if (typeof globalThis.WebSocket === 'undefined') {
179
+ return captureScreenshotFallback(chrome, url, outPath);
180
+ }
181
+ // Launch Chrome with remote debugging on auto-assigned port
182
+ const proc = spawn(chrome, [
183
+ '--headless=new',
184
+ '--disable-gpu',
185
+ '--no-sandbox',
186
+ '--disable-software-rasterizer',
187
+ '--window-size=1280,800',
188
+ '--hide-scrollbars',
189
+ '--disable-extensions',
190
+ '--disable-background-networking',
191
+ '--disable-sync',
192
+ '--disable-translate',
193
+ '--disable-default-apps',
194
+ '--mute-audio',
195
+ '--no-first-run',
196
+ '--remote-debugging-port=0',
197
+ 'about:blank',
198
+ ], { stdio: ['ignore', 'ignore', 'pipe'] });
199
+ try {
200
+ // Parse the debug port from Chrome's stderr
201
+ const port = await new Promise((resolve, reject) => {
202
+ const timeout = setTimeout(() => reject(new Error('Chrome startup timeout')), 10_000);
203
+ let stderr = '';
204
+ proc.stderr.on('data', (chunk) => {
205
+ stderr += chunk.toString();
206
+ const match = stderr.match(/DevTools listening on ws:\/\/127\.0\.0\.1:(\d+)\//);
207
+ if (match) {
208
+ clearTimeout(timeout);
209
+ resolve(parseInt(match[1], 10));
210
+ }
211
+ });
212
+ proc.on('exit', () => { clearTimeout(timeout); reject(new Error('Chrome exited early')); });
213
+ });
214
+ // Find the page target's WebSocket URL
215
+ const targets = await fetchJson(`http://127.0.0.1:${port}/json/list`);
216
+ const pageTarget = targets.find((t) => t.type === 'page');
217
+ if (!pageTarget)
218
+ throw new Error('No page target found');
219
+ // Connect via CDP
220
+ const ws = new WebSocket(pageTarget.webSocketDebuggerUrl);
221
+ await new Promise((resolve, reject) => {
222
+ ws.addEventListener('open', () => resolve());
223
+ ws.addEventListener('error', () => reject(new Error('WebSocket connection failed')));
224
+ });
225
+ // Enable Page events and navigate
226
+ await cdpSend(ws, 'Page.enable');
227
+ const loadPromise = cdpWaitFor(ws, 'Page.loadEventFired', 20_000);
228
+ await cdpSend(ws, 'Page.navigate', { url });
229
+ await loadPromise;
230
+ // Small delay for lazy-loaded content / animations
231
+ await new Promise((r) => setTimeout(r, 1500));
232
+ // Get the actual content dimensions
233
+ const metrics = await cdpSend(ws, 'Page.getLayoutMetrics');
234
+ const width = 1280;
235
+ const height = Math.min(Math.ceil(metrics.contentSize.height), 10_000); // cap at 10k px
236
+ // Capture full-page screenshot
237
+ const result = await cdpSend(ws, 'Page.captureScreenshot', {
238
+ format: 'png',
239
+ captureBeyondViewport: true,
240
+ clip: { x: 0, y: 0, width, height, scale: 1 },
241
+ });
242
+ // Write to disk
243
+ writeFileSync(outPath, Buffer.from(result.data, 'base64'));
244
+ ws.close();
245
+ return outPath;
75
246
  }
76
247
  catch {
77
248
  return null;
78
249
  }
250
+ finally {
251
+ proc.kill();
252
+ }
79
253
  }
80
254
  //# sourceMappingURL=screenshot.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"screenshot.js","sourceRoot":"","sources":["../src/screenshot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAChD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE5C,MAAM,eAAe,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC;AAE5E,4CAA4C;AAC5C,MAAM,YAAY,GAA6B;IAC7C,MAAM,EAAE;QACN,8DAA8D;QAC9D,oDAAoD;QACpD,4EAA4E;KAC7E;IACD,KAAK,EAAE;QACL,wBAAwB;QACxB,+BAA+B;QAC/B,mBAAmB;QACnB,2BAA2B;QAC3B,oBAAoB;KACrB;IACD,KAAK,EAAE;QACL,4DAA4D;QAC5D,kEAAkE;KACnE;CACF,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,UAAU;IACxB,MAAM,KAAK,GAAG,YAAY,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC;IAC7C,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,IAAI,UAAU,CAAC,CAAC,CAAC;YAAE,OAAO,CAAC,CAAC;IAC9B,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,GAAW,EAAE,IAAY;IAC/D,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAEzB,SAAS,CAAC,eAAe,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChD,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,EAAE,GAAG,IAAI,MAAM,CAAC,CAAC;IAErD,IAAI,CAAC;QACH,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC1C,QAAQ,CAAC,MAAM,EAAE;gBACf,gBAAgB;gBAChB,eAAe;gBACf,cAAc;gBACd,+BAA+B;gBAC/B,gBAAgB,OAAO,EAAE;gBACzB,wBAAwB;gBACxB,mBAAmB;gBACnB,sBAAsB;gBACtB,iCAAiC;gBACjC,gBAAgB;gBAChB,qBAAqB;gBACrB,wBAAwB;gBACxB,cAAc;gBACd,gBAAgB;gBAChB,GAAG;aACJ,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,GAAG,EAAE,EAAE;gBAC9B,IAAI,GAAG;oBAAE,MAAM,CAAC,GAAG,CAAC,CAAC;;oBAChB,OAAO,EAAE,CAAC;YACjB,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,IAAI,UAAU,CAAC,OAAO,CAAC;YAAE,OAAO,OAAO,CAAC;QACxC,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"screenshot.js","sourceRoot":"","sources":["../src/screenshot.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import type Database from 'better-sqlite3';
2
+ export interface SearchFilters {
3
+ project?: string;
4
+ source?: string;
5
+ after?: string;
6
+ before?: string;
7
+ skill?: string;
8
+ file?: string;
9
+ minDuration?: number;
10
+ }
11
+ export interface SearchResult {
12
+ sessionId: string;
13
+ title: string;
14
+ projectDir: string;
15
+ projectName: string;
16
+ source: string;
17
+ date: string;
18
+ durationMinutes: number;
19
+ turns: number;
20
+ linesOfCode: number;
21
+ skills: string[];
22
+ snippet: string;
23
+ score: number;
24
+ }
25
+ /**
26
+ * Decode projectDir to a human-readable project name.
27
+ * e.g. "-Users-test-Dev-myapp" → "Users/test/Dev/myapp"
28
+ */
29
+ export declare function decodeProjectName(projectDir: string): string;
30
+ export declare function searchSessions(db: Database.Database, query?: string, filters?: SearchFilters): SearchResult[];
package/dist/search.js ADDED
@@ -0,0 +1,153 @@
1
+ // Search logic combining FTS5 content search with metadata filters
2
+ import { searchFts } from './db.js';
3
+ // ── Helpers ──────────────────────────────────────────────────
4
+ /**
5
+ * Decode projectDir to a human-readable project name.
6
+ * e.g. "-Users-test-Dev-myapp" → "Users/test/Dev/myapp"
7
+ */
8
+ export function decodeProjectName(projectDir) {
9
+ return projectDir.replace(/^-/, '').replace(/-/g, '/');
10
+ }
11
+ function rowToResult(row, snippet, score) {
12
+ const skills = row.skills ? JSON.parse(row.skills) : [];
13
+ return {
14
+ sessionId: row.id,
15
+ title: row.title ?? '',
16
+ projectDir: row.project_dir,
17
+ projectName: decodeProjectName(row.project_dir),
18
+ source: row.source,
19
+ date: row.start_time ?? '',
20
+ durationMinutes: row.duration_minutes ?? 0,
21
+ turns: row.turns ?? 0,
22
+ linesOfCode: (row.loc_added ?? 0) + (row.loc_removed ?? 0),
23
+ skills,
24
+ snippet,
25
+ score,
26
+ };
27
+ }
28
+ // ── Main Search Function ─────────────────────────────────────
29
+ const MAX_RESULTS = 50;
30
+ export function searchSessions(db, query, filters) {
31
+ if (query) {
32
+ return searchWithFts(db, query, filters);
33
+ }
34
+ return searchWithFilters(db, filters);
35
+ }
36
+ // ── FTS path: query provided ─────────────────────────────────
37
+ function searchWithFts(db, query, filters) {
38
+ // FTS now returns deduplicated results (one per session, best rank)
39
+ const ftsResults = searchFts(db, query, MAX_RESULTS * 3);
40
+ if (ftsResults.length === 0)
41
+ return [];
42
+ const fileSessionIds = filters?.file ? getFileFilteredSessionIds(db, filters.file) : null;
43
+ // F10: Batch fetch all session rows in one query instead of N+1
44
+ const ftsIds = ftsResults.map((r) => r.sessionId);
45
+ const placeholders = ftsIds.map(() => '?').join(',');
46
+ const allRows = db.prepare(`SELECT * FROM sessions WHERE id IN (${placeholders})`).all(...ftsIds);
47
+ const rowMap = new Map();
48
+ for (const row of allRows)
49
+ rowMap.set(row.id, row);
50
+ // Apply metadata filters and build results in FTS rank order
51
+ const results = [];
52
+ for (const fts of ftsResults) {
53
+ if (fileSessionIds && !fileSessionIds.has(fts.sessionId))
54
+ continue;
55
+ const row = rowMap.get(fts.sessionId);
56
+ if (!row)
57
+ continue;
58
+ if (!matchesFilters(row, filters))
59
+ continue;
60
+ results.push(rowToResult(row, fts.snippet, fts.rank));
61
+ if (results.length >= MAX_RESULTS)
62
+ break;
63
+ }
64
+ return results;
65
+ }
66
+ // ── Filter-only path: no text query ──────────────────────────
67
+ function searchWithFilters(db, filters) {
68
+ const conditions = [];
69
+ const params = [];
70
+ if (filters?.project) {
71
+ conditions.push('s.project_dir LIKE ?');
72
+ params.push(`%${filters.project}%`);
73
+ }
74
+ if (filters?.source) {
75
+ conditions.push('s.source = ?');
76
+ params.push(filters.source);
77
+ }
78
+ if (filters?.after) {
79
+ conditions.push('s.start_time >= ?');
80
+ params.push(filters.after);
81
+ }
82
+ if (filters?.before) {
83
+ conditions.push('s.start_time <= ?');
84
+ params.push(filters.before);
85
+ }
86
+ if (filters?.minDuration) {
87
+ conditions.push('s.duration_minutes >= ?');
88
+ params.push(filters.minDuration);
89
+ }
90
+ if (filters?.skill) {
91
+ // F25: Use json_each for proper JSON array searching instead of LIKE
92
+ conditions.push('EXISTS (SELECT 1 FROM json_each(s.skills) WHERE value = ?)');
93
+ params.push(filters.skill);
94
+ }
95
+ let sql;
96
+ if (filters?.file) {
97
+ sql = `
98
+ SELECT DISTINCT s.*
99
+ FROM sessions s
100
+ JOIN session_files sf ON sf.session_id = s.id
101
+ WHERE sf.file_path LIKE ?
102
+ ${conditions.length ? 'AND ' + conditions.join(' AND ') : ''}
103
+ ORDER BY s.start_time DESC
104
+ LIMIT ?
105
+ `;
106
+ params.unshift(`%${filters.file}%`);
107
+ params.push(MAX_RESULTS);
108
+ }
109
+ else {
110
+ sql = `
111
+ SELECT s.*
112
+ FROM sessions s
113
+ ${conditions.length ? 'WHERE ' + conditions.join(' AND ') : ''}
114
+ ORDER BY s.start_time DESC
115
+ LIMIT ?
116
+ `;
117
+ params.push(MAX_RESULTS);
118
+ }
119
+ const rows = db.prepare(sql).all(...params);
120
+ return rows.map((row, i) => rowToResult(row, '', i));
121
+ }
122
+ // ── Filter helpers ───────────────────────────────────────────
123
+ function matchesFilters(row, filters) {
124
+ if (!filters)
125
+ return true;
126
+ if (filters.project && !row.project_dir.includes(filters.project)) {
127
+ return false;
128
+ }
129
+ if (filters.source && row.source !== filters.source) {
130
+ return false;
131
+ }
132
+ if (filters.after && (row.start_time ?? '') < filters.after) {
133
+ return false;
134
+ }
135
+ if (filters.before && (row.start_time ?? '') > filters.before) {
136
+ return false;
137
+ }
138
+ if (filters.minDuration && (row.duration_minutes ?? 0) < filters.minDuration) {
139
+ return false;
140
+ }
141
+ if (filters.skill) {
142
+ const skills = row.skills ? JSON.parse(row.skills) : [];
143
+ if (!skills.includes(filters.skill)) {
144
+ return false;
145
+ }
146
+ }
147
+ return true;
148
+ }
149
+ function getFileFilteredSessionIds(db, filePath) {
150
+ const rows = db.prepare('SELECT DISTINCT session_id FROM session_files WHERE file_path LIKE ?').all(`%${filePath}%`);
151
+ return new Set(rows.map((r) => r.session_id));
152
+ }
153
+ //# sourceMappingURL=search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.js","sourceRoot":"","sources":["../src/search.ts"],"names":[],"mappings":"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"}
package/dist/server.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  import type { Server } from 'node:http';
2
- export declare function createApp(sessionsBasePath?: string): import("express-serve-static-core").Express;
2
+ export declare function createApp(sessionsBasePath?: string, dbPath?: string): import("express-serve-static-core").Express;
3
3
  export declare function startServer(port?: number): Promise<Server>;