diff --git a/.github/workflows/deploy-edge.yml b/.github/workflows/deploy-edge.yml index bc215cb..40f77a9 100644 --- a/.github/workflows/deploy-edge.yml +++ b/.github/workflows/deploy-edge.yml @@ -113,6 +113,12 @@ jobs: run: | echo "Cleaning up build artifacts..." + # Remove .vite directory (Vite's internal build manifest - not needed) + if [ -d "dist/.vite" ]; then + echo "🗑️ Removing .vite directory..." + rm -rf dist/.vite + fi + # Remove .vitepress directory if it exists if [ -d "dist/.vitepress" ]; then echo "🗑️ Removing .vitepress directory..." @@ -124,20 +130,13 @@ jobs: find dist -name ".DS_Store" -type f -delete 2>/dev/null || true find dist -name "*.log" -type f -delete 2>/dev/null || true - # Verify only one manifest.json exists - MANIFEST_COUNT=$(find dist -name "manifest.json" | wc -l) - echo "Found $MANIFEST_COUNT manifest.json file(s)" - - if [ "$MANIFEST_COUNT" -eq 0 ]; then + # Verify the extension manifest exists (only check root manifest) + if [ ! -f "dist/manifest.json" ]; then echo "❌ ERROR: No manifest.json found in dist/" exit 1 fi - if [ "$MANIFEST_COUNT" -gt 1 ]; then - echo "❌ ERROR: Multiple manifest.json files found:" - find dist -name "manifest.json" - exit 1 - fi + echo "✅ Found dist/manifest.json" # Display build size DIST_SIZE=$(du -sh dist | cut -f1) @@ -167,8 +166,8 @@ jobs: echo "❌ EDGE_CLIENT_ID secret is not set" exit 1 fi - if [ -z "${{ secrets.EDGE_CLIENT_SECRET }}" ]; then - echo "❌ EDGE_CLIENT_SECRET secret is not set" + if [ -z "${{ secrets.EDGE_API_KEY }}" ]; then + echo "❌ EDGE_API_KEY secret is not set" exit 1 fi echo "✅ All secrets are configured" @@ -183,22 +182,30 @@ jobs: - name: 🚀 Upload to Edge Add-ons # Only deploy on push to main (not on PRs) if: github.event_name == 'push' && github.ref == 'refs/heads/main' - uses: AhmedV20/edge-addon@v1 + uses: wdzeng/edge-addon@v2 with: product-id: ${{ secrets.EDGE_PRODUCT_ID }} - client-id: ${{ secrets.EDGE_CLIENT_ID }} - client-secret: ${{ secrets.EDGE_CLIENT_SECRET }} - access-token-url: ${{ secrets.EDGE_ACCESS_TOKEN_URL }} zip-path: ${{ steps.create-zip.outputs.zip-name }} - - - name: ✅ Deployment success + api-key: ${{ secrets.EDGE_API_KEY }} + client-id: ${{ secrets.EDGE_CLIENT_ID }} + upload-only: true + notes-for-certification: | + v${{ needs.validate.outputs.version }} release + - Bug fixes and performance improvements + - CSS isolation fixes + - GitHub API optimization + + GitHub: https://github.com/AhmedV20/codemind + + - name: ✅ Upload success if: success() run: | - echo "✅ Successfully deployed v${{ needs.validate.outputs.version }} to Edge Add-ons!" - echo "🔗 Download artifact from GitHub Actions for manual verification" + echo "✅ Successfully uploaded v${{ needs.validate.outputs.version }} to Edge Add-ons!" + echo "⏳ Publish manually from Edge Partner Center dashboard" + echo "🔗 https://partner.microsoft.com/en-us/dashboard/microsoftedge/overview" - name: ❌ Deployment failed if: failure() run: | - echo "❌ Deployment failed! Check the logs above." + echo "❌ Upload failed! Check the logs above." echo "💡 The build artifact may still be available for manual upload" \ No newline at end of file diff --git a/README.md b/README.md index 0a814ec..486b778 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@
[![Stars](https://img.shields.io/github/stars/AhmedV20/codemind?style=social)](https://github.com/AhmedV20/codemind/stargazers) -[![Version](https://img.shields.io/badge/version-1.1.0-blue)](https://github.com/AhmedV20/codemind/releases) +[![Version](https://img.shields.io/badge/version-1.1.1-blue)](https://github.com/AhmedV20/codemind/releases) [![Build](https://img.shields.io/github/actions/workflow/status/AhmedV20/codemind/ci.yml?label=CI/Build)](https://github.com/AhmedV20/codemind/actions) [![Privacy](https://img.shields.io/badge/Privacy-Protected-green)](PRIVACY.md) [![License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) @@ -27,12 +27,14 @@
+
-Edge +Edge +


-

🔄 Under Review

-

Our Edge extension is currently being reviewed by Microsoft. Check back soon!

+

✅ Available Now

+

Get CodeMind from the Microsoft Edge Add-ons Store!


@@ -56,14 +58,27 @@ ### 💡 What is CodeMind? -CodeMind is a browser extension that uses AI to analyze GitHub repositories. It fetches the repository structure, README, dependencies, and key files, then generates a comprehensive summary explaining what the project does, who it's for, and how to use it. +CodeMind is a powerful browser extension that uses AI to instantly understand any GitHub repository. Simply click a button and get: + +- **Smart Summaries** — Understand what the project does, who it's for, and its key features +- **Code Structure Analysis** — Learn how the codebase is organized +- **Tech Stack Detection** — See all languages, frameworks, and dependencies at a glance +- **Interactive Q&A** — Ask follow-up questions and get detailed answers about any part of the code + + **How to use:** -1. Install the extension from your browser's store (or manually - see the [manual installation](#-manual-installation) guide) +1. Install from the [Edge Add-ons Store](https://microsoftedge.microsoft.com/addons/detail/hfggelncfoaompalbnkgbincglagmbnj) or [manually](#-manual-installation) 2. Navigate to any GitHub repository 3. Click the **CodeMind** button next to the Insights tab -4. Configure your AI provider in the settings panel +4. Configure your AI provider (Gemini, Claude, HuggingFace, or OpenRouter) 5. Click **Analyze Repository** to get your summary --- diff --git a/package-lock.json b/package-lock.json index eedecc0..4e2415a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,19 +1,21 @@ { "name": "codemind", - "version": "1.0.0", + "version": "1.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "codemind", - "version": "1.0.0", + "version": "1.1.0", "dependencies": { "html2canvas": "^1.4.1", "jspdf": "^2.5.2", + "jszip": "^3.10.1", "lucide-react": "^0.469.0", "react": "^18.3.1", "react-dom": "^18.3.1", "react-markdown": "^9.0.1", + "remark-gfm": "^4.0.1", "zustand": "^4.5.5" }, "devDependencies": { @@ -3044,6 +3046,12 @@ "url": "https://opencollective.com/core-js" } }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -4003,6 +4011,12 @@ "node": ">= 4" } }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "license": "MIT" + }, "node_modules/import-fresh": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", @@ -4030,6 +4044,12 @@ "node": ">=0.8.19" } }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, "node_modules/inline-style-parser": { "version": "0.2.7", "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.7.tgz", @@ -4154,6 +4174,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -4269,6 +4295,18 @@ "html2canvas": "^1.0.0-rc.5" } }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "license": "(MIT OR GPL-3.0-or-later)", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -4293,6 +4331,15 @@ "node": ">= 0.8.0" } }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "license": "MIT", + "dependencies": { + "immediate": "~3.0.5" + } + }, "node_modules/lilconfig": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", @@ -4387,6 +4434,44 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, + "node_modules/markdown-table": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", + "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-find-and-replace": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", + "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/mdast-util-from-markdown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz", @@ -4411,6 +4496,107 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/mdast-util-gfm": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", + "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-gfm-autolink-literal": "^2.0.0", + "mdast-util-gfm-footnote": "^2.0.0", + "mdast-util-gfm-strikethrough": "^2.0.0", + "mdast-util-gfm-table": "^2.0.0", + "mdast-util-gfm-task-list-item": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", + "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-find-and-replace": "^3.0.0", + "micromark-util-character": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-strikethrough": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", + "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", + "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/mdast-util-mdx-expression": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", @@ -4619,6 +4805,127 @@ "micromark-util-types": "^2.0.0" } }, + "node_modules/micromark-extension-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", + "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", + "license": "MIT", + "dependencies": { + "micromark-extension-gfm-autolink-literal": "^2.0.0", + "micromark-extension-gfm-footnote": "^2.0.0", + "micromark-extension-gfm-strikethrough": "^2.0.0", + "micromark-extension-gfm-table": "^2.0.0", + "micromark-extension-gfm-tagfilter": "^2.0.0", + "micromark-extension-gfm-task-list-item": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", + "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", + "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", + "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", + "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/micromark-factory-destination": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", @@ -5166,6 +5473,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "license": "(MIT AND Zlib)" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -5512,6 +5825,12 @@ "node": ">= 0.8.0" } }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, "node_modules/property-information": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", @@ -5636,6 +5955,21 @@ "pify": "^2.3.0" } }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -5656,6 +5990,24 @@ "license": "MIT", "optional": true }, + "node_modules/remark-gfm": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz", + "integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-gfm": "^3.0.0", + "micromark-extension-gfm": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/remark-parse": { "version": "11.0.0", "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", @@ -5689,6 +6041,21 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/remark-stringify": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", + "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-to-markdown": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/resolve": { "version": "1.22.11", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", @@ -5791,6 +6158,12 @@ "tslib": "^2.1.0" } }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -5820,6 +6193,12 @@ "node": ">=10" } }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "license": "MIT" + }, "node_modules/sharp": { "version": "0.34.5", "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", @@ -5918,6 +6297,15 @@ "node": ">=0.1.14" } }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/stringify-entities": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", @@ -6390,7 +6778,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true, "license": "MIT" }, "node_modules/utrie": { diff --git a/package.json b/package.json index 3a73cba..ebe3f6c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemind", - "version": "1.1.0", + "version": "1.1.1", "description": "AI-Powered Repository Analyzer for GitHub", "type": "module", "scripts": { @@ -12,10 +12,12 @@ "dependencies": { "html2canvas": "^1.4.1", "jspdf": "^2.5.2", + "jszip": "^3.10.1", "lucide-react": "^0.469.0", "react": "^18.3.1", "react-dom": "^18.3.1", "react-markdown": "^9.0.1", + "remark-gfm": "^4.0.1", "zustand": "^4.5.5" }, "devDependencies": { diff --git a/public/manifest.json b/public/manifest.json index c96d972..336f62a 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 3, "name": "CodeMind - AI Repository Analyzer", - "version": "1.1.0", + "version": "1.1.1", "description": "Understand any GitHub repository in seconds with AI-powered analysis.", "icons": { "16": "icons/icon16.png", @@ -19,7 +19,8 @@ "https://api.anthropic.com/*", "https://generativelanguage.googleapis.com/*", "https://router.huggingface.co/*", - "https://openrouter.ai/*" + "https://openrouter.ai/*", + "https://raw.githubusercontent.com/*" ], "background": { "service_worker": "src/background/index.ts", diff --git a/src/background/api/github.ts b/src/background/api/github.ts index 0666487..6120fb0 100644 --- a/src/background/api/github.ts +++ b/src/background/api/github.ts @@ -8,6 +8,9 @@ import { } from '@shared/types'; import { API_ENDPOINTS } from '@shared/constants'; +// Raw content URL - NOT rate limited like the API! +const RAW_CONTENT_URL = 'https://raw.githubusercontent.com'; + // Key files to fetch for better analysis const KEY_FILES_CONFIG = [ // Package managers / Dependencies @@ -65,6 +68,7 @@ export class GitHubClient { setToken(token: string | null) { this.token = token; + console.log('[GitHubClient] Token set:', token ? `${token.substring(0, 8)}...` : 'null'); } private getHeaders(): HeadersInit { @@ -111,13 +115,24 @@ export class GitHubClient { ); if (!response.ok) { + // Try to get more details from the response body + let errorDetails = ''; + try { + const errorBody = await response.json(); + errorDetails = errorBody.message || ''; + } catch { + errorDetails = response.statusText || `HTTP ${response.status}`; + } + + console.error('[GitHubClient] API error:', response.status, errorDetails); + if (response.status === 404) { throw new Error('Repository not found. It may be private or deleted.'); } if (response.status === 403) { - throw new Error('API rate limit exceeded. Try again later or add a GitHub token.'); + throw new Error(`API rate limit exceeded. ${errorDetails}`); } - throw new Error(`Failed to fetch repository: ${response.statusText}`); + throw new Error(`Failed to fetch repository: ${errorDetails}`); } const data = await response.json(); @@ -142,28 +157,32 @@ export class GitHubClient { } /** - * Fetch README content + * Fetch README content using raw.githubusercontent.com (bypasses API rate limits) */ - async fetchReadme(owner: string, repo: string): Promise { - try { - const response = await fetch( - `${this.baseUrl}/repos/${owner}/${repo}/readme`, - { - headers: { - ...this.getHeaders(), - 'Accept': 'application/vnd.github.v3.raw', - } - } - ); + async fetchReadme(owner: string, repo: string, branch?: string): Promise { + // Try common README filenames using raw URL (NOT rate limited!) + const readmeNames = ['README.md', 'readme.md', 'README.rst', 'README.txt', 'README']; + const branchToUse = branch || 'main'; - if (!response.ok) { - return null; + for (const filename of readmeNames) { + try { + const rawUrl = `${RAW_CONTENT_URL}/${owner}/${repo}/${branchToUse}/${filename}`; + const response = await fetch(rawUrl); + + if (response.ok) { + return await response.text(); + } + } catch { + // Try next filename } + } - return await response.text(); - } catch { - return null; + // Fallback: try 'master' branch if 'main' didn't work + if (branchToUse === 'main') { + return this.fetchReadme(owner, repo, 'master'); } + + return null; } /** @@ -238,19 +257,14 @@ export class GitHubClient { } /** - * Fetch a single file's content + * Fetch a single file's content using raw.githubusercontent.com + * This bypasses API rate limits! */ async fetchFileContent(owner: string, repo: string, branch: string, path: string): Promise { try { - const response = await fetch( - `${this.baseUrl}/repos/${owner}/${repo}/contents/${path}?ref=${branch}`, - { - headers: { - ...this.getHeaders(), - 'Accept': 'application/vnd.github.v3.raw', - } - } - ); + // Use raw.githubusercontent.com - NOT rate limited! + const rawUrl = `${RAW_CONTENT_URL}/${owner}/${repo}/${branch}/${path}`; + const response = await fetch(rawUrl); if (!response.ok) { return null; diff --git a/src/background/api/providers/openrouter.ts b/src/background/api/providers/openrouter.ts index c8ecac8..defc6bc 100644 --- a/src/background/api/providers/openrouter.ts +++ b/src/background/api/providers/openrouter.ts @@ -11,7 +11,7 @@ export class OpenRouterProvider implements AIProvider { private apiKey: string; private model: string; - constructor(apiKey: string, model = 'google/gemini-2.0-flash-exp:free') { + constructor(apiKey: string, model = 'deepseek/deepseek-r1-0528:free') { this.apiKey = apiKey; this.model = model; } diff --git a/src/background/index.ts b/src/background/index.ts index de1849d..1c8cb40 100644 --- a/src/background/index.ts +++ b/src/background/index.ts @@ -51,6 +51,8 @@ chrome.runtime.onMessage.addListener(( case 'SAVE_SETTINGS': if (message.settings) { settingsManager.save(message.settings).then(() => { + // Explicitly clear cache to ensure next read gets fresh data + settingsManager.clearCache(); sendResponse({ success: true }); }).catch(error => { sendResponse({ error: error.message }); diff --git a/src/background/services/analysis.ts b/src/background/services/analysis.ts index 258f1a5..c34631d 100644 --- a/src/background/services/analysis.ts +++ b/src/background/services/analysis.ts @@ -25,10 +25,13 @@ export class AnalysisService { return cached; } - // Get settings - const settings = await settingsManager.get(); + // Force refresh settings to ensure we have the latest token + // This fixes the race condition when user just saved a new GitHub token + const settings = await settingsManager.forceRefresh(); // Set GitHub token if available + const hasGitHubToken = !!(settings.github?.token); + console.log('[AnalysisService] GitHub token available:', hasGitHubToken); if (settings.github?.token) { githubClient.setToken(settings.github.token); } diff --git a/src/background/services/settings.ts b/src/background/services/settings.ts index 25d2824..fcf87bd 100644 --- a/src/background/services/settings.ts +++ b/src/background/services/settings.ts @@ -69,6 +69,14 @@ export class SettingsManager { this.cachedSettings = null; } + /** + * Force refresh settings from storage (clears cache and reloads) + */ + async forceRefresh(): Promise { + this.clearCache(); + return this.get(); + } + private mergeWithDefaults(stored: Partial): ExtensionSettings { return this.deepMerge(DEFAULT_SETTINGS, stored) as ExtensionSettings; } diff --git a/src/content/components/ChatInterface.tsx b/src/content/components/ChatInterface.tsx index 971c101..a194b70 100644 --- a/src/content/components/ChatInterface.tsx +++ b/src/content/components/ChatInterface.tsx @@ -1,5 +1,6 @@ import React, { useState, useRef, useEffect } from 'react'; import ReactMarkdown from 'react-markdown'; +import remarkGfm from 'remark-gfm'; import { Send, X, Loader2, AlertTriangle, RefreshCw } from 'lucide-react'; import { useAnalysisStore } from '../hooks/useAnalysis'; import { SUGGESTED_QUESTIONS } from '@shared/constants'; @@ -29,13 +30,13 @@ const ChatInterface: React.FC = ({ onClose }) => { const inputRef = useRef(null); // Detect rate limit error and show modal - const isRateLimitError = chatError?.includes('rate limit') || chatError?.includes('Rate limit'); + const isGitHubAuthError = chatError?.includes('rate limit') || chatError?.includes('Rate limit'); useEffect(() => { - if (isRateLimitError) { + if (isGitHubAuthError) { setShowRateLimitModal(true); } - }, [isRateLimitError]); + }, [isGitHubAuthError]); // Auto-scroll to bottom useEffect(() => { @@ -175,7 +176,7 @@ const ChatInterface: React.FC = ({ onClose }) => { {parsed.hasThinking && parsed.thinking && ( )} - {parsed.content} + {parsed.content} ); })()} @@ -208,7 +209,7 @@ const ChatInterface: React.FC = ({ onClose }) => { {parsed.hasThinking && parsed.thinking && ( )} - {parsed.content} + {parsed.content} ); })()} @@ -251,7 +252,7 @@ const ChatInterface: React.FC = ({ onClose }) => {
{chatError}
- {isRateLimitError && ( + {isGitHubAuthError && ( )} - {!isRateLimitError && ( + {!isGitHubAuthError && (
); @@ -420,7 +451,7 @@ const HomeTab: React.FC = () => { width: '72px', height: '72px', borderRadius: '20px', - background: isRateLimitError + background: isGitHubAuthError ? 'linear-gradient(135deg, rgba(139, 92, 246, 0.15) 0%, rgba(99, 102, 241, 0.1) 100%)' : 'linear-gradient(135deg, rgba(248, 81, 73, 0.15) 0%, rgba(218, 54, 51, 0.1) 100%)', display: 'flex', @@ -428,7 +459,7 @@ const HomeTab: React.FC = () => { justifyContent: 'center', marginBottom: '20px', }}> - +

{ color: 'var(--gai-text-color)', marginBottom: '8px', }}> - {isRateLimitError ? 'GitHub Rate Limit' : 'Something Went Wrong'} + {isGitHubAuthError ? 'GitHub Rate Limit' : 'Something Went Wrong'}

{ maxWidth: '300px', lineHeight: 1.5, }}> - {isRateLimitError + {isGitHubAuthError ? 'GitHub API rate limit exceeded. Add a token for 5,000 requests/hour or wait ~60 minutes.' : error}

- {isRateLimitError && ( + {isGitHubAuthError && (