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>
This commit is contained in:
355 files changed
+47028
No files matched your search
@@ -0,0 +1,50 @@
|
||||
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 }
|
||||
}
|
||||
Reference in new issue
Block a user