Files
LLeMbas-CLI/src/git/repo.ts
T
HomerandClaude Opus 5.5 f9bad01ed7
ci / check (push) Canceled after 0s
LLeMbas CLI 1.0.0
The first public release of LLeMbas CLI: a terminal coding agent and project manager for any LLM
API, with permission modes, git snapshots, memory and skills, knowledge bases, MCP, voice, and a
link to a LLeMbas instance whose web UI can work its sessions too. Signed Linux binaries for x64
and arm64.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 21:59:03 +00:00

51 lines
2.2 KiB
TypeScript

import { git } from "./run.ts"
export interface RepoState {
branch: string
upstream?: string
ahead: number
behind: number
/** Changed paths, as `git status --porcelain` codes: " M src/a.ts", "?? new.txt". */
changes: string[]
recent: string[]
detached: boolean
}
/** Branch, divergence, working-tree changes and the last commits — or undefined outside a repo. */
export function repoState(root: string, commits = 5): RepoState | undefined {
const st = git(root, ["status", "--porcelain=v1", "--branch", "--untracked-files=normal"])
if (st.code !== 0) return undefined
const [head = "", ...changes] = st.out.split("\n")
// "## main...origin/main [ahead 2, behind 1]" | "## HEAD (no branch)" | "## No commits yet on main"
const m = /^## (?:No commits yet on )?(.+?)(?:\.\.\.(\S+))?(?: \[(.+)\])?$/.exec(head)
const detached = head.includes("(no branch)")
const info = m?.[3] ?? ""
const log = git(root, ["log", `-${commits}`, "--format=%h %s"])
return {
branch: detached ? "HEAD (detached)" : (m?.[1] ?? "?"),
upstream: m?.[2],
ahead: Number(/ahead (\d+)/.exec(info)?.[1] ?? 0),
behind: Number(/behind (\d+)/.exec(info)?.[1] ?? 0),
changes: changes.filter(Boolean),
recent: log.code === 0 && log.out ? log.out.split("\n") : [],
detached,
}
}
/** The git block of the system prompt. */
export function describeRepo(s: RepoState): string {
const lines = [`Branch: ${s.branch}${s.upstream ? ` (tracking ${s.upstream}${s.ahead || s.behind ? `, ahead ${s.ahead}, behind ${s.behind}` : ", up to date"})` : " (no upstream)"}`]
if (s.changes.length) {
const shown = s.changes.slice(0, 20).map((c) => ` ${c}`)
lines.push(`Uncommitted changes (${s.changes.length}):`, ...shown, ...(s.changes.length > 20 ? [` … ${s.changes.length - 20} more`] : []))
} else lines.push("Working tree clean.")
if (s.recent.length) lines.push("Recent commits:", ...s.recent.map((c) => ` ${c}`))
else lines.push("No commits yet.")
return lines.join("\n")
}
export function gitInit(root: string): { ok: boolean; message: string } {
const r = git(root, ["init", "-q", "-b", "main"])
return r.code === 0 ? { ok: true, message: `initialised an empty git repository in ${root} (branch main, no remote)` } : { ok: false, message: r.err }
}