Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions .claude/agents/har-fixer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
name: har-fixer
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>
model: inherit
---

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.

Your primary workflow:

1. **Environment Setup**: Always start by reading the documentation at the top of the `har-view.ts` file to understand the dev environment.

2. **Launch Development Environment**: Execute `pnpm har:view` to bring up the har:view development environment. Ensure the environment starts successfully before proceeding.

3. **Browser Navigation**: Use the Playwright MCP to interact with the development environment. Navigate to the specific Gitcasso snapshot that needs investigation or fixing.

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.

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.

6. **Enhancer Modification**: Based on your analysis, make targeted changes to the specific enhancer's detection logic. Focus on:
- Improving selector accuracy
- Handling edge cases in the DOM structure
- Optimizing detection algorithms for the specific site pattern
- Ensuring compatibility with dynamic content loading

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.

8. **Documentation**: Clearly explain what issues you found, what changes you made, and why those changes improve the detection logic.

Key principles:
- Always work incrementally - make small, targeted changes and test frequently
- Focus on the specific snapshot mentioned by the user unless told otherwise
- Pay attention to browser console errors and network issues that might affect detection
- Consider how your changes might impact other sites or snapshots
- Be methodical in your debugging approach - document what you try and what results you observe

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.
1 change: 1 addition & 0 deletions .claude/commands/finish-wc.md
Original file line number Diff line number Diff line change
@@ -0,0 +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.
27 changes: 17 additions & 10 deletions browser-extension/src/entrypoints/content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import { EnhancerRegistry, TextareaRegistry } from '../lib/registries'
const enhancers = new EnhancerRegistry()
const enhancedTextareas = new TextareaRegistry()

// Expose for debugging in har:view
;(window as any).gitcassoTextareaRegistry = enhancedTextareas

function sendEventToBackground(type: 'ENHANCED' | 'DESTROYED', spot: CommentSpot): void {
const message: CommentEvent = {
spot,
Expand Down Expand Up @@ -85,16 +88,20 @@ function enhanceMaybe(textarea: HTMLTextAreaElement) {
logger.debug('activating textarea {}', textarea)
injectStyles()

const enhancedTextarea = enhancers.tryToEnhance(textarea)
if (enhancedTextarea) {
logger.debug(
'Identified textarea:',
enhancedTextarea.spot.type,
enhancedTextarea.spot.unique_key,
)
enhancedTextareas.register(enhancedTextarea)
} else {
logger.debug('No handler found for textarea')
try {
const enhancedTextarea = enhancers.tryToEnhance(textarea)
if (enhancedTextarea) {
logger.debug(
'Identified textarea:',
enhancedTextarea.spot.type,
enhancedTextarea.spot.unique_key,
)
enhancedTextareas.register(enhancedTextarea)
} else {
logger.debug('No handler found for textarea')
}
} catch (e) {
logger.error(e)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ export class GitHubIssueAddCommentEnhancer implements CommentEnhancer<GitHubIssu
return ['GH_ISSUE_ADD_COMMENT']
}

tryToEnhance(_textarea: HTMLTextAreaElement): GitHubIssueAddCommentSpot | null {
tryToEnhance(textarea: HTMLTextAreaElement): GitHubIssueAddCommentSpot | null {
if (textarea.id === 'feedback') {
return null
}
if (document.querySelector('meta[name="hostname"]')?.getAttribute('content') !== 'github.com') {
return null
}
Expand All @@ -31,6 +34,7 @@ export class GitHubIssueAddCommentEnhancer implements CommentEnhancer<GitHubIssu
const match = window.location.pathname.match(/^\/([^/]+)\/([^/]+)(?:\/issues\/(\d+))/)
logger.debug(`${this.constructor.name} found match`, window.location.pathname)
if (!match) return null

const [, owner, repo, numberStr] = match
const slug = `${owner}/${repo}`
const number = parseInt(numberStr!, 10)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ export class GitHubPRNewCommentEnhancer implements CommentEnhancer<GitHubPRNewCo
return ['GH_PR_NEW_COMMENT']
}

tryToEnhance(_textarea: HTMLTextAreaElement): GitHubPRNewCommentSpot | null {
tryToEnhance(textarea: HTMLTextAreaElement): GitHubPRNewCommentSpot | null {
if (textarea.id === 'feedback') {
return null
}
if (document.querySelector('meta[name="hostname"]')?.getAttribute('content') !== 'github.com') {
return null
}
Expand Down
4 changes: 4 additions & 0 deletions browser-extension/src/lib/registries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,4 +132,8 @@ export class TextareaRegistry {
get(textarea: HTMLTextAreaElement): EnhancedTextarea | undefined {
return this.textareas.get(textarea)
}

getAllEnhanced(): EnhancedTextarea[] {
return Array.from(this.textareas.values())
}
}
116 changes: 96 additions & 20 deletions browser-extension/tests/har-view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
* - Location patching uses history.pushState to simulate original URLs
* - Chrome APIs are mocked for extension testing outside browser context
* - Extension assets served from `./output/chrome-mv3-dev` via `/chrome-mv3-dev` route
* - Floating rebuild button in gitcasso mode triggers `npx wxt build --mode development` and then refresh
* - Floating rebuild button in gitcasso mode triggers `pnpm run build:dev` and then refresh
* - CommentSpot monitoring panel displays enhanced textareas with spot data and element info
* - Real-time updates every 2 seconds to track textarea enhancement detection and debugging
*/

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

// Inject patched content script with location patching
const contentScriptTag = `
const contentScriptTag =
`
<script>
// Patch window.location before loading content script
console.log('Patching window.location to simulate original URL...');
Expand All @@ -333,27 +336,18 @@ function injectGitcassoScript(key: keyof typeof PAGES, html: string) {

// Replace the problematic webextension-polyfill error check
const patchedCode = code.replace(
/throw new Error\\("This script should only be loaded in a browser extension\\."/g,
'console.warn("Webextension-polyfill check bypassed for HAR testing"'
'throw new Error("This script should only be loaded in a browser extension.")',
'console.warn("Webextension-polyfill check bypassed for HAR testing")'
);

// Mock necessary APIs before executing
window.chrome = window.chrome || {
runtime: {
getURL: (path) => 'chrome-extension://gitcasso-test/' + path,
onMessage: { addListener: () => {} },
sendMessage: () => Promise.resolve(),
id: 'gitcasso-test'
}
};
window.browser = window.chrome;

// Execute the patched script

// Execute the patched script with browser API mocks prepended
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;';
const script = document.createElement('script');
script.textContent = patchedCode;
script.textContent = browserMocks + patchedCode;
document.head.appendChild(script);

console.log('Gitcasso content script loaded with location patching for:', '${urlParts.href}');
console.log('Gitcasso content script loaded with location patching for:', '` +
urlParts.href +
`');
})
.catch(error => {
console.error('Failed to load and patch content script:', error);
Expand Down Expand Up @@ -442,6 +436,88 @@ function injectGitcassoScript(key: keyof typeof PAGES, html: string) {
});

document.body.appendChild(rebuildButton);

// Create CommentSpot display
const commentSpotDisplay = document.createElement('div');
commentSpotDisplay.id = 'gitcasso-comment-spots';
commentSpotDisplay.style.cssText =
'position: fixed;' +
'top: 80px;' +
'right: 20px;' +
'width: 300px;' +
'max-height: 400px;' +
'background: rgba(255, 255, 255, 0.95);' +
'border: 1px solid #ddd;' +
'border-radius: 8px;' +
'padding: 15px;' +
'font-family: Monaco, Menlo, Ubuntu Mono, monospace;' +
'font-size: 11px;' +
'line-height: 1.4;' +
'overflow-y: auto;' +
'z-index: 999998;' +
'box-shadow: 0 4px 12px rgba(0,0,0,0.2);' +
'backdrop-filter: blur(10px);';

// Simplified display formatting
const styles = {
header: 'font-weight: bold; margin-bottom: 8px; color: #333;',
spotContainer: 'margin-bottom: 12px; padding: 8px; border: 1px solid #eee; border-radius: 4px;',
spotTitle: 'font-weight: bold; color: #555;',
jsonPre: 'margin: 4px 0; font-size: 10px;',
textareaHeader: 'font-weight: bold; color: #007acc; margin-top: 8px;',
textareaPre: 'margin: 4px 0; font-size: 10px; color: #666;',
noInfo: 'color: #999; font-style: italic; margin-top: 4px;',
empty: 'color: #666; font-style: italic;'
};

function formatSpot(enhanced, index) {
const { textarea, spot } = enhanced;
const rect = textarea.getBoundingClientRect();
const textareaInfo = {
id: textarea.id || '',
name: textarea.name || '',
className: textarea.className || '',
tagName: textarea.tagName,
placeholder: textarea.placeholder || '',
value: textarea.value ? textarea.value.substring(0, 50) + '...' : '',
parentElement: textarea.parentElement ? textarea.parentElement.tagName + (textarea.parentElement.className ? '.' + textarea.parentElement.className : '') : '',
position: {
top: rect.top,
left: rect.left,
width: rect.width,
height: rect.height
}
};

return '<div style="' + styles.spotContainer + '">' +
'<div style="' + styles.spotTitle + '">Spot ' + (index + 1) + ':</div>' +
'<pre style="' + styles.jsonPre + '">' + JSON.stringify(spot, null, 2) + '</pre>' +
'<div style="' + styles.textareaHeader + '">Textarea Info:</div>' +
'<pre style="' + styles.textareaPre + '">' + JSON.stringify(textareaInfo, null, 2) + '</pre>' +
'</div>';
}

function updateCommentSpotDisplay() {
const enhanced = window.gitcassoTextareaRegistry ? window.gitcassoTextareaRegistry.getAllEnhanced() : [];

console.log('Enhanced textareas:', enhanced.length);
console.log('All textareas on page:', document.querySelectorAll('textarea').length);

const content = enhanced.length > 0
? '<div style="' + styles.header + '">CommentSpots (' + enhanced.length + '):</div>' +
enhanced.map(formatSpot).join('')
: '<div style="' + styles.empty + '">No CommentSpots detected yet...<br><small>Textareas found: ' + document.querySelectorAll('textarea').length + '</small></div>';

commentSpotDisplay.innerHTML = content;
}

// Initial update
setTimeout(updateCommentSpotDisplay, 100);

// Update display periodically
setInterval(updateCommentSpotDisplay, 2000);

document.body.appendChild(commentSpotDisplay);
</script>
`
if (!html.includes('</body>')) {
Expand Down
Loading