UNPKG

@deep-assistant/agent

Version:

A minimal, public domain AI CLI agent compatible with OpenCode's JSON interface. Bun-only runtime.

106 lines (101 loc) 2.76 kB
import z from "zod" import { Filesystem } from "../util/filesystem" import path from "path" import { $ } from "bun" import { Storage } from "../storage/storage" import { Log } from "../util/log" import { Flag } from "../flag/flag" export namespace Project { const log = Log.create({ service: "project" }) export const Info = z .object({ id: z.string(), worktree: z.string(), vcs: z.literal("git").optional(), time: z.object({ created: z.number(), initialized: z.number().optional(), }), }) .meta({ ref: "Project", }) export type Info = z.infer<typeof Info> export async function fromDirectory(directory: string) { log.info("fromDirectory", { directory }) const matches = Filesystem.up({ targets: [".git"], start: directory }) const git = await matches.next().then((x) => x.value) await matches.return() if (!git) { const project: Info = { id: "global", worktree: "/", vcs: "none", // No VCS time: { created: Date.now(), }, } await Storage.write<Info>(["project", "global"], project) return project } let worktree = path.dirname(git) const timer = log.time("git.rev-parse") let id = await Bun.file(path.join(git, "opencode")) .text() .then((x) => x.trim()) .catch(() => {}) if (!id) { const roots = await $`git rev-list --max-parents=0 --all` .quiet() .nothrow() .cwd(worktree) .text() .then((x) => x .split("\n") .filter(Boolean) .map((x) => x.trim()) .toSorted(), ) id = roots[0] if (id) Bun.file(path.join(git, "opencode")).write(id) } timer.stop() if (!id) { const project: Info = { id: "global", worktree: "/", time: { created: Date.now(), }, } await Storage.write<Info>(["project", "global"], project) return project } worktree = await $`git rev-parse --path-format=absolute --show-toplevel` .quiet() .nothrow() .cwd(worktree) .text() .then((x) => x.trim()) const project: Info = { id, worktree, vcs: "git", time: { created: Date.now(), }, } await Storage.write<Info>(["project", id], project) return project } export async function setInitialized(projectID: string) { await Storage.update<Info>(["project", projectID], (draft) => { draft.time.initialized = Date.now() }) } export async function list() { const keys = await Storage.list(["project"]) return await Promise.all(keys.map((x) => Storage.read<Info>(x))) } }