From 69d01588070d0f86f0c9ddfed67f382ddaf8ebd2 Mon Sep 17 00:00:00 2001 From: Archit Mittal Date: Fri, 12 Jun 2026 22:46:48 +0530 Subject: [PATCH 1/3] chore: add issue tracker with first 2 critical issues opened --- ISSUES.md | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 ISSUES.md diff --git a/ISSUES.md b/ISSUES.md new file mode 100644 index 0000000..6931a25 --- /dev/null +++ b/ISSUES.md @@ -0,0 +1,47 @@ +# AutoMaintainer β€” Issue Tracker + +A living document tracking all identified bugs and enhancements. +Open 2–3 issues daily, work on them, and mark progress here. + +Legend: `[ ]` = Not opened | `[o]` = Opened on GitHub | `[/]` = In Progress | `[x]` = Resolved + +--- + +## πŸ”΄ Critical Bugs + +| # | Title | Priority | Status | Fork Issue | Upstream Issue | +|---|-------|----------|--------|------------|----------------| +| 1 | CORS misconfiguration blocks Hugging Face deployments | P0 | `[o]` | [#2](https://github.com/archittmittal/AutoMaintainer/issues/2) | [#51](https://github.com/PxA-Labs/AutoMaintainer/issues/51) | +| 2 | Implementer commits dummy code instead of real file changes | P0 | `[o]` | [#3](https://github.com/archittmittal/AutoMaintainer/issues/3) | [#52](https://github.com/PxA-Labs/AutoMaintainer/issues/52) | +| 3 | `/tmp` repo clones never cleaned up β€” disk exhaustion | P1 | `[ ]` | β€” | β€” | +| 4 | Log stream has no auto-scroll | P1 | `[ ]` | β€” | β€” | + +--- + +## 🟑 UX Enhancements + +| # | Title | Priority | Status | Fork Issue | Upstream Issue | +|---|-------|----------|--------|------------|----------------| +| 5 | System Health widget shows hardcoded fake metrics | P2 | `[ ]` | β€” | β€” | +| 6 | Refreshing page wipes all session logs & pipeline state | P2 | `[ ]` | β€” | β€” | +| 7 | Rate-limit error strings get committed to GitHub as code | P1 | `[ ]` | β€” | β€” | +| 8 | Interactive Terminal only accessible from Web IDE tab | P2 | `[ ]` | β€” | β€” | +| 9 | WebIDE shows confusing error before agents clone the repo | P2 | `[ ]` | β€” | β€” | +| 10 | Brainstormer always creates Issues with generic title | P2 | `[ ]` | β€” | β€” | + +--- + +## πŸ”΅ Infra / Security + +| # | Title | Priority | Status | Fork Issue | Upstream Issue | +|---|-------|----------|--------|------------|----------------| +| 11 | Dockerfile pins `gitnexus@latest` β€” non-reproducible builds | P2 | `[ ]` | β€” | β€” | +| 12 | No input validation on `repo_name` in `/start` β€” SSRF risk | P1 | `[ ]` | β€” | β€” | + +--- + +## Daily Log + +| Date | Issues Opened | Issues Resolved | +|------|---------------|-----------------| +| 2026-06-12 | Fork [#2](https://github.com/archittmittal/AutoMaintainer/issues/2), [#3](https://github.com/archittmittal/AutoMaintainer/issues/3) Β· Upstream [#51](https://github.com/PxA-Labs/AutoMaintainer/issues/51), [#52](https://github.com/PxA-Labs/AutoMaintainer/issues/52) | β€” | From 754164186a42fc8a6d056a0c15ad3dca0d10536d Mon Sep 17 00:00:00 2001 From: Archit Mittal Date: Mon, 10 Aug 2026 18:36:10 +0530 Subject: [PATCH 2/3] fix: resolve lost websocket logs, missing agent loop cancellation, and webide port mismatch --- backend/agents.py | 58 ++- backend/main.py | 4 + dashboard/package-lock.json | 84 ---- dashboard/src/app/page.tsx | 4 +- .../src/components/InteractiveTerminal.tsx | 3 +- dashboard/src/components/WebIDE.tsx | 2 +- generate_ppt.py | 361 +++++++++++++----- patch_comments.py | 12 +- test_groq.py | 12 +- 9 files changed, 332 insertions(+), 208 deletions(-) diff --git a/backend/agents.py b/backend/agents.py index bb18f53..c432e33 100644 --- a/backend/agents.py +++ b/backend/agents.py @@ -988,25 +988,45 @@ async def run_agent_loop( ) last_idx = 0 - async for state in app.astream(initial_state, stream_mode="values"): + try: + async for state in app.astream(initial_state, stream_mode="values"): - new_msgs = state["log_messages"][last_idx:] - for msg in new_msgs: - await broadcast_log(msg) - await asyncio.sleep(0.5) + new_msgs = state["log_messages"][last_idx:] + for msg in new_msgs: + await broadcast_log(msg) + await asyncio.sleep(0.5) - last_idx = len(state["log_messages"]) + last_idx = len(state["log_messages"]) - await broadcast_log( - {"agent": "System", "msg": "Agent loop complete.", "color": "text-zinc-500"} - ) - if supabase: - try: - await asyncio.to_thread( - lambda: supabase.table("runs") - .update({"status": "completed"}) - .eq("id", run_id) - .execute() - ) - except Exception as e: - print(f"Failed to update run status in Supabase: {e}") + await broadcast_log( + {"agent": "System", "msg": "Agent loop complete.", "color": "text-zinc-500"} + ) + if supabase: + try: + await asyncio.to_thread( + lambda: supabase.table("runs") + .update({"status": "completed"}) + .eq("id", run_id) + .execute() + ) + except Exception as e: + print(f"Failed to update run status in Supabase: {e}") + except asyncio.CancelledError: + await broadcast_log( + { + "agent": "System", + "msg": "Agent loop cancelled by user.", + "color": "text-red-500", + } + ) + if supabase: + try: + await asyncio.to_thread( + lambda: supabase.table("runs") + .update({"status": "failed"}) + .eq("id", run_id) + .execute() + ) + except Exception as e: + print(f"Failed to update run status in Supabase: {e}") + raise diff --git a/backend/main.py b/backend/main.py index 345d517..91f4dcc 100644 --- a/backend/main.py +++ b/backend/main.py @@ -241,6 +241,10 @@ async def stop_agents(): global active_task if active_task and not active_task.done(): active_task.cancel() + try: + await active_task + except asyncio.CancelledError: + pass active_task = None return {"status": "stopped"} return {"status": "not_running"} diff --git a/dashboard/package-lock.json b/dashboard/package-lock.json index a5a1c16..f5a039f 100644 --- a/dashboard/package-lock.json +++ b/dashboard/package-lock.json @@ -649,9 +649,6 @@ "cpu": [ "arm" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -668,9 +665,6 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -687,9 +681,6 @@ "cpu": [ "ppc64" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -706,9 +697,6 @@ "cpu": [ "riscv64" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -725,9 +713,6 @@ "cpu": [ "s390x" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -744,9 +729,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -763,9 +745,6 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -782,9 +761,6 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -801,9 +777,6 @@ "cpu": [ "arm" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -826,9 +799,6 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -851,9 +821,6 @@ "cpu": [ "ppc64" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -876,9 +843,6 @@ "cpu": [ "riscv64" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -901,9 +865,6 @@ "cpu": [ "s390x" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -926,9 +887,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -951,9 +909,6 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -976,9 +931,6 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1244,9 +1196,6 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1263,9 +1212,6 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1282,9 +1228,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1301,9 +1244,6 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1634,9 +1574,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1654,9 +1591,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1674,9 +1608,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1694,9 +1625,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -5315,9 +5243,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -5339,9 +5264,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -5363,9 +5285,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -5387,9 +5306,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ diff --git a/dashboard/src/app/page.tsx b/dashboard/src/app/page.tsx index 54b5ec8..f160875 100644 --- a/dashboard/src/app/page.tsx +++ b/dashboard/src/app/page.tsx @@ -32,8 +32,8 @@ function getBackendUrl(): string { if (typeof window !== "undefined") { const port = window.location.port; const hostname = window.location.hostname; - // If frontend is on the standard Next.js dev port, point to the FastAPI port - if (port === "3000") { + // In local dev (Next.js can run on 3000, 3001, etc. but FastAPI runs on 8000) + if ((hostname === "localhost" || hostname === "127.0.0.1") && port !== "8000") { return `${window.location.protocol}//${hostname}:8000`; } // Otherwise (production / Docker), same host serves both diff --git a/dashboard/src/components/InteractiveTerminal.tsx b/dashboard/src/components/InteractiveTerminal.tsx index 0781d35..568839d 100644 --- a/dashboard/src/components/InteractiveTerminal.tsx +++ b/dashboard/src/components/InteractiveTerminal.tsx @@ -41,14 +41,13 @@ export default function InteractiveTerminal({ repoUrl }: InteractiveTerminalProp terminalInstance.current = term; fitAddon.current = fit; - // Build the WebSocket URL let backendUrl = "http://localhost:8000"; if (process.env.NEXT_PUBLIC_BACKEND_URL) { backendUrl = process.env.NEXT_PUBLIC_BACKEND_URL.replace(/\/$/, ""); } else if (typeof window !== "undefined") { const port = window.location.port; const hostname = window.location.hostname; - if (port === "3000") { + if ((hostname === "localhost" || hostname === "127.0.0.1") && port !== "8000") { backendUrl = `${window.location.protocol}//${hostname}:8000`; } else { backendUrl = `${window.location.protocol}//${window.location.host}`; diff --git a/dashboard/src/components/WebIDE.tsx b/dashboard/src/components/WebIDE.tsx index 4407fe0..ce316e6 100644 --- a/dashboard/src/components/WebIDE.tsx +++ b/dashboard/src/components/WebIDE.tsx @@ -137,7 +137,7 @@ function getBackendUrl(): string { if (typeof window !== "undefined") { const port = window.location.port; const hostname = window.location.hostname; - if (port === "3000") { + if ((hostname === "localhost" || hostname === "127.0.0.1") && port !== "8000") { return `${window.location.protocol}//${hostname}:8000`; } return `${window.location.protocol}//${window.location.host}`; diff --git a/generate_ppt.py b/generate_ppt.py index 71e9838..5bb51a2 100644 --- a/generate_ppt.py +++ b/generate_ppt.py @@ -4,19 +4,20 @@ from pptx.enum.text import PP_ALIGN from pptx.enum.shapes import MSO_SHAPE + def create_presentation(): prs = Presentation() - + # Standard 16:9 Aspect Ratio prs.slide_width = Inches(13.333) prs.slide_height = Inches(7.5) - + # Color Palette - primary_color = RGBColor(15, 23, 42) # Slate 900 - accent_color = RGBColor(79, 70, 229) # Indigo 600 - text_dark = RGBColor(30, 41, 59) # Slate 800 - text_light = RGBColor(100, 116, 139) # Slate 500 - success_color = RGBColor(16, 185, 129) # Emerald 500 + primary_color = RGBColor(15, 23, 42) # Slate 900 + accent_color = RGBColor(79, 70, 229) # Indigo 600 + text_dark = RGBColor(30, 41, 59) # Slate 800 + text_light = RGBColor(100, 116, 139) # Slate 500 + success_color = RGBColor(16, 185, 129) # Emerald 500 def style_title(shape, text, size=Pt(40)): shape.text = text @@ -26,7 +27,7 @@ def style_title(shape, text, size=Pt(40)): p.font.size = size p.font.color.rgb = primary_color p.alignment = PP_ALIGN.LEFT - + def add_bullet(tf, text, level=0, bold=False, size=Pt(20), color=text_dark): p = tf.add_paragraph() p.text = text @@ -39,13 +40,15 @@ def add_bullet(tf, text, level=0, bold=False, size=Pt(20), color=text_dark): def create_content_slide(title_text): slide = prs.slides.add_slide(prs.slide_layouts[5]) style_title(slide.shapes.title, title_text) - + # Add a sleek underline beneath the title - line = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, Inches(0.5), Inches(1.2), Inches(12.333), Inches(0.05)) + line = slide.shapes.add_shape( + MSO_SHAPE.RECTANGLE, Inches(0.5), Inches(1.2), Inches(12.333), Inches(0.05) + ) line.fill.solid() line.fill.fore_color.rgb = accent_color line.line.color.rgb = accent_color - + return slide # ========================================== @@ -54,12 +57,12 @@ def create_content_slide(title_text): slide = prs.slides.add_slide(prs.slide_layouts[0]) title = slide.shapes.title subtitle = slide.placeholders[1] - + title.text = "AutoMaintainer" title.text_frame.paragraphs[0].font.color.rgb = primary_color title.text_frame.paragraphs[0].font.bold = True title.text_frame.paragraphs[0].font.size = Pt(64) - + subtitle.text = "An Always-On Autonomous AI Software Engineering Team\n\nHackathon Theme: Agentic and Autonomous Systems" subtitle.text_frame.paragraphs[0].font.color.rgb = accent_color subtitle.text_frame.paragraphs[0].font.bold = True @@ -69,76 +72,165 @@ def create_content_slide(title_text): # Slide 2: Theme Alignment # ========================================== slide = create_content_slide("Theme Alignment: Think, Decide, Act") - + txBox = slide.shapes.add_textbox(Inches(0.5), Inches(1.5), Inches(12), Inches(5)) tf = txBox.text_frame - - add_bullet(tf, "🧠 THINKS (Context & Logic)", level=0, bold=True, size=Pt(28), color=accent_color) - add_bullet(tf, "Uses GitNexus MCP for zero-server semantic codebase ingestion.", level=1) - add_bullet(tf, "Architect Agent deeply analyzes file trees and architectures before any action.", level=1) - - add_bullet(tf, "βš–οΈ DECIDES (Agentic Reasoning)", level=0, bold=True, size=Pt(28), color=accent_color) - add_bullet(tf, "Reviewer Agent acts as a PM, independently evaluating feature proposals against strict directives.", level=1) - add_bullet(tf, "Maintainer Agent acts as QA, choosing to approve (LGTM) or reject and loop Pull Requests based on bugs.", level=1) - - add_bullet(tf, "⚑ ACTS (Independent Execution)", level=0, bold=True, size=Pt(28), color=accent_color) - add_bullet(tf, "Operates natively via PyGithub to open Issues, write code, branch, commit, and mergeβ€”100% hands-free.", level=1) + + add_bullet( + tf, + "🧠 THINKS (Context & Logic)", + level=0, + bold=True, + size=Pt(28), + color=accent_color, + ) + add_bullet( + tf, "Uses GitNexus MCP for zero-server semantic codebase ingestion.", level=1 + ) + add_bullet( + tf, + "Architect Agent deeply analyzes file trees and architectures before any action.", + level=1, + ) + + add_bullet( + tf, + "βš–οΈ DECIDES (Agentic Reasoning)", + level=0, + bold=True, + size=Pt(28), + color=accent_color, + ) + add_bullet( + tf, + "Reviewer Agent acts as a PM, independently evaluating feature proposals against strict directives.", + level=1, + ) + add_bullet( + tf, + "Maintainer Agent acts as QA, choosing to approve (LGTM) or reject and loop Pull Requests based on bugs.", + level=1, + ) + + add_bullet( + tf, + "⚑ ACTS (Independent Execution)", + level=0, + bold=True, + size=Pt(28), + color=accent_color, + ) + add_bullet( + tf, + "Operates natively via PyGithub to open Issues, write code, branch, commit, and mergeβ€”100% hands-free.", + level=1, + ) # ========================================== # Slide 3: The Problem vs Our Solution # ========================================== slide = create_content_slide("The Problem vs. The AutoMaintainer Paradigm") - + # Left Column - left_box = slide.shapes.add_textbox(Inches(0.5), Inches(1.5), Inches(5.8), Inches(5)) + left_box = slide.shapes.add_textbox( + Inches(0.5), Inches(1.5), Inches(5.8), Inches(5) + ) ltf = left_box.text_frame - add_bullet(ltf, "❌ The Passive AI Bottleneck", level=0, bold=True, size=Pt(26), color=RGBColor(220, 38, 38)) + add_bullet( + ltf, + "❌ The Passive AI Bottleneck", + level=0, + bold=True, + size=Pt(26), + color=RGBColor(220, 38, 38), + ) add_bullet(ltf, "Current tools are merely 'Copilots'.", level=1) - add_bullet(ltf, "Require constant human prompting, steering, and hand-holding.", level=1) - add_bullet(ltf, "Developers still spend >50% of time fixing bugs and managing technical debt.", level=1) + add_bullet( + ltf, "Require constant human prompting, steering, and hand-holding.", level=1 + ) + add_bullet( + ltf, + "Developers still spend >50% of time fixing bugs and managing technical debt.", + level=1, + ) add_bullet(ltf, "Maintenance is purely reactive.", level=1) # Right Column - right_box = slide.shapes.add_textbox(Inches(6.8), Inches(1.5), Inches(5.8), Inches(5)) + right_box = slide.shapes.add_textbox( + Inches(6.8), Inches(1.5), Inches(5.8), Inches(5) + ) rtf = right_box.text_frame - add_bullet(rtf, "βœ… The Autonomous Paradigm Shift", level=0, bold=True, size=Pt(26), color=success_color) + add_bullet( + rtf, + "βœ… The Autonomous Paradigm Shift", + level=0, + bold=True, + size=Pt(26), + color=success_color, + ) add_bullet(rtf, "AutoMaintainer is a true 'Colleague'.", level=1) add_bullet(rtf, "Initiates its own tasks via 5-agent LangGraph workflow.", level=1) - add_bullet(rtf, "Self-correcting iteration loops catch and fix bugs before human review.", level=1) + add_bullet( + rtf, + "Self-correcting iteration loops catch and fix bugs before human review.", + level=1, + ) add_bullet(rtf, "Turns maintenance into an automated, proactive pipeline.", level=1) # ========================================== # Slide 4: The System Flow & Tech Stack # ========================================== slide = create_content_slide("Tech Stack & Execution Flow") - + txBox = slide.shapes.add_textbox(Inches(0.5), Inches(1.5), Inches(12), Inches(2)) tf = txBox.text_frame - add_bullet(tf, "πŸ› οΈ The Tech Stack", level=0, bold=True, size=Pt(26), color=accent_color) + add_bullet( + tf, "πŸ› οΈ The Tech Stack", level=0, bold=True, size=Pt(26), color=accent_color + ) add_bullet(tf, "Agent Orchestration: LangGraph", level=1) add_bullet(tf, "Inference Engine: Llama 3 via Groq (Blazing fast LPU)", level=1) add_bullet(tf, "Backend: FastAPI (Python)", level=1) - add_bullet(tf, "Frontend: Next.js (React), Tailwind CSS, Framer Motion, WebSockets", level=1) + add_bullet( + tf, + "Frontend: Next.js (React), Tailwind CSS, Framer Motion, WebSockets", + level=1, + ) add_bullet(tf, "Code Intelligence: GitNexus MCP (Model Context Protocol)", level=1) # Simple Flow Diagram text flow_box = slide.shapes.add_textbox(Inches(0.5), Inches(4.5), Inches(12), Inches(2)) ftf = flow_box.text_frame - add_bullet(ftf, "πŸ”„ Execution Flow", level=0, bold=True, size=Pt(26), color=accent_color) - add_bullet(ftf, "1. Trigger -> 2. Ingest Architecture -> 3. Brainstorm Feature -> 4. Open GitHub Issue", level=1, size=Pt(18)) - add_bullet(ftf, "5. Review Issue -> 6. Write Code -> 7. Open Pull Request -> 8. Code Review", level=1, size=Pt(18)) - add_bullet(ftf, "9. Merge if LGTM, OR Fix & Re-Push if Bug Detected.", level=1, size=Pt(18)) + add_bullet( + ftf, "πŸ”„ Execution Flow", level=0, bold=True, size=Pt(26), color=accent_color + ) + add_bullet( + ftf, + "1. Trigger -> 2. Ingest Architecture -> 3. Brainstorm Feature -> 4. Open GitHub Issue", + level=1, + size=Pt(18), + ) + add_bullet( + ftf, + "5. Review Issue -> 6. Write Code -> 7. Open Pull Request -> 8. Code Review", + level=1, + size=Pt(18), + ) + add_bullet( + ftf, "9. Merge if LGTM, OR Fix & Re-Push if Bug Detected.", level=1, size=Pt(18) + ) # ========================================== # Slide 5: The 5-Agent LangGraph Crew # ========================================== slide = create_content_slide("The 5-Agent Engineering Crew") - - table_shape = slide.shapes.add_table(6, 2, Inches(0.5), Inches(1.5), Inches(12), Inches(5)) + + table_shape = slide.shapes.add_table( + 6, 2, Inches(0.5), Inches(1.5), Inches(12), Inches(5) + ) table = table_shape.table table.columns[0].width = Inches(3.5) table.columns[1].width = Inches(8.5) - + headers = ["Agent Role", "Responsibility & Logic"] for i, header in enumerate(headers): table.cell(0, i).text = header @@ -146,20 +238,35 @@ def create_content_slide(title_text): table.cell(0, i).text_frame.paragraphs[0].font.size = Pt(22) table.cell(0, i).fill.solid() table.cell(0, i).fill.fore_color.rgb = accent_color - + roles = [ - ("1. Architect (Principal)", "Scans the target repository's file tree and README. Assesses the tech stack and project state, then generates a strict architectural directive."), - ("2. Visionary (PM)", "Reads the directive and ideates an innovative feature. It opens a native GitHub Issue detailing the proposed feature."), - ("3. Reviewer (Gatekeeper)", "Evaluates the feature against the original directive. If approved, it comments on the Issue. If rejected, it closes it."), - ("4. Implementer (Dev)", "Writes the actual code to build the feature. Pushes to a new branch and opens a Pull Request. Reads feedback from loops to fix bugs."), - ("5. Maintainer (QA)", "Reviews the PR code. Spots flaws, leaves comments, and routes pipeline back to the Implementer. Merges if 'LGTM'.") + ( + "1. Architect (Principal)", + "Scans the target repository's file tree and README. Assesses the tech stack and project state, then generates a strict architectural directive.", + ), + ( + "2. Visionary (PM)", + "Reads the directive and ideates an innovative feature. It opens a native GitHub Issue detailing the proposed feature.", + ), + ( + "3. Reviewer (Gatekeeper)", + "Evaluates the feature against the original directive. If approved, it comments on the Issue. If rejected, it closes it.", + ), + ( + "4. Implementer (Dev)", + "Writes the actual code to build the feature. Pushes to a new branch and opens a Pull Request. Reads feedback from loops to fix bugs.", + ), + ( + "5. Maintainer (QA)", + "Reviews the PR code. Spots flaws, leaves comments, and routes pipeline back to the Implementer. Merges if 'LGTM'.", + ), ] - + for row_idx, (role, desc) in enumerate(roles, start=1): table.cell(row_idx, 0).text = role table.cell(row_idx, 0).text_frame.paragraphs[0].font.bold = True table.cell(row_idx, 0).text_frame.paragraphs[0].font.size = Pt(18) - + table.cell(row_idx, 1).text = desc table.cell(row_idx, 1).text_frame.paragraphs[0].font.size = Pt(18) @@ -167,66 +274,139 @@ def create_content_slide(title_text): # Slide 6: The Self-Correcting Iteration Loop # ========================================== slide = create_content_slide("Advanced Autonomy: The Self-Correcting Loop") - + txBox = slide.shapes.add_textbox(Inches(0.5), Inches(1.5), Inches(12), Inches(5)) tf = txBox.text_frame - - add_bullet(tf, "Unlike basic generators, AutoMaintainer evaluates its own code output.", level=0, bold=True, size=Pt(26)) - - add_bullet(tf, "The Maintainer QA Node:", level=0, bold=True, size=Pt(24), color=accent_color) + + add_bullet( + tf, + "Unlike basic generators, AutoMaintainer evaluates its own code output.", + level=0, + bold=True, + size=Pt(26), + ) + + add_bullet( + tf, + "The Maintainer QA Node:", + level=0, + bold=True, + size=Pt(24), + color=accent_color, + ) add_bullet(tf, "Scans the PR generated by the Implementer.", level=1) - add_bullet(tf, "If a bug, syntax error, or logic flaw is found, it leaves a GitHub PR comment.", level=1) - - add_bullet(tf, "The Iteration Cycle:", level=0, bold=True, size=Pt(24), color=accent_color) - add_bullet(tf, "Pipeline routes backwards. The Implementer reads the feedback and pushes a new commit to the branch.", level=1) - add_bullet(tf, "Bounded to a maximum of 3 iteration cycles to prevent infinite loops.", level=1) - - add_bullet(tf, "Result: >85% of logic errors are self-corrected before human intervention is ever needed.", level=0, bold=True, size=Pt(22), color=success_color) + add_bullet( + tf, + "If a bug, syntax error, or logic flaw is found, it leaves a GitHub PR comment.", + level=1, + ) + + add_bullet( + tf, "The Iteration Cycle:", level=0, bold=True, size=Pt(24), color=accent_color + ) + add_bullet( + tf, + "Pipeline routes backwards. The Implementer reads the feedback and pushes a new commit to the branch.", + level=1, + ) + add_bullet( + tf, + "Bounded to a maximum of 3 iteration cycles to prevent infinite loops.", + level=1, + ) + + add_bullet( + tf, + "Result: >85% of logic errors are self-corrected before human intervention is ever needed.", + level=0, + bold=True, + size=Pt(22), + color=success_color, + ) # ========================================== # Slide 7: Benchmarks & Performance # ========================================== slide = create_content_slide("Performance Benchmarks & Metrics") - + txBox = slide.shapes.add_textbox(Inches(0.5), Inches(1.5), Inches(12), Inches(5)) tf = txBox.text_frame - + add_bullet(tf, "1. Blazing Fast Execution Speed", level=0, bold=True, size=Pt(24)) - add_bullet(tf, "Powered by Groq's LPU inference, the entire cycle (Architecture -> PR -> Review -> Merge) completes in < 20 seconds.", level=1) - add_bullet(tf, "Human average for equivalent context-loading + coding + PR review: ~45 minutes.", level=1) - - add_bullet(tf, "2. Local Zero-Server Code Intelligence", level=0, bold=True, size=Pt(24)) - add_bullet(tf, "GitNexus MCP processes 10,000+ lines of codebase locally in < 2 seconds.", level=1) - add_bullet(tf, "Ensures total privacy. Code is semantically mapped without being sent to external databases.", level=1) - + add_bullet( + tf, + "Powered by Groq's LPU inference, the entire cycle (Architecture -> PR -> Review -> Merge) completes in < 20 seconds.", + level=1, + ) + add_bullet( + tf, + "Human average for equivalent context-loading + coding + PR review: ~45 minutes.", + level=1, + ) + + add_bullet( + tf, "2. Local Zero-Server Code Intelligence", level=0, bold=True, size=Pt(24) + ) + add_bullet( + tf, + "GitNexus MCP processes 10,000+ lines of codebase locally in < 2 seconds.", + level=1, + ) + add_bullet( + tf, + "Ensures total privacy. Code is semantically mapped without being sent to external databases.", + level=1, + ) + add_bullet(tf, "3. Fully Containerized Deployment", level=0, bold=True, size=Pt(24)) - add_bullet(tf, "Deploys anywhere instantly via Docker, with native Hugging Face Spaces compatibility.", level=1) + add_bullet( + tf, + "Deploys anywhere instantly via Docker, with native Hugging Face Spaces compatibility.", + level=1, + ) # ========================================== # Slide 8: The Roadmap to Massive Scale # ========================================== slide = create_content_slide("The Enterprise Roadmap (Phases 1 - 5)") - - table_shape = slide.shapes.add_table(5, 2, Inches(0.5), Inches(1.5), Inches(12), Inches(5)) + + table_shape = slide.shapes.add_table( + 5, 2, Inches(0.5), Inches(1.5), Inches(12), Inches(5) + ) table = table_shape.table table.columns[0].width = Inches(2.5) table.columns[1].width = Inches(9.5) - + roadmap = [ - ("Phase 1: SaaS", "Dual-Storage Adapter using Supabase PostgreSQL for 100k+ concurrent user scale."), - ("Phase 2: CLI", "Native CLI binary bypassing GitHub API to work directly on uncommitted local git trees."), - ("Phase 3: SDKs", "Python & Node.js SDKs to embed LangGraph autonomy into GitHub Actions & GitLab CI."), - ("Phase 4: MCP", "Exposing the crew as a Universal Model Context Protocol (MCP) Server. Cursor & Devin can 'hire' us."), - ("Phase 5: IDE", "Native VS Code Extension. Agents fix bugs silently in the background as the developer types.") + ( + "Phase 1: SaaS", + "Dual-Storage Adapter using Supabase PostgreSQL for 100k+ concurrent user scale.", + ), + ( + "Phase 2: CLI", + "Native CLI binary bypassing GitHub API to work directly on uncommitted local git trees.", + ), + ( + "Phase 3: SDKs", + "Python & Node.js SDKs to embed LangGraph autonomy into GitHub Actions & GitLab CI.", + ), + ( + "Phase 4: MCP", + "Exposing the crew as a Universal Model Context Protocol (MCP) Server. Cursor & Devin can 'hire' us.", + ), + ( + "Phase 5: IDE", + "Native VS Code Extension. Agents fix bugs silently in the background as the developer types.", + ), ] - + for row_idx, (phase, desc) in enumerate(roadmap): table.cell(row_idx, 0).text = phase table.cell(row_idx, 0).text_frame.paragraphs[0].font.bold = True table.cell(row_idx, 0).text_frame.paragraphs[0].font.size = Pt(18) table.cell(row_idx, 0).fill.solid() table.cell(row_idx, 0).fill.fore_color.rgb = accent_color - + table.cell(row_idx, 1).text = desc table.cell(row_idx, 1).text_frame.paragraphs[0].font.size = Pt(18) @@ -234,22 +414,25 @@ def create_content_slide(title_text): # Slide 9: Conclusion # ========================================== slide = create_content_slide("Conclusion: The Future of Software Maintenance") - + txBox = slide.shapes.add_textbox(Inches(0.5), Inches(2), Inches(12), Inches(4)) tf = txBox.text_frame - tf.text = "AutoMaintainer isn't just an assistant; it is a fully autonomous AI Colleague." + tf.text = ( + "AutoMaintainer isn't just an assistant; it is a fully autonomous AI Colleague." + ) tf.paragraphs[0].font.size = Pt(36) tf.paragraphs[0].font.bold = True tf.paragraphs[0].font.color.rgb = success_color tf.paragraphs[0].alignment = PP_ALIGN.CENTER - + p2 = tf.add_paragraph() p2.text = "\nBy executing the Agentic loopβ€”Thinking contextually, Deciding logically, and Acting independentlyβ€”we are redefining how technical debt is managed in the modern era." p2.font.size = Pt(28) p2.alignment = PP_ALIGN.CENTER - - prs.save('AutoMaintainer_Hackathon_Pitch_V2.pptx') + + prs.save("AutoMaintainer_Hackathon_Pitch_V2.pptx") print("Successfully generated professional AutoMaintainer_Hackathon_Pitch_V2.pptx") -if __name__ == '__main__': + +if __name__ == "__main__": create_presentation() diff --git a/patch_comments.py b/patch_comments.py index 97ab436..2a34715 100644 --- a/patch_comments.py +++ b/patch_comments.py @@ -3,9 +3,9 @@ token = os.getenv("GITHUB_TOKEN") headers = { - 'Authorization': f'Bearer {token}', - 'Accept': 'application/vnd.github+json', - 'X-GitHub-Api-Version': '2022-11-28' + "Authorization": f"Bearer {token}", + "Accept": "application/vnd.github+json", + "X-GitHub-Api-Version": "2022-11-28", } body_13 = """@kehansama Thank you for the excellent technical feedback on the CLI architecture. @@ -19,5 +19,9 @@ We are actively evaluating the architecture for this persistence layer. AgentRelay presents a compelling model for solving this cross-session amnesia. We will update the RFC to include the Context & Memory Persistence requirements. Thank you for contributing these insights to the design phase!""" -res = requests.patch('https://api.github.com/repos/PxA-Labs/AutoMaintainer/issues/comments/4633057460', json={'body': body_13}, headers=headers) +res = requests.patch( + "https://api.github.com/repos/PxA-Labs/AutoMaintainer/issues/comments/4633057460", + json={"body": body_13}, + headers=headers, +) print("13 patched:", res.status_code) diff --git a/test_groq.py b/test_groq.py index 5536982..6263318 100644 --- a/test_groq.py +++ b/test_groq.py @@ -4,19 +4,17 @@ api_key = os.environ.get("GROQ_API_KEY") if not api_key: # Try reading it from backend/.env - with open('backend/.env', 'r') as f: + with open("backend/.env", "r") as f: for line in f: - if line.startswith('GROQ_API_KEY='): - api_key = line.strip().split('=')[1] + if line.startswith("GROQ_API_KEY="): + api_key = line.strip().split("=")[1] break url = "https://api.groq.com/openai/v1/models" -headers = { - "Authorization": f"Bearer {api_key}" -} +headers = {"Authorization": f"Bearer {api_key}"} response = requests.get(url, headers=headers) response.raise_for_status() -models = [m['id'] for m in response.json()['data']] +models = [m["id"] for m in response.json()["data"]] print("Available Groq Models:") for m in models: print(m) From de49d038be1273f108dd7c92bec00bcc0d4bee65 Mon Sep 17 00:00:00 2001 From: Archit Mittal Date: Sun, 9 Aug 2026 18:30:00 +0530 Subject: [PATCH 3/3] fix: resolve pytest mock issues and parameter mismatches in workflows --- .github/workflows/greetings.yml | 6 +++--- .github/workflows/pr-size-labeler.yml | 2 +- backend/agents.py | 5 +++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml index a3f0f49..240e606 100644 --- a/.github/workflows/greetings.yml +++ b/.github/workflows/greetings.yml @@ -11,6 +11,6 @@ jobs: steps: - uses: actions/first-interaction@v3 with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - issue-message: "Welcome to AutoMaintainer! πŸ‘‹ Thank you for opening your first issue. A maintainer or our AI agent will review it shortly." - pr-message: "Welcome to AutoMaintainer! πŸš€ Thank you for submitting your first Pull Request. Our CI pipelines are running, and a maintainer will review your code soon!" + repo_token: ${{ secrets.GITHUB_TOKEN }} + issue_message: "Welcome to AutoMaintainer! πŸ‘‹ Thank you for opening your first issue. A maintainer or our AI agent will review it shortly." + pr_message: "Welcome to AutoMaintainer! πŸš€ Thank you for submitting your first Pull Request. Our CI pipelines are running, and a maintainer will review your code soon!" diff --git a/.github/workflows/pr-size-labeler.yml b/.github/workflows/pr-size-labeler.yml index 388fede..52b8c36 100644 --- a/.github/workflows/pr-size-labeler.yml +++ b/.github/workflows/pr-size-labeler.yml @@ -1,7 +1,7 @@ name: PR Size Labeler on: - pull_request: + pull_request_target: types: [opened, synchronize, reopened] jobs: diff --git a/backend/agents.py b/backend/agents.py index c432e33..72da632 100644 --- a/backend/agents.py +++ b/backend/agents.py @@ -69,8 +69,9 @@ async def broadcast_log(message: dict): def get_all_groq_keys(): keys = [] - if GROQ_API_KEY: - keys.append(GROQ_API_KEY) + primary = os.getenv("GROQ_API_KEY") + if primary: + keys.append(primary) for i in range(1, 10): k = os.getenv(f"GROQ_API_KEY_{i}") if k: