mirror of
https://github.com/harivansh-afk/sandbox-agent.git
synced 2026-04-17 19:03:57 +00:00
Add header status pill showing task/session/sandbox state
Surface aggregate status (error, provisioning, running, ready, no sandbox) as a colored pill in the transcript panel header. Integrates task runtime status, session status, and sandbox availability via the sandboxProcesses interest topic so the pill accurately reflects unreachable sandboxes. Includes mock tasks demonstrating error, provisioning, and running states, unit tests for deriveHeaderStatus, and workspace-dashboard integration. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
098b8113f3
commit
5bd85e4a28
77 changed files with 2329 additions and 4134 deletions
|
|
@ -1,205 +0,0 @@
|
|||
import { mkdirSync, rmSync, writeFileSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { resolve } from "node:path";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import type { DaytonaClientLike, DaytonaDriver } from "../src/driver.js";
|
||||
import type { DaytonaCreateSandboxOptions } from "../src/integrations/daytona/client.js";
|
||||
import { DaytonaProvider } from "../src/providers/daytona/index.js";
|
||||
|
||||
class RecordingDaytonaClient implements DaytonaClientLike {
|
||||
createSandboxCalls: DaytonaCreateSandboxOptions[] = [];
|
||||
executedCommands: string[] = [];
|
||||
|
||||
async createSandbox(options: DaytonaCreateSandboxOptions) {
|
||||
this.createSandboxCalls.push(options);
|
||||
return {
|
||||
id: "sandbox-1",
|
||||
state: "started",
|
||||
snapshot: "snapshot-foundry",
|
||||
labels: {},
|
||||
};
|
||||
}
|
||||
|
||||
async getSandbox(sandboxId: string) {
|
||||
return {
|
||||
id: sandboxId,
|
||||
state: "started",
|
||||
snapshot: "snapshot-foundry",
|
||||
labels: {},
|
||||
};
|
||||
}
|
||||
|
||||
async startSandbox(_sandboxId: string, _timeoutSeconds?: number) {}
|
||||
|
||||
async stopSandbox(_sandboxId: string, _timeoutSeconds?: number) {}
|
||||
|
||||
async deleteSandbox(_sandboxId: string) {}
|
||||
|
||||
async executeCommand(_sandboxId: string, command: string) {
|
||||
this.executedCommands.push(command);
|
||||
return { exitCode: 0, result: "" };
|
||||
}
|
||||
|
||||
async getPreviewEndpoint(sandboxId: string, port: number) {
|
||||
return {
|
||||
url: `https://preview.example/sandbox/${sandboxId}/port/${port}`,
|
||||
token: "preview-token",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function createProviderWithClient(client: DaytonaClientLike): DaytonaProvider {
|
||||
const daytonaDriver: DaytonaDriver = {
|
||||
createClient: () => client,
|
||||
};
|
||||
|
||||
return new DaytonaProvider(
|
||||
{
|
||||
apiKey: "test-key",
|
||||
image: "ubuntu:24.04",
|
||||
},
|
||||
daytonaDriver,
|
||||
);
|
||||
}
|
||||
|
||||
describe("daytona provider snapshot image behavior", () => {
|
||||
it("creates sandboxes using a snapshot-capable image recipe", async () => {
|
||||
const client = new RecordingDaytonaClient();
|
||||
const provider = createProviderWithClient(client);
|
||||
|
||||
const handle = await provider.createSandbox({
|
||||
workspaceId: "default",
|
||||
repoId: "repo-1",
|
||||
repoRemote: "https://github.com/acme/repo.git",
|
||||
branchName: "feature/test",
|
||||
taskId: "task-1",
|
||||
});
|
||||
|
||||
expect(client.createSandboxCalls).toHaveLength(1);
|
||||
const createCall = client.createSandboxCalls[0];
|
||||
if (!createCall) {
|
||||
throw new Error("expected create sandbox call");
|
||||
}
|
||||
|
||||
expect(typeof createCall.image).not.toBe("string");
|
||||
if (typeof createCall.image === "string") {
|
||||
throw new Error("expected daytona image recipe object");
|
||||
}
|
||||
|
||||
const dockerfile = createCall.image.dockerfile;
|
||||
expect(dockerfile).toContain("apt-get install -y curl ca-certificates git openssh-client nodejs npm");
|
||||
expect(dockerfile).toContain("sandbox-agent/0.3.0/install.sh");
|
||||
const installAgentLines = dockerfile.match(/sandbox-agent install-agent [a-z0-9-]+/gi) ?? [];
|
||||
expect(installAgentLines.length).toBeGreaterThanOrEqual(2);
|
||||
const commands = client.executedCommands.join("\n");
|
||||
expect(commands).toContain("GIT_TERMINAL_PROMPT=0");
|
||||
expect(commands).toContain("GIT_ASKPASS=/bin/echo");
|
||||
expect(commands).not.toContain("[[");
|
||||
expect(commands).not.toContain("GIT_AUTH_ARGS=()");
|
||||
expect(commands).not.toContain("${GIT_AUTH_ARGS[@]}");
|
||||
expect(commands).not.toContain(".extraheader");
|
||||
|
||||
expect(handle.metadata.snapshot).toBe("snapshot-foundry");
|
||||
expect(handle.metadata.image).toBe("ubuntu:24.04");
|
||||
expect(handle.metadata.cwd).toBe("/home/daytona/foundry/default/repo-1/task-1/repo");
|
||||
expect(client.executedCommands.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("starts sandbox-agent with ACP timeout env override", async () => {
|
||||
const previous = process.env.HF_SANDBOX_AGENT_ACP_REQUEST_TIMEOUT_MS;
|
||||
const previousHome = process.env.HOME;
|
||||
const tempHome = resolve(tmpdir(), `daytona-provider-test-${Date.now()}`);
|
||||
mkdirSync(resolve(tempHome, ".codex"), { recursive: true });
|
||||
writeFileSync(resolve(tempHome, ".codex", "auth.json"), JSON.stringify({ access_token: "test-token" }));
|
||||
process.env.HOME = tempHome;
|
||||
process.env.HF_SANDBOX_AGENT_ACP_REQUEST_TIMEOUT_MS = "240000";
|
||||
|
||||
try {
|
||||
const client = new RecordingDaytonaClient();
|
||||
const provider = createProviderWithClient(client);
|
||||
|
||||
await provider.ensureSandboxAgent({
|
||||
workspaceId: "default",
|
||||
sandboxId: "sandbox-1",
|
||||
});
|
||||
|
||||
const startCommand = client.executedCommands.find(
|
||||
(command) => command.includes("export SANDBOX_AGENT_ACP_REQUEST_TIMEOUT_MS=") && command.includes("sandbox-agent server --no-token"),
|
||||
);
|
||||
|
||||
const joined = client.executedCommands.join("\n");
|
||||
expect(joined).toContain("sandbox-agent/0.3.0/install.sh");
|
||||
expect(joined).toContain("SANDBOX_AGENT_ACP_REQUEST_TIMEOUT_MS");
|
||||
expect(joined).toContain("apt-get install -y nodejs npm");
|
||||
expect(joined).toContain("sandbox-agent server --no-token --host 0.0.0.0 --port 2468");
|
||||
expect(joined).toContain('mkdir -p "$HOME/.codex" "$HOME/.config/codex"');
|
||||
expect(joined).toContain("unset OPENAI_API_KEY CODEX_API_KEY");
|
||||
expect(joined).not.toContain('rm -f "$HOME/.codex/auth.json"');
|
||||
expect(startCommand).toBeTruthy();
|
||||
} finally {
|
||||
if (previous === undefined) {
|
||||
delete process.env.HF_SANDBOX_AGENT_ACP_REQUEST_TIMEOUT_MS;
|
||||
} else {
|
||||
process.env.HF_SANDBOX_AGENT_ACP_REQUEST_TIMEOUT_MS = previous;
|
||||
}
|
||||
if (previousHome === undefined) {
|
||||
delete process.env.HOME;
|
||||
} else {
|
||||
process.env.HOME = previousHome;
|
||||
}
|
||||
rmSync(tempHome, { force: true, recursive: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("fails with explicit timeout when daytona createSandbox hangs", async () => {
|
||||
const previous = process.env.HF_DAYTONA_REQUEST_TIMEOUT_MS;
|
||||
process.env.HF_DAYTONA_REQUEST_TIMEOUT_MS = "120";
|
||||
|
||||
const hangingClient: DaytonaClientLike = {
|
||||
createSandbox: async () => await new Promise(() => {}),
|
||||
getSandbox: async (sandboxId) => ({ id: sandboxId, state: "started" }),
|
||||
startSandbox: async () => {},
|
||||
stopSandbox: async () => {},
|
||||
deleteSandbox: async () => {},
|
||||
executeCommand: async () => ({ exitCode: 0, result: "" }),
|
||||
getPreviewEndpoint: async (sandboxId, port) => ({
|
||||
url: `https://preview.example/sandbox/${sandboxId}/port/${port}`,
|
||||
token: "preview-token",
|
||||
}),
|
||||
};
|
||||
|
||||
try {
|
||||
const provider = createProviderWithClient(hangingClient);
|
||||
await expect(
|
||||
provider.createSandbox({
|
||||
workspaceId: "default",
|
||||
repoId: "repo-1",
|
||||
repoRemote: "https://github.com/acme/repo.git",
|
||||
branchName: "feature/test",
|
||||
taskId: "task-timeout",
|
||||
}),
|
||||
).rejects.toThrow("daytona create sandbox timed out after 120ms");
|
||||
} finally {
|
||||
if (previous === undefined) {
|
||||
delete process.env.HF_DAYTONA_REQUEST_TIMEOUT_MS;
|
||||
} else {
|
||||
process.env.HF_DAYTONA_REQUEST_TIMEOUT_MS = previous;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("executes backend-managed sandbox commands through provider API", async () => {
|
||||
const client = new RecordingDaytonaClient();
|
||||
const provider = createProviderWithClient(client);
|
||||
|
||||
const result = await provider.executeCommand({
|
||||
workspaceId: "default",
|
||||
sandboxId: "sandbox-1",
|
||||
command: "echo backend-push",
|
||||
label: "manual push",
|
||||
});
|
||||
|
||||
expect(result.exitCode).toBe(0);
|
||||
expect(client.executedCommands).toContain("echo backend-push");
|
||||
});
|
||||
});
|
||||
|
|
@ -3,7 +3,6 @@ import { join } from "node:path";
|
|||
import { ConfigSchema, type AppConfig } from "@sandbox-agent/foundry-shared";
|
||||
import type { BackendDriver } from "../../src/driver.js";
|
||||
import { initActorRuntimeContext } from "../../src/actors/context.js";
|
||||
import { createProviderRegistry } from "../../src/providers/index.js";
|
||||
import { createDefaultAppShellServices } from "../../src/services/app-shell-runtime.js";
|
||||
|
||||
export function createTestConfig(overrides?: Partial<AppConfig>): AppConfig {
|
||||
|
|
@ -21,7 +20,8 @@ export function createTestConfig(overrides?: Partial<AppConfig>): AppConfig {
|
|||
backup_retention_days: 7,
|
||||
},
|
||||
providers: {
|
||||
daytona: { image: "ubuntu:24.04" },
|
||||
local: {},
|
||||
e2b: {},
|
||||
},
|
||||
...overrides,
|
||||
});
|
||||
|
|
@ -29,7 +29,6 @@ export function createTestConfig(overrides?: Partial<AppConfig>): AppConfig {
|
|||
|
||||
export function createTestRuntimeContext(driver: BackendDriver, configOverrides?: Partial<AppConfig>): { config: AppConfig } {
|
||||
const config = createTestConfig(configOverrides);
|
||||
const providers = createProviderRegistry(config, driver);
|
||||
initActorRuntimeContext(config, providers, undefined, driver, createDefaultAppShellServices());
|
||||
initActorRuntimeContext(config, undefined, driver, createDefaultAppShellServices());
|
||||
return { config };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,10 @@
|
|||
import type {
|
||||
BackendDriver,
|
||||
DaytonaClientLike,
|
||||
DaytonaDriver,
|
||||
GitDriver,
|
||||
GithubDriver,
|
||||
StackDriver,
|
||||
SandboxAgentDriver,
|
||||
SandboxAgentClientLike,
|
||||
TmuxDriver,
|
||||
} from "../../src/driver.js";
|
||||
import type { ListEventsRequest, ListPage, ListPageRequest, ProcessInfo, ProcessLogsResponse, SessionEvent, SessionRecord } from "sandbox-agent";
|
||||
import type { BackendDriver, GitDriver, GithubDriver, StackDriver, TmuxDriver } from "../../src/driver.js";
|
||||
|
||||
export function createTestDriver(overrides?: Partial<BackendDriver>): BackendDriver {
|
||||
return {
|
||||
git: overrides?.git ?? createTestGitDriver(),
|
||||
stack: overrides?.stack ?? createTestStackDriver(),
|
||||
github: overrides?.github ?? createTestGithubDriver(),
|
||||
sandboxAgent: overrides?.sandboxAgent ?? createTestSandboxAgentDriver(),
|
||||
daytona: overrides?.daytona ?? createTestDaytonaDriver(),
|
||||
tmux: overrides?.tmux ?? createTestTmuxDriver(),
|
||||
};
|
||||
}
|
||||
|
|
@ -63,79 +50,6 @@ export function createTestGithubDriver(overrides?: Partial<GithubDriver>): Githu
|
|||
};
|
||||
}
|
||||
|
||||
export function createTestSandboxAgentDriver(overrides?: Partial<SandboxAgentDriver>): SandboxAgentDriver {
|
||||
return {
|
||||
createClient: (_opts) => createTestSandboxAgentClient(),
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
export function createTestSandboxAgentClient(overrides?: Partial<SandboxAgentClientLike>): SandboxAgentClientLike {
|
||||
const defaultProcess: ProcessInfo = {
|
||||
id: "process-1",
|
||||
command: "bash",
|
||||
args: ["-lc", "echo test"],
|
||||
createdAtMs: Date.now(),
|
||||
cwd: "/workspace",
|
||||
exitCode: null,
|
||||
exitedAtMs: null,
|
||||
interactive: true,
|
||||
pid: 123,
|
||||
status: "running",
|
||||
tty: true,
|
||||
};
|
||||
const defaultLogs: ProcessLogsResponse = {
|
||||
processId: defaultProcess.id,
|
||||
stream: "combined",
|
||||
entries: [],
|
||||
};
|
||||
return {
|
||||
createSession: async (_prompt) => ({ id: "test-session-1", status: "running" }),
|
||||
sessionStatus: async (sessionId) => ({ id: sessionId, status: "running" }),
|
||||
listSessions: async (_request?: ListPageRequest): Promise<ListPage<SessionRecord>> => ({
|
||||
items: [],
|
||||
nextCursor: undefined,
|
||||
}),
|
||||
listEvents: async (_request: ListEventsRequest): Promise<ListPage<SessionEvent>> => ({
|
||||
items: [],
|
||||
nextCursor: undefined,
|
||||
}),
|
||||
createProcess: async () => defaultProcess,
|
||||
listProcesses: async () => ({ processes: [defaultProcess] }),
|
||||
getProcessLogs: async () => defaultLogs,
|
||||
stopProcess: async () => ({ ...defaultProcess, status: "exited", exitCode: 0, exitedAtMs: Date.now() }),
|
||||
killProcess: async () => ({ ...defaultProcess, status: "exited", exitCode: 137, exitedAtMs: Date.now() }),
|
||||
deleteProcess: async () => {},
|
||||
sendPrompt: async (_request) => {},
|
||||
cancelSession: async (_sessionId) => {},
|
||||
destroySession: async (_sessionId) => {},
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
export function createTestDaytonaDriver(overrides?: Partial<DaytonaDriver>): DaytonaDriver {
|
||||
return {
|
||||
createClient: (_opts) => createTestDaytonaClient(),
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
export function createTestDaytonaClient(overrides?: Partial<DaytonaClientLike>): DaytonaClientLike {
|
||||
return {
|
||||
createSandbox: async () => ({ id: "sandbox-test-1", state: "started" }),
|
||||
getSandbox: async (sandboxId) => ({ id: sandboxId, state: "started" }),
|
||||
startSandbox: async () => {},
|
||||
stopSandbox: async () => {},
|
||||
deleteSandbox: async () => {},
|
||||
executeCommand: async () => ({ exitCode: 0, result: "" }),
|
||||
getPreviewEndpoint: async (sandboxId, port) => ({
|
||||
url: `https://preview.example/sandbox/${sandboxId}/port/${port}`,
|
||||
token: "preview-token",
|
||||
}),
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
export function createTestTmuxDriver(overrides?: Partial<TmuxDriver>): TmuxDriver {
|
||||
return {
|
||||
setWindowStatus: () => 0,
|
||||
|
|
|
|||
|
|
@ -1,14 +1,5 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
taskKey,
|
||||
taskStatusSyncKey,
|
||||
historyKey,
|
||||
projectBranchSyncKey,
|
||||
projectKey,
|
||||
projectPrSyncKey,
|
||||
sandboxInstanceKey,
|
||||
workspaceKey,
|
||||
} from "../src/actors/keys.js";
|
||||
import { taskKey, historyKey, projectBranchSyncKey, projectKey, projectPrSyncKey, taskSandboxKey, workspaceKey } from "../src/actors/keys.js";
|
||||
|
||||
describe("actor keys", () => {
|
||||
it("prefixes every key with workspace namespace", () => {
|
||||
|
|
@ -16,11 +7,10 @@ describe("actor keys", () => {
|
|||
workspaceKey("default"),
|
||||
projectKey("default", "repo"),
|
||||
taskKey("default", "repo", "task"),
|
||||
sandboxInstanceKey("default", "daytona", "sbx"),
|
||||
taskSandboxKey("default", "sbx"),
|
||||
historyKey("default", "repo"),
|
||||
projectPrSyncKey("default", "repo"),
|
||||
projectBranchSyncKey("default", "repo"),
|
||||
taskStatusSyncKey("default", "repo", "task", "sandbox-1", "session-1"),
|
||||
];
|
||||
|
||||
for (const key of keys) {
|
||||
|
|
|
|||
|
|
@ -1,52 +0,0 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
import { ConfigSchema, type AppConfig } from "@sandbox-agent/foundry-shared";
|
||||
import { createProviderRegistry } from "../src/providers/index.js";
|
||||
|
||||
function makeConfig(): AppConfig {
|
||||
return ConfigSchema.parse({
|
||||
auto_submit: true,
|
||||
notify: ["terminal"],
|
||||
workspace: { default: "default" },
|
||||
backend: {
|
||||
host: "127.0.0.1",
|
||||
port: 7741,
|
||||
dbPath: "~/.local/share/foundry/task.db",
|
||||
opencode_poll_interval: 2,
|
||||
github_poll_interval: 30,
|
||||
backup_interval_secs: 3600,
|
||||
backup_retention_days: 7,
|
||||
},
|
||||
providers: {
|
||||
local: {},
|
||||
daytona: { image: "ubuntu:24.04" },
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
describe("provider registry", () => {
|
||||
it("defaults to local when daytona is not configured", () => {
|
||||
const registry = createProviderRegistry(makeConfig());
|
||||
expect(registry.defaultProviderId()).toBe("local");
|
||||
});
|
||||
|
||||
it("prefers daytona when an api key is configured", () => {
|
||||
const registry = createProviderRegistry(
|
||||
ConfigSchema.parse({
|
||||
...makeConfig(),
|
||||
providers: {
|
||||
...makeConfig().providers,
|
||||
daytona: {
|
||||
...makeConfig().providers.daytona,
|
||||
apiKey: "test-token",
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
expect(registry.defaultProviderId()).toBe("daytona");
|
||||
});
|
||||
|
||||
it("returns the built-in provider", () => {
|
||||
const registry = createProviderRegistry(makeConfig());
|
||||
expect(registry.get("daytona").id()).toBe("daytona");
|
||||
});
|
||||
});
|
||||
50
foundry/packages/backend/test/sandbox-config.test.ts
Normal file
50
foundry/packages/backend/test/sandbox-config.test.ts
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
import { ConfigSchema, type AppConfig } from "@sandbox-agent/foundry-shared";
|
||||
import { availableSandboxProviderIds, defaultSandboxProviderId, resolveSandboxProviderId } from "../src/sandbox-config.js";
|
||||
|
||||
function makeConfig(overrides?: Partial<AppConfig>): AppConfig {
|
||||
return ConfigSchema.parse({
|
||||
auto_submit: true,
|
||||
notify: ["terminal"],
|
||||
workspace: { default: "default" },
|
||||
backend: {
|
||||
host: "127.0.0.1",
|
||||
port: 7741,
|
||||
dbPath: "~/.local/share/foundry/task.db",
|
||||
opencode_poll_interval: 2,
|
||||
github_poll_interval: 30,
|
||||
backup_interval_secs: 3600,
|
||||
backup_retention_days: 7,
|
||||
},
|
||||
providers: {
|
||||
local: {},
|
||||
e2b: {},
|
||||
},
|
||||
...overrides,
|
||||
});
|
||||
}
|
||||
|
||||
describe("sandbox config", () => {
|
||||
it("defaults to local when e2b is not configured", () => {
|
||||
const config = makeConfig();
|
||||
expect(defaultSandboxProviderId(config)).toBe("local");
|
||||
expect(availableSandboxProviderIds(config)).toEqual(["local"]);
|
||||
});
|
||||
|
||||
it("prefers e2b when an api key is configured", () => {
|
||||
const config = makeConfig({
|
||||
providers: {
|
||||
local: {},
|
||||
e2b: { apiKey: "test-token" },
|
||||
},
|
||||
});
|
||||
expect(defaultSandboxProviderId(config)).toBe("e2b");
|
||||
expect(availableSandboxProviderIds(config)).toEqual(["e2b", "local"]);
|
||||
expect(resolveSandboxProviderId(config, "e2b")).toBe("e2b");
|
||||
});
|
||||
|
||||
it("rejects selecting e2b without an api key", () => {
|
||||
const config = makeConfig();
|
||||
expect(() => resolveSandboxProviderId(config, "e2b")).toThrow("E2B provider is not configured");
|
||||
});
|
||||
});
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
import { resolveEventListOffset } from "../src/actors/sandbox-instance/persist.js";
|
||||
|
||||
describe("sandbox-instance persist event offset", () => {
|
||||
it("returns newest tail when cursor is omitted", () => {
|
||||
expect(resolveEventListOffset({ total: 180, limit: 50 })).toBe(130);
|
||||
});
|
||||
|
||||
it("returns zero when total rows are below page size", () => {
|
||||
expect(resolveEventListOffset({ total: 20, limit: 50 })).toBe(0);
|
||||
});
|
||||
|
||||
it("uses explicit cursor when provided", () => {
|
||||
expect(resolveEventListOffset({ cursor: "7", total: 180, limit: 50 })).toBe(7);
|
||||
});
|
||||
|
||||
it("normalizes invalid cursors to zero", () => {
|
||||
expect(resolveEventListOffset({ cursor: "-3", total: 180, limit: 50 })).toBe(0);
|
||||
expect(resolveEventListOffset({ cursor: "not-a-number", total: 180, limit: 50 })).toBe(0);
|
||||
});
|
||||
});
|
||||
|
|
@ -56,7 +56,7 @@ describe("workspace isolation", () => {
|
|||
workspaceId: "alpha",
|
||||
repoId: repoA.repoId,
|
||||
task: "task A",
|
||||
providerId: "daytona",
|
||||
providerId: "local",
|
||||
explicitBranchName: "feature/a",
|
||||
explicitTitle: "A",
|
||||
});
|
||||
|
|
@ -65,7 +65,7 @@ describe("workspace isolation", () => {
|
|||
workspaceId: "beta",
|
||||
repoId: repoB.repoId,
|
||||
task: "task B",
|
||||
providerId: "daytona",
|
||||
providerId: "local",
|
||||
explicitBranchName: "feature/b",
|
||||
explicitTitle: "B",
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue