mirror of
https://github.com/getpaseo/paseo.git
synced 2026-07-29 12:01:31 +00:00
Migrate monorepo to Zod 4
This commit is contained in:
@@ -26,7 +26,7 @@
|
||||
"test": "vitest run"
|
||||
},
|
||||
"dependencies": {
|
||||
"zod": "^3.23.8"
|
||||
"zod": "^4.4.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.9.0",
|
||||
|
||||
@@ -199,7 +199,7 @@ const AgentSelectOptionSchema = z.object({
|
||||
label: z.string(),
|
||||
description: z.string().optional(),
|
||||
isDefault: z.boolean().optional(),
|
||||
metadata: z.record(z.unknown()).optional(),
|
||||
metadata: z.record(z.string(), z.unknown()).optional(),
|
||||
});
|
||||
|
||||
export const AgentFeatureToggleSchema = z.object({
|
||||
@@ -235,7 +235,7 @@ const AgentModelDefinitionSchema: z.ZodType<AgentModelDefinition> = z
|
||||
label: z.string(),
|
||||
description: z.string().optional(),
|
||||
isDefault: z.boolean().optional(),
|
||||
metadata: z.record(z.unknown()).optional(),
|
||||
metadata: z.record(z.string(), z.unknown()).optional(),
|
||||
thinkingOptions: z.array(AgentSelectOptionSchema).optional(),
|
||||
defaultThinkingOptionId: z.string().optional(),
|
||||
})
|
||||
@@ -285,21 +285,21 @@ const McpStdioServerConfigSchema = z.object({
|
||||
type: z.literal("stdio"),
|
||||
command: z.string(),
|
||||
args: z.array(z.string()).optional(),
|
||||
env: z.record(z.string()).optional(),
|
||||
env: z.record(z.string(), z.string()).optional(),
|
||||
alwaysLoad: z.boolean().optional(),
|
||||
});
|
||||
|
||||
const McpHttpServerConfigSchema = z.object({
|
||||
type: z.literal("http"),
|
||||
url: z.string(),
|
||||
headers: z.record(z.string()).optional(),
|
||||
headers: z.record(z.string(), z.string()).optional(),
|
||||
alwaysLoad: z.boolean().optional(),
|
||||
});
|
||||
|
||||
const McpSseServerConfigSchema = z.object({
|
||||
type: z.literal("sse"),
|
||||
url: z.string(),
|
||||
headers: z.record(z.string()).optional(),
|
||||
headers: z.record(z.string(), z.string()).optional(),
|
||||
alwaysLoad: z.boolean().optional(),
|
||||
});
|
||||
|
||||
@@ -315,7 +315,7 @@ const AgentSessionConfigSchema = z.object({
|
||||
modeId: z.string().optional(),
|
||||
model: z.string().optional(),
|
||||
thinkingOptionId: z.string().optional(),
|
||||
featureValues: z.record(z.unknown()).optional(),
|
||||
featureValues: z.record(z.string(), z.unknown()).optional(),
|
||||
title: z.string().trim().min(1).max(MAX_EXPLICIT_AGENT_TITLE_CHARS).optional().nullable(),
|
||||
approvalPolicy: z.string().optional(),
|
||||
sandboxMode: z.string().optional(),
|
||||
@@ -323,16 +323,16 @@ const AgentSessionConfigSchema = z.object({
|
||||
webSearch: z.boolean().optional(),
|
||||
extra: z
|
||||
.object({
|
||||
codex: z.record(z.unknown()).optional(),
|
||||
claude: z.record(z.unknown()).optional(),
|
||||
codex: z.record(z.string(), z.unknown()).optional(),
|
||||
claude: z.record(z.string(), z.unknown()).optional(),
|
||||
})
|
||||
.partial()
|
||||
.optional(),
|
||||
systemPrompt: z.string().optional(),
|
||||
mcpServers: z.record(McpServerConfigSchema).optional(),
|
||||
mcpServers: z.record(z.string(), McpServerConfigSchema).optional(),
|
||||
});
|
||||
|
||||
const AgentPermissionUpdateSchema = z.record(z.unknown());
|
||||
const AgentPermissionUpdateSchema = z.record(z.string(), z.unknown());
|
||||
const AgentPermissionActionSchema = z.object({
|
||||
id: z.string(),
|
||||
label: z.string(),
|
||||
@@ -345,7 +345,7 @@ export const AgentPermissionResponseSchema: z.ZodType<AgentPermissionResponse> =
|
||||
z.object({
|
||||
behavior: z.literal("allow"),
|
||||
selectedActionId: z.string().optional(),
|
||||
updatedInput: z.record(z.unknown()).optional(),
|
||||
updatedInput: z.record(z.string(), z.unknown()).optional(),
|
||||
updatedPermissions: z.array(AgentPermissionUpdateSchema).optional(),
|
||||
}),
|
||||
z.object({
|
||||
@@ -356,23 +356,20 @@ export const AgentPermissionResponseSchema: z.ZodType<AgentPermissionResponse> =
|
||||
}),
|
||||
]);
|
||||
|
||||
export const AgentPermissionRequestPayloadSchema: z.ZodType<
|
||||
AgentPermissionRequest,
|
||||
z.ZodTypeDef,
|
||||
unknown
|
||||
> = z.object({
|
||||
id: z.string(),
|
||||
provider: AgentProviderSchema,
|
||||
name: z.string(),
|
||||
kind: z.enum(["tool", "plan", "question", "mode", "other"]),
|
||||
title: z.string().optional(),
|
||||
description: z.string().optional(),
|
||||
input: z.record(z.unknown()).optional(),
|
||||
detail: z.lazy(() => ToolCallDetailPayloadSchema).optional(),
|
||||
suggestions: z.array(AgentPermissionUpdateSchema).optional(),
|
||||
actions: z.array(AgentPermissionActionSchema).optional(),
|
||||
metadata: z.record(z.unknown()).optional(),
|
||||
});
|
||||
export const AgentPermissionRequestPayloadSchema: z.ZodType<AgentPermissionRequest, unknown> =
|
||||
z.object({
|
||||
id: z.string(),
|
||||
provider: AgentProviderSchema,
|
||||
name: z.string(),
|
||||
kind: z.enum(["tool", "plan", "question", "mode", "other"]),
|
||||
title: z.string().optional(),
|
||||
description: z.string().optional(),
|
||||
input: z.record(z.string(), z.unknown()).optional(),
|
||||
detail: z.lazy(() => ToolCallDetailPayloadSchema).optional(),
|
||||
suggestions: z.array(AgentPermissionUpdateSchema).optional(),
|
||||
actions: z.array(AgentPermissionActionSchema).optional(),
|
||||
metadata: z.record(z.string(), z.unknown()).optional(),
|
||||
});
|
||||
|
||||
const UnknownValueSchema = z.union([
|
||||
z.null(),
|
||||
@@ -410,8 +407,9 @@ const WorktreeSetupDetailPayloadSchema = z.object({
|
||||
truncated: z.boolean().optional(),
|
||||
});
|
||||
|
||||
const ToolCallDetailPayloadSchema: z.ZodType<ToolCallDetail, z.ZodTypeDef, unknown> =
|
||||
z.discriminatedUnion("type", [
|
||||
const ToolCallDetailPayloadSchema: z.ZodType<ToolCallDetail, unknown> = z.discriminatedUnion(
|
||||
"type",
|
||||
[
|
||||
WorktreeSetupDetailPayloadSchema,
|
||||
z.object({
|
||||
type: z.literal("shell"),
|
||||
@@ -505,7 +503,8 @@ const ToolCallDetailPayloadSchema: z.ZodType<ToolCallDetail, z.ZodTypeDef, unkno
|
||||
input: UnknownValueSchema,
|
||||
output: UnknownValueSchema,
|
||||
}),
|
||||
]);
|
||||
],
|
||||
);
|
||||
|
||||
const ToolCallBasePayloadSchema = z.object({
|
||||
type: z.literal("tool_call"),
|
||||
@@ -535,51 +534,49 @@ const ToolCallCanceledPayloadSchema = ToolCallBasePayloadSchema.extend({
|
||||
error: z.null(),
|
||||
});
|
||||
|
||||
const ToolCallTimelineItemPayloadSchema: z.ZodType<ToolCallTimelineItem, z.ZodTypeDef, unknown> =
|
||||
z.union([
|
||||
ToolCallRunningPayloadSchema,
|
||||
ToolCallCompletedPayloadSchema,
|
||||
ToolCallFailedPayloadSchema,
|
||||
ToolCallCanceledPayloadSchema,
|
||||
]);
|
||||
const ToolCallTimelineItemPayloadSchema: z.ZodType<ToolCallTimelineItem, unknown> = z.union([
|
||||
ToolCallRunningPayloadSchema,
|
||||
ToolCallCompletedPayloadSchema,
|
||||
ToolCallFailedPayloadSchema,
|
||||
ToolCallCanceledPayloadSchema,
|
||||
]);
|
||||
|
||||
export const AgentTimelineItemPayloadSchema: z.ZodType<AgentTimelineItem, z.ZodTypeDef, unknown> =
|
||||
z.union([
|
||||
z.object({
|
||||
type: z.literal("user_message"),
|
||||
text: z.string(),
|
||||
messageId: z.string().optional(),
|
||||
}),
|
||||
z.object({
|
||||
type: z.literal("assistant_message"),
|
||||
text: z.string(),
|
||||
messageId: z.string().optional(),
|
||||
}),
|
||||
z.object({
|
||||
type: z.literal("reasoning"),
|
||||
text: z.string(),
|
||||
}),
|
||||
ToolCallTimelineItemPayloadSchema,
|
||||
z.object({
|
||||
type: z.literal("todo"),
|
||||
items: z.array(
|
||||
z.object({
|
||||
text: z.string(),
|
||||
completed: z.boolean(),
|
||||
}),
|
||||
),
|
||||
}),
|
||||
z.object({
|
||||
type: z.literal("error"),
|
||||
message: z.string(),
|
||||
}),
|
||||
z.object({
|
||||
type: z.literal("compaction"),
|
||||
status: z.enum(["loading", "completed"]),
|
||||
trigger: z.enum(["auto", "manual"]).optional(),
|
||||
preTokens: z.number().optional(),
|
||||
}),
|
||||
]);
|
||||
export const AgentTimelineItemPayloadSchema: z.ZodType<AgentTimelineItem, unknown> = z.union([
|
||||
z.object({
|
||||
type: z.literal("user_message"),
|
||||
text: z.string(),
|
||||
messageId: z.string().optional(),
|
||||
}),
|
||||
z.object({
|
||||
type: z.literal("assistant_message"),
|
||||
text: z.string(),
|
||||
messageId: z.string().optional(),
|
||||
}),
|
||||
z.object({
|
||||
type: z.literal("reasoning"),
|
||||
text: z.string(),
|
||||
}),
|
||||
ToolCallTimelineItemPayloadSchema,
|
||||
z.object({
|
||||
type: z.literal("todo"),
|
||||
items: z.array(
|
||||
z.object({
|
||||
text: z.string(),
|
||||
completed: z.boolean(),
|
||||
}),
|
||||
),
|
||||
}),
|
||||
z.object({
|
||||
type: z.literal("error"),
|
||||
message: z.string(),
|
||||
}),
|
||||
z.object({
|
||||
type: z.literal("compaction"),
|
||||
status: z.enum(["loading", "completed"]),
|
||||
trigger: z.enum(["auto", "manual"]).optional(),
|
||||
preTokens: z.number().optional(),
|
||||
}),
|
||||
]);
|
||||
|
||||
export const AgentStreamEventPayloadSchema = z.discriminatedUnion("type", [
|
||||
z.object({
|
||||
@@ -755,7 +752,7 @@ export const AudioPlayedMessageSchema = z.object({
|
||||
});
|
||||
|
||||
const AgentDirectoryFilterSchema = z.object({
|
||||
labels: z.record(z.string()).optional(),
|
||||
labels: z.record(z.string(), z.string()).optional(),
|
||||
projectKeys: z.array(z.string()).optional(),
|
||||
statuses: z.array(AgentStatusSchema).optional(),
|
||||
includeArchived: z.boolean().optional(),
|
||||
@@ -786,7 +783,7 @@ export const UpdateAgentRequestMessageSchema = z.object({
|
||||
type: z.literal("update_agent_request"),
|
||||
agentId: z.string(),
|
||||
name: z.string().optional(),
|
||||
labels: z.record(z.string()).optional(),
|
||||
labels: z.record(z.string(), z.string()).optional(),
|
||||
requestId: z.string(),
|
||||
});
|
||||
|
||||
@@ -1138,18 +1135,18 @@ export type CreateAgentWorktreeTarget = z.infer<typeof CreateAgentWorktreeTarget
|
||||
export const CreateAgentRequestMessageSchema = z.object({
|
||||
type: z.literal("create_agent_request"),
|
||||
config: AgentSessionConfigSchema,
|
||||
env: z.record(z.string()).optional(),
|
||||
env: z.record(z.string(), z.string()).optional(),
|
||||
workspaceId: z.string().optional(),
|
||||
worktreeName: z.string().optional(),
|
||||
initialPrompt: z.string().optional(),
|
||||
clientMessageId: z.string().optional(),
|
||||
outputSchema: z.record(z.unknown()).optional(),
|
||||
outputSchema: z.record(z.string(), z.unknown()).optional(),
|
||||
images: z.array(ImageAttachmentSchema).optional(),
|
||||
attachments: AgentAttachmentsSchema,
|
||||
git: GitSetupOptionsSchema.optional(),
|
||||
worktree: CreateAgentWorktreeTargetSchema.optional(),
|
||||
autoArchive: z.boolean().optional(),
|
||||
labels: z.record(z.string()).default({}),
|
||||
labels: z.record(z.string(), z.string()).default({}),
|
||||
requestId: z.string(),
|
||||
});
|
||||
|
||||
@@ -1205,7 +1202,7 @@ export const ImportAgentRequestMessageSchema = z.object({
|
||||
sessionId: z.string().optional(),
|
||||
providerHandleId: z.string().optional(),
|
||||
cwd: z.string().optional(),
|
||||
labels: z.record(z.string()).optional(),
|
||||
labels: z.record(z.string(), z.string()).optional(),
|
||||
requestId: z.string(),
|
||||
});
|
||||
|
||||
@@ -1832,7 +1829,7 @@ const ListCommandsDraftConfigSchema = z.object({
|
||||
modeId: z.string().optional(),
|
||||
model: z.string().optional(),
|
||||
thinkingOptionId: z.string().optional(),
|
||||
featureValues: z.record(z.unknown()).optional(),
|
||||
featureValues: z.record(z.string(), z.unknown()).optional(),
|
||||
});
|
||||
|
||||
export const ListProviderFeaturesRequestMessageSchema = z.object({
|
||||
@@ -2094,7 +2091,7 @@ export const ActivityLogPayloadSchema = z.object({
|
||||
timestamp: z.coerce.date(),
|
||||
type: z.enum(["transcript", "assistant", "tool_call", "tool_result", "error", "system"]),
|
||||
content: z.string(),
|
||||
metadata: z.record(z.unknown()).optional(),
|
||||
metadata: z.record(z.string(), z.unknown()).optional(),
|
||||
});
|
||||
|
||||
export const ActivityLogMessageSchema = z.object({
|
||||
@@ -2241,7 +2238,7 @@ export const ServerInfoStatusPayloadSchema = z
|
||||
serverId: z.string().trim().min(1),
|
||||
hostname: ServerInfoHostnameSchema.optional(),
|
||||
version: ServerInfoVersionSchema.optional(),
|
||||
capabilities: ServerCapabilitiesFromUnknownSchema,
|
||||
capabilities: ServerCapabilitiesFromUnknownSchema.optional(),
|
||||
// COMPAT(providersSnapshot): added in v0.1.48, remove gating when all clients use snapshot
|
||||
features: z
|
||||
.object({
|
||||
@@ -3486,7 +3483,7 @@ export const PullRequestTimelineResponseSchema = z.object({
|
||||
githubFeaturesEnabled: z.boolean().optional().default(true),
|
||||
})
|
||||
.optional()
|
||||
.default({}),
|
||||
.prefault({}),
|
||||
});
|
||||
|
||||
export const CheckoutSwitchBranchResponseSchema = z.object({
|
||||
|
||||
@@ -33,6 +33,34 @@ describe("paseo config schema", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("normalizes partial worktree lifecycle config without dropping present commands", () => {
|
||||
expect(
|
||||
PaseoConfigSchema.parse({
|
||||
worktree: {
|
||||
setup: 'echo "setup ran" > setup.log',
|
||||
},
|
||||
}),
|
||||
).toEqual({
|
||||
worktree: {
|
||||
setup: ['echo "setup ran" > setup.log'],
|
||||
teardown: [],
|
||||
},
|
||||
});
|
||||
|
||||
expect(
|
||||
PaseoConfigSchema.parse({
|
||||
worktree: {
|
||||
teardown: ["npm run clean"],
|
||||
},
|
||||
}),
|
||||
).toEqual({
|
||||
worktree: {
|
||||
setup: [],
|
||||
teardown: ["npm run clean"],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("parses all metadata generation instruction entries", () => {
|
||||
expect(
|
||||
PaseoConfigSchema.parse({
|
||||
|
||||
@@ -58,8 +58,8 @@ export const PaseoConfigRawSchema = z
|
||||
.passthrough();
|
||||
|
||||
export const WorktreeConfigSchema = PaseoWorktreeConfigRawSchema.extend({
|
||||
setup: z.unknown().transform(normalizeLifecycleCommands),
|
||||
teardown: z.unknown().transform(normalizeLifecycleCommands),
|
||||
setup: z.unknown().optional().transform(normalizeLifecycleCommands),
|
||||
teardown: z.unknown().optional().transform(normalizeLifecycleCommands),
|
||||
})
|
||||
.passthrough()
|
||||
.catch({ setup: [], teardown: [] });
|
||||
|
||||
@@ -24,7 +24,7 @@ export const ProviderCommandSchema = z.discriminatedUnion("mode", [
|
||||
|
||||
export const ProviderRuntimeSettingsSchema = z.object({
|
||||
command: ProviderCommandSchema.optional(),
|
||||
env: z.record(z.string()).optional(),
|
||||
env: z.record(z.string(), z.string()).optional(),
|
||||
disallowedTools: z.array(z.string()).optional(),
|
||||
});
|
||||
|
||||
@@ -48,8 +48,8 @@ export const ProviderOverrideSchema = z.object({
|
||||
label: z.string().optional(),
|
||||
description: z.string().optional(),
|
||||
command: z.array(z.string().min(1)).min(1).optional(),
|
||||
env: z.record(z.string()).optional(),
|
||||
params: z.record(z.unknown()).optional(),
|
||||
env: z.record(z.string(), z.string()).optional(),
|
||||
params: z.record(z.string(), z.unknown()).optional(),
|
||||
models: z.array(ProviderProfileModelSchema).optional(),
|
||||
additionalModels: z.array(ProviderProfileModelSchema).optional(),
|
||||
disallowedTools: z.array(z.string()).optional(),
|
||||
@@ -61,7 +61,7 @@ const BUILTIN_PROVIDER_IDS = ["claude", "codex", "copilot", "opencode", "pi", "o
|
||||
const PROVIDER_ID_PATTERN = /^[a-z][a-z0-9-]*$/;
|
||||
|
||||
export const ProviderOverridesSchema = z
|
||||
.record(ProviderOverrideSchema)
|
||||
.record(z.string(), ProviderOverrideSchema)
|
||||
.superRefine((providers, ctx) => {
|
||||
const builtinProviderIdSet = new Set<string>(BUILTIN_PROVIDER_IDS);
|
||||
const validExtendsValues = new Set<string>([...BUILTIN_PROVIDER_IDS, "acp"]);
|
||||
@@ -111,7 +111,7 @@ export const ProviderOverridesSchema = z
|
||||
});
|
||||
|
||||
export const AgentProviderRuntimeSettingsMapSchema = z
|
||||
.record(ProviderRuntimeSettingsSchema)
|
||||
.record(z.string(), ProviderRuntimeSettingsSchema)
|
||||
.superRefine((providers, ctx) => {
|
||||
for (const providerId of Object.keys(providers)) {
|
||||
const parsedProviderId = AgentProviderSchema.safeParse(providerId);
|
||||
|
||||
@@ -10,11 +10,11 @@ import {
|
||||
const ScheduleCreateTargetSchema = z.discriminatedUnion("type", [
|
||||
z.object({
|
||||
type: z.literal("self"),
|
||||
agentId: z.string().uuid(),
|
||||
agentId: z.guid(),
|
||||
}),
|
||||
z.object({
|
||||
type: z.literal("agent"),
|
||||
agentId: z.string().uuid(),
|
||||
agentId: z.guid(),
|
||||
}),
|
||||
z.object({
|
||||
type: z.literal("new-agent"),
|
||||
|
||||
@@ -20,7 +20,7 @@ export type ScheduleCadence = z.infer<typeof ScheduleCadenceSchema>;
|
||||
export const ScheduleTargetSchema = z.discriminatedUnion("type", [
|
||||
z.object({
|
||||
type: z.literal("agent"),
|
||||
agentId: z.string().uuid(),
|
||||
agentId: z.guid(),
|
||||
}),
|
||||
z.object({
|
||||
type: z.literal("new-agent"),
|
||||
@@ -35,16 +35,16 @@ export const ScheduleTargetSchema = z.discriminatedUnion("type", [
|
||||
sandboxMode: z.string().trim().min(1).optional(),
|
||||
networkAccess: z.boolean().optional(),
|
||||
webSearch: z.boolean().optional(),
|
||||
featureValues: z.record(z.unknown()).optional(),
|
||||
featureValues: z.record(z.string(), z.unknown()).optional(),
|
||||
extra: z
|
||||
.object({
|
||||
codex: z.record(z.unknown()).optional(),
|
||||
claude: z.record(z.unknown()).optional(),
|
||||
codex: z.record(z.string(), z.unknown()).optional(),
|
||||
claude: z.record(z.string(), z.unknown()).optional(),
|
||||
})
|
||||
.partial()
|
||||
.optional(),
|
||||
systemPrompt: z.string().optional(),
|
||||
mcpServers: z.record(z.unknown()).optional(),
|
||||
mcpServers: z.record(z.string(), z.unknown()).optional(),
|
||||
}),
|
||||
}),
|
||||
]);
|
||||
@@ -56,7 +56,7 @@ export const ScheduleRunSchema = z.object({
|
||||
startedAt: z.string(),
|
||||
endedAt: z.string().nullable(),
|
||||
status: z.enum(["running", "succeeded", "failed"]),
|
||||
agentId: z.string().uuid().nullable(),
|
||||
agentId: z.guid().nullable(),
|
||||
output: z.string().nullable(),
|
||||
error: z.string().nullable(),
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user