browser-debug-mcp-bridge 1.9.0 → 1.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/README.md +271 -188
  2. package/apps/mcp-server/dist/db/automation-repository.js +199 -0
  3. package/apps/mcp-server/dist/db/automation-repository.js.map +1 -0
  4. package/apps/mcp-server/dist/db/connection.js +1 -5
  5. package/apps/mcp-server/dist/db/connection.js.map +1 -1
  6. package/apps/mcp-server/dist/db/events-repository.js +79 -10
  7. package/apps/mcp-server/dist/db/events-repository.js.map +1 -1
  8. package/apps/mcp-server/dist/db/index.js +2 -0
  9. package/apps/mcp-server/dist/db/index.js.map +1 -1
  10. package/apps/mcp-server/dist/db/migrations.js +493 -0
  11. package/apps/mcp-server/dist/db/migrations.js.map +1 -1
  12. package/apps/mcp-server/dist/db/schema.js +192 -1
  13. package/apps/mcp-server/dist/db/schema.js.map +1 -1
  14. package/apps/mcp-server/dist/document-response-rewriter.js +196 -0
  15. package/apps/mcp-server/dist/document-response-rewriter.js.map +1 -0
  16. package/apps/mcp-server/dist/json-rewrite.js +189 -0
  17. package/apps/mcp-server/dist/json-rewrite.js.map +1 -0
  18. package/apps/mcp-server/dist/main.js +375 -4
  19. package/apps/mcp-server/dist/main.js.map +1 -1
  20. package/apps/mcp-server/dist/mcp/server.js +4168 -310
  21. package/apps/mcp-server/dist/mcp/server.js.map +1 -1
  22. package/apps/mcp-server/dist/mcp-bridge.js +46 -3
  23. package/apps/mcp-server/dist/mcp-bridge.js.map +1 -1
  24. package/apps/mcp-server/dist/next-asset-mapper.js +701 -0
  25. package/apps/mcp-server/dist/next-asset-mapper.js.map +1 -0
  26. package/apps/mcp-server/dist/next-source-override-planner.js +601 -0
  27. package/apps/mcp-server/dist/next-source-override-planner.js.map +1 -0
  28. package/apps/mcp-server/dist/override-audit-contract.js +51 -0
  29. package/apps/mcp-server/dist/override-audit-contract.js.map +1 -0
  30. package/apps/mcp-server/dist/override-audit.js +740 -0
  31. package/apps/mcp-server/dist/override-audit.js.map +1 -0
  32. package/apps/mcp-server/dist/override-capabilities.js +136 -0
  33. package/apps/mcp-server/dist/override-capabilities.js.map +1 -0
  34. package/apps/mcp-server/dist/override-observed-assets.js +179 -0
  35. package/apps/mcp-server/dist/override-observed-assets.js.map +1 -0
  36. package/apps/mcp-server/dist/override-poc.js +336 -0
  37. package/apps/mcp-server/dist/override-poc.js.map +1 -0
  38. package/apps/mcp-server/dist/override-profile-generator.js +403 -0
  39. package/apps/mcp-server/dist/override-profile-generator.js.map +1 -0
  40. package/apps/mcp-server/dist/override-response-planner.js +557 -0
  41. package/apps/mcp-server/dist/override-response-planner.js.map +1 -0
  42. package/apps/mcp-server/dist/override-rule-types.js +32 -0
  43. package/apps/mcp-server/dist/override-rule-types.js.map +1 -0
  44. package/apps/mcp-server/dist/retention.js +4 -3
  45. package/apps/mcp-server/dist/retention.js.map +1 -1
  46. package/apps/mcp-server/dist/rsc-flight-patch-safety.js +269 -0
  47. package/apps/mcp-server/dist/rsc-flight-patch-safety.js.map +1 -0
  48. package/apps/mcp-server/dist/runtime-paths.js +33 -0
  49. package/apps/mcp-server/dist/runtime-paths.js.map +1 -0
  50. package/apps/mcp-server/dist/websocket/messages.js +13 -0
  51. package/apps/mcp-server/dist/websocket/messages.js.map +1 -1
  52. package/apps/mcp-server/dist/websocket/websocket-server.js +10 -0
  53. package/apps/mcp-server/dist/websocket/websocket-server.js.map +1 -1
  54. package/apps/mcp-server/package.json +1 -0
  55. package/package.json +16 -1
  56. package/scripts/mcp-start.cjs +201 -11
@@ -0,0 +1,740 @@
1
+ import { isOverridePocFailureCode, isOverridePlanAuditKind, } from './override-audit-contract.js';
2
+ const DEBUGGER_SETUP_FAILURE_CODES = new Set([
3
+ 'DEBUGGER_ATTACH_FAILED',
4
+ 'DEBUGGER_SETUP_FAILED',
5
+ 'NETWORK_ENABLE_FAILED',
6
+ 'FETCH_ENABLE_FAILED',
7
+ 'CACHE_DISABLE_FAILED',
8
+ 'SERVICE_WORKER_BYPASS_FAILED',
9
+ 'BROWSER_CACHE_CLEAR_FAILED',
10
+ 'TAB_RELOAD_FAILED',
11
+ ]);
12
+ const RSC_FAILURE_CODES = new Set([
13
+ 'RESPONSE_BODY_READ_FAILED',
14
+ 'RSC_PATCH_UNSUPPORTED',
15
+ 'RSC_CONTENT_TYPE_MISMATCH',
16
+ 'RSC_FLIGHT_UNSUPPORTED_RECORD',
17
+ 'RSC_FLIGHT_STRUCTURAL_DRIFT',
18
+ 'RSC_PATCH_ANCHOR_MISMATCH',
19
+ 'RSC_PATCH_UNSAFE',
20
+ ]);
21
+ function parseJsonValue(value) {
22
+ if (!value) {
23
+ return null;
24
+ }
25
+ try {
26
+ return JSON.parse(value);
27
+ }
28
+ catch {
29
+ return null;
30
+ }
31
+ }
32
+ function parseJsonStringArray(value) {
33
+ const parsed = parseJsonValue(value);
34
+ return Array.isArray(parsed)
35
+ ? parsed.filter((entry) => typeof entry === 'string')
36
+ : [];
37
+ }
38
+ function mapRunRow(row) {
39
+ return {
40
+ runId: row.run_id,
41
+ sessionId: row.session_id,
42
+ startedAt: row.started_at,
43
+ endedAt: row.ended_at,
44
+ runStatus: row.run_status,
45
+ tabId: row.tab_id,
46
+ selectedTabId: row.selected_tab_id,
47
+ targetAssetUrl: row.target_asset_url,
48
+ localFilePath: row.local_file_path,
49
+ resolvedLocalFilePath: row.resolved_local_file_path,
50
+ contentType: row.content_type,
51
+ autoReload: row.auto_reload === 1,
52
+ configPath: row.config_path,
53
+ fileExists: row.file_exists === 1,
54
+ fileSizeBytes: row.file_size_bytes,
55
+ matchedRequests: row.matched_requests,
56
+ fulfilledRequests: row.fulfilled_requests,
57
+ lastMatchedAt: row.last_matched_at,
58
+ lastFulfilledAt: row.last_fulfilled_at,
59
+ lastErrorCode: isOverridePocFailureCode(row.last_error_code) ? row.last_error_code : null,
60
+ lastErrorMessage: row.last_error_message,
61
+ };
62
+ }
63
+ function mapPlanAuditRow(row) {
64
+ const plannerKind = isOverridePlanAuditKind(row.planner_kind)
65
+ ? row.planner_kind
66
+ : 'response-patch';
67
+ return {
68
+ planId: row.plan_id,
69
+ sessionId: row.session_id,
70
+ createdAt: row.created_at,
71
+ plannerKind,
72
+ toolName: row.tool_name,
73
+ profileId: row.profile_id,
74
+ ruleId: row.rule_id,
75
+ ruleType: row.rule_type,
76
+ requestMethod: row.request_method,
77
+ matchMode: row.match_mode,
78
+ targetAssetUrl: row.target_asset_url,
79
+ localFilePath: row.local_file_path,
80
+ configPath: row.config_path,
81
+ contentType: row.content_type,
82
+ originalSha256: row.original_sha256,
83
+ patchedSha256: row.patched_sha256,
84
+ originalBytes: row.original_bytes,
85
+ patchedBytes: row.patched_bytes,
86
+ patchSummary: parseJsonValue(row.patch_summary_json),
87
+ preview: parseJsonValue(row.preview_json),
88
+ warnings: parseJsonStringArray(row.warnings_json),
89
+ blockers: parseJsonStringArray(row.blockers_json),
90
+ capturedFromLiveSession: parseJsonValue(row.captured_from_live_session_json),
91
+ rollback: parseJsonValue(row.rollback_json),
92
+ };
93
+ }
94
+ function mapRequestRow(row) {
95
+ return {
96
+ requestLogId: row.request_log_id,
97
+ runId: row.run_id,
98
+ sessionId: row.session_id,
99
+ requestId: row.request_id,
100
+ timestamp: row.ts,
101
+ requestUrl: row.request_url,
102
+ status: row.request_status,
103
+ failureCode: isOverridePocFailureCode(row.failure_code) ? row.failure_code : null,
104
+ errorMessage: row.error_message,
105
+ responseCode: row.response_code,
106
+ };
107
+ }
108
+ function parseCspMetaTags(value) {
109
+ if (!value) {
110
+ return [];
111
+ }
112
+ try {
113
+ const parsed = JSON.parse(value);
114
+ return Array.isArray(parsed)
115
+ ? parsed.filter((entry) => typeof entry === 'string' && entry.trim().length > 0)
116
+ : [];
117
+ }
118
+ catch {
119
+ return [];
120
+ }
121
+ }
122
+ function getObservedAssetDiagnostics(db, sessionId, targetAssetUrl) {
123
+ const rows = db.prepare(`
124
+ SELECT asset_url, last_seen_at, integrity, service_worker_controlled, csp_meta_json
125
+ FROM override_observed_assets
126
+ WHERE session_id = ?
127
+ ORDER BY last_seen_at DESC
128
+ LIMIT 500
129
+ `).all(sessionId);
130
+ const target = rows.find((row) => row.asset_url === targetAssetUrl);
131
+ const cspMetaTags = new Set();
132
+ for (const row of rows) {
133
+ for (const tag of parseCspMetaTags(row.csp_meta_json)) {
134
+ cspMetaTags.add(tag);
135
+ }
136
+ }
137
+ return {
138
+ observedAssetCount: rows.length,
139
+ targetAssetObserved: target !== undefined,
140
+ targetAssetIntegrity: target?.integrity ?? null,
141
+ latestObservedAt: rows.reduce((latest, row) => {
142
+ return latest === null ? row.last_seen_at : Math.max(latest, row.last_seen_at);
143
+ }, null),
144
+ serviceWorkerControlled: rows.some((row) => row.service_worker_controlled === 1),
145
+ cspMetaTagCount: cspMetaTags.size,
146
+ sriAssetCount: rows.filter((row) => typeof row.integrity === 'string' && row.integrity.trim().length > 0).length,
147
+ };
148
+ }
149
+ export function upsertOverridePocRun(db, record) {
150
+ const now = Date.now();
151
+ db.prepare(`
152
+ INSERT INTO override_runs (
153
+ run_id,
154
+ session_id,
155
+ started_at,
156
+ ended_at,
157
+ run_status,
158
+ tab_id,
159
+ selected_tab_id,
160
+ target_asset_url,
161
+ local_file_path,
162
+ resolved_local_file_path,
163
+ content_type,
164
+ auto_reload,
165
+ config_path,
166
+ file_exists,
167
+ file_size_bytes,
168
+ matched_requests,
169
+ fulfilled_requests,
170
+ last_matched_at,
171
+ last_fulfilled_at,
172
+ last_error_code,
173
+ last_error_message,
174
+ created_at,
175
+ updated_at
176
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
177
+ ON CONFLICT(run_id) DO UPDATE SET
178
+ ended_at = excluded.ended_at,
179
+ run_status = excluded.run_status,
180
+ tab_id = excluded.tab_id,
181
+ selected_tab_id = excluded.selected_tab_id,
182
+ target_asset_url = excluded.target_asset_url,
183
+ local_file_path = excluded.local_file_path,
184
+ resolved_local_file_path = excluded.resolved_local_file_path,
185
+ content_type = excluded.content_type,
186
+ auto_reload = excluded.auto_reload,
187
+ config_path = excluded.config_path,
188
+ file_exists = excluded.file_exists,
189
+ file_size_bytes = excluded.file_size_bytes,
190
+ matched_requests = excluded.matched_requests,
191
+ fulfilled_requests = excluded.fulfilled_requests,
192
+ last_matched_at = excluded.last_matched_at,
193
+ last_fulfilled_at = excluded.last_fulfilled_at,
194
+ last_error_code = excluded.last_error_code,
195
+ last_error_message = excluded.last_error_message,
196
+ updated_at = excluded.updated_at
197
+ `).run(record.runId, record.sessionId, record.startedAt, record.endedAt ?? null, record.runStatus, record.tabId, record.selectedTabId ?? null, record.targetAssetUrl, record.localFilePath, record.resolvedLocalFilePath, record.contentType, record.autoReload ? 1 : 0, record.configPath, record.fileExists ? 1 : 0, record.fileSizeBytes ?? null, record.matchedRequests, record.fulfilledRequests, record.lastMatchedAt ?? null, record.lastFulfilledAt ?? null, record.lastErrorCode ?? null, record.lastErrorMessage ?? null, now, now);
198
+ return record;
199
+ }
200
+ export function upsertOverridePocRequest(db, record) {
201
+ const now = Date.now();
202
+ db.prepare(`
203
+ INSERT INTO override_requests (
204
+ request_log_id,
205
+ run_id,
206
+ session_id,
207
+ request_id,
208
+ ts,
209
+ request_url,
210
+ request_status,
211
+ failure_code,
212
+ error_message,
213
+ response_code,
214
+ created_at,
215
+ updated_at
216
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
217
+ ON CONFLICT(request_log_id) DO UPDATE SET
218
+ request_status = excluded.request_status,
219
+ failure_code = excluded.failure_code,
220
+ error_message = excluded.error_message,
221
+ response_code = excluded.response_code,
222
+ updated_at = excluded.updated_at
223
+ `).run(record.requestLogId, record.runId, record.sessionId, record.requestId, record.timestamp, record.requestUrl, record.status, record.failureCode ?? null, record.errorMessage ?? null, record.responseCode ?? null, now, now);
224
+ return record;
225
+ }
226
+ function encodeJson(value) {
227
+ return JSON.stringify(value ?? null);
228
+ }
229
+ export function insertOverridePlanAudit(db, record) {
230
+ const now = Date.now();
231
+ db.prepare(`
232
+ INSERT INTO override_plan_audits (
233
+ plan_id,
234
+ session_id,
235
+ created_at,
236
+ planner_kind,
237
+ tool_name,
238
+ profile_id,
239
+ rule_id,
240
+ rule_type,
241
+ request_method,
242
+ match_mode,
243
+ target_asset_url,
244
+ local_file_path,
245
+ config_path,
246
+ content_type,
247
+ original_sha256,
248
+ patched_sha256,
249
+ original_bytes,
250
+ patched_bytes,
251
+ patch_summary_json,
252
+ preview_json,
253
+ warnings_json,
254
+ blockers_json,
255
+ captured_from_live_session_json,
256
+ rollback_json,
257
+ updated_at
258
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
259
+ ON CONFLICT(plan_id) DO UPDATE SET
260
+ session_id = excluded.session_id,
261
+ planner_kind = excluded.planner_kind,
262
+ tool_name = excluded.tool_name,
263
+ profile_id = excluded.profile_id,
264
+ rule_id = excluded.rule_id,
265
+ rule_type = excluded.rule_type,
266
+ request_method = excluded.request_method,
267
+ match_mode = excluded.match_mode,
268
+ target_asset_url = excluded.target_asset_url,
269
+ local_file_path = excluded.local_file_path,
270
+ config_path = excluded.config_path,
271
+ content_type = excluded.content_type,
272
+ original_sha256 = excluded.original_sha256,
273
+ patched_sha256 = excluded.patched_sha256,
274
+ original_bytes = excluded.original_bytes,
275
+ patched_bytes = excluded.patched_bytes,
276
+ patch_summary_json = excluded.patch_summary_json,
277
+ preview_json = excluded.preview_json,
278
+ warnings_json = excluded.warnings_json,
279
+ blockers_json = excluded.blockers_json,
280
+ captured_from_live_session_json = excluded.captured_from_live_session_json,
281
+ rollback_json = excluded.rollback_json,
282
+ updated_at = excluded.updated_at
283
+ `).run(record.planId, record.sessionId ?? null, record.createdAt, record.plannerKind, record.toolName, record.profileId ?? null, record.ruleId, record.ruleType, record.requestMethod, record.matchMode, record.targetAssetUrl, record.localFilePath ?? null, record.configPath ?? null, record.contentType, record.originalSha256 ?? null, record.patchedSha256 ?? null, record.originalBytes ?? null, record.patchedBytes ?? null, encodeJson(record.patchSummary), record.preview === undefined || record.preview === null ? null : encodeJson(record.preview), encodeJson(record.warnings), encodeJson(record.blockers), record.capturedFromLiveSession === undefined || record.capturedFromLiveSession === null
284
+ ? null
285
+ : encodeJson(record.capturedFromLiveSession), encodeJson(record.rollback), now);
286
+ return record;
287
+ }
288
+ export function listOverridePocRuns(db, sessionId, limit, offset) {
289
+ const rows = db.prepare(`
290
+ SELECT
291
+ run_id,
292
+ session_id,
293
+ started_at,
294
+ ended_at,
295
+ run_status,
296
+ tab_id,
297
+ selected_tab_id,
298
+ target_asset_url,
299
+ local_file_path,
300
+ resolved_local_file_path,
301
+ content_type,
302
+ auto_reload,
303
+ config_path,
304
+ file_exists,
305
+ file_size_bytes,
306
+ matched_requests,
307
+ fulfilled_requests,
308
+ last_matched_at,
309
+ last_fulfilled_at,
310
+ last_error_code,
311
+ last_error_message
312
+ FROM override_runs
313
+ WHERE session_id = ?
314
+ ORDER BY started_at DESC, run_id DESC
315
+ LIMIT ? OFFSET ?
316
+ `).all(sessionId, limit + 1, offset);
317
+ const hasMore = rows.length > limit;
318
+ const page = rows.slice(0, limit).map(mapRunRow);
319
+ return {
320
+ runs: page,
321
+ hasMore,
322
+ nextOffset: hasMore ? offset + limit : null,
323
+ };
324
+ }
325
+ export function listOverridePlanAudits(db, options) {
326
+ const rows = (options.planId
327
+ ? db.prepare(`
328
+ SELECT
329
+ plan_id,
330
+ session_id,
331
+ created_at,
332
+ planner_kind,
333
+ tool_name,
334
+ profile_id,
335
+ rule_id,
336
+ rule_type,
337
+ request_method,
338
+ match_mode,
339
+ target_asset_url,
340
+ local_file_path,
341
+ config_path,
342
+ content_type,
343
+ original_sha256,
344
+ patched_sha256,
345
+ original_bytes,
346
+ patched_bytes,
347
+ patch_summary_json,
348
+ preview_json,
349
+ warnings_json,
350
+ blockers_json,
351
+ captured_from_live_session_json,
352
+ rollback_json
353
+ FROM override_plan_audits
354
+ WHERE session_id = ? AND plan_id = ?
355
+ ORDER BY created_at DESC, plan_id DESC
356
+ LIMIT ? OFFSET ?
357
+ `).all(options.sessionId, options.planId, options.limit + 1, options.offset)
358
+ : db.prepare(`
359
+ SELECT
360
+ plan_id,
361
+ session_id,
362
+ created_at,
363
+ planner_kind,
364
+ tool_name,
365
+ profile_id,
366
+ rule_id,
367
+ rule_type,
368
+ request_method,
369
+ match_mode,
370
+ target_asset_url,
371
+ local_file_path,
372
+ config_path,
373
+ content_type,
374
+ original_sha256,
375
+ patched_sha256,
376
+ original_bytes,
377
+ patched_bytes,
378
+ patch_summary_json,
379
+ preview_json,
380
+ warnings_json,
381
+ blockers_json,
382
+ captured_from_live_session_json,
383
+ rollback_json
384
+ FROM override_plan_audits
385
+ WHERE session_id = ?
386
+ ORDER BY created_at DESC, plan_id DESC
387
+ LIMIT ? OFFSET ?
388
+ `).all(options.sessionId, options.limit + 1, options.offset));
389
+ const hasMore = rows.length > options.limit;
390
+ const page = rows.slice(0, options.limit).map(mapPlanAuditRow);
391
+ return {
392
+ plans: page,
393
+ hasMore,
394
+ nextOffset: hasMore ? options.offset + options.limit : null,
395
+ };
396
+ }
397
+ export function listOverridePocRequests(db, sessionId, limit, offset, runId) {
398
+ const rows = (runId
399
+ ? db.prepare(`
400
+ SELECT
401
+ request_log_id,
402
+ run_id,
403
+ session_id,
404
+ request_id,
405
+ ts,
406
+ request_url,
407
+ request_status,
408
+ failure_code,
409
+ error_message,
410
+ response_code
411
+ FROM override_requests
412
+ WHERE session_id = ? AND run_id = ?
413
+ ORDER BY ts DESC, request_log_id DESC
414
+ LIMIT ? OFFSET ?
415
+ `).all(sessionId, runId, limit + 1, offset)
416
+ : db.prepare(`
417
+ SELECT
418
+ request_log_id,
419
+ run_id,
420
+ session_id,
421
+ request_id,
422
+ ts,
423
+ request_url,
424
+ request_status,
425
+ failure_code,
426
+ error_message,
427
+ response_code
428
+ FROM override_requests
429
+ WHERE session_id = ?
430
+ ORDER BY ts DESC, request_log_id DESC
431
+ LIMIT ? OFFSET ?
432
+ `).all(sessionId, limit + 1, offset));
433
+ const hasMore = rows.length > limit;
434
+ const page = rows.slice(0, limit).map(mapRequestRow);
435
+ return {
436
+ requests: page,
437
+ hasMore,
438
+ nextOffset: hasMore ? offset + limit : null,
439
+ };
440
+ }
441
+ export function diagnoseOverridePoc(db, sessionId, runId) {
442
+ const runRow = (runId
443
+ ? db.prepare(`
444
+ SELECT
445
+ run_id,
446
+ session_id,
447
+ started_at,
448
+ ended_at,
449
+ run_status,
450
+ tab_id,
451
+ selected_tab_id,
452
+ target_asset_url,
453
+ local_file_path,
454
+ resolved_local_file_path,
455
+ content_type,
456
+ auto_reload,
457
+ config_path,
458
+ file_exists,
459
+ file_size_bytes,
460
+ matched_requests,
461
+ fulfilled_requests,
462
+ last_matched_at,
463
+ last_fulfilled_at,
464
+ last_error_code,
465
+ last_error_message
466
+ FROM override_runs
467
+ WHERE session_id = ? AND run_id = ?
468
+ LIMIT 1
469
+ `).get(sessionId, runId)
470
+ : db.prepare(`
471
+ SELECT
472
+ run_id,
473
+ session_id,
474
+ started_at,
475
+ ended_at,
476
+ run_status,
477
+ tab_id,
478
+ selected_tab_id,
479
+ target_asset_url,
480
+ local_file_path,
481
+ resolved_local_file_path,
482
+ content_type,
483
+ auto_reload,
484
+ config_path,
485
+ file_exists,
486
+ file_size_bytes,
487
+ matched_requests,
488
+ fulfilled_requests,
489
+ last_matched_at,
490
+ last_fulfilled_at,
491
+ last_error_code,
492
+ last_error_message
493
+ FROM override_runs
494
+ WHERE session_id = ?
495
+ ORDER BY started_at DESC, run_id DESC
496
+ LIMIT 1
497
+ `).get(sessionId));
498
+ if (!runRow) {
499
+ return {
500
+ sessionId,
501
+ runId: null,
502
+ summary: null,
503
+ indicators: {
504
+ exactUrlMismatch: 'possible',
505
+ cacheOrNoReload: 'possible',
506
+ serviceWorkerInterference: 'possible',
507
+ sriOrCspInterference: 'possible',
508
+ tabSelectionIssue: 'possible',
509
+ debuggerLifecycleIssue: 'possible',
510
+ },
511
+ observedAssets: null,
512
+ issues: [{
513
+ code: 'NO_OVERRIDE_RUNS',
514
+ severity: 'warning',
515
+ message: 'No override audit runs were recorded for this session.',
516
+ suggestedActions: [
517
+ 'Enable the override once for the session before requesting a diagnosis.',
518
+ 'Confirm the extension is pointed at the same local server base URL as the MCP server.',
519
+ ],
520
+ }],
521
+ };
522
+ }
523
+ const run = mapRunRow(runRow);
524
+ const requestFailureRows = db.prepare(`
525
+ SELECT failure_code
526
+ FROM override_requests
527
+ WHERE session_id = ? AND run_id = ? AND request_status = 'failed'
528
+ `).all(sessionId, run.runId);
529
+ const requestFailureCount = requestFailureRows.length;
530
+ const requestFailureCodes = new Set(requestFailureRows
531
+ .map((row) => row.failure_code)
532
+ .filter((value) => isOverridePocFailureCode(value)));
533
+ const issues = [];
534
+ const observedAssets = getObservedAssetDiagnostics(db, sessionId, run.targetAssetUrl);
535
+ let exactUrlMismatch = 'unlikely';
536
+ let cacheOrNoReload = 'unlikely';
537
+ let serviceWorkerInterference = 'unlikely';
538
+ let sriOrCspInterference = 'unlikely';
539
+ let tabSelectionIssue = 'unlikely';
540
+ let debuggerLifecycleIssue = 'unlikely';
541
+ if (run.lastErrorCode === 'CONFIG_DISABLED') {
542
+ issues.push({
543
+ code: 'CONFIG_DISABLED',
544
+ severity: 'error',
545
+ message: 'The override config is disabled, so no replacement can occur.',
546
+ suggestedActions: [
547
+ 'Set `enabled` to `true` in the selected override config file.',
548
+ 'Refresh override status before enabling again.',
549
+ ],
550
+ });
551
+ }
552
+ if (run.lastErrorCode === 'LOCAL_FILE_MISSING') {
553
+ issues.push({
554
+ code: 'LOCAL_FILE_MISSING',
555
+ severity: 'error',
556
+ message: 'The configured local override file was missing when the run started.',
557
+ suggestedActions: [
558
+ 'Fix the local file path in the override config.',
559
+ 'Verify the file exists on disk for the machine running the extension.',
560
+ ],
561
+ });
562
+ }
563
+ if (run.lastErrorCode && DEBUGGER_SETUP_FAILURE_CODES.has(run.lastErrorCode)) {
564
+ debuggerLifecycleIssue = 'observed';
565
+ if (run.lastErrorCode === 'TAB_RELOAD_FAILED') {
566
+ cacheOrNoReload = 'observed';
567
+ }
568
+ if (run.lastErrorCode === 'SERVICE_WORKER_BYPASS_FAILED') {
569
+ serviceWorkerInterference = 'observed';
570
+ }
571
+ issues.push({
572
+ code: run.lastErrorCode,
573
+ severity: 'error',
574
+ message: 'Chrome debugger attach/setup failed before the override was fully armed.',
575
+ suggestedActions: [
576
+ 'Retry after closing any other debugger attached to the same tab.',
577
+ 'Confirm the selected tab is still open, bound to the active session, and can be reloaded.',
578
+ 'If this is repeatable, inspect the precise failure code to see which CDP setup command failed.',
579
+ ],
580
+ });
581
+ }
582
+ if (run.lastErrorCode === 'DEBUGGER_DETACHED') {
583
+ debuggerLifecycleIssue = 'observed';
584
+ issues.push({
585
+ code: 'DEBUGGER_DETACHED',
586
+ severity: 'error',
587
+ message: 'The debugger detached unexpectedly while the override run was active.',
588
+ suggestedActions: [
589
+ 'Retry the run and watch for tab reloads or extension restarts.',
590
+ 'Check whether another debugger client is stealing the tab attachment.',
591
+ ],
592
+ });
593
+ }
594
+ if (observedAssets.observedAssetCount > 0 && !observedAssets.targetAssetObserved) {
595
+ exactUrlMismatch = 'observed';
596
+ issues.push({
597
+ code: 'TARGET_ASSET_NOT_OBSERVED',
598
+ severity: 'warning',
599
+ message: 'The configured target asset URL was not present in the persisted script/style observations for this session.',
600
+ suggestedActions: [
601
+ 'Run `observe_override_assets` on the target route and compare the observed URLs with the override rule.',
602
+ 'Regenerate or update the profile from observed assets before enabling the override.',
603
+ ],
604
+ });
605
+ }
606
+ if (observedAssets.targetAssetIntegrity) {
607
+ sriOrCspInterference = 'observed';
608
+ issues.push({
609
+ code: 'TARGET_ASSET_SRI_PRESENT',
610
+ severity: 'error',
611
+ message: 'The observed target asset has an integrity attribute, so replaced bytes can be rejected by the browser.',
612
+ suggestedActions: [
613
+ 'Remove or rewrite the document integrity attribute before relying on this override.',
614
+ 'Use a target without SRI or keep this override blocked until SRI mitigation exists.',
615
+ ],
616
+ });
617
+ }
618
+ else if (observedAssets.sriAssetCount > 0) {
619
+ sriOrCspInterference = 'possible';
620
+ issues.push({
621
+ code: 'OBSERVED_SRI_ASSETS',
622
+ severity: 'info',
623
+ message: 'Some observed assets use integrity attributes; verify the selected override target is not SRI-protected.',
624
+ suggestedActions: ['Inspect `list_observed_override_assets` before selecting a target asset.'],
625
+ });
626
+ }
627
+ if (observedAssets.cspMetaTagCount > 0) {
628
+ sriOrCspInterference = sriOrCspInterference === 'observed' ? 'observed' : 'possible';
629
+ issues.push({
630
+ code: 'CSP_META_PRESENT',
631
+ severity: 'warning',
632
+ message: 'The page had CSP meta tags when assets were observed; strict policies can block replacement behavior.',
633
+ suggestedActions: [
634
+ 'Review CSP console errors after enabling the override.',
635
+ 'Prefer exact script/style asset replacement over adding new script sources.',
636
+ ],
637
+ });
638
+ }
639
+ if (observedAssets.serviceWorkerControlled) {
640
+ serviceWorkerInterference = 'possible';
641
+ issues.push({
642
+ code: 'SERVICE_WORKER_CONTROLLED_PAGE',
643
+ severity: 'warning',
644
+ message: 'The observed page was controlled by a service worker. Overrides attempt to bypass service workers, but stale registrations can still confuse reload behavior.',
645
+ suggestedActions: [
646
+ 'Hard reload after enabling the override.',
647
+ 'Unregister the service worker in devtools if requests still do not reach the override path.',
648
+ ],
649
+ });
650
+ }
651
+ if (run.matchedRequests === 0) {
652
+ exactUrlMismatch = 'possible';
653
+ cacheOrNoReload = 'possible';
654
+ serviceWorkerInterference = 'possible';
655
+ tabSelectionIssue = 'possible';
656
+ issues.push({
657
+ code: 'NO_REQUEST_MATCHED',
658
+ severity: 'warning',
659
+ message: 'The run never saw a request for the configured target asset URL.',
660
+ suggestedActions: [
661
+ 'Verify the configured URL exactly matches the asset requested by the live page.',
662
+ 'Confirm the selected tab is the one loading the target asset.',
663
+ 'Force a hard reload if the page may already have the asset cached or prefetched.',
664
+ ],
665
+ });
666
+ }
667
+ if (run.matchedRequests > 0 && run.fulfilledRequests === 0) {
668
+ sriOrCspInterference = 'possible';
669
+ issues.push({
670
+ code: 'MATCHED_BUT_NOT_FULFILLED',
671
+ severity: 'warning',
672
+ message: 'The target asset was matched, but no fulfilled response was recorded.',
673
+ suggestedActions: [
674
+ 'Inspect failed override request rows for exact failure codes such as `OVERRIDE_ASSET_FETCH_FAILED`, `FULFILL_FAILED`, or `RSC_PATCH_ANCHOR_MISMATCH`.',
675
+ 'Check the page for integrity or CSP restrictions if the fulfilled asset still does not execute.',
676
+ ],
677
+ });
678
+ }
679
+ if (requestFailureCodes.has('OVERRIDE_ASSET_FETCH_FAILED')) {
680
+ issues.push({
681
+ code: 'OVERRIDE_ASSET_FETCH_FAILED',
682
+ severity: 'error',
683
+ message: 'The extension matched the request but could not fetch local override bytes from the server.',
684
+ suggestedActions: [
685
+ 'Confirm the extension server base URL points at the intended local server.',
686
+ 'Check the override config and local file path served by `/overrides/poc/asset`.',
687
+ ],
688
+ });
689
+ }
690
+ if (requestFailureCodes.has('FULFILL_FAILED')) {
691
+ sriOrCspInterference = 'possible';
692
+ issues.push({
693
+ code: 'FULFILL_FAILED',
694
+ severity: 'error',
695
+ message: 'Chrome accepted the match but the request fulfill step failed.',
696
+ suggestedActions: [
697
+ 'Review the failed request rows and browser console for blocking errors.',
698
+ 'Check for CSP, integrity, or page-specific script loading constraints.',
699
+ ],
700
+ });
701
+ }
702
+ for (const failureCode of RSC_FAILURE_CODES) {
703
+ if (!requestFailureCodes.has(failureCode)) {
704
+ continue;
705
+ }
706
+ issues.push({
707
+ code: failureCode,
708
+ severity: failureCode === 'RSC_PATCH_UNSUPPORTED' ? 'warning' : 'error',
709
+ message: 'A Next.js RSC override request matched, but the live Flight response could not be safely patched.',
710
+ suggestedActions: [
711
+ 'Regenerate the source override plan from the current production route and rebuild the local Next.js app.',
712
+ 'Verify the captured RSC headers, content type, original hash, and literal patch anchors still match the live response.',
713
+ 'Keep the override blocked if the patch would mutate Flight protocol structure instead of literal rendered text.',
714
+ ],
715
+ });
716
+ }
717
+ return {
718
+ sessionId,
719
+ runId: run.runId,
720
+ summary: {
721
+ runStatus: run.runStatus,
722
+ matchedRequests: run.matchedRequests,
723
+ fulfilledRequests: run.fulfilledRequests,
724
+ requestFailureCount,
725
+ lastErrorCode: run.lastErrorCode ?? null,
726
+ lastErrorMessage: run.lastErrorMessage ?? null,
727
+ },
728
+ indicators: {
729
+ exactUrlMismatch,
730
+ cacheOrNoReload,
731
+ serviceWorkerInterference,
732
+ sriOrCspInterference,
733
+ tabSelectionIssue,
734
+ debuggerLifecycleIssue,
735
+ },
736
+ observedAssets,
737
+ issues,
738
+ };
739
+ }
740
+ //# sourceMappingURL=override-audit.js.map