Skip to content
Open
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
4 changes: 4 additions & 0 deletions code-reference-finder/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
OPENROUTER_API_KEY=your_openrouter_api_key
TINYFISH_API_KEY=your_tinyfish_api_key
GITHUB_TOKEN=your_github_personal_access_token
STACKEXCHANGE_KEY=your_stackexchange_api_key
41 changes: 41 additions & 0 deletions code-reference-finder/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*

# env files (can opt-in for committing if needed)
.env*

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
151 changes: 151 additions & 0 deletions code-reference-finder/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
# Code Reference Finder

**Live:** [https://code-reference-finder.vercel.app](https://code-reference-finder.vercel.app)

Code Reference Finder helps you understand unfamiliar code by finding real-world usage examples from GitHub repositories and Stack Overflow. Paste a code snippet (or right-click selected code on GitHub), and it uses AI to analyze the libraries and APIs used, then dispatches web agents to search GitHub and Stack Overflow, extract relevant examples, and display them side-by-side with relevance scores.

## Demo

https://github.com/user-attachments/assets/73feb7c2-60dd-492b-b440-165d0170a4aa


## TinyFish API Usage

The app dispatches 10 parallel TinyFish web agents — 5 for GitHub repos and 5 for Stack Overflow posts. Each agent receives a goal prompt tailored to its platform.

**GitHub agents** navigate the repository and read the README to extract relevant code examples:

```typescript
const response = await fetch("https://agent.tinyfish.ai/v1/automation/run-sse", {
method: "POST",
headers: {
"X-API-Key": process.env.TINYFISH_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
url: "https://github.com/owner/repo",
goal: `You are analyzing a GitHub repository to determine how it relates to specific libraries and APIs.

TARGET LIBRARIES: @tanstack/react-query, axios
TARGET APIs/SYMBOLS: useQuery, axios.get

INSTRUCTIONS:
1. Go to the repository page and read ONLY the README.
2. Extract: what the project does, any code examples shown, and how it relates to the target libraries/APIs.
3. Score relevance 0-100.

Return a JSON object with: title, sourceUrl, platform, relevanceScore, alignmentExplanation, codeSnippets...`,
}),
});
```

**Stack Overflow agents** reason over the post metadata (title, tags, score, excerpt) without navigating:

```typescript
const response = await fetch("https://agent.tinyfish.ai/v1/automation/run-sse", {
method: "POST",
headers: {
"X-API-Key": process.env.TINYFISH_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
url: "https://example.com",
goal: `You are a reasoning agent analyzing a Stack Overflow post.

STACK OVERFLOW POST DATA:
- Title: How to pass parameters to useQuery with Axios
- Score: 38 | Answered: true | Tags: reactjs, axios, react-query

TARGET LIBRARIES: @tanstack/react-query, axios

Score relevance 0-100 based on: Do the tags match? Does the title discuss the target APIs?
Would this post help someone understand how to use these libraries?

Return a JSON object with: title, sourceUrl, platform, relevanceScore, alignmentExplanation, questionTitle, votes, tags...`,
}),
});
```

Both agent types stream SSE events including a `STREAMING_URL` (live view of the agent working) and a final `COMPLETE` event with the extracted reference data JSON.

## How to Run

### Prerequisites

- Node.js 18+
- API keys for: [OpenRouter](https://openrouter.ai/keys), [TinyFish](https://mino.ai/api-keys), [GitHub](https://github.com/settings/tokens), and [Stack Exchange](https://stackapps.com/apps/oauth/register)

### Setup

1. Install dependencies:

```bash
npm install
```

2. Create a `.env.local` file with your API keys (see `.env.example`):

```
OPENROUTER_API_KEY=your_openrouter_api_key
TINYFISH_API_KEY=your_tinyfish_api_key
GITHUB_TOKEN=your_github_personal_access_token
STACKEXCHANGE_KEY=your_stackexchange_api_key
```

3. Start the dev server:

```bash
npm run dev
```

4. Open [http://localhost:3000](http://localhost:3000)

### Chrome Extension (optional)

To use the side panel and right-click context menu on GitHub:

1. Go to `chrome://extensions` and enable Developer mode
2. Click "Load unpacked" and select the `extension/` folder
3. Copy any unknown code and paste it in the input area to start using it.

## Architecture Diagram

```
┌──────────────────────────────────────────────────────────────────┐
│ User (Browser) │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ Next.js Frontend (React + Tailwind + Framer Motion) │ │
│ │ │ │
│ │ 1. Paste code snippet or right-click on GitHub │ │
│ │ 2. View analysis (language, libraries, APIs, patterns) │ │
│ │ 3. Watch agents search & extract in real-time │ │
│ │ 4. Browse results sorted by relevance score │ │
│ └───────────────────────┬────────────────────────────────────┘ │
└──────────────────────────┼───────────────────────────────────────┘
│ POST /api/analyze (SSE stream)
┌──────────────────────────────────────────────────────────────────┐
│ Next.js API Route (SSE) │
│ │
│ Stage 1 — Code Analysis (OpenRouter / Gemini Flash) │
│ • Identifies language, libraries, APIs, patterns │
│ • Generates 10 search queries (5 GitHub + 5 Stack Overflow) │
│ │
│ Stage 2 — Search Execution │
│ • GitHub Search API (5 queries, rate-limited) │
│ • Stack Exchange API (5 queries, parallel) │
│ • Deduplicates and picks top 5 from each platform │
│ │
│ Stage 3 — Agent Extraction (10 parallel TinyFish agents) │
│ • GitHub agents: navigate repo, read README, extract examples │
│ • SO agents: reason over post metadata, score relevance │
│ │
│ Stage 4 — Pipeline Complete │
└────────┬──────────────┬──────────────┬──────────────┬────────────┘
│ │ │ │
▼ ▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌───────────┐ ┌───────────┐
│ OpenRouter│ │ GitHub │ │ Stack │ │ TinyFish │
│ (LLM) │ │ API │ │ Exchange │ │ (Agents) │
└──────────┘ └──────────┘ └───────────┘ └───────────┘
```
25 changes: 25 additions & 0 deletions code-reference-finder/extension/background.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Open side panel when extension icon is clicked
chrome.sidePanel.setPanelBehavior({ openPanelOnActionClick: true });

// Create context menu for selected code
chrome.runtime.onInstalled.addListener(() => {
chrome.contextMenus.create({
id: 'find-references',
title: 'Find References for Selected Code',
contexts: ['selection'],
});
});

// Handle context menu clicks — this IS a valid user gesture, so sidePanel.open works
chrome.contextMenus.onClicked.addListener((info, tab) => {
if (info.menuItemId === 'find-references' && info.selectionText && tab?.id) {
// Store code first
chrome.storage.local.set({
pendingCode: info.selectionText,
pendingTimestamp: Date.now(),
});

// Open side panel (allowed from context menu handler)
chrome.sidePanel.open({ tabId: tab.id });
}
});
16 changes: 16 additions & 0 deletions code-reference-finder/extension/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"manifest_version": 3,
"name": "Code Reference Finder",
"version": "1.0.0",
"description": "Find real-world usage examples for unfamiliar code from GitHub and Stack Overflow",
"permissions": ["sidePanel", "contextMenus", "storage"],
"side_panel": {
"default_path": "sidepanel.html"
},
"background": {
"service_worker": "background.js"
},
"action": {
"default_title": "Code Reference Finder"
}
}
22 changes: 22 additions & 0 deletions code-reference-finder/extension/sidepanel.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Code Reference Finder</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
html, body { width: 100%; height: 100%; overflow: hidden; background: #09090b; }
iframe { width: 100%; height: 100%; border: none; }
</style>
</head>
<body>
<iframe
id="app-frame"
src="https://code-reference-finder.vercel.app"
allow="clipboard-read; clipboard-write"
></iframe>

<script src="sidepanel.js"></script>
</body>
</html>
31 changes: 31 additions & 0 deletions code-reference-finder/extension/sidepanel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const appFrame = document.getElementById('app-frame');
let lastTimestamp = 0;

function injectCode(code) {
appFrame.contentWindow.postMessage(
{ type: 'INJECT_CODE', code: code },
'*'
);
}

// Check for pending code on load (side panel just opened)
appFrame.addEventListener('load', () => {
chrome.storage.local.get(['pendingCode', 'pendingTimestamp'], (data) => {
if (data.pendingCode && data.pendingTimestamp > lastTimestamp) {
lastTimestamp = data.pendingTimestamp;
// Small delay to ensure the Next.js app is ready
setTimeout(() => injectCode(data.pendingCode), 500);
}
});
});

// Watch for new code stored by content script or background
chrome.storage.onChanged.addListener((changes) => {
if (changes.pendingCode && changes.pendingTimestamp) {
const newTimestamp = changes.pendingTimestamp.newValue;
if (newTimestamp > lastTimestamp) {
lastTimestamp = newTimestamp;
injectCode(changes.pendingCode.newValue);
}
}
});
20 changes: 20 additions & 0 deletions code-reference-finder/next.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import type { NextConfig } from 'next';

const nextConfig: NextConfig = {
async headers() {
return [
{
// Allow Chrome extension to embed this app in an iframe
source: '/(.*)',
headers: [
{
key: 'Content-Security-Policy',
value: "frame-ancestors 'self' chrome-extension://*",
},
],
},
];
},
};

export default nextConfig;
Loading