# Project export: Splat

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: Cal Hacks 11.0
- Tagline: Revolutionizing debugging by bringing simple and intuitive tools nested right in your command terminal.
- Devpost: https://devpost.com/software/splat-rdcn9i
- GitHub: https://github.com/ehcaw/calhacks24
- Demo: https://readymag.website/u460970526/5060187/
- Team: 3 GitHub contributor(s) — Jason Son (55 commits), ehcaw (44 commits), daniel ung (24 commits)

## Devpost submission (written by the team)

### Overview

A development tool specialized in bug elimination right from your command line. ⭐️

### Inspiration

Splat was inspired by a universal coding gripe: debugging. Despite a seemingly simple concept, none of the Splat team had found a simple and intuitive debugging assistant–so we created our own, inspired by linters. 🔨

### What it does

&

### How we built it

Splat takes your compile & runtime errors and does the squinting for you. Splat retrieves, sorts, & parses all the errors into a graph structure, & creates an undirected adjacency list, to list the relationships between each function mentioned in the stack trace. Splat compiles & compresses the list so that it can interpret the error & its workflow through the context that we have. Finally, the interpretation is returned to your terminal as Where and What the error is. With a simple click, you're able to see How to fix your error and use suggestions right from your code. Viola! ⚙️ Technologies used The Splat team used Python, Groq, Fetch.ai, and Llama to build a system of file packaging, prompt engineering, and error parsing. ❌

### Challenges we ran into

We were unable to correct multiple errors at a time: this took too much circumstance and context implementation that we didn't have time for implementation. Ensuring universality for all runners (py, node, javac, ...) were difficult for code replacement/completion, although error parsing was certainly successful. Fetch.ai's documentation was not fleshed out - although we're a really big fan of the tech, we ran into implementation issues due to lack of documentation and help around the technology. Parsing all errors and retrieving the absolute path was one of our toughest battles but has been overpassed. Judges expressed concern over context window, and possibilities of exceeding it. Although we did consider the context window in case of production files (1M+ lines), we attempted to resolve this problem by selecting only relevant files and their relationships with those who are Nth degree related. 🏆

### Accomplishments we're proud of

None of us have ever thought about coding DevTools. When Warp told us that we can make something in the command line, we thought about what all programmers will always run into - errors! Listed below are individual, independent achievements. Ensured universality between all languages when compiling and simplifying errors Robust, sleek error parsing with sub-100ms response time 🍎

### What we learned

Working with CLI Working with development tools Error handling and in-depth exception parsing 📝 What do we plan next? Visiting Top Dog and Sweethearts Cafe in Berkeley. Making it so we can handle multiple exceptions, and solve each of them with context of the previous error. We planned on doing this initially by returning a list of objects and iterating over them, but we decided to stick to looking at an error, one at a time. If we were to implement it, we would use a queue and between every operation, we would process the context after each error, and pass down the line.

## README (from the GitHub repository)

# splat
splat is a tool that combines your compile/runtime errors and grabs context from every crevice to deliver a highly educated debug response. This is perfect for whenever you have an error that needs to be quickly fixed, understood, and prevented for later in the future.
created at calhacks 11.0
```
 /\_/\
( o.o )
 > ^ <
```
## Features
- **AI-Optimized**: We use an extremely fast inference model [Groq](https://groq.com/) in order to produce an instant debug error, with still the same amount of accuracy.
- **Simple to Use**: <ins>splat</ins> can be used out-of-the-box and globally in any project without any configuration.
- **Git Aware**: <ins>splat</ins> takes into consideration your .gitignore files so that we won't use any sensitive info.
- **Highly Contextual**: You can use <ins>splat</ins> with a `-r` flag, grabbing all nodes to the Nth degree related to all error stack files in order to grab the most related content, delivering a highly accurate, optimized, and contextual debug response.

## Known Bugs
- <ins>splat</ins> will not conform to any formatting configurations when inserting code
- <ins>splat</ins> does not do well with running sub-module entrypoints that do not originate in the root directory
  
## Quick Start
You can use <ins>splat</ins> out of the box:  

`splat squash <?-r> <!entrypoint>`.

Example:
Just like you would enter your app, do so with <ins>splat</ins>.  

`splat squash "python3 foo.py"`

`splat squash -r "python3 main.py"`

And that's it!


## Detected evidence (automated analysis)

Indexed codebase: 40 recognized source files, 61 KB.
- C (language) — detected in the code
- CSS (language) — detected in the code
- FastAPI (technology) — detected in the code
- HTML (language) — detected in the code
- Java (language) — detected in the code
- JavaScript (language) — detected in the code
- Next.js (technology) — detected in the code
- Python (language) — detected in the code
- React (technology) — detected in the code
- Tailwind CSS (technology) — detected in the code
- TypeScript (language) — detected in the code

## Codebase structure (from repository index)

### Files (59 of 59)

```
.gitignore
agents/__init__.py
agents/agents.py
agents/file_writer_agent.py
cli/cli.py
cli/process_monitor.py
cli/term_sesh.py
cli/zap.py
config.toml
errortrace.py
handlers/fastapi_handlers.py
module.py
process/agent_handler.py
process/process.py
README.md
relational.py
requirements.txt
setup.py
setup.sh
splat.egg-info/dependency_links.txt
splat.egg-info/entry_points.txt
splat.egg-info/PKG-INFO
splat.egg-info/requires.txt
splat.egg-info/SOURCES.txt
splat.egg-info/top_level.txt
terminalout/terminal.py
test.py
test/FaultyJava.java
test/main.py
test/test-nextjs-project/.eslintrc.json
test/test-nextjs-project/.gitignore
test/test-nextjs-project/next.config.mjs
test/test-nextjs-project/package.json
test/test-nextjs-project/postcss.config.mjs
test/test-nextjs-project/README.md
test/test-nextjs-project/src/app/globals.css
test/test-nextjs-project/src/app/layout.tsx
test/test-nextjs-project/src/app/page.tsx
test/test-nextjs-project/tailwind.config.ts
test/test-nextjs-project/tsconfig.json
test/test-react-app/.gitignore
test/test-react-app/package.json
test/test-react-app/public/index.html
test/test-react-app/public/manifest.json
test/test-react-app/public/robots.txt
test/test-react-app/README.md
test/test-react-app/src/App.css
test/test-react-app/src/App.js
test/test-react-app/src/App.test.js
test/test-react-app/src/index.css
test/test-react-app/src/index.js
test/test-react-app/src/reportWebVitals.js
test/test-react-app/src/setupTests.js
test/test.c
test/test.js
test/test.py
test/test.ts
utils/__init__.py
utils/utils.py
```

### Dependencies

- requirements.txt: black, click, dotenv, fastapi, groq, prompt_toolkit, pydantic, pydantic_ai, python-dotenv, repopack, requests, setuptools, uvicorn, virtualenv, zmq
- test/test-nextjs-project/package.json: @types/node@^20, @types/react@^18, @types/react-dom@^18, eslint@^8, eslint-config-next@14.2.15, next@14.2.15, postcss@^8, react@^18.3.1, react-dom@^18, tailwindcss@^3.4.1, typescript@^5
- test/test-react-app/package.json: @testing-library/jest-dom@^5.17.0, @testing-library/react@^13.4.0, @testing-library/user-event@^13.5.0, react@^18.3.1, react-dom@^18.3.1, react-scripts@5.0.1, web-vitals@^2.1.4

### Recent commits (newest first)

- Ok my cat didn't work so I fixed it
- Adding myself as a collaborator...
- clean child terminal monitoring
- new terminal monitoring approach with tmux
- naive terminal approach
- removed all the testing files and removed the fetchai agent code
- Update README.md
- cleaned up splat
- formatting fix
- formatting fix
- broken ahhj files
- Merge branch 'main' of https://github.com/ehcaw/calhacks24
- broken ahhj files
- Update README.md
- monday left me broken
- add: dependencies to match wache's and mine
- add: requirements.txt upgrade to dodge error
- Merge pull request #2 from ehcaw/baka-branch
- Merge branch 'main' into baka-branch
- fix

## Key source files (fetched from GitHub, selected and truncated for size)

### requirements.txt

```
click
repopack
setuptools
virtualenv
groq
fastapi
uvicorn
dotenv
python-dotenv
prompt_toolkit
requests
black
pydantic_ai
pydantic
zmq

```

### test/test-nextjs-project/package.json

```
{
  "name": "test-nextjs-project",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "next": "14.2.15",
    "react": "^18.3.1",
    "react-dom": "^18"
  },
  "devDependencies": {
    "@types/node": "^20",
    "@types/react": "^18",
    "@types/react-dom": "^18",
    "eslint": "^8",
    "eslint-config-next": "14.2.15",
    "postcss": "^8",
    "tailwindcss": "^3.4.1",
    "typescript": "^5"
  }
}

```

### test/test-react-app/package.json

```
{
  "name": "test-react-app",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^5.17.0",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^13.5.0",
    "react": "^18.3.1",
    "react-dom": "^18.3.1",
    "react-scripts": "5.0.1",
    "web-vitals": "^2.1.4"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

```

### test/main.py

```python
# main.py
from fastapi import FastAPI, HTTPException, Request
from fastapi.responses import JSONResponse
from pydantic import BaseModel
from typing import List, Optional
import random
import traceback
import os
import logging
from fastapi.logger import logger as fastapi_logger

fastapi_logger.setLevel(logging.ERROR)

app = FastAPI()

# Set this environment variable to True to display tracebacks
DISPLAY_TRACEBACK_ON_500 = os.environ.get("DISPLAY_TRACEBACK_ON_500", "False").lower() == "true"

class User(BaseModel):
    id: int
    name: str
    email: str

class Item(BaseModel):
    id: int
    name: str
    price: float

users = [
    User(id=1, name="Alice", email="alice@example.com"),
    User(id=2, name="Bob", email="bob@example.com"),
]

items = [
    Item(id=1, name="Laptop", price=999.99),
    Item(id=2, name="Phone", price=499.99),
]

@app.exception_handler(Exception)
async def debug_exception_handler(request: Request, exc: Exception):
    if DISPLAY_TRACEBACK_ON_500:
        return JSONResponse(
            status_code=500,
            content={
                "message": "Internal Server Error",
                "traceback": "".join(
                    traceback.format_exception(
                        etype=type(exc), value=exc, tb=exc.__traceback__
                    )
                )
            }
        )
    else:
        return JSONResponse(
            status_code=500,
            content={"message": "Internal Server Error"}
        )

@app.get("/users", response_model=List[User])
async def get_users():
    # BUG: This endpoint will randomly fail
    if random.random() < 0.5:
        raise HTTPException(status_code=500, detail="Random server error")
    return users

@app.get("/items", response_model=List[Item])
async def get_items():
    # BUG: This endpoint will return items with incorrect types
    return [{"id": "not_an_int", "name": item.name, "price": str(item.price)} for item in items]

@app.post("/process")
async def process_data(data: dict):
    # BUG: This endpoint doesn't properly handle missing keys
    result = data['value1'] + data['value2']
    return {"result": result}

@app.get("/user/{user_id}")
async def get_user(user_id: int):
    # BUG: This endpoint doesn't properly handle non-existent users
    user = next((u for u in users if u.id == user_id), None)
    return user

@app.put("/item/{item_id}")
async def update_item(item_id: int, item: Item):
    # BUG: This endpoint updates the wrong item
    for i, existing_item in enumerate(items):
        if existing_item.id == item_id + 1:  # Intentional off-by-one error
            items[i] = item
            return {"message": "Item updated successfully"}
    raise HTTPException(status_code=404, detail="Item not found")

@app.get("/error")
async def trigger_error():
    # This endpoint always raises an exception to test the traceback functionality
    raise Exception("This is a test exception")

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)
```

### cli/cli.py

```python
import click
import sys
import cmd
from process_monitor import ProcessMonitor
from zap import Zapper
from term_sesh import TermSesh

class ZapShell(cmd.Cmd):
    intro = 'Welcome to the Zap CLI. Type help or ? to list commands.\n'
    prompt = 'zap> '

    def __init__(self):
        super().__init__()
        self.ctx = None
        self.zapper = None
        self.term_sesh = None

    # Command definitions
    def do_hello(self, arg):
        """Say hello"""
        click.echo('Hello!')

    def do_echo(self, arg):
        """Echo the input"""
        click.echo(arg)

    def do_exit(self, arg):
        """Exit the application"""
        click.echo('Goodbye!')
        if self.term_sesh:
            if self.term_sesh.monitor:
                self.term_sesh.monitor.is_running = False
            if self.term_sesh.terminal_process:
                self.term_sesh.terminal_process.terminate()
            self.term_sesh.kill_tmux_session()
        click.echo('Goodbye!')
        return True
        return True

    def do_start(self, arg):
        """Start up the terminal session using tmux"""
        self.zapper = Zapper()
        self.zapper.start()
        self.term_sesh = TermSesh(session_name='zapper_session')
        if self.term_sesh.open_new_terminal():
            self.term_sesh.monitor = ProcessMonitor(self.term_sesh)
            self.term_sesh.monitor.start_monitoring()
            click.echo("tmux session and monitoring started successfully")
            self.term_sesh.publisher.send_json({'type': 'info', 'data': 'tmux session started'})
            self.term_sesh.send_to_terminal("ls")
            self.term_sesh.send_to_terminal("cat setup.py")
        else:
            click.echo("Failed to start terminal session")



    def do_send(self, arg):
        """Send a command to the terminal"""
        if not self.term_sesh or not self.term_sesh.is_terminal_active():
            click.echo("No active terminal session. Use 'start' first.")
            return

        response = self.term_sesh.send_to_terminal(arg)
        if response:
            click.echo(f"Command sent: {response}")
    def do_quit(self, arg):
        """Exit the application"""
        return self.do_exit(arg)

    # Shortcut for exit
    do_EOF = do_quit

    def default(self, line):
        """Handle unknown commands"""
        if self.term_sesh and self.term_sesh.is_terminal_active():
            self.do_send(line)
        else:
            click.echo(f"Unknown command: {line}")
        click.echo(f"Unknown command: {line}")
    def precmd(self, line):
            """Check terminal status before each command"""
            if self.term_sesh and not self.term_sesh.is_terminal_active():
                click.echo("Terminal session ended unexpectedly")
            return line

@click.group(invoke_without_command=True)
@click.pass_context
def cli(ctx):
    """Zap CLI - An interactive command line tool"""
    if ctx.invoked_subcommand is None:
        # Start the interactive shell
        shell = ZapShell()
        shell.ctx = ctx
        shell.cmdloop()

@cli.command()
def version():
    """Show the version"""
    click.echo('Zap CLI v0.1.0')

def main():
    try:
        cli()
    except KeyboardInterrupt:
        click.echo("\nGoodbye!")
        sys.exit(0)

if __name__ == '__main__':
    main()

```

### test/test-react-app/src/App.js

```javascript
import logo from './logo.svg';
import './App.css';

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo"
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

export default App;

```

### test/test-react-app/src/index.js

```javascript
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

```

### test/test-nextjs-project/src/app/layout.tsx

```typescript
import type { Metadata } from "next";
import localFont from "next/font/local";
import "./globals.css";

const geistSans = localFont({
  src: "./fonts/GeistVF.woff",
  variable: "--font-geist-sans",
  weight: "100 900",
});
const geistMono = localFont({
  src: "./fonts/GeistMonoVF.woff",
  variable: "--font-geist-mono",
  weight: "100 900",
});

export const metadata: Metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body
        className={`${geistSans.variable} ${geistMono.variable} antialiased`}
      >
        {children}
      </body>
    </html>
  );
}

```

### test/test-nextjs-project/src/app/page.tsx

```typescript
// src/app/page.tsx
"use client"
import { useState } from 'react';

export default function Home() {
  const [result, setResult] = useState('');

  const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    const formData = new FormData(event.currentTarget);
    const endpoint = formData.get('endpoint') as string;

    try {
      const response = await fetch(`http://localhost:8000${endpoint}`);
      const data = await response.json();
      setResult(JSON.stringify(data, null, 2));
    } catch (error) {
      setResult(`Error: ${error}`);
    }
  };

  return (
    <div className="container mx-auto p-4">
      <h1 className="text-2xl font-bold mb-4">FastAPI Bug Tester</h1>
      <form onSubmit={handleSubmit} className="mb-4">
        <select name="endpoint" className="mr-2 p-2 border rounded">
          <option value="/users">Get Users</option>
          <option value="/items">Get Items</option>
          <option value="/process">Process Data</option>
        </select>
        <button type="submit" className="bg-blue-500 text-white p-2 rounded">
          Send Request
        </button>
      </form>
      <pre className="bg-gray-100 p-4 rounded">{result}</pre>
    </div>
  );
}
```

### test.py

```python
from utils.utils import detect_framework_or_language

framework = detect_framework_or_language("python3 ./test/main.py")
print(framework)

```

[28 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]