browsertrack 0.1.2 → 0.2.1

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 (52) hide show
  1. package/AGENTS.md +6 -2
  2. package/dist/{chunk-ILRYKMME.js → chunk-3HOXPTM2.js} +97 -3
  3. package/dist/chunk-3HOXPTM2.js.map +1 -0
  4. package/dist/{chunk-G2Y3CXCY.js → chunk-464D4U2U.js} +86 -3
  5. package/dist/chunk-464D4U2U.js.map +1 -0
  6. package/dist/{chunk-SPCIROIU.js → chunk-7OCOQGDN.js} +24 -5
  7. package/dist/chunk-7OCOQGDN.js.map +1 -0
  8. package/dist/{chunk-SKCMT2DE.js → chunk-INXDWPJW.js} +806 -160
  9. package/dist/chunk-INXDWPJW.js.map +1 -0
  10. package/dist/cli/index.js +202 -6
  11. package/dist/cli/index.js.map +1 -1
  12. package/dist/client/index.cjs +809 -161
  13. package/dist/client/index.d.ts +62 -11
  14. package/dist/client/index.js +7 -3
  15. package/dist/client.iife.js +206 -27
  16. package/dist/{notes-CBvN91Wf.d.ts → commands-fjuqKzkm.d.ts} +125 -91
  17. package/dist/core/index.d.ts +2 -2
  18. package/dist/daemon/index.d.ts +3 -3
  19. package/dist/daemon/index.js +2 -2
  20. package/dist/{engine-CeT9URuN.d.ts → engine-CmchnMDq.d.ts} +13 -2
  21. package/dist/index.d.ts +4 -4
  22. package/dist/index.js +4 -4
  23. package/dist/mcp/index.d.ts +4 -4
  24. package/dist/mcp/index.js +2 -2
  25. package/dist/{projects-CY8ungMt.d.ts → projects-DB7S312i.d.ts} +1 -1
  26. package/dist/{server-Dd8NX2Mk.d.ts → server-DiVmTrIR.d.ts} +1 -1
  27. package/docs/component-resolver.md +108 -0
  28. package/docs/index.md +3 -1
  29. package/docs/mcp-reference.md +15 -2
  30. package/docs/scenarios-flows.md +86 -0
  31. package/docs/visual-notes.md +36 -0
  32. package/package.json +1 -1
  33. package/packages/client/src/client.ts +18 -1
  34. package/packages/client/src/config.ts +84 -1
  35. package/packages/client/src/index.ts +4 -1
  36. package/packages/client/src/interceptors/interaction.ts +3 -0
  37. package/packages/client/src/notes/inspector.ts +640 -166
  38. package/packages/client/src/source/resolver.ts +272 -0
  39. package/packages/core/src/types/events.ts +3 -0
  40. package/packages/core/src/types/notes.ts +36 -0
  41. package/packages/daemon/src/notes/engine.ts +6 -0
  42. package/packages/daemon/src/server/ws.ts +23 -1
  43. package/packages/daemon/src/storage/db.ts +106 -3
  44. package/packages/mcp/src/handlers.ts +59 -0
  45. package/packages/mcp/src/tools.ts +28 -0
  46. package/test/client/component-resolver.test.ts +141 -0
  47. package/test/client/interceptors.test.ts +120 -0
  48. package/test/daemon/scenario-storage.test.ts +158 -0
  49. package/dist/chunk-G2Y3CXCY.js.map +0 -1
  50. package/dist/chunk-ILRYKMME.js.map +0 -1
  51. package/dist/chunk-SKCMT2DE.js.map +0 -1
  52. package/dist/chunk-SPCIROIU.js.map +0 -1
package/AGENTS.md CHANGED
@@ -33,6 +33,7 @@ graph TD
33
33
 
34
34
  1. **Find open notes:** Call `list_notes({ status: "OPEN" })`.
35
35
  2. **Inspect note context:** Call `get_note({ noteId: "note_xxx" })`.
36
+ - **Check `elementContext.componentSource`**: In React, Vue, or Svelte apps, this gives you the exact component name, source file (`sourceFile`), and line number (`sourceLine`). Open that file directly!
36
37
  - Review the target selector (`target.selector`), viewport dimensions, bounding box (`boundingRect`), and screenshot path.
37
38
  - Check if layout overflow (`overflow-x`, min-width, flex wrapping) is causing the issue.
38
39
  3. **Apply the fix:** Edit the corresponding CSS, style rules, or component markup.
@@ -49,6 +50,7 @@ When an error or unexpected behavior occurs in the frontend:
49
50
  1. **List open incidents:** Call `list_incidents({ status: "OPEN" })`.
50
51
  2. **Retrieve incident details:** Call `get_incident({ incidentId: "inc_xxx" })`.
51
52
  - Inspect stack traces, exact source line/column, last user interactions, and failing network calls.
53
+ - **Check `lastInteractedElement.componentSource`** to see which React/Vue component and source file was clicked right before the crash.
52
54
  3. **Inspect interaction timeline (if needed):** Call `get_breadcrumbs({ incidentId: "inc_xxx" })` to see what clicks, inputs, or navigations led to the failure.
53
55
  4. **Inspect failed network requests (if needed):** Call `get_network_failures()` to examine 4xx/5xx status codes, request URLs, and response details.
54
56
  5. **Apply code fix:** Edit the source file causing the bug.
@@ -70,10 +72,12 @@ When an error or unexpected behavior occurs in the frontend:
70
72
  | `get_page_state` | Query current URL, document title, readyState, and active element | `sessionId` |
71
73
  | `capture_element` | Capture an on-demand screenshot of a selector or full viewport | `selector`, `sessionId` |
72
74
 
73
- ### 📝 Visual Notes & Layout Inspector
75
+ ### 📝 Visual Notes, Scenarios & Layout Inspector
74
76
  | MCP Tool | Purpose | Key Arguments |
75
77
  | :--- | :--- | :--- |
76
- | `list_notes` | List visual annotations left on elements/regions | `status`, `projectId`, `limit` |
78
+ | `list_notes` | List visual annotations left on elements/regions | `status`, `projectId`, `scenarioId`, `limit` |
79
+ | `list_scenarios` | List multi-step reproduction flows and user scenarios | `status`, `projectId`, `limit` |
80
+ | `get_scenario` | Retrieve full chronological step-by-step reproduction flow | `scenarioId` *(required)* |
77
81
  | `get_note` | Get full note details (DOM context, selector, bounding rect, screenshot) | `noteId` *(required)* |
78
82
  | `capture_note_context` | Inspect live DOM bounding box, styles, and overflow on an element | `selector` *(required)*, `sessionId` |
79
83
  | `verify_note` | Run automated layout verification and before/after comparison | `noteId` *(required)*, `observationWindowMs` |
@@ -135,6 +135,9 @@ var StorageDB = class {
135
135
  region_json TEXT,
136
136
  screenshot_path TEXT,
137
137
  incident_id TEXT,
138
+ scenario_id TEXT,
139
+ step_number INTEGER,
140
+ scenario_title TEXT,
138
141
  status TEXT DEFAULT 'OPEN',
139
142
  created_at TEXT,
140
143
  updated_at TEXT,
@@ -157,7 +160,20 @@ var StorageDB = class {
157
160
  CREATE INDEX IF NOT EXISTS idx_incidents_project ON incidents(project_id, status);
158
161
  CREATE INDEX IF NOT EXISTS idx_incidents_fp ON incidents(fingerprint);
159
162
  CREATE INDEX IF NOT EXISTS idx_notes_project ON notes(project_id, status);
163
+ CREATE INDEX IF NOT EXISTS idx_notes_scenario ON notes(scenario_id, step_number);
160
164
  `);
165
+ try {
166
+ this.db.exec("ALTER TABLE notes ADD COLUMN scenario_id TEXT;");
167
+ } catch {
168
+ }
169
+ try {
170
+ this.db.exec("ALTER TABLE notes ADD COLUMN step_number INTEGER;");
171
+ } catch {
172
+ }
173
+ try {
174
+ this.db.exec("ALTER TABLE notes ADD COLUMN scenario_title TEXT;");
175
+ } catch {
176
+ }
161
177
  }
162
178
  // --- PROJECTS ---
163
179
  upsertProject(project) {
@@ -459,8 +475,8 @@ var StorageDB = class {
459
475
  `INSERT INTO notes (
460
476
  id, project_id, session_id, type, message, route, url,
461
477
  viewport_json, scroll_json, target_json, element_context_json, region_json,
462
- screenshot_path, incident_id, status, created_at, updated_at, resolved_at
463
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
478
+ screenshot_path, incident_id, scenario_id, step_number, scenario_title, status, created_at, updated_at, resolved_at
479
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
464
480
  ).run(
465
481
  note.id,
466
482
  note.projectId,
@@ -476,6 +492,9 @@ var StorageDB = class {
476
492
  note.region ? JSON.stringify(note.region) : null,
477
493
  note.screenshots?.original || null,
478
494
  note.incidentId || null,
495
+ note.scenarioId || null,
496
+ note.stepNumber ?? null,
497
+ note.scenarioTitle || null,
479
498
  note.status,
480
499
  note.createdAt,
481
500
  note.updatedAt,
@@ -502,6 +521,10 @@ var StorageDB = class {
502
521
  sql += " AND route = ?";
503
522
  params.push(options.route);
504
523
  }
524
+ if (options.scenarioId) {
525
+ sql += " AND scenario_id = ?";
526
+ params.push(options.scenarioId);
527
+ }
505
528
  sql += " ORDER BY created_at DESC LIMIT ?";
506
529
  params.push(options.limit || 50);
507
530
  const rows = this.db.prepare(sql).all(...params);
@@ -511,6 +534,71 @@ var StorageDB = class {
511
534
  this.db.prepare("DELETE FROM note_verifications WHERE note_id = ?").run(id);
512
535
  this.db.prepare("DELETE FROM notes WHERE id = ?").run(id);
513
536
  }
537
+ // --- SCENARIOS (MULTI-STEP FLOWS) ---
538
+ listScenarios(options = {}) {
539
+ let sql = `
540
+ SELECT
541
+ scenario_id,
542
+ project_id,
543
+ COALESCE(MAX(scenario_title), 'Scenario') as title,
544
+ COUNT(id) as steps_count,
545
+ CASE WHEN SUM(CASE WHEN status != 'RESOLVED' THEN 1 ELSE 0 END) = 0 THEN 'RESOLVED' ELSE 'OPEN' END as status,
546
+ MIN(route) as route,
547
+ MIN(created_at) as first_step_at,
548
+ MAX(created_at) as last_step_at
549
+ FROM notes
550
+ WHERE scenario_id IS NOT NULL
551
+ `;
552
+ const params = [];
553
+ if (options.projectId) {
554
+ sql += " AND (project_id = ? OR project_id IS NULL)";
555
+ params.push(options.projectId);
556
+ }
557
+ sql += " GROUP BY scenario_id";
558
+ if (options.status) {
559
+ if (options.status === "RESOLVED") {
560
+ sql += " HAVING SUM(CASE WHEN status != 'RESOLVED' THEN 1 ELSE 0 END) = 0";
561
+ } else {
562
+ sql += " HAVING SUM(CASE WHEN status != 'RESOLVED' THEN 1 ELSE 0 END) > 0";
563
+ }
564
+ }
565
+ sql += " ORDER BY last_step_at DESC LIMIT ?";
566
+ params.push(options.limit || 50);
567
+ const rows = this.db.prepare(sql).all(...params);
568
+ return rows.map((r) => ({
569
+ id: r.scenario_id,
570
+ projectId: r.project_id,
571
+ title: r.title,
572
+ stepsCount: Number(r.steps_count),
573
+ status: r.status,
574
+ route: r.route || "/",
575
+ firstStepAt: r.first_step_at,
576
+ lastStepAt: r.last_step_at
577
+ }));
578
+ }
579
+ getScenario(scenarioId) {
580
+ const rows = this.db.prepare("SELECT * FROM notes WHERE scenario_id = ? ORDER BY COALESCE(step_number, 999999) ASC, created_at ASC").all(scenarioId);
581
+ if (!rows || rows.length === 0) return null;
582
+ const steps = rows.map((r) => this.mapNoteRow(r));
583
+ const title = steps.find((s) => s.scenarioTitle)?.scenarioTitle || `Scenario ${scenarioId}`;
584
+ const allResolved = steps.every((s) => s.status === "RESOLVED");
585
+ return {
586
+ id: scenarioId,
587
+ projectId: steps[0].projectId,
588
+ title,
589
+ stepsCount: steps.length,
590
+ status: allResolved ? "RESOLVED" : "OPEN",
591
+ steps,
592
+ createdAt: steps[0].createdAt,
593
+ updatedAt: steps[steps.length - 1].updatedAt
594
+ };
595
+ }
596
+ deleteScenario(scenarioId) {
597
+ const notes = this.db.prepare("SELECT id FROM notes WHERE scenario_id = ?").all(scenarioId);
598
+ for (const n of notes) {
599
+ this.deleteNote(n.id);
600
+ }
601
+ }
514
602
  updateNoteStatus(id, status) {
515
603
  const now = (/* @__PURE__ */ new Date()).toISOString();
516
604
  const resolvedAt = status === "RESOLVED" ? now : null;
@@ -622,6 +710,9 @@ var StorageDB = class {
622
710
  region: row.region_json ? JSON.parse(row.region_json) : void 0,
623
711
  status: row.status,
624
712
  incidentId: row.incident_id || void 0,
713
+ scenarioId: row.scenario_id || void 0,
714
+ stepNumber: row.step_number != null ? Number(row.step_number) : void 0,
715
+ scenarioTitle: row.scenario_title || void 0,
625
716
  screenshots: row.screenshot_path ? {
626
717
  original: row.screenshot_path
627
718
  } : void 0,
@@ -831,6 +922,9 @@ var NotesEngine = class {
831
922
  region: payload.region,
832
923
  status: "OPEN",
833
924
  incidentId: payload.incidentId,
925
+ scenarioId: payload.scenarioId,
926
+ stepNumber: payload.stepNumber,
927
+ scenarioTitle: payload.scenarioTitle,
834
928
  screenshots: screenshotPath ? { original: screenshotPath } : void 0,
835
929
  createdAt: now,
836
930
  updatedAt: now
@@ -1225,4 +1319,4 @@ export {
1225
1319
  NoteVerificationEngine,
1226
1320
  VerificationEngine
1227
1321
  };
1228
- //# sourceMappingURL=chunk-ILRYKMME.js.map
1322
+ //# sourceMappingURL=chunk-3HOXPTM2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../packages/daemon/src/config.ts","../packages/daemon/src/storage/db.ts","../packages/daemon/src/storage/screenshot-store.ts","../packages/daemon/src/session/manager.ts","../packages/daemon/src/notes/engine.ts","../packages/daemon/src/notes/verification.ts","../packages/daemon/src/verification/engine.ts"],"sourcesContent":["import os from 'node:os';\nimport path from 'node:path';\n\nexport interface DaemonConfig {\n host: string;\n port: number;\n dataDir: string;\n dbPath: string;\n screenshotsDir: string;\n maxEventsPerSession: number;\n verbose: boolean;\n}\n\nexport function getDaemonConfig(overrides: Partial<DaemonConfig> = {}): DaemonConfig {\n const homeDir = os.homedir();\n const dataDir = overrides.dataDir || path.join(homeDir, '.browsertrack');\n const dbPath = overrides.dbPath || path.join(dataDir, 'browsertrack.db');\n const screenshotsDir = overrides.screenshotsDir || path.join(dataDir, 'projects');\n\n return {\n host: overrides.host || '127.0.0.1',\n port: overrides.port || 7331,\n dataDir,\n dbPath,\n screenshotsDir,\n maxEventsPerSession: overrides.maxEventsPerSession || 1000,\n verbose: !!overrides.verbose,\n };\n}\n","import Database from 'better-sqlite3';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport type {\n Breadcrumb,\n ElementSummary,\n Incident,\n IncidentOccurrence,\n IncidentSeverity,\n IncidentStatus,\n NetworkEvent,\n Project,\n Session,\n VerificationResult,\n VisualNote,\n NoteStatus,\n NoteVerificationResult,\n ScenarioOverview,\n ScenarioDetail,\n} from '../../../core/src/index.js';\n\nexport class StorageDB {\n private db: Database.Database;\n\n constructor(dbPath: string) {\n const dir = path.dirname(dbPath);\n fs.mkdirSync(dir, { recursive: true });\n\n this.db = new Database(dbPath);\n this.db.pragma('journal_mode = WAL');\n this.db.pragma('synchronous = NORMAL');\n this.initTables();\n }\n\n private initTables(): void {\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS projects (\n id TEXT PRIMARY KEY,\n name TEXT UNIQUE,\n origin TEXT,\n path TEXT,\n created_at TEXT,\n updated_at TEXT\n );\n\n CREATE TABLE IF NOT EXISTS sessions (\n id TEXT PRIMARY KEY,\n project_id TEXT,\n origin TEXT,\n url TEXT,\n title TEXT,\n user_agent TEXT,\n connected_at TEXT,\n last_seen_at TEXT,\n active INTEGER DEFAULT 1\n );\n\n CREATE TABLE IF NOT EXISTS events (\n id TEXT PRIMARY KEY,\n session_id TEXT,\n event_type TEXT,\n payload TEXT,\n timestamp INTEGER,\n route TEXT,\n url TEXT\n );\n\n CREATE TABLE IF NOT EXISTS incidents (\n id TEXT PRIMARY KEY,\n project_id TEXT,\n session_id TEXT,\n type TEXT,\n severity TEXT,\n message TEXT,\n source_file TEXT,\n source_line INTEGER,\n source_col INTEGER,\n fingerprint TEXT UNIQUE,\n route TEXT,\n first_seen TEXT,\n last_seen TEXT,\n occurrences INTEGER DEFAULT 1,\n status TEXT DEFAULT 'OPEN',\n stack TEXT,\n breadcrumbs TEXT,\n network_failures TEXT,\n last_element TEXT,\n screenshot_path TEXT\n );\n\n CREATE TABLE IF NOT EXISTS incident_occurrences (\n id TEXT PRIMARY KEY,\n incident_id TEXT,\n session_id TEXT,\n timestamp TEXT,\n route TEXT,\n url TEXT,\n stack TEXT,\n breadcrumbs TEXT,\n last_element TEXT\n );\n\n CREATE TABLE IF NOT EXISTS screenshots (\n id TEXT PRIMARY KEY,\n incident_id TEXT,\n file_path TEXT,\n format TEXT,\n width INTEGER,\n height INTEGER,\n created_at TEXT\n );\n\n CREATE TABLE IF NOT EXISTS verifications (\n id TEXT PRIMARY KEY,\n incident_id TEXT,\n status TEXT,\n checks TEXT,\n before_screenshot TEXT,\n after_screenshot TEXT,\n message TEXT,\n created_at TEXT\n );\n\n CREATE TABLE IF NOT EXISTS notes (\n id TEXT PRIMARY KEY,\n project_id TEXT,\n session_id TEXT,\n type TEXT,\n message TEXT,\n route TEXT,\n url TEXT,\n viewport_json TEXT,\n scroll_json TEXT,\n target_json TEXT,\n element_context_json TEXT,\n region_json TEXT,\n screenshot_path TEXT,\n incident_id TEXT,\n scenario_id TEXT,\n step_number INTEGER,\n scenario_title TEXT,\n status TEXT DEFAULT 'OPEN',\n created_at TEXT,\n updated_at TEXT,\n resolved_at TEXT\n );\n\n CREATE TABLE IF NOT EXISTS note_verifications (\n id TEXT PRIMARY KEY,\n note_id TEXT,\n status TEXT,\n checks TEXT,\n geometry_diff TEXT,\n before_screenshot TEXT,\n after_screenshot TEXT,\n message TEXT,\n created_at TEXT\n );\n\n CREATE INDEX IF NOT EXISTS idx_events_session ON events(session_id, timestamp);\n CREATE INDEX IF NOT EXISTS idx_incidents_project ON incidents(project_id, status);\n CREATE INDEX IF NOT EXISTS idx_incidents_fp ON incidents(fingerprint);\n CREATE INDEX IF NOT EXISTS idx_notes_project ON notes(project_id, status);\n CREATE INDEX IF NOT EXISTS idx_notes_scenario ON notes(scenario_id, step_number);\n `);\n\n // Schema migrations for scenario fields\n try {\n this.db.exec('ALTER TABLE notes ADD COLUMN scenario_id TEXT;');\n } catch {}\n try {\n this.db.exec('ALTER TABLE notes ADD COLUMN step_number INTEGER;');\n } catch {}\n try {\n this.db.exec('ALTER TABLE notes ADD COLUMN scenario_title TEXT;');\n } catch {}\n }\n\n // --- PROJECTS ---\n public upsertProject(project: { id: string; name: string; origin: string; path?: string }): Project {\n const now = new Date().toISOString();\n const existing = this.db.prepare('SELECT * FROM projects WHERE name = ? OR origin = ?').get(project.name, project.origin) as any;\n\n if (existing) {\n this.db\n .prepare('UPDATE projects SET name = ?, origin = ?, path = COALESCE(?, path), updated_at = ? WHERE id = ?')\n .run(project.name, project.origin, project.path || null, now, existing.id);\n return {\n id: existing.id,\n name: project.name,\n origin: project.origin,\n path: project.path || existing.path,\n createdAt: existing.created_at,\n updatedAt: now,\n };\n }\n\n this.db\n .prepare('INSERT INTO projects (id, name, origin, path, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?)')\n .run(project.id, project.name, project.origin, project.path || null, now, now);\n\n return {\n id: project.id,\n name: project.name,\n origin: project.origin,\n path: project.path,\n createdAt: now,\n updatedAt: now,\n };\n }\n\n public getProject(idOrName: string): Project | null {\n const row = this.db.prepare('SELECT * FROM projects WHERE id = ? OR name = ?').get(idOrName, idOrName) as any;\n if (!row) return null;\n return {\n id: row.id,\n name: row.name,\n origin: row.origin,\n path: row.path,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n };\n }\n\n public getProjectByOrigin(origin: string): Project | null {\n const row = this.db.prepare('SELECT * FROM projects WHERE origin = ?').get(origin) as any;\n if (!row) return null;\n return {\n id: row.id,\n name: row.name,\n origin: row.origin,\n path: row.path,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n };\n }\n\n public listProjects(): Project[] {\n const rows = this.db.prepare('SELECT * FROM projects ORDER BY updated_at DESC').all() as any[];\n return rows.map((row) => ({\n id: row.id,\n name: row.name,\n origin: row.origin,\n path: row.path,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n }));\n }\n\n // --- SESSIONS ---\n public upsertSession(session: Session): void {\n const existing = this.db.prepare('SELECT id FROM sessions WHERE id = ?').get(session.id);\n if (existing) {\n this.db\n .prepare('UPDATE sessions SET url = ?, title = ?, last_seen_at = ?, active = ? WHERE id = ?')\n .run(session.url, session.title, session.lastSeenAt, session.active ? 1 : 0, session.id);\n } else {\n this.db\n .prepare(\n 'INSERT INTO sessions (id, project_id, origin, url, title, user_agent, connected_at, last_seen_at, active) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)'\n )\n .run(\n session.id,\n session.projectId,\n session.origin,\n session.url,\n session.title,\n session.userAgent,\n session.connectedAt,\n session.lastSeenAt,\n session.active ? 1 : 0\n );\n }\n }\n\n public getSession(id: string): Session | null {\n const row = this.db.prepare('SELECT * FROM sessions WHERE id = ?').get(id) as any;\n if (!row) return null;\n return {\n id: row.id,\n projectId: row.project_id,\n origin: row.origin,\n url: row.url,\n title: row.title,\n userAgent: row.user_agent,\n connectedAt: row.connected_at,\n lastSeenAt: row.last_seen_at,\n active: row.active === 1,\n };\n }\n\n public listSessions(projectId?: string, activeOnly = false): Session[] {\n let sql = 'SELECT * FROM sessions WHERE 1=1';\n const params: any[] = [];\n\n if (projectId) {\n sql += ' AND project_id = ?';\n params.push(projectId);\n }\n if (activeOnly) {\n sql += ' AND active = 1';\n }\n sql += ' ORDER BY last_seen_at DESC';\n\n const rows = this.db.prepare(sql).all(...params) as any[];\n return rows.map((row) => ({\n id: row.id,\n projectId: row.project_id,\n origin: row.origin,\n url: row.url,\n title: row.title,\n userAgent: row.user_agent,\n connectedAt: row.connected_at,\n lastSeenAt: row.last_seen_at,\n active: row.active === 1,\n }));\n }\n\n public deactivateSession(id: string): void {\n this.db.prepare('UPDATE sessions SET active = 0, last_seen_at = ? WHERE id = ?').run(new Date().toISOString(), id);\n }\n\n // --- EVENTS & RETENTION ---\n public insertEvent(event: {\n id: string;\n sessionId: string;\n eventType: string;\n payload: any;\n timestamp: number;\n route?: string;\n url?: string;\n }): void {\n this.db\n .prepare('INSERT INTO events (id, session_id, event_type, payload, timestamp, route, url) VALUES (?, ?, ?, ?, ?, ?, ?)')\n .run(\n event.id,\n event.sessionId,\n event.eventType,\n JSON.stringify(event.payload),\n event.timestamp,\n event.route || '',\n event.url || ''\n );\n }\n\n public pruneSessionEvents(sessionId: string, maxEvents = 1000): void {\n this.db\n .prepare(\n `DELETE FROM events \n WHERE session_id = ? AND id NOT IN (\n SELECT id FROM events WHERE session_id = ? ORDER BY timestamp DESC LIMIT ?\n )`\n )\n .run(sessionId, sessionId, maxEvents);\n }\n\n public getEvents(options: { sessionId?: string; eventType?: string; limit?: number }): any[] {\n let sql = 'SELECT * FROM events WHERE 1=1';\n const params: any[] = [];\n\n if (options.sessionId) {\n sql += ' AND session_id = ?';\n params.push(options.sessionId);\n }\n if (options.eventType) {\n sql += ' AND event_type = ?';\n params.push(options.eventType);\n }\n\n sql += ' ORDER BY timestamp DESC LIMIT ?';\n params.push(options.limit || 50);\n\n const rows = this.db.prepare(sql).all(...params) as any[];\n return rows.map((r) => ({\n id: r.id,\n sessionId: r.session_id,\n eventType: r.event_type,\n payload: JSON.parse(r.payload),\n timestamp: r.timestamp,\n route: r.route,\n url: r.url,\n }));\n }\n\n // --- INCIDENTS ---\n public findIncidentByFingerprint(fingerprint: string): Incident | null {\n const row = this.db.prepare('SELECT * FROM incidents WHERE fingerprint = ?').get(fingerprint) as any;\n if (!row) return null;\n return this.mapIncidentRow(row);\n }\n\n public getIncident(id: string): Incident | null {\n const row = this.db.prepare('SELECT * FROM incidents WHERE id = ?').get(id) as any;\n if (!row) return null;\n return this.mapIncidentRow(row);\n }\n\n public listIncidents(options: { projectId?: string; status?: IncidentStatus; severity?: IncidentSeverity; limit?: number } = {}): Incident[] {\n let sql = 'SELECT * FROM incidents WHERE 1=1';\n const params: any[] = [];\n\n if (options.projectId) {\n sql += ' AND project_id = ?';\n params.push(options.projectId);\n }\n if (options.status) {\n sql += ' AND status = ?';\n params.push(options.status);\n }\n if (options.severity) {\n sql += ' AND severity = ?';\n params.push(options.severity);\n }\n\n sql += ' ORDER BY last_seen DESC LIMIT ?';\n params.push(options.limit || 50);\n\n const rows = this.db.prepare(sql).all(...params) as any[];\n return rows.map((r) => this.mapIncidentRow(r));\n }\n\n public insertIncident(incident: Incident): void {\n this.db\n .prepare(\n `INSERT INTO incidents (\n id, project_id, session_id, type, severity, message, source_file, source_line, source_col,\n fingerprint, route, first_seen, last_seen, occurrences, status, stack, breadcrumbs,\n network_failures, last_element, screenshot_path\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`\n )\n .run(\n incident.id,\n incident.projectId,\n incident.sessionId,\n incident.type,\n incident.severity,\n incident.message,\n incident.source.file,\n incident.source.line,\n incident.source.column || null,\n incident.fingerprint,\n incident.route,\n incident.firstSeen,\n incident.lastSeen,\n incident.occurrences,\n incident.status,\n incident.stack || null,\n JSON.stringify(incident.breadcrumbs || []),\n JSON.stringify(incident.networkFailures || []),\n incident.lastElement ? JSON.stringify(incident.lastElement) : null,\n incident.screenshots?.error || null\n );\n }\n\n public updateIncidentOccurrence(\n incidentId: string,\n update: {\n sessionId: string;\n lastSeen: string;\n occurrences: number;\n route: string;\n breadcrumbs: Breadcrumb[];\n lastElement?: ElementSummary;\n stack?: string;\n }\n ): void {\n this.db\n .prepare(\n `UPDATE incidents \n SET session_id = ?, last_seen = ?, occurrences = ?, route = ?, breadcrumbs = ?, last_element = COALESCE(?, last_element), stack = COALESCE(?, stack)\n WHERE id = ?`\n )\n .run(\n update.sessionId,\n update.lastSeen,\n update.occurrences,\n update.route,\n JSON.stringify(update.breadcrumbs || []),\n update.lastElement ? JSON.stringify(update.lastElement) : null,\n update.stack || null,\n incidentId\n );\n }\n\n public updateIncidentStatus(id: string, status: IncidentStatus): void {\n this.db.prepare('UPDATE incidents SET status = ? WHERE id = ?').run(status, id);\n }\n\n public insertIncidentOccurrence(occurrence: IncidentOccurrence): void {\n this.db\n .prepare(\n `INSERT INTO incident_occurrences (id, incident_id, session_id, timestamp, route, url, stack, breadcrumbs, last_element)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`\n )\n .run(\n occurrence.id,\n occurrence.incidentId,\n occurrence.sessionId,\n occurrence.timestamp,\n occurrence.route,\n occurrence.url,\n occurrence.stack || null,\n JSON.stringify(occurrence.breadcrumbs || []),\n occurrence.lastElement ? JSON.stringify(occurrence.lastElement) : null\n );\n }\n\n // --- VERIFICATIONS ---\n public insertVerification(v: {\n id: string;\n incidentId: string;\n status: IncidentStatus;\n checks: any[];\n beforeScreenshot?: string;\n afterScreenshot?: string;\n message?: string;\n createdAt: string;\n }): void {\n this.db\n .prepare(\n `INSERT INTO verifications (id, incident_id, status, checks, before_screenshot, after_screenshot, message, created_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)`\n )\n .run(\n v.id,\n v.incidentId,\n v.status,\n JSON.stringify(v.checks),\n v.beforeScreenshot || null,\n v.afterScreenshot || null,\n v.message || null,\n v.createdAt\n );\n }\n\n public getLatestVerification(incidentId: string): VerificationResult | null {\n const row = this.db.prepare('SELECT * FROM verifications WHERE incident_id = ? ORDER BY created_at DESC LIMIT 1').get(incidentId) as any;\n if (!row) return null;\n return {\n incidentId: row.incident_id,\n status: row.status as IncidentStatus,\n checks: JSON.parse(row.checks || '[]'),\n screenshots: {\n before: row.before_screenshot || undefined,\n after: row.after_screenshot || undefined,\n },\n timestamp: row.created_at,\n message: row.message || undefined,\n };\n }\n\n // --- VISUAL NOTES ---\n public insertNote(note: VisualNote): void {\n this.db\n .prepare(\n `INSERT INTO notes (\n id, project_id, session_id, type, message, route, url,\n viewport_json, scroll_json, target_json, element_context_json, region_json,\n screenshot_path, incident_id, scenario_id, step_number, scenario_title, status, created_at, updated_at, resolved_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`\n )\n .run(\n note.id,\n note.projectId,\n note.sessionId,\n note.type,\n note.message,\n note.route,\n note.url,\n JSON.stringify(note.viewport),\n JSON.stringify(note.scroll),\n note.target ? JSON.stringify(note.target) : null,\n note.elementContext ? JSON.stringify(note.elementContext) : null,\n note.region ? JSON.stringify(note.region) : null,\n note.screenshots?.original || null,\n note.incidentId || null,\n note.scenarioId || null,\n note.stepNumber ?? null,\n note.scenarioTitle || null,\n note.status,\n note.createdAt,\n note.updatedAt,\n note.resolvedAt || null\n );\n }\n\n public getNote(id: string): VisualNote | null {\n const row = this.db.prepare('SELECT * FROM notes WHERE id = ?').get(id) as any;\n if (!row) return null;\n return this.mapNoteRow(row);\n }\n\n public listNotes(options: { projectId?: string; status?: NoteStatus; route?: string; scenarioId?: string; limit?: number } = {}): VisualNote[] {\n let sql = 'SELECT * FROM notes WHERE 1=1';\n const params: any[] = [];\n\n if (options.projectId) {\n sql += ' AND project_id = ?';\n params.push(options.projectId);\n }\n if (options.status) {\n sql += ' AND status = ?';\n params.push(options.status);\n }\n if (options.route) {\n sql += ' AND route = ?';\n params.push(options.route);\n }\n if (options.scenarioId) {\n sql += ' AND scenario_id = ?';\n params.push(options.scenarioId);\n }\n\n sql += ' ORDER BY created_at DESC LIMIT ?';\n params.push(options.limit || 50);\n\n const rows = this.db.prepare(sql).all(...params) as any[];\n return rows.map((r) => this.mapNoteRow(r));\n }\n\n public deleteNote(id: string): void {\n this.db.prepare('DELETE FROM note_verifications WHERE note_id = ?').run(id);\n this.db.prepare('DELETE FROM notes WHERE id = ?').run(id);\n }\n\n // --- SCENARIOS (MULTI-STEP FLOWS) ---\n public listScenarios(options: { projectId?: string; status?: NoteStatus; limit?: number } = {}): ScenarioOverview[] {\n let sql = `\n SELECT \n scenario_id, \n project_id, \n COALESCE(MAX(scenario_title), 'Scenario') as title,\n COUNT(id) as steps_count,\n CASE WHEN SUM(CASE WHEN status != 'RESOLVED' THEN 1 ELSE 0 END) = 0 THEN 'RESOLVED' ELSE 'OPEN' END as status,\n MIN(route) as route,\n MIN(created_at) as first_step_at,\n MAX(created_at) as last_step_at\n FROM notes\n WHERE scenario_id IS NOT NULL\n `;\n const params: any[] = [];\n if (options.projectId) {\n sql += ' AND (project_id = ? OR project_id IS NULL)';\n params.push(options.projectId);\n }\n sql += ' GROUP BY scenario_id';\n\n if (options.status) {\n if (options.status === 'RESOLVED') {\n sql += \" HAVING SUM(CASE WHEN status != 'RESOLVED' THEN 1 ELSE 0 END) = 0\";\n } else {\n sql += \" HAVING SUM(CASE WHEN status != 'RESOLVED' THEN 1 ELSE 0 END) > 0\";\n }\n }\n\n sql += ' ORDER BY last_step_at DESC LIMIT ?';\n params.push(options.limit || 50);\n\n const rows = this.db.prepare(sql).all(...params) as any[];\n return rows.map((r) => ({\n id: r.scenario_id,\n projectId: r.project_id,\n title: r.title,\n stepsCount: Number(r.steps_count),\n status: r.status as NoteStatus,\n route: r.route || '/',\n firstStepAt: r.first_step_at,\n lastStepAt: r.last_step_at,\n }));\n }\n\n public getScenario(scenarioId: string): ScenarioDetail | null {\n const rows = this.db\n .prepare('SELECT * FROM notes WHERE scenario_id = ? ORDER BY COALESCE(step_number, 999999) ASC, created_at ASC')\n .all(scenarioId) as any[];\n\n if (!rows || rows.length === 0) return null;\n\n const steps = rows.map((r) => this.mapNoteRow(r));\n const title = steps.find((s) => s.scenarioTitle)?.scenarioTitle || `Scenario ${scenarioId}`;\n const allResolved = steps.every((s) => s.status === 'RESOLVED');\n\n return {\n id: scenarioId,\n projectId: steps[0].projectId,\n title,\n stepsCount: steps.length,\n status: allResolved ? 'RESOLVED' : 'OPEN',\n steps,\n createdAt: steps[0].createdAt,\n updatedAt: steps[steps.length - 1].updatedAt,\n };\n }\n\n public deleteScenario(scenarioId: string): void {\n const notes = this.db.prepare('SELECT id FROM notes WHERE scenario_id = ?').all(scenarioId) as any[];\n for (const n of notes) {\n this.deleteNote(n.id);\n }\n }\n\n public updateNoteStatus(id: string, status: NoteStatus): void {\n const now = new Date().toISOString();\n const resolvedAt = status === 'RESOLVED' ? now : null;\n this.db\n .prepare('UPDATE notes SET status = ?, updated_at = ?, resolved_at = COALESCE(?, resolved_at) WHERE id = ?')\n .run(status, now, resolvedAt, id);\n }\n\n public updateNote(id: string, updates: Partial<VisualNote>): void {\n const now = new Date().toISOString();\n const current = this.getNote(id);\n if (!current) return;\n\n this.db\n .prepare(\n `UPDATE notes \n SET message = COALESCE(?, message), status = COALESCE(?, status),\n screenshot_path = COALESCE(?, screenshot_path), updated_at = ?\n WHERE id = ?`\n )\n .run(\n updates.message || null,\n updates.status || null,\n updates.screenshots?.original || updates.screenshots?.after || null,\n now,\n id\n );\n }\n\n public insertNoteVerification(v: NoteVerificationResult): void {\n this.db\n .prepare(\n `INSERT INTO note_verifications (\n id, note_id, status, checks, geometry_diff, before_screenshot, after_screenshot, message, created_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`\n )\n .run(\n `nver_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`,\n v.noteId,\n v.status,\n JSON.stringify(v.checks),\n v.geometryDiff ? JSON.stringify(v.geometryDiff) : null,\n v.screenshots?.before || null,\n v.screenshots?.after || null,\n v.message || null,\n v.timestamp\n );\n }\n\n public getLatestNoteVerification(noteId: string): NoteVerificationResult | null {\n const row = this.db.prepare('SELECT * FROM note_verifications WHERE note_id = ? ORDER BY created_at DESC LIMIT 1').get(noteId) as any;\n if (!row) return null;\n return {\n noteId: row.note_id,\n status: row.status as NoteStatus,\n checks: JSON.parse(row.checks || '[]'),\n geometryDiff: row.geometry_diff ? JSON.parse(row.geometry_diff) : undefined,\n screenshots: {\n before: row.before_screenshot || undefined,\n after: row.after_screenshot || undefined,\n },\n timestamp: row.created_at,\n message: row.message || undefined,\n };\n }\n\n public clearAll(): void {\n this.db.exec(`\n DELETE FROM events;\n DELETE FROM incident_occurrences;\n DELETE FROM incidents;\n DELETE FROM screenshots;\n DELETE FROM verifications;\n DELETE FROM notes;\n DELETE FROM note_verifications;\n DELETE FROM sessions;\n `);\n }\n\n private mapIncidentRow(row: any): Incident {\n return {\n id: row.id,\n projectId: row.project_id,\n sessionId: row.session_id,\n type: row.type,\n severity: row.severity as IncidentSeverity,\n message: row.message,\n source: {\n file: row.source_file,\n line: row.source_line,\n column: row.source_col || undefined,\n },\n fingerprint: row.fingerprint,\n route: row.route,\n firstSeen: row.first_seen,\n lastSeen: row.last_seen,\n occurrences: row.occurrences,\n status: row.status as IncidentStatus,\n stack: row.stack || undefined,\n breadcrumbs: JSON.parse(row.breadcrumbs || '[]'),\n networkFailures: JSON.parse(row.network_failures || '[]'),\n lastElement: row.last_element ? JSON.parse(row.last_element) : undefined,\n screenshots: row.screenshot_path\n ? {\n error: row.screenshot_path,\n }\n : undefined,\n };\n }\n\n private mapNoteRow(row: any): VisualNote {\n return {\n id: row.id,\n projectId: row.project_id,\n sessionId: row.session_id,\n type: row.type,\n message: row.message,\n route: row.route,\n url: row.url,\n viewport: JSON.parse(row.viewport_json || '{}'),\n scroll: JSON.parse(row.scroll_json || '{}'),\n target: row.target_json ? JSON.parse(row.target_json) : undefined,\n elementContext: row.element_context_json ? JSON.parse(row.element_context_json) : undefined,\n region: row.region_json ? JSON.parse(row.region_json) : undefined,\n status: row.status as NoteStatus,\n incidentId: row.incident_id || undefined,\n scenarioId: row.scenario_id || undefined,\n stepNumber: row.step_number != null ? Number(row.step_number) : undefined,\n scenarioTitle: row.scenario_title || undefined,\n screenshots: row.screenshot_path\n ? {\n original: row.screenshot_path,\n }\n : undefined,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n resolvedAt: row.resolved_at || undefined,\n };\n }\n\n public close(): void {\n this.db.close();\n }\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\n\nexport class ScreenshotStore {\n private baseDir: string;\n\n constructor(baseDir: string) {\n this.baseDir = baseDir;\n fs.mkdirSync(this.baseDir, { recursive: true });\n }\n\n public saveScreenshot(projectId: string, incidentId: string, name: string, dataUrl: string): { filePath: string; format: string } | null {\n try {\n if (!dataUrl || !dataUrl.startsWith('data:image/')) return null;\n\n const match = dataUrl.match(/^data:image\\/([a-zA-Z0-9+]+);base64,(.+)$/);\n if (!match) return null;\n\n let format = match[1].toLowerCase();\n if (format === 'jpeg') format = 'jpg';\n const base64Data = match[2];\n const buffer = Buffer.from(base64Data, 'base64');\n\n const targetDir = path.join(this.baseDir, projectId || 'default', 'incidents', incidentId);\n fs.mkdirSync(targetDir, { recursive: true });\n\n const fileName = `${name}.${format}`;\n const filePath = path.join(targetDir, fileName);\n\n fs.writeFileSync(filePath, buffer);\n\n return { filePath, format };\n } catch {\n return null;\n }\n }\n\n public getScreenshotPath(projectId: string, incidentId: string, name: string): string | null {\n const targetDir = path.join(this.baseDir, projectId || 'default', 'incidents', incidentId);\n if (!fs.existsSync(targetDir)) return null;\n\n const files = fs.readdirSync(targetDir);\n const match = files.find((f) => f.startsWith(`${name}.`));\n if (match) {\n return path.join(targetDir, match);\n }\n return null;\n }\n}\n","import type { WebSocket } from 'ws';\nimport type { ClientCommand, CommandResponse, Session } from '../../../core/src/index.js';\nimport type { StorageDB } from '../storage/db.js';\n\ninterface ActiveSessionSocket {\n sessionId: string;\n ws: WebSocket;\n origin: string;\n projectId: string;\n pendingCommands: Map<\n string,\n {\n resolve: (res: CommandResponse) => void;\n reject: (err: Error) => void;\n timer: any;\n }\n >;\n}\n\nexport class SessionManager {\n private activeSockets: Map<string, ActiveSessionSocket> = new Map();\n private db: StorageDB;\n\n constructor(db: StorageDB) {\n this.db = db;\n }\n\n public registerSocket(sessionId: string, ws: WebSocket, origin: string, projectId: string): void {\n this.activeSockets.set(sessionId, {\n sessionId,\n ws,\n origin,\n projectId,\n pendingCommands: new Map(),\n });\n }\n\n public unregisterSocket(sessionId: string): void {\n const active = this.activeSockets.get(sessionId);\n if (active) {\n for (const pending of active.pendingCommands.values()) {\n clearTimeout(pending.timer);\n pending.reject(new Error('Session disconnected before command completed'));\n }\n active.pendingCommands.clear();\n this.activeSockets.delete(sessionId);\n this.db.deactivateSession(sessionId);\n }\n }\n\n public handleCommandResponse(sessionId: string, response: CommandResponse): void {\n const active = this.activeSockets.get(sessionId);\n if (!active) return;\n\n const pending = active.pendingCommands.get(response.id);\n if (pending) {\n clearTimeout(pending.timer);\n active.pendingCommands.delete(response.id);\n pending.resolve(response);\n }\n }\n\n public async sendCommand<T = any>(sessionId: string, command: ClientCommand<T>, timeoutMs = 5000): Promise<CommandResponse> {\n const active = this.activeSockets.get(sessionId);\n if (!active || active.ws.readyState !== 1 /* WebSocket.OPEN */) {\n return {\n id: command.id,\n ok: false,\n error: `Session ${sessionId} is not actively connected`,\n };\n }\n\n return new Promise<CommandResponse>((resolve, reject) => {\n const timer = setTimeout(() => {\n active.pendingCommands.delete(command.id);\n resolve({\n id: command.id,\n ok: false,\n error: `Command ${command.type} timed out after ${timeoutMs}ms`,\n });\n }, timeoutMs);\n\n active.pendingCommands.set(command.id, {\n resolve,\n reject,\n timer,\n });\n\n try {\n active.ws.send(\n JSON.stringify({\n type: 'command',\n command,\n })\n );\n } catch (err: any) {\n clearTimeout(timer);\n active.pendingCommands.delete(command.id);\n resolve({\n id: command.id,\n ok: false,\n error: err?.message || 'Failed to send command over WebSocket',\n });\n }\n });\n }\n\n public getActiveSessionForProject(projectId: string): Session | null {\n for (const active of this.activeSockets.values()) {\n if (active.projectId === projectId) {\n return this.db.getSession(active.sessionId);\n }\n }\n return null;\n }\n\n public getAnyActiveSession(): Session | null {\n const first = this.activeSockets.keys().next().value;\n if (!first) return null;\n return this.db.getSession(first);\n }\n\n public getActiveCount(): number {\n return this.activeSockets.size;\n }\n\n public broadcastToProject(projectId: string, message: any): void {\n const raw = typeof message === 'string' ? message : JSON.stringify(message);\n for (const active of this.activeSockets.values()) {\n if (active.projectId === projectId && active.ws.readyState === 1 /* OPEN */) {\n try {\n active.ws.send(raw);\n } catch {}\n }\n }\n }\n\n public sendToSession(sessionId: string, message: any): void {\n const active = this.activeSockets.get(sessionId);\n if (active && active.ws.readyState === 1) {\n try {\n const raw = typeof message === 'string' ? message : JSON.stringify(message);\n active.ws.send(raw);\n } catch {}\n }\n }\n}\n","import crypto from 'node:crypto';\nimport path from 'node:path';\nimport fs from 'node:fs';\nimport type { VisualNote } from '../../../core/src/index.js';\nimport type { StorageDB } from '../storage/db.js';\nimport type { ScreenshotStore } from '../storage/screenshot-store.js';\n\nexport class NotesEngine {\n private db: StorageDB;\n private screenshotStore: ScreenshotStore;\n\n constructor(db: StorageDB, screenshotStore: ScreenshotStore) {\n this.db = db;\n this.screenshotStore = screenshotStore;\n }\n\n public createNoteFromClient(payload: {\n sessionId: string;\n noteType?: 'element' | 'region' | 'page';\n message: string;\n route?: string;\n url?: string;\n viewport?: { width: number; height: number; devicePixelRatio: number };\n scroll?: { scrollX: number; scrollY: number };\n target?: any;\n elementContext?: any;\n region?: any;\n screenshot?: string;\n incidentId?: string;\n scenarioId?: string;\n stepNumber?: number;\n scenarioTitle?: string;\n }): VisualNote {\n const session = this.db.getSession(payload.sessionId);\n const projectId = session?.projectId || 'default';\n const noteId = `note_${crypto.randomUUID().slice(0, 8)}`;\n const now = new Date().toISOString();\n\n let screenshotPath: string | undefined;\n if (payload.screenshot) {\n const saved = this.saveNoteScreenshot(projectId, noteId, 'original', payload.screenshot);\n if (saved) {\n screenshotPath = saved;\n }\n }\n\n const note: VisualNote = {\n id: noteId,\n projectId,\n sessionId: payload.sessionId,\n type: payload.noteType || 'element',\n message: payload.message,\n route: payload.route || '/',\n url: payload.url || '',\n viewport: payload.viewport || { width: 1280, height: 800, devicePixelRatio: 1 },\n scroll: payload.scroll || { scrollX: 0, scrollY: 0 },\n target: payload.target,\n elementContext: payload.elementContext,\n region: payload.region,\n status: 'OPEN',\n incidentId: payload.incidentId,\n scenarioId: payload.scenarioId,\n stepNumber: payload.stepNumber,\n scenarioTitle: payload.scenarioTitle,\n screenshots: screenshotPath ? { original: screenshotPath } : undefined,\n createdAt: now,\n updatedAt: now,\n };\n\n this.db.insertNote(note);\n return note;\n }\n\n public saveNoteScreenshot(projectId: string, noteId: string, name: string, dataUrl: string): string | null {\n try {\n if (!dataUrl || !dataUrl.startsWith('data:image/')) return null;\n\n const match = dataUrl.match(/^data:image\\/([a-zA-Z0-9+]+);base64,(.+)$/);\n if (!match) return null;\n\n let format = match[1].toLowerCase();\n if (format === 'jpeg') format = 'jpg';\n const base64Data = match[2];\n const buffer = Buffer.from(base64Data, 'base64');\n\n const targetDir = path.join((this.screenshotStore as any).baseDir, projectId || 'default', 'notes', noteId);\n fs.mkdirSync(targetDir, { recursive: true });\n\n const fileName = `${name}.${format}`;\n const filePath = path.join(targetDir, fileName);\n\n fs.writeFileSync(filePath, buffer);\n return filePath;\n } catch {\n return null;\n }\n }\n}\n","import crypto from 'node:crypto';\nimport type { DOMRectJson, NoteStatus, NoteVerificationResult, OverflowCheckResult, VisualNote } from '../../../core/src/index.js';\nimport type { NotesEngine } from './engine.js';\nimport type { SessionManager } from '../session/manager.js';\nimport type { StorageDB } from '../storage/db.js';\n\nexport class NoteVerificationEngine {\n private db: StorageDB;\n private sessionManager: SessionManager;\n private notesEngine: NotesEngine;\n\n constructor(db: StorageDB, sessionManager: SessionManager, notesEngine: NotesEngine) {\n this.db = db;\n this.sessionManager = sessionManager;\n this.notesEngine = notesEngine;\n }\n\n public async verifyNote(noteId: string, options: { observationWindowMs?: number } = {}): Promise<NoteVerificationResult> {\n const note = this.db.getNote(noteId);\n if (!note) {\n return {\n noteId,\n status: 'FAILED',\n checks: [{ type: 'note_exists', passed: false, details: `Note ${noteId} not found` }],\n timestamp: new Date().toISOString(),\n message: `Note ${noteId} not found in database`,\n };\n }\n\n // 1. Find active session\n let session = this.sessionManager.getActiveSessionForProject(note.projectId);\n if (!session) {\n session = this.sessionManager.getAnyActiveSession();\n }\n\n if (!session) {\n const result: NoteVerificationResult = {\n noteId,\n status: 'INCONCLUSIVE',\n checks: [],\n timestamp: new Date().toISOString(),\n message: 'No active browser session currently connected to verify visual note.',\n };\n this.recordNoteVerification(result, note);\n return result;\n }\n\n // 2. Set status to VERIFYING\n this.db.updateNoteStatus(noteId, 'VERIFYING');\n\n // 3. Navigation check / route sync\n const pageStateCmd = await this.sessionManager.sendCommand(session.id, {\n id: `cmd_${crypto.randomUUID().slice(0, 8)}`,\n type: 'get_page_state',\n });\n\n const currentRoute = pageStateCmd.result?.route || '/';\n const isRouteMatch = currentRoute === note.route || currentRoute.startsWith(note.route);\n\n if (!isRouteMatch && note.route) {\n await this.sessionManager.sendCommand(session.id, {\n id: `cmd_${crypto.randomUUID().slice(0, 8)}`,\n type: 'navigate',\n params: { url: note.route },\n });\n // Wait for navigation observation window\n await new Promise((r) => setTimeout(r, options.observationWindowMs || 1000));\n }\n\n const checks: Array<{ type: string; passed: boolean; details?: string }> = [];\n\n checks.push({\n type: 'route_loaded',\n passed: true,\n details: `Route ${note.route || '/'} loaded`,\n });\n\n // 4. Target element checks\n const targetSelector = note.target?.selector || (note.type === 'page' ? 'body' : 'body');\n let elementExists = true;\n let elementVisible = true;\n let currentRect: DOMRectJson | undefined;\n let overflowResult: OverflowCheckResult | undefined;\n\n if (note.type === 'element' && targetSelector) {\n const queryCmd = await this.sessionManager.sendCommand(session.id, {\n id: `cmd_${crypto.randomUUID().slice(0, 8)}`,\n type: 'query_element',\n params: { selector: targetSelector },\n });\n\n elementExists = queryCmd.ok && !!queryCmd.result?.exists;\n elementVisible = queryCmd.ok && !!queryCmd.result?.visible;\n currentRect = queryCmd.result?.boundingRect;\n\n checks.push({\n type: 'element_exists',\n passed: elementExists,\n details: elementExists ? `Element ${targetSelector} exists in DOM` : `Element ${targetSelector} not found`,\n });\n\n checks.push({\n type: 'element_visible',\n passed: elementVisible,\n details: elementVisible ? `Element ${targetSelector} is visible` : `Element ${targetSelector} is hidden`,\n });\n\n // 5. Layout Overflow Probe\n const overflowCmd = await this.sessionManager.sendCommand(session.id, {\n id: `cmd_${crypto.randomUUID().slice(0, 8)}`,\n type: 'check_overflow',\n params: { selector: targetSelector },\n });\n\n if (overflowCmd.ok && overflowCmd.result) {\n const ovf = overflowCmd.result as OverflowCheckResult;\n overflowResult = ovf;\n const isOverflowingNow = !!ovf.overflow;\n\n checks.push({\n type: 'no_viewport_overflow',\n passed: !isOverflowingNow,\n details: !isOverflowingNow\n ? `Element fits within viewport (width: ${ovf.viewportWidth}px, rect right: ${ovf.rect?.right}px)`\n : `Element overflows viewport by ${ovf.overflowRightPx}px (rect right: ${ovf.rect?.right}px, viewport: ${ovf.viewportWidth}px)`,\n });\n }\n }\n\n // 6. Capture \"after\" screenshot\n let afterScreenshotPath: string | undefined;\n const captureCmd = await this.sessionManager.sendCommand(session.id, {\n id: `cmd_${crypto.randomUUID().slice(0, 8)}`,\n type: 'capture_element',\n params: { selector: targetSelector },\n });\n\n if (captureCmd.ok && captureCmd.result?.dataUrl) {\n const saved = this.notesEngine.saveNoteScreenshot(note.projectId, note.id, 'after', captureCmd.result.dataUrl);\n if (saved) {\n afterScreenshotPath = saved;\n }\n }\n\n // 7. Calculate Geometry Difference\n const beforeRect = note.target?.boundingRect;\n const overflowFixed = overflowResult ? !overflowResult.overflow : undefined;\n\n const geometryDiff = {\n before: beforeRect,\n current: currentRect || (overflowResult?.rect as DOMRectJson),\n viewportWidth: overflowResult?.viewportWidth || note.viewport.width,\n overflowFixed,\n overflowPx: overflowResult?.overflowRightPx || 0,\n };\n\n // 8. Verdict\n const anyFailed = checks.some((c) => !c.passed);\n let status: NoteStatus = 'VERIFIED';\n\n if (anyFailed) {\n status = 'FAILED';\n } else {\n status = 'VERIFIED';\n }\n\n const verificationResult: NoteVerificationResult = {\n noteId,\n status,\n checks,\n geometryDiff,\n screenshots: {\n before: note.screenshots?.original,\n after: afterScreenshotPath,\n },\n timestamp: new Date().toISOString(),\n message:\n status === 'VERIFIED'\n ? 'Visual note verified: target element is present, visible, and layout checks (including viewport overflow) passed.'\n : 'Visual note verification failed: target element missing, hidden, or still overflowing.',\n };\n\n this.recordNoteVerification(verificationResult, note);\n return verificationResult;\n }\n\n private recordNoteVerification(result: NoteVerificationResult, note: VisualNote): void {\n this.db.updateNoteStatus(note.id, result.status);\n this.db.insertNoteVerification(result);\n }\n}\n","import crypto from 'node:crypto';\nimport type {\n Incident,\n IncidentStatus,\n ProbeResult,\n VerificationProbe,\n VerificationRecipe,\n VerificationResult,\n} from '../../../core/src/index.js';\nimport type { SessionManager } from '../session/manager.js';\nimport type { StorageDB } from '../storage/db.js';\nimport type { ScreenshotStore } from '../storage/screenshot-store.js';\n\nexport class VerificationEngine {\n private db: StorageDB;\n private sessionManager: SessionManager;\n private screenshotStore: ScreenshotStore;\n\n constructor(db: StorageDB, sessionManager: SessionManager, screenshotStore: ScreenshotStore) {\n this.db = db;\n this.sessionManager = sessionManager;\n this.screenshotStore = screenshotStore;\n }\n\n public async verifyIncident(incidentId: string, recipe?: VerificationRecipe): Promise<VerificationResult> {\n const incident = this.db.getIncident(incidentId);\n if (!incident) {\n return {\n incidentId,\n status: 'FAILED',\n checks: [{ type: 'no_incident', passed: false, details: `Incident ${incidentId} not found` }],\n timestamp: new Date().toISOString(),\n message: `Incident ${incidentId} not found in database`,\n };\n }\n\n // 1. Find active session\n let session = this.sessionManager.getActiveSessionForProject(incident.projectId);\n if (!session) {\n session = this.sessionManager.getAnyActiveSession();\n }\n\n if (!session) {\n const result: VerificationResult = {\n incidentId,\n status: 'INCONCLUSIVE',\n checks: [],\n timestamp: new Date().toISOString(),\n message: 'No active browser session currently connected to verify the fix.',\n };\n this.recordVerification(result, incident);\n return result;\n }\n\n // 2. Set status to VERIFYING and record baseline\n this.db.updateIncidentStatus(incidentId, 'VERIFYING');\n const baselineOccurrences = incident.occurrences;\n\n // 3. Initiate browser reload or navigation\n const targetRoute = recipe?.route || incident.route;\n const observationMs = recipe?.observationWindowMs || 2000;\n\n if (recipe?.route && recipe.route !== incident.route) {\n await this.sessionManager.sendCommand(session.id, {\n id: `cmd_${crypto.randomUUID().slice(0, 8)}`,\n type: 'navigate',\n params: { url: recipe.route },\n });\n } else {\n await this.sessionManager.sendCommand(session.id, {\n id: `cmd_${crypto.randomUUID().slice(0, 8)}`,\n type: 'reload',\n params: { force: true },\n });\n }\n\n // 4. Observation window\n await new Promise((resolve) => setTimeout(resolve, observationMs));\n\n // 5. Check if incident re-occurred\n const freshIncident = this.db.getIncident(incidentId);\n const hasReoccurred = freshIncident ? freshIncident.occurrences > baselineOccurrences : false;\n\n const checks: ProbeResult[] = [];\n checks.push({\n type: 'no_incident',\n passed: !hasReoccurred,\n details: hasReoccurred\n ? `Incident reoccurred (${freshIncident?.occurrences} occurrences vs baseline ${baselineOccurrences})`\n : 'No recurring error observed during verification window',\n });\n\n // 6. Run additional probes\n const probes = recipe?.expect || [];\n for (const probe of probes) {\n const probeRes = await this.evaluateProbe(session.id, probe);\n checks.push(probeRes);\n }\n\n // 7. Check target element or last element for after-screenshot\n let afterScreenshotPath: string | undefined;\n const targetSelector = recipe?.targetSelector || incident.lastElement?.selector;\n\n if (targetSelector) {\n const captureCmd = await this.sessionManager.sendCommand(session.id, {\n id: `cmd_${crypto.randomUUID().slice(0, 8)}`,\n type: 'capture_element',\n params: { selector: targetSelector },\n });\n\n if (captureCmd.ok && captureCmd.result?.dataUrl) {\n const saved = this.screenshotStore.saveScreenshot(\n incident.projectId,\n incident.id,\n 'verified',\n captureCmd.result.dataUrl\n );\n if (saved) {\n afterScreenshotPath = saved.filePath;\n }\n }\n }\n\n // 8. Calculate verdict\n let verdict: IncidentStatus = 'VERIFIED';\n const anyCheckFailed = checks.some((c) => !c.passed);\n\n if (anyCheckFailed || hasReoccurred) {\n verdict = 'FAILED';\n } else {\n // Check if incident required an explicit interaction (like button click) that wasn't covered by probes\n const wasInteractionError = incident.breadcrumbs.some((b) => b.type === 'click' || b.type === 'submit');\n if (wasInteractionError && probes.length === 0) {\n verdict = 'INCONCLUSIVE';\n }\n }\n\n const verificationResult: VerificationResult = {\n incidentId,\n status: verdict,\n checks,\n screenshots: {\n before: incident.screenshots?.error,\n after: afterScreenshotPath,\n },\n timestamp: new Date().toISOString(),\n message:\n verdict === 'VERIFIED'\n ? 'Fix verified: Error did not reoccur and all checks passed.'\n : verdict === 'FAILED'\n ? 'Verification failed: Error reoccurred or probe expectation was not met.'\n : 'Verification inconclusive: Error did not appear on reload, but specific interaction may need manual verification or custom probes.',\n };\n\n this.recordVerification(verificationResult, incident);\n return verificationResult;\n }\n\n private async evaluateProbe(sessionId: string, probe: VerificationProbe): Promise<ProbeResult> {\n try {\n switch (probe.type) {\n case 'element_exists': {\n if (!probe.selector) {\n return { type: probe.type, passed: false, details: 'Missing selector in probe' };\n }\n const res = await this.sessionManager.sendCommand(sessionId, {\n id: `cmd_${crypto.randomUUID().slice(0, 8)}`,\n type: 'query_element',\n params: { selector: probe.selector },\n });\n const exists = res.ok && !!res.result?.exists;\n return {\n type: probe.type,\n passed: exists,\n details: exists ? `Element ${probe.selector} exists in DOM` : `Element ${probe.selector} does not exist`,\n };\n }\n\n case 'element_visible': {\n if (!probe.selector) {\n return { type: probe.type, passed: false, details: 'Missing selector in probe' };\n }\n const res = await this.sessionManager.sendCommand(sessionId, {\n id: `cmd_${crypto.randomUUID().slice(0, 8)}`,\n type: 'query_element',\n params: { selector: probe.selector },\n });\n const visible = res.ok && !!res.result?.exists && !!res.result?.visible;\n return {\n type: probe.type,\n passed: visible,\n details: visible ? `Element ${probe.selector} is visible` : `Element ${probe.selector} is not visible`,\n };\n }\n\n case 'text_contains': {\n if (!probe.selector || !probe.text) {\n return { type: probe.type, passed: false, details: 'Missing selector or text in probe' };\n }\n const res = await this.sessionManager.sendCommand(sessionId, {\n id: `cmd_${crypto.randomUUID().slice(0, 8)}`,\n type: 'query_element',\n params: { selector: probe.selector },\n });\n const innerText = res.result?.innerText || '';\n const contains = res.ok && innerText.includes(probe.text);\n return {\n type: probe.type,\n passed: contains,\n details: contains\n ? `Element ${probe.selector} contains text \"${probe.text}\"`\n : `Element text \"${innerText}\" did not contain \"${probe.text}\"`,\n };\n }\n\n case 'route_is': {\n if (!probe.route) {\n return { type: probe.type, passed: false, details: 'Missing route in probe' };\n }\n const res = await this.sessionManager.sendCommand(sessionId, {\n id: `cmd_${crypto.randomUUID().slice(0, 8)}`,\n type: 'get_page_state',\n });\n const currentRoute = res.result?.route || '';\n const matches = res.ok && (currentRoute === probe.route || currentRoute.startsWith(probe.route));\n return {\n type: probe.type,\n passed: matches,\n details: matches\n ? `Current route matches ${probe.route}`\n : `Current route is \"${currentRoute}\", expected \"${probe.route}\"`,\n };\n }\n\n default:\n return {\n type: probe.type,\n passed: true,\n details: `Probe ${probe.type} evaluated`,\n };\n }\n } catch (err: any) {\n return {\n type: probe.type,\n passed: false,\n details: err?.message || 'Probe execution error',\n };\n }\n }\n\n private recordVerification(result: VerificationResult, incident: Incident): void {\n this.db.updateIncidentStatus(incident.id, result.status);\n this.db.insertVerification({\n id: `ver_${crypto.randomUUID().slice(0, 8)}`,\n incidentId: incident.id,\n status: result.status,\n checks: result.checks,\n beforeScreenshot: result.screenshots?.before,\n afterScreenshot: result.screenshots?.after,\n message: result.message,\n createdAt: result.timestamp,\n });\n }\n}\n"],"mappings":"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","names":["path","fs","path","path","fs","crypto","crypto"]}
@@ -6,7 +6,7 @@ import {
6
6
  StorageDB,
7
7
  VerificationEngine,
8
8
  getDaemonConfig
9
- } from "./chunk-ILRYKMME.js";
9
+ } from "./chunk-3HOXPTM2.js";
10
10
 
11
11
  // packages/mcp/src/tools.ts
12
12
  var TOOLS = [
@@ -165,6 +165,7 @@ var TOOLS = [
165
165
  type: "object",
166
166
  properties: {
167
167
  projectId: { type: "string", description: "Filter notes by project ID or name" },
168
+ scenarioId: { type: "string", description: "Filter notes by scenario / flow ID" },
168
169
  status: {
169
170
  type: "string",
170
171
  enum: ["OPEN", "IN_PROGRESS", "VERIFYING", "RESOLVED", "FAILED", "INCONCLUSIVE"],
@@ -174,6 +175,33 @@ var TOOLS = [
174
175
  }
175
176
  }
176
177
  },
178
+ {
179
+ name: "list_scenarios",
180
+ description: "List recorded reproduction scenarios and multi-step user interaction flows",
181
+ inputSchema: {
182
+ type: "object",
183
+ properties: {
184
+ projectId: { type: "string", description: "Filter scenarios by project ID or name" },
185
+ status: {
186
+ type: "string",
187
+ enum: ["OPEN", "RESOLVED"],
188
+ description: "Filter by scenario status"
189
+ },
190
+ limit: { type: "number", description: "Maximum number of scenarios to return (default: 20)" }
191
+ }
192
+ }
193
+ },
194
+ {
195
+ name: "get_scenario",
196
+ description: "Retrieve full chronological step-by-step reproduction flow with selectors, route, screenshots, and action details",
197
+ inputSchema: {
198
+ type: "object",
199
+ properties: {
200
+ scenarioId: { type: "string", description: "The unique ID of the scenario / flow (e.g. scen_123)" }
201
+ },
202
+ required: ["scenarioId"]
203
+ }
204
+ },
177
205
  {
178
206
  name: "get_note",
179
207
  description: "Retrieve full debugging context for a visual note (message, route, viewport dimensions, target element selector, DOM context, screenshot file path, project path)",
@@ -329,7 +357,8 @@ async function handleToolCall(name, args, ctx) {
329
357
  tag: incident.lastElement.tag,
330
358
  visible: incident.lastElement.visible,
331
359
  innerText: incident.lastElement.innerText,
332
- outerHTML: incident.lastElement.outerHTML
360
+ outerHTML: incident.lastElement.outerHTML,
361
+ componentSource: incident.lastElement.componentSource
333
362
  } : void 0,
334
363
  recentBreadcrumbs: breadcrumbsTimeline,
335
364
  networkFailures: incident.networkFailures,
@@ -455,6 +484,7 @@ async function handleToolCall(name, args, ctx) {
455
484
  case "list_notes": {
456
485
  const notes = db.listNotes({
457
486
  projectId: args.projectId,
487
+ scenarioId: args.scenarioId,
458
488
  status: args.status,
459
489
  limit: args.limit || 20
460
490
  });
@@ -465,6 +495,9 @@ async function handleToolCall(name, args, ctx) {
465
495
  type: n.type,
466
496
  status: n.status,
467
497
  route: n.route,
498
+ scenarioId: n.scenarioId,
499
+ stepNumber: n.stepNumber,
500
+ scenarioTitle: n.scenarioTitle,
468
501
  viewport: `${n.viewport.width} \xD7 ${n.viewport.height}`,
469
502
  target: n.target?.selector || n.type,
470
503
  message: n.message,
@@ -473,6 +506,53 @@ async function handleToolCall(name, args, ctx) {
473
506
  }))
474
507
  };
475
508
  }
509
+ case "list_scenarios": {
510
+ const scenarios = db.listScenarios({
511
+ projectId: args.projectId,
512
+ status: args.status,
513
+ limit: args.limit || 20
514
+ });
515
+ return {
516
+ total: scenarios.length,
517
+ scenarios: scenarios.map((s) => ({
518
+ id: s.id,
519
+ title: s.title,
520
+ stepsCount: s.stepsCount,
521
+ status: s.status,
522
+ route: s.route,
523
+ firstStepAt: s.firstStepAt,
524
+ lastStepAt: s.lastStepAt
525
+ }))
526
+ };
527
+ }
528
+ case "get_scenario": {
529
+ const scenario = db.getScenario(args.scenarioId);
530
+ if (!scenario) {
531
+ throw new Error(`Scenario '${args.scenarioId}' not found.`);
532
+ }
533
+ return {
534
+ id: scenario.id,
535
+ title: scenario.title,
536
+ stepsCount: scenario.stepsCount,
537
+ status: scenario.status,
538
+ steps: scenario.steps.map((step) => ({
539
+ id: step.id,
540
+ stepNumber: step.stepNumber,
541
+ type: step.type,
542
+ message: step.message,
543
+ route: step.route,
544
+ url: step.url,
545
+ targetSelector: step.target?.selector,
546
+ boundingRect: step.target?.boundingRect || step.region,
547
+ elementContext: step.elementContext,
548
+ screenshot: step.screenshots?.original,
549
+ status: step.status,
550
+ createdAt: step.createdAt
551
+ })),
552
+ createdAt: scenario.createdAt,
553
+ updatedAt: scenario.updatedAt
554
+ };
555
+ }
476
556
  case "get_note": {
477
557
  const note = db.getNote(args.noteId);
478
558
  if (!note) {
@@ -484,6 +564,9 @@ async function handleToolCall(name, args, ctx) {
484
564
  type: note.type,
485
565
  status: note.status,
486
566
  message: note.message,
567
+ scenarioId: note.scenarioId,
568
+ stepNumber: note.stepNumber,
569
+ scenarioTitle: note.scenarioTitle,
487
570
  route: note.route,
488
571
  url: note.url,
489
572
  viewport: note.viewport,
@@ -656,4 +739,4 @@ export {
656
739
  handleToolCall,
657
740
  createMcpServer
658
741
  };
659
- //# sourceMappingURL=chunk-G2Y3CXCY.js.map
742
+ //# sourceMappingURL=chunk-464D4U2U.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../packages/mcp/src/tools.ts","../packages/mcp/src/handlers.ts","../packages/mcp/src/server.ts"],"sourcesContent":["import type { Tool } from '@modelcontextprotocol/sdk/types.js';\n\nexport const TOOLS: Tool[] = [\n {\n name: 'list_projects',\n description: 'List all registered projects tracked by BrowserTrack/BrowserDiag',\n inputSchema: {\n type: 'object',\n properties: {},\n },\n },\n {\n name: 'list_sessions',\n description: 'List active and recent browser sessions connected to the local development daemon',\n inputSchema: {\n type: 'object',\n properties: {\n projectId: { type: 'string', description: 'Filter sessions by project ID or name' },\n activeOnly: { type: 'boolean', description: 'Show only currently active WebSocket sessions (default: true)' },\n },\n },\n },\n {\n name: 'list_incidents',\n description: 'List recorded browser runtime errors, unhandled rejections, and console errors grouped into incidents',\n inputSchema: {\n type: 'object',\n properties: {\n projectId: { type: 'string', description: 'Filter by project ID or name' },\n status: {\n type: 'string',\n enum: ['OPEN', 'FIX_ATTEMPTED', 'VERIFYING', 'VERIFIED', 'FAILED', 'INCONCLUSIVE'],\n description: 'Filter by incident status',\n },\n severity: {\n type: 'string',\n enum: ['error', 'warn', 'fatal'],\n description: 'Filter by severity',\n },\n limit: { type: 'number', description: 'Maximum number of incidents to return (default: 20)' },\n },\n },\n },\n {\n name: 'get_incident',\n description: 'Retrieve compact and high-signal debugging context for a specific error incident (stack trace, breadcrumbs, network failures, last interacted element, error screenshot)',\n inputSchema: {\n type: 'object',\n properties: {\n incidentId: { type: 'string', description: 'The unique ID of the incident (e.g. inc_42)' },\n },\n required: ['incidentId'],\n },\n },\n {\n name: 'get_console',\n description: 'Get recent console logs, warnings, and errors from a browser session',\n inputSchema: {\n type: 'object',\n properties: {\n sessionId: { type: 'string', description: 'Browser session ID (optional, defaults to active session)' },\n limit: { type: 'number', description: 'Number of console logs to retrieve (default: 30)' },\n },\n },\n },\n {\n name: 'get_network_failures',\n description: 'Get recent failed HTTP network requests (4xx, 5xx, network errors, timeouts, aborts)',\n inputSchema: {\n type: 'object',\n properties: {\n sessionId: { type: 'string', description: 'Browser session ID (optional)' },\n limit: { type: 'number', description: 'Maximum number of failed requests to return (default: 20)' },\n },\n },\n },\n {\n name: 'get_breadcrumbs',\n description: 'Get the sequence of recent user interactions, navigations, console logs, and network events prior to an error',\n inputSchema: {\n type: 'object',\n properties: {\n sessionId: { type: 'string', description: 'Browser session ID (optional)' },\n incidentId: { type: 'string', description: 'Incident ID to fetch breadcrumbs from (optional)' },\n limit: { type: 'number', description: 'Maximum number of breadcrumbs (default: 50)' },\n },\n },\n },\n {\n name: 'get_page_state',\n description: 'Query the live page state (URL, route, document title, readyState, active element) from the connected browser session',\n inputSchema: {\n type: 'object',\n properties: {\n sessionId: { type: 'string', description: 'Target session ID (optional, defaults to active)' },\n },\n },\n },\n {\n name: 'capture_element',\n description: 'Capture a screenshot of a specific DOM element or the entire visible page in the active browser tab',\n inputSchema: {\n type: 'object',\n properties: {\n selector: { type: 'string', description: 'CSS selector of the element to capture (e.g. [data-testid=\"user-card\"])' },\n sessionId: { type: 'string', description: 'Browser session ID (optional)' },\n },\n },\n },\n {\n name: 'verify_incident',\n description: 'Trigger closed-loop verification of a bug fix: reloads the browser, checks if the incident reoccurs, evaluates optional verification probes, and records before/after screenshots',\n inputSchema: {\n type: 'object',\n properties: {\n incidentId: { type: 'string', description: 'The ID of the incident to verify' },\n route: { type: 'string', description: 'Optional route to navigate to for verification (defaults to incident route)' },\n targetSelector: { type: 'string', description: 'Optional element selector to inspect and capture after-fix screenshot' },\n expect: {\n type: 'array',\n description: 'Optional verification probes to evaluate after reload',\n items: {\n type: 'object',\n properties: {\n type: {\n type: 'string',\n enum: ['element_exists', 'element_visible', 'text_contains', 'route_is', 'no_incident'],\n },\n selector: { type: 'string' },\n text: { type: 'string' },\n route: { type: 'string' },\n },\n required: ['type'],\n },\n },\n observationWindowMs: { type: 'number', description: 'Observation window in milliseconds (default: 2000)' },\n },\n required: ['incidentId'],\n },\n },\n {\n name: 'get_verification',\n description: 'Retrieve the latest verification result and before/after screenshot artifacts for an incident',\n inputSchema: {\n type: 'object',\n properties: {\n incidentId: { type: 'string', description: 'The ID of the incident' },\n },\n required: ['incidentId'],\n },\n },\n {\n name: 'list_notes',\n description: 'List visual development notes / screen annotations left on elements, regions, or pages during development',\n inputSchema: {\n type: 'object',\n properties: {\n projectId: { type: 'string', description: 'Filter notes by project ID or name' },\n scenarioId: { type: 'string', description: 'Filter notes by scenario / flow ID' },\n status: {\n type: 'string',\n enum: ['OPEN', 'IN_PROGRESS', 'VERIFYING', 'RESOLVED', 'FAILED', 'INCONCLUSIVE'],\n description: 'Filter by note status (default: OPEN)',\n },\n limit: { type: 'number', description: 'Maximum number of notes to return (default: 20)' },\n },\n },\n },\n {\n name: 'list_scenarios',\n description: 'List recorded reproduction scenarios and multi-step user interaction flows',\n inputSchema: {\n type: 'object',\n properties: {\n projectId: { type: 'string', description: 'Filter scenarios by project ID or name' },\n status: {\n type: 'string',\n enum: ['OPEN', 'RESOLVED'],\n description: 'Filter by scenario status',\n },\n limit: { type: 'number', description: 'Maximum number of scenarios to return (default: 20)' },\n },\n },\n },\n {\n name: 'get_scenario',\n description: 'Retrieve full chronological step-by-step reproduction flow with selectors, route, screenshots, and action details',\n inputSchema: {\n type: 'object',\n properties: {\n scenarioId: { type: 'string', description: 'The unique ID of the scenario / flow (e.g. scen_123)' },\n },\n required: ['scenarioId'],\n },\n },\n {\n name: 'get_note',\n description: 'Retrieve full debugging context for a visual note (message, route, viewport dimensions, target element selector, DOM context, screenshot file path, project path)',\n inputSchema: {\n type: 'object',\n properties: {\n noteId: { type: 'string', description: 'The unique ID of the visual note (e.g. note_42)' },\n },\n required: ['noteId'],\n },\n },\n {\n name: 'resolve_note',\n description: 'Mark a visual note as RESOLVED once the layout or styling issue has been fixed',\n inputSchema: {\n type: 'object',\n properties: {\n noteId: { type: 'string', description: 'The ID of the visual note to resolve' },\n },\n required: ['noteId'],\n },\n },\n {\n name: 'reopen_note',\n description: 'Reopen a previously resolved visual note',\n inputSchema: {\n type: 'object',\n properties: {\n noteId: { type: 'string', description: 'The ID of the visual note to reopen' },\n },\n required: ['noteId'],\n },\n },\n {\n name: 'verify_note',\n description: 'Run closed-loop layout & visual verification for a note: checks route, element existence/visibility, evaluates viewport overflow probes, captures after-screenshot, and computes geometry diff',\n inputSchema: {\n type: 'object',\n properties: {\n noteId: { type: 'string', description: 'The ID of the visual note to verify' },\n observationWindowMs: { type: 'number', description: 'Observation window in milliseconds (default: 1000)' },\n },\n required: ['noteId'],\n },\n },\n {\n name: 'get_note_verification',\n description: 'Retrieve the latest verification result, before/after screenshot references, and layout geometry diff for a visual note',\n inputSchema: {\n type: 'object',\n properties: {\n noteId: { type: 'string', description: 'The ID of the visual note' },\n },\n required: ['noteId'],\n },\n },\n {\n name: 'capture_note_context',\n description: 'Inspect live DOM context, bounding box, overflow, and styles for a target element in the active browser tab',\n inputSchema: {\n type: 'object',\n properties: {\n selector: { type: 'string', description: 'CSS selector of the target element' },\n sessionId: { type: 'string', description: 'Browser session ID (optional)' },\n },\n required: ['selector'],\n },\n },\n];\n","import type { StorageDB } from '../../daemon/src/storage/db.js';\nimport type { VerificationEngine } from '../../daemon/src/verification/engine.js';\nimport type { NoteVerificationEngine } from '../../daemon/src/notes/verification.js';\nimport type { SessionManager } from '../../daemon/src/session/manager.js';\n\nexport interface McpContext {\n db: StorageDB;\n sessionManager?: SessionManager;\n verificationEngine?: VerificationEngine;\n noteVerificationEngine?: NoteVerificationEngine;\n daemonUrl?: string;\n}\n\nexport async function handleToolCall(name: string, args: any, ctx: McpContext): Promise<any> {\n const { db, sessionManager, verificationEngine, noteVerificationEngine } = ctx;\n\n switch (name) {\n case 'list_projects': {\n const projects = db.listProjects();\n return {\n projects: projects.map((p) => ({\n id: p.id,\n name: p.name,\n origin: p.origin,\n path: p.path,\n updatedAt: p.updatedAt,\n })),\n };\n }\n\n case 'list_sessions': {\n const activeOnly = args.activeOnly !== false;\n const sessions = db.listSessions(args.projectId, activeOnly);\n return {\n count: sessions.length,\n sessions: sessions.map((s) => ({\n id: s.id,\n projectId: s.projectId,\n origin: s.origin,\n url: s.url,\n title: s.title,\n active: s.active,\n lastSeenAt: s.lastSeenAt,\n })),\n };\n }\n\n case 'list_incidents': {\n const incidents = db.listIncidents({\n projectId: args.projectId,\n status: args.status,\n severity: args.severity,\n limit: args.limit || 20,\n });\n return {\n total: incidents.length,\n incidents: incidents.map((inc) => ({\n id: inc.id,\n type: inc.type,\n severity: inc.severity,\n message: inc.message,\n source: `${inc.source.file}:${inc.source.line}`,\n route: inc.route,\n status: inc.status,\n occurrences: inc.occurrences,\n firstSeen: inc.firstSeen,\n lastSeen: inc.lastSeen,\n })),\n };\n }\n\n case 'get_incident': {\n const incident = db.getIncident(args.incidentId);\n if (!incident) {\n throw new Error(`Incident '${args.incidentId}' not found.`);\n }\n\n // Compact breadcrumbs summary (last 10 most relevant)\n const breadcrumbsTimeline = incident.breadcrumbs.slice(-15).map((b) => {\n const time = new Date(b.timestamp).toISOString().split('T')[1]?.slice(0, 8);\n return `[${time}] ${b.message}`;\n });\n\n return {\n id: incident.id,\n status: incident.status,\n type: incident.type,\n severity: incident.severity,\n message: incident.message,\n source: {\n file: incident.source.file,\n line: incident.source.line,\n column: incident.source.column,\n },\n route: incident.route,\n occurrences: incident.occurrences,\n firstSeen: incident.firstSeen,\n lastSeen: incident.lastSeen,\n stack: incident.stack,\n lastInteractedElement: incident.lastElement\n ? {\n selector: incident.lastElement.selector,\n tag: incident.lastElement.tag,\n visible: incident.lastElement.visible,\n innerText: incident.lastElement.innerText,\n outerHTML: incident.lastElement.outerHTML,\n componentSource: incident.lastElement.componentSource,\n }\n : undefined,\n recentBreadcrumbs: breadcrumbsTimeline,\n networkFailures: incident.networkFailures,\n screenshot: incident.screenshots?.error,\n };\n }\n\n case 'get_console': {\n const limit = args.limit || 30;\n const events = db.getEvents({\n sessionId: args.sessionId,\n eventType: 'console',\n limit,\n });\n\n return {\n logs: events.map((e) => ({\n level: e.payload.level,\n message: e.payload.message,\n timestamp: new Date(e.timestamp).toISOString(),\n route: e.route,\n })),\n };\n }\n\n case 'get_network_failures': {\n const limit = args.limit || 20;\n const events = db.getEvents({\n sessionId: args.sessionId,\n limit: 100,\n });\n\n const failures = events\n .filter((e) => (e.eventType === 'fetch' || e.eventType === 'xhr') && (e.payload.status >= 400 || e.payload.error))\n .slice(0, limit)\n .map((e) => ({\n url: e.payload.url,\n method: e.payload.method,\n status: e.payload.status,\n error: e.payload.error,\n durationMs: e.payload.durationMs,\n timestamp: new Date(e.timestamp).toISOString(),\n }));\n\n return { failures };\n }\n\n case 'get_breadcrumbs': {\n if (args.incidentId) {\n const incident = db.getIncident(args.incidentId);\n if (!incident) {\n throw new Error(`Incident '${args.incidentId}' not found.`);\n }\n return {\n incidentId: args.incidentId,\n breadcrumbs: incident.breadcrumbs.slice(-(args.limit || 50)),\n };\n }\n\n const events = db.getEvents({\n sessionId: args.sessionId,\n limit: args.limit || 50,\n });\n\n return {\n breadcrumbs: events.map((e) => ({\n type: e.eventType,\n message: e.payload.message || `${e.eventType} on ${e.route}`,\n timestamp: new Date(e.timestamp).toISOString(),\n route: e.route,\n })),\n };\n }\n\n case 'get_page_state': {\n if (!sessionManager) {\n throw new Error('Live browser connection not available: Daemon session manager not attached.');\n }\n let session = args.sessionId ? db.getSession(args.sessionId) : sessionManager.getAnyActiveSession();\n if (!session) {\n throw new Error('No active browser session connected.');\n }\n\n const cmdRes = await sessionManager.sendCommand(session.id, {\n id: `cmd_mcp_${Date.now()}`,\n type: 'get_page_state',\n });\n\n if (!cmdRes.ok) {\n throw new Error(cmdRes.error || 'Failed to retrieve page state from browser.');\n }\n return cmdRes.result;\n }\n\n case 'capture_element': {\n if (!sessionManager) {\n throw new Error('Live browser connection not available: Daemon session manager not attached.');\n }\n let session = args.sessionId ? db.getSession(args.sessionId) : sessionManager.getAnyActiveSession();\n if (!session) {\n throw new Error('No active browser session connected.');\n }\n\n const cmdRes = await sessionManager.sendCommand(session.id, {\n id: `cmd_mcp_${Date.now()}`,\n type: 'capture_element',\n params: { selector: args.selector },\n });\n\n if (!cmdRes.ok) {\n throw new Error(cmdRes.error || cmdRes.reason || 'Failed to capture element screenshot.');\n }\n return {\n ok: true,\n format: cmdRes.result?.format || 'webp',\n width: cmdRes.result?.width,\n height: cmdRes.result?.height,\n dataUrlPreview: cmdRes.result?.dataUrl ? `${cmdRes.result.dataUrl.slice(0, 100)}...` : undefined,\n };\n }\n\n case 'verify_incident': {\n if (!verificationEngine) {\n throw new Error('Verification engine not available: Daemon session manager not attached.');\n }\n\n const res = await verificationEngine.verifyIncident(args.incidentId, {\n route: args.route,\n targetSelector: args.targetSelector,\n expect: args.expect,\n observationWindowMs: args.observationWindowMs,\n });\n\n return res;\n }\n\n case 'get_verification': {\n const v = db.getLatestVerification(args.incidentId);\n if (!v) {\n throw new Error(`No verification records found for incident '${args.incidentId}'.`);\n }\n return v;\n }\n\n case 'list_notes': {\n const notes = db.listNotes({\n projectId: args.projectId,\n scenarioId: args.scenarioId,\n status: args.status,\n limit: args.limit || 20,\n });\n\n return {\n total: notes.length,\n notes: notes.map((n) => ({\n id: n.id,\n type: n.type,\n status: n.status,\n route: n.route,\n scenarioId: n.scenarioId,\n stepNumber: n.stepNumber,\n scenarioTitle: n.scenarioTitle,\n viewport: `${n.viewport.width} × ${n.viewport.height}`,\n target: n.target?.selector || n.type,\n message: n.message,\n screenshotAvailable: !!n.screenshots?.original,\n createdAt: n.createdAt,\n })),\n };\n }\n\n case 'list_scenarios': {\n const scenarios = db.listScenarios({\n projectId: args.projectId,\n status: args.status,\n limit: args.limit || 20,\n });\n\n return {\n total: scenarios.length,\n scenarios: scenarios.map((s) => ({\n id: s.id,\n title: s.title,\n stepsCount: s.stepsCount,\n status: s.status,\n route: s.route,\n firstStepAt: s.firstStepAt,\n lastStepAt: s.lastStepAt,\n })),\n };\n }\n\n case 'get_scenario': {\n const scenario = db.getScenario(args.scenarioId);\n if (!scenario) {\n throw new Error(`Scenario '${args.scenarioId}' not found.`);\n }\n\n return {\n id: scenario.id,\n title: scenario.title,\n stepsCount: scenario.stepsCount,\n status: scenario.status,\n steps: scenario.steps.map((step) => ({\n id: step.id,\n stepNumber: step.stepNumber,\n type: step.type,\n message: step.message,\n route: step.route,\n url: step.url,\n targetSelector: step.target?.selector,\n boundingRect: step.target?.boundingRect || step.region,\n elementContext: step.elementContext,\n screenshot: step.screenshots?.original,\n status: step.status,\n createdAt: step.createdAt,\n })),\n createdAt: scenario.createdAt,\n updatedAt: scenario.updatedAt,\n };\n }\n\n case 'get_note': {\n const note = db.getNote(args.noteId);\n if (!note) {\n throw new Error(`Visual note '${args.noteId}' not found.`);\n }\n\n const project = db.getProject(note.projectId);\n\n return {\n id: note.id,\n type: note.type,\n status: note.status,\n message: note.message,\n scenarioId: note.scenarioId,\n stepNumber: note.stepNumber,\n scenarioTitle: note.scenarioTitle,\n route: note.route,\n url: note.url,\n viewport: note.viewport,\n scroll: note.scroll,\n target: note.target,\n elementContext: note.elementContext,\n region: note.region,\n screenshot: {\n available: !!note.screenshots?.original,\n original: note.screenshots?.original,\n after: note.screenshots?.after,\n },\n project: project\n ? {\n id: project.id,\n name: project.name,\n origin: project.origin,\n path: project.path,\n }\n : undefined,\n relatedIncidentId: note.incidentId,\n createdAt: note.createdAt,\n updatedAt: note.updatedAt,\n resolvedAt: note.resolvedAt,\n };\n }\n\n case 'resolve_note': {\n const note = db.getNote(args.noteId);\n if (!note) {\n throw new Error(`Visual note '${args.noteId}' not found.`);\n }\n db.updateNoteStatus(args.noteId, 'RESOLVED');\n return {\n ok: true,\n noteId: args.noteId,\n status: 'RESOLVED',\n resolvedAt: new Date().toISOString(),\n };\n }\n\n case 'reopen_note': {\n const note = db.getNote(args.noteId);\n if (!note) {\n throw new Error(`Visual note '${args.noteId}' not found.`);\n }\n db.updateNoteStatus(args.noteId, 'OPEN');\n return {\n ok: true,\n noteId: args.noteId,\n status: 'OPEN',\n };\n }\n\n case 'verify_note': {\n if (!noteVerificationEngine) {\n throw new Error('Note verification engine not available: Daemon session manager not attached.');\n }\n const res = await noteVerificationEngine.verifyNote(args.noteId, {\n observationWindowMs: args.observationWindowMs,\n });\n return res;\n }\n\n case 'get_note_verification': {\n const v = db.getLatestNoteVerification(args.noteId);\n if (!v) {\n throw new Error(`No verification records found for visual note '${args.noteId}'.`);\n }\n return v;\n }\n\n case 'capture_note_context': {\n if (!sessionManager) {\n throw new Error('Live browser connection not available: Daemon session manager not attached.');\n }\n let session = args.sessionId ? db.getSession(args.sessionId) : sessionManager.getAnyActiveSession();\n if (!session) {\n throw new Error('No active browser session connected.');\n }\n\n const queryCmd = await sessionManager.sendCommand(session.id, {\n id: `cmd_ctx_${Date.now()}`,\n type: 'query_element',\n params: { selector: args.selector },\n });\n\n const overflowCmd = await sessionManager.sendCommand(session.id, {\n id: `cmd_ovf_${Date.now()}`,\n type: 'check_overflow',\n params: { selector: args.selector },\n });\n\n const styleCmd = await sessionManager.sendCommand(session.id, {\n id: `cmd_sty_${Date.now()}`,\n type: 'get_element_style',\n params: { selector: args.selector },\n });\n\n return {\n selector: args.selector,\n element: queryCmd.result,\n overflow: overflowCmd.result,\n styles: styleCmd.result?.styles,\n };\n }\n\n default:\n throw new Error(`Unknown MCP tool: ${name}`);\n }\n}\n","import { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';\nimport { getDaemonConfig } from '../../daemon/src/config.js';\nimport { StorageDB } from '../../daemon/src/storage/db.js';\nimport { ScreenshotStore } from '../../daemon/src/storage/screenshot-store.js';\nimport { SessionManager } from '../../daemon/src/session/manager.js';\nimport { NotesEngine } from '../../daemon/src/notes/engine.js';\nimport { NoteVerificationEngine } from '../../daemon/src/notes/verification.js';\nimport { VerificationEngine } from '../../daemon/src/verification/engine.js';\nimport type { McpContext } from './handlers.js';\nimport { handleToolCall } from './handlers.js';\nimport { TOOLS } from './tools.js';\n\nexport interface McpServerOptions {\n dbPath?: string;\n context?: Partial<McpContext>;\n}\n\nexport function createMcpServer(options: McpServerOptions = {}) {\n const config = getDaemonConfig({ dbPath: options.dbPath });\n const db = options.context?.db || new StorageDB(config.dbPath);\n const screenshotStore = new ScreenshotStore(config.screenshotsDir);\n const sessionManager = options.context?.sessionManager || new SessionManager(db);\n const verificationEngine = options.context?.verificationEngine || new VerificationEngine(db, sessionManager, screenshotStore);\n const notesEngine = new NotesEngine(db, screenshotStore);\n const noteVerificationEngine = options.context?.noteVerificationEngine || new NoteVerificationEngine(db, sessionManager, notesEngine);\n\n const ctx: McpContext = {\n db,\n sessionManager,\n verificationEngine,\n noteVerificationEngine,\n daemonUrl: `http://${config.host}:${config.port}`,\n ...options.context,\n };\n\n const server = new Server(\n {\n name: 'browsertrack-mcp',\n version: '0.1.0',\n },\n {\n capabilities: {\n tools: {},\n },\n }\n );\n\n server.setRequestHandler(ListToolsRequestSchema, async () => {\n return { tools: TOOLS };\n });\n\n server.setRequestHandler(CallToolRequestSchema, async (request) => {\n const { name, arguments: args } = request.params;\n try {\n const result = await handleToolCall(name, args || {}, ctx);\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n } catch (err: any) {\n return {\n isError: true,\n content: [\n {\n type: 'text',\n text: `Error executing tool ${name}: ${err?.message || String(err)}`,\n },\n ],\n };\n }\n });\n\n return {\n server,\n async startStdio() {\n const transport = new StdioServerTransport();\n await server.connect(transport);\n },\n };\n}\n"],"mappings":"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","names":[]}