mirror of
https://github.com/harivansh-afk/sandbox-agent.git
synced 2026-04-20 05:04:49 +00:00
feat(factory): finish workbench milestone pass
This commit is contained in:
parent
bf282199b5
commit
49cba9e6c2
137 changed files with 819 additions and 338 deletions
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "@openhandoff/backend",
|
||||
"name": "@sandbox-agent/factory-backend",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
"@hono/node-server": "^1.19.7",
|
||||
"@hono/node-ws": "^1.3.0",
|
||||
"@iarna/toml": "^2.2.5",
|
||||
"@openhandoff/shared": "workspace:*",
|
||||
"@sandbox-agent/factory-shared": "workspace:*",
|
||||
"@sandbox-agent/persist-rivet": "workspace:*",
|
||||
"drizzle-orm": "^0.44.5",
|
||||
"hono": "^4.11.9",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { AppConfig } from "@openhandoff/shared";
|
||||
import type { AppConfig } from "@sandbox-agent/factory-shared";
|
||||
import type { BackendDriver } from "../driver.js";
|
||||
import type { NotificationService } from "../notifications/index.js";
|
||||
import type { ProviderRegistry } from "../providers/index.js";
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { HandoffStatus, ProviderId } from "@openhandoff/shared";
|
||||
import type { HandoffStatus, ProviderId } from "@sandbox-agent/factory-shared";
|
||||
|
||||
export interface HandoffCreatedEvent {
|
||||
workspaceId: string;
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import {
|
|||
sandboxInstanceKey,
|
||||
workspaceKey
|
||||
} from "./keys.js";
|
||||
import type { ProviderId } from "@openhandoff/shared";
|
||||
import type { ProviderId } from "@sandbox-agent/factory-shared";
|
||||
|
||||
export function actorClient(c: any) {
|
||||
return c.client();
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { actor, queue } from "rivetkit";
|
||||
import { workflow } from "rivetkit/workflow";
|
||||
import type { ProviderId } from "@openhandoff/shared";
|
||||
import type { ProviderId } from "@sandbox-agent/factory-shared";
|
||||
import { getHandoff, getSandboxInstance, selfHandoffStatusSync } from "../handles.js";
|
||||
import { logActorWarning, resolveErrorMessage, resolveErrorStack } from "../logging.js";
|
||||
import { type PollingControlState, runWorkflowPollingLoop } from "../polling.js";
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import type {
|
|||
HandoffWorkbenchSendMessageInput,
|
||||
HandoffWorkbenchUpdateDraftInput,
|
||||
ProviderId
|
||||
} from "@openhandoff/shared";
|
||||
} from "@sandbox-agent/factory-shared";
|
||||
import { expectQueueResponse } from "../../services/queue.js";
|
||||
import { selfHandoff } from "../handles.js";
|
||||
import { handoffDb } from "./db/db.js";
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// @ts-nocheck
|
||||
import { eq } from "drizzle-orm";
|
||||
import type { HandoffRecord, HandoffStatus } from "@openhandoff/shared";
|
||||
import type { HandoffRecord, HandoffStatus } from "@sandbox-agent/factory-shared";
|
||||
import { getOrCreateWorkspace } from "../../handles.js";
|
||||
import { handoff as handoffTable, handoffRuntime, handoffSandboxes } from "../db/schema.js";
|
||||
import { historyKey } from "../../keys.js";
|
||||
|
|
|
|||
|
|
@ -46,6 +46,8 @@ import {
|
|||
|
||||
export { HANDOFF_QUEUE_NAMES, handoffWorkflowQueueName } from "./queue.js";
|
||||
|
||||
const INIT_ENSURE_NAME_TIMEOUT_MS = 5 * 60_000;
|
||||
|
||||
type HandoffQueueName = (typeof HANDOFF_QUEUE_NAMES)[number];
|
||||
|
||||
type WorkflowHandler = (loopCtx: any, msg: { name: HandoffQueueName; body: any; complete: (response: unknown) => Promise<void> }) => Promise<void>;
|
||||
|
|
@ -75,7 +77,11 @@ const commandHandlers: Record<HandoffQueueName, WorkflowHandler> = {
|
|||
const body = msg.body;
|
||||
await loopCtx.removed("init-failed", "step");
|
||||
try {
|
||||
await loopCtx.step("init-ensure-name", async () => initEnsureNameActivity(loopCtx));
|
||||
await loopCtx.step({
|
||||
name: "init-ensure-name",
|
||||
timeout: INIT_ENSURE_NAME_TIMEOUT_MS,
|
||||
run: async () => initEnsureNameActivity(loopCtx),
|
||||
});
|
||||
await loopCtx.step("init-assert-name", async () => initAssertNameActivity(loopCtx));
|
||||
|
||||
const sandbox = await loopCtx.step({
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
import { and, desc, eq } from "drizzle-orm";
|
||||
import { actor, queue } from "rivetkit";
|
||||
import { Loop, workflow } from "rivetkit/workflow";
|
||||
import type { HistoryEvent } from "@openhandoff/shared";
|
||||
import type { HistoryEvent } from "@sandbox-agent/factory-shared";
|
||||
import { selfHistory } from "../handles.js";
|
||||
import { historyDb } from "./db/db.js";
|
||||
import { events } from "./db/schema.js";
|
||||
|
|
|
|||
|
|
@ -27,5 +27,5 @@ export function logActorWarning(
|
|||
...(context ?? {})
|
||||
};
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn("[openhandoff][actor:warn]", payload);
|
||||
console.warn("[factory][actor:warn]", payload);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import type {
|
|||
RepoOverview,
|
||||
RepoStackAction,
|
||||
RepoStackActionResult
|
||||
} from "@openhandoff/shared";
|
||||
} from "@sandbox-agent/factory-shared";
|
||||
import { getActorRuntimeContext } from "../context.js";
|
||||
import {
|
||||
getHandoff,
|
||||
|
|
@ -21,7 +21,7 @@ import {
|
|||
selfProject
|
||||
} from "../handles.js";
|
||||
import { isActorNotFoundError, logActorWarning, resolveErrorMessage } from "../logging.js";
|
||||
import { openhandoffRepoClonePath } from "../../services/openhandoff-paths.js";
|
||||
import { factoryRepoClonePath } from "../../services/factory-paths.js";
|
||||
import { expectQueueResponse } from "../../services/queue.js";
|
||||
import { withRepoGitLock } from "../../services/repo-git-lock.js";
|
||||
import { branches, handoffIndex, prCache, repoMeta } from "./db/schema.js";
|
||||
|
|
@ -125,7 +125,7 @@ export function projectWorkflowQueueName(name: ProjectQueueName): ProjectQueueNa
|
|||
|
||||
async function ensureLocalClone(c: any, remoteUrl: string): Promise<string> {
|
||||
const { config, driver } = getActorRuntimeContext();
|
||||
const localPath = openhandoffRepoClonePath(config, c.state.workspaceId, c.state.repoId);
|
||||
const localPath = factoryRepoClonePath(config, c.state.workspaceId, c.state.repoId);
|
||||
await driver.git.ensureCloned(remoteUrl, localPath);
|
||||
c.state.localPath = localPath;
|
||||
return localPath;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { setTimeout as delay } from "node:timers/promises";
|
|||
import { eq } from "drizzle-orm";
|
||||
import { actor, queue } from "rivetkit";
|
||||
import { Loop, workflow } from "rivetkit/workflow";
|
||||
import type { ProviderId } from "@openhandoff/shared";
|
||||
import type { ProviderId } from "@sandbox-agent/factory-shared";
|
||||
import type { SessionEvent, SessionRecord } from "sandbox-agent";
|
||||
import { sandboxInstanceDb } from "./db/db.js";
|
||||
import { sandboxInstance as sandboxInstanceTable } from "./db/schema.js";
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ import type {
|
|||
RepoRecord,
|
||||
SwitchResult,
|
||||
WorkspaceUseInput
|
||||
} from "@openhandoff/shared";
|
||||
} from "@sandbox-agent/factory-shared";
|
||||
import { getActorRuntimeContext } from "../context.js";
|
||||
import { getHandoff, getOrCreateHistory, getOrCreateProject, selfWorkspace } from "../handles.js";
|
||||
import { logActorWarning, resolveErrorMessage } from "../logging.js";
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|||
import { dirname } from "node:path";
|
||||
import { homedir } from "node:os";
|
||||
import * as toml from "@iarna/toml";
|
||||
import { ConfigSchema, type AppConfig } from "@openhandoff/shared";
|
||||
import { ConfigSchema, type AppConfig } from "@sandbox-agent/factory-shared";
|
||||
|
||||
export const CONFIG_PATH = `${homedir()}/.config/openhandoff/config.toml`;
|
||||
export const CONFIG_PATH = `${homedir()}/.config/sandbox-agent-factory/config.toml`;
|
||||
|
||||
export function loadConfig(path = CONFIG_PATH): AppConfig {
|
||||
if (!existsSync(path)) {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { AppConfig } from "@openhandoff/shared";
|
||||
import type { AppConfig } from "@sandbox-agent/factory-shared";
|
||||
|
||||
export function defaultWorkspace(config: AppConfig): string {
|
||||
const ws = config.workspace.default.trim();
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ export interface ActorSqliteDbOptions<TSchema extends Record<string, unknown>> {
|
|||
/**
|
||||
* Override base directory for per-actor SQLite files.
|
||||
*
|
||||
* Default: `<cwd>/.openhandoff/backend/sqlite`
|
||||
* Default: `<cwd>/.sandbox-agent-factory/backend/sqlite`
|
||||
*/
|
||||
baseDir?: string;
|
||||
}
|
||||
|
|
@ -53,7 +53,7 @@ export function actorSqliteDb<TSchema extends Record<string, unknown>>(
|
|||
}) as unknown as DatabaseProvider<any & RawAccess>;
|
||||
}
|
||||
|
||||
const baseDir = options.baseDir ?? join(process.cwd(), ".openhandoff", "backend", "sqlite");
|
||||
const baseDir = options.baseDir ?? join(process.cwd(), ".sandbox-agent-factory", "backend", "sqlite");
|
||||
const migrationsFolder = fileURLToPath(options.migrationsFolderUrl);
|
||||
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ function ensureAskpassScript(): string {
|
|||
return cachedAskpassPath;
|
||||
}
|
||||
|
||||
const dir = mkdtempSync(resolve(tmpdir(), "openhandoff-git-askpass-"));
|
||||
const dir = mkdtempSync(resolve(tmpdir(), "factory-git-askpass-"));
|
||||
const path = resolve(dir, "askpass.sh");
|
||||
|
||||
// Git invokes $GIT_ASKPASS with the prompt string as argv[1]. Provide both username and password.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { AgentType } from "@openhandoff/shared";
|
||||
import type { AgentType } from "@sandbox-agent/factory-shared";
|
||||
import type {
|
||||
ListEventsRequest,
|
||||
ListPage,
|
||||
|
|
@ -144,7 +144,7 @@ export class SandboxAgentClient {
|
|||
const modeId = modeIdForAgent(normalized.agent ?? this.agent);
|
||||
|
||||
// Codex defaults to a restrictive "read-only" preset in some environments.
|
||||
// For OpenHandoff automation we need to allow edits + command execution + network
|
||||
// For Sandbox Agent Factory automation we need to allow edits + command execution + network
|
||||
// access (git push / PR creation). Use full-access where supported.
|
||||
//
|
||||
// If the agent doesn't support session modes, ignore.
|
||||
|
|
|
|||
|
|
@ -205,11 +205,11 @@ export class DaytonaProvider implements SandboxProvider {
|
|||
image: this.buildSnapshotImage(),
|
||||
envVars: this.buildEnvVars(),
|
||||
labels: {
|
||||
"openhandoff.workspace": req.workspaceId,
|
||||
"openhandoff.handoff": req.handoffId,
|
||||
"openhandoff.repo_id": req.repoId,
|
||||
"openhandoff.repo_remote": req.repoRemote,
|
||||
"openhandoff.branch": req.branchName,
|
||||
"factory.workspace": req.workspaceId,
|
||||
"factory.handoff": req.handoffId,
|
||||
"factory.repo_id": req.repoId,
|
||||
"factory.repo_remote": req.repoRemote,
|
||||
"factory.branch": req.branchName,
|
||||
},
|
||||
autoStopInterval: this.config.autoStopInterval,
|
||||
})
|
||||
|
|
@ -220,7 +220,7 @@ export class DaytonaProvider implements SandboxProvider {
|
|||
state: sandbox.state ?? null
|
||||
});
|
||||
|
||||
const repoDir = `/home/daytona/openhandoff/${req.workspaceId}/${req.repoId}/${req.handoffId}/repo`;
|
||||
const repoDir = `/home/daytona/sandbox-agent-factory/${req.workspaceId}/${req.repoId}/${req.handoffId}/repo`;
|
||||
|
||||
// Prepare a working directory for the agent. This must succeed for the handoff to work.
|
||||
const installStartedAt = Date.now();
|
||||
|
|
@ -258,8 +258,8 @@ export class DaytonaProvider implements SandboxProvider {
|
|||
`git fetch origin --prune`,
|
||||
// The handoff branch may not exist remotely yet (agent push creates it). Base off current branch (default branch).
|
||||
`if git show-ref --verify --quiet "refs/remotes/origin/${req.branchName}"; then git checkout -B "${req.branchName}" "origin/${req.branchName}"; else git checkout -B "${req.branchName}" "$(git branch --show-current 2>/dev/null || echo main)"; fi`,
|
||||
`git config user.email "openhandoff@local" >/dev/null 2>&1 || true`,
|
||||
`git config user.name "OpenHandoff" >/dev/null 2>&1 || true`,
|
||||
`git config user.email "factory@local" >/dev/null 2>&1 || true`,
|
||||
`git config user.name "Sandbox Agent Factory" >/dev/null 2>&1 || true`,
|
||||
].join("; ")
|
||||
)}`
|
||||
].join(" "),
|
||||
|
|
@ -294,12 +294,12 @@ export class DaytonaProvider implements SandboxProvider {
|
|||
client.getSandbox(req.sandboxId)
|
||||
);
|
||||
const labels = info.labels ?? {};
|
||||
const workspaceId = labels["openhandoff.workspace"] ?? req.workspaceId;
|
||||
const repoId = labels["openhandoff.repo_id"] ?? "";
|
||||
const handoffId = labels["openhandoff.handoff"] ?? "";
|
||||
const workspaceId = labels["factory.workspace"] ?? req.workspaceId;
|
||||
const repoId = labels["factory.repo_id"] ?? "";
|
||||
const handoffId = labels["factory.handoff"] ?? "";
|
||||
const cwd =
|
||||
repoId && handoffId
|
||||
? `/home/daytona/openhandoff/${workspaceId}/${repoId}/${handoffId}/repo`
|
||||
? `/home/daytona/sandbox-agent-factory/${workspaceId}/${repoId}/${handoffId}/repo`
|
||||
: null;
|
||||
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { ProviderId } from "@openhandoff/shared";
|
||||
import type { AppConfig } from "@openhandoff/shared";
|
||||
import type { ProviderId } from "@sandbox-agent/factory-shared";
|
||||
import type { AppConfig } from "@sandbox-agent/factory-shared";
|
||||
import type { BackendDriver } from "../driver.js";
|
||||
import { DaytonaProvider } from "./daytona/index.js";
|
||||
import { LocalProvider } from "./local/index.js";
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ export class LocalProvider implements SandboxProvider {
|
|||
|
||||
private rootDir(): string {
|
||||
return expandHome(
|
||||
this.config.rootDir?.trim() || "~/.local/share/openhandoff/local-sandboxes",
|
||||
this.config.rootDir?.trim() || "~/.local/share/sandbox-agent-factory/local-sandboxes",
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { ProviderId } from "@openhandoff/shared";
|
||||
import type { ProviderId } from "@sandbox-agent/factory-shared";
|
||||
|
||||
export interface ProviderCapabilities {
|
||||
remote: boolean;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { AppConfig } from "@openhandoff/shared";
|
||||
import type { AppConfig } from "@sandbox-agent/factory-shared";
|
||||
import { homedir } from "node:os";
|
||||
import { dirname, join, resolve } from "node:path";
|
||||
|
||||
|
|
@ -9,17 +9,17 @@ function expandPath(input: string): string {
|
|||
return input;
|
||||
}
|
||||
|
||||
export function openhandoffDataDir(config: AppConfig): string {
|
||||
export function factoryDataDir(config: AppConfig): string {
|
||||
// Keep data collocated with the backend DB by default.
|
||||
const dbPath = expandPath(config.backend.dbPath);
|
||||
return resolve(dirname(dbPath));
|
||||
}
|
||||
|
||||
export function openhandoffRepoClonePath(
|
||||
export function factoryRepoClonePath(
|
||||
config: AppConfig,
|
||||
workspaceId: string,
|
||||
repoId: string
|
||||
): string {
|
||||
return resolve(join(openhandoffDataDir(config), "repos", workspaceId, repoId));
|
||||
return resolve(join(factoryDataDir(config), "repos", workspaceId, repoId));
|
||||
}
|
||||
|
||||
|
|
@ -12,7 +12,7 @@ class RecordingDaytonaClient implements DaytonaClientLike {
|
|||
return {
|
||||
id: "sandbox-1",
|
||||
state: "started",
|
||||
snapshot: "snapshot-openhandoff",
|
||||
snapshot: "snapshot-factory",
|
||||
labels: {},
|
||||
};
|
||||
}
|
||||
|
|
@ -21,7 +21,7 @@ class RecordingDaytonaClient implements DaytonaClientLike {
|
|||
return {
|
||||
id: sandboxId,
|
||||
state: "started",
|
||||
snapshot: "snapshot-openhandoff",
|
||||
snapshot: "snapshot-factory",
|
||||
labels: {},
|
||||
};
|
||||
}
|
||||
|
|
@ -92,9 +92,9 @@ describe("daytona provider snapshot image behavior", () => {
|
|||
expect(commands).toContain("GIT_TERMINAL_PROMPT=0");
|
||||
expect(commands).toContain("GIT_ASKPASS=/bin/echo");
|
||||
|
||||
expect(handle.metadata.snapshot).toBe("snapshot-openhandoff");
|
||||
expect(handle.metadata.snapshot).toBe("snapshot-factory");
|
||||
expect(handle.metadata.image).toBe("ubuntu:24.04");
|
||||
expect(handle.metadata.cwd).toBe("/home/daytona/openhandoff/default/repo-1/handoff-1/repo");
|
||||
expect(handle.metadata.cwd).toBe("/home/daytona/sandbox-agent-factory/default/repo-1/handoff-1/repo");
|
||||
expect(client.executedCommands.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ describe("validateRemote", () => {
|
|||
mkdirSync(brokenRepoDir, { recursive: true });
|
||||
writeFileSync(resolve(brokenRepoDir, ".git"), "gitdir: /definitely/missing/worktree\n", "utf8");
|
||||
await execFileAsync("git", ["init", remoteRepoDir]);
|
||||
await execFileAsync("git", ["-C", remoteRepoDir, "config", "user.name", "OpenHandoff Test"]);
|
||||
await execFileAsync("git", ["-C", remoteRepoDir, "config", "user.name", "Factory Test"]);
|
||||
await execFileAsync("git", ["-C", remoteRepoDir, "config", "user.email", "test@example.com"]);
|
||||
writeFileSync(resolve(remoteRepoDir, "README.md"), "# test\n", "utf8");
|
||||
await execFileAsync("git", ["-C", remoteRepoDir, "add", "README.md"]);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { ConfigSchema, type AppConfig } from "@openhandoff/shared";
|
||||
import { ConfigSchema, type AppConfig } from "@sandbox-agent/factory-shared";
|
||||
import type { BackendDriver } from "../../src/driver.js";
|
||||
import { initActorRuntimeContext } from "../../src/actors/context.js";
|
||||
import { createProviderRegistry } from "../../src/providers/index.js";
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
import { ConfigSchema, type AppConfig } from "@openhandoff/shared";
|
||||
import { ConfigSchema, type AppConfig } from "@sandbox-agent/factory-shared";
|
||||
import { createProviderRegistry } from "../src/providers/index.js";
|
||||
|
||||
function makeConfig(): AppConfig {
|
||||
|
|
@ -10,7 +10,7 @@ function makeConfig(): AppConfig {
|
|||
backend: {
|
||||
host: "127.0.0.1",
|
||||
port: 7741,
|
||||
dbPath: "~/.local/share/openhandoff/handoff.db",
|
||||
dbPath: "~/.local/share/sandbox-agent-factory/handoff.db",
|
||||
opencode_poll_interval: 2,
|
||||
github_poll_interval: 30,
|
||||
backup_interval_secs: 3600,
|
||||
|
|
|
|||
|
|
@ -3,41 +3,41 @@ import { normalizeRemoteUrl, repoIdFromRemote } from "../src/services/repo.js";
|
|||
|
||||
describe("normalizeRemoteUrl", () => {
|
||||
test("accepts GitHub shorthand owner/repo", () => {
|
||||
expect(normalizeRemoteUrl("rivet-dev/openhandoff")).toBe(
|
||||
"https://github.com/rivet-dev/openhandoff.git"
|
||||
expect(normalizeRemoteUrl("rivet-dev/sandbox-agent-factory")).toBe(
|
||||
"https://github.com/rivet-dev/sandbox-agent-factory.git"
|
||||
);
|
||||
});
|
||||
|
||||
test("accepts github.com/owner/repo without scheme", () => {
|
||||
expect(normalizeRemoteUrl("github.com/rivet-dev/openhandoff")).toBe(
|
||||
"https://github.com/rivet-dev/openhandoff.git"
|
||||
expect(normalizeRemoteUrl("github.com/rivet-dev/sandbox-agent-factory")).toBe(
|
||||
"https://github.com/rivet-dev/sandbox-agent-factory.git"
|
||||
);
|
||||
});
|
||||
|
||||
test("canonicalizes GitHub repo URLs without .git", () => {
|
||||
expect(normalizeRemoteUrl("https://github.com/rivet-dev/openhandoff")).toBe(
|
||||
"https://github.com/rivet-dev/openhandoff.git"
|
||||
expect(normalizeRemoteUrl("https://github.com/rivet-dev/sandbox-agent-factory")).toBe(
|
||||
"https://github.com/rivet-dev/sandbox-agent-factory.git"
|
||||
);
|
||||
});
|
||||
|
||||
test("canonicalizes GitHub non-clone URLs (e.g. /tree/main)", () => {
|
||||
expect(normalizeRemoteUrl("https://github.com/rivet-dev/openhandoff/tree/main")).toBe(
|
||||
"https://github.com/rivet-dev/openhandoff.git"
|
||||
expect(normalizeRemoteUrl("https://github.com/rivet-dev/sandbox-agent-factory/tree/main")).toBe(
|
||||
"https://github.com/rivet-dev/sandbox-agent-factory.git"
|
||||
);
|
||||
});
|
||||
|
||||
test("does not rewrite scp-style ssh remotes", () => {
|
||||
expect(normalizeRemoteUrl("git@github.com:rivet-dev/openhandoff.git")).toBe(
|
||||
"git@github.com:rivet-dev/openhandoff.git"
|
||||
expect(normalizeRemoteUrl("git@github.com:rivet-dev/sandbox-agent-factory.git")).toBe(
|
||||
"git@github.com:rivet-dev/sandbox-agent-factory.git"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("repoIdFromRemote", () => {
|
||||
test("repoId is stable across equivalent GitHub inputs", () => {
|
||||
const a = repoIdFromRemote("rivet-dev/openhandoff");
|
||||
const b = repoIdFromRemote("https://github.com/rivet-dev/openhandoff.git");
|
||||
const c = repoIdFromRemote("https://github.com/rivet-dev/openhandoff/tree/main");
|
||||
const a = repoIdFromRemote("rivet-dev/sandbox-agent-factory");
|
||||
const b = repoIdFromRemote("https://github.com/rivet-dev/sandbox-agent-factory.git");
|
||||
const c = repoIdFromRemote("https://github.com/rivet-dev/sandbox-agent-factory/tree/main");
|
||||
expect(a).toBe(b);
|
||||
expect(b).toBe(c);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ function createRepo(): { repoPath: string } {
|
|||
const repoPath = mkdtempSync(join(tmpdir(), "hf-isolation-repo-"));
|
||||
execFileSync("git", ["init"], { cwd: repoPath });
|
||||
execFileSync("git", ["config", "user.email", "test@example.com"], { cwd: repoPath });
|
||||
execFileSync("git", ["config", "user.name", "OpenHandoff Test"], { cwd: repoPath });
|
||||
execFileSync("git", ["config", "user.name", "Factory Test"], { cwd: repoPath });
|
||||
writeFileSync(join(repoPath, "README.md"), "hello\n", "utf8");
|
||||
execFileSync("git", ["add", "README.md"], { cwd: repoPath });
|
||||
execFileSync("git", ["commit", "-m", "init"], { cwd: repoPath });
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ function locationToNames(entry, names) {
|
|||
}
|
||||
|
||||
for (const t of targets) {
|
||||
const db = new Database(`/root/.local/share/openhandoff/rivetkit/databases/${t.actorId}.db`, { readonly: true });
|
||||
const db = new Database(`/root/.local/share/sandbox-agent-factory/rivetkit/databases/${t.actorId}.db`, { readonly: true });
|
||||
const token = new TextDecoder().decode(db.query("SELECT value FROM kv WHERE hex(key)=?").get("03").value);
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { Database } from "bun:sqlite";
|
||||
|
||||
const db = new Database("/root/.local/share/openhandoff/rivetkit/databases/2e443238457137bf.db", { readonly: true });
|
||||
const db = new Database("/root/.local/share/sandbox-agent-factory/rivetkit/databases/2e443238457137bf.db", { readonly: true });
|
||||
const rows = db.query("SELECT hex(key) as k, value as v FROM kv WHERE hex(key) LIKE ? ORDER BY key").all("07%");
|
||||
const out = rows.map((r) => {
|
||||
const bytes = new Uint8Array(r.v);
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import { decodeReadRangeWire } from "/rivet-handoff-fixes/rivetkit-typescript/pa
|
|||
import { readRangeWireToOtlp } from "/rivet-handoff-fixes/rivetkit-typescript/packages/traces/src/read-range.ts";
|
||||
|
||||
const actorId = "2e443238457137bf";
|
||||
const db = new Database(`/root/.local/share/openhandoff/rivetkit/databases/${actorId}.db`, { readonly: true });
|
||||
const db = new Database(`/root/.local/share/sandbox-agent-factory/rivetkit/databases/${actorId}.db`, { readonly: true });
|
||||
const row = db.query("SELECT value FROM kv WHERE hex(key)=?").get("03");
|
||||
const token = new TextDecoder().decode(row.value);
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ function decodeAscii(u8) {
|
|||
}
|
||||
|
||||
for (const actorId of actorIds) {
|
||||
const dbPath = `/root/.local/share/openhandoff/rivetkit/databases/${actorId}.db`;
|
||||
const dbPath = `/root/.local/share/sandbox-agent-factory/rivetkit/databases/${actorId}.db`;
|
||||
const db = new Database(dbPath, { readonly: true });
|
||||
|
||||
const wfStateRow = db.query("SELECT value FROM kv WHERE hex(key)=?").get("0715041501");
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { TO_CLIENT_VERSIONED, decodeWorkflowHistoryTransport } from "rivetkit/in
|
|||
import util from "node:util";
|
||||
|
||||
const actorId = "2e443238457137bf";
|
||||
const db = new Database(`/root/.local/share/openhandoff/rivetkit/databases/${actorId}.db`, { readonly: true });
|
||||
const db = new Database(`/root/.local/share/sandbox-agent-factory/rivetkit/databases/${actorId}.db`, { readonly: true });
|
||||
const row = db.query("SELECT value FROM kv WHERE hex(key) = ?").get("03");
|
||||
const token = new TextDecoder().decode(row.value);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue