# Project export: DevShack

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: CruzHacks 2024
- Tagline: Generate informative documentation for any project in the most practical ways!
- Devpost: https://devpost.com/software/devshack
- GitHub: https://github.com/leavism/automated-commenting-machine
- Result: winner ([MLH - Cloudflare] Best AI Application Built with Cloudflare)
- Team: 3 GitHub contributor(s) — Huy Dang (33 commits), Avinh Huynh (31 commits), Odera Nwosu (18 commits)

## Devpost submission (written by the team)

### Inspiration

Programming can get a little hectic when you're honed in on solving a complex problem, and you have to pull yourself back to remember to use version control. While using Git is undeniably crucial, crafting meaningful commit messages becomes a hassle when the code base is evolving rapidly.

### What it does

To tackle this, we devised a straightforward solution, feeding the code changes into a large language model to automate the creation of commit messages. When we saw how effective our implementation was, we actually started using it during CruzHacks as we increased the scope of our project. Taking it a step further, we implemented a parser that utilizes language models to generate inline documentation, effectively eliminating the tedious aspects of future programming assignments for the rest of our academic career.

### How we built it

Embarking on CruzHack, our team decided to spice things up by learning and making our project in a new programming language. Our first milestone for the hackathon was actually learning Rust. We arrived early to claim our table, put our heads down, and learned Rust for the entire first night. Once the sun rose at 6AM Satuday morning, we were pumped with caffeine and ready to actually start putting together our program. We implemented a simple command handler with plans on expanding our program beyond the original scope. To get commit messages written for us, we called git to produce code changes that is then piped into an API request to send to the Mistral 7B LLM hosted on Cloudflare. With a bit of prompt engineering, Mistral 7B was able to produce a 128 character messages that fit the conventional standard of commit messages, that we then pipe into a git commit -m call to actually commit the code! That way users didn't have to manually copy and paste the generated message when performing a commit. We took great care to streamline this process, requiring almost zero effort on the user end so that they can just focus on the programming. Once we saw how effective this implementation was, we took it a step further by considering what else was tedious during the development process. We quickly agreed that it was writing documentation for our functions. Our team actually consisted of members that had a background in web development so we actually wrote the code to write JSDocs for our JavaScript and TypeScript programs.

### Challenges we ran into

The first problem we ran into was command handling. Our program had multiple features, and implementing a command handler ensure well organized and modular code. We spent the entire first night implementing a sound and scalable command handler which formed a strong foundation for the rest of the project. The next big challenge was writing effective prompts for the language models. Asking these models to "write a meaningful description of these code changes" did not consistently generate meaningful commit messages. 8 out of 10 times the messages were subpar and worse then anything we could write with minimal effort. So we put on our prompt engineer helmets and just tested several different models with different prompts to write commit messages. We found that the Mistral 7b model hosted by CloudFlare generated consistent good results. The biggest challenge we ran into was when we proceeded to implement the feature to write inline JSDocs for our JavaScript and TypeScript programs. We needed to figure out how to parse the files to locate the functions to keep track of their positions so that when we received the JSDocs from the language models we didn't overwrite the functions when writing the comments inline. We ended up using a library called Treesitter to parse JavaScript and TypeScript, but that meant this feature only supported those two languages.

### Accomplishments we're proud of

& what we learned Our goal for this hackathon was to learn and use Rust. Our team consisted of members who came from a web development background (hence the language models only writing JSDocs), so we actually learned Rust as we were working on our project. We're extremely proud of this accomplishment and getting a working project was just icing on the cake.

### What's next

We developed this project with full intentions to use it everyday for our programming assignments. This means continuous tweaks and changes to the program until we're happy with how it functions. Some of us may fork it to make specific changes for their workflow in the future.

## README (from the GitHub repository)

# Automated Committing Machine

This was a caffeine fueled Rust project, hacked together over the course of CruzHacks 2024, that will look at your code changes and write commit messages for you. Even though the free Yerba Mate was good enough, we actually won the MLH AI with Cloudflare track!

Our entry into CruzHacks 20234: https://devpost.com/software/devshack


## Detected evidence (automated analysis)

Indexed codebase: 18 recognized source files, 33 KB.
- Rust (language) — detected in the code
- TypeScript (language) — detected in the code
- OpenAI (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (21 of 21)

```
.gitignore
Cargo.toml
foo.txt
README.md
src/app_config/config.rs
src/app_config/mod.rs
src/comment_handler/comment.rs
src/comment_handler/mod.rs
src/git_handler/git.rs
src/git_handler/mod.rs
src/git_handler/read_me_gen.rs
src/handlers/commit.rs
src/handlers/mod.rs
src/handlers/prs.rs
src/img_handler/base64_to_jpg.rs
src/img_handler/code_summarizer.rs
src/img_handler/img.rs
src/img_handler/mod.rs
src/main.rs
src/README.md
src/test/typescript-test.ts
```

### Dependencies

- Cargo.toml: anyhow@1.0, async-openai@0.18.0, async-recursion@1.0.5, clap@3.1.6, dirs@5.0.1, inquire@0.6.2, mime_guess@2.0, regex@1.10.2, reqwest@0.11.23, serde@1.0.195, serde_json@1.0, spinoff@0.8.0, tokio@1.35.1, toml@0.8.8, which@6.0.0

### Recent commits (newest first)

- Update README.md
- Merge pull request #9 from leavism/cmd_handler
- refactor(subcommand): renamed `SubCommand::RM` to `SubCommand::CRead` to better reflect its functionality of creating a readme file.
- refactor(git\_handler, readme\_gen): remove deprecated model and increase max characters limit for generated commit messages in README summary.
- refactor(git\_handler): add readme summary generator function to git\_handler module and use it in PRs handler to generate readme summary.
- Merge remote-tracking branch 'origin/HEAD' into cmd_handler
- Merge pull request #8 from leavism/rust-parser
- Removed dead code, renamed function
- Removed dead code, renamed functiondfs
- feat(handlers, comment\_handler): added `comment_handler` to generate JSDocs for TypeScript functions
- Merge branch 'cmd_handler' into rust-parser
- Added new comment command
- Fixed empty files & dir
- Merge pull request #7 from leavism/summary
- Merge branch 'summary' of https://github.com/leavism/automated-commenting-machine into summary
- yay
- Fixed main.rs
- feat(comment_handler): async function to comment typescript code
- refactor(git\_handler): simplified `edit_commit_message` function by removing unnecessary ampersand reference.
- refactor(.vscode): remove .vscode settings and placed into .gitignore

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

### Cargo.toml

```
[package]
name = "automated-commenting-machine"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
clap = { version = "3.1.6", features = ["derive"] }
mime_guess = "2.0"

serde = "1.0.195"
tokio = { version = "1.35.1", features = ["full"] }
inquire = "0.6.2"
anyhow = "1.0"
toml = "0.8.8"
async-recursion = "1.0.5"
dirs = "5.0.1"
reqwest = "0.11.23"
spinoff = "0.8.0"
which = "6.0.0"
async-openai = "0.18.0"
regex = "1.10.2"
serde_json = "1.0"

```

### src/main.rs

```rust
pub mod app_config;
mod comment_handler;
mod git_handler;
mod handlers;
mod img_handler;
use crate::{app_config::config, git_handler::git};
use anyhow::{Context, Result};
use clap::{Parser, Subcommand};
use dirs::home_dir;
use handlers::prs::execute_prs;
use reqwest::Client;
use std::time::Duration;

#[derive(Parser, Debug)]
#[clap(
    author = "SF Hacks @ CruzHacks ^-^",
    version = "0.0.1",
    about = "Hii this Devtool automates some boring parts of coding like git commits"
)]
/// A Very simple Package Hunter
struct Arguments {
    #[clap(subcommand)]
    cmd: SubCommand,
}

#[derive(Subcommand, Debug)]
enum SubCommand {
    // Writes commit message based on git diff
    Commit {},
    // Creates a README
    CRead { path: Option<String> },
    // Writes JSDocs for TypeScript functions
    Comment { path: String },
}

#[tokio::main]
async fn main() -> Result<()> {
    let args = Arguments::parse();

    match args.cmd {
        SubCommand::Comment { path } => {
println!("Generating comments for {}", path);
            let result = comment_handler::comment::comment_file(&path).await?;
            println!("Done!\n{}", result);
        }
        SubCommand::CRead { path } => {
            match &path {
                Some(path) => execute_prs(path),
                None => execute_prs("."),
            }
            .await?
        }
        SubCommand::Commit {} => {
            let config_file = home_dir()
                .context("Failed to retrieve config directory.")?
                .join(".acm/config.toml");

            let config = config::load_config(&config_file).await?;

            git::git_checks().await?;

            let diffs = git::git_diff().await?;

            let http_client = Client::builder()
                .timeout(Duration::from_secs(config.request_timeout))
                .build()?;

            let commit_message =
                git::generate_commit_message(&http_client, &config, &diffs).await?;
            let commit_message = git::edit_commit_message(commit_message.trim())?;
            println!("{}", &git::git_commit(&commit_message).await?)
        }
    }
    Ok(())
}

```

### src/app_config/mod.rs

```rust
pub mod config;
```

### src/comment_handler/mod.rs

```rust
pub mod comment;

```

### src/handlers/mod.rs

```rust
pub mod prs;
pub mod commit;
```

### src/git_handler/mod.rs

```rust
pub mod git;
pub mod read_me_gen;
```

### src/img_handler/mod.rs

```rust
pub mod img;
pub(crate) mod code_summarizer;

```

### src/test/typescript-test.ts

```typescript
function multiply(a: number, b: number) {
	return a * b;
}

type Vector2 = {
	x: number;
	y: number;
};

function getDistance(p1: Vector2, p2: Vector2) {
	const { x: x1, y: y1 } = p1;
	const { x: x2, y: y2 } = p2;
	const y = x2 - x1;
	const x = y2 - y1;
	return Math.sqrt(x * x + y * y);
};
```

### src/comment_handler/comment.rs

```rust
use anyhow::{ensure, Context, Result};
use tokio::process::Command;

async fn run_comment_command(args: &[&str]) -> Result<String> {
    let response = Command::new("aicomment")
        .args(args)
        .output()
        .await
        .context("Failed to execute python script.")?;

    ensure!(
        response.status.success(),
        "{}",
        String::from_utf8_lossy(&response.stderr)
    );

    String::from_utf8(response.stdout).context("Failed to decode output of Python script.")
}

pub async fn comment_file(path: &str) -> Result<String> {
    let result = run_comment_command(&[path, "--gpt4"])
        .await?
        .trim()
        .to_string();

    Ok(result)
}

```

### src/handlers/commit.rs

```rust

// use crate::{git_handler::git, app_config::config};

// use anyhow::{Context, Result};
// use dirs::home_dir;
// use reqwest::Client;
// use std::time::Duration;


// pub async fn execute_commit() -> Result<()>  {
//     let config_file = home_dir()
//         .context("Failed to retrieve config directory.")?
//         .join(".acm/config.toml");

//     let config = config::load_config(&config_file).await?;

//     git::git_checks().await?;

//     let diffs = git::git_diff().await?;

//     let http_client = Client::builder()
//         .timeout(Duration::from_secs(config.request_timeout))
//         .build()?;

//     let commit_message = git::generate_commit_message(&http_client, &config, &diffs).await?;
//     let commit_message = git::edit_commit_message(commit_message.trim())?;
//     println!("{}", &git::git_commit(&commit_message).await?);
//     Ok(())
// }

```

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