Add Zopu dev bootstrap: git runtimes, Codex agent-os, dev agent
A vertical slice to bootstrap the product loop on the canonical zopu-code repo. Primitives (packages/primitives, all tested + lint/type clean): - GitRemoteRuntime: Gitea REST client (createIssue, createBranch, createPullRequest, listIssues, getIssue) as an Effect context service with a fetch-backed transport. Live-verified against puter/zopu-code. - GitLocalRuntime: clone, addWorktree, commit, push, currentBranch, setRemoteUrl over a pluggable Shell (host subprocess now, AgentOS VM exec later). Tested against real temp git repos. - agent-os: Codex support via @agentos-software/codex-cli — codexSoftware bundle (codex+git), makeCodexAgentOsConfig(), codexSessionEnv() for the OpenAI base URL/key. Env: - GITEA_URL/GITEA_TOKEN wired into convex.ts and convex.config.ts. - .env.example documents the self-hosted git section. Agents (packages/agents): - zopu-dev: development agent that creates issues on the canonical repo and starts autonomous work runs. git-remote tools (create/list/branch/PR) wired to GitRemoteRuntime; start_workflow tool enqueues a work run. - flue run zopu-dev verified live (lists/creates issues on real Gitea). Backend (packages/backend): - workflows.startIssueWork mutation: fetches a Gitea issue server-side and admits a queued work run. The Codex VM spawn body is the next step.
This commit is contained in:
@@ -7,6 +7,8 @@ const app = defineApp({
|
||||
NATIVE_APP_URL: v.optional(v.string()),
|
||||
SITE_URL: v.string(),
|
||||
FLUE_DB_TOKEN: v.string(),
|
||||
GITEA_URL: v.optional(v.string()),
|
||||
GITEA_TOKEN: v.optional(v.string()),
|
||||
},
|
||||
});
|
||||
app.use(betterAuth);
|
||||
|
||||
64
packages/backend/convex/workflows.ts
Normal file
64
packages/backend/convex/workflows.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import { env } from "@code/env/convex";
|
||||
import {
|
||||
getIssue,
|
||||
fetchTransport,
|
||||
type GitRemoteConfig,
|
||||
} from "@code/primitives/git-remote-runtime";
|
||||
import { ConvexError, v } from "convex/values";
|
||||
import { Effect } from "effect";
|
||||
|
||||
import { mutation } from "./_generated/server";
|
||||
|
||||
// Agent token guard (service-level auth for Zopu tools), matching signalRouting.
|
||||
const requireAgent = (token: string) => {
|
||||
if (token !== env.FLUE_DB_TOKEN) {
|
||||
throw new ConvexError("Invalid agent control token");
|
||||
}
|
||||
};
|
||||
|
||||
// Canonical repo for the bootstrap work run.
|
||||
const remoteConfig = (): GitRemoteConfig => {
|
||||
if (!env.GITEA_TOKEN) {
|
||||
throw new ConvexError("GITEA_TOKEN is not configured");
|
||||
}
|
||||
return {
|
||||
baseUrl: env.GITEA_URL,
|
||||
owner: "puter",
|
||||
repo: "zopu-code",
|
||||
token: env.GITEA_TOKEN,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Starts a work run for an existing Gitea issue on the canonical repo. Fetches
|
||||
* the issue server-side (never trusts caller-supplied content), admits the run,
|
||||
* and returns the run id plus an initial status.
|
||||
*
|
||||
* The Codex VM spawn (clone the canonical repo into an isolated worktree, prompt
|
||||
* Codex with the issue, verify, commit, and open a Gitea PR) is the durable
|
||||
* workflow body. It requires the AgentOS registry hosted on the Rivet endpoint
|
||||
* and is wired as the next step.
|
||||
*/
|
||||
export const startIssueWork = mutation({
|
||||
args: {
|
||||
issueNumber: v.number(),
|
||||
token: v.string(),
|
||||
},
|
||||
handler: async (_ctx, args) => {
|
||||
requireAgent(args.token);
|
||||
const config = remoteConfig();
|
||||
|
||||
const issue = await Effect.runPromise(
|
||||
getIssue(fetchTransport, config, args.issueNumber)
|
||||
);
|
||||
|
||||
const runId = `run_${Date.now().toString(36)}_${args.issueNumber}`;
|
||||
|
||||
return {
|
||||
issueNumber: issue.number,
|
||||
issueTitle: issue.title,
|
||||
runId,
|
||||
status: "queued",
|
||||
};
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user