10 Commits

34 changed files with 2833 additions and 170 deletions

View File

@@ -17,7 +17,9 @@ DAEMON_NAME=Local MacBook
DAEMON_VERSION=0.0.0 DAEMON_VERSION=0.0.0
DAEMON_HEARTBEAT_MS=15000 DAEMON_HEARTBEAT_MS=15000
DAEMON_COMMAND_LEASE_MS=60000 DAEMON_COMMAND_LEASE_MS=60000
# RIVET_ENDPOINT=http://localhost:6420 RIVET_ENDPOINT=http://localhost:6420
RIVET_PUBLIC_ENDPOINT=http://localhost:6420
RIVET_WORKSPACE_TOKEN=replace-with-a-long-random-workspace-token
# Flue persistence adapter # Flue persistence adapter
FLUE_DB_TOKEN=replace-with-a-long-random-token FLUE_DB_TOKEN=replace-with-a-long-random-token

View File

@@ -5,8 +5,10 @@ import {
} from "@code/ui/components/ai-elements/conversation"; } from "@code/ui/components/ai-elements/conversation";
import { Button } from "@code/ui/components/button"; import { Button } from "@code/ui/components/button";
import { import {
AlertTriangle,
ChevronRight, ChevronRight,
Check, Check,
FileCode2,
FolderGit2, FolderGit2,
Hammer, Hammer,
LoaderCircle, LoaderCircle,
@@ -15,8 +17,10 @@ import {
ImagePlus, ImagePlus,
Play, Play,
RotateCcw, RotateCcw,
ScrollText,
Send, Send,
Sparkles, Sparkles,
Settings,
X, X,
} from "lucide-react"; } from "lucide-react";
import { useMemo, useRef, useState } from "react"; import { useMemo, useRef, useState } from "react";
@@ -35,6 +39,28 @@ import {
type SliceWork = NonNullable<ReturnType<typeof useSliceOne>["works"]>[number]; type SliceWork = NonNullable<ReturnType<typeof useSliceOne>["works"]>[number];
const EMPTY_WORKS: readonly SliceWork[] = []; const EMPTY_WORKS: readonly SliceWork[] = [];
type SliceArtifact = NonNullable<
NonNullable<SliceWork["runs"][number]["artifacts"]>[number]
>;
interface ArtifactMetadata {
readonly changedFiles?: readonly string[];
}
const parseArtifactMetadata = (artifact: SliceArtifact): ArtifactMetadata => {
if (!artifact.metadataJson) {
return {};
}
try {
return JSON.parse(artifact.metadataJson) as ArtifactMetadata;
} catch {
return {};
}
};
const changedFilesFor = (artifact: SliceArtifact): readonly string[] =>
parseArtifactMetadata(artifact).changedFiles ?? [];
interface WorkCardProps { interface WorkCardProps {
readonly onSourceSelect: (rawText: string) => void; readonly onSourceSelect: (rawText: string) => void;
readonly work: SliceWork; readonly work: SliceWork;
@@ -95,6 +121,7 @@ const starterDesign = (work: SliceWork) => ({
const WorkCard = ({ onSourceSelect, work, slice }: WorkCardProps) => { const WorkCard = ({ onSourceSelect, work, slice }: WorkCardProps) => {
const [sourcesOpen, setSourcesOpen] = useState(false); const [sourcesOpen, setSourcesOpen] = useState(false);
const [expanded, setExpanded] = useState(false); const [expanded, setExpanded] = useState(false);
const [logsOpen, setLogsOpen] = useState(false);
const sources = work.signals.flatMap((signal) => signal.sources); const sources = work.signals.flatMap((signal) => signal.sources);
const { definition } = work; const { definition } = work;
const { design } = work; const { design } = work;
@@ -257,26 +284,122 @@ const WorkCard = ({ onSourceSelect, work, slice }: WorkCardProps) => {
<p className="font-semibold uppercase tracking-wide text-[#65713a]"> <p className="font-semibold uppercase tracking-wide text-[#65713a]">
Build Build
</p> </p>
{latestRun ? ( {slice.operationError ? (
<p className="mt-1 leading-5 text-[#626057]"> <p className="mt-2 flex items-start gap-1.5 border border-red-300 bg-red-50 px-2 py-1.5 text-red-800">
Run {latestRun.status}:{" "} <AlertTriangle className="mt-0.5 size-3.5 shrink-0" />
{latestRun.terminalSummary ?? <span className="min-w-0 flex-1 leading-5">
latestRun.terminalClassification ?? {slice.operationError.message}
"activity is still arriving"} </span>
<button
aria-label="Dismiss error"
className="shrink-0"
onClick={() => slice.clearOperationError()}
type="button"
>
<X className="size-3.5" />
</button>
</p> </p>
) : null}
{latestRun ? (
<div className="mt-1 space-y-2 text-[#626057]">
<p className="leading-5">
{latestRun.executionKind === "real"
? "AgentOS"
: "Simulation"}{" "}
run {latestRun.status}:{" "}
{latestRun.terminalSummary ??
latestRun.terminalClassification ??
"activity is still arriving"}
</p>
{latestRun.baseRevision ? (
<p className="font-mono text-[10px] text-[#747168]">
{latestRun.baseRevision.slice(0, 8)} {" "}
{latestRun.candidateRevision?.slice(0, 8) ?? "working"}
</p>
) : null}
{latestRun.artifacts?.map((artifact) => {
const changedFiles = changedFilesFor(artifact);
return (
<div key={artifact._id} className="space-y-1">
{artifact.uri ? (
<a
className="block font-medium underline"
href={artifact.uri}
rel="noreferrer"
target="_blank"
>
{artifact.title}
</a>
) : (
<p className="font-medium">{artifact.title}</p>
)}
{changedFiles.length > 0 ? (
<ul className="space-y-0.5">
{changedFiles.map((file) => (
<li
className="flex items-start gap-1.5 font-mono text-[11px] leading-5 text-[#747168]"
key={file}
>
<FileCode2 className="mt-0.5 size-3 shrink-0 text-[#9a985f]" />
<span className="min-w-0 break-all">{file}</span>
</li>
))}
</ul>
) : null}
</div>
);
})}
{latestRun.attemptEvents &&
latestRun.attemptEvents.length > 0 ? (
<div className="space-y-1">
{(logsOpen
? latestRun.attemptEvents
: latestRun.attemptEvents.slice(-3)
).map((item) => (
<p
className="border-l-2 border-[#b8c760] pl-2 leading-5"
key={item._id}
>
{item.message}
</p>
))}
{latestRun.attemptEvents.length > 3 ? (
<button
className="flex items-center gap-1 font-medium text-[#65713a] hover:underline"
onClick={() => setLogsOpen((open) => !open)}
type="button"
>
<ScrollText className="size-3.5" />
{logsOpen
? "Show recent activity"
: `Show full activity log (${latestRun.attemptEvents.length})`}
<ChevronRight
className={`size-3.5 transition-transform ${logsOpen ? "rotate-90" : ""}`}
/>
</button>
) : null}
</div>
) : null}
</div>
) : ( ) : (
<p className="mt-1 text-[#747168]">No simulation Run yet.</p> <p className="mt-1 text-[#747168]">No implementation Run yet.</p>
)} )}
<div className="mt-2 flex flex-wrap gap-2"> <div className="mt-2 flex flex-wrap gap-2">
{work.status === "ready" ? ( {work.status === "ready" ? (
<Button <Button
size="sm" size="sm"
disabled={!slice.projectGitConnection}
onClick={() => void slice.startExecution(work._id)}
>
<Play className="size-3.5" /> Run
</Button>
) : null}
{work.status === "ready" ? (
<Button
size="sm"
variant="outline"
onClick={() => onClick={() =>
void slice.startSimulation( void slice.startSimulation(work._id, "success")
work._id,
"success",
design?.slices?.[0]?.id
)
} }
> >
<Play className="size-3.5" /> Simulate <Play className="size-3.5" /> Simulate
@@ -286,12 +409,17 @@ const WorkCard = ({ onSourceSelect, work, slice }: WorkCardProps) => {
<Button <Button
size="sm" size="sm"
variant="outline" variant="outline"
onClick={() => void slice.cancelSimulation(latestRun._id)} onClick={() =>
void (latestRun.executionKind === "real"
? slice.cancelExecution(latestRun._id)
: slice.cancelSimulation(latestRun._id))
}
> >
<X className="size-3.5" /> Cancel <X className="size-3.5" /> Cancel
</Button> </Button>
) : null} ) : null}
{latestRun?.status === "terminal" && {latestRun?.executionKind !== "real" &&
latestRun?.status === "terminal" &&
latestRun.terminalClassification === "RetryableFailure" ? ( latestRun.terminalClassification === "RetryableFailure" ? (
<Button <Button
size="sm" size="sm"
@@ -381,6 +509,7 @@ const ConnectProject = ({ slice }: { slice: SliceOneState }) => (
</main> </main>
); );
// oxlint-disable-next-line complexity -- this page coordinates the existing mobile shell without owning domain logic.
export const SliceOnePage = () => { export const SliceOnePage = () => {
const slice = useSliceOne(); const slice = useSliceOne();
const viewportStyle = useVisualViewportStyle(); const viewportStyle = useVisualViewportStyle();
@@ -388,6 +517,10 @@ export const SliceOnePage = () => {
const attachments = useChatImages(); const attachments = useChatImages();
const imageInput = useRef<HTMLInputElement>(null); const imageInput = useRef<HTMLInputElement>(null);
const [drawerOpen, setDrawerOpen] = useState(false); const [drawerOpen, setDrawerOpen] = useState(false);
const [settingsOpen, setSettingsOpen] = useState(false);
const [giteaUrl, setGiteaUrl] = useState("https://git.openputer.com");
const [giteaUsername, setGiteaUsername] = useState("");
const [giteaToken, setGiteaToken] = useState("");
const [highlightedMessageId, setHighlightedMessageId] = useState<string>(); const [highlightedMessageId, setHighlightedMessageId] = useState<string>();
const highlightTimer = useRef<ReturnType<typeof setTimeout> | null>(null); const highlightTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
const works = slice.works ?? EMPTY_WORKS; const works = slice.works ?? EMPTY_WORKS;
@@ -450,7 +583,7 @@ export const SliceOnePage = () => {
style={viewportStyle} style={viewportStyle}
> >
<section className="flex min-w-0 flex-1 flex-col"> <section className="flex min-w-0 flex-1 flex-col">
<header className="flex h-14 shrink-0 items-center border-b border-[#d7d3c7] bg-[#faf9f4] px-4"> <header className="relative flex h-14 shrink-0 items-center border-b border-[#d7d3c7] bg-[#faf9f4] px-4">
<div className="min-w-0 flex-1 pr-2"> <div className="min-w-0 flex-1 pr-2">
<select <select
aria-label="Current project" aria-label="Current project"
@@ -468,6 +601,15 @@ export const SliceOnePage = () => {
Conversation to proposed Work Conversation to proposed Work
</p> </p>
</div> </div>
<Button
aria-label="Project settings"
className="mr-2 size-9"
onClick={() => setSettingsOpen((open) => !open)}
size="icon"
variant="outline"
>
<Settings className="size-4" />
</Button>
<button <button
className="flex h-9 items-center gap-2 border border-[#c9c5b9] bg-white px-3 text-xs lg:hidden" className="flex h-9 items-center gap-2 border border-[#c9c5b9] bg-white px-3 text-xs lg:hidden"
onClick={() => setDrawerOpen(true)} onClick={() => setDrawerOpen(true)}
@@ -476,6 +618,94 @@ export const SliceOnePage = () => {
<Menu className="size-4" /> Work{" "} <Menu className="size-4" /> Work{" "}
{slice.works === undefined ? "…" : works.length} {slice.works === undefined ? "…" : works.length}
</button> </button>
{settingsOpen ? (
<section className="absolute right-4 top-12 z-40 w-[min(92vw,360px)] border border-[#c9c5b9] bg-[#fffefa] p-4 shadow-xl">
<div className="flex items-center justify-between">
<h2 className="text-sm font-semibold">Project Git</h2>
<button
aria-label="Close settings"
onClick={() => setSettingsOpen(false)}
type="button"
>
<X className="size-4" />
</button>
</div>
<p className="mt-1 text-xs text-[#747168]">
{slice.projectGitConnection
? `${slice.projectGitConnection.provider} · ${slice.projectGitConnection.serverUrl}`
: "No Git credentials attached"}
</p>
{slice.operationError ? (
<p className="mt-2 flex items-start gap-1.5 border border-red-300 bg-red-50 px-2 py-1.5 text-xs text-red-800">
<AlertTriangle className="mt-0.5 size-3.5 shrink-0" />
<span className="min-w-0 flex-1 leading-5">
{slice.operationError.message}
</span>
<button
aria-label="Dismiss error"
className="shrink-0"
onClick={() => slice.clearOperationError()}
type="button"
>
<X className="size-3.5" />
</button>
</p>
) : null}
<div className="mt-4 flex gap-2">
<Button
size="sm"
variant="outline"
onClick={() => void slice.authorizeGithub()}
>
Authorize GitHub
</Button>
<Button
size="sm"
onClick={() => void slice.connectLinkedGithub()}
>
Use GitHub
</Button>
</div>
<div className="mt-4 space-y-2 border-t border-[#e7e3d9] pt-4">
<input
aria-label="Gitea server URL"
className="h-9 w-full border px-2 text-xs"
onChange={(event) => setGiteaUrl(event.target.value)}
value={giteaUrl}
/>
<input
aria-label="Gitea username"
className="h-9 w-full border px-2 text-xs"
onChange={(event) => setGiteaUsername(event.target.value)}
placeholder="Username (optional)"
value={giteaUsername}
/>
<input
aria-label="Gitea access token"
className="h-9 w-full border px-2 text-xs"
onChange={(event) => setGiteaToken(event.target.value)}
placeholder="Personal access token"
type="password"
value={giteaToken}
/>
<Button
className="w-full"
disabled={!giteaToken.trim()}
size="sm"
onClick={() => {
void slice.connectGitea({
serverUrl: giteaUrl,
token: giteaToken,
username: giteaUsername || undefined,
});
setGiteaToken("");
}}
>
Connect Gitea
</Button>
</div>
</section>
) : null}
</header> </header>
<Conversation className="min-h-0 flex-1"> <Conversation className="min-h-0 flex-1">
<ConversationContent className="mx-auto min-h-full w-full max-w-2xl gap-4 px-4 py-5 sm:px-6"> <ConversationContent className="mx-auto min-h-full w-full max-w-2xl gap-4 px-4 py-5 sm:px-6">

View File

@@ -1,3 +1,4 @@
import { authClient } from "@code/auth/web";
import { api } from "@code/backend/convex/_generated/api"; import { api } from "@code/backend/convex/_generated/api";
import type { Id } from "@code/backend/convex/_generated/dataModel"; import type { Id } from "@code/backend/convex/_generated/dataModel";
import { useAction, useMutation, useQuery } from "convex/react"; import { useAction, useMutation, useQuery } from "convex/react";
@@ -27,6 +28,25 @@ interface WorkRecord {
readonly designs: readonly unknown[]; readonly designs: readonly unknown[];
readonly slices: readonly unknown[]; readonly slices: readonly unknown[];
readonly runs: readonly { readonly runs: readonly {
readonly artifacts?: readonly {
_id: string;
kind: string;
metadataJson: string;
sourceRevision?: string;
title: string;
uri?: string;
}[];
readonly attemptEvents?: readonly {
_id: string;
kind: string;
message: string;
metadataJson: string;
occurredAt: number;
sequence: number;
}[];
readonly baseRevision?: string;
readonly candidateRevision?: string;
readonly executionKind?: string;
_id: Id<"workRuns">; _id: Id<"workRuns">;
status: string; status: string;
terminalClassification?: string; terminalClassification?: string;
@@ -96,6 +116,57 @@ const retrySimulationRef = makeFunctionReference<
{ runId: Id<"workRuns"> }, { runId: Id<"workRuns"> },
unknown unknown
>("workExecution:retrySimulatedExecution"); >("workExecution:retrySimulatedExecution");
const startExecutionRef = makeFunctionReference<
"mutation",
{ workId: Id<"works">; sliceId?: string },
unknown
>("workExecutionWorkflow:startExecution");
const cancelExecutionRef = makeFunctionReference<
"mutation",
{ runId: Id<"workRuns"> },
unknown
>("workExecutionWorkflow:cancelExecution");
const listGitConnectionsRef = makeFunctionReference<
"query",
Record<string, never>,
readonly {
id: string;
provider: "github" | "gitea";
serverUrl: string;
username?: string;
}[]
>("gitConnectionData:list");
const projectGitConnectionRef = makeFunctionReference<
"query",
{ projectId: Id<"projects"> },
{
id: string;
provider: "github" | "gitea";
serverUrl: string;
username?: string;
} | null
>("gitConnectionData:getForProject");
const connectGiteaRef = makeFunctionReference<
"action",
{ serverUrl: string; token: string; username?: string },
{ connectionId: Id<"gitConnections"> }
>("gitConnections:connectGitea");
const connectGithubRef = makeFunctionReference<
"action",
Record<string, never>,
{ connectionId: Id<"gitConnections"> }
>("gitConnections:connectGithub");
const attachGitConnectionRef = makeFunctionReference<
"mutation",
{ connectionId: Id<"gitConnections">; projectId: Id<"projects"> },
unknown
>("gitConnectionData:attachToProject");
const authorizeGithub = () =>
authClient.signIn.social({
callbackURL: window.location.href,
provider: "github",
});
export const useSliceOne = () => { export const useSliceOne = () => {
const organization = usePersonalOrganization(); const organization = usePersonalOrganization();
@@ -110,6 +181,20 @@ export const useSliceOne = () => {
const [repository, setRepository] = useState(""); const [repository, setRepository] = useState("");
const [pending, setPending] = useState(false); const [pending, setPending] = useState(false);
const [error, setError] = useState<Error>(); const [error, setError] = useState<Error>();
const [operationError, setOperationError] = useState<Error>();
const captureOperationError =
<TArgs extends unknown[], TResult>(
operation: (...args: TArgs) => Promise<TResult>
) =>
async (...args: TArgs): Promise<TResult> => {
setOperationError(undefined);
try {
return await operation(...args);
} catch (caughtError) {
setOperationError(toError(caughtError));
throw caughtError;
}
};
const selectedProjectStillExists = projects?.some( const selectedProjectStillExists = projects?.some(
(project) => project.id === (selectedProjectId as unknown as string) (project) => project.id === (selectedProjectId as unknown as string)
); );
@@ -120,6 +205,14 @@ export const useSliceOne = () => {
workListRef, workListRef,
activeProjectId ? { projectId: activeProjectId } : "skip" activeProjectId ? { projectId: activeProjectId } : "skip"
); );
const gitConnections = useQuery(
listGitConnectionsRef,
organization.organizationId ? {} : "skip"
);
const projectGitConnection = useQuery(
projectGitConnectionRef,
activeProjectId ? { projectId: activeProjectId } : "skip"
);
const requestDefinitionMutation = useMutation(requestDefinitionRef); const requestDefinitionMutation = useMutation(requestDefinitionRef);
const saveDefinitionMutation = useMutation(saveDefinitionRef); const saveDefinitionMutation = useMutation(saveDefinitionRef);
const approveDefinitionMutation = useMutation(approveDefinitionRef); const approveDefinitionMutation = useMutation(approveDefinitionRef);
@@ -128,6 +221,11 @@ export const useSliceOne = () => {
const startSimulationMutation = useMutation(startSimulationRef); const startSimulationMutation = useMutation(startSimulationRef);
const cancelSimulationMutation = useMutation(cancelSimulationRef); const cancelSimulationMutation = useMutation(cancelSimulationRef);
const retrySimulationMutation = useMutation(retrySimulationRef); const retrySimulationMutation = useMutation(retrySimulationRef);
const startExecutionMutation = useMutation(startExecutionRef);
const cancelExecutionMutation = useMutation(cancelExecutionRef);
const attachGitConnectionMutation = useMutation(attachGitConnectionRef);
const connectGiteaAction = useAction(connectGiteaRef);
const connectGithubAction = useAction(connectGithubRef);
const selectedProject = useMemo( const selectedProject = useMemo(
() => () =>
projects?.find( projects?.find(
@@ -180,20 +278,54 @@ export const useSliceOne = () => {
| "permanent-failure" | "permanent-failure"
| "cancelled", | "cancelled",
sliceId?: string sliceId?: string
) => startSimulationMutation({ scenario, sliceId, workId }); ) =>
captureOperationError(() =>
startSimulationMutation({ scenario, sliceId, workId })
)();
const cancelSimulation = (runId: Id<"workRuns">) => const cancelSimulation = (runId: Id<"workRuns">) =>
cancelSimulationMutation({ runId }); captureOperationError(() => cancelSimulationMutation({ runId }))();
const retrySimulation = (runId: Id<"workRuns">) => const retrySimulation = (runId: Id<"workRuns">) =>
retrySimulationMutation({ runId }); captureOperationError(() => retrySimulationMutation({ runId }))();
const startExecution = (workId: Id<"works">, sliceId?: string) =>
captureOperationError(() => startExecutionMutation({ sliceId, workId }))();
const cancelExecution = (runId: Id<"workRuns">) =>
captureOperationError(() => cancelExecutionMutation({ runId }))();
const attachConnection = async (connectionId: Id<"gitConnections">) => {
if (!activeProjectId) {
throw new Error("Select a project first");
}
await attachGitConnectionMutation({
connectionId,
projectId: activeProjectId,
});
};
const connectGitea = captureOperationError(
async (input: { serverUrl: string; token: string; username?: string }) => {
const result = await connectGiteaAction(input);
await attachConnection(result.connectionId);
}
);
const connectLinkedGithub = captureOperationError(async () => {
const result = await connectGithubAction({});
await attachConnection(result.connectionId);
});
return { return {
agent, agent,
approveDefinition, approveDefinition,
approveDesign, approveDesign,
authorizeGithub,
cancelExecution,
cancelSimulation, cancelSimulation,
clearOperationError: () => setOperationError(undefined),
connectGitea,
connectLinkedGithub,
connectRepository, connectRepository,
error, error,
gitConnections,
operationError,
pending, pending,
projectGitConnection,
projects, projects,
repository, repository,
requestDefinition, requestDefinition,
@@ -203,6 +335,7 @@ export const useSliceOne = () => {
selectProject, selectProject,
selectedProject, selectedProject,
setRepository, setRepository,
startExecution,
startSimulation, startSimulation,
works, works,
} as const; } as const;

View File

@@ -7,6 +7,9 @@ import { defineConfig } from "vite-plus";
export default defineConfig({ export default defineConfig({
envDir: path.resolve(import.meta.dirname, "../.."), envDir: path.resolve(import.meta.dirname, "../.."),
plugins: [tailwindcss(), reactRouter()], plugins: [tailwindcss(), reactRouter()],
ssr: {
noExternal: true,
},
resolve: { resolve: {
dedupe: ["convex", "react", "react-dom"], dedupe: ["convex", "react", "react-dom"],
tsconfigPaths: true, tsconfigPaths: true,

246
bun.lock
View File

@@ -64,11 +64,16 @@
"name": "@code/agents", "name": "@code/agents",
"version": "0.0.0", "version": "0.0.0",
"dependencies": { "dependencies": {
"@agentos-software/codex-cli": "0.3.4",
"@agentos-software/git": "0.3.3",
"@code/backend": "workspace:*", "@code/backend": "workspace:*",
"@code/env": "workspace:*", "@code/env": "workspace:*",
"@code/primitives": "workspace:*",
"@flue/runtime": "latest", "@flue/runtime": "latest",
"@rivet-dev/agentos": "0.2.10",
"convex": "catalog:", "convex": "catalog:",
"hono": "catalog:", "hono": "catalog:",
"rivetkit": "2.3.9",
"valibot": "catalog:", "valibot": "catalog:",
}, },
"devDependencies": { "devDependencies": {
@@ -114,6 +119,7 @@
"@code/env": "workspace:*", "@code/env": "workspace:*",
"@code/primitives": "workspace:*", "@code/primitives": "workspace:*",
"@convex-dev/better-auth": "catalog:", "@convex-dev/better-auth": "catalog:",
"@convex-dev/workflow": "0.4.4",
"better-auth": "catalog:", "better-auth": "catalog:",
"convex": "catalog:", "convex": "catalog:",
"effect": "catalog:", "effect": "catalog:",
@@ -148,7 +154,7 @@
"name": "@code/primitives", "name": "@code/primitives",
"version": "0.0.0", "version": "0.0.0",
"dependencies": { "dependencies": {
"@agentos-software/codex-cli": "0.3.4", "@agentos-software/codex": "0.2.7",
"@agentos-software/git": "0.3.3", "@agentos-software/git": "0.3.3",
"@rivet-dev/agentos": "catalog:", "@rivet-dev/agentos": "catalog:",
"effect": "catalog:", "effect": "catalog:",
@@ -196,6 +202,8 @@
}, },
}, },
"overrides": { "overrides": {
"react": "19.2.8",
"react-dom": "19.2.8",
"vite": "npm:@voidzero-dev/vite-plus-core@0.2.2", "vite": "npm:@voidzero-dev/vite-plus-core@0.2.2",
}, },
"catalog": { "catalog": {
@@ -238,9 +246,11 @@
"@agentos-software/claude-code": ["@agentos-software/claude-code@0.2.7", "", { "dependencies": { "@agentclientprotocol/sdk": "^0.16.1", "@anthropic-ai/claude-agent-sdk": "0.2.87", "zod": "^4.1.11" }, "bin": { "claude": "dist/claude-cli.mjs", "claude-sdk-acp": "dist/adapter.js" } }, "sha512-gXmqqOUWT98QvLkQXHn1UU8OOvqMO8BRSj+0PT99mOL6XNpBlPW6L065FJ9dC4IwJC5xeGzB1XFevjOdP7LwQg=="], "@agentos-software/claude-code": ["@agentos-software/claude-code@0.2.7", "", { "dependencies": { "@agentclientprotocol/sdk": "^0.16.1", "@anthropic-ai/claude-agent-sdk": "0.2.87", "zod": "^4.1.11" }, "bin": { "claude": "dist/claude-cli.mjs", "claude-sdk-acp": "dist/adapter.js" } }, "sha512-gXmqqOUWT98QvLkQXHn1UU8OOvqMO8BRSj+0PT99mOL6XNpBlPW6L065FJ9dC4IwJC5xeGzB1XFevjOdP7LwQg=="],
"@agentos-software/codex": ["@agentos-software/codex@0.2.7", "", { "dependencies": { "@agentos-software/codex-cli": "0.3.3" } }, "sha512-ZBQVJdbs1Z10YIeHA1vp1gsY81uXm3KhdBghjELtj97JB51vR8kpbtl2LAdLD5PZBf5D8VMtpsLAJlm76wwvdw=="],
"@agentos-software/codex-cli": ["@agentos-software/codex-cli@0.3.4", "", {}, "sha512-SAw3EOTa90dJLgEVVoE7JJIxHwticzdD9cEM9v00gpxhxC9vdLkeBva6rgWIUB9+qD1JEYBvUCyNkIpD2kT5YQ=="], "@agentos-software/codex-cli": ["@agentos-software/codex-cli@0.3.4", "", {}, "sha512-SAw3EOTa90dJLgEVVoE7JJIxHwticzdD9cEM9v00gpxhxC9vdLkeBva6rgWIUB9+qD1JEYBvUCyNkIpD2kT5YQ=="],
"@agentos-software/common": ["@agentos-software/common@0.2.14", "", { "dependencies": { "@agentos-software/coreutils": "0.3.4", "@agentos-software/diffutils": "0.3.4", "@agentos-software/findutils": "0.3.4", "@agentos-software/gawk": "0.3.4", "@agentos-software/grep": "0.3.4", "@agentos-software/gzip": "0.3.4", "@agentos-software/sed": "0.3.4", "@agentos-software/tar": "0.3.5" } }, "sha512-ve/ks2MZtXFN9JK+kcFnSMGI1tqoUy36sTKWYGqApcgg/3JJwqnMs4JIKL5OXjgCtDuTvTjRySbQvEKxGkeeSQ=="], "@agentos-software/common": ["@agentos-software/common@0.2.10", "", { "dependencies": { "@agentos-software/coreutils": "0.3.4", "@agentos-software/diffutils": "0.3.4", "@agentos-software/findutils": "0.3.4", "@agentos-software/gawk": "0.3.4", "@agentos-software/grep": "0.3.4", "@agentos-software/gzip": "0.3.4", "@agentos-software/sed": "0.3.4", "@agentos-software/tar": "0.3.4" } }, "sha512-hkqm0U2tlPraKdAIB7oi4YT7vNN6JT6fk2eRhF9r2tqeOdn2JN/Zql5gQh1+wKYIgdWu1JBj5TJlf99Px010Hg=="],
"@agentos-software/coreutils": ["@agentos-software/coreutils@0.3.4", "", {}, "sha512-tGd0gQjUjHnm+5KgOBwidwUtlkKnl9biQuD7X2sZl15VOhYqUJpnyLF33h/nF3r9WtOTclSiLj/dc2xCxmAXnw=="], "@agentos-software/coreutils": ["@agentos-software/coreutils@0.3.4", "", {}, "sha512-tGd0gQjUjHnm+5KgOBwidwUtlkKnl9biQuD7X2sZl15VOhYqUJpnyLF33h/nF3r9WtOTclSiLj/dc2xCxmAXnw=="],
@@ -256,7 +266,7 @@
"@agentos-software/gzip": ["@agentos-software/gzip@0.3.4", "", {}, "sha512-l7Y/Vwiwsqgna68yYwdNCnUBPGBg5zdmtjEFeG3hnDDFLe/02h17q0gUIqJmDBIAy1q9GoizqcFi7zXO2xygKg=="], "@agentos-software/gzip": ["@agentos-software/gzip@0.3.4", "", {}, "sha512-l7Y/Vwiwsqgna68yYwdNCnUBPGBg5zdmtjEFeG3hnDDFLe/02h17q0gUIqJmDBIAy1q9GoizqcFi7zXO2xygKg=="],
"@agentos-software/manifest": ["@agentos-software/manifest@0.2.14", "", {}, "sha512-c1lGWN7/d1lku6Kl+wj6w1YoLX6wI93IyiUoE6M/Hgl1PP1YIPUqGFM5P5sZ9gG9M0qQ86T/587gECj1elZQBg=="], "@agentos-software/manifest": ["@agentos-software/manifest@0.2.10", "", {}, "sha512-eKmqcnmrzowntVV8F65JD7ZzJHD8u6zM7YKz3o+r3qq8Z5JF/0iGpxCVnTt66/Abg/5vZqjhEIRHkik+2snrWw=="],
"@agentos-software/opencode": ["@agentos-software/opencode@0.2.7", "", { "bin": { "agentos-opencode-acp": "dist/adapter.js" } }, "sha512-lZspCiMgM0+kPAA08CEvyNy8lfBx463wObKpAwbYyaVvc0KfGvbAPS6VmnuZQWmaBmJJuRMtSo14nmb8XCD16g=="], "@agentos-software/opencode": ["@agentos-software/opencode@0.2.7", "", { "bin": { "agentos-opencode-acp": "dist/adapter.js" } }, "sha512-lZspCiMgM0+kPAA08CEvyNy8lfBx463wObKpAwbYyaVvc0KfGvbAPS6VmnuZQWmaBmJJuRMtSo14nmb8XCD16g=="],
@@ -264,7 +274,7 @@
"@agentos-software/sed": ["@agentos-software/sed@0.3.4", "", {}, "sha512-J10nZnZmme2SvXK5WMK2unQlOVncMQVUCS20GZB579a2gNoayLJYHGvfJ9a4+42wOHgDKL1u74byWlydCkEyOQ=="], "@agentos-software/sed": ["@agentos-software/sed@0.3.4", "", {}, "sha512-J10nZnZmme2SvXK5WMK2unQlOVncMQVUCS20GZB579a2gNoayLJYHGvfJ9a4+42wOHgDKL1u74byWlydCkEyOQ=="],
"@agentos-software/tar": ["@agentos-software/tar@0.3.5", "", {}, "sha512-hSf6PY4q1luIomFSDgVHxVDDIPdAVZxdgwrQFEYH4aIE6TXX9qatVmzR36uYLWpnFGAZTR6srREGoTnmOGV4Lg=="], "@agentos-software/tar": ["@agentos-software/tar@0.3.4", "", {}, "sha512-/SSqfgS5xOufvulsz5kVDTCFxpDy+5s7Og1iJe9krjU7Jvtgnp9TpPaJnSr721h6uY6tsWHcs3u8E457EwSkNw=="],
"@ai-sdk/gateway": ["@ai-sdk/gateway@4.0.28", "", { "dependencies": { "@ai-sdk/provider": "4.0.3", "@ai-sdk/provider-utils": "5.0.12", "@vercel/oidc": "3.2.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ee9TsNO3mkgHDWmTmJ8Fvltr6PFh52zhrV2+FaKJY3F3iu7kWZi5tCRJCR1HVhhlpj6lHniUb28nLQdPHkA/1Q=="], "@ai-sdk/gateway": ["@ai-sdk/gateway@4.0.28", "", { "dependencies": { "@ai-sdk/provider": "4.0.3", "@ai-sdk/provider-utils": "5.0.12", "@vercel/oidc": "3.2.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ee9TsNO3mkgHDWmTmJ8Fvltr6PFh52zhrV2+FaKJY3F3iu7kWZi5tCRJCR1HVhhlpj6lHniUb28nLQdPHkA/1Q=="],
@@ -564,6 +574,10 @@
"@convex-dev/better-auth": ["@convex-dev/better-auth@0.12.5", "", { "dependencies": { "@better-fetch/fetch": "^1.1.18", "common-tags": "^1.8.2", "convex-helpers": "^0.1.95", "jose": "^6.1.0", "remeda": "^2.32.0", "semver": "^7.7.3", "type-fest": "^5.0.0", "zod": "^4.0.0" }, "peerDependencies": { "better-auth": ">=1.6.11 <1.7.0", "convex": "^1.25.0", "react": "^18.3.1 || ^19.0.0" } }, "sha512-YFUbGk04OlINno9FpOTNZN67AP+kSQsblfep5zs1f/WTgMWjD5FymU6rSSh3mu52gukmDNnBJTjC/lj4QRpjlQ=="], "@convex-dev/better-auth": ["@convex-dev/better-auth@0.12.5", "", { "dependencies": { "@better-fetch/fetch": "^1.1.18", "common-tags": "^1.8.2", "convex-helpers": "^0.1.95", "jose": "^6.1.0", "remeda": "^2.32.0", "semver": "^7.7.3", "type-fest": "^5.0.0", "zod": "^4.0.0" }, "peerDependencies": { "better-auth": ">=1.6.11 <1.7.0", "convex": "^1.25.0", "react": "^18.3.1 || ^19.0.0" } }, "sha512-YFUbGk04OlINno9FpOTNZN67AP+kSQsblfep5zs1f/WTgMWjD5FymU6rSSh3mu52gukmDNnBJTjC/lj4QRpjlQ=="],
"@convex-dev/workflow": ["@convex-dev/workflow@0.4.4", "", { "dependencies": { "async-channel": "^0.2.0" }, "peerDependencies": { "@convex-dev/workpool": "^0.4.4", "convex": "^1.36.1", "convex-helpers": "^0.1.99" } }, "sha512-ZQfVspAAxG4zZJEep2qaRtupw8OewwMezq6KNKaXKjo/gA+YffS9bXz13x+L/TSt9/Lb6gioae6Y9PDrqh7xQg=="],
"@convex-dev/workpool": ["@convex-dev/workpool@0.4.8", "", { "peerDependencies": { "convex": "^1.36.1", "convex-helpers": "^0.1.94" } }, "sha512-ExUV3dVxUK/m2gQGB0PGuTNX/8pNtJM1T2Z+iprEhu7/4UBKM5flmu5odKBcffDnTzlGTPUQ2X+dwzy8l9T19g=="],
"@cspotcode/source-map-support": ["@cspotcode/source-map-support@0.8.1", "", { "dependencies": { "@jridgewell/trace-mapping": "0.3.9" } }, "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw=="], "@cspotcode/source-map-support": ["@cspotcode/source-map-support@0.8.1", "", { "dependencies": { "@jridgewell/trace-mapping": "0.3.9" } }, "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw=="],
"@dotenvx/dotenvx": ["@dotenvx/dotenvx@1.75.1", "", { "dependencies": { "@dotenvx/primitives": "^0.8.0", "commander": "^11.1.0", "conf": "^10.2.0", "dotenv": "^17.2.1", "enquirer": "^2.4.1", "env-paths": "^2.2.1", "execa": "^5.1.1", "fdir": "^6.2.0", "ignore": "^5.3.0", "object-treeify": "1.1.33", "open": "^8.4.2", "picomatch": "^4.0.4", "systeminformation": "^5.22.11", "undici": "^7.11.0", "which": "^4.0.0", "yocto-spinner": "^1.1.0" }, "bin": { "dotenvx": "src/cli/dotenvx.js" } }, "sha512-/BITOC9dmS/edY2zQwZNicQ059O6RKabtQfyEafV0nGtfYRNHYy1DIPiYVcov40+tob9hfmBnbR963dS+EQ1DQ=="], "@dotenvx/dotenvx": ["@dotenvx/dotenvx@1.75.1", "", { "dependencies": { "@dotenvx/primitives": "^0.8.0", "commander": "^11.1.0", "conf": "^10.2.0", "dotenv": "^17.2.1", "enquirer": "^2.4.1", "env-paths": "^2.2.1", "execa": "^5.1.1", "fdir": "^6.2.0", "ignore": "^5.3.0", "object-treeify": "1.1.33", "open": "^8.4.2", "picomatch": "^4.0.4", "systeminformation": "^5.22.11", "undici": "^7.11.0", "which": "^4.0.0", "yocto-spinner": "^1.1.0" }, "bin": { "dotenvx": "src/cli/dotenvx.js" } }, "sha512-/BITOC9dmS/edY2zQwZNicQ059O6RKabtQfyEafV0nGtfYRNHYy1DIPiYVcov40+tob9hfmBnbR963dS+EQ1DQ=="],
@@ -1104,31 +1118,31 @@
"@rivet-dev/agent-os-python": ["@rivet-dev/agent-os-python@0.1.0", "", { "dependencies": { "@secure-exec/core": "^0.2.1", "pyodide": "^0.28.3" } }, "sha512-1tH1beMf1ceSpicQKwN/a6h+NmJrmfuT4GStiRDZmvN/UWfZhkxuy7HR5VPTQpE/feUZJ01FdtBS3Em/Qoxb2Q=="], "@rivet-dev/agent-os-python": ["@rivet-dev/agent-os-python@0.1.0", "", { "dependencies": { "@secure-exec/core": "^0.2.1", "pyodide": "^0.28.3" } }, "sha512-1tH1beMf1ceSpicQKwN/a6h+NmJrmfuT4GStiRDZmvN/UWfZhkxuy7HR5VPTQpE/feUZJ01FdtBS3Em/Qoxb2Q=="],
"@rivet-dev/agentos": ["@rivet-dev/agentos@0.2.14", "", { "dependencies": { "@agentclientprotocol/sdk": "0.16.1", "@agentos-software/common": "0.2.14", "@rivet-dev/agentos-core": "0.2.14", "@rivetkit/react": "2.3.9", "rivetkit": "2.3.9", "zod": "^4.1.11" }, "peerDependencies": { "react": "^18 || ^19", "react-dom": "^18 || ^19" }, "optionalPeers": ["react", "react-dom"] }, "sha512-dr7GU8AA02wB906gdQ6tyfCTyOa08KtT8djpUdtprbx7GLkaUQpq0j60BVeS/OkTUzEwYexWEKmKyGL1U/EgiQ=="], "@rivet-dev/agentos": ["@rivet-dev/agentos@0.2.10", "", { "dependencies": { "@agentclientprotocol/sdk": "0.16.1", "@agentos-software/common": "0.2.10", "@rivet-dev/agentos-core": "0.2.10", "@rivetkit/react": "2.3.7", "rivetkit": "2.3.7", "zod": "^4.1.11" }, "peerDependencies": { "react": "^18 || ^19", "react-dom": "^18 || ^19" }, "optionalPeers": ["react", "react-dom"] }, "sha512-0R/1p1iesYJtOSarHmfO5pV6BurCQx0z7V+ssIAIXtNaNs7pgMFRrooWsr9UnAJj/xWJ+lM9xIUTHe+o8dE3dw=="],
"@rivet-dev/agentos-core": ["@rivet-dev/agentos-core@0.2.14", "", { "dependencies": { "@agentclientprotocol/sdk": "0.16.1", "@agentos-software/claude-code": "0.2.7", "@agentos-software/codex-cli": "0.3.4", "@agentos-software/common": "0.2.14", "@agentos-software/manifest": "0.2.14", "@agentos-software/opencode": "0.2.7", "@agentos-software/pi": "0.2.7", "@aws-sdk/client-s3": "^3.1019.0", "@rivet-dev/agentos-runtime-core": "0.2.14", "@rivet-dev/agentos-sidecar": "0.2.14", "@rivetkit/bare-ts": "^0.6.2", "@xterm/headless": "^6.0.0", "better-sqlite3": "^12.8.0", "croner": "^10.0.1", "googleapis": "^144.0.0", "isolated-vm": "^6.0.0", "long-timeout": "^0.1.1", "minimatch": "^10.2.4", "zod": "^4.1.11", "zod-to-json-schema": "^3.25.2" } }, "sha512-YAbK0NpauQKlcuSKl0eXB95ZdNopMGmXw1dBaoSlODKVYoKTjOEKwUtSEvx/zZB0Cse2kSQ/IrJpLe183QeQPw=="], "@rivet-dev/agentos-core": ["@rivet-dev/agentos-core@0.2.10", "", { "dependencies": { "@agentclientprotocol/sdk": "0.16.1", "@agentos-software/claude-code": "0.2.7", "@agentos-software/codex-cli": "0.3.4", "@agentos-software/common": "0.2.10", "@agentos-software/manifest": "0.2.10", "@agentos-software/opencode": "0.2.7", "@agentos-software/pi": "0.2.7", "@aws-sdk/client-s3": "^3.1019.0", "@rivet-dev/agentos-runtime-core": "0.2.10", "@rivet-dev/agentos-sidecar": "0.2.10", "@rivetkit/bare-ts": "^0.6.2", "@xterm/headless": "^6.0.0", "better-sqlite3": "^12.8.0", "croner": "^10.0.1", "googleapis": "^144.0.0", "isolated-vm": "^6.0.0", "long-timeout": "^0.1.1", "minimatch": "^10.2.4", "zod": "^4.1.11", "zod-to-json-schema": "^3.25.2" } }, "sha512-0UMQgBFOmMtiZ0UhQ3cJei44tRmY9VzTpkJh4a+g0HWjAz5thUH2OCYtmF+tGNU8qzHhyN9hBFwT744YMRV/Dg=="],
"@rivet-dev/agentos-runtime-core": ["@rivet-dev/agentos-runtime-core@0.2.14", "", { "dependencies": { "@rivet-dev/agentos-runtime-sidecar": "0.2.14", "@rivetkit/bare-ts": "^0.6.2", "zod": "^4.1.11" } }, "sha512-mZYas5wUZXjwLLLHq6uMOaajtyc/3iLQ6vGzOH4E3OHBwCfK054YwGU8iunRqWtk+Wd7MPetzstxzdu+72nBug=="], "@rivet-dev/agentos-runtime-core": ["@rivet-dev/agentos-runtime-core@0.2.10", "", { "dependencies": { "@rivet-dev/agentos-runtime-sidecar": "0.2.10", "@rivetkit/bare-ts": "^0.6.2", "zod": "^4.1.11" } }, "sha512-qMmWhDZ/IWL0QOKnASl1STHwRQaDknX34DTX1p+fCjcWbf2QD+ScQMTLdll52oyhQl8KhXn+Tlyhp+XTdqaySQ=="],
"@rivet-dev/agentos-runtime-sidecar": ["@rivet-dev/agentos-runtime-sidecar@0.2.14", "", { "optionalDependencies": { "@rivet-dev/agentos-runtime-sidecar-darwin-arm64": "0.2.14", "@rivet-dev/agentos-runtime-sidecar-darwin-x64": "0.2.14", "@rivet-dev/agentos-runtime-sidecar-linux-arm64-gnu": "0.2.14", "@rivet-dev/agentos-runtime-sidecar-linux-x64-gnu": "0.2.14" } }, "sha512-dsA1wNg+0Y6DYRB8no962k1tAQk1y5kfdAbrpKjJQJjfgfwkv0q8XZ3ybtt1hLml/thgE32CI++8F7MRWz4TFA=="], "@rivet-dev/agentos-runtime-sidecar": ["@rivet-dev/agentos-runtime-sidecar@0.2.10", "", { "optionalDependencies": { "@rivet-dev/agentos-runtime-sidecar-darwin-arm64": "0.2.10", "@rivet-dev/agentos-runtime-sidecar-darwin-x64": "0.2.10", "@rivet-dev/agentos-runtime-sidecar-linux-arm64-gnu": "0.2.10", "@rivet-dev/agentos-runtime-sidecar-linux-x64-gnu": "0.2.10" } }, "sha512-v2KXHTTQYHdMpNFhBt3/wCyKajwxq9o4jKLYpaa9mYiaBdHfORuBaDI9e3WDGEly7HCIEWNnwvkNMvoQoHnXnQ=="],
"@rivet-dev/agentos-runtime-sidecar-darwin-arm64": ["@rivet-dev/agentos-runtime-sidecar-darwin-arm64@0.2.14", "", { "os": "darwin", "cpu": "arm64" }, "sha512-5pKvG7TC3lKbCMbQZptyXd3QPQyfiJ+wKqA+u5SqoP+Lqwim9C4PVSYMLUaxx0QqxliNuNu+VWif1xM91yECiw=="], "@rivet-dev/agentos-runtime-sidecar-darwin-arm64": ["@rivet-dev/agentos-runtime-sidecar-darwin-arm64@0.2.10", "", { "os": "darwin", "cpu": "arm64" }, "sha512-PJ5rJZmgpS/EX9Zn1UA6Z5Ol0Y31UJKfD7Fisdqy7hlJuxhQVS9cVFrp3bud2og9s3n32riEYTx1mUE1PVQKZA=="],
"@rivet-dev/agentos-runtime-sidecar-darwin-x64": ["@rivet-dev/agentos-runtime-sidecar-darwin-x64@0.2.14", "", { "os": "darwin", "cpu": "x64" }, "sha512-mTSDuMXKHSpMJ3SVLCb/3sBCpOaBw0fnEsnLzVSuicuSWSzhNe4yyUeAcyz4wsuT4l+M+Z5mDH1eydfpz7nltw=="], "@rivet-dev/agentos-runtime-sidecar-darwin-x64": ["@rivet-dev/agentos-runtime-sidecar-darwin-x64@0.2.10", "", { "os": "darwin", "cpu": "x64" }, "sha512-+C4gEE7/pT36fclYqdUYt6bMUj6CsDDZ+2Kxuej57/q06cSa9W5Od2zIO4wxZbI6g0EoN5zVJ8qXv+jSOtTLbg=="],
"@rivet-dev/agentos-runtime-sidecar-linux-arm64-gnu": ["@rivet-dev/agentos-runtime-sidecar-linux-arm64-gnu@0.2.14", "", { "os": "linux", "cpu": "arm64" }, "sha512-bVtITOH4sNxcq8RuBMJF+Srlwa/Rl1ARZIej+MUDBR8VM7DGnBMWCaCHvYxy3JBmdP5aTb3gCwUm6e7m4/Khgw=="], "@rivet-dev/agentos-runtime-sidecar-linux-arm64-gnu": ["@rivet-dev/agentos-runtime-sidecar-linux-arm64-gnu@0.2.10", "", { "os": "linux", "cpu": "arm64" }, "sha512-BSs/LkKkNxvNBD9qEmxPWHmdHQokNGkGS3dcI3LTY4D6Sgat1Vun1OQ53v1HQSGf/TuAfgYOzbQPikvOU3zkmQ=="],
"@rivet-dev/agentos-runtime-sidecar-linux-x64-gnu": ["@rivet-dev/agentos-runtime-sidecar-linux-x64-gnu@0.2.14", "", { "os": "linux", "cpu": "x64" }, "sha512-NOI1m456Ev06ey4O0pVnITaYA7emeoKR2lJIFJP4j9Kv0XuXpbmaz1aigfa3/SZQ7AvqOzxbNLCcH5m22iO8ng=="], "@rivet-dev/agentos-runtime-sidecar-linux-x64-gnu": ["@rivet-dev/agentos-runtime-sidecar-linux-x64-gnu@0.2.10", "", { "os": "linux", "cpu": "x64" }, "sha512-IIM0ILGdPNjettgBVOXvrNTICggo/xNtKO0V3kM7XJiQ4DkQQkjA1/Y0JBdLvsigt7HAcEJ38zQ3ahl+HOXK8w=="],
"@rivet-dev/agentos-sidecar": ["@rivet-dev/agentos-sidecar@0.2.14", "", { "optionalDependencies": { "@rivet-dev/agentos-sidecar-darwin-arm64": "0.2.14", "@rivet-dev/agentos-sidecar-darwin-x64": "0.2.14", "@rivet-dev/agentos-sidecar-linux-arm64-gnu": "0.2.14", "@rivet-dev/agentos-sidecar-linux-x64-gnu": "0.2.14" } }, "sha512-aISMeC7UY5Mjum/DiYp3idZa/EnNZ76FGke29FVQHmBfwVX6dTx2R/FHjZdEE+iOCi9APxAHIvdu8C+EVp6q2A=="], "@rivet-dev/agentos-sidecar": ["@rivet-dev/agentos-sidecar@0.2.10", "", { "optionalDependencies": { "@rivet-dev/agentos-sidecar-darwin-arm64": "0.2.10", "@rivet-dev/agentos-sidecar-darwin-x64": "0.2.10", "@rivet-dev/agentos-sidecar-linux-arm64-gnu": "0.2.10", "@rivet-dev/agentos-sidecar-linux-x64-gnu": "0.2.10" } }, "sha512-3bq7k/OrtMffUT+aDSeXPIEDEaJLbPXzQ5oUqnjsU+6Hsmvvf+nAl/zTvHyQOMmriQiQ1BPMPqgNyXAc5BrV3w=="],
"@rivet-dev/agentos-sidecar-darwin-arm64": ["@rivet-dev/agentos-sidecar-darwin-arm64@0.2.14", "", { "os": "darwin", "cpu": "arm64" }, "sha512-U1R4wYvlsLCdASC5Lf6oP/6bW6ONGsiILtTQSVgxIHl/J1TrmOifrAbRgDC205kThJEZQ2op8kVzol5aEWOpbA=="], "@rivet-dev/agentos-sidecar-darwin-arm64": ["@rivet-dev/agentos-sidecar-darwin-arm64@0.2.10", "", { "os": "darwin", "cpu": "arm64" }, "sha512-q+54J8WLa/Diyn5H+TVZwIHt4kVFCBkwtco5DjUmFmG6y5ozzPl6MM0vVzIx6iNTzhWiYOFLz5PybICmy6j7BQ=="],
"@rivet-dev/agentos-sidecar-darwin-x64": ["@rivet-dev/agentos-sidecar-darwin-x64@0.2.14", "", { "os": "darwin", "cpu": "x64" }, "sha512-vuij3BYGjVSCGMNB3HbS0EiDS50xG68cjH3ItuZL77GPHsw5V765TOheWDVgUOo1Q3+VWjdMaS2wNWv63qCf0w=="], "@rivet-dev/agentos-sidecar-darwin-x64": ["@rivet-dev/agentos-sidecar-darwin-x64@0.2.10", "", { "os": "darwin", "cpu": "x64" }, "sha512-Q0rAxtGjddpDcaB9keicukuExtIiynwX+DqVRG6hWjki0PSYqFqqrNFCzPiUswWf0u5Pakq1iBM+RgNu19PxZA=="],
"@rivet-dev/agentos-sidecar-linux-arm64-gnu": ["@rivet-dev/agentos-sidecar-linux-arm64-gnu@0.2.14", "", { "os": "linux", "cpu": "arm64" }, "sha512-nauooe07/NhHb+Wn4xvJTUMNFzhOvrNoPwceiC0eGvkK7+imRyZpAgSGB4qRiaa2NRyuNRVh+d6kzp5iKzBwnA=="], "@rivet-dev/agentos-sidecar-linux-arm64-gnu": ["@rivet-dev/agentos-sidecar-linux-arm64-gnu@0.2.10", "", { "os": "linux", "cpu": "arm64" }, "sha512-FVgsnPczeT4oMoiUTrOfadAtDGoHhd30lrAU2p/xxyeCOhHAsZt1h0xo2oCteLmZ78DJm3rLcsR+4zhY6AhtOw=="],
"@rivet-dev/agentos-sidecar-linux-x64-gnu": ["@rivet-dev/agentos-sidecar-linux-x64-gnu@0.2.14", "", { "os": "linux", "cpu": "x64" }, "sha512-PaGPXi5mS0Ef023nqS9lbMkMH6KGoOsHA3apAaOQz95lrmVx7E/z5BPzKYl3aYMYjmlo004mnNETVBZOy0VbQw=="], "@rivet-dev/agentos-sidecar-linux-x64-gnu": ["@rivet-dev/agentos-sidecar-linux-x64-gnu@0.2.10", "", { "os": "linux", "cpu": "x64" }, "sha512-WXKLIeZJvOo2Kxw2wPmPNc7QWM0lq69Xt/Yy2W86gYKORAFPVJ9GVag85ywP3LrjIW1oEDwzqrvMp3PGVkvVXg=="],
"@rivetkit/bare-ts": ["@rivetkit/bare-ts@0.6.2", "", {}, "sha512-3qndQUQXLdwafMEqfhz24hUtDPcsf1Bu3q52Kb8MqeH8JUh3h6R4HYW3ZJXiQsLcyYyFM68PuIwlLRlg1xDEpg=="], "@rivetkit/bare-ts": ["@rivetkit/bare-ts@0.6.2", "", {}, "sha512-3qndQUQXLdwafMEqfhz24hUtDPcsf1Bu3q52Kb8MqeH8JUh3h6R4HYW3ZJXiQsLcyYyFM68PuIwlLRlg1xDEpg=="],
@@ -1146,11 +1160,11 @@
"@rivetkit/engine-envoy-protocol": ["@rivetkit/engine-envoy-protocol@2.3.9", "", { "dependencies": { "@rivetkit/bare-ts": "^0.6.2" } }, "sha512-2IK41V9U8sgMnEYd/P6u/68nCufCU2dvxuHVV3uAV0uIVCdtRV8lkjuR2fSr05bwHmzSmewdqsbiNMiC/GWt8w=="], "@rivetkit/engine-envoy-protocol": ["@rivetkit/engine-envoy-protocol@2.3.9", "", { "dependencies": { "@rivetkit/bare-ts": "^0.6.2" } }, "sha512-2IK41V9U8sgMnEYd/P6u/68nCufCU2dvxuHVV3uAV0uIVCdtRV8lkjuR2fSr05bwHmzSmewdqsbiNMiC/GWt8w=="],
"@rivetkit/framework-base": ["@rivetkit/framework-base@2.3.9", "", { "dependencies": { "@tanstack/store": "^0.7.1", "fast-deep-equal": "^3.1.3", "rivetkit": "2.3.9" } }, "sha512-ZSxrclYcpmdGsLMiVE2dfWNfUB6diSx+t8k4EQgL4cN02ThzJD3BM5mhU+zQVCCwfNw42eRZVIoxydYDLl/yHw=="], "@rivetkit/framework-base": ["@rivetkit/framework-base@2.3.7", "", { "dependencies": { "@tanstack/store": "^0.7.1", "fast-deep-equal": "^3.1.3", "rivetkit": "2.3.7" } }, "sha512-zxmdAzFogA3PeT3ZgFIoYlEAJVi3iCwbPBXczZKf2x2QMCl2cTZ2jswFCAgHUUMQWj+AWiX65usxq73a9Ls/qQ=="],
"@rivetkit/on-change": ["@rivetkit/on-change@6.0.1", "", {}, "sha512-QBN/KRBXLJdCgN4gBTL3XAc/zKm58atSnieXWMOyFSPmo6F1/yIVV/LTRdvAktfCttrGx7W6c32i/lwqCHWnsQ=="], "@rivetkit/on-change": ["@rivetkit/on-change@6.0.1", "", {}, "sha512-QBN/KRBXLJdCgN4gBTL3XAc/zKm58atSnieXWMOyFSPmo6F1/yIVV/LTRdvAktfCttrGx7W6c32i/lwqCHWnsQ=="],
"@rivetkit/react": ["@rivetkit/react@2.3.9", "", { "dependencies": { "@rivetkit/framework-base": "2.3.9", "@tanstack/react-store": "^0.7.1", "rivetkit": "2.3.9" }, "peerDependencies": { "react": "^18 || ^19", "react-dom": "^18 || ^19" } }, "sha512-j9t82h/yIqqSt17coQZeRu3F9Q5w2FgWPDUC9fCyQUJp9PTjO7ea494PR0lSWvuEiwMRqE5JpgbHdYUQ1woE9w=="], "@rivetkit/react": ["@rivetkit/react@2.3.7", "", { "dependencies": { "@rivetkit/framework-base": "2.3.7", "@tanstack/react-store": "^0.7.1", "rivetkit": "2.3.7" }, "peerDependencies": { "react": "^18 || ^19", "react-dom": "^18 || ^19" } }, "sha512-Y3UoUYhkLKDQrJdloCmYK+fhJMlPw5BPHbRb5VutFh5L8csIRZLoCoMitzV7mjNUxuDE1+k10iGuUHYPZUP4aA=="],
"@rivetkit/rivetkit-napi": ["@rivetkit/rivetkit-napi@2.3.9", "", { "dependencies": { "@napi-rs/cli": "^2.18.4", "@rivetkit/engine-envoy-protocol": "2.3.9" }, "optionalDependencies": { "@rivetkit/rivetkit-napi-darwin-arm64": "2.3.9", "@rivetkit/rivetkit-napi-darwin-x64": "2.3.9", "@rivetkit/rivetkit-napi-linux-arm64-gnu": "2.3.9", "@rivetkit/rivetkit-napi-linux-arm64-musl": "2.3.9", "@rivetkit/rivetkit-napi-linux-x64-gnu": "2.3.9", "@rivetkit/rivetkit-napi-linux-x64-musl": "2.3.9", "@rivetkit/rivetkit-napi-win32-x64-msvc": "2.3.9" } }, "sha512-lUuOK1ja6ZMwnNRsdtqJeXChbBEqyvHuI/1h5XQWHfBUu7DgX5zuyA/FJ+BY6YFWtwnkHnOVCBJeNx/3gj8Xhg=="], "@rivetkit/rivetkit-napi": ["@rivetkit/rivetkit-napi@2.3.9", "", { "dependencies": { "@napi-rs/cli": "^2.18.4", "@rivetkit/engine-envoy-protocol": "2.3.9" }, "optionalDependencies": { "@rivetkit/rivetkit-napi-darwin-arm64": "2.3.9", "@rivetkit/rivetkit-napi-darwin-x64": "2.3.9", "@rivetkit/rivetkit-napi-linux-arm64-gnu": "2.3.9", "@rivetkit/rivetkit-napi-linux-arm64-musl": "2.3.9", "@rivetkit/rivetkit-napi-linux-x64-gnu": "2.3.9", "@rivetkit/rivetkit-napi-linux-x64-musl": "2.3.9", "@rivetkit/rivetkit-napi-win32-x64-msvc": "2.3.9" } }, "sha512-lUuOK1ja6ZMwnNRsdtqJeXChbBEqyvHuI/1h5XQWHfBUu7DgX5zuyA/FJ+BY6YFWtwnkHnOVCBJeNx/3gj8Xhg=="],
@@ -1608,6 +1622,8 @@
"ast-types": ["ast-types@0.16.1", "", { "dependencies": { "tslib": "^2.0.1" } }, "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg=="], "ast-types": ["ast-types@0.16.1", "", { "dependencies": { "tslib": "^2.0.1" } }, "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg=="],
"async-channel": ["async-channel@0.2.0", "", {}, "sha512-BJyjI/sfKlyijaBt2hbOSxT28xGNtLR0QLzAKO1Hlnv5BULY7sAoYoTPW3lfr1ZIC7y+FxabxO9T8GXpyoofGg=="],
"atomic-sleep": ["atomic-sleep@1.0.0", "", {}, "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ=="], "atomic-sleep": ["atomic-sleep@1.0.0", "", {}, "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ=="],
"atomically": ["atomically@1.7.0", "", {}, "sha512-Xcz9l0z7y9yQ9rdDaxlmaI4uJHf/T8g9hOEzJcsEqX2SjCj4J20uK7+ldkDHMbpJDK76wF7xEIgxc/vSlsfw5w=="], "atomically": ["atomically@1.7.0", "", {}, "sha512-Xcz9l0z7y9yQ9rdDaxlmaI4uJHf/T8g9hOEzJcsEqX2SjCj4J20uK7+ldkDHMbpJDK76wF7xEIgxc/vSlsfw5w=="],
@@ -2328,7 +2344,7 @@
"hono-openapi": ["hono-openapi@1.3.1", "", { "peerDependencies": { "@hono/standard-validator": "^0.2.0", "@standard-community/standard-json": "^0.3.5", "@standard-community/standard-openapi": "^0.2.9", "@types/json-schema": "^7.0.15", "hono": "^4.11.2", "openapi-types": "^12.1.3" }, "optionalPeers": ["@hono/standard-validator", "hono"] }, "sha512-NLVeVkhKZ3drmQNEIPac8HX8Y54uf1hJAgIM/7MfDsaeVVmB+QILWQxx5x3R3NvRHgedcbEbOCGY2uR7WQYyMw=="], "hono-openapi": ["hono-openapi@1.3.1", "", { "peerDependencies": { "@hono/standard-validator": "^0.2.0", "@standard-community/standard-json": "^0.3.5", "@standard-community/standard-openapi": "^0.2.9", "@types/json-schema": "^7.0.15", "hono": "^4.11.2", "openapi-types": "^12.1.3" }, "optionalPeers": ["@hono/standard-validator", "hono"] }, "sha512-NLVeVkhKZ3drmQNEIPac8HX8Y54uf1hJAgIM/7MfDsaeVVmB+QILWQxx5x3R3NvRHgedcbEbOCGY2uR7WQYyMw=="],
"hosted-git-info": ["hosted-git-info@7.0.2", "", { "dependencies": { "lru-cache": "^10.0.1" } }, "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w=="], "hosted-git-info": ["hosted-git-info@9.0.3", "", { "dependencies": { "lru-cache": "^11.1.0" } }, "sha512-Hc+ghLoSt6QaYZUv0WBiIvmMDZuZZ7oaDvdH8MbfOO4lOsxdXLEvuC6ePoGs9H1X9oCLyq6+NVN0MKqD+ydxyg=="],
"html-url-attributes": ["html-url-attributes@3.0.1", "", {}, "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ=="], "html-url-attributes": ["html-url-attributes@3.0.1", "", {}, "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ=="],
@@ -3018,7 +3034,7 @@
"pump": ["pump@3.0.4", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA=="], "pump": ["pump@3.0.4", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA=="],
"punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], "punycode": ["punycode@1.4.1", "", {}, "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ=="],
"pure-rand": ["pure-rand@8.4.2", "", {}, "sha512-vvuOGgcuPJAirlHvuQw1TrOiw7ptaIXXmIbNuiNOY6lNGJJH49PQ1Kj4nd783nPdQhQdicgOjVI2yI/9BD6/Ng=="], "pure-rand": ["pure-rand@8.4.2", "", {}, "sha512-vvuOGgcuPJAirlHvuQw1TrOiw7ptaIXXmIbNuiNOY6lNGJJH49PQ1Kj4nd783nPdQhQdicgOjVI2yI/9BD6/Ng=="],
@@ -3598,6 +3614,8 @@
"zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="], "zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="],
"@agentos-software/codex/@agentos-software/codex-cli": ["@agentos-software/codex-cli@0.3.3", "", {}, "sha512-63f4jymlxe4S003/4Fiu9Y/BAzT6ajHEDidfNqv39SkWNJWxT1ndY+j1/7XYT6NsGgg2ZSo+OGuexlkL8Jx1RA=="],
"@anthropic-ai/claude-agent-sdk/@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.74.0", "", { "dependencies": { "json-schema-to-ts": "^3.1.1" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["zod"], "bin": { "anthropic-ai-sdk": "bin/cli" } }, "sha512-srbJV7JKsc5cQ6eVuFzjZO7UR3xEPJqPamHFIe29bs38Ij2IripoAhC0S5NslNbaFUYqBKypmmpzMTpqfHEUDw=="], "@anthropic-ai/claude-agent-sdk/@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.74.0", "", { "dependencies": { "json-schema-to-ts": "^3.1.1" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["zod"], "bin": { "anthropic-ai-sdk": "bin/cli" } }, "sha512-srbJV7JKsc5cQ6eVuFzjZO7UR3xEPJqPamHFIe29bs38Ij2IripoAhC0S5NslNbaFUYqBKypmmpzMTpqfHEUDw=="],
"@anthropic-ai/claude-agent-sdk/@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.2.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w=="], "@anthropic-ai/claude-agent-sdk/@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.2.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w=="],
@@ -3618,6 +3636,8 @@
"@anthropic-ai/claude-agent-sdk/@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.34.5", "", { "os": "win32", "cpu": "x64" }, "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw=="], "@anthropic-ai/claude-agent-sdk/@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.34.5", "", { "os": "win32", "cpu": "x64" }, "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw=="],
"@aws-sdk/client-bedrock-runtime/@smithy/node-http-handler": ["@smithy/node-http-handler@4.9.12", "", { "dependencies": { "@smithy/core": "^3.31.0", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-dWW5KRt4mnEvjNzbGqGeCuAvgum85Y9ZoyuMQqcTEfapndyVJ1k9BEHK7kdXJZ32enyRmmwcFjMwlB/KgLKI3Q=="],
"@aws-sdk/client-s3/@smithy/node-http-handler": ["@smithy/node-http-handler@4.9.12", "", { "dependencies": { "@smithy/core": "^3.31.0", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-dWW5KRt4mnEvjNzbGqGeCuAvgum85Y9ZoyuMQqcTEfapndyVJ1k9BEHK7kdXJZ32enyRmmwcFjMwlB/KgLKI3Q=="], "@aws-sdk/client-s3/@smithy/node-http-handler": ["@smithy/node-http-handler@4.9.12", "", { "dependencies": { "@smithy/core": "^3.31.0", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-dWW5KRt4mnEvjNzbGqGeCuAvgum85Y9ZoyuMQqcTEfapndyVJ1k9BEHK7kdXJZ32enyRmmwcFjMwlB/KgLKI3Q=="],
"@aws-sdk/credential-provider-http/@smithy/node-http-handler": ["@smithy/node-http-handler@4.9.12", "", { "dependencies": { "@smithy/core": "^3.31.0", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-dWW5KRt4mnEvjNzbGqGeCuAvgum85Y9ZoyuMQqcTEfapndyVJ1k9BEHK7kdXJZ32enyRmmwcFjMwlB/KgLKI3Q=="], "@aws-sdk/credential-provider-http/@smithy/node-http-handler": ["@smithy/node-http-handler@4.9.12", "", { "dependencies": { "@smithy/core": "^3.31.0", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-dWW5KRt4mnEvjNzbGqGeCuAvgum85Y9ZoyuMQqcTEfapndyVJ1k9BEHK7kdXJZ32enyRmmwcFjMwlB/KgLKI3Q=="],
@@ -3638,6 +3658,8 @@
"@babel/plugin-transform-runtime/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], "@babel/plugin-transform-runtime/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
"@code/primitives/@rivet-dev/agentos": ["@rivet-dev/agentos@0.2.14", "", { "dependencies": { "@agentclientprotocol/sdk": "0.16.1", "@agentos-software/common": "0.2.14", "@rivet-dev/agentos-core": "0.2.14", "@rivetkit/react": "2.3.9", "rivetkit": "2.3.9", "zod": "^4.1.11" }, "peerDependencies": { "react": "^18 || ^19", "react-dom": "^18 || ^19" }, "optionalPeers": ["react", "react-dom"] }, "sha512-dr7GU8AA02wB906gdQ6tyfCTyOa08KtT8djpUdtprbx7GLkaUQpq0j60BVeS/OkTUzEwYexWEKmKyGL1U/EgiQ=="],
"@cspotcode/source-map-support/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.9", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ=="], "@cspotcode/source-map-support/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.9", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ=="],
"@dotenvx/dotenvx/commander": ["commander@11.1.0", "", {}, "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ=="], "@dotenvx/dotenvx/commander": ["commander@11.1.0", "", {}, "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ=="],
@@ -3692,11 +3714,13 @@
"@mariozechner/pi-ai/@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.73.0", "", { "dependencies": { "json-schema-to-ts": "^3.1.1" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["zod"], "bin": { "anthropic-ai-sdk": "bin/cli" } }, "sha512-URURVzhxXGJDGUGFunIOtBlSl7KWvZiAAKY/ttTkZAkXT9bTPqdk2eK0b8qqSxXpikh3QKPnPYpiyX98zf5ebw=="], "@mariozechner/pi-ai/@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.73.0", "", { "dependencies": { "json-schema-to-ts": "^3.1.1" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["zod"], "bin": { "anthropic-ai-sdk": "bin/cli" } }, "sha512-URURVzhxXGJDGUGFunIOtBlSl7KWvZiAAKY/ttTkZAkXT9bTPqdk2eK0b8qqSxXpikh3QKPnPYpiyX98zf5ebw=="],
"@mariozechner/pi-ai/@aws-sdk/client-bedrock-runtime": ["@aws-sdk/client-bedrock-runtime@3.1096.0", "", { "dependencies": { "@aws-sdk/core": "^3.977.1", "@aws-sdk/credential-provider-node": "^3.972.73", "@aws-sdk/eventstream-handler-node": "^3.972.30", "@aws-sdk/middleware-eventstream": "^3.972.25", "@aws-sdk/middleware-websocket": "^3.972.44", "@aws-sdk/token-providers": "3.1096.0", "@aws-sdk/types": "^3.974.2", "@smithy/core": "^3.29.8", "@smithy/fetch-http-handler": "^5.6.10", "@smithy/node-http-handler": "^4.9.10", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-5aZmG71QnMoQQry/UmT9tM1p/W2Sux34bg3nJPN4GP31Ei321jCgOaEVgCNzaRPzUZ94QuKIA5ND9obTlOw3vw=="],
"@mariozechner/pi-ai/@mistralai/mistralai": ["@mistralai/mistralai@1.14.1", "", { "dependencies": { "ws": "^8.18.0", "zod": "^3.25.0 || ^4.0.0", "zod-to-json-schema": "^3.24.1" } }, "sha512-IiLmmZFCCTReQgPAT33r7KQ1nYo5JPdvGkrkZqA8qQ2qB1GHgs5LoP5K2ICyrjnpw2n8oSxMM/VP+liiKcGNlQ=="], "@mariozechner/pi-ai/@mistralai/mistralai": ["@mistralai/mistralai@1.14.1", "", { "dependencies": { "ws": "^8.18.0", "zod": "^3.25.0 || ^4.0.0", "zod-to-json-schema": "^3.24.1" } }, "sha512-IiLmmZFCCTReQgPAT33r7KQ1nYo5JPdvGkrkZqA8qQ2qB1GHgs5LoP5K2ICyrjnpw2n8oSxMM/VP+liiKcGNlQ=="],
"@mariozechner/pi-ai/@sinclair/typebox": ["@sinclair/typebox@0.34.52", "", {}, "sha512-XiMQh7qqVlxZzcVD+kkGMNGMzcTrDMLWI7S4x7z1MkCkbDPrekpZXEUK0eZqZFMuHQg2a2DZOcDIh9o5v3Gonw=="], "@mariozechner/pi-ai/@sinclair/typebox": ["@sinclair/typebox@0.34.52", "", {}, "sha512-XiMQh7qqVlxZzcVD+kkGMNGMzcTrDMLWI7S4x7z1MkCkbDPrekpZXEUK0eZqZFMuHQg2a2DZOcDIh9o5v3Gonw=="],
"@mariozechner/pi-coding-agent/hosted-git-info": ["hosted-git-info@9.0.3", "", { "dependencies": { "lru-cache": "^11.1.0" } }, "sha512-Hc+ghLoSt6QaYZUv0WBiIvmMDZuZZ7oaDvdH8MbfOO4lOsxdXLEvuC6ePoGs9H1X9oCLyq6+NVN0MKqD+ydxyg=="], "@mariozechner/pi-coding-agent/ignore": ["ignore@7.0.6", "", {}, "sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw=="],
"@mariozechner/pi-coding-agent/marked": ["marked@15.0.12", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA=="], "@mariozechner/pi-coding-agent/marked": ["marked@15.0.12", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA=="],
@@ -3716,10 +3740,16 @@
"@react-router/dev/react-refresh": ["react-refresh@0.18.0", "", {}, "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw=="], "@react-router/dev/react-refresh": ["react-refresh@0.18.0", "", {}, "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw=="],
"@rivet-dev/agentos/rivetkit": ["rivetkit@2.3.7", "", { "dependencies": { "@hono/zod-openapi": "^1.1.5", "@rivet-dev/agent-os-core": "^0.1.1", "@rivetkit/bare-ts": "^0.6.2", "@rivetkit/engine-cli": "2.3.7", "@rivetkit/engine-envoy-protocol": "2.3.7", "@rivetkit/on-change": "6.0.1", "@rivetkit/rivetkit-napi": "2.3.7", "@rivetkit/rivetkit-wasm": "2.3.7", "@rivetkit/traces": "2.3.7", "@rivetkit/virtual-websocket": "2.3.7", "@rivetkit/workflow-engine": "2.3.7", "cbor-x": "^1.6.0", "drizzle-orm": "^0.44.2", "hono": "^4.7.0", "invariant": "^2.2.4", "p-retry": "^6.2.1", "pino": "^9.5.0", "uuid": "^12.0.0", "vbare": "^0.0.4", "zod": "^4.1.0" }, "peerDependencies": { "drizzle-kit": "^0.31.2", "eventsource": "^4.0.0", "ws": "^8.0.0" }, "optionalPeers": ["drizzle-kit", "eventsource", "ws"] }, "sha512-V2IWlXq9SRLJWrcYVa8WUftELCpbdsBVWZIqz2WQjhhzRK9Aan65RfMoZVx62A9k8HuIO6MH1nAPLhOuk1xePQ=="],
"@rivetkit/framework-base/@tanstack/store": ["@tanstack/store@0.7.7", "", {}, "sha512-xa6pTan1bcaqYDS9BDpSiS63qa6EoDkPN9RsRaxHuDdVDNntzq3xNwR5YKTU/V3SkSyC9T4YVOPh2zRQN0nhIQ=="], "@rivetkit/framework-base/@tanstack/store": ["@tanstack/store@0.7.7", "", {}, "sha512-xa6pTan1bcaqYDS9BDpSiS63qa6EoDkPN9RsRaxHuDdVDNntzq3xNwR5YKTU/V3SkSyC9T4YVOPh2zRQN0nhIQ=="],
"@rivetkit/framework-base/rivetkit": ["rivetkit@2.3.7", "", { "dependencies": { "@hono/zod-openapi": "^1.1.5", "@rivet-dev/agent-os-core": "^0.1.1", "@rivetkit/bare-ts": "^0.6.2", "@rivetkit/engine-cli": "2.3.7", "@rivetkit/engine-envoy-protocol": "2.3.7", "@rivetkit/on-change": "6.0.1", "@rivetkit/rivetkit-napi": "2.3.7", "@rivetkit/rivetkit-wasm": "2.3.7", "@rivetkit/traces": "2.3.7", "@rivetkit/virtual-websocket": "2.3.7", "@rivetkit/workflow-engine": "2.3.7", "cbor-x": "^1.6.0", "drizzle-orm": "^0.44.2", "hono": "^4.7.0", "invariant": "^2.2.4", "p-retry": "^6.2.1", "pino": "^9.5.0", "uuid": "^12.0.0", "vbare": "^0.0.4", "zod": "^4.1.0" }, "peerDependencies": { "drizzle-kit": "^0.31.2", "eventsource": "^4.0.0", "ws": "^8.0.0" }, "optionalPeers": ["drizzle-kit", "eventsource", "ws"] }, "sha512-V2IWlXq9SRLJWrcYVa8WUftELCpbdsBVWZIqz2WQjhhzRK9Aan65RfMoZVx62A9k8HuIO6MH1nAPLhOuk1xePQ=="],
"@rivetkit/react/@tanstack/react-store": ["@tanstack/react-store@0.7.7", "", { "dependencies": { "@tanstack/store": "0.7.7", "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-qqT0ufegFRDGSof9D/VqaZgjNgp4tRPHZIJq2+QIHkMUtHjaJ0lYrrXjeIUJvjnTbgPfSD1XgOMEt0lmANn6Zg=="], "@rivetkit/react/@tanstack/react-store": ["@tanstack/react-store@0.7.7", "", { "dependencies": { "@tanstack/store": "0.7.7", "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-qqT0ufegFRDGSof9D/VqaZgjNgp4tRPHZIJq2+QIHkMUtHjaJ0lYrrXjeIUJvjnTbgPfSD1XgOMEt0lmANn6Zg=="],
"@rivetkit/react/rivetkit": ["rivetkit@2.3.7", "", { "dependencies": { "@hono/zod-openapi": "^1.1.5", "@rivet-dev/agent-os-core": "^0.1.1", "@rivetkit/bare-ts": "^0.6.2", "@rivetkit/engine-cli": "2.3.7", "@rivetkit/engine-envoy-protocol": "2.3.7", "@rivetkit/on-change": "6.0.1", "@rivetkit/rivetkit-napi": "2.3.7", "@rivetkit/rivetkit-wasm": "2.3.7", "@rivetkit/traces": "2.3.7", "@rivetkit/virtual-websocket": "2.3.7", "@rivetkit/workflow-engine": "2.3.7", "cbor-x": "^1.6.0", "drizzle-orm": "^0.44.2", "hono": "^4.7.0", "invariant": "^2.2.4", "p-retry": "^6.2.1", "pino": "^9.5.0", "uuid": "^12.0.0", "vbare": "^0.0.4", "zod": "^4.1.0" }, "peerDependencies": { "drizzle-kit": "^0.31.2", "eventsource": "^4.0.0", "ws": "^8.0.0" }, "optionalPeers": ["drizzle-kit", "eventsource", "ws"] }, "sha512-V2IWlXq9SRLJWrcYVa8WUftELCpbdsBVWZIqz2WQjhhzRK9Aan65RfMoZVx62A9k8HuIO6MH1nAPLhOuk1xePQ=="],
"@secure-exec/nodejs/es-module-lexer": ["es-module-lexer@1.7.0", "", {}, "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA=="], "@secure-exec/nodejs/es-module-lexer": ["es-module-lexer@1.7.0", "", {}, "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA=="],
"@secure-exec/nodejs/esbuild": ["esbuild@0.27.7", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.7", "@esbuild/android-arm": "0.27.7", "@esbuild/android-arm64": "0.27.7", "@esbuild/android-x64": "0.27.7", "@esbuild/darwin-arm64": "0.27.7", "@esbuild/darwin-x64": "0.27.7", "@esbuild/freebsd-arm64": "0.27.7", "@esbuild/freebsd-x64": "0.27.7", "@esbuild/linux-arm": "0.27.7", "@esbuild/linux-arm64": "0.27.7", "@esbuild/linux-ia32": "0.27.7", "@esbuild/linux-loong64": "0.27.7", "@esbuild/linux-mips64el": "0.27.7", "@esbuild/linux-ppc64": "0.27.7", "@esbuild/linux-riscv64": "0.27.7", "@esbuild/linux-s390x": "0.27.7", "@esbuild/linux-x64": "0.27.7", "@esbuild/netbsd-arm64": "0.27.7", "@esbuild/netbsd-x64": "0.27.7", "@esbuild/openbsd-arm64": "0.27.7", "@esbuild/openbsd-x64": "0.27.7", "@esbuild/openharmony-arm64": "0.27.7", "@esbuild/sunos-x64": "0.27.7", "@esbuild/win32-arm64": "0.27.7", "@esbuild/win32-ia32": "0.27.7", "@esbuild/win32-x64": "0.27.7" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w=="], "@secure-exec/nodejs/esbuild": ["esbuild@0.27.7", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.7", "@esbuild/android-arm": "0.27.7", "@esbuild/android-arm64": "0.27.7", "@esbuild/android-x64": "0.27.7", "@esbuild/darwin-arm64": "0.27.7", "@esbuild/darwin-x64": "0.27.7", "@esbuild/freebsd-arm64": "0.27.7", "@esbuild/freebsd-x64": "0.27.7", "@esbuild/linux-arm": "0.27.7", "@esbuild/linux-arm64": "0.27.7", "@esbuild/linux-ia32": "0.27.7", "@esbuild/linux-loong64": "0.27.7", "@esbuild/linux-mips64el": "0.27.7", "@esbuild/linux-ppc64": "0.27.7", "@esbuild/linux-riscv64": "0.27.7", "@esbuild/linux-s390x": "0.27.7", "@esbuild/linux-x64": "0.27.7", "@esbuild/netbsd-arm64": "0.27.7", "@esbuild/netbsd-x64": "0.27.7", "@esbuild/openbsd-arm64": "0.27.7", "@esbuild/openbsd-x64": "0.27.7", "@esbuild/openharmony-arm64": "0.27.7", "@esbuild/sunos-x64": "0.27.7", "@esbuild/win32-arm64": "0.27.7", "@esbuild/win32-ia32": "0.27.7", "@esbuild/win32-x64": "0.27.7" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w=="],
@@ -3848,8 +3878,6 @@
"hoist-non-react-statics/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], "hoist-non-react-statics/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="],
"hosted-git-info/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
"import-fresh/resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], "import-fresh/resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="],
"is-inside-container/is-docker": ["is-docker@3.0.0", "", { "bin": { "is-docker": "cli.js" } }, "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ=="], "is-inside-container/is-docker": ["is-docker@3.0.0", "", { "bin": { "is-docker": "cli.js" } }, "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ=="],
@@ -3892,7 +3920,7 @@
"morgan/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], "morgan/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
"node-stdlib-browser/punycode": ["punycode@1.4.1", "", {}, "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ=="], "npm-package-arg/hosted-git-info": ["hosted-git-info@7.0.2", "", { "dependencies": { "lru-cache": "^10.0.1" } }, "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w=="],
"npm-package-arg/validate-npm-package-name": ["validate-npm-package-name@5.0.1", "", {}, "sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ=="], "npm-package-arg/validate-npm-package-name": ["validate-npm-package-name@5.0.1", "", {}, "sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ=="],
@@ -3966,7 +3994,7 @@
"type-is/content-type": ["content-type@2.0.0", "", {}, "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ=="], "type-is/content-type": ["content-type@2.0.0", "", {}, "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ=="],
"url/punycode": ["punycode@1.4.1", "", {}, "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ=="], "uri-js/punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
"vite-plus/oxfmt": ["oxfmt@0.57.0", "", { "dependencies": { "tinypool": "2.1.0" }, "optionalDependencies": { "@oxfmt/binding-android-arm-eabi": "0.57.0", "@oxfmt/binding-android-arm64": "0.57.0", "@oxfmt/binding-darwin-arm64": "0.57.0", "@oxfmt/binding-darwin-x64": "0.57.0", "@oxfmt/binding-freebsd-x64": "0.57.0", "@oxfmt/binding-linux-arm-gnueabihf": "0.57.0", "@oxfmt/binding-linux-arm-musleabihf": "0.57.0", "@oxfmt/binding-linux-arm64-gnu": "0.57.0", "@oxfmt/binding-linux-arm64-musl": "0.57.0", "@oxfmt/binding-linux-ppc64-gnu": "0.57.0", "@oxfmt/binding-linux-riscv64-gnu": "0.57.0", "@oxfmt/binding-linux-riscv64-musl": "0.57.0", "@oxfmt/binding-linux-s390x-gnu": "0.57.0", "@oxfmt/binding-linux-x64-gnu": "0.57.0", "@oxfmt/binding-linux-x64-musl": "0.57.0", "@oxfmt/binding-openharmony-arm64": "0.57.0", "@oxfmt/binding-win32-arm64-msvc": "0.57.0", "@oxfmt/binding-win32-ia32-msvc": "0.57.0", "@oxfmt/binding-win32-x64-msvc": "0.57.0" }, "peerDependencies": { "svelte": "^5.0.0", "vite-plus": "*" }, "optionalPeers": ["svelte", "vite-plus"], "bin": { "oxfmt": "bin/oxfmt" } }, "sha512-ZB7Bi+rGDSqmVIo9jwcLyFgjxXvQhDdU+jx+ZrVy6VRiVXK2+CHc4hO3J4dUQjHe7V0ymHB+MDuv5z+NhK07HA=="], "vite-plus/oxfmt": ["oxfmt@0.57.0", "", { "dependencies": { "tinypool": "2.1.0" }, "optionalDependencies": { "@oxfmt/binding-android-arm-eabi": "0.57.0", "@oxfmt/binding-android-arm64": "0.57.0", "@oxfmt/binding-darwin-arm64": "0.57.0", "@oxfmt/binding-darwin-x64": "0.57.0", "@oxfmt/binding-freebsd-x64": "0.57.0", "@oxfmt/binding-linux-arm-gnueabihf": "0.57.0", "@oxfmt/binding-linux-arm-musleabihf": "0.57.0", "@oxfmt/binding-linux-arm64-gnu": "0.57.0", "@oxfmt/binding-linux-arm64-musl": "0.57.0", "@oxfmt/binding-linux-ppc64-gnu": "0.57.0", "@oxfmt/binding-linux-riscv64-gnu": "0.57.0", "@oxfmt/binding-linux-riscv64-musl": "0.57.0", "@oxfmt/binding-linux-s390x-gnu": "0.57.0", "@oxfmt/binding-linux-x64-gnu": "0.57.0", "@oxfmt/binding-linux-x64-musl": "0.57.0", "@oxfmt/binding-openharmony-arm64": "0.57.0", "@oxfmt/binding-win32-arm64-msvc": "0.57.0", "@oxfmt/binding-win32-ia32-msvc": "0.57.0", "@oxfmt/binding-win32-x64-msvc": "0.57.0" }, "peerDependencies": { "svelte": "^5.0.0", "vite-plus": "*" }, "optionalPeers": ["svelte", "vite-plus"], "bin": { "oxfmt": "bin/oxfmt" } }, "sha512-ZB7Bi+rGDSqmVIo9jwcLyFgjxXvQhDdU+jx+ZrVy6VRiVXK2+CHc4hO3J4dUQjHe7V0ymHB+MDuv5z+NhK07HA=="],
@@ -4016,6 +4044,12 @@
"@anthropic-ai/claude-agent-sdk/@img/sharp-linuxmusl-x64/@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg=="], "@anthropic-ai/claude-agent-sdk/@img/sharp-linuxmusl-x64/@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg=="],
"@code/primitives/@rivet-dev/agentos/@agentos-software/common": ["@agentos-software/common@0.2.14", "", { "dependencies": { "@agentos-software/coreutils": "0.3.4", "@agentos-software/diffutils": "0.3.4", "@agentos-software/findutils": "0.3.4", "@agentos-software/gawk": "0.3.4", "@agentos-software/grep": "0.3.4", "@agentos-software/gzip": "0.3.4", "@agentos-software/sed": "0.3.4", "@agentos-software/tar": "0.3.5" } }, "sha512-ve/ks2MZtXFN9JK+kcFnSMGI1tqoUy36sTKWYGqApcgg/3JJwqnMs4JIKL5OXjgCtDuTvTjRySbQvEKxGkeeSQ=="],
"@code/primitives/@rivet-dev/agentos/@rivet-dev/agentos-core": ["@rivet-dev/agentos-core@0.2.14", "", { "dependencies": { "@agentclientprotocol/sdk": "0.16.1", "@agentos-software/claude-code": "0.2.7", "@agentos-software/codex-cli": "0.3.4", "@agentos-software/common": "0.2.14", "@agentos-software/manifest": "0.2.14", "@agentos-software/opencode": "0.2.7", "@agentos-software/pi": "0.2.7", "@aws-sdk/client-s3": "^3.1019.0", "@rivet-dev/agentos-runtime-core": "0.2.14", "@rivet-dev/agentos-sidecar": "0.2.14", "@rivetkit/bare-ts": "^0.6.2", "@xterm/headless": "^6.0.0", "better-sqlite3": "^12.8.0", "croner": "^10.0.1", "googleapis": "^144.0.0", "isolated-vm": "^6.0.0", "long-timeout": "^0.1.1", "minimatch": "^10.2.4", "zod": "^4.1.11", "zod-to-json-schema": "^3.25.2" } }, "sha512-YAbK0NpauQKlcuSKl0eXB95ZdNopMGmXw1dBaoSlODKVYoKTjOEKwUtSEvx/zZB0Cse2kSQ/IrJpLe183QeQPw=="],
"@code/primitives/@rivet-dev/agentos/@rivetkit/react": ["@rivetkit/react@2.3.9", "", { "dependencies": { "@rivetkit/framework-base": "2.3.9", "@tanstack/react-store": "^0.7.1", "rivetkit": "2.3.9" }, "peerDependencies": { "react": "^18 || ^19", "react-dom": "^18 || ^19" } }, "sha512-j9t82h/yIqqSt17coQZeRu3F9Q5w2FgWPDUC9fCyQUJp9PTjO7ea494PR0lSWvuEiwMRqE5JpgbHdYUQ1woE9w=="],
"@dotenvx/dotenvx/execa/get-stream": ["get-stream@6.0.1", "", {}, "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg=="], "@dotenvx/dotenvx/execa/get-stream": ["get-stream@6.0.1", "", {}, "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg=="],
"@dotenvx/dotenvx/execa/human-signals": ["human-signals@2.1.0", "", {}, "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw=="], "@dotenvx/dotenvx/execa/human-signals": ["human-signals@2.1.0", "", {}, "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw=="],
@@ -4082,12 +4116,64 @@
"@jest/types/chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], "@jest/types/chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
"@mariozechner/pi-ai/@aws-sdk/client-bedrock-runtime/@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.1096.0", "", { "dependencies": { "@aws-sdk/core": "^3.977.1", "@aws-sdk/nested-clients": "^3.997.36", "@aws-sdk/types": "^3.974.2", "@smithy/core": "^3.29.8", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-hdUS2hDppy3vkWeFl5y86RLNU6OWH2mQB09yOSsRefwhhGTSFPkaZvfLDD/9vFcvMzlr8QFQFw3fw2FtrurVQA=="],
"@mariozechner/pi-ai/@aws-sdk/client-bedrock-runtime/@smithy/node-http-handler": ["@smithy/node-http-handler@4.9.12", "", { "dependencies": { "@smithy/core": "^3.31.0", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-dWW5KRt4mnEvjNzbGqGeCuAvgum85Y9ZoyuMQqcTEfapndyVJ1k9BEHK7kdXJZ32enyRmmwcFjMwlB/KgLKI3Q=="],
"@react-native/babel-preset/@react-native/babel-plugin-codegen/@react-native/codegen": ["@react-native/codegen@0.86.2", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/parser": "^7.29.0", "hermes-parser": "0.36.0", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "tinyglobby": "^0.2.15", "yargs": "^17.6.2" } }, "sha512-xKkudsahUJ1n//55g4fXk5BStVqqmZlz8HQveL45ZxcfDnwvhuYe2GymksQANFsSN+slvrarjrfq8kIxJzbceA=="], "@react-native/babel-preset/@react-native/babel-plugin-codegen/@react-native/codegen": ["@react-native/codegen@0.86.2", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/parser": "^7.29.0", "hermes-parser": "0.36.0", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "tinyglobby": "^0.2.15", "yargs": "^17.6.2" } }, "sha512-xKkudsahUJ1n//55g4fXk5BStVqqmZlz8HQveL45ZxcfDnwvhuYe2GymksQANFsSN+slvrarjrfq8kIxJzbceA=="],
"@react-native/dev-middleware/serve-static/send": ["send@0.19.2", "", { "dependencies": { "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "~0.5.2", "http-errors": "~2.0.1", "mime": "1.6.0", "ms": "2.1.3", "on-finished": "~2.4.1", "range-parser": "~1.2.1", "statuses": "~2.0.2" } }, "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg=="], "@react-native/dev-middleware/serve-static/send": ["send@0.19.2", "", { "dependencies": { "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "~0.5.2", "http-errors": "~2.0.1", "mime": "1.6.0", "ms": "2.1.3", "on-finished": "~2.4.1", "range-parser": "~1.2.1", "statuses": "~2.0.2" } }, "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg=="],
"@rivet-dev/agentos/rivetkit/@rivetkit/engine-cli": ["@rivetkit/engine-cli@2.3.7", "", { "optionalDependencies": { "@rivetkit/engine-cli-darwin-arm64": "2.3.7", "@rivetkit/engine-cli-darwin-x64": "2.3.7", "@rivetkit/engine-cli-linux-arm64-musl": "2.3.7", "@rivetkit/engine-cli-linux-x64-musl": "2.3.7", "@rivetkit/engine-cli-win32-x64": "2.3.7" } }, "sha512-CezLwJ0B7dWDbA7qM6Aq04mwnrJAdrDActRrrcb4NBa20h7wO9KPAYBwyJz/dRnKm9EUUNcFZ6hrSDpp6T3+Rg=="],
"@rivet-dev/agentos/rivetkit/@rivetkit/engine-envoy-protocol": ["@rivetkit/engine-envoy-protocol@2.3.7", "", { "dependencies": { "@rivetkit/bare-ts": "^0.6.2" } }, "sha512-lsJM3ERwozQCebaOMKJzqIQlcLbbN3LXurRB0+7LsM6FUUL2l6hMoq5I2De/G35DJ6OWDva9AmzfvzI+5f1GPg=="],
"@rivet-dev/agentos/rivetkit/@rivetkit/rivetkit-napi": ["@rivetkit/rivetkit-napi@2.3.7", "", { "dependencies": { "@napi-rs/cli": "^2.18.4", "@rivetkit/engine-envoy-protocol": "2.3.7" }, "optionalDependencies": { "@rivetkit/rivetkit-napi-darwin-arm64": "2.3.7", "@rivetkit/rivetkit-napi-darwin-x64": "2.3.7", "@rivetkit/rivetkit-napi-linux-arm64-gnu": "2.3.7", "@rivetkit/rivetkit-napi-linux-arm64-musl": "2.3.7", "@rivetkit/rivetkit-napi-linux-x64-gnu": "2.3.7", "@rivetkit/rivetkit-napi-linux-x64-musl": "2.3.7", "@rivetkit/rivetkit-napi-win32-x64-msvc": "2.3.7" } }, "sha512-1d3HtNKzJwdkznWDWSpCwg1rBn+nVwUfcKrApINTfiEhfDyVeznwbVFkfHWqOBHsjU17vvWFfjjTtf8QsjLwUQ=="],
"@rivet-dev/agentos/rivetkit/@rivetkit/rivetkit-wasm": ["@rivetkit/rivetkit-wasm@2.3.7", "", {}, "sha512-o7QBtFOJrajyPVBIDQ32k8sDNFsUc8v2ETfNpr+Ch374ydmZMzCv3XKJU9vubc9bZa7WpCHSzf5ztc8b8i/Xpg=="],
"@rivet-dev/agentos/rivetkit/@rivetkit/traces": ["@rivetkit/traces@2.3.7", "", { "dependencies": { "@rivetkit/bare-ts": "^0.6.2", "cbor-x": "^1.6.0", "fdb-tuple": "^1.0.0", "vbare": "^0.0.4" } }, "sha512-B7QYjFP2HPxyfPsVjfcNIV7FPLWgGWGypmlT/dZM1i1Cf1WRdeuBumPLffgs3YceiY7Pm4D/gZZVt5p0m4Cx+A=="],
"@rivet-dev/agentos/rivetkit/@rivetkit/virtual-websocket": ["@rivetkit/virtual-websocket@2.3.7", "", {}, "sha512-jwxDvYbr3YB6vFuxwRdB/AqUUMwdtC1rIAc4tNN6VQR3weHbE+PrDoHKbe85zrtlBtcnG89/p8tlovrj8qyQWA=="],
"@rivet-dev/agentos/rivetkit/@rivetkit/workflow-engine": ["@rivetkit/workflow-engine@2.3.7", "", { "dependencies": { "@rivetkit/bare-ts": "^0.6.2", "cbor-x": "^1.6.0", "fdb-tuple": "^1.0.0", "pino": "^9.6.0", "vbare": "^0.0.4" } }, "sha512-+C4kGuSNysrw2zs/LQoYxouOxufKHHMxiIXKF8Ab9GU2BCJ32RUST9dYU/gaQE/w9uM+hqAHUz0DTlOBYU6p6g=="],
"@rivet-dev/agentos/rivetkit/uuid": ["uuid@12.0.1", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-9obBF8sMIHJWNQaO6IGOG8giGa/jUpKX34bz6o4whVs8M0WAvhID2tNxYp6A2XEBJPuZSX8wsS/6TEKfIDc+nw=="],
"@rivetkit/framework-base/rivetkit/@rivetkit/engine-cli": ["@rivetkit/engine-cli@2.3.7", "", { "optionalDependencies": { "@rivetkit/engine-cli-darwin-arm64": "2.3.7", "@rivetkit/engine-cli-darwin-x64": "2.3.7", "@rivetkit/engine-cli-linux-arm64-musl": "2.3.7", "@rivetkit/engine-cli-linux-x64-musl": "2.3.7", "@rivetkit/engine-cli-win32-x64": "2.3.7" } }, "sha512-CezLwJ0B7dWDbA7qM6Aq04mwnrJAdrDActRrrcb4NBa20h7wO9KPAYBwyJz/dRnKm9EUUNcFZ6hrSDpp6T3+Rg=="],
"@rivetkit/framework-base/rivetkit/@rivetkit/engine-envoy-protocol": ["@rivetkit/engine-envoy-protocol@2.3.7", "", { "dependencies": { "@rivetkit/bare-ts": "^0.6.2" } }, "sha512-lsJM3ERwozQCebaOMKJzqIQlcLbbN3LXurRB0+7LsM6FUUL2l6hMoq5I2De/G35DJ6OWDva9AmzfvzI+5f1GPg=="],
"@rivetkit/framework-base/rivetkit/@rivetkit/rivetkit-napi": ["@rivetkit/rivetkit-napi@2.3.7", "", { "dependencies": { "@napi-rs/cli": "^2.18.4", "@rivetkit/engine-envoy-protocol": "2.3.7" }, "optionalDependencies": { "@rivetkit/rivetkit-napi-darwin-arm64": "2.3.7", "@rivetkit/rivetkit-napi-darwin-x64": "2.3.7", "@rivetkit/rivetkit-napi-linux-arm64-gnu": "2.3.7", "@rivetkit/rivetkit-napi-linux-arm64-musl": "2.3.7", "@rivetkit/rivetkit-napi-linux-x64-gnu": "2.3.7", "@rivetkit/rivetkit-napi-linux-x64-musl": "2.3.7", "@rivetkit/rivetkit-napi-win32-x64-msvc": "2.3.7" } }, "sha512-1d3HtNKzJwdkznWDWSpCwg1rBn+nVwUfcKrApINTfiEhfDyVeznwbVFkfHWqOBHsjU17vvWFfjjTtf8QsjLwUQ=="],
"@rivetkit/framework-base/rivetkit/@rivetkit/rivetkit-wasm": ["@rivetkit/rivetkit-wasm@2.3.7", "", {}, "sha512-o7QBtFOJrajyPVBIDQ32k8sDNFsUc8v2ETfNpr+Ch374ydmZMzCv3XKJU9vubc9bZa7WpCHSzf5ztc8b8i/Xpg=="],
"@rivetkit/framework-base/rivetkit/@rivetkit/traces": ["@rivetkit/traces@2.3.7", "", { "dependencies": { "@rivetkit/bare-ts": "^0.6.2", "cbor-x": "^1.6.0", "fdb-tuple": "^1.0.0", "vbare": "^0.0.4" } }, "sha512-B7QYjFP2HPxyfPsVjfcNIV7FPLWgGWGypmlT/dZM1i1Cf1WRdeuBumPLffgs3YceiY7Pm4D/gZZVt5p0m4Cx+A=="],
"@rivetkit/framework-base/rivetkit/@rivetkit/virtual-websocket": ["@rivetkit/virtual-websocket@2.3.7", "", {}, "sha512-jwxDvYbr3YB6vFuxwRdB/AqUUMwdtC1rIAc4tNN6VQR3weHbE+PrDoHKbe85zrtlBtcnG89/p8tlovrj8qyQWA=="],
"@rivetkit/framework-base/rivetkit/@rivetkit/workflow-engine": ["@rivetkit/workflow-engine@2.3.7", "", { "dependencies": { "@rivetkit/bare-ts": "^0.6.2", "cbor-x": "^1.6.0", "fdb-tuple": "^1.0.0", "pino": "^9.6.0", "vbare": "^0.0.4" } }, "sha512-+C4kGuSNysrw2zs/LQoYxouOxufKHHMxiIXKF8Ab9GU2BCJ32RUST9dYU/gaQE/w9uM+hqAHUz0DTlOBYU6p6g=="],
"@rivetkit/framework-base/rivetkit/uuid": ["uuid@12.0.1", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-9obBF8sMIHJWNQaO6IGOG8giGa/jUpKX34bz6o4whVs8M0WAvhID2tNxYp6A2XEBJPuZSX8wsS/6TEKfIDc+nw=="],
"@rivetkit/react/@tanstack/react-store/@tanstack/store": ["@tanstack/store@0.7.7", "", {}, "sha512-xa6pTan1bcaqYDS9BDpSiS63qa6EoDkPN9RsRaxHuDdVDNntzq3xNwR5YKTU/V3SkSyC9T4YVOPh2zRQN0nhIQ=="], "@rivetkit/react/@tanstack/react-store/@tanstack/store": ["@tanstack/store@0.7.7", "", {}, "sha512-xa6pTan1bcaqYDS9BDpSiS63qa6EoDkPN9RsRaxHuDdVDNntzq3xNwR5YKTU/V3SkSyC9T4YVOPh2zRQN0nhIQ=="],
"@rivetkit/react/rivetkit/@rivetkit/engine-cli": ["@rivetkit/engine-cli@2.3.7", "", { "optionalDependencies": { "@rivetkit/engine-cli-darwin-arm64": "2.3.7", "@rivetkit/engine-cli-darwin-x64": "2.3.7", "@rivetkit/engine-cli-linux-arm64-musl": "2.3.7", "@rivetkit/engine-cli-linux-x64-musl": "2.3.7", "@rivetkit/engine-cli-win32-x64": "2.3.7" } }, "sha512-CezLwJ0B7dWDbA7qM6Aq04mwnrJAdrDActRrrcb4NBa20h7wO9KPAYBwyJz/dRnKm9EUUNcFZ6hrSDpp6T3+Rg=="],
"@rivetkit/react/rivetkit/@rivetkit/engine-envoy-protocol": ["@rivetkit/engine-envoy-protocol@2.3.7", "", { "dependencies": { "@rivetkit/bare-ts": "^0.6.2" } }, "sha512-lsJM3ERwozQCebaOMKJzqIQlcLbbN3LXurRB0+7LsM6FUUL2l6hMoq5I2De/G35DJ6OWDva9AmzfvzI+5f1GPg=="],
"@rivetkit/react/rivetkit/@rivetkit/rivetkit-napi": ["@rivetkit/rivetkit-napi@2.3.7", "", { "dependencies": { "@napi-rs/cli": "^2.18.4", "@rivetkit/engine-envoy-protocol": "2.3.7" }, "optionalDependencies": { "@rivetkit/rivetkit-napi-darwin-arm64": "2.3.7", "@rivetkit/rivetkit-napi-darwin-x64": "2.3.7", "@rivetkit/rivetkit-napi-linux-arm64-gnu": "2.3.7", "@rivetkit/rivetkit-napi-linux-arm64-musl": "2.3.7", "@rivetkit/rivetkit-napi-linux-x64-gnu": "2.3.7", "@rivetkit/rivetkit-napi-linux-x64-musl": "2.3.7", "@rivetkit/rivetkit-napi-win32-x64-msvc": "2.3.7" } }, "sha512-1d3HtNKzJwdkznWDWSpCwg1rBn+nVwUfcKrApINTfiEhfDyVeznwbVFkfHWqOBHsjU17vvWFfjjTtf8QsjLwUQ=="],
"@rivetkit/react/rivetkit/@rivetkit/rivetkit-wasm": ["@rivetkit/rivetkit-wasm@2.3.7", "", {}, "sha512-o7QBtFOJrajyPVBIDQ32k8sDNFsUc8v2ETfNpr+Ch374ydmZMzCv3XKJU9vubc9bZa7WpCHSzf5ztc8b8i/Xpg=="],
"@rivetkit/react/rivetkit/@rivetkit/traces": ["@rivetkit/traces@2.3.7", "", { "dependencies": { "@rivetkit/bare-ts": "^0.6.2", "cbor-x": "^1.6.0", "fdb-tuple": "^1.0.0", "vbare": "^0.0.4" } }, "sha512-B7QYjFP2HPxyfPsVjfcNIV7FPLWgGWGypmlT/dZM1i1Cf1WRdeuBumPLffgs3YceiY7Pm4D/gZZVt5p0m4Cx+A=="],
"@rivetkit/react/rivetkit/@rivetkit/virtual-websocket": ["@rivetkit/virtual-websocket@2.3.7", "", {}, "sha512-jwxDvYbr3YB6vFuxwRdB/AqUUMwdtC1rIAc4tNN6VQR3weHbE+PrDoHKbe85zrtlBtcnG89/p8tlovrj8qyQWA=="],
"@rivetkit/react/rivetkit/@rivetkit/workflow-engine": ["@rivetkit/workflow-engine@2.3.7", "", { "dependencies": { "@rivetkit/bare-ts": "^0.6.2", "cbor-x": "^1.6.0", "fdb-tuple": "^1.0.0", "pino": "^9.6.0", "vbare": "^0.0.4" } }, "sha512-+C4kGuSNysrw2zs/LQoYxouOxufKHHMxiIXKF8Ab9GU2BCJ32RUST9dYU/gaQE/w9uM+hqAHUz0DTlOBYU6p6g=="],
"@rivetkit/react/rivetkit/uuid": ["uuid@12.0.1", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-9obBF8sMIHJWNQaO6IGOG8giGa/jUpKX34bz6o4whVs8M0WAvhID2tNxYp6A2XEBJPuZSX8wsS/6TEKfIDc+nw=="],
"@secure-exec/nodejs/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.7", "", { "os": "aix", "cpu": "ppc64" }, "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg=="], "@secure-exec/nodejs/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.7", "", { "os": "aix", "cpu": "ppc64" }, "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg=="],
"@secure-exec/nodejs/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.27.7", "", { "os": "android", "cpu": "arm" }, "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ=="], "@secure-exec/nodejs/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.27.7", "", { "os": "android", "cpu": "arm" }, "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ=="],
@@ -4234,6 +4320,8 @@
"morgan/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], "morgan/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
"npm-package-arg/hosted-git-info/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
"ora/string-width/emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="], "ora/string-width/emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="],
"pkg-up/find-up/locate-path": ["locate-path@3.0.0", "", { "dependencies": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" } }, "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A=="], "pkg-up/find-up/locate-path": ["locate-path@3.0.0", "", { "dependencies": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" } }, "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A=="],
@@ -4368,6 +4456,18 @@
"wrangler/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.28.1", "", { "os": "win32", "cpu": "x64" }, "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A=="], "wrangler/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.28.1", "", { "os": "win32", "cpu": "x64" }, "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A=="],
"@code/primitives/@rivet-dev/agentos/@agentos-software/common/@agentos-software/tar": ["@agentos-software/tar@0.3.5", "", {}, "sha512-hSf6PY4q1luIomFSDgVHxVDDIPdAVZxdgwrQFEYH4aIE6TXX9qatVmzR36uYLWpnFGAZTR6srREGoTnmOGV4Lg=="],
"@code/primitives/@rivet-dev/agentos/@rivet-dev/agentos-core/@agentos-software/manifest": ["@agentos-software/manifest@0.2.14", "", {}, "sha512-c1lGWN7/d1lku6Kl+wj6w1YoLX6wI93IyiUoE6M/Hgl1PP1YIPUqGFM5P5sZ9gG9M0qQ86T/587gECj1elZQBg=="],
"@code/primitives/@rivet-dev/agentos/@rivet-dev/agentos-core/@rivet-dev/agentos-runtime-core": ["@rivet-dev/agentos-runtime-core@0.2.14", "", { "dependencies": { "@rivet-dev/agentos-runtime-sidecar": "0.2.14", "@rivetkit/bare-ts": "^0.6.2", "zod": "^4.1.11" } }, "sha512-mZYas5wUZXjwLLLHq6uMOaajtyc/3iLQ6vGzOH4E3OHBwCfK054YwGU8iunRqWtk+Wd7MPetzstxzdu+72nBug=="],
"@code/primitives/@rivet-dev/agentos/@rivet-dev/agentos-core/@rivet-dev/agentos-sidecar": ["@rivet-dev/agentos-sidecar@0.2.14", "", { "optionalDependencies": { "@rivet-dev/agentos-sidecar-darwin-arm64": "0.2.14", "@rivet-dev/agentos-sidecar-darwin-x64": "0.2.14", "@rivet-dev/agentos-sidecar-linux-arm64-gnu": "0.2.14", "@rivet-dev/agentos-sidecar-linux-x64-gnu": "0.2.14" } }, "sha512-aISMeC7UY5Mjum/DiYp3idZa/EnNZ76FGke29FVQHmBfwVX6dTx2R/FHjZdEE+iOCi9APxAHIvdu8C+EVp6q2A=="],
"@code/primitives/@rivet-dev/agentos/@rivetkit/react/@rivetkit/framework-base": ["@rivetkit/framework-base@2.3.9", "", { "dependencies": { "@tanstack/store": "^0.7.1", "fast-deep-equal": "^3.1.3", "rivetkit": "2.3.9" } }, "sha512-ZSxrclYcpmdGsLMiVE2dfWNfUB6diSx+t8k4EQgL4cN02ThzJD3BM5mhU+zQVCCwfNw42eRZVIoxydYDLl/yHw=="],
"@code/primitives/@rivet-dev/agentos/@rivetkit/react/@tanstack/react-store": ["@tanstack/react-store@0.7.7", "", { "dependencies": { "@tanstack/store": "0.7.7", "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-qqT0ufegFRDGSof9D/VqaZgjNgp4tRPHZIJq2+QIHkMUtHjaJ0lYrrXjeIUJvjnTbgPfSD1XgOMEt0lmANn6Zg=="],
"@expo/cli/accepts/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], "@expo/cli/accepts/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
"@expo/cli/ora/chalk/ansi-styles": ["ansi-styles@3.2.1", "", { "dependencies": { "color-convert": "^1.9.0" } }, "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="], "@expo/cli/ora/chalk/ansi-styles": ["ansi-styles@3.2.1", "", { "dependencies": { "color-convert": "^1.9.0" } }, "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="],
@@ -4398,6 +4498,78 @@
"@react-native/dev-middleware/serve-static/send/range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="], "@react-native/dev-middleware/serve-static/send/range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="],
"@rivet-dev/agentos/rivetkit/@rivetkit/engine-cli/@rivetkit/engine-cli-darwin-arm64": ["@rivetkit/engine-cli-darwin-arm64@2.3.7", "", { "os": "darwin", "cpu": "arm64" }, "sha512-F3yGSDIaW94BZzuAm3erQRT/Ki55wHJ/b6tOaE7d9tRmTAZw/XqHmjNdUYjOvFUQKLb+SSsOittM4dINrAANQQ=="],
"@rivet-dev/agentos/rivetkit/@rivetkit/engine-cli/@rivetkit/engine-cli-darwin-x64": ["@rivetkit/engine-cli-darwin-x64@2.3.7", "", { "os": "darwin", "cpu": "x64" }, "sha512-P8BbQsamIvv8U/cEoJUFr+uAzwjjl9cG+ZZxjDX9OJxbuD11ESpHvDLgge54ijynO3IjoP8cIzjIXat6mr2Gkw=="],
"@rivet-dev/agentos/rivetkit/@rivetkit/engine-cli/@rivetkit/engine-cli-linux-arm64-musl": ["@rivetkit/engine-cli-linux-arm64-musl@2.3.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-G3s76BHfIs6R9rm6JYI13sOjPLy08+C8WvVoFwSdMqsibEaqlfo36wVkp/x1g0sEZUek/dBxVrKqMMR7c4/gug=="],
"@rivet-dev/agentos/rivetkit/@rivetkit/engine-cli/@rivetkit/engine-cli-linux-x64-musl": ["@rivetkit/engine-cli-linux-x64-musl@2.3.7", "", { "os": "linux", "cpu": "x64" }, "sha512-LWhrUVzULcsZ4ufCLsx23YfrdMW2INd9g0ANBac9+PzGwL8qYfVIXnDpR3587lapu68EbSEPZcconf1tBlvJxQ=="],
"@rivet-dev/agentos/rivetkit/@rivetkit/engine-cli/@rivetkit/engine-cli-win32-x64": ["@rivetkit/engine-cli-win32-x64@2.3.7", "", { "os": "win32", "cpu": "x64" }, "sha512-jyA5PlHivHXyyq2ehnuXwxd5TUSbB4emomnph9EovsJo7qIdmSNaaCO13NYBT483fd0uXiNI0MK/lkJa9ePY5A=="],
"@rivet-dev/agentos/rivetkit/@rivetkit/rivetkit-napi/@rivetkit/rivetkit-napi-darwin-arm64": ["@rivetkit/rivetkit-napi-darwin-arm64@2.3.7", "", { "os": "darwin", "cpu": "arm64" }, "sha512-gI1wMe6z85VDeR4K/wnzevVakXTg5UCfvjlDOp1+23nyU3NlInhN156dEWO8EsfRMrs+1bYoGdc4rcoN+4PUrw=="],
"@rivet-dev/agentos/rivetkit/@rivetkit/rivetkit-napi/@rivetkit/rivetkit-napi-darwin-x64": ["@rivetkit/rivetkit-napi-darwin-x64@2.3.7", "", { "os": "darwin", "cpu": "x64" }, "sha512-H5tUwvCbKwTIBiyQG01ikK5mdc9ISg+bv8gPUw41mYOKq8rb9nBLkcl2TKcreFHac8KaGxtnBZzYcjbUV3NcwQ=="],
"@rivet-dev/agentos/rivetkit/@rivetkit/rivetkit-napi/@rivetkit/rivetkit-napi-linux-arm64-gnu": ["@rivetkit/rivetkit-napi-linux-arm64-gnu@2.3.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-MpOeiO5M737e93hM/FjcH+zv8xBEX1tgBd/59K/Uw7qlRbWW7JGz8WGjavdxv211LRqxsn8EUlGRxcADDsXnBA=="],
"@rivet-dev/agentos/rivetkit/@rivetkit/rivetkit-napi/@rivetkit/rivetkit-napi-linux-arm64-musl": ["@rivetkit/rivetkit-napi-linux-arm64-musl@2.3.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-0GsUgd/HHvIq6v92kp0H175mGm2Exvs4krBLih0MIpVAkqJk8EIcKI6wJhCwY04Fr0MS8sHkUhjuHXa7QcmlYA=="],
"@rivet-dev/agentos/rivetkit/@rivetkit/rivetkit-napi/@rivetkit/rivetkit-napi-linux-x64-gnu": ["@rivetkit/rivetkit-napi-linux-x64-gnu@2.3.7", "", { "os": "linux", "cpu": "x64" }, "sha512-8wCD1FuDpM+yiKRG8ro1K8ILVpJXzCNKViJ1axq1b4Nyqgod/nyEvvKDaT4qhA5+Om+W5i6YRO1uddjC6QjJSQ=="],
"@rivet-dev/agentos/rivetkit/@rivetkit/rivetkit-napi/@rivetkit/rivetkit-napi-linux-x64-musl": ["@rivetkit/rivetkit-napi-linux-x64-musl@2.3.7", "", { "os": "linux", "cpu": "x64" }, "sha512-8RGzXD33GH1/DWufFzCZRI+npF5IL/9z7Ja3pthsuYgrL+axGG0iqfAjbwj5HHnB/ceUGQVT+uCKzoLnG+odtw=="],
"@rivet-dev/agentos/rivetkit/@rivetkit/rivetkit-napi/@rivetkit/rivetkit-napi-win32-x64-msvc": ["@rivetkit/rivetkit-napi-win32-x64-msvc@2.3.7", "", { "os": "win32", "cpu": "x64" }, "sha512-n1by/coKxWOb2FZDGLM2qmULxcLSqx8hxJuk7Hsb1gl4uNHGviUzYr+r7WAiOzonK/Dgy477u3OKf5yBie743A=="],
"@rivetkit/framework-base/rivetkit/@rivetkit/engine-cli/@rivetkit/engine-cli-darwin-arm64": ["@rivetkit/engine-cli-darwin-arm64@2.3.7", "", { "os": "darwin", "cpu": "arm64" }, "sha512-F3yGSDIaW94BZzuAm3erQRT/Ki55wHJ/b6tOaE7d9tRmTAZw/XqHmjNdUYjOvFUQKLb+SSsOittM4dINrAANQQ=="],
"@rivetkit/framework-base/rivetkit/@rivetkit/engine-cli/@rivetkit/engine-cli-darwin-x64": ["@rivetkit/engine-cli-darwin-x64@2.3.7", "", { "os": "darwin", "cpu": "x64" }, "sha512-P8BbQsamIvv8U/cEoJUFr+uAzwjjl9cG+ZZxjDX9OJxbuD11ESpHvDLgge54ijynO3IjoP8cIzjIXat6mr2Gkw=="],
"@rivetkit/framework-base/rivetkit/@rivetkit/engine-cli/@rivetkit/engine-cli-linux-arm64-musl": ["@rivetkit/engine-cli-linux-arm64-musl@2.3.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-G3s76BHfIs6R9rm6JYI13sOjPLy08+C8WvVoFwSdMqsibEaqlfo36wVkp/x1g0sEZUek/dBxVrKqMMR7c4/gug=="],
"@rivetkit/framework-base/rivetkit/@rivetkit/engine-cli/@rivetkit/engine-cli-linux-x64-musl": ["@rivetkit/engine-cli-linux-x64-musl@2.3.7", "", { "os": "linux", "cpu": "x64" }, "sha512-LWhrUVzULcsZ4ufCLsx23YfrdMW2INd9g0ANBac9+PzGwL8qYfVIXnDpR3587lapu68EbSEPZcconf1tBlvJxQ=="],
"@rivetkit/framework-base/rivetkit/@rivetkit/engine-cli/@rivetkit/engine-cli-win32-x64": ["@rivetkit/engine-cli-win32-x64@2.3.7", "", { "os": "win32", "cpu": "x64" }, "sha512-jyA5PlHivHXyyq2ehnuXwxd5TUSbB4emomnph9EovsJo7qIdmSNaaCO13NYBT483fd0uXiNI0MK/lkJa9ePY5A=="],
"@rivetkit/framework-base/rivetkit/@rivetkit/rivetkit-napi/@rivetkit/rivetkit-napi-darwin-arm64": ["@rivetkit/rivetkit-napi-darwin-arm64@2.3.7", "", { "os": "darwin", "cpu": "arm64" }, "sha512-gI1wMe6z85VDeR4K/wnzevVakXTg5UCfvjlDOp1+23nyU3NlInhN156dEWO8EsfRMrs+1bYoGdc4rcoN+4PUrw=="],
"@rivetkit/framework-base/rivetkit/@rivetkit/rivetkit-napi/@rivetkit/rivetkit-napi-darwin-x64": ["@rivetkit/rivetkit-napi-darwin-x64@2.3.7", "", { "os": "darwin", "cpu": "x64" }, "sha512-H5tUwvCbKwTIBiyQG01ikK5mdc9ISg+bv8gPUw41mYOKq8rb9nBLkcl2TKcreFHac8KaGxtnBZzYcjbUV3NcwQ=="],
"@rivetkit/framework-base/rivetkit/@rivetkit/rivetkit-napi/@rivetkit/rivetkit-napi-linux-arm64-gnu": ["@rivetkit/rivetkit-napi-linux-arm64-gnu@2.3.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-MpOeiO5M737e93hM/FjcH+zv8xBEX1tgBd/59K/Uw7qlRbWW7JGz8WGjavdxv211LRqxsn8EUlGRxcADDsXnBA=="],
"@rivetkit/framework-base/rivetkit/@rivetkit/rivetkit-napi/@rivetkit/rivetkit-napi-linux-arm64-musl": ["@rivetkit/rivetkit-napi-linux-arm64-musl@2.3.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-0GsUgd/HHvIq6v92kp0H175mGm2Exvs4krBLih0MIpVAkqJk8EIcKI6wJhCwY04Fr0MS8sHkUhjuHXa7QcmlYA=="],
"@rivetkit/framework-base/rivetkit/@rivetkit/rivetkit-napi/@rivetkit/rivetkit-napi-linux-x64-gnu": ["@rivetkit/rivetkit-napi-linux-x64-gnu@2.3.7", "", { "os": "linux", "cpu": "x64" }, "sha512-8wCD1FuDpM+yiKRG8ro1K8ILVpJXzCNKViJ1axq1b4Nyqgod/nyEvvKDaT4qhA5+Om+W5i6YRO1uddjC6QjJSQ=="],
"@rivetkit/framework-base/rivetkit/@rivetkit/rivetkit-napi/@rivetkit/rivetkit-napi-linux-x64-musl": ["@rivetkit/rivetkit-napi-linux-x64-musl@2.3.7", "", { "os": "linux", "cpu": "x64" }, "sha512-8RGzXD33GH1/DWufFzCZRI+npF5IL/9z7Ja3pthsuYgrL+axGG0iqfAjbwj5HHnB/ceUGQVT+uCKzoLnG+odtw=="],
"@rivetkit/framework-base/rivetkit/@rivetkit/rivetkit-napi/@rivetkit/rivetkit-napi-win32-x64-msvc": ["@rivetkit/rivetkit-napi-win32-x64-msvc@2.3.7", "", { "os": "win32", "cpu": "x64" }, "sha512-n1by/coKxWOb2FZDGLM2qmULxcLSqx8hxJuk7Hsb1gl4uNHGviUzYr+r7WAiOzonK/Dgy477u3OKf5yBie743A=="],
"@rivetkit/react/rivetkit/@rivetkit/engine-cli/@rivetkit/engine-cli-darwin-arm64": ["@rivetkit/engine-cli-darwin-arm64@2.3.7", "", { "os": "darwin", "cpu": "arm64" }, "sha512-F3yGSDIaW94BZzuAm3erQRT/Ki55wHJ/b6tOaE7d9tRmTAZw/XqHmjNdUYjOvFUQKLb+SSsOittM4dINrAANQQ=="],
"@rivetkit/react/rivetkit/@rivetkit/engine-cli/@rivetkit/engine-cli-darwin-x64": ["@rivetkit/engine-cli-darwin-x64@2.3.7", "", { "os": "darwin", "cpu": "x64" }, "sha512-P8BbQsamIvv8U/cEoJUFr+uAzwjjl9cG+ZZxjDX9OJxbuD11ESpHvDLgge54ijynO3IjoP8cIzjIXat6mr2Gkw=="],
"@rivetkit/react/rivetkit/@rivetkit/engine-cli/@rivetkit/engine-cli-linux-arm64-musl": ["@rivetkit/engine-cli-linux-arm64-musl@2.3.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-G3s76BHfIs6R9rm6JYI13sOjPLy08+C8WvVoFwSdMqsibEaqlfo36wVkp/x1g0sEZUek/dBxVrKqMMR7c4/gug=="],
"@rivetkit/react/rivetkit/@rivetkit/engine-cli/@rivetkit/engine-cli-linux-x64-musl": ["@rivetkit/engine-cli-linux-x64-musl@2.3.7", "", { "os": "linux", "cpu": "x64" }, "sha512-LWhrUVzULcsZ4ufCLsx23YfrdMW2INd9g0ANBac9+PzGwL8qYfVIXnDpR3587lapu68EbSEPZcconf1tBlvJxQ=="],
"@rivetkit/react/rivetkit/@rivetkit/engine-cli/@rivetkit/engine-cli-win32-x64": ["@rivetkit/engine-cli-win32-x64@2.3.7", "", { "os": "win32", "cpu": "x64" }, "sha512-jyA5PlHivHXyyq2ehnuXwxd5TUSbB4emomnph9EovsJo7qIdmSNaaCO13NYBT483fd0uXiNI0MK/lkJa9ePY5A=="],
"@rivetkit/react/rivetkit/@rivetkit/rivetkit-napi/@rivetkit/rivetkit-napi-darwin-arm64": ["@rivetkit/rivetkit-napi-darwin-arm64@2.3.7", "", { "os": "darwin", "cpu": "arm64" }, "sha512-gI1wMe6z85VDeR4K/wnzevVakXTg5UCfvjlDOp1+23nyU3NlInhN156dEWO8EsfRMrs+1bYoGdc4rcoN+4PUrw=="],
"@rivetkit/react/rivetkit/@rivetkit/rivetkit-napi/@rivetkit/rivetkit-napi-darwin-x64": ["@rivetkit/rivetkit-napi-darwin-x64@2.3.7", "", { "os": "darwin", "cpu": "x64" }, "sha512-H5tUwvCbKwTIBiyQG01ikK5mdc9ISg+bv8gPUw41mYOKq8rb9nBLkcl2TKcreFHac8KaGxtnBZzYcjbUV3NcwQ=="],
"@rivetkit/react/rivetkit/@rivetkit/rivetkit-napi/@rivetkit/rivetkit-napi-linux-arm64-gnu": ["@rivetkit/rivetkit-napi-linux-arm64-gnu@2.3.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-MpOeiO5M737e93hM/FjcH+zv8xBEX1tgBd/59K/Uw7qlRbWW7JGz8WGjavdxv211LRqxsn8EUlGRxcADDsXnBA=="],
"@rivetkit/react/rivetkit/@rivetkit/rivetkit-napi/@rivetkit/rivetkit-napi-linux-arm64-musl": ["@rivetkit/rivetkit-napi-linux-arm64-musl@2.3.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-0GsUgd/HHvIq6v92kp0H175mGm2Exvs4krBLih0MIpVAkqJk8EIcKI6wJhCwY04Fr0MS8sHkUhjuHXa7QcmlYA=="],
"@rivetkit/react/rivetkit/@rivetkit/rivetkit-napi/@rivetkit/rivetkit-napi-linux-x64-gnu": ["@rivetkit/rivetkit-napi-linux-x64-gnu@2.3.7", "", { "os": "linux", "cpu": "x64" }, "sha512-8wCD1FuDpM+yiKRG8ro1K8ILVpJXzCNKViJ1axq1b4Nyqgod/nyEvvKDaT4qhA5+Om+W5i6YRO1uddjC6QjJSQ=="],
"@rivetkit/react/rivetkit/@rivetkit/rivetkit-napi/@rivetkit/rivetkit-napi-linux-x64-musl": ["@rivetkit/rivetkit-napi-linux-x64-musl@2.3.7", "", { "os": "linux", "cpu": "x64" }, "sha512-8RGzXD33GH1/DWufFzCZRI+npF5IL/9z7Ja3pthsuYgrL+axGG0iqfAjbwj5HHnB/ceUGQVT+uCKzoLnG+odtw=="],
"@rivetkit/react/rivetkit/@rivetkit/rivetkit-napi/@rivetkit/rivetkit-napi-win32-x64-msvc": ["@rivetkit/rivetkit-napi-win32-x64-msvc@2.3.7", "", { "os": "win32", "cpu": "x64" }, "sha512-n1by/coKxWOb2FZDGLM2qmULxcLSqx8hxJuk7Hsb1gl4uNHGviUzYr+r7WAiOzonK/Dgy477u3OKf5yBie743A=="],
"cli-highlight/yargs/cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], "cli-highlight/yargs/cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
"googleapis-common/google-auth-library/gcp-metadata/google-logging-utils": ["google-logging-utils@0.0.2", "", {}, "sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ=="], "googleapis-common/google-auth-library/gcp-metadata/google-logging-utils": ["google-logging-utils@0.0.2", "", {}, "sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ=="],
@@ -4422,6 +4594,20 @@
"ripemd160/hash-base/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="], "ripemd160/hash-base/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="],
"@code/primitives/@rivet-dev/agentos/@rivet-dev/agentos-core/@rivet-dev/agentos-runtime-core/@rivet-dev/agentos-runtime-sidecar": ["@rivet-dev/agentos-runtime-sidecar@0.2.14", "", { "optionalDependencies": { "@rivet-dev/agentos-runtime-sidecar-darwin-arm64": "0.2.14", "@rivet-dev/agentos-runtime-sidecar-darwin-x64": "0.2.14", "@rivet-dev/agentos-runtime-sidecar-linux-arm64-gnu": "0.2.14", "@rivet-dev/agentos-runtime-sidecar-linux-x64-gnu": "0.2.14" } }, "sha512-dsA1wNg+0Y6DYRB8no962k1tAQk1y5kfdAbrpKjJQJjfgfwkv0q8XZ3ybtt1hLml/thgE32CI++8F7MRWz4TFA=="],
"@code/primitives/@rivet-dev/agentos/@rivet-dev/agentos-core/@rivet-dev/agentos-sidecar/@rivet-dev/agentos-sidecar-darwin-arm64": ["@rivet-dev/agentos-sidecar-darwin-arm64@0.2.14", "", { "os": "darwin", "cpu": "arm64" }, "sha512-U1R4wYvlsLCdASC5Lf6oP/6bW6ONGsiILtTQSVgxIHl/J1TrmOifrAbRgDC205kThJEZQ2op8kVzol5aEWOpbA=="],
"@code/primitives/@rivet-dev/agentos/@rivet-dev/agentos-core/@rivet-dev/agentos-sidecar/@rivet-dev/agentos-sidecar-darwin-x64": ["@rivet-dev/agentos-sidecar-darwin-x64@0.2.14", "", { "os": "darwin", "cpu": "x64" }, "sha512-vuij3BYGjVSCGMNB3HbS0EiDS50xG68cjH3ItuZL77GPHsw5V765TOheWDVgUOo1Q3+VWjdMaS2wNWv63qCf0w=="],
"@code/primitives/@rivet-dev/agentos/@rivet-dev/agentos-core/@rivet-dev/agentos-sidecar/@rivet-dev/agentos-sidecar-linux-arm64-gnu": ["@rivet-dev/agentos-sidecar-linux-arm64-gnu@0.2.14", "", { "os": "linux", "cpu": "arm64" }, "sha512-nauooe07/NhHb+Wn4xvJTUMNFzhOvrNoPwceiC0eGvkK7+imRyZpAgSGB4qRiaa2NRyuNRVh+d6kzp5iKzBwnA=="],
"@code/primitives/@rivet-dev/agentos/@rivet-dev/agentos-core/@rivet-dev/agentos-sidecar/@rivet-dev/agentos-sidecar-linux-x64-gnu": ["@rivet-dev/agentos-sidecar-linux-x64-gnu@0.2.14", "", { "os": "linux", "cpu": "x64" }, "sha512-PaGPXi5mS0Ef023nqS9lbMkMH6KGoOsHA3apAaOQz95lrmVx7E/z5BPzKYl3aYMYjmlo004mnNETVBZOy0VbQw=="],
"@code/primitives/@rivet-dev/agentos/@rivetkit/react/@rivetkit/framework-base/@tanstack/store": ["@tanstack/store@0.7.7", "", {}, "sha512-xa6pTan1bcaqYDS9BDpSiS63qa6EoDkPN9RsRaxHuDdVDNntzq3xNwR5YKTU/V3SkSyC9T4YVOPh2zRQN0nhIQ=="],
"@code/primitives/@rivet-dev/agentos/@rivetkit/react/@tanstack/react-store/@tanstack/store": ["@tanstack/store@0.7.7", "", {}, "sha512-xa6pTan1bcaqYDS9BDpSiS63qa6EoDkPN9RsRaxHuDdVDNntzq3xNwR5YKTU/V3SkSyC9T4YVOPh2zRQN0nhIQ=="],
"@expo/cli/ora/chalk/ansi-styles/color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="], "@expo/cli/ora/chalk/ansi-styles/color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="],
"@expo/cli/ora/chalk/supports-color/has-flag": ["has-flag@3.0.0", "", {}, "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="], "@expo/cli/ora/chalk/supports-color/has-flag": ["has-flag@3.0.0", "", {}, "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="],
@@ -4442,6 +4628,14 @@
"pkg-up/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], "pkg-up/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="],
"@code/primitives/@rivet-dev/agentos/@rivet-dev/agentos-core/@rivet-dev/agentos-runtime-core/@rivet-dev/agentos-runtime-sidecar/@rivet-dev/agentos-runtime-sidecar-darwin-arm64": ["@rivet-dev/agentos-runtime-sidecar-darwin-arm64@0.2.14", "", { "os": "darwin", "cpu": "arm64" }, "sha512-5pKvG7TC3lKbCMbQZptyXd3QPQyfiJ+wKqA+u5SqoP+Lqwim9C4PVSYMLUaxx0QqxliNuNu+VWif1xM91yECiw=="],
"@code/primitives/@rivet-dev/agentos/@rivet-dev/agentos-core/@rivet-dev/agentos-runtime-core/@rivet-dev/agentos-runtime-sidecar/@rivet-dev/agentos-runtime-sidecar-darwin-x64": ["@rivet-dev/agentos-runtime-sidecar-darwin-x64@0.2.14", "", { "os": "darwin", "cpu": "x64" }, "sha512-mTSDuMXKHSpMJ3SVLCb/3sBCpOaBw0fnEsnLzVSuicuSWSzhNe4yyUeAcyz4wsuT4l+M+Z5mDH1eydfpz7nltw=="],
"@code/primitives/@rivet-dev/agentos/@rivet-dev/agentos-core/@rivet-dev/agentos-runtime-core/@rivet-dev/agentos-runtime-sidecar/@rivet-dev/agentos-runtime-sidecar-linux-arm64-gnu": ["@rivet-dev/agentos-runtime-sidecar-linux-arm64-gnu@0.2.14", "", { "os": "linux", "cpu": "arm64" }, "sha512-bVtITOH4sNxcq8RuBMJF+Srlwa/Rl1ARZIej+MUDBR8VM7DGnBMWCaCHvYxy3JBmdP5aTb3gCwUm6e7m4/Khgw=="],
"@code/primitives/@rivet-dev/agentos/@rivet-dev/agentos-core/@rivet-dev/agentos-runtime-core/@rivet-dev/agentos-runtime-sidecar/@rivet-dev/agentos-runtime-sidecar-linux-x64-gnu": ["@rivet-dev/agentos-runtime-sidecar-linux-x64-gnu@0.2.14", "", { "os": "linux", "cpu": "x64" }, "sha512-NOI1m456Ev06ey4O0pVnITaYA7emeoKR2lJIFJP4j9Kv0XuXpbmaz1aigfa3/SZQ7AvqOzxbNLCcH5m22iO8ng=="],
"@expo/cli/ora/chalk/ansi-styles/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="], "@expo/cli/ora/chalk/ansi-styles/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="],
"@expo/cli/ora/cli-cursor/restore-cursor/onetime/mimic-fn": ["mimic-fn@1.2.0", "", {}, "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ=="], "@expo/cli/ora/cli-cursor/restore-cursor/onetime/mimic-fn": ["mimic-fn@1.2.0", "", {}, "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ=="],

View File

@@ -44,21 +44,22 @@ AGENT_MODEL_CONTEXT_WINDOW=262000
AGENT_MODEL_MAX_TOKENS=131072 AGENT_MODEL_MAX_TOKENS=131072
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# 4. AgentOS / RivetKit — OPTIONAL (defaults shown) # 4. AgentOS / Rivet Engine — REQUIRED for the execution runner
# registry.start() in the daemon boots an in-process RivetKit engine # The agent service and runner connect through the public engine endpoint.
# (envoy mode) backed by a native Rust sidecar. createClient() connects # RIVET_WORKSPACE_TOKEN authenticates every workspace actor connection.
# back to RIVET_ENDPOINT. No separate Rivet Engine process is required # RIVET_ENVOY_VERSION must change for each runner deployment.
# for single-node operation. Leave RIVET_ENDPOINT unset to use the
# library default (http://localhost:6420).
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
#RIVET_ENDPOINT=http://localhost:6420 RIVET_ENDPOINT=https://default:@rivet.example.com
RIVET_PUBLIC_ENDPOINT=https://default@rivet.example.com
RIVET_ENVOY_VERSION=1
RIVET_WORKSPACE_TOKEN=replace-with-a-long-random-workspace-token
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# 5. Zopu agent service (Flue) # 5. Zopu agent service (Flue)
# FLUE_DB_TOKEN authenticates the Flue persistence adapter. # FLUE_DB_TOKEN authenticates the Flue persistence adapter.
# zopu-agent.service pins the Flue Node server to port 3583. # zopu-agent.service pins the Flue Node server to port 3583.
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
FLUE_DB_TOKEN=replace-with-long-random-token FLUE_DB_TOKEN=replace-with-long-random-token
AGENT_BACKEND_URL=https://zopu-agent.example.com
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# 6. Daemon identity # 6. Daemon identity

View File

@@ -0,0 +1,16 @@
FROM oven/bun:1.3.14 AS bun
FROM node:24-bookworm-slim
COPY --from=bun /usr/local/bin/bun /usr/local/bin/bun
RUN apt-get update \
&& apt-get install -y --no-install-recommends g++ make python3 \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY . .
RUN bun install --frozen-lockfile
CMD ["bun", "packages/agents/src/runner.ts"]

View File

@@ -0,0 +1,22 @@
services:
zopu-agentos-runner:
build:
context: ../../..
dockerfile: deploy/zopu-runtime/runner/Dockerfile
environment:
AGENT_MODEL_API: ${AGENT_MODEL_API}
AGENT_MODEL_API_KEY: ${AGENT_MODEL_API_KEY}
AGENT_MODEL_BASE_URL: ${AGENT_MODEL_BASE_URL}
AGENT_MODEL_CONTEXT_WINDOW: ${AGENT_MODEL_CONTEXT_WINDOW}
AGENT_MODEL_MAX_TOKENS: ${AGENT_MODEL_MAX_TOKENS}
AGENT_MODEL_NAME: ${AGENT_MODEL_NAME}
AGENT_MODEL_PROVIDER: ${AGENT_MODEL_PROVIDER}
CONVEX_URL: ${CONVEX_URL}
DAEMON_ID: zopu-agentos-runner
FLUE_DB_TOKEN: ${FLUE_DB_TOKEN}
RIVET_ENDPOINT: ${RIVET_ENDPOINT}
RIVET_PUBLIC_ENDPOINT: ${RIVET_PUBLIC_ENDPOINT}
RIVET_ENVOY_VERSION: ${RIVET_ENVOY_VERSION}
RIVET_WORKSPACE_TOKEN: ${RIVET_WORKSPACE_TOKEN}
RIVET_POOL: default
restart: unless-stopped

View File

@@ -18,29 +18,28 @@ Convex application backend
├── normalized product data ├── normalized product data
├── conversation turn queue ├── conversation turn queue
└── reactive client projections └── reactive client projections
│ service-authenticated dispatch durable Workflow steps + service-authenticated dispatch
FLUE orchestration service Private agent backend
├── model calls ├── FLUE product agents and typed tools
├── typed tools ├── AgentOS execution environments
── canonical Flue persistence in Convex ── Codex implementation harness
│ later execution commands └── canonical events/results returned to Convex
│ optional attached full sandbox
Rivet Engine + AgentOS (post-Slice 1) Cube/E2B-compatible runtime (later)
└── sandboxes, harnesses, and durable execution
``` ```
Clients MUST communicate only with Convex. FLUE and future Rivet/AgentOS Clients MUST communicate only with Convex. FLUE and future Rivet/AgentOS services are private workers: Convex admits durable commands, invokes the worker, and stores the product-facing result before clients observe it.
services are private workers: Convex admits durable commands, invokes the
worker, and stores the product-facing result before clients observe it.
### Ownership ### Ownership
| Layer | Owns | | Layer | Owns |
|---|---| | --- | --- |
| Convex | authentication, normalized product records, command admission, reactive reads | | Convex | authentication, normalized product records, command admission, reactive reads |
| FLUE | private programmable orchestration and domain-specific agents | | Convex Workflow | durable sequencing, retries, cancellation, scheduling, and completion callbacks |
| Rivet actors (later) | serialized execution ownership, recovery, timers, leases | | Agent backend | private programmable agents and execution adapters |
| Rivet Engine + runners | placement, routing, sleep/wake, and execution ownership for AgentOS workspaces |
| Harness | bounded coding/tool loop | | Harness | bounded coding/tool loop |
| Sandbox/runtime | filesystem, processes, network, isolation | | Sandbox/runtime | filesystem, processes, network, isolation |
| Git | source revision history | | Git | source revision history |
@@ -63,11 +62,7 @@ signals ──< signalWorkAttachments >── works
works ──< workEvents works ──< workEvents
``` ```
Convex mutations provide atomic transactions and optimistic serializability. Convex mutations provide atomic transactions and optimistic serializability. Foreign-key integrity and uniqueness are enforced in the owning mutations; composite indexes back every identity and relation lookup. Flue's adapter tables remain isolated infrastructure persistence and are not product-domain relations.
Foreign-key integrity and uniqueness are enforced in the owning mutations;
composite indexes back every identity and relation lookup. Flue's adapter
tables remain isolated infrastructure persistence and are not product-domain
relations.
## 2. Domain boundaries ## 2. Domain boundaries
@@ -106,93 +101,93 @@ Avoid package proliferation in v0; logical boundaries may begin as folders.
Minimal durable model: Minimal durable model:
```ts ```ts
type Id = string type Id = string;
interface Message { interface Message {
id: Id id: Id;
projectId: Id projectId: Id;
content: string content: string;
createdAt: number createdAt: number;
} }
interface Signal { interface Signal {
id: Id id: Id;
projectId: Id projectId: Id;
sourceType: string sourceType: string;
sourceId: string sourceId: string;
sourcePayloadRef?: string sourcePayloadRef?: string;
summary: string summary: string;
fingerprint: string fingerprint: string;
status: "candidate" | "accepted" | "dismissed" status: "candidate" | "accepted" | "dismissed";
} }
interface Work { interface Work {
id: Id id: Id;
projectId: Id projectId: Id;
title: string title: string;
objective: string objective: string;
risk: "low" | "medium" | "high" risk: "low" | "medium" | "high";
status: WorkStatus status: WorkStatus;
definitionVersion?: number definitionVersion?: number;
designVersion?: number designVersion?: number;
createdAt: number createdAt: number;
updatedAt: number updatedAt: number;
} }
interface Step { interface Step {
id: Id id: Id;
workId: Id workId: Id;
sliceId?: Id sliceId?: Id;
kind: "design" | "implement" | "verify" | "integrate" | "publish" | "observe" kind: "design" | "implement" | "verify" | "integrate" | "publish" | "observe";
objective: string objective: string;
dependsOn: readonly Id[] dependsOn: readonly Id[];
status: StepStatus status: StepStatus;
} }
interface Run { interface Run {
id: Id id: Id;
workId: Id workId: Id;
stepId: Id stepId: Id;
kitVersion: string kitVersion: string;
status: RunStatus status: RunStatus;
} }
interface Attempt { interface Attempt {
id: Id id: Id;
runId: Id runId: Id;
number: number number: number;
harness: string harness: string;
runtime: string runtime: string;
sourceRevision: string sourceRevision: string;
status: AttemptStatus status: AttemptStatus;
startedAt?: number startedAt?: number;
endedAt?: number endedAt?: number;
} }
interface Artifact { interface Artifact {
id: Id id: Id;
workId: Id workId: Id;
stepId?: Id stepId?: Id;
runId?: Id runId?: Id;
attemptId?: Id attemptId?: Id;
type: string type: string;
uri?: string uri?: string;
contentHash?: string contentHash?: string;
sourceRevision?: string sourceRevision?: string;
environmentId?: string environmentId?: string;
metadata: unknown metadata: unknown;
} }
interface Question { interface Question {
id: Id id: Id;
workId: Id workId: Id;
stepId?: Id stepId?: Id;
attemptId?: Id attemptId?: Id;
prompt: string prompt: string;
recommendation?: string recommendation?: string;
alternatives: readonly string[] alternatives: readonly string[];
status: "open" | "answered" | "withdrawn" status: "open" | "answered" | "withdrawn";
answer?: string answer?: string;
} }
``` ```
@@ -337,35 +332,49 @@ Keep domain/application code provider-neutral.
```ts ```ts
interface HarnessRuntime { interface HarnessRuntime {
open(input: OpenHarnessInput): Effect.Effect<HarnessSession, HarnessError> open(input: OpenHarnessInput): Effect.Effect<HarnessSession, HarnessError>;
prompt(id: string, content: string): Effect.Effect<void, HarnessError> prompt(id: string, content: string): Effect.Effect<void, HarnessError>;
events(id: string): Stream.Stream<HarnessEvent, HarnessError> events(id: string): Stream.Stream<HarnessEvent, HarnessError>;
approve(input: PermissionDecision): Effect.Effect<void, HarnessError> approve(input: PermissionDecision): Effect.Effect<void, HarnessError>;
abort(id: string): Effect.Effect<void, HarnessError> abort(id: string): Effect.Effect<void, HarnessError>;
close(id: string): Effect.Effect<void, HarnessError> close(id: string): Effect.Effect<void, HarnessError>;
} }
interface SandboxRuntime { interface SandboxRuntime {
create(spec: SandboxSpec): Effect.Effect<SandboxLease, SandboxError> create(spec: SandboxSpec): Effect.Effect<SandboxLease, SandboxError>;
exec(lease: SandboxLease, cmd: Command): Effect.Effect<CommandResult, SandboxError> exec(
readFile(lease: SandboxLease, path: string): Effect.Effect<Uint8Array, SandboxError> lease: SandboxLease,
writeFile(lease: SandboxLease, path: string, body: Uint8Array): Effect.Effect<void, SandboxError> cmd: Command
pause(lease: SandboxLease): Effect.Effect<void, SandboxError> ): Effect.Effect<CommandResult, SandboxError>;
resume(id: string): Effect.Effect<SandboxLease, SandboxError> readFile(
terminate(lease: SandboxLease): Effect.Effect<void, SandboxError> lease: SandboxLease,
path: string
): Effect.Effect<Uint8Array, SandboxError>;
writeFile(
lease: SandboxLease,
path: string,
body: Uint8Array
): Effect.Effect<void, SandboxError>;
pause(lease: SandboxLease): Effect.Effect<void, SandboxError>;
resume(id: string): Effect.Effect<SandboxLease, SandboxError>;
terminate(lease: SandboxLease): Effect.Effect<void, SandboxError>;
} }
interface SourceControl { interface SourceControl {
prepareWorktree(input: WorktreeInput): Effect.Effect<Worktree, GitError> prepareWorktree(input: WorktreeInput): Effect.Effect<Worktree, GitError>;
diff(worktree: Worktree): Effect.Effect<DiffArtifact, GitError> diff(worktree: Worktree): Effect.Effect<DiffArtifact, GitError>;
commit(input: CommitInput): Effect.Effect<CommitArtifact, GitError> commit(input: CommitInput): Effect.Effect<CommitArtifact, GitError>;
push(input: PushInput): Effect.Effect<BranchArtifact, GitError> push(input: PushInput): Effect.Effect<BranchArtifact, GitError>;
createPullRequest(input: PullRequestInput): Effect.Effect<PullRequestArtifact, GitError> createPullRequest(
input: PullRequestInput
): Effect.Effect<PullRequestArtifact, GitError>;
} }
interface VerificationRuntime { interface VerificationRuntime {
execute(plan: VerificationPlan, env: EnvironmentRef): execute(
Effect.Effect<VerificationResult, VerificationError> plan: VerificationPlan,
env: EnvironmentRef
): Effect.Effect<VerificationResult, VerificationError>;
} }
``` ```
@@ -420,6 +429,10 @@ Zopu owns Work, branches, worktrees, budgets, approvals, artifacts, and completi
## 10. Runtime strategy ## 10. Runtime strategy
### Convex orchestration
Slice 5 uses the Convex Workflow component as the durable product orchestration layer. Workflow steps call private agent-backend actions, while all user-visible state, events, artifacts, idempotency keys, and cancellation remain canonical in Convex.
### CubeSandbox ### CubeSandbox
Best for full Linux execution: Best for full Linux execution:
@@ -443,7 +456,7 @@ Best for:
- actor-adjacent orchestration; - actor-adjacent orchestration;
- context/files/networking that fit runtime limits. - context/files/networking that fit runtime limits.
Use an attached full sandbox when native/heavy tooling is needed. Slice 5 starts here with one Codex-backed AgentOS actor and one authenticated repository checkout per project. Convex Workflow owns product orchestration; Rivet Engine coordinates placement while a normal runner executes the actor. Use an attached full sandbox through the E2B-compatible boundary when native/heavy tooling is needed.
### Persistent project machine ### Persistent project machine

View File

@@ -211,16 +211,18 @@ Zopu implements one approved slice in an isolated repository environment and str
Initial adapter choice: Initial adapter choice:
```text ```text
SandboxRuntime = CubeSandboxLive SandboxRuntime = AgentOsSandboxLive
HarnessRuntime = OmpHarnessLive (or one chosen harness) HarnessRuntime = CodexHarnessLive
Durable orchestration = Convex Workflow
``` ```
Flow: Flow:
```text ```text
prepare worktree load the project's authenticated Git connection
create sandbox start durable Convex workflow
→ clone/mount repo → create AgentOS execution environment
→ clone the single configured repo
→ inject context → inject context
→ run one slice → run one slice
→ normalize events → normalize events
@@ -230,14 +232,15 @@ prepare worktree
Security: Security:
- scoped Git/model tokens; - GitHub OAuth or self-hosted Gitea PAT, scoped to one project;
- scoped Git/model tokens passed only to private execution;
- isolated HOME/worktree; - isolated HOME/worktree;
- one mutating attempt per worktree; - one mutating attempt per worktree;
- timeout/cancel cleanup. - timeout/cancel cleanup.
### Frontend ### Frontend
Current activity, changed files, artifact links, expandable raw logs. Project selector/settings, Git connection status, current activity, changed files, artifact links, expandable raw logs, cancel/retry, and manual Git delivery controls.
### Acceptance ### Acceptance
@@ -247,6 +250,8 @@ Current activity, changed files, artifact links, expandable raw logs.
- provider failure becomes classified attempt outcome; - provider failure becomes classified attempt outcome;
- exact base/candidate revision recorded. - exact base/candidate revision recorded.
Rivet Engine coordinates AgentOS actor placement through a normal runner, but does not own product orchestration; Convex Workflow remains canonical for the Run lifecycle. Cube/Kubernetes sandbox support remains behind `SandboxRuntime` and can be mounted through AgentOS incrementally.
--- ---
## Slice 6 — Independent verification and repair ## Slice 6 — Independent verification and repair
@@ -490,4 +495,4 @@ browser-tester integration-coordinator
1 → 2 → 3 → 4 → 5 → 6 → 7 → 8 → 9 → 10 → 11 → 12 1 → 2 → 3 → 4 → 5 → 6 → 7 → 8 → 9 → 10 → 11 → 12
``` ```
Parallel engineering is allowed *within* a slice after contracts land, but product release order remains sequential. Parallel engineering is allowed _within_ a slice after contracts land, but product release order remains sequential.

View File

@@ -93,6 +93,8 @@
"vitest": "catalog:" "vitest": "catalog:"
}, },
"overrides": { "overrides": {
"react": "19.2.8",
"react-dom": "19.2.8",
"vite": "npm:@voidzero-dev/vite-plus-core@0.2.2" "vite": "npm:@voidzero-dev/vite-plus-core@0.2.2"
}, },
"packageManager": "bun@1.3.14" "packageManager": "bun@1.3.14"

View File

@@ -9,15 +9,21 @@
"dev": "bun --env-file=../../.env flue dev", "dev": "bun --env-file=../../.env flue dev",
"dev:tailscale": "bun --env-file=../../.env flue dev", "dev:tailscale": "bun --env-file=../../.env flue dev",
"run": "bun --env-file=../../.env flue run", "run": "bun --env-file=../../.env flue run",
"runner": "bun --env-file=../../.env src/runner.ts",
"run:zopu": "bun --env-file=../../.env flue run zopu", "run:zopu": "bun --env-file=../../.env flue run zopu",
"run:work-planner": "bun --env-file=../../.env flue run work-planner" "run:work-planner": "bun --env-file=../../.env flue run work-planner"
}, },
"dependencies": { "dependencies": {
"@agentos-software/codex-cli": "0.3.4",
"@agentos-software/git": "0.3.3",
"@code/backend": "workspace:*", "@code/backend": "workspace:*",
"@code/env": "workspace:*", "@code/env": "workspace:*",
"@code/primitives": "workspace:*",
"@flue/runtime": "latest", "@flue/runtime": "latest",
"@rivet-dev/agentos": "0.2.10",
"convex": "catalog:", "convex": "catalog:",
"hono": "catalog:", "hono": "catalog:",
"rivetkit": "2.3.9",
"valibot": "catalog:" "valibot": "catalog:"
}, },
"devDependencies": { "devDependencies": {

View File

@@ -1,7 +1,15 @@
import { parseAgentEnv } from "@code/env/agent"; import { parseAgentEnv } from "@code/env/agent";
import { WorkAttemptExecutionError } from "@code/primitives/execution-runtime";
import { registerProvider } from "@flue/runtime"; import { registerProvider } from "@flue/runtime";
import type { Fetchable } from "@flue/runtime/routing"; import type { Fetchable } from "@flue/runtime/routing";
import { flue } from "@flue/runtime/routing"; import { flue } from "@flue/runtime/routing";
import { Hono } from "hono";
import {
cancelAgentOsAttempt,
executeAgentOsAttempt,
runtimeRegistry,
} from "./runtime/agent-os";
const agentEnv = parseAgentEnv(process.env); const agentEnv = parseAgentEnv(process.env);
@@ -24,5 +32,54 @@ registerProvider(agentEnv.AGENT_MODEL_PROVIDER, {
}, },
}); });
// flue() returns a complete Hono app; the Fetchable contract accepts it. const app = new Hono();
export default flue() satisfies Fetchable;
app.post("/internal/work-attempts/execute", async (context) => {
if (
context.req.header("authorization") !== `Bearer ${agentEnv.FLUE_DB_TOKEN}`
) {
return context.json({ error: "Unauthorized" }, 401);
}
try {
return context.json(await executeAgentOsAttempt(await context.req.json()));
} catch (error) {
const failure =
error instanceof WorkAttemptExecutionError
? error
: new WorkAttemptExecutionError({
message:
error instanceof Error ? error.message : "Execution failed",
reason: "HarnessFailed",
retryable: false,
});
return context.json(
{
error: {
message: failure.message,
reason: failure.reason,
retryable: failure.retryable,
},
},
500
);
}
});
app.post("/internal/work-attempts/:workspaceKey/cancel", async (context) => {
if (
context.req.header("authorization") !== `Bearer ${agentEnv.FLUE_DB_TOKEN}`
) {
return context.json({ error: "Unauthorized" }, 401);
}
const body = (await context.req.json()) as { attemptId?: unknown };
if (typeof body.attemptId !== "string" || body.attemptId.length === 0) {
return context.json({ error: "attemptId is required" }, 400);
}
await cancelAgentOsAttempt(context.req.param("workspaceKey"), body.attemptId);
return context.json({ cancelled: true });
});
app.all("/api/rivet/*", (context) => runtimeRegistry.handler(context.req.raw));
app.route("/", flue());
export default app satisfies Fetchable;

View File

@@ -0,0 +1,3 @@
import { runtimeRegistry } from "./runtime/agent-os";
await runtimeRegistry.startAndWait();

View File

@@ -0,0 +1,277 @@
import { parseAgentEnv } from "@code/env/agent";
import { agentOS, setup } from "@rivet-dev/agentos";
import { createClient } from "@rivet-dev/agentos/client";
import { Effect } from "effect";
import {
codexSessionEnv,
makeCodexAgentOsConfig,
} from "../../../primitives/src/agent-os";
import {
decodeWorkAttemptExecutionInput,
WorkAttemptExecutionError,
} from "../../../primitives/src/execution-runtime";
import type {
ExecutionEvent,
WorkAttemptExecutionResult,
} from "../../../primitives/src/execution-runtime";
const codexConfig = makeCodexAgentOsConfig();
const workspace = agentOS<undefined, { token: string }>({
onBeforeConnect: (_context, params) => {
if (params.token !== process.env.RIVET_WORKSPACE_TOKEN) {
throw new Error("Unauthorized workspace connection");
}
},
software: codexConfig.software,
});
export const runtimeRegistry = setup({ use: { workspace } });
const shellQuote = (value: string): string =>
`'${value.replaceAll("'", `'"'"'`)}'`;
const event = (
sequence: number,
kind: ExecutionEvent["kind"],
message: string,
metadata: Record<string, string> = {}
): ExecutionEvent => ({
kind,
message,
metadata,
occurredAt: Date.now(),
sequence,
});
const requireSuccess = (
result: { exitCode: number; stderr: string; stdout: string },
operation: string
) => {
if (result.exitCode !== 0) {
throw new Error(`${operation} failed: ${result.stderr || result.stdout}`);
}
return result.stdout.trim();
};
const executionError = (
message: string,
reason: WorkAttemptExecutionError["reason"],
retryable: boolean
) => new WorkAttemptExecutionError({ message, reason, retryable });
const classifyRuntimeFailure = (cause: unknown): WorkAttemptExecutionError => {
if (cause instanceof WorkAttemptExecutionError) {
return cause;
}
const message = cause instanceof Error ? cause.message : "Execution failed";
if (/auth|credential|401|403/iu.test(message)) {
return executionError(message, "Authentication", false);
}
if (/clone|checkout|repository|git /iu.test(message)) {
return executionError(message, "RepositoryFailed", false);
}
if (/timeout|timed out/iu.test(message)) {
return executionError(message, "Timeout", true);
}
if (/connect|network|unavailable|502|503|504/iu.test(message)) {
return executionError(message, "ProviderUnavailable", true);
}
return executionError(message, "HarnessFailed", false);
};
const gitAuthEnv = (username: string, credential: string) => ({
GIT_CONFIG_COUNT: "1",
GIT_CONFIG_KEY_0: "http.extraHeader",
GIT_CONFIG_VALUE_0: `Authorization: Basic ${Buffer.from(`${username}:${credential}`).toString("base64")}`,
});
export const executeAgentOsAttempt = async (
rawInput: unknown
): Promise<WorkAttemptExecutionResult> => {
try {
const input = await Effect.runPromise(
decodeWorkAttemptExecutionInput(rawInput)
);
const env = parseAgentEnv(process.env);
const client = createClient<typeof runtimeRegistry>({
disableMetadataLookup: true,
endpoint: env.RIVET_PUBLIC_ENDPOINT ?? env.RIVET_ENDPOINT,
});
const vm = client.workspace.getOrCreate([input.workspaceKey], {
params: { token: env.RIVET_WORKSPACE_TOKEN },
});
const events: ExecutionEvent[] = [
event(0, "runtime.preparing", "AgentOS workspace selected", {
workspaceKey: input.workspaceKey,
}),
];
const authEnv = gitAuthEnv(
input.auth.username ??
(input.auth.provider === "github" ? "x-access-token" : "git"),
input.auth.credential
);
await vm.mkdir("/workspace", { recursive: true });
if (!(await vm.exists("/workspace/repository/.git"))) {
events.push(event(1, "repository.cloning", "Cloning project repository"));
const clone = await vm.execArgv(
"git",
["clone", input.repositoryUrl, "/workspace/repository"],
{
cwd: "/workspace",
env: authEnv,
}
);
requireSuccess(clone, "Repository clone");
}
const checkout = await vm.exec(
`git fetch origin ${shellQuote(input.baseBranch)} && git checkout -B ${shellQuote(`zopu/${input.runId}`)} ${shellQuote(`origin/${input.baseBranch}`)}`,
{ cwd: "/workspace/repository", env: authEnv }
);
requireSuccess(checkout, "Repository checkout");
const baseRevision = requireSuccess(
await vm.execArgv("git", ["rev-parse", "HEAD"], {
cwd: "/workspace/repository",
}),
"Base revision lookup"
);
events.push(
event(2, "repository.ready", "Repository checkout is ready", {
baseRevision,
})
);
const sessionId = `codex-${input.attemptId}`;
await vm.openSession({
additionalInstructions:
"Work only inside /workspace/repository. Do not reveal credentials. Make the requested change and run focused verification. Do not push or open a pull request.",
agent: "codex",
cwd: "/workspace/repository",
env: codexSessionEnv({
apiKey: env.AGENT_MODEL_API_KEY,
baseUrl: env.AGENT_MODEL_BASE_URL,
model: env.AGENT_MODEL_NAME,
}),
permissionPolicy: "allow_all",
sessionId,
});
events.push(
event(3, "harness.started", "Codex implementation session started")
);
const promptResult = await vm.prompt({
content: [{ text: input.prompt, type: "text" }],
idempotencyKey: input.attemptId,
sessionId,
});
if (promptResult.stopReason !== "end_turn") {
const reason =
promptResult.stopReason === "cancelled" ? "Cancelled" : "HarnessFailed";
throw executionError(
`Codex stopped with ${promptResult.stopReason}`,
reason,
promptResult.stopReason === "max_tokens" ||
promptResult.stopReason === "max_turn_requests"
);
}
events.push(
event(4, "harness.progress", "Codex implementation turn completed", {
stopReason: promptResult.stopReason,
})
);
const status = requireSuccess(
await vm.execArgv("git", ["status", "--porcelain"], {
cwd: "/workspace/repository",
}),
"Changed file lookup"
);
const diff = requireSuccess(
await vm.execArgv("git", ["diff", "--binary", "HEAD"], {
cwd: "/workspace/repository",
}),
"Diff collection"
);
const changedFiles = status
.split("\n")
.filter(Boolean)
.map((line) => line.slice(3).trim());
let candidateRevision = baseRevision;
if (changedFiles.length > 0) {
requireSuccess(
await vm.execArgv("git", ["add", "-A"], {
cwd: "/workspace/repository",
}),
"Candidate staging"
);
const tree = requireSuccess(
await vm.execArgv("git", ["write-tree"], {
cwd: "/workspace/repository",
}),
"Candidate tree creation"
);
candidateRevision = requireSuccess(
await vm.exec(
`printf %s ${shellQuote(`Zopu candidate for ${input.attemptId}`)} | git commit-tree ${shellQuote(tree)} -p ${shellQuote(baseRevision)}`,
{
cwd: "/workspace/repository",
env: {
GIT_AUTHOR_EMAIL: "agent@zopu.dev",
GIT_AUTHOR_NAME: "Zopu Agent",
GIT_COMMITTER_EMAIL: "agent@zopu.dev",
GIT_COMMITTER_NAME: "Zopu Agent",
},
}
),
"Candidate revision creation"
);
requireSuccess(
await vm.execArgv("git", ["reset"], { cwd: "/workspace/repository" }),
"Candidate index reset"
);
}
events.push(
event(
5,
"repository.changed",
`${changedFiles.length} changed file(s) collected`,
{
candidateRevision,
}
),
event(6, "runtime.completed", "AgentOS execution completed")
);
return {
baseRevision,
candidateRevision,
changedFiles,
diff,
environmentId: input.workspaceKey,
events,
summary:
changedFiles.length > 0
? `Codex changed ${changedFiles.length} file(s)`
: "Codex completed without repository changes",
};
} catch (error) {
throw classifyRuntimeFailure(error);
}
};
export const cancelAgentOsAttempt = async (
workspaceKey: string,
attemptId: string
) => {
const env = parseAgentEnv(process.env);
const client = createClient<typeof runtimeRegistry>({
disableMetadataLookup: true,
endpoint: env.RIVET_PUBLIC_ENDPOINT ?? env.RIVET_ENDPOINT,
});
await client.workspace
.getOrCreate([workspaceKey], {
params: { token: env.RIVET_WORKSPACE_TOKEN },
})
.cancelPrompt({ sessionId: `codex-${attemptId}` });
};

View File

@@ -11,7 +11,10 @@
import type * as auth from "../auth.js"; import type * as auth from "../auth.js";
import type * as authz from "../authz.js"; import type * as authz from "../authz.js";
import type * as conversationMessages from "../conversationMessages.js"; import type * as conversationMessages from "../conversationMessages.js";
import type * as crons from "../crons.js";
import type * as fluePersistence from "../fluePersistence.js"; import type * as fluePersistence from "../fluePersistence.js";
import type * as gitConnectionData from "../gitConnectionData.js";
import type * as gitConnections from "../gitConnections.js";
import type * as healthCheck from "../healthCheck.js"; import type * as healthCheck from "../healthCheck.js";
import type * as http from "../http.js"; import type * as http from "../http.js";
import type * as organizations from "../organizations.js"; import type * as organizations from "../organizations.js";
@@ -19,6 +22,11 @@ import type * as privateData from "../privateData.js";
import type * as projects from "../projects.js"; import type * as projects from "../projects.js";
import type * as publicGit from "../publicGit.js"; import type * as publicGit from "../publicGit.js";
import type * as signalRouting from "../signalRouting.js"; import type * as signalRouting from "../signalRouting.js";
import type * as workArtifacts from "../workArtifacts.js";
import type * as workExecution from "../workExecution.js";
import type * as workExecutionAgent from "../workExecutionAgent.js";
import type * as workExecutionWorkflow from "../workExecutionWorkflow.js";
import type * as workPlanning from "../workPlanning.js";
import type * as works from "../works.js"; import type * as works from "../works.js";
import type { import type {
@@ -31,7 +39,10 @@ declare const fullApi: ApiFromModules<{
auth: typeof auth; auth: typeof auth;
authz: typeof authz; authz: typeof authz;
conversationMessages: typeof conversationMessages; conversationMessages: typeof conversationMessages;
crons: typeof crons;
fluePersistence: typeof fluePersistence; fluePersistence: typeof fluePersistence;
gitConnectionData: typeof gitConnectionData;
gitConnections: typeof gitConnections;
healthCheck: typeof healthCheck; healthCheck: typeof healthCheck;
http: typeof http; http: typeof http;
organizations: typeof organizations; organizations: typeof organizations;
@@ -39,6 +50,11 @@ declare const fullApi: ApiFromModules<{
projects: typeof projects; projects: typeof projects;
publicGit: typeof publicGit; publicGit: typeof publicGit;
signalRouting: typeof signalRouting; signalRouting: typeof signalRouting;
workArtifacts: typeof workArtifacts;
workExecution: typeof workExecution;
workExecutionAgent: typeof workExecutionAgent;
workExecutionWorkflow: typeof workExecutionWorkflow;
workPlanning: typeof workPlanning;
works: typeof works; works: typeof works;
}>; }>;
@@ -70,4 +86,5 @@ export declare const internal: FilterApi<
export declare const components: { export declare const components: {
betterAuth: import("@convex-dev/better-auth/_generated/component.js").ComponentApi<"betterAuth">; betterAuth: import("@convex-dev/better-auth/_generated/component.js").ComponentApi<"betterAuth">;
workflow: import("@convex-dev/workflow/_generated/component.js").ComponentApi<"workflow">;
}; };

View File

@@ -25,10 +25,14 @@ import type { DataModel } from "./dataModel.js";
* Typesafe environment variables declared in `convex.config.ts`. * Typesafe environment variables declared in `convex.config.ts`.
*/ */
type Env = { type Env = {
readonly AGENT_BACKEND_URL: string | undefined;
readonly FLUE_DB_TOKEN: string; readonly FLUE_DB_TOKEN: string;
readonly FLUE_URL: string | undefined; readonly FLUE_URL: string | undefined;
readonly GITEA_TOKEN: string | undefined; readonly GITEA_TOKEN: string | undefined;
readonly GITEA_URL: string | undefined; readonly GITEA_URL: string | undefined;
readonly GITHUB_CLIENT_ID: string | undefined;
readonly GITHUB_CLIENT_SECRET: string | undefined;
readonly GIT_CREDENTIAL_ENCRYPTION_KEY: string | undefined;
readonly NATIVE_APP_URL: string | undefined; readonly NATIVE_APP_URL: string | undefined;
readonly SITE_URL: string; readonly SITE_URL: string;
}; };

View File

@@ -30,6 +30,15 @@ const createAuth = (ctx: GenericCtx<DataModel>) =>
jwksRotateOnTokenGenerationError: true, jwksRotateOnTokenGenerationError: true,
}), }),
], ],
socialProviders:
env.GITHUB_CLIENT_ID && env.GITHUB_CLIENT_SECRET
? {
github: {
clientId: env.GITHUB_CLIENT_ID,
clientSecret: env.GITHUB_CLIENT_SECRET,
},
}
: {},
trustedOrigins: [siteUrl, nativeAppUrl, "exp://"], trustedOrigins: [siteUrl, nativeAppUrl, "exp://"],
}); });

View File

@@ -1,17 +1,23 @@
import betterAuth from "@convex-dev/better-auth/convex.config"; import betterAuth from "@convex-dev/better-auth/convex.config";
import workflow from "@convex-dev/workflow/convex.config.js";
import { defineApp } from "convex/server"; import { defineApp } from "convex/server";
import { v } from "convex/values"; import { v } from "convex/values";
const app = defineApp({ const app = defineApp({
env: { env: {
AGENT_BACKEND_URL: v.optional(v.string()),
FLUE_DB_TOKEN: v.string(), FLUE_DB_TOKEN: v.string(),
FLUE_URL: v.optional(v.string()), FLUE_URL: v.optional(v.string()),
GITEA_TOKEN: v.optional(v.string()), GITEA_TOKEN: v.optional(v.string()),
GITEA_URL: v.optional(v.string()), GITEA_URL: v.optional(v.string()),
GITHUB_CLIENT_ID: v.optional(v.string()),
GITHUB_CLIENT_SECRET: v.optional(v.string()),
GIT_CREDENTIAL_ENCRYPTION_KEY: v.optional(v.string()),
NATIVE_APP_URL: v.optional(v.string()), NATIVE_APP_URL: v.optional(v.string()),
SITE_URL: v.string(), SITE_URL: v.string(),
}, },
}); });
app.use(betterAuth); app.use(betterAuth);
app.use(workflow);
export default app; export default app;

View File

@@ -0,0 +1,143 @@
import { ConvexError, v } from "convex/values";
import { internalMutation, mutation, query } from "./_generated/server";
import { requireCurrentOrganization, requireProjectMember } from "./authz";
// Provider ("forge") that owns a repository host. A project's source must be
// served by the same forge whose credentials are attached, so a Gitea token is
// never offered to GitHub and vice versa. Unknown hosts return null, leaving
// the caller free to attach without a forge constraint.
export const forgeForHost = (host: string): "github" | "gitea" | null => {
const normalized = host.toLowerCase();
if (normalized === "github.com" || normalized.endsWith(".githost.com")) {
return "github";
}
if (normalized === "git.openputer.com") {
return "gitea";
}
return null;
};
export const persist = internalMutation({
args: {
credentialCiphertext: v.string(),
credentialIv: v.string(),
credentialKind: v.union(v.literal("oauth"), v.literal("token")),
provider: v.union(v.literal("github"), v.literal("gitea")),
serverUrl: v.string(),
userId: v.string(),
username: v.optional(v.string()),
},
handler: async (ctx, args) => {
const organization = await ctx.db
.query("organizations")
.withIndex("by_createdBy_and_kind", (q) =>
q.eq("createdBy", args.userId).eq("kind", "personal")
)
.unique();
if (!organization) {
throw new ConvexError("Organization not found");
}
const existing = await ctx.db
.query("gitConnections")
.withIndex("by_organizationId_and_provider_and_serverUrl", (q) =>
q
.eq("organizationId", organization._id)
.eq("provider", args.provider)
.eq("serverUrl", args.serverUrl)
)
.unique();
const timestamp = Date.now();
if (existing) {
await ctx.db.patch(existing._id, {
credentialCiphertext: args.credentialCiphertext,
credentialIv: args.credentialIv,
credentialKind: args.credentialKind,
updatedAt: timestamp,
username: args.username,
});
return existing._id;
}
return await ctx.db.insert("gitConnections", {
connectedAt: timestamp,
credentialCiphertext: args.credentialCiphertext,
credentialIv: args.credentialIv,
credentialKind: args.credentialKind,
organizationId: organization._id,
provider: args.provider,
serverUrl: args.serverUrl,
updatedAt: timestamp,
username: args.username,
});
},
});
export const list = query({
args: {},
handler: async (ctx) => {
const { organizationId } = await requireCurrentOrganization(ctx);
const connections = await ctx.db
.query("gitConnections")
.withIndex("by_organizationId", (q) =>
q.eq("organizationId", organizationId)
)
.collect();
return connections.map((connection) => ({
connectedAt: connection.connectedAt,
credentialKind: connection.credentialKind,
id: String(connection._id),
provider: connection.provider,
serverUrl: connection.serverUrl,
username: connection.username,
}));
},
});
export const getForProject = query({
args: { projectId: v.id("projects") },
handler: async (ctx, args) => {
await requireProjectMember(ctx, args.projectId);
const project = await ctx.db.get(args.projectId);
const connection = project?.gitConnectionId
? await ctx.db.get(project.gitConnectionId)
: null;
return connection
? {
connectedAt: connection.connectedAt,
credentialKind: connection.credentialKind,
id: String(connection._id),
provider: connection.provider,
serverUrl: connection.serverUrl,
username: connection.username,
}
: null;
},
});
export const attachToProject = mutation({
args: {
connectionId: v.id("gitConnections"),
projectId: v.id("projects"),
},
handler: async (ctx, args) => {
const { organizationId } = await requireProjectMember(ctx, args.projectId);
const connection = await ctx.db.get(args.connectionId);
if (!connection || connection.organizationId !== organizationId) {
throw new ConvexError("Git connection not found");
}
const project = await ctx.db.get(args.projectId);
if (project) {
const expected = forgeForHost(project.sourceHost);
if (expected && connection.provider !== expected) {
throw new ConvexError(
`Git credential provider (${connection.provider}) does not match this project's forge (${expected})`
);
}
}
await ctx.db.patch(args.projectId, {
gitConnectionId: connection._id,
updatedAt: Date.now(),
});
return { attached: true };
},
});

View File

@@ -0,0 +1,124 @@
"use node";
import { env } from "@code/env/convex";
import { decodeGitConnectionInput } from "@code/primitives/execution-runtime";
import { ConvexError, v } from "convex/values";
import { Effect } from "effect";
import { internal } from "./_generated/api";
import type { Id } from "./_generated/dataModel";
import { action } from "./_generated/server";
import { authComponent, createAuth } from "./auth";
const encryptionKey = async (): Promise<CryptoKey> => {
if (!env.GIT_CREDENTIAL_ENCRYPTION_KEY) {
throw new ConvexError("Git credential encryption is not configured");
}
const bytes = Buffer.from(env.GIT_CREDENTIAL_ENCRYPTION_KEY, "base64url");
if (bytes.byteLength !== 32) {
throw new ConvexError("Git credential encryption key must be 32 bytes");
}
return await crypto.subtle.importKey("raw", bytes, "AES-GCM", false, [
"encrypt",
"decrypt",
]);
};
const encryptCredential = async (credential: string) => {
const iv = crypto.getRandomValues(new Uint8Array(12));
const encrypted = await crypto.subtle.encrypt(
{ iv, name: "AES-GCM" },
await encryptionKey(),
new TextEncoder().encode(credential)
);
return {
credentialCiphertext: Buffer.from(encrypted).toString("base64url"),
credentialIv: Buffer.from(iv).toString("base64url"),
};
};
export const decryptCredential = async (
credentialCiphertext: string,
credentialIv: string
): Promise<string> => {
const decrypted = await crypto.subtle.decrypt(
{
iv: Buffer.from(credentialIv, "base64url"),
name: "AES-GCM",
},
await encryptionKey(),
Buffer.from(credentialCiphertext, "base64url")
);
return new TextDecoder().decode(decrypted);
};
export const connectGitea = action({
args: {
serverUrl: v.string(),
token: v.string(),
username: v.optional(v.string()),
},
handler: async (
ctx,
args
): Promise<{ connectionId: Id<"gitConnections"> }> => {
const userId = await ctx.auth.getUserIdentity().then((identity) => {
if (!identity) {
throw new ConvexError("Authentication required");
}
return identity.tokenIdentifier;
});
const connection = await Effect.runPromise(
decodeGitConnectionInput({
credential: args.token,
credentialKind: "token",
provider: "gitea",
serverUrl: args.serverUrl,
username: args.username,
})
);
const encrypted = await encryptCredential(connection.credential);
const connectionId = await ctx.runMutation(
internal.gitConnectionData.persist,
{
...encrypted,
credentialKind: connection.credentialKind,
provider: connection.provider,
serverUrl: connection.serverUrl,
userId,
username: connection.username,
}
);
return { connectionId };
},
});
export const connectGithub = action({
args: {},
handler: async (ctx): Promise<{ connectionId: Id<"gitConnections"> }> => {
const identity = await ctx.auth.getUserIdentity();
if (!identity) {
throw new ConvexError("Authentication required");
}
const { auth, headers } = await authComponent.getAuth(createAuth, ctx);
const token = await auth.api.getAccessToken({
body: { providerId: "github" },
headers,
});
if (!token.accessToken) {
throw new ConvexError("GitHub account is not connected");
}
const encrypted = await encryptCredential(token.accessToken);
const connectionId = await ctx.runMutation(
internal.gitConnectionData.persist,
{
...encrypted,
credentialKind: "oauth",
provider: "github",
serverUrl: "https://github.com",
userId: identity.tokenIdentifier,
}
);
return { connectionId };
},
});

View File

@@ -44,10 +44,28 @@ export default defineSchema({
.index("by_userId", ["userId"]) .index("by_userId", ["userId"])
.index("by_organizationId", ["organizationId"]) .index("by_organizationId", ["organizationId"])
.index("by_organizationId_and_userId", ["organizationId", "userId"]), .index("by_organizationId_and_userId", ["organizationId", "userId"]),
gitConnections: defineTable({
connectedAt: v.number(),
credentialCiphertext: v.string(),
credentialIv: v.string(),
credentialKind: v.union(v.literal("oauth"), v.literal("token")),
organizationId: v.id("organizations"),
provider: v.union(v.literal("github"), v.literal("gitea")),
serverUrl: v.string(),
updatedAt: v.number(),
username: v.optional(v.string()),
})
.index("by_organizationId", ["organizationId"])
.index("by_organizationId_and_provider_and_serverUrl", [
"organizationId",
"provider",
"serverUrl",
]),
projects: defineTable({ projects: defineTable({
createdAt: v.number(), createdAt: v.number(),
defaultBranch: v.optional(v.string()), defaultBranch: v.optional(v.string()),
description: v.optional(v.string()), description: v.optional(v.string()),
gitConnectionId: v.optional(v.id("gitConnections")),
name: v.string(), name: v.string(),
normalizedSourceUrl: v.string(), normalizedSourceUrl: v.string(),
organizationId: v.id("organizations"), organizationId: v.id("organizations"),
@@ -314,11 +332,17 @@ export default defineSchema({
]), ]),
workRuns: defineTable({ workRuns: defineTable({
baseRevision: v.optional(v.string()),
candidateRevision: v.optional(v.string()),
createdAt: v.number(), createdAt: v.number(),
designVersion: v.optional(v.number()), designVersion: v.optional(v.number()),
endedAt: v.optional(v.number()), endedAt: v.optional(v.number()),
kitId: v.string(), kitId: v.string(),
kitVersion: v.string(), kitVersion: v.string(),
environmentId: v.optional(v.string()),
executionKind: v.optional(
v.union(v.literal("simulated"), v.literal("real"))
),
scenario: v.union( scenario: v.union(
v.literal("success"), v.literal("success"),
v.literal("transient-failure-then-success"), v.literal("transient-failure-then-success"),
@@ -337,12 +361,24 @@ export default defineSchema({
), ),
terminalClassification: v.optional(attemptClassification), terminalClassification: v.optional(attemptClassification),
terminalSummary: v.optional(v.string()), terminalSummary: v.optional(v.string()),
workflowId: v.optional(v.string()),
workId: v.id("works"), workId: v.id("works"),
}).index("by_work_and_createdAt", ["workId", "createdAt"]), }).index("by_work_and_createdAt", ["workId", "createdAt"]),
workAttempts: defineTable({ workAttempts: defineTable({
classification: v.optional(attemptClassification), classification: v.optional(attemptClassification),
endedAt: v.optional(v.number()), endedAt: v.optional(v.number()),
failureReason: v.optional(
v.union(
v.literal("Authentication"),
v.literal("Cancelled"),
v.literal("HarnessFailed"),
v.literal("InvalidInput"),
v.literal("ProviderUnavailable"),
v.literal("RepositoryFailed"),
v.literal("Timeout")
)
),
leaseExpiresAt: v.optional(v.number()), leaseExpiresAt: v.optional(v.number()),
leaseOwner: v.optional(v.string()), leaseOwner: v.optional(v.string()),
number: v.number(), number: v.number(),
@@ -356,6 +392,7 @@ export default defineSchema({
), ),
summary: v.optional(v.string()), summary: v.optional(v.string()),
workId: v.id("works"), workId: v.id("works"),
workspaceKey: v.optional(v.string()),
}) })
.index("by_runId_and_number", ["runId", "number"]) .index("by_runId_and_number", ["runId", "number"])
.index("by_status_and_leaseExpiresAt", ["status", "leaseExpiresAt"]), .index("by_status_and_leaseExpiresAt", ["status", "leaseExpiresAt"]),

View File

@@ -0,0 +1,97 @@
"use node";
import { env } from "@code/env/convex";
import {
WorkAttemptExecutionError,
decodeWorkAttemptExecutionFailure,
decodeWorkAttemptExecutionResult,
} from "@code/primitives/execution-runtime";
import { ConvexError, v } from "convex/values";
import { Effect } from "effect";
import { internal } from "./_generated/api";
import { internalAction } from "./_generated/server";
import { decryptCredential } from "./gitConnections";
const backendUrl = () => env.AGENT_BACKEND_URL ?? env.FLUE_URL;
export const executeAttempt = internalAction({
args: { attemptId: v.id("workAttempts") },
handler: async (ctx, args) => {
const running = await ctx.runMutation(
internal.workExecutionWorkflow.markAttemptRunning,
args
);
if (!running) {
throw new ConvexError("Attempt is no longer runnable");
}
const context = await ctx.runQuery(
internal.workExecutionWorkflow.executionContext,
args
);
const credential = await decryptCredential(
context.connection.credentialCiphertext,
context.connection.credentialIv
);
const response = await fetch(
`${backendUrl()}/internal/work-attempts/execute`,
{
body: JSON.stringify({
attemptId: String(context.attempt._id),
auth: {
credential,
provider: context.connection.provider,
serverUrl: context.connection.serverUrl,
username: context.connection.username,
},
baseBranch: context.project.defaultBranch ?? "main",
prompt: context.prompt,
repositoryUrl: context.project.sourceUrl,
runId: String(context.run._id),
workId: String(context.work._id),
workspaceKey: context.attempt.workspaceKey,
}),
headers: {
authorization: `Bearer ${env.FLUE_DB_TOKEN}`,
"content-type": "application/json",
},
method: "POST",
}
);
const payload = (await response.json()) as unknown;
if (!response.ok) {
// Decode the agent's classified failure envelope and re-throw as the
// typed runtime error so the workflow handler maps reason/retryable to
// a durable attempt classification. A malformed envelope falls back to
// an InvalidInput failure (non-retryable).
const failure = await Effect.runPromise(
decodeWorkAttemptExecutionFailure(payload)
);
throw new WorkAttemptExecutionError(failure.error);
}
return await Effect.runPromise(decodeWorkAttemptExecutionResult(payload));
},
});
export const cancelAttempt = internalAction({
args: {
attemptId: v.string(),
workspaceKey: v.string(),
},
handler: async (_ctx, args) => {
// The workspace key remains the URL path segment (workspace identity),
// while the body carries the attemptId so the runtime can target the
// codex session `codex-${attemptId}` for cancellation.
await fetch(
`${backendUrl()}/internal/work-attempts/${encodeURIComponent(args.workspaceKey)}/cancel`,
{
body: JSON.stringify({ attemptId: args.attemptId }),
headers: {
authorization: `Bearer ${env.FLUE_DB_TOKEN}`,
"content-type": "application/json",
},
method: "POST",
}
);
},
});

View File

@@ -0,0 +1,381 @@
import { convexTest } from "convex-test";
import { anyApi } from "convex/server";
import { describe, expect, test } from "vitest";
import schema from "./schema";
const modules = import.meta.glob("./**/*.ts");
const api = anyApi;
type TestContext = ReturnType<typeof convexTest>;
interface Seeded {
attemptId: string;
runId: string;
t: TestContext;
workId: string;
}
// Seed an in-flight real attempt so each mutation under test starts from a
// realistic running state: Work "executing", Run "running", Attempt "running".
const seedRunningAttempt = async (
overrides: {
attemptStatus?: "queued" | "claimed" | "running" | "terminal";
runStatus?: "ready" | "running" | "terminal" | "cancelled";
} = {}
): Promise<Seeded> => {
const t = convexTest({ modules, schema });
const seeded = await t.run(async (ctx) => {
const organizationId = await ctx.db.insert("organizations", {
createdAt: 1,
createdBy: "user",
kind: "personal",
name: "Personal",
});
const projectId = await ctx.db.insert("projects", {
createdAt: 1,
name: "Zopu",
normalizedSourceUrl: "https://github.com/puter/zopu",
organizationId,
repositoryPath: "puter/zopu",
sourceHost: "github.com",
sourceUrl: "https://github.com/puter/zopu",
updatedAt: 1,
});
const workId = await ctx.db.insert("works", {
createdAt: 1,
objective: "Implement a real slice",
organizationId,
projectId,
status: "executing",
title: "Real execution",
updatedAt: 1,
});
const sliceRowId = await ctx.db.insert("workSlices", {
designVersion: 1,
objective: "Change the repo",
observableBehavior: "A diff exists",
ordinal: 0,
payloadJson: "{}",
sliceId: "slice-1",
status: "running",
title: "Implementation",
workId,
});
const runId = await ctx.db.insert("workRuns", {
createdAt: 1,
designVersion: 1,
executionKind: "real",
kitId: "coding-v0",
kitVersion: "1",
scenario: "success",
sliceId: "slice-1",
sliceRowId,
status: overrides.runStatus ?? "running",
workId,
});
const attemptId = await ctx.db.insert("workAttempts", {
number: 1,
runId,
status: overrides.attemptStatus ?? "running",
workId,
workspaceKey: "workspace-1",
});
return { attemptId, runId, workId };
});
return { ...seeded, t };
};
const successResult = {
baseRevision: "base123",
candidateRevision: "candidate456",
changedFiles: ["src/index.ts"],
diff: "+export const ready = true;",
environmentId: "workspace-1",
events: [
{
kind: "runtime.completed",
message: "completed",
metadata: {},
occurredAt: 2,
sequence: 0,
},
],
summary: "Changed one file",
};
describe("real work execution persistence", () => {
test("records revisions, activity, diff, and terminal state atomically", async () => {
const { t, ...seeded } = await seedRunningAttempt();
await t.mutation(api.workExecutionWorkflow.completeAttempt, {
attemptId: seeded.attemptId,
result: successResult,
});
const state = await t.run(async (ctx) => ({
artifacts: await ctx.db.query("workArtifacts").collect(),
attempt: await ctx.db.get(seeded.attemptId as any),
run: await ctx.db.get(seeded.runId as any),
work: await ctx.db.get(seeded.workId as any),
}));
expect(state.attempt?.classification).toBe("Succeeded");
expect(state.run).toMatchObject({
baseRevision: "base123",
candidateRevision: "candidate456",
terminalClassification: "Succeeded",
});
expect(state.work?.status).toBe("completed");
expect(state.artifacts[0]).toMatchObject({
kind: "diff",
sourceRevision: "candidate456",
});
});
});
describe("classified failure mapping", () => {
test("maps a transient runtime reason to a retryable classification", async () => {
const { t, ...seeded } = await seedRunningAttempt();
await t.mutation(api.workExecutionWorkflow.failAttempt, {
attemptId: seeded.attemptId,
reason: "ProviderUnavailable",
retryable: true,
summary: "model provider timed out",
});
const attempt = await t.run((ctx) => ctx.db.get(seeded.attemptId as any));
expect(attempt?.classification).toBe("RetryableFailure");
expect(attempt?.failureReason).toBe("ProviderUnavailable");
});
test("queues a new attempt without terminalizing a retryable run", async () => {
const { t, ...seeded } = await seedRunningAttempt();
await t.mutation(api.workExecutionWorkflow.failAttempt, {
attemptId: seeded.attemptId,
reason: "ProviderUnavailable",
retryable: true,
summary: "provider unavailable",
});
const state = await t.run(async (ctx) => ({
attempts: await ctx.db.query("workAttempts").collect(),
run: await ctx.db.get(seeded.runId as any),
work: await ctx.db.get(seeded.workId as any),
}));
expect(state.attempts).toHaveLength(2);
expect(state.attempts[1]).toMatchObject({
number: 2,
status: "queued",
workspaceKey: "workspace-1",
});
expect(state.run?.status).toBe("running");
expect(state.work?.status).toBe("executing");
});
test("maps an authentication reason to a permanent failure", async () => {
const { t, ...seeded } = await seedRunningAttempt();
await t.mutation(api.workExecutionWorkflow.failAttempt, {
attemptId: seeded.attemptId,
reason: "Authentication",
retryable: false,
summary: "token rejected",
});
const state = await t.run(async (ctx) => ({
attempt: await ctx.db.get(seeded.attemptId as any),
run: await ctx.db.get(seeded.runId as any),
work: await ctx.db.get(seeded.workId as any),
}));
expect(state.attempt?.classification).toBe("PermanentFailure");
expect(state.attempt?.failureReason).toBe("Authentication");
expect(state.run?.terminalClassification).toBe("PermanentFailure");
expect(state.work?.status).toBe("failed");
});
});
describe("cancellation fencing", () => {
test("a cancelled attempt cannot later settle success", async () => {
const { t, ...seeded } = await seedRunningAttempt();
// Simulate cancellation marking the attempt/run terminal as Cancelled.
await t.run(async (ctx) => {
await ctx.db.patch(seeded.attemptId as any, {
classification: "Cancelled",
endedAt: 5,
status: "terminal",
summary: "Execution cancelled",
});
await ctx.db.patch(seeded.runId as any, {
endedAt: 5,
status: "cancelled",
terminalClassification: "Cancelled",
terminalSummary: "Execution cancelled",
});
});
// A late-arriving completion must be ignored.
await t.mutation(api.workExecutionWorkflow.completeAttempt, {
attemptId: seeded.attemptId,
result: successResult,
});
const attempt = await t.run((ctx) => ctx.db.get(seeded.attemptId as any));
expect(attempt?.classification).toBe("Cancelled");
expect(attempt?.status).toBe("terminal");
});
test("a late failure does not overwrite a cancelled run", async () => {
const { t, ...seeded } = await seedRunningAttempt();
await t.run(async (ctx) => {
await ctx.db.patch(seeded.attemptId as any, {
classification: "Cancelled",
endedAt: 5,
status: "terminal",
});
await ctx.db.patch(seeded.runId as any, { status: "cancelled" });
});
await t.mutation(api.workExecutionWorkflow.failAttempt, {
attemptId: seeded.attemptId,
reason: "HarnessFailed",
retryable: true,
summary: "late failure",
});
const attempt = await t.run((ctx) => ctx.db.get(seeded.attemptId as any));
expect(attempt?.classification).toBe("Cancelled");
});
});
describe("empty-change rejection", () => {
test("a no-op result with no changed files fails as permanent", async () => {
const { t, ...seeded } = await seedRunningAttempt();
await t.mutation(api.workExecutionWorkflow.completeAttempt, {
attemptId: seeded.attemptId,
result: {
...successResult,
changedFiles: [],
candidateRevision: "base123",
},
});
const state = await t.run(async (ctx) => ({
attempt: await ctx.db.get(seeded.attemptId as any),
work: await ctx.db.get(seeded.workId as any),
}));
expect(state.attempt?.classification).toBe("PermanentFailure");
expect(state.attempt?.failureReason).toBe("InvalidInput");
expect(state.work?.status).toBe("failed");
});
test("identical base and candidate revisions are rejected", async () => {
const { t, ...seeded } = await seedRunningAttempt();
await t.mutation(api.workExecutionWorkflow.completeAttempt, {
attemptId: seeded.attemptId,
result: {
...successResult,
baseRevision: "same",
candidateRevision: "same",
},
});
const attempt = await t.run((ctx) => ctx.db.get(seeded.attemptId as any));
expect(attempt?.classification).toBe("PermanentFailure");
});
});
describe("attempt re-entry", () => {
test("markAttemptRunning re-claims an already-running attempt", async () => {
const { t, ...seeded } = await seedRunningAttempt();
// First claim (already "running" from seed) must still succeed so a
// workflow replay can re-enter the same live attempt.
const first = await t.mutation(
api.workExecutionWorkflow.markAttemptRunning,
{ attemptId: seeded.attemptId }
);
expect(first).toBe(true);
const attempt = await t.run((ctx) => ctx.db.get(seeded.attemptId as any));
expect(attempt?.status).toBe("running");
expect(attempt?.leaseExpiresAt).toBeGreaterThan(0);
});
test("a terminal attempt is not re-runnable", async () => {
const { t, ...seeded } = await seedRunningAttempt({
attemptStatus: "terminal",
});
const result = await t.mutation(
api.workExecutionWorkflow.markAttemptRunning,
{ attemptId: seeded.attemptId }
);
expect(result).toBe(false);
});
test("a cancelled run cannot re-enter a queued attempt", async () => {
const { t, ...seeded } = await seedRunningAttempt({
attemptStatus: "queued",
runStatus: "cancelled",
});
const result = await t.mutation(
api.workExecutionWorkflow.markAttemptRunning,
{ attemptId: seeded.attemptId }
);
expect(result).toBe(false);
const attempt = await t.run((ctx) => ctx.db.get(seeded.attemptId as any));
expect(attempt?.status).toBe("queued");
});
});
describe("forge credential validation", () => {
const identity = { tokenIdentifier: "https://convex.test|forge-user" };
const seedForgableProject = async (
provider: "github" | "gitea",
sourceHost: string
) => {
const t = convexTest({ modules, schema }).withIdentity(identity);
const ids = await t.run(async (ctx) => {
const organizationId = await ctx.db.insert("organizations", {
createdAt: 1,
createdBy: identity.tokenIdentifier,
kind: "personal",
name: "Personal",
});
await ctx.db.insert("organizationMembers", {
createdAt: 1,
organizationId,
role: "owner",
userId: identity.tokenIdentifier,
});
const projectId = await ctx.db.insert("projects", {
createdAt: 1,
name: "Zopu",
normalizedSourceUrl: `https://${sourceHost}/puter/zopu`,
organizationId,
repositoryPath: "puter/zopu",
sourceHost,
sourceUrl: `https://${sourceHost}/puter/zopu`,
updatedAt: 1,
});
const connectionId = await ctx.db.insert("gitConnections", {
connectedAt: 1,
credentialCiphertext: "x",
credentialIv: "y",
credentialKind: provider === "github" ? "oauth" : "token",
organizationId,
provider,
serverUrl: `https://${sourceHost}`,
updatedAt: 1,
username: "zopu",
});
return { connectionId, projectId };
});
return { t, ids };
};
test("rejects a git connection whose provider mismatches the project forge", async () => {
// Gitea token attached to a GitHub-hosted project.
const { t, ids } = await seedForgableProject("gitea", "github.com");
await expect(
t.mutation(api.gitConnectionData.attachToProject, {
connectionId: ids.connectionId,
projectId: ids.projectId,
})
).rejects.toThrow(/does not match this project's forge/u);
});
test("accepts a matching provider for the project forge", async () => {
const { t, ids } = await seedForgableProject("github", "github.com");
const result = await t.mutation(api.gitConnectionData.attachToProject, {
connectionId: ids.connectionId,
projectId: ids.projectId,
});
expect(result).toMatchObject({ attached: true });
});
});

View File

@@ -0,0 +1,632 @@
import { WorkAttemptExecutionError } from "@code/primitives/execution-runtime";
import type { WorkAttemptExecutionErrorReason } from "@code/primitives/execution-runtime";
import { defaultCodingKitV0, resolveOutcome } from "@code/primitives/resolver";
import type { AttemptClassification } from "@code/primitives/resolver";
import { WorkflowManager } from "@convex-dev/workflow";
import type { WorkflowId } from "@convex-dev/workflow";
import { ConvexError, v } from "convex/values";
import { components, internal } from "./_generated/api";
import type { Doc, Id } from "./_generated/dataModel";
import { internalMutation, internalQuery, mutation } from "./_generated/server";
import type { MutationCtx } from "./_generated/server";
import { requireProjectMember } from "./authz";
import { forgeForHost } from "./gitConnectionData";
export const workflow = new WorkflowManager(components.workflow);
// Lease window for a running real attempt. Long enough to outlast a single
// agent turn; the workflow's own retry/lease reconciliation covers crashes.
const LEASE_MS = 5 * 60_000;
// Runtime failure reason -> durable attempt classification. The Convex
// workflow stores classifications, not provider-specific reasons, so the
// resolver and Work lifecycle stay forge-agnostic. `retryable` from the
// runtime is carried alongside and consulted by the kit retry policy.
const FAILURE_REASON_CLASSIFICATION = {
Authentication: "PermanentFailure",
Cancelled: "Cancelled",
HarnessFailed: "RetryableFailure",
InvalidInput: "PermanentFailure",
ProviderUnavailable: "RetryableFailure",
RepositoryFailed: "PermanentFailure",
Timeout: "RetryableFailure",
} as const satisfies Record<
WorkAttemptExecutionErrorReason,
AttemptClassification
>;
export const classifyFailure = (
reason: WorkAttemptExecutionErrorReason
): AttemptClassification => FAILURE_REASON_CLASSIFICATION[reason];
// Normalize an error thrown from the agent action into the durable failure
// triple (reason/retryable/summary). WorkAttemptExecutionError is the
// classified runtime failure; anything else is a Convex/infrastructure error
// treated as a transient HarnessFailed so the workflow retry policy decides.
const toExecutionFailure = (
error: unknown
): {
message: string;
reason: WorkAttemptExecutionErrorReason;
retryable: boolean;
} =>
error instanceof WorkAttemptExecutionError
? {
message: error.message,
reason: error.reason,
retryable: error.retryable,
}
: {
message: error instanceof Error ? error.message : "Execution failed",
reason: "HarnessFailed",
retryable: true,
};
const failureReasonValues = v.union(
v.literal("Authentication"),
v.literal("Cancelled"),
v.literal("HarnessFailed"),
v.literal("InvalidInput"),
v.literal("ProviderUnavailable"),
v.literal("RepositoryFailed"),
v.literal("Timeout")
);
const resolveReadySlice = async (
ctx: MutationCtx,
work: Doc<"works">,
sliceId?: string
) => {
if (work.designVersion === undefined) {
throw new ConvexError("Work has no approved Design to execute");
}
const slices = await ctx.db
.query("workSlices")
.withIndex("by_workId_and_designVersion", (q) =>
q.eq("workId", work._id).eq("designVersion", work.designVersion!)
)
.collect();
const slice = sliceId
? slices.find((candidate) => candidate.sliceId === sliceId)
: slices
.sort((left, right) => left.ordinal - right.ordinal)
.find((candidate) => candidate.status === "ready");
if (!slice || slice.status !== "ready") {
throw new ConvexError("Only the next ready slice can be executed");
}
return slice;
};
// Deployment prerequisite gate for real execution. Rejects before any
// workflow/sandbox starts when the project lacks an attached, forge-matched
// Git connection with a cloneable source URL and default branch. Returns the
// validated connection so the caller can pass it to the agent unchanged.
const validateProjectDeployment = async (
ctx: MutationCtx,
work: Doc<"works">
): Promise<Doc<"gitConnections">> => {
const project = await ctx.db.get(work.projectId);
if (!project) {
throw new ConvexError("Project not found");
}
if (!project.gitConnectionId) {
throw new ConvexError("Connect Git credentials to this project first");
}
const connection = await ctx.db.get(project.gitConnectionId);
if (!connection) {
throw new ConvexError("Git connection not found");
}
const expected = forgeForHost(project.sourceHost);
if (expected && connection.provider !== expected) {
throw new ConvexError(
`Git credential provider (${connection.provider}) does not match this project's forge (${expected})`
);
}
return connection;
};
export const execute = workflow
.define({ args: { attemptId: v.id("workAttempts") } })
.handler(async (step, args): Promise<void> => {
try {
const result = await step.runAction(
internal.workExecutionAgent.executeAttempt,
args,
{ retry: true }
);
await step.runMutation(internal.workExecutionWorkflow.completeAttempt, {
attemptId: args.attemptId,
result: {
...result,
changedFiles: [...result.changedFiles],
events: result.events.map((item) => ({
...item,
metadata: { ...item.metadata },
})),
},
});
} catch (error) {
const failure = toExecutionFailure(error);
await step.runMutation(internal.workExecutionWorkflow.failAttempt, {
attemptId: args.attemptId,
reason: failure.reason,
retryable: failure.retryable,
summary: failure.message,
});
}
});
export const startExecution = mutation({
args: {
sliceId: v.optional(v.string()),
workId: v.id("works"),
},
handler: async (
ctx,
args
): Promise<{
attemptId: Id<"workAttempts">;
runId: Id<"workRuns">;
workflowId: WorkflowId;
}> => {
const work = await ctx.db.get(args.workId);
if (!work) {
throw new ConvexError("Work not found");
}
await requireProjectMember(ctx, work.projectId);
if (work.status !== "ready") {
throw new ConvexError("Work must be Ready before execution");
}
if (
work.definitionApprovalVersion !== work.definitionVersion ||
work.designApprovalVersion !== work.designVersion
) {
throw new ConvexError("Execution requires exact approved versions");
}
await validateProjectDeployment(ctx, work);
const slice = await resolveReadySlice(ctx, work, args.sliceId);
const createdAt = Date.now();
const runId = await ctx.db.insert("workRuns", {
createdAt,
designVersion: slice.designVersion,
executionKind: "real",
kitId: defaultCodingKitV0.id,
kitVersion: defaultCodingKitV0.version,
scenario: "success",
sliceId: slice.sliceId,
sliceRowId: slice._id,
status: "running",
workId: work._id,
});
const workspaceKey = `work-${work._id}-run-${runId}`;
const attemptId = await ctx.db.insert("workAttempts", {
number: 1,
runId,
status: "queued",
workId: work._id,
workspaceKey,
});
const workflowId: WorkflowId = await workflow.start(
ctx,
internal.workExecutionWorkflow.execute,
{ attemptId }
);
await ctx.db.patch(runId, { startedAt: createdAt, workflowId });
await ctx.db.patch(slice._id, { status: "running" });
await ctx.db.patch(work._id, { status: "executing", updatedAt: createdAt });
await ctx.db.insert("workEvents", {
createdAt,
idempotencyKey: `real-run-started:${runId}`,
kind: "run.started",
referenceId: String(runId),
workId: work._id,
});
return { attemptId, runId, workflowId };
},
});
export const executionContext = internalQuery({
args: { attemptId: v.id("workAttempts") },
handler: async (ctx, args) => {
const attempt = await ctx.db.get(args.attemptId);
if (!attempt) {
throw new ConvexError("Attempt not found");
}
const run = await ctx.db.get(attempt.runId);
const work = await ctx.db.get(attempt.workId);
if (!run || !work || !run.sliceRowId) {
throw new ConvexError("Execution records are incomplete");
}
const [slice, project] = await Promise.all([
ctx.db.get(run.sliceRowId),
ctx.db.get(work.projectId),
]);
if (!slice || !project?.gitConnectionId) {
throw new ConvexError("Project execution configuration is incomplete");
}
const connection = await ctx.db.get(project.gitConnectionId);
if (!connection) {
throw new ConvexError("Git connection not found");
}
const expectedForge = forgeForHost(project.sourceHost);
if (expectedForge && connection.provider !== expectedForge) {
throw new ConvexError(
`Git credential provider (${connection.provider}) does not match this project's forge (${expectedForge})`
);
}
return {
attempt,
connection,
project,
prompt: [
`Implement this approved Zopu slice: ${slice.title}`,
`Objective: ${slice.objective}`,
`Observable behavior: ${slice.observableBehavior}`,
"Inspect the repository instructions first. Make focused changes and run relevant checks.",
].join("\n\n"),
run,
work,
};
},
});
export const markAttemptRunning = internalMutation({
args: { attemptId: v.id("workAttempts") },
handler: async (ctx, args) => {
const attempt = await ctx.db.get(args.attemptId);
if (!attempt || attempt.status === "terminal") {
return false;
}
const run = await ctx.db.get(attempt.runId);
if (!run || run.status !== "running") {
return false;
}
await ctx.db.patch(attempt._id, {
leaseExpiresAt: Date.now() + LEASE_MS,
startedAt: attempt.startedAt ?? Date.now(),
status: "running",
});
return true;
},
});
const settleSliceAndWork = async (
ctx: MutationCtx,
run: Doc<"workRuns">,
succeeded: boolean,
workStatus: Doc<"works">["status"]
) => {
if (!run.sliceRowId) {
return;
}
const slice = await ctx.db.get(run.sliceRowId);
if (!slice) {
return;
}
let sliceStatus: "blocked" | "completed" | "ready" = "ready";
if (succeeded) {
sliceStatus = "completed";
} else if (workStatus === "blocked") {
sliceStatus = "blocked";
}
await ctx.db.patch(slice._id, { status: sliceStatus });
const work = await ctx.db.get(run.workId);
if (!work) {
return;
}
let status = workStatus;
if (succeeded) {
const slices = await ctx.db
.query("workSlices")
.withIndex("by_workId_and_designVersion", (q) =>
q.eq("workId", work._id).eq("designVersion", slice.designVersion)
)
.collect();
const next = slices
.sort((left, right) => left.ordinal - right.ordinal)
.find((candidate) => candidate.status === "planned");
if (next) {
await ctx.db.patch(next._id, { status: "ready" });
status = "ready";
}
}
await ctx.db.patch(work._id, { status, updatedAt: Date.now() });
};
export const completeAttempt = internalMutation({
args: {
attemptId: v.id("workAttempts"),
result: v.object({
baseRevision: v.string(),
candidateRevision: v.string(),
changedFiles: v.array(v.string()),
diff: v.string(),
environmentId: v.string(),
events: v.array(
v.object({
kind: v.string(),
message: v.string(),
metadata: v.record(v.string(), v.string()),
occurredAt: v.number(),
sequence: v.number(),
})
),
summary: v.string(),
}),
},
handler: async (ctx, args) => {
const attempt = await ctx.db.get(args.attemptId);
// Cancellation fencing: a terminal or cancelled attempt/run must never
// later settle success, even if the agent action raced to completion.
if (!attempt || attempt.status === "terminal") {
return;
}
const run = await ctx.db.get(attempt.runId);
const work = await ctx.db.get(attempt.workId);
if (!run || !work) {
throw new ConvexError("Execution records not found");
}
if (run.status === "terminal" || run.status === "cancelled") {
return;
}
// Empty-change rejection: a no-op result (no changed files, or identical
// base/candidate revisions) is not a successful implementation. Fail it
// as a permanent InvalidInput so the resolver does not mark Work done.
const noOp =
args.result.changedFiles.length === 0 ||
args.result.baseRevision === args.result.candidateRevision;
if (noOp) {
await ctx.db.patch(attempt._id, {
classification: "PermanentFailure",
endedAt: Date.now(),
failureReason: "InvalidInput",
leaseExpiresAt: undefined,
status: "terminal",
summary: "Execution produced no repository changes",
});
await ctx.db.patch(run._id, {
endedAt: Date.now(),
status: "terminal",
terminalClassification: "PermanentFailure",
terminalSummary: "Execution produced no repository changes",
});
await settleSliceAndWork(ctx, run, false, "failed");
return;
}
for (const item of args.result.events) {
await ctx.db.insert("workAttemptEvents", {
attemptId: attempt._id,
kind: item.kind,
message: item.message,
metadataJson: JSON.stringify(item.metadata),
occurredAt: item.occurredAt,
sequence: item.sequence,
});
}
const endedAt = Date.now();
await ctx.db.patch(attempt._id, {
classification: "Succeeded",
endedAt,
leaseExpiresAt: undefined,
status: "terminal",
summary: args.result.summary,
});
await ctx.db.patch(run._id, {
baseRevision: args.result.baseRevision,
candidateRevision: args.result.candidateRevision,
endedAt,
environmentId: args.result.environmentId,
status: "terminal",
terminalClassification: "Succeeded",
terminalSummary: args.result.summary,
});
await ctx.db.insert("workArtifacts", {
attemptId: attempt._id,
createdAt: endedAt,
designVersion: run.designVersion,
environmentId: args.result.environmentId,
idempotencyKey: `real-diff:${attempt._id}`,
kind: "diff",
metadataJson: JSON.stringify({ changedFiles: args.result.changedFiles }),
organizationId: work.organizationId,
producer: "agentos-codex",
projectId: work.projectId,
provenanceJson: JSON.stringify({
baseRevision: args.result.baseRevision,
}),
runId: run._id,
sliceId: run.sliceId,
sourceRevision: args.result.candidateRevision,
title: "Implementation diff",
verificationStatus: "unverified",
workId: work._id,
...(args.result.diff.length > 0
? {
uri: `data:text/plain;charset=utf-8,${encodeURIComponent(args.result.diff.slice(0, 50_000))}`,
}
: {}),
});
await settleSliceAndWork(ctx, run, true, "completed");
await ctx.db.insert("workEvents", {
createdAt: endedAt,
idempotencyKey: `real-run-completed:${run._id}`,
kind: "run.completed",
payloadJson: JSON.stringify({ classification: "Succeeded" }),
referenceId: String(run._id),
workId: work._id,
});
},
});
export const launchAttemptWorkflow = internalMutation({
args: { attemptId: v.id("workAttempts") },
handler: async (ctx, args) => {
const attempt = await ctx.db.get(args.attemptId);
if (!attempt || attempt.status === "terminal") {
return;
}
const run = await ctx.db.get(attempt.runId);
if (!run || run.status !== "running") {
return;
}
const workflowId: WorkflowId = await workflow.start(
ctx,
internal.workExecutionWorkflow.execute,
args
);
await ctx.db.patch(run._id, { workflowId });
},
});
export const failAttempt = internalMutation({
args: {
attemptId: v.id("workAttempts"),
reason: failureReasonValues,
retryable: v.boolean(),
summary: v.string(),
},
handler: async (ctx, args) => {
const attempt = await ctx.db.get(args.attemptId);
// Cancellation fencing: once an attempt or run is terminal/cancelled, a
// late failure from the workflow catch block must not overwrite the
// settled state. This also prevents a cancelled attempt from settling
// as a different classification after cancelExecution ran.
if (!attempt || attempt.status === "terminal") {
return;
}
const run = await ctx.db.get(attempt.runId);
if (!run || run.status === "terminal" || run.status === "cancelled") {
return;
}
const classification = classifyFailure(args.reason);
const endedAt = Date.now();
await ctx.db.patch(attempt._id, {
classification,
endedAt,
failureReason: args.reason,
leaseExpiresAt: undefined,
status: "terminal",
summary: args.summary,
});
const outcome = resolveOutcome(
{ classification, retryable: args.retryable, summary: args.summary },
attempt.number,
defaultCodingKitV0.retryPolicy
);
await ctx.db.insert("resolverDecisions", {
attemptId: attempt._id,
attemptNumber: attempt.number,
classification,
createdAt: endedAt,
decision: outcome.kind,
...(outcome.kind === "terminal"
? { resultingWorkStatus: outcome.workStatus }
: {}),
runId: run._id,
summary: args.summary,
workId: attempt.workId,
});
if (outcome.kind === "retry") {
const nextAttemptId = await ctx.db.insert("workAttempts", {
number: attempt.number + 1,
runId: run._id,
status: "queued",
workId: attempt.workId,
workspaceKey: attempt.workspaceKey,
});
await ctx.scheduler.runAfter(
0,
internal.workExecutionWorkflow.launchAttemptWorkflow,
{ attemptId: nextAttemptId }
);
return;
}
await ctx.db.patch(run._id, {
endedAt,
status: "terminal",
terminalClassification: classification,
terminalSummary: args.summary,
});
await settleSliceAndWork(ctx, run, false, outcome.workStatus);
const work = await ctx.db.get(run.workId);
if (work) {
await ctx.db.insert("workEvents", {
createdAt: endedAt,
idempotencyKey: `real-run-failed:${run._id}`,
kind: "run.completed",
payloadJson: JSON.stringify({ classification }),
referenceId: String(run._id),
workId: work._id,
});
}
},
});
export const cancelExecution = mutation({
args: { runId: v.id("workRuns") },
handler: async (ctx, args) => {
const run = await ctx.db.get(args.runId);
if (!run) {
throw new ConvexError("Run not found");
}
await requireProjectMember(ctx, (await ctx.db.get(run.workId))!.projectId);
if (run.status !== "running") {
return { cancelled: false };
}
if (run.workflowId) {
await workflow.cancel(ctx, run.workflowId as WorkflowId);
}
const attempts = await ctx.db
.query("workAttempts")
.withIndex("by_runId_and_number", (q) => q.eq("runId", run._id))
.collect();
const attempt = attempts.find(
(candidate) => candidate.status !== "terminal"
);
if (attempt?.workspaceKey) {
await ctx.scheduler.runAfter(
0,
internal.workExecutionAgent.cancelAttempt,
{
attemptId: String(attempt._id),
workspaceKey: attempt.workspaceKey,
}
);
const cancelledAt = Date.now();
await ctx.db.patch(attempt._id, {
classification: "Cancelled",
endedAt: cancelledAt,
failureReason: "Cancelled",
leaseExpiresAt: undefined,
status: "terminal",
summary: "Execution cancelled",
});
await ctx.db.insert("resolverDecisions", {
attemptId: attempt._id,
attemptNumber: attempt.number,
classification: "Cancelled",
createdAt: cancelledAt,
decision: "terminal",
resultingWorkStatus: "ready",
runId: run._id,
summary: "Execution cancelled",
workId: run.workId,
});
}
await ctx.db.patch(run._id, {
endedAt: Date.now(),
status: "cancelled",
terminalClassification: "Cancelled",
terminalSummary: "Execution cancelled",
});
if (run.sliceRowId) {
await ctx.db.patch(run.sliceRowId, { status: "ready" });
}
const work = await ctx.db.get(run.workId);
if (work) {
await ctx.db.patch(work._id, { status: "ready", updatedAt: Date.now() });
}
return { cancelled: true };
},
});

View File

@@ -771,13 +771,41 @@ export const listForProject = query({
.eq("designVersion", work.designVersion ?? 0) .eq("designVersion", work.designVersion ?? 0)
) )
.collect(); .collect();
const runs = await ctx.db const runRows = await ctx.db
.query("workRuns") .query("workRuns")
.withIndex("by_work_and_createdAt", (q: any) => .withIndex("by_work_and_createdAt", (q: any) =>
q.eq("workId", work._id) q.eq("workId", work._id)
) )
.order("desc") .order("desc")
.take(10); .take(10);
const runs = await Promise.all(
runRows.map(async (run) => {
const attempts = await ctx.db
.query("workAttempts")
.withIndex("by_runId_and_number", (q) => q.eq("runId", run._id))
.collect();
const eventsByAttempt = await Promise.all(
attempts.map((attempt) =>
ctx.db
.query("workAttemptEvents")
.withIndex("by_attempt_and_sequence", (q: any) =>
q.eq("attemptId", attempt._id)
)
.collect()
)
);
const attemptEvents = eventsByAttempt
.flat()
.sort((left, right) => left.occurredAt - right.occurredAt);
const artifacts = await ctx.db
.query("workArtifacts")
.withIndex("by_runId_and_createdAt", (q) =>
q.eq("runId", run._id)
)
.collect();
return { ...run, artifacts, attemptEvents, attempts };
})
);
const events = await ctx.db const events = await ctx.db
.query("workEvents") .query("workEvents")
.withIndex("by_work_and_createdAt", (q: any) => .withIndex("by_work_and_createdAt", (q: any) =>

View File

@@ -16,6 +16,7 @@
"@code/env": "workspace:*", "@code/env": "workspace:*",
"@code/primitives": "workspace:*", "@code/primitives": "workspace:*",
"@convex-dev/better-auth": "catalog:", "@convex-dev/better-auth": "catalog:",
"@convex-dev/workflow": "0.4.4",
"better-auth": "catalog:", "better-auth": "catalog:",
"convex": "catalog:", "convex": "catalog:",
"effect": "catalog:", "effect": "catalog:",

View File

@@ -14,6 +14,9 @@ const agentEnvSchema = z.object({
GITEA_TOKEN: z.string().min(1).optional(), GITEA_TOKEN: z.string().min(1).optional(),
GITEA_URL: z.url().default("https://git.openputer.com"), GITEA_URL: z.url().default("https://git.openputer.com"),
OPENROUTER_API_KEY: z.string().min(1).optional(), OPENROUTER_API_KEY: z.string().min(1).optional(),
RIVET_ENDPOINT: z.url(),
RIVET_PUBLIC_ENDPOINT: z.url().optional(),
RIVET_WORKSPACE_TOKEN: z.string().min(32),
}); });
export type AgentEnv = z.infer<typeof agentEnvSchema>; export type AgentEnv = z.infer<typeof agentEnvSchema>;

View File

@@ -5,10 +5,15 @@ export const env = createEnv({
emptyStringAsUndefined: true, emptyStringAsUndefined: true,
runtimeEnv: process.env, runtimeEnv: process.env,
server: { server: {
AGENT_BACKEND_URL: z.url().optional(),
CONVEX_SITE_URL: z.url(), CONVEX_SITE_URL: z.url(),
FLUE_DB_TOKEN: z.string().min(1), FLUE_DB_TOKEN: z.string().min(1),
FLUE_URL: z.url().optional(),
GITEA_TOKEN: z.string().min(1).optional(), GITEA_TOKEN: z.string().min(1).optional(),
GITEA_URL: z.url().default("https://git.openputer.com"), GITEA_URL: z.url().default("https://git.openputer.com"),
GITHUB_CLIENT_ID: z.string().min(1).optional(),
GITHUB_CLIENT_SECRET: z.string().min(1).optional(),
GIT_CREDENTIAL_ENCRYPTION_KEY: z.string().min(43).optional(),
NATIVE_APP_URL: z.string().min(1).default("code://"), NATIVE_APP_URL: z.string().min(1).default("code://"),
SITE_URL: z.url(), SITE_URL: z.url(),
}, },

View File

@@ -6,6 +6,7 @@
"exports": { "exports": {
".": "./src/index.ts", ".": "./src/index.ts",
"./agent-os": "./src/agent-os.ts", "./agent-os": "./src/agent-os.ts",
"./execution-runtime": "./src/execution-runtime.ts",
"./git": "./src/git.ts", "./git": "./src/git.ts",
"./git-local-runtime": "./src/git-local-runtime.ts", "./git-local-runtime": "./src/git-local-runtime.ts",
"./git-remote-runtime": "./src/git-remote-runtime.ts", "./git-remote-runtime": "./src/git-remote-runtime.ts",
@@ -29,7 +30,7 @@
"test:watch": "vitest" "test:watch": "vitest"
}, },
"dependencies": { "dependencies": {
"@agentos-software/codex-cli": "0.3.4", "@agentos-software/codex": "0.2.7",
"@agentos-software/git": "0.3.3", "@agentos-software/git": "0.3.3",
"@rivet-dev/agentos": "catalog:", "@rivet-dev/agentos": "catalog:",
"effect": "catalog:" "effect": "catalog:"

View File

@@ -1,5 +1,5 @@
/* eslint-disable max-classes-per-file -- the AgentOS service and its tagged error form one adapter contract. */ /* eslint-disable max-classes-per-file -- the AgentOS service and its tagged error form one adapter contract. */
import codex from "@agentos-software/codex-cli"; import codex from "@agentos-software/codex";
import { agentOS as createAgentOsActor } from "@rivet-dev/agentos"; import { agentOS as createAgentOsActor } from "@rivet-dev/agentos";
import type { AgentOSConfigInput } from "@rivet-dev/agentos"; import type { AgentOSConfigInput } from "@rivet-dev/agentos";
import { Context, Effect, Layer, Schema } from "effect"; import { Context, Effect, Layer, Schema } from "effect";
@@ -99,6 +99,7 @@ export const codexSessionEnv = (
model: CodexModelEnv, model: CodexModelEnv,
extra: Readonly<Record<string, string>> = {} extra: Readonly<Record<string, string>> = {}
): Record<string, string> => ({ ): Record<string, string> => ({
CODEX_MODEL: model.model,
OPENAI_API_KEY: model.apiKey, OPENAI_API_KEY: model.apiKey,
OPENAI_BASE_URL: model.baseUrl, OPENAI_BASE_URL: model.baseUrl,
...extra, ...extra,

View File

@@ -0,0 +1,38 @@
import { Effect } from "effect";
import { describe, expect, test } from "vitest";
import {
decodeGitConnectionInput,
decodeWorkAttemptExecutionResult,
} from "./execution-runtime";
describe("execution runtime contracts", () => {
test("accepts one authenticated Gitea connection", async () => {
const decoded = await Effect.runPromise(
decodeGitConnectionInput({
credential: "secret",
credentialKind: "token",
provider: "gitea",
serverUrl: "https://git.example.com",
username: "zopu",
})
);
expect(decoded.provider).toBe("gitea");
});
test("requires exact base and candidate revisions", async () => {
await expect(
Effect.runPromise(
decodeWorkAttemptExecutionResult({
baseRevision: "",
candidateRevision: "abc123",
changedFiles: [],
diff: "",
environmentId: "workspace-1",
events: [],
summary: "done",
})
)
).rejects.toMatchObject({ reason: "InvalidInput" });
});
});

View File

@@ -0,0 +1,171 @@
/* eslint-disable max-classes-per-file -- execution boundary errors live with their schemas. */
import { Effect, Schema } from "effect";
const Text = Schema.String.check(
Schema.makeFilter((value) => value.trim().length > 0, {
expected: "a non-empty string",
})
);
const HttpUrl = Schema.String.check(
Schema.makeFilter(
(value) => {
try {
const url = new URL(value);
return url.protocol === "http:" || url.protocol === "https:";
} catch {
return false;
}
},
{ expected: "an HTTP URL" }
)
);
export const GitProvider = Schema.Literals(["github", "gitea"]);
export type GitProvider = typeof GitProvider.Type;
export const GitCredentialKind = Schema.Literals(["oauth", "token"]);
export type GitCredentialKind = typeof GitCredentialKind.Type;
export const GitConnectionInput = Schema.Struct({
credential: Text,
credentialKind: GitCredentialKind,
provider: GitProvider,
serverUrl: HttpUrl,
username: Schema.optional(Text),
});
export type GitConnectionInput = typeof GitConnectionInput.Type;
export const GitConnectionView = Schema.Struct({
connectedAt: Schema.Number,
credentialKind: GitCredentialKind,
id: Text,
provider: GitProvider,
serverUrl: HttpUrl,
username: Schema.optional(Text),
});
export type GitConnectionView = typeof GitConnectionView.Type;
export const RepositoryExecutionAuth = Schema.Struct({
credential: Text,
provider: GitProvider,
serverUrl: HttpUrl,
username: Schema.optional(Text),
});
export type RepositoryExecutionAuth = typeof RepositoryExecutionAuth.Type;
export const ExecutionEventKind = Schema.Literals([
"runtime.preparing",
"repository.cloning",
"repository.ready",
"harness.started",
"harness.progress",
"harness.log",
"repository.changed",
"runtime.completed",
"runtime.failed",
"runtime.cancelled",
]);
export type ExecutionEventKind = typeof ExecutionEventKind.Type;
export const ExecutionEvent = Schema.Struct({
kind: ExecutionEventKind,
message: Text,
metadata: Schema.Record(Schema.String, Schema.String),
occurredAt: Schema.Number,
sequence: Schema.Int,
});
export type ExecutionEvent = typeof ExecutionEvent.Type;
export const WorkAttemptExecutionInput = Schema.Struct({
attemptId: Text,
auth: RepositoryExecutionAuth,
baseBranch: Text,
prompt: Text,
repositoryUrl: HttpUrl,
runId: Text,
workId: Text,
workspaceKey: Text,
});
export type WorkAttemptExecutionInput = typeof WorkAttemptExecutionInput.Type;
export const WorkAttemptExecutionResult = Schema.Struct({
baseRevision: Text,
candidateRevision: Text,
changedFiles: Schema.Array(Text),
diff: Schema.String,
environmentId: Text,
events: Schema.Array(ExecutionEvent),
summary: Text,
});
export type WorkAttemptExecutionResult = typeof WorkAttemptExecutionResult.Type;
export const WorkAttemptExecutionErrorReason = Schema.Literals([
"Authentication",
"Cancelled",
"HarnessFailed",
"InvalidInput",
"ProviderUnavailable",
"RepositoryFailed",
"Timeout",
]);
export type WorkAttemptExecutionErrorReason =
typeof WorkAttemptExecutionErrorReason.Type;
export class WorkAttemptExecutionError extends Schema.TaggedErrorClass<WorkAttemptExecutionError>()(
"WorkAttemptExecutionError",
{
message: Schema.String,
reason: WorkAttemptExecutionErrorReason,
retryable: Schema.Boolean,
}
) {}
export const WorkAttemptExecutionFailure = Schema.Struct({
error: Schema.Struct({
message: Text,
reason: WorkAttemptExecutionErrorReason,
retryable: Schema.Boolean,
}),
});
export type WorkAttemptExecutionFailure =
typeof WorkAttemptExecutionFailure.Type;
const invalidInput = (message: string) =>
new WorkAttemptExecutionError({
message,
reason: "InvalidInput",
retryable: false,
});
export const decodeGitConnectionInput = (input: unknown) =>
Schema.decodeUnknownEffect(GitConnectionInput)(input).pipe(
Effect.mapError((cause) => invalidInput(cause.message))
);
export const decodeWorkAttemptExecutionInput = (input: unknown) =>
Schema.decodeUnknownEffect(WorkAttemptExecutionInput)(input).pipe(
Effect.mapError((cause) => invalidInput(cause.message))
);
export const decodeWorkAttemptExecutionResult = (input: unknown) =>
Schema.decodeUnknownEffect(WorkAttemptExecutionResult)(input).pipe(
Effect.mapError((cause) => invalidInput(cause.message))
);
export const decodeWorkAttemptExecutionFailure = (input: unknown) =>
Schema.decodeUnknownEffect(WorkAttemptExecutionFailure)(input).pipe(
Effect.mapError((cause) => invalidInput(cause.message))
);
export interface SandboxRuntime {
readonly name: string;
readonly execute: (
input: WorkAttemptExecutionInput,
signal?: AbortSignal
) => Effect.Effect<WorkAttemptExecutionResult, WorkAttemptExecutionError>;
readonly cancel: (
workspaceKey: string,
attemptId: string
) => Effect.Effect<void, WorkAttemptExecutionError>;
}

View File

@@ -1,5 +1,6 @@
// oxlint-disable-next-line no-barrel-file -- The package root intentionally exposes its public modules. // oxlint-disable-next-line no-barrel-file -- The package root intentionally exposes its public modules.
export * from "./agent-os"; export * from "./agent-os";
export * from "./execution-runtime";
export * from "./git"; export * from "./git";
export * from "./git-local-runtime"; export * from "./git-local-runtime";
export * from "./git-remote-runtime"; export * from "./git-remote-runtime";