mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-29 04:32:57 +00:00
feat(workspaces): choose runtime when creating workspaces
Expose the runtime catalog and carry an explicit runtime ID through workspace creation while preserving omitted-field compatibility for older clients. The runtime POC made useGitActions require WorkspaceGitBoundary, but Command Center mounted that consumer without the boundary and crashed. Bind the active workspace at that consumer. Keep provisional Worktree reservations unpublished until final placement so observers never bind the source checkout as the new workspace. Gate legacy cwd Git compatibility by hostVisiblePath instead of runtime kind because Local and Worktree remain host-visible runtimes.
This commit is contained in:
@@ -2172,12 +2172,25 @@ export const ArchiveWorkspaceRequestSchema = z.object({
|
||||
requestId: z.string(),
|
||||
});
|
||||
|
||||
export const WorkspaceRuntimeCatalogEntrySchema = z.object({
|
||||
runtimeId: z.string(),
|
||||
builtin: z.boolean(),
|
||||
label: z.string().optional(),
|
||||
requiresGitProject: z.boolean(),
|
||||
});
|
||||
|
||||
export const WorkspaceRuntimeListRequestSchema = z.object({
|
||||
type: z.literal("workspace.runtime.list.request"),
|
||||
requestId: z.string(),
|
||||
});
|
||||
|
||||
// Create a new workspace record. Unlike open_project, this never deduplicates by
|
||||
// directory: it always produces a fresh workspace. The source discriminates
|
||||
// between an existing local directory and a newly created paseo worktree.
|
||||
export const WorkspaceCreateRequestSchema = z.object({
|
||||
type: z.literal("workspace.create.request"),
|
||||
requestId: z.string(),
|
||||
runtimeId: z.string().optional(),
|
||||
// Optional user-set title applied to the created workspace.
|
||||
title: z.string().optional(),
|
||||
// Optional prompt context for workspace-level name/branch generation.
|
||||
@@ -2733,6 +2746,7 @@ export const SessionInboundMessageSchema = z.discriminatedUnion("type", [
|
||||
ProjectGithubCloneRequestSchema,
|
||||
ArchiveWorkspaceRequestSchema,
|
||||
WorkspaceCreateRequestSchema,
|
||||
WorkspaceRuntimeListRequestSchema,
|
||||
WorkspaceClearAttentionRequestSchema,
|
||||
FileExplorerRequestSchema,
|
||||
FileSubscribeRequestSchema,
|
||||
@@ -2981,6 +2995,8 @@ export const ServerInfoStatusPayloadSchema = z
|
||||
checkoutRefresh: z.boolean().optional(),
|
||||
// COMPAT(workspaceMultiplicity): added in v0.1.97, drop the gate when floor >= v0.1.97
|
||||
workspaceMultiplicity: z.boolean().optional(),
|
||||
// COMPAT(workspaceRuntimes): added in v0.3.2, remove gate after 2027-02-11.
|
||||
workspaceRuntimes: z.boolean().optional(),
|
||||
// COMPAT(projectRemove): added in v0.1.97, drop the gate when floor >= v0.1.97.
|
||||
projectRemove: z.boolean().optional(),
|
||||
// COMPAT(projectAdd): added in v0.1.97, drop the gate when floor >= v0.1.97.
|
||||
@@ -3963,6 +3979,14 @@ export const WorkspaceCreateResponseSchema = z.object({
|
||||
}),
|
||||
});
|
||||
|
||||
export const WorkspaceRuntimeListResponseSchema = z.object({
|
||||
type: z.literal("workspace.runtime.list.response"),
|
||||
payload: z.object({
|
||||
runtimes: z.array(WorkspaceRuntimeCatalogEntrySchema),
|
||||
requestId: z.string(),
|
||||
}),
|
||||
});
|
||||
|
||||
export const WorkspaceClearAttentionResponseSchema = z.object({
|
||||
type: z.literal("workspace.clear_attention.response"),
|
||||
payload: z.object({
|
||||
@@ -5551,6 +5575,7 @@ export const SessionOutboundMessageSchema = z.discriminatedUnion("type", [
|
||||
CancelAgentResponseMessageSchema,
|
||||
ClearAgentAttentionResponseMessageSchema,
|
||||
WorkspaceCreateResponseSchema,
|
||||
WorkspaceRuntimeListResponseSchema,
|
||||
WorkspaceClearAttentionResponseSchema,
|
||||
SendAgentMessageResponseMessageSchema,
|
||||
SetVoiceModeResponseMessageSchema,
|
||||
@@ -5778,6 +5803,10 @@ export type WorkspaceRecoveryRestoreResponse = z.infer<
|
||||
>;
|
||||
export type WorkspaceCreateRequest = z.infer<typeof WorkspaceCreateRequestSchema>;
|
||||
export type WorkspaceCreateResponse = z.infer<typeof WorkspaceCreateResponseSchema>;
|
||||
export type WorkspaceRuntimeCatalogEntry = z.infer<typeof WorkspaceRuntimeCatalogEntrySchema>;
|
||||
export type WorkspaceRuntimeListPayload = z.infer<
|
||||
typeof WorkspaceRuntimeListResponseSchema
|
||||
>["payload"];
|
||||
export type ProjectRenameResponsePayload = z.infer<typeof ProjectRenameResponsePayloadSchema>;
|
||||
export type ProjectRemoveResponsePayload = z.infer<typeof ProjectRemoveResponsePayloadSchema>;
|
||||
export type WaitForFinishResponseMessage = z.infer<typeof WaitForFinishResponseMessageSchema>;
|
||||
|
||||
@@ -5,6 +5,8 @@ import {
|
||||
SessionInboundMessageSchema,
|
||||
SessionOutboundMessageSchema,
|
||||
WorkspaceCreateRequestSchema,
|
||||
WorkspaceRuntimeListRequestSchema,
|
||||
WorkspaceRuntimeListResponseSchema,
|
||||
WorkspaceDescriptorPayloadSchema,
|
||||
WorkspaceScriptPayloadSchema,
|
||||
} from "./messages.js";
|
||||
@@ -1118,4 +1120,45 @@ describe("workspace message schemas", () => {
|
||||
expect(newDirectory.type).toBe("workspace.create.request");
|
||||
expect(newDirectory.source.kind).toBe("directory");
|
||||
});
|
||||
|
||||
test("workspace runtime catalog and optional create selection stay wire-compatible", () => {
|
||||
expect(
|
||||
WorkspaceRuntimeListRequestSchema.parse({
|
||||
type: "workspace.runtime.list.request",
|
||||
requestId: "runtime-list",
|
||||
}),
|
||||
).toEqual({ type: "workspace.runtime.list.request", requestId: "runtime-list" });
|
||||
expect(
|
||||
WorkspaceRuntimeListResponseSchema.parse({
|
||||
type: "workspace.runtime.list.response",
|
||||
payload: {
|
||||
requestId: "runtime-list",
|
||||
runtimes: [
|
||||
{ runtimeId: "local", builtin: true, requiresGitProject: false },
|
||||
{
|
||||
runtimeId: "fixture",
|
||||
builtin: false,
|
||||
label: "Fixture",
|
||||
requiresGitProject: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
}).payload.runtimes,
|
||||
).toHaveLength(2);
|
||||
expect(
|
||||
WorkspaceCreateRequestSchema.parse({
|
||||
type: "workspace.create.request",
|
||||
requestId: "old-client",
|
||||
source: { kind: "directory", path: "/repo" },
|
||||
}),
|
||||
).not.toHaveProperty("runtimeId");
|
||||
expect(
|
||||
WorkspaceCreateRequestSchema.parse({
|
||||
type: "workspace.create.request",
|
||||
requestId: "new-client",
|
||||
source: { kind: "directory", path: "/repo" },
|
||||
runtimeId: "fixture",
|
||||
}).runtimeId,
|
||||
).toBe("fixture");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user