git/git

Source: src/git/git.ts

The git a run is allowed to do - and nothing else.

A prompt is not a permission boundary. An agent given bash and told “never push” will push the day it decides that is what the user meant. So the agent writes the commit message - a text, which is what a model is for - and the irreversible act stays here, in code that can only do what it has functions for.

What has no function here, on purpose: push, reset, rebase, checkout of an existing branch, anything --force, anything that rewrites history. Adding one is a decision someone has to take in a diff, not an argument a model can produce at runtime.

deleteBranch is the one that looks like an exception and is not: -d makes git refuse any branch holding commits nothing else reaches, so it can clear away a name and never work.

branchName

function

export function branchName(request: string, prefix = "combo"): string { /* … */ }

A branch name from a request: combo/add-a-cache.

Kept short and free of anything git dislikes. The prefix says who made it, so a git branch listing shows at a glance what came from a run.

commitAll

function

export async function commitAll(cwd: string, message: string): Promise<GitResult<string>> { /* … */ }

Stages everything and commits it, with the message read from stdin.

-F - rather than -m: a message written by a model contains quotes, backticks and newlines, and none of them should ever reach a shell. There is no shell here at all, and this keeps it that way for the body too.

Returns the short sha. A clean working tree is an error, not an empty commit.

createBranch

function

export async function createBranch(cwd: string, name: string): Promise<GitResult<string>> { /* … */ }

Creates a branch and switches to it.

checkout -b fails when the branch exists, and that failure is kept: landing on somebody else’s branch is exactly what a dedicated branch is meant to prevent.

diff

function

export async function diff(cwd: string, maxBytes = 60_000): Promise<GitResult<string>> { /* … */ }

The diff itself, truncated to maxBytes.

It is written straight into a prompt, and an agent that receives half a megabyte of diff writes a worse message than one that receives the first pages and is told it was cut.

diffStat

function

export async function diffStat(cwd: string): Promise<GitResult<string>> { /* … */ }

git diff --stat over tracked changes, including what is staged.

isRepository

function

export async function isRepository(cwd: string): Promise<boolean> { /* … */ }

Whether cwd is inside a git working tree.

status

function

export async function status(cwd: string): Promise<GitResult<string>> { /* … */ }

Porcelain status. Empty means a clean working tree - nothing to commit.

untracked

function

export async function untracked(cwd: string): Promise<string[]> { /* … */ }

Untracked files, which git diff does not show but git add -A will commit.