ci / check (push) Canceled after 0s
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>
51 lines
2.2 KiB
TypeScript
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 }
|
|
}
|