mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-28 20:22:45 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
95752e54e6 |
@@ -26,6 +26,7 @@ describe("existing run workspace resolution", () => {
|
|||||||
await expect(resolveExistingRunWorkspace({ fetchWorkspaces }, "workspace-2")).resolves.toEqual({
|
await expect(resolveExistingRunWorkspace({ fetchWorkspaces }, "workspace-2")).resolves.toEqual({
|
||||||
id: "workspace-2",
|
id: "workspace-2",
|
||||||
cwd: "/workspace/two",
|
cwd: "/workspace/two",
|
||||||
|
createdForRun: false,
|
||||||
});
|
});
|
||||||
expect(fetchWorkspaces).toHaveBeenCalledWith({
|
expect(fetchWorkspaces).toHaveBeenCalledWith({
|
||||||
filter: { query: "workspace-2" },
|
filter: { query: "workspace-2" },
|
||||||
|
|||||||
@@ -504,6 +504,32 @@ async function connectToDaemonOrThrow(
|
|||||||
interface RunWorkspace {
|
interface RunWorkspace {
|
||||||
id?: string;
|
id?: string;
|
||||||
cwd: string;
|
cwd: string;
|
||||||
|
createdForRun: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateRunAgentInput = Parameters<ConnectedDaemonClient["createAgent"]>[0];
|
||||||
|
|
||||||
|
async function createAgentInRunWorkspace(
|
||||||
|
client: ConnectedDaemonClient,
|
||||||
|
workspace: RunWorkspace,
|
||||||
|
input: CreateRunAgentInput,
|
||||||
|
): Promise<AgentSnapshotPayload> {
|
||||||
|
try {
|
||||||
|
return await client.createAgent(input);
|
||||||
|
} catch (error) {
|
||||||
|
if (workspace.createdForRun && workspace.id) {
|
||||||
|
try {
|
||||||
|
const archived = await client.archiveWorkspace(workspace.id);
|
||||||
|
if (archived.error) {
|
||||||
|
console.error(`Warning: failed to clean up workspace ${workspace.id}: ${archived.error}`);
|
||||||
|
}
|
||||||
|
} catch (cleanupError) {
|
||||||
|
const message = cleanupError instanceof Error ? cleanupError.message : String(cleanupError);
|
||||||
|
console.error(`Warning: failed to clean up workspace ${workspace.id}: ${message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RunWorkspaceLookupClient {
|
export interface RunWorkspaceLookupClient {
|
||||||
@@ -523,7 +549,7 @@ export async function resolveExistingRunWorkspace(
|
|||||||
});
|
});
|
||||||
const workspace = result.entries.find((entry) => entry.id === workspaceId);
|
const workspace = result.entries.find((entry) => entry.id === workspaceId);
|
||||||
if (workspace) {
|
if (workspace) {
|
||||||
return { id: workspace.id, cwd: workspace.workspaceDirectory };
|
return { id: workspace.id, cwd: workspace.workspaceDirectory, createdForRun: false };
|
||||||
}
|
}
|
||||||
|
|
||||||
throw {
|
throw {
|
||||||
@@ -551,7 +577,7 @@ async function resolveRunWorkspace(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!newWorkspace && resolveRunCallerAgentId()) {
|
if (!newWorkspace && resolveRunCallerAgentId()) {
|
||||||
return { cwd };
|
return { cwd, createdForRun: false };
|
||||||
}
|
}
|
||||||
|
|
||||||
const ambientWorkspaceId = newWorkspace ? undefined : process.env.PASEO_WORKSPACE_ID?.trim();
|
const ambientWorkspaceId = newWorkspace ? undefined : process.env.PASEO_WORKSPACE_ID?.trim();
|
||||||
@@ -578,7 +604,11 @@ async function resolveRunWorkspace(
|
|||||||
console.error(
|
console.error(
|
||||||
"Tip: pass --workspace <id> (or set PASEO_WORKSPACE_ID) to run in an existing workspace.",
|
"Tip: pass --workspace <id> (or set PASEO_WORKSPACE_ID) to run in an existing workspace.",
|
||||||
);
|
);
|
||||||
return { id: result.workspace.id, cwd: result.workspace.workspaceDirectory ?? cwd };
|
return {
|
||||||
|
id: result.workspace.id,
|
||||||
|
cwd: result.workspace.workspaceDirectory ?? cwd,
|
||||||
|
createdForRun: true,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function runRunCommand(
|
export async function runRunCommand(
|
||||||
@@ -627,7 +657,7 @@ export async function runRunCommand(
|
|||||||
|
|
||||||
const callStructuredTurn = async (structuredPrompt: string): Promise<string> => {
|
const callStructuredTurn = async (structuredPrompt: string): Promise<string> => {
|
||||||
if (!structuredAgent) {
|
if (!structuredAgent) {
|
||||||
structuredAgent = await client.createAgent({
|
structuredAgent = await createAgentInRunWorkspace(client, workspace, {
|
||||||
provider: resolvedProviderModel.provider,
|
provider: resolvedProviderModel.provider,
|
||||||
cwd: runCwd,
|
cwd: runCwd,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
@@ -698,7 +728,7 @@ export async function runRunCommand(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create the agent
|
// Create the agent
|
||||||
const agent = await client.createAgent({
|
const agent = await createAgentInRunWorkspace(client, workspace, {
|
||||||
provider: resolvedProviderModel.provider,
|
provider: resolvedProviderModel.provider,
|
||||||
cwd: runCwd,
|
cwd: runCwd,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import { $ } from "zx";
|
|||||||
import { mkdtemp, rm, writeFile } from "fs/promises";
|
import { mkdtemp, rm, writeFile } from "fs/promises";
|
||||||
import { tmpdir } from "os";
|
import { tmpdir } from "os";
|
||||||
import { join } from "path";
|
import { join } from "path";
|
||||||
|
import { createE2ETestContext } from "./helpers/test-daemon.ts";
|
||||||
|
|
||||||
$.verbose = false;
|
$.verbose = false;
|
||||||
|
|
||||||
@@ -268,6 +269,56 @@ try {
|
|||||||
assert(output.includes("unknown option"), "should report unknown option for --isolation");
|
assert(output.includes("unknown option"), "should report unknown option for --isolation");
|
||||||
console.log("✓ run --isolation is rejected\n");
|
console.log("✓ run --isolation is rejected\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test 17: failed agent creation does not leave the run's workspace behind
|
||||||
|
{
|
||||||
|
console.log("Test 17: failed agent creation cleans up its workspace");
|
||||||
|
const ctx = await createE2ETestContext({ timeout: 45000 });
|
||||||
|
try {
|
||||||
|
await $({ cwd: ctx.workDir })`git init -b main`;
|
||||||
|
await $({ cwd: ctx.workDir })`git config user.email test@getpaseo.local`;
|
||||||
|
await $({ cwd: ctx.workDir })`git config user.name "Paseo Test"`;
|
||||||
|
await $({ cwd: ctx.workDir })`git commit --allow-empty -m initial`;
|
||||||
|
|
||||||
|
const before = await ctx.paseo(["workspace", "ls", "--json"]);
|
||||||
|
assert.strictEqual(before.exitCode, 0, before.stderr);
|
||||||
|
|
||||||
|
const result = await ctx.paseo(
|
||||||
|
[
|
||||||
|
"run",
|
||||||
|
"--provider",
|
||||||
|
"claude",
|
||||||
|
"--mode",
|
||||||
|
"bypass",
|
||||||
|
"--new-workspace",
|
||||||
|
"worktree",
|
||||||
|
"--worktree-mode",
|
||||||
|
"branch-off",
|
||||||
|
"--new-branch",
|
||||||
|
"failed-run-workspace",
|
||||||
|
"--base",
|
||||||
|
"main",
|
||||||
|
"--background",
|
||||||
|
"do something",
|
||||||
|
],
|
||||||
|
{
|
||||||
|
env: { PASEO_AGENT_ID: "", PASEO_WORKSPACE_ID: "" },
|
||||||
|
},
|
||||||
|
);
|
||||||
|
assert.notStrictEqual(result.exitCode, 0, "invalid mode should reject agent creation");
|
||||||
|
assert(
|
||||||
|
`${result.stdout}\n${result.stderr}`.includes("Invalid mode 'bypass'"),
|
||||||
|
`failure should reach provider mode validation\nstdout:\n${result.stdout}\nstderr:\n${result.stderr}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
const after = await ctx.paseo(["workspace", "ls", "--json"]);
|
||||||
|
assert.strictEqual(after.exitCode, 0, after.stderr);
|
||||||
|
assert.deepStrictEqual(JSON.parse(after.stdout), JSON.parse(before.stdout));
|
||||||
|
} finally {
|
||||||
|
await ctx.stop();
|
||||||
|
}
|
||||||
|
console.log("✓ failed agent creation cleans up its workspace\n");
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
// Clean up temp directory
|
// Clean up temp directory
|
||||||
await rm(paseoHome, { recursive: true, force: true });
|
await rm(paseoHome, { recursive: true, force: true });
|
||||||
|
|||||||
Reference in New Issue
Block a user