Implement execution workspaces and work products
This commit is contained in:
@@ -2,11 +2,12 @@ import type {
|
||||
ExecutionWorkspaceMode,
|
||||
ExecutionWorkspaceStrategy,
|
||||
IssueExecutionWorkspaceSettings,
|
||||
ProjectExecutionWorkspaceDefaultMode,
|
||||
ProjectExecutionWorkspacePolicy,
|
||||
} from "@paperclipai/shared";
|
||||
import { asString, parseObject } from "../adapters/utils.js";
|
||||
|
||||
type ParsedExecutionWorkspaceMode = Exclude<ExecutionWorkspaceMode, "inherit">;
|
||||
type ParsedExecutionWorkspaceMode = Exclude<ExecutionWorkspaceMode, "inherit" | "reuse_existing">;
|
||||
|
||||
function cloneRecord(value: Record<string, unknown> | null | undefined): Record<string, unknown> | null {
|
||||
if (!value) return null;
|
||||
@@ -16,7 +17,7 @@ function cloneRecord(value: Record<string, unknown> | null | undefined): Record<
|
||||
function parseExecutionWorkspaceStrategy(raw: unknown): ExecutionWorkspaceStrategy | null {
|
||||
const parsed = parseObject(raw);
|
||||
const type = asString(parsed.type, "");
|
||||
if (type !== "project_primary" && type !== "git_worktree") {
|
||||
if (type !== "project_primary" && type !== "git_worktree" && type !== "adapter_managed" && type !== "cloud_sandbox") {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
@@ -34,12 +35,28 @@ export function parseProjectExecutionWorkspacePolicy(raw: unknown): ProjectExecu
|
||||
if (Object.keys(parsed).length === 0) return null;
|
||||
const enabled = typeof parsed.enabled === "boolean" ? parsed.enabled : false;
|
||||
const defaultMode = asString(parsed.defaultMode, "");
|
||||
const defaultProjectWorkspaceId =
|
||||
typeof parsed.defaultProjectWorkspaceId === "string" ? parsed.defaultProjectWorkspaceId : undefined;
|
||||
const allowIssueOverride =
|
||||
typeof parsed.allowIssueOverride === "boolean" ? parsed.allowIssueOverride : undefined;
|
||||
const normalizedDefaultMode = (() => {
|
||||
if (
|
||||
defaultMode === "shared_workspace" ||
|
||||
defaultMode === "isolated_workspace" ||
|
||||
defaultMode === "operator_branch" ||
|
||||
defaultMode === "adapter_default"
|
||||
) {
|
||||
return defaultMode as ProjectExecutionWorkspaceDefaultMode;
|
||||
}
|
||||
if (defaultMode === "project_primary") return "shared_workspace";
|
||||
if (defaultMode === "isolated") return "isolated_workspace";
|
||||
return undefined;
|
||||
})();
|
||||
return {
|
||||
enabled,
|
||||
...(defaultMode === "project_primary" || defaultMode === "isolated" ? { defaultMode } : {}),
|
||||
...(normalizedDefaultMode ? { defaultMode: normalizedDefaultMode } : {}),
|
||||
...(allowIssueOverride !== undefined ? { allowIssueOverride } : {}),
|
||||
...(defaultProjectWorkspaceId ? { defaultProjectWorkspaceId } : {}),
|
||||
...(parseExecutionWorkspaceStrategy(parsed.workspaceStrategy)
|
||||
? { workspaceStrategy: parseExecutionWorkspaceStrategy(parsed.workspaceStrategy) }
|
||||
: {}),
|
||||
@@ -52,6 +69,9 @@ export function parseProjectExecutionWorkspacePolicy(raw: unknown): ProjectExecu
|
||||
...(parsed.pullRequestPolicy && typeof parsed.pullRequestPolicy === "object" && !Array.isArray(parsed.pullRequestPolicy)
|
||||
? { pullRequestPolicy: { ...(parsed.pullRequestPolicy as Record<string, unknown>) } }
|
||||
: {}),
|
||||
...(parsed.runtimePolicy && typeof parsed.runtimePolicy === "object" && !Array.isArray(parsed.runtimePolicy)
|
||||
? { runtimePolicy: { ...(parsed.runtimePolicy as Record<string, unknown>) } }
|
||||
: {}),
|
||||
...(parsed.cleanupPolicy && typeof parsed.cleanupPolicy === "object" && !Array.isArray(parsed.cleanupPolicy)
|
||||
? { cleanupPolicy: { ...(parsed.cleanupPolicy as Record<string, unknown>) } }
|
||||
: {}),
|
||||
@@ -62,9 +82,24 @@ export function parseIssueExecutionWorkspaceSettings(raw: unknown): IssueExecuti
|
||||
const parsed = parseObject(raw);
|
||||
if (Object.keys(parsed).length === 0) return null;
|
||||
const mode = asString(parsed.mode, "");
|
||||
const normalizedMode = (() => {
|
||||
if (
|
||||
mode === "inherit" ||
|
||||
mode === "shared_workspace" ||
|
||||
mode === "isolated_workspace" ||
|
||||
mode === "operator_branch" ||
|
||||
mode === "reuse_existing" ||
|
||||
mode === "agent_default"
|
||||
) {
|
||||
return mode;
|
||||
}
|
||||
if (mode === "project_primary") return "shared_workspace";
|
||||
if (mode === "isolated") return "isolated_workspace";
|
||||
return "";
|
||||
})();
|
||||
return {
|
||||
...(mode === "inherit" || mode === "project_primary" || mode === "isolated" || mode === "agent_default"
|
||||
? { mode }
|
||||
...(normalizedMode
|
||||
? { mode: normalizedMode as IssueExecutionWorkspaceSettings["mode"] }
|
||||
: {}),
|
||||
...(parseExecutionWorkspaceStrategy(parsed.workspaceStrategy)
|
||||
? { workspaceStrategy: parseExecutionWorkspaceStrategy(parsed.workspaceStrategy) }
|
||||
@@ -80,7 +115,14 @@ export function defaultIssueExecutionWorkspaceSettingsForProject(
|
||||
): IssueExecutionWorkspaceSettings | null {
|
||||
if (!projectPolicy?.enabled) return null;
|
||||
return {
|
||||
mode: projectPolicy.defaultMode === "isolated" ? "isolated" : "project_primary",
|
||||
mode:
|
||||
projectPolicy.defaultMode === "isolated_workspace"
|
||||
? "isolated_workspace"
|
||||
: projectPolicy.defaultMode === "operator_branch"
|
||||
? "operator_branch"
|
||||
: projectPolicy.defaultMode === "adapter_default"
|
||||
? "agent_default"
|
||||
: "shared_workspace",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -90,16 +132,19 @@ export function resolveExecutionWorkspaceMode(input: {
|
||||
legacyUseProjectWorkspace: boolean | null;
|
||||
}): ParsedExecutionWorkspaceMode {
|
||||
const issueMode = input.issueSettings?.mode;
|
||||
if (issueMode && issueMode !== "inherit") {
|
||||
if (issueMode && issueMode !== "inherit" && issueMode !== "reuse_existing") {
|
||||
return issueMode;
|
||||
}
|
||||
if (input.projectPolicy?.enabled) {
|
||||
return input.projectPolicy.defaultMode === "isolated" ? "isolated" : "project_primary";
|
||||
if (input.projectPolicy.defaultMode === "isolated_workspace") return "isolated_workspace";
|
||||
if (input.projectPolicy.defaultMode === "operator_branch") return "operator_branch";
|
||||
if (input.projectPolicy.defaultMode === "adapter_default") return "agent_default";
|
||||
return "shared_workspace";
|
||||
}
|
||||
if (input.legacyUseProjectWorkspace === false) {
|
||||
return "agent_default";
|
||||
}
|
||||
return "project_primary";
|
||||
return "shared_workspace";
|
||||
}
|
||||
|
||||
export function buildExecutionWorkspaceAdapterConfig(input: {
|
||||
@@ -119,7 +164,7 @@ export function buildExecutionWorkspaceAdapterConfig(input: {
|
||||
const hasWorkspaceControl = projectHasPolicy || issueHasWorkspaceOverrides || input.legacyUseProjectWorkspace === false;
|
||||
|
||||
if (hasWorkspaceControl) {
|
||||
if (input.mode === "isolated") {
|
||||
if (input.mode === "isolated_workspace") {
|
||||
const strategy =
|
||||
input.issueSettings?.workspaceStrategy ??
|
||||
input.projectPolicy?.workspaceStrategy ??
|
||||
|
||||
Reference in New Issue
Block a user