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
23 changes: 16 additions & 7 deletions .github/workflows/agentblame.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ on:
types: [closed]

jobs:
transfer-notes:
post-merge:
# Only run if the PR was merged (not just closed)
if: github.event.pull_request.merged == true
runs-on: ubuntu-latest
Expand All @@ -26,20 +26,29 @@ jobs:
- name: Install dependencies
run: bun install

- name: Fetch attribution notes
- name: Fetch notes, tags, and PR head
run: |
git fetch origin refs/notes/agentblame:refs/notes/agentblame 2>/dev/null || echo "No existing notes"
git fetch origin refs/notes/agentblame:refs/notes/agentblame 2>/dev/null || echo "No existing attribution notes"
git fetch origin refs/notes/agentblame-analytics:refs/notes/agentblame-analytics 2>/dev/null || echo "No existing analytics notes"
git fetch origin --tags 2>/dev/null || echo "No tags to fetch"
git fetch origin refs/pull/${{ github.event.pull_request.number }}/head:refs/pull/${{ github.event.pull_request.number }}/head 2>/dev/null || echo "Could not fetch PR head"

- name: Transfer notes if needed
run: bun run packages/action/src/transfer-notes.ts
- name: Process merge (transfer notes + update analytics)
run: bun run packages/cli/src/post-merge.ts
env:
PR_NUMBER: ${{ github.event.pull_request.number }}
PR_TITLE: ${{ github.event.pull_request.title }}
PR_AUTHOR: ${{ github.event.pull_request.user.login }}
BASE_REF: ${{ github.event.pull_request.base.ref }}
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
MERGE_SHA: ${{ github.event.pull_request.merge_commit_sha }}

- name: Push notes
- name: Push notes and tags
run: |
git push origin refs/notes/agentblame 2>/dev/null || echo "No notes to push"
# Push attribution notes
git push origin refs/notes/agentblame 2>/dev/null || echo "No attribution notes to push"
# Push analytics notes
git push origin refs/notes/agentblame-analytics 2>/dev/null || echo "No analytics notes to push"
# Push analytics anchor tag
git push origin agentblame-analytics-anchor 2>/dev/null || echo "No analytics tag to push"
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,4 @@ agentblame-chrome.zip

# Build artifacts
packages/chrome/agentblame-chrome-*.zip
Implementation.md
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ agentblame/
│ │ └── src/
│ │ ├── lib/ # Core types, utilities, git operations
│ │ ├── capture.ts # Hook handler for Cursor/Claude Code
│ │ ├── transfer-notes.ts # GitHub Action entry point
│ │ ├── post-merge.ts # GitHub Action entry point
│ │ ├── blame.ts # blame command
│ │ ├── sync.ts # sync command
│ │ └── index.ts # CLI entry point
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ agentblame/
│ │ ├── capture.ts
│ │ ├── blame.ts
│ │ ├── sync.ts
│ │ ├── transfer-notes.ts
│ │ ├── post-merge.ts
│ │ └── index.ts
│ └── chrome/ # Chrome extension
└── docs/ # Documentation
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "agentblame",
"displayName": "Agent Blame",
"description": "Track AI-generated vs human-written code. Provides git notes storage, CLI, and GitHub PR attribution.",
"version": "0.1.0",
"version": "0.2.3",
"private": true,
"license": "Apache-2.0",
"repository": {
Expand All @@ -27,7 +27,7 @@
"ab:blame": "bun run packages/cli/src/index.ts blame",
"ab:sync": "bun run packages/cli/src/index.ts sync",
"ab:status": "bun run packages/cli/src/index.ts status",
"ab:transfer-notes": "bun run packages/cli/src/transfer-notes.ts",
"ab:post-merge": "bun run packages/cli/src/post-merge.ts",
"ab:capture": "bun run packages/cli/src/capture.ts",
"cleanup": "bun run packages/cli/src/cleanup.ts",
"logs:clear": "rm -f ~/.agentblame/logs/*.log && echo 'Logs cleared.'"
Expand Down
13 changes: 13 additions & 0 deletions packages/chrome/build-chrome.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ function copyStatic(): void {

// Copy content CSS
copyFileSync(join(SRC_DIR, "content", "content.css"), join(DIST_DIR, "content", "content.css"));
copyFileSync(join(SRC_DIR, "content", "chart.css"), join(DIST_DIR, "content", "chart.css"));

// Copy icons (if they exist)
const iconsDir = join(SRC_DIR, "icons");
Expand Down Expand Up @@ -82,6 +83,18 @@ async function bundle(): Promise<void> {
});
console.log("✓ Bundled content.js");

// Bundle analytics entry script (for repo pages)
await build({
entryPoints: [join(SRC_DIR, "content", "analytics-entry.ts")],
bundle: true,
outfile: join(DIST_DIR, "content", "analytics-entry.js"),
format: "iife",
target: "chrome100",
minify: false,
sourcemap: true,
});
console.log("✓ Bundled analytics-entry.js");

// Bundle background service worker
await build({
entryPoints: [join(SRC_DIR, "background", "background.ts")],
Expand Down
2 changes: 1 addition & 1 deletion packages/chrome/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@agentblame/chrome",
"version": "0.1.1",
"version": "0.2.3",
"description": "Agent Blame Chrome Extension - See AI attribution on GitHub PRs",
"private": true,
"scripts": {
Expand Down
120 changes: 120 additions & 0 deletions packages/chrome/src/content/analytics-entry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/**
* Analytics Entry Point
*
* Content script entry point for GitHub Insights pages.
* Injects the "Agent Blame" item into the Insights sidebar.
*/

import {
isInsightsPage,
injectSidebarItem,
removeSidebarItem,
handleHashChange,
} from "./analytics-tab";

let observer: MutationObserver | null = null;

/**
* Initialize analytics sidebar injection
*/
function init(): void {
console.log("[Agent Blame] Analytics entry loaded on:", window.location.href);
console.log("[Agent Blame] isInsightsPage:", isInsightsPage());

if (isInsightsPage()) {
// Wait a bit for GitHub to fully render the page
setTimeout(() => {
console.log("[Agent Blame] Injecting sidebar item...");
injectSidebarItem();
}, 500);
}

// Watch for DOM changes (GitHub uses dynamic rendering)
setupObserver();

// Handle hash changes for navigation
setupHashListener();

// Handle GitHub's Turbo navigation
setupTurboListener();
}

/**
* Setup MutationObserver for dynamic content
*/
function setupObserver(): void {
if (observer) {
observer.disconnect();
}

observer = new MutationObserver(() => {
if (isInsightsPage()) {
injectSidebarItem();
} else {
removeSidebarItem();
}
});

// Observe the sidebar area for changes
const sidebar = document.querySelector(".Layout-sidebar");
if (sidebar) {
observer.observe(sidebar, { childList: true, subtree: true });
}

// Also observe body for major page changes
observer.observe(document.body, {
childList: true,
subtree: false,
});
}

/**
* Handle hash changes (for #agent-blame navigation)
*/
function setupHashListener(): void {
window.addEventListener("hashchange", () => {
console.log("[Agent Blame] Hash changed to:", window.location.hash);
handleHashChange();
});

// Also handle popstate for back/forward
window.addEventListener("popstate", () => {
console.log("[Agent Blame] Popstate - hash:", window.location.hash);
handleHashChange();
});
}

/**
* Handle GitHub's Turbo Drive navigation
*/
function setupTurboListener(): void {
// Turbo Drive fires these events on navigation
document.addEventListener("turbo:load", () => {
console.log("[Agent Blame] Turbo load");
if (isInsightsPage()) {
setTimeout(() => injectSidebarItem(), 100);
}
});

document.addEventListener("turbo:render", () => {
console.log("[Agent Blame] Turbo render");
if (isInsightsPage()) {
setTimeout(() => injectSidebarItem(), 100);
}
});

// Also handle the older pjax events (some GitHub pages still use these)
document.addEventListener("pjax:end", () => {
console.log("[Agent Blame] PJAX end");
if (isInsightsPage()) {
setTimeout(() => injectSidebarItem(), 100);
}
});
}

// Initialize when DOM is ready
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", init);
} else {
init();
}
Loading