Skip to content

Commit e226890

Browse files
authored
Improve har:view to show info on the spot that was found. (#51)
2 parents 9b299c3 + a6705fc commit e226890

File tree

9 files changed

+286
-127
lines changed

9 files changed

+286
-127
lines changed

.claude/agents/har-fixer.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
---
2+
name: har-fixer
3+
description: Use this agent when you need to fix or improve the detection logic for a specific Gitcasso snapshot by testing changes in the har:view development environment. Examples: <example>Context: User has identified issues with comment spot detection in a specific snapshot and wants to test fixes. user: 'The comment detection is missing some spots in snapshot ABC123, can you help fix the enhancer logic?' assistant: 'I'll use the har-fixer agent to investigate and fix the detection issues in that snapshot.' <commentary>Since the user wants to fix detection logic for a specific snapshot, use the har-fixer agent to run the har:view environment and test changes.</commentary></example> <example>Context: User wants to validate that recent changes to an enhancer are working correctly. user: 'I made some changes to the GitHub enhancer, can you test it against snapshot XYZ789?' assistant: 'Let me use the har-fixer agent to test your enhancer changes against that specific snapshot.' <commentary>The user wants to test enhancer changes against a specific snapshot, so use the har-fixer agent to validate the changes in the har:view environment.</commentary></example>
4+
model: inherit
5+
---
6+
7+
You are an expert Gitcasso snapshot debugging specialist with deep knowledge of browser extension development. You operate exclusively within the `browser-extension` directory and specialize in using the har:view development environment to diagnose and fix detection logic issues.
8+
9+
Your primary workflow:
10+
11+
1. **Environment Setup**: Always start by reading the documentation at the top of the `har-view.ts` file to understand the dev environment.
12+
13+
2. **Launch Development Environment**: Execute `pnpm har:view` to bring up the har:view development environment. Ensure the environment starts successfully before proceeding.
14+
15+
3. **Browser Navigation**: Use the Playwright MCP to interact with the development environment. Navigate to the specific Gitcasso snapshot that needs investigation or fixing.
16+
17+
4. **Code Synchronization**: Always click the button with id `gitcasso-rebuild-btn` to ensure you're testing against the latest code changes. Wait for the rebuild to complete before analyzing results.
18+
19+
5. **Detection Analysis**: Examine the detected spots in the `gitcasso-comment-spots` element. Analyze what spots are being detected, what might be missing, and identify patterns in the detection logic that need improvement.
20+
21+
6. **Enhancer Modification**: Based on your analysis, make targeted changes to the specific enhancer's detection logic. Focus on:
22+
- Improving selector accuracy
23+
- Handling edge cases in the DOM structure
24+
- Optimizing detection algorithms for the specific site pattern
25+
- Ensuring compatibility with dynamic content loading
26+
27+
7. **Iterative Testing**: After making changes, rebuild and test again to validate improvements. Continue this cycle until the detection logic works correctly for the target snapshot.
28+
29+
8. **Documentation**: Clearly explain what issues you found, what changes you made, and why those changes improve the detection logic.
30+
31+
Key principles:
32+
- Always work incrementally - make small, targeted changes and test frequently
33+
- Focus on the specific snapshot mentioned by the user unless told otherwise
34+
- Pay attention to browser console errors and network issues that might affect detection
35+
- Consider how your changes might impact other sites or snapshots
36+
- Be methodical in your debugging approach - document what you try and what results you observe
37+
38+
You have expertise in CSS selectors, DOM manipulation, JavaScript debugging, and understanding how different websites structure their comment systems. Use this knowledge to create robust, reliable detection logic that works across various edge cases.

.claude/commands/finish-wc.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Run `git status` to see the changes in the working copy. Complete whatever tasks are necessary to complete this change. Make sure that `pnpm -r precommit` succeeds. Don't fix `precommit` just be reverting the changes, the goal is to complete the change.

browser-extension/src/entrypoints/content.ts

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ import { EnhancerRegistry, TextareaRegistry } from '../lib/registries'
66
const enhancers = new EnhancerRegistry()
77
const enhancedTextareas = new TextareaRegistry()
88

9+
// Expose for debugging in har:view
10+
;(window as any).gitcassoTextareaRegistry = enhancedTextareas
11+
912
function sendEventToBackground(type: 'ENHANCED' | 'DESTROYED', spot: CommentSpot): void {
1013
const message: CommentEvent = {
1114
spot,
@@ -85,16 +88,20 @@ function enhanceMaybe(textarea: HTMLTextAreaElement) {
8588
logger.debug('activating textarea {}', textarea)
8689
injectStyles()
8790

88-
const enhancedTextarea = enhancers.tryToEnhance(textarea)
89-
if (enhancedTextarea) {
90-
logger.debug(
91-
'Identified textarea:',
92-
enhancedTextarea.spot.type,
93-
enhancedTextarea.spot.unique_key,
94-
)
95-
enhancedTextareas.register(enhancedTextarea)
96-
} else {
97-
logger.debug('No handler found for textarea')
91+
try {
92+
const enhancedTextarea = enhancers.tryToEnhance(textarea)
93+
if (enhancedTextarea) {
94+
logger.debug(
95+
'Identified textarea:',
96+
enhancedTextarea.spot.type,
97+
enhancedTextarea.spot.unique_key,
98+
)
99+
enhancedTextareas.register(enhancedTextarea)
100+
} else {
101+
logger.debug('No handler found for textarea')
102+
}
103+
} catch (e) {
104+
logger.error(e)
98105
}
99106
}
100107

browser-extension/src/lib/enhancers/github/githubIssueAddComment.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ export class GitHubIssueAddCommentEnhancer implements CommentEnhancer<GitHubIssu
2020
return ['GH_ISSUE_ADD_COMMENT']
2121
}
2222

23-
tryToEnhance(_textarea: HTMLTextAreaElement): GitHubIssueAddCommentSpot | null {
23+
tryToEnhance(textarea: HTMLTextAreaElement): GitHubIssueAddCommentSpot | null {
24+
if (textarea.id === 'feedback') {
25+
return null
26+
}
2427
if (document.querySelector('meta[name="hostname"]')?.getAttribute('content') !== 'github.com') {
2528
return null
2629
}
@@ -31,6 +34,7 @@ export class GitHubIssueAddCommentEnhancer implements CommentEnhancer<GitHubIssu
3134
const match = window.location.pathname.match(/^\/([^/]+)\/([^/]+)(?:\/issues\/(\d+))/)
3235
logger.debug(`${this.constructor.name} found match`, window.location.pathname)
3336
if (!match) return null
37+
3438
const [, owner, repo, numberStr] = match
3539
const slug = `${owner}/${repo}`
3640
const number = parseInt(numberStr!, 10)

browser-extension/src/lib/enhancers/github/githubPRNewComment.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ export class GitHubPRNewCommentEnhancer implements CommentEnhancer<GitHubPRNewCo
1616
return ['GH_PR_NEW_COMMENT']
1717
}
1818

19-
tryToEnhance(_textarea: HTMLTextAreaElement): GitHubPRNewCommentSpot | null {
19+
tryToEnhance(textarea: HTMLTextAreaElement): GitHubPRNewCommentSpot | null {
20+
if (textarea.id === 'feedback') {
21+
return null
22+
}
2023
if (document.querySelector('meta[name="hostname"]')?.getAttribute('content') !== 'github.com') {
2124
return null
2225
}

browser-extension/src/lib/registries.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,4 +132,8 @@ export class TextareaRegistry {
132132
get(textarea: HTMLTextAreaElement): EnhancedTextarea | undefined {
133133
return this.textareas.get(textarea)
134134
}
135+
136+
getAllEnhanced(): EnhancedTextarea[] {
137+
return Array.from(this.textareas.values())
138+
}
135139
}

browser-extension/tests/har-view.ts

Lines changed: 96 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@
1414
* - Location patching uses history.pushState to simulate original URLs
1515
* - Chrome APIs are mocked for extension testing outside browser context
1616
* - Extension assets served from `./output/chrome-mv3-dev` via `/chrome-mv3-dev` route
17-
* - Floating rebuild button in gitcasso mode triggers `npx wxt build --mode development` and then refresh
17+
* - Floating rebuild button in gitcasso mode triggers `pnpm run build:dev` and then refresh
18+
* - CommentSpot monitoring panel displays enhanced textareas with spot data and element info
19+
* - Real-time updates every 2 seconds to track textarea enhancement detection and debugging
1820
*/
1921

2022
import { spawn } from 'node:child_process'
@@ -310,7 +312,8 @@ function injectGitcassoScript(key: keyof typeof PAGES, html: string) {
310312
const urlParts = getUrlParts(key)
311313

312314
// Inject patched content script with location patching
313-
const contentScriptTag = `
315+
const contentScriptTag =
316+
`
314317
<script>
315318
// Patch window.location before loading content script
316319
console.log('Patching window.location to simulate original URL...');
@@ -333,27 +336,18 @@ function injectGitcassoScript(key: keyof typeof PAGES, html: string) {
333336
334337
// Replace the problematic webextension-polyfill error check
335338
const patchedCode = code.replace(
336-
/throw new Error\\("This script should only be loaded in a browser extension\\."/g,
337-
'console.warn("Webextension-polyfill check bypassed for HAR testing"'
339+
'throw new Error("This script should only be loaded in a browser extension.")',
340+
'console.warn("Webextension-polyfill check bypassed for HAR testing")'
338341
);
339-
340-
// Mock necessary APIs before executing
341-
window.chrome = window.chrome || {
342-
runtime: {
343-
getURL: (path) => 'chrome-extension://gitcasso-test/' + path,
344-
onMessage: { addListener: () => {} },
345-
sendMessage: () => Promise.resolve(),
346-
id: 'gitcasso-test'
347-
}
348-
};
349-
window.browser = window.chrome;
350-
351-
// Execute the patched script
342+
343+
// Execute the patched script with browser API mocks prepended
344+
const browserMocks = 'window.chrome=window.chrome||{runtime:{getURL:path=>"chrome-extension://gitcasso-test/"+path,onMessage:{addListener:()=>{}},sendMessage:()=>Promise.resolve(),id:"gitcasso-test"}};window.browser=window.chrome;';
352345
const script = document.createElement('script');
353-
script.textContent = patchedCode;
346+
script.textContent = browserMocks + patchedCode;
354347
document.head.appendChild(script);
355-
356-
console.log('Gitcasso content script loaded with location patching for:', '${urlParts.href}');
348+
console.log('Gitcasso content script loaded with location patching for:', '` +
349+
urlParts.href +
350+
`');
357351
})
358352
.catch(error => {
359353
console.error('Failed to load and patch content script:', error);
@@ -442,6 +436,88 @@ function injectGitcassoScript(key: keyof typeof PAGES, html: string) {
442436
});
443437
444438
document.body.appendChild(rebuildButton);
439+
440+
// Create CommentSpot display
441+
const commentSpotDisplay = document.createElement('div');
442+
commentSpotDisplay.id = 'gitcasso-comment-spots';
443+
commentSpotDisplay.style.cssText =
444+
'position: fixed;' +
445+
'top: 80px;' +
446+
'right: 20px;' +
447+
'width: 300px;' +
448+
'max-height: 400px;' +
449+
'background: rgba(255, 255, 255, 0.95);' +
450+
'border: 1px solid #ddd;' +
451+
'border-radius: 8px;' +
452+
'padding: 15px;' +
453+
'font-family: Monaco, Menlo, Ubuntu Mono, monospace;' +
454+
'font-size: 11px;' +
455+
'line-height: 1.4;' +
456+
'overflow-y: auto;' +
457+
'z-index: 999998;' +
458+
'box-shadow: 0 4px 12px rgba(0,0,0,0.2);' +
459+
'backdrop-filter: blur(10px);';
460+
461+
// Simplified display formatting
462+
const styles = {
463+
header: 'font-weight: bold; margin-bottom: 8px; color: #333;',
464+
spotContainer: 'margin-bottom: 12px; padding: 8px; border: 1px solid #eee; border-radius: 4px;',
465+
spotTitle: 'font-weight: bold; color: #555;',
466+
jsonPre: 'margin: 4px 0; font-size: 10px;',
467+
textareaHeader: 'font-weight: bold; color: #007acc; margin-top: 8px;',
468+
textareaPre: 'margin: 4px 0; font-size: 10px; color: #666;',
469+
noInfo: 'color: #999; font-style: italic; margin-top: 4px;',
470+
empty: 'color: #666; font-style: italic;'
471+
};
472+
473+
function formatSpot(enhanced, index) {
474+
const { textarea, spot } = enhanced;
475+
const rect = textarea.getBoundingClientRect();
476+
const textareaInfo = {
477+
id: textarea.id || '',
478+
name: textarea.name || '',
479+
className: textarea.className || '',
480+
tagName: textarea.tagName,
481+
placeholder: textarea.placeholder || '',
482+
value: textarea.value ? textarea.value.substring(0, 50) + '...' : '',
483+
parentElement: textarea.parentElement ? textarea.parentElement.tagName + (textarea.parentElement.className ? '.' + textarea.parentElement.className : '') : '',
484+
position: {
485+
top: rect.top,
486+
left: rect.left,
487+
width: rect.width,
488+
height: rect.height
489+
}
490+
};
491+
492+
return '<div style="' + styles.spotContainer + '">' +
493+
'<div style="' + styles.spotTitle + '">Spot ' + (index + 1) + ':</div>' +
494+
'<pre style="' + styles.jsonPre + '">' + JSON.stringify(spot, null, 2) + '</pre>' +
495+
'<div style="' + styles.textareaHeader + '">Textarea Info:</div>' +
496+
'<pre style="' + styles.textareaPre + '">' + JSON.stringify(textareaInfo, null, 2) + '</pre>' +
497+
'</div>';
498+
}
499+
500+
function updateCommentSpotDisplay() {
501+
const enhanced = window.gitcassoTextareaRegistry ? window.gitcassoTextareaRegistry.getAllEnhanced() : [];
502+
503+
console.log('Enhanced textareas:', enhanced.length);
504+
console.log('All textareas on page:', document.querySelectorAll('textarea').length);
505+
506+
const content = enhanced.length > 0
507+
? '<div style="' + styles.header + '">CommentSpots (' + enhanced.length + '):</div>' +
508+
enhanced.map(formatSpot).join('')
509+
: '<div style="' + styles.empty + '">No CommentSpots detected yet...<br><small>Textareas found: ' + document.querySelectorAll('textarea').length + '</small></div>';
510+
511+
commentSpotDisplay.innerHTML = content;
512+
}
513+
514+
// Initial update
515+
setTimeout(updateCommentSpotDisplay, 100);
516+
517+
// Update display periodically
518+
setInterval(updateCommentSpotDisplay, 2000);
519+
520+
document.body.appendChild(commentSpotDisplay);
445521
</script>
446522
`
447523
if (!html.includes('</body>')) {

0 commit comments

Comments
 (0)